diff --git a/dispatch.h b/dispatch.h index fa389e2..3cd91d4 100644 --- a/dispatch.h +++ b/dispatch.h @@ -37,17 +37,17 @@ #define MRPRIMEIX(primeop) (((primeop) >> 4) | ((primeop) & 3)) #define MRGEN(opcode, name, target) \ - disp_mr[MRPRIMEIX(opcode)] = &⌖ \ + gvp->disp_mr[MRPRIMEIX(opcode)] = &⌖ \ /* printf("MR opcode %05o (%s), ix=%0d\n", opcode, name, MRPRIMEIX(opcode)); */ \ if ((opcode & 01700) != 01500) { \ - disp_mr[MRPRIMEIX(opcode | 02000)] = &⌖ \ + gvp->disp_mr[MRPRIMEIX(opcode | 02000)] = &⌖ \ /* printf("MR opcode %05o (%s), ix=%0d\n", opcode | 02000, name, MRPRIMEIX(opcode | 02000)); */ \ } /* initialize table to "bad memory reference instruction" */ for (i=0; i < 128; i++) - disp_mr[i] = &&d_badmr; + gvp->disp_mr[i] = &&d_badmr; MRGEN(00100, "JMP", d_jmp); MRGEN(00101, "EAL", d_ealeaa); @@ -111,13 +111,13 @@ MRGEN(03503, "JSX", d_jsx); #define GENIX(inst) ((inst>>4) & 06000) | (inst & 01777) #define DIGEN(opcode, name, target) \ - disp_gen[GENIX(opcode)] = &⌖ \ + gvp->disp_gen[GENIX(opcode)] = &⌖ \ //printf("Opcode %06o (%s), ix=%0o\n", opcode, name, GENIX(opcode)) /* initialize entire table to jump to bad generic label */ for (i=0; i < 010000; i++) { - disp_gen[i] = &&d_badgen; + gvp->disp_gen[i] = &&d_badgen; } /* initialize class 0 generics (first 2 bits are zero) */ @@ -230,14 +230,14 @@ DIGEN(001324, "MDIW", d_mdxx); /* initialize class 1 generics (shift group) */ for (i = 02000; i < 04000; i++) { - disp_gen[i] = &&d_gen1; + gvp->disp_gen[i] = &&d_gen1; } /* initialize class 2 generics (skip group) */ #if 0 for (i = 04000; i < 06000; i++) { - disp_gen[i] = &&d_gen2; + gvp->disp_gen[i] = &&d_gen2; } #endif diff --git a/em.c b/em.c index e1a8fee..b0fea9a 100644 --- a/em.c +++ b/em.c @@ -431,6 +431,9 @@ typedef struct { typedef struct { + void *disp_gen[4096]; /* generic dispatch table */ + void *disp_mr[128]; /* V/R memory ref dispatch table */ + /* traceflags is the variable used to test tracing of each instruction traceuser is the user number to trace, 0 meaning any user traceseg is the procedure segment number to trace, 0 meaning any @@ -2787,25 +2790,19 @@ static ors(unsigned short pcbw) { short ownedx, freex, savedx; unsigned short modals; -#define NUREGS 8 currs = (crs[MODALS] & 0340) >> 5; TRACE(T_PX, "ors: currs = %d, modals = %o\n", currs, crs[MODALS]); -#if 0 +#if 1 /* this is the code for handling more than 2 register sets. It is "smarter" than the Prime u-code, so probably doesn't pass DIAG tests. I haven't tested whether the extra overhead of keeping a LRU queue for register sets is worth it vs. the simpler Prime - way. One problem is that different models had different #'s of - registers, and the emulator needs a table of these values. - Either that, or it probably could initialize all register sets - using the first (user) register set as a template when process - exchange is enabled. (Primos only initializes the number of - user register sets that a particular model actually has.) */ + way. */ ownedx = freex = savedx = -1; - for (rx = NUREGS-1; rx >= 0; rx--) { /* search LRU first */ + for (rx = regsets[cpuid]-1; rx >= 0; rx--) { /* search LRU first */ rs = regq[rx]; TRACE(T_PX, "ors: check rs %d: owner=%o/%o, saved=%d\n", rs, regs.sym.userregs[rs][21]>>16, regs.sym.userregs[rs][21] & 0xFFFF, regs.sym.userregs[rs][20] & 1); ownerl = regs.sym.userregs[rs][21] & 0xFFFF; /* OWNERH/OWNERL */ @@ -2819,7 +2816,7 @@ static ors(unsigned short pcbw) { ownedx = rx; } else if (ownerl == 0) freex = rx; - else if (savedx < 0 && regs.sym.userregs[rs][20] & 1) /* KEYS/MODALS */ + else if (savedx < 0 && (regs.sym.userregs[rs][20] & 1)) /* KEYS/MODALS */ savedx = rx; } if (ownedx >= 0) { @@ -2832,11 +2829,11 @@ static ors(unsigned short pcbw) { rx = savedx; TRACE(T_PX, "ors: using saved reg set %d\n", regq[rx]); } else { - rx = NUREGS-1; /* least recently used */ + rx = regsets[cpuid]-1; /* least recently used */ TRACE(T_PX, "ors: no reg set found; using %d\n", regq[rx]); } rs = regq[rx]; - if (rs > NUREGS) + if (rs >= regsets[cpuid]) fatal("ors: rs chosen is too big"); modals = (crs[MODALS] & ~0340) | (rs << 5); @@ -2873,7 +2870,7 @@ static ors(unsigned short pcbw) { If no process can be found to run, the dispatcher idles and waits for an external interrupt. - */ +*/ static dispatcher() { ea_t pcbp, rlp; @@ -3825,8 +3822,6 @@ main (int argc, char **argv) { - bits 7-16 are the opcode the index into the table is bits 1-2, 7-16, for a 12-bit index */ - void *disp_gen[4096]; /* generic dispatch table */ - void *disp_mr[128]; /* V/R memory ref dispatch table */ int boot; /* true if reading a boot record */ char *bootarg; /* argument to -boot, if any */ char bootfile[16]; /* boot file to load (optional) */ @@ -4518,7 +4513,7 @@ xec: if ((inst & 036000) == 0) { TRACE(T_INST, " generic class %d\n", inst>>14); - goto *disp_gen[GENIX(inst)]; + goto *gvp->disp_gen[GENIX(inst)]; } /* get x bit and adjust opcode so that PMA manual opcode @@ -4552,7 +4547,7 @@ xec: if ((crs[KEYS] & 016000) == 014000) { /* 64V mode */ ea = ea64v(inst, earp); TRACE(T_INST, " EA: %o/%o %s\n",ea>>16, ea & 0xFFFF, searchloadmap(ea,' ')); - goto *disp_mr[VMRINSTIX(inst)]; + goto *(gvp->disp_mr[VMRINSTIX(inst)]); } else if ((crs[KEYS] & 0016000) == 010000) { goto imode; @@ -4564,17 +4559,17 @@ xec: } else if (crs[KEYS] & 004000) { /* 32R/64R */ ea = ea32r64r(earp, inst); TRACE(T_INST, " EA: %o/%o %s\n",ea>>16, ea & 0xFFFF, searchloadmap(ea,' ')); - goto *disp_mr[RMRINSTIX(inst)]; + goto *(gvp->disp_mr[RMRINSTIX(inst)]); } else if (crs[KEYS] & 002000) { ea = ea32s(inst); TRACE(T_INST, " EA: %o/%o %s\n",ea>>16, ea & 0xFFFF, searchloadmap(ea,' ')); - goto *disp_mr[SMRINSTIX(inst)]; + goto *(gvp->disp_mr[SMRINSTIX(inst)]); } else if ((crs[KEYS] & 016000) == 0) { ea = ea16s(inst); TRACE(T_INST, " EA: %o/%o %s\n",ea>>16, ea & 0xFFFF, searchloadmap(ea,' ')); - goto *disp_mr[SMRINSTIX(inst)]; + goto *(gvp->disp_mr[SMRINSTIX(inst)]); } else { printf("Bad CPU mode in EA calculation, keys = %o\n", crs[KEYS]); diff --git a/emdev.h b/emdev.h index 5205593..6a9fd1e 100644 --- a/emdev.h +++ b/emdev.h @@ -651,6 +651,7 @@ int mtread (int fd, unsigned short *iobuf, int nw, int cmd, int *mtstat) { if (cmd & 0x80) { /* forward motion */ if (*mtstat & 0x20) /* already at EOT, can't read */ return 0; +retry: n = read(fd, buf, 4); TRACE(T_TIO, " mtread read foward, %d bytes for reclen\n", n); if (n == 0) { /* now we're at EOT */ @@ -670,7 +671,7 @@ readerr: if (n < 4) { fprintf(stderr," only read %d bytes for reclen\n", n); fmterr: - warn("Tape file isn't in .TAP format"); + fprintf(stderr," TAP format error at position %d\n", lseek(fd, 0, SEEK_CUR)); *mtstat |= 0x200; /* raw error */ return 0; } @@ -680,21 +681,20 @@ fmterr: *mtstat |= 0x100; return 0; } - if (reclen == 0xFFFF) { /* hit EOT mark */ + if (reclen == 0xFFFFFFFF) { /* hit EOT mark */ /* NOTE: simh .tap doc says to backup here, probably to wipe out - EOT if more data is written. IMO, EOT should never be written - to simulated tape files. */ + the EOT if more data is written. IMO, EOT should never be + written to simulated tape files - it only causes problems. - if ((n=lseek(fd, -4, SEEK_CUR)) == -1) { - perror("em: unable to backspace over EOT"); - goto readerr; - } - *mtstat |= 0x20; - return 0; + The Prime emulator ignores .tap EOT marks, since that makes it + possible to concatenate .tap files */ + + goto retry; } - if (reclen & 0x8000) { /* record marked in error */ - /* NOTE: .tap may have non-zero record length here... */ + if (reclen & 0x80000000) { /* record marked in error */ + /* XXX: can .tap have non-zero record length here? */ + fprintf(stderr,"tape read error at position %ulld\n", lseek(fd, 0, SEEK_CUR)); *mtstat |= 0xB600; /* set all error bits */; return 0; } @@ -741,7 +741,10 @@ fmterr: 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; + if (reclen2 != reclen) { + fprintf(stderr," record length mismatch; leading %d, trailing %d\n", reclen, reclen2); + goto fmterr; + } /* XXX: maybe should pad odd-length record with a zero... */ return (bytestoread+1)/2; @@ -756,11 +759,16 @@ fmterr: /* backup 4 bytes, read reclen */ - if (lseek(fd, -4, SEEK_CUR) == -1) + if (lseek(fd, -4, SEEK_CUR) == -1) { + perror("backspacing trailing reclen"); goto fmterr; + } n = read(fd, buf, 4); if (n == -1) goto readerr; - if (n != 4) goto fmterr; + if (n != 4) { + fprintf(stderr,"only read %d bytes for trailing reclen backspacing\n", n); + goto fmterr; + } reclen = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24); /* backup reclen+8 bytes unless this is a file mark, error, @@ -770,23 +778,36 @@ fmterr: *mtstat |= 0x100; /* set filemark status */ goto repo; } - if (reclen & 0x8000) /* error record (don't report) */ - goto repo; - if (reclen == 0xFFFF) { + + /* ignore attempts to backspace over error records. This will + cause Magsav to read the next record instead, and it may + recover. Re-reading the error record 10 times won't help! */ + + if (reclen & 0x80000000) /* error record (don't report) */ + return 0; + if (reclen == 0xFFFFFFFF) { warn("em: devmt: read EOT backwards??"); reclen = 0; goto repo; } - if (lseek(fd, -(reclen+8), SEEK_CUR) == -1) + if (lseek(fd, -(reclen+8), SEEK_CUR) == -1) { + perror("lseek failed backspacing"); goto fmterr; + } /* read leading reclen again to make sure we're positioned correctly */ n = read(fd, buf, 4); if (n == -1) goto readerr; - if (n != 4) goto fmterr; + if (n != 4) { + fprintf(stderr, "only read %d bytes for leading reclen backspacing\n", n); + goto fmterr; + } reclen2 = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24); - if (reclen2 != reclen) goto fmterr; + if (reclen2 != reclen) { + fprintf(stderr," record length mismatch backspacing; leading %d, trailing %d\n", reclen, reclen2); + goto fmterr; + } /* finally, backup over the reclen to be positioned for read */ @@ -958,16 +979,14 @@ int devmt (int class, int func, int device) { fatal("em: no unit selected on tape OTA '01"); usel = u; - /* XXX: if the tape device file changes (inode changes?), close - and re-open the file (new tape reel). Does offline need to - be reported at least once in this case? Or should it somehow - be related to rewinds? (only do the check at BOT?) */ + /* if the tape is at BOT, close and re-open it on every operation + so that if the tape device file is changed, we'll see the new + file. Hacky, but it works. :) */ -#if 0 - if (unit[u].mtstat & 8 && /* tape device file changed */) { - /* close tape fd if open & set to -1 */ + if (unit[u].fd >= 0 && (unit[u].mtstat & 8)) { + close(unit[u].fd); + unit[u].fd = -1; } -#endif /* if the tape file has never been opened, do it now. */ @@ -1495,7 +1514,9 @@ int devcp (int class, int func, int device) { gvp->instpermsec = (gvp->instcount-previnstcount) / ((tv.tv_sec-prev_tv.tv_sec-1)*1000 + (tv.tv_usec+1000000-prev_tv.tv_usec)/1000); //printf("instcount = %d, previnstcount = %d, diff=%d, instpermsec=%d\n", gvp->instcount, previnstcount, gvp->instcount-previnstcount, gvp->instpermsec); +#ifdef NOIDLE printf("\ninstpermsec=%d\n", gvp->instpermsec); +#endif previnstcount = gvp->instcount; prev_tv = tv; } diff --git a/regs.h b/regs.h index 398aba7..4976c8c 100644 --- a/regs.h +++ b/regs.h @@ -1,3 +1,7 @@ +/* this number includes the 2 system register sets plus n "user" + register sets. Some Prime models had more than 2 system register + sets, but the emulator only has 2 */ + #define REGSETS 10 /* these are 16-bit offsets into crs (current register set) */ @@ -85,6 +89,55 @@ #define BR 12 #define OWNER32 (OWNERH/2) +/* this is the number of user register sets for this cpuid */ + +static short regsets[] = { \ + 2, /* 00 P400 */ + 2, /* 01 P400 (> REV A U-CODE) */ + 2, /* 02 RESERVED */ + 2, /* 03 P350 */ + 2, /* 04 P450/P550 */ + 2, /* 05 P750 */ + 2, /* 06 P650 */ + 2, /* 07 P150/P250 */ + 2, /* 08 P850 */ + 2, /* 09 MOLE/550 */ + 2, /* 10 MOLE/650 */ + 2, /* 11 P2250 */ + 2, /* 12 P750Y */ + 2, /* 13 P550Y */ + 2, /* 14 P850Y */ + 4, /* 15 P9950 */ + 8, /* 16 P9650 */ + 8, /* 17 P2550 */ + 4, /* 18 P9955 */ + 4, /* 19 P9750 */ + 2, /* 20 TBD */ + 8, /* 21 P2350 */ + 8, /* 22 P2655 */ + 8, /* 23 P9655 */ + 4, /* 24 P9955-TIGGER */ + 8, /* 25 P2450 */ + 4, /* 26 P4050 */ + 4, /* 27 P4150 */ + 4, /* 28 P6350 */ + 4, /* 29 P6550 */ + 4, /* 30 P9955-II */ + 8, /* 31 P2755 */ + 8, /* 32 P2455 */ + 4, /* 33 P5310 */ + 4, /* 34 P9755 */ + 4, /* 35 P2850 */ + 4, /* 36 P2950 */ + 4, /* 37 P5330 */ + 4, /* 38 P4450 */ + 4, /* 39 P5370 */ + 4, /* 40 P6650 */ + 4, /* 41 P6450 */ + 4, /* 42 P6150 */ + 4, /* 43 P5320 */ + 4}; /* 44 P5340 */ + static union { int rs[REGSETS][32];