mirror of
https://github.com/prirun/p50em.git
synced 2026-02-01 05:52:03 +00:00
update instpermsec every 5 seconds to support varying host CPU speeds
changes to support accurate real-time clock in devcp changes to backstop idle instruction (BDX)
This commit is contained in:
130
em.c
130
em.c
@@ -17,6 +17,22 @@
|
||||
|
||||
|
||||
NOTE: this only runs on a big-endian machine, like the Prime.
|
||||
|
||||
To boot (from 2466, dev '26, unit 3):
|
||||
|
||||
time ./em --tport 8000 --cpuid 5 --ss 14714 --boot --map MFD.2462/PRIRUN/RING0.MAP MFD.2462/PRIRUN/RING3.MAP <dev26u3 2>err
|
||||
|
||||
or:
|
||||
|
||||
14114 for dev26u0
|
||||
14134 for dev26u1
|
||||
14154 for dev26u2
|
||||
|
||||
14314 for dev27u0
|
||||
14334 for dev27u1
|
||||
14354 for dev27u2
|
||||
14374 for dev27u3
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -208,10 +224,11 @@ unsigned short sswitch = 0; /* sense switches, set with --ss */
|
||||
unsigned short cpuid = 27; /* STPM CPU model, set with --cpuid */
|
||||
|
||||
unsigned long instcount=0; /* global instruction count */
|
||||
unsigned long previnstcount=0; /* value of above at last gettimeofday */
|
||||
|
||||
unsigned short inhcount = 0; /* number of instructions to stay inhibited */
|
||||
|
||||
unsigned int instpermsec = 2600; /* initial assumption for inst/msec */
|
||||
unsigned int instpermsec = 2000; /* initial assumption for inst/msec */
|
||||
|
||||
jmp_buf jmpbuf; /* for longjumps to the fetch loop */
|
||||
|
||||
@@ -2382,20 +2399,20 @@ nfy(unsigned short inst) {
|
||||
if (T_PX) fprintf(stderr,"%o/%o: opcode %o %s, ea=%o/%o, count=%d, bol=%o, I am %o\n", RPH, RPL, inst, nfyname[inst-01200], 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);
|
||||
printf("NFY: 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 = get32r(pcbp+PCBWAIT, 0);
|
||||
if (utempl != ea) {
|
||||
printf("NFYB: bol=%o, pcb waiting on %o/%o != ea %o/%o\n", utempl>>16, utempl&0xFFFF, ea>>16, ea&0xFFFF);
|
||||
printf("NFY: bol=%o, pcb waiting on %o/%o != ea %o/%o\n", utempl>>16, utempl&0xFFFF, ea>>16, ea&0xFFFF);
|
||||
fatal(NULL);
|
||||
}
|
||||
bol = get16r(pcbp+PCBLINK, 0); /* get new beginning of wait list */
|
||||
resched = ready(pcbp, begend); /* put this pcb on the ready list */
|
||||
}
|
||||
scount = scount-1;
|
||||
#if 1
|
||||
#if 0
|
||||
/* NOTE: shouldn't have to do this if everything is working right, but with
|
||||
PRIMOS we get:
|
||||
CFatal error: instruction #81929908 at 6/54311: 315 4400
|
||||
@@ -2659,12 +2676,8 @@ main (int argc, char **argv) {
|
||||
ea_t zea1, zea2;
|
||||
unsigned char zch1, zch2, *zcp1, *zcp2, zspace;
|
||||
|
||||
unsigned int instpermsecmask = 03777; /* nearest mask of above */
|
||||
unsigned long long bootmsec; /* time we booted */
|
||||
unsigned long long curmsec; /* current time in milliseconds */
|
||||
|
||||
struct timeval boot_tv;
|
||||
struct timeval tv;
|
||||
struct timeval tv, prev_tv;
|
||||
struct timezone tz;
|
||||
float mips;
|
||||
|
||||
@@ -2840,6 +2853,7 @@ main (int argc, char **argv) {
|
||||
perror("gettimeofday failed");
|
||||
fatal(NULL);
|
||||
}
|
||||
prev_tv = boot_tv;
|
||||
|
||||
/* main instruction decode loop */
|
||||
|
||||
@@ -2892,7 +2906,7 @@ main (int argc, char **argv) {
|
||||
/* poll any devices that requested a poll */
|
||||
|
||||
for (i=0; i<64; i++)
|
||||
if (devpoll[i] && (--devpoll[i] == 0)) {
|
||||
if (devpoll[i] && (--devpoll[i] <= 0)) {
|
||||
if (!devmap[i])
|
||||
fatal("devpoll set but devmap is null");
|
||||
#if 0
|
||||
@@ -2966,6 +2980,19 @@ main (int argc, char **argv) {
|
||||
RPL++;
|
||||
instcount++;
|
||||
|
||||
/* update instpermsec every 5 seconds */
|
||||
|
||||
if (instcount-previnstcount > instpermsec*1000*5) {
|
||||
if (gettimeofday(&tv, NULL) != 0)
|
||||
fatal("em: gettimeofday failed");
|
||||
instpermsec = (instcount-previnstcount) /
|
||||
((tv.tv_sec*1000+(tv.tv_usec/1000)) - (prev_tv.tv_sec*1000+(prev_tv.tv_usec/1000)));
|
||||
//printf("instcount = %d, previnstcount = %d, diff=%d, instpermsec=%d\n", instcount, previnstcount, instcount-previnstcount, instpermsec);
|
||||
//printf("instpermsec=%d\n", instpermsec);
|
||||
previnstcount = instcount;
|
||||
prev_tv = tv;
|
||||
}
|
||||
|
||||
/* while a process is running, RP is the real program counter, PBH
|
||||
is the active procedure segment, and PBL is zero. When a
|
||||
process stops running, RP is copied to PB. When a process
|
||||
@@ -2978,16 +3005,6 @@ main (int argc, char **argv) {
|
||||
if (crs[MODALS] & 010) { /* px enabled, bump 1ms process timer */
|
||||
if (crs[TIMERL]++ > instpermsec) {
|
||||
crs[TIMERL] = 0;
|
||||
#if 0
|
||||
if (crs[OWNERL] == 0100100)
|
||||
printf("SUP timer=%d\n", *(short *)(crs+TIMER));
|
||||
|
||||
/* bump all timers, applying corrections based on actual time
|
||||
if necessary */
|
||||
|
||||
if (!gettimeofday(&tv, &tz))
|
||||
fatal("em: gettimeofday failed");
|
||||
#endif
|
||||
|
||||
/* if 1ms resolution process timer overflows, set pcb abort flag */
|
||||
|
||||
@@ -4081,25 +4098,64 @@ bidy:
|
||||
#if 1
|
||||
m = get16(RP);
|
||||
if (crs[X] > 100 && m == RPL-1) {
|
||||
//fprintf(stderr," BDX loop detected at %o/%o, remainder=%d\n", prevpc>>16, prevpc&0xffff, crs[X]);
|
||||
utempl = instpermsec*10;
|
||||
for (i=0; i<64; i++)
|
||||
if (devpoll[i] && devpoll[i] < utempl)
|
||||
struct timeval tv0,tv1;
|
||||
long delayusec, actualmsec;
|
||||
|
||||
/* for BDX *-1 loop (backstop process mainly), we want to change
|
||||
this to a 10ms sleep so that the emulation host doesn't peg the
|
||||
CPU.
|
||||
|
||||
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,
|
||||
so we only get to delay about 3ms here.
|
||||
*/
|
||||
|
||||
utempl = instpermsec*10; /* limit delay to 10 millisecs */
|
||||
for (i=0; i<64; i++) /* check device timers */
|
||||
if (devpoll[i]) /* poll set? */
|
||||
if (devpoll[i] < 0 || devpoll[i] <= 100) { /* too fast! */
|
||||
utempl = 1;
|
||||
break;
|
||||
} else if (devpoll[i] < utempl)
|
||||
utempl = devpoll[i];
|
||||
utempl--;
|
||||
for (i=0; i<64; i++)
|
||||
if (devpoll[i])
|
||||
devpoll[i] -= utempl;
|
||||
usleep(utempl*1000/instpermsec);
|
||||
crs[X] = 0;
|
||||
utempa = crs[TIMER];
|
||||
crs[TIMER] += utempl/instpermsec;
|
||||
if (crs[TIMER] < utempa) {
|
||||
tempea = *(ea_t *)(crs+OWNER);
|
||||
utempa = get16r(tempea+4, 0) | 1; /* set process abort flag */
|
||||
put16r(utempa, tempea+4, 0);
|
||||
utempl--; /* utempl = # instructions */
|
||||
delayusec = utempl*1000/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");
|
||||
if (tv1.tv_usec > tv0.tv_usec)
|
||||
actualmsec = (tv1.tv_sec-tv0.tv_sec)*1000 + (tv1.tv_usec-tv0.tv_usec)/1000;
|
||||
else
|
||||
actualmsec = (tv1.tv_sec-tv0.tv_sec-1)*1000 + (tv1.tv_usec+1000000-tv0.tv_usec)/1000;
|
||||
// fprintf(stderr," BDX loop at %o/%o, remainder=%d, owner=%o, utempl=%d, wanted %d us, got %d ms\n", prevpc>>16, 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] = 0;
|
||||
utempa = crs[TIMER];
|
||||
if (actualmsec > 0) {
|
||||
crs[TIMER] += actualmsec;
|
||||
if (crs[TIMER] < utempa) {
|
||||
tempea = *(ea_t *)(crs+OWNER);
|
||||
utempa = get16r(tempea+4, 0) | 1; /* set process abort flag */
|
||||
put16r(utempa, tempea+4, 0);
|
||||
}
|
||||
} else {
|
||||
crs[TIMERL] += utempl;
|
||||
}
|
||||
instcount += actualmsec*instpermsec;
|
||||
}
|
||||
instcount += utempl;
|
||||
}
|
||||
if (crs[X] != 0)
|
||||
RPL = m;
|
||||
|
||||
35
emdev.h
35
emdev.h
@@ -539,7 +539,11 @@ int devcp (short class, short func, short device) {
|
||||
static short enabled = 0;
|
||||
static unsigned short clkvec;
|
||||
static short clkpic;
|
||||
static unsigned long ticks=0;
|
||||
static struct timeval start_tv;
|
||||
|
||||
struct timeval tv;
|
||||
unsigned long elapsedms,targetticks;
|
||||
int datnow, i;
|
||||
time_t unixtime;
|
||||
ea_t datnowea;
|
||||
@@ -572,6 +576,9 @@ int devcp (short class, short func, short device) {
|
||||
//traceflags = ~TB_MAP;
|
||||
//fprintf(stderr,"Clock interrupt enabled!\n");
|
||||
enabled = 1;
|
||||
if (gettimeofday(&start_tv, NULL) != 0)
|
||||
fatal("em: gettimeofday 2 failed");
|
||||
ticks = 0;
|
||||
SETCLKPOLL;
|
||||
|
||||
/* if --map is used, lookup DATNOW symbol and set the 32-bit
|
||||
@@ -627,7 +634,7 @@ int devcp (short class, short func, short device) {
|
||||
if (func == 02) { /* set PIC interval */
|
||||
clkpic = *(short *)(crs+A);
|
||||
SETCLKPOLL;
|
||||
//printf("Clock PIC interval set to %d\n", clkpic);
|
||||
printf("Clock PIC interval set to %d\n", clkpic);
|
||||
} else if (func == 07) {
|
||||
//printf("Clock control register set to '%o\n", crs[A]);
|
||||
} else if (func == 013) {
|
||||
@@ -642,9 +649,31 @@ int devcp (short class, short func, short device) {
|
||||
|
||||
case 4:
|
||||
if (enabled) {
|
||||
if (intvec == -1)
|
||||
if (intvec == -1) {
|
||||
intvec = clkvec;
|
||||
SETCLKPOLL;
|
||||
ticks++;
|
||||
if (gettimeofday(&tv, NULL) != 0)
|
||||
fatal("em: gettimeofday 3 failed");
|
||||
if (tv.tv_usec > start_tv.tv_usec)
|
||||
elapsedms = (tv.tv_sec-start_tv.tv_sec)*1000 + (tv.tv_usec-start_tv.tv_usec)/1000;
|
||||
else
|
||||
elapsedms = (tv.tv_sec-start_tv.tv_sec-1)*1000 + (tv.tv_usec+1000000-start_tv.tv_usec)/1000;
|
||||
targetticks = elapsedms/(-clkpic*3.2/1000);
|
||||
if (ticks < targetticks) {
|
||||
//printf("Clock catchup, elapsed=%d, target=%d, ticks=%d\n", elapsedms, targetticks, ticks);
|
||||
devpoll[device] = 100; /* behind, so catch-up */
|
||||
} else {
|
||||
#if 0
|
||||
if (ticks%1000 == 0)
|
||||
printf("Clock check: target=%d, ticks=%d\n", targetticks, ticks);
|
||||
#endif
|
||||
SETCLKPOLL;
|
||||
if (ticks > targetticks)
|
||||
devpoll[device] = devpoll[device]*2;
|
||||
}
|
||||
} else {
|
||||
devpoll[device] = 100; /* couldn't interrupt, try again soon */
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user