Preliminary groundwork for FPU support
This commit is contained in:
parent
00116ced94
commit
0c6db1df46
18 changed files with 756 additions and 173 deletions
|
|
@ -190,7 +190,7 @@ B2 was not an actual 80386 stepping; it is a *pseudo-stepping* that provides a s
|
|||
passes all 32-bit multiplication tests.
|
||||
|
||||
As previously discussed, Windows 95 SETUP will refuse to install on any "A" or "B" stepping, but if it's already been
|
||||
installed, it *will* start up.
|
||||
installed, it *will* start up on a B1 stepping.
|
||||
|
||||
PCjs stepping support is extremely limited at this point. Here's a summary:
|
||||
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@
|
|||
<machine id="ibm5160" class="pc" border="1" width="980px" pos="center" background="#FAEBD7">
|
||||
<name pos="center">IBM PC XT (Model 5160), CGA, 640K, 10Mb Drive</name>
|
||||
<computer id="xt-cga-640k" name="IBM PC XT"/>
|
||||
<cpu id="cpu8088" model="8088" autostart="true"/>
|
||||
<fpu id="fpu8087" model="8087"/>
|
||||
<ram id="ramLow" addr="0x00000" test="false" size="0xa0000" comment="0xa0000 (640Kb) size overrides SW1|ROM BIOS memory test has been disabled"/>
|
||||
<rom id="romHDC" addr="0xc8000" size="0x2000" file="/devices/pc/hdc/ibm-xebec-1982.json"/>
|
||||
<rom id="romBASIC" addr="0xf6000" size="0x8000" file="/devices/pc/basic/ibm-basic-1.10.json"/>
|
||||
<rom id="romBIOS" addr="0xfe000" size="0x2000" file="/devices/pc/bios/5160/1982-11-08.json"/>
|
||||
<video ref="/devices/pc/video/ibm/cga/ibm-cga-960-keygrid.xml"/>
|
||||
<cpu id="cpu8088" model="8088" autostart="true"/>
|
||||
<keyboard ref="/devices/pc/keyboard/keyboard-minimal.xml"/>
|
||||
<debugger id="debugger"/>
|
||||
<panel ref="/devices/pc/panel/wide.xml"/>
|
||||
<fdc ref="/disks/pc/library.xml" width="320px"/>
|
||||
<fdc ref="/disks/pc/private/disks.xml" width="320px"/>
|
||||
<chipset id="chipset" model="5160" sw1="01001001" pos="left" padleft="8px" padbottom="8px">
|
||||
<control type="switches" label="SW1" binding="sw1" left="0px"/>
|
||||
<control type="description" binding="swdesc" left="0px"/>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<fdc ref="/disks/pc/library.xml" automount=''/>
|
||||
<debugger id="debugger" messages="" commands=''/>
|
||||
<panel ref="/devices/pc/panel/wide386.xml"/>
|
||||
<hdc id="hdcAT" type="at" drives='[{name:"68Mb Hard Disk",type:4,path:"http://static.pcjs.org/devices/pc/machine/compaq/deskpro386/vga/4096kb/WIN95-68Mb.json.gz"}]'/>
|
||||
<hdc id="hdcAT" type="at" drives='[{name:"68Mb Hard Disk",type:4,path:"http://static.pcjs.org/devices/pc/machine/compaq/deskpro386/vga/4096kb/WIN95-68Mb.json"}]'/>
|
||||
<chipset id="chipset" model="deskpro386" floppies="[1200,1200]" monitor="vga"/>
|
||||
<serial id="com1" adapter="1"/>
|
||||
<serial id="com2" adapter="2" binding="print"/>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<control type="list" binding="listDrives"/>
|
||||
<control type="list" binding="listDisks">
|
||||
<disk path="">None</disk>
|
||||
<manifest ref="/disks/pc/diags/ibm/2.20/manifest.xml" disk="*"/>
|
||||
<manifest ref="/disks/pc/dos/ibm/1.00/manifest.xml" disk="*"/>
|
||||
<manifest ref="/disks/pc/dos/ibm/1.10/manifest.xml" disk="*"/>
|
||||
<manifest ref="/disks/pc/dos/ibm/2.00/manifest.xml" disk="*"/>
|
||||
|
|
@ -47,8 +48,8 @@
|
|||
<manifest ref="/disks/pc/apps/microsoft/word/3.1/manifest.xml" disk="*"/>
|
||||
<manifest ref="/disks/pc/apps/microsoft/word/5.0/manifest.xml" disk="*"/>
|
||||
<manifest ref="/disks/pc/apps/microsoft/winword/2.0c/manifest.xml" disk="*"/>
|
||||
<disk path="/disks/pc/games/id/wolf3d/1WOLF14.json">Wolfenstein 3D (v1.4)</disk>
|
||||
<manifest ref="/disks/pc/games/microsoft/flightsim/manifest.xml" disk="*"/>
|
||||
<manifest ref="/disks/pc/tools/borland/pascal/3.00b/manifest.xml" disk="*"/>
|
||||
<manifest ref="/disks/pc/tools/borland/pascal/3.01a/manifest.xml" disk="*"/>
|
||||
<manifest ref="/disks/pc/tools/microsoft/basic/manifest.xml" disk="*"/>
|
||||
<manifest ref="/disks/pc/tools/microsoft/c/4.00/manifest.xml" disk="*"/>
|
||||
<manifest ref="/disks/pc/tools/microsoft/masm/4.00/manifest.xml" disk="*"/>
|
||||
|
|
@ -58,6 +59,8 @@
|
|||
<manifest ref="/disks/pc/tools/microsoft/windows/sdk/1.04/manifest.xml" disk="*"/>
|
||||
<manifest ref="/disks/pc/tools/microsoft/windows/sdk/2.03/manifest.xml" disk="*"/>
|
||||
<manifest ref="/disks/pc/tools/microsoft/windows/sdk/3.00/manifest.xml" disk="*"/>
|
||||
<manifest ref="/disks/pc/games/microsoft/flightsim/manifest.xml" disk="*"/>
|
||||
<disk path="/disks/pc/games/id/wolf3d/1WOLF14.json">Wolfenstein 3D (v1.4)</disk>
|
||||
<manifest ref="/apps/pc/1981/visicalc/manifest.xml" disk="disk01"/>
|
||||
<manifest ref="/apps/pc/1982/esuite/manifest.xml" disk="disk01"/>
|
||||
<manifest ref="/apps/pc/1985/rogue/manifest.xml" disk="disk01"/>
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
Turbo Pascal 3.0
|
||||
---
|
||||
|
||||
[Manifest](manifest.xml) updated using:
|
||||
|
||||
diskdump --disk=private/TURBO30.img --format=json --output=TURBO30.json --manifest
|
||||
|
||||
The original diskettes are not part of the repository/website.
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml-stylesheet type="text/xsl" href="/versions/pcjs/1.20.1/manifest.xsl"?>
|
||||
<manifest type="software">
|
||||
<title>Turbo Pascal</title>
|
||||
<disk id="disk01" size="368640" chs="40:2:9" img="static/TURBO30.img" href="/disks/pc/tools/borland/pascal/3.0/TURBO30.json" md5="b1243614e885cb2a16047cff1adcb00b" md5json="672b78ada3c22756676b71fdf83c23af">
|
||||
<name>Turbo Pascal 3.0</name>
|
||||
</disk>
|
||||
</manifest>
|
||||
|
|
@ -30,18 +30,19 @@ At the time of this writing, the recommended order is:
|
|||
* [shared/weblib.js](../../shared/lib/weblib.js)
|
||||
* [shared/component.js](../../shared/lib/component.js)
|
||||
* [pcjs/defines.js](defines.js)
|
||||
* [pcjs/x86.js](x86.js)
|
||||
* [pcjs/interrupts.js](interrupts.js)
|
||||
* [pcjs/messages.js](messages.js)
|
||||
* [pcjs/panel.js](panel.js)
|
||||
* [pcjs/bus.js](bus.js)
|
||||
* [pcjs/memory.js](memory.js)
|
||||
* [pcjs/cpu.js](cpu.js)
|
||||
* [pcjs/x86.js](x86.js)
|
||||
* [pcjs/x86seg.js](x86seg.js)
|
||||
* [pcjs/x86cpu.js](x86cpu.js)
|
||||
* [pcjs/x86cpu.js](x86fpu.js)
|
||||
* [pcjs/x86func.js](x86func.js)
|
||||
* [pcjs/x86ops.js](x86ops.js)
|
||||
* [pcjs/x86op0f.js](x86op0f.js)
|
||||
* [pcjs/x86func.js](x86func.js)
|
||||
* [pcjs/x86modb.js](x86modb.js)
|
||||
* [pcjs/x86modw.js](x86modw.js)
|
||||
* [pcjs/x86modb16.js](x86modb16.js)
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ function ChipSet(parmsChipSet)
|
|||
* a separate question. FYI, with only 16Kb, the ROM BIOS will still try to boot, and fail miserably.
|
||||
*/
|
||||
this.sw1Init = 0;
|
||||
var sw1 = parmsChipSet['sw1'];
|
||||
var sw1 = parmsChipSet[ChipSet.CONTROLS.SW1];
|
||||
if (sw1) {
|
||||
this.sw1Init = this.parseSwitches(sw1, ChipSet.PPI_SW.MEMORY.X4 | ChipSet.PPI_SW.MONITOR.MONO);
|
||||
} else {
|
||||
|
|
@ -201,7 +201,9 @@ function ChipSet(parmsChipSet)
|
|||
* NOTE: If you use the "size" parameter, you will not be able to dynamically alter the memory configuration;
|
||||
* the RAM component will ignore any changes to SW1.
|
||||
*/
|
||||
this.sw2Init = this.parseSwitches(parmsChipSet['sw2'] || "11110000", 0);
|
||||
this.sw2Init = this.parseSwitches(parmsChipSet[ChipSet.CONTROLS.SW2] || "11110000", 0);
|
||||
|
||||
this.sCellClass = PCJSCLASS + "-bitCell";
|
||||
|
||||
/*
|
||||
* The SW1 memory setting is actually just a multiplier: it's multiplied by 16Kb on a MODEL_5150, 64Kb otherwise.
|
||||
|
|
@ -288,6 +290,12 @@ ChipSet.MODELS = {
|
|||
"deskpro386": ChipSet.MODEL_DESKPRO386
|
||||
};
|
||||
|
||||
ChipSet.CONTROLS = {
|
||||
SW1: "sw1",
|
||||
SW2: "sw2",
|
||||
SWDESC: "swdesc"
|
||||
};
|
||||
|
||||
/*
|
||||
* Values returned by ChipSet.getSWVideoMonitor()
|
||||
*/
|
||||
|
|
@ -983,6 +991,8 @@ ChipSet.COPROC = { // TODO: Define a variable for this
|
|||
};
|
||||
|
||||
/**
|
||||
* setBinding(sHTMLType, sBinding, control)
|
||||
*
|
||||
* @this {ChipSet}
|
||||
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
|
||||
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "sw1")
|
||||
|
|
@ -992,31 +1002,43 @@ ChipSet.COPROC = { // TODO: Define a variable for this
|
|||
ChipSet.prototype.setBinding = function(sHTMLType, sBinding, control)
|
||||
{
|
||||
switch (sBinding) {
|
||||
case "sw1":
|
||||
case ChipSet.CONTROLS.SW1:
|
||||
this.bindings[sBinding] = control;
|
||||
this.addSwitches(sBinding, 8, this.sw1Init, {
|
||||
0: (this.model == ChipSet.MODEL_5150? "Bootable Floppy Drive" : "Loop on POST"),
|
||||
/*
|
||||
* NOTE: Both the Aug 1981 and the Apr 1984 IBM 5150 Technical Reference Manuals list SW1-2 as "RESERVED", but
|
||||
* contemporary articles discussing 8087 support in early PCs all indicate that switch SW1-2 must be set to the
|
||||
* OFF position if a coprocessor is installed.
|
||||
*
|
||||
* The 1981 5150 TechRef doesn't mention 8087 support at all, whereas the 1984 5150 TechRef discusses it in
|
||||
* a fair bit of detail, including the fact that 8087 exceptions generate an NMI (despite Intel's warning in their
|
||||
* "iAPX 86,88 User's Manual", on page S-27, that "[t]he 8087 should not be tied to the CPU's NMI (non-maskable
|
||||
* interrupt) line.")
|
||||
*
|
||||
* In light of this, we have effectively disabled the "Reserved" option below, since model will never be < 5150.
|
||||
*/
|
||||
1: (this.model < ChipSet.MODEL_5150? "Reserved" : "Coprocessor"),
|
||||
2: "Base Memory Size", // up to 64Kb on a MODEL_5150, 256Kb on a MODEL_5160
|
||||
4: "Monitor Type",
|
||||
6: "Number of Floppy Drives"
|
||||
});
|
||||
return true;
|
||||
case ChipSet.CONTROLS.SW2:
|
||||
if (this.model == ChipSet.MODEL_5150) {
|
||||
this.bindings[sBinding] = control;
|
||||
this.addSwitches(sBinding, control, 8, this.sw1Init, {
|
||||
0: (this.model == ChipSet.MODEL_5150? "Bootable Floppy Drive" : "Loop on POST"),
|
||||
1: (this.model == ChipSet.MODEL_5150? "Reserved" : "Coprocessor"),
|
||||
2: "Base Memory Size", // up to 64Kb on a MODEL_5150, 256Kb on a MODEL_5160
|
||||
4: "Monitor Type",
|
||||
6: "Number of Floppy Drives"
|
||||
this.addSwitches(sBinding, 8, this.sw2Init, {
|
||||
0: "Expansion Memory Size", // up to 480Kb, which, when combined with 64Kb of MODEL_5150 base memory, gives a maximum of 544Kb
|
||||
4: "Reserved"
|
||||
});
|
||||
return true;
|
||||
case "sw2":
|
||||
if (this.model == ChipSet.MODEL_5150) {
|
||||
this.bindings[sBinding] = control;
|
||||
this.addSwitches(sBinding, control, 8, this.sw2Init, {
|
||||
0: "Expansion Memory Size", // up to 480Kb, which, when combined with 64Kb of MODEL_5150 base memory, gives a maximum of 544Kb
|
||||
4: "Reserved"
|
||||
});
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case "swdesc":
|
||||
this.bindings[sBinding] = control;
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ChipSet.CONTROLS.SWDESC:
|
||||
this.bindings[sBinding] = control;
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
|
@ -1069,6 +1091,9 @@ 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;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1119,7 +1144,9 @@ ChipSet.prototype.reset = function(fHard)
|
|||
var i;
|
||||
this.sw1 = this.sw1Init;
|
||||
this.sw2 = this.sw2Init;
|
||||
this.updateSwitchDesc();
|
||||
this.updateSwitches(ChipSet.CONTROLS.SW1, this.sw1);
|
||||
this.updateSwitches(ChipSet.CONTROLS.SW2, this.sw2);
|
||||
this.updateSwitchDescriptions();
|
||||
|
||||
/*
|
||||
* DMA (Direct Memory Access) Controller initialization
|
||||
|
|
@ -2196,45 +2223,91 @@ ChipSet.prototype.getSWVideoMonitor = function(fInit)
|
|||
};
|
||||
|
||||
/**
|
||||
* addSwitches(s, control, n, v, oTips)
|
||||
* addSwitches(sBinding, n, v, oTips)
|
||||
*
|
||||
* @this {ChipSet}
|
||||
* @param {string} s is the name of the control
|
||||
* @param {Object} control is the HTML control DOM object
|
||||
* @param {string} sBinding is the name of the control
|
||||
* @param {number} n is the number of switches to add
|
||||
* @param {number} v contains the current value(s) of the switches
|
||||
* @param {Object} oTips contains tooltips for the various cells
|
||||
*/
|
||||
ChipSet.prototype.addSwitches = function(s, control, n, v, oTips)
|
||||
ChipSet.prototype.addSwitches = function(sBinding, n, v, oTips)
|
||||
{
|
||||
var sHTML = "";
|
||||
var sCellClass = PCJSCLASS + "-bitCell";
|
||||
var control = this.bindings[sBinding];
|
||||
for (var i = 1; i <= n; i++) {
|
||||
var sCellClasses = sCellClass;
|
||||
if (!i) sCellClasses += " " + PCJSCLASS + "-bitCellLeft";
|
||||
var sCellID = s + "-" + i;
|
||||
var sCellClasses = this.sCellClass;
|
||||
if (!i) sCellClasses += " " + this.sCellClass + "Left";
|
||||
var sCellID = sBinding + "-" + i;
|
||||
sHTML += "<div id=\"" + sCellID + "\" class=\"" + sCellClasses + "\" data-value=\"0\">" + i + "</div>\n";
|
||||
}
|
||||
control.innerHTML = sHTML;
|
||||
var aeCells = Component.getElementsByClass(control, sCellClass);
|
||||
var sTip = null;
|
||||
for (i = 0; i < aeCells.length; i++) {
|
||||
if (oTips != null && oTips[i] != null) {
|
||||
sTip = oTips[i];
|
||||
this.updateSwitches(sBinding, v, oTips);
|
||||
};
|
||||
|
||||
/**
|
||||
* updateSwitches(sBinding, v, oTips)
|
||||
*
|
||||
* @this {ChipSet}
|
||||
* @param {string} sBinding is the name of the control
|
||||
* @param {number} v contains the current value(s) of the switches
|
||||
* @param {Object} [oTips] contains tooltips for the various cells
|
||||
*/
|
||||
ChipSet.prototype.updateSwitches = function(sBinding, v, oTips)
|
||||
{
|
||||
var control = this.bindings[sBinding];
|
||||
if (control) {
|
||||
var aeCells = Component.getElementsByClass(control, this.sCellClass);
|
||||
for (var i = 0; i < aeCells.length; i++) {
|
||||
var sTip = null;
|
||||
if (oTips != null && oTips[i] != null) {
|
||||
sTip = oTips[i];
|
||||
}
|
||||
if (sTip) aeCells[i].setAttribute("title", sTip);
|
||||
this.setSwitch(aeCells[i], (v & (0x1 << i))? false : true);
|
||||
aeCells[i].onclick = function(chipset, eSwitch) {
|
||||
/*
|
||||
* If we defined the onclick handler below as "function(e)" instead of simply "function()", then we could
|
||||
* also receive an event object (e); however, IE reportedly requires that we examine a global (window.event)
|
||||
* instead. If that's true, and if we ever care to get more details about the click event, then we might
|
||||
* have to worry about that (eg, define a local var: "var event = window.event || e").
|
||||
*/
|
||||
return function onClickSwitch() {
|
||||
chipset.toggleSwitch(eSwitch);
|
||||
};
|
||||
}(this, aeCells[i]);
|
||||
}
|
||||
if (sTip) aeCells[i].setAttribute("title", sTip);
|
||||
this.setSwitch(aeCells[i], (v & (0x1 << i))? false : true);
|
||||
aeCells[i].onclick = function(chipset, eSwitch) {
|
||||
/*
|
||||
* If we defined the onclick handler below as "function(e)" instead of simply "function()", then we could
|
||||
* also receive an event object (e); however, IE reportedly requires that we examine a global (window.event)
|
||||
* instead. If that's true, and if we ever care to get more details about the click event, then we might
|
||||
* have to worry about that (eg, define a local var: "var event = window.event || e").
|
||||
*/
|
||||
return function onClickSwitch() {
|
||||
chipset.toggleSwitch(eSwitch);
|
||||
};
|
||||
}(this, aeCells[i]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* updateSwitchDescriptions()
|
||||
*
|
||||
* @this {ChipSet}
|
||||
*/
|
||||
ChipSet.prototype.updateSwitchDescriptions = function()
|
||||
{
|
||||
var controlDesc = this.bindings[ChipSet.CONTROLS.SWDESC];
|
||||
if (controlDesc != null) {
|
||||
var sText = "";
|
||||
/*
|
||||
* TODO: Monitor type 0 used to be "None" (ie, "No Monitor"), which was correct in a pre-EGA world,
|
||||
* but in the post-EGA world, it depends. We should ask the Video component for a definitive answer.
|
||||
*/
|
||||
var asMonitorTypes = {
|
||||
0: "Enhanced Color",
|
||||
1: "TV",
|
||||
2: "Color",
|
||||
3: "Monochrome"
|
||||
};
|
||||
sText += this.getSWMemorySize(true) + "Kb";
|
||||
sText += ", " + ((this.sw1 & ChipSet.PPI_SW.COPROC)? "" : "No ") + "Coprocessor";
|
||||
sText += ", " + asMonitorTypes[this.getSWVideoMonitor(true)] + " Monitor";
|
||||
sText += ", " + this.getSWFloppyDrives(true) + " Floppy Drives";
|
||||
if (this.sw1 != null && this.sw1 != this.sw1Init || this.sw2 != null && this.sw2 != this.sw2Init) {
|
||||
sText += " (Reset required)";
|
||||
}
|
||||
controlDesc.textContent = sText;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -2278,48 +2351,16 @@ ChipSet.prototype.toggleSwitch = function(control)
|
|||
var asParts = sID.split("-");
|
||||
var b = (0x1 << (+asParts[1] - 1));
|
||||
switch (asParts[0]) {
|
||||
case "sw1":
|
||||
case ChipSet.CONTROLS.SW1:
|
||||
this.sw1Init = (this.sw1Init & ~b) | (f? 0 : b);
|
||||
break;
|
||||
case "sw2":
|
||||
case ChipSet.CONTROLS.SW2:
|
||||
this.sw2Init = (this.sw2Init & ~b) | (f? 0 : b);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this.updateSwitchDesc();
|
||||
};
|
||||
|
||||
/**
|
||||
* updateSwitchDesc()
|
||||
*
|
||||
* @this {ChipSet}
|
||||
*/
|
||||
ChipSet.prototype.updateSwitchDesc = function()
|
||||
{
|
||||
var controlDesc = this.bindings["swdesc"];
|
||||
/*
|
||||
* TODO: Monitor type 0 used to be "No" (as in "No Monitor"), which was correct in the pre-EGA world,
|
||||
* but in the post-EGA world, it depends. We could ask the Video component for a definitive answer, but
|
||||
* but what we print here isn't that critical, because most people won't bother with a Control Panel,
|
||||
* which is really the only beneficiary of this code.
|
||||
*/
|
||||
var asMonitorTypes = {
|
||||
0: "Enhanced Color",
|
||||
1: "TV",
|
||||
2: "Color",
|
||||
3: "Monochrome"
|
||||
};
|
||||
if (controlDesc != null) {
|
||||
var sText = "";
|
||||
sText += this.getSWMemorySize(true) + "Kb";
|
||||
sText += ", " + asMonitorTypes[this.getSWVideoMonitor(true)] + " Monitor";
|
||||
sText += ", " + this.getSWFloppyDrives(true) + " Floppy Drives";
|
||||
if (this.sw1 != null && this.sw1 != this.sw1Init || this.sw2 != null && this.sw2 != this.sw2Init) {
|
||||
sText += " (Reset required)";
|
||||
}
|
||||
controlDesc.textContent = sText;
|
||||
}
|
||||
this.updateSwitchDescriptions();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -5284,7 +5325,7 @@ ChipSet.init = function()
|
|||
var parmsChipSet = Component.getComponentParms(eChipSet);
|
||||
var chipset = new ChipSet(parmsChipSet);
|
||||
Component.bindComponentControls(chipset, eChipSet, PCJSCLASS);
|
||||
chipset.updateSwitchDesc();
|
||||
chipset.updateSwitchDescriptions();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -138,8 +138,7 @@ function CPU(parmsCPU, nCyclesDefault)
|
|||
*/
|
||||
this.aVideo = [];
|
||||
|
||||
var cpu = this;
|
||||
this.onRunTimeout = function onRunTimeout() { cpu.runCPU(); };
|
||||
this.onRunTimeout = this.runCPU.bind(this); // function onRunTimeout() { cpu.runCPU(); };
|
||||
|
||||
this.setReady();
|
||||
}
|
||||
|
|
@ -179,9 +178,10 @@ CPU.STATUS_UPDATES_PER_SECOND = 2;
|
|||
*/
|
||||
CPU.prototype.initBus = function(cmp, bus, cpu, dbg)
|
||||
{
|
||||
this.cmp = cmp;
|
||||
this.bus = bus;
|
||||
this.dbg = dbg;
|
||||
this.cmp = cmp;
|
||||
|
||||
/*
|
||||
* Attach the Video component to the CPU, so that the CPU can periodically update
|
||||
* the video display via updateVideo(), as cycles permit.
|
||||
|
|
@ -189,13 +189,17 @@ CPU.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
for (var video = null; (video = cmp.getMachineComponent("Video", video));) {
|
||||
this.aVideo.push(video);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach the ChipSet component to the CPU, so that it can obtain the IDT vector number of
|
||||
* pending hardware interrupts, in response to ChipSet's updateINTR() notifications.
|
||||
* Attach the ChipSet component to the CPU so that it can obtain the IDT vector number
|
||||
* of pending hardware interrupts in response to the ChipSet's updateINTR() notifications.
|
||||
*
|
||||
* We must also call chipset.updateAllTimers() periodically; stepCPU() takes care of that.
|
||||
*/
|
||||
this.chipset = cmp.getMachineComponent("ChipSet");
|
||||
|
||||
this.fpu = cmp.getMachineComponent("FPU");
|
||||
|
||||
this.setReady();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ if (DEBUGGER) {
|
|||
|
||||
Debugger.COMMANDS = {
|
||||
'?': "help/print",
|
||||
'a [#]': "assemble",
|
||||
'a [#]': "assemble", // TODO: Implement this command someday
|
||||
'b [#]': "breakpoint", // multiple variations (use b? to list them)
|
||||
'c': "clear output",
|
||||
'd [#]': "dump memory", // additional syntax: d [#] [l#], where l# is a number of bytes to dump
|
||||
|
|
@ -320,67 +320,113 @@ if (DEBUGGER) {
|
|||
};
|
||||
|
||||
/*
|
||||
* Instruction ordinals
|
||||
* CPU instruction ordinals
|
||||
*
|
||||
* Note that individual instructions end with ordinal 162 and instruction groups begin with ordinal 163;
|
||||
* the disassembler knows it's dealing with a group whenever the ordinal is not a valid index into INS_NAMES.
|
||||
*/
|
||||
Debugger.INS = {
|
||||
NONE: 0, AAA: 1, AAD: 2, AAM: 3, AAS: 4, ADC: 5, ADD: 6, AND: 7,
|
||||
ARPL: 8, AS: 9, BOUND: 10, BSF: 11, BSR: 12, BT: 13, BTC: 14, BTR: 15,
|
||||
BTS: 16, CALL: 17, CBW: 18, CLC: 19, CLD: 20, CLI: 21, CLTS: 22, CMC: 23,
|
||||
CMP: 24, CMPSB: 25, CMPSW: 26, CS: 27, CWD: 28, DAA: 29, DAS: 30, DEC: 31,
|
||||
DIV: 32, DS: 33, ENTER: 34, ES: 35, ESC: 36, FADD: 37, FBLD: 38, FBSTP: 39,
|
||||
FCOM: 40, FCOMP: 41, FDIV: 42, FDIVR: 43, FIADD: 44, FICOM: 45, FICOMP: 46, FIDIV: 47,
|
||||
FIDIVR: 48, FILD: 49, FIMUL: 50, FIST: 51, FISTP: 52, FISUB: 53, FISUBR: 54, FLD: 55,
|
||||
FLDCW: 56, FLDENV: 57, FMUL: 58, FNSAVE: 59, FNSTCW: 60, FNSTENV:61, FNSTSW: 62, FRSTOR: 63,
|
||||
FS: 64, FST: 65, FSTP: 66, FSUB: 67, FSUBR: 68, GS: 69, HLT: 70, IBTS: 71,
|
||||
IDIV: 72, IMUL: 73, IN: 74, INC: 75, INS: 76, INT: 77, INT3: 78, INTO: 79,
|
||||
IRET: 80, JBE: 81, JC: 82, JCXZ: 83, JG: 84, JGE: 85, JL: 86, JLE: 87,
|
||||
JMP: 88, JA: 89, JNC: 90, JNO: 91, JNP: 92, JNS: 93, JNZ: 94, JO: 95,
|
||||
JP: 96, JS: 97, JZ: 98, LAHF: 99, LAR: 100, LDS: 101, LEA: 102, LEAVE: 103,
|
||||
LES: 104, LFS: 105, LGDT: 106, LGS: 107, LIDT: 108, LLDT: 109, LMSW: 110, LOADALL:111,
|
||||
LOCK: 112, LODSB: 113, LODSW: 114, LOOP: 115, LOOPNZ: 116, LOOPZ: 117, LSL: 118, LSS: 119,
|
||||
LTR: 120, MOV: 121, MOVSB: 122, MOVSW: 123, MOVSX: 124, MOVZX: 125, MUL: 126, NEG: 127,
|
||||
NOP: 128, NOT: 129, OR: 130, OS: 131, OUT: 132, OUTS: 133, POP: 134, POPA: 135,
|
||||
POPF: 136, PUSHF: 137, PUSHA: 138, PUSH: 139, RCL: 140, RCR: 141, REPNZ: 142, REPZ: 143,
|
||||
RET: 144, RETF: 145, ROL: 146, ROR: 147, SAHF: 148, SALC: 149, SAR: 150, SBB: 151,
|
||||
SCASB: 152, SCASW: 153, SETBE: 154, SETC: 155, SETG: 156, SETGE: 157, SETL: 158, SETLE: 159,
|
||||
SETNBE: 160, SETNC: 161, SETNO: 162, SETNP: 163, SETNS: 164, SETNZ: 165, SETO: 166, SETP: 167,
|
||||
SETS: 168, SETZ: 169, SGDT: 170, SHL: 171, SHLD: 172, SHR: 173, SHRD: 174, SIDT: 175,
|
||||
SLDT: 176, SMSW: 177, SS: 178, STC: 179, STD: 180, STI: 181, STOSB: 182, STOSW: 183,
|
||||
STR: 184, SUB: 185, TEST: 186, VERR: 187, VERW: 188, WAIT: 189, XBTS: 190, XCHG: 191,
|
||||
XLAT: 192, XOR: 193, GRP1B: 194, GRP1W: 195, GRP1SW: 196, GRP2B: 197, GRP2W: 198, GRP2B1: 199,
|
||||
GRP2W1: 200, GRP2BC: 201, GRP2WC: 202, GRP3B: 203, GRP3W: 204, GRP4B: 205, GRP4W: 206, OP0F: 207,
|
||||
GRP6: 208, GRP7: 209, GRP8: 210
|
||||
DIV: 32, DS: 33, ENTER: 34, ES: 35, ESC: 36, FS: 37, GS: 38, HLT: 39,
|
||||
IBTS: 40, IDIV: 41, IMUL: 42, IN: 43, INC: 44, INS: 45, INT: 46, INT3: 47,
|
||||
INTO: 48, IRET: 49, JBE: 50, JC: 51, JCXZ: 52, JG: 53, JGE: 54, JL: 55,
|
||||
JLE: 56, JMP: 57, JA: 58, JNC: 59, JNO: 60, JNP: 61, JNS: 62, JNZ: 63,
|
||||
JO: 64, JP: 65, JS: 66, JZ: 67, LAHF: 68, LAR: 69, LDS: 70, LEA: 71,
|
||||
LEAVE: 72, LES: 73, LFS: 74, LGDT: 75, LGS: 76, LIDT: 77, LLDT: 78, LMSW: 79,
|
||||
LOADALL:80, LOCK: 81, LODSB: 82, LODSW: 83, LOOP: 84, LOOPNZ: 85, LOOPZ: 86, LSL: 87,
|
||||
LSS: 88, LTR: 89, MOV: 90, MOVSB: 91, MOVSW: 92, MOVSX: 93, MOVZX: 94, MUL: 95,
|
||||
NEG: 96, NOP: 97, NOT: 98, OR: 99, OS: 100, OUT: 101, OUTS: 102, POP: 103,
|
||||
POPA: 104, POPF: 105, PUSHF: 106, PUSHA: 107, PUSH: 108, RCL: 109, RCR: 110, REPNZ: 111,
|
||||
REPZ: 112, RET: 113, RETF: 114, ROL: 115, ROR: 116, SAHF: 117, SALC: 118, SAR: 119,
|
||||
SBB: 120, SCASB: 121, SCASW: 122, SETBE: 123, SETC: 124, SETG: 125, SETGE: 126, SETL: 127,
|
||||
SETLE: 128, SETNBE: 129, SETNC: 130, SETNO: 131, SETNP: 132, SETNS: 133, SETNZ: 134, SETO: 135,
|
||||
SETP: 136, SETS: 137, SETZ: 138, SGDT: 139, SHL: 140, SHLD: 141, SHR: 142, SHRD: 143,
|
||||
SIDT: 144, SLDT: 145, SMSW: 146, SS: 147, STC: 148, STD: 149, STI: 150, STOSB: 151,
|
||||
STOSW: 152, STR: 153, SUB: 154, TEST: 155, VERR: 156, VERW: 157, WAIT: 158, XBTS: 159,
|
||||
XCHG: 160, XLAT: 161, XOR: 162, GRP1B: 163, GRP1W: 164, GRP1SW: 165, GRP2B: 166, GRP2W: 167,
|
||||
GRP2B1: 168, GRP2W1: 169, GRP2BC: 170, GRP2WC: 171, GRP3B: 172, GRP3W: 173, GRP4B: 174, GRP4W: 175,
|
||||
OP0F: 176, GRP6: 177, GRP7: 178, GRP8: 179
|
||||
};
|
||||
|
||||
/*
|
||||
* Instruction names (mnemonics), indexed by instruction ordinal (above)
|
||||
* CPU instruction names (mnemonics), indexed by CPU instruction ordinal (above)
|
||||
*/
|
||||
Debugger.INS_NAMES = [
|
||||
"INVALID","AAA", "AAD", "AAM", "AAS", "ADC", "ADD", "AND",
|
||||
"ARPL", "AS:", "BOUND", "BSF", "BSR", "BT", "BTC", "BTR",
|
||||
"BTS", "CALL", "CBW", "CLC", "CLD", "CLI", "CLTS", "CMC",
|
||||
"CMP", "CMPSB", "CMPSW", "CS:", "CWD", "DAA", "DAS", "DEC",
|
||||
"DIV", "DS:", "ENTER", "ES:", "ESC", "FADD", "FBLD", "FBSTP",
|
||||
"FCOM", "FCOMP", "FDIV", "FDIVR", "FIADD", "FICOM", "FICOMP", "FIDIV",
|
||||
"FIDIVR", "FILD", "FIMUL", "FIST", "FISTP", "FISUB", "FISUBR", "FLD",
|
||||
"FLDCW", "FLDENV", "FMUL", "FNSAVE", "FNSTCW", "FNSTENV","FNSTSW", "FRSTOR",
|
||||
"FS:", "FST", "FSTP", "FSUB", "FSUBR", "GS:", "HLT", "IBTS",
|
||||
"IDIV", "IMUL", "IN", "INC", "INS", "INT", "INT3", "INTO",
|
||||
"IRET", "JBE", "JC", "JCXZ", "JG", "JGE", "JL", "JLE",
|
||||
"JMP", "JA", "JNC", "JNO", "JNP", "JNS", "JNZ", "JO",
|
||||
"JP", "JS", "JZ", "LAHF", "LAR", "LDS", "LEA", "LEAVE",
|
||||
"LES", "LFS", "LGDT", "LGS", "LIDT", "LLDT", "LMSW", "LOADALL",
|
||||
"LOCK", "LODSB", "LODSW", "LOOP", "LOOPNZ", "LOOPZ", "LSL", "LSS",
|
||||
"LTR", "MOV", "MOVSB", "MOVSW", "MOVSX", "MOVZX", "MUL", "NEG",
|
||||
"NOP", "NOT", "OR", "OS:", "OUT", "OUTS", "POP", "POPA",
|
||||
"POPF", "PUSHF", "PUSHA", "PUSH", "RCL", "RCR", "REPNZ", "REPZ",
|
||||
"RET", "RETF", "ROL", "ROR", "SAHF", "SALC", "SAR", "SBB",
|
||||
"SCASB", "SCASW", "SETBE", "SETC", "SETG", "SETGE", "SETL", "SETLE",
|
||||
"SETNBE", "SETNC", "SETNO", "SETNP", "SETNS", "SETNZ", "SETO", "SETP",
|
||||
"SETS", "SETZ", "SGDT", "SHL", "SHLD", "SHR", "SHRD", "SIDT",
|
||||
"SLDT", "SMSW", "SS:", "STC", "STD", "STI", "STOSB", "STOSW",
|
||||
"STR", "SUB", "TEST", "VERR", "VERW", "WAIT", "XBTS", "XCHG",
|
||||
"XLAT", "XOR"
|
||||
"DIV", "DS:", "ENTER", "ES:", "ESC", "FS:", "GS:", "HLT",
|
||||
"IBTS", "IDIV", "IMUL", "IN", "INC", "INS", "INT", "INT3",
|
||||
"INTO", "IRET", "JBE", "JC", "JCXZ", "JG", "JGE", "JL",
|
||||
"JLE", "JMP", "JA", "JNC", "JNO", "JNP", "JNS", "JNZ",
|
||||
"JO", "JP", "JS", "JZ", "LAHF", "LAR", "LDS", "LEA",
|
||||
"LEAVE", "LES", "LFS", "LGDT", "LGS", "LIDT", "LLDT", "LMSW",
|
||||
"LOADALL","LOCK", "LODSB", "LODSW", "LOOP", "LOOPNZ", "LOOPZ", "LSL",
|
||||
"LSS", "LTR", "MOV", "MOVSB", "MOVSW", "MOVSX", "MOVZX", "MUL",
|
||||
"NEG", "NOP", "NOT", "OR", "OS:", "OUT", "OUTS", "POP",
|
||||
"POPA", "POPF", "PUSHF", "PUSHA", "PUSH", "RCL", "RCR", "REPNZ",
|
||||
"REPZ", "RET", "RETF", "ROL", "ROR", "SAHF", "SALC", "SAR",
|
||||
"SBB", "SCASB", "SCASW", "SETBE", "SETC", "SETG", "SETGE", "SETL",
|
||||
"SETLE", "SETNBE", "SETNC", "SETNO", "SETNP", "SETNS", "SETNZ", "SETO",
|
||||
"SETP", "SETS", "SETZ", "SGDT", "SHL", "SHLD", "SHR", "SHRD",
|
||||
"SIDT", "SLDT", "SMSW", "SS:", "STC", "STD", "STI", "STOSB",
|
||||
"STOSW", "STR", "SUB", "TEST", "VERR", "VERW", "WAIT", "XBTS",
|
||||
"XCHG", "XLAT", "XOR"
|
||||
];
|
||||
|
||||
/*
|
||||
* FPU instruction ordinals
|
||||
*
|
||||
* Unlike CPU instruction ordinals, these are not organized alphabetically (which I did only for the
|
||||
* sake of tidiness), but rather by functionality; ie:
|
||||
*
|
||||
* 0-3: real transfers
|
||||
* 4-6: integer transfers
|
||||
* 7-8: packed decimal transfers
|
||||
* 9-11: addition
|
||||
* 12-17: subtraction
|
||||
* 18-20: multiplication
|
||||
* 21-26: division
|
||||
* 27-33: other
|
||||
* 34-40: comparisons
|
||||
* 41-45: transcendental
|
||||
* 46-52: constants
|
||||
* 53-76: coprocessor control
|
||||
*
|
||||
* Also, unlike the CPU instructions, there is no NONE ("INVALID") instruction; if an ESC instruction
|
||||
* can't be decoded as a valid FPU instruction, then it should remain an ESC instruction.
|
||||
*/
|
||||
Debugger.FINS = {
|
||||
FLD: 0, FST: 1, FSTP: 2, FXCH: 3, FILD: 4, FIST: 5, FISTP: 6, FBLD: 7,
|
||||
FBSTP: 8, FADD: 9, FADDP: 10, FIADD: 11, FSUB: 12, FSUBP: 13, FISUB: 14, FSUBR: 15,
|
||||
FSUBRP: 16, FISUBR: 17, FMUL: 18, FMULP: 19, FIMUL: 20, FDIV: 21, FDIVP: 22, FIDIV: 23,
|
||||
FDIVR: 24, FDIVRP: 25, FIDIVR: 26, FSQRT: 27, FSCALE: 28, FPREM: 29, FRNDINT:30, FXTRACT:31,
|
||||
FABS: 32, FCHS: 33, FCOM: 34, FCOMP: 35, FCOMPP: 36, FICOM: 37, FICOMP: 38, FTST: 39,
|
||||
FXAM: 40, FPTAN: 41, FPATAN: 42, F2XM1: 43, FYL2X: 44, FYL2XP1:45, FLDZ: 46, FLD1: 47,
|
||||
FLDPI: 48, FLDL2T: 49, FLDL2E: 50, FLDLG2: 51, FLDLN2: 52, FINIT: 53, FNINIT: 54, FDISI: 55,
|
||||
FNDISI: 56, FENI: 57, FNENI: 58, FLDCW: 59, FSTCW: 60, FNSTCW: 61, FSTSW: 62, FNSTSW: 63,
|
||||
FCLEX: 64, FNCLEX: 65, FSTENV: 66, FNSTENV:67, FLDENV: 68, FSAVE: 69, FNSAVE: 70, FRSTOR: 71,
|
||||
FINCSTP:72, FDECSTP:73, FFREE: 74, FNOP: 75, FWAIT: 76
|
||||
};
|
||||
|
||||
/*
|
||||
* FPU instruction names (mnemonics), indexed by FPU instruction ordinal (above)
|
||||
*/
|
||||
Debugger.FINS_NAMES = [
|
||||
"FLD", "FST", "FSTP", "FXCH", "FILD", "FIST", "FISTP", "FBLD",
|
||||
"FBSTP", "FADD", "FADDP", "FIADD", "FSUB", "FSUBP", "FISUB", "FSUBR",
|
||||
"FSUBRP", "FISUBR", "FMUL", "FMULP", "FIMUL", "FDIV", "FDIVP", "FIDIV",
|
||||
"FDIVR", "FDIVRP", "FIDIVR", "FSQRT", "FSCALE", "FPREM", "FRNDINT","FXTRACT",
|
||||
"FABS", "FCHS", "FCOM", "FCOMP", "FCOMPP", "FICOM", "FICOMP", "FTST",
|
||||
"FXAM", "FPTAN", "FPATAN", "F2XM1", "FYL2X", "FYL2XP1","FLDZ", "FLD1",
|
||||
"FLDPI", "FLDL2T", "FLDL2E", "FLDLG2", "FLDLN2", "FINIT", "FNINIT", "FDISI",
|
||||
"FNDISI", "FENI", "FNENI", "FLDCW", "FSTCW", "FNSTCW", "FSTSW", "FNSTSW",
|
||||
"FCLEX", "FNCLEX", "FSTENV", "FNSTENV","FLDENV", "FSAVE", "FNSAVE", "FRSTOR",
|
||||
"FINCSTP","FDECSTP","FFREE", "FNOP", "FWAIT"
|
||||
];
|
||||
|
||||
Debugger.CPU_8086 = 0;
|
||||
|
|
|
|||
|
|
@ -494,6 +494,14 @@ var X86 = {
|
|||
INTN: 0xCD, // opINTn()
|
||||
INTO: 0xCE, // opINTO()
|
||||
IRET: 0xCF, // opIRET()
|
||||
ESC0: 0xD8, // opESC0()
|
||||
ESC1: 0xD9, // opESC1()
|
||||
ESC2: 0xDA, // opESC2()
|
||||
ESC3: 0xDB, // opESC3()
|
||||
ESC4: 0xDC, // opESC4()
|
||||
ESC5: 0xDD, // opESC5()
|
||||
ESC6: 0xDE, // opESC6()
|
||||
ESC7: 0xDF, // opESC7()
|
||||
LOOPNZ: 0xE0, // opLOOPNZ()
|
||||
LOOPZ: 0xE1, // opLOOPZ()
|
||||
LOOP: 0xE2, // opLOOP()
|
||||
|
|
@ -510,6 +518,80 @@ var X86 = {
|
|||
CALLMASK: 0x38FF, // mask 2-byte GRP4W opcodes with this before comparing to CALLW or CALLFDW
|
||||
UD2: 0x0B0F // UD2 (invalid opcode "guaranteed" to generate UD_FAULT on all post-8086 processors)
|
||||
},
|
||||
/*
|
||||
* Floating Point Unit (FPU), aka Numeric Data Processor (NDP), aka Numeric Processor Extension (NPX) definitions
|
||||
*/
|
||||
FPU: {
|
||||
MODEL_8087: 8087,
|
||||
MODEL_80287: 80287,
|
||||
MODEL_80387: 80387,
|
||||
CONTROL: { // FPU Control Word
|
||||
IM: 0x0001, // bit 0: Invalid Operation Mask
|
||||
DM: 0x0002, // bit 1: Denormalized Operand Mask
|
||||
ZM: 0x0004, // bit 2: Zero Divide Mask
|
||||
OM: 0x0008, // bit 3: Overflow Mask
|
||||
UM: 0x0010, // bit 4: Underflow Mask
|
||||
PM: 0x0020, // bit 5: Precision Mask
|
||||
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)
|
||||
},
|
||||
STATUS: { // FPU Status Word
|
||||
IE: 0x0001, // bit 0: Invalid Operation
|
||||
DE: 0x0002, // bit 1: Denormalized Operand
|
||||
ZE: 0x0004, // bit 2: Zero Divide
|
||||
OE: 0x0008, // bit 3: Overflow
|
||||
UE: 0x0010, // bit 4: Underflow
|
||||
PE: 0x0020, // bit 5: Precision
|
||||
SF: 0x0040, // bit 6: Stack Fault (80387 and later)
|
||||
ES: 0x0080, // bit 7: Exception Summary (Interrupt Request on 8087)
|
||||
C0: 0x0100, // bit 8: Condition Code 0
|
||||
C1: 0x0200, // bit 9: Condition Code 1
|
||||
C2: 0x0400, // bit 10: Condition Code 2
|
||||
ST: 0x3800, // bits 11-13: Stack Top
|
||||
C3: 0x4000, // bit 14: Condition Code 3
|
||||
BUSY: 0x8000 // bit 15: Busy
|
||||
},
|
||||
TAG: {
|
||||
VALID: 0x0,
|
||||
ZERO: 0x1,
|
||||
SPECIAL: 0x2,
|
||||
EMPTY: 0x3
|
||||
}
|
||||
/*
|
||||
C3 C2 C1 C0 Condition Code (CC) values following an Examine
|
||||
|
||||
0 0 0 0 Valid, positive unnormalized (+Unnormal)
|
||||
0 0 0 1 Invalid, positive, exponent=0 (+NaN)
|
||||
0 0 1 0 Valid, negative, unnormalized (-Unnormal)
|
||||
0 0 1 1 Invalid, negative, exponent=0 (-NaN)
|
||||
0 1 0 0 Valid, positive, normalized (+Normal)
|
||||
0 1 0 1 Infinity, positive (+Infinity)
|
||||
0 1 1 0 Valid, negative, normalized (-Normal)
|
||||
0 1 1 1 Infinity, negative (-Infinity)
|
||||
1 0 0 0 Zero, positive (+0)
|
||||
1 0 0 1 Empty
|
||||
1 0 1 0 Zero, negative (-0)
|
||||
1 0 1 1 Empty
|
||||
1 1 0 0 Invalid, positive, exponent=0 (+Denormal)
|
||||
1 1 0 1 Empty
|
||||
1 1 1 0 Invalid, negative, exponent=0 (-Denormal)
|
||||
1 1 1 1 Empty
|
||||
|
||||
Condition Code (CC) values following an FCOM or FTST
|
||||
|
||||
0 0 ? 0 ST > source operand (FCOM); ST > 0 (FTST)
|
||||
0 0 ? 1 ST < source operand (FCOM); ST < 0 (FTST)
|
||||
1 0 ? 0 ST = source operand (FCOM); ST = 0 (FTST)
|
||||
1 1 ? 1 ST is not comparable
|
||||
|
||||
Condition Code (CC) values following a Remainder
|
||||
|
||||
Q1 0 Q0 Q2 Complete reduction (he three low bits of the quotient stored in C0, C3, and C1)
|
||||
? 1 ? ? Incomplete reduction
|
||||
*/
|
||||
},
|
||||
CYCLES_8088: {
|
||||
nWordCyclePenalty: 4, // NOTE: accurate for the 8088/80188 only (on the 8086/80186, it applies to odd addresses only)
|
||||
nEACyclesBase: 5, // base or index only (BX, BP, SI or DI)
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ if (!I386) {
|
|||
*
|
||||
* The X86CPU class uses the following (parmsCPU) properties:
|
||||
*
|
||||
* model: a number (eg, 8088) that should match one of the X86.MODEL values
|
||||
* stepping: a string (eg, "B1") that should match one of the X86.STEPPING values
|
||||
* model: a number (eg, 8088) that should match one of the X86.MODEL values (default is 8088)
|
||||
* stepping: a string (eg, "B1") that should match one of the X86.STEPPING values (default is "")
|
||||
*
|
||||
* This extends the CPU class and passes any remaining parmsCPU properties to the CPU class
|
||||
* constructor, along with a default speed (cycles per second) based on the specified (or default)
|
||||
|
|
@ -1070,6 +1070,12 @@ X86CPU.prototype.resetRegs = function()
|
|||
this.regMDLo = this.regMDHi = 0;
|
||||
this.regXX = 0; // internal register for segment register and control register moves
|
||||
|
||||
/*
|
||||
* This internal "register" is set in selected opcode handlers to record the original opcode; ordinarily,
|
||||
* we dispatch on the opcode but never save it, because it's rarely needed.
|
||||
*/
|
||||
this.bOpcode = 0;
|
||||
|
||||
/*
|
||||
* Another internal "register" we occasionally need is an interim copy of bModRM, set inside selected opcode
|
||||
* handlers so that the helper function can have access to the instruction's bModRM without resorting to a
|
||||
|
|
|
|||
296
modules/pcjs/lib/x86fpu.js
Normal file
296
modules/pcjs/lib/x86fpu.js
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
/**
|
||||
* @fileoverview Implements PCjs 8087 FPU logic.
|
||||
* @author <a href="mailto:Jeff@pcjs.org">Jeff Parsons</a>
|
||||
* @version 1.0
|
||||
* Created 2015-Nov-09
|
||||
*
|
||||
* Copyright © 2012-2015 Jeff Parsons <Jeff@pcjs.org>
|
||||
*
|
||||
* This file is part of PCjs, which is part of the JavaScript Machines Project (aka JSMachines)
|
||||
* at <http://jsmachines.net/> and <http://pcjs.org/>.
|
||||
*
|
||||
* PCjs is free software: you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation, either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCjs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCjs. If not,
|
||||
* see <http://www.gnu.org/licenses/gpl.html>.
|
||||
*
|
||||
* You are required to include the above copyright notice in every source code file of every
|
||||
* copy or modified version of this work, and to display that copyright notice on every screen
|
||||
* that loads or runs any version of this software (see Computer.sCopyright).
|
||||
*
|
||||
* Some PCjs files also attempt to load external resource files, such as character-image files,
|
||||
* ROM files, and disk image files. Those external resource files are not considered part of the
|
||||
* PCjs program for purposes of the GNU General Public License, and the author does not claim
|
||||
* any copyright as to their contents.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
if (NODE) {
|
||||
var str = require("../../shared/lib/strlib");
|
||||
var web = require("../../shared/lib/weblib");
|
||||
var Component = require("../../shared/lib/component");
|
||||
var X86 = require("./x86");
|
||||
}
|
||||
|
||||
/**
|
||||
* X86FPU(parmsFPU)
|
||||
*
|
||||
* The X86FPU class uses the following (parmsFPU) properties:
|
||||
*
|
||||
* model: a number (eg, 8087) that should match one of the X86.FPU.MODEL values (default is 8087)
|
||||
* stepping: a string (eg, "B1") that should match one of the X86.FPU.STEPPING values (default is "")
|
||||
*
|
||||
* @constructor
|
||||
* @extends Component
|
||||
* @param {Object} parmsFPU
|
||||
*/
|
||||
function X86FPU(parmsFPU)
|
||||
{
|
||||
Component.call(this, "FPU", parmsFPU, X86FPU);
|
||||
|
||||
this.model = parmsFPU['model'] || X86.FPU.MODEL_8087;
|
||||
|
||||
/*
|
||||
* We take the 'stepping' value, convert it to a hex value, and then add that to the model to provide
|
||||
* a single value that's unique for any given CPU stepping. If no stepping is provided, then stepping
|
||||
* is equal to model.
|
||||
*/
|
||||
var stepping = parmsFPU['stepping'];
|
||||
this.stepping = this.model + (stepping? str.parseInt(stepping, 16) : 0);
|
||||
|
||||
/*
|
||||
* Initialize the coprocessor to match the requested model.
|
||||
*
|
||||
* NOTE: Technically, the FPU's internal registers are 80-bit, but all JavaScript gives us are 64-bit floats.
|
||||
*/
|
||||
this.aFPUEmpty = new Array(8);
|
||||
this.aFPURegs = new Float64Array(8);
|
||||
|
||||
this.regFPUTmpSR = new Float32Array(1);
|
||||
this.intFPUTmpSR = new Int32Array(this.regFPUTmpSR.buffer);
|
||||
|
||||
this.regFPUTmpLR = new Float64Array(1);
|
||||
this.intFPUTmpLR = new Int32Array(this.regFPUTmpLR.buffer);
|
||||
|
||||
this.regFPUInsAddr = this.regFPUDataAddr = this.regFPUOpcode = 0;
|
||||
|
||||
this.resetFPU();
|
||||
}
|
||||
|
||||
Component.subclass(X86FPU);
|
||||
|
||||
/*
|
||||
* Operand types:
|
||||
*
|
||||
* ST stack top; the register currently at the top of the stack
|
||||
* ST(i) register in the stack i (0<=i<=7) stack elements from the top; ST(1) is the next-on-stack register, ST(2) is below ST(1), etc
|
||||
* SR (short-real) short real (32 bits) number in memory
|
||||
* LR (long-real) long real (64 bits) number in memory
|
||||
* TR (temp-real) temporary real (80 bits) number in memory
|
||||
* PD (packed-decimal) packed decimal integer (18 digits, 10 bytes) in memory
|
||||
* WI (word-integer) word binary integer (16 bits) in memory
|
||||
* SI (short-integer) short binary integer (32 bits) in memory
|
||||
* LI (long-integer) long binary integer (64 bits) in memory
|
||||
* NN (nn-bytes) memory area nn bytes long
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* initBus(cmp, bus, cpu, dbg)
|
||||
*
|
||||
* @this {X86FPU}
|
||||
* @param {Computer} cmp
|
||||
* @param {Bus} bus
|
||||
* @param {X86CPU} cpu
|
||||
* @param {Debugger} dbg
|
||||
*/
|
||||
X86FPU.prototype.initBus = function(cmp, bus, cpu, dbg)
|
||||
{
|
||||
this.cpu = cpu;
|
||||
this.setReady();
|
||||
};
|
||||
|
||||
/**
|
||||
* resetFPU()
|
||||
*
|
||||
* @this {X86FPU}
|
||||
*/
|
||||
X86FPU.prototype.resetFPU = function()
|
||||
{
|
||||
for (var i = 0; i < this.aFPUEmpty.length; i++) this.aFPUEmpty[i] = true;
|
||||
this.regFPUControl = 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;
|
||||
this.regFPUStatus = 0;
|
||||
this.iFPUReg = 0; // copy of the ST bits in regFPUStatus
|
||||
};
|
||||
|
||||
/**
|
||||
* setFPUTmpSRFromEA()
|
||||
*
|
||||
* Sets the internal regFPUTmpSR register to the (32-bit) short-real value located at regEA.
|
||||
*
|
||||
* @this {X86FPU}
|
||||
*/
|
||||
X86FPU.prototype.setFPUTmpSRFromEA = function()
|
||||
{
|
||||
this.intFPUTmpSR[0] = this.cpu.getLong(this.cpu.regEA);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnFPU(bOpcode, bModRM, dst, src)
|
||||
*
|
||||
* @this {X86FPU}
|
||||
* @param {number} bOpcode (0xD8-0xDF)
|
||||
* @param {number} bModRM
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
*/
|
||||
X86FPU.prototype.fnFPU = function(bOpcode, bModRM, dst, src)
|
||||
{
|
||||
this.regFPUOpcode = bOpcode;
|
||||
this.regFPUInsAddr = this.cpu.regLIP;
|
||||
this.regFPUDataAddr = this.cpu.regEA;
|
||||
|
||||
this.println("FPU(" + str.toHexByte(bOpcode) + "," + str.toHexByte(bModRM) + ")");
|
||||
|
||||
var mod = (bModRM >> 6) & 0x3;
|
||||
var reg = (bModRM >> 3) & 0x7;
|
||||
var r_m = (bModRM & 0x7);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
switch(bOpcode) {
|
||||
|
||||
case X86.OPCODE.ESC0:
|
||||
switch(modReg) {
|
||||
case 0x00:
|
||||
this.fnFADDsr(); // ST=ST+[short-real]
|
||||
break;
|
||||
case 0x30:
|
||||
this.fnFADDi(r_m); // ST=ST+ST(i)
|
||||
break;
|
||||
case 0x31:
|
||||
this.fnFMULi(r_m); // ST=ST*ST(i)
|
||||
break;
|
||||
case 0x32:
|
||||
// this.fnFCOMi(r_m);
|
||||
break;
|
||||
case 0x33:
|
||||
// this.fnFCOMPi(r_m);
|
||||
break;
|
||||
case 0x34:
|
||||
// this.fnFSUBi(r_m); // ST=ST-ST(i)
|
||||
break;
|
||||
case 0x35:
|
||||
// this.fnFSUBRi(r_m); // ST=ST-ST(i)
|
||||
break;
|
||||
case 0x36:
|
||||
// this.fnFDIVi(r_m); // ST=ST/ST(i)
|
||||
break;
|
||||
case 0x37:
|
||||
// this.fnFDIVRi(r_m); // ST=ST/ST(i)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case X86.OPCODE.ESC3:
|
||||
switch(modReg) {
|
||||
case 0x34:
|
||||
switch(r_m) {
|
||||
case 0:
|
||||
// this.fnFENI();
|
||||
break;
|
||||
case 1:
|
||||
// this.fnFDISI;
|
||||
break;
|
||||
case 2:
|
||||
// this.fnFCLEX();
|
||||
break;
|
||||
case 3:
|
||||
this.fnFINIT();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* fnFINIT()
|
||||
*
|
||||
* @this {X86FPU}
|
||||
*/
|
||||
X86FPU.prototype.fnFINIT = function()
|
||||
{
|
||||
this.resetFPU();
|
||||
};
|
||||
|
||||
/**
|
||||
* fnFADDi()
|
||||
*
|
||||
* @this {X86FPU}
|
||||
* @param {number} i
|
||||
*/
|
||||
X86FPU.prototype.fnFADDi = function(i)
|
||||
{
|
||||
this.aFPURegs[this.iFPUReg] += this.aFPURegs[i];
|
||||
};
|
||||
|
||||
/**
|
||||
* fnFMULi()
|
||||
*
|
||||
* @this {X86FPU}
|
||||
* @param {number} i
|
||||
*/
|
||||
X86FPU.prototype.fnFMULi = function(i)
|
||||
{
|
||||
this.aFPURegs[this.iFPUReg] *= this.aFPURegs[i];
|
||||
};
|
||||
|
||||
/**
|
||||
* fnFADDsr()
|
||||
*
|
||||
* @this {X86FPU}
|
||||
*/
|
||||
X86FPU.prototype.fnFADDsr = function()
|
||||
{
|
||||
this.setFPUTmpSRFromEA();
|
||||
this.aFPURegs[this.iFPUReg] += this.regFPUTmpSR[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* X86FPU.init()
|
||||
*
|
||||
* This function operates on every HTML element of class "fpu", extracting the
|
||||
* JSON-encoded parameters for the X86FPU constructor from the element's "data-value"
|
||||
* attribute, invoking the constructor to create an X86FPU component, and then binding
|
||||
* any associated HTML controls to the new component.
|
||||
*/
|
||||
X86FPU.init = function()
|
||||
{
|
||||
var aeFPUs = Component.getElementsByClass(window.document, PCJSCLASS, "fpu");
|
||||
for (var iFPU = 0; iFPU < aeFPUs.length; iFPU++) {
|
||||
var eFPU = aeFPUs[iFPU];
|
||||
var parmsFPU = Component.getComponentParms(eFPU);
|
||||
var fpu = new X86FPU(parmsFPU);
|
||||
Component.bindComponentControls(fpu, eFPU, PCJSCLASS);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize every FPU module on the page
|
||||
*/
|
||||
web.onInit(X86FPU.init);
|
||||
|
||||
if (NODE) module.exports = X86FPU;
|
||||
|
|
@ -945,6 +945,11 @@ 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.nStepCycles -= (this.regEA === X86.ADDR_INVALID? 2 : 8);
|
||||
return dst;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3771,14 +3771,95 @@ X86.opXLAT = function()
|
|||
};
|
||||
|
||||
/**
|
||||
* op=0xD8-0xDF (ESC)
|
||||
* opESC()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} bOpcode
|
||||
*/
|
||||
X86.opESC = function(bOpcode)
|
||||
{
|
||||
this.bOpcode = bOpcode;
|
||||
this.aOpModRegWord[this.bModRM = this.getIPByte()].call(this, X86.fnESC);
|
||||
};
|
||||
|
||||
/**
|
||||
* op=0xD8 (ESC0)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opESC = function()
|
||||
X86.opESC0 = function()
|
||||
{
|
||||
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnESC);
|
||||
this.nStepCycles -= 8; // TODO: Fix
|
||||
X86.opESC.call(this, X86.OPCODE.ESC0);
|
||||
};
|
||||
|
||||
/**
|
||||
* op=0xD9 (ESC1)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opESC1 = function()
|
||||
{
|
||||
X86.opESC.call(this, X86.OPCODE.ESC1);
|
||||
};
|
||||
|
||||
/**
|
||||
* op=0xDA (ESC2)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opESC2 = function()
|
||||
{
|
||||
X86.opESC.call(this, X86.OPCODE.ESC2);
|
||||
};
|
||||
|
||||
/**
|
||||
* op=0xDB (ESC3)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opESC3 = function()
|
||||
{
|
||||
X86.opESC.call(this, X86.OPCODE.ESC3);
|
||||
};
|
||||
|
||||
/**
|
||||
* op=0xDC (ESC4)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opESC4 = function()
|
||||
{
|
||||
X86.opESC.call(this, X86.OPCODE.ESC4);
|
||||
};
|
||||
|
||||
/**
|
||||
* op=0xDD (ESC5)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opESC5 = function()
|
||||
{
|
||||
X86.opESC.call(this, X86.OPCODE.ESC5);
|
||||
};
|
||||
|
||||
/**
|
||||
* op=0xDE (ESC6)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opESC6 = function()
|
||||
{
|
||||
X86.opESC.call(this, X86.OPCODE.ESC6);
|
||||
};
|
||||
|
||||
/**
|
||||
* op=0xDF (ESC7)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opESC7 = function()
|
||||
{
|
||||
X86.opESC.call(this, X86.OPCODE.ESC7);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -4421,8 +4502,8 @@ X86.aOps = [
|
|||
* Even as of the Pentium, opcode 0xD6 is still marked as "reserved", but it's always been SALC (aka SETALC).
|
||||
*/
|
||||
X86.opAAM, X86.opAAD, X86.opSALC, X86.opXLAT, // 0xD4-0xD7
|
||||
X86.opESC, X86.opESC, X86.opESC, X86.opESC, // 0xD8-0xDB
|
||||
X86.opESC, X86.opESC, X86.opESC, X86.opESC, // 0xDC-0xDF
|
||||
X86.opESC0, X86.opESC1, X86.opESC2, X86.opESC3, // 0xD8-0xDB
|
||||
X86.opESC4, X86.opESC5, X86.opESC6, X86.opESC7, // 0xDC-0xDF
|
||||
X86.opLOOPNZ, X86.opLOOPZ, X86.opLOOP, X86.opJCXZ, // 0xE0-0xE3
|
||||
X86.opINb, X86.opINw, X86.opOUTb, X86.opOUTw, // 0xE4-0xE7
|
||||
X86.opCALL, X86.opJMP, X86.opJMPF, X86.opJMPs, // 0xE8-0xEB
|
||||
|
|
|
|||
|
|
@ -528,6 +528,12 @@
|
|||
<xsl:otherwise></xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="fpu">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@fpu"><xsl:value-of select="@fpu"/></xsl:when>
|
||||
<xsl:otherwise>0</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="cycles">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@cycles"><xsl:value-of select="@cycles"/></xsl:when>
|
||||
|
|
@ -567,7 +573,34 @@
|
|||
<xsl:call-template name="component">
|
||||
<xsl:with-param name="machine" select="$machine"/>
|
||||
<xsl:with-param name="class" select="'cpu'"/>
|
||||
<xsl:with-param name="parms">,model:<xsl:value-of select="$model"/>,stepping:'<xsl:value-of select="$stepping"/>',cycles:<xsl:value-of select="$cycles"/>,multiplier:<xsl:value-of select="$multiplier"/>,autoStart:<xsl:value-of select="$autoStart"/>,csStart:<xsl:value-of select="$csStart"/>,csInterval:<xsl:value-of select="$csInterval"/>,csStop:<xsl:value-of select="$csStop"/></xsl:with-param>
|
||||
<xsl:with-param name="parms">,model:<xsl:value-of select="$model"/>,stepping:'<xsl:value-of select="$stepping"/>',fpu:<xsl:value-of select="$fpu"/>,cycles:<xsl:value-of select="$cycles"/>,multiplier:<xsl:value-of select="$multiplier"/>,autoStart:<xsl:value-of select="$autoStart"/>,csStart:<xsl:value-of select="$csStart"/>,csInterval:<xsl:value-of select="$csInterval"/>,csStop:<xsl:value-of select="$csStop"/></xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="fpu[@ref]">
|
||||
<xsl:param name="machine" select="''"/>
|
||||
<xsl:variable name="componentFile"><xsl:value-of select="$rootDir"/><xsl:value-of select="@ref"/></xsl:variable>
|
||||
<xsl:apply-templates select="document($componentFile)/fpu"><xsl:with-param name="machine" select="$machine"/></xsl:apply-templates>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="fpu[not(@ref)]">
|
||||
<xsl:param name="machine" select="''"/>
|
||||
<xsl:variable name="model">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@model"><xsl:value-of select="@model"/></xsl:when>
|
||||
<xsl:otherwise>8087</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="stepping">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@stepping"><xsl:value-of select="@stepping"/></xsl:when>
|
||||
<xsl:otherwise></xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:call-template name="component">
|
||||
<xsl:with-param name="machine" select="$machine"/>
|
||||
<xsl:with-param name="class" select="'fpu'"/>
|
||||
<xsl:with-param name="parms">,model:<xsl:value-of select="$model"/>,stepping:'<xsl:value-of select="$stepping"/>'</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@
|
|||
"./modules/pcjs/lib/cpu.js",
|
||||
"./modules/pcjs/lib/x86seg.js",
|
||||
"./modules/pcjs/lib/x86cpu.js",
|
||||
"./modules/pcjs/lib/x86fpu.js",
|
||||
"./modules/pcjs/lib/x86func.js",
|
||||
"./modules/pcjs/lib/x86ops.js",
|
||||
"./modules/pcjs/lib/x86op0f.js",
|
||||
|
|
|
|||
Loading…
Reference in a new issue