1
0
mirror of https://github.com/prirun/p50em.git synced 2026-03-10 20:23:36 +00:00

removed dup iget16 in BDX, no wait common case handled first in WAIT

cleaned up/added a few comments, added messages to fatal() calls
This commit is contained in:
Jim
2007-10-06 00:00:00 -04:00
parent c463fce90d
commit 4779beb25e
2 changed files with 139 additions and 134 deletions

254
em.c
View File

@@ -721,7 +721,7 @@ readloadmap(char *filename) {
TRACEA("Reading load map from %s... ", filename);
if ((mapf = fopen(filename, "r")) == NULL) {
perror("Map file open");
fatal(NULL);
fatal("Error reading map file");
}
lc = 0;
while (fgets(line, sizeof(line), mapf) != NULL) {
@@ -1503,13 +1503,11 @@ void macheck (unsigned short p300vec, unsigned short chkvec, unsigned int dswsta
if PX not enabled, simulate JST p300vec,* to invoke the check.
Then longjmp back to the fetch loop */
if (crs[MODALS] & 010) {
printf(" map: missing memory while PX enabled\n");
} else {
m = get16(p300vec);
put16(RPL, m);
RP = m+1;
}
if (crs[MODALS] & 010)
fatal(" macheck: machine check (missing memory) with PX enabled\n");
m = get16(p300vec);
put16(RPL, m);
RP = m+1;
/* similar code in the fault handler */
@@ -2502,15 +2500,10 @@ static argt() {
/* reload the caller's base registers for EA calculations */
brsave[0] = rp >> 16; brsave[1] = 0;
#if 0
*(long long *)(brsave+2) = get64(stackfp+4);
/* HACK: set ring bits on LB and SB to get correct ring on args */
brsave[2] |= (brsave[0] & RINGMASK16);
brsave[4] |= (brsave[0] & RINGMASK16);
#else
/* set ring bits on LB and SB to get correct ring on args */
*(ea_t *)(brsave+2) = get32(stackfp+4) | (rp & RINGMASK32);
*(ea_t *)(brsave+4) = get32(stackfp+6) | (rp & RINGMASK32);
#endif
argdisp = crs[Y];
argsleft = crs[YL];
while (argsleft > 0 || !crs[XL]) {
@@ -3209,8 +3202,8 @@ static dispatcher() {
if (crs[OWNERL] == pcbw) {
TRACE(T_PX, "disp: reg set already owned by %o: no save or load\n", crs[OWNERL]);
/* NOTE: call newkeys to make sure amask gets set correctly! Otherwise, 32R mode programs
are flaky */
/* NOTE: call newkeys to make sure amask gets set correctly!
Otherwise, 32R mode programs are flaky */
newkeys(crs[KEYS]);
} else {
pxregsave(0);
@@ -3219,7 +3212,7 @@ static dispatcher() {
RP = *(unsigned int *)(crs+PB);
crs[PBL] = 0;
crs[KEYS] &= ~3; /* erase "in dispatcher" and "save done" */
crs[KEYS] &= ~3; /* erase "in dispatcher" and "save done" */
TRACE(T_PX, "disp: returning from dispatcher, running process %o/%o at %o/%o, modals=%o, ppa=%o, pla=%o, ppb=%o, plb=%o\n", crs[OWNERH], crs[OWNERL], RPH, RPL, crs[MODALS], regs.sym.pcba, regs.sym.pla, regs.sym.pcbb, regs.sym.plb);
/* if this process' abort flags are set, clear them and take process fault */
@@ -3227,7 +3220,6 @@ static dispatcher() {
utempa = get16r0(pcbp+PCBABT);
if (utempa != 0) {
TRACE(T_PX, "dispatch: abort flags for %o are %o\n", crs[OWNERL], utempa);
//printf("dispatch: abort flags for %o are %o\n", crs[OWNERL], utempa);
put16r0(0, pcbp+PCBABT);
fault(PROCESSFAULT, utempa, 0);
fatal("fault returned after process fault");
@@ -3368,55 +3360,59 @@ static pwait() {
bol = utempl & 0xFFFF; /* beginning of wait list */
TRACE(T_PX, " wait list count was %d, bol was %o\n", count, bol);
count++;
if (count > 0) { /* I have to wait */
if (count == 1 && bol != 0)
fatal("WAIT: count == 1 but bol != 0");
if (count > 1 && bol == 0)
fatal("WAIT: count > 1 but bol == 0");
if (regs.sym.pcba == 0)
fatal("WAIT: pcba is zero");
if (count <= 0) { /* no wait is needed (mutex locks) */
put16(*(unsigned short *)&count, ea); /* so update count and continue */
return;
}
/* I have to wait */
if (count == 1 && bol != 0)
fatal("WAIT: count == 1 but bol != 0");
if (count > 1 && bol == 0)
fatal("WAIT: count > 1 but bol == 0");
if (regs.sym.pcba == 0)
fatal("WAIT: pcba is zero");
#if 0
/* enabling this causes rev 23.4 to fail:
/* enabling this causes rev 23.4 to fail:
WAIT: pcba=100500 != ownerl=71600
Fatal error: instruction #86137885 at 6/15274 UNLOAD+'120: 315 1400
owner=71600 DUMPCB, keys=14000, modals=77 */
if (regs.sym.pcba != crs[OWNERL]) {
printf("WAIT: pcba=%o != ownerl=%o\n", regs.sym.pcba, crs[OWNERL]);
fatal(NULL);
}
if (regs.sym.pcba != crs[OWNERL]) {
printf("WAIT: pcba=%o != ownerl=%o\n", regs.sym.pcba, crs[OWNERL]);
fatal(NULL);
}
#endif
mylev = get16r0(*(ea_t *)(crs+OWNER));
mylev = get16r0(*(ea_t *)(crs+OWNER));
if (bol != 0) {
pcbp = MAKEVA(crs[OWNERH],bol);
pcblevnext = get32r0(pcbp);
pcblev = pcblevnext >> 16;
}
TRACE(T_PX, " my level=%o, pcblev=%o\n", mylev, pcblev);
if (bol != 0) {
pcbp = MAKEVA(crs[OWNERH],bol);
pcblevnext = get32r0(pcbp);
pcblev = pcblevnext >> 16;
}
TRACE(T_PX, " my level=%o, pcblev=%o\n", mylev, pcblev);
if (count == 1 || mylev < pcblev) { /* add me to the beginning */
utempl = (count<<16) | crs[OWNERL];
put32r0(utempl, ea); /* update semaphore count/bol */
} else {
/* do a priority scan... */
while (pcblev <= mylev && bol != 0) {
prevpcbp = pcbp;
bol = pcblevnext & 0xFFFF;
if (bol != 0) {
pcbp = MAKEVA(crs[OWNERH],bol);
pcblevnext = get32r0(pcbp);
pcblev = pcblevnext >> 16;
}
if (count == 1 || mylev < pcblev) { /* add me to the beginning */
utempl = (count<<16) | crs[OWNERL];
put32r0(utempl, ea); /* update semaphore count/bol */
} else {
/* do a priority scan... */
while (pcblev <= mylev && bol != 0) {
prevpcbp = pcbp;
bol = pcblevnext & 0xFFFF;
if (bol != 0) {
pcbp = MAKEVA(crs[OWNERH],bol);
pcblevnext = get32r0(pcbp);
pcblev = pcblevnext >> 16;
}
put16r0(crs[OWNERL], prevpcbp+PCBLINK);
put16r0(*(unsigned short *)&count, ea); /* update count */
TRACE(T_PX, " new count=%d, new link for pcb %o=%o, bol=%o\n", count, prevpcbp&0xffff, crs[OWNERL], bol);
}
unready(ea, bol);
dispatcher();
} else
put16(*(unsigned short *)&count, ea); /* just update count and continue */
put16r0(crs[OWNERL], prevpcbp+PCBLINK);
put16r0(*(unsigned short *)&count, ea); /* update count */
TRACE(T_PX, " new count=%d, new link for pcb %o=%o, bol=%o\n", count, prevpcbp&0xffff, crs[OWNERL], bol);
}
unready(ea, bol);
dispatcher();
}
/* this handles several forms of notify:
@@ -6133,75 +6129,81 @@ d_bdy: /* 0140724 */
d_bdx: /* 0140734 */
TRACE(T_FLOW, " BDX\n");
#ifndef NOIDLE
m = iget16(RP);
if (crs[X] > 100 && m == RPL-1) {
struct timeval tv0,tv1;
long delayusec, actualmsec;
/* for BDX *-1 loop (backstop process mainly), we want to change
this to a long sleep so that the emulation host's CPU isn't
pegged the whole time the emulator is running.
So first, check to see if any device times expire sooner than
this, and if so, limit the sleep time to the lowest expiration
value (this is stored as number of instructions left until the
timer expires).
NOTE: In practice, the clock device ticks at 330 times a sec
under standard Primos so we only get to delay about 3ms here,
but it still keeps CPU usage to 4-5% on a 1.5GHz Mac. Primos
mods to make the clock tick 20 times per second allows for
much longer sleeps here, ie, CPU overhead is 0.7% while idle.
*/
stopwatch_start(&sw_idle);
utempl = gvp->instpermsec*100; /* limit delay to 100 msecs */
for (i=0; i<64; i++) /* check device timers */
if (devpoll[i]) /* poll set? */
if (devpoll[i] <= 100) { /* too fast! */
utempl = 1;
break;
} else if (devpoll[i] < utempl)
utempl = devpoll[i];
utempl--; /* utempl = # instructions */
delayusec = utempl*1000/gvp->instpermsec;
if (delayusec > 1000) {
if (gettimeofday(&tv0, NULL) != 0)
fatal("em: gettimeofday 0 failed");
usleep(delayusec);
if (gettimeofday(&tv1, NULL) != 0)
fatal("em: gettimeofday 1 failed");
actualmsec = (tv1.tv_sec-tv0.tv_sec-1)*1000 + (tv1.tv_usec+1000000-tv0.tv_usec)/1000;
// TRACEA(" BDX loop at %o/%o, remainder=%d, owner=%o, utempl=%d, wanted %d us, got %d ms\n", gvp->prevpc>>16, gvp->prevpc&0xffff, crs[X], crs[OWNERL], utempl, delayusec, actualusec);
/* do timer bookkeeping that would have occurred if we had
actually looped on BDX utempl times */
for (i=0; i<64; i++)
if (devpoll[i] > 0)
devpoll[i] -= utempl;
crs[X] = 1; /* decremented below */
utempa = crs[TIMER];
if (actualmsec > 0) {
crs[TIMER] += actualmsec;
if (crs[TIMER] < utempa) {
tempea = *(ea_t *)(crs+OWNER);
utempa = get16r0(tempea+4) | 1; /* set process abort flag */
put16r0(utempa, tempea+4);
}
} else {
crs[TIMERL] += utempl;
}
gvp->instcount += actualmsec*gvp->instpermsec;
}
stopwatch_stop(&sw_idle);
}
#endif
if ((short)(--crs[X]) != 0)
RPL = iget16(RP);
else
if ((short)(--crs[X]) == 0)
INCRP;
else {
m = iget16(RP);
#ifndef NOIDLE
if (crs[X] > 100 && m == RPL-1) {
struct timeval tv0,tv1;
long delayusec, actualmsec;
/* for BDX *-1 loop (backstop process mainly), we want to change
this to a long sleep so that the emulation host's CPU isn't
pegged the whole time the emulator is running.
So first, check to see if any device times expire sooner than
this, and if so, limit the sleep time to the lowest expiration
value (this is stored as number of instructions left until the
timer expires).
NOTE: In practice, the clock device ticks at 330 times a sec
under standard Primos so we only get to delay about 3ms here,
but it still keeps CPU usage to 4-5% on a 1.5GHz Mac. Primos
mods to make the clock tick 20 times per second allows for
much longer sleeps here, ie, CPU overhead is 0.7% while idle.
*/
stopwatch_start(&sw_idle);
utempl = gvp->instpermsec*100; /* limit delay to 100 msecs */
for (i=0; i<64; i++) /* check device timers */
if (devpoll[i]) /* poll set? */
if (devpoll[i] <= 100) { /* too fast! */
utempl = 1;
break;
} else if (devpoll[i] < utempl)
utempl = devpoll[i];
/* this decrement ensures that if a device had a poll pending,
we won't decrement it to zero below, ie, it'll still fire
in the main loop */
utempl--; /* utempl = # instructions */
delayusec = utempl*1000/gvp->instpermsec;
if (delayusec > 1000) {
if (gettimeofday(&tv0, NULL) != 0)
fatal("em: gettimeofday 0 failed");
usleep(delayusec);
if (gettimeofday(&tv1, NULL) != 0)
fatal("em: gettimeofday 1 failed");
actualmsec = (tv1.tv_sec-tv0.tv_sec-1)*1000 + (tv1.tv_usec+1000000-tv0.tv_usec)/1000;
// TRACEA(" BDX loop at %o/%o, remainder=%d, owner=%o, utempl=%d, wanted %d us, got %d ms\n", gvp->prevpc>>16, gvp->prevpc&0xffff, crs[X], crs[OWNERL], utempl, delayusec, actualusec);
/* do timer bookkeeping that would have occurred if we had
actually looped on BDX utempl times */
for (i=0; i<64; i++)
if (devpoll[i] > 0)
devpoll[i] -= utempl;
if (actualmsec > 0) {
utempa = crs[TIMER];
crs[TIMER] += actualmsec;
if (crs[TIMER] < utempa) { /* timer overflowed */
tempea = *(ea_t *)(crs+OWNER);
utempa = get16r0(tempea+4) | 1; /* set process abort flag */
put16r0(utempa, tempea+4);
}
} else {
crs[TIMERL] += utempl;
}
gvp->instcount += actualmsec*gvp->instpermsec;
}
stopwatch_stop(&sw_idle);
}
#endif
RPL = m;
}
goto fetch;
d_a1a: /* 0141206 */

19
emdev.h
View File

@@ -1517,17 +1517,20 @@ int devcp (int class, int func, int device) {
}
}
/* update instpermsec every 5 seconds
NB: this should probably be done whether the clock is running
or not */
/* update instpermsec every 5 seconds. Check for instcount
overflow and reset when it occurs.
if (gvp->instcount-previnstcount > gvp->instpermsec*1000*5) {
gvp->instpermsec = (gvp->instcount-previnstcount) /
((tv.tv_sec-prev_tv.tv_sec-1)*1000 + (tv.tv_usec+1000000-prev_tv.tv_usec)/1000);
//printf("gvp->instcount = %d, previnstcount = %d, diff=%d, instpermsec=%d\n", gvp->instcount, previnstcount, gvp->instcount-previnstcount, gvp->instpermsec);
XXX: this code should probably be done whether or not the clock is running */
if ((gvp->instcount < previnstcount) || (gvp->instcount-previnstcount > gvp->instpermsec*1000*5)) {
if (gvp->instcount-previnstcount > gvp->instpermsec*1000*5) {
gvp->instpermsec = (gvp->instcount-previnstcount) /
((tv.tv_sec-prev_tv.tv_sec-1)*1000 + (tv.tv_usec+1000000-prev_tv.tv_usec)/1000);
//printf("gvp->instcount = %u, previnstcount = %u, diff=%u, 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;
prev_tv = tv;
}