From ef2420f585511bf3630af9520cf79332273c3510 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Mon, 10 Oct 2016 18:16:36 -0700 Subject: [PATCH] Handled BYTE register accesses in the IOPAGE more consistently --- modules/pdp11/lib/bus.js | 48 ++++++++++++++++-------------- versions/pdpjs/1.30.1/pdp11-dbg.js | 2 +- versions/pdpjs/1.30.1/pdp11.js | 2 +- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/modules/pdp11/lib/bus.js b/modules/pdp11/lib/bus.js index 576f2b2ef..b55a8ec2f 100644 --- a/modules/pdp11/lib/bus.js +++ b/modules/pdp11/lib/bus.js @@ -207,34 +207,36 @@ BusPDP11.IOHANDLER = { * first, and depending on the underlying I/O device, that may or may not have side-effects. It's really * up to the device to know whether that matters, and provide all the necessary handlers if it does. * - * TODO: Unlike regular Memory blocks, IOPAGE accesses permit word accesses on ODD addresses; that works + * Unlike regular Memory blocks, IOPAGE accesses permit word accesses on ODD addresses; that works * just fine by registering WORD handlers for the appropriate ODD addresses. What is unclear, however, * is what is exactly supposed to happen when the CPU reads or writes a BYTE from an ODD IOPAGE address; - * it's likely that our built-in fallbacks are NOT correct for those cases. + * it seems clear that our built-in fallbacks are NOT correct in all cases. * * For example, let's imagine that only read/write WORD handlers have been registered for ODD address - * 177701 (ie, General Register R1, Set 0). If a readByte(177701) request is made, we would fallback to - * reading the word at 177700 and returning the high byte, but that would fetch the contents of General - * Register R0 instead of R1, which clearly seems wrong. + * 177701 (ie, general register R1, set 0). If a readByte(177701) request is made, we would fallback to + * reading the word at 177700 and returning the high byte, but that would fetch the contents of general + * register R0 instead of R1, which is clearly wrong. * * One solution is for the caller to register both BYTE and WORD handlers for ODD addresses, making * the caller responsible for the defining the correct behavior in all cases. However, that's more work * for the caller, and we're just punting the problem instead of solving it. * * Another solution is for addIOHandlers() to detect the ODD address case, and install custom fallback - * handlers for read and write BYTE accesses. In the above example, the custom read BYTE handler would - * invoke the read WORD handler and mask the result with 0xff, and the custom write BYTE handler would + * handlers for read and write BYTE accesses. In the above example, the custom read BYTE handler could + * invoke the read WORD handler and mask the result with 0xff, and the custom write BYTE handler could * first call the read WORD handler, insert the new data into the low byte of the result, and then * call the write WORD handler. * - * addIOHandlers() currently implements the second solution. Again, we're assuming that's the correct - * behavior for ODD IOPAGE accesses, which may not be a valid assumption. + * However, that would produce inconsistent results between EVEN and ODD addresses in the register + * address range (0o177700 through 0o177717), so I'm assuming that the correct solution is to install + * alternate fallback BYTE handlers for ALL addresses in that range. The alternate read BYTE handler will + * mask its result with 0xff, and the alternate write BYTE handler will store the (zero-extended) byte to + * the entire corresponding register. * - * One of things that gives me pause about the second solution is that when the destination of a MOVB - * instruction is a general register, the byte is sign-extended to a word. So it seems to strange to have - * a different MOVB behavior when the destination is ODD general register using an ODD IOPAGE address. - * Other byte instructions, like CLRB, would function identically when modifying ODD general registers, - * regardless how they are referenced. + * One of things that gives me pause about this solution is that it differs from the behavior of a MOVB + * instruction when the destination is a general register, because MOVB always sign-extends the source byte + * to a word; it does NOT zero-extend. So it seems to strange to have a different MOVB behavior when the + * destination register is specified using an IOPAGE address. But, maybe that was by design. * * TODO: Another small potential improvement would be for addIOHandlers() to predefine fall-backs for all * missing handlers, in both the ODD and EVEN cases, so there's never a need to check each function index @@ -1193,23 +1195,23 @@ BusPDP11.prototype.addIOTable = function(component, table) var fnWriteWord = afn[3]? afn[3].bind(component) : null; /* - * As discussed in the IOController comments above, when handlers are being registered for ODD addresses, - * we assume that we need different fallback handlers when reading and/or writing bytes. + * As discussed in the IOController comments above, when handlers are being registered for the following + * addresses, we must install different fallback handlers for all BYTE accesses. */ - if (addr & 0x1) { + if (addr >= PDP11.UNIBUS.R0SET0 && addr <= PDP11.UNIBUS.R6USER) { if (!fnReadByte && fnReadWord) { - fnReadByte = function(fnReadWord) { + fnReadByte = function readByteIORegister(readWord) { return function(addr) { - return fnReadWord(addr) & 0xff; + return readWord(addr) & 0xff; }.bind(component); }(fnReadWord); } - if (!fnWriteByte && fnWriteWord && fnReadWord) { - fnWriteByte = function(fnWriteWord, fnReadWord) { + if (!fnWriteByte && fnWriteWord) { + fnWriteByte = function writeByteIORegister(writeWord) { return function(data, addr) { - return fnWriteWord((fnReadWord(addr) & ~0xff) | data, addr); + return writeWord(data, addr); }.bind(component); - }(fnWriteWord, fnReadWord); + }(fnWriteWord); } } this.addIOHandlers(addr, addr, fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, afn[4]); diff --git a/versions/pdpjs/1.30.1/pdp11-dbg.js b/versions/pdpjs/1.30.1/pdp11-dbg.js index 9fd884407..cc465f45f 100644 --- a/versions/pdpjs/1.30.1/pdp11-dbg.js +++ b/versions/pdpjs/1.30.1/pdp11-dbg.js @@ -716,7 +716,7 @@ function Mb(a,b,c,d,e){for(var f=b,g=c,l=f>>>a.Y;0>>=a.Y;0>>=a.Y;0>>this.Y].tb(a&this.f,a)};h.ia=function(a){return this.W[(a&this.i)>>>this.Y].Yb(a&this.f,a)};function Qb(a,b){var c=b&a.f,d=(b&a.i)>>>a.Y;a.w++;b=a.W[d].Ab(c,b);a.w--;return b}h.mb=function(a,b){this.W[(a&this.i)>>>this.Y].ub(a&this.f,b&255,a)}; function Rb(a,b,c){a.w++;a.W[(b&a.i)>>>a.Y].Gb(b&a.f,c&255,b);a.w--}h.Sa=function(a,b){this.W[(a&this.i)>>>this.Y].fc(a&this.f,b&65535,a)};function Sb(a){for(var b=0,c=[],d=0;da.b.Vb)){var g=f[0]?f[0].bind(b):null,l=f[1]?f[1].bind(b):null,m=f[2]?f[2].bind(b):null,p=f[3]?f[3].bind(b):null;e&1&&(!g&&m&&(g=function(a){return function(b){return a(b)&255}.bind(b)}(m)),!l&&p&&m&&(l=function(a,c){return function(b,d){return a(c(d)&-256|b,d)}.bind(b)}(p,m)));Tb(a,e,e,g,l,m,p,f[4])}}}function Vb(a,b){a.B.push(b)} +function Ub(a,b,c){for(var d in c){var e=+d,f=c[d];if(!(f[5]&&f[5]>a.b.Vb)){var g=f[0]?f[0].bind(b):null,l=f[1]?f[1].bind(b):null,m=f[2]?f[2].bind(b):null,p=f[3]?f[3].bind(b):null;65472<=e&&65487>=e&&(!g&&m&&(g=function(a){return function(b){return a(b)&255}.bind(b)}(m)),!l&&p&&(l=function(a){return function(b,c){return a(b,c)}.bind(b)}(p)));Tb(a,e,e,g,l,m,p,f[4])}}}function Vb(a,b){a.B.push(b)} function Wb(a,b){a.w||(a.j&&E(a.j,536870912)&&B(a.j,"memory fault on address "+I(a.j,b),!0,!0),a.b.$(4,b))}function Ob(a,b,c){n("Memory block error ("+a+": "+k(b)+","+k(c)+")");return!1}function J(a){r.call(this,"Device",a,J,256);this.i={data:0,Gd:0,rb:20,Jd:0};this.f={Hd:0,Fb:-1}}y(J);h=J.prototype;h.Ca=function(a,b,c,d){this.w=b;this.b=c;this.j=d;var e=this;this.f.Fb=Xb(this.b,function(){e.f.Ha|=128;e.f.Ha&64&&(Yb(e.b,0,6,64),Zb(e.b,e.f.Fb,1E3/60))});Ub(b,this,K);Vb(b,this.reset.bind(this));G(this)}; h.yc=function(){var a=this.f.Ha;this.f.Ha&=-129;return a};h.fd=function(a){this.f.Ha=a;a&64&&Zb(this.b,this.f.Fb,1E3/60);this.f.Ha=a&-129};h.Ac=function(){var a=this.b;return a.G&62337|a.ra<<5|a.sa<<1};h.hd=function(a){var b=this.b;a&=62337;if(b.G!=a){b.G=a;b.ra=a>>5&3;b.sa=a>>1&15;var c=0;a&257&&(c=4,a&1&&(c|=2));b.sb!=c&&(b.sb=c,hc(b))}ic(this)};h.Bc=function(){var a=this.b.Ja;a&65280&&(a=(a<<8|a>>8)&65535);return a};h.Cc=function(){return this.b.Cb};h.Dc=function(){return this.b.Ka}; h.jd=function(a){var b=this.b;b.Ka!=a&&(b.Ka=a,a&16?(b.hb=4194303,b.va=3915776):(b.hb=262143,b.va=253952),hc(b));ic(this)};function ic(a){a.i.rb=a.i.rb&-8|(a.b.sb?a.b.Ka&16?1:2:4)}h.Pc=function(a){return this.b.R[1][a>>1&7]};h.vd=function(a,b){this.b.R[1][b>>1&7]=a&65295};h.Nc=function(a){return this.b.R[1][(a>>1&7)+8]};h.td=function(a,b){this.b.R[1][(b>>1&7)+8]=a&65295};h.Oc=function(a){return this.b.oa[1][a>>1&7]};h.ud=function(a,b){b=b>>1&7;this.b.oa[1][b]=a;this.b.R[1][b]&=65295}; diff --git a/versions/pdpjs/1.30.1/pdp11.js b/versions/pdpjs/1.30.1/pdp11.js index 248d99dee..b919f7a39 100644 --- a/versions/pdpjs/1.30.1/pdp11.js +++ b/versions/pdpjs/1.30.1/pdp11.js @@ -710,7 +710,7 @@ Ma.prototype.reset=function(){for(var a=0;a>>a.c;0h&&(u=h);if(!e&&n&&n.size){if(n.type==d){if(f+h<=n.ya)return n.Oa+=n.ya-f,n.ya=f,!0;if(f>=n.ya+n.Oa){u=n.size-(f-p);u>h&&(u=h);n.Oa=f-n.ya+u;f=p+a.l;h-=u;l++;continue}}return Ya(1,f,h)}f=new E(a,f,u,a.l,d,e);Ra(f,a.I,n);a.b[l++]=f;f=p+a.l;h-=u}return 0>=h?(a.status(Math.floor(c/1024)+"Kb "+Za[d]+" at "+k(b,8,!0)),!0):Ya(2,b,c)} function Va(a,b,c){var d=[];for(b>>>=a.c;0>>=a.c;0>>a.c].Xa(b&a.g,b)}function ab(a,b){return a.b[(b&a.i)>>>a.c].jc(b&a.g,b)}function bb(a,b,c){a.b[(b&a.i)>>>a.c].Rc(b&a.g,c&65535,b)} function cb(a){for(var b=0,c=[],d=0;da.a.Db)){var h=f[0]?f[0].bind(b):null,l=f[1]?f[1].bind(b):null,n=f[2]?f[2].bind(b):null,p=f[3]?f[3].bind(b):null;e&1&&(!h&&n&&(h=function(a){return function(b){return a(b)&255}.bind(b)}(n)),!l&&p&&n&&(l=function(a,c){return function(b,d){return a(c(d)&-256|b,d)}.bind(b)}(p,n)));db(a,e,e,h,l,n,p,f[4])}}}function fb(a,b){a.s.push(b)}function G(a){a.o||F(a.a,4)} +function eb(a,b,c){for(var d in c){var e=+d,f=c[d];if(!(f[5]&&f[5]>a.a.Db)){var h=f[0]?f[0].bind(b):null,l=f[1]?f[1].bind(b):null,n=f[2]?f[2].bind(b):null,p=f[3]?f[3].bind(b):null;65472<=e&&65487>=e&&(!h&&n&&(h=function(a){return function(b){return a(b)&255}.bind(b)}(n)),!l&&p&&(l=function(a){return function(b,c){return a(b,c)}.bind(b)}(p)));db(a,e,e,h,l,n,p,f[4])}}}function fb(a,b){a.s.push(b)}function G(a){a.o||F(a.a,4)} function Ya(a,b,c){q("Memory block error ("+a+": "+k(b)+","+k(c)+")");return!1}function H(a){v.call(this,"Device",a,H);this.c={data:0,Wc:0,Ma:20,$c:0};this.b={Zc:0,ab:-1}}x(H);g=H.prototype;g.ja=function(a,b,c,d){this.l=b;this.a=c;this.I=d;var e=this;this.b.ab=gb(this.a,function(){e.b.ka|=128;e.b.ka&64&&(hb(e.a,0,6,64),ib(e.a,e.b.ab,1E3/60))});eb(b,this,I);fb(b,this.reset.bind(this));D(this)};g.Mb=function(){var a=this.b.ka;this.b.ka&=-129;return a}; g.vc=function(a){this.b.ka=a;a&64&&ib(this.a,this.b.ab,1E3/60);this.b.ka=a&-129};g.Ob=function(){var a=this.a;return a.B&62337|a.Da<<5|a.Ea<<1};g.xc=function(a){var b=this.a;a&=62337;if(b.B!=a){b.B=a;b.Da=a>>5&3;b.Ea=a>>1&15;var c=0;a&257&&(c=4,a&1&&(c|=2));b.Na!=c&&(b.Na=c,jb(b))}kb(this)};g.Pb=function(){var a=this.a.la;a&65280&&(a=(a<<8|a>>8)&65535);return a};g.Qb=function(){return this.a.Za};g.Rb=function(){return this.a.ma}; g.yc=function(a){var b=this.a;b.ma!=a&&(b.ma=a,a&16?(b.Va=4194303,b.Fa=3915776):(b.Va=262143,b.Fa=253952),jb(b));kb(this)};function kb(a){a.c.Ma=a.c.Ma&-8|(a.a.Na?a.a.ma&16?1:2:4)}g.cc=function(a){return this.a.C[1][a>>1&7]};g.Kc=function(a,b){this.a.C[1][b>>1&7]=a&65295};g.ac=function(a){return this.a.C[1][(a>>1&7)+8]};g.Ic=function(a,b){this.a.C[1][(b>>1&7)+8]=a&65295};g.bc=function(a){return this.a.O[1][a>>1&7]};g.Jc=function(a,b){b=b>>1&7;this.a.O[1][b]=a;this.a.C[1][b]&=65295};