New skeleton for x86fpu.js

This commit is contained in:
Jeff Parsons 2015-11-13 18:20:20 -08:00
commit 2b1b62d565
7 changed files with 1440 additions and 167 deletions

View file

@ -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();
};
/**

View file

@ -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();
};

View file

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

View file

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

View file

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

View file

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