From 4703c0b8fdcd85f2e7af868882e1febb434261e7 Mon Sep 17 00:00:00 2001 From: Jim Date: Wed, 7 Feb 2007 00:00:00 -0500 Subject: [PATCH] extensive changes to devmt tape controller emulation changed to use iget16 instead of get16 to fetch instructions added test in notify for semaphore overflow - call fatal() --- ea64v.h | 2 +- em.c | 101 +++++++++--- emdev.h | 496 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 545 insertions(+), 54 deletions(-) diff --git a/ea64v.h b/ea64v.h index aed9255..ddbdecf 100644 --- a/ea64v.h +++ b/ea64v.h @@ -101,7 +101,7 @@ labA: /* here for long, 2-word, V-mode memory reference */ labB: - a = get16(RP); + a = iget16(RP); RPL++; if (T_EAV) fprintf(stderr," 2-word format, a=%o\n", a); y = (inst & 020); diff --git a/em.c b/em.c index e55428a..dbe75e3 100644 --- a/em.c +++ b/em.c @@ -175,6 +175,7 @@ char gen0nam[][5] = { T_MODE trace CPU mode changes T_EAAP AP effective address calculation T_DIO disk I/O + T_TIO tape I/O T_MAP segmentation T_PCL PCL instructions T_FAULT Faults @@ -193,6 +194,7 @@ char gen0nam[][5] = { #define TB_PCL 0x00000200 #define TB_FAULT 0x00000400 #define TB_PX 0x00000800 +#define TB_TIO 0x00001000 #define T_EAR (traceflags & TB_EAR) #define T_EAV (traceflags & TB_EAV) @@ -206,6 +208,7 @@ char gen0nam[][5] = { #define T_PCL (traceflags & TB_PCL) #define T_FAULT (traceflags & TB_FAULT) #define T_PX (traceflags & TB_PX) +#define T_TIO (traceflags & TB_TIO) #define T_TRACE1 TB_FLOW | TB_INST | T_DIO | T_PCL | T_FAULT @@ -667,6 +670,31 @@ double get64r(ea_t ea, ea_t rpring) { } } +/* Instruction version of get16 (can be replaced by get16 too...) + This needs to be checked more... not sure it actually improves performance + all that much, and it doesn't work for self-modifying code in R-mode or + Ring 0 */ + +#if 1 +unsigned short iget16(ea_t ea) { + static ea_t eanext = -1; /* ea of lower 16 bits in instl */ + static unsigned long instl; + + if (ea & 0x80000000) { /* check for R-mode inst in register */ + eanext = -1; + return get16(ea); + } + if (ea == eanext) { + eanext = -1; + return instl & 0xFFFF; + } + instl = get32(ea); + eanext = INCVA(ea,1); + return instl >> 16; +} +#else +#define iget16(ea) get16((ea)) +#endif put16r(unsigned short value, ea_t ea, ea_t rpring) { pa_t pa; @@ -950,20 +978,31 @@ long devpoll[64] = {0}; #include "emdev.h" #if 0 + +/* this is the "full system" controller configuration */ + int (*devmap[64])(short, short, short) = { /* '0x */ 0,0,0,0,devasr,0,0,devpnc, - /* '1x */ devnone,devnone,0,devmt,devmt,devamlc, devamlc, devamlc, + /* '1x */ devnone,devnone,0,devnone,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 + +/* this is the "minimum system" controller configuration */ + int (*devmap[64])(short, short, short) = { /* '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, +#if 1 + /* '1x */ devnone,devnone,0,devnone,devmt,devnone, devnone, devnone, +#else + /* '1x */ devnone,devnone,0,devnone,devnone,devnone, devnone, devnone, +#endif + /* '2x */ devcp,0,devnone,devnone,devnone,devnone,devdisk,devnone, /* '3x */ 0,0,devnone,0,0,devnone,devnone,devnone, /* '4x */ 0,0,0,0,0,0,0,devnone, /* '5x */ devnone,devnone,devnone,devnone,devamlc,0,devnone,0, @@ -2397,6 +2436,14 @@ nfy(unsigned short inst) { scount = utempl>>16; /* count (signed) */ bol = utempl & 0xFFFF; /* beginning of wait list */ if (T_PX) fprintf(stderr,"%o/%o: opcode %o %s, ea=%o/%o, count=%d, bol=%o, I am %o\n", RPH, RPL, inst, nfyname[inst-01200], ea>>16, ea&0xFFFF, scount, bol, crs[OWNERL]); + + /* on later models, semaphore overflow should cause a fault */ + + if (scount == -32768) { + printf("NFY: semaphore overflow at ea %o/%o %s\n", ea>>16, ea&0xFFFF, searchloadmap(ea, 'x')); + fatal(NULL); + } + if (scount > 0) { if (bol == 0) { printf("NFY: bol is zero, count is %d for semaphore at %o/%o\n", scount, ea>>16, ea&0xFFFF); @@ -2411,6 +2458,7 @@ nfy(unsigned short inst) { bol = get16r(pcbp+PCBLINK, 0); /* get new beginning of wait list */ resched = ready(pcbp, begend); /* put this pcb on the ready list */ } + scount = scount-1; #if 0 /* NOTE: shouldn't have to do this if everything is working right, but with @@ -2653,6 +2701,8 @@ main (int argc, char **argv) { ea_t tempea; unsigned int ea32; /* full V/I mode eff address */ ea_t ea; /* final MR effective address */ + ea_t eanext; /* ea of lower 16 bits in instl */ + unsigned long instl; ea_t earp; /* RP to use for eff address calcs */ unsigned short eabit; unsigned short opcode; @@ -2772,8 +2822,10 @@ main (int argc, char **argv) { traceflags |= TB_FAULT; else if (strcmp(argv[i+1],"px") == 0) traceflags |= TB_PX; + else if (strcmp(argv[i+1],"tio") == 0) + traceflags |= TB_TIO; else if (strcmp(argv[i+1],"all") == 0) - traceflags = -1; + traceflags = ~0; else fprintf(stderr,"Unrecognized trace flag: %s\n", argv[i+1]); i++; @@ -2976,7 +3028,8 @@ main (int argc, char **argv) { if ((ea & 0xFFFF) < 040) ea = 0x80000000 | (ea & 0xFFFF); #endif - inst = get16(ea); + + inst = iget16(ea); RPL++; instcount++; @@ -3054,9 +3107,9 @@ xec: case 001314: if (T_FLOW) fprintf(stderr," CGT\n"); - tempa = get16(RP); /* get number of words */ + tempa = iget16(RP); /* get number of words */ if (1 <= crs[A] && crs[A] < tempa) - RPL = get16(INCVA(RP,crs[A])); + RPL = iget16(INCVA(RP,crs[A])); else RPL += tempa; continue; @@ -3169,7 +3222,7 @@ xec: } } #endif - utempa = get16(RP); + utempa = iget16(RP); RPL++; PUTFLR(0,utempa); utempl = GETFLR(0); @@ -3190,7 +3243,7 @@ xec: } } #endif - utempa = get16(RP); + utempa = iget16(RP); RPL++; PUTFLR(1,utempa); utempl = GETFLR(1); @@ -3903,7 +3956,7 @@ irtn: if (T_FLOW) fprintf(stderr," BCLT\n"); bclt: if (crs[KEYS] & 0200) - RPL = get16(RP); + RPL = iget16(RP); else RPL++; continue; @@ -3912,7 +3965,7 @@ bclt: if (T_FLOW) fprintf(stderr," BCLE\n"); bcle: if (crs[KEYS] & 0300) - RPL = get16(RP); + RPL = iget16(RP); else RPL++; continue; @@ -3921,7 +3974,7 @@ bcle: if (T_FLOW) fprintf(stderr," BCEQ\n"); bceq: if (crs[KEYS] & 0100) - RPL = get16(RP); + RPL = iget16(RP); else RPL++; continue; @@ -3930,7 +3983,7 @@ bceq: if (T_FLOW) fprintf(stderr," BCNE\n"); bcne: if (!(crs[KEYS] & 0100)) - RPL = get16(RP); + RPL = iget16(RP); else RPL++; continue; @@ -3939,7 +3992,7 @@ bcne: if (T_FLOW) fprintf(stderr," BCGE\n"); bcge: if (!(crs[KEYS] & 0200)) - RPL = get16(RP); + RPL = iget16(RP); else RPL++; continue; @@ -3948,7 +4001,7 @@ bcge: if (T_FLOW) fprintf(stderr," BCGT\n"); bcgt: if (!(crs[KEYS] & 0300)) - RPL = get16(RP); + RPL = iget16(RP); else RPL++; continue; @@ -3956,7 +4009,7 @@ bcgt: case 0141705: if (T_FLOW) fprintf(stderr," BCR\n"); if (!(crs[KEYS] & 0100000)) - RPL = get16(RP); + RPL = iget16(RP); else RPL++; continue; @@ -3964,7 +4017,7 @@ bcgt: case 0141704: if (T_FLOW) fprintf(stderr," BCS\n"); if (crs[KEYS] & 0100000) - RPL = get16(RP); + RPL = iget16(RP); else RPL++; continue; @@ -3972,7 +4025,7 @@ bcgt: case 0141707: if (T_FLOW) fprintf(stderr," BMLT/BLR\n"); if (!(crs[KEYS] & 020000)) - RPL = get16(RP); + RPL = iget16(RP); else RPL++; continue; @@ -3981,7 +4034,7 @@ bcgt: if (T_FLOW) fprintf(stderr," BLS\n"); bls: if (crs[KEYS] & 020000) - RPL = get16(RP); + RPL = iget16(RP); else RPL++; continue; @@ -4072,7 +4125,7 @@ bls: crs[X]++; bidx: if (crs[X] != 0) - RPL = get16(RP); + RPL = iget16(RP); else RPL++; continue; @@ -4082,7 +4135,7 @@ bidx: crs[Y]++; bidy: if (crs[Y] != 0) - RPL = get16(RP); + RPL = iget16(RP); else RPL++; continue; @@ -4096,7 +4149,7 @@ bidy: if (T_FLOW) fprintf(stderr," BDX\n"); crs[X]--; #if 1 - m = get16(RP); + m = iget16(RP); if (crs[X] > 100 && m == RPL-1) { struct timeval tv0,tv1; long delayusec, actualmsec; @@ -4753,7 +4806,7 @@ lcgt: case 0141711: if (T_FLOW) fprintf(stderr," BMLE\n"); if (!(crs[KEYS] & 020000)) - RPL = get16(RP); + RPL = iget16(RP); else goto bceq; continue; @@ -6406,7 +6459,7 @@ svc() { /* get svc code word, break into class and function */ - code = get16(RP); + code = iget16(RP); class = (code >> 6) & 077; if (class == 0) class = 1; diff --git a/emdev.h b/emdev.h index fb35bbe..fdd0dff 100644 --- a/emdev.h +++ b/emdev.h @@ -47,8 +47,8 @@ '45 = disk (was D/A converter type 6060 (analog output) - obsolete) '46 = disk '47 = #2 PNC - '50 = #1 HSSMLC (cs/slcdim.pma) - '51 = #2 HSSMLC + '50 = #1 HSSMLC/MDLC (cs/slcdim.pma) + '51 = #2 HSSMLC/MDLC '52 = #3 AMLC or ICS1 '53 = #2 AMLC '54 = #1 AMLC @@ -56,6 +56,7 @@ '56 = old SMLC (RTOS User Guide, A-1 & Hacker's Guide) '60-67 = reserved for user devices (GPIB) '70-'73 = Megatek graphics terminals + '75-'76 = T$GPPI Devices emulated by Primos in ks/ptrap.ftn for I/O instructions in Ring 3: '01 = paper tape reader @@ -464,42 +465,467 @@ readasr: /* Device '14 - magtape controller #1 - */ + + NOTES: + + This code only supports 1 tape controller (4 units), but could be + extended to support 2 controllers (eg, see disk controller code) + + All tape files are assumed to be in SimH .TAP format: + - 4-bytes (little endian integer) indicating data record length (in bytes) + - n bytes of data + - repeat of the 4-byte data record length + - odd length records have a pad byte inserted + - if MSB of record length is set, there is an error in the record + - record length of zero indicates a file mark (doesn't repeat) + - record length of all 1's indicates end-of-tape mark (doesn't repeat) + + Tape files are named according to the device and unit, like disk drives: + - dev14u0, dev14u1, dev14u2, dev14u3 + These names are usually just links to the actual tape file. + + Tape status word bits (MSB to LSB): + 1 = Vertical Parity Error + 2 = Runaway + 3 = CRC Error + 4 = LRCC Error + 5 = False Gap or Insufficient DMX Range + 6 = Uncorrectable Read Error + 7 = Raw Erorr + 8 = Illegal Command + 9 = Selected Tape Ready (online and not rewinding) + 10 = Selected Tape Online + 11 = Selected Tape is at End Of Tape (EOT) + 12 = Selected Tape is Rewinding + 13 = Selected Tape is at Beginning Of Tape (BOT) + 14 = Selected Tape is Write Protected + 15 = DMX Overrun + 16 = Rewind Interrupt + + OTA '01 Motion control A-register bits: + 1 = Select Tape Only + 2 = 0 for File operation, 1 for Record operation + 3 = 1 for Space operation + 4 = 1 for Read & Correct + 5 = 1 for 7-track + 6 = 1 for 9-track + 7 = unused + 8 = 1 for 2 chars/word, 0 for 1 char/word (not supported here) + 9-11 = motion: 100 = Forward, 010 = Reverse, 001 = Rewind + 12 = 1 for Write + 13 = 1 for Unit 0 + 14 = 1 for Unit 1 + 15 = 1 for Unit 2 + 16 = 1 for Unit 3 + +*/ + +int mtread (int fd, unsigned short *iobuf, int nw, int fw, int *mtstat) { + unsigned char buf[4]; + int n,reclen,reclen2; + + if (T_TIO) fprintf(stderr," mtread initial tape status is 0x%04x\n", *mtstat); + if (fw) { + if (*mtstat & 0x20) /* already at EOT, can't read */ + return 0; + n = read(fd, buf, 4); + if (T_TIO) fprintf(stderr," mtread read %d byte for reclen\n", n); + if (n == 0) { /* now we're at EOT */ + *mtstat |= 0x20; + return 0; + } + *mtstat &= ~8; /* not at BOT now */ +readerr: + if (n == -1) { + perror("Error reading from tape file"); + *mtstat = 0; + return 0; + } + if (n < 4) { +fmterr: + warn("Premature EOF: tape file isn't in .TAP format"); + *mtstat = 0; + return 0; + } + reclen = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24); + if (T_TIO) fprintf(stderr, " mtread reclen = %d bytes\n", reclen); + if (reclen == 0) { /* hit a file mark */ + *mtstat |= 0x100; + return 0; + } + if (reclen > 16*1024) { + fprintf(stderr,"em: reclen = %d in tape file - too big!\n"); + *mtstat = 0; + return 0; + } + if (reclen & 1) + warn("odd-length record in tape file!"); + n = read(fd, iobuf, reclen); + if (T_TIO) fprintf(stderr," mtread read %d bytes of data \n", n); + if (n == -1) goto readerr; + if (n != reclen) goto fmterr; + + /* now get the trailing record length */ + + n = read(fd, buf, 4); + if (T_TIO) fprintf(stderr," mtread read %d bytes for trailer reclen\n", n); + if (n == -1) goto readerr; + if (n != 4) goto fmterr; + reclen2 = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24); + if (reclen2 != reclen) goto fmterr; + return (reclen+1)/2; + + } else { + warn("Backspace not implemented"); + fatal(NULL); + + /* if spacing backward, see if we're at BOT */ + + if (!fw && lseek(fd, 0, SEEK_CUR) == 0) + *mtstat |= 8; /* yep, at BOT */ + } +} + +int mtwrite (int fd, unsigned short *iobuf, int nw, int *mtstat) { + int n; + + n = write(fd, iobuf, nw*2); + if (nw*2 != n) { + perror("Error writing to tape file"); + fatal(NULL); + } + *mtstat &= ~8; /* not at BOT now */ +} int devmt (short class, short func, short device) { + static unsigned short mtvec = 0114; /* interrupt vector */ + static unsigned short dmxchan = 0; /* dmx channel number */ + static unsigned short datareg = 0xFFFF; /* data holding register */ + static unsigned short enabled = 0; /* interrupts enabled */ + static unsigned short interrupting = 0; /* true if interrupt pending */ + static unsigned short usel = 0; /* last unit selected */ + static struct { + int fd; /* tape file descriptor */ + int mtstat; /* last tape status */ + int firstwrite; /* true if next write is the first */ + } unit[4]; + + int u; + char devfile[8]; + + /* the largest rec size Primos ever supported is 16K bytes, plus 8 + bytes for the 4-byte .TAP format record length at the beginning & + end of each record */ + + unsigned short iobuf[8*1024+4]; /* 16-bit WORDS! */ + unsigned short dmxreg; /* DMA/C register address */ + unsigned short dmxaddr; + unsigned long dmcpair; + short dmxnw; + int i,n; + char reclen[4]; + switch (class) { - case -1: + case -1: /* initialize emulator device */ + for (u=0; u<4; u++) { + unit[u].fd = -1; + unit[u].mtstat = 0; + unit[u].firstwrite = 1; + } return 0; case 0: - if (T_INST) fprintf(stderr," OCP '%02o%02o\n", func, device); + if (T_INST || T_TIO) fprintf(stderr," OCP '%02o%02o\n", func, device); + + if (func == 012 || func == 013) { /* set normal/diag mode - ignored */ + ; + + } else if (func == 014) { /* ack interrupt */ + /* this is a hack because Primos acks interrupts immediately after + OTA 01 (due to a tape controller bug) */ + if (interrupting) + interrupting--; + + } else if (func == 015) { /* set interrupt mask */ + enabled = 1; + + } else if (func == 016) { /* reset interrupt mask */ + enabled = 0; + + } else if (func == 017) { /* initialize */ + mtvec = 014; + dmxchan = 0; + datareg = 0xFFFF; + interrupting = 0; + usel = 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 (T_INST || T_TIO) fprintf(stderr," SKS '%02o%02o\n", func, device); + 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 (BLOCKIO) { - printf("Device '%o not supported, so I/O hangs\n", device); + if (T_INST || T_TIO) fprintf(stderr," INA '%02o%02o\n", func, device); + if (func == 0) { + if (datareg == 0xFFFF) + warn("INA 00 on tape device w/o matching OTA!"); + crs[A] = datareg; + datareg = 0xFFFF; + 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 (BLOCKIO) { - printf("Device '%o not supported, so I/O hangs\n", device); + if (T_INST || T_TIO) fprintf(stderr," OTA '%02o%02o, A='%06o %04x\n", func, device, crs[A], crs[A]); + +#if 0 + /* don't accept any OTA's if we're interrupting */ + + if (interrupting) + break; +#endif + + if (func == 01) { + + /* here's the hard part where everything happens... decode unit first */ + + u = crs[A] & 0xF; + if (u == 1) u = 3; + else if (u == 2) u = 2; + else if (u == 4) u = 1; + else if (u == 8) u = 0; + else + fatal("em: no unit selected on tape OTA '01"); + usel = u; + + /* if the tape file has never been opened, do it now. + if the tape file inode changes, re-open the file (new tape reel) */ + + if (unit[u].fd == -1) { + unit[u].mtstat = 0; + unit[u].firstwrite = 1; + snprintf(devfile,sizeof(devfile),"dev%ou%d", device, u); + if (T_TIO) fprintf(stderr," filename for tape dev '%o unit %d is %s\n", device, u, devfile); + if ((unit[u].fd = open(devfile, O_RDWR, 0770)) == -1) { + fprintf(stderr,"em: unable to open tape device file %s for device '%o unit %d for read/write\n", devfile, device, u); + IOSKIP; + break; + } + unit[u].mtstat = 0x00C8; /* Ready, Online, BOT */ + } + + /* "select only" is ignored. On a real tape controller, this + blocks if the previous tape operation is in progress */ + + if (crs[A] & 0x8000) { + if (T_TIO) fprintf(stderr," select only\n"); + IOSKIP; + break; + } + + /* clear "last operation" error bits in mtstat, but preserve status + things like "at BOT", "at EOT", "write protected" */ + + unit[u].mtstat &= 0x00EC; + + /* for rewind, read, write, & space, setup a completion + interrupt if controller interrupts are enabled. NOTE: there + is a race condition here. Immediately following OTA 01, + Primos clears pending interrupts. To get around this, + "interrupting" is a counter and we set it to 2 so that when + Primos clears interrupts, the counter is decremented in this + driver, but the interrupt will still occur later */ + + interrupting = 2; + devpoll[device] = 10; + + if ((crs[A] & 0x00E0) == 0x0020) { /* rewind */ + if (T_TIO) fprintf(stderr," rewind\n"); + if (lseek(unit[u].fd, 0, SEEK_SET) == -1) { + perror("Unable to rewind tape drive file"); + fatal(NULL); + } + unit[u].mtstat = 0x00C8; /* Ready, Online, BOT */ + IOSKIP; + break; + } + + /* Now we're reading, writing, or spacing either a record or file: + - space file/record (forward or backward) = okay + - read record = okay, read file doesn't make sense + - write record = okay, write file = write file mark */ + + + /* write file mark + NOTE: the tape file should probably be truncated on the first + write, not on each file mark */ + + if ((crs[A] & 0x4010) == 0x0010) { + if (T_TIO) fprintf(stderr," write file mark\n"); + *(int *)iobuf = 0; + n = mtwrite(unit[u].fd, iobuf, 2, &unit[u].mtstat); + ftruncate(unit[u].fd, lseek(unit[u].fd, 0, SEEK_CUR)); + IOSKIP; + break; + } + + /* space forward or backward a record or file at a time */ + + if (crs[A] & 0x2000) { /* space operation */ + if ((crs[A] & 0xC0) == 0) + warn("Motion = 0 for tape spacing operation"); + else if (crs[A] & 0x4000) { /* record operation */ + if (T_TIO) fprintf(stderr," space record, dir=%x\n", crs[A] & 0x80); + n = mtread(unit[u].fd, iobuf, 0, crs[A] & 0x80, &unit[u].mtstat); + } else { + if (T_TIO) fprintf(stderr," space file, dir=%x\n", crs[A] & 0x80); + n = 1; + while (n != 0) { + n = mtread(unit[u].fd, iobuf, 0, crs[A] & 0x80, &unit[u].mtstat); + } + } + IOSKIP; + break; + } + + /* read/write backward aren't supported */ + + if (((crs[A] & 0x00E0) == 0x0040) && ((crs[A] & 0x2000) == 0)) { + warn("em: read/write reverse not supported for tapes"); + unit[u].mtstat = 0; + IOSKIP; + break; + } + + /* read/write record */ + + if (T_TIO) fprintf(stderr," read/write record\n"); + dmxreg = dmxchan & 0x7FF; + if (dmxchan & 0x0800) { /* DMC */ + dmcpair = get32r(dmxreg, 0); /* fetch begin/end pair */ + dmxaddr = dmcpair>>16; + dmxnw = (dmcpair & 0xffff) - dmxaddr + 1; + if (T_INST || T_TIO) fprintf(stderr, " DMC channels: ['%o]='%o, ['%o]='%o, nwords=%d\n", dmxreg, dmxaddr, dmxreg+1, (dmcpair & 0xffff), dmxnw); + + } else { /* DMA */ + dmxreg = dmxreg << 1; + dmxnw = regs.sym.regdmx[dmxreg]; + if (dmxnw <= 0) + dmxnw = -(dmxnw>>4); + else + dmxnw = -((dmxnw>>4) ^ 0xF000); + dmxaddr = regs.sym.regdmx[dmxreg+1]; + if (T_INST || T_TIO) fprintf(stderr, " DMA channels: ['%o]='%o, ['%o]='%o, nwords=%d\n", dmxreg, regs.sym.regdmx[dmxreg], dmxreg+1, dmxaddr, dmxnw); + } + if (dmxnw < 0 || dmxnw > sizeof(iobuf)/2) { + fprintf(stderr,"devmt: requested DMX of size %d, emulator buffer is %d words\n", dmxnw, sizeof(iobuf)/2); + fatal(NULL); + } + + /* IMPORTANT: for mtwrite, the record length words are stored in + iobuf and the length returned by mtwrite reflects that. But + for mtread, lengths are not stored in iobuf and the actual + data record length is the return value */ + + if (crs[A] & 0x10) { /* write record */ + //traceflags = ~0; + if (T_TIO) fprintf(stderr," write record\n"); + for (i=0; i>8 & 0xFF; + reclen[2] = n>>16 & 0xFF; + reclen[3] = n>>24 & 0xFF; + *(int *)iobuf = *(int *)reclen; + *(int *)(iobuf+2+dmxnw) = *(int *)reclen; + mtwrite(unit[u].fd, iobuf, dmxnw+4, &unit[u].mtstat); + n = dmxnw; + } else { /* read record */ + if (T_TIO) fprintf(stderr," read record\n"); + n = mtread(unit[u].fd, iobuf, sizeof(iobuf), 1, &unit[u].mtstat); + if (n > dmxnw) { + if (T_TIO) fprintf(stderr, " DMA Overrun, reclen = %d words, DMA = %d words\n", n, dmxnw); + unit[u].mtstat |= 0x800; /* DMA overrun status bit */ + n = dmxnw; + } + for (i=0; i> 1; /* unit => 0/1/2/4 */ @@ -1066,14 +1508,10 @@ int devdisk (short class, short func, short device) { 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"); + fprintf(stderr,"em: unable to open disk device file %s for device '%o unit %d; flagging \n", devfile, device, u); 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 +#ifdef DISKSAFE 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 @@ -1424,10 +1862,10 @@ int devamlc (short class, short func, short device) { /* 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); + write(dc[device].sockfd[lx], "\r\nDisconnecting logged out session\r\n", 36); close(dc[device].sockfd[lx]); dc[device].dss &= ~bitmask16[lx+1]; - printf("Closing AMLC line %d on device '%o\n", lx, device); + printf("em: closing AMLC line %d on device '%o\n", lx, device); } IOSKIP; @@ -1501,7 +1939,7 @@ conloop: 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); + printf("em: AMLC connection, fd=%d, device='%o, line=%d\n", fd, newdevice, lx); break; } if (!newdevice) {