From 292af061fc368a6c3d567db4a714f29caff2245f Mon Sep 17 00:00:00 2001 From: Jim Date: Thu, 30 Mar 2006 00:00:00 -0500 Subject: [PATCH] correct SSSN: actually an illegal shift opcode, add --nport option for PNC --- em.c | 55 ++++-- emdev.h | 510 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 504 insertions(+), 61 deletions(-) diff --git a/em.c b/em.c index 94637c5..d909359 100644 --- a/em.c +++ b/em.c @@ -311,7 +311,8 @@ 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) */ +int tport; /* --tport option (incoming terminals) */ +int nport; /* --nport option (PNC/Ringnet) */ /* load map related data, specified with --map */ @@ -894,7 +895,12 @@ void fault(unsigned short fvec, unsigned short fcode, ea_t faddr) { if (m != 0) { if (1 || T_FLOW) fprintf(stderr," fault JST* '%o [%o]\n", fvec, m); put16(faultrp & 0xFFFF, m); + /* NOTE: should this set RP to m (segment 0), or just set RPL? */ +#if 0 + RPL = m; +#else RP = m; +#endif RPL++; } else { printf("#%d: fault '%o, fcode=%o, faddr=%o/%o, faultrp=%o/%o\n", instcount, fvec, fcode, faddr>>16, faddr&0xFFFF, faultrp>>16, faultrp&0xFFFF); @@ -928,7 +934,7 @@ long devpoll[64] = {0}; #if 0 int (*devmap[64])(short, short, short) = { - /* '0x */ 0,0,0,0,devasr,0,0,0, + /* '0x */ 0,0,0,0,devasr,0,0,devpnc, /* '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, @@ -938,11 +944,11 @@ int (*devmap[64])(short, short, short) = { /* '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, + /* '0x */ 0,0,0,0,devasr,0,0,devpnc, /* '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, + /* '4x */ 0,0,0,0,0,0,0,devnone, /* '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}; @@ -2688,7 +2694,8 @@ main (int argc, char **argv) { boot = 0; pmap32bits = 0; csoffset = 0; - tport = 0; + tport = -1; + nport = -1; /* check args */ @@ -2714,12 +2721,18 @@ main (int argc, char **argv) { cpuid = templ; } else fprintf(stderr,"--cpuid needs an argument\n"); - } else if (strcmp(argv[i],"--port") == 0) { + } else if (strcmp(argv[i],"--tport") == 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"); + fprintf(stderr,"--tport needs an argument\n"); + } else if (strcmp(argv[i],"--nport") == 0) { + if (i+1 < argc && argv[i+1][0] != '-') { + sscanf(argv[i+1],"%d", &templ); + nport = templ; + } else + fprintf(stderr,"--nport 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) @@ -2763,8 +2776,10 @@ 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) + if (tport == -1) tport = 8000; + if (nport == -1) + nport = 8001; fprintf(stderr,"Sense switches set to %o\n", sswitch); @@ -2786,7 +2801,7 @@ main (int argc, char **argv) { rvec[2] = 01000; rvec[3] = rvec[4] = rvec[5] = 0; rvec[6] = 0; - /* setup DMA register '21 for the next boot record */ + /* setup DMA register '20 (address only) for the next boot record */ regs.sym.regdmx[041] = 03000; } else { @@ -2849,7 +2864,7 @@ main (int argc, char **argv) { savetraceflags = traceflags; #endif -#if 1 +#if 0 if (traceflags != 0) savetraceflags = traceflags; if (crs[OWNERL] == 0100200 && savetraceflags) @@ -2954,8 +2969,7 @@ main (int argc, char **argv) { /* while a process is running, RP is the real program counter, PBH is the active procedure segment, and PBL is zero. When a process stops running, RP is copied to PB. When a process - starts running again, PB is copied to RP. See seg14.pma, - WRMSAV. */ + starts running again, PB is copied to RP. */ crs[PBH] = RPH; crs[PBL] = 0; @@ -3606,11 +3620,6 @@ stfa: put64(*(double *)(stpm+4), INCVA(ea,4)); continue; - case 040310: - if (T_FLOW) fprintf(stderr," SSSN\n", inst); - fault(UIIFAULT, RPL, RP); - continue; - /* JW: I think this is an invalid opcode that Prime uses when unexpected things happen, for example: @@ -4887,6 +4896,15 @@ lcgt: *(unsigned int *)(crs+L) = utempl; break; + case 00300: + if (inst == 040310) { + printf("SSSN @ %o/%o\n", RPH, RPL); + if (T_FLOW) fprintf(stderr," SSSN\n", inst); + fault(UIIFAULT, RPL, RP); + break; + } + goto badshift; + case 00400: /* ARL */ if (T_FLOW) fprintf(stderr," ARL %d\n", scount); crs[KEYS] &= ~0120000; /* clear C,L */ @@ -5022,6 +5040,7 @@ lcgt: break; default: +badshift: printf("emulator warning: unrecognized shift instruction %o at %o/%o\n", inst, RPH, RPL); if (T_INST) fprintf(stderr," unrecognized shift instruction!: %o\n", inst); } @@ -6002,6 +6021,8 @@ keys = 14200, modals=100177 case 0301: if (T_FLOW) fprintf(stderr," STLR\n"); + if (MAKEVA(012,037122) <= ea && ea <= MAKEVA(012,042664)) + printf("STLR in PNCDIM at %o/%o, ea=%o/%o, L=%o/%o\n", RPH, RPL-2, ea>>16, ea&0xffff, crs[A], crs[B]); utempa = ea; /* word number portion only */ if (utempa & 040000) { /* absolute RF addressing */ RESTRICT(); diff --git a/emdev.h b/emdev.h index b4c2caa..aef13f5 100644 --- a/emdev.h +++ b/emdev.h @@ -19,7 +19,7 @@ '07 = #1 PNC '10 = ICS2 #1 or ICS1 '11 = ICS2 #2 or ICS1 - '12 = floppy disk/diskette + '12 = floppy disk/diskette (magtape controller #3 at rev 22.1?) '13 = #2 magtape controller '14 = #1 magtape controller '15 = #5 AMLC or ICS1 @@ -153,6 +153,8 @@ int devnew (short class, short func, short device) { int devnone (short class, short func, short device) { + static short lastdev=-1; + switch (class) { case -1: @@ -160,24 +162,23 @@ int devnone (short class, short func, short device) { 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; } + if (device != lastdev) + fprintf(stderr, " unimplemented device '%o\n", device); + lastdev = device; } @@ -501,10 +502,10 @@ int devmt (short class, short func, short device) { /* Device '20: control panel switches and lights, and realtime clock - OCP '0020 = start Line Frequency Clock, enable mem increment, ack previous overflow + OCP '0020 = start Line Frequency Clock, enable mem increment, ack previous overflow (something else on VCP?) OCP '0120 = ack PIC interrupt OCP '0220 = stop LFC, disable mem increment, ack previous overflow - OCP '0420 = select LFC for memory increment + OCP '0420 = select LFC for memory increment (something else on VCP?) OCP '0520 = select external clock for memory increment OCP '0620 = starts a new 50-ms watchdog timeout interval OCP '0720 = stops the watchdog timer @@ -554,19 +555,28 @@ int devcp (short class, short func, short device) { case 0: if (T_INST) fprintf(stderr," OCP '%02o%02o\n", func, device); - if (func == 01) { /* ack PIC interrupt */ + if (func == 00) { /* does something on VCP after OCP '0420 */ + ; + + } else if (func == 01) { /* ack PIC interrupt */ + ; + + } else if (func == 02) { /* stop LFC (IO.PNC DIAG) */ + ; + + } else if (func == 04) { /* does something on VCP during boot */ ; } else if (func == 015) { /* set interrupt mask */ - fprintf(stderr,"Clock interrupt enabled!\n"); /* this enables tracing when the clock process initializes */ //traceflags = ~TB_MAP; + //fprintf(stderr,"Clock interrupt enabled!\n"); enabled = 1; -#if 1 SETCLKPOLL; -#else - devpoll[device] = 600000; -#endif + + /* if --map is used, lookup DATNOW symbol and set the 32-bit + Primos time value (DATNOW+TIMNOW) */ + datnowea = 0; for (i=0; i>12; + + /* this is for conditional execution, and needs some work... */ + if (m & 04000) { /* "execute if ..." */ if (order == 2 || order == 5 || order == 6) dc[device].oar++; @@ -841,9 +873,24 @@ int devdisk (short class, short func, short device) { strcpy(ordertext,"Read"); else if (order == 6) strcpy(ordertext,"Write"); - if (T_INST || T_DIO) fprintf(stderr," %s, head=%d, track=%d, rec=%d, recsize=%d\n", ordertext, head, track, rec, recsize); + if (T_INST || T_DIO) fprintf(stderr,"%s, head=%d, track=%d, rec=%d, recsize=%d\n", ordertext, head, track, rec, recsize); + if (u == -1) { + fprintf(stderr," Device '%o, order %d with no unit selected\n", device, order); + dc[device].status |= 2; /* select error (right?)... */ + break; + } + if (recsize != 0) { + fprintf(stderr," Device '%o, order %d, recsize=%d\n", device, order, recsize); + dc[device].status |= 02000; /* header check (right error?) */ + break; + } + if (track != dc[device].unit[u].curtrack) { + fprintf(stderr," Device '%o, order %d at track %d, but already positioned to track %d\n", device, order, track, dc[device].unit[u].curtrack); + dc[device].status |= 4; /* illegal seek */ + break; + } if (dc[device].unit[u].devfd == -1) { - if (T_INST || T_DIO) fprintf(stderr," Unit not selected or not ready\n"); + if (T_INST || T_DIO) fprintf(stderr," Device '%o unit %d not ready\n", device, u); dc[device].status = 0100001; } else if (order == 2) { if (T_INST || T_DIO) fprintf(stderr," Format order\n"); @@ -854,12 +901,58 @@ int devdisk (short class, short func, short device) { phyra = (track*dc[device].unit[u].theads*dc[device].unit[u].spt) + head*9 + rec; if (T_INST || T_DIO) fprintf(stderr, " Unix ra=%d, byte offset=%d\n", phyra, phyra*2080); - if (lseek(dc[device].unit[u].devfd, phyra*2080, SEEK_SET) == -1) { - perror("Unable to seek drive file"); - fatal(NULL); + + /* does this record exist in the disk unit hash table? If it does, + we'll do I/O to the hash entry. If it doesn't, then for read, + go to the disk file; for write, make a new hash entry */ + + hashp = NULL; + +#ifndef DISKMOD + //fprintf(stderr," R/W, modrecs=%p\n", dc[device].unit[u].modrecs); + for (hashp = dc[device].unit[u].modrecs[phyra%HASHMAX]; hashp != NULL; hashp = *((unsigned char **)hashp)) { + //fprintf(stderr," lookup, hashp=%p\n", hashp); + if (phyra == *((int *)(hashp+sizeof(void *)))) + break; } + //fprintf(stderr,"After search, hashp=%p\n", hashp); + + if (hashp == NULL) + if (order == 5) { /* read */ +#endif + if (lseek(dc[device].unit[u].devfd, phyra*2080, SEEK_SET) == -1) { + perror("Unable to seek drive file"); + fatal(NULL); + } +#ifndef DISKMOD + } else { /* write */ + hashp = malloc(1040*2 + sizeof(void*) + sizeof(int)); + *(unsigned char **)hashp = dc[device].unit[u].modrecs[phyra%HASHMAX]; + *((int *)(hashp+sizeof(void *))) = phyra; + //fprintf(stderr," Write, new hashp = %p, old bucket head = %p\n", hashp, *(unsigned char **)hashp); + dc[device].unit[u].modrecs[phyra%HASHMAX] = hashp; + hashp = hashp + sizeof(void*) + sizeof(int); + } + else + hashp = hashp + sizeof(void*) + sizeof(int); + //fprintf(stderr," Before disk op %d, hashp=%p\n", order, hashp); +#endif + +#if 0 + if (order == 6) { + dmareg = dc[device].dmachan << 1; + dmanw = regs.sym.regdmx[dmareg]; + dmanw = -(dmanw>>4); + dmaaddr = regs.sym.regdmx[dmareg+1]; + phyra2 = get16r(dmaaddr+0, 0); + phyra2 = phyra2<<16 | get16r(dmaaddr+1, 0); + if (phyra2 != phyra) + fprintf(stderr,"devdisk: phyra=%d, phyra2=%d; CRA mismatch (dmanw = %d)!\n", phyra, phyra2, dmanw); + } +#endif + while (dc[device].dmanch >= 0) { - dmareg = ((dc[device].dmachan & 036) << 1) | (dc[device].dmachan & 1); + dmareg = dc[device].dmachan << 1; dmanw = regs.sym.regdmx[dmareg]; dmanw = -(dmanw>>4); dmaaddr = regs.sym.regdmx[dmareg+1]; @@ -873,7 +966,10 @@ int devdisk (short class, short func, short device) { iobufp = mem+mapva(dmaaddr, WACC, &access, 0); else iobufp = mem+dmaaddr; - if ((nb=read(dc[device].unit[u].devfd, (char *)iobufp, dmanw*2)) != dmanw*2) { + if (hashp != NULL) { + memcpy((char *)iobufp, hashp, dmanw*2); + hashp += dmanw*2; + } else 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); @@ -888,7 +984,10 @@ int devdisk (short class, short func, short device) { iobuf[i] = get16r(dmaaddr+i, 0); } else iobufp = mem+dmaaddr; - if (write(dc[device].unit[u].devfd, (char *)iobufp, dmanw*2) != dmanw*2) { + if (hashp != NULL) { + memcpy(hashp, (char *)iobufp, dmanw*2); + hashp += dmanw*2; + } else if (write(dc[device].unit[u].devfd, (char *)iobufp, dmanw*2) != dmanw*2) { perror("Unable to write drive file"); fatal(NULL); } @@ -901,27 +1000,56 @@ int devdisk (short class, short func, short device) { } break; - /* NOTE: for seek command, the track should probably be stored - in a state variable, then checked for equality on - read/write. If not equal, a disk fault should occur rather - than reading/writing from the wrong cylinder. */ - case 3: /* SSEEK = Seek */ - track = m1 & 01777; + u = dc[device].usel; + if (u == -1) { + fprintf(stderr," Device '%o, order %d with no unit selected\n", device, order); + dc[device].status |= 2; /* select error (right?)... */ + break; + } + if (m1 & 0100000) + track = 0; + else + track = m1 & 01777; if (T_INST || T_DIO) fprintf(stderr," seek track %d, restore=%d, clear=%d\n", track, (m1 & 0100000) != 0, (m1 & 040000) != 0); + dc[device].unit[u].curtrack = track; break; case 4: /* DSEL = Select unit */ - u = (m1 & 017) >> 1; /* unit = 0/1/2/4 */ - if (u == 4) u = 3; /* unit = 0/1/2/3 */ + u = (m1 & 017); /* get unit bits */ + if (u == 0) { + dc[device].usel = -1; /* de-select */ + if (T_INST || T_DIO) fprintf(stderr," de-select\n"); + break; + } + if (u != 1 && u != 2 && u != 4 && u != 8) { + fprintf(stderr," Device '%o, bad select '%o\n", device, u); + dc[device].usel = -1; /* de-select */ + dc[device].status != 2; /* select error */ + break; + } + u = u >> 1; /* unit => 0/1/2/4 */ + if (u == 4) u = 3; /* unit => 0/1/2/3 */ + if (T_INST || T_DIO) fprintf(stderr," select unit %d\n", u); dc[device].usel = u; if (dc[device].unit[u].devfd == -1) { snprintf(devfile,sizeof(devfile),"dev%ou%d", device, u); - if (T_INST || T_DIO) fprintf(stderr," filename for unit %d is %s\n", u, devfile); - if ((dc[device].unit[u].devfd = open(devfile, O_RDWR, 0)) == -1) + if (T_INST || T_DIO) fprintf(stderr," filename for dev '%o unit %d is %s\n", device, u, devfile); + /* NOTE: add O_CREAT to allow creating new drives on the fly */ + if ((dc[device].unit[u].devfd = open(devfile, O_RDWR, 0770)) == -1) { + perror ("Unable to open device file"); dc[device].status = 0100001; /* not ready */ + } else { + /* NOTE: this is a hack, because Primos 20.2.8 doesn't do + a reset if a disk device (file) doesn't exist and is created + under a running simulation */ + dc[device].status = 0100000; /* clear status */ +#ifndef DISKMOD + dc[device].unit[u].modrecs = calloc(HASHMAX, sizeof(void *)); + //fprintf(stderr," Device '%o, unit %d, modrecs=%p\n", device, u, dc[device].unit[u].modrecs); +#endif + } } - if (T_INST || T_DIO) fprintf(stderr," select unit %d\n", u); break; case 7: /* DSTALL = Stall */ @@ -974,6 +1102,9 @@ int devdisk (short class, short func, short device) { break; default: + /* NOTE: orders 1 & 8 are supposed to halt the channel program + but leave the controller busy (model 4004). + Orders 10 & 12 (Store/Load) are not implemented */ printf("Unrecognized channel order = %d\n", order); fatal(NULL); } @@ -1352,10 +1483,17 @@ conloop: goto conloop; } - /* do a receive/transmit scan loop for every line - NOTE: should probably do a read & write select to find lines to process */ + /* 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++) { + + /* Transmit is first. Lots of opportunity to optimize this + by doing one or two mapva calls, directly examining the queue, + doing the write (which may be partial), then updating the queue + for however many characters were actually sent. */ + if (dc[device].xmitenabled & bitmask16[lx+1]) { n = 0; if (dc[device].dmqmode) { @@ -1380,7 +1518,8 @@ conloop: } put16r(0, dc[device].baseaddr + lx, 0); } - /* need to setup DMT xmit poll here, and/or look for char time interrupt */ + /* 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 @@ -1412,6 +1551,9 @@ conloop: 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); + + /* zero length read means the socket has been closed */ + if (n == 0) { n = -1; errno = EPIPE; @@ -1456,3 +1598,283 @@ conloop: break; } } + + + +/* PNC (ring net) device handler + + PNC ring buffers are 256 words (later version appear to support 256, + 512, and 1024 word packets). "nbkini" (rev 18) allocates 12 ring + buffers + 1 for every 2 nodes in the ring. Both the 1-to-2 queue + for received packets, and 2-to-1 queue for xmit packets have 63 + entries. PNC ring buffers are wired and do not cross page + boundaries. + + The actual xmit/recv buffers for PNC are 256 words, and each buffer + has an associated "block header", stored in a different location in + system memory, that is 8 words. + + The BH fields are (16-bit words): + 0: type field (1) + 1: free pool id (3 for ring buffers) + 2-3: pointer to data block + + 4-7 are available for use by the drivers. For PNC: + 4: number of words received (calculated by pncdim based on DMA regs) + or number of + 5: receive status word + 6: data 1 + 7: data 2 + + The PNC data buffer has a 2-word header: + 0: To (left) and From (right) bytes containing node-id + 1: "Type" word. + Bit 1 set = odd number of bytes + Bit 8 set = normal data messages (otherwise, a timer message) + + + Primos PNC usage: + + OCP '0007 + - disconnect from ring + + OCP '0207 + - inject a token into the ring + + OCP '0507 + - set PNC into "delay" mode (token recovery BS) + + OCP '1007 + - stop any xmit in progress + + + INA '1707 + - read PNC status word + - does this in a loop until "connected" bit is clear after disconnect above + - PNC status word: + bit 1 set if receive interrupt (rcv complete) + bit 2 set if xmit interrupt (xmit complete) + bit 3 set if "PNC booster" (repeater?) + bit 4-5 not used + bit 6 set if connected to ring + bit 7 set if multiple tokens detected (only after xmit EOR) + bit 8 set if token detected (only after xmit EOR) + bits 9-16 controller node ID + + INA '1207 + - read receive status word (byte?) + bit 1 set for previous ACK + bit 2 set for multiple previous ACK + bit 3 set for previous WACK + bit 4 set for previous NACK + bits 5-6 unused + bit 7 ACK byte parity error + bit 8 ACK byte check error (parity on bits 1-6) + bit 9 recv buffer parity error + bit 10 recv busy + bit 11 end of range before end of message + + INA '1407 + - read xmit status word + bit 1 set for ACK + bit 2 set for multiple ACK (more than 1 node accepted packet) + bit 3 set for WACK + bit 4 set for NACK (bad CRC) + bit 5 unused + bit 6 parity bit of ACK (PNC only) + bit 7 ACK byte parity error + bit 8 ACK byte check error (parity on bits 1-6) + bit 9 xmit buffer parity error + bit 10 xmit busy + bit 11 packet did not return + bit 12 packet returned with bits 6-8 nonzero + bits 13-16 retry count (booster only, zero on PNC) + + OCP '1707 + - initialize + + OTA '1707 + - set my node ID (in A register) + - if this fails, no PNC present + + OTA '1607 + - set interrupt vector (in A reg) + + OTA '1407 + - initiate receive, dma channel in A + + OTA '1507 + - initiate xmit, dma channel in A + + OCP '0107 + - connect to the ring + - (Primos follows this with INA '1707 until "connected" bit is set) + + OCP '1407 + - ack receive (clears recv interrupt request) + + OCP '0407 + - ack xmit (clears xmit interrupt request) + + OCP '1507 + - set interrupt mask (enable interrupts) + + OCP '1107 + - rev 20 does this, not sure what it does + +*/ + +int devpnc (short class, short func, short device) { + + /* PNC controller status bits */ +#define PNCRCVINT 0x8000 /* bit 1 rcv interrupt (rcv complete) */ +#define PNCXMITINT 0x4000 /* bit 2 xmit interrupt (xmit complete) */ +#define PNCBOOSTER 0x2000 /* bit 3 */ +#define PNCINTENAB 0x1000 /* bit 4 (JW usage) */ + +#define PNCCONNECTED 0x400 /* bit 6 */ +#define PNCTWOTOKENS 0x200 /* bit 7, only set after xmit EOR */ +#define PNCTOKDETECT 0x100 /* bit 8, only set after xmit EOR */ + + static short pncstat; /* controller status word */ + static short recvstat; /* receive status word */ + static short xmitstat; /* xmit status word */ + static short intvec; /* PNC interrupt vector */ + + unsigned short dmachan, dmareg, dmaaddr, dmaword; + short i, dmanw; + + //traceflags = ~TB_MAP; + + switch (class) { + + case -1: + return 0; + + case 0: + if (T_INST) fprintf(stderr," OCP '%02o%02o\n", func, device); + if (func == 00) { /* disconnect from ring */ + pncstat &= ~PNCCONNECTED; + + } else if (func == 01) { /* connect to the ring */ + pncstat |= PNCCONNECTED; + + } else if (func == 02) { /* inject a token */ + ; + + } else if (func == 04) { /* ack xmit (clear xmit int) */ + pncstat &= ~PNCXMITINT; + xmitstat = 0; /* right? */ + + } else if (func == 05) { /* set PNC into "delay" mode */ + printf("Set PNC to delay mode\n"); + + } else if (func == 010) { /* stop xmit in progress */ + xmitstat = 0; + + } else if (func == 011) { /* dunno what this is - rev 20 startup */ + ; + + } else if (func == 012) { /* set normal mode */ + ; + + } else if (func == 013) { /* set diagnostic mode */ + ; + + } else if (func == 014) { /* ack receive (clear rcv int) */ + pncstat &= ~PNCRCVINT; + recvstat = 0; /* right? */ + + } else if (func == 015) { /* set interrupt mask (enable int) */ + pncstat |= PNCINTENAB; + + } else if (func == 016) { /* clear interrupt mask (disenable int) */ + pncstat &= ~PNCINTENAB; + + } else if (func == 017) { /* initialize */ + pncstat = 0; + recvstat = 0; + xmitstat = 0; + intvec = 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 == 99) + IOSKIP; /* assume it's always ready */ + 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 == 011) { /* input ID */ + crs[A] = 07; + IOSKIP; + + } else if (func == 012) { /* read receive status word */ + crs[A] = recvstat; + IOSKIP; + + } else if (func == 014) { /* read xmit status word */ + crs[A] = xmitstat; + IOSKIP; + + } else if (func == 017) { /* read controller status word */ + crs[A] = pncstat; + 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 == 014) { /* initiate recv, dma chan in A */ + dmachan = crs[A]; + dmareg = dmachan << 1; + dmanw = regs.sym.regdmx[dmareg]; + dmanw = -(dmanw>>4); + dmaaddr = regs.sym.regdmx[dmareg+1]; + printf("PNC recv: dmachan=%o, dmareg=%o, dmaaddr=%o, dmanw=%d\n", dmachan, dmareg, dmaaddr, dmanw); + IOSKIP; + + } else if (func == 015) { /* initiate xmit, dma chan in A */ + dmachan = crs[A]; + dmareg = dmachan<<1; + dmanw = regs.sym.regdmx[dmareg]; + dmanw = -(dmanw>>4); + dmaaddr = regs.sym.regdmx[dmareg+1]; + printf("PNC xmit: dmachan=%o, dmareg=%o, dmaaddr=%o, dmanw=%d\n", dmachan, dmareg, dmaaddr, dmanw); + for (i=0; i