From 0cbae3ea11e29cbc60e6a64f3545070950c530b2 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Thu, 26 Mar 2015 12:13:16 -0700 Subject: [PATCH] Assorted tweaks for the DeskPro 386 ROM --- devices/pc/bios/compaq/deskpro386/notes.md | 42 ++++++++++++++++++++++ modules/pcjs/lib/chipset.js | 7 ++++ modules/pcjs/lib/ram.js | 2 +- modules/pcjs/lib/x86cpu.js | 2 +- modules/pcjs/lib/x86func.js | 20 ++++++++--- modules/pcjs/lib/x86seg.js | 14 +++++--- 6 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 devices/pc/bios/compaq/deskpro386/notes.md diff --git a/devices/pc/bios/compaq/deskpro386/notes.md b/devices/pc/bios/compaq/deskpro386/notes.md new file mode 100644 index 000000000..3d5690850 --- /dev/null +++ b/devices/pc/bios/compaq/deskpro386/notes.md @@ -0,0 +1,42 @@ +Debugging Notes +=== + +Checkpoint +--- +This code: + + F000:F9E9 B000 MOV AL,00 + F000:F9EB E620 OUT 20,AL + +triggers the following warning: + + notice: PIC0(0x20): unsupported OCW2 automatic EOI command: 0x00 + +and the very next instruction: + + F000:F9ED E6A0 OUT A0,AL + +triggers the same warning: + + notice: PIC1(0xA0): unsupported OCW2 automatic EOI command: 0x00 + +Checkpoint +--- +There's a loop at F000:B5AA that stores 0x4000 DWORDs into RAM (ie, 64Kb), where each DWORD is +a single-bit left rotation of the preceding DWORD. This is followed by another loop that loads +each DWORD and verifies that it contains the appropriate bit. + +Then a stack is set up in RAM (at 0030:0100) and the first CALL is issued: + + F000:BC2E E87DEC CALL A8AE + +There's some CMOS I/O activity, serial and parallel port I/O, more CMOS I/O, and then some EGA I/O. + +When arrive here: + + C000:016D B80700 MOV AX,0007 + C000:0170 CD10 INT 10 + +and we complain that the IDTR limit for the real-mode IDT isn't 0x3FF (it's been set to 0xFFFF instead). +That may be OK, but I need to verify that that's what the ROM intended. If it is, then I'll probably need +to change our assertion from "cpu.addrIDTLimit == 0x03FF" to "cpu.addrIDTLimit >= 0x03FF". diff --git a/modules/pcjs/lib/chipset.js b/modules/pcjs/lib/chipset.js index c2a75c89a..1d8e2588c 100644 --- a/modules/pcjs/lib/chipset.js +++ b/modules/pcjs/lib/chipset.js @@ -4348,6 +4348,13 @@ ChipSet.prototype.out8042InBuffCmd = function(port, bOut, addrFrom) this.set8042OutPort(ChipSet.KBC.OUTPORT.NO_RESET | ChipSet.KBC.OUTPORT.A20_ON); break; + case ChipSet.KBC.CMD.INTF_TEST: // 0xAB + /* + * TODO: Determine all the side-effects of the Interface Test, if any. + */ + this.set8042OutBuff(ChipSet.KBC.DATA.INTF_TEST.OK); + break; + case ChipSet.KBC.CMD.READ_TEST: // 0xE0 this.set8042OutBuff((this.b8042CmdData & ChipSet.KBC.DATA.CMD.NO_CLOCK)? 0 : ChipSet.KBC.TESTPORT.KBD_CLOCK); break; diff --git a/modules/pcjs/lib/ram.js b/modules/pcjs/lib/ram.js index b754feee3..468e9870b 100644 --- a/modules/pcjs/lib/ram.js +++ b/modules/pcjs/lib/ram.js @@ -351,8 +351,8 @@ CompaqController.writeByte = function writeCompaqControllerByte(off, b) } } controller.bMappings = b; + if (DEBUG) this.cpu.stopCPU(); } - if (DEBUG) this.cpu.stopCPU(); }; CompaqController.ACCESS = [CompaqController.readByte, CompaqController.readByte, CompaqController.readByte, diff --git a/modules/pcjs/lib/x86cpu.js b/modules/pcjs/lib/x86cpu.js index 33b6706c6..8e9f02390 100644 --- a/modules/pcjs/lib/x86cpu.js +++ b/modules/pcjs/lib/x86cpu.js @@ -3402,7 +3402,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles) if (I386 && (this.opPrefixes & (X86.OPFLAG.ADDRSIZE | X86.OPFLAG.DATASIZE))) { this.resetSizes(); - if (DEBUG && DEBUGGER) { + if (MAXDEBUG && DEBUGGER) { this.println("80386 override processed"); this.stopCPU(); break; diff --git a/modules/pcjs/lib/x86func.js b/modules/pcjs/lib/x86func.js index 7d5976e16..1bea121b3 100644 --- a/modules/pcjs/lib/x86func.js +++ b/modules/pcjs/lib/x86func.js @@ -1393,10 +1393,15 @@ X86.fnRCLd = function RCLd(dst, src) { var result = dst; var flagsIn = (DEBUG? this.getPS() : 0); - var shift = src & this.nShiftCountMask; + var shift = src & this.nShiftCountMask; // Yes, this 32-bit-only function could mask with 0x1f directly if (shift) { var carry = this.getCarry(); - result = (dst << shift) | (carry << (shift - 1)) | (dst >>> (32 - shift)); + /* + * JavaScript Alert: much like a post-8086 Intel CPU, JavaScript shift counts are mod 32, + * so "dst >>> 32" is equivalent to "dst >>> 0", which doesn't shift any bits at all. To + * compensate, we shift one bit less than the maximum, and then shift one bit farther. + */ + result = (dst << shift) | (carry << (shift - 1)) | ((dst >>> (32 - shift)) >>> 1); carry = dst << (shift - 1); X86.setRotateResult.call(this, result, carry, X86.RESULT.DWORD); } @@ -1472,10 +1477,15 @@ X86.fnRCRd = function RCRd(dst, src) { var result = dst; var flagsIn = (DEBUG? this.getPS() : 0); - var shift = src & this.nShiftCountMask; + var shift = src & this.nShiftCountMask; // Yes, this 32-bit-only function could mask with 0x1f directly if (shift) { var carry = this.getCarry(); - result = (dst >>> shift) | (carry << (32 - shift)) | (dst << (33 - shift)); + /* + * JavaScript Alert: much like a post-8086 Intel CPU, JavaScript shift counts are mod 32, + * so "dst << 32" is equivalent to "dst << 0", which doesn't shift any bits at all. To + * compensate, we shift one bit less than the maximum, and then shift one bit farther. + */ + result = (dst >>> shift) | (carry << (32 - shift)) | ((dst << (32 - shift)) << 1); carry = dst << (32 - shift); X86.setRotateResult.call(this, result, carry, X86.RESULT.DWORD); } @@ -1507,7 +1517,7 @@ X86.fnRETF = function RETF(n) * * TODO: I'm not clear on whether a conforming code segment must also be marked readable, so I'm playing * it safe and using CODE_CONFORMING instead of CODE_CONFORMING_READABLE. Also, for the record, I've not - * seen this situation occur in OS/2 1.0 yet. + * seen this situation occur yet (eg, in OS/2 1.0). */ if ((this.segDS.sel & X86.SEL.MASK) && this.segDS.dpl < this.segCS.cpl && (this.segDS.acc & X86.DESC.ACC.TYPE.CODE_CONFORMING) != X86.DESC.ACC.TYPE.CODE_CONFORMING) { this.assert(false); // I'm not asserting this is bad, I just want to see it in action diff --git a/modules/pcjs/lib/x86seg.js b/modules/pcjs/lib/x86seg.js index b243e9394..d43e7507b 100644 --- a/modules/pcjs/lib/x86seg.js +++ b/modules/pcjs/lib/x86seg.js @@ -121,11 +121,10 @@ X86Seg.ID = { */ X86Seg.loadReal = function loadReal(sel, fSuppress) { - this.cpu.assert(!(sel & ~0xffff)); - this.sel = sel; + this.sel = sel & 0xffff; this.dataSize = this.addrSize = 2; this.dataMask = this.addrMask = 0xffff; - return this.base = sel << 4; + return this.base = this.sel << 4; }; /** @@ -157,7 +156,7 @@ X86Seg.loadProt = function loadProt(sel, fSuppress) var addrDTLimit; var cpu = this.cpu; - this.cpu.assert(!(sel & ~0xffff)); + sel &= 0xffff; if (!(sel & X86.SEL.LDT)) { addrDT = cpu.addrGDT; @@ -205,7 +204,12 @@ X86Seg.loadProt = function loadProt(sel, fSuppress) X86Seg.loadIDTReal = function loadIDTReal(nIDT) { var cpu = this.cpu; - cpu.assert(nIDT >= 0 && nIDT < 256 && !cpu.addrIDT && cpu.addrIDTLimit == 0x03FF); + /* + * NOTE: The Compaq DeskPro 386 ROM loads the IDTR for the real-mode IDT with a limit of 0xffff instead + * of the normal 0x3ff. A limit higher than 0x3ff is OK, since all real-mode IDT entries are 4 bytes, and + * there's no way to issue an interrupt with a vector > 0xff. Just something to be aware of. + */ + cpu.assert(nIDT >= 0 && nIDT < 256 && !cpu.addrIDT && cpu.addrIDTLimit >= 0x3ff); /* * Intel documentation for INT/INTO under "REAL ADDRESS MODE EXCEPTIONS" says: *