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
|
|
@ -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