[Simh] [Simh-dev] Beautiful theory meets ugly fact

Mark Pizzolato mark at infocomm.com
Thu Sep 7 09:34:57 EDT 2006


--- Bob Supnik <bob at supnik.org> wrote:

> My trial implementation of idle for the PDP-11 seemed to work, but 
> there was one peculiar effect: some of the typeouts from the 
> operating system suddenly started having noticeable pauses between 
> characters.  Since the timeout for the console output was far
> shorter 
> than a calibrated millisecond ever should be, this made no sense.
> 
> I dumped the calibrated clock values and sure enough, with idle on,
> 
> instructions per msec dropped from 70,000 to around 80, less than
> the 
> console output delay.  This made no sense, unless the waits being 
> done by idle were completely screwing up clock calibration.
> 
> So I wrote a quick test program and discovered that, under Windoze,
> 
> the basic clock tick is 15msec and change, not 1msec.  This is 
> confirmed by various postings on the Web.  It's even worse under 
> early versions of (95 and 98), where the clock tick was on a 55msec
> 
> interval.  So the attempts to wait for 1-10 msec were all failing, 
> and the clock calibration values were getting badly skewed in order
> 
> to try to compensate.
> 
> With a minimum 15msec wait under Windoze, the notion of waiting
> until 
> the next simulated event won't work, since on the VAX, the clock 
> ticks every 10msec.  The distortions introduced by WIndoze' long
> wait 
> in fact cause clock calibration to fail, and the simulator won't
> keep 
> accurate time.
> 
> Back to the drawing boards.

It is not as bad as it may seem.

When I did this a couple of years ago, I made the same observation. 
I noticed that on some systems the windows system tick was 10ms and
on others it was 15ms.  This difference suggested that I might be
able to influence it.  As it turns out, windows has a user
controllable clock tick.  It can dynamically be set down to as low as
1ms.

You might want to try the attached code which has been working for me
for several years.

On windows (Visual Studio or MingW), you need to link with mmlib,
which means you add -lwinmm to the LDFLAGS in your makefile.

The attached sim_timer.h and sim_timer.c provide the generic timer
and waiting plumbing, while the individual simulator (say vax_cpu.c)
has the following code:

#define	YIELD()		((cpu_unit.flags & UNIT_IDLEYIELD) ? \
				sim_yield_until_event (clk_tps,	TMR_CLK) : 0)

where UNIT_IDLEYIELD is a flag enabling yielding, and YIELD() is
called by the instruction implementation when it has been determined
that the system is idle.  For example:

case TSTL:
	CC_IIZZ_L (op0);				/* set cc's */
	if ((cc == CC_Z) &&
	    (((PSL_GETIPL (PSL) == 0x1) && (PSL&PSL_IS)) || /* NetBSD IPL 1
on Interrupt stack */
             ((PSL_GETIPL (PSL) == 0x0) && (fault_PC&0x80000000) &&
((PC-fault_PC) == 6) && ((fault_PC&0x7fffffff) < 0x4000)))) /*
Quasijarus IPL 0 in system space */
            YIELD();   /* BSD Idle Loop */
	break;

and

case BRB:
	BRANCHB (brdisp);				/* branch  */
	if (PC == fault_PC) 
		if (PSL_GETIPL (PSL) == 0x1F) ABORT (STOP_LOOP);
		else YIELD();		/* Vanilla spin Idle Loop */
	break;

case BRW:
	BRANCHW (brdisp);				/* branch */
	if (PC == fault_PC) 
		if (PSL_GETIPL (PSL) == 0x1F) ABORT (STOP_LOOP);
		else YIELD();		/* Vanilla spin Idle Loop */
	break;

and

case BBS:
	if (op_bb_n (opnd, acc)) { 
		BRANCHB (brdisp);			/* br if bit set */
		if ((PSL_GETIPL (PSL) == 0x3) && (PSL&PSL_IS))
                    YIELD(); } /* VMS Idle Loop IPL 3 on Interrupt
stack */
	break;

and

case MFPR:
	r = op_mfpr (opnd);
	WRITE_L (r);
	CC_IIZP_L (r);
	if ((opnd[0] ==	MT_RXCS) &&
	    ((r&CSR_DONE) == 0) &&	
	    (fault_PC == 0x20043740))		/* Boot	ROM Character Prompt */
		YIELD();
	break;

------

in scp.c, the following is used for sim_process_event:

t_stat sim_process_event (void)
{
UNIT *uptr;
t_stat reason;

if (stop_cpu) return SCPE_STOP;				/* stop CPU? */
if (sim_clock_queue == NULL) {				/* queue empty? */
	UPDATE_SIM_TIME (noqueue_time);			/* update sim time */
	sim_interval +=	NOQUEUE_WAIT;			/* flag	queue empty */
	noqueue_time +=	NOQUEUE_WAIT;
	return SCPE_OK;  }
UPDATE_SIM_TIME (sim_clock_queue->time);		/* update sim time */
do {	uptr = sim_clock_queue;				/* get first */
	sim_clock_queue = uptr->next;			/* remove first */
	uptr->next = NULL;				/* hygiene */
	uptr->time = 0;
	if (sim_clock_queue != NULL) sim_interval += sim_clock_queue->time;
	else sim_interval += NOQUEUE_WAIT, noqueue_time += NOQUEUE_WAIT;
	if (uptr->action != NULL) reason = uptr->action (uptr);
	else reason = SCPE_OK;
   } while ((reason == SCPE_OK) && (sim_interval <= 0));

/* Empty queue forces sim_interval != 0 */

return reason;
}


-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: sim_timer.c
URL: <http://mailman.trailing-edge.com/pipermail/simh/attachments/20060907/ba30aaec/attachment-0003.c>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: sim_timer.h
URL: <http://mailman.trailing-edge.com/pipermail/simh/attachments/20060907/ba30aaec/attachment-0003.h>


More information about the Simh mailing list