Smoothed out PCx86 dynamic CPU speed recalculation by no longer truncating the current cycle multiplier
This commit is contained in:
parent
591d6b85d5
commit
7f973a03b9
23 changed files with 1351 additions and 1308 deletions
|
|
@ -891,8 +891,8 @@ class CPU8080 extends Component {
|
|||
*/
|
||||
this.nCyclesRecalc += this.nCyclesThisRun;
|
||||
|
||||
if (DEBUG && this.messageEnabled(Messages8080.LOG) && msRemainsThisRun) {
|
||||
this.log("calcRemainingTime: " + msRemainsThisRun + "ms to sleep after " + this.msEndThisRun + "ms");
|
||||
if (DEBUG && this.messageEnabled(Messages8080.CPU) && msRemainsThisRun) {
|
||||
this.printMessage("calcRemainingTime: " + msRemainsThisRun + "ms to sleep after " + this.msEndThisRun + "ms");
|
||||
}
|
||||
|
||||
this.msEndThisRun += msRemainsThisRun;
|
||||
|
|
|
|||
|
|
@ -155,8 +155,8 @@ class Debugger8080 extends Debugger {
|
|||
this.sInitCommands = parmsDbg['commands'];
|
||||
|
||||
/*
|
||||
* Make it easier to access Debugger8080 commands from an external REPL (eg, the WebStorm
|
||||
* "live" console window); eg:
|
||||
* Make it easier to access Debugger commands from an external REPL, like the WebStorm "live" console
|
||||
* window; eg:
|
||||
*
|
||||
* pc8080('r')
|
||||
* pc8080('dw 0:0')
|
||||
|
|
@ -769,7 +769,7 @@ class Debugger8080 extends Debugger {
|
|||
this.dbg = this;
|
||||
this.bitsMessage = this.bitsWarning = Messages8080.WARN;
|
||||
this.sMessagePrev = null;
|
||||
this.aMessageBuffer = [];
|
||||
this.aMessageLog = [];
|
||||
/*
|
||||
* Internally, we use "key" instead of "keys", since the latter is a method on JavasScript objects,
|
||||
* but externally, we allow the user to specify "keys"; "kbd" is also allowed as shorthand for "keyboard".
|
||||
|
|
@ -1016,8 +1016,8 @@ class Debugger8080 extends Debugger {
|
|||
sMessage += " at " + this.toHexAddr(this.newAddr(this.cpu.getPC()));
|
||||
}
|
||||
|
||||
if (this.bitsMessage & Messages8080.BUFFER) {
|
||||
this.aMessageBuffer.push(sMessage);
|
||||
if (this.bitsMessage & Messages8080.LOG) {
|
||||
this.aMessageLog.push(sMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -3035,11 +3035,11 @@ class Debugger8080 extends Debugger {
|
|||
else if (asArgs[2] == "off") {
|
||||
this.bitsMessage &= ~bitsMessage;
|
||||
fCriteria = false;
|
||||
if (bitsMessage == Messages8080.BUFFER) {
|
||||
for (var i = 0; i < this.aMessageBuffer.length; i++) {
|
||||
this.println(this.aMessageBuffer[i]);
|
||||
if (bitsMessage == Messages8080.LOG) {
|
||||
for (var i = 0; i < this.aMessageLog.length; i++) {
|
||||
this.println(this.aMessageLog[i]);
|
||||
}
|
||||
this.aMessageBuffer = [];
|
||||
this.aMessageLog = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,9 +43,8 @@ var Messages8080 = {
|
|||
SERIAL: 0x00800000,
|
||||
SPEAKER: 0x02000000,
|
||||
COMPUTER: 0x04000000,
|
||||
LOG: 0x10000000,
|
||||
WARN: 0x20000000,
|
||||
BUFFER: 0x40000000,
|
||||
LOG: 0x20000000,
|
||||
WARN: 0x40000000,
|
||||
HALT: 0x80000000|0
|
||||
};
|
||||
|
||||
|
|
@ -78,16 +77,15 @@ Messages8080.CATEGORIES = {
|
|||
"serial": Messages8080.SERIAL,
|
||||
"speaker": Messages8080.SPEAKER,
|
||||
"computer": Messages8080.COMPUTER,
|
||||
"log": Messages8080.LOG,
|
||||
"warn": Messages8080.WARN,
|
||||
/*
|
||||
* Now we turn to message actions rather than message types; for example, setting "halt"
|
||||
* on or off doesn't enable "halt" messages, but rather halts the CPU on any message above.
|
||||
*
|
||||
* Similarly, "m buffer on" turns on message buffering, deferring the display of all messages
|
||||
* until "m buffer off" is issued.
|
||||
* Similarly, "m log on" turns on message logging, deferring the display of all messages
|
||||
* until "m log off" is issued.
|
||||
*/
|
||||
"buffer": Messages8080.BUFFER,
|
||||
"log": Messages8080.LOG,
|
||||
"warn": Messages8080.WARN,
|
||||
"halt": Messages8080.HALT
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -570,7 +570,7 @@ class CPU extends Component {
|
|||
*/
|
||||
calcCycles()
|
||||
{
|
||||
var nMultiplier = (this.counts.mhzCurrent / this.counts.mhzBase)|0;
|
||||
var nMultiplier = this.counts.mhzCurrent / this.counts.mhzBase;
|
||||
if (!nMultiplier || nMultiplier > this.counts.nTargetMultiplier) nMultiplier = this.counts.nTargetMultiplier;
|
||||
this.counts.msPerYield = Math.round(1000 / CPU.YIELDS_PER_SECOND);
|
||||
this.counts.nCyclesPerYield = Math.floor(this.counts.nBaseCyclesPerSecond / CPU.YIELDS_PER_SECOND * nMultiplier);
|
||||
|
|
@ -713,9 +713,9 @@ class CPU extends Component {
|
|||
var fSuccess = true;
|
||||
if (nMultiplier !== undefined) {
|
||||
/*
|
||||
* If we haven't reached 80% (0.8) of the current target speed, revert to the default multiplier.
|
||||
* If we haven't reached 90% (0.9) of the current target speed, revert to the default multiplier.
|
||||
*/
|
||||
if (this.counts.mhzCurrent > 0 && this.counts.mhzCurrent / this.counts.mhzTarget < 0.8) {
|
||||
if (this.counts.mhzCurrent > 0 && this.counts.mhzCurrent < this.counts.mhzTarget * 0.9) {
|
||||
nMultiplier = this.counts.nBaseMultiplier;
|
||||
fSuccess = false;
|
||||
}
|
||||
|
|
@ -855,7 +855,7 @@ class CPU extends Component {
|
|||
|
||||
this.calcSpeed(nCycles, msElapsed);
|
||||
|
||||
if (msRemainsThisRun < 0 || this.counts.mhzCurrent < this.counts.mhzTarget) {
|
||||
if (msRemainsThisRun < 0) {
|
||||
/*
|
||||
* Try "throwing out" the effects of large anomalies, by moving the overall run start time up;
|
||||
* ordinarily, this should only happen when the someone is using an external Debugger or some other
|
||||
|
|
@ -866,14 +866,17 @@ class CPU extends Component {
|
|||
}
|
||||
/*
|
||||
* If the last burst took MORE time than we allotted (ie, it's taking more than 1 second to simulate
|
||||
* nCyclesActual), all we can do is yield for as little time as possible (ie, 0ms) and hope that the
|
||||
* simulation is at least usable.
|
||||
* nBaseCyclesPerSecond), all we can do is yield for as little time as possible (ie, 0ms) and hope
|
||||
* that the simulation is at least usable.
|
||||
*/
|
||||
msRemainsThisRun = 0;
|
||||
}
|
||||
else if (this.counts.mhzCurrent < this.counts.mhzTarget) {
|
||||
msRemainsThisRun = 0;
|
||||
}
|
||||
|
||||
if (DEBUG && this.messageEnabled(Messages.LOG) && msRemainsThisRun) {
|
||||
this.log("calcRemainingTime: " + msRemainsThisRun + "ms to sleep after " + this.counts.msEndThisRun + "ms");
|
||||
if (DEBUG && this.messageEnabled(Messages.CPU)) {
|
||||
this.printMessage("calcRemainingTime: sleep " + msRemainsThisRun + "ms after " + (this.counts.msEndThisRun - this.counts.msStartThisRun) + "ms burst");
|
||||
}
|
||||
|
||||
this.counts.msEndThisRun += msRemainsThisRun;
|
||||
|
|
@ -1102,9 +1105,17 @@ class CPU extends Component {
|
|||
if (timer[1] < 0) continue;
|
||||
timer[1] -= nCycles;
|
||||
if (timer[1] <= 0) {
|
||||
if (DEBUG && this.messageEnabled(Messages.CPU)) {
|
||||
this.printMessage("updateTimer(" + nCycles + "): firing " + timer[0] + " with only " + (timer[1] + nCycles) + " cycles left");
|
||||
}
|
||||
timer[1] = -1; // zero is technically an "active" value, so ensure the timer is dormant now
|
||||
timer[3](); // safe to invoke the callback function now
|
||||
if (timer[2] >= 0) this.setTimer(iTimer, timer[2]);
|
||||
if (timer[2] >= 0) {
|
||||
this.setTimer(iTimer, timer[2]);
|
||||
if (DEBUG && this.messageEnabled(Messages.CPU)) {
|
||||
this.printMessage("updateTimer(" + nCycles + "): rearming " + timer[0] + " for " + timer[2] + "ms (" + timer[1] + " cycles)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,8 +224,8 @@ class DebuggerX86 extends Debugger {
|
|||
this.sInitCommands = parmsDbg['commands'];
|
||||
|
||||
/*
|
||||
* Make it easier to access Debugger commands from an external REPL (eg, the WebStorm
|
||||
* "live" console window); eg:
|
||||
* Make it easier to access Debugger commands from an external REPL, like the WebStorm "live" console
|
||||
* window; eg:
|
||||
*
|
||||
* pcx86('r')
|
||||
* pcx86('dw 0:0')
|
||||
|
|
@ -2154,6 +2154,7 @@ class DebuggerX86 extends Debugger {
|
|||
this.dbg = this;
|
||||
this.bitsMessage = this.bitsWarning = Messages.WARN;
|
||||
this.sMessagePrev = null;
|
||||
this.aMessageLog = [];
|
||||
/*
|
||||
* Internally, we use "key" instead of "keys", since the latter is a method on JavasScript objects,
|
||||
* but externally, we allow the user to specify "keys"; "kbd" is also allowed as shorthand for "keyboard".
|
||||
|
|
@ -2502,6 +2503,11 @@ class DebuggerX86 extends Debugger {
|
|||
sMessage += " at " + this.toHexAddr(this.newAddr(this.cpu.getIP(), this.cpu.getCS())) + " (%" + Str.toHex(this.cpu.regLIP) + ")";
|
||||
}
|
||||
|
||||
if (this.bitsMessage & Messages.LOG) {
|
||||
this.aMessageLog.push(sMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.sMessagePrev && sMessage == this.sMessagePrev) return;
|
||||
this.sMessagePrev = sMessage;
|
||||
|
||||
|
|
@ -5442,6 +5448,12 @@ class DebuggerX86 extends Debugger {
|
|||
else if (asArgs[2] == "off") {
|
||||
this.bitsMessage &= ~bitsMessage;
|
||||
fCriteria = false;
|
||||
if (bitsMessage == Messages.LOG) {
|
||||
for (var i = 0; i < this.aMessageLog.length; i++) {
|
||||
this.println(this.aMessageLog[i]);
|
||||
}
|
||||
this.aMessageLog = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,12 +107,15 @@ Messages.CATEGORIES = {
|
|||
"computer": Messages.COMPUTER,
|
||||
"dos": Messages.DOS,
|
||||
"data": Messages.DATA,
|
||||
"log": Messages.LOG,
|
||||
"warn": Messages.WARN,
|
||||
/*
|
||||
* Now we turn to message actions rather than message types; for example, setting "halt"
|
||||
* on or off doesn't enable "halt" messages, but rather halts the CPU on any message above.
|
||||
*
|
||||
* Similarly, "m log on" turns on message logging, deferring the display of all messages
|
||||
* until "m log off" is issued.
|
||||
*/
|
||||
"log": Messages.LOG,
|
||||
"warn": Messages.WARN,
|
||||
"halt": Messages.HALT
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ class DebuggerPDP11 extends Debugger {
|
|||
this.afnDumpers = {};
|
||||
this.bitsMessage = this.bitsWarning = 0;
|
||||
this.sMessagePrev = null;
|
||||
this.aMessageBuffer = [];
|
||||
this.aMessageLog = [];
|
||||
this.messageInit(parmsDbg['messages']);
|
||||
this.sInitCommands = parmsDbg['commands'];
|
||||
|
||||
|
|
@ -847,7 +847,7 @@ class DebuggerPDP11 extends Debugger {
|
|||
this.dbg = this;
|
||||
this.bitsMessage = this.bitsWarning = MessagesPDP11.WARN;
|
||||
this.sMessagePrev = null;
|
||||
this.aMessageBuffer = [];
|
||||
this.aMessageLog = [];
|
||||
/*
|
||||
* Internally, we use "key" instead of "keys", since the latter is a method on JavasScript objects,
|
||||
* but externally, we allow the user to specify "keys"; "kbd" is also allowed as shorthand for "keyboard".
|
||||
|
|
@ -1014,8 +1014,8 @@ class DebuggerPDP11 extends Debugger {
|
|||
if (this.sMessagePrev && sMessage == this.sMessagePrev) return;
|
||||
this.sMessagePrev = sMessage;
|
||||
|
||||
if (this.bitsMessage & MessagesPDP11.BUFFER) {
|
||||
this.aMessageBuffer.push(sMessage);
|
||||
if (this.bitsMessage & MessagesPDP11.LOG) {
|
||||
this.aMessageLog.push(sMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -3203,12 +3203,12 @@ class DebuggerPDP11 extends Debugger {
|
|||
else if (asArgs[2] == "off") {
|
||||
this.bitsMessage &= ~bitsMessage;
|
||||
fCriteria = false;
|
||||
if (bitsMessage == MessagesPDP11.BUFFER) {
|
||||
var i = this.aMessageBuffer.length >= 1000? this.aMessageBuffer.length - 1000 : 0;
|
||||
while (i < this.aMessageBuffer.length) {
|
||||
this.println(this.aMessageBuffer[i++]);
|
||||
if (bitsMessage == MessagesPDP11.LOG) {
|
||||
var i = this.aMessageLog.length >= 1000? this.aMessageLog.length - 1000 : 0;
|
||||
while (i < this.aMessageLog.length) {
|
||||
this.println(this.aMessageLog[i++]);
|
||||
}
|
||||
this.aMessageBuffer = [];
|
||||
this.aMessageLog = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,9 +55,8 @@ var MessagesPDP11 = {
|
|||
TIMER: 0x00200000,
|
||||
SPEAKER: 0x01000000,
|
||||
COMPUTER: 0x02000000,
|
||||
LOG: 0x10000000,
|
||||
WARN: 0x20000000,
|
||||
BUFFER: 0x40000000,
|
||||
LOG: 0x20000000,
|
||||
WARN: 0x40000000,
|
||||
HALT: 0x80000000|0
|
||||
};
|
||||
|
||||
|
|
@ -102,16 +101,15 @@ MessagesPDP11.CATEGORIES = {
|
|||
"timer": MessagesPDP11.TIMER,
|
||||
"speaker": MessagesPDP11.SPEAKER,
|
||||
"computer": MessagesPDP11.COMPUTER,
|
||||
"log": MessagesPDP11.LOG,
|
||||
"warn": MessagesPDP11.WARN,
|
||||
/*
|
||||
* Now we turn to message actions rather than message types; for example, setting "halt"
|
||||
* on or off doesn't enable "halt" messages, but rather halts the CPU on any message above.
|
||||
*
|
||||
* Similarly, "m buffer on" turns on message buffering, deferring the display of all messages
|
||||
* until "m buffer off" is issued.
|
||||
* Similarly, "m log on" turns on message logging, deferring the display of all messages
|
||||
* until "m log off" is issued.
|
||||
*/
|
||||
"buffer": MessagesPDP11.BUFFER,
|
||||
"log": MessagesPDP11.LOG,
|
||||
"warn": MessagesPDP11.WARN,
|
||||
"halt": MessagesPDP11.HALT
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue