mirror of
https://github.com/prirun/p50em.git
synced 2026-02-26 16:23:28 +00:00
first implementation of process exchange, WAIT, NFY +
added restricted instruction checking added CALF more PCL work
This commit is contained in:
516
em.c
516
em.c
@@ -184,6 +184,7 @@ char gen0nam[][5] = {
|
||||
T_DIO disk I/O
|
||||
T_MAP segmentation
|
||||
T_PCL PCL instructions
|
||||
T_FAULT Faults
|
||||
*/
|
||||
|
||||
#define TB_EAR 0x00000001
|
||||
@@ -196,6 +197,7 @@ char gen0nam[][5] = {
|
||||
#define TB_DIO 0x00000080
|
||||
#define TB_MAP 0x00000100
|
||||
#define TB_PCL 0x00000200
|
||||
#define TB_FAULT 0x00000400
|
||||
|
||||
#define T_EAR (traceflags & TB_EAR)
|
||||
#define T_EAV (traceflags & TB_EAV)
|
||||
@@ -207,6 +209,7 @@ char gen0nam[][5] = {
|
||||
#define T_DIO (traceflags & TB_DIO)
|
||||
#define T_MAP (traceflags & TB_MAP)
|
||||
#define T_PCL (traceflags & TB_PCL)
|
||||
#define T_FAULT (traceflags & TB_FAULT)
|
||||
|
||||
int traceflags=0; /* each bit is a trace flag */
|
||||
|
||||
@@ -235,6 +238,8 @@ jmp_buf jmpbuf;
|
||||
#endif
|
||||
unsigned short mem[MEMSIZE]; /* system's physical memory */
|
||||
|
||||
#define MAKEVA(seg,word) (((int)(seg))<<16) | (word)
|
||||
|
||||
unsigned int bitmask32[33] = {0,
|
||||
0x80000000, 0x40000000, 0x20000000, 0x10000000,
|
||||
0x08000000, 0x04000000, 0x02000000, 0x01000000,
|
||||
@@ -261,7 +266,7 @@ unsigned short amask; /* address mask */
|
||||
#define RINGMASK16 0x6000 /* ring bits */
|
||||
#define EXTMASK16 0x1000 /* E-bit */
|
||||
|
||||
/* Fault codes */
|
||||
/* Fault/interrupt vectors */
|
||||
|
||||
#define RESTRICTFAULT 062
|
||||
#define PROCESSFAULT 063
|
||||
@@ -279,7 +284,7 @@ unsigned short amask; /* address mask */
|
||||
#define POINTERFAULT 077
|
||||
|
||||
int verbose;
|
||||
int domemdump; /* -memdump arg */
|
||||
int domemdump; /* -memdump arg */
|
||||
int boot; /* true if reading a boot record */
|
||||
|
||||
#define DTAR(ea) (((ea)>>26) & 3)
|
||||
@@ -327,7 +332,7 @@ pa_t mapva(ea_t ea, short intacc, short *access) {
|
||||
sdw = *(unsigned int *)(mem+staddr+relseg*2);
|
||||
if (T_MAP) fprintf(stderr," staddr=%o, sdw=%o\n", staddr, sdw);
|
||||
if (sdw & 0x8000)
|
||||
fault(SEGFAULT, 2, ea); /* fcode = fault bit set */
|
||||
fault(SEGFAULT, 2, ea); /* fcode = sdw fault bit set */
|
||||
|
||||
/* XXX: should ring be weakened with ea ring? */
|
||||
|
||||
@@ -477,8 +482,54 @@ put64(double value, ea_t ea) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void calf(ea_t ea) {
|
||||
ea_t pcbp, stackfp, csea;
|
||||
unsigned short first,next,last;
|
||||
unsigned short cs[6];
|
||||
|
||||
pcbp = *(ea_t *)(crs+OWNER); /* my pcb pointer */
|
||||
|
||||
/* make sure the concealed stack isn't empty or full */
|
||||
|
||||
first = get16(pcbp+PCBCSFIRST);
|
||||
next = get16(pcbp+PCBCSNEXT);
|
||||
last = get16(pcbp+PCBCSLAST);
|
||||
if (first == last)
|
||||
fatal("CALF: Concealed stack is empty");
|
||||
csea = MAKEVA(crs[OWNERH], next-6);
|
||||
|
||||
/* make sure ecb specifies zero arguments */
|
||||
|
||||
if (get16(ea+5) !=0) {
|
||||
printf("CALF ecb at %o/%o has arguments!\n", ea>>16, ea&0xFFFF);
|
||||
fatal(NULL);
|
||||
}
|
||||
|
||||
pcl(ea);
|
||||
|
||||
/* get the concealed stack entries and adjust the new stack frame */
|
||||
|
||||
*(unsigned int *)(cs+0) = get32(csea+0);
|
||||
*(double *)(cs+2) = get64(csea+2);
|
||||
|
||||
put16(1, stackfp+0); /* flag it as CALF frame */
|
||||
put32(*(unsigned int *)(cs+0), stackfp+2); /* return PB */
|
||||
put16(cs[2], stackfp+8); /* return keys */
|
||||
put16(cs[3], stackfp+10); /* fault code */
|
||||
put32(*(unsigned int *)(cs+4), stackfp+11); /* fault address */
|
||||
|
||||
/* pop the concealed stack */
|
||||
|
||||
put16(next-6, pcbp+PCBCSNEXT);
|
||||
}
|
||||
|
||||
|
||||
void fault(unsigned short fvec, unsigned short fcode, ea_t faddr) {
|
||||
ea_t pcbp, pxfvec, csea;
|
||||
unsigned short first, next, last;
|
||||
unsigned short m;
|
||||
unsigned short ring;
|
||||
ea_t faultrp;
|
||||
|
||||
if (fvec == PROCESSFAULT || fvec == SVCFAULT || fvec == ARITHFAULT)
|
||||
@@ -495,9 +546,44 @@ void fault(unsigned short fvec, unsigned short fcode, ea_t faddr) {
|
||||
fprintf(stderr,"fault '%o, fcode=%o, faddr=%o/%o, faultrp=%o/%o\n", fvec, fcode, faddr>>16, faddr&0xFFFF, faultrp>>16, faultrp&0xFFFF);
|
||||
crs[FCODE] = fcode;
|
||||
*(unsigned int *)(crs+FADDR) = faddr;
|
||||
|
||||
if (crs[MODALS] & 010) { /* process exchange is enabled */
|
||||
fatal("fault: fault '%o at RP=%o/%o with PX enabled\n", fvec, RPH, RPL);
|
||||
pcbp = *(ea_t *)(crs+OWNER);
|
||||
if (fvec == PROCESSFAULT || fvec == ACCESSFAULT || fvec == STACKFAULT || fvec == SEGFAULT)
|
||||
pxfvec = get32(pcbp+PCBFVR0); /* use R0 handler */
|
||||
else if (fvec == PAGEFAULT)
|
||||
pxfvec = get32(pcbp+PCBFVPF);
|
||||
else {
|
||||
ring = (RPH>>13) & 3; /* use current ring handler */
|
||||
pxfvec = get32(pcbp+PCBFVEC+2*ring);
|
||||
}
|
||||
|
||||
/* push a concealed stack entry */
|
||||
|
||||
first = get16(pcbp+PCBCSFIRST);
|
||||
next = get16(pcbp+PCBCSNEXT);
|
||||
last = get16(pcbp+PCBCSLAST);
|
||||
if (next > last)
|
||||
fatal("CALF: Concealed stack is full!");
|
||||
csea = MAKEVA(crs[OWNERH], next);
|
||||
put32(RP, csea);
|
||||
put16(crs[KEYS], csea+2);
|
||||
put16(fcode, csea+3);
|
||||
put32(faddr, csea+4);
|
||||
put16(next+6, pcbp+PCBCSNEXT);
|
||||
|
||||
/* update RP to jump to the fault vector in the fault table */
|
||||
|
||||
if (fvec == PAGEFAULT)
|
||||
RP = pxfvec;
|
||||
else
|
||||
RP = pxfvec + (fvec-062)*4;
|
||||
crs[KEYS] = (crs[KEYS] & 0161777) | (6<<10); /* V-mode */
|
||||
|
||||
if (T_FAULT) fprintf(stderr, "fault: continuing at RP=%o/%o\n", RPH, RPL);
|
||||
|
||||
} else { /* process exchange is disabled */
|
||||
/* need to check for standard/vectored interrupt mode here... */
|
||||
m = get16(fvec);
|
||||
if (m != 0) {
|
||||
if (1 || T_FLOW) fprintf(stderr," JST* '%o [%o]\n", fvec, m);
|
||||
@@ -536,7 +622,7 @@ fatal(char *msg) {
|
||||
void (*devmap[64])(short, short, short) = {
|
||||
0,0,0,0,devasr,0,0,0,
|
||||
0,0,0,devmt,devmt,0,0,0,
|
||||
devcp,0,0,0,0,0,devdisk,devdisk,
|
||||
devcp,0,0,0,0,0,devdisk,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,
|
||||
@@ -792,8 +878,6 @@ special:
|
||||
}
|
||||
|
||||
|
||||
#define MAKEVA(seg,word) (((int)(seg))<<16) | (word)
|
||||
|
||||
ea_t ea64v (ea_t earp, unsigned short inst, short i, short x, short *opcode, short *bit) {
|
||||
|
||||
ea_t ea; /* full seg/word va */
|
||||
@@ -1236,12 +1320,14 @@ ea_t pclea(unsigned short brsave[6], ea_t rp, unsigned short *bitarg, short *sto
|
||||
#28891410: fault '77, fcode=120000, faddr=24000/27117, faultrp=24000/30760
|
||||
|
||||
0003 Unexpected POINTER fault. Returning to 030760
|
||||
|
||||
Changing <= to < in the ring comparison makes Case 37 work and Case 35 fail.
|
||||
*/
|
||||
|
||||
#if 1
|
||||
if (ea & 0x80000000)
|
||||
if ((ea & 0xFFFF0000) != 0x80000000)
|
||||
if ((ea & 0x1FFF0000) || ((RP & RINGMASK32) < (ea & RINGMASK32)))
|
||||
if ((ea & 0x1FFF0000) || ((RP & RINGMASK32) <= (ea & RINGMASK32)))
|
||||
fault(POINTERFAULT, ea>>16, iwea);
|
||||
#endif
|
||||
bit = 0;
|
||||
@@ -1254,24 +1340,16 @@ ea_t pclea(unsigned short brsave[6], ea_t rp, unsigned short *bitarg, short *sto
|
||||
if (T_PCL) printf(" After indirect, PCLAP ea = %o/%o, bit=%d\n", ea>>16, ea & 0xFFFF, bit);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (ea & 0x80000000)
|
||||
if ((ea & 0xFFFF0000) != 0x80000000)
|
||||
if ((ea & 0x1FFF0000) || ((RP & RINGMASK32) < (ea & RINGMASK32)))
|
||||
fault(POINTERFAULT, ea>>16, iwea);
|
||||
#endif
|
||||
|
||||
if (!*store) {
|
||||
#if 1
|
||||
/* Case 36 wants a pointer fault here... */
|
||||
#if 0
|
||||
/* Case 36 wants a pointer fault here... See Case 31, 34, 37 also */
|
||||
if (ea & 0x80000000)
|
||||
if ((ea & 0xFFFF0000) != 0x80000000)
|
||||
if ((ea & 0x1FFF0000) || ((RP & RINGMASK32) < (ea & RINGMASK32)))
|
||||
if ((ea & 0x1FFF0000) || ((RP & RINGMASK32) <= (ea & RINGMASK32)))
|
||||
fault(POINTERFAULT, ea>>16, iwea);
|
||||
#if 0
|
||||
#else
|
||||
if (ea & 0x80000000)
|
||||
fault(POINTERFAULT, ea>>16, iwea);
|
||||
#endif
|
||||
#endif
|
||||
*(unsigned int *)(crs+XB) = ea;
|
||||
crs[X] = bit;
|
||||
@@ -1312,17 +1390,19 @@ pcl (ea_t ecbea) {
|
||||
/* get a copy of the ecb. gates must be aligned on a 16-word
|
||||
boundary, therefore can't cross a page boundary, and mapva has
|
||||
already ensured that the ecb page is resident. For a non-gate
|
||||
ecb, use individual memory accesses instead of memcpy. (Could be
|
||||
optimized later by checking to see if the ecb crosses a page,
|
||||
accessing the last word, then doing the memcpy.) */
|
||||
ecb, check to see if it crosses a page boundary. If not, a
|
||||
memcpy is okay; if it does, do fetches */
|
||||
|
||||
if (access == 1) {
|
||||
if ((ecbea & 0xF) != 0)
|
||||
fault(ACCESSFAULT, 0, ecbea);
|
||||
memcpy(ecb,mem+pa,sizeof(ecb));
|
||||
} else if ((pa & 01777) <= 01750) {
|
||||
memcpy(ecb,mem+pa,sizeof(ecb));
|
||||
} else {
|
||||
for (i=0; i<9; i++)
|
||||
ecb[i]=get16(ecbea+i);
|
||||
*(double *)(ecb+0) = get64(ecbea+0);
|
||||
*(double *)(ecb+4) = get64(ecbea+4);
|
||||
ecb[8] = get16(ecbea+8);
|
||||
}
|
||||
|
||||
/* XXX: P400 docs say "no ring change takes place if not a
|
||||
@@ -1363,7 +1443,7 @@ pcl (ea_t ecbea) {
|
||||
if (T_PCL) printf(" no room for frame, extension pointer is %o/%o\n", stackfp>>16, stackfp&0xFFFF);
|
||||
|
||||
/* XXX: faddr may need to be the last segment tried when this is changed to loop.
|
||||
CPU.PCL Case 26 wants fault address word number to be 3 (?) */
|
||||
CPU.PCL Case 26 wants fault address word number to be 3; set EHDB */
|
||||
|
||||
if (stackfp == 0 || (stackfp & 0xFFFF) + stacksize > 0xFFFF)
|
||||
fault(STACKFAULT, 0, MAKEVA(stackrootseg,0) | (newrp & RINGMASK32));
|
||||
@@ -1371,13 +1451,11 @@ pcl (ea_t ecbea) {
|
||||
|
||||
/* setup the new stack frame at stackfp
|
||||
|
||||
NOTE: this RP store is unnecessary since it'll be updated later,
|
||||
but CPU.PCL Case 45 fails with an incorrect page fault address if
|
||||
the store is omitted. Ring must be added to stackfp so that any
|
||||
page faults that occur while setting up the stack will have the
|
||||
correct ring for CPU.PCL tests */
|
||||
NOTE: Ring must be added to stackfp so that any page faults that
|
||||
occur while setting up the stack will have the correct ring for
|
||||
CPU.PCL tests */
|
||||
|
||||
stackfp |= (newrp & RINGMASK32); /* do this earlier?? */
|
||||
stackfp |= (newrp & RINGMASK32);
|
||||
put16(0, stackfp);
|
||||
put16(stackrootseg, stackfp+1);
|
||||
put32(RP, stackfp+2);
|
||||
@@ -1387,7 +1465,8 @@ pcl (ea_t ecbea) {
|
||||
put16(RPL, stackfp+9);
|
||||
|
||||
#if 0
|
||||
/* LATER: save caller's base registers for address calculations */
|
||||
/* LATER: save caller's base registers for address calculations, and
|
||||
pass to argt */
|
||||
|
||||
if (ecb[5] > 0) {
|
||||
brsave[0] = RPH; brsave[1] = 0;
|
||||
@@ -1418,9 +1497,11 @@ pcl (ea_t ecbea) {
|
||||
ea = MAKEVA(stackrootseg,0) | (newrp & RINGMASK32);
|
||||
put32((stackfp+stacksize) & ~RINGMASK32, ea);
|
||||
|
||||
/* transfer arguments if arguments are expected.
|
||||
/* transfer arguments if arguments are expected. There is no
|
||||
documentation explaining how the Y register is used during
|
||||
argument transfer, so:
|
||||
Y(high) = stack frame offset to store next argument
|
||||
YL = number of arguments left to transfer */
|
||||
Y(low) = number of arguments left to transfer (JW hack!) */
|
||||
|
||||
if (ecb[5] > 0) {
|
||||
crs[Y] = ecb[4];
|
||||
@@ -1484,11 +1565,17 @@ argt() {
|
||||
|
||||
/* NOTE: some version of ucode only store 16 bits for omitted args.
|
||||
Set EHDB to prevent this error.
|
||||
Some tests want ring/E-bits stripped, others want ring bits left
|
||||
alone. Sorry... */
|
||||
|
||||
Case 29 wants ring/E-bits preserved for omitted arguments */
|
||||
|
||||
#if 0
|
||||
#define OMITTEDARG_MASK 0x8FFFFFFF
|
||||
#else
|
||||
#define OMITTEDARG_MASK 0xEFFFFFFF
|
||||
#endif
|
||||
|
||||
if ((ea & 0x8FFF0000) == 0x80000000) {
|
||||
ea = ea & 0x8FFFFFFF; /* strip ring & E bits */
|
||||
ea = ea & OMITTEDARG_MASK; /* strip ring &/or E bits */
|
||||
put32(ea, stackfp+crs[Y]);
|
||||
} else {
|
||||
put32(ea, stackfp+crs[Y]);
|
||||
@@ -1540,6 +1627,241 @@ void prtn() {
|
||||
if (T_INST) printf(" Finished PRTN, RP=%o/%o\n", RPH, RPL);
|
||||
}
|
||||
|
||||
|
||||
/* process exchange register save: saves the current register
|
||||
set to the process pcb. If this process was also the running
|
||||
process (PBL == 0), copy RP to PB before the save */
|
||||
|
||||
pxregsave() {
|
||||
ea_t pcbp, regp;
|
||||
unsigned short i, mask;
|
||||
|
||||
/* if registers aren't owned or are already saved, return */
|
||||
|
||||
if (crs[OWNERL] == 0 || (crs[KEYS] & 1))
|
||||
return;
|
||||
|
||||
/* if this process was the currently running process, copy RP
|
||||
to PB */
|
||||
|
||||
if (crs[PBL] == 0)
|
||||
*(unsigned int *)(crs+PB) = RP;
|
||||
|
||||
pcbp = *(unsigned int *)(crs+OWNERH);
|
||||
regp = pcbp+PCBREGS;
|
||||
mask = 0;
|
||||
for (i=0; i<16; i++) {
|
||||
if (crsl[i] != 0) {
|
||||
mask |= bitmask16[i+1];
|
||||
put32(crsl[i], regp);
|
||||
regp += 2;
|
||||
}
|
||||
}
|
||||
put16(mask, pcbp+PCBMASK);
|
||||
crs[KEYS] |= 1;
|
||||
put16(crs[KEYS], pcbp+PCBKEYS);
|
||||
}
|
||||
|
||||
/* pxregload: load pcbp's registers from their pcb to the
|
||||
current register set
|
||||
NOTE: this doesn't update RP! */
|
||||
|
||||
pxregload (ea_t pcbp) {
|
||||
ea_t regp;
|
||||
unsigned short i, mask;
|
||||
|
||||
regp = pcbp+PCBREGS;
|
||||
mask = get16(pcbp+PCBMASK);
|
||||
for (i=0; i<16; i++) {
|
||||
if (mask & bitmask16[i+1]) {
|
||||
crsl[i] = get32(regp);
|
||||
regp += 2;
|
||||
} else {
|
||||
crsl[i] = 0;
|
||||
}
|
||||
}
|
||||
crs[OWNERL] = pcbp & 0xFFFF;
|
||||
}
|
||||
|
||||
/* the process exchange dispatcher's job is to:
|
||||
- determine the highest priority process ready to run
|
||||
- find a register set to use
|
||||
- save the registers if they are currently owned and not already saved
|
||||
- load this process' registers into the register set
|
||||
- clear the save done bit in keys
|
||||
- cause a process fault if any of this process' pcb abort flags are set
|
||||
|
||||
If no process can be found to run, the dispatcher idles and waits
|
||||
for an external interrupt.
|
||||
*/
|
||||
|
||||
dispatcher() {
|
||||
ea_t pcbp, rlp;
|
||||
unsigned short newrs;
|
||||
unsigned short rlbol;
|
||||
unsigned short utempa;
|
||||
|
||||
if (regs.sym.pcba != 0)
|
||||
pcbp = MAKEVA(crs[OWNERH], regs.sym.pcba);
|
||||
else if (regs.sym.pcbb != 0) {
|
||||
pcbp = MAKEVA(crs[OWNERH], regs.sym.pcbb);
|
||||
regs.sym.pcba = regs.sym.pcbb;
|
||||
regs.sym.pcbb = 0;
|
||||
} else {
|
||||
rlp = MAKEVA(crs[OWNERH], regs.sym.pla);
|
||||
#if 1
|
||||
if (regs.sym.pla < 0100 || regs.sym.pla > 0154)
|
||||
fatal("regs.sym.pla is out of range!");
|
||||
#endif
|
||||
while(1) {
|
||||
rlbol = get16(rlp);
|
||||
if (rlbol != 0)
|
||||
break;
|
||||
rlp += 2;
|
||||
}
|
||||
if (rlbol == 1)
|
||||
goto idle;
|
||||
pcbp = MAKEVA(crs[OWNERH], rlbol);
|
||||
regs.sym.pcba = rlbol;
|
||||
regs.sym.pla = rlp & 0xFFFF;
|
||||
}
|
||||
|
||||
/* pcbp now points to the process we're going to run. BY
|
||||
definition, this process should not be on any wait lists,
|
||||
so pcb.waitlist(seg) should be zero. Check it */
|
||||
|
||||
utempa = get16(pcbp+PCBWAIT);
|
||||
if (utempa != 0) {
|
||||
printf("dispatch: pcb %o/%o selected, but wait segno = %o\n", pcbp>>16, pcbp&0xFFFF, utempa);
|
||||
fatal(NULL);
|
||||
}
|
||||
printf("process %o/%o selected\n", pcbp>>16, pcbp&0xFFFF);
|
||||
|
||||
/* find a register set for this process (for now use the current
|
||||
register set) */
|
||||
|
||||
newrs = (crs[MODALS] >> 5) & 7;
|
||||
|
||||
/* make the new register set the current register set */
|
||||
|
||||
crs[MODALS] = (crs[MODALS] & ~0340) | (newrs << 5);
|
||||
|
||||
/* If the selected register set is owned and hasn't been saved, save
|
||||
it before taking it */
|
||||
|
||||
if (crs[OWNERL] == (pcbp & 0xFFFF))
|
||||
printf("dispatch: register set %d already owned by %o - no save\n", newrs, crs[OWNERL]);
|
||||
else {
|
||||
pxregsave();
|
||||
pxregload(pcbp);
|
||||
crs[KEYS] = get16(pcbp+PCBKEYS) & ~1; /* erase save done */
|
||||
RP = *(unsigned int *)(crs+PB);
|
||||
crs[PBL] = 0;
|
||||
}
|
||||
|
||||
/* if this process' abort flags are set, process fault */
|
||||
|
||||
utempa = get16(pcbp+PCBABT);
|
||||
if (utempa != 0) {
|
||||
printf("dispatch: abort flags for %o are %o\n", crs[OWNERL], utempa);
|
||||
fault(PROCESSFAULT, utempa, 0);
|
||||
fatal("fault returned after process fault");
|
||||
}
|
||||
printf("returning from dispatcher, running process %o/%o at %o/%o\n", crs[OWNERH], crs[OWNERL], RPH, RPL);
|
||||
return;
|
||||
|
||||
idle:
|
||||
fatal("dispatch idle...");
|
||||
}
|
||||
|
||||
/* take me off the ready list, setting my pcb link pointer to the arg
|
||||
passed in. The dispatcher should always be entered after this
|
||||
routine. */
|
||||
|
||||
unready (ea_t waitlist, unsigned short newlink) {
|
||||
unsigned short level, bol, eol;
|
||||
unsigned int rl;
|
||||
ea_t rlp, pcbp;
|
||||
|
||||
if (regs.sym.pcba != crs[OWNERL])
|
||||
fatal("unready: pcba mismatch");
|
||||
|
||||
pcbp = *(ea_t *)(crs+OWNER);
|
||||
rlp = MAKEVA(crs[OWNERH], regs.sym.pla);
|
||||
rl = get32(rlp);
|
||||
bol = rl >> 16;
|
||||
eol = rl & 0xFFFF;
|
||||
if (bol != (pcbp & 0xFFFF)) {
|
||||
printf("rlp=%o/%o, bol=%o, pcbp=%o/%o, pla=%o, pcba=%o\n", rlp>>16, rlp&0xFFFF, bol, pcbp>>16, pcbp&0xFFFF, regs.sym.pla, regs.sym.pcba);
|
||||
fatal("unready: I'm not first on the ready list");
|
||||
}
|
||||
if (bol == eol) {
|
||||
bol = 0;
|
||||
eol = 0;
|
||||
} else {
|
||||
bol = get16(pcbp+1);
|
||||
}
|
||||
rl = (bol<<16) | eol;
|
||||
put32(rl, rlp); /* update ready list */
|
||||
printf("unready: new rl bol/eol = %o/%o\n", rl>>16, rl&0xFFFF);
|
||||
put16(newlink, pcbp+1); /* update my pcb link */
|
||||
put32(waitlist, pcbp+2); /* update my pcb wait address */
|
||||
regs.sym.pcba = 0;
|
||||
}
|
||||
|
||||
|
||||
/* pcbp points to the pcb to put on the ready list
|
||||
begend is 1 for beginning, 0 for end
|
||||
returns true if this process is higher priority than me
|
||||
*/
|
||||
|
||||
unsigned short ready (ea_t pcbp, unsigned short begend) {
|
||||
ea_t rlp;
|
||||
unsigned short bol,eol,pcbwn,level,resched;
|
||||
unsigned int rl;
|
||||
|
||||
if ((pcbp & 0xFFFF) == crs[OWNERL])
|
||||
fatal("Tried to put myself on the ready list!");
|
||||
if (regs.sym.pcba != crs[OWNERL])
|
||||
fatal("I'm running, but not regs.sym.pcba!");
|
||||
|
||||
level = get16(pcbp+PCBLEV);
|
||||
rlp = MAKEVA(crs[OWNERH],level);
|
||||
rl = get32(rlp);
|
||||
//printf("ready: pcbp=%o/%o\n", pcbp>>16, pcbp&0xFFFF);
|
||||
//printf("ready: old bol/eol for level %o = %o/%o\n", level, rl>>16, rl&0xFFFF);
|
||||
pcbwn = pcbp; /* pcb word number */
|
||||
if ((rl>>16) == 0) { /* bol=0: this RL level was empty */
|
||||
put32(0, pcbp+1); /* set link and wait SN in pcb */
|
||||
rl = (pcbwn<<16) | pcbwn; /* set beg=end */
|
||||
} else if (begend) { /* notify to beginning */
|
||||
put32(rl & 0xFFFF0000, pcbp+1); /* set link and wait SN in pcb */
|
||||
rl = (pcbwn<<16) | rl&0xFFFF; /* new is bol, eol is unchanged */
|
||||
} else { /* notify to end */
|
||||
put32(0, pcbp+1); /* set link and wait SN in pcb */
|
||||
rl = (rl & 0xFFFF0000) | pcbwn; /* rl bol is unchanged, eol is new */
|
||||
}
|
||||
put32(rl, rlp);
|
||||
printf("ready: new bol/eol for level %o = %o/%o\n", level, rl>>16, rl&0xFFFF);
|
||||
|
||||
/* is this new process higher priority than me? If so, return 1
|
||||
so that the dispatcher is entered. If not, check for new plb/pcbb */
|
||||
|
||||
resched = 0;
|
||||
if (level < regs.sym.pla || (level == regs.sym.pla && begend)) {
|
||||
regs.sym.plb = regs.sym.pla;
|
||||
regs.sym.pcbb = regs.sym.pcba;
|
||||
regs.sym.pla = level;
|
||||
regs.sym.pcba = pcbp & 0xFFFF;
|
||||
resched = 1;
|
||||
} else if (level < regs.sym.plb) {
|
||||
regs.sym.plb = level;
|
||||
regs.sym.pcbb = pcbp & 0xFFFF;
|
||||
}
|
||||
return resched;
|
||||
}
|
||||
|
||||
|
||||
main (int argc, char **argv) {
|
||||
|
||||
short tempa,tempa1,tempa2;
|
||||
@@ -1567,6 +1889,8 @@ main (int argc, char **argv) {
|
||||
int scount; /* shift count */
|
||||
unsigned short trapvalue;
|
||||
ea_t trapaddr;
|
||||
unsigned short resched, begend, bol, ppatemp;
|
||||
ea_t pcbp;
|
||||
|
||||
/* master clear:
|
||||
- clear all registers
|
||||
@@ -1625,6 +1949,8 @@ main (int argc, char **argv) {
|
||||
traceflags |= TB_MAP;
|
||||
else if (strcmp(argv[i+1],"pcl") == 0)
|
||||
traceflags |= TB_PCL;
|
||||
else if (strcmp(argv[i+1],"fault") == 0)
|
||||
traceflags |= TB_FAULT;
|
||||
else if (strcmp(argv[i+1],"all") == 0)
|
||||
traceflags = -1;
|
||||
else
|
||||
@@ -1707,6 +2033,10 @@ main (int argc, char **argv) {
|
||||
}
|
||||
#endif
|
||||
prevpc = RP;
|
||||
|
||||
/* as a speedup later, fetch 32/64 bits (or the rest of the page)
|
||||
and maintain a prefetch queue */
|
||||
|
||||
inst = get16(RP);
|
||||
RPL++;
|
||||
//m = get16(RP); /* this is dangerous and should be removed! */
|
||||
@@ -1724,7 +2054,7 @@ main (int argc, char **argv) {
|
||||
|
||||
xec:
|
||||
instcount++;
|
||||
if (T_FLOW) fprintf(stderr,"\n%o/%o: %o %o A='%o/%:0d B='%o/%d X=%o/%d Y=%o/%d C=%d L=%d LT=%d EQ=%d #%d\n", RPH, RPL-1, inst, m, crs[A], *(short *)(crs+A), crs[B], *(short *)(crs+B), crs[X], *(short *)(crs+X), crs[Y], *(short *)(crs+Y), (crs[KEYS]&0100000) != 0, (crs[KEYS]&040000) != 0, (crs[KEYS]&0200) != 0, (crs[KEYS]&0100) != 0, instcount);
|
||||
if (T_FLOW) fprintf(stderr,"\n%o@%o/%o: %o %o A='%o/%:0d B='%o/%d X=%o/%d Y=%o/%d C=%d L=%d LT=%d EQ=%d #%d\n", crs[OWNERL], RPH, RPL-1, inst, m, crs[A], *(short *)(crs+A), crs[B], *(short *)(crs+B), crs[X], *(short *)(crs+X), crs[Y], *(short *)(crs+Y), (crs[KEYS]&0100000) != 0, (crs[KEYS]&040000) != 0, (crs[KEYS]&0200) != 0, (crs[KEYS]&0100) != 0, instcount);
|
||||
|
||||
/* generic? */
|
||||
|
||||
@@ -1825,6 +2155,7 @@ xec:
|
||||
|
||||
if (inst == 000000) {
|
||||
if (T_FLOW) fprintf(stderr," HLT\n");
|
||||
restrict();
|
||||
fatal("Program halt");
|
||||
}
|
||||
|
||||
@@ -2259,12 +2590,14 @@ stfa:
|
||||
|
||||
if (000400 <= inst && inst <= 000402) {
|
||||
if (T_FLOW) fprintf(stderr," ENB\n");
|
||||
restrict();
|
||||
crs[MODALS] &= ~0100000;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (001000 <= inst && inst <= 001002) {
|
||||
if (T_FLOW) fprintf(stderr," INH\n");
|
||||
restrict();
|
||||
crs[MODALS] |= 0100000;
|
||||
continue;
|
||||
}
|
||||
@@ -2293,12 +2626,14 @@ stfa:
|
||||
|
||||
if (inst == 000415) {
|
||||
if (T_FLOW) fprintf(stderr," ESIM\n");
|
||||
restrict();
|
||||
crs[MODALS] &= ~040000;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inst == 000417) {
|
||||
if (T_FLOW) fprintf(stderr," EVIM\n");
|
||||
restrict();
|
||||
crs[MODALS] |= 040000;
|
||||
continue;
|
||||
}
|
||||
@@ -2309,8 +2644,16 @@ stfa:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inst == 000705) {
|
||||
if (T_FLOW || T_PCL) fprintf(stderr," CALF\n");
|
||||
ea = apea(NULL);
|
||||
calf(ea);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inst == 000711) {
|
||||
if (T_FLOW) fprintf(stderr," LPSW\n");
|
||||
restrict();
|
||||
ea = apea(NULL);
|
||||
RPH = get16(ea);
|
||||
RPL = get16(ea+1);
|
||||
@@ -2322,7 +2665,7 @@ stfa:
|
||||
if (1 || T_INST) fprintf(stderr," RPH=%o, RPL=%o, keys=%o, modals=%o\n", RPH, RPL, crs[KEYS], crs[MODALS]);
|
||||
if (crs[MODALS] & 010) {
|
||||
printf("Process exchange enabled:\n");
|
||||
printf(" OWNERH=%o, PLA=%o, PCBA=%o, PLB=%o, PCBB=%o\n", crs[OWNERH], regs.sym.pla, regs.sym.pcba, regs.sym.plb, regs.sym.pcbb);
|
||||
printf(" OWNER=%o/%o, PLA=%o, PCBA=%o, PLB=%o, PCBB=%o\n", crs[OWNERH], crs[OWNERL], regs.sym.pla, regs.sym.pcba, regs.sym.plb, regs.sym.pcbb);
|
||||
for (i=regs.sym.pla;; i += 2) {
|
||||
ea = MAKEVA(crs[OWNERH], i);
|
||||
utempa = get16(ea);
|
||||
@@ -2332,7 +2675,7 @@ stfa:
|
||||
while (utempa > 0)
|
||||
utempa = dumppcb(utempa);
|
||||
}
|
||||
traceflags = -1;
|
||||
traceflags = ~TB_MAP;
|
||||
}
|
||||
if (crs[MODALS] & 020)
|
||||
printf("Mapped I/O enabled\n");
|
||||
@@ -2370,9 +2713,75 @@ stfa:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inst == 000315) {
|
||||
if (T_FLOW) fprintf(stderr," WAIT\n", inst);
|
||||
restrict();
|
||||
ea = apea(NULL);
|
||||
printf("%o/%o: WAIT on %o/%o, I am %o\n", RPH, RPL, ea>>16, ea&0xFFFF, crs[OWNERL]);
|
||||
utempl = get32(ea); /* get count and BOL */
|
||||
scount = utempl>>16; /* count (signed) */
|
||||
bol = utempl & 0xFFFF; /* beginning of wait list */
|
||||
printf(" wait list count was %d, bol was %o\n", scount, bol);
|
||||
scount++;
|
||||
if (scount >= 1) { /* I have to wait */
|
||||
if (scount == 1) { /* I'm the only waiter */
|
||||
utempl = (scount<<16) | crs[OWNERL];
|
||||
bol = 0;
|
||||
} else {
|
||||
/* XXX: this should do a priority scan... */
|
||||
utempl = (scount<<16) | crs[OWNERL];
|
||||
}
|
||||
unready(ea, bol); /* take me off the ready list */
|
||||
put32(utempl, ea); /* update semaphore count/bol */
|
||||
dispatcher();
|
||||
} else
|
||||
put16(*(unsigned short *)&scount, ea); /* just update count and continue */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inst == 001211 || inst == 001210) {
|
||||
if (T_FLOW) fprintf(stderr," NFYB/E\n", inst);
|
||||
resched = 0;
|
||||
begend = inst & 1;
|
||||
ppatemp = regs.sym.pcba;
|
||||
if (ppatemp != crs[OWNERL]) {
|
||||
printf("NFY: regs.pcba = %o, but crs[OWNERL] = %o\n", regs.sym.pcba, crs[OWNERL]);
|
||||
fatal(NULL);
|
||||
}
|
||||
restrict();
|
||||
ea = apea(NULL);
|
||||
utempl = get32(ea); /* get count and BOL */
|
||||
scount = utempl>>16; /* count (signed) */
|
||||
bol = utempl & 0xFFFF; /* beginning of wait list */
|
||||
printf("%o/%o: NFYB/E opcode %o, ea=%o/%o, count=%d, bol=%o, I am %o\n", RPH, RPL, inst, ea>>16, ea&0xFFFF, scount, bol, crs[OWNERL]);
|
||||
if (scount > 0) {
|
||||
if (bol == 0) {
|
||||
printf("NFYB: bol is zero, count is %d for semaphore at %o/%o\n", scount, ea>>16, ea&0xFFFF);
|
||||
fatal(NULL);
|
||||
}
|
||||
pcbp = MAKEVA(crs[OWNERH], bol);
|
||||
utempl = get32(pcbp+PCBWAIT);
|
||||
if (utempl != ea) {
|
||||
printf("NFYB: bol=%o, pcb waiting on %o/%o != ea %o/%o\n", utempl>>16, utempl&0xFFFF, ea>>16, ea&0xFFFF);
|
||||
fatal(NULL);
|
||||
}
|
||||
bol = get16(pcbp+PCBLINK); /* get new beginning of wait list */
|
||||
resched = ready(pcbp, begend); /* put this pcb on the ready list */
|
||||
}
|
||||
scount = scount-1;
|
||||
utempl = (scount<<16) | bol;
|
||||
put32(utempl, ea); /* update the semaphore */
|
||||
if (resched)
|
||||
dispatcher();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (inst == 001702) {
|
||||
if (T_FLOW) fprintf(stderr," IDLE?\n", inst);
|
||||
fatal("IDLE loop");
|
||||
restrict();
|
||||
dispatcher();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2389,15 +2798,7 @@ stfa:
|
||||
|
||||
if (T_FLOW) fprintf(stderr," unrecognized generic class 0 instruction!\n");
|
||||
printf(" unrecognized generic class 0 instruction %o!\n", inst);
|
||||
#if 0
|
||||
m = get16(066);
|
||||
if (m != 0) {
|
||||
if (T_FLOW) fprintf(stderr," JST* '66 [%o]\n", m);
|
||||
put16(RPL,m);
|
||||
RPL = m+1;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
/* needs to do UII/ILL fault here... */
|
||||
fatal(NULL);
|
||||
|
||||
}
|
||||
@@ -3702,6 +4103,7 @@ lcgt:
|
||||
|
||||
if ((inst & 0177760) == 0100240) {
|
||||
if (T_FLOW) fprintf(stderr," SNR %d\n", (inst & 017)+1);
|
||||
restrict();
|
||||
if (!(sswitch & bitmask16[(inst & 017)+1]))
|
||||
RPL++;
|
||||
continue;
|
||||
@@ -3709,6 +4111,7 @@ lcgt:
|
||||
|
||||
if ((inst & 0177760) == 0101240) {
|
||||
if (T_FLOW) fprintf(stderr," SNS %d\n", (inst & 017)+1);
|
||||
restrict();
|
||||
if (sswitch & bitmask16[(inst & 017)+1])
|
||||
RPL++;
|
||||
continue;
|
||||
@@ -3716,6 +4119,7 @@ lcgt:
|
||||
|
||||
if (inst == 0100200) { /* skip if machine check flop is reset */
|
||||
if (T_FLOW) fprintf(stderr," SMCR\n");
|
||||
restrict();
|
||||
RPL++;
|
||||
continue;
|
||||
}
|
||||
@@ -4108,6 +4512,7 @@ lcgt:
|
||||
if (crs[KEYS] & 010000) { /* V/I mode */
|
||||
//traceflags = ~TB_MAP;
|
||||
if (T_FLOW || T_PCL) printf("#%d %o/%o: PCL %o/%o\n", instcount, RPH, RPL-2, ea>>16, ea&0xFFFF);
|
||||
if (T_FLOW || T_PCL) fprintf(stderr,"#%d %o/%o: PCL %o/%o\n", instcount, RPH, RPL-2, ea>>16, ea&0xFFFF);
|
||||
pcl(ea);
|
||||
} else {
|
||||
if (T_FLOW) fprintf(stderr," CREP\n");
|
||||
@@ -4541,11 +4946,11 @@ lcgt:
|
||||
if (T_FLOW) fprintf(stderr," STLR\n");
|
||||
utempa = ea; /* word number portion only */
|
||||
if (utempa & 040000) { /* absolute RF addressing */
|
||||
if (restrict()) break;
|
||||
restrict();
|
||||
regs.s32[utempa & 0377] = *(int *)(crs+L);
|
||||
} else {
|
||||
utempa &= 037;
|
||||
if (utempa > 017 && restrict()) break;
|
||||
if (utempa > 017) restrict();
|
||||
*(((int *)crs)+utempa) = *(int *)(crs+L);
|
||||
}
|
||||
continue;
|
||||
@@ -4555,11 +4960,11 @@ lcgt:
|
||||
if (T_FLOW) fprintf(stderr," LDLR\n");
|
||||
utempa = ea; /* word number portion only */
|
||||
if (utempa & 040000) { /* absolute RF addressing */
|
||||
if (restrict()) break;
|
||||
restrict();
|
||||
*(int *)(crs+L) = regs.s32[utempa & 0377];
|
||||
} else {
|
||||
utempa &= 037;
|
||||
if (utempa > 017 && restrict()) break;
|
||||
if (utempa > 017) restrict();
|
||||
*(int *)(crs+L) = *(((int *)crs)+utempa);
|
||||
}
|
||||
continue;
|
||||
@@ -5240,6 +5645,7 @@ pio(unsigned int inst) {
|
||||
devmap[device](class, func, device);
|
||||
else {
|
||||
printf("pio: no handler for device '%o\n", device);
|
||||
return;
|
||||
fatal(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
3
emdev.h
3
emdev.h
@@ -251,6 +251,9 @@ readasr:
|
||||
printf("Unexpected error reading from tty, n=%d", n);
|
||||
fatal(NULL);
|
||||
}
|
||||
} else if (func == 04 || func == 05) { /* read control register 1/2 */
|
||||
crs[A] = 0;
|
||||
IOSKIP;
|
||||
} else if (func == 011) { /* read device id? */
|
||||
crs[A] = 4;
|
||||
IOSKIP;
|
||||
|
||||
22
regs.h
22
regs.h
@@ -128,3 +128,25 @@ unsigned short memtocrs[] = {
|
||||
SBL, /* 15 = unnamed (SB word) */
|
||||
LBH, /* 16 = unnamed (LB seg) */
|
||||
LBL}; /* 17 = unnamed (LB word) */
|
||||
|
||||
#define PCBLEV 0
|
||||
#define PCBLINK 1
|
||||
#define PCBWAIT 2
|
||||
#define PCBABT 4
|
||||
#define PCBCPU 5
|
||||
#define PCBPET 8
|
||||
#define PCBDTAR2 10
|
||||
#define PCBDTAR3 12
|
||||
#define PCBIT 14
|
||||
#define PCBMASK 16
|
||||
#define PCBKEYS 17
|
||||
#define PCBREGS 18
|
||||
#define PCBFVEC 50
|
||||
#define PCBFVR0 50
|
||||
#define PCBFVR1 52
|
||||
#define PCBFVR2 54
|
||||
#define PCBFVR3 56
|
||||
#define PCBFVPF 58
|
||||
#define PCBCSFIRST 60
|
||||
#define PCBCSNEXT 61
|
||||
#define PCBCSLAST 62
|
||||
|
||||
Reference in New Issue
Block a user