Work-around for serial mouse interrupts arriving too quickly

This commit is contained in:
Jeff Parsons 2015-03-18 14:45:36 -07:00 committed by jeffpar
commit bc153c3016
9 changed files with 96 additions and 41 deletions

View file

@ -585,7 +585,7 @@ La(function(){for(var a=db(window.document,"pcjs","video"),b=0;b<a.length;b++){v
function Kj(a){this.Tl=a.adapter;switch(this.Tl){case 1:this.Lk=1016;this.ih=4;break;case 2:this.Lk=760;this.ih=3;break;default:xa("Unrecognized serial adapter #"+this.Tl);return}this.ue=null;n.call(this,"SerialPort",a,Kj,2097152);var b=a.binding,c;a=Lj;b&&(void 0===c&&(c="Panel"),(c=ab(c,this.id))&&(b=c.na[b])&&this.Bb(null,a,b))}Xa(n,Kj);var Lj="buffer";k=Kj.prototype;k.ll=function(a,b){return a==this.Xg?(this.De=b,this):null};
k.Bb=function(a,b,c){var d=this;switch(b){case Lj:return this.na[b]=this.ue=c,c.onkeydown=function(a){a=a||window.event;var b=a.keyCode;8===b&&(a.preventDefault&&a.preventDefault(),Mj(d,[b]))},c.onkeypress=function(a){a=a||window.event;Mj(d,[a.which||a.keyCode])},!0}return!1};k.uc=function(a,b,c,d){this.fa=b;this.N=c;this.X=d;this.da=rb(a,"ChipSet");bc(b,this,Nj,this.Lk);fc(b,this,Oj,this.Lk);hb(this)};k.bc=function(a,b){if(!b)if(!a||!this.restore)this.reset();else if(!this.restore(a))return!1;return!0};
k.ac=function(a){return a&&this.save?this.save():!0};k.reset=function(){this.Be()};k.save=function(){var a=new De(this),b=0,c=[];c[b++]=this.gj;c[b++]=this.rl;c[b++]=this.vf;c[b++]=this.Nh;c[b++]=this.oe;c[b++]=this.fd;c[b++]=this.xd;c[b++]=this.Qc;c[b++]=this.pl;c[b]=this.ug;a.set(0,c);return a.data()};k.restore=function(a){return this.Be(a[0])};
k.Be=function(a){var b=0;void 0===a&&(a=[0,0,384,0,1,0,0,96,48,[]]);this.gj=a[b++];this.rl=a[b++];this.vf=a[b++];this.Nh=a[b++];this.oe=a[b++];this.fd=a[b++];this.xd=a[b++];this.Qc=a[b++];this.pl=a[b++];this.ug=a[b];return!0};function Mj(a,b){a.ug=a.ug.concat(b);Pj(a)}function Pj(a){0<a.ug.length&&!(a.Qc&1)&&(a.gj=a.ug.shift(),a.Qc|=1);var b=-1;a.Qc&1&&a.Nh&1&&(b=4);0<=b?(a.oe&=-8,a.oe|=b,a.da&&a.ih&&Qh(a.da,a.ih)):(a.oe|=1,a.da&&a.ih&&Rh(a.da,a.ih))}
k.Be=function(a){var b=0;void 0===a&&(a=[0,0,384,0,1,0,0,96,48,[]]);this.gj=a[b++];this.rl=a[b++];this.vf=a[b++];this.Nh=a[b++];this.oe=a[b++];this.fd=a[b++];this.xd=a[b++];this.Qc=a[b++];this.pl=a[b++];this.ug=a[b];return!0};function Mj(a,b){a.ug=a.ug.concat(b);Pj(a)}function Pj(a){0<a.ug.length&&!(a.Qc&1)&&(a.gj=a.ug.shift(),a.Qc|=1);var b=-1;a.Qc&1&&a.Nh&1&&(b=4);0<=b?(a.oe&=-8,a.oe|=b,a.da&&a.ih&&Qh(a.da,a.ih,100)):(a.oe|=1,a.da&&a.ih&&Rh(a.da,a.ih))}
k.cp=function(a,b){var c=this.fd&128?this.vf&255:this.gj;p(this,a,null,b,this.fd&128?"DLL":"RBR",c);this.Qc&=-2;Pj(this);return c};k.Oo=function(a,b){var c=this.fd&128?this.vf>>8:this.Nh;p(this,a,null,b,this.fd&128?"DLM":"IER",c);return c};k.Po=function(a,b){var c=this.oe;p(this,a,null,b,"IIR",c);return c};k.Qo=function(a,b){var c=this.fd;p(this,a,null,b,"LCR",c);return c};k.So=function(a,b){var c=this.xd;p(this,a,null,b,"MCR",c);return c};
k.Ro=function(a,b){var c=this.Qc;p(this,a,null,b,"LSR",c);return c};k.Yo=function(a,b){var c=this.pl;p(this,a,null,b,"MSR",c);return c};k.tq=function(a,b,c){p(this,a,b,c,this.fd&128?"DLL":"THR");this.fd&128?this.vf=this.vf&-256|b:(this.rl=b,this.Qc&=-97,this.ue?(13!=b&&(8==b?this.ue.value=this.ue.value.slice(0,-1):(this.ue.value+=String.fromCharCode(b),this.ue.scrollTop=this.ue.scrollHeight)),a=!0):a=!1,a&&(this.Qc|=96))};
k.eq=function(a,b,c){p(this,a,b,c,this.fd&128?"DLM":"IER");this.fd&128?this.vf=this.vf&255|b<<8:this.Nh=b};k.fq=function(a,b,c){p(this,a,b,c,"LCR");this.fd=b};
@ -595,7 +595,7 @@ k.uc=function(a,b,c,d){this.xa=a;this.fa=b;this.N=c;this.X=d;this.video=rb(this.
k.ac=function(a){return a&&this.save?this.save():!0};k.reset=function(){this.Be()};k.save=function(){var a=new De(this);a.set(0,this.Vk());return a.data()};k.restore=function(a){return this.Be(a[0])};k.Be=function(a){var b=0;void 0===a&&(a=[!1,-1,-1,0,0,!1,!1,0]);this.setActive(a[b++]);this.ee=a[b++];this.fe=a[b++];this.xf=a[b++];this.yf=a[b++];this.ci=a[b++];this.di=a[b++];this.xd=a[b];return!0};
k.Vk=function(){var a=0,b=[];b[a++]=this.ld;b[a++]=this.ee;b[a++]=this.fe;b[a++]=this.xf;b[a++]=this.yf;b[a++]=this.ci;b[a++]=this.di;b[a]=this.xd;return b};k.qh=function(a){this.gi=a};function Qj(a,b){b&&(a.wj||(b.addEventListener("mousemove",function(b){a.$l(b)},!1),b.addEventListener("mousedown",function(b){a.nj(b.button,!0)},!1),b.addEventListener("mouseup",function(b){a.nj(b.button,!1)},!1),a.wj=!0),b.style.cursor="none")}function Rj(a){a&&(a.style.cursor="auto")}
k.$l=function(a){if(this.ld&&this.N&&this.N.ba.fb){if(0>this.ee||0>this.fe)this.ee=a.clientX,this.fe=a.clientY;this.gi?(this.xf=a.movementX||a.mozMovementX||a.webkitMovementX||0,this.yf=a.movementY||a.mozMovementY||a.webkitMovementY||0):(this.xf=a.clientX-this.ee,this.yf=a.clientY-this.fe);(this.xf||this.yf)&&Tj(this,null,a.clientX,a.clientY);this.ee=a.clientX;this.fe=a.clientY}};
k.nj=function(a,b){if(this.ld&&this.N&&this.N.ba.fb){var c;!(c=!1!==this.gi)&&(c=this.video)&&(c=this.video,c=c.bo?c.hf(!0):!1);c||(this.gi=null);switch(a){case 0:this.ci!=b&&(this.ci=b,Tj(this,"mouse button1 "+(b?"dn":"up")));break;case 2:this.di!=b&&(this.di=b,Tj(this,"mouse button2 "+(b?"dn":"up")))}}};
k.nj=function(a,b){if(this.ld&&this.N&&this.N.ba.fb){var c;!(c=!1!==this.gi)&&(c=this.video)&&(c=this.video,c=c.bo?c.hf(!0):!1);c||(this.gi=null);c="mouse button"+a+" "+(b?"dn":"up");switch(a){case 0:this.ci!=b&&(this.ci=b,Tj(this,c));break;case 2:this.di!=b&&(this.di=b,Tj(this,c))}}};
function Tj(a,b,c,d){var e=64|(a.ci?32:0)|(a.di?16:0)|(a.yf&192)>>4|(a.xf&192)>>6,f=a.xf&63,g=a.yf&63;a.ma(2097152)&&a.Ta((b?b+": ":"")+(void 0!==d?"mouse ("+c+","+d+"): ":"")+"serial packet ["+l(e)+","+l(f)+","+l(g)+"]",0,!0);Mj(a.Jg,[e,f,g]);a.xf=a.yf=0}La(function(){for(var a=db(window.document,"pcjs","mouse"),b=0;b<a.length;b++){var c=a[b],d=bb(c),d=new Sj(d);cb(d,c)}});
function Uj(a,b,c){n.call(this,"Disk",{id:a.Vl+".disk"+ ++Vj},Uj,1048576);this.V=a;this.xa=a.xa;this.X=a.X;this.Ja=b;this.Hd=b.name;this.Rf=b.Rf;this.hi=this.Sd=!1;this.create(c,b.ub,b.vb,b.zb,b.mb);this.Pe=[];this.Ch=[];this.ce=null;this.bm=0;this.Fj=!1;hb(this)}var Vj=0;Xa(n,Uj);k=Uj.prototype;k.uc=function(a,b,c,d){this.X=d};k.bc=function(a,b){b||!this.hi||this.Sd||(hb(this,!1),this.load(this.Hd,this.rf,null,this.Zn,this));return!0};k.Zn=function(){hb(this,!0)};
k.ac=function(a,b){if(this.Sd){var c,d=0;if(this.Fj&&!za("Disk writes are still in progress, shut down anyway?"))return!1;for(;c=Wj(this,!1);)if(d=c[0]){this.V.ya('Unable to save "'+this.Hd+'" (error '+d+")");break}b&&this.Sd&&(c="action=close&volume="+this.rf,c+="&machine="+this.V.Tf(),c+="&user="+this.V.ze(),va(wa()+"/api/v1/disk?"+c,!0),this.Sd=!1);!d&&a&&this.V.ya(this.Hd+" saved")}return!0};

View file

@ -559,7 +559,7 @@ za(function(){for(var a=Ra(window.document,"pcjs","video"),b=0;b<a.length;b++){v
function zi(a){this.$k=a.adapter;switch(this.$k){case 1:this.Xj=1016;this.sg=4;break;case 2:this.Xj=760;this.sg=3;break;default:m("Unrecognized serial adapter #"+this.$k);return}this.Pd=null;n.call(this,"SerialPort",a,zi);var b=a.binding,c;a=Ai;b&&(void 0===c&&(c="Panel"),(c=Oa(c,this.id))&&(b=c.la[b])&&this.Ab(null,a,b))}La(n,zi);var Ai="buffer";k=zi.prototype;k.vk=function(a,b){return a==this.yh?(this.Yd=b,this):null};
k.Ab=function(a,b,c){var d=this;switch(b){case Ai:return this.la[b]=this.Pd=c,c.onkeydown=function(a){a=a||window.event;var b=a.keyCode;8===b&&(a.preventDefault&&a.preventDefault(),Bi(d,[b]))},c.onkeypress=function(a){a=a||window.event;Bi(d,[a.which||a.keyCode])},!0}return!1};k.wc=function(a,b,c,d){this.ga=b;this.S=c;this.Ta=d;this.aa=bb(a,"ChipSet");Ib(b,this,Ci,this.Xj);Kb(b,this,Di,this.Xj);p(this)};k.Yb=function(a,b){if(!b)if(!a||!this.restore)this.reset();else if(!this.restore(a))return!1;return!0};
k.Xb=function(a){return a&&this.save?this.save():!0};k.reset=function(){this.Wd()};k.save=function(){var a=new Pd(this),b=0,c=[];c[b++]=this.oi;c[b++]=this.Bk;c[b++]=this.Te;c[b++]=this.Wg;c[b++]=this.Kd;c[b++]=this.te;c[b++]=this.ad;c[b++]=this.Bc;c[b++]=this.zk;c[b]=this.Mf;a.set(0,c);return a.data()};k.restore=function(a){return this.Wd(a[0])};
k.Wd=function(a){var b=0;void 0===a&&(a=[0,0,384,0,1,0,0,96,48,[]]);this.oi=a[b++];this.Bk=a[b++];this.Te=a[b++];this.Wg=a[b++];this.Kd=a[b++];this.te=a[b++];this.ad=a[b++];this.Bc=a[b++];this.zk=a[b++];this.Mf=a[b];return!0};function Bi(a,b){a.Mf=a.Mf.concat(b);Ei(a)}function Ei(a){0<a.Mf.length&&!(a.Bc&1)&&(a.oi=a.Mf.shift(),a.Bc|=1);var b=-1;a.Bc&1&&a.Wg&1&&(b=4);0<=b?(a.Kd&=-8,a.Kd|=b,a.aa&&a.sg&&Sg(a.aa,a.sg)):(a.Kd|=1,a.aa&&a.sg&&Tg(a.aa,a.sg))}
k.Wd=function(a){var b=0;void 0===a&&(a=[0,0,384,0,1,0,0,96,48,[]]);this.oi=a[b++];this.Bk=a[b++];this.Te=a[b++];this.Wg=a[b++];this.Kd=a[b++];this.te=a[b++];this.ad=a[b++];this.Bc=a[b++];this.zk=a[b++];this.Mf=a[b];return!0};function Bi(a,b){a.Mf=a.Mf.concat(b);Ei(a)}function Ei(a){0<a.Mf.length&&!(a.Bc&1)&&(a.oi=a.Mf.shift(),a.Bc|=1);var b=-1;a.Bc&1&&a.Wg&1&&(b=4);0<=b?(a.Kd&=-8,a.Kd|=b,a.aa&&a.sg&&Sg(a.aa,a.sg,100)):(a.Kd|=1,a.aa&&a.sg&&Tg(a.aa,a.sg))}
k.io=function(){var a=this.te&128?this.Te&255:this.oi;this.Bc&=-2;Ei(this);return a};k.Sn=function(){return this.te&128?this.Te>>8:this.Wg};k.Tn=function(){return this.Kd};k.Un=function(){return this.te};k.Wn=function(){return this.ad};k.Vn=function(){return this.Bc};k.bo=function(){return this.zk};
k.vp=function(a,b){if(this.te&128)this.Te=this.Te&-256|b;else{this.Bk=b;this.Bc&=-97;var c;this.Pd?(13!=b&&(8==b?this.Pd.value=this.Pd.value.slice(0,-1):(this.Pd.value+=String.fromCharCode(b),this.Pd.scrollTop=this.Pd.scrollHeight)),c=!0):c=!1;c&&(this.Bc|=96)}};k.gp=function(a,b){this.te&128?this.Te=this.Te&255|b<<8:this.Wg=b};k.hp=function(a,b){this.te=b};
k.ip=function(a,b){var c=this.ad;this.ad=b;if(this.Yd&&(c^b)&3){var c=this.Yd,d=this.ad,e=3==(d&3);if(e){if(!c.Vc){var f=!1;c.ad&2||(c.reset(),c.Zb("serial mouse reset"),f=!0);c.ad&1||(c.Zb("serial mouse ID requested"),f=!0);f&&(Bi(c.$f,[77,77]),c.Zb("serial mouse ID sent"));Fi(c,c.za);c.setActive(e)}}else c.Vc&&(c.Zb("serial mouse inactive"),Gi(c.za),c.setActive(e));c.ad=d}};

View file

@ -3043,7 +3043,7 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
var nIRQ = (nIRL == null? undefined : pic.nIRQBase + nIRL);
if (pic.bISR & bIREnd) {
if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) {
this.printMessage("outPIC" + iPIC + "(0x" + str.toHexByte(pic.port) + "): IRQ " + nIRQ + " going out of service", true);
this.printMessage("outPIC" + iPIC + "(0x" + str.toHexByte(pic.port) + "): IRQ " + nIRQ + " ending @" + this.dbg.hexOffset(this.cpu.getIP(), this.cpu.getCS()) + " stack=" + this.dbg.hexOffset(this.cpu.getSP(), this.cpu.getSS()), true);
}
pic.bISR &= ~bIREnd;
this.checkIRR();

View file

@ -573,6 +573,9 @@ CPU.prototype.setBurstCycles = function(nCycles)
* NOTE: If nDelta is negative, we will actually be increasing nStepCycles and nBurstCycles.
* Which is OK, but if we're also taking snapshots of the cycle counts, to make sure that instruction
* costs are being properly assessed, then we need to update nSnapCycles as well.
*
* TODO: If the delta is negative, we could simply ignore the request, but we must first carefully
* consider the impact on the ChipSet timers.
*/
if (DEBUG) this.nSnapCycles -= nDelta;
this.nStepCycles -= nDelta;

View file

@ -470,8 +470,8 @@ Mouse.prototype.moveMouse = function(event)
}
if (this.xDelta || this.yDelta) {
/*
* As sendPacket() indicates, the x and y coordinates we pass below are for diagnostic purposes
* only. sendPacket() really only cares about xDelta and yDelta, which it then zeroes on completion.
* As sendPacket() indicates, any x and y coordinates we supply are for diagnostic purposes only.
* sendPacket() only cares about the xDelta and yDelta properties, which it then zeroes on completion.
*/
this.sendPacket(null, event.clientX, event.clientY);
}
@ -499,19 +499,17 @@ Mouse.prototype.clickMouse = function(iButton, fDown)
this.fLocked = null;
}
}
var sDiag;
var sDiag = DEBUGGER? ("mouse button" + iButton + ' ' + (fDown? "dn" : "up")) : null;
switch (iButton) {
case 0:
if (this.fButton1 != fDown) {
this.fButton1 = fDown;
sDiag = DEBUGGER? ("mouse button1 " + (fDown? "dn" : "up")) : null;
this.sendPacket(sDiag);
}
break;
case 2:
if (this.fButton2 != fDown) {
this.fButton2 = fDown;
sDiag = DEBUGGER? ("mouse button2 " + (fDown? "dn" : "up")) : null;
this.sendPacket(sDiag);
}
break;

View file

@ -156,6 +156,33 @@ SerialPort.DLL = {REG: 0}; // Divisor Latch LSB (only when SerialPo
SerialPort.THR = {REG: 0}; // Transmitter Holding Register (write)
SerialPort.DL_DEFAULT = 0x180; // we select an arbitrary default Divisor Latch equivalent to 300 baud
/*
* The divisor is stored in wDL. If we take the frequency value 1843200 and divide it by wDL*128, we get the
* maximum number of bytes per second that the SerialPort interface should generate. For example, if a baud
* rate of 1200 is being used, the divisor will be 0x60 (96), so we calculate 1843200/(96*128) = 150, which means
* there should be a 1000ms/150 or 6.667ms delay between bytes delivered.
*
* TODO: Enforce that delay. However, the delay should be converted from real-world milliseconds to the
* appropriate number of CPU cycles we can pass to setBurstCycles(). This will also require the CPU to call
* us at the start of each burst, to see if advanceRBR() has more data to deliver. For now, I'm throttling
* SerialPort interrupts by passing a hard-coded delay to setIRR(). The setIRR() delay does not ensure any
* particular baud rate, it simply gives the underlying Interrupt Service Routine (ISR) some breathing room.
*
* The Microsoft Windows 1.01 serial mouse driver ISR issues an EOI before it has safely exited, relying solely
* on the fact that a 1200 baud serial device would not normally interrupt frequently enough to blow the stack.
* However, in PCjs, all you have to do is enable Debugger messages on every serial interrupt and mouse event,
* eg:
*
* m serial on;m pic on;m mouse on
*
* to slow the machine down to the point where serial mouse interrupts overwhelm the ISR. The Debugger messages
* display the current stack pointer, which you can watch drop to zero and then wrap around, no doubt trampling
* lots of code and data along the way.
*
* This problem can also occur without being forced by the Debugger; eg, whenever the physical machine's mouse is
* configured for a high interrupt rate.
*/
/*
* Receiver Buffer Register (RBR.REG, offset 0; eg, 0x3F8 or 0x2F8)
*/
@ -261,7 +288,8 @@ SerialPort.SCR = {REG: 7};
* @param {Mouse} mouse component
* @return {Component} this or null, based on whether or not the specified ID matches
*/
SerialPort.prototype.attachMouse = function(id, mouse) {
SerialPort.prototype.attachMouse = function(id, mouse)
{
if (id == this.idComponent) {
this.mouse = mouse;
return this;
@ -276,7 +304,8 @@ SerialPort.prototype.attachMouse = function(id, mouse) {
*
* @this {SerialPort}
*
SerialPort.prototype.syncMouse = function() {
SerialPort.prototype.syncMouse = function()
{
if (this.mouse) this.mouse.notifyMCR(this.bMCR);
};
*/
@ -290,7 +319,8 @@ SerialPort.prototype.syncMouse = function() {
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
* @return {boolean} true if binding was successful, false if unrecognized binding request
*/
SerialPort.prototype.setBinding = function(sHTMLType, sBinding, control) {
SerialPort.prototype.setBinding = function(sHTMLType, sBinding, control)
{
var serial = this;
switch (sBinding) {
case SerialPort.sIOBuffer:
@ -339,7 +369,8 @@ SerialPort.prototype.setBinding = function(sHTMLType, sBinding, control) {
* @param {X86CPU} cpu
* @param {Debugger} dbg
*/
SerialPort.prototype.initBus = function(cmp, bus, cpu, dbg) {
SerialPort.prototype.initBus = function(cmp, bus, cpu, dbg)
{
this.bus = bus;
this.cpu = cpu;
this.dbg = dbg;
@ -357,7 +388,8 @@ SerialPort.prototype.initBus = function(cmp, bus, cpu, dbg) {
* @param {boolean} [fRepower]
* @return {boolean} true if successful, false if failure
*/
SerialPort.prototype.powerUp = function(data, fRepower) {
SerialPort.prototype.powerUp = function(data, fRepower)
{
if (!fRepower) {
if (!data || !this.restore) {
this.reset();
@ -375,7 +407,8 @@ SerialPort.prototype.powerUp = function(data, fRepower) {
* @param {boolean} fSave
* @return {Object|boolean}
*/
SerialPort.prototype.powerDown = function(fSave) {
SerialPort.prototype.powerDown = function(fSave)
{
return fSave && this.save ? this.save() : true;
};
@ -384,7 +417,8 @@ SerialPort.prototype.powerDown = function(fSave) {
*
* @this {SerialPort}
*/
SerialPort.prototype.reset = function() {
SerialPort.prototype.reset = function()
{
this.initState();
};
@ -396,7 +430,8 @@ SerialPort.prototype.reset = function() {
* @this {SerialPort}
* @return {Object}
*/
SerialPort.prototype.save = function() {
SerialPort.prototype.save = function()
{
var state = new State(this);
state.set(0, this.saveRegisters());
return state.data();
@ -411,7 +446,8 @@ SerialPort.prototype.save = function() {
* @param {Object} data
* @return {boolean} true if successful, false if failure
*/
SerialPort.prototype.restore = function(data) {
SerialPort.prototype.restore = function(data)
{
return this.initState(data[0]);
};
@ -422,7 +458,8 @@ SerialPort.prototype.restore = function(data) {
* @param {Array} [data]
* @return {boolean} true if successful, false if failure
*/
SerialPort.prototype.initState = function(data) {
SerialPort.prototype.initState = function(data)
{
/*
* The NS8250A spec doesn't explicitly say what the RBR and THR are initialized to on a reset,
* but I think we can safely assume zeros. Similarly, we reset the baud rate Divisor Latch (wDL)
@ -462,7 +499,8 @@ SerialPort.prototype.initState = function(data) {
* @this {SerialPort}
* @return {Array}
*/
SerialPort.prototype.saveRegisters = function() {
SerialPort.prototype.saveRegisters = function()
{
var i = 0;
var data = [];
data[i++] = this.bRBR;
@ -484,7 +522,8 @@ SerialPort.prototype.saveRegisters = function() {
* @this {SerialPort}
* @param {Array} ab is an array of bytes to propagate to the bRBR (Receiver Buffer Register)
*/
SerialPort.prototype.sendRBR = function(ab) {
SerialPort.prototype.sendRBR = function(ab)
{
this.abReceive = this.abReceive.concat(ab);
this.advanceRBR();
};
@ -494,7 +533,8 @@ SerialPort.prototype.sendRBR = function(ab) {
*
* @this {SerialPort}
*/
SerialPort.prototype.advanceRBR = function() {
SerialPort.prototype.advanceRBR = function()
{
if (this.abReceive.length > 0 && !(this.bLSR & SerialPort.LSR.DR)) {
this.bRBR = this.abReceive.shift();
this.bLSR |= SerialPort.LSR.DR;
@ -510,7 +550,8 @@ SerialPort.prototype.advanceRBR = function() {
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
* @return {number} simulated port value
*/
SerialPort.prototype.inRBR = function(port, addrFrom) {
SerialPort.prototype.inRBR = function(port, addrFrom)
{
var b = ((this.bLCR & SerialPort.LCR.DLAB) ? (this.wDL & 0xff) : this.bRBR);
this.printMessageIO(port, null, addrFrom, (this.bLCR & SerialPort.LCR.DLAB) ? "DLL" : "RBR", b);
this.bLSR &= ~SerialPort.LSR.DR;
@ -526,7 +567,8 @@ SerialPort.prototype.inRBR = function(port, addrFrom) {
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
* @return {number} simulated port value
*/
SerialPort.prototype.inIER = function(port, addrFrom) {
SerialPort.prototype.inIER = function(port, addrFrom)
{
var b = ((this.bLCR & SerialPort.LCR.DLAB) ? (this.wDL >> 8) : this.bIER);
this.printMessageIO(port, null, addrFrom, (this.bLCR & SerialPort.LCR.DLAB) ? "DLM" : "IER", b);
return b;
@ -540,7 +582,8 @@ SerialPort.prototype.inIER = function(port, addrFrom) {
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
* @return {number} simulated port value
*/
SerialPort.prototype.inIIR = function(port, addrFrom) {
SerialPort.prototype.inIIR = function(port, addrFrom)
{
var b = this.bIIR;
this.printMessageIO(port, null, addrFrom, "IIR", b);
return b;
@ -554,7 +597,8 @@ SerialPort.prototype.inIIR = function(port, addrFrom) {
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
* @return {number} simulated port value
*/
SerialPort.prototype.inLCR = function(port, addrFrom) {
SerialPort.prototype.inLCR = function(port, addrFrom)
{
var b = this.bLCR;
this.printMessageIO(port, null, addrFrom, "LCR", b);
return b;
@ -568,7 +612,8 @@ SerialPort.prototype.inLCR = function(port, addrFrom) {
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
* @return {number} simulated port value
*/
SerialPort.prototype.inMCR = function(port, addrFrom) {
SerialPort.prototype.inMCR = function(port, addrFrom)
{
var b = this.bMCR;
this.printMessageIO(port, null, addrFrom, "MCR", b);
return b;
@ -582,7 +627,8 @@ SerialPort.prototype.inMCR = function(port, addrFrom) {
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
* @return {number} simulated port value
*/
SerialPort.prototype.inLSR = function(port, addrFrom) {
SerialPort.prototype.inLSR = function(port, addrFrom)
{
var b = this.bLSR;
this.printMessageIO(port, null, addrFrom, "LSR", b);
return b;
@ -596,7 +642,8 @@ SerialPort.prototype.inLSR = function(port, addrFrom) {
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
* @return {number} simulated port value
*/
SerialPort.prototype.inMSR = function(port, addrFrom) {
SerialPort.prototype.inMSR = function(port, addrFrom)
{
var b = this.bMSR;
this.printMessageIO(port, null, addrFrom, "MSR", b);
return b;
@ -610,7 +657,8 @@ SerialPort.prototype.inMSR = function(port, addrFrom) {
* @param {number} bOut
* @param {number} [addrFrom] (not defined whenever the Debugger tries to write the specified port)
*/
SerialPort.prototype.outTHR = function(port, bOut, addrFrom) {
SerialPort.prototype.outTHR = function(port, bOut, addrFrom)
{
this.printMessageIO(port, bOut, addrFrom, (this.bLCR & SerialPort.LCR.DLAB) ? "DLL" : "THR");
if (this.bLCR & SerialPort.LCR.DLAB) {
this.wDL = (this.wDL & ~0xff) | bOut;
@ -634,7 +682,8 @@ SerialPort.prototype.outTHR = function(port, bOut, addrFrom) {
* @param {number} bOut
* @param {number} [addrFrom] (not defined whenever the Debugger tries to write the specified port)
*/
SerialPort.prototype.outIER = function(port, bOut, addrFrom) {
SerialPort.prototype.outIER = function(port, bOut, addrFrom)
{
this.printMessageIO(port, bOut, addrFrom, (this.bLCR & SerialPort.LCR.DLAB) ? "DLM" : "IER");
if (this.bLCR & SerialPort.LCR.DLAB) {
this.wDL = (this.wDL & 0xff) | (bOut << 8);
@ -651,7 +700,8 @@ SerialPort.prototype.outIER = function(port, bOut, addrFrom) {
* @param {number} bOut
* @param {number} [addrFrom] (not defined whenever the Debugger tries to write the specified port)
*/
SerialPort.prototype.outLCR = function(port, bOut, addrFrom) {
SerialPort.prototype.outLCR = function(port, bOut, addrFrom)
{
this.printMessageIO(port, bOut, addrFrom, "LCR");
this.bLCR = bOut;
};
@ -664,7 +714,8 @@ SerialPort.prototype.outLCR = function(port, bOut, addrFrom) {
* @param {number} bOut
* @param {number} [addrFrom] (not defined whenever the Debugger tries to write the specified port)
*/
SerialPort.prototype.outMCR = function(port, bOut, addrFrom) {
SerialPort.prototype.outMCR = function(port, bOut, addrFrom)
{
var bPrev = this.bMCR;
this.printMessageIO(port, bOut, addrFrom, "MCR");
this.bMCR = bOut;
@ -678,7 +729,8 @@ SerialPort.prototype.outMCR = function(port, bOut, addrFrom) {
*
* @this {SerialPort}
*/
SerialPort.prototype.updateIRR = function() {
SerialPort.prototype.updateIRR = function()
{
var bIIR = -1;
if ((this.bLSR & SerialPort.LSR.DR) && (this.bIER & SerialPort.IER.RBR_AVAIL)) {
bIIR = SerialPort.IIR.INT_RBR;
@ -686,7 +738,7 @@ SerialPort.prototype.updateIRR = function() {
if (bIIR >= 0) {
this.bIIR &= ~(SerialPort.IIR.NO_INT | SerialPort.IIR.INT_BITS);
this.bIIR |= bIIR;
if (this.chipset && this.nIRQ) this.chipset.setIRR(this.nIRQ);
if (this.chipset && this.nIRQ) this.chipset.setIRR(this.nIRQ, 100);
} else {
this.bIIR |= SerialPort.IIR.NO_INT;
if (this.chipset && this.nIRQ) this.chipset.clearIRR(this.nIRQ);
@ -700,7 +752,8 @@ SerialPort.prototype.updateIRR = function() {
* @param {number} b
* @return {boolean} true if echoed, false if not
*/
SerialPort.prototype.echoByte = function(b) {
SerialPort.prototype.echoByte = function(b)
{
if (this.controlIOBuffer) {
if (b != 0x0D) {
if (b == 0x08) {
@ -746,7 +799,8 @@ SerialPort.aPortOutput = {
* attribute, invoking the constructor to create a SerialPort component, and then binding
* any associated HTML controls to the new component.
*/
SerialPort.init = function() {
SerialPort.init = function()
{
var aeSerial = Component.getElementsByClass(window.document, PCJSCLASS, "serial");
for (var iSerial = 0; iSerial < aeSerial.length; iSerial++) {
var eSerial = aeSerial[iSerial];

View file

@ -85,7 +85,7 @@ if (I386) {
* cycles would hurt overall performance. Similarly, 8254 timer counters are updated only on-demand.
*
* The 8237 and 8254, along with the 8259 interrupt controller and several other "chips", are combined
* into a single "Chipset" component, to keep the number of components we juggle to a minimum.
* into a single ChipSet component, to keep the number of components we juggle to a minimum.
*
* All that being said, this does not change the overall goal: to produce as accurate a simulation as
* possible, within the limits of what JavaScript allows and how precisely/predictably it behaves.

View file

@ -585,7 +585,7 @@ La(function(){for(var a=db(window.document,"pcjs","video"),b=0;b<a.length;b++){v
function Kj(a){this.Tl=a.adapter;switch(this.Tl){case 1:this.Lk=1016;this.ih=4;break;case 2:this.Lk=760;this.ih=3;break;default:xa("Unrecognized serial adapter #"+this.Tl);return}this.ue=null;n.call(this,"SerialPort",a,Kj,2097152);var b=a.binding,c;a=Lj;b&&(void 0===c&&(c="Panel"),(c=ab(c,this.id))&&(b=c.na[b])&&this.Bb(null,a,b))}Xa(n,Kj);var Lj="buffer";k=Kj.prototype;k.ll=function(a,b){return a==this.Xg?(this.De=b,this):null};
k.Bb=function(a,b,c){var d=this;switch(b){case Lj:return this.na[b]=this.ue=c,c.onkeydown=function(a){a=a||window.event;var b=a.keyCode;8===b&&(a.preventDefault&&a.preventDefault(),Mj(d,[b]))},c.onkeypress=function(a){a=a||window.event;Mj(d,[a.which||a.keyCode])},!0}return!1};k.uc=function(a,b,c,d){this.fa=b;this.N=c;this.X=d;this.da=rb(a,"ChipSet");bc(b,this,Nj,this.Lk);fc(b,this,Oj,this.Lk);hb(this)};k.bc=function(a,b){if(!b)if(!a||!this.restore)this.reset();else if(!this.restore(a))return!1;return!0};
k.ac=function(a){return a&&this.save?this.save():!0};k.reset=function(){this.Be()};k.save=function(){var a=new De(this),b=0,c=[];c[b++]=this.gj;c[b++]=this.rl;c[b++]=this.vf;c[b++]=this.Nh;c[b++]=this.oe;c[b++]=this.fd;c[b++]=this.xd;c[b++]=this.Qc;c[b++]=this.pl;c[b]=this.ug;a.set(0,c);return a.data()};k.restore=function(a){return this.Be(a[0])};
k.Be=function(a){var b=0;void 0===a&&(a=[0,0,384,0,1,0,0,96,48,[]]);this.gj=a[b++];this.rl=a[b++];this.vf=a[b++];this.Nh=a[b++];this.oe=a[b++];this.fd=a[b++];this.xd=a[b++];this.Qc=a[b++];this.pl=a[b++];this.ug=a[b];return!0};function Mj(a,b){a.ug=a.ug.concat(b);Pj(a)}function Pj(a){0<a.ug.length&&!(a.Qc&1)&&(a.gj=a.ug.shift(),a.Qc|=1);var b=-1;a.Qc&1&&a.Nh&1&&(b=4);0<=b?(a.oe&=-8,a.oe|=b,a.da&&a.ih&&Qh(a.da,a.ih)):(a.oe|=1,a.da&&a.ih&&Rh(a.da,a.ih))}
k.Be=function(a){var b=0;void 0===a&&(a=[0,0,384,0,1,0,0,96,48,[]]);this.gj=a[b++];this.rl=a[b++];this.vf=a[b++];this.Nh=a[b++];this.oe=a[b++];this.fd=a[b++];this.xd=a[b++];this.Qc=a[b++];this.pl=a[b++];this.ug=a[b];return!0};function Mj(a,b){a.ug=a.ug.concat(b);Pj(a)}function Pj(a){0<a.ug.length&&!(a.Qc&1)&&(a.gj=a.ug.shift(),a.Qc|=1);var b=-1;a.Qc&1&&a.Nh&1&&(b=4);0<=b?(a.oe&=-8,a.oe|=b,a.da&&a.ih&&Qh(a.da,a.ih,100)):(a.oe|=1,a.da&&a.ih&&Rh(a.da,a.ih))}
k.cp=function(a,b){var c=this.fd&128?this.vf&255:this.gj;p(this,a,null,b,this.fd&128?"DLL":"RBR",c);this.Qc&=-2;Pj(this);return c};k.Oo=function(a,b){var c=this.fd&128?this.vf>>8:this.Nh;p(this,a,null,b,this.fd&128?"DLM":"IER",c);return c};k.Po=function(a,b){var c=this.oe;p(this,a,null,b,"IIR",c);return c};k.Qo=function(a,b){var c=this.fd;p(this,a,null,b,"LCR",c);return c};k.So=function(a,b){var c=this.xd;p(this,a,null,b,"MCR",c);return c};
k.Ro=function(a,b){var c=this.Qc;p(this,a,null,b,"LSR",c);return c};k.Yo=function(a,b){var c=this.pl;p(this,a,null,b,"MSR",c);return c};k.tq=function(a,b,c){p(this,a,b,c,this.fd&128?"DLL":"THR");this.fd&128?this.vf=this.vf&-256|b:(this.rl=b,this.Qc&=-97,this.ue?(13!=b&&(8==b?this.ue.value=this.ue.value.slice(0,-1):(this.ue.value+=String.fromCharCode(b),this.ue.scrollTop=this.ue.scrollHeight)),a=!0):a=!1,a&&(this.Qc|=96))};
k.eq=function(a,b,c){p(this,a,b,c,this.fd&128?"DLM":"IER");this.fd&128?this.vf=this.vf&255|b<<8:this.Nh=b};k.fq=function(a,b,c){p(this,a,b,c,"LCR");this.fd=b};
@ -595,7 +595,7 @@ k.uc=function(a,b,c,d){this.xa=a;this.fa=b;this.N=c;this.X=d;this.video=rb(this.
k.ac=function(a){return a&&this.save?this.save():!0};k.reset=function(){this.Be()};k.save=function(){var a=new De(this);a.set(0,this.Vk());return a.data()};k.restore=function(a){return this.Be(a[0])};k.Be=function(a){var b=0;void 0===a&&(a=[!1,-1,-1,0,0,!1,!1,0]);this.setActive(a[b++]);this.ee=a[b++];this.fe=a[b++];this.xf=a[b++];this.yf=a[b++];this.ci=a[b++];this.di=a[b++];this.xd=a[b];return!0};
k.Vk=function(){var a=0,b=[];b[a++]=this.ld;b[a++]=this.ee;b[a++]=this.fe;b[a++]=this.xf;b[a++]=this.yf;b[a++]=this.ci;b[a++]=this.di;b[a]=this.xd;return b};k.qh=function(a){this.gi=a};function Qj(a,b){b&&(a.wj||(b.addEventListener("mousemove",function(b){a.$l(b)},!1),b.addEventListener("mousedown",function(b){a.nj(b.button,!0)},!1),b.addEventListener("mouseup",function(b){a.nj(b.button,!1)},!1),a.wj=!0),b.style.cursor="none")}function Rj(a){a&&(a.style.cursor="auto")}
k.$l=function(a){if(this.ld&&this.N&&this.N.ba.fb){if(0>this.ee||0>this.fe)this.ee=a.clientX,this.fe=a.clientY;this.gi?(this.xf=a.movementX||a.mozMovementX||a.webkitMovementX||0,this.yf=a.movementY||a.mozMovementY||a.webkitMovementY||0):(this.xf=a.clientX-this.ee,this.yf=a.clientY-this.fe);(this.xf||this.yf)&&Tj(this,null,a.clientX,a.clientY);this.ee=a.clientX;this.fe=a.clientY}};
k.nj=function(a,b){if(this.ld&&this.N&&this.N.ba.fb){var c;!(c=!1!==this.gi)&&(c=this.video)&&(c=this.video,c=c.bo?c.hf(!0):!1);c||(this.gi=null);switch(a){case 0:this.ci!=b&&(this.ci=b,Tj(this,"mouse button1 "+(b?"dn":"up")));break;case 2:this.di!=b&&(this.di=b,Tj(this,"mouse button2 "+(b?"dn":"up")))}}};
k.nj=function(a,b){if(this.ld&&this.N&&this.N.ba.fb){var c;!(c=!1!==this.gi)&&(c=this.video)&&(c=this.video,c=c.bo?c.hf(!0):!1);c||(this.gi=null);c="mouse button"+a+" "+(b?"dn":"up");switch(a){case 0:this.ci!=b&&(this.ci=b,Tj(this,c));break;case 2:this.di!=b&&(this.di=b,Tj(this,c))}}};
function Tj(a,b,c,d){var e=64|(a.ci?32:0)|(a.di?16:0)|(a.yf&192)>>4|(a.xf&192)>>6,f=a.xf&63,g=a.yf&63;a.ma(2097152)&&a.Ta((b?b+": ":"")+(void 0!==d?"mouse ("+c+","+d+"): ":"")+"serial packet ["+l(e)+","+l(f)+","+l(g)+"]",0,!0);Mj(a.Jg,[e,f,g]);a.xf=a.yf=0}La(function(){for(var a=db(window.document,"pcjs","mouse"),b=0;b<a.length;b++){var c=a[b],d=bb(c),d=new Sj(d);cb(d,c)}});
function Uj(a,b,c){n.call(this,"Disk",{id:a.Vl+".disk"+ ++Vj},Uj,1048576);this.V=a;this.xa=a.xa;this.X=a.X;this.Ja=b;this.Hd=b.name;this.Rf=b.Rf;this.hi=this.Sd=!1;this.create(c,b.ub,b.vb,b.zb,b.mb);this.Pe=[];this.Ch=[];this.ce=null;this.bm=0;this.Fj=!1;hb(this)}var Vj=0;Xa(n,Uj);k=Uj.prototype;k.uc=function(a,b,c,d){this.X=d};k.bc=function(a,b){b||!this.hi||this.Sd||(hb(this,!1),this.load(this.Hd,this.rf,null,this.Zn,this));return!0};k.Zn=function(){hb(this,!0)};
k.ac=function(a,b){if(this.Sd){var c,d=0;if(this.Fj&&!za("Disk writes are still in progress, shut down anyway?"))return!1;for(;c=Wj(this,!1);)if(d=c[0]){this.V.ya('Unable to save "'+this.Hd+'" (error '+d+")");break}b&&this.Sd&&(c="action=close&volume="+this.rf,c+="&machine="+this.V.Tf(),c+="&user="+this.V.ze(),va(wa()+"/api/v1/disk?"+c,!0),this.Sd=!1);!d&&a&&this.V.ya(this.Hd+" saved")}return!0};

View file

@ -559,7 +559,7 @@ za(function(){for(var a=Ra(window.document,"pcjs","video"),b=0;b<a.length;b++){v
function zi(a){this.$k=a.adapter;switch(this.$k){case 1:this.Xj=1016;this.sg=4;break;case 2:this.Xj=760;this.sg=3;break;default:m("Unrecognized serial adapter #"+this.$k);return}this.Pd=null;n.call(this,"SerialPort",a,zi);var b=a.binding,c;a=Ai;b&&(void 0===c&&(c="Panel"),(c=Oa(c,this.id))&&(b=c.la[b])&&this.Ab(null,a,b))}La(n,zi);var Ai="buffer";k=zi.prototype;k.vk=function(a,b){return a==this.yh?(this.Yd=b,this):null};
k.Ab=function(a,b,c){var d=this;switch(b){case Ai:return this.la[b]=this.Pd=c,c.onkeydown=function(a){a=a||window.event;var b=a.keyCode;8===b&&(a.preventDefault&&a.preventDefault(),Bi(d,[b]))},c.onkeypress=function(a){a=a||window.event;Bi(d,[a.which||a.keyCode])},!0}return!1};k.wc=function(a,b,c,d){this.ga=b;this.S=c;this.Ta=d;this.aa=bb(a,"ChipSet");Ib(b,this,Ci,this.Xj);Kb(b,this,Di,this.Xj);p(this)};k.Yb=function(a,b){if(!b)if(!a||!this.restore)this.reset();else if(!this.restore(a))return!1;return!0};
k.Xb=function(a){return a&&this.save?this.save():!0};k.reset=function(){this.Wd()};k.save=function(){var a=new Pd(this),b=0,c=[];c[b++]=this.oi;c[b++]=this.Bk;c[b++]=this.Te;c[b++]=this.Wg;c[b++]=this.Kd;c[b++]=this.te;c[b++]=this.ad;c[b++]=this.Bc;c[b++]=this.zk;c[b]=this.Mf;a.set(0,c);return a.data()};k.restore=function(a){return this.Wd(a[0])};
k.Wd=function(a){var b=0;void 0===a&&(a=[0,0,384,0,1,0,0,96,48,[]]);this.oi=a[b++];this.Bk=a[b++];this.Te=a[b++];this.Wg=a[b++];this.Kd=a[b++];this.te=a[b++];this.ad=a[b++];this.Bc=a[b++];this.zk=a[b++];this.Mf=a[b];return!0};function Bi(a,b){a.Mf=a.Mf.concat(b);Ei(a)}function Ei(a){0<a.Mf.length&&!(a.Bc&1)&&(a.oi=a.Mf.shift(),a.Bc|=1);var b=-1;a.Bc&1&&a.Wg&1&&(b=4);0<=b?(a.Kd&=-8,a.Kd|=b,a.aa&&a.sg&&Sg(a.aa,a.sg)):(a.Kd|=1,a.aa&&a.sg&&Tg(a.aa,a.sg))}
k.Wd=function(a){var b=0;void 0===a&&(a=[0,0,384,0,1,0,0,96,48,[]]);this.oi=a[b++];this.Bk=a[b++];this.Te=a[b++];this.Wg=a[b++];this.Kd=a[b++];this.te=a[b++];this.ad=a[b++];this.Bc=a[b++];this.zk=a[b++];this.Mf=a[b];return!0};function Bi(a,b){a.Mf=a.Mf.concat(b);Ei(a)}function Ei(a){0<a.Mf.length&&!(a.Bc&1)&&(a.oi=a.Mf.shift(),a.Bc|=1);var b=-1;a.Bc&1&&a.Wg&1&&(b=4);0<=b?(a.Kd&=-8,a.Kd|=b,a.aa&&a.sg&&Sg(a.aa,a.sg,100)):(a.Kd|=1,a.aa&&a.sg&&Tg(a.aa,a.sg))}
k.io=function(){var a=this.te&128?this.Te&255:this.oi;this.Bc&=-2;Ei(this);return a};k.Sn=function(){return this.te&128?this.Te>>8:this.Wg};k.Tn=function(){return this.Kd};k.Un=function(){return this.te};k.Wn=function(){return this.ad};k.Vn=function(){return this.Bc};k.bo=function(){return this.zk};
k.vp=function(a,b){if(this.te&128)this.Te=this.Te&-256|b;else{this.Bk=b;this.Bc&=-97;var c;this.Pd?(13!=b&&(8==b?this.Pd.value=this.Pd.value.slice(0,-1):(this.Pd.value+=String.fromCharCode(b),this.Pd.scrollTop=this.Pd.scrollHeight)),c=!0):c=!1;c&&(this.Bc|=96)}};k.gp=function(a,b){this.te&128?this.Te=this.Te&255|b<<8:this.Wg=b};k.hp=function(a,b){this.te=b};
k.ip=function(a,b){var c=this.ad;this.ad=b;if(this.Yd&&(c^b)&3){var c=this.Yd,d=this.ad,e=3==(d&3);if(e){if(!c.Vc){var f=!1;c.ad&2||(c.reset(),c.Zb("serial mouse reset"),f=!0);c.ad&1||(c.Zb("serial mouse ID requested"),f=!0);f&&(Bi(c.$f,[77,77]),c.Zb("serial mouse ID sent"));Fi(c,c.za);c.setActive(e)}}else c.Vc&&(c.Zb("serial mouse inactive"),Gi(c.za),c.setActive(e));c.ad=d}};