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:
parent
c4f7df2944
commit
0948124f29
14
dispatch.h
14
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
|
||||
|
||||
|
||||
35
em.c
35
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]);
|
||||
|
||||
79
emdev.h
79
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;
|
||||
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
53
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];
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user