Resolved a problem with the original timer implementation, where a call to setTimer() made in the middle of a CPU burst would not properly account for cycles already executed as part of the current burst

This commit is contained in:
Jeff Parsons 2016-10-12 22:08:45 -07:00 committed by Jeff Parsons
commit 8bb978d7a9
7 changed files with 423 additions and 406 deletions

View file

@ -973,7 +973,13 @@ CPU8080.prototype.setTimer = function(iTimer, ms, fReset)
if (iTimer >= 0 && iTimer < this.aTimers.length) {
if (fReset || this.aTimers[iTimer][0] < 0) {
nCycles = this.getMSCycles(ms);
this.aTimers[iTimer][0] = nCycles;
/*
* We must now confront the following problem: if the CPU is currently executing a burst of cycles,
* the number of cycles it has executed in that burst so far must NOT be charged against the cycle
* timeout we're about to set. The simplest way to resolve that is to immediately call endBurst()
* and bias the above cycle timeout by the number of cycles that the burst executed.
*/
this.aTimers[iTimer][0] = nCycles + this.endBurst();
}
}
return nCycles;
@ -1036,14 +1042,18 @@ CPU8080.prototype.updateTimers = function(nCycles)
};
/**
* endBurst()
* endBurst(fReset)
*
* @this {CPU8080}
* @param {boolean} [fReset]
* @return {number} (number of cycles executed in the most recent burst)
*/
CPU8080.prototype.endBurst = function()
CPU8080.prototype.endBurst = function(fReset)
{
this.nBurstCycles -= this.nStepCycles;
var nCycles = this.nBurstCycles -= this.nStepCycles;
this.nStepCycles = 0;
if (fReset) this.nBurstCycles = 0;
return nCycles;
};
/**
@ -1071,35 +1081,34 @@ CPU8080.prototype.runCPU = function(fUpdateFocus)
try {
do {
/*
* nCyclesPerBurst is how many cycles we WANT to run on each iteration of stepCPU(), and may
* be as HIGH as nCyclesPerYield, but it may be significantly less. getBurstCycles() will adjust
* nCyclesPerBurst downward if any CPU timers need to fire during the next burst.
* nCycles is how many cycles we WANT to run on each iteration of stepCPU(), and may be as
* HIGH as nCyclesPerYield, but it may be significantly less. getBurstCycles() will adjust
* nCycles downward if any CPU timers need to fire during the next burst.
*/
var nCyclesPerBurst = this.getBurstCycles(this.flags.checksum? 1 : this.nCyclesPerYield);
var nCycles = this.getBurstCycles(this.flags.checksum? 1 : this.nCyclesPerYield);
/*
* Execute the burst.
*/
this.stepCPU(nCyclesPerBurst);
this.stepCPU(nCycles);
/*
* nCycles is how many cycles stepCPU() actually ran (nBurstCycles less any remaining nStepCycles).
* Terminate the burst, returning the number of cycles that stepCPU() actually ran.
*/
var nCycles = this.nBurstCycles - this.nStepCycles;
/*
* Update any/all timers, firing those whose cycle countdowns have reached (or dropped below) zero.
*/
this.updateTimers(nCycles);
nCycles = this.endBurst(true);
/*
* Add nCycles to nCyclesThisRun, as well as nRunCycles (the cycle count since the CPU first started).
*/
this.nCyclesThisRun += nCycles;
this.nRunCycles += nCycles;
this.addCycles(0, true);
this.updateChecksum(nCycles);
/*
* Update any/all timers, firing those whose cycle countdowns have reached (or dropped below) zero.
*/
this.updateTimers(nCycles);
this.nCyclesNextYield -= nCycles;
if (this.nCyclesNextYield <= 0) {
this.nCyclesNextYield += this.nCyclesPerYield;