From 9fa29413941b1c2e6709abe0c66bedd017a444ff Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Sun, 2 Aug 2015 21:11:19 -0700 Subject: [PATCH] Limited Debug register support --- modules/pcjs/lib/debugger.js | 53 +++++++++++------- modules/pcjs/lib/disk.js | 2 +- modules/pcjs/lib/memory.js | 19 +++++-- modules/pcjs/lib/x86.js | 15 +++--- modules/pcjs/lib/x86cpu.js | 101 ++++++++++++++++++++++++++++++----- modules/pcjs/lib/x86func.js | 7 +++ modules/pcjs/lib/x86op0f.js | 56 +++++++------------ 7 files changed, 168 insertions(+), 85 deletions(-) diff --git a/modules/pcjs/lib/debugger.js b/modules/pcjs/lib/debugger.js index 957cd1354..55d7109bf 100644 --- a/modules/pcjs/lib/debugger.js +++ b/modules/pcjs/lib/debugger.js @@ -1662,6 +1662,10 @@ if (DEBUGGER) { /** * newAddr(off, sel, addr, fProt, fData32, fAddr32) * + * NOTES: If 'off' is undefined, it may be because parseExpression() was unable to parse the given value, + * in which case we need to make sure that 'off' passes through as undefined, so that callers can test for + * "dbgAddr.off == null" to detect invalid addresses. + * * @this {Debugger} * @param {number|null|undefined} [off] (default is zero) * @param {number|null|undefined} [sel] (default is undefined) @@ -2406,9 +2410,11 @@ if (DEBUGGER) { while ((i = s.indexOf('$', i)) >= 0) { sAddr = s.substr(i+1, 9); dbgAddr = this.parseAddr(sAddr); - sReplace = sAddr + ' "' + this.getSZ(dbgAddr) + '"'; - s = s.replace('$' + sAddr, sReplace); - i += sReplace.length; + if (dbgAddr) { + sReplace = sAddr + ' "' + this.getSZ(dbgAddr) + '"'; + s = s.replace('$' + sAddr, sReplace); + i += sReplace.length; + } } /* * Replace every ^XXXX:XXXX, where XXXX:XXXX is a segmented address, with the FCB filename stored at that address. @@ -2417,10 +2423,12 @@ if (DEBUGGER) { while ((i = s.indexOf('^', i)) >= 0) { sAddr = s.substr(i+1, 9); dbgAddr = this.parseAddr(sAddr); - this.incAddr(dbgAddr); - sReplace = sAddr + ' "' + this.getSZ(dbgAddr, 11) + '"'; - s = s.replace('^' + sAddr, sReplace); - i += sReplace.length; + if (dbgAddr) { + this.incAddr(dbgAddr); + sReplace = sAddr + ' "' + this.getSZ(dbgAddr, 11) + '"'; + s = s.replace('^' + sAddr, sReplace); + i += sReplace.length; + } } return s; }; @@ -4049,7 +4057,7 @@ if (DEBUGGER) { * @param {string|undefined} sAddr * @param {number|undefined} [type] is the address segment type, in case sAddr doesn't specify a segment * @param {boolean} [fNoChecks] (eg, true when setting breakpoints that may not be valid now, but will be later) - * @return {{DbgAddr}} + * @return {{DbgAddr}|null|undefined} */ Debugger.prototype.parseAddr = function(sAddr, type, fNoChecks) { @@ -4076,6 +4084,7 @@ if (DEBUGGER) { addr = null; } else { addr = this.parseExpression(sAddr); + if (addr == null) off = null; } } else { @@ -4085,8 +4094,10 @@ if (DEBUGGER) { } } - dbgAddr = this.newAddr(off, sel, addr); - if (!fNoChecks) this.checkLimit(dbgAddr); + if (off != null) { + dbgAddr = this.newAddr(off, sel, addr); + if (!fNoChecks) this.checkLimit(dbgAddr); + } return dbgAddr; }; @@ -4548,7 +4559,7 @@ if (DEBUGGER) { Debugger.prototype.doAssemble = function(asArgs) { var dbgAddr = this.parseAddr(asArgs[1], Debugger.ADDR_CODE); - if (dbgAddr.off == null) return; + if (!dbgAddr) return; this.dbgAddrAssemble = dbgAddr; if (asArgs[2] === undefined) { @@ -4626,7 +4637,7 @@ if (DEBUGGER) { var dbgAddr = {}; if (sAddr != "*") { dbgAddr = this.parseAddr(sAddr, Debugger.ADDR_CODE, true); - if (dbgAddr.off == null) return; + if (!dbgAddr) return; } /* @@ -4767,7 +4778,7 @@ if (DEBUGGER) { } } var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR_DATA); - if (dbgAddr.off == null || dbgAddr.sel == null && dbgAddr.addr == null) return; + if (!dbgAddr) return; var sDump = ""; if (BACKTRACK && sCmd == "di") { @@ -4821,7 +4832,8 @@ if (DEBUGGER) { return; } var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR_DATA); - if (dbgAddr.off == null) return; + if (!dbgAddr) return; + for (var i = 2; i < asArgs.length; i++) { var b = str.parseInt(asArgs[i], 16); if (b === undefined) { @@ -5004,8 +5016,7 @@ if (DEBUGGER) { Debugger.prototype.doList = function(sSymbol) { var dbgAddr = this.parseAddr(sSymbol, Debugger.ADDR_CODE); - - if (dbgAddr.off == null && dbgAddr.addr == null) return; + if (!dbgAddr) return; var addr = this.getAddr(dbgAddr); sSymbol = sSymbol? (sSymbol + ": ") : ""; @@ -5064,7 +5075,9 @@ if (DEBUGGER) { var fJSON = (asArgs[1] == "json"); var iDrive, iSector = 0, nSectors = 0; + var dbgAddr = (fJSON? {} : this.parseAddr(asArgs[1], Debugger.ADDR_DATA)); + if (!dbgAddr) return; iDrive = this.parseValue(asArgs[2], "drive #"); if (iDrive === undefined) return; @@ -5086,7 +5099,7 @@ if (DEBUGGER) { * drive and its disk are inseparable; it's certainly possible that its disk object may be empty at * this point, but that will only affect whether the read succeeds or not. */ - var dc = this.fdc; + var dc = this .fdc; if (iDrive >= 2 && this.hdc) { iDrive -= 2; dc = this.hdc; @@ -5547,7 +5560,7 @@ if (DEBUGGER) { { if (sAddr !== undefined) { var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR_CODE); - if (dbgAddr.off == null) return; + if (!dbgAddr) return; this.setTempBreakpoint(dbgAddr); } if (!this.runCPU(true)) { @@ -5841,7 +5854,7 @@ if (DEBUGGER) { Debugger.prototype.doUnassemble = function(sAddr, sAddrEnd, n) { var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR_CODE); - if (dbgAddr.off == null) return; + if (!dbgAddr) return; if (n === undefined) n = 1; var dbgAddrEnd = this.newAddr(this.maskReg, dbgAddr.sel, this.bus.nBusLimit); @@ -5850,7 +5863,7 @@ if (DEBUGGER) { if (sAddrEnd !== undefined) { dbgAddrEnd = this.parseAddr(sAddrEnd, Debugger.ADDR_CODE); - if (dbgAddrEnd.off == null || dbgAddrEnd.off < dbgAddr.off) return; + if (!dbgAddrEnd || dbgAddrEnd.off < dbgAddr.off) return; cb = dbgAddrEnd.off - dbgAddr.off; if (!DEBUG && cb > 0x100) { diff --git a/modules/pcjs/lib/disk.js b/modules/pcjs/lib/disk.js index fc95ed408..caec5aa6e 100644 --- a/modules/pcjs/lib/disk.js +++ b/modules/pcjs/lib/disk.js @@ -2142,7 +2142,7 @@ Disk.prototype.toJSON = function() /* * Last but not least, insert line breaks after every object definition, to ease the pain on text editors. */ - s = s.replace(/},/gm, "},\n"); + s = s.replace(/([\]}]),/gm, "$1,\n"); return s; }; diff --git a/modules/pcjs/lib/memory.js b/modules/pcjs/lib/memory.js index 08adaf69b..6341b63e6 100644 --- a/modules/pcjs/lib/memory.js +++ b/modules/pcjs/lib/memory.js @@ -108,7 +108,7 @@ function Memory(addr, used, size, type, controller, cpu) this.type = type || Memory.TYPE.NONE; this.fReadOnly = (type == Memory.TYPE.ROM); this.controller = null; - this.cpu = cpu; + this.cpu = cpu; // If a CPU reference is provided, then this must be an UNPAGED Memory block allocation this.fDirty = this.fDirtyEver = false; this.setPhysBlock(); @@ -490,6 +490,8 @@ Memory.prototype = { /** * getPageBlock(addr, fWrite) * + * Called for UNPAGED Memory blocks only. + * * @this {Memory} * @param {number} addr * @param {boolean} fWrite (true if called for a write, false if for a read) @@ -526,7 +528,7 @@ Memory.prototype = { * * NOTE: Some Memory blocks already require access to the CPU (eg, UNPAGED blocks that need to call cpu.mapPageBlock()), * while others require access only if the CPU has set a read or write breakpoint in one of its Debug registers; the latter - * case is handled here by virtue of the cpu parameter. + * case is handled here by virtue of the CPU parameter. * * @this {Memory} * @param {number} off @@ -552,9 +554,15 @@ Memory.prototype = { /** * removeBreakpoint(off, fWrite) * - * NOTE: If this Memory block is not an UNPAGED block that might need to call cpu.mapPageBlock()), and it no longer - * has any read or write breakpoints associated with it, then it no longer needs a CPU reference. However, the latter - * is a moot point, because the "checked" memory access functions should be swapped out when this function is done. + * NOTE: If this Memory block is not an UNPAGED block that might need to call cpu.mapPageBlock()), and it no + * longer has any read or write breakpoints associated with it, then it no longer needs a CPU reference. The + * existence of a CPU reference only impacts the performance of the "checked" memory access functions, so it's + * not critical to eliminate it, but we do it anyway, in case the "checked" functions become re-enabled later + * (eg, by the Debugger -- yeah, the Debugger, which is why eliminating it isn't critical). + * + * TODO: Another option would be to count CPU references separately from Debugger references, so that when the + * former goes to zero, we can unconditionally remove the CPU reference; UNPAGED blocks would automatically + * increment that reference count, so their CPU reference would never go away. * * @this {Memory} * @param {number} off @@ -575,6 +583,7 @@ Memory.prototype = { } Component.assert(this.cWriteBreakpoints >= 0); } + if (!this.cReadBreakpoints && !this.cWriteBreakpoints && this.type != Memory.TYPE.UNPAGED) this.cpu = null; }, /** * readNone(off) diff --git a/modules/pcjs/lib/x86.js b/modules/pcjs/lib/x86.js index e74366c69..8bd7e2e7f 100644 --- a/modules/pcjs/lib/x86.js +++ b/modules/pcjs/lib/x86.js @@ -409,18 +409,19 @@ var X86 = { * Bit values for opFlags, which are all reset to zero prior to each instruction */ OPFLAG: { - NOREAD: 0x0001, - NOWRITE: 0x0002, - NOINTR: 0x0004, // indicates a segreg has been set, or a prefix, or an STI (delay INTR acknowledgement) - FAULT: 0x0008, // indicates a fault occurred during the current instruction + NOREAD: 0x0001, // disable memory reads for the remainder of the current instruction + NOWRITE: 0x0002, // disable memory writes for the remainder of the current instruction + NOINTR: 0x0004, // a segreg has been set, or a prefix, or an STI (delay INTR acknowledgement) SEG: 0x0010, // segment override LOCK: 0x0020, // lock prefix REPZ: 0x0040, // repeat while Z (NOTE: this value MUST match PS.ZF; see opCMPSb/opCMPSw/opSCASb/opSCASw) REPNZ: 0x0080, // repeat while NZ - REPEAT: 0x0100, // indicates that an instruction is being repeated (ie, some iteration AFTER the first) + REPEAT: 0x0100, // an instruction is being repeated (ie, some iteration AFTER the first) PUSHSP: 0x0200, // the SP register is potentially being referenced by a PUSH SP opcode, adjustment may be required - DATASIZE: 0x1000, // data size override - ADDRSIZE: 0x2000 // address size override + DATASIZE: 0x0400, // data size override + ADDRSIZE: 0x0800, // address size override + FAULT: 0x1000, // a fault occurred during the current instruction + DEBUG: 0x2000 // a DEBUG exception occurred during the current instruction }, /* * Bit values for intFlags diff --git a/modules/pcjs/lib/x86cpu.js b/modules/pcjs/lib/x86cpu.js index 32c0b0695..105de30ad 100644 --- a/modules/pcjs/lib/x86cpu.js +++ b/modules/pcjs/lib/x86cpu.js @@ -1683,7 +1683,7 @@ X86CPU.prototype.checkIntReturn = function(addr) * * These functions provide Debug register functionality by leveraging the same Memory block-based breakpoint * support originally created for our built-in Debugger. Only minimal changes were required to the Memory - * component, by adding additional checkMemoryException() call-outs to the "checked" Memory access functions. + * component, by adding additional checkMemoryException() call-outs from the "checked" Memory access functions. * * Note that those call-outs occur only AFTER our own Debugger (if present) has checked the address and has * passed on it, because we want our own Debugger's breakpoints to take precedence over any breakpoints that @@ -1712,6 +1712,58 @@ X86CPU.prototype.removeMemCheck = function(addr, fWrite) this.aMemBlocks[iBlock].removeBreakpoint(addr & this.nBlockLimit, fWrite); }; +/** + * checkDebugRegisters(fEnable) + * + * opMOVdr() simplifies its life by doing work ONLY if the contents of a Debug register is actually changing. + * + * Whenever a single register is about to change, it calls this function with fEnable set to false to REMOVE any + * active checks, then updates the Debug register, then calls us again with fEnable set to true to (re)ADD active + * checks. + * + * @this {X86CPU} + * @param {boolean} fEnable + */ +X86CPU.prototype.checkDebugRegisters = function(fEnable) +{ + /* + * We use a constant mask for the enable bits (X86.DR7.L0 | X86.DR7.G0) and shift our copy of regDR7 + * right 2 bits after each Debug register check. + * + * Similarly, we make a copy of regDR7 in bitsDR7 and shift the latter right 4 bits at a time, so that + * the RW and LEN bits for the next Debug register are always in positions 1-0 and 3-2, respectively. + */ + var regDR7 = this.regDR[7]; + var bitsDR7 = regDR7 >> 16; + + for (var i = 0; i < 4; i++) { + if (regDR7 & (X86.DR7.L0 | X86.DR7.G0)) { + /* + * We look only to the low bit of the RW field to determine if we should be watching for a write. + * FYI, if the low bit is clear but the high bit is set, that's "undefined"; we treat it as a read. + */ + var fWrite = !!(bitsDR7 & 0x1); + /* + * The address in regDR[i] should already be masked with ~0x1 for 2-byte accesses (LEN == 0x1) or + * with ~0x3 for 4-byte accesses (LEN == 0x3), but if the client forgets, the hardware supposedly + * enforces it, so that's what we do here, too. + * + * FYI, if LEN is set to the "undefined" value of (0x2), we still apply a mask to the address, albeit + * a nonsensical mask of ~0x2 or 0xfffffffd. That's how we define that particular "undefined" LEN. + */ + var addr = this.regDR[i]; + var len = ((bitsDR7 >> 2) & 0x3); + addr &= ~len; // NOTE: if LEN == 0x0, we don't need to mask, but ~0x0 is equivalent to no mask + if (fEnable) { + this.addMemCheck(addr, fWrite); + } else { + this.removeMemCheck(addr, fWrite); + } + } + regDR7 >>= 2; bitsDR7 >>= 4; + } +}; + /** * checkMemoryException(addr, nb, fWrite) * @@ -1719,8 +1771,8 @@ X86CPU.prototype.removeMemCheck = function(addr, fWrite) * giving us the opportunity look for a matching "read" or "write" breakpoint enabled in one of the DRn registers. * * TODO: This currently does not discriminate between data reads and execution reads. When we switch to a true - * "prefetch" model, that would also be a good time to include a signal to this function that any "read" accesses - * are actually "exec" accesses. + * "prefetch" model, that would also be a good time to include a signal to this function which "read" accesses are + * are actually "exec" accesses. * * @this {X86CPU} * @param {number} addr @@ -1729,24 +1781,45 @@ X86CPU.prototype.removeMemCheck = function(addr, fWrite) */ X86CPU.prototype.checkMemoryException = function(addr, nb, fWrite) { - if (this.regDR[7] & X86.DR7.ENABLE) { + /* + * NOTE: We're preventing redundant X86.EXCEPTION.DEBUG exceptions for a single instruction by checking + * X86.OPFLAG.DEBUG. I decided not to rely on the generic X86.OPFLAG.FAULT, because if an instruction + * first triggers a DIFFERENT exception which then triggers a DEBUG exception (eg, because a Debug register + * was set on the IDT entry of the first exception), that we'd actually like to see the DEBUG exception, + * as opposed to, say, a double fault. TODO: Determine if that SHOULD generate a double-fault. + */ + if (!(this.opFlags & X86.OPFLAG.FAULT) && (this.regDR[7] & X86.DR7.ENABLE)) { + nb--; + /* + * We use a constant mask for the enable bits (X86.DR7.L0 | X86.DR7.G0) and shift our copy of regDR7 + * right 2 bits after each Debug register check. + * + * Similarly, we make a copy of regDR7 in bitsDR7 and shift the latter right 4 bits at a time, so that + * the RW and LEN bits for the next Debug register are always in positions 1-0 and 3-2, respectively. + */ var regDR7 = this.regDR[7]; - var bitsEnabled = X86.DR7.L0 | X86.DR7.G0; - var bitsRWMask = 0x00030000; - var bitsRWRequired = (fWrite? 0x00010000 : (fWrite == false? 0x00030000 : 0)); - var bitsLENMask = 0x000C0000; - var bitsLENRequired = (nb == 1? 0x00000000 : (nb == 2? 0x00040000 : 0x000C000)); + var bitsDR7 = regDR7 >> 16; + + var bitsRWMask = X86.DR7.RW0 >> 16; + var bitsRWRequired = (fWrite? 0x1 : (fWrite == false? 0x3 : 0x0)); + for (var i = 0; i < 4; i++) { - if ((regDR7 & bitsEnabled) && (regDR7 & bitsRWMask) == bitsRWRequired) { - if ((regDR7 & bitsLENMask) == bitsLENRequired && addr == this.regDR[i]) { + if ((regDR7 & (X86.DR7.L0 | X86.DR7.G0)) && (bitsDR7 & bitsRWMask) == bitsRWRequired) { + /* + * NOTE: We reduced nb from 1-4 to 0-3 above, so we don't need to add 1 to len either. + */ + var len = (bitsDR7 >> 2); + /* + * Time to determine if addr through addr + nb overlaps regDR[i] through regDR[i] + len. + */ + if (addr + nb >= this.regDR[i] && addr <= this.regDR[i] + len) { this.regDR[6] |= (1 << i); + this.opFlags |= X86.OPFLAG.DEBUG; X86.fnFault.call(this, X86.EXCEPTION.DEBUG); return; } } - bitsEnabled <<= 2; - bitsRWMask <<= 2; bitsRWRequired <<= 2; - bitsLENMask <<= 2; bitsLENRequired <<= 2; + regDR7 >>= 2; bitsDR7 >>= 4; } } }; diff --git a/modules/pcjs/lib/x86func.js b/modules/pcjs/lib/x86func.js index b8ff96c48..4e77ff2d4 100644 --- a/modules/pcjs/lib/x86func.js +++ b/modules/pcjs/lib/x86func.js @@ -3693,6 +3693,13 @@ X86.fnSrcNone = function SrcNone() */ X86.fnFault = function(nFault, nError, fHalt, nCycles) { + /* + * This flag is used by selected opcodes to provide an early exit if X86.OPFLAG.FAULT is set, in some cases + * making it possible for an instruction to be restarted (eg, opINSw()), and in other cases preventing a redundant + * fault from being generated. However, to prevent multiple X86.EXCEPTION.DEBUG exceptions on a single instruction, + * checkMemoryException() currently relies on its own OPFLAG.DEBUG, on the theory that we should be allowed to see + * DEBUG exceptions triggered by other exceptions. + */ this.opFlags |= X86.OPFLAG.FAULT; if (!this.aFlags.fComplete) { diff --git a/modules/pcjs/lib/x86op0f.js b/modules/pcjs/lib/x86op0f.js index 23571e7a9..7f8b9c89e 100644 --- a/modules/pcjs/lib/x86op0f.js +++ b/modules/pcjs/lib/x86op0f.js @@ -338,7 +338,7 @@ X86.opMOVrc = function MOVrc() */ if (this.nCPL) { /* - * You're not allowed to read control registers if the current privilege level is not zero + * You're not allowed to read control registers if the current privilege level is not zero. */ X86.fnFault.call(this, X86.EXCEPTION.GP_FAULT, 0); return; @@ -366,7 +366,7 @@ X86.opMOVrc = function MOVrc() this.nStepCycles -= 6; /* - * TODO: Implement BACKTRACK for this instruction (although Control registers are not likely to be a conduit for much interesting data). + * TODO: Implement BACKTRACK for this instruction (although Control registers are not likely to be a conduit for interesting data). */ }; @@ -387,7 +387,7 @@ X86.opMOVrd = function MOVrd() */ if (this.nCPL) { /* - * You're not allowed to read control registers if the current privilege level is not zero + * You're not allowed to read control registers if the current privilege level is not zero. */ X86.fnFault.call(this, X86.EXCEPTION.GP_FAULT, 0); return; @@ -406,7 +406,7 @@ X86.opMOVrd = function MOVrd() this.nStepCycles -= 22; /* - * TODO: Implement BACKTRACK for this instruction (although Debug registers are not likely to be a conduit for much interesting data). + * TODO: Implement BACKTRACK for this instruction (although Debug registers are not likely to be a conduit for interesting data). */ }; @@ -436,7 +436,7 @@ X86.opMOVcr = function MOVcr() */ if (this.nCPL) { /* - * You're not allowed to write control registers if the current privilege level is not zero + * You're not allowed to write control registers if the current privilege level is not zero. */ X86.fnFault.call(this, X86.EXCEPTION.GP_FAULT, 0); return; @@ -464,7 +464,7 @@ X86.opMOVcr = function MOVcr() } /* - * TODO: Implement BACKTRACK for this instruction (although Control registers are not likely to be a conduit for much interesting data). + * TODO: Implement BACKTRACK for this instruction (although Control registers are not likely to be a conduit for interesting data). */ }; @@ -485,7 +485,7 @@ X86.opMOVdr = function MOVdr() */ if (this.nCPL) { /* - * You're not allowed to write control registers if the current privilege level is not zero + * You're not allowed to write control registers if the current privilege level is not zero. */ X86.fnFault.call(this, X86.EXCEPTION.GP_FAULT, 0); return; @@ -498,38 +498,18 @@ X86.opMOVdr = function MOVdr() X86.opUndefined.call(this); return; } + var regDR = this.getReg(bModRM & 0x7); - if (iDst == 7) { - var regDR7 = this.regDR[7]; - if ((regDR ^ regDR7) & X86.DR7.ENABLE) { - /* - * We need to check changes to the Debug Control Register (DR7); specifically, if any of - * DR0-DR3 are transitioning from disabled to enabled, or vice versa, then we need to call - * addMemCheck(), or removeMemCheck(), as appropriate. - */ - var bitsEnabled = X86.DR7.L0 | X86.DR7.G0; - var bitsRWMask = 0x00030000; - for (var i = 0; i < 4; i++) { - var fEnabled = (regDR & bitsEnabled); - if (!fEnabled != !(regDR7 & bitsEnabled)) { - var bitsRW = (regDR & bitsRWMask) >> (i << 1); - var fWrite = !!(bitsRW & 0x00010000); - if (fEnabled) { - this.addMemCheck(this.regDR[i], fWrite); - } else { - this.removeMemCheck(this.regDR[i], fWrite); - } - } - bitsEnabled <<= 2; - bitsRWMask <<= 2; - } - } + if (regDR != this.regDR[iDst]) { + this.checkDebugRegisters(false); + this.regDR[iDst] = regDR; + this.checkDebugRegisters(true); } - this.regDR[iDst] = regDR; + this.nStepCycles -= (iDst < 4? 22 : 14); /* - * TODO: Implement BACKTRACK for this instruction (although Debug registers are not likely to be a conduit for much interesting data). + * TODO: Implement BACKTRACK for this instruction (although Debug registers are not likely to be a conduit for interesting data). */ }; @@ -550,7 +530,7 @@ X86.opMOVrt = function MOVrt() */ if (this.nCPL) { /* - * You're not allowed to read control registers if the current privilege level is not zero + * You're not allowed to read control registers if the current privilege level is not zero. */ X86.fnFault.call(this, X86.EXCEPTION.GP_FAULT, 0); return; @@ -567,7 +547,7 @@ X86.opMOVrt = function MOVrt() this.nStepCycles -= 12; /* - * TODO: Implement BACKTRACK for this instruction (although Test registers are not likely to be a conduit for much interesting data). + * TODO: Implement BACKTRACK for this instruction (although Test registers are not likely to be a conduit for interesting data). */ }; @@ -588,7 +568,7 @@ X86.opMOVtr = function MOVtr() */ if (this.nCPL) { /* - * You're not allowed to write control registers if the current privilege level is not zero + * You're not allowed to write control registers if the current privilege level is not zero. */ X86.fnFault.call(this, X86.EXCEPTION.GP_FAULT, 0); return; @@ -610,7 +590,7 @@ X86.opMOVtr = function MOVtr() this.nStepCycles -= 12; /* - * TODO: Implement BACKTRACK for this instruction (although Test registers are not likely to be a conduit for much interesting data). + * TODO: Implement BACKTRACK for this instruction (although Test registers are not likely to be a conduit for interesting data). */ };