Added support for DRn and TRn instructions (although they're effectively NOPs for now)
This commit is contained in:
parent
a1e3c366eb
commit
2150744668
167 changed files with 9213 additions and 2029 deletions
|
|
@ -375,13 +375,24 @@ if (DEBUGGER) {
|
|||
Debugger.REG_CR1 = 0x21;
|
||||
Debugger.REG_CR2 = 0x22;
|
||||
Debugger.REG_CR3 = 0x23;
|
||||
Debugger.REG_DR0 = 0x28;
|
||||
Debugger.REG_DR1 = 0x29;
|
||||
Debugger.REG_DR2 = 0x2A;
|
||||
Debugger.REG_DR3 = 0x2B;
|
||||
Debugger.REG_DR6 = 0x2E;
|
||||
Debugger.REG_DR7 = 0x2F;
|
||||
Debugger.REG_TR0 = 0x30;
|
||||
Debugger.REG_TR6 = 0x36;
|
||||
Debugger.REG_TR7 = 0x37;
|
||||
|
||||
Debugger.REGS = [
|
||||
"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH",
|
||||
"AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI",
|
||||
"ES", "CS", "SS", "DS", "FS", "GS", "IP", "PS",
|
||||
"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI",
|
||||
"CR0", "CR1", "CR2", "CR3"
|
||||
"CR0", "CR1", "CR2", "CR3", null, null, null, null, // register names used with TYPE_CTLREG
|
||||
"DR0", "DR1", "DR2", "DR3", null, null, "DR6", "DR7", // register names used with TYPE_DBGREG
|
||||
null, null, null, null, null, null, "TR6", "TR7" // register names used with TYPE_TSTREG
|
||||
];
|
||||
|
||||
Debugger.REG_ES = 0x00; // bits 0-1 are standard SegReg encodings
|
||||
|
|
@ -919,7 +930,11 @@ if (DEBUGGER) {
|
|||
0x05: [Debugger.INS.LOADALL,Debugger.TYPE_80286],
|
||||
0x06: [Debugger.INS.CLTS, Debugger.TYPE_80286],
|
||||
0x20: [Debugger.INS.MOV, Debugger.TYPE_MODREG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_CTLREG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
||||
0x21: [Debugger.INS.MOV, Debugger.TYPE_MODREG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_DBGREG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
||||
0x22: [Debugger.INS.MOV, Debugger.TYPE_CTLREG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODREG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
||||
0x23: [Debugger.INS.MOV, Debugger.TYPE_DBGREG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODREG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
||||
0x24: [Debugger.INS.MOV, Debugger.TYPE_MODREG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_TSTREG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
||||
0x26: [Debugger.INS.MOV, Debugger.TYPE_TSTREG | Debugger.TYPE_DWORD | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODREG | Debugger.TYPE_DWORD | Debugger.TYPE_IN],
|
||||
0x80: [Debugger.INS.JO, Debugger.TYPE_IMMREL | Debugger.TYPE_VWORD | Debugger.TYPE_IN | Debugger.TYPE_80386],
|
||||
0x81: [Debugger.INS.JNO, Debugger.TYPE_IMMREL | Debugger.TYPE_VWORD | Debugger.TYPE_IN | Debugger.TYPE_80386],
|
||||
0x82: [Debugger.INS.JC, Debugger.TYPE_IMMREL | Debugger.TYPE_VWORD | Debugger.TYPE_IN | Debugger.TYPE_80386],
|
||||
|
|
@ -3509,7 +3524,7 @@ if (DEBUGGER) {
|
|||
break;
|
||||
}
|
||||
if (sOperands.length > 0) sOperands += ",";
|
||||
sOperands += sOperand;
|
||||
sOperands += (sOperand || "???");
|
||||
}
|
||||
|
||||
var sLine = this.hexAddr(dbgAddrIns) + " ";
|
||||
|
|
@ -3608,6 +3623,12 @@ if (DEBUGGER) {
|
|||
else if (typeMode == Debugger.TYPE_CTLREG) {
|
||||
bReg += Debugger.REG_CR0;
|
||||
}
|
||||
else if (typeMode == Debugger.TYPE_DBGREG) {
|
||||
bReg += Debugger.REG_DR0;
|
||||
}
|
||||
else if (typeMode == Debugger.TYPE_TSTREG) {
|
||||
bReg += Debugger.REG_TR0;
|
||||
}
|
||||
else {
|
||||
var typeSize = type & Debugger.TYPE_SIZE;
|
||||
if (typeSize >= Debugger.TYPE_WORD) {
|
||||
|
|
@ -5935,7 +5956,7 @@ if (DEBUGGER) {
|
|||
}
|
||||
}
|
||||
|
||||
var ch, ch0, i;
|
||||
var ch0, i;
|
||||
switch (sCmd) {
|
||||
case "reset":
|
||||
if (this.cmp) this.cmp.reset();
|
||||
|
|
|
|||
|
|
@ -2139,6 +2139,10 @@ Disk.prototype.toJSON = function()
|
|||
*/
|
||||
s = s.replace(/,"[^"]*":([0-9]+|true|false)/gm, "");
|
||||
s = s.replace(/(sector|length|data|pattern):/gm, "\"$1\":");
|
||||
/*
|
||||
* Last but not least, insert line breaks after every object definition, to ease the pain on text editors.
|
||||
*/
|
||||
s = s.replace(/},/gm, "},\n");
|
||||
return s;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -168,10 +168,10 @@ SerialPort.DL_DEFAULT = 0x180; // we select an arbitrary default Diviso
|
|||
* SerialPort interrupts by passing a hard-coded delay to setIRR(). The setIRR() delay does not ensure any
|
||||
* particular baud rate, it simply gives the underlying Interrupt Service Routine (ISR) some breathing room.
|
||||
*
|
||||
* The Microsoft Windows 1.01 serial mouse driver ISR issues an EOI before it has safely exited, relying solely
|
||||
* on the fact that a 1200 baud serial device would not normally interrupt frequently enough to blow the stack.
|
||||
* However, in PCjs, all you have to do is enable Debugger messages on every serial interrupt and mouse event,
|
||||
* eg:
|
||||
* The Microsoft Windows 1.01 serial mouse driver ISR issues an EOI before it has safely exited, presumably
|
||||
* relying on the fact that a 1200 baud serial device would not normally interrupt frequently enough to blow
|
||||
* the stack. However, in PCjs, all you have to do is enable Debugger messages on every serial interrupt
|
||||
* and mouse event, eg:
|
||||
*
|
||||
* m serial on;m pic on;m mouse on
|
||||
*
|
||||
|
|
@ -179,8 +179,9 @@ SerialPort.DL_DEFAULT = 0x180; // we select an arbitrary default Diviso
|
|||
* display the current stack pointer, which you can watch drop to zero and then wrap around, no doubt trampling
|
||||
* lots of code and data along the way.
|
||||
*
|
||||
* This problem can also occur without being forced by the Debugger; eg, whenever the physical machine's mouse is
|
||||
* configured for a high interrupt rate.
|
||||
* This problem could also occur without being forced by the Debugger; eg, if your physical machine's mouse was
|
||||
* configured for a high interrupt rate, and your browser generated mouse events at a comparable rate, then you
|
||||
* could blow the simulation's stack.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1103,6 +1103,82 @@ X86CPU.prototype.reset = function()
|
|||
if (SAMPLER) this.iSampleNext = this.iSampleFreq = this.iSampleSkip = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* getReg(i)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} i (0-7)
|
||||
* @return {number}
|
||||
*/
|
||||
X86CPU.prototype.getReg = function(i)
|
||||
{
|
||||
var reg;
|
||||
switch(i) {
|
||||
case 0x0:
|
||||
reg = this.regEAX;
|
||||
break;
|
||||
case 0x1:
|
||||
reg = this.regECX;
|
||||
break;
|
||||
case 0x2:
|
||||
reg = this.regEDX;
|
||||
break;
|
||||
case 0x3:
|
||||
reg = this.regEBX;
|
||||
break;
|
||||
case 0x4:
|
||||
reg = this.regESP;
|
||||
break;
|
||||
case 0x5:
|
||||
reg = this.regEBP;
|
||||
break;
|
||||
case 0x6:
|
||||
reg = this.regESI;
|
||||
break;
|
||||
case 0x7:
|
||||
reg = this.regEDI;
|
||||
break;
|
||||
}
|
||||
return reg;
|
||||
};
|
||||
|
||||
/**
|
||||
* setReg(i, reg)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} i (0-7)
|
||||
* @param {number} reg
|
||||
*/
|
||||
X86CPU.prototype.setReg = function(i, reg)
|
||||
{
|
||||
switch(i) {
|
||||
case 0x0:
|
||||
this.regEAX = reg;
|
||||
break;
|
||||
case 0x1:
|
||||
this.regECX = reg;
|
||||
break;
|
||||
case 0x2:
|
||||
this.regEDX = reg;
|
||||
break;
|
||||
case 0x3:
|
||||
this.regEBX = reg;
|
||||
break;
|
||||
case 0x4:
|
||||
this.regESP = reg;
|
||||
break;
|
||||
case 0x5:
|
||||
this.regEBP = reg;
|
||||
break;
|
||||
case 0x6:
|
||||
this.regESI = reg;
|
||||
break;
|
||||
case 0x7:
|
||||
this.regEDI = reg;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* resetRegs()
|
||||
*
|
||||
|
|
@ -1236,8 +1312,8 @@ X86CPU.prototype.resetRegs = function()
|
|||
this.regCR1 = 0; // reserved
|
||||
this.regCR2 = 0; // page fault linear address (PFLA)
|
||||
this.regCR3 = 0; // page directory base register (PDBR)
|
||||
this.aRegDR = new Array(8); // Debug Registers DR0-DR7
|
||||
this.aRegTR = new Array(8); // Test Registers TR0-TR7
|
||||
this.regDRn = [0,0,0,0,null,null,0,0]; // Debug Registers DR0-DR7 (DR4-DR5 are undefined)
|
||||
this.regTRn = [null,null,null,null,null,null,0,0]; // Test Registers TR0-TR7 (TR0-TR5 are undefined)
|
||||
this.segFS = new X86Seg(this, X86Seg.ID.DATA, "FS");
|
||||
this.segGS = new X86Seg(this, X86Seg.ID.DATA, "GS");
|
||||
this.disablePageBlocks();
|
||||
|
|
@ -1666,8 +1742,8 @@ X86CPU.prototype.saveProtMode = function()
|
|||
a.push(this.regCR1);
|
||||
a.push(this.regCR2);
|
||||
a.push(this.regCR3);
|
||||
a.push(this.aRegDR);
|
||||
a.push(this.aRegTR);
|
||||
a.push(this.regDRn);
|
||||
a.push(this.regTRn);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
|
@ -1697,8 +1773,8 @@ X86CPU.prototype.restoreProtMode = function(a)
|
|||
this.regCR1 = a[8];
|
||||
this.regCR2 = a[9];
|
||||
this.regCR3 = a[10];
|
||||
this.aRegDR = a[11];
|
||||
this.aRegTR = a[12];
|
||||
this.regDRn = a[11];
|
||||
this.regTRn = a[12];
|
||||
}
|
||||
this.setProtMode();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3694,7 +3694,7 @@ X86.fnFault = function(nFault, nError, fHalt, nCycles)
|
|||
this.opFlags |= X86.OPFLAG.FAULT;
|
||||
|
||||
if (!this.aFlags.fComplete) {
|
||||
this.printMessage("Fault " + str.toHexByte(nFault) + " blocked by Debugger", Messages.WARN);
|
||||
this.printMessage("Fault " + str.toHexByte(nFault) + " blocked by PCjs", Messages.WARN);
|
||||
this.setIP(this.opLIP - this.segCS.base);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ X86.opLSL = function LSL()
|
|||
};
|
||||
|
||||
/**
|
||||
* opLOADALL()
|
||||
* opLOADALL286()
|
||||
*
|
||||
* op=0x0F,0x05 (LOADALL)
|
||||
*
|
||||
|
|
@ -138,12 +138,12 @@ X86.opLSL = function LSL()
|
|||
* 85A-85F IDTR
|
||||
* 860-865 TSS descriptor cache
|
||||
*
|
||||
* Oddly, the above document gives two contradictory cycle counts for LOADALL: 190 and 195. I'll go with 195, for
|
||||
* no particular reason.
|
||||
* Oddly, the above document gives two contradictory cycle counts for LOADALL: 190 and 195. I'll go with 195, since
|
||||
* the PCMag_Prog_TechRef mentions that time as well.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opLOADALL = function LOADALL()
|
||||
X86.opLOADALL286 = function LOADALL286()
|
||||
{
|
||||
if (this.nCPL) {
|
||||
/*
|
||||
|
|
@ -212,21 +212,121 @@ X86.opCLTS = function CLTS()
|
|||
this.nStepCycles -= 2;
|
||||
};
|
||||
|
||||
/**
|
||||
* opLOADALL386()
|
||||
*
|
||||
* op=0x0F,0x07 (LOADALL ES:[EDI])
|
||||
*
|
||||
* Excerpt from Intel Internal Correspondence on "386 LOADALL Instruction" (undated):
|
||||
*
|
||||
* 1.5. 386 LOADALL Memory Format
|
||||
*
|
||||
* The following tables define the LOADALL memory format. The LOADALL instruction uses a 512-byte block of
|
||||
* memory, where the lowest addressed byte is given in ES:[(E)DI]. The area above offset CC hex is used for
|
||||
* processor dependent registers (temporaries, invisible registers). These are loaded into the processor,
|
||||
* but will not affect normal program execution. All values in the memory area are read from a four byte field,
|
||||
* to keep the memory format DWORD aligned, but it is possible to locate memory area at a non-aligned address.
|
||||
* In this case, the execution time of LOADALL will DOUBLE For this reason, the memory dump area should always
|
||||
* be DWORD aligned.
|
||||
*
|
||||
* Offset Register
|
||||
* 0x00 CR0
|
||||
* 0x04 EFLAGS
|
||||
* 0x08 EIP
|
||||
* 0x0C EDI
|
||||
* 0x10 ESI
|
||||
* 0x14 EBP
|
||||
* 0x18 ESP
|
||||
* 0x1C EBX
|
||||
* 0x20 EDX
|
||||
* 0x24 ECX
|
||||
* 0x28 EAX
|
||||
* 0x2C DR6
|
||||
* 0x30 DR7
|
||||
* 0x34 TR (TSS Selector--Word)
|
||||
* 0x38 LDTR (LDT Selector--Word)
|
||||
* 0x3C GS
|
||||
* 0x40 FS
|
||||
* 0x44 DS
|
||||
* 0x48 SS
|
||||
* 0x4C CS
|
||||
* 0x50 ES
|
||||
* 0x54 TSS (AR)
|
||||
* 0x58 TSS (BASE)
|
||||
* 0x5C TSS (LIMIT)
|
||||
* 0x60 IDT (AR)
|
||||
* 0x64 IDT (BASE)
|
||||
* 0x68 IDT (LIMIT)
|
||||
* 0x6C GDT (AR)
|
||||
* 0x70 GDT (BASE)
|
||||
* 0x74 GDT (LIMIT)
|
||||
* 0x78 LDT (AR)
|
||||
* 0x7C LDT (BASE)
|
||||
* 0x80 LDT (LIMIT)
|
||||
* 0x84 GS (AR)
|
||||
* 0x88 GS (BASE)
|
||||
* 0x8C GS (LIMIT)
|
||||
* 0x90 FS (AR)
|
||||
* 0x94 FS (BASE)
|
||||
* 0x98 FS (LIMIT)
|
||||
* 0x9C DS (AR)
|
||||
* 0xA0 DS (BASE)
|
||||
* 0xA4 DS (LIMIT)
|
||||
* 0xA8 SS (AR)
|
||||
* 0xAC SS (BASE)
|
||||
* 0xB0 SS (LIMIT)
|
||||
* 0xB4 CS (AR)
|
||||
* 0xB8 CS (BASE)
|
||||
* 0xBC CS (LIMIT)
|
||||
* 0xC0 ES (AR)
|
||||
* 0xC4 ES (BASE)
|
||||
* 0xC8 ES (LIMIT)
|
||||
*
|
||||
* Each descriptor entry consists of 3 pieces:
|
||||
*
|
||||
* AR
|
||||
* BASE
|
||||
* LIMIT
|
||||
*
|
||||
* The AR part has the same format as the second dword of a segment descriptor except that only the AR byte (bits 8-15)
|
||||
* and the G and B/D bits (bits 23 and 22) are used. All other bits in the AR field are ignored. The BASE and LIMIT parts
|
||||
* contain full 32-bit values, fully expanded and unscrambled from the 386 descriptor. In particular, the LIMIT field
|
||||
* loaded for a page granular segment gives a byte granular limit, so should contain the page limit*4096 plus 4095.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opLOADALL386 = function LOADALL386()
|
||||
{
|
||||
if (this.nCPL) {
|
||||
/*
|
||||
* To use LOADALL, CPL must be zero.
|
||||
*/
|
||||
X86.fnFault.call(this, X86.EXCEPTION.GP_FAULT, 0, true);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* TODO: Implement
|
||||
*/
|
||||
X86.opUndefined.call(this);
|
||||
|
||||
this.nStepCycles -= 100; // I've not seen a documented time for the 80386 LOADALL, so we'll make a guess
|
||||
};
|
||||
|
||||
/**
|
||||
* opMOVrc()
|
||||
*
|
||||
* op=0x0F,0x20 (MOV reg,creg)
|
||||
* op=0x0F,0x20 (MOV reg,ctlreg)
|
||||
*
|
||||
* NOTE: Since this instruction uses only 32-bit general-purpose registers, our ModRM decoders
|
||||
* are going to be more hindrance than help, so we fully decode and execute the instruction ourselves.
|
||||
*
|
||||
* From PCMag_Prog_TechRef, p.476: "The 80386 executes the MOV to/from control registers (CRn) regardless
|
||||
* of the setting of the MOD field. The MOD field should be set to 0b11, but an early 80386 documentation
|
||||
* of the setting of the MOD field. The MOD field should be set to 11, but an early 80386 documentation
|
||||
* error indicated that the MOD field value was a don't care. Early versions of the 80486 detect
|
||||
* a MOD != 0b11 as an illegal opcode. This was changed in later versions to ignore the value of MOD.
|
||||
* Assemblers that generate MOD != 0b11 for these instructions will fail on some 80486s."
|
||||
* a MOD != 11 as an illegal opcode. This was changed in later versions to ignore the value of MOD.
|
||||
* Assemblers that generate MOD != 11 for these instructions will fail on some 80486s."
|
||||
*
|
||||
* And in fact, the Compaq DeskPro 386 ROM BIOS executes this instruction with MOD set to 0b00, so we have
|
||||
* And in fact, the Compaq DeskPro 386 ROM BIOS executes this instruction with MOD set to 00, so we have
|
||||
* to ignore it.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
|
|
@ -261,32 +361,7 @@ X86.opMOVrc = function MOVrc()
|
|||
return;
|
||||
}
|
||||
|
||||
switch(bModRM & 0x7) {
|
||||
case 0x0:
|
||||
this.regEAX = reg;
|
||||
break;
|
||||
case 0x1:
|
||||
this.regECX = reg;
|
||||
break;
|
||||
case 0x2:
|
||||
this.regEDX = reg;
|
||||
break;
|
||||
case 0x3:
|
||||
this.regEBX = reg;
|
||||
break;
|
||||
case 0x4:
|
||||
this.regESP = reg;
|
||||
break;
|
||||
case 0x5:
|
||||
this.regEBP = reg;
|
||||
break;
|
||||
case 0x6:
|
||||
this.regESI = reg;
|
||||
break;
|
||||
case 0x7:
|
||||
this.regEDI = reg;
|
||||
break;
|
||||
}
|
||||
this.setReg(bModRM & 0x7, reg);
|
||||
|
||||
this.nStepCycles -= 6;
|
||||
|
||||
|
|
@ -295,21 +370,61 @@ X86.opMOVrc = function MOVrc()
|
|||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* opMOVrd()
|
||||
*
|
||||
* op=0x0F,0x21 (MOV reg,dbgreg)
|
||||
*
|
||||
* NOTE: Since this instruction uses only 32-bit general-purpose registers, our ModRM decoders
|
||||
* are going to be more hindrance than help, so we fully decode and execute the instruction ourselves.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opMOVrd = function MOVrd()
|
||||
{
|
||||
/*
|
||||
* NOTE: The following code shouldn't need to also test X86.PS.VM, because V86-mode is CPL 3.
|
||||
*/
|
||||
if (this.nCPL) {
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
var bModRM = this.getIPByte();
|
||||
var iSrc = (bModRM & 0x38) >> 3;
|
||||
|
||||
if (iSrc == 4 || iSrc == 5) {
|
||||
X86.opUndefined.call(this);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setReg(bModRM & 0x7, this.regDRn[iSrc]);
|
||||
|
||||
this.nStepCycles -= 22;
|
||||
|
||||
/*
|
||||
* TODO: Implement BACKTRACK for this instruction....
|
||||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* opMOVcr()
|
||||
*
|
||||
* op=0x0F,0x22 (MOV creg,reg)
|
||||
* op=0x0F,0x22 (MOV ctlreg,reg)
|
||||
*
|
||||
* NOTE: Since this instruction uses only 32-bit general-purpose registers, our ModRM decoders
|
||||
* are going to be more hindrance than help, so we fully decode and execute the instruction ourselves.
|
||||
*
|
||||
* From PCMag_Prog_TechRef, p.476: "The 80386 executes the MOV to/from control registers (CRn) regardless
|
||||
* of the setting of the MOD field. The MOD field should be set to 0b11, but an early 80386 documentation
|
||||
* of the setting of the MOD field. The MOD field should be set to 11, but an early 80386 documentation
|
||||
* error indicated that the MOD field value was a don't care. Early versions of the 80486 detect
|
||||
* a MOD != 0b11 as an illegal opcode. This was changed in later versions to ignore the value of MOD.
|
||||
* Assemblers that generate MOD != 0b11 for these instructions will fail on some 80486s."
|
||||
* a MOD != 11 as an illegal opcode. This was changed in later versions to ignore the value of MOD.
|
||||
* Assemblers that generate MOD != 11 for these instructions will fail on some 80486s."
|
||||
*
|
||||
* And in fact, the Compaq DeskPro 386 ROM BIOS executes this instruction with MOD set to 0b00, so we have
|
||||
* And in fact, the Compaq DeskPro 386 ROM BIOS executes this instruction with MOD set to 00, so we have
|
||||
* to ignore it.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
|
|
@ -327,34 +442,9 @@ X86.opMOVcr = function MOVcr()
|
|||
return;
|
||||
}
|
||||
|
||||
var reg;
|
||||
var bModRM = this.getIPByte();
|
||||
switch(bModRM & 0x7) {
|
||||
case 0x0:
|
||||
reg = this.regEAX;
|
||||
break;
|
||||
case 0x1:
|
||||
reg = this.regECX;
|
||||
break;
|
||||
case 0x2:
|
||||
reg = this.regEDX;
|
||||
break;
|
||||
case 0x3:
|
||||
reg = this.regEBX;
|
||||
break;
|
||||
case 0x4:
|
||||
reg = this.regESP;
|
||||
break;
|
||||
case 0x5:
|
||||
reg = this.regEBP;
|
||||
break;
|
||||
case 0x6:
|
||||
reg = this.regESI;
|
||||
break;
|
||||
case 0x7:
|
||||
reg = this.regEDI;
|
||||
break;
|
||||
}
|
||||
|
||||
var reg = this.getReg(bModRM & 0x7);
|
||||
|
||||
switch((bModRM & 0x38) >> 3) {
|
||||
case 0x0:
|
||||
|
|
@ -379,6 +469,132 @@ X86.opMOVcr = function MOVcr()
|
|||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* opMOVdr()
|
||||
*
|
||||
* op=0x0F,0x23 (MOV dbgreg,reg)
|
||||
*
|
||||
* NOTE: Since this instruction uses only 32-bit general-purpose registers, our ModRM decoders
|
||||
* are going to be more hindrance than help, so we fully decode and execute the instruction ourselves.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opMOVdr = function MOVdr()
|
||||
{
|
||||
/*
|
||||
* NOTE: The following code shouldn't need to also test X86.PS.VM, because V86-mode is CPL 3.
|
||||
*/
|
||||
if (this.nCPL) {
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
var bModRM = this.getIPByte();
|
||||
var iDst = (bModRM & 0x38) >> 3;
|
||||
|
||||
if (iDst == 4 || iDst == 5) {
|
||||
X86.opUndefined.call(this);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Do something with the Debug registers....
|
||||
*/
|
||||
this.regDRn[iDst] = this.getReg(bModRM & 0x7);
|
||||
|
||||
this.nStepCycles -= (iDst < 4? 22 : 14);
|
||||
|
||||
/*
|
||||
* TODO: Implement BACKTRACK for this instruction....
|
||||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* opMOVrt()
|
||||
*
|
||||
* op=0x0F,0x24 (MOV reg,tstreg)
|
||||
*
|
||||
* NOTE: Since this instruction uses only 32-bit general-purpose registers, our ModRM decoders
|
||||
* are going to be more hindrance than help, so we fully decode and execute the instruction ourselves.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opMOVrt = function MOVrt()
|
||||
{
|
||||
/*
|
||||
* NOTE: The following code shouldn't need to also test X86.PS.VM, because V86-mode is CPL 3.
|
||||
*/
|
||||
if (this.nCPL) {
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
var bModRM = this.getIPByte();
|
||||
var iSrc = (bModRM & 0x38) >> 3;
|
||||
|
||||
if (iSrc < 6) {
|
||||
X86.opUndefined.call(this);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setReg(bModRM & 0x7, this.regTRn[iSrc]);
|
||||
|
||||
this.nStepCycles -= 12;
|
||||
|
||||
/*
|
||||
* TODO: Implement BACKTRACK for this instruction....
|
||||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* opMOVtr()
|
||||
*
|
||||
* op=0x0F,0x26 (MOV tstreg,reg)
|
||||
*
|
||||
* NOTE: Since this instruction uses only 32-bit general-purpose registers, our ModRM decoders
|
||||
* are going to be more hindrance than help, so we fully decode and execute the instruction ourselves.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opMOVtr = function MOVtr()
|
||||
{
|
||||
/*
|
||||
* NOTE: The following code shouldn't need to also test X86.PS.VM, because V86-mode is CPL 3.
|
||||
*/
|
||||
if (this.nCPL) {
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
var bModRM = this.getIPByte();
|
||||
var iDst = (bModRM & 0x38) >> 3;
|
||||
|
||||
if (iDst < 6) {
|
||||
X86.opUndefined.call(this);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Do something with the Test registers....
|
||||
*/
|
||||
this.regTRn[iDst] = this.getReg(bModRM & 0x7);
|
||||
|
||||
this.nStepCycles -= 12;
|
||||
|
||||
/*
|
||||
* TODO: Implement BACKTRACK for this instruction....
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* NOTE: The following 16 new conditional jumps actually rely on the OPERAND override setting
|
||||
* for determining whether a signed 16-bit or 32-bit displacement will be fetched, even though
|
||||
|
|
@ -1352,7 +1568,7 @@ X86.aOps0F[0x00] = X86.opGRP6;
|
|||
X86.aOps0F[0x01] = X86.opGRP7;
|
||||
X86.aOps0F[0x02] = X86.opLAR;
|
||||
X86.aOps0F[0x03] = X86.opLSL;
|
||||
X86.aOps0F[0x05] = X86.opLOADALL;
|
||||
X86.aOps0F[0x05] = X86.opLOADALL286;
|
||||
X86.aOps0F[0x06] = X86.opCLTS;
|
||||
|
||||
/*
|
||||
|
|
@ -1402,8 +1618,14 @@ X86.aOps0F[0xFF] = X86.opInvalid;
|
|||
|
||||
if (I386) {
|
||||
X86.aOps0F386 = [];
|
||||
X86.aOps0F386[0x05] = X86.opInvalid; // the 80286 LOADALL opcode is invalid on the 80386
|
||||
X86.aOps0F386[0x07] = X86.opLOADALL386;
|
||||
X86.aOps0F386[0x20] = X86.opMOVrc;
|
||||
X86.aOps0F386[0x21] = X86.opMOVrd;
|
||||
X86.aOps0F386[0x22] = X86.opMOVcr;
|
||||
X86.aOps0F386[0x23] = X86.opMOVdr;
|
||||
X86.aOps0F386[0x24] = X86.opMOVrt;
|
||||
X86.aOps0F386[0x26] = X86.opMOVtr;
|
||||
X86.aOps0F386[0x80] = X86.opJOw;
|
||||
X86.aOps0F386[0x81] = X86.opJNOw;
|
||||
X86.aOps0F386[0x82] = X86.opJCw;
|
||||
|
|
|
|||
Loading…
Reference in a new issue