v1.19.4: I/O bug fixes (16-bit input could trash EAX, and support for true 16-bit/32-bit I/O was lacking)
This commit is contained in:
parent
be5de49829
commit
cea314d7e8
30 changed files with 9220 additions and 2210 deletions
|
|
@ -159,6 +159,13 @@ function Bus(parmsBus, cpu, dbg)
|
|||
this.aPortOutputNotify = [];
|
||||
this.fPortInputBreakAll = this.fPortOutputBreakAll = false;
|
||||
|
||||
/*
|
||||
* By default, all I/O ports are 1 byte wide; ports that are wider must add themselves to one or both of
|
||||
* these lists, using addPortInputWidth() and/or addPortOutputWidth().
|
||||
*/
|
||||
this.aPortInputWidth = [];
|
||||
this.aPortOutputWidth = [];
|
||||
|
||||
/*
|
||||
* Allocate empty Memory blocks to span the entire physical address space.
|
||||
*/
|
||||
|
|
@ -1376,43 +1383,84 @@ Bus.prototype.addPortInputTable = function(component, table, offset)
|
|||
};
|
||||
|
||||
/**
|
||||
* checkPortInputNotify(port, addrLIP)
|
||||
* addPortInputWidth(port, size)
|
||||
*
|
||||
* By default, all input ports are 1 byte wide; ports that are wider must call this function.
|
||||
*
|
||||
* @this {Bus}
|
||||
* @param {number} port
|
||||
* @param {number} size (1, 2 or 4)
|
||||
*/
|
||||
Bus.prototype.addPortInputWidth = function(port, size)
|
||||
{
|
||||
this.aPortInputWidth[port] = size;
|
||||
};
|
||||
|
||||
/**
|
||||
* checkPortInputNotify(port, size, addrLIP)
|
||||
*
|
||||
* @this {Bus}
|
||||
* @param {number} port
|
||||
* @param {number} size (1, 2 or 4)
|
||||
* @param {number} [addrLIP] is the LIP value at the time of the input
|
||||
* @return {number} simulated port value (0xff if none)
|
||||
* @return {number} simulated port data
|
||||
*
|
||||
* NOTE: It seems that parts of the ROM BIOS (like the RS-232 probes around F000:E5D7 in the 5150 BIOS)
|
||||
* assume that ports for non-existent hardware return 0xff rather than 0x00, hence my new default (0xff) below.
|
||||
*/
|
||||
Bus.prototype.checkPortInputNotify = function(port, addrLIP)
|
||||
Bus.prototype.checkPortInputNotify = function(port, size, addrLIP)
|
||||
{
|
||||
var bIn = 0xff;
|
||||
var aNotify = this.aPortInputNotify[port];
|
||||
var data = 0, shift = 0;
|
||||
|
||||
if (BACKTRACK) {
|
||||
this.cpu.backTrack.btiIO = 0;
|
||||
}
|
||||
if (aNotify !== undefined) {
|
||||
if (aNotify[0]) {
|
||||
var b = aNotify[0]( port, addrLIP);
|
||||
if (b !== undefined) {
|
||||
this.assert(!(b & ~0xff));
|
||||
bIn = b;
|
||||
while (size > 0) {
|
||||
|
||||
var aNotify = this.aPortInputNotify[port];
|
||||
var sizePort = this.aPortInputWidth[port] || 1;
|
||||
var maskPort = (sizePort == 1? 0xff : (sizePort == 2? 0xffff : -1));
|
||||
var dataPort = maskPort;
|
||||
|
||||
/*
|
||||
* TODO: We need to decide what to do about 8-bit I/O to a 16-bit port
|
||||
* (ditto for 16-bit I/O to a 32-bit port). We probably should pass the
|
||||
* size through to the aNotify[0] handler, and let it decide what to do,
|
||||
* but I don't feel like changing all the I/O handlers right now. The
|
||||
* good news, at least, is that the 8-bit handlers would not have to do
|
||||
* anything special. This assert will warn us if this is a pressing need.
|
||||
*/
|
||||
this.assert(size >= sizePort);
|
||||
|
||||
if (BACKTRACK) {
|
||||
this.cpu.backTrack.btiIO = 0;
|
||||
}
|
||||
|
||||
if (aNotify !== undefined) {
|
||||
if (aNotify[0]) {
|
||||
dataPort = aNotify[0](port, addrLIP);
|
||||
if (dataPort === undefined) {
|
||||
dataPort = maskPort;
|
||||
} else {
|
||||
dataPort &= maskPort;
|
||||
}
|
||||
}
|
||||
if (DEBUGGER && this.dbg && this.fPortInputBreakAll != aNotify[1]) {
|
||||
this.dbg.checkPortInput(port, size, dataPort);
|
||||
}
|
||||
}
|
||||
if (DEBUGGER && this.dbg && this.fPortInputBreakAll != aNotify[1]) {
|
||||
this.dbg.checkPortInput(port, bIn);
|
||||
else {
|
||||
if (DEBUGGER && this.dbg) {
|
||||
this.dbg.messageIO(this, port, null, addrLIP);
|
||||
if (this.fPortInputBreakAll) this.dbg.checkPortInput(port, size, dataPort);
|
||||
}
|
||||
}
|
||||
|
||||
data |= dataPort << shift;
|
||||
shift += (sizePort << 3);
|
||||
port += sizePort;
|
||||
size -= sizePort;
|
||||
}
|
||||
else {
|
||||
if (DEBUGGER && this.dbg) {
|
||||
this.dbg.messageIO(this, port, null, addrLIP);
|
||||
if (this.fPortInputBreakAll) this.dbg.checkPortInput(port, bIn);
|
||||
}
|
||||
}
|
||||
return bIn;
|
||||
|
||||
this.assert(!size);
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1497,31 +1545,69 @@ Bus.prototype.addPortOutputTable = function(component, table, offset)
|
|||
};
|
||||
|
||||
/**
|
||||
* checkPortOutputNotify(port, bOut, addrLIP)
|
||||
* addPortOutputWidth(port, size)
|
||||
*
|
||||
* By default, all output ports are 1 byte wide; ports that are wider must call this function.
|
||||
*
|
||||
* @this {Bus}
|
||||
* @param {number} port
|
||||
* @param {number} bOut
|
||||
* @param {number} size (1, 2 or 4)
|
||||
*/
|
||||
Bus.prototype.addPortOutputWidth = function(port, size)
|
||||
{
|
||||
this.aPortOutputWidth[port] = size;
|
||||
};
|
||||
|
||||
/**
|
||||
* checkPortOutputNotify(port, size, data, addrLIP)
|
||||
*
|
||||
* @this {Bus}
|
||||
* @param {number} port
|
||||
* @param {number} size
|
||||
* @param {number} data
|
||||
* @param {number} [addrLIP] is the LIP value at the time of the output
|
||||
*/
|
||||
Bus.prototype.checkPortOutputNotify = function(port, bOut, addrLIP)
|
||||
Bus.prototype.checkPortOutputNotify = function(port, size, data, addrLIP)
|
||||
{
|
||||
var aNotify = this.aPortOutputNotify[port];
|
||||
if (aNotify !== undefined) {
|
||||
if (aNotify[0]) {
|
||||
this.assert(!(bOut & ~0xff));
|
||||
aNotify[0](port, bOut, addrLIP);
|
||||
var shift = 0;
|
||||
|
||||
while (size > 0) {
|
||||
|
||||
var aNotify = this.aPortOutputNotify[port];
|
||||
var sizePort = this.aPortOutputWidth[port] || 1;
|
||||
var maskPort = (sizePort == 1? 0xff : (sizePort == 2? 0xffff : -1));
|
||||
var dataPort = (data >>>= shift) & maskPort;
|
||||
|
||||
/*
|
||||
* TODO: We need to decide what to do about 8-bit I/O to a 16-bit port
|
||||
* (ditto for 16-bit I/O to a 32-bit port). We probably should pass the
|
||||
* size through to the aNotify[0] handler, and let it decide what to do,
|
||||
* but I don't feel like changing all the I/O handlers right now. The
|
||||
* good news, at least, is that the 8-bit handlers would not have to do
|
||||
* anything special. This assert will warn us if this is a pressing need.
|
||||
*/
|
||||
this.assert(size >= sizePort);
|
||||
|
||||
if (aNotify !== undefined) {
|
||||
if (aNotify[0]) {
|
||||
aNotify[0](port, dataPort, addrLIP);
|
||||
}
|
||||
if (DEBUGGER && this.dbg && this.fPortOutputBreakAll != aNotify[1]) {
|
||||
this.dbg.checkPortOutput(port, size, dataPort);
|
||||
}
|
||||
}
|
||||
if (DEBUGGER && this.dbg && this.fPortOutputBreakAll != aNotify[1]) {
|
||||
this.dbg.checkPortOutput(port, bOut);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (DEBUGGER && this.dbg) {
|
||||
this.dbg.messageIO(this, port, bOut, addrLIP);
|
||||
if (this.fPortOutputBreakAll) this.dbg.checkPortOutput(port, bOut);
|
||||
else {
|
||||
if (DEBUGGER && this.dbg) {
|
||||
this.dbg.messageIO(this, port, dataPort, addrLIP);
|
||||
if (this.fPortOutputBreakAll) this.dbg.checkPortOutput(port, size, dataPort);
|
||||
}
|
||||
}
|
||||
|
||||
shift += (sizePort << 3);
|
||||
port += sizePort;
|
||||
size -= sizePort;
|
||||
}
|
||||
this.assert(!size);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -953,10 +953,10 @@ if (DEBUGGER) {
|
|||
/* 0xE9 */ [Debugger.INS.JMP, Debugger.TYPE_IMMREL | Debugger.TYPE_VWORD | Debugger.TYPE_IN],
|
||||
/* 0xEA */ [Debugger.INS.JMP, Debugger.TYPE_IMM | Debugger.TYPE_FARP | Debugger.TYPE_IN],
|
||||
/* 0xEB */ [Debugger.INS.JMP, Debugger.TYPE_IMMREL | Debugger.TYPE_BYTE | Debugger.TYPE_IN],
|
||||
/* 0xEC */ [Debugger.INS.IN, Debugger.TYPE_AL | Debugger.TYPE_OUT, Debugger.TYPE_DX | Debugger.TYPE_IN],
|
||||
/* 0xED */ [Debugger.INS.IN, Debugger.TYPE_AX | Debugger.TYPE_OUT, Debugger.TYPE_DX | Debugger.TYPE_IN],
|
||||
/* 0xEE */ [Debugger.INS.OUT, Debugger.TYPE_DX | Debugger.TYPE_IN, Debugger.TYPE_AL | Debugger.TYPE_IN],
|
||||
/* 0xEF */ [Debugger.INS.OUT, Debugger.TYPE_DX | Debugger.TYPE_IN, Debugger.TYPE_AX | Debugger.TYPE_IN],
|
||||
/* 0xEC */ [Debugger.INS.IN, Debugger.TYPE_AL | Debugger.TYPE_OUT, Debugger.TYPE_DX | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||
/* 0xED */ [Debugger.INS.IN, Debugger.TYPE_AX | Debugger.TYPE_OUT, Debugger.TYPE_DX | Debugger.TYPE_WORD | Debugger.TYPE_IN],
|
||||
/* 0xEE */ [Debugger.INS.OUT, Debugger.TYPE_DX | Debugger.TYPE_WORD | Debugger.TYPE_IN, Debugger.TYPE_AL | Debugger.TYPE_IN],
|
||||
/* 0xEF */ [Debugger.INS.OUT, Debugger.TYPE_DX | Debugger.TYPE_WORD | Debugger.TYPE_IN, Debugger.TYPE_AX | Debugger.TYPE_IN],
|
||||
|
||||
/* 0xF0 */ [Debugger.INS.LOCK, Debugger.TYPE_PREFIX],
|
||||
/* 0xF1 */ [Debugger.INS.NONE],
|
||||
|
|
@ -3254,7 +3254,7 @@ if (DEBUGGER) {
|
|||
*/
|
||||
Debugger.prototype.init = function()
|
||||
{
|
||||
this.println("Type ? for list of debugger commands");
|
||||
this.println("Type ? for help with PCjs Debugger commands");
|
||||
this.updateStatus();
|
||||
if (this.sInitCommands) {
|
||||
var a = this.parseCommand(this.sInitCommands);
|
||||
|
|
@ -3719,41 +3719,43 @@ if (DEBUGGER) {
|
|||
};
|
||||
|
||||
/**
|
||||
* checkPortInput(port, bIn)
|
||||
* checkPortInput(port, size, data)
|
||||
*
|
||||
* This "check" function is called by the Bus component to inform us that port input occurred.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} port
|
||||
* @param {number} bIn
|
||||
* @param {number} size
|
||||
* @param {number} data
|
||||
* @return {boolean} true if breakpoint hit, false if not
|
||||
*/
|
||||
Debugger.prototype.checkPortInput = function(port, bIn)
|
||||
Debugger.prototype.checkPortInput = function(port, size, data)
|
||||
{
|
||||
/*
|
||||
* We trust that the Bus component won't call us unless we told it to, so we halt unconditionally
|
||||
*/
|
||||
this.println("break on input from port " + str.toHexWord(port) + ": " + str.toHexByte(bIn));
|
||||
this.println("break on input from port " + str.toHexWord(port) + ": " + str.toHex(data));
|
||||
this.stopCPU(true);
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* checkPortOutput(port, bOut)
|
||||
* checkPortOutput(port, size, data)
|
||||
*
|
||||
* This "check" function is called by the Bus component to inform us that port output occurred.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} port
|
||||
* @param {number} bOut
|
||||
* @param {number} size
|
||||
* @param {number} data
|
||||
* @return {boolean} true if breakpoint hit, false if not
|
||||
*/
|
||||
Debugger.prototype.checkPortOutput = function(port, bOut)
|
||||
Debugger.prototype.checkPortOutput = function(port, size, data)
|
||||
{
|
||||
/*
|
||||
* We trust that the Bus component won't call us unless we told it to, so we halt unconditionally
|
||||
*/
|
||||
this.println("break on output to port " + str.toHexWord(port) + ": " + str.toHexByte(bOut));
|
||||
this.println("break on output to port " + str.toHexWord(port) + ": " + str.toHex(data));
|
||||
this.stopCPU(true);
|
||||
return true;
|
||||
};
|
||||
|
|
@ -5940,6 +5942,8 @@ if (DEBUGGER) {
|
|||
/**
|
||||
* doInput(sPort)
|
||||
*
|
||||
* Simulate a 1-byte port input operation.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {string|undefined} sPort
|
||||
*/
|
||||
|
|
@ -5961,7 +5965,7 @@ if (DEBUGGER) {
|
|||
}
|
||||
var port = this.parseValue(sPort);
|
||||
if (port !== undefined) {
|
||||
var bIn = this.bus.checkPortInputNotify(port);
|
||||
var bIn = this.bus.checkPortInputNotify(port, 1);
|
||||
this.println(str.toHexWord(port) + ": " + str.toHexByte(bIn));
|
||||
}
|
||||
};
|
||||
|
|
@ -6341,6 +6345,8 @@ if (DEBUGGER) {
|
|||
/**
|
||||
* doOutput(sPort, sByte)
|
||||
*
|
||||
* Simulate a 1-byte port output operation.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {string|undefined} sPort
|
||||
* @param {string|undefined} sByte (string representation of 1 byte)
|
||||
|
|
@ -6364,33 +6370,11 @@ if (DEBUGGER) {
|
|||
var port = this.parseValue(sPort, "port #");
|
||||
var bOut = this.parseValue(sByte);
|
||||
if (port !== undefined && bOut !== undefined) {
|
||||
this.bus.checkPortOutputNotify(port, bOut);
|
||||
this.bus.checkPortOutputNotify(port, 1, bOut);
|
||||
this.println(str.toHexWord(port) + ": " + str.toHexByte(bOut));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* shiftArgs(asArgs)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {Array.<string>} [asArgs]
|
||||
*/
|
||||
Debugger.prototype.shiftArgs = function(asArgs)
|
||||
{
|
||||
if (asArgs && asArgs.length) {
|
||||
var s0 = asArgs[0];
|
||||
var ch0 = s0.charAt(0);
|
||||
for (var i = 1; i < s0.length; i++) {
|
||||
var ch = s0.charAt(i);
|
||||
if (ch0 == '?' || ch0 == 'r' || ch < 'a' || ch > 'z') {
|
||||
asArgs[0] = s0.substr(i);
|
||||
asArgs.unshift(s0.substr(0, i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* doRegisters(asArgs, fInstruction)
|
||||
*
|
||||
|
|
@ -7122,6 +7106,31 @@ if (DEBUGGER) {
|
|||
return a;
|
||||
};
|
||||
|
||||
/**
|
||||
* shiftArgs(asArgs)
|
||||
*
|
||||
* This is used with commands (eg, "b") that have suffixed variations (eg, "bp", "br", "bw");
|
||||
* we extract the suffix from the command and insert it into the argument array as a separate element.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {Array.<string>} [asArgs]
|
||||
*/
|
||||
Debugger.prototype.shiftArgs = function(asArgs)
|
||||
{
|
||||
if (asArgs && asArgs.length) {
|
||||
var s0 = asArgs[0];
|
||||
var ch0 = s0.charAt(0);
|
||||
for (var i = 1; i < s0.length; i++) {
|
||||
var ch = s0.charAt(i);
|
||||
if (ch0 == '?' || ch0 == 'r' || ch < 'a' || ch > 'z') {
|
||||
asArgs[0] = s0.substr(i);
|
||||
asArgs.unshift(s0.substr(0, i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* doCommand(sCmd, fQuiet)
|
||||
*
|
||||
|
|
@ -7155,6 +7164,9 @@ if (DEBUGGER) {
|
|||
var ch = sCmd.charAt(0);
|
||||
if (ch == '"' || ch == "'") return true;
|
||||
|
||||
/*
|
||||
* Zap the previous message buffer to ensure the new command's output is not tossed out as a repeat.
|
||||
*/
|
||||
this.sMessagePrev = null;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1726,7 +1726,7 @@ FDC.prototype.outFDCData = function(port, bOut, addrFrom)
|
|||
}
|
||||
if (DEBUG && this.messageEnabled()) {
|
||||
this.printMessage("unsupported FDC command: " + str.toHexByte(bCmd));
|
||||
this.dbg.stopCPU();
|
||||
if (MAXDEBUG) this.dbg.stopCPU();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1954,8 +1954,8 @@ FDC.prototype.doCmd = function()
|
|||
|
||||
default:
|
||||
if (DEBUG && this.messageEnabled()) {
|
||||
this.printMessage("FDC operation unsupported (command=" + str.toHexByte(bCmd) + ")");
|
||||
this.dbg.stopCPU();
|
||||
this.printMessage("unsupported FDC operation: " + str.toHexByte(bCmd));
|
||||
if (MAXDEBUG) this.dbg.stopCPU();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -513,6 +513,11 @@ HDC.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
bus.addPortInputTable(this, this.fATC? HDC.aATCPortInput : HDC.aXTCPortInput);
|
||||
bus.addPortOutputTable(this, this.fATC? HDC.aATCPortOutput : HDC.aXTCPortOutput);
|
||||
|
||||
if (this.fATC) {
|
||||
bus.addPortInputWidth(HDC.ATC.DATA.PORT, 2);
|
||||
bus.addPortOutputWidth(HDC.ATC.DATA.PORT, 2);
|
||||
}
|
||||
|
||||
cpu.addIntNotify(Interrupts.DISK, this.intBIOSDisk.bind(this));
|
||||
cpu.addIntNotify(Interrupts.ALT_DISK, this.intBIOSDiskette.bind(this));
|
||||
|
||||
|
|
@ -1371,14 +1376,14 @@ HDC.prototype.outXTCNoise = function(port, bOut, addrFrom)
|
|||
};
|
||||
|
||||
/**
|
||||
* inATCData(port, addrFrom)
|
||||
* inATCByte(port, addrFrom)
|
||||
*
|
||||
* @this {HDC}
|
||||
* @param {number} port (0x1F0)
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
* @return {number} simulated port value
|
||||
*/
|
||||
HDC.prototype.inATCData = function(port, addrFrom)
|
||||
HDC.prototype.inATCByte = function(port, addrFrom)
|
||||
{
|
||||
var bIn = -1;
|
||||
|
||||
|
|
@ -1429,7 +1434,7 @@ HDC.prototype.inATCData = function(port, addrFrom)
|
|||
this.regSecCnt = (this.regSecCnt - 1) & 0xff;
|
||||
/*
|
||||
* TODO: If the WITH_ECC bit is set in the READ_DATA command, then we need to support "stuffing" 4
|
||||
* additional bytes into the inATCData() stream. And we must first set DATA_REQ in the STATUS register.
|
||||
* additional bytes into the inATCByte() stream. And we must first set DATA_REQ in the STATUS register.
|
||||
*/
|
||||
if (this.drive.nBytes >= this.drive.cbSector) {
|
||||
/*
|
||||
|
|
@ -1454,7 +1459,7 @@ HDC.prototype.inATCData = function(port, addrFrom)
|
|||
*/
|
||||
hdc.regStatus = HDC.ATC.STATUS.ERROR;
|
||||
hdc.regError = HDC.ATC.ERROR.NO_CHS;
|
||||
if (DEBUG) hdc.printMessage("HDC.inATCData(): read failed");
|
||||
if (DEBUG) hdc.printMessage("HDC.inATCByte(): read failed");
|
||||
}
|
||||
}, false);
|
||||
} else {
|
||||
|
|
@ -1468,14 +1473,29 @@ HDC.prototype.inATCData = function(port, addrFrom)
|
|||
};
|
||||
|
||||
/**
|
||||
* outATCData(port, bOut, addrFrom)
|
||||
* inATCData(port, addrFrom)
|
||||
*
|
||||
* Wrapper around inATCByte() to treat this as a 16-bit port; see addPortInputWidth(HDC.ATC.DATA.PORT, 2).
|
||||
*
|
||||
* @this {HDC}
|
||||
* @param {number} port (0x1F0)
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||
* @return {number} simulated port data
|
||||
*/
|
||||
HDC.prototype.inATCData = function(port, addrFrom)
|
||||
{
|
||||
return this.inATCByte(port, addrFrom) | (this.inATCByte(port, addrFrom) << 8);
|
||||
};
|
||||
|
||||
/**
|
||||
* outATCByte(port, bOut, addrFrom)
|
||||
*
|
||||
* @this {HDC}
|
||||
* @param {number} port (0x1F0)
|
||||
* @param {number} bOut
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to write the specified port)
|
||||
*/
|
||||
HDC.prototype.outATCData = function(port, bOut, addrFrom)
|
||||
HDC.prototype.outATCByte = function(port, bOut, addrFrom)
|
||||
{
|
||||
if (this.drive) {
|
||||
if (this.drive.nBytes >= this.drive.cbSector) {
|
||||
|
|
@ -1487,7 +1507,7 @@ HDC.prototype.outATCData = function(port, bOut, addrFrom)
|
|||
this.regStatus = HDC.ATC.STATUS.ERROR;
|
||||
this.regError = HDC.ATC.ERROR.NO_CHS;
|
||||
if (DEBUG && this.messageEnabled()) {
|
||||
this.printMessage("HDC.outATCData(" + str.toHexByte(bOut) + "): write failed");
|
||||
this.printMessage("HDC.outATCByte(" + str.toHexByte(bOut) + "): write failed");
|
||||
}
|
||||
}
|
||||
else if (this.drive.ibSector == 1 || this.drive.ibSector == this.drive.cbSector) {
|
||||
|
|
@ -1519,7 +1539,7 @@ HDC.prototype.outATCData = function(port, bOut, addrFrom)
|
|||
* TODO: What to do about unexpected writes? The number of bytes has exceeded what the command specified.
|
||||
*/
|
||||
if (DEBUG && this.messageEnabled()) {
|
||||
this.printMessage("HDC.outATCData(" + str.toHexByte(bOut) + "): write exceeds count (" + this.drive.nBytes + ")");
|
||||
this.printMessage("HDC.outATCByte(" + str.toHexByte(bOut) + "): write exceeds count (" + this.drive.nBytes + ")");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1527,11 +1547,27 @@ HDC.prototype.outATCData = function(port, bOut, addrFrom)
|
|||
* TODO: What to do about unexpected writes? No command was specified.
|
||||
*/
|
||||
if (DEBUG && this.messageEnabled()) {
|
||||
this.printMessage("HDC.outATCData(" + str.toHexByte(bOut) + "): write without command");
|
||||
this.printMessage("HDC.outATCByte(" + str.toHexByte(bOut) + "): write without command");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* outATCData(port, data, addrFrom)
|
||||
*
|
||||
* Wrapper around outATCByte() to treat this as a 16-bit port; see addPortOutputWidth(HDC.ATC.DATA.PORT, 2)
|
||||
*
|
||||
* @this {HDC}
|
||||
* @param {number} port (0x1F0)
|
||||
* @param {number} data
|
||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to write the specified port)
|
||||
*/
|
||||
HDC.prototype.outATCData = function(port, data, addrFrom)
|
||||
{
|
||||
this.outATCByte(port, data & 0xff, addrFrom);
|
||||
this.outATCByte(port, (data >> 8) & 0xff, addrFrom);
|
||||
};
|
||||
|
||||
/**
|
||||
* inATCError(port, addrFrom)
|
||||
*
|
||||
|
|
@ -1839,7 +1875,7 @@ HDC.prototype.doATC = function()
|
|||
bCmd = (bCmd >= HDC.ATC.COMMAND.DIAGNOSE? bCmd : (bCmd & HDC.ATC.COMMAND.MASK));
|
||||
/*
|
||||
* Since the ATC doesn't use DMA, we must now set some additional Drive state for the benefit of any
|
||||
* follow-up I/O instructions. For example, any subsequent inATCData() and outATCData() calls need to
|
||||
* follow-up I/O instructions. For example, any subsequent inATCByte() and outATCByte() calls need to
|
||||
* know which drive to talk to ("this.drive"), to issue their own readData() and writeData() calls.
|
||||
*
|
||||
* The XTC didn't need this, because it used doDMARead(), doDMAWrite(), doDMAFormat() helper functions,
|
||||
|
|
@ -1873,14 +1909,14 @@ HDC.prototype.doATC = function()
|
|||
/*
|
||||
* We're using a call to readData() that disables auto-increment, so that once we've got the first
|
||||
* byte of the next sector, we can signal an interrupt without also consuming the first byte, allowing
|
||||
* inATCData() to begin with that byte.
|
||||
* inATCByte() to begin with that byte.
|
||||
*/
|
||||
hdc.regStatus = HDC.ATC.STATUS.BUSY;
|
||||
this.readData(drive, function onATCReadDataFirst(b, fAsync) {
|
||||
if (b >= 0 && hdc.chipset) {
|
||||
hdc.setATCIRR();
|
||||
/*
|
||||
* Bytes from the requested sector(s) will now be delivered via inATCData().
|
||||
* Bytes from the requested sector(s) will now be delivered via inATCByte().
|
||||
*
|
||||
* FYI, I'm taking a shotgun approach to these status bits: I need to clear STATUS.BUSY and
|
||||
* set STATUS.DATA_REQ, because otherwise CompaqDeskPro386 reads will fail, and I need to set
|
||||
|
|
@ -1952,7 +1988,7 @@ HDC.prototype.doATC = function()
|
|||
default:
|
||||
if (DEBUG && this.messageEnabled()) {
|
||||
this.printMessage("HDC.doATC(" + str.toHexByte(this.regCommand) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation"));
|
||||
if (bCmd >= 0) this.dbg.stopCPU();
|
||||
if (MAXDEBUG && bCmd >= 0) this.dbg.stopCPU();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -2155,7 +2191,7 @@ HDC.prototype.doXTC = function()
|
|||
this.beginResult(HDC.XTC.DATA.STATUS.ERROR | bDrive);
|
||||
if (DEBUG && this.messageEnabled()) {
|
||||
this.printMessage("HDC.doXTC(" + str.toHexByte(bCmdOrig) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation"));
|
||||
if (bCmd >= 0) this.dbg.stopCPU();
|
||||
if (MAXDEBUG && bCmd >= 0) this.dbg.stopCPU();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3022,14 +3022,15 @@ X86CPU.prototype.setPS = function(regPS, cpl)
|
|||
};
|
||||
|
||||
/**
|
||||
* checkIOPM(port, nPorts)
|
||||
* checkIOPM(port, nPorts, fInput)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} port (0x0000 to 0xffff)
|
||||
* @param {number} nPorts (1 to 4)
|
||||
* @param {boolean} [fInput] (true if input, false if output; output assumed if not specified)
|
||||
* @return {boolean} true if allowed, false if not
|
||||
*/
|
||||
X86CPU.prototype.checkIOPM = function(port, nPorts)
|
||||
X86CPU.prototype.checkIOPM = function(port, nPorts, fInput)
|
||||
{
|
||||
var bitsPorts = 0;
|
||||
if (I386 && (this.regCR0 & X86.CR0.MSW.PE) && (this.nCPL > this.nIOPL || (this.regPS & X86.PS.VM)) && this.segTSS.addrIOPM) {
|
||||
|
|
@ -3044,7 +3045,7 @@ X86CPU.prototype.checkIOPM = function(port, nPorts)
|
|||
}
|
||||
}
|
||||
if (bitsPorts) {
|
||||
if (this.messageEnabled(Messages.PORT)) this.printMessage("checkIOPM(" + str.toHexWord(port) + "," + nPorts + "): trapped", true, true);
|
||||
if (this.messageEnabled(Messages.PORT)) this.printMessage("checkIOPM(" + str.toHexWord(port) + "," + nPorts + "," + (fInput? "input" : "output") + "): trapped", true, true);
|
||||
X86.fnFault.call(this, X86.EXCEPTION.GP_FAULT, 0, false);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1510,8 +1510,8 @@ X86.opINSb = function INSb()
|
|||
|
||||
if (nReps--) {
|
||||
var port = this.regEDX & 0xffff;
|
||||
if (!this.checkIOPM(port, 1)) return;
|
||||
var b = this.bus.checkPortInputNotify(port, this.regLIP - nDelta - 1);
|
||||
if (!this.checkIOPM(port, 1, true)) return;
|
||||
var b = this.bus.checkPortInputNotify(port, 1, this.regLIP - nDelta - 1);
|
||||
this.setSOByte(this.segES, this.regEDI & maskAddr, b);
|
||||
if (this.opFlags & X86.OPFLAG.FAULT) return;
|
||||
if (BACKTRACK) this.backTrack.btiMem0 = this.backTrack.btiIO;
|
||||
|
|
@ -1559,20 +1559,12 @@ X86.opINSw = function INSw()
|
|||
if (this.opPrefixes & X86.OPFLAG.REPEAT) nCycles = 4;
|
||||
}
|
||||
if (nReps--) {
|
||||
var addrFrom = this.regLIP - nDelta - 1;
|
||||
var w = 0, shift = 0;
|
||||
var port = this.regEDX & 0xffff;
|
||||
if (!this.checkIOPM(port, 1)) return;
|
||||
for (var n = 0; n < this.sizeData; n++) {
|
||||
w |= this.bus.checkPortInputNotify(port, addrFrom) << shift;
|
||||
shift += 8;
|
||||
if (BACKTRACK) {
|
||||
if (!n) {
|
||||
this.backTrack.btiMem0 = this.backTrack.btiIO;
|
||||
} else if (n == 1) {
|
||||
this.backTrack.btiMem1 = this.backTrack.btiIO;
|
||||
}
|
||||
}
|
||||
if (!this.checkIOPM(port, this.sizeData, true)) return;
|
||||
var w = this.bus.checkPortInputNotify(port, this.sizeData, this.regLIP - nDelta - 1);
|
||||
if (BACKTRACK) {
|
||||
this.backTrack.btiMem0 = this.backTrack.btiIO;
|
||||
this.backTrack.btiMem1 = this.backTrack.btiIO;
|
||||
}
|
||||
this.setSOWord(this.segES, this.regEDI & maskAddr, w);
|
||||
if (this.opFlags & X86.OPFLAG.FAULT) return;
|
||||
|
|
@ -1620,11 +1612,11 @@ X86.opOUTSb = function OUTSb()
|
|||
}
|
||||
if (nReps--) {
|
||||
var port = this.regEDX & 0xffff;
|
||||
if (!this.checkIOPM(port, 1)) return;
|
||||
if (!this.checkIOPM(port, 1, false)) return;
|
||||
var b = this.getSOByte(this.segDS, this.regESI & maskAddr);
|
||||
if (this.opFlags & X86.OPFLAG.FAULT) return;
|
||||
if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiMem0;
|
||||
this.bus.checkPortOutputNotify(port, b, this.regLIP - nDelta - 1);
|
||||
this.bus.checkPortOutputNotify(port, 1, b, this.regLIP - nDelta - 1);
|
||||
this.regESI = (this.regESI & ~maskAddr) | ((this.regESI + ((this.regPS & X86.PS.DF)? -1 : 1)) & maskAddr);
|
||||
this.regECX = (this.regECX & ~maskAddr) | ((this.regECX - nDelta) & maskAddr);
|
||||
this.nStepCycles -= nCycles;
|
||||
|
|
@ -1670,20 +1662,13 @@ X86.opOUTSw = function OUTSw()
|
|||
if (nReps--) {
|
||||
var w = this.getSOWord(this.segDS, this.regESI & maskAddr);
|
||||
if (this.opFlags & X86.OPFLAG.FAULT) return;
|
||||
var addrFrom = this.regLIP - nDelta - 1, shift = 0;
|
||||
var port = this.regEDX & 0xffff;
|
||||
if (!this.checkIOPM(port, 1)) return;
|
||||
for (var n = 0; n < this.sizeData; n++) {
|
||||
if (BACKTRACK) {
|
||||
if (!n) {
|
||||
this.backTrack.btiIO = this.backTrack.btiMem0;
|
||||
} else if (n == 1) {
|
||||
this.backTrack.btiIO = this.backTrack.btiMem1;
|
||||
}
|
||||
}
|
||||
this.bus.checkPortOutputNotify(port, (w >> shift) & 0xff, addrFrom);
|
||||
shift += 8;
|
||||
if (!this.checkIOPM(port, this.sizeData, false)) return;
|
||||
if (BACKTRACK) {
|
||||
this.backTrack.btiIO = this.backTrack.btiMem0;
|
||||
this.backTrack.btiIO = this.backTrack.btiMem1;
|
||||
}
|
||||
this.bus.checkPortOutputNotify(port, this.sizeData, w, this.regLIP - nDelta - 1);
|
||||
this.regESI = (this.regESI & ~maskAddr) | ((this.regESI + ((this.regPS & X86.PS.DF)? -this.sizeData : this.sizeData)) & maskAddr);
|
||||
this.regECX = (this.regECX & ~maskAddr) | ((this.regECX - nDelta) & maskAddr);
|
||||
this.nStepCycles -= nCycles;
|
||||
|
|
@ -3771,8 +3756,8 @@ X86.opJCXZ = function JCXZ()
|
|||
X86.opINb = function INb()
|
||||
{
|
||||
var port = this.getIPByte();
|
||||
if (!this.checkIOPM(port, 1)) return;
|
||||
this.regEAX = (this.regEAX & ~0xff) | this.bus.checkPortInputNotify(port, this.regLIP - 2);
|
||||
if (!this.checkIOPM(port, 1, true)) return;
|
||||
this.regEAX = (this.regEAX & ~0xff) | (this.bus.checkPortInputNotify(port, 1, this.regLIP - 2) & 0xff);
|
||||
if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiIO;
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesInP;
|
||||
};
|
||||
|
|
@ -3785,16 +3770,12 @@ X86.opINb = function INb()
|
|||
X86.opINw = function INw()
|
||||
{
|
||||
var port = this.getIPByte();
|
||||
if (!this.checkIOPM(port, 2)) return;
|
||||
this.regEAX = this.bus.checkPortInputNotify(port, this.regLIP - 2);
|
||||
if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiIO;
|
||||
/*
|
||||
* TODO: Specs are clear that bits 8-15 of the port address for the FIRST byte of I/O will be zero, but
|
||||
* what about the SECOND byte? If the port is 0xff, will the SECOND byte of I/O use port 0x00 or 0x100?
|
||||
* Our code (below) assumes the latter. Mask (port + 1) with 0xff if it turns out the former is true.
|
||||
*/
|
||||
this.regEAX |= (this.bus.checkPortInputNotify(port + 1, this.regLIP - 2) << 8);
|
||||
if (BACKTRACK) this.backTrack.btiAH = this.backTrack.btiIO;
|
||||
if (!this.checkIOPM(port, this.sizeData, true)) return;
|
||||
this.regEAX = (this.regEAX & ~this.maskData) | (this.bus.checkPortInputNotify(port, this.sizeData, this.regLIP - 2) & this.maskData);
|
||||
if (BACKTRACK) {
|
||||
this.backTrack.btiAL = this.backTrack.btiIO;
|
||||
this.backTrack.btiAH = this.backTrack.btiIO;
|
||||
}
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesInP;
|
||||
};
|
||||
|
||||
|
|
@ -3806,8 +3787,8 @@ X86.opINw = function INw()
|
|||
X86.opOUTb = function OUTb()
|
||||
{
|
||||
var port = this.getIPByte();
|
||||
if (!this.checkIOPM(port, 1)) return;
|
||||
this.bus.checkPortOutputNotify(port, this.regEAX & 0xff, this.regLIP - 2);
|
||||
if (!this.checkIOPM(port, 1, false)) return;
|
||||
this.bus.checkPortOutputNotify(port, 1, this.regEAX & 0xff, this.regLIP - 2);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesOutP;
|
||||
};
|
||||
|
||||
|
|
@ -3819,14 +3800,8 @@ X86.opOUTb = function OUTb()
|
|||
X86.opOUTw = function OUTw()
|
||||
{
|
||||
var port = this.getIPByte();
|
||||
if (!this.checkIOPM(port, 2)) return;
|
||||
this.bus.checkPortOutputNotify(port, this.regEAX & 0xff, this.regLIP - 2);
|
||||
/*
|
||||
* TODO: Specs are clear that bits 8-15 of the port address for the FIRST byte of I/O will be zero, but
|
||||
* what about the SECOND byte? If the port is 0xff, will the SECOND byte of I/O use port 0x00 or 0x100?
|
||||
* Our code (below) assumes the latter. Mask (port + 1) with 0xff if it turns out the former is true.
|
||||
*/
|
||||
this.bus.checkPortOutputNotify(port + 1, (this.regEAX >> 8) & 0xff, this.regLIP - 2);
|
||||
if (!this.checkIOPM(port, this.sizeData, false)) return;
|
||||
this.bus.checkPortOutputNotify(port, this.sizeData, this.regEAX & this.maskData, this.regLIP - 2);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesOutP;
|
||||
};
|
||||
|
||||
|
|
@ -3891,8 +3866,8 @@ X86.opJMPs = function JMPs()
|
|||
X86.opINDXb = function INDXb()
|
||||
{
|
||||
var port = this.regEDX & 0xffff;
|
||||
if (!this.checkIOPM(port, 1)) return;
|
||||
this.regEAX = (this.regEAX & ~0xff) | this.bus.checkPortInputNotify(port, this.regLIP - 1);
|
||||
if (!this.checkIOPM(port, 1, true)) return;
|
||||
this.regEAX = (this.regEAX & ~0xff) | (this.bus.checkPortInputNotify(port, 1, this.regLIP - 1) & 0xff);
|
||||
if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiIO;
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesInDX;
|
||||
};
|
||||
|
|
@ -3905,11 +3880,12 @@ X86.opINDXb = function INDXb()
|
|||
X86.opINDXw = function INDXw()
|
||||
{
|
||||
var port = this.regEDX & 0xffff;
|
||||
if (!this.checkIOPM(port, 2)) return;
|
||||
this.regEAX = this.bus.checkPortInputNotify(port, this.regLIP - 1);
|
||||
if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiIO;
|
||||
this.regEAX |= (this.bus.checkPortInputNotify((port + 1) & 0xffff, this.regLIP - 1) << 8);
|
||||
if (BACKTRACK) this.backTrack.btiAH = this.backTrack.btiIO;
|
||||
if (!this.checkIOPM(port, this.sizeData, true)) return;
|
||||
this.regEAX = (this.regEAX & ~this.maskData) | (this.bus.checkPortInputNotify(port, this.sizeData, this.regLIP - 1) & this.maskData);
|
||||
if (BACKTRACK) {
|
||||
this.backTrack.btiAL = this.backTrack.btiIO;
|
||||
this.backTrack.btiAH = this.backTrack.btiIO;
|
||||
}
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesInDX;
|
||||
};
|
||||
|
||||
|
|
@ -3921,9 +3897,9 @@ X86.opINDXw = function INDXw()
|
|||
X86.opOUTDXb = function OUTDXb()
|
||||
{
|
||||
var port = this.regEDX & 0xffff;
|
||||
if (!this.checkIOPM(port, 1)) return;
|
||||
if (!this.checkIOPM(port, 1, false)) return;
|
||||
if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiAL;
|
||||
this.bus.checkPortOutputNotify(port, this.regEAX & 0xff, this.regLIP - 1);
|
||||
this.bus.checkPortOutputNotify(port, 1, this.regEAX & 0xff, this.regLIP - 1);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesOutDX;
|
||||
};
|
||||
|
||||
|
|
@ -3935,11 +3911,12 @@ X86.opOUTDXb = function OUTDXb()
|
|||
X86.opOUTDXw = function OUTDXw()
|
||||
{
|
||||
var port = this.regEDX & 0xffff;
|
||||
if (!this.checkIOPM(port, 2)) return;
|
||||
if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiAL;
|
||||
this.bus.checkPortOutputNotify(port, this.regEAX & 0xff, this.regLIP - 1);
|
||||
if (BACKTRACK) this.backTrack.btiIO = this.backTrack.btiAH;
|
||||
this.bus.checkPortOutputNotify((port + 1) & 0xffff, (this.regEAX >> 8) & 0xff, this.regLIP - 1);
|
||||
if (!this.checkIOPM(port, 2, false)) return;
|
||||
if (BACKTRACK) {
|
||||
this.backTrack.btiIO = this.backTrack.btiAL;
|
||||
this.backTrack.btiIO = this.backTrack.btiAH;
|
||||
}
|
||||
this.bus.checkPortOutputNotify(port, this.sizeData, this.regEAX & this.maskData, this.regLIP - 1);
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesOutDX;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue