80386 development
This commit is contained in:
parent
e75e734233
commit
70bca48b17
127 changed files with 1039 additions and 958 deletions
|
|
@ -47,7 +47,7 @@ if (typeof module !== 'undefined') {
|
|||
*
|
||||
* The ChipSet component has the following component-specific (parmsChipSet) properties:
|
||||
*
|
||||
* model: 5150, 5160 or 5170 (should correspond to a ChipSet.MODEL_* constant)
|
||||
* model: "5150", "5160", "5170" or "deskpro386" (should be a member of ChipSet.MODELS)
|
||||
* sw1: 8-character binary string representing the SW1 DIP switches (SW1[1-8])
|
||||
* sw2: 8-character binary string representing the SW2 DIP switches (SW2[1-8]) (MODEL_5150 only)
|
||||
* sound: true to enable (experimental) sound support (default); false to disable
|
||||
|
|
@ -151,7 +151,7 @@ function ChipSet(parmsChipSet)
|
|||
Component.call(this, "ChipSet", parmsChipSet, ChipSet, Messages.CHIPSET);
|
||||
|
||||
this.model = parmsChipSet['model'];
|
||||
this.model = (this.model? parseInt(this.model, 10) : ChipSet.MODEL_5150);
|
||||
this.model = this.model && ChipSet.MODELS[this.model] || ChipSet.MODEL_5150;
|
||||
|
||||
/*
|
||||
* SW1 describes the number of floppy drives, the amount of base memory, the primary monitor type,
|
||||
|
|
@ -265,12 +265,29 @@ Component.subclass(Component, ChipSet);
|
|||
ChipSet.MODEL_5150 = 5150; // used in reference to the 1st 5150 BIOS, dated Apr 24, 1981
|
||||
ChipSet.MODEL_5160 = 5160; // used in reference to the 1st 5160 BIOS, dated Nov 8, 1982
|
||||
ChipSet.MODEL_5170 = 5170; // used in reference to the 1st 5170 BIOS, dated Jan 10, 1984
|
||||
|
||||
/*
|
||||
* The following are fake model numbers, used only to document issues/features of note in later IBM PC AT BIOS revisions.
|
||||
*/
|
||||
ChipSet.MODEL_5170_REV2 = 5170.2; // used in reference to the 2nd 5170 BIOS, dated Jun 10, 1985
|
||||
ChipSet.MODEL_5170_REV3 = 5170.3; // used in reference to the 3rd 5170 BIOS, dated Nov 15, 1985
|
||||
|
||||
/*
|
||||
* The following are even more fake model numbers, as we begin to depart from the IBM lineage. All that
|
||||
* really matters at this point is that MODEL_DESKPRO386 > MODEL_5170.
|
||||
*/
|
||||
ChipSet.MODEL_DESKPRO386 = 5180;
|
||||
|
||||
/*
|
||||
* Last but not least, a complete list of supported model strings, and corresponding internal model numbers.
|
||||
*/
|
||||
ChipSet.MODELS = {
|
||||
"5150": ChipSet.MODEL_5150,
|
||||
"5160": ChipSet.MODEL_5160,
|
||||
"5170": ChipSet.MODEL_5170,
|
||||
"deskpro386": ChipSet.MODEL_DESKPRO386
|
||||
};
|
||||
|
||||
/*
|
||||
* Values returned by ChipSet.getSWVideoMonitor()
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1328,6 +1328,74 @@ if (DEBUGGER) {
|
|||
if (this.controlDebug) this.controlDebug.focus();
|
||||
};
|
||||
|
||||
/**
|
||||
* newAddr(off, seg, addr, fData32, fAddr32)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} off
|
||||
* @param {number} seg
|
||||
* @param {number|null} [addr]
|
||||
* @param {boolean} [fData32]
|
||||
* @param {boolean} [fAddr32]
|
||||
* @return {Array} containing [off, seg, addr]
|
||||
*/
|
||||
Debugger.prototype.newAddr = function(off, seg, addr, fData32, fAddr32)
|
||||
{
|
||||
return [off, seg, addr, false, fData32, fAddr32];
|
||||
};
|
||||
|
||||
/**
|
||||
* incAddr(aAddr, inc)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {Array} aAddr containing [off, seg, addr]
|
||||
* @param {number|undefined} inc contains value to increment by (default is 1)
|
||||
*/
|
||||
Debugger.prototype.incAddr = function(aAddr, inc)
|
||||
{
|
||||
inc = (inc === undefined? 1 : inc);
|
||||
if (aAddr[2] != null) {
|
||||
aAddr[2] += inc;
|
||||
}
|
||||
if (aAddr[1] != null) {
|
||||
aAddr[0] += inc;
|
||||
var limit = this.getSegment(aAddr[1]).limit;
|
||||
if (aAddr[0] > limit) {
|
||||
aAddr[0] = 0;
|
||||
aAddr[2] = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* hexAddr(aAddr)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {Array} aAddr containing [off, seg]
|
||||
* @return {string} the hex representation of the address
|
||||
*/
|
||||
Debugger.prototype.hexAddr = function(aAddr)
|
||||
{
|
||||
return aAddr[1] == null? ("%" + str.toHex(aAddr[2])) : this.hexOffset(aAddr[0], aAddr[1], aAddr[4]);
|
||||
};
|
||||
|
||||
/**
|
||||
* hexOffset(off, sel)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} off
|
||||
* @param {number} [sel]
|
||||
* @param {boolean} [fData32] is true if 32-bit OPERAND size in effect
|
||||
* @return {string} the hex representation of off (or sel:off)
|
||||
*/
|
||||
Debugger.prototype.hexOffset = function(off, sel, fData32)
|
||||
{
|
||||
if (sel !== undefined) {
|
||||
return str.toHex(sel, 4) + ":" + str.toHex(off, fData32? 8 : 4);
|
||||
}
|
||||
return str.toHex(off);
|
||||
};
|
||||
|
||||
/**
|
||||
* dumpDOS(s)
|
||||
*
|
||||
|
|
@ -1646,6 +1714,12 @@ if (DEBUGGER) {
|
|||
case Debugger.REG_DI:
|
||||
n = cpu.regEDI; cch = 4;
|
||||
break;
|
||||
case Debugger.REG_IP:
|
||||
n = cpu.getIP(); cch = this.cchReg;
|
||||
break;
|
||||
case Debugger.REG_PS:
|
||||
n = cpu.getPS(); cch = this.cchReg;
|
||||
break;
|
||||
case Debugger.REG_SEG + Debugger.REG_ES:
|
||||
n = cpu.getES(); cch = 4;
|
||||
break;
|
||||
|
|
@ -1658,54 +1732,52 @@ if (DEBUGGER) {
|
|||
case Debugger.REG_SEG + Debugger.REG_DS:
|
||||
n = cpu.getDS(); cch = 4;
|
||||
break;
|
||||
case Debugger.REG_SEG + Debugger.REG_FS:
|
||||
n = cpu.getFS(); cch = 4;
|
||||
break;
|
||||
case Debugger.REG_SEG + Debugger.REG_GS:
|
||||
n = cpu.getGS(); cch = 4;
|
||||
break;
|
||||
case Debugger.REG_IP:
|
||||
n = cpu.getIP(); cch = this.cchReg;
|
||||
break;
|
||||
case Debugger.REG_PS:
|
||||
n = cpu.getPS(); cch = this.cchReg;
|
||||
break;
|
||||
case Debugger.REG_EAX:
|
||||
n = cpu.regEAX; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_ECX:
|
||||
n = cpu.regECX; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_EDX:
|
||||
n = cpu.regEDX; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_EBX:
|
||||
n = cpu.regEBX; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_ESP:
|
||||
n = cpu.getSP(); cch = 8;
|
||||
break;
|
||||
case Debugger.REG_EBP:
|
||||
n = cpu.regEBP; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_ESI:
|
||||
n = cpu.regESI; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_EDI:
|
||||
n = cpu.regEDI; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_CR0:
|
||||
n = cpu.regCR0; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_CR1:
|
||||
n = cpu.regCR1; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_CR2:
|
||||
n = cpu.regCR2; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_CR3:
|
||||
n = cpu.regCR3; cch = 8;
|
||||
break;
|
||||
}
|
||||
if (I386 && !cch) {
|
||||
switch(iReg) {
|
||||
case Debugger.REG_EAX:
|
||||
n = cpu.regEAX; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_ECX:
|
||||
n = cpu.regECX; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_EDX:
|
||||
n = cpu.regEDX; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_EBX:
|
||||
n = cpu.regEBX; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_ESP:
|
||||
n = cpu.getSP(); cch = 8;
|
||||
break;
|
||||
case Debugger.REG_EBP:
|
||||
n = cpu.regEBP; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_ESI:
|
||||
n = cpu.regESI; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_EDI:
|
||||
n = cpu.regEDI; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_CR0:
|
||||
n = cpu.regCR0; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_CR1:
|
||||
n = cpu.regCR1; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_CR2:
|
||||
n = cpu.regCR2; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_CR3:
|
||||
n = cpu.regCR3; cch = 8;
|
||||
break;
|
||||
case Debugger.REG_SEG + Debugger.REG_FS:
|
||||
n = cpu.getFS(); cch = 4;
|
||||
break;
|
||||
case Debugger.REG_SEG + Debugger.REG_GS:
|
||||
n = cpu.getGS(); cch = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cch) s = str.toHex(n, cch);
|
||||
}
|
||||
|
|
@ -2258,71 +2330,6 @@ if (DEBUGGER) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* newAddr(off, seg, addr)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} off
|
||||
* @param {number} seg
|
||||
* @param {number} [addr] is the physical address, if known
|
||||
* @return {Array} containing [off, seg, addr]
|
||||
*/
|
||||
Debugger.prototype.newAddr = function(off, seg, addr)
|
||||
{
|
||||
return [off, seg, addr];
|
||||
};
|
||||
|
||||
/**
|
||||
* incAddr(aAddr, inc)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {Array} aAddr containing [off, seg, addr]
|
||||
* @param {number|undefined} inc contains value to increment by (default is 1)
|
||||
*/
|
||||
Debugger.prototype.incAddr = function(aAddr, inc)
|
||||
{
|
||||
inc = (inc === undefined? 1 : inc);
|
||||
if (aAddr[2] != null) {
|
||||
aAddr[2] += inc;
|
||||
}
|
||||
if (aAddr[1] != null) {
|
||||
aAddr[0] += inc;
|
||||
var limit = this.getSegment(aAddr[1]).limit;
|
||||
if (aAddr[0] > limit) {
|
||||
aAddr[0] = 0;
|
||||
aAddr[2] = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* hexAddr(aAddr)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {Array} aAddr containing [off, seg]
|
||||
* @return {string} the hex representation of the address
|
||||
*/
|
||||
Debugger.prototype.hexAddr = function(aAddr)
|
||||
{
|
||||
return aAddr[1] == null? ("%" + str.toHex(aAddr[2])) : this.hexOffset(aAddr[0], aAddr[1]);
|
||||
};
|
||||
|
||||
/**
|
||||
* hexOffset(off, sel)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} off
|
||||
* @param {number} [sel]
|
||||
* @return {string} the hex representation of off (or sel:off)
|
||||
*/
|
||||
Debugger.prototype.hexOffset = function(off, sel)
|
||||
{
|
||||
if (sel !== undefined) {
|
||||
return str.toHex(sel, 4) + ":" + str.toHex(off, this.cchAddr < 8? 4 : 8);
|
||||
}
|
||||
return str.toHex(off);
|
||||
};
|
||||
|
||||
/**
|
||||
* checksEnabled(fRelease)
|
||||
*
|
||||
|
|
@ -2360,7 +2367,7 @@ if (DEBUGGER) {
|
|||
}
|
||||
/*
|
||||
* Halt whenever ring 3 code is running with interrupts disabled, because that's likely an
|
||||
* error (technically, we should also check the IOPL, too, because if IOPL is 3, this is OK).
|
||||
* error (TODO: we should also check the IOPL, too, because if IOPL is 3, then this is OK).
|
||||
*/
|
||||
if (this.cpu.segCS.cpl == 3 && !(this.cpu.regPS & X86.PS.IF)) {
|
||||
return true;
|
||||
|
|
@ -2380,7 +2387,7 @@ if (DEBUGGER) {
|
|||
|
||||
/*
|
||||
* This is a good example of what NOT to do in a high-frequency function, and defeats
|
||||
* the purpose of preallocating and preinitializing the history array in historyInit():
|
||||
* the purpose of pre-allocating and pre-initializing the history array in historyInit():
|
||||
*
|
||||
* this.aOpcodeHistory[this.iOpcodeHistory] = this.newAddr(this.cpu.getIP(), this.cpu.getCS(), addr);
|
||||
*
|
||||
|
|
@ -2491,6 +2498,10 @@ if (DEBUGGER) {
|
|||
if (sel == this.cpu.getDS()) return this.cpu.segDS;
|
||||
if (sel == this.cpu.getES()) return this.cpu.segES;
|
||||
if (sel == this.cpu.getSS()) return this.cpu.segSS;
|
||||
if (I386) {
|
||||
if (sel == this.cpu.getFS()) return this.cpu.segFS;
|
||||
if (sel == this.cpu.getGS()) return this.cpu.segGS;
|
||||
}
|
||||
var seg = new X86Seg(this.cpu, X86Seg.ID.DEBUG, "DBG");
|
||||
/*
|
||||
* TODO: Confirm that it's OK for this function to drop any error from seg.load() on the floor....
|
||||
|
|
@ -2552,6 +2563,22 @@ if (DEBUGGER) {
|
|||
return b;
|
||||
};
|
||||
|
||||
/**
|
||||
* getWord(aAddr, inc)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {Array} aAddr
|
||||
* @param {number} [inc]
|
||||
* @return {number}
|
||||
*/
|
||||
Debugger.prototype.getWord = function(aAddr, inc)
|
||||
{
|
||||
if (aAddr[4]) {
|
||||
return this.getLong(aAddr, inc? 4 : 0);
|
||||
}
|
||||
return this.getShort(aAddr, inc? 2 : 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* getShort(aAddr, inc)
|
||||
*
|
||||
|
|
@ -2865,16 +2892,26 @@ if (DEBUGGER) {
|
|||
* getInstruction(aAddr, sComment, nSequence)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {Array} aAddr (updated to next instruction)
|
||||
* @param {Array} aAddr (aAddr[4] is true if 32-bit operands, aAddr[5] is true if 32-bit addresses)
|
||||
* @param {string} [sComment] is an associated comment
|
||||
* @param {number} [nSequence] is an associated sequence number, undefined if none
|
||||
* @return {string}
|
||||
* @return {string} (and aAddr is updated to the next instruction)
|
||||
*/
|
||||
Debugger.prototype.getInstruction = function(aAddr, sComment, nSequence)
|
||||
{
|
||||
var aAddrIns = this.newAddr(aAddr[0], aAddr[1], aAddr[2]);
|
||||
var aAddrIns = this.newAddr(aAddr[0], aAddr[1], aAddr[2], this.cpu.segCS.addrSize == 4);
|
||||
|
||||
var bOpcode = this.getByte(aAddr, 1);
|
||||
|
||||
/*
|
||||
* Prior to calling getInstruction(), doUnassemble() checks for these prefixes as well,
|
||||
* updating aAddr[4] and/or aAddr[5] as appropriate; if that's been done, then let's suppress
|
||||
* the display of those prefixes and simply incorporate them into the byte stream.
|
||||
*/
|
||||
if (aAddr[4] != null && bOpcode == X86.OPCODE.OS || aAddr[5] != null && bOpcode == X86.OPCODE.AS) {
|
||||
bOpcode = this.getByte(aAddr, 1);
|
||||
}
|
||||
|
||||
var aOpDesc = this.aaOpDescs[bOpcode];
|
||||
var iIns = aOpDesc[0];
|
||||
var bModRM = -1;
|
||||
|
|
@ -2894,7 +2931,10 @@ if (DEBUGGER) {
|
|||
var sOpcode = Debugger.INS_NAMES[aOpDesc[0]];
|
||||
var cOperands = 2;
|
||||
var sOperands = "";
|
||||
if (this.isStringIns(bOpcode)) cOperands = 0; // suppress display of operands for string instructions
|
||||
if (this.isStringIns(bOpcode)) {
|
||||
cOperands = 0; // suppress display of operands for string instructions
|
||||
if (aAddr[4] && sOpcode.slice(-1) == 'W') sOpcode = sOpcode.slice(0, -1) + 'D';
|
||||
}
|
||||
|
||||
var typeCPU = null;
|
||||
for (var iOperand = 1; iOperand <= cOperands; iOperand++) {
|
||||
|
|
@ -2991,7 +3031,7 @@ if (DEBUGGER) {
|
|||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} type
|
||||
* @param {Array} aAddr
|
||||
* @param {Array} aAddr (aAddr[4] is true if 32-bit operands, aAddr[5] is true if 32-bit addresses)
|
||||
* @return {string} operand
|
||||
*/
|
||||
Debugger.prototype.getImmOperand = function(type, aAddr)
|
||||
|
|
@ -3022,7 +3062,7 @@ if (DEBUGGER) {
|
|||
sOperand = str.toHex(this.getShort(aAddr, 2), 4);
|
||||
break;
|
||||
case Debugger.TYPE_FARP:
|
||||
sOperand = this.hexAddr(this.newAddr(this.getShort(aAddr, 2), this.getShort(aAddr, 2)));
|
||||
sOperand = this.hexAddr(this.newAddr(this.getWord(aAddr, 2), this.getShort(aAddr, 2), null, aAddr[4]));
|
||||
break;
|
||||
default:
|
||||
sOperand = "imm(" + str.toHexWord(type) + ")";
|
||||
|
|
@ -3298,8 +3338,8 @@ if (DEBUGGER) {
|
|||
*
|
||||
* EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
|
||||
* ESP=00000000 EBP=00000000 ESI=00000000 EDI=00000000
|
||||
* SS=0000 DS=0000 ES=0000 PS=00000002 V0 D0 I0 T0 S0 Z0 A0 P0 C0
|
||||
* F000:0000FFF0 EA05F900F0 JMP F000:0000F905
|
||||
* SS=0000 DS=0000 ES=0000 FS=0000 GS=0000 PS=00000002 V0 D0 I0 T0 S0 Z0 A0 P0 C0
|
||||
* F000:FFF0 EA05F900F0 JMP F000:F905
|
||||
*
|
||||
* Sample 80286 protected-mode register dump:
|
||||
*
|
||||
|
|
@ -4121,7 +4161,7 @@ if (DEBUGGER) {
|
|||
* We must create a new aAddr from the address we obtained from aHistory, because
|
||||
* aAddr was a reference, not a copy, and we don't want getInstruction() modifying the original.
|
||||
*
|
||||
* TODO: By using a new address for each iteration, history dumps fail to disassemble 32-bit overrides properly.
|
||||
* TODO: By using a new address for each line, history dumps fail to disassemble 32-bit overrides properly.
|
||||
*/
|
||||
aAddr = this.newAddr(aAddr[0], aAddr[1], aAddr[2]);
|
||||
this.println(this.getInstruction(aAddr, "history", n));
|
||||
|
|
@ -4554,10 +4594,7 @@ if (DEBUGGER) {
|
|||
if (asArgs != null && asArgs.length > 1) {
|
||||
var sReg = asArgs[1];
|
||||
if (sReg == 'p') {
|
||||
/*
|
||||
* If the CPU has not defined addrGDT, then there are no protected-mode registers.
|
||||
*/
|
||||
fProt = (this.cpu.addrGDT !== undefined);
|
||||
fProt = (this.cpu.model >= X86.MODEL_80286);
|
||||
} else {
|
||||
// fIns = false;
|
||||
var sValue = null;
|
||||
|
|
@ -4589,9 +4626,6 @@ if (DEBUGGER) {
|
|||
case "AX":
|
||||
this.cpu.regEAX = (this.cpu.regEAX & ~0xffff) | (w & 0xffff);
|
||||
break;
|
||||
case "EAX":
|
||||
this.cpu.regEAX = w;
|
||||
break;
|
||||
case "BL":
|
||||
this.cpu.regEBX = (this.cpu.regEBX & ~0xff) | (w & 0xff);
|
||||
break;
|
||||
|
|
@ -4601,9 +4635,6 @@ if (DEBUGGER) {
|
|||
case "BX":
|
||||
this.cpu.regEBX = (this.cpu.regEBX & ~0xffff) | (w & 0xffff);
|
||||
break;
|
||||
case "EBX":
|
||||
this.cpu.regEBX = w;
|
||||
break;
|
||||
case "CL":
|
||||
this.cpu.regECX = (this.cpu.regECX & ~0xff) | (w & 0xff);
|
||||
break;
|
||||
|
|
@ -4613,9 +4644,6 @@ if (DEBUGGER) {
|
|||
case "CX":
|
||||
this.cpu.regECX = (this.cpu.regECX & ~0xffff) | (w & 0xffff);
|
||||
break;
|
||||
case "ECX":
|
||||
this.cpu.regECX = w;
|
||||
break;
|
||||
case "DL":
|
||||
this.cpu.regEDX = (this.cpu.regEDX & ~0xff) | (w & 0xff);
|
||||
break;
|
||||
|
|
@ -4625,33 +4653,18 @@ if (DEBUGGER) {
|
|||
case "DX":
|
||||
this.cpu.regEDX = (this.cpu.regEDX & ~0xffff) | (w & 0xffff);
|
||||
break;
|
||||
case "EDX":
|
||||
this.cpu.regEDX = w;
|
||||
break;
|
||||
case "SP":
|
||||
this.cpu.setSP((this.cpu.getSP() & ~0xffff) | (w & 0xffff));
|
||||
break;
|
||||
case "ESP":
|
||||
this.cpu.setSP(w);
|
||||
break;
|
||||
case "BP":
|
||||
this.cpu.regEBP = (this.cpu.regEBP & ~0xffff) | (w & 0xffff);
|
||||
break;
|
||||
case "EBP":
|
||||
this.cpu.regEBP = w;
|
||||
break;
|
||||
case "SI":
|
||||
this.cpu.regESI = (this.cpu.regESI & ~0xffff) | (w & 0xffff);
|
||||
break;
|
||||
case "ESI":
|
||||
this.cpu.regESI = w;
|
||||
break;
|
||||
case "DI":
|
||||
this.cpu.regEDI = (this.cpu.regEDI & ~0xffff) | (w & 0xffff);
|
||||
break;
|
||||
case "EDI":
|
||||
this.cpu.regEDI = w;
|
||||
break;
|
||||
case "DS":
|
||||
this.cpu.setDS(w);
|
||||
break;
|
||||
|
|
@ -4720,6 +4733,47 @@ if (DEBUGGER) {
|
|||
*/
|
||||
default:
|
||||
fUnknown = true;
|
||||
if (I386 && this.cpu.model >= X86.MODEL_80386) {
|
||||
fUnknown = false;
|
||||
switch(sRegMatch){
|
||||
case "EAX":
|
||||
this.cpu.regEAX = w;
|
||||
break;
|
||||
case "EBX":
|
||||
this.cpu.regEBX = w;
|
||||
break;
|
||||
case "ECX":
|
||||
this.cpu.regECX = w;
|
||||
break;
|
||||
case "EDX":
|
||||
this.cpu.regEDX = w;
|
||||
break;
|
||||
case "ESP":
|
||||
this.cpu.setSP(w);
|
||||
break;
|
||||
case "EBP":
|
||||
this.cpu.regEBP = w;
|
||||
break;
|
||||
case "ESI":
|
||||
this.cpu.regESI = w;
|
||||
break;
|
||||
case "EDI":
|
||||
this.cpu.regEDI = w;
|
||||
break;
|
||||
case "FS":
|
||||
this.cpu.setFS(w);
|
||||
break;
|
||||
case "GS":
|
||||
this.cpu.setGS(w);
|
||||
break;
|
||||
/*
|
||||
* TODO: Add support for CR0-CR3, DR0-DR7, and TR6-TR7.
|
||||
*/
|
||||
default:
|
||||
fUnknown = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -4996,9 +5050,14 @@ if (DEBUGGER) {
|
|||
aAddr[4] = !aAddr[4];
|
||||
} else if (bOpcode == X86.OPCODE.AS) {
|
||||
aAddr[5] = !aAddr[5];
|
||||
} else {
|
||||
/*
|
||||
* For all prefixes (except for the OPERAND and ADDRESS overrides, which getInstruction()
|
||||
* now incorporates into the instruction), we will want to dump an additional instruction.
|
||||
*/
|
||||
if (!n) n++;
|
||||
nSequence = null;
|
||||
}
|
||||
if (!n) n++;
|
||||
nSequence = null;
|
||||
} else {
|
||||
fInitSize = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,13 +47,15 @@ var X86 = {
|
|||
* This constant is used to mark points in the code where the physical address being returned
|
||||
* is invalid and should not be used. TODO: There are still functions that will use an invalid
|
||||
* address, which is why we've tried to choose a value that causes the least harm, but ultimately,
|
||||
* we must add checks to those functions or throw a special JavaScript exception to bypass them.
|
||||
* we must add checks to those functions or throw special JavaScript exceptions to bypass them.
|
||||
*
|
||||
* This value is also used to indicate non-existent EA address calculations, which are usually
|
||||
* detected with "regEA === ADDR_INVALID" and "regEAWrite === ADDR_INVALID" tests. In a 32-bit CPU,
|
||||
* -1 (ie, 0xffffffff) could actually be a valid address, so consider changing it to NaN or null;
|
||||
* my concern is that, by mixing non-numbers (specifically, values outside the range of signed 32-bit
|
||||
* integers), performance may suffer.
|
||||
* detected with "regEA === ADDR_INVALID" and "regEAWrite === ADDR_INVALID" tests. In a 32-bit
|
||||
* CPU, -1 (ie, 0xffffffff) could actually be a valid address, so consider changing ADDR_INVALID
|
||||
* to NaN or null (which is also why all ADDR_INVALID tests should use strict equality operators).
|
||||
*
|
||||
* The main reason I'm NOT using NaN or null now is my concern that, by mixing non-numbers
|
||||
* (specifically, values outside the range of signed 32-bit integers), performance may suffer.
|
||||
*/
|
||||
ADDR_INVALID: -1,
|
||||
|
||||
|
|
@ -242,7 +244,7 @@ var X86 = {
|
|||
},
|
||||
RESULT: {
|
||||
/*
|
||||
* Flags were originally computed based on the following 16-bit result registers:
|
||||
* Flags were originally computed using 16-bit result registers:
|
||||
*
|
||||
* CF: resultZeroCarry & resultSize (ie, 0x100 or 0x10000)
|
||||
* PF: resultParitySign & 0xff
|
||||
|
|
@ -251,7 +253,7 @@ var X86 = {
|
|||
* SF: resultParitySign & (resultSize >> 1)
|
||||
* OF: (resultParitySign ^ resultAuxOverflow ^ (resultParitySign >> 1)) & (resultSize >> 1)
|
||||
*
|
||||
* I386 support requires that we now rely on the following 32-bit result registers:
|
||||
* I386 support requires that we now rely on 32-bit result registers:
|
||||
*
|
||||
* resultDst, resultSrc, resultArith, resultLogic and resultType
|
||||
*
|
||||
|
|
@ -266,8 +268,8 @@ var X86 = {
|
|||
*
|
||||
* where resultType contains both a size, which must be one of BYTE (0x80), WORD (0x8000),
|
||||
* or DWORD (0x80000000), along with bits for each of the arithmetic and/or logical flags that
|
||||
* are currently "cached" in result registers (eg, X86.RESULT.CF for carry, X86.RESULT.OF for
|
||||
* overflow, etc).
|
||||
* are currently "cached" in the result registers (eg, X86.RESULT.CF for carry, X86.RESULT.OF
|
||||
* for overflow, etc).
|
||||
*
|
||||
* WARNING: Do not confuse these RESULT flag definitions with the PS flag definitions. RESULT
|
||||
* flags are used only as "cached" flag indicators, packed into bits 0-5 of resultType; they do
|
||||
|
|
@ -284,16 +286,20 @@ var X86 = {
|
|||
* setLogicResult(value, type [, carry [, overflow]])
|
||||
*
|
||||
* Since most logical operations clear both CF and OF, most calls to setLogicResult() can omit the
|
||||
* two optional parameters.
|
||||
* last two optional parameters.
|
||||
*
|
||||
* The type parameter of these methods indicates both the size of the result (BYTE, WORD or DWORD)
|
||||
* and which of the flags should now be considered "cached" by the result registers. If the previous
|
||||
* resultType specifies any flags not contained in the new type parameter, then those flags must be
|
||||
* immediately calculated and written to the appropriate bit(s) in regPS.
|
||||
* resultType specifies any flags not present in the new type parameter, then those flags are
|
||||
* calculated and written to the appropriate regPS bit(s) *before* the result registers are updated.
|
||||
*
|
||||
* Arithmetic operations are assumed to represent an "added" result; if a "subtracted" result is
|
||||
* provided instead (eg, from CMP, DEC, SUB, etc), then setArithResult() must include a 5th parameter
|
||||
* (fSubtract).
|
||||
* (fSubtract); eg:
|
||||
*
|
||||
* setArithResult(dst, src, dst-src, X86.RESULT.BYTE | X86.RESULT.ALL, true)
|
||||
*
|
||||
* TODO: Consider separating setArithResult() into two functions: setAddResult() and setSubResult().
|
||||
*/
|
||||
BYTE: 0x80, // result is byte value
|
||||
WORD: 0x8000, // result is word value
|
||||
|
|
@ -401,19 +407,19 @@ X86.BACKTRACK = {
|
|||
};
|
||||
|
||||
/*
|
||||
* Some PS flags are stored directly in regPS, hence the "direct" designation.
|
||||
* Some PS flags are always stored directly in regPS, hence the "direct" designation.
|
||||
*/
|
||||
X86.PS.DIRECT = (X86.PS.TF | X86.PS.IF | X86.PS.DF);
|
||||
|
||||
/*
|
||||
* However, PS arithmetic and logical flags may be "cached" across result registers.
|
||||
* However, PS arithmetic and logical flags may be "cached" across several result registers.
|
||||
*/
|
||||
X86.PS.CACHED = (X86.PS.CF | X86.PS.PF | X86.PS.AF | X86.PS.ZF | X86.PS.SF | X86.PS.OF);
|
||||
|
||||
/*
|
||||
* These are the default "always set" PS bits for the 8086/8088; other processors must
|
||||
* adjust these bits accordingly. The final adjusted value is then stored in the X86CPU
|
||||
* object as "this.PS_SET"; setPS() must use that value, NOT this one.
|
||||
* object as PS_SET; setPS() must use PS_SET, *not* PS.SET.
|
||||
*/
|
||||
X86.PS.SET = (X86.PS.BIT1 | X86.PS.IOPL.MASK | X86.PS.NT | X86.PS.BIT15);
|
||||
|
||||
|
|
@ -424,9 +430,10 @@ X86.PS.SET = (X86.PS.BIT1 | X86.PS.IOPL.MASK | X86.PS.NT | X86.PS.BIT15);
|
|||
X86.PS.SAHF = (X86.PS.CF | X86.PS.PF | X86.PS.AF | X86.PS.ZF | X86.PS.SF);
|
||||
|
||||
/*
|
||||
* Before we zero opFlags, we first see if any of the following PREFIX bits were set. If any were set, they are OR'ed
|
||||
* into opPrefixes; otherwise, opPrefixes is zeroed as well. This gives prefix-conscious instructions like LODS, MOVS,
|
||||
* STOS, CMPS, etc, a way of determining which prefixes, if any, immediately preceded them.
|
||||
* Before we zero opFlags, we first see if any of the following PREFIX bits were set. If any were set,
|
||||
* they are OR'ed into opPrefixes; otherwise, opPrefixes is zeroed as well. This gives prefix-conscious
|
||||
* instructions like LODS, MOVS, STOS, CMPS, etc, a way of determining which prefixes, if any, immediately
|
||||
* preceded them.
|
||||
*/
|
||||
X86.OPFLAG.PREFIXES = (X86.OPFLAG.SEG | X86.OPFLAG.LOCK | X86.OPFLAG.REPZ | X86.OPFLAG.REPNZ | X86.OPFLAG.DATASIZE | X86.OPFLAG.ADDRSIZE);
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ str.isValidInt = function(s, base)
|
|||
* to ensure we don't get partial values (see isValidInt() for details).
|
||||
*
|
||||
* @param {string} s is the string representation of some number
|
||||
* @param {number} [base] is the radix to assume (default is 16)
|
||||
* @param {number} [base] is the default radix to use (default is 16); can be overridden by prefixes/suffixes
|
||||
* @return {number|undefined} corresponding value, or undefined if invalid
|
||||
*/
|
||||
str.parseInt = function(s, base)
|
||||
|
|
|
|||
Loading…
Reference in a new issue