Allow the Debugger to step over "ADD [BX+SI],AL" in the rare case that it's valid

This commit is contained in:
Jeff Parsons 2015-10-20 09:57:46 -07:00
commit 8218e1a7da
2 changed files with 27 additions and 20 deletions

View file

@ -49,8 +49,8 @@ if (!I386) {
/* /*
* These are the original ModRM decoders, which were simpler and faster because they could treat all * These are the original ModRM decoders, which were simpler and faster because they could treat all
* word instructions as 16-bit, assume bits 16-31 of all registers were always zero, and use masking * word instructions as 16-bit, assume bits 16-31 of all registers were always zero, and use masking
* constants instead of variables. If I386 is enabled, these decoders are not used, and the compiler * constants instead of variables. If I386 is enabled, these decoders are not used, and the Closure
* will eliminate them from the compiled code. * Compiler will eliminate them from the compiled JavaScript code.
*/ */
if (NODE) { if (NODE) {
var X86ModB = require("./x86modb"); var X86ModB = require("./x86modb");
@ -814,7 +814,7 @@ X86CPU.prototype.enablePageBlocks = function()
* Note that since the incoming address (addr) is a linear address, we never need to mask it with nBusMask, * Note that since the incoming address (addr) is a linear address, we never need to mask it with nBusMask,
* but all the intermediate (PDE, PTE) and final physical addresses we calculate should still be masked. * but all the intermediate (PDE, PTE) and final physical addresses we calculate should still be masked.
* *
* Granted, nBusMask on a 32-bit bus is generally going to be 0xffffffff (-1), so making might seem like * Granted, nBusMask on a 32-bit bus is generally going to be 0xffffffff (-1), so masking might seem like
* a waste of time; however, if we decide to once again rely on nBusMask for emulating A20 wrap-around * a waste of time; however, if we decide to once again rely on nBusMask for emulating A20 wrap-around
* (instead of changing the physical memory map to alias the 2nd Mb to the 1st Mb), then performing * (instead of changing the physical memory map to alias the 2nd Mb to the 1st Mb), then performing
* consistent masking will be important. * consistent masking will be important.
@ -993,9 +993,9 @@ X86CPU.prototype.disablePageBlocks = function()
* It is recommended that you add an interrupt handler to the 8086 software that is to be run on the 80286, * It is recommended that you add an interrupt handler to the 8086 software that is to be run on the 80286,
* which will treat these interrupts as invalid operations. * which will treat these interrupts as invalid operations.
* *
* This additional software does not significantly effect the existing 8086 software because the interrupts * This additional software does not significantly effect [sic] the existing 8086 software because the interrupts
* do not normally occur and should not already have been used since they are in the interrupt group reserved * do not normally occur and should not already have been used since they are in the interrupt group reserved
* by Intel. [Note to Intel: IBM caaaaaaan't hear you]. * by Intel. [NOTE: IBM ignored Intel's admonishments.]
* *
* 2. Do not Rely on 8086/8088 Instruction Clock Counts * 2. Do not Rely on 8086/8088 Instruction Clock Counts
* *
@ -1035,7 +1035,7 @@ X86CPU.prototype.disablePageBlocks = function()
* 8. Do not Rely on the Value Written by PUSH SP * 8. Do not Rely on the Value Written by PUSH SP
* *
* The 80286 will push a different value on the stack for PUSH SP than the 8086/8088. If the value pushed is * The 80286 will push a different value on the stack for PUSH SP than the 8086/8088. If the value pushed is
* important [and when would it NOT be???], replace PUSH SP instructions with the following three instructions: * important [and when would it NOT be?], replace PUSH SP instructions with the following three instructions:
* *
* PUSH BP * PUSH BP
* MOV BP,SP * MOV BP,SP
@ -1118,7 +1118,7 @@ X86CPU.prototype.initProcessor = function()
* Instruction handlers that contain "hard-coded" 80286 cycle times include: opINSb, opINSw, opOUTSb, * Instruction handlers that contain "hard-coded" 80286 cycle times include: opINSb, opINSw, opOUTSb,
* opOUTSw, opENTER, and opLEAVE. * opOUTSw, opENTER, and opLEAVE.
*/ */
this.aOps = X86.aOps.slice(); // make copies of aOps and others before modifying them this.aOps = X86.aOps.slice(); // make copies of opcode tables before modifying
this.aOpGrp4b = X86.aOpGrp4b.slice(); this.aOpGrp4b = X86.aOpGrp4b.slice();
this.aOpGrp4w = X86.aOpGrp4w.slice(); this.aOpGrp4w = X86.aOpGrp4w.slice();
this.nShiftCountMask = 0x1f; // on newer processors, all shift counts are MOD 32 this.nShiftCountMask = 0x1f; // on newer processors, all shift counts are MOD 32
@ -1326,8 +1326,8 @@ X86CPU.prototype.setReg = function(i, reg)
* Similarly, regLSP mirrors the linear address corresponding to SS:SP, and therefore you must rely on getSP() * Similarly, regLSP mirrors the linear address corresponding to SS:SP, and therefore you must rely on getSP()
* to read the current SP, and setSP() and setSS() to update SP and SS. * to read the current SP, and setSP() and setSS() to update SP and SS.
* *
* The other segment registers, such as segDS and segES, have similar getters and setters, but they do not mirror * The other segment registers, such as segDS and segES, have similar getters and setters, but we do not mirror
* any segment:offset values in the same way that regLIP mirrors CS:IP, or that regLSP mirrors SS:SP. * any other segment:offset values in the same way that regLIP mirrors CS:IP, or that regLSP mirrors SS:SP.
* *
* @this {X86CPU} * @this {X86CPU}
*/ */
@ -1366,7 +1366,7 @@ X86CPU.prototype.resetRegs = function()
*/ */
this.regCR0 = X86.CR0.MSW.ON; this.regCR0 = X86.CR0.MSW.ON;
this.addrIDT = 0; this.addrIDTLimit = 0x03FF; this.addrIDT = 0; this.addrIDTLimit = 0x03FF;
this.regPS = this.nIOPL = 0; // these should be set before the first setPS() call this.regPS = this.nIOPL = 0;// these should be set before the first setPS() call
/* /*
* Define all the result registers that can be used to "cache" arithmetic and logical flags. * Define all the result registers that can be used to "cache" arithmetic and logical flags.
@ -1395,14 +1395,18 @@ X86CPU.prototype.resetRegs = function()
/* /*
* These are used to snapshot regLIP and regLSP, to help make instructions restartable; * These are used to snapshot regLIP and regLSP, to help make instructions restartable;
* currently opLIP is updated prior to every instruction, but opLSP is updated only for instructions * currently opLIP is updated prior to every instruction, but opLSP is updated only for instructions
* that read/write the stack (eg, RETF) and should otherwise remain set to X86.ADDR_INVALID. * that modify the stack pointer (eg, RETF) and should otherwise remain set to X86.ADDR_INVALID.
*
* More recently, opCS was added to selectively snapshot an instruction's original CS in case an
* exception occurs accessing the stack after a new CS has been loaded, allowing the exception handler
* to recover the old CS and make instructions like CALLF restartable; otherwise, opCS should remain -1.
*/ */
this.opCS = -1; this.opCS = -1;
this.opLIP = this.opLSP = X86.ADDR_INVALID; this.opLIP = this.opLSP = X86.ADDR_INVALID;
/* /*
* Segment registers used to be defined as separate variables (eg, regCS and regCS0 stored the segment * Segment registers used to be defined as separate selector and base variables (eg, regCS and regCS0),
* number and base linear address, respectively), but segment registers are now defined as X86Seg objects. * but now they are defined as X86Seg objects.
*/ */
this.segCS = new X86Seg(this, X86Seg.ID.CODE, "CS"); this.segCS = new X86Seg(this, X86Seg.ID.CODE, "CS");
this.segDS = new X86Seg(this, X86Seg.ID.DATA, "DS"); this.segDS = new X86Seg(this, X86Seg.ID.DATA, "DS");
@ -1455,8 +1459,8 @@ X86CPU.prototype.resetRegs = function()
* (and too difficult in protected-mode) to merit the overhead. Ditto for SP, which can't really * (and too difficult in protected-mode) to merit the overhead. Ditto for SP, which can't really
* be considered a general-purpose register. * be considered a general-purpose register.
* *
* Every time getByte() is called, btMemLo is filled with the matching backtrack info; similarly, * Every time getByte() is called, btiMem0 is filled with the matching backtrack info; similarly,
* every time getWord() is called, btMemLo and btMemHi are filled with the matching backtrack info * every time getWord() is called, btiMem0 and btiMem1 are filled with the matching backtrack info
* for the low and high bytes, respectively. * for the low and high bytes, respectively.
*/ */
this.backTrack = { this.backTrack = {

View file

@ -49,12 +49,15 @@ X86.opADDmb = function ADDmb()
var b = this.getIPByte(); var b = this.getIPByte();
/* /*
* Opcode bytes 0x00 0x00 are sufficiently uncommon that it's more likely we've started * Opcode bytes 0x00 0x00 are sufficiently uncommon that it's more likely we've started
* executing in the weeds, so we'll print a warning if you're in DEBUG mode, and optionally * executing in the weeds, so if you're in DEBUG mode, we'll print a warning and stop the
* stop the CPU if a Debugger is available. * CPU if a Debugger is available.
*
* Notice that we also test fRunning: this allows the Debugger to step over the instruction,
* because its trace ("t") command doesn't "run" the CPU; it merely "steps" the CPU.
*/ */
if (DEBUG && !b) { if (DEBUG && !b && this.aFlags.fRunning) {
this.printMessage("suspicious opcode: 0x00 0x00", DEBUGGER || this.bitsMessage); this.printMessage("suspicious opcode: 0x00 0x00", DEBUGGER || this.bitsMessage);
if (DEBUGGER && this.dbg) this.stopCPU(); if (DEBUGGER && this.dbg) this.dbg.stopCPU();
} }
this.aOpModMemByte[b].call(this, X86.fnADDb); this.aOpModMemByte[b].call(this, X86.fnADDb);
}; };
@ -4157,7 +4160,7 @@ X86.opHLT = function HLT()
*/ */
if (DEBUGGER && this.dbg && this.messageEnabled(Messages.HALT)) { if (DEBUGGER && this.dbg && this.messageEnabled(Messages.HALT)) {
this.rewindIP(-1); // this is purely for the Debugger's benefit, to show the HLT this.rewindIP(-1); // this is purely for the Debugger's benefit, to show the HLT
this.stopCPU(); this.dbg.stopCPU();
return; return;
} }
/* /*