Smoothed out PCx86 dynamic CPU speed recalculation by no longer truncating the current cycle multiplier

This commit is contained in:
Jeff Parsons 2017-08-08 19:25:08 -07:00 committed by Jeff Parsons
commit 7f973a03b9
23 changed files with 1351 additions and 1308 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -7345,12 +7345,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
};
@ -12314,7 +12317,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);
@ -12457,9 +12460,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;
}
@ -12599,7 +12602,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
@ -12610,14 +12613,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;
@ -12846,9 +12852,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)");
}
}
}
}
}
@ -55283,7 +55297,7 @@ class SerialPort extends Component {
if (this.connection) {
var exports = this.connection['exports'];
if (exports) {
var fnConnect = exports['connect'];
var fnConnect = /** @function */ (exports['connect']);
if (fnConnect) fnConnect.call(this.connection, this.fNullModem);
this.sendData = exports['receiveData'];
if (this.sendData) {
@ -67050,8 +67064,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')
@ -68980,6 +68994,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".
@ -69328,6 +69343,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;
@ -72268,6 +72288,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 = [];
}
}
}
}

View file

@ -117,14 +117,14 @@ l.kc=function(a,b,c,d){this.pa=a;this.na=b;this.Da=d;for(b=0;b<Ec.length;b++)(d=
l.Rb=function(a,b){if(!b){if(a&&this.restore){Ic(this);if(!this.restore(a))return!1;Jc(this)}else this.reset();this.tb("No debugger detected")}Lc(this);return!0};l.Qb=function(a,b){var c=this.X.cb;b&&Mc(this);return a?this.save(c):!0};l.Fd=function(){return this.X.cb?!0:this.X.Fd||void 0===this.ia.run?Nc(this):!1};l.li=function(){return 0};
function Jc(a){void 0===a.V.If&&(a.V.If=0);void 0===a.V.Ke&&(a.V.Ke=-1);void 0===a.V.Le&&(a.V.Le=-1);a.X.zf=0<=a.V.If&&0<a.V.Ke;a.X.zf&&(a.V.Hf=0,a.V.se=a.V.If-a.Ic)}
l.Ab=function(a,b,c){var d=this;a=!1;switch(b){case "power":case "reset":this.ia[b]=c;a=!0;break;case "run":this.ia[b]=c;c.onclick=function(){var a=d.X.cb,b;if(b=d.pa)if(b=d.pa,b.X.Xd&&(b.X.Xd=!1,b.X.Ie&&!b.X.Sb&&b.ue(Oc)),b.X.Sb)b=!0;else{var c=null,h,k=db(b.id);for(h=0;h<k.length&&(c=k[h],c===b||c.X.ready);h++);if(h==k.length)for(h=0;h<k.length&&(c=k[h],c===b||c.X.Sb);h++);h==k.length&&(c=b);q("The "+c.type+" component ("+c.id+") is not "+(c.X.ready?"powered yet":"ready yet"+(c.Df?" (waiting for notification)":
""))+".");b=!1}b&&a==d.X.cb&&(d.X.cb?Mc(d,!0):Nc(d,!0))};a=!0;break;case "speed":this.ia[b]=c;a=!0;break;case "setSpeed":this.ia[b]=c,c.onclick=function(){Pc(d,d.V.md<<1,!0)},c.textContent=this.V.re.toFixed(2)+"Mhz",a=!0}return a};function Qc(a,b){a.X.cb&&(b=a.A-b,a.A-=b,a.Sc-=b)}function Rc(a){var b=a.V.hd/a.V.Gf|0;if(!b||b>a.V.md)b=a.V.md;a.V.yi=Math.round(1E3/Hc);a.V.Ml=Math.floor(a.V.xd/Hc*b);a.V.rg=b}
""))+".");b=!1}b&&a==d.X.cb&&(d.X.cb?Mc(d,!0):Nc(d,!0))};a=!0;break;case "speed":this.ia[b]=c;a=!0;break;case "setSpeed":this.ia[b]=c,c.onclick=function(){Pc(d,d.V.md<<1,!0)},c.textContent=this.V.re.toFixed(2)+"Mhz",a=!0}return a};function Qc(a,b){a.X.cb&&(b=a.A-b,a.A-=b,a.Sc-=b)}function Rc(a){var b=a.V.hd/a.V.Gf;if(!b||b>a.V.md)b=a.V.md;a.V.yi=Math.round(1E3/Hc);a.V.Ml=Math.floor(a.V.xd/Hc*b);a.V.rg=b}
function Sc(a,b){var c=a.Ic+a.Tc+a.Sc-a.A;b&&1<a.V.md&&a.V.hd>a.V.Gf&&(c=Math.round(c/a.V.md));return c}function Ic(a){a.Ic=a.Tc=a.Sc=a.A=0;Jc(a);Pc(a,a.V.zi)}
function Pc(a,b,c){if(void 0!==b){0<a.V.hd&&.8>a.V.hd/a.V.re&&(b=a.V.zi);a.V.hd=0;a.V.md=b;b=a.V.Gf*a.V.md;if(a.V.re!=b){a.V.re=b;b=a.V.re.toFixed(2)+"Mhz";var d=a.ia.setSpeed;d&&(d.textContent=b);a.tb("target speed: "+b)}c&&a.pa&&Tc(a.pa)}a.Ic+=a.Tc;a.Tc=0;a.V.Zc=a.V.Nd=0;Rc(a);for(c=a.qa.length-1;0<=c;c--)b=a.qa[c],0<=b[2]&&Uc(a,c,b[2],!0)}function Gc(a,b,c,d){d=void 0===d?-1:d;var e=a.qa.length;a.qa.push([b,-1,d,c]);0<=d&&Uc(a,e,d)}
function Pc(a,b,c){if(void 0!==b){0<a.V.hd&&a.V.hd<.9*a.V.re&&(b=a.V.zi);a.V.hd=0;a.V.md=b;b=a.V.Gf*a.V.md;if(a.V.re!=b){a.V.re=b;b=a.V.re.toFixed(2)+"Mhz";var d=a.ia.setSpeed;d&&(d.textContent=b);a.tb("target speed: "+b)}c&&a.pa&&Tc(a.pa)}a.Ic+=a.Tc;a.Tc=0;a.V.Zc=a.V.Nd=0;Rc(a);for(c=a.qa.length-1;0<=c;c--)b=a.qa[c],0<=b[2]&&Uc(a,c,b[2],!0)}function Gc(a,b,c,d){d=void 0===d?-1:d;var e=a.qa.length;a.qa.push([b,-1,d,c]);0<=d&&Uc(a,e,d)}
function Uc(a,b,c,d){0<=b&&b<a.qa.length&&(b=a.qa[b],d||0>b[1])&&(c=a.V.xd*a.V.rg/1E3*c|0,a.X.cb&&(c+=Vc(a)),b[1]=c)}function Wc(a){for(var b=[],c=0;c<a.qa.length;c++){var d=a.qa[c];b.push([d[0],d[1],d[2]])}return b}function Vc(a,b){var c=a.Sc-=a.A;a.A=0;b&&(a.Sc=0);return c}
l.kn=function(){if(this.X.cb){Rc(this);this.V.Jf=0;this.V.Je=ua();this.V.Zc||(this.V.Zc=this.V.Je);if(this.V.Nd){var a=this.V.Je-this.V.Nd;a>this.V.yi&&(this.V.Zc+=a,this.V.Zc>this.V.Je&&(this.V.Zc=this.V.Je))}try{this.X.Zf=!1;do{for(var b,c=this.X.zf?1:this.V.xd*this.V.rg|0,d=this.qa.length-1;0<=d;d--){var e=this.qa[d];0>e[1]||c>e[1]&&(c=e[1])}b=c;if(this.U){Xc(this.U);var f=this.U,a=b,g=f.qa[0];if(g.Kd){var h=(Sc(f.R,f.N)-g.jd)/f.Aa|0,k=Yc(f,0)-h;g.mode==Zc&&(k-=h);var m=k*f.Aa|0;g.mode==Zc&&(m>>=
1);a>m&&(a=m)}b=a;var r=this.U,a=b;if(r.A&&r.A[$c]&ad){var y=r.W-Sc(r.R,r.N);0<y&&a>y&&(a=y)}b=a}try{this.th(b)}catch(N){if("number"!=typeof N)throw N;}b=Vc(this,!0);this.V.Jf+=b;this.Tc+=b;a=b;if(this.X.zf){var t=!1;this.V.Hf=this.V.Hf+this.li()|0;this.V.se-=a;0>=this.V.se&&(this.V.se+=this.V.Ke,t=!0);0<=this.V.Le&&this.V.Le<=Sc(this)&&(this.V.Ke=this.V.Le=-1,Jc(this),Mc(this),t=!0);t&&this.tb(Sc(this)+" cycles: checksum="+ia(this.V.Hf))}for(var a=b,z=this.qa.length-1;0<=z;z--){var B=this.qa[z];
0>B[1]||(B[1]-=a,0>=B[1]&&(B[1]=-1,B[3](),0<=B[2]&&Uc(this,z,B[2])))}}while(this.X.cb&&!this.X.Zf)}catch(N){Mc(this);Lc(this);this.pa&&this.pa.stop(ua(),Sc(this));mb(this,N.stack||N.message);return}if(this.X.cb){b=setTimeout;c=this.pi;this.V.Nd=ua();d=this.V.yi;this.V.Jf&&(d=Math.round(d*this.V.Jf/this.V.Ml));d-=this.V.Nd-this.V.Je;if(e=this.V.Nd-this.V.Zc)this.V.hd=Math.round(this.Tc/(10*e))/100,864E5<=e&&(this.Ic=0,this.U&&Xc(this.U,!0),Pc(this));if(0>d||this.V.hd<this.V.re)-1E3>d&&(this.V.Zc-=
d),d=0;this.V.Nd+=d;b(c,d)}}};function Nc(a,b){var c;a.X.error?(a.tb(a.toString()+" error"),c=!0):c=!1;if(c)return!1;if(a.X.cb)return a.tb(a.toString()+" busy"),!1;Pc(a);a.X.cb=!0;a.X.Pj=!0;a.U&&a.U.start();if(c=a.ia.run)c.textContent="Halt";a.pa&&(bd(a.pa,!0),b&&Tc(a.pa,!0),a.pa.start(a.V.Zc,Sc(a)));setTimeout(a.pi,0);return!0}l.th=function(){return 0};
0>B[1]||(B[1]-=a,0>=B[1]&&(B[1]=-1,B[3](),0<=B[2]&&Uc(this,z,B[2])))}}while(this.X.cb&&!this.X.Zf)}catch(N){Mc(this);Lc(this);this.pa&&this.pa.stop(ua(),Sc(this));mb(this,N.stack||N.message);return}if(this.X.cb){b=setTimeout;c=this.pi;this.V.Nd=ua();d=this.V.yi;this.V.Jf&&(d=Math.round(d*this.V.Jf/this.V.Ml));d-=this.V.Nd-this.V.Je;if(e=this.V.Nd-this.V.Zc)this.V.hd=Math.round(this.Tc/(10*e))/100,864E5<=e&&(this.Ic=0,this.U&&Xc(this.U,!0),Pc(this));0>d?(-1E3>d&&(this.V.Zc-=d),d=0):this.V.hd<this.V.re&&
(d=0);this.V.Nd+=d;b(c,d)}}};function Nc(a,b){var c;a.X.error?(a.tb(a.toString()+" error"),c=!0):c=!1;if(c)return!1;if(a.X.cb)return a.tb(a.toString()+" busy"),!1;Pc(a);a.X.cb=!0;a.X.Pj=!0;a.U&&a.U.start();if(c=a.ia.run)c.textContent="Halt";a.pa&&(bd(a.pa,!0),b&&Tc(a.pa,!0),a.pa.start(a.V.Zc,Sc(a)));setTimeout(a.pi,0);return!0}l.th=function(){return 0};
function Mc(a,b){if(a.X.cb){Vc(a);a.Ic+=a.Tc;a.Tc=0;a.X.cb=!1;a.U&&a.U.stop();var c=a.ia.run;c&&(c.textContent="Run");a.pa&&(a.pa.stop(Date.now()||+new Date,Sc(a)),bd(a.pa,!0));a.Da||a.status("Stopped")}a.X.complete=b}function Lc(a){a.pa&&bd(a.pa,void 0)}var Hc=30,Ec=["power","reset"];
function cd(a,b,c,d){this.A=a;this.Da=a.Da;this.id=b;this.Xf=c||"";this.ha=0;this.jb=65535;this.C=this.jb+1;this.rb=this.jc=this.ext=this.nb=this.type=this.va=0;this.cc=-1;this.T=this.Jc=2;this.O=this.sa=65535;this.J=this.wi;this.I=this.H=this.xf;this.B={ha:-1,va:0,jb:0,nb:0,type:0,ext:0,cc:-1};1==this.id&&(this.Xe=0,this.D=null,this.ne=!1,this.G=Array(32),this.F=[]);dd(this,!0,d);this.id||(this.Jb=this.qb=this.ai)}l=cd.prototype;l.wi=function(a){this.ha=a&65535;return this.va=this.ha<<4};
l.Ff=function(a,b){var c,d,e=this.A;a&=65535;a&4?(c=e.mc.va,d=c+e.mc.jb|0):(c=e.Ob,d=e.Oc);if(c){c=c+(a&65528)|0;if(d-c|0)return e.A-=15,ed(this,c,a,b);this.id<fd&&w.call(e,b&&this.id==gd?10:13,a&65532)}return-1};l.Gl=function(a){var b=this.A;a=b.Xb+(a<<2);var c=b.ga(a);b.N&=-769;return this.load(b.ga(a+2))+c|0};l.Fl=function(a){var b=this.A;a<<=3;var c=b.Xb+a|0;if(7<=(b.Qc-c|0))return this.D=!0,a=ed(this,c,a),-1!==a&&(a+=this.Xe),a;w.call(b,13,a|2);return-1};l.ai=function(a){return this.va+a|0};

File diff suppressed because one or more lines are too long