1
0
mirror of https://github.com/prirun/p50em.git synced 2026-01-13 15:17:32 +00:00

added "# of register sets" array, enabled multi-register set code ("ors") +

moved dispatch tables to global variable structure
This commit is contained in:
Jim 2007-09-12 00:00:00 -04:00
parent c4f7df2944
commit 0948124f29
4 changed files with 125 additions and 56 deletions

View File

@ -37,17 +37,17 @@
#define MRPRIMEIX(primeop) (((primeop) >> 4) | ((primeop) & 3)) #define MRPRIMEIX(primeop) (((primeop) >> 4) | ((primeop) & 3))
#define MRGEN(opcode, name, target) \ #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)); */ \ /* printf("MR opcode %05o (%s), ix=%0d\n", opcode, name, MRPRIMEIX(opcode)); */ \
if ((opcode & 01700) != 01500) { \ 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)); */ \ /* printf("MR opcode %05o (%s), ix=%0d\n", opcode | 02000, name, MRPRIMEIX(opcode | 02000)); */ \
} }
/* initialize table to "bad memory reference instruction" */ /* initialize table to "bad memory reference instruction" */
for (i=0; i < 128; i++) for (i=0; i < 128; i++)
disp_mr[i] = &&d_badmr; gvp->disp_mr[i] = &&d_badmr;
MRGEN(00100, "JMP", d_jmp); MRGEN(00100, "JMP", d_jmp);
MRGEN(00101, "EAL", d_ealeaa); MRGEN(00101, "EAL", d_ealeaa);
@ -111,13 +111,13 @@ MRGEN(03503, "JSX", d_jsx);
#define GENIX(inst) ((inst>>4) & 06000) | (inst & 01777) #define GENIX(inst) ((inst>>4) & 06000) | (inst & 01777)
#define DIGEN(opcode, name, target) \ #define DIGEN(opcode, name, target) \
disp_gen[GENIX(opcode)] = &&target; \ gvp->disp_gen[GENIX(opcode)] = &&target; \
//printf("Opcode %06o (%s), ix=%0o\n", opcode, name, GENIX(opcode)) //printf("Opcode %06o (%s), ix=%0o\n", opcode, name, GENIX(opcode))
/* initialize entire table to jump to bad generic label */ /* initialize entire table to jump to bad generic label */
for (i=0; i < 010000; i++) { 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) */ /* initialize class 0 generics (first 2 bits are zero) */
@ -230,14 +230,14 @@ DIGEN(001324, "MDIW", d_mdxx);
/* initialize class 1 generics (shift group) */ /* initialize class 1 generics (shift group) */
for (i = 02000; i < 04000; i++) { for (i = 02000; i < 04000; i++) {
disp_gen[i] = &&d_gen1; gvp->disp_gen[i] = &&d_gen1;
} }
/* initialize class 2 generics (skip group) */ /* initialize class 2 generics (skip group) */
#if 0 #if 0
for (i = 04000; i < 06000; i++) { for (i = 04000; i < 06000; i++) {
disp_gen[i] = &&d_gen2; gvp->disp_gen[i] = &&d_gen2;
} }
#endif #endif

35
em.c
View File

@ -431,6 +431,9 @@ typedef struct {
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 /* traceflags is the variable used to test tracing of each instruction
traceuser is the user number to trace, 0 meaning any user traceuser is the user number to trace, 0 meaning any user
traceseg is the procedure segment number to trace, 0 meaning any traceseg is the procedure segment number to trace, 0 meaning any
@ -2787,25 +2790,19 @@ static ors(unsigned short pcbw) {
short ownedx, freex, savedx; short ownedx, freex, savedx;
unsigned short modals; unsigned short modals;
#define NUREGS 8
currs = (crs[MODALS] & 0340) >> 5; currs = (crs[MODALS] & 0340) >> 5;
TRACE(T_PX, "ors: currs = %d, modals = %o\n", currs, crs[MODALS]); 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 /* 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 "smarter" than the Prime u-code, so probably doesn't pass DIAG
tests. I haven't tested whether the extra overhead of keeping a tests. I haven't tested whether the extra overhead of keeping a
LRU queue for register sets is worth it vs. the simpler Prime LRU queue for register sets is worth it vs. the simpler Prime
way. One problem is that different models had different #'s of way. */
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.) */
ownedx = freex = savedx = -1; 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]; 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); 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 */ ownerl = regs.sym.userregs[rs][21] & 0xFFFF; /* OWNERH/OWNERL */
@ -2819,7 +2816,7 @@ static ors(unsigned short pcbw) {
ownedx = rx; ownedx = rx;
} else if (ownerl == 0) } else if (ownerl == 0)
freex = rx; 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; savedx = rx;
} }
if (ownedx >= 0) { if (ownedx >= 0) {
@ -2832,11 +2829,11 @@ static ors(unsigned short pcbw) {
rx = savedx; rx = savedx;
TRACE(T_PX, "ors: using saved reg set %d\n", regq[rx]); TRACE(T_PX, "ors: using saved reg set %d\n", regq[rx]);
} else { } 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]); TRACE(T_PX, "ors: no reg set found; using %d\n", regq[rx]);
} }
rs = regq[rx]; rs = regq[rx];
if (rs > NUREGS) if (rs >= regsets[cpuid])
fatal("ors: rs chosen is too big"); fatal("ors: rs chosen is too big");
modals = (crs[MODALS] & ~0340) | (rs << 5); 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 If no process can be found to run, the dispatcher idles and waits
for an external interrupt. for an external interrupt.
*/ */
static dispatcher() { static dispatcher() {
ea_t pcbp, rlp; ea_t pcbp, rlp;
@ -3825,8 +3822,6 @@ main (int argc, char **argv) {
- bits 7-16 are the opcode - bits 7-16 are the opcode
the index into the table is bits 1-2, 7-16, for a 12-bit index */ 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 */ int boot; /* true if reading a boot record */
char *bootarg; /* argument to -boot, if any */ char *bootarg; /* argument to -boot, if any */
char bootfile[16]; /* boot file to load (optional) */ char bootfile[16]; /* boot file to load (optional) */
@ -4518,7 +4513,7 @@ xec:
if ((inst & 036000) == 0) { if ((inst & 036000) == 0) {
TRACE(T_INST, " generic class %d\n", inst>>14); 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 /* get x bit and adjust opcode so that PMA manual opcode
@ -4552,7 +4547,7 @@ xec:
if ((crs[KEYS] & 016000) == 014000) { /* 64V mode */ if ((crs[KEYS] & 016000) == 014000) { /* 64V mode */
ea = ea64v(inst, earp); ea = ea64v(inst, earp);
TRACE(T_INST, " EA: %o/%o %s\n",ea>>16, ea & 0xFFFF, searchloadmap(ea,' ')); 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) { } else if ((crs[KEYS] & 0016000) == 010000) {
goto imode; goto imode;
@ -4564,17 +4559,17 @@ xec:
} else if (crs[KEYS] & 004000) { /* 32R/64R */ } else if (crs[KEYS] & 004000) { /* 32R/64R */
ea = ea32r64r(earp, inst); ea = ea32r64r(earp, inst);
TRACE(T_INST, " EA: %o/%o %s\n",ea>>16, ea & 0xFFFF, searchloadmap(ea,' ')); 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) { } else if (crs[KEYS] & 002000) {
ea = ea32s(inst); ea = ea32s(inst);
TRACE(T_INST, " EA: %o/%o %s\n",ea>>16, ea & 0xFFFF, searchloadmap(ea,' ')); 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) { } else if ((crs[KEYS] & 016000) == 0) {
ea = ea16s(inst); ea = ea16s(inst);
TRACE(T_INST, " EA: %o/%o %s\n",ea>>16, ea & 0xFFFF, searchloadmap(ea,' ')); 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 { } else {
printf("Bad CPU mode in EA calculation, keys = %o\n", crs[KEYS]); printf("Bad CPU mode in EA calculation, keys = %o\n", crs[KEYS]);

79
emdev.h
View File

@ -651,6 +651,7 @@ int mtread (int fd, unsigned short *iobuf, int nw, int cmd, int *mtstat) {
if (cmd & 0x80) { /* forward motion */ if (cmd & 0x80) { /* forward motion */
if (*mtstat & 0x20) /* already at EOT, can't read */ if (*mtstat & 0x20) /* already at EOT, can't read */
return 0; return 0;
retry:
n = read(fd, buf, 4); n = read(fd, buf, 4);
TRACE(T_TIO, " mtread read foward, %d bytes for reclen\n", n); TRACE(T_TIO, " mtread read foward, %d bytes for reclen\n", n);
if (n == 0) { /* now we're at EOT */ if (n == 0) { /* now we're at EOT */
@ -670,7 +671,7 @@ readerr:
if (n < 4) { if (n < 4) {
fprintf(stderr," only read %d bytes for reclen\n", n); fprintf(stderr," only read %d bytes for reclen\n", n);
fmterr: 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 */ *mtstat |= 0x200; /* raw error */
return 0; return 0;
} }
@ -680,21 +681,20 @@ fmterr:
*mtstat |= 0x100; *mtstat |= 0x100;
return 0; 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 /* NOTE: simh .tap doc says to backup here, probably to wipe out
EOT if more data is written. IMO, EOT should never be written the EOT if more data is written. IMO, EOT should never be
to simulated tape files. */ written to simulated tape files - it only causes problems.
if ((n=lseek(fd, -4, SEEK_CUR)) == -1) { The Prime emulator ignores .tap EOT marks, since that makes it
perror("em: unable to backspace over EOT"); possible to concatenate .tap files */
goto readerr;
goto retry;
} }
*mtstat |= 0x20; if (reclen & 0x80000000) { /* record marked in error */
return 0; /* XXX: can .tap have non-zero record length here? */
} fprintf(stderr,"tape read error at position %ulld\n", lseek(fd, 0, SEEK_CUR));
if (reclen & 0x8000) { /* record marked in error */
/* NOTE: .tap may have non-zero record length here... */
*mtstat |= 0xB600; /* set all error bits */; *mtstat |= 0xB600; /* set all error bits */;
return 0; return 0;
} }
@ -741,7 +741,10 @@ fmterr:
if (n == -1) goto readerr; if (n == -1) goto readerr;
if (n != 4) goto fmterr; if (n != 4) goto fmterr;
reclen2 = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24); 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... */ /* XXX: maybe should pad odd-length record with a zero... */
return (bytestoread+1)/2; return (bytestoread+1)/2;
@ -756,11 +759,16 @@ fmterr:
/* backup 4 bytes, read reclen */ /* 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; goto fmterr;
}
n = read(fd, buf, 4); n = read(fd, buf, 4);
if (n == -1) goto readerr; 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); reclen = buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24);
/* backup reclen+8 bytes unless this is a file mark, error, /* backup reclen+8 bytes unless this is a file mark, error,
@ -770,23 +778,36 @@ fmterr:
*mtstat |= 0x100; /* set filemark status */ *mtstat |= 0x100; /* set filemark status */
goto repo; goto repo;
} }
if (reclen & 0x8000) /* error record (don't report) */
goto repo; /* ignore attempts to backspace over error records. This will
if (reclen == 0xFFFF) { 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??"); warn("em: devmt: read EOT backwards??");
reclen = 0; reclen = 0;
goto repo; goto repo;
} }
if (lseek(fd, -(reclen+8), SEEK_CUR) == -1) if (lseek(fd, -(reclen+8), SEEK_CUR) == -1) {
perror("lseek failed backspacing");
goto fmterr; goto fmterr;
}
/* read leading reclen again to make sure we're positioned correctly */ /* read leading reclen again to make sure we're positioned correctly */
n = read(fd, buf, 4); n = read(fd, buf, 4);
if (n == -1) goto readerr; 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); 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 */ /* 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"); fatal("em: no unit selected on tape OTA '01");
usel = u; usel = u;
/* XXX: if the tape device file changes (inode changes?), close /* if the tape is at BOT, close and re-open it on every operation
and re-open the file (new tape reel). Does offline need to so that if the tape device file is changed, we'll see the new
be reported at least once in this case? Or should it somehow file. Hacky, but it works. :) */
be related to rewinds? (only do the check at BOT?) */
#if 0 if (unit[u].fd >= 0 && (unit[u].mtstat & 8)) {
if (unit[u].mtstat & 8 && /* tape device file changed */) { close(unit[u].fd);
/* close tape fd if open & set to -1 */ unit[u].fd = -1;
} }
#endif
/* if the tape file has never been opened, do it now. */ /* 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) / gvp->instpermsec = (gvp->instcount-previnstcount) /
((tv.tv_sec-prev_tv.tv_sec-1)*1000 + (tv.tv_usec+1000000-prev_tv.tv_usec)/1000); ((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); //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); printf("\ninstpermsec=%d\n", gvp->instpermsec);
#endif
previnstcount = gvp->instcount; previnstcount = gvp->instcount;
prev_tv = tv; prev_tv = tv;
} }

53
regs.h
View File

@ -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 #define REGSETS 10
/* these are 16-bit offsets into crs (current register set) */ /* these are 16-bit offsets into crs (current register set) */
@ -85,6 +89,55 @@
#define BR 12 #define BR 12
#define OWNER32 (OWNERH/2) #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 { static union {
int rs[REGSETS][32]; int rs[REGSETS][32];