mirror of
https://github.com/prirun/p50em.git
synced 2026-01-13 15:17:32 +00:00
--tport option, support for physical queues (RTQ, ABQ) for DMQ (QAMLC)
This commit is contained in:
parent
09b9592915
commit
03dedb4106
170
em.c
170
em.c
@ -311,6 +311,7 @@ int domemdump; /* --memdump arg */
|
||||
int boot; /* true if reading a boot record */
|
||||
int pmap32bits; /* true if 32-bit page maps */
|
||||
int csoffset; /* concealed stack segment offset */
|
||||
int tport; /* --port option (incoming terminals) */
|
||||
|
||||
/* load map related data, specified with --map */
|
||||
|
||||
@ -907,7 +908,8 @@ void fault(unsigned short fvec, unsigned short fcode, ea_t faddr) {
|
||||
|
||||
|
||||
fatal(char *msg) {
|
||||
printf("Fatal error: instruction #%d at %o/%o %s: %o %o keys=%o, modals=%o\n", instcount, prevpc >> 16, prevpc & 0xFFFF, searchloadmap(prevpc,' '), get16(prevpc), get16(prevpc+1), crs[KEYS], crs[MODALS]);
|
||||
|
||||
printf("Fatal error: instruction #%d at %o/%o %s: %o %o\nowner=%o %s, keys=%o, modals=%o\n", instcount, prevpc >> 16, prevpc & 0xFFFF, searchloadmap(prevpc,' '), get16(prevpc), get16(prevpc+1), crs[OWNERL], searchloadmap(*(unsigned int *)(crs+OWNER),' '), crs[KEYS], crs[MODALS]);
|
||||
if (msg)
|
||||
printf("%s\n", msg);
|
||||
/* should do a register dump, RL dump, PCB dump, etc. here... */
|
||||
@ -924,15 +926,27 @@ long devpoll[64] = {0};
|
||||
|
||||
#include "emdev.h"
|
||||
|
||||
void (*devmap[64])(short, short, short) = {
|
||||
0,0,0,0,devasr,0,0,0,
|
||||
0,0,0,devmt,devmt,0,0,0,
|
||||
devcp,0,0,0,0,0,devdisk,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0};
|
||||
#if 0
|
||||
int (*devmap[64])(short, short, short) = {
|
||||
/* '0x */ 0,0,0,0,devasr,0,0,0,
|
||||
/* '1x */ devnone,devnone,0,devmt,devmt,devamlc, devamlc, devamlc,
|
||||
/* '2x */ devcp,0,devdisk,devdisk,devdisk,devdisk,devdisk,devdisk,
|
||||
/* '3x */ 0,0,devamlc,0,0,devamlc,devnone,devnone,
|
||||
/* '4x */ 0,0,0,0,0,0,0,0,
|
||||
/* '5x */ devnone,devnone,devamlc,devamlc,devamlc,0,devnone,0,
|
||||
/* '6x */ 0,0,0,0,0,0,0,0,
|
||||
/* '7x */ 0,0,0,0,0,devnone,devnone,0};
|
||||
#else
|
||||
int (*devmap[64])(short, short, short) = {
|
||||
/* '0x */ 0,0,0,0,devasr,0,0,0,
|
||||
/* '1x */ devnone,devnone,0,devmt,devmt,devnone, devnone, devnone,
|
||||
/* '2x */ devcp,0,devdisk,devdisk,devdisk,devdisk,devdisk,devdisk,
|
||||
/* '3x */ 0,0,devnone,0,0,devnone,devnone,devnone,
|
||||
/* '4x */ 0,0,0,0,0,0,0,0,
|
||||
/* '5x */ devnone,devnone,devnone,devnone,devamlc,0,devnone,0,
|
||||
/* '6x */ 0,0,0,0,0,0,0,0,
|
||||
/* '7x */ 0,0,0,0,0,devnone,devnone,0};
|
||||
#endif
|
||||
|
||||
/* read a short (16-bit) integer in big-endian from stdin */
|
||||
|
||||
@ -2549,6 +2563,59 @@ stc(n) {
|
||||
}
|
||||
|
||||
|
||||
/* queue instructions where physical queues may be involved */
|
||||
|
||||
int rtq(ea_t qcbea, unsigned short *qent, ea_t rp) {
|
||||
|
||||
unsigned int qtop, qbot, qtemp;
|
||||
unsigned short qseg, qmask;
|
||||
ea_t qentea;
|
||||
|
||||
qtop = get16r(qcbea, rp);
|
||||
qbot = get16r(qcbea+1, rp);
|
||||
|
||||
if (qtop == qbot)
|
||||
return 0; /* queue is empty */
|
||||
qseg = get16r(qcbea+2, rp);
|
||||
qmask = get16r(qcbea+3, rp);
|
||||
qentea = MAKEVA(qseg & 0xfff, qtop);
|
||||
if (qseg & 0x8000) /* virtual queue */
|
||||
*qent = get16r(qentea, rp);
|
||||
else {
|
||||
RESTRICTR(rp);
|
||||
*qent = mem[qentea];
|
||||
}
|
||||
qtop = (qtop & ~qmask) | ((qtop+1) & qmask);
|
||||
put16r(qtop & 0xFFFF, qcbea, rp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int abq(ea_t qcbea, unsigned short qent, ea_t rp) {
|
||||
|
||||
unsigned int qtop, qbot, qtemp;
|
||||
unsigned short qseg, qmask;
|
||||
ea_t qentea;
|
||||
|
||||
qtop = get16r(qcbea, rp);
|
||||
qbot = get16r(qcbea+1, rp);
|
||||
qseg = get16r(qcbea+2, rp);
|
||||
qmask = get16r(qcbea+3, rp);
|
||||
qtemp = (qbot & ~qmask) | ((qbot+1) & qmask);
|
||||
if (qtemp == qtop) /* queue full */
|
||||
return 0;
|
||||
qentea = MAKEVA(qseg & 0xfff,qbot);
|
||||
if (qseg & 0x8000) /* virtual queue */
|
||||
put16r(crs[A], qentea, rp);
|
||||
else {
|
||||
RESTRICTR(rp);
|
||||
mem[qentea] = qent;
|
||||
}
|
||||
put16r(qtemp, qcbea+1, rp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
main (int argc, char **argv) {
|
||||
|
||||
short tempa,tempa1,tempa2;
|
||||
@ -2621,6 +2688,7 @@ main (int argc, char **argv) {
|
||||
boot = 0;
|
||||
pmap32bits = 0;
|
||||
csoffset = 0;
|
||||
tport = 0;
|
||||
|
||||
/* check args */
|
||||
|
||||
@ -2646,6 +2714,12 @@ main (int argc, char **argv) {
|
||||
cpuid = templ;
|
||||
} else
|
||||
fprintf(stderr,"--cpuid needs an argument\n");
|
||||
} else if (strcmp(argv[i],"--port") == 0) {
|
||||
if (i+1 < argc && argv[i+1][0] != '-') {
|
||||
sscanf(argv[i+1],"%d", &templ);
|
||||
tport = templ;
|
||||
} else
|
||||
fprintf(stderr,"--cpuid needs an argument\n");
|
||||
} else if (strcmp(argv[i],"--trace") == 0)
|
||||
while (i+1 < argc && argv[i+1][0] != '-') {
|
||||
if (strcmp(argv[i+1],"ear") == 0)
|
||||
@ -2689,6 +2763,8 @@ main (int argc, char **argv) {
|
||||
pmap32bits = (cpuid == 15 || cpuid == 18 || cpuid == 19 || cpuid == 24 || cpuid >= 26);
|
||||
if ((26 <= cpuid && cpuid <= 29) || cpuid >= 35)
|
||||
csoffset = 1;
|
||||
if (tport == 0)
|
||||
tport = 8000;
|
||||
|
||||
fprintf(stderr,"Sense switches set to %o\n", sswitch);
|
||||
|
||||
@ -2696,7 +2772,11 @@ main (int argc, char **argv) {
|
||||
|
||||
for (i=0; i<64; i++)
|
||||
if (devmap[i])
|
||||
devmap[i](-1, 0, i);
|
||||
if (devmap[i](-1, 0, i)) { /* if initialization fails, */
|
||||
devmap[i] = devnone; /* remove device */
|
||||
printf("emulator: device '%o removed\n", i);
|
||||
}
|
||||
|
||||
|
||||
os_init();
|
||||
|
||||
@ -2764,23 +2844,23 @@ main (int argc, char **argv) {
|
||||
traceflags = ~TB_MAP;
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
if (traceflags != 0)
|
||||
savetraceflags = traceflags;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
if (traceflags != 0)
|
||||
savetraceflags = traceflags;
|
||||
if (crs[OWNERL] == 0100100 && savetraceflags)
|
||||
if (crs[OWNERL] == 0100200 && savetraceflags)
|
||||
traceflags = savetraceflags;
|
||||
else
|
||||
traceflags = 0;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* NOTE: this tends to hang if the location being monitored isn't
|
||||
wired */
|
||||
/* NOTE: this tends to cause a page fault loop if the location
|
||||
being monitored isn't wired */
|
||||
|
||||
if (trapaddr != 0 && (crs[OWNERL] & 0100000) && (crs[MODALS] & 010)) {
|
||||
traceflags = -1;
|
||||
@ -2800,6 +2880,10 @@ main (int argc, char **argv) {
|
||||
if (devpoll[i] && (--devpoll[i] == 0)) {
|
||||
if (!devmap[i])
|
||||
fatal("devpoll set but devmap is null");
|
||||
#if 0
|
||||
if (i == 054)
|
||||
traceflags = savetraceflags;
|
||||
#endif
|
||||
devmap[i](4, 0, i);
|
||||
}
|
||||
|
||||
@ -2915,12 +2999,10 @@ main (int argc, char **argv) {
|
||||
xec:
|
||||
/* NOTE: don't trace JMP * instructions (used to test PX) */
|
||||
|
||||
if (inst != 03777 && savetraceflags)
|
||||
traceflags = savetraceflags;
|
||||
else
|
||||
if (inst == 03777)
|
||||
traceflags = 0;
|
||||
|
||||
if (T_FLOW) fprintf(stderr,"\n #%u [%s %o] IT=%d SB: %o/%o LB: %o/%o %s XB: %o/%o\n%o/%o: %o A='%o/%:0d B='%o/%d X=%o/%d Y=%o/%d C=%d L=%d LT=%d EQ=%d K=%o M=%o\n", instcount, searchloadmap(*(unsigned int *)(crs+OWNER),'x'), crs[OWNERL], *(short *)(crs+TIMER), crs[SBH], crs[SBL], crs[LBH], crs[LBL], searchloadmap(*(unsigned int *)(crs+LBH),'l'), crs[XBH], crs[XBL], RPH, RPL-1, inst, crs[A], *(short *)(crs+A), crs[B], *(short *)(crs+B), crs[X], *(short *)(crs+X), crs[Y], *(short *)(crs+Y), (crs[KEYS]&0100000) != 0, (crs[KEYS]&020000) != 0, (crs[KEYS]&0200) != 0, (crs[KEYS]&0100) != 0, crs[KEYS], crs[MODALS]);
|
||||
if (T_FLOW) fprintf(stderr,"\n #%u [%s %o] IT=%d SB: %o/%o LB: %o/%o %s XB: %o/%o\n%o/%o: %o A='%o/%:0d B='%o/%d L='%o/%d E='%o/%d X=%o/%d Y=%o/%d C=%d L=%d LT=%d EQ=%d K=%o M=%o\n", instcount, searchloadmap(*(unsigned int *)(crs+OWNER),'x'), crs[OWNERL], *(short *)(crs+TIMER), crs[SBH], crs[SBL], crs[LBH], crs[LBL], searchloadmap(*(unsigned int *)(crs+LBH),'l'), crs[XBH], crs[XBL], RPH, RPL-1, inst, crs[A], *(short *)(crs+A), crs[B], *(short *)(crs+B), *(unsigned int *)(crs+L), *(int *)(crs+L), *(unsigned int *)(crs+E), *(int *)(crs+E), crs[X], *(short *)(crs+X), crs[Y], *(short *)(crs+Y), (crs[KEYS]&0100000) != 0, (crs[KEYS]&020000) != 0, (crs[KEYS]&0200) != 0, (crs[KEYS]&0100) != 0, crs[KEYS], crs[MODALS]);
|
||||
|
||||
/* begin instruction decode: generic? */
|
||||
|
||||
@ -3539,11 +3621,14 @@ stfa:
|
||||
|
||||
case 001702:
|
||||
if (T_FLOW) fprintf(stderr," 1702?\n", inst);
|
||||
printf(" 1702? at #%d, OWNERL=%o, RP=%o/%o\n", instcount, crs[OWNERL], RPH, RPL);
|
||||
#if 1
|
||||
fatal("Primos software assertion failure");
|
||||
#else
|
||||
RESTRICT();
|
||||
//fault(UIIFAULT, RPL, RP);
|
||||
traceflags = ~TB_MAP;
|
||||
dispatcher();
|
||||
#endif
|
||||
continue;
|
||||
|
||||
case 000601:
|
||||
@ -4651,24 +4736,21 @@ lcgt:
|
||||
*(int *)(crs+E) = templ;
|
||||
continue;
|
||||
|
||||
/* queue instructions */
|
||||
/* queue instructions
|
||||
|
||||
NOTE: ABQ is typically used in software to add an item to a
|
||||
hardware (physical) queue and RTQ is used by DMQ hardware
|
||||
to fetch items from the queue. */
|
||||
|
||||
case 0141714:
|
||||
if (T_FLOW) fprintf(stderr," RTQ\n");
|
||||
ea = apea(NULL);
|
||||
qtop = get16(ea);
|
||||
qbot = get16(ea+1);
|
||||
if (qtop == qbot) {
|
||||
if (rtq(ea,&utempa,RP)) {
|
||||
crs[A] = utempa;
|
||||
crs[KEYS] &= ~0100;
|
||||
} else {
|
||||
crs[A] = 0;
|
||||
crs[KEYS] |= 0100;
|
||||
} else {
|
||||
qseg = get16(ea+2) & 0x7FFF;
|
||||
qmask = get16(ea+3);
|
||||
qea = MAKEVA(qseg,qtop);
|
||||
crs[A] = get16(qea);
|
||||
qtop = (qtop & ~qmask) | ((qtop+1) & qmask);
|
||||
put16(qtop, ea);
|
||||
crs[KEYS] &= ~0100;
|
||||
}
|
||||
continue;
|
||||
|
||||
@ -4694,19 +4776,10 @@ lcgt:
|
||||
case 0141716:
|
||||
if (T_FLOW) fprintf(stderr," ABQ\n");
|
||||
ea = apea(NULL);
|
||||
qtop = get16(ea);
|
||||
qbot = get16(ea+1);
|
||||
qseg = get16(ea+2) & 0x7FFF;
|
||||
qmask = get16(ea+3);
|
||||
qtemp = (qbot & ~qmask) | ((qbot+1) & qmask);
|
||||
if (qtemp == qtop) { /* queue full */
|
||||
crs[KEYS] |= 0100;
|
||||
} else {
|
||||
qea = MAKEVA(qseg,qbot);
|
||||
put16(crs[A],qea);
|
||||
put16(qtemp, ea+1);
|
||||
if (abq(ea, crs[A], RP))
|
||||
crs[KEYS] &= ~0100;
|
||||
}
|
||||
else
|
||||
crs[KEYS] |= 0100;
|
||||
continue;
|
||||
|
||||
case 0141717:
|
||||
@ -6627,8 +6700,11 @@ pio(unsigned int inst) {
|
||||
if (devmap[device])
|
||||
devmap[device](class, func, device);
|
||||
else {
|
||||
fprintf(stderr,"pio: no handler for device '%o\n", device);
|
||||
return;
|
||||
#if 1
|
||||
printf("pio: no handler, class=%d, func='%o, device='%o, A='%o\n", class, func, device, crs[A]);
|
||||
fatal(NULL);
|
||||
#else
|
||||
fprintf(stderr, "pio: no handler, class=%d, func='%o, device='%o, A='%o\n", class, func, device, crs[A]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
667
emdev.h
667
emdev.h
@ -8,29 +8,37 @@
|
||||
INA/OTA instructions skip if they succeed (data was read/written)
|
||||
|
||||
Device numbers:
|
||||
'00 = polling (?)
|
||||
'01 = paper tape reader
|
||||
'02 = paper tape punch
|
||||
'03 = 1st MPC (line printer/card reader/card punch)
|
||||
'03 = #1 MPC/URC (line printer/card reader/card punch)
|
||||
'04 = SOC board (system console/user terminal)
|
||||
'05 = 2nd MPC (line printer/card reader/card punch)
|
||||
'05 = #2 MPC/URC (line printer/card reader/card punch)
|
||||
'06 = card punch? (RTOS User Guide, A-1) / IPC (Engr Handbook p.101)
|
||||
'07 = PNC
|
||||
'12 = diskette
|
||||
'13 = 2nd magtape controller
|
||||
'14 = 1st magtape controller
|
||||
'06 = Interproc. Channel (IPC) (R20 Hacker's Guide)
|
||||
'07 = #1 PNC
|
||||
'10 = ICS2 #1 or ICS1
|
||||
'11 = ICS2 #2 or ICS1
|
||||
'12 = floppy disk/diskette
|
||||
'13 = #2 magtape controller
|
||||
'14 = #1 magtape controller
|
||||
'15 = #5 AMLC or ICS1
|
||||
'16 = #6 AMLC or ICS1
|
||||
'17 = #7 AMLC or ICS1
|
||||
'20 = control panel / real-time clock
|
||||
'21 = 1st 4002 disk controller
|
||||
'22 = disk
|
||||
'23 = disk
|
||||
'24 = disk
|
||||
'25 = disk
|
||||
'21 = 1st 4002 (Option B') disk controller
|
||||
'22 = disk #3
|
||||
'23 = disk #4
|
||||
'24 = disk (was Writable Control Store)
|
||||
'25 = disk (was 4000 disk controller)
|
||||
'26 = 1st disk controller
|
||||
'27 = 2nd disk controller
|
||||
'30-32 = BPIOC #1-3 (RTOS User Guide, A-1)
|
||||
'33 = 1st Versatec (verdim)
|
||||
'34 = 2nd Versatec
|
||||
'35 = 4th AMLC
|
||||
'36-37 = ELFBUS #1 & 2
|
||||
'32 = AMLC #8 or ICS1
|
||||
'33 = #1 Versatec (verdim)
|
||||
'34 = #2 Versatec
|
||||
'35 = #4 AMLC or ICS1
|
||||
'36-37 = ELFBUS #1 & 2 (ICS1 #1, ICS1 #2)
|
||||
'40 = A/D converter type 6000
|
||||
'41 = digital input type 6020
|
||||
'42 = digital input #2
|
||||
@ -38,26 +46,34 @@
|
||||
'44 = digital output #2
|
||||
'45 = disk (was D/A converter type 6060 (analog output) - obsolete)
|
||||
'46 = disk
|
||||
'50 = 1st HSSMLC (cs/slcdim.pma)
|
||||
'51 = 2nd HSSMLC
|
||||
'52 = 3rd AMLC
|
||||
'53 = 2nd AMLC
|
||||
'54 = 1st AMLC
|
||||
'47 = #2 PNC
|
||||
'50 = #1 HSSMLC (cs/slcdim.pma)
|
||||
'51 = #2 HSSMLC
|
||||
'52 = #3 AMLC or ICS1
|
||||
'53 = #2 AMLC
|
||||
'54 = #1 AMLC
|
||||
'55 = MACI autocall unit
|
||||
'56 = old SMLC (RTOS User Guide, A-1)
|
||||
'60-67 = reserved for user devices
|
||||
'56 = old SMLC (RTOS User Guide, A-1 & Hacker's Guide)
|
||||
'60-67 = reserved for user devices (GPIB)
|
||||
'70-'73 = Megatek graphics terminals
|
||||
|
||||
Devices emulated by Primos in ks/ptrap.ftn:
|
||||
'04 = console, '01 = paper tape reader, '02 = paper tape punch,
|
||||
'20 = control panel
|
||||
Devices emulated by Primos in ks/ptrap.ftn for I/O instructions in Ring 3:
|
||||
'01 = paper tape reader
|
||||
'02 = paper tape punch
|
||||
'04 = console
|
||||
'20 = control panel lights & sense switches
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <time.h>
|
||||
|
||||
/* this macro is used when I/O is successful. In VI modes, it sets
|
||||
the EQ condition code bit. In SR modes, it does a skip */
|
||||
@ -81,15 +97,18 @@
|
||||
|
||||
|
||||
|
||||
/* this is a template for device handlers */
|
||||
/* this is a template for new device handlers */
|
||||
|
||||
void devnull (short class, short func, short device) {
|
||||
int devnew (short class, short func, short device) {
|
||||
|
||||
switch (class) {
|
||||
|
||||
case -1:
|
||||
return 0;
|
||||
|
||||
case 0:
|
||||
if (T_INST) fprintf(stderr," OCP '%02o%02o\n", func, device);
|
||||
if (func == 0) {
|
||||
if (func == 99) {
|
||||
;
|
||||
} else {
|
||||
printf("Unimplemented OCP device '%02o function '%02o\n", device, func);
|
||||
@ -99,7 +118,7 @@ void devnull (short class, short func, short device) {
|
||||
|
||||
case 1:
|
||||
if (T_INST) fprintf(stderr," SKS '%02o%02o\n", func, device);
|
||||
if (func == 0)
|
||||
if (func == 99)
|
||||
IOSKIP; /* assume it's always ready */
|
||||
else {
|
||||
printf("Unimplemented SKS device '%02o function '%02o\n", device, func);
|
||||
@ -109,7 +128,7 @@ void devnull (short class, short func, short device) {
|
||||
|
||||
case 2:
|
||||
if (T_INST) fprintf(stderr," INA '%02o%02o\n", func, device);
|
||||
if (func == 0) {
|
||||
if (func == 99) {
|
||||
;
|
||||
} else {
|
||||
printf("Unimplemented INA device '%02o function '%02o\n", device, func);
|
||||
@ -119,10 +138,10 @@ void devnull (short class, short func, short device) {
|
||||
|
||||
case 3:
|
||||
if (T_INST) fprintf(stderr," OTA '%02o%02o\n", func, device);
|
||||
if (func == 0 | func == 1) {
|
||||
IOSKIP; /* OTA '0004 always works on Unix */
|
||||
if (func == 99) {
|
||||
IOSKIP;
|
||||
} else {
|
||||
printf("Unimplemented OTA device '%02o function '%02o\n", device, func);
|
||||
printf("Unimplemented OTA device '%02o function '%02o, A='%o\n", device, func, crs[A]);
|
||||
fatal(NULL);
|
||||
}
|
||||
break;
|
||||
@ -130,6 +149,38 @@ void devnull (short class, short func, short device) {
|
||||
}
|
||||
|
||||
|
||||
/* this is a template for null (not present) devices */
|
||||
|
||||
int devnone (short class, short func, short device) {
|
||||
|
||||
switch (class) {
|
||||
|
||||
case -1:
|
||||
return 0;
|
||||
|
||||
case 0:
|
||||
if (T_INST) fprintf(stderr," OCP '%02o%02o\n", func, device);
|
||||
fprintf(stderr, " unimplemented device '%o\n", device);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (T_INST) fprintf(stderr," SKS '%02o%02o\n", func, device);
|
||||
fprintf(stderr, " unimplemented device '%o\n", device);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (T_INST) fprintf(stderr," INA '%02o%02o\n", func, device);
|
||||
fprintf(stderr, " unimplemented device '%o\n", device);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (T_INST) fprintf(stderr," OTA '%02o%02o\n", func, device);
|
||||
fprintf(stderr, " unimplemented device '%o\n", device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Device '4: system console
|
||||
|
||||
NOTES:
|
||||
@ -193,7 +244,7 @@ void devnull (short class, short func, short device) {
|
||||
*/
|
||||
|
||||
|
||||
void devasr (short class, short func, short device) {
|
||||
int devasr (short class, short func, short device) {
|
||||
|
||||
static int ttydev;
|
||||
static int ttyflags;
|
||||
@ -211,6 +262,7 @@ void devasr (short class, short func, short device) {
|
||||
switch (class) {
|
||||
|
||||
case -1:
|
||||
setsid();
|
||||
ttydev = open("/dev/tty", O_RDWR, 0);
|
||||
if (ttydev < 0) {
|
||||
perror(" error opening /dev/tty");
|
||||
@ -233,7 +285,7 @@ void devasr (short class, short func, short device) {
|
||||
perror(" unable to set tty attributes");
|
||||
fatal(NULL);
|
||||
}
|
||||
break;
|
||||
return 0;
|
||||
|
||||
case 0:
|
||||
if (T_INST) fprintf(stderr," OCP '%02o%02o\n", func, device);
|
||||
@ -390,7 +442,7 @@ readasr:
|
||||
/* NOTE: 9950 does this in rev 20, others don't */
|
||||
IOSKIP;
|
||||
} else {
|
||||
printf("Unimplemented OTA '04 function '%02o\n", func);
|
||||
printf("Unimplemented OTA device '%02o function '%02o, A='%o\n", device, func, crs[A]);
|
||||
fatal(NULL);
|
||||
}
|
||||
break;
|
||||
@ -413,10 +465,13 @@ readasr:
|
||||
/* Device '14 - magtape controller #1
|
||||
*/
|
||||
|
||||
void devmt (short class, short func, short device) {
|
||||
int devmt (short class, short func, short device) {
|
||||
|
||||
switch (class) {
|
||||
|
||||
case -1:
|
||||
return 0;
|
||||
|
||||
case 0:
|
||||
if (T_INST) fprintf(stderr," OCP '%02o%02o\n", func, device);
|
||||
break;
|
||||
@ -479,29 +534,51 @@ void devmt (short class, short func, short device) {
|
||||
IMPORTANT NOTE: this device ('20) never skips!
|
||||
*/
|
||||
|
||||
void devcp (short class, short func, short device) {
|
||||
int devcp (short class, short func, short device) {
|
||||
static short enabled = 0;
|
||||
static unsigned short clkvec;
|
||||
static short clkpic;
|
||||
|
||||
int datnow, i;
|
||||
time_t unixtime;
|
||||
ea_t datnowea;
|
||||
struct tm *tms;
|
||||
|
||||
#define SETCLKPOLL devpoll[device] = instpermsec*(-clkpic*3.2)/1000;
|
||||
|
||||
switch (class) {
|
||||
|
||||
case -1:
|
||||
return 0;
|
||||
|
||||
case 0:
|
||||
if (T_INST) fprintf(stderr," OCP '%02o%02o\n", func, device);
|
||||
printf("OCP '%02o%02o\n", func, device);
|
||||
|
||||
if (func == 0 || func == 015) {
|
||||
fprintf(stderr,"Clock process initialized!\n");
|
||||
if (func == 01) { /* ack PIC interrupt */
|
||||
;
|
||||
|
||||
} else if (func == 015) { /* set interrupt mask */
|
||||
fprintf(stderr,"Clock interrupt enabled!\n");
|
||||
/* this enables tracing when the clock process initializes */
|
||||
//traceflags = ~TB_MAP;
|
||||
enabled = 1;
|
||||
#if 0
|
||||
#if 1
|
||||
SETCLKPOLL;
|
||||
#else
|
||||
devpoll[device] = 600000;
|
||||
#endif
|
||||
datnowea = 0;
|
||||
for (i=0; i<numsyms; i++) {
|
||||
if (strcmp(mapsym[i].symname, "DATNOW") == 0)
|
||||
datnowea = mapsym[i].address;
|
||||
}
|
||||
if (datnowea != 0) {
|
||||
unixtime = time(NULL);
|
||||
tms = localtime(&unixtime);
|
||||
datnow = tms->tm_year<<25 | (tms->tm_mon+1)<<21 | tms->tm_mday<<16 | ((tms->tm_hour*3600 + tms->tm_min*60 + tms->tm_sec)/4);
|
||||
put32(datnow, datnowea);
|
||||
}
|
||||
|
||||
} else if (func == 016 || func == 017) {
|
||||
enabled = 0;
|
||||
devpoll[device] = 0;
|
||||
@ -521,7 +598,7 @@ void devcp (short class, short func, short device) {
|
||||
case 2:
|
||||
if (T_INST) fprintf(stderr," INA '%02o%02o\n", func, device);
|
||||
if (func == 011) { /* input ID */
|
||||
crs[A] != 0120; /* this is the SOC board */
|
||||
crs[A] = 0120; /* this is the SOC board */
|
||||
} else if (func == 016) {
|
||||
crs[A] = sswitch;
|
||||
} else if (func == 017) { /* read switches in momentary down position */
|
||||
@ -537,15 +614,15 @@ void devcp (short class, short func, short device) {
|
||||
if (func == 02) { /* set PIC interval */
|
||||
clkpic = *(short *)(crs+A);
|
||||
SETCLKPOLL;
|
||||
printf("Clock PIC interval set to %d\n", clkpic);
|
||||
//printf("Clock PIC interval set to %d\n", clkpic);
|
||||
} else if (func == 07) {
|
||||
printf("Clock control register set to '%o\n", crs[A]);
|
||||
//printf("Clock control register set to '%o\n", crs[A]);
|
||||
} else if (func == 013) {
|
||||
clkvec = crs[A];
|
||||
printf("Clock interrupt vector address = '%o\n", clkvec);
|
||||
//printf("Clock interrupt vector address = '%o\n", clkvec);
|
||||
} else if (func == 017) { /* write lights */
|
||||
} else {
|
||||
printf("Unimplemented OTA device '%02o function '%02o\n", device, func);
|
||||
printf("Unimplemented OTA device '%02o function '%02o, A='%o\n", device, func, crs[A]);
|
||||
fatal(NULL);
|
||||
}
|
||||
break;
|
||||
@ -594,12 +671,14 @@ void devcp (short class, short func, short device) {
|
||||
|
||||
*/
|
||||
|
||||
void devdisk (short class, short func, short device) {
|
||||
int devdisk (short class, short func, short device) {
|
||||
|
||||
#define S_HALT 0
|
||||
#define S_RUN 1
|
||||
#define S_INT 2
|
||||
|
||||
#define MAXDRIVES 8
|
||||
|
||||
#if 0
|
||||
#define CID4005 0100
|
||||
#else
|
||||
@ -620,7 +699,7 @@ void devdisk (short class, short func, short device) {
|
||||
unsigned short spt; /* sectors per track */
|
||||
int devfd; /* Unix device file descriptor */
|
||||
int readnum; /* increments on each read */
|
||||
} unit[4];
|
||||
} unit[MAXDRIVES];
|
||||
} dc[64];
|
||||
|
||||
short i,u;
|
||||
@ -638,6 +717,7 @@ void devdisk (short class, short func, short device) {
|
||||
unsigned int utempl;
|
||||
char ordertext[8];
|
||||
int theads, spt, phyra;
|
||||
int nb; /* number of bytes returned from read/write */
|
||||
char devfile[8];
|
||||
char rtfile[16]; /* read trace file name */
|
||||
int rtnw; /* total number of words read (all channels) */
|
||||
@ -649,7 +729,7 @@ void devdisk (short class, short func, short device) {
|
||||
dc[i].state = S_HALT;
|
||||
dc[i].status = 0100000;
|
||||
dc[i].usel = -1;
|
||||
for (u=0; u<4; u++) {
|
||||
for (u=0; u<MAXDRIVES; u++) {
|
||||
dc[i].unit[u].rtfd = -1;
|
||||
dc[i].unit[u].theads = 40;
|
||||
dc[i].unit[u].spt = 9;
|
||||
@ -657,7 +737,7 @@ void devdisk (short class, short func, short device) {
|
||||
dc[i].unit[u].readnum = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
return 0;
|
||||
|
||||
case 0:
|
||||
if (T_INST || T_DIO) fprintf(stderr," OCP '%2o%2o\n", func, device);
|
||||
@ -718,7 +798,7 @@ void devdisk (short class, short func, short device) {
|
||||
dc[device].oar = crs[A];
|
||||
devpoll[device] = 1;
|
||||
} else {
|
||||
printf("Unimplemented OTA device '%02o function '%02o\n", device, func);
|
||||
printf("Unimplemented OTA device '%02o function '%02o, A='%o\n", device, func, crs[A]);
|
||||
fatal(NULL);
|
||||
}
|
||||
IOSKIP;
|
||||
@ -793,9 +873,10 @@ void devdisk (short class, short func, short device) {
|
||||
iobufp = mem+mapva(dmaaddr, WACC, &access, 0);
|
||||
else
|
||||
iobufp = mem+dmaaddr;
|
||||
if (read(dc[device].unit[u].devfd, (char *)iobufp, dmanw*2) != dmanw*2) {
|
||||
perror("Unable to read drive file");
|
||||
fatal(NULL);
|
||||
if ((nb=read(dc[device].unit[u].devfd, (char *)iobufp, dmanw*2)) != dmanw*2) {
|
||||
fprintf(stderr, "Disk read error: device='%o, u=%d, fd=%d, nb=%d\n", device, u, dc[device].unit[u].devfd, nb);
|
||||
if (nb == -1) perror("Unable to read drive file");
|
||||
memset((char *)iobufp, 0, dmanw*2);
|
||||
}
|
||||
if (iobufp == iobuf)
|
||||
for (i=0; i<dmanw; i++)
|
||||
@ -899,3 +980,479 @@ void devdisk (short class, short func, short device) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
AMLC I/O operations:
|
||||
|
||||
OCP '0054 - stop clock
|
||||
OCP '0154 - single step clock
|
||||
|
||||
OCP '1234 - set normal/DMT mode
|
||||
OCP '1354 - set diagnostic/DMQ mode
|
||||
OCP '1554 - enable interrupts
|
||||
OCP '1654 - disable interrupts
|
||||
OCP '1754 - initialize AMLC
|
||||
|
||||
SKS '0454 - skip if NOT interrupting
|
||||
|
||||
INA '0054 - input data set sense bit for all lines (read clear to send)
|
||||
INA '0754 - input AMLC status and clear (always skips)
|
||||
INA '1154 - input AMLC controller ID
|
||||
INA '1454 - input DMA/C channel number
|
||||
INA '1554 - input DMT/DMQ base address
|
||||
INA '1654 - input interrupt vector address
|
||||
|
||||
OTA '0054 - output line number for INA '0054 (older models only)
|
||||
OTA '0154 - output line configuration for 1 line
|
||||
OTA '0254 - output line control for 1 line
|
||||
OTA '1454 - output DMA/C channel number
|
||||
OTA '1554 - output DMT/DMQ base address
|
||||
OTA '1654 - output interrupt vector address
|
||||
OTA '1754 - output programmable clock constant
|
||||
|
||||
Primos AMLC usage:
|
||||
|
||||
OCP '17xx
|
||||
- initialize controller
|
||||
- clear all registers and flip-flops
|
||||
- start line clock
|
||||
- clear all line control bits during the 1st line scan
|
||||
- responds not ready until 1 line scan is complete
|
||||
|
||||
INA '11xx
|
||||
- read AMLC ID
|
||||
- emulator always returns '20054 (DMQ, 16 lines)
|
||||
|
||||
OTA '17xx
|
||||
- set AMLC programmable clock constant
|
||||
- ignored by the emulator
|
||||
|
||||
OTA '14xx
|
||||
- set DMC channel address for double input buffers
|
||||
- emulator stores in a structure
|
||||
|
||||
OCP '13xx
|
||||
- set dmq mode (used to be "set diagnostic mode")
|
||||
- ignored by the emulator
|
||||
|
||||
OTA '15xx
|
||||
- set DMT Base Address
|
||||
- also used for DMQ address?
|
||||
- emulator stores in a structure
|
||||
|
||||
OTA '16xx
|
||||
- set interrupt vector address
|
||||
- emulator stores in a structure
|
||||
|
||||
OTA '01xx
|
||||
- set line configuration
|
||||
- emulator ignores: all lines are 8-bit raw
|
||||
|
||||
OTA '02xx
|
||||
- set line control
|
||||
- emulator ignores: all lines are enabled
|
||||
|
||||
OCP '15xx/'16xx
|
||||
- enable/disable interrupts
|
||||
- emulator stores in a structure
|
||||
*/
|
||||
|
||||
int devamlc (short class, short func, short device) {
|
||||
|
||||
#define MAXLINES 128
|
||||
#define MAXFD MAXLINES+20
|
||||
#define MAXBOARDS 8
|
||||
/* AMLC poll rate in milliseconds */
|
||||
#define AMLCPOLL 50
|
||||
|
||||
#if 1
|
||||
#define QAMLC 020000 /* this is to enable QAMLC/DMQ functionality */
|
||||
#else
|
||||
#define QAMLC 0
|
||||
#endif
|
||||
|
||||
static short inited = 0;
|
||||
static short devices[MAXBOARDS]; /* list of AMLC devices initialized */
|
||||
static int tsfd; /* socket fd for terminal server */
|
||||
static struct { /* maps socket fd to device & line */
|
||||
int device;
|
||||
int line;
|
||||
} socktoline[MAXLINES];
|
||||
static struct {
|
||||
char dmqmode; /* 0=DMT, 1=DMQ */
|
||||
char bufnum; /* 0=1st input buffer, 1=2nd */
|
||||
char eor; /* 1=End of Range on input */
|
||||
unsigned short dmcchan; /* DMC channel (for input) */
|
||||
unsigned short baseaddr; /* DMT/Q base address (for output) */
|
||||
unsigned short intvector; /* interrupt vector */
|
||||
char intenable; /* interrupts enabled? */
|
||||
char interrupting; /* am I interrupting? */
|
||||
unsigned short xmitenabled; /* 1 bit per line */
|
||||
unsigned short recvenabled; /* 1 bit per line */
|
||||
unsigned short ctinterrupt; /* 1 bit per line */
|
||||
unsigned short dss; /* 1 bit per line */
|
||||
unsigned short sockfd[16]; /* Unix socket fd, 1 per line */
|
||||
} dc[64];
|
||||
|
||||
int lx;
|
||||
unsigned short utempa;
|
||||
unsigned int utempl;
|
||||
ea_t qcbea, dmcea, dmcbufbegea, dmcbufendea;
|
||||
unsigned short dmcnw;
|
||||
int dmcpair;
|
||||
int optval;
|
||||
int tsflags;
|
||||
struct sockaddr_in addr;
|
||||
int fd;
|
||||
unsigned int addrlen;
|
||||
unsigned char buf[1024];
|
||||
int i, n, nw, newdevice;
|
||||
|
||||
switch (class) {
|
||||
|
||||
case -1:
|
||||
|
||||
/* this part of initialization only occurs once, no matter how many
|
||||
AMLC boards are configured */
|
||||
|
||||
if (!inited) {
|
||||
for (i=0; i<MAXBOARDS; i++)
|
||||
devices[i] = 0;
|
||||
if (tport != 0) {
|
||||
tsfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (tsfd == -1) {
|
||||
perror("socket failed for AMLC");
|
||||
fatal(NULL);
|
||||
}
|
||||
optval = 1;
|
||||
if (setsockopt(tsfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))) {
|
||||
perror("setsockopt failed for AMLC");
|
||||
fatal(NULL);
|
||||
}
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(tport);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
if(bind(tsfd, (struct sockaddr *)&addr, sizeof(addr))) {
|
||||
perror("bind: unable to bind for AMLC");
|
||||
fatal(NULL);
|
||||
}
|
||||
if(listen(tsfd, 10)) {
|
||||
perror("listen failed for AMLC");
|
||||
fatal(NULL);
|
||||
}
|
||||
if (fcntl(tsfd, F_GETFL, tsflags) == -1) {
|
||||
perror("unable to get ts flags for AMLC");
|
||||
fatal(NULL);
|
||||
}
|
||||
tsflags |= O_NONBLOCK;
|
||||
if (fcntl(tsfd, F_SETFL, tsflags) == -1) {
|
||||
perror("unable to set ts flags for AMLC");
|
||||
fatal(NULL);
|
||||
}
|
||||
} else
|
||||
printf("--tport is zero, can't start AMLC devices");
|
||||
inited = 1;
|
||||
}
|
||||
|
||||
/* this part of initialization occurs for every AMLC board */
|
||||
|
||||
if (!inited)
|
||||
return -1;
|
||||
|
||||
/* add this device to the devices array, in the proper slot
|
||||
so we can tell what order the boards should be in */
|
||||
|
||||
switch (device) {
|
||||
case 054: devices[0] = device; break;
|
||||
case 053: devices[1] = device; break;
|
||||
case 052: devices[2] = device; break;
|
||||
case 035: devices[3] = device; break;
|
||||
case 015: devices[4] = device; break;
|
||||
case 016: devices[5] = device; break;
|
||||
case 017: devices[6] = device; break;
|
||||
case 032: devices[7] = device; break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 0:
|
||||
if (T_INST) fprintf(stderr," OCP '%02o%02o\n", func, device);
|
||||
//printf(" OCP '%02o%02o\n", func, device);
|
||||
|
||||
if (func == 012) { /* set normal (DMT) mode */
|
||||
dc[device].dmqmode = 0;
|
||||
|
||||
} else if (func == 013 && QAMLC) { /* set diagnostic (DMQ) mode */
|
||||
dc[device].dmqmode = 1;
|
||||
|
||||
} else if (func == 015) { /* enable interrupts */
|
||||
dc[device].intenable = 1;
|
||||
|
||||
} else if (func == 016) { /* disable interrupts */
|
||||
dc[device].intenable = 0;
|
||||
|
||||
} else if (func == 017) { /* initialize AMLC */
|
||||
dc[device].dmqmode = 0;
|
||||
dc[device].bufnum = 0;
|
||||
dc[device].dmcchan = 0;
|
||||
dc[device].baseaddr = 0;
|
||||
dc[device].intvector = 0;
|
||||
dc[device].intenable = 0;
|
||||
dc[device].interrupting = 0;
|
||||
dc[device].xmitenabled = 0;
|
||||
dc[device].recvenabled = 0;
|
||||
dc[device].ctinterrupt = 0;
|
||||
dc[device].dss = 0; /* NOTE: this is stored inverted: 1=connected */
|
||||
dc[device].eor = 0;
|
||||
|
||||
} else {
|
||||
printf("Unimplemented OCP device '%02o function '%02o\n", device, func);
|
||||
fatal(NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (T_INST) fprintf(stderr," SKS '%02o%02o\n", func, device);
|
||||
|
||||
if (func == 04) { /* skip if not interrupting */
|
||||
if (!dc[device].interrupting)
|
||||
IOSKIP;
|
||||
|
||||
} else {
|
||||
printf("Unimplemented SKS device '%02o function '%02o\n", device, func);
|
||||
fatal(NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (T_INST) fprintf(stderr," INA '%02o%02o\n", func, device);
|
||||
|
||||
if (func == 00) { /* input Data Set Sense (carrier) */
|
||||
crs[A] = ~dc[device].dss; /* to the outside world, 1 = no carrier*/
|
||||
IOSKIP;
|
||||
|
||||
} else if (func == 07) { /* input AMLC status */
|
||||
crs[A] = 040000 | (dc[device].bufnum<<8) | (dc[device].intenable<<5) || (dc[device].dmqmode<<4);
|
||||
if (dc[device].eor) {
|
||||
crs[A] |= 0100000;
|
||||
dc[device].eor = 0;
|
||||
}
|
||||
if (dc[device].ctinterrupt)
|
||||
if (dc[device].ctinterrupt & 0xfffe)
|
||||
crs[A] |= 0xcf; /* multiple char time interrupt */
|
||||
else
|
||||
crs[A] |= 0x8f; /* last line cti */
|
||||
dc[device].interrupting = 0;
|
||||
//printf("INA '07%02o returns 0x%x\n", device, crs[A]);
|
||||
IOSKIP;
|
||||
|
||||
} else if (func == 011) { /* input ID */
|
||||
crs[A] = QAMLC | 054;
|
||||
IOSKIP;
|
||||
|
||||
} else {
|
||||
printf("Unimplemented INA device '%02o function '%02o\n", device, func);
|
||||
fatal(NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (T_INST) fprintf(stderr," OTA '%02o%02o\n", func, device);
|
||||
|
||||
if (func == 01) { /* set line configuration */
|
||||
lx = crs[A] >> 12;
|
||||
//printf("OTA '01%02o: AMLC line %d config = %x\n", device, lx, crs[A]);
|
||||
/* if DTR drops on a connected line, disconnect */
|
||||
if (!(crs[A] & 0x400) && (dc[device].dss & bitmask16[lx+1])) {
|
||||
/* see similar code below */
|
||||
write(dc[device].sockfd[lx], "\r\nDisconnecting on logout\r\n", 27);
|
||||
close(dc[device].sockfd[lx]);
|
||||
dc[device].dss &= ~bitmask16[lx+1];
|
||||
printf("Closing AMLC line %d on device '%o\n", lx, device);
|
||||
}
|
||||
IOSKIP;
|
||||
|
||||
} else if (func == 02) { /* set line control */
|
||||
//printf("OTA '02%02o: AMLC line control = %x\n", device, crs[A]);
|
||||
lx = (crs[A]>>12);
|
||||
if (crs[A] & 040) /* character time interrupt enable/disable */
|
||||
dc[device].ctinterrupt |= bitmask16[lx+1];
|
||||
else
|
||||
dc[device].ctinterrupt &= ~bitmask16[lx+1];
|
||||
if (crs[A] & 010) /* transmit enable/disable */
|
||||
dc[device].xmitenabled |= bitmask16[lx+1];
|
||||
else
|
||||
dc[device].xmitenabled &= ~bitmask16[lx+1];
|
||||
if (crs[A] & 01) /* receive enable/disable */
|
||||
dc[device].recvenabled |= bitmask16[lx+1];
|
||||
else
|
||||
dc[device].recvenabled &= ~bitmask16[lx+1];
|
||||
if ((dc[device].ctinterrupt || dc[device].xmitenabled || dc[device].recvenabled) && devpoll[device] == 0)
|
||||
devpoll[device] = AMLCPOLL*instpermsec; /* setup another poll */
|
||||
IOSKIP;
|
||||
|
||||
} else if (func == 014) { /* set DMA/C channel (for input) */
|
||||
dc[device].dmcchan = crs[A] & 0x7ff;
|
||||
//printf("OTA '14%02o: AMLC chan = %o\n", device, dc[device].dmcchan);
|
||||
if (!(crs[A] & 0x800))
|
||||
fatal("Can't run AMLC in DMA mode!");
|
||||
IOSKIP;
|
||||
|
||||
} else if (func == 015) { /* set DMT/DMQ base address (for output) */
|
||||
dc[device].baseaddr = crs[A];
|
||||
IOSKIP;
|
||||
|
||||
} else if (func == 016) { /* set interrupt vector */
|
||||
dc[device].intvector = crs[A];
|
||||
IOSKIP;
|
||||
|
||||
} else if (func == 017) { /* set programmable clock constant */
|
||||
IOSKIP;
|
||||
|
||||
} else {
|
||||
printf("Unimplemented OTA device '%02o function '%02o, A='%o\n", device, func, crs[A]);
|
||||
fatal(NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
//printf("poll device '%o, cti=%x, xmit=%x, recv=%x, dss=%x\n", device, dc[device].ctinterrupt, dc[device].xmitenabled, dc[device].recvenabled, dc[device].dss);
|
||||
|
||||
/* check for new connections */
|
||||
|
||||
conloop:
|
||||
|
||||
while ((fd = accept(tsfd, (struct sockaddr *)&addr, &addrlen)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (fd == -1) {
|
||||
if (errno != EWOULDBLOCK) {
|
||||
perror("accept error for AMLC");
|
||||
fatal("accept error for AMLC");
|
||||
}
|
||||
} else {
|
||||
if (fd >= MAXFD)
|
||||
fatal("New connection fd is too big");
|
||||
newdevice = 0;
|
||||
for (i=0; !newdevice && i<MAXBOARDS; i++)
|
||||
if (devices[i])
|
||||
for (lx=0; lx<16; lx++)
|
||||
if (!(dc[devices[i]].dss & bitmask16[lx+1])) {
|
||||
newdevice = devices[i];
|
||||
socktoline[fd].device = newdevice;
|
||||
socktoline[fd].line = lx;
|
||||
dc[newdevice].dss |= bitmask16[lx+1];
|
||||
dc[newdevice].sockfd[lx] = fd;
|
||||
printf("AMLC connection, fd=%d, device='%o, line=%d\n", fd, newdevice, lx);
|
||||
break;
|
||||
}
|
||||
if (!newdevice) {
|
||||
warn("No free AMLC connection");
|
||||
write(fd, "\rAll AMLC lines are in use!\r\n", 29);
|
||||
close(fd);
|
||||
}
|
||||
goto conloop;
|
||||
}
|
||||
|
||||
/* do a receive/transmit scan loop for every line
|
||||
NOTE: should probably do a read & write select to find lines to process */
|
||||
|
||||
for (lx = 0; lx < 16; lx++) {
|
||||
if (dc[device].xmitenabled & bitmask16[lx+1]) {
|
||||
n = 0;
|
||||
if (dc[device].dmqmode) {
|
||||
qcbea = dc[device].baseaddr + lx*4;
|
||||
if (dc[device].dss & bitmask16[lx+1]) {
|
||||
while (n < sizeof(buf) && rtq(qcbea, &utempa, 0)) {
|
||||
if (utempa & 0x8000) { /* valid character */
|
||||
//printf("Device %o, line %d, entry=%o (%c)\n", device, lx, utempa, utempa & 0x7f);
|
||||
buf[n++] = utempa ^ 0x80;
|
||||
}
|
||||
}
|
||||
} else { /* no line connected, just drain queue */
|
||||
//printf("Draining output queue on line %d\n", lx);
|
||||
put16r(get16r(qcbea, 0), qcbea+1, 0);
|
||||
}
|
||||
} else { /* DMT */
|
||||
utempa = get16r(dc[device].baseaddr + lx, 0);
|
||||
if (utempa != 0) {
|
||||
if ((utempa & 0x8000) && (dc[device].dss & bitmask16[lx+1])) {
|
||||
//printf("Device %o, line %d, entry=%o (%c)\n", device, lx, utempa, utempa & 0x7f);
|
||||
buf[n++] = utempa ^ 0x80;
|
||||
}
|
||||
put16r(0, dc[device].baseaddr + lx, 0);
|
||||
}
|
||||
/* need to setup DMT xmit poll here, and/or look for char time interrupt */
|
||||
}
|
||||
|
||||
/* NOTE: probably need to check for partial writes here, or put the
|
||||
socket in blocking mode. Would be best to know how many characters
|
||||
to remove from the queue in the loop above. */
|
||||
|
||||
if (n > 0)
|
||||
if ((nw = write(dc[device].sockfd[lx], buf, n)) != n) {
|
||||
perror("Writing to AMLC");
|
||||
fatal("Writing to AMLC");
|
||||
}
|
||||
}
|
||||
|
||||
/* process input, but only as much as will fit into the DMC buffer */
|
||||
|
||||
if ((dc[device].dss & dc[device].recvenabled & bitmask16[lx+1]) && !dc[device].eor) {
|
||||
if (dc[device].bufnum)
|
||||
dmcea = dc[device].dmcchan ^ 2;
|
||||
else
|
||||
dmcea = dc[device].dmcchan;
|
||||
dmcpair = get32r(dmcea, 0);
|
||||
dmcbufbegea = dmcpair>>16;
|
||||
dmcbufendea = dmcpair & 0xffff;
|
||||
dmcnw = dmcbufendea - dmcbufbegea + 1;
|
||||
if (dmcnw <= 0)
|
||||
continue;
|
||||
if (dmcnw > sizeof(buf))
|
||||
dmcnw = sizeof(buf);
|
||||
while ((n = read(dc[device].sockfd[lx], buf, dmcnw)) == -1 && errno == EINTR)
|
||||
;
|
||||
//printf("processing recv on device %o, line %d, b#=%d, dmcnw=%d, n=%d\n", device, lx, dc[device].bufnum, dmcnw, n);
|
||||
if (n == 0) {
|
||||
n = -1;
|
||||
errno = EPIPE;
|
||||
}
|
||||
if (n == -1) {
|
||||
n = 0;
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
;
|
||||
else if (errno == EPIPE) {
|
||||
/* see similar code above */
|
||||
close(dc[device].sockfd[lx]);
|
||||
dc[device].dss &= ~bitmask16[lx+1];
|
||||
printf("Closing AMLC line %d on device '%o\n", lx, device);
|
||||
} else {
|
||||
perror("Reading AMLC");
|
||||
fatal("Reading AMLC");
|
||||
}
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
for (i=0; i<n; i++) {
|
||||
utempa = lx<<12 | 0x0200 | buf[i];
|
||||
put16r(utempa, dmcbufbegea, 0);
|
||||
//printf("******* stored character %o (%c) at %o\n", utempa, utempa&0x7f, dmcbufbegea);
|
||||
dmcbufbegea = INCVA(dmcbufbegea, 1);
|
||||
}
|
||||
put16r(dmcbufbegea, dmcea, 0);
|
||||
if (dmcbufbegea > dmcbufendea) { /* end of range has occurred */
|
||||
dc[device].bufnum = 1-dc[device].bufnum;
|
||||
dc[device].eor = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (intvec == -1 && dc[device].intenable && (dc[device].ctinterrupt || dc[device].eor)) {
|
||||
intvec = dc[device].intvector;
|
||||
dc[device].interrupting = 1;
|
||||
}
|
||||
|
||||
if ((dc[device].ctinterrupt || dc[device].xmitenabled || dc[device].recvenabled) && devpoll[device] == 0)
|
||||
devpoll[device] = AMLCPOLL*instpermsec; /* setup another poll */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user