Fix the IBM 2.20 Diagnostics System Board test
This commit is contained in:
parent
cd0ed8c62a
commit
99880e01da
5 changed files with 171 additions and 107 deletions
|
|
@ -70,7 +70,7 @@ In the above example, a pre-generated disk image could be created from the comma
|
||||||
|
|
||||||
or with the "--path" option, which specifies either a single file or a set files separated by semi-colons:
|
or with the "--path" option, which specifies either a single file or a set files separated by semi-colons:
|
||||||
|
|
||||||
node diskdump "--path=./apps/pc/1981/visicalc/bin/vc.com;../readme.md" --format=json --output=./apps/pc/1981/visicalc/disk.json
|
node diskdump --path="./apps/pc/1981/visicalc/bin/vc.com;../readme.md" --format=json --output=./apps/pc/1981/visicalc/disk.json
|
||||||
|
|
||||||
or via the PCjs server's DiskDump API:
|
or via the PCjs server's DiskDump API:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<?xml-stylesheet type="text/xsl" href="/versions/pcjs/1.16.0/machine.xsl"?>
|
<?xml-stylesheet type="text/xsl" href="/versions/pcjs/1.16.0/machine.xsl"?>
|
||||||
<machine id="ibm5150" class="pc" border="1" width="740px" pos="center" style="background-color:#FAEBD7">
|
<machine id="ibm5150" class="pc" border="1" pos="center" style="background-color:#FAEBD7">
|
||||||
<name pos="center">IBM PC (Model 5150) running IBM Advanced Diagnostics 2.20</name>
|
<name pos="center">IBM PC (Model 5150) running IBM Advanced Diagnostics 2.20</name>
|
||||||
<computer id="pc-mda-64k" name="IBM PC"/>
|
<computer id="pc-mda-64k" name="IBM PC"/>
|
||||||
<ram id="ramLow" addr="0x00000"/>
|
<ram id="ramLow" addr="0x00000"/>
|
||||||
|
|
@ -16,7 +16,9 @@
|
||||||
<control type="button" class="input" binding="reset">Reset</control>
|
<control type="button" class="input" binding="reset">Reset</control>
|
||||||
</cpu>
|
</cpu>
|
||||||
<keyboard ref="/devices/pc/keyboard/minimal.xml"/>
|
<keyboard ref="/devices/pc/keyboard/minimal.xml"/>
|
||||||
<fdc id="fdcNEC" automount='{A: {name: "IBM Advanced Diagnostics", path: "/disks/pc/diags/ibm/2.20/5150_5155_5160_ADVDIAG_220.json"}}' pos="right">
|
<debugger id="debugger"/>
|
||||||
|
<panel ref="/devices/pc/panel/wide.xml"/>
|
||||||
|
<fdc id="fdcNEC" pos="left" padleft="8px" automount='{A: {name: "IBM Advanced Diagnostics", path: "/disks/pc/diags/ibm/2.20/5150_5155_5160_ADVDIAG_220.json"}}'>
|
||||||
<control type="list" class="input" binding="listDrives"/>
|
<control type="list" class="input" binding="listDrives"/>
|
||||||
<control type="list" class="input" binding="listDisks">
|
<control type="list" class="input" binding="listDisks">
|
||||||
<disk path="">None</disk>
|
<disk path="">None</disk>
|
||||||
|
|
|
||||||
|
|
@ -230,8 +230,7 @@ function ChipSet(parmsChipSet)
|
||||||
this.fSpeaker = false;
|
this.fSpeaker = false;
|
||||||
if (parmsChipSet['sound']) {
|
if (parmsChipSet['sound']) {
|
||||||
if (window && 'webkitAudioContext' in window) {
|
if (window && 'webkitAudioContext' in window) {
|
||||||
// noinspection JSPotentiallyInvalidConstructorUsage
|
this.contextAudio = new window['webkitAudioContext']();
|
||||||
this.contextAudio = new webkitAudioContext();
|
|
||||||
} else {
|
} else {
|
||||||
if (DEBUG) this.log("webkitAudioContext not available");
|
if (DEBUG) this.log("webkitAudioContext not available");
|
||||||
}
|
}
|
||||||
|
|
@ -291,15 +290,18 @@ ChipSet.aMonitorSwitches = {
|
||||||
/*
|
/*
|
||||||
* 8237A DMA Controller (DMAC) I/O ports
|
* 8237A DMA Controller (DMAC) I/O ports
|
||||||
*
|
*
|
||||||
* MODEL_5150 and up uses DMA channel 0 for memory refresh cycles and channel 2 for the FDC
|
* MODEL_5150 and up uses DMA channel 0 for memory refresh cycles and channel 2 for the FDC.
|
||||||
* MODEL_5160 and up uses DMA channel 3 for HDC transfers (XTC only)
|
|
||||||
* MODEL_5170 and up contain *two* DMA Controllers, which we refer to as DMA0 and DMA1; channel 4
|
|
||||||
* on DMA1 is used to "cascade" channels 0-3 from DMA0, so only channels 5-7 are available on DMA1
|
|
||||||
*
|
*
|
||||||
* QUESTION: Why does the MODEL_5150 ROM BIOS set the page register for channel 1 (port 0x83) to zero?
|
* MODEL_5160 and up uses DMA channel 3 for HDC transfers (XTC only).
|
||||||
*
|
*
|
||||||
* For FDC DMA notes, refer to: http://wiki.osdev.org/ISA_DMA
|
* DMA0 refers to the original DMA controller found on all models, and DMA1 refers to the additional
|
||||||
* For general DMA notes, refer to: http://www.freebsd.org/doc/en/books/developers-handbook/dma.html
|
* controller found on MODEL_5170 and up; channel 4 on DMA1 is used to "cascade" channels 0-3 from DMA0,
|
||||||
|
* so only channels 5-7 are available on DMA1.
|
||||||
|
*
|
||||||
|
* For FDC DMA notes, refer to http://wiki.osdev.org/ISA_DMA
|
||||||
|
* For general DMA notes, refer to http://www.freebsd.org/doc/en/books/developers-handbook/dma.html
|
||||||
|
*
|
||||||
|
* TODO: Determine why the MODEL_5150 ROM BIOS sets the page register for channel 1 (port 0x83) to zero
|
||||||
*/
|
*/
|
||||||
ChipSet.DMA0 = {
|
ChipSet.DMA0 = {
|
||||||
INDEX: 0,
|
INDEX: 0,
|
||||||
|
|
@ -316,10 +318,10 @@ ChipSet.DMA0 = {
|
||||||
REQUEST: 0x09,
|
REQUEST: 0x09,
|
||||||
MASK: 0x0A,
|
MASK: 0x0A,
|
||||||
MODE: 0x0B,
|
MODE: 0x0B,
|
||||||
CLEAR_FF: 0x0C,
|
RESET_FF: 0x0C, // reset flip-flop
|
||||||
MASTER_CLR: 0x0D,
|
MASTER_CLEAR: 0x0D, // master clear
|
||||||
CLEAR_MASK: 0x0E, // TODO: Provide handlers
|
MASK_CLEAR: 0x0E, // TODO: Provide handlers
|
||||||
ALL_MASK: 0x0F, // TODO: Provide handlers
|
MASK_ALL: 0x0F, // TODO: Provide handlers
|
||||||
CH2_PAGE: 0x81, // OUT: DMA channel 2 page register
|
CH2_PAGE: 0x81, // OUT: DMA channel 2 page register
|
||||||
CH3_PAGE: 0x82, // OUT: DMA channel 3 page register
|
CH3_PAGE: 0x82, // OUT: DMA channel 3 page register
|
||||||
CH1_PAGE: 0x83, // OUT: DMA channel 1 page register
|
CH1_PAGE: 0x83, // OUT: DMA channel 1 page register
|
||||||
|
|
@ -345,10 +347,10 @@ ChipSet.DMA1 = {
|
||||||
REQUEST: 0xD2,
|
REQUEST: 0xD2,
|
||||||
MASK: 0xD4,
|
MASK: 0xD4,
|
||||||
MODE: 0xD6,
|
MODE: 0xD6,
|
||||||
CLEAR_FF: 0xD8,
|
RESET_FF: 0xD8, // reset flip-flop
|
||||||
MASTER_CLR: 0xDA,
|
MASTER_CLEAR: 0xDA, // master clear
|
||||||
CLEAR_MASK: 0xDC, // TODO: Provide handlers
|
MASK_CLEAR: 0xDC, // TODO: Provide handlers
|
||||||
ALL_MASK: 0xDE // TODO: Provide handlers
|
MASK_ALL: 0xDE // TODO: Provide handlers
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -363,6 +365,18 @@ ChipSet.DMA_CMD = {
|
||||||
DACK_ACTIVE_HI: 0x80
|
DACK_ACTIVE_HI: 0x80
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ChipSet.DMA_STATUS = {
|
||||||
|
CH0_TC: 0x01, // Channel 0 has reached Terminal Count (TC)
|
||||||
|
CH1_TC: 0x02, // Channel 1 has reached Terminal Count (TC)
|
||||||
|
CH2_TC: 0x04, // Channel 2 has reached Terminal Count (TC)
|
||||||
|
CH3_TC: 0x08, // Channel 3 has reached Terminal Count (TC)
|
||||||
|
ALL_TC: 0x0f, // all TC bits are cleared whenever DMA_STATUS is read
|
||||||
|
CH0_REQ: 0x10, // Channel 0 DMA requested
|
||||||
|
CH1_REQ: 0x20, // Channel 1 DMA requested
|
||||||
|
CH2_REQ: 0x40, // Channel 2 DMA requested
|
||||||
|
CH3_REQ: 0x80 // Channel 3 DMA requested
|
||||||
|
};
|
||||||
|
|
||||||
ChipSet.DMA_MASK = {
|
ChipSet.DMA_MASK = {
|
||||||
CHANNEL: 0x03,
|
CHANNEL: 0x03,
|
||||||
CHANNEL_SET: 0x04
|
CHANNEL_SET: 0x04
|
||||||
|
|
@ -375,7 +389,7 @@ ChipSet.DMA_MODE = {
|
||||||
XFER_WRITE: 0x04,
|
XFER_WRITE: 0x04,
|
||||||
XFER_READ: 0x08,
|
XFER_READ: 0x08,
|
||||||
AUTOINIT: 0x10,
|
AUTOINIT: 0x10,
|
||||||
DECREMENT: 0x20,
|
DECREMENT: 0x20, // clear for INCREMENT
|
||||||
MODE: 0xC0,
|
MODE: 0xC0,
|
||||||
MODE_DEMAND: 0x00,
|
MODE_DEMAND: 0x00,
|
||||||
MODE_SINGLE: 0x40,
|
MODE_SINGLE: 0x40,
|
||||||
|
|
@ -383,6 +397,7 @@ ChipSet.DMA_MODE = {
|
||||||
MODE_CASCADE: 0xC0
|
MODE_CASCADE: 0xC0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ChipSet.DMA_REFRESH = 0x00; // DMA channel assigned to the Floppy Drive Controller (FDC)
|
||||||
ChipSet.DMA_FDC = 0x02; // DMA channel assigned to the Floppy Drive Controller (FDC)
|
ChipSet.DMA_FDC = 0x02; // DMA channel assigned to the Floppy Drive Controller (FDC)
|
||||||
ChipSet.DMA_HDC = 0x03; // DMA channel assigned to the Hard Drive Controller (HDC; XTC only)
|
ChipSet.DMA_HDC = 0x03; // DMA channel assigned to the Hard Drive Controller (HDC; XTC only)
|
||||||
|
|
||||||
|
|
@ -519,7 +534,7 @@ ChipSet.TIMER_CTRL = {
|
||||||
PORT: 0x43, // write-only control register (use the Read-Back command to get status)
|
PORT: 0x43, // write-only control register (use the Read-Back command to get status)
|
||||||
BCD: 0x01,
|
BCD: 0x01,
|
||||||
MODE: 0x0E,
|
MODE: 0x0E,
|
||||||
MODE0: 0x00, // interrupt on terminal count
|
MODE0: 0x00, // interrupt on Terminal Count (TC)
|
||||||
MODE1: 0x02, // programmable one-shot
|
MODE1: 0x02, // programmable one-shot
|
||||||
MODE2: 0x04, // rate generator
|
MODE2: 0x04, // rate generator
|
||||||
MODE3: 0x06, // square wave generator
|
MODE3: 0x06, // square wave generator
|
||||||
|
|
@ -945,6 +960,9 @@ ChipSet.prototype.initBus = function(cmp, bus, cpu, dbg)
|
||||||
if (DEBUGGER) {
|
if (DEBUGGER) {
|
||||||
if (dbg) {
|
if (dbg) {
|
||||||
var chipset = this;
|
var chipset = this;
|
||||||
|
/*
|
||||||
|
* TODO: Add more "dumpers" (eg, for DMA, RTC, 8042, etc)
|
||||||
|
*/
|
||||||
dbg.messageDump(Debugger.MESSAGE.PIC, function onDumpPIC() {
|
dbg.messageDump(Debugger.MESSAGE.PIC, function onDumpPIC() {
|
||||||
chipset.dumpPIC();
|
chipset.dumpPIC();
|
||||||
});
|
});
|
||||||
|
|
@ -1571,7 +1589,9 @@ ChipSet.prototype.restore = function(data)
|
||||||
ChipSet.prototype.initDMAController = function(iDMAC, aState)
|
ChipSet.prototype.initDMAController = function(iDMAC, aState)
|
||||||
{
|
{
|
||||||
var controller = this.aDMACs[iDMAC] = {};
|
var controller = this.aDMACs[iDMAC] = {};
|
||||||
if (!aState || aState.length != 5) aState = [0, undefined, undefined, 0, []];
|
if (!aState || aState.length != 5) {
|
||||||
|
aState = [0, undefined, undefined, 0, []];
|
||||||
|
}
|
||||||
controller.bStatus = aState[0];
|
controller.bStatus = aState[0];
|
||||||
controller.bCmd = aState[1];
|
controller.bCmd = aState[1];
|
||||||
controller.bReq = aState[2];
|
controller.bReq = aState[2];
|
||||||
|
|
@ -1645,14 +1665,14 @@ ChipSet.prototype.saveDMAControllers = function()
|
||||||
{
|
{
|
||||||
var data = [];
|
var data = [];
|
||||||
for (var iDMAC = 0; iDMAC < this.aDMACs; iDMAC++) {
|
for (var iDMAC = 0; iDMAC < this.aDMACs; iDMAC++) {
|
||||||
var a = [];
|
|
||||||
var controller = this.aDMACs[iDMAC];
|
var controller = this.aDMACs[iDMAC];
|
||||||
a[0] = controller.bStatus;
|
data[iDMAC] = [
|
||||||
a[1] = controller.bCmd;
|
controller.bStatus,
|
||||||
a[2] = controller.bReq;
|
controller.bCmd,
|
||||||
a[3] = controller.bIndex;
|
controller.bReq,
|
||||||
a[4] = this.saveDMAChannels(controller);
|
controller.bIndex,
|
||||||
data[iDMAC] = a;
|
this.saveDMAChannels(controller)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
@ -1668,18 +1688,18 @@ ChipSet.prototype.saveDMAChannels = function(controller)
|
||||||
{
|
{
|
||||||
var data = [];
|
var data = [];
|
||||||
for (var iChannel = 0; iChannel < controller.aChannels.length; iChannel++) {
|
for (var iChannel = 0; iChannel < controller.aChannels.length; iChannel++) {
|
||||||
var a = [];
|
|
||||||
var channel = controller.aChannels[iChannel];
|
var channel = controller.aChannels[iChannel];
|
||||||
a[0] = channel.masked;
|
data[iChannel] = [
|
||||||
a[1] = channel.addrInit;
|
channel.masked,
|
||||||
a[2] = channel.countInit;
|
channel.addrInit,
|
||||||
a[3] = channel.addrCurrent;
|
channel.countInit,
|
||||||
a[4] = channel.countCurrent;
|
channel.addrCurrent,
|
||||||
a[5] = channel.mode;
|
channel.countCurrent,
|
||||||
a[6] = channel.bPage;
|
channel.mode,
|
||||||
a[8] = channel.sDevice;
|
channel.bPage,
|
||||||
a[9] = channel.sFunction;
|
channel.sDevice,
|
||||||
data[iChannel] = a;
|
channel.sFunction
|
||||||
|
];
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
@ -1695,7 +1715,9 @@ ChipSet.prototype.saveDMAChannels = function(controller)
|
||||||
ChipSet.prototype.initPIC = function(iPIC, port, aState)
|
ChipSet.prototype.initPIC = function(iPIC, port, aState)
|
||||||
{
|
{
|
||||||
var pic = this.aPICs[iPIC] = {};
|
var pic = this.aPICs[iPIC] = {};
|
||||||
if (!aState || aState.length != 8) aState = [0, [undefined, undefined, undefined, undefined]];
|
if (!aState || aState.length != 8) {
|
||||||
|
aState = [0, [undefined, undefined, undefined, undefined]];
|
||||||
|
}
|
||||||
pic.port = port;
|
pic.port = port;
|
||||||
pic.nIRQBase = iPIC << 3;
|
pic.nIRQBase = iPIC << 3;
|
||||||
pic.nDelay = aState[0];
|
pic.nDelay = aState[0];
|
||||||
|
|
@ -1718,17 +1740,17 @@ ChipSet.prototype.savePICs = function()
|
||||||
{
|
{
|
||||||
var data = [];
|
var data = [];
|
||||||
for (var iPIC = 0; iPIC < this.aPICs.length; iPIC++) {
|
for (var iPIC = 0; iPIC < this.aPICs.length; iPIC++) {
|
||||||
var a = [];
|
|
||||||
var pic = this.aPICs[iPIC];
|
var pic = this.aPICs[iPIC];
|
||||||
a[0] = pic.nDelay;
|
data[iPIC] = [
|
||||||
a[1] = pic.aICW;
|
pic.nDelay,
|
||||||
a[2] = pic.nICW;
|
pic.aICW,
|
||||||
a[3] = pic.bIMR;
|
pic.nICW,
|
||||||
a[4] = pic.bIRR;
|
pic.bIMR,
|
||||||
a[5] = pic.bISR;
|
pic.bIRR,
|
||||||
a[6] = pic.bIRLow;
|
pic.bISR,
|
||||||
a[7] = pic.bOCW3;
|
pic.bIRLow,
|
||||||
data[iPIC] = a;
|
pic.bOCW3
|
||||||
|
];
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
@ -1744,7 +1766,7 @@ ChipSet.prototype.initTimer = function(iTimer, aState)
|
||||||
{
|
{
|
||||||
var timer = this.aTimers[iTimer] = {};
|
var timer = this.aTimers[iTimer] = {};
|
||||||
if (aState === undefined || aState.length != 13) {
|
if (aState === undefined || aState.length != 13) {
|
||||||
aState = [ [], [], [], [] ];
|
aState = [ [0,0], [0,0], [0,0], [0,0] ];
|
||||||
}
|
}
|
||||||
timer.countInit = aState[0];
|
timer.countInit = aState[0];
|
||||||
timer.countStart = aState[1];
|
timer.countStart = aState[1];
|
||||||
|
|
@ -1771,22 +1793,22 @@ ChipSet.prototype.saveTimers = function()
|
||||||
{
|
{
|
||||||
var data = [];
|
var data = [];
|
||||||
for (var iTimer = 0; iTimer < this.aTimers.length; iTimer++) {
|
for (var iTimer = 0; iTimer < this.aTimers.length; iTimer++) {
|
||||||
var a = [];
|
|
||||||
var timer = this.aTimers[iTimer];
|
var timer = this.aTimers[iTimer];
|
||||||
a[0] = timer.countInit;
|
data[iTimer] = [
|
||||||
a[1] = timer.countStart;
|
timer.countInit,
|
||||||
a[2] = timer.countCurrent;
|
timer.countStart,
|
||||||
a[3] = timer.countLatched;
|
timer.countCurrent,
|
||||||
a[4] = timer.bcd;
|
timer.countLatched,
|
||||||
a[5] = timer.mode;
|
timer.bcd,
|
||||||
a[6] = timer.rw;
|
timer.mode,
|
||||||
a[7] = timer.countIndex;
|
timer.rw,
|
||||||
a[8] = timer.countBytes;
|
timer.countIndex,
|
||||||
a[9] = timer.fOUT;
|
timer.countBytes,
|
||||||
a[10] = timer.fLatched;
|
timer.fOUT,
|
||||||
a[11] = timer.fCounting;
|
timer.fLatched,
|
||||||
a[12] = timer.nStartCycles;
|
timer.fCounting,
|
||||||
data[iTimer] = a;
|
timer.nStartCycles
|
||||||
|
];
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
@ -2080,7 +2102,7 @@ ChipSet.prototype.dumpCMOS = function()
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {number} iDMAC
|
* @param {number} iDMAC
|
||||||
* @param {number} iChannel
|
* @param {number} iChannel
|
||||||
* @param {number} port
|
* @param {number} port (0x00, 0x02, 0x04, 0x06 for DMAC 0, 0xC0, 0xC4, 0xC8, 0xCC for DMAC 1)
|
||||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||||
* @return {number} simulated port value
|
* @return {number} simulated port value
|
||||||
*/
|
*/
|
||||||
|
|
@ -2089,8 +2111,25 @@ ChipSet.prototype.inDMAChannelAddr = function(iDMAC, iChannel, port, addrFrom)
|
||||||
var controller = this.aDMACs[iDMAC];
|
var controller = this.aDMACs[iDMAC];
|
||||||
var channel = controller.aChannels[iChannel];
|
var channel = controller.aChannels[iChannel];
|
||||||
var b = channel.addrCurrent[controller.bIndex];
|
var b = channel.addrCurrent[controller.bIndex];
|
||||||
controller.bIndex ^= 0x1;
|
|
||||||
this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".ADDR[" + controller.bIndex + "]", Debugger.MESSAGE.DMA, b);
|
this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".ADDR[" + controller.bIndex + "]", Debugger.MESSAGE.DMA, b);
|
||||||
|
controller.bIndex ^= 0x1;
|
||||||
|
/*
|
||||||
|
* Technically, aTimers[ChipSet.TIMER1.INDEX].fOut is what drives DMA requests for DMA channel 0 (ChipSet.DMA_REFRESH),
|
||||||
|
* every 15us, once the BIOS has initialized the channel's "mode" with MODE_SINGLE, INCREMENT, AUTOINIT, and XFER_READ (0x58)
|
||||||
|
* and initialized TIMER1 appropriately.
|
||||||
|
*
|
||||||
|
* However, we don't need to be that particular. Simply simulate an ever-increasing address after every read of the full DMA channel 0 address.
|
||||||
|
*/
|
||||||
|
if (!iDMAC && iChannel == ChipSet.DMA_REFRESH && !controller.bIndex) {
|
||||||
|
channel.addrCurrent[0]++;
|
||||||
|
if (channel.addrCurrent[0] > 0xff) {
|
||||||
|
channel.addrCurrent[0] = 0;
|
||||||
|
channel.addrCurrent[1]++;
|
||||||
|
if (channel.addrCurrent[1] > 0xff) {
|
||||||
|
channel.addrCurrent[1] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return b;
|
return b;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -2100,7 +2139,7 @@ ChipSet.prototype.inDMAChannelAddr = function(iDMAC, iChannel, port, addrFrom)
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {number} iDMAC
|
* @param {number} iDMAC
|
||||||
* @param {number} iChannel
|
* @param {number} iChannel
|
||||||
* @param {number} port
|
* @param {number} port (0x00, 0x02, 0x04, 0x06 for DMAC 0, 0xC0, 0xC4, 0xC8, 0xCC for DMAC 1)
|
||||||
* @param {number} bOut
|
* @param {number} bOut
|
||||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||||
*/
|
*/
|
||||||
|
|
@ -2119,7 +2158,7 @@ ChipSet.prototype.outDMAChannelAddr = function outDMAChannelAddr(iDMAC, iChannel
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {number} iDMAC
|
* @param {number} iDMAC
|
||||||
* @param {number} iChannel
|
* @param {number} iChannel
|
||||||
* @param {number} port
|
* @param {number} port (0x01, 0x03, 0x05, 0x07 for DMAC 0, 0xC2, 0xC6, 0xCA, 0xCE for DMAC 1)
|
||||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||||
* @return {number} simulated port value
|
* @return {number} simulated port value
|
||||||
*/
|
*/
|
||||||
|
|
@ -2128,8 +2167,29 @@ ChipSet.prototype.inDMAChannelCount = function(iDMAC, iChannel, port, addrFrom)
|
||||||
var controller = this.aDMACs[iDMAC];
|
var controller = this.aDMACs[iDMAC];
|
||||||
var channel = controller.aChannels[iChannel];
|
var channel = controller.aChannels[iChannel];
|
||||||
var b = channel.countCurrent[controller.bIndex];
|
var b = channel.countCurrent[controller.bIndex];
|
||||||
controller.bIndex ^= 0x1;
|
|
||||||
this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".COUNT[" + controller.bIndex + "]", Debugger.MESSAGE.DMA, b);
|
this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".COUNT[" + controller.bIndex + "]", Debugger.MESSAGE.DMA, b);
|
||||||
|
controller.bIndex ^= 0x1;
|
||||||
|
/*
|
||||||
|
* Technically, aTimers[ChipSet.TIMER1.INDEX].fOut is what drives DMA requests for DMA channel 0 (ChipSet.DMA_REFRESH),
|
||||||
|
* every 15us, once the BIOS has initialized the channel's "mode" with MODE_SINGLE, INCREMENT, AUTOINIT, and XFER_READ (0x58)
|
||||||
|
* and initialized TIMER1 appropriately.
|
||||||
|
*
|
||||||
|
* However, we don't need to be that particular. Simply simulate an ever-decreasing count after every read of the full DMA channel 0 count.
|
||||||
|
*/
|
||||||
|
if (!iDMAC && iChannel == ChipSet.DMA_REFRESH && !controller.bIndex) {
|
||||||
|
channel.countCurrent[0]--;
|
||||||
|
if (channel.countCurrent[0] < 0) {
|
||||||
|
channel.countCurrent[0] = 0xff;
|
||||||
|
channel.countCurrent[1]--;
|
||||||
|
if (channel.countCurrent[1] < 0) {
|
||||||
|
channel.countCurrent[1] = 0xff;
|
||||||
|
/*
|
||||||
|
* This is the logical point to indicate Terminal Count (TC), but again, there's no need to be
|
||||||
|
* so particular; inDMAStatus() has its own logic for periodically signalling TC.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return b;
|
return b;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -2139,7 +2199,7 @@ ChipSet.prototype.inDMAChannelCount = function(iDMAC, iChannel, port, addrFrom)
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {number} iDMAC
|
* @param {number} iDMAC
|
||||||
* @param {number} iChannel (ports 0x01, 0x03, 0x05, 0x07)
|
* @param {number} iChannel (ports 0x01, 0x03, 0x05, 0x07)
|
||||||
* @param {number} port
|
* @param {number} port (0x01, 0x03, 0x05, 0x07 for DMAC 0, 0xC2, 0xC6, 0xCA, 0xCE for DMAC 1)
|
||||||
* @param {number} bOut
|
* @param {number} bOut
|
||||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||||
*/
|
*/
|
||||||
|
|
@ -2155,17 +2215,11 @@ ChipSet.prototype.outDMAChannelCount = function(iDMAC, iChannel, port, bOut, add
|
||||||
/**
|
/**
|
||||||
* inDMAStatus(iDMAC, port, addrFrom)
|
* inDMAStatus(iDMAC, port, addrFrom)
|
||||||
*
|
*
|
||||||
* @this {ChipSet}
|
|
||||||
* @param {number} iDMAC
|
|
||||||
* @param {number} port
|
|
||||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
|
||||||
* @return {number} simulated port value
|
|
||||||
*
|
|
||||||
* From the 8237A spec:
|
* From the 8237A spec:
|
||||||
*
|
*
|
||||||
* "The Status register is available to be read out of the 8237A by the microprocessor.
|
* "The Status register is available to be read out of the 8237A by the microprocessor.
|
||||||
* It contains information about the status of the devices at this point. This information includes
|
* It contains information about the status of the devices at this point. This information includes
|
||||||
* which channels have reached a terminal count and which channels have pending DMA requests.
|
* which channels have reached Terminal Count (TC) and which channels have pending DMA requests.
|
||||||
*
|
*
|
||||||
* Bits 0–3 are set every time a TC is reached by that channel or an external EOP is applied.
|
* Bits 0–3 are set every time a TC is reached by that channel or an external EOP is applied.
|
||||||
* These bits are cleared upon Reset and on each Status Read.
|
* These bits are cleared upon Reset and on each Status Read.
|
||||||
|
|
@ -2175,6 +2229,12 @@ ChipSet.prototype.outDMAChannelCount = function(iDMAC, iChannel, port, bOut, add
|
||||||
* TRIVIA: This hook wasn't installed when I was testing with the MODEL_5150 ROM BIOS, and it
|
* TRIVIA: This hook wasn't installed when I was testing with the MODEL_5150 ROM BIOS, and it
|
||||||
* didn't matter, but the MODEL_5160 ROM BIOS checks it several times, including @F000:E156, where
|
* didn't matter, but the MODEL_5160 ROM BIOS checks it several times, including @F000:E156, where
|
||||||
* it verifies that TIMER1 didn't request service on channel 0.
|
* it verifies that TIMER1 didn't request service on channel 0.
|
||||||
|
*
|
||||||
|
* @this {ChipSet}
|
||||||
|
* @param {number} iDMAC
|
||||||
|
* @param {number} port (0x08 for DMAC 0, 0xD0 for DMAC 1)
|
||||||
|
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||||
|
* @return {number} simulated port value
|
||||||
*/
|
*/
|
||||||
ChipSet.prototype.inDMAStatus = function(iDMAC, port, addrFrom)
|
ChipSet.prototype.inDMAStatus = function(iDMAC, port, addrFrom)
|
||||||
{
|
{
|
||||||
|
|
@ -2185,8 +2245,8 @@ ChipSet.prototype.inDMAStatus = function(iDMAC, port, addrFrom)
|
||||||
* status is read.
|
* status is read.
|
||||||
*/
|
*/
|
||||||
var controller = this.aDMACs[iDMAC];
|
var controller = this.aDMACs[iDMAC];
|
||||||
var b = controller.bStatus | 0x1;
|
var b = controller.bStatus | ChipSet.DMA_STATUS.CH0_TC;
|
||||||
controller.bStatus &= ~0xf;
|
controller.bStatus &= ~ChipSet.DMA_STATUS.ALL_TC;
|
||||||
this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".STATUS", Debugger.MESSAGE.DMA, b);
|
this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".STATUS", Debugger.MESSAGE.DMA, b);
|
||||||
return b;
|
return b;
|
||||||
};
|
};
|
||||||
|
|
@ -2196,7 +2256,7 @@ ChipSet.prototype.inDMAStatus = function(iDMAC, port, addrFrom)
|
||||||
*
|
*
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {number} iDMAC
|
* @param {number} iDMAC
|
||||||
* @param {number} port
|
* @param {number} port (0x08 for DMAC 0, 0xD0 for DMAC 1)
|
||||||
* @param {number} bOut
|
* @param {number} bOut
|
||||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||||
*/
|
*/
|
||||||
|
|
@ -2209,12 +2269,6 @@ ChipSet.prototype.outDMACmd = function(iDMAC, port, bOut, addrFrom)
|
||||||
/**
|
/**
|
||||||
* outDMAReq(iDMAC, port, bOut, addrFrom)
|
* outDMAReq(iDMAC, port, bOut, addrFrom)
|
||||||
*
|
*
|
||||||
* @this {ChipSet}
|
|
||||||
* @param {number} iDMAC
|
|
||||||
* @param {number} port
|
|
||||||
* @param {number} bOut
|
|
||||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
|
||||||
*
|
|
||||||
* From the 8237A spec:
|
* From the 8237A spec:
|
||||||
*
|
*
|
||||||
* "The 8237A can respond to requests for DMA service which are initiated by software as well as by a DREQ.
|
* "The 8237A can respond to requests for DMA service which are initiated by software as well as by a DREQ.
|
||||||
|
|
@ -2224,6 +2278,12 @@ ChipSet.prototype.outDMACmd = function(iDMAC, port, bOut, addrFrom)
|
||||||
*
|
*
|
||||||
* To set or reset a bit the software loads the proper form of the data word.... In order to make a software request,
|
* To set or reset a bit the software loads the proper form of the data word.... In order to make a software request,
|
||||||
* the channel must be in Block Mode."
|
* the channel must be in Block Mode."
|
||||||
|
*
|
||||||
|
* @this {ChipSet}
|
||||||
|
* @param {number} iDMAC
|
||||||
|
* @param {number} port (0x09 for DMAC 0, 0xD2 for DMAC 1)
|
||||||
|
* @param {number} bOut
|
||||||
|
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||||
*/
|
*/
|
||||||
ChipSet.prototype.outDMAReq = function(iDMAC, port, bOut, addrFrom)
|
ChipSet.prototype.outDMAReq = function(iDMAC, port, bOut, addrFrom)
|
||||||
{
|
{
|
||||||
|
|
@ -2246,7 +2306,7 @@ ChipSet.prototype.outDMAReq = function(iDMAC, port, bOut, addrFrom)
|
||||||
*
|
*
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {number} iDMAC
|
* @param {number} iDMAC
|
||||||
* @param {number} port
|
* @param {number} port (0x0A for DMAC 0, 0xD4 for DMAC 1)
|
||||||
* @param {number} bOut
|
* @param {number} bOut
|
||||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||||
*/
|
*/
|
||||||
|
|
@ -2256,7 +2316,7 @@ ChipSet.prototype.outDMAMask = function(iDMAC, port, bOut, addrFrom)
|
||||||
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASK", Debugger.MESSAGE.DMA);
|
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASK", Debugger.MESSAGE.DMA);
|
||||||
var iChannel = bOut & ChipSet.DMA_MASK.CHANNEL;
|
var iChannel = bOut & ChipSet.DMA_MASK.CHANNEL;
|
||||||
var channel = controller.aChannels[iChannel];
|
var channel = controller.aChannels[iChannel];
|
||||||
channel.masked = (bOut & ChipSet.DMA_MASK.CHANNEL_SET? true : false);
|
channel.masked = !!(bOut & ChipSet.DMA_MASK.CHANNEL_SET);
|
||||||
if (!channel.masked) this.requestDMA(controller.nChannelBase + iChannel);
|
if (!channel.masked) this.requestDMA(controller.nChannelBase + iChannel);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -2265,7 +2325,7 @@ ChipSet.prototype.outDMAMask = function(iDMAC, port, bOut, addrFrom)
|
||||||
*
|
*
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {number} iDMAC
|
* @param {number} iDMAC
|
||||||
* @param {number} port
|
* @param {number} port (0x0B for DMAC 0, 0xD6 for DMAC 1)
|
||||||
* @param {number} bOut
|
* @param {number} bOut
|
||||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||||
*/
|
*/
|
||||||
|
|
@ -2277,37 +2337,39 @@ ChipSet.prototype.outDMAMode = function(iDMAC, port, bOut, addrFrom)
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* outDMAIndex(iDMAC, port, bOut, addrFrom)
|
* outDMAResetFF(iDMAC, port, bOut, addrFrom)
|
||||||
*
|
*
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {number} iDMAC
|
* @param {number} iDMAC
|
||||||
* @param {number} port
|
* @param {number} port (0x0C for DMAC 0, 0xD8 for DMAC 1)
|
||||||
* @param {number} bOut
|
* @param {number} bOut
|
||||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||||
*
|
*
|
||||||
* Any write to this port simply resets the controller's "first/last flip-flop", which determines whether
|
* Any write to this port simply resets the controller's "first/last flip-flop", which determines whether
|
||||||
* the even or odd byte of a DMA address or count register will be accessed next.
|
* the even or odd byte of a DMA address or count register will be accessed next.
|
||||||
*/
|
*/
|
||||||
ChipSet.prototype.outDMAIndex = function(iDMAC, port, bOut, addrFrom)
|
ChipSet.prototype.outDMAResetFF = function(iDMAC, port, bOut, addrFrom)
|
||||||
{
|
{
|
||||||
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".INDEX", Debugger.MESSAGE.DMA);
|
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".RESET_FF", Debugger.MESSAGE.DMA);
|
||||||
this.aDMACs[iDMAC].bIndex = 0;
|
this.aDMACs[iDMAC].bIndex = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* outDMAClear(iDMAC, port, bOut, addrFrom)
|
* outDMAMasterClear(iDMAC, port, bOut, addrFrom)
|
||||||
*
|
*
|
||||||
* @this {ChipSet}
|
* @this {ChipSet}
|
||||||
* @param {number} iDMAC
|
* @param {number} iDMAC
|
||||||
* @param {number} port
|
* @param {number} port (0x0D for DMAC 0, 0xDA for DMAC 1)
|
||||||
* @param {number} bOut
|
* @param {number} bOut
|
||||||
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
|
||||||
*/
|
*/
|
||||||
ChipSet.prototype.outDMAClear = function(iDMAC, port, bOut, addrFrom)
|
ChipSet.prototype.outDMAMasterClear = function(iDMAC, port, bOut, addrFrom)
|
||||||
{
|
{
|
||||||
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CLEAR", Debugger.MESSAGE.DMA);
|
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASTER_CLEAR", Debugger.MESSAGE.DMA);
|
||||||
/*
|
/*
|
||||||
* The value written to this port doesn't matter; any write triggers a "master clear" operation
|
* The value written to this port doesn't matter; any write triggers a "master clear" operation
|
||||||
|
*
|
||||||
|
* TODO: Can't we just call initDMAController(), which would also take care of clearing controller.bStatus?
|
||||||
*/
|
*/
|
||||||
var controller = this.aDMACs[iDMAC];
|
var controller = this.aDMACs[iDMAC];
|
||||||
for (var i = 0; i < controller.aChannels.length; i++) {
|
for (var i = 0; i < controller.aChannels.length; i++) {
|
||||||
|
|
@ -4517,8 +4579,8 @@ ChipSet.aPortOutput = {
|
||||||
0x09: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAReq(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
|
0x09: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAReq(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
|
||||||
0x0A: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAMask(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
|
0x0A: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAMask(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
|
||||||
0x0B: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAMode(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
|
0x0B: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAMode(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
|
||||||
0x0C: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAIndex(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
|
0x0C: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAResetFF(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
|
||||||
0x0D: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAClear(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
|
0x0D: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAMasterClear(ChipSet.DMA0.INDEX, port, bOut, addrFrom); },
|
||||||
0x20: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICLo(ChipSet.PIC0.INDEX, bOut, addrFrom); },
|
0x20: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICLo(ChipSet.PIC0.INDEX, bOut, addrFrom); },
|
||||||
0x21: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICHi(ChipSet.PIC0.INDEX, bOut, addrFrom); },
|
0x21: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outPICHi(ChipSet.PIC0.INDEX, bOut, addrFrom); },
|
||||||
0x40: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outTimer(ChipSet.TIMER0.INDEX, bOut, addrFrom); },
|
0x40: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outTimer(ChipSet.TIMER0.INDEX, bOut, addrFrom); },
|
||||||
|
|
@ -4571,8 +4633,8 @@ ChipSet.aPortOutput5170 = {
|
||||||
0xD2: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAReq(ChipSet.DMA1.INDEX, port, bOut, addrFrom); },
|
0xD2: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAReq(ChipSet.DMA1.INDEX, port, bOut, addrFrom); },
|
||||||
0xD4: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAMask(ChipSet.DMA1.INDEX, port, bOut, addrFrom); },
|
0xD4: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAMask(ChipSet.DMA1.INDEX, port, bOut, addrFrom); },
|
||||||
0xD6: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAMode(ChipSet.DMA1.INDEX, port, bOut, addrFrom); },
|
0xD6: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAMode(ChipSet.DMA1.INDEX, port, bOut, addrFrom); },
|
||||||
0xD8: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAIndex(ChipSet.DMA1.INDEX, port, bOut, addrFrom); },
|
0xD8: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAResetFF(ChipSet.DMA1.INDEX, port, bOut, addrFrom); },
|
||||||
0xDA: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAClear(ChipSet.DMA1.INDEX, port, bOut, addrFrom); }
|
0xDA: /** @this {ChipSet} */ function(port, bOut, addrFrom) { this.outDMAMasterClear(ChipSet.DMA1.INDEX, port, bOut, addrFrom); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -807,7 +807,7 @@ Keyboard.prototype.setBinding = function(sHTMLClass, sHTMLType, sBinding, contro
|
||||||
this.bindings[id] = control;
|
this.bindings[id] = control;
|
||||||
control.onclick = function(kbd, sKey, keyCode) {
|
control.onclick = function(kbd, sKey, keyCode) {
|
||||||
return function onClickKeyboard(event) {
|
return function onClickKeyboard(event) {
|
||||||
if (DEBUG) kbd.println(sKey + " clicked");
|
if (DEBUG) kbd.messageDebugger(sKey + " clicked", Debugger.MESSAGE.KEYS);
|
||||||
if (kbd.cpu) kbd.cpu.setFocus();
|
if (kbd.cpu) kbd.cpu.setFocus();
|
||||||
return !kbd.keySimulatePress(keyCode);
|
return !kbd.keySimulatePress(keyCode);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -32,4 +32,4 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var webkitAudioContext;
|
// var webkitAudioContext;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue