1
0
mirror of https://github.com/prirun/p50em.git synced 2026-01-13 07:09:38 +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 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)] = &&target; \
gvp->disp_gen[GENIX(opcode)] = &&target; \
//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

33
em.c
View File

@ -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);
@ -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]);

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 (*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;
The Prime emulator ignores .tap EOT marks, since that makes it
possible to concatenate .tap files */
goto retry;
}
*mtstat |= 0x20;
return 0;
}
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;
}

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
/* 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];