Immunized cursor blink rate from changes to CPU speed

This commit is contained in:
Jeff Parsons 2016-08-23 12:52:11 -07:00
commit c1b34a87ed
5 changed files with 219 additions and 201 deletions

View file

@ -79,21 +79,21 @@ function CPU8080(parmsCPU, nCyclesDefault)
var nMultiplier = parmsCPU['multiplier'] || 1;
this.aCounts = {};
this.aCounts.nCyclesPerSecond = nCycles;
this.aCounts.nVideoUpdates = 0;
this.counts = {};
this.counts.nCyclesPerSecond = nCycles;
this.counts.nVideoUpdates = 0;
/*
* nCyclesMultiplier replaces the old "speed" variable (0, 1, 2) and eliminates the need for
* the constants (SPEED_SLOW, SPEED_FAST and SPEED_MAX). The UI simply doubles the multiplier
* until we've exceeded the host's speed limit and then starts the multiplier over at 1.
*/
this.aCounts.nCyclesMultiplier = nMultiplier;
this.aCounts.mhzDefault = Math.round(this.aCounts.nCyclesPerSecond / 10000) / 100;
this.counts.nCyclesMultiplier = nMultiplier;
this.counts.mhzDefault = Math.round(this.counts.nCyclesPerSecond / 10000) / 100;
/*
* TODO: Take care of this with an initial setSpeed() call instead?
*/
this.aCounts.mhzTarget = this.aCounts.mhzDefault * this.aCounts.nCyclesMultiplier;
this.counts.mhzTarget = this.counts.mhzDefault * this.counts.nCyclesMultiplier;
/*
* We add a number of flags to the set initialized by Component
@ -117,10 +117,10 @@ function CPU8080(parmsCPU, nCyclesDefault)
* and call resetChecksum().
*/
this.flags.fChecksum = false;
this.aCounts.nChecksum = this.aCounts.nCyclesChecksumNext = 0;
this.aCounts.nCyclesChecksumStart = parmsCPU["csStart"];
this.aCounts.nCyclesChecksumInterval = parmsCPU["csInterval"];
this.aCounts.nCyclesChecksumStop = parmsCPU["csStop"];
this.counts.nChecksum = this.counts.nCyclesChecksumNext = 0;
this.counts.nCyclesChecksumStart = parmsCPU["csStart"];
this.counts.nCyclesChecksumInterval = parmsCPU["csInterval"];
this.counts.nCyclesChecksumStop = parmsCPU["csStop"];
/*
* Array of countdown timers managed by addTimer() and setTimer().
@ -141,16 +141,16 @@ Component.subclass(CPU8080);
* calcCycles(), which uses the nCyclesPerSecond passed to the constructor as a starting
* point and computes the following variables:
*
* this.aCounts.nCyclesPerYield (this.aCounts.nCyclesPerSecond / CPU8080.YIELDS_PER_SECOND)
* this.aCounts.nCyclesPerVideoUpdate (this.aCounts.nCyclesPerSecond / CPU8080.VIDEO_UPDATES_PER_SECOND)
* this.aCounts.nCyclesPerStatusUpdate (this.aCounts.nCyclesPerSecond / CPU8080.STATUS_UPDATES_PER_SECOND)
* this.counts.nCyclesPerYield (this.counts.nCyclesPerSecond / CPU8080.YIELDS_PER_SECOND)
* this.counts.nCyclesPerVideoUpdate (this.counts.nCyclesPerSecond / CPU8080.VIDEO_UPDATES_PER_SECOND)
* this.counts.nCyclesPerStatusUpdate (this.counts.nCyclesPerSecond / CPU8080.STATUS_UPDATES_PER_SECOND)
*
* The above variables are also multiplied by any cycle multiplier in effect, via setSpeed(),
* and then they're used to initialize another set of variables for each runCPU() iteration:
*
* this.aCounts.nCyclesNextYield <= this.aCounts.nCyclesPerYield
* this.aCounts.nCyclesNextVideoUpdate <= this.aCounts.nCyclesPerVideoUpdate
* this.aCounts.nCyclesNextStatusUpdate <= this.aCounts.nCyclesPerStatusUpdate
* this.counts.nCyclesNextYield <= this.counts.nCyclesPerYield
* this.counts.nCyclesNextVideoUpdate <= this.counts.nCyclesPerVideoUpdate
* this.counts.nCyclesNextStatusUpdate <= this.counts.nCyclesPerStatusUpdate
*/
CPU8080.YIELDS_PER_SECOND = 30;
CPU8080.VIDEO_UPDATES_PER_SECOND = 60;
@ -207,7 +207,7 @@ CPU8080.prototype.initBus = function(cmp, bus, cpu, dbg)
*/
CPU8080.prototype.reset = function()
{
this.aCounts.nVideoUpdates = 0;
this.counts.nVideoUpdates = 0;
};
/**
@ -375,16 +375,16 @@ CPU8080.prototype.getChecksum = function()
*/
CPU8080.prototype.resetChecksum = function()
{
if (this.aCounts.nCyclesChecksumStart === undefined) this.aCounts.nCyclesChecksumStart = 0;
if (this.aCounts.nCyclesChecksumInterval === undefined) this.aCounts.nCyclesChecksumInterval = -1;
if (this.aCounts.nCyclesChecksumStop === undefined) this.aCounts.nCyclesChecksumStop = -1;
this.flags.fChecksum = (this.aCounts.nCyclesChecksumStart >= 0 && this.aCounts.nCyclesChecksumInterval > 0);
if (this.counts.nCyclesChecksumStart === undefined) this.counts.nCyclesChecksumStart = 0;
if (this.counts.nCyclesChecksumInterval === undefined) this.counts.nCyclesChecksumInterval = -1;
if (this.counts.nCyclesChecksumStop === undefined) this.counts.nCyclesChecksumStop = -1;
this.flags.fChecksum = (this.counts.nCyclesChecksumStart >= 0 && this.counts.nCyclesChecksumInterval > 0);
if (this.flags.fChecksum) {
this.aCounts.nChecksum = 0;
this.aCounts.nCyclesChecksumNext = this.aCounts.nCyclesChecksumStart - this.nTotalCycles;
this.counts.nChecksum = 0;
this.counts.nCyclesChecksumNext = this.counts.nCyclesChecksumStart - this.nTotalCycles;
/*
* this.aCounts.nCyclesChecksumNext = this.aCounts.nCyclesChecksumStart + this.aCounts.nCyclesChecksumInterval -
* (this.nTotalCycles % this.aCounts.nCyclesChecksumInterval);
* this.counts.nCyclesChecksumNext = this.counts.nCyclesChecksumStart + this.counts.nCyclesChecksumInterval -
* (this.nTotalCycles % this.counts.nCyclesChecksumInterval);
*/
return true;
}
@ -409,15 +409,15 @@ CPU8080.prototype.updateChecksum = function(nCycles)
* Get a 32-bit summation of the current CPU state and add it to our running 32-bit checksum
*/
var fDisplay = false;
this.aCounts.nChecksum = (this.aCounts.nChecksum + this.getChecksum())|0;
this.aCounts.nCyclesChecksumNext -= nCycles;
if (this.aCounts.nCyclesChecksumNext <= 0) {
this.aCounts.nCyclesChecksumNext += this.aCounts.nCyclesChecksumInterval;
this.counts.nChecksum = (this.counts.nChecksum + this.getChecksum())|0;
this.counts.nCyclesChecksumNext -= nCycles;
if (this.counts.nCyclesChecksumNext <= 0) {
this.counts.nCyclesChecksumNext += this.counts.nCyclesChecksumInterval;
fDisplay = true;
}
if (this.aCounts.nCyclesChecksumStop >= 0) {
if (this.aCounts.nCyclesChecksumStop <= this.getCycles()) {
this.aCounts.nCyclesChecksumInterval = this.aCounts.nCyclesChecksumStop = -1;
if (this.counts.nCyclesChecksumStop >= 0) {
if (this.counts.nCyclesChecksumStop <= this.getCycles()) {
this.counts.nCyclesChecksumInterval = this.counts.nCyclesChecksumStop = -1;
this.resetChecksum();
this.stopCPU();
fDisplay = true;
@ -438,7 +438,7 @@ CPU8080.prototype.updateChecksum = function(nCycles)
*/
CPU8080.prototype.displayChecksum = function()
{
this.println(this.getCycles() + " cycles: " + "checksum=" + str.toHex(this.aCounts.nChecksum));
this.println(this.getCycles() + " cycles: " + "checksum=" + str.toHex(this.counts.nChecksum));
};
/**
@ -522,7 +522,7 @@ CPU8080.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
case "setSpeed":
this.bindings[sBinding] = control;
control.onclick = function onClickSetSpeed() {
cpu.setSpeed(cpu.aCounts.nCyclesMultiplier << 1, true);
cpu.setSpeed(cpu.counts.nCyclesMultiplier << 1, true);
};
control.textContent = this.getSpeedTarget();
fBound = true;
@ -622,26 +622,26 @@ CPU8080.prototype.calcCycles = function(fRecalc)
*/
var vMultiplier = 1;
if (fRecalc) {
if (this.aCounts.nCyclesMultiplier > 1 && this.aCounts.mhz) {
vMultiplier = (this.aCounts.mhz / this.aCounts.mhzDefault);
if (this.counts.nCyclesMultiplier > 1 && this.counts.mhz) {
vMultiplier = (this.counts.mhz / this.counts.mhzDefault);
}
}
this.aCounts.msPerYield = Math.round(1000 / CPU8080.YIELDS_PER_SECOND);
this.aCounts.nCyclesPerBurst = Math.floor(this.aCounts.nCyclesPerSecond / nMostUpdatesPerSecond * vMultiplier);
this.aCounts.nCyclesPerYield = Math.floor(this.aCounts.nCyclesPerSecond / CPU8080.YIELDS_PER_SECOND * vMultiplier);
this.aCounts.nCyclesPerVideoUpdate = Math.floor(this.aCounts.nCyclesPerSecond / this.refreshRate * vMultiplier);
this.aCounts.nCyclesPerStatusUpdate = Math.floor(this.aCounts.nCyclesPerSecond / CPU8080.STATUS_UPDATES_PER_SECOND * vMultiplier);
this.counts.msPerYield = Math.round(1000 / CPU8080.YIELDS_PER_SECOND);
this.counts.nCyclesPerBurst = Math.floor(this.counts.nCyclesPerSecond / nMostUpdatesPerSecond * vMultiplier);
this.counts.nCyclesPerYield = Math.floor(this.counts.nCyclesPerSecond / CPU8080.YIELDS_PER_SECOND * vMultiplier);
this.counts.nCyclesPerVideoUpdate = Math.floor(this.counts.nCyclesPerSecond / this.refreshRate * vMultiplier);
this.counts.nCyclesPerStatusUpdate = Math.floor(this.counts.nCyclesPerSecond / CPU8080.STATUS_UPDATES_PER_SECOND * vMultiplier);
/*
* And initialize "next" yield, video update, and status update cycle "threshold" counters to those "per" values
*/
if (!fRecalc) {
this.aCounts.nCyclesNextYield = this.aCounts.nCyclesPerYield;
this.aCounts.nCyclesNextVideoUpdate = this.aCounts.nCyclesPerVideoUpdate;
this.aCounts.nCyclesNextStatusUpdate = this.aCounts.nCyclesPerStatusUpdate;
this.counts.nCyclesNextYield = this.counts.nCyclesPerYield;
this.counts.nCyclesNextVideoUpdate = this.counts.nCyclesPerVideoUpdate;
this.counts.nCyclesNextStatusUpdate = this.counts.nCyclesPerStatusUpdate;
}
this.aCounts.nCyclesRecalc = 0;
this.counts.nCyclesRecalc = 0;
};
/**
@ -664,11 +664,11 @@ CPU8080.prototype.calcCycles = function(fRecalc)
CPU8080.prototype.getCycles = function(fScaled)
{
var nCycles = this.nTotalCycles + this.nRunCycles + this.nBurstCycles - this.nStepCycles;
if (fScaled && this.aCounts.nCyclesMultiplier > 1 && this.aCounts.mhz > this.aCounts.mhzDefault) {
if (fScaled && this.counts.nCyclesMultiplier > 1 && this.counts.mhz > this.counts.mhzDefault) {
/*
* We could scale the current cycle count by the current effective speed (this.aCounts.mhz); eg:
* We could scale the current cycle count by the current effective speed (this.counts.mhz); eg:
*
* nCycles = Math.round(nCycles / (this.aCounts.mhz / this.aCounts.mhzDefault));
* nCycles = Math.round(nCycles / (this.counts.mhz / this.counts.mhzDefault));
*
* but that speed will fluctuate somewhat: large fluctuations at first, but increasingly smaller
* fluctuations after each burst of instructions that runCPU() executes.
@ -683,7 +683,7 @@ CPU8080.prototype.getCycles = function(fScaled)
* interface allows any value, as does the CPU "multiplier" parmsCPU property (from the machine's
* XML file).
*/
nCycles = Math.round(nCycles / this.aCounts.nCyclesMultiplier);
nCycles = Math.round(nCycles / this.counts.nCyclesMultiplier);
}
return nCycles;
};
@ -698,7 +698,7 @@ CPU8080.prototype.getCycles = function(fScaled)
*/
CPU8080.prototype.getCyclesPerSecond = function()
{
return this.aCounts.nCyclesPerSecond;
return this.counts.nCyclesPerSecond;
};
/**
@ -712,7 +712,7 @@ CPU8080.prototype.getCyclesPerSecond = function()
*/
CPU8080.prototype.resetCycles = function()
{
this.aCounts.mhz = 0;
this.counts.mhz = 0;
this.nTotalCycles = this.nRunCycles = this.nBurstCycles = this.nStepCycles = 0;
this.resetChecksum();
this.setSpeed(1);
@ -726,7 +726,7 @@ CPU8080.prototype.resetCycles = function()
*/
CPU8080.prototype.getSpeed = function()
{
return this.aCounts.nCyclesMultiplier;
return this.counts.nCyclesMultiplier;
};
/**
@ -740,7 +740,7 @@ CPU8080.prototype.getSpeedCurrent = function()
/*
* TODO: Has toFixed() been "fixed" in all browsers (eg, IE) to return a rounded value now?
*/
return ((this.flags.fRunning && this.aCounts.mhz)? (this.aCounts.mhz.toFixed(2) + "Mhz") : "Stopped");
return ((this.flags.fRunning && this.counts.mhz)? (this.counts.mhz.toFixed(2) + "Mhz") : "Stopped");
};
/**
@ -754,7 +754,7 @@ CPU8080.prototype.getSpeedTarget = function()
/*
* TODO: Has toFixed() been "fixed" in all browsers (eg, IE) to return a rounded value now?
*/
return this.aCounts.mhzTarget.toFixed(2) + "Mhz";
return this.counts.mhzTarget.toFixed(2) + "Mhz";
};
/**
@ -778,15 +778,15 @@ CPU8080.prototype.setSpeed = function(nMultiplier, fUpdateFocus)
/*
* If we haven't reached 80% (0.8) of the current target speed, revert to a multiplier of one (1).
*/
if (this.aCounts.mhz / this.aCounts.mhzTarget < 0.8) {
if (this.counts.mhz / this.counts.mhzTarget < 0.8) {
nMultiplier = 1;
} else {
fSuccess = true;
}
this.aCounts.nCyclesMultiplier = nMultiplier;
var mhz = this.aCounts.mhzDefault * this.aCounts.nCyclesMultiplier;
if (this.aCounts.mhzTarget != mhz) {
this.aCounts.mhzTarget = mhz;
this.counts.nCyclesMultiplier = nMultiplier;
var mhz = this.counts.mhzDefault * this.counts.nCyclesMultiplier;
if (this.counts.mhzTarget != mhz) {
this.counts.mhzTarget = mhz;
var sSpeed = this.getSpeedTarget();
var controlSpeed = this.bindings["setSpeed"];
if (controlSpeed) controlSpeed.textContent = sSpeed;
@ -796,8 +796,8 @@ CPU8080.prototype.setSpeed = function(nMultiplier, fUpdateFocus)
}
this.addCycles(this.nRunCycles);
this.nRunCycles = 0;
this.aCounts.msStartRun = usr.getTime();
this.aCounts.msEndThisRun = 0;
this.counts.msStartRun = usr.getTime();
this.counts.msEndThisRun = 0;
this.calcCycles();
return fSuccess;
};
@ -812,7 +812,7 @@ CPU8080.prototype.setSpeed = function(nMultiplier, fUpdateFocus)
CPU8080.prototype.calcSpeed = function(nCycles, msElapsed)
{
if (msElapsed) {
this.aCounts.mhz = Math.round(nCycles / (msElapsed * 10)) / 100;
this.counts.mhz = Math.round(nCycles / (msElapsed * 10)) / 100;
if (msElapsed >= 86400000) {
this.nTotalCycles = 0;
this.setSpeed(); // reset all counters once per day so that we never have to worry about overflow
@ -827,11 +827,11 @@ CPU8080.prototype.calcSpeed = function(nCycles, msElapsed)
*/
CPU8080.prototype.calcStartTime = function()
{
if (this.aCounts.nCyclesRecalc >= this.aCounts.nCyclesPerSecond) {
if (this.counts.nCyclesRecalc >= this.counts.nCyclesPerSecond) {
this.calcCycles(true);
}
this.aCounts.nCyclesThisRun = 0;
this.aCounts.msStartThisRun = usr.getTime();
this.counts.nCyclesThisRun = 0;
this.counts.msStartThisRun = usr.getTime();
/*
* Try to detect situations where the browser may have throttled us, such as when the user switches
@ -858,19 +858,19 @@ CPU8080.prototype.calcStartTime = function()
* to hit its target speed, since you would expect any instruction that displays a message to be an
* EXTREMELY slow instruction.
*/
if (this.aCounts.msEndThisRun) {
var msDelta = this.aCounts.msStartThisRun - this.aCounts.msEndThisRun;
if (msDelta > this.aCounts.msPerYield) {
if (this.counts.msEndThisRun) {
var msDelta = this.counts.msStartThisRun - this.counts.msEndThisRun;
if (msDelta > this.counts.msPerYield) {
if (MAXDEBUG) this.println("large time delay: " + msDelta + "ms");
this.aCounts.msStartRun += msDelta;
this.counts.msStartRun += msDelta;
/*
* Bumping msStartRun forward should NEVER cause it to exceed msStartThisRun; however, just
* in case, I make absolutely sure it cannot happen, since doing so could result in negative
* speed calculations.
*/
this.assert(this.aCounts.msStartRun <= this.aCounts.msStartThisRun);
if (this.aCounts.msStartRun > this.aCounts.msStartThisRun) {
this.aCounts.msStartRun = this.aCounts.msStartThisRun;
this.assert(this.counts.msStartRun <= this.counts.msStartThisRun);
if (this.counts.msStartRun > this.counts.msStartThisRun) {
this.counts.msStartRun = this.counts.msStartThisRun;
}
}
}
@ -884,47 +884,47 @@ CPU8080.prototype.calcStartTime = function()
*/
CPU8080.prototype.calcRemainingTime = function()
{
this.aCounts.msEndThisRun = usr.getTime();
this.counts.msEndThisRun = usr.getTime();
var msYield = this.aCounts.msPerYield;
if (this.aCounts.nCyclesThisRun) {
var msYield = this.counts.msPerYield;
if (this.counts.nCyclesThisRun) {
/*
* Normally, we would assume we executed a full quota of work over msPerYield, but since the CPU
* now has the option of calling yieldCPU(), that might not be true. If nCyclesThisRun is correct, then
* the ratio of nCyclesThisRun/nCyclesPerYield should represent the percentage of work we performed,
* and so applying that percentage to msPerYield should give us a better estimate of work vs. time.
*/
msYield = Math.round(msYield * this.aCounts.nCyclesThisRun / this.aCounts.nCyclesPerYield);
msYield = Math.round(msYield * this.counts.nCyclesThisRun / this.counts.nCyclesPerYield);
}
var msElapsedThisRun = this.aCounts.msEndThisRun - this.aCounts.msStartThisRun;
var msElapsedThisRun = this.counts.msEndThisRun - this.counts.msStartThisRun;
var msRemainsThisRun = msYield - msElapsedThisRun;
/*
* We could pass only "this run" results to calcSpeed():
*
* nCycles = this.aCounts.nCyclesThisRun;
* nCycles = this.counts.nCyclesThisRun;
* msElapsed = msElapsedThisRun;
*
* but it seems preferable to use longer time periods and hopefully get a more accurate speed.
*
* Also, if msRemainsThisRun >= 0 && this.aCounts.nCyclesMultiplier == 1, we could pass these results instead:
* Also, if msRemainsThisRun >= 0 && this.counts.nCyclesMultiplier == 1, we could pass these results instead:
*
* nCycles = this.aCounts.nCyclesThisRun;
* msElapsed = this.aCounts.msPerYield;
* nCycles = this.counts.nCyclesThisRun;
* msElapsed = this.counts.msPerYield;
*
* to insure that we display a smooth, constant N Mhz. But for now, I prefer seeing any fluctuations.
*/
var nCycles = this.nRunCycles;
var msElapsed = this.aCounts.msEndThisRun - this.aCounts.msStartRun;
var msElapsed = this.counts.msEndThisRun - this.counts.msStartRun;
if (MAXDEBUG && msRemainsThisRun < 0 && this.aCounts.nCyclesMultiplier > 1) {
if (MAXDEBUG && msRemainsThisRun < 0 && this.counts.nCyclesMultiplier > 1) {
this.println("warning: updates @" + msElapsedThisRun + "ms (prefer " + Math.round(msYield) + "ms)");
}
this.calcSpeed(nCycles, msElapsed);
if (msRemainsThisRun < 0 || this.aCounts.mhz < this.aCounts.mhzTarget) {
if (msRemainsThisRun < 0 || this.counts.mhz < this.counts.mhzTarget) {
/*
* If the last burst took MORE time than we allotted (ie, it's taking more than 1 second to simulate
* nCyclesPerSecond), all we can do is yield for as little time as possible (ie, 0ms) and hope that the
@ -937,13 +937,13 @@ CPU8080.prototype.calcRemainingTime = function()
* Last but not least, update nCyclesRecalc, so that when runCPU() starts up again and calls calcStartTime(),
* it'll be ready to decide if calcCycles() should be called again.
*/
this.aCounts.nCyclesRecalc += this.aCounts.nCyclesThisRun;
this.counts.nCyclesRecalc += this.counts.nCyclesThisRun;
if (DEBUG && this.messageEnabled(Messages8080.LOG) && msRemainsThisRun) {
this.log("calcRemainingTime: " + msRemainsThisRun + "ms to sleep after " + this.aCounts.msEndThisRun + "ms");
this.log("calcRemainingTime: " + msRemainsThisRun + "ms to sleep after " + this.counts.msEndThisRun + "ms");
}
this.aCounts.msEndThisRun += msRemainsThisRun;
this.counts.msEndThisRun += msRemainsThisRun;
return msRemainsThisRun;
};
@ -980,9 +980,9 @@ CPU8080.prototype.addTimer = function(callBack)
* This is preferred over JavaScript's setTimeout(), because all our timers are effectively paused when
* the CPU is paused (eg, when the Debugger halts execution). Moreover, setTimeout() handlers only run after
* runCPU() yields, which is far too granular for some components (eg, when the SerialPort tries to simulate
* receiver interrupts at 9600 baud).
* interrupts at 9600 baud).
*
* Ideally, the only function that would use setTimeout() is runCPU(), while the rest of the components would
* Ideally, the only function that would use setTimeout() is runCPU(), while the rest of the components
* use setTimer(); however, due to legacy code (ie, code that predates these functions) and/or laziness,
* that's currently not the case. TODO: Fix.
*
@ -995,24 +995,36 @@ CPU8080.prototype.setTimer = function(iTimer, ms)
{
var nCycles = -1;
if (iTimer >= 0 && iTimer < this.aTimers.length) {
nCycles = (this.aCounts.nCyclesPerSecond * this.aCounts.nCyclesMultiplier) / 1000 * ms;
nCycles = this.getCyclesMS(ms);
this.aTimers[iTimer][0] = nCycles;
}
return nCycles;
};
/**
* getTimerBurst(nCycles)
* getCyclesMS(ms)
*
* Used by runCPU() to either accept or shorten the current burst if any timers need to fire soon.
* @this {CPU8080}
* @param {number} ms
* @return {number} number of corresponding cycles
*/
CPU8080.prototype.getCyclesMS = function(ms)
{
return (this.counts.nCyclesPerSecond * this.counts.nCyclesMultiplier) / 1000 * ms;
};
/**
* getCyclesBurst(nCycles)
*
* Used by runCPU() to get min(nCycles,[timer cycle counts])
*
* @this {CPU8080}
* @param {number} nCycles (number of cycles about to execute)
* @return {number} (either nCycles or less if a timer needs to fire)
*/
CPU8080.prototype.getTimerBurst = function(nCycles)
CPU8080.prototype.getCyclesBurst = function(nCycles)
{
for (var i = 0; i < this.aTimers.length; i++) {
for (var i = this.aTimers.length - 1; i >= 0; i--) {
var timer = this.aTimers[i];
if (timer[0] < 0) continue;
if (nCycles > timer[0]) {
@ -1034,7 +1046,7 @@ CPU8080.prototype.getTimerBurst = function(nCycles)
*/
CPU8080.prototype.updateTimers = function(nCycles)
{
for (var i = 0; i < this.aTimers.length; i++) {
for (var i = this.aTimers.length - 1; i >= 0; i--) {
var timer = this.aTimers[i];
if (timer[0] < 0) continue;
timer[0] -= nCycles;
@ -1072,12 +1084,12 @@ CPU8080.prototype.runCPU = function(fUpdateFocus)
* nCyclesPerBurst is how many cycles we WANT to run on each iteration of stepCPU(), but it may run
* significantly less (or slightly more, since we can't execute partial instructions).
*/
var nCyclesPerBurst = (this.flags.fChecksum? 1 : this.aCounts.nCyclesPerBurst);
var nCyclesPerBurst = (this.flags.fChecksum? 1 : this.counts.nCyclesPerBurst);
/*
* Adjust nCyclesPerBurst if there are any CPU timers that need to fire within the current burst.
*/
nCyclesPerBurst = this.getTimerBurst(nCyclesPerBurst);
nCyclesPerBurst = this.getCyclesBurst(nCyclesPerBurst);
/*
* Execute the burst.
@ -1097,27 +1109,27 @@ CPU8080.prototype.runCPU = function(fUpdateFocus)
/*
* Add nCycles to nCyclesThisRun, as well as nRunCycles (the cycle count since the CPU first started).
*/
this.aCounts.nCyclesThisRun += nCycles;
this.counts.nCyclesThisRun += nCycles;
this.nRunCycles += nCycles;
this.addCycles(0, true);
this.updateChecksum(nCycles);
this.aCounts.nCyclesNextVideoUpdate -= nCycles;
if (this.aCounts.nCyclesNextVideoUpdate <= 0) {
this.aCounts.nCyclesNextVideoUpdate += this.aCounts.nCyclesPerVideoUpdate;
if (this.cmp) this.cmp.updateVideo(this.aCounts.nVideoUpdates++);
if (this.aCounts.nVideoUpdates > this.refreshRate) this.aCounts.nVideoUpdates = 0;
this.counts.nCyclesNextVideoUpdate -= nCycles;
if (this.counts.nCyclesNextVideoUpdate <= 0) {
this.counts.nCyclesNextVideoUpdate += this.counts.nCyclesPerVideoUpdate;
if (this.cmp) this.cmp.updateVideo(this.counts.nVideoUpdates++);
if (this.counts.nVideoUpdates > this.refreshRate) this.counts.nVideoUpdates = 0;
}
this.aCounts.nCyclesNextStatusUpdate -= nCycles;
if (this.aCounts.nCyclesNextStatusUpdate <= 0) {
this.aCounts.nCyclesNextStatusUpdate += this.aCounts.nCyclesPerStatusUpdate;
this.counts.nCyclesNextStatusUpdate -= nCycles;
if (this.counts.nCyclesNextStatusUpdate <= 0) {
this.counts.nCyclesNextStatusUpdate += this.counts.nCyclesPerStatusUpdate;
if (this.cmp) this.cmp.updateStatus();
}
this.aCounts.nCyclesNextYield -= nCycles;
if (this.aCounts.nCyclesNextYield <= 0) {
this.aCounts.nCyclesNextYield += this.aCounts.nCyclesPerYield;
this.counts.nCyclesNextYield -= nCycles;
if (this.counts.nCyclesNextYield <= 0) {
this.counts.nCyclesNextYield += this.counts.nCyclesPerYield;
break;
}
} while (this.flags.fRunning);
@ -1150,7 +1162,7 @@ CPU8080.prototype.startCPU = function(fUpdateFocus)
* threshold counter.
*/
this.setSpeed();
if (this.cmp) this.cmp.start(this.aCounts.msStartRun, this.getCycles());
if (this.cmp) this.cmp.start(this.counts.msStartRun, this.getCycles());
this.flags.fRunning = true;
this.flags.fStarting = true;
if (this.chipset) this.chipset.start();
@ -1233,7 +1245,7 @@ CPU8080.prototype.updateCPU = function(fForce)
*/
CPU8080.prototype.yieldCPU = function()
{
this.aCounts.nCyclesNextYield = 0; // this will break us out of runCPU(), once we break out of stepCPU()
this.counts.nCyclesNextYield = 0; // this will break us out of runCPU(), once we break out of stepCPU()
this.nBurstCycles -= this.nStepCycles;
this.nStepCycles = 0; // this will break us out of stepCPU()
// if (DEBUG) this.nSnapCycles = this.nBurstCycles;

View file

@ -2465,7 +2465,7 @@ if (DEBUGGER) {
sLine += (nSequence != null? '=' + nSequence.toString() : "");
} else {
var nCycles = this.cpu.getCycles();
sLine += "cycles=" + nCycles.toString() + " cs=" + str.toHex(this.cpu.aCounts.nChecksum);
sLine += "cycles=" + nCycles.toString() + " cs=" + str.toHex(this.cpu.counts.nChecksum);
}
}
return sLine;
@ -3719,11 +3719,11 @@ if (DEBUGGER) {
Debugger8080.prototype.doInfo = function(asArgs)
{
if (DEBUG) {
this.println("msPerYield: " + this.cpu.aCounts.msPerYield);
this.println("nCyclesPerBurst: " + this.cpu.aCounts.nCyclesPerBurst);
this.println("nCyclesPerYield: " + this.cpu.aCounts.nCyclesPerYield);
this.println("nCyclesPerVideoUpdate: " + this.cpu.aCounts.nCyclesPerVideoUpdate);
this.println("nCyclesPerStatusUpdate: " + this.cpu.aCounts.nCyclesPerStatusUpdate);
this.println("msPerYield: " + this.cpu.counts.msPerYield);
this.println("nCyclesPerBurst: " + this.cpu.counts.nCyclesPerBurst);
this.println("nCyclesPerYield: " + this.cpu.counts.nCyclesPerYield);
this.println("nCyclesPerVideoUpdate: " + this.cpu.counts.nCyclesPerVideoUpdate);
this.println("nCyclesPerStatusUpdate: " + this.cpu.counts.nCyclesPerStatusUpdate);
return true;
}
return false;
@ -3974,13 +3974,13 @@ if (DEBUGGER) {
if (asArgs[3] !== undefined) nCycles = +asArgs[3]; // warning: decimal instead of hex conversion
switch (asArgs[2]) {
case "int":
this.cpu.aCounts.nCyclesChecksumInterval = nCycles;
this.cpu.counts.nCyclesChecksumInterval = nCycles;
break;
case "start":
this.cpu.aCounts.nCyclesChecksumStart = nCycles;
this.cpu.counts.nCyclesChecksumStart = nCycles;
break;
case "stop":
this.cpu.aCounts.nCyclesChecksumStop = nCycles;
this.cpu.counts.nCyclesChecksumStop = nCycles;
break;
default:
this.println("unknown cs option");

View file

@ -893,12 +893,12 @@ Keyboard8080.prototype.checkSoftKeysToRelease = function()
* options:
*
* 1) Snapshot the CPU cycle count each time a byte is transmitted (see outVT100UARTStatus()) and then every
* time this is polled, see if the cycle count has exceeded the snapshot value by the necessary threshold
* amount; if we assume 361.69ns per CPU cycle, there are 22 CPU cycles for every 1 LBA4 cycle, and since
* transmission time is supposed to last for 160 LBA4 cycles, that means 22*160 CPU cycles, or 3520 cycles.
* time this is polled, see if the cycle count has exceeded the snapshot value by the necessary threshold;
* if we assume 361.69ns per CPU cycle, there are 22 CPU cycles for every 1 LBA4 cycle, and since transmission
* time is supposed to last for 160 LBA4 cycles, the threshold is 22*160 CPU cycles, or 3520 cycles.
*
* 2) Set a CPU timer using the new setTimer() interface, which can be passed the number of milliseconds to
* wait before firing (in this case, 7945ms).
* wait before firing (in this case, roughly 1.27ms).
*
* 3) Call the ChipSet's getVT100LBA(4) function for the state of the simulated LBA4, and count 160 LBA4
* transitions; however, that would be the worst solution, because there's no guarantee that the firmware's
@ -912,7 +912,12 @@ Keyboard8080.prototype.checkSoftKeysToRelease = function()
Keyboard8080.prototype.isVT100TransmitterReady = function()
{
if (this.fVT100UARTBusy) {
if (this.cpu.getCycles() >= this.nVT100UARTCycleSnap + 3520) {
/*
* NOTE: getCyclesMS(1.2731488) should work out to 3520 cycles for a CPU clocked at 361.69ns per cycle,
* which is roughly 2.76Mhz. We could just hard-code 3520 instead of calling getCyclesMS(), but this helps
* maintain a reasonable blink rate for the cursor even when the user cranks up the CPU speed.
*/
if (this.cpu.getCycles() >= this.nVT100UARTCycleSnap + this.cpu.getCyclesMS(1.2731488)) {
this.fVT100UARTBusy = false;
}
}