New skeleton for x86fpu.js
This commit is contained in:
parent
1b3734440e
commit
2b1b62d565
7 changed files with 1440 additions and 167 deletions
|
|
@ -40,6 +40,7 @@ if (NODE) {
|
|||
var Interrupts = require("./interrupts");
|
||||
var Messages = require("./messages");
|
||||
var State = require("./state");
|
||||
var X86 = require("./x86");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -985,7 +986,7 @@ ChipSet.NMI = { // this.bNMI
|
|||
/*
|
||||
* Coprocessor Control Registers (MODEL_5170)
|
||||
*/
|
||||
ChipSet.COPROC = { // TODO: Define a variable for this
|
||||
ChipSet.COPROC = { // TODO: Define a variable for this?
|
||||
PORT_CLEAR: 0xF0, // clear the coprocessor's "busy" state
|
||||
PORT_RESET: 0xF1 // reset the coprocessor
|
||||
};
|
||||
|
|
@ -1058,7 +1059,12 @@ ChipSet.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
this.cpu = cpu;
|
||||
this.dbg = dbg;
|
||||
this.cmp = cmp;
|
||||
|
||||
this.fpu = cmp.getMachineComponent("FPU");
|
||||
if (this.fpu) this.sw1Init |= ChipSet.PPI_SW.COPROC;
|
||||
|
||||
this.kbd = cmp.getMachineComponent("Keyboard");
|
||||
|
||||
/*
|
||||
* This divisor is invariant, so we calculate it as soon as we're able to query the CPU's base speed.
|
||||
*/
|
||||
|
|
@ -1091,9 +1097,6 @@ ChipSet.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
}
|
||||
cpu.addIntNotify(Interrupts.RTC, this.intBIOSRTC.bind(this));
|
||||
}
|
||||
if (cpu.fpu) {
|
||||
this.sw1Init |= ChipSet.PPI_SW.COPROC;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -3513,6 +3516,43 @@ ChipSet.prototype.getIRRVector = function(iPIC)
|
|||
return nIDT;
|
||||
};
|
||||
|
||||
/**
|
||||
* setFPUInterrupt()
|
||||
*
|
||||
* @this {ChipSet}
|
||||
*/
|
||||
ChipSet.prototype.setFPUInterrupt = function()
|
||||
{
|
||||
if (this.model >= ChipSet.MODEL_5170) {
|
||||
this.setIRR(ChipSet.IRQ.COPROC);
|
||||
} else {
|
||||
/*
|
||||
* TODO: Determine whether we need to maintain an "Active NMI" state; ie, if NMI.DISABLE is cleared
|
||||
* later, and the coprocessor is still indicating an error condition, should we then generate an NMI?
|
||||
*/
|
||||
if (!(this.bNMI & ChipSet.NMI.DISABLE)) {
|
||||
X86.fnInterrupt.call(this.cpu, X86.EXCEPTION.NMI);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* clearFPUInterrupt(fSet)
|
||||
*
|
||||
* @this {ChipSet}
|
||||
*/
|
||||
ChipSet.prototype.clearFPUInterrupt = function()
|
||||
{
|
||||
if (this.model >= ChipSet.MODEL_5170) {
|
||||
this.clearIRR(ChipSet.IRQ.COPROC);
|
||||
} else {
|
||||
/*
|
||||
* TODO: If we maintain an "Active NMI" state, then we will need code here to clear that state, as well
|
||||
* as code in outNMI() to clear that state and generate an NMI as needed.
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* inTimer(iTimer, addrFrom)
|
||||
*
|
||||
|
|
@ -4959,11 +4999,9 @@ ChipSet.prototype.outNMI = function(port, bOut, addrFrom)
|
|||
*/
|
||||
ChipSet.prototype.outCoprocClear = function(port, bOut, addrFrom)
|
||||
{
|
||||
/*
|
||||
* TODO: Implement
|
||||
*/
|
||||
this.printMessageIO(port, bOut, addrFrom, "COPROC.CLEAR");
|
||||
this.assert(!bOut);
|
||||
if (this.fpu) this.fpu.clearBusy();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -4978,11 +5016,9 @@ ChipSet.prototype.outCoprocClear = function(port, bOut, addrFrom)
|
|||
*/
|
||||
ChipSet.prototype.outCoprocReset = function(port, bOut, addrFrom)
|
||||
{
|
||||
/*
|
||||
* TODO: Implement
|
||||
*/
|
||||
this.printMessageIO(port, bOut, addrFrom, "COPROC.RESET");
|
||||
this.assert(!bOut);
|
||||
if (this.fpu) this.fpu.resetFPU();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@ CPU.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
this.cmp = cmp;
|
||||
this.bus = bus;
|
||||
this.dbg = dbg;
|
||||
this.fpu = cmp.getMachineComponent("FPU");
|
||||
|
||||
/*
|
||||
* Attach the Video component to the CPU, so that the CPU can periodically update
|
||||
|
|
@ -197,9 +198,6 @@ CPU.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
* We must also call chipset.updateAllTimers() periodically; stepCPU() takes care of that.
|
||||
*/
|
||||
this.chipset = cmp.getMachineComponent("ChipSet");
|
||||
|
||||
this.fpu = cmp.getMachineComponent("FPU");
|
||||
|
||||
this.setReady();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -534,7 +534,8 @@ if (DEBUGGER) {
|
|||
Debugger.TYPE_OTHER = 0xF000; // "other" field
|
||||
|
||||
/*
|
||||
* TYPE_SIZE values.
|
||||
* TYPE_SIZE values. Some definitions use duplicate values when the operands are the
|
||||
* same size and the Debugger doesn't need to make a distinction.
|
||||
*/
|
||||
Debugger.TYPE_NONE = 0x0000; // (all other TYPE fields ignored)
|
||||
Debugger.TYPE_BYTE = 0x0001; // (b) byte, regardless of operand size
|
||||
|
|
@ -544,18 +545,16 @@ if (DEBUGGER) {
|
|||
Debugger.TYPE_LONG = 0x0005; // (d) 32-bit value
|
||||
Debugger.TYPE_SEGP = 0x0006; // (p) 32-bit or 48-bit pointer
|
||||
Debugger.TYPE_FARP = 0x0007; // (p) 32-bit or 48-bit pointer for JMP/CALL
|
||||
Debugger.TYPE_2WORD = 0x0008; // (a) two memory operands (BOUND only)
|
||||
Debugger.TYPE_DESC = 0x0009; // (s) 6 byte pseudo-descriptor
|
||||
Debugger.TYPE_PREFIX = 0x000A; // (treat similarly to TYPE_NONE)
|
||||
Debugger.TYPE_ST = 0x000B; // FPU ST
|
||||
Debugger.TYPE_STREG = 0x000C; // FPU ST register
|
||||
Debugger.TYPE_SI = 0x000D; // FPU SI (short-integer; 32-bit)
|
||||
Debugger.TYPE_SR = 0x000D; // FPU SR (short-real; 32-bit)
|
||||
Debugger.TYPE_LI = 0x000E; // FPU LI (long-integer; 64-bit)
|
||||
Debugger.TYPE_LR = 0x000E; // FPU LR (long-real; 64-bit)
|
||||
Debugger.TYPE_TR = 0x000F; // FPU TR (temp-real; 80-bit)
|
||||
Debugger.TYPE_PD = 0x000F; // FPU PD (packed-decimal, 18 digits; 80-bit)
|
||||
Debugger.TYPE_ENV = 0x000F; // FPU ENV (environment; 14 bytes)
|
||||
Debugger.TYPE_PREFIX = 0x0008; // (treat similarly to TYPE_NONE)
|
||||
Debugger.TYPE_ST = 0x0009; // FPU ST (implicit top)
|
||||
Debugger.TYPE_STREG = 0x000A; // FPU ST (explicit register)
|
||||
Debugger.TYPE_SI = 0x000B; // FPU SI (short-integer; 32-bit)
|
||||
Debugger.TYPE_SR = 0x000B; // FPU SR (short-real; 32-bit)
|
||||
Debugger.TYPE_LI = 0x000C; // FPU LI (long-integer; 64-bit)
|
||||
Debugger.TYPE_LR = 0x000C; // FPU LR (long-real; 64-bit)
|
||||
Debugger.TYPE_TR = 0x000D; // FPU TR (temp-real; 80-zbit)
|
||||
Debugger.TYPE_PD = 0x000D; // FPU PD (packed-decimal, 18 digits; 80-bit)
|
||||
Debugger.TYPE_ENV = 0x000E; // FPU ENV (environment; 14 bytes)
|
||||
Debugger.TYPE_FPU = 0x000F; // FPU SAVE (save/restore; 94 bytes)
|
||||
|
||||
/*
|
||||
|
|
@ -816,7 +815,7 @@ if (DEBUGGER) {
|
|||
|
||||
/* 0x60 */ [Debugger.INS.PUSHA, Debugger.TYPE_NONE | Debugger.TYPE_80286],
|
||||
/* 0x61 */ [Debugger.INS.POPA, Debugger.TYPE_NONE | Debugger.TYPE_80286],
|
||||
/* 0x62 */ [Debugger.INS.BOUND, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_IN | Debugger.TYPE_80286, Debugger.TYPE_MODRM | Debugger.TYPE_2WORD | Debugger.TYPE_IN],
|
||||
/* 0x62 */ [Debugger.INS.BOUND, Debugger.TYPE_REG | Debugger.TYPE_WORD | Debugger.TYPE_IN | Debugger.TYPE_80286, Debugger.TYPE_MODRM | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||
/* 0x63 */ [Debugger.INS.ARPL, Debugger.TYPE_MODRM | Debugger.TYPE_SHORT | Debugger.TYPE_OUT, Debugger.TYPE_REG | Debugger.TYPE_SHORT | Debugger.TYPE_IN],
|
||||
/* 0x64 */ [Debugger.INS.FS, Debugger.TYPE_PREFIX | Debugger.TYPE_80386],
|
||||
/* 0x65 */ [Debugger.INS.GS, Debugger.TYPE_PREFIX | Debugger.TYPE_80386],
|
||||
|
|
@ -1067,6 +1066,9 @@ if (DEBUGGER) {
|
|||
0xBF: [Debugger.INS.MOVSX, Debugger.TYPE_REG | Debugger.TYPE_LONG | Debugger.TYPE_OUT | Debugger.TYPE_80386, Debugger.TYPE_MODRM | Debugger.TYPE_SHORT | Debugger.TYPE_IN]
|
||||
};
|
||||
|
||||
/*
|
||||
* Be sure to keep the following table in sync with X86FPU.aaOps
|
||||
*/
|
||||
Debugger.aaaOpFPUDescs = {
|
||||
0xD8: {
|
||||
0x00: [Debugger.FINS.FADD, Debugger.TYPE_MODRM | Debugger.TYPE_SR | Debugger.TYPE_IN],
|
||||
|
|
@ -1097,7 +1099,7 @@ if (DEBUGGER) {
|
|||
0x30: [Debugger.FINS.FLD, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT],
|
||||
0x31: [Debugger.FINS.FXCH, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT],
|
||||
0x32: [Debugger.FINS.FNOP],
|
||||
0x33: [Debugger.FINS.FSTP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT],
|
||||
0x33: [Debugger.FINS.FSTP, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT],
|
||||
0x40: [Debugger.FINS.FCHS],
|
||||
0x41: [Debugger.FINS.FABS],
|
||||
0x44: [Debugger.FINS.FTST],
|
||||
|
|
@ -1144,14 +1146,14 @@ if (DEBUGGER) {
|
|||
0x43: [Debugger.FINS.FINIT]
|
||||
},
|
||||
0xDC: {
|
||||
0x00: [Debugger.FINS.FADD, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x01: [Debugger.FINS.FMUL, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x02: [Debugger.FINS.FCOM, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x03: [Debugger.FINS.FCOMP, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x04: [Debugger.FINS.FSUB, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x05: [Debugger.FINS.FSUBR, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x06: [Debugger.FINS.FDIV, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x07: [Debugger.FINS.FDIVR, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x00: [Debugger.FINS.FADD, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x01: [Debugger.FINS.FMUL, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x02: [Debugger.FINS.FCOM, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x03: [Debugger.FINS.FCOMP, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x04: [Debugger.FINS.FSUB, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x05: [Debugger.FINS.FSUBR, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x06: [Debugger.FINS.FDIV, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x07: [Debugger.FINS.FDIVR, Debugger.TYPE_MODRM | Debugger.TYPE_LR | Debugger.TYPE_IN],
|
||||
0x30: [Debugger.FINS.FADD, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN],
|
||||
0x31: [Debugger.FINS.FMUL, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_OUT, Debugger.TYPE_IMPREG | Debugger.TYPE_ST | Debugger.TYPE_IN],
|
||||
0x32: [Debugger.FINS.FCOM, Debugger.TYPE_IMPREG | Debugger.TYPE_STREG | Debugger.TYPE_IN],
|
||||
|
|
@ -4902,14 +4904,14 @@ if (DEBUGGER) {
|
|||
var r_m = (bModRM & 0x7);
|
||||
|
||||
/*
|
||||
* Similar to how fnFPU() decodes FPU instructions, we now combine mod and reg into
|
||||
* one decodable value: put mod in the high nibble and reg in the low nibble, after first
|
||||
* Similar to how fnFPU() decodes FPU instructions, we combine mod and reg into one
|
||||
* decodable value: put mod in the high nibble and reg in the low nibble, after first
|
||||
* collapsing all mod values < 3 to zero.
|
||||
*/
|
||||
var modReg = (mod < 3? 0 : 0x30) + reg;
|
||||
|
||||
/*
|
||||
* Use values >= 0x40 to indicate mod == 0x3, with reg in the high nibble, and r_m in the low.
|
||||
* Use values >= 0x40 to indicate mod == 0x3, with reg in the high nibble and r_m in the low.
|
||||
*/
|
||||
if ((bOpcode == X86.OPCODE.ESC1 || bOpcode == X86.OPCODE.ESC3) && modReg >= 0x34) {
|
||||
modReg = (reg << 4) | r_m;
|
||||
|
|
@ -4949,7 +4951,6 @@ if (DEBUGGER) {
|
|||
sOperand = str.toHex((this.getByte(dbgAddr, 1) << 24) >> 24, dbgAddr.fData32? 8: 4);
|
||||
break;
|
||||
case Debugger.TYPE_WORD:
|
||||
case Debugger.TYPE_2WORD:
|
||||
if (dbgAddr.fData32) {
|
||||
sOperand = str.toHex(this.getLong(dbgAddr, 4));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -532,10 +532,13 @@ var X86 = {
|
|||
OM: 0x0008, // bit 3: Overflow Mask
|
||||
UM: 0x0010, // bit 4: Underflow Mask
|
||||
PM: 0x0020, // bit 5: Precision Mask
|
||||
// bit 6: unused
|
||||
IEM: 0x0080, // bit 7: Interrupt Enable Mask (0 enables interrupts, 1 masks them; 8087 only)
|
||||
PC: 0x0300, // bits 8-9: Precision Control
|
||||
RC: 0x0C00, // bits 10-11: Rounding Control
|
||||
IC: 0x1000 // bit 12: Infinity Control (0 for Projective, 1 for Affine)
|
||||
IC: 0x1000, // bit 12: Infinity Control (0 for Projective, 1 for Affine)
|
||||
// bits 13-15: unused
|
||||
INIT: 0x03BF // X86.FPU.CONTROL.IM | X86.FPU.CONTROL.DM | X86.FPU.CONTROL.ZM | X86.FPU.CONTROL.OM | X86.FPU.CONTROL.UM | X86.FPU.CONTROL.PM | X86.FPU.CONTROL.IEM | X86.FPU.CONTROL.PC
|
||||
},
|
||||
STATUS: { // FPU Status Word
|
||||
IE: 0x0001, // bit 0: Invalid Operation
|
||||
|
|
@ -545,6 +548,7 @@ var X86 = {
|
|||
UE: 0x0010, // bit 4: Underflow
|
||||
PE: 0x0020, // bit 5: Precision
|
||||
SF: 0x0040, // bit 6: Stack Fault (80387 and later)
|
||||
EXC: 0x007F, // all of the above exceptions
|
||||
ES: 0x0080, // bit 7: Exception Summary (Interrupt Request on 8087)
|
||||
C0: 0x0100, // bit 8: Condition Code 0
|
||||
C1: 0x0200, // bit 9: Condition Code 1
|
||||
|
|
@ -553,11 +557,12 @@ var X86 = {
|
|||
C3: 0x4000, // bit 14: Condition Code 3
|
||||
BUSY: 0x8000 // bit 15: Busy
|
||||
},
|
||||
TAG: {
|
||||
VALID: 0x0,
|
||||
ZERO: 0x1,
|
||||
SPECIAL: 0x2,
|
||||
EMPTY: 0x3
|
||||
TAGS: {
|
||||
VALID: 0x0,
|
||||
ZERO: 0x1,
|
||||
SPECIAL:0x2,
|
||||
EMPTY: 0x3,
|
||||
MASK: 0x3
|
||||
}
|
||||
/*
|
||||
C3 C2 C1 C0 Condition Code (CC) values following an Examine
|
||||
|
|
|
|||
|
|
@ -3937,7 +3937,7 @@ X86CPU.prototype.checkINTR = function()
|
|||
this.intFlags &= ~X86.INTFLAG.INTR;
|
||||
if (nIDT >= 0) {
|
||||
this.intFlags &= ~X86.INTFLAG.HALT;
|
||||
X86.fnINT.call(this, this.nFault = nIDT, null, 11);
|
||||
X86.fnInterrupt.call(this, nIDT);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -3947,7 +3947,7 @@ X86CPU.prototype.checkINTR = function()
|
|||
if ((this.intFlags & X86.INTFLAG.TRAP)) {
|
||||
this.intFlags &= ~X86.INTFLAG.TRAP;
|
||||
if (I386 && this.model >= X86.MODEL_80386) this.regDR[6] |= X86.DR6.BS;
|
||||
X86.fnINT.call(this, this.nFault = X86.EXCEPTION.DB_EXC, null, 11);
|
||||
X86.fnInterrupt.call(this, X86.EXCEPTION.DB_EXC);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -946,8 +946,7 @@ X86.fnDIVw = function(dst, src)
|
|||
X86.fnESC = function(dst, src)
|
||||
{
|
||||
if (this.fpu) {
|
||||
this.fpu.fnFPU(this.bOpcode, this.bModRM, dst, src);
|
||||
this.stopCPU();
|
||||
this.fpu.opFPU(this.bOpcode, this.bModRM, dst, src);
|
||||
}
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 2 : 8);
|
||||
return dst;
|
||||
|
|
@ -3879,6 +3878,23 @@ X86.fnSRCxx = function()
|
|||
return this.regXX;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnInterrupt(nIDT, nCycles)
|
||||
*
|
||||
* Helper to dispatch external interrupts. nCycles defaults to 11 for the 8086/8088
|
||||
* if no alternate value is specified.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} nIDT
|
||||
* @param {number} [nCycles] (number of cycles in addition to the default of nOpCyclesInt)
|
||||
*/
|
||||
X86.fnInterrupt = function(nIDT, nCycles)
|
||||
{
|
||||
this.nFault = nIDT;
|
||||
if (nCycles === undefined) nCycles = 11;
|
||||
X86.fnINT.call(this, nIDT, null, nCycles);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnTrap(nIDT, nCycles)
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in a new issue