v1.16.4: Time to roll out a few bug fixes and the groundwork for BACKTRACK support

This commit is contained in:
Jeff Parsons 2014-12-29 11:30:38 -08:00 committed by jeffpar
commit ad015c1ce6
32 changed files with 7380 additions and 1252 deletions

View file

@ -170,7 +170,7 @@ function Bus(parmsBus, cpu, dbg)
* obj: a reference to the source object (eg, ROM object, Sector object)
* off: the offset within the source object that this object refers to
* slot: the slot in abtObjects which this object currently occupies
* refs: the number of memory references, as recorded by setBackTrackIndex()
* refs: the number of memory references, as recorded by writeBackTrack()
*/
this.abtObjects = [];
this.cbtDeletions = 0;
@ -527,7 +527,7 @@ Bus.prototype.setWordDirect = function(addr, w)
/**
* addBackTrackObject(obj, bto, off)
*
* If bto is null, then we create bto (ie, an object that references obj and records off).
* If bto is null, then we create bto (ie, an object that wraps obj and records off).
*
* If bto is NOT null, then we verify that off is within bto's range; if not, then we must
* create a new bto and return that instead.
@ -541,7 +541,7 @@ Bus.prototype.setWordDirect = function(addr, w)
Bus.prototype.addBackTrackObject = function(obj, bto, off)
{
if (BACKTRACK && obj) {
if (!bto || off < bto.off || off >= bto.off + Bus.BACKTRACK.OFF_MAX) {
if (!bto || bto.obj != obj || off < bto.off || off >= bto.off + Bus.BACKTRACK.OFF_MAX) {
var slot;
var cbtObjects = this.abtObjects.length;
bto = {obj: obj, off: off, slot: 0, refs: 0};
@ -570,38 +570,74 @@ Bus.prototype.addBackTrackObject = function(obj, bto, off)
};
/**
* setBackTrackIndex(addr, bto, off)
* writeBackTrackObject(addr, bto, off)
*
* @this {Bus}
* @param {number} addr is a physical (non-segmented) address
* @param {Object|null} bto
* @param {number} off
*/
Bus.prototype.setBackTrackIndex = function(addr, bto, off)
Bus.prototype.writeBackTrackObject = function(addr, bto, off)
{
if (BACKTRACK && bto) {
this.assert(off - bto.off >= 0 && off - bto.off < Bus.BACKTRACK.OFF_MAX);
var bti = (bto.slot << Bus.BACKTRACK.SLOT_SHIFT) | (Bus.BACKTRACK.GEN_START << Bus.BACKTRACK.GEN_SHIFT) | (off - bto.off);
this.writeBackTrack(addr, bti);
}
};
/**
* readBackTrack(addr)
*
* @this {Bus}
* @param {number} addr is a physical (non-segmented) address
* @return {number}
*/
Bus.prototype.readBackTrack = function(addr)
{
if (BACKTRACK) {
return this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].readBackTrack(addr & this.blockLimit);
}
return 0;
};
/**
* writeBackTrack(addr, bti)
*
* @this {Bus}
* @param {number} addr is a physical (non-segmented) address
* @param {number} bti
*/
Bus.prototype.writeBackTrack = function(addr, bti)
{
if (BACKTRACK) {
var slot = bti >>> Bus.BACKTRACK.SLOT_SHIFT;
var btiPrev = this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].writeBackTrack(addr & this.blockLimit, bti);
if (btiPrev != bti) {
var slotPrev = btiPrev >>> Bus.BACKTRACK.SLOT_SHIFT;
if (slot != slotPrev) {
if (btiPrev) {
var slot = btiPrev >>> Bus.BACKTRACK.SLOT_SHIFT;
var btoPrev = this.abtObjects[slot];
var btoPrev = this.abtObjects[slotPrev];
if (!btoPrev) {
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages.WARN)) {
this.dbg.message("setBackTrackIndex(%" + str.toHex(addr) + "): previous index (" + str.toHex(btiPrev) + ") refers to empty slot");
this.dbg.message("writeBackTrack(%" + str.toHex(addr) + ',' + str.toHex(bti) + "): previous index (" + str.toHex(btiPrev) + ") refers to empty slot (" + slotPrev + ")");
}
}
else if (btoPrev.refs <= 0) {
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages.WARN)) {
this.dbg.message("setBackTrackIndex(%" + str.toHex(addr) + "): previous index (" + str.toHex(btiPrev) + ") refers object to with bad ref count (" + btoPrev.refs + ")");
this.dbg.message("writeBackTrack(%" + str.toHex(addr) + ',' + str.toHex(bti) + "): previous index (" + str.toHex(btiPrev) + ") refers to object with bad ref count (" + btoPrev.refs + ")");
}
} else if (!--btoPrev.refs) {
this.abtObjects[slot] = null;
this.abtObjects[slotPrev] = null;
this.cbtDeletions++;
}
}
bto.refs++;
if (bti) {
var bto = this.abtObjects[slot];
if (bto) {
this.assert(slot == bto.slot);
bto.refs++;
}
}
}
}
};

View file

@ -2813,7 +2813,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
chipset.println('loading ' + obj.file.sPath + '[' + obj.offFile + '] at %' + str.toHex(addrCur));
}
bto = chipset.bus.addBackTrackObject(obj, bto, off);
chipset.bus.setBackTrackIndex(addrCur, bto, off);
chipset.bus.writeBackTrackObject(addrCur, bto, off);
}
}
fAsyncRequest = fAsync;

View file

@ -1043,9 +1043,9 @@ if (DEBUGGER) {
0x13: {
0x00: "disk reset",
0x01: "get status",
0x02: "read drive DL (CH:DH:CL:AL) into ES:BX",
0x03: "write drive DL (CH:DH:CL:AL) from ES:BX",
0x04: "verify drive DL (CH:DH:CL:AL)",
0x02: "read drive DL (CH:DH:CL,AL) into ES:BX",
0x03: "write drive DL (CH:DH:CL,AL) from ES:BX",
0x04: "verify drive DL (CH:DH:CL,AL)",
0x05: "format drive DL using ES:BX",
0x08: "read drive DL parameters into ES:DI",
0x15: "get drive DL DASD type",

View file

@ -78,11 +78,11 @@ if (typeof module !== 'undefined') {
*
* N Number the number of data bytes written in a sector
*
* NCN New Cylinder Number the new cylinder number for a Seek operation
* NCN New Cylinder Number the new cylinder number for a SEEK operation
*
* ND Non-Data Mode indicates an operation in the non-data mode
*
* PCN Present Cylinder Number the cylinder number at the completion of a Sense Interrupt Status command
* PCN Present Cylinder Number the cylinder number at the completion of a SENSE INTERRUPT STATUS command
* (present position of the head)
*
* R Record the sector number to be read or written
@ -227,19 +227,20 @@ if (DEBUG) {
* are supported, hence bit 1 is always 0 (ie, FDC.REG_OUTPUT.DS2 and FDC.REG_OUTPUT.DS3 are not supported) and bits
* 6 and 7 are unused (FDC.REG_OUTPUT.MOTOR_D2 and FDC.REG_OUTPUT.MOTOR_D3 are not supported).
*/
FDC.REG_OUTPUT = {};
FDC.REG_OUTPUT.PORT = 0x3F2;
FDC.REG_OUTPUT.DS = 0x03; // drive select bits
FDC.REG_OUTPUT.DS0 = 0x00;
FDC.REG_OUTPUT.DS1 = 0x01;
FDC.REG_OUTPUT.DS2 = 0x02; // reserved on the MODEL_5170
FDC.REG_OUTPUT.DS3 = 0x03; // reserved on the MODEL_5170
FDC.REG_OUTPUT.ENABLE = 0x04; // clearing this bit resets the FDC
FDC.REG_OUTPUT.INT_ENABLE = 0x08; // enables both FDC and DMA (Channel 2) interrupt requests (IRQ 6)
FDC.REG_OUTPUT.MOTOR_D0 = 0x10;
FDC.REG_OUTPUT.MOTOR_D1 = 0x20;
FDC.REG_OUTPUT.MOTOR_D2 = 0x40; // reserved on the MODEL_5170
FDC.REG_OUTPUT.MOTOR_D3 = 0x80; // reserved on the MODEL_5170
FDC.REG_OUTPUT = {
PORT: 0x3F2,
DS: 0x03, // drive select bits
DS0: 0x00,
DS1: 0x01,
DS2: 0x02, // reserved on the MODEL_5170
DS3: 0x03, // reserved on the MODEL_5170
ENABLE: 0x04, // clearing this bit resets the FDC
INT_ENABLE: 0x08, // enables both FDC and DMA (Channel 2) interrupt requests (IRQ 6)
MOTOR_D0: 0x10,
MOTOR_D1: 0x20,
MOTOR_D2: 0x40, // reserved on the MODEL_5170
MOTOR_D3: 0x80 // reserved on the MODEL_5170
};
/*
* FDC Main Status Register (0x3F4, read-only)
@ -247,22 +248,96 @@ FDC.REG_OUTPUT.MOTOR_D3 = 0x80; // reserved on the MODEL_5170
* On the MODEL_5170 "PC AT Fixed Disk and Diskette Drive Adapter", bits 2 and 3 are reserved, since that adapter
* supported a maximum of two diskette drives.
*/
FDC.REG_STATUS = {};
FDC.REG_STATUS.PORT = 0x3F4;
FDC.REG_STATUS.BUSY_A = 0x01;
FDC.REG_STATUS.BUSY_B = 0x02;
FDC.REG_STATUS.BUSY_C = 0x04; // reserved on the MODEL_5170
FDC.REG_STATUS.BUSY_D = 0x08; // reserved on the MODEL_5170
FDC.REG_STATUS.BUSY = 0x10; // a read or write command is in progress
FDC.REG_STATUS.NON_DMA = 0x20; // FDC is in non-DMA mode
FDC.REG_STATUS.READ_DATA = 0x40; // transfer is from FDC Data Register to processor (if clear, then transfer is from processor to the FDC Data Register)
FDC.REG_STATUS.RQM = 0x80; // indicates FDC Data Register is ready to send or receive data to or from the processor (Request for Master)
FDC.REG_STATUS = {
PORT: 0x3F4,
BUSY_A: 0x01,
BUSY_B: 0x02,
BUSY_C: 0x04, // reserved on the MODEL_5170
BUSY_D: 0x08, // reserved on the MODEL_5170
BUSY: 0x10, // a read or write command is in progress
NON_DMA: 0x20, // FDC is in non-DMA mode
READ_DATA: 0x40, // transfer is from FDC Data Register to processor (if clear, then transfer is from processor to the FDC Data Register)
RQM: 0x80 // indicates FDC Data Register is ready to send or receive data to or from the processor (Request for Master)
};
/*
* FDC Data Register (0x3F5, read-write)
*/
FDC.REG_DATA = {};
FDC.REG_DATA.PORT = 0x3F5;
FDC.REG_DATA = {
PORT: 0x3F5,
/*
* FDC Commands
*
* NOTE: FDC command bytes need to be masked with FDC.REG_DATA.CMD.MASK before comparing to the values below, since a
* number of commands use the following additional bits as follows:
*
* SK (0x20): Skip Deleted Data Address Mark
* MF (0x40): Modified Frequency Modulation (as opposed to FM or Frequency Modulation)
* MT (0x80): multi-track operation (ie, data processed under both head 0 and head 1)
*
* We don't support MT (Multi-Track) operations at this time, and the MF and SK designations cannot be supported as long
* as our diskette images contain only the original data bytes without any formatting information.
*/
CMD: {
READ_TRACK: 0x02,
SPECIFY: 0x03,
SENSE_DRIVE: 0x04,
WRITE_DATA: 0x05,
READ_DATA: 0x06,
RECALIBRATE: 0x07,
SENSE_INT: 0x08, // this command is used to clear the FDC interrupt following the clearing/setting of FDC.REG_OUTPUT.ENABLE
WRITE_DEL_DATA: 0x09,
READ_ID: 0x0A,
READ_DEL_DATA: 0x0C,
FORMAT_TRACK: 0x0D,
SEEK: 0x0F,
SCAN_EQUAL: 0x11,
SCAN_LO_EQUAL: 0x19,
SCAN_HI_EQUAL: 0x1D,
MASK: 0x1F,
SK: 0x20, // SK (Skip Deleted Data Address Mark)
MF: 0x40, // MF (Modified Frequency Modulation)
MT: 0x80 // MT (Multi-Track; ie, data under both heads will be processed)
},
/*
* FDC status/error results, generally assigned according to the corresponding ST0, ST1, ST2 or ST3 status bit.
*
* TODO: Determine when EQUIP_CHECK is *really* set; also, "77 step pulses" sounds suspiciously like a typo.
*/
RES: {
NONE: 0x00000000, // ST0 (IC): Normal termination of command (NT)
NOT_READY: 0x00000008, // ST0 (NR): When the FDD is in the not-ready state and a read or write command is issued, this flag is set; if a read or write command is issued to side 1 of a single sided drive, then this flag is set
EQUIP_CHECK: 0x00000010, // ST0 (EC): If a fault signal is received from the FDD, or if the track 0 signal fails to occur after 77 step pulses (recalibrate command), then this flag is set
SEEK_END: 0x00000020, // ST0 (SE): When the FDC completes the Seek command, this flag is set to 1 (high)
INCOMPLETE: 0x00000040, // ST0 (IC): Abnormal termination of command (AT); execution of command was started, but was not successfully completed
RESET: 0x000000C0, // ST0 (IC): Abnormal termination because during command execution the ready signal from the drive changed state
INVALID: 0x00000080, // ST0 (IC): Invalid command issue (IC); command which was issued was never started
ST0: 0x000000FF,
NO_ID_MARK: 0x00000100, // ST1 (MA): If the FDC cannot detect the ID Address Mark, this flag is set; at the same time, the MD (Missing Address Mark in Data Field) of Status Register 2 is set
NOT_WRITABLE: 0x00000200, // ST1 (NW): During Execution of a Write Data, Write Deleted Data, or Format a Cylinder command, if the FDC detects a write protect signal from the FDD, then this flag is set
NO_DATA: 0x00000400, // ST1 (ND): FDC cannot find specified sector (or specified ID if READ_ID command)
DMA_OVERRUN: 0x00001000, // ST1 (OR): If the FDC is not serviced by the main systems during data transfers within a certain time interval, this flag is set
CRC_ERROR: 0x00002000, // ST1 (DE): When the FDC detects a CRC error in either the ID field or the data field, this flag is set
END_OF_CYL: 0x00008000, // ST1 (EN): When the FDC tries to access a sector beyond the final sector of a cylinder, this flag is set
ST1: 0x0000FF00,
NO_DATA_MARK: 0x00010000, // ST2 (MD): When data is read from the medium, if the FDC cannot find a Data Address Mark or Deleted Data Address Mark, then this flag is set
BAD_CYL: 0x00020000, // ST2 (BC): This bit is related to the ND bit, and when the contents of C on the medium are different from that stored in the ID Register, and the content of C is FF, then this flag is set
SCAN_FAILED: 0x00040000, // ST2 (SN): During execution of the Scan command, if the FDC cannot find a sector on the cylinder which meets the condition, then this flag is set
SCAN_EQUAL: 0x00080000, // ST2 (SH): During execution of the Scan command, if the condition of "equal" is satisfied, this flag is set
WRONG_CYL: 0x00100000, // ST2 (WC): This bit is related to the ND bit, and when the contents of C on the medium are different from that stored in the ID Register, this flag is set
DATA_FIELD: 0x00200000, // ST2 (DD): If the FDC detects a CRC error in the data, then this flag is set
STRL_MARK: 0x00400000, // ST2 (CM): During execution of the Read Data or Scan command, if the FDC encounters a sector which contains a Deleted Data Address Mark, this flag is set
ST2: 0x00FF0000,
DRIVE: 0x03000000, // ST3 (Ux): Status of the "Drive Select" signals from the diskette drive
HEAD: 0x04000000, // ST3 (HD): Status of the "Side Select" signal from the diskette drive
TWOSIDE: 0x08000000, // ST3 (TS): Status of the "Two Side" signal from the diskette drive
TRACK0: 0x10000000, // ST3 (T0): Status of the "Track 0" signal from the diskette drive
READY: 0x20000000, // ST3 (RY): Status of the "Ready" signal from the diskette drive
WRITEPROT: 0x40000000, // ST3 (WP): Status of the "Write Protect" signal from the diskette drive
FAULT: 0x80000000, // ST3 (FT): Status of the "Fault" signal from the diskette drive
ST3: 0xFF000000
}
};
/*
* FDC "Fixed Disk" Register (0x3F6, write-only)
@ -278,100 +353,30 @@ FDC.REG_DATA.PORT = 0x3F5;
* hard disk drive, so this port must be shared with the HDC; bits 0-6 are valid for 50 microseconds after a write to
* the Drive Head Register.
*/
FDC.REG_INPUT = {};
FDC.REG_INPUT.PORT = 0x3F7;
FDC.REG_INPUT.DS0 = 0x01; // Drive Select 0
FDC.REG_INPUT.DS1 = 0x02; // Drive Select 1
FDC.REG_INPUT.HS0 = 0x04; // Head Select 0
FDC.REG_INPUT.HS1 = 0x08; // Head Select 1
FDC.REG_INPUT.HS2 = 0x10; // Head Select 2
FDC.REG_INPUT.HS3 = 0x20; // Head Select 3
FDC.REG_INPUT.WRITE_GATE = 0x40; // Write Gate
FDC.REG_INPUT.DISK_CHANGE = 0x80; // Diskette Change
FDC.REG_INPUT = {
PORT: 0x3F7,
DS0: 0x01, // Drive Select 0
DS1: 0x02, // Drive Select 1
HS0: 0x04, // Head Select 0
HS1: 0x08, // Head Select 1
HS2: 0x10, // Head Select 2
HS3: 0x20, // Head Select 3
WRITE_GATE: 0x40, // Write Gate
DISK_CHANGE:0x80 // Diskette Change
};
/*
* FDC Diskette Control Register (0x3F7, write-only, MODEL_5170 only)
*
* Only bits 0-1 are used; bits 2-7 are reserved.
*/
FDC.REG_CONTROL = {};
FDC.REG_CONTROL.PORT = 0x3F7;
FDC.REG_CONTROL.RATE500K = 0x00; // 500,000 bps
FDC.REG_CONTROL.RATE300K = 0x02; // 300,000 bps
FDC.REG_CONTROL.RATE250K = 0x01; // 250,000 bps
FDC.REG_CONTROL.RATEUNUSED = 0x03;
/*
* FDC Commands
*
* NOTE: FDC command bytes need to be masked with FDC.REG_DATA.CMD.MASK before comparing to the values below, since a
* number of commands use the following additional bits as follows:
*
* SK (0x20): Skip Deleted Data Address Mark
* MF (0x40): Modified Frequency Modulation (as opposed to FM or Frequency Modulation)
* MT (0x80): multi-track operation (ie, data processed under both head 0 and head 1)
*
* We don't support MT (Multi-Track) operations at this time, and the MF and SK designations cannot be supported as long
* as our diskette images contain only the original data bytes without any formatting information.
*/
FDC.REG_DATA.CMD = {};
FDC.REG_DATA.CMD.READ_TRACK = 0x02;
FDC.REG_DATA.CMD.SPECIFY = 0x03;
FDC.REG_DATA.CMD.SENSE_DRIVE = 0x04;
FDC.REG_DATA.CMD.WRITE_DATA = 0x05;
FDC.REG_DATA.CMD.READ_DATA = 0x06;
FDC.REG_DATA.CMD.RECALIBRATE = 0x07;
FDC.REG_DATA.CMD.SENSE_INT = 0x08; // this command is used to clear the FDC interrupt following the clearing/setting of FDC.REG_OUTPUT.ENABLE
FDC.REG_DATA.CMD.WRITE_DEL_DATA = 0x09;
FDC.REG_DATA.CMD.READ_ID = 0x0A;
FDC.REG_DATA.CMD.READ_DEL_DATA = 0x0C;
FDC.REG_DATA.CMD.FORMAT_TRACK = 0x0D;
FDC.REG_DATA.CMD.SEEK = 0x0F;
FDC.REG_DATA.CMD.SCAN_EQUAL = 0x11;
FDC.REG_DATA.CMD.SCAN_LO_EQUAL = 0x19;
FDC.REG_DATA.CMD.SCAN_HI_EQUAL = 0x1D;
FDC.REG_DATA.CMD.MASK = 0x1F;
FDC.REG_DATA.CMD.SK = 0x20; // SK (Skip Deleted Data Address Mark)
FDC.REG_DATA.CMD.MF = 0x40; // MF (Modified Frequency Modulation)
FDC.REG_DATA.CMD.MT = 0x80; // MT (Multi-Track; ie, data under both heads will be processed)
/*
* FDC status/error results, generally assigned according to the corresponding ST0, ST1, ST2 or ST3 status bit.
*
* TODO: Determine when EQUIP_CHECK is *really* set; also, "77 step pulses" sounds suspiciously like a typo.
*/
FDC.REG_DATA.RES = {};
FDC.REG_DATA.RES.NONE = 0x00000000; // ST0 (IC): Normal termination of command (NT)
FDC.REG_DATA.RES.NOT_READY = 0x00000008; // ST0 (NR): When the FDD is in the not-ready state and a read or write command is issued, this flag is set; if a read or write command is issued to side 1 of a single sided drive, then this flag is set
FDC.REG_DATA.RES.EQUIP_CHECK = 0x00000010; // ST0 (EC): If a fault signal is received from the FDD, or if the track 0 signal fails to occur after 77 step pulses (recalibrate command), then this flag is set
FDC.REG_DATA.RES.SEEK_END = 0x00000020; // ST0 (SE): When the FDC completes the Seek command, this flag is set to 1 (high)
FDC.REG_DATA.RES.INCOMPLETE = 0x00000040; // ST0 (IC): Abnormal termination of command (AT); execution of command was started, but was not successfully completed
FDC.REG_DATA.RES.RESET = 0x000000C0; // ST0 (IC): Abnormal termination because during command execution the ready signal from the drive changed state
FDC.REG_DATA.RES.INVALID = 0x00000080; // ST0 (IC): Invalid command issue (IC); command which was issued was never started
FDC.REG_DATA.RES.ST0 = 0x000000FF;
FDC.REG_DATA.RES.NO_ID_MARK = 0x00000100; // ST1 (MA): If the FDC cannot detect the ID Address Mark, this flag is set; at the same time, the MD (Missing Address Mark in Data Field) of Status Register 2 is set
FDC.REG_DATA.RES.NOT_WRITABLE = 0x00000200; // ST1 (NW): During Execution of a Write Data, Write Deleted Data, or Format a Cylinder command, if the FDC detects a write protect signal from the FDD, then this flag is set
FDC.REG_DATA.RES.NO_DATA = 0x00000400; // ST1 (ND): FDC cannot find specified sector (or specified ID if READ_ID command)
FDC.REG_DATA.RES.DMA_OVERRUN = 0x00001000; // ST1 (OR): If the FDC is not serviced by the main systems during data transfers within a certain time interval, this flag is set
FDC.REG_DATA.RES.CRC_ERROR = 0x00002000; // ST1 (DE): When the FDC detects a CRC error in either the ID field or the data field, this flag is set
FDC.REG_DATA.RES.END_OF_CYL = 0x00008000; // ST1 (EN): When the FDC tries to access a sector beyond the final sector of a cylinder, this flag is set
FDC.REG_DATA.RES.ST1 = 0x0000FF00;
FDC.REG_DATA.RES.NO_DATA_MARK = 0x00010000; // ST2 (MD): When data is read from the medium, if the FDC cannot find a Data Address Mark or Deleted Data Address Mark, then this flag is set
FDC.REG_DATA.RES.BAD_CYL = 0x00020000; // ST2 (BC): This bit is related to the ND bit, and when the contents of C on the medium are different from that stored in the ID Register, and the content of C is FF, then this flag is set
FDC.REG_DATA.RES.SCAN_FAILED = 0x00040000; // ST2 (SN): During execution of the Scan command, if the FDC cannot find a sector on the cylinder which meets the condition, then this flag is set
FDC.REG_DATA.RES.SCAN_EQUAL = 0x00080000; // ST2 (SH): During execution of the Scan command, if the condition of "equal" is satisfied, this flag is set
FDC.REG_DATA.RES.WRONG_CYL = 0x00100000; // ST2 (WC): This bit is related to the ND bit, and when the contents of C on the medium are different from that stored in the ID Register, this flag is set
FDC.REG_DATA.RES.DATA_FIELD = 0x00200000; // ST2 (DD): If the FDC detects a CRC error in the data, then this flag is set
FDC.REG_DATA.RES.STRL_MARK = 0x00400000; // ST2 (CM): During execution of the Read Data or Scan command, if the FDC encounters a sector which contains a Deleted Data Address Mark, this flag is set
FDC.REG_DATA.RES.ST2 = 0x00FF0000;
FDC.REG_DATA.RES.DRIVE = 0x03000000; // ST3 (Ux): Status of the "Drive Select" signals from the diskette drive
FDC.REG_DATA.RES.HEAD = 0x04000000; // ST3 (HD): Status of the "Side Select" signal from the diskette drive
FDC.REG_DATA.RES.TWOSIDE = 0x08000000; // ST3 (TS): Status of the "Two Side" signal from the diskette drive
FDC.REG_DATA.RES.TRACK0 = 0x10000000; // ST3 (T0): Status of the "Track 0" signal from the diskette drive
FDC.REG_DATA.RES.READY = 0x20000000; // ST3 (RY): Status of the "Ready" signal from the diskette drive
FDC.REG_DATA.RES.WRITEPROT = 0x40000000; // ST3 (WP): Status of the "Write Protect" signal from the diskette drive
FDC.REG_DATA.RES.FAULT = 0x80000000; // ST3 (FT): Status of the "Fault" signal from the diskette drive
FDC.REG_DATA.RES.ST3 = 0xFF000000;
FDC.REG_CONTROL = {
PORT: 0x3F7,
RATE500K: 0x00, // 500,000 bps
RATE300K: 0x02, // 300,000 bps
RATE250K: 0x01, // 250,000 bps
RATEUNUSED: 0x03
};
/*
* FDC Command Sequences
@ -894,7 +899,7 @@ FDC.prototype.initDrive = function(drive, iDrive, data)
* but I'm using per-drive variables so that the FDC component can be a good client to both the CPU and other components.
*
* COMPATIBILITY ALERT: The MODEL_5170 BIOS ("DSKETTE_SETUP") attempts to discern the drive type (double-density vs.
* high-capacity) by "slapping" the heads around. Literally (it uses a constant named "TRK_SLAP" equal to 48).
* high-capacity) by "slapping" the heads around -- "litrally" (it uses a constant named "TRK_SLAP" equal to 48).
* After seeking to "TRK_SLAP", the BIOS performs a series of seeks, looking for the precise point where the heads
* return to track 0.
*
@ -2206,7 +2211,7 @@ FDC.prototype.doRead = function(drive)
if (drive.disk) {
if (DEBUG && this.messageEnabled()) {
this.messagePrint("FDC.doRead(CHS=" + drive.bCylinder + ':' + drive.bHead + ':' + drive.bSector + ",LBA=" + (drive.bCylinder * (drive.disk.nHeads * drive.disk.nSectors) + drive.bHead * drive.disk.nSectors + drive.bSector-1) + ')');
this.messagePrint("FDC.doRead(CHS=" + drive.bCylinder + ':' + drive.bHead + ':' + drive.bSector + ",PBA=" + (drive.bCylinder * (drive.disk.nHeads * drive.disk.nSectors) + drive.bHead * drive.disk.nSectors + drive.bSector-1) + ')');
}
drive.sector = null;
drive.resCode = FDC.REG_DATA.RES.NONE;
@ -2229,7 +2234,7 @@ FDC.prototype.doWrite = function(drive)
if (drive.disk) {
if (DEBUG && this.messageEnabled()) {
this.messagePrint("FDC.doWrite(CHS=" + drive.bCylinder + ':' + drive.bHead + ':' + drive.bSector + ",LBA=" + (drive.bCylinder * (drive.disk.nHeads * drive.disk.nSectors) + drive.bHead * drive.disk.nSectors + drive.bSector-1) + ')');
this.messagePrint("FDC.doWrite(CHS=" + drive.bCylinder + ':' + drive.bHead + ':' + drive.bSector + ",PBA=" + (drive.bCylinder * (drive.disk.nHeads * drive.disk.nSectors) + drive.bHead * drive.disk.nSectors + drive.bSector-1) + ')');
}
if (drive.disk.fWriteProtected) {
drive.resCode = FDC.REG_DATA.RES.NOT_WRITABLE | FDC.REG_DATA.RES.INCOMPLETE;

View file

@ -286,39 +286,120 @@ HDC.ATC = {
/*
* XTC (XT Controller) Registers
*/
/*
* XTC Data Register (0x320, read-write)
*
* Writes to this register are discussed below; see HDC Commands.
*
* Reads from this register after a command has been executed retrieve a "status byte",
* which must NOT be confused with the Status Register (see below). This data "status byte"
* contains only two bits of interest: XTC_DATA.STATUS_ERROR and XTC_DATA.STATUS_UNIT.
*/
HDC.XTC = {};
HDC.XTC.DATA = {};
HDC.XTC.DATA.PORT = 0x320; // port address
HDC.XTC.DATA.STATUS_OK = 0x00; // no error
HDC.XTC.DATA.STATUS_ERROR = 0x02; // error occurred during command execution
HDC.XTC.DATA.STATUS_UNIT = 0x20; // logical unit number of the drive
/*
* XTC Status Register (0x321, read-only)
*
* WARNING: The IBM Technical Reference Manual *badly* confuses the XTC_DATA "status byte" (above)
* that the controller sends following an HDC.XTC.DATA.CMD operation with the Status Register (below).
* In fact, it's so badly confused that it completely fails to document any of the Status Register
* bits below; I'm forced to guess at their meanings from the HDC BIOS listing.
*/
HDC.XTC.STATUS = {};
HDC.XTC.STATUS.PORT = 0x321; // port address
HDC.XTC.STATUS.NONE = 0x00;
HDC.XTC.STATUS.REQ = 0x01; // HDC BIOS: request bit
HDC.XTC.STATUS.IOMODE = 0x02; // HDC BIOS: mode bit (GUESS: set whenever XTC_DATA contains a response?)
HDC.XTC.STATUS.BUS = 0x04; // HDC BIOS: command/data bit (GUESS: set whenever XTC_DATA ready for request?)
HDC.XTC.STATUS.BUSY = 0x08; // HDC BIOS: busy bit
HDC.XTC.STATUS.INTERRUPT = 0x20; // HDC BIOS: interrupt bit
HDC.XTC = {
/*
* XTC Data Register (0x320, read-write)
*
* Writes to this register are discussed below; see HDC Commands.
*
* Reads from this register after a command has been executed retrieve a "status byte",
* which must NOT be confused with the Status Register (see below). This data "status byte"
* contains only two bits of interest: XTC.DATA.STATUS.ERROR and XTC.DATA.STATUS.UNIT.
*/
DATA: {
PORT: 0x320, // port address
STATUS: {
OK: 0x00, // no error
ERROR: 0x02, // error occurred during command execution
UNIT: 0x20 // logical unit number of the drive
},
/*
* XTC Commands, as issued to XTC_DATA
*
* Commands are multi-byte sequences sent to XTC_DATA, starting with a XTC_DATA.CMD byte,
* and followed by 5 more bytes, for a total of 6 bytes, which collectively are called a
* Device Control Block (DCB). Not all commands use all 6 bytes, but all 6 bytes must be present;
* unused bytes are simply ignored.
*
* XTC_DATA.CMD (3-bit class code, 5-bit operation code)
* XTC_DATA.HEAD (1-bit drive number, 5-bit head number)
* XTC_DATA.CLSEC (upper bits of 10-bit cylinder number, 6-bit sector number)
* XTC_DATA.CH (lower bits of 10-bit cylinder number)
* XTC_DATA.COUNT (8-bit interleave or block count)
* XTC_DATA.CTRL (8-bit control field)
*
* One command, HDC.XTC.DATA.CMD.INIT_DRIVE, must include 8 additional bytes following the DCB:
*
* maximum number of cylinders (high)
* maximum number of cylinders (low)
* maximum number of heads
* start reduced write current cylinder (high)
* start reduced write current cylinder (low)
* start write precompensation cylinder (high)
* start write precompensation cylinder (low)
* maximum ECC data burst length
*
* Note that the 3 word values above are stored in "big-endian" format (high byte followed by low byte),
* rather than the more typical "little-endian" format (low byte followed by high byte).
*/
CMD: {
TEST_READY: 0x00, // Test Drive Ready
RECALIBRATE: 0x01, // Recalibrate
REQUEST_SENSE: 0x03, // Request Sense Status
FORMAT_DRIVE: 0x04, // Format Drive
READ_VERF: 0x05, // Read Verify
FORMAT_TRK: 0x06, // Format Track
FORMAT_BAD: 0x07, // Format Bad Track
READ_DATA: 0x08, // Read
WRITE_DATA: 0x0A, // Write
SEEK: 0x0B, // Seek
INIT_DRIVE: 0x0C, // Initialize Drive Characteristics
READ_ECC_BURST: 0x0D, // Read ECC Burst Error Length
READ_BUFFER: 0x0E, // Read Data from Sector Buffer
WRITE_BUFFER: 0x0F, // Write Data to Sector Buffer
RAM_DIAGNOSTIC: 0xE0, // RAM Diagnostic
DRV_DIAGNOSTIC: 0xE3, // HDC BIOS: CHK_DRV_CMD
CTL_DIAGNOSTIC: 0xE4, // HDC BIOS: CNTLR_DIAG_CMD
READ_LONG: 0xE5, // HDC BIOS: RD_LONG_CMD
WRITE_LONG: 0xE6 // HDC BIOS: WR_LONG_CMD
},
ERR: {
/*
* HDC error conditions, as returned in byte 0 of the (4) bytes returned by the Request Sense Status command
*/
NONE: 0x00,
NO_INDEX: 0x01, // no index signal detected
SEEK_INCOMPLETE:0x02, // no seek-complete signal
WRITE_FAULT: 0x03,
NOT_READY: 0x04, // after the controller selected the drive, the drive did not respond with a ready signal
NO_TRACK: 0x06, // after stepping the max number of cylinders, the controller did not receive the track 00 signal from the drive
STILL_SEEKING: 0x08,
ECC_ID_ERROR: 0x10,
ECC_DATA_ERROR: 0x11,
NO_ADDR_MARK: 0x12,
NO_SECTOR: 0x14,
BAD_SEEK: 0x15, // seek error: the cylinder and/or head address did not compare with the expected target address
ECC_CORRECTABLE:0x18, // correctable data error
BAD_TRACK: 0x19,
BAD_CMD: 0x20,
BAD_DISK_ADDR: 0x21,
RAM: 0x30,
CHECKSUM: 0x31,
POLYNOMIAL: 0x32,
MASK: 0x3F
},
SENSE: {
ADDR_VALID: 0x80
}
},
/*
* XTC Status Register (0x321, read-only)
*
* WARNING: The IBM Technical Reference Manual *badly* confuses the XTC_DATA "status byte" (above)
* that the controller sends following an HDC.XTC.DATA.CMD operation with the Status Register (below).
* In fact, it's so badly confused that it completely fails to document any of the Status Register
* bits below; I'm forced to guess at their meanings from the HDC BIOS listing.
*/
STATUS: {
PORT: 0x321, // port address
NONE: 0x00,
REQ: 0x01, // HDC BIOS: request bit
IOMODE: 0x02, // HDC BIOS: mode bit (GUESS: set whenever XTC_DATA contains a response?)
BUS: 0x04, // HDC BIOS: command/data bit (GUESS: set whenever XTC_DATA ready for request?)
BUSY: 0x08, // HDC BIOS: busy bit
INTERRUPT: 0x20 // HDC BIOS: interrupt bit
}
};
/*
* XTC Config Register (0x322, read-only)
@ -332,87 +413,6 @@ HDC.XTC.STATUS.INTERRUPT = 0x20; // HDC BIOS: interrupt bit
* OFF, OFF Drive Type 3 (306 cylinders, 4 heads)
*/
/*
* XTC Commands, as issued to XTC_DATA
*
* Commands are multi-byte sequences sent to XTC_DATA, starting with a XTC_DATA.CMD byte,
* and followed by 5 more bytes, for a total of 6 bytes, which collectively are called a
* Device Control Block (DCB). Not all commands use all 6 bytes, but all 6 bytes must be present;
* unused bytes are simply ignored.
*
* XTC_DATA.CMD (3-bit class code, 5-bit operation code)
* XTC_DATA.HEAD (1-bit drive number, 5-bit head number)
* XTC_DATA.CLSEC (upper bits of 10-bit cylinder number, 6-bit sector number)
* XTC_DATA.CH (lower bits of 10-bit cylinder number)
* XTC_DATA.COUNT (8-bit interleave or block count)
* XTC_DATA.CTRL (8-bit control field)
*
* One command, HDC.XTC.DATA.CMD.INIT_DRIVE, must include 8 additional bytes following the DCB:
*
* maximum number of cylinders (high)
* maximum number of cylinders (low)
* maximum number of heads
* start reduced write current cylinder (high)
* start reduced write current cylinder (low)
* start write precompensation cylinder (high)
* start write precompensation cylinder (low)
* maximum ECC data burst length
*
* Note that the 3 word values above are stored in "big-endian" format (high byte followed by low byte),
* rather than the more typical "little-endian" format (low byte followed by high byte).
*/
HDC.XTC.DATA.CMD = {
TEST_READY: 0x00, // Test Drive Ready
RECALIBRATE: 0x01, // Recalibrate
REQUEST_SENSE: 0x03, // Request Sense Status
FORMAT_DRIVE: 0x04, // Format Drive
READ_VERF: 0x05, // Read Verify
FORMAT_TRK: 0x06, // Format Track
FORMAT_BAD: 0x07, // Format Bad Track
READ_DATA: 0x08, // Read
WRITE_DATA: 0x0A, // Write
SEEK: 0x0B, // Seek
INIT_DRIVE: 0x0C, // Initialize Drive Characteristics
READ_ECC_BURST: 0x0D, // Read ECC Burst Error Length
READ_BUFFER: 0x0E, // Read Data from Sector Buffer
WRITE_BUFFER: 0x0F, // Write Data to Sector Buffer
RAM_DIAGNOSTIC: 0xE0, // RAM Diagnostic
DRV_DIAGNOSTIC: 0xE3, // HDC BIOS: CHK_DRV_CMD
CTL_DIAGNOSTIC: 0xE4, // HDC BIOS: CNTLR_DIAG_CMD
READ_LONG: 0xE5, // HDC BIOS: RD_LONG_CMD
WRITE_LONG: 0xE6 // HDC BIOS: WR_LONG_CMD
};
/*
* HDC error conditions, as returned in byte 0 of the (4) bytes returned by the Request Sense Status command
*/
HDC.XTC.DATA.ERR = {
NONE: 0x00,
NO_INDEX: 0x01, // no index signal detected
SEEK_INCOMPLETE:0x02, // no seek-complete signal
WRITE_FAULT: 0x03,
NOT_READY: 0x04, // after the controller selected the drive, the drive did not respond with a ready signal
NO_TRACK: 0x06, // after stepping the max number of cylinders, the controller did not receive the track 00 signal from the drive
STILL_SEEKING: 0x08,
ECC_ID_ERROR: 0x10,
ECC_DATA_ERROR: 0x11,
NO_ADDR_MARK: 0x12,
NO_SECTOR: 0x14,
BAD_SEEK: 0x15, // seek error: the cylinder and/or head address did not compare with the expected target address
ECC_CORRECTABLE:0x18, // correctable data error
BAD_TRACK: 0x19,
BAD_CMD: 0x20,
BAD_DISK_ADDR: 0x21,
RAM: 0x30,
CHECKSUM: 0x31,
POLYNOMIAL: 0x32,
MASK: 0x3F
};
HDC.XTC.DATA.SENSE = {
ADDR_VALID: 0x80
};
/*
* HDC Command Sequences
*
@ -2021,12 +2021,12 @@ HDC.prototype.doXTC = function()
/*
* Although not terribly clear from IBM's "Fixed Disk Adapter" documentation, a data "status byte"
* also follows the 4 "sense bytes". Interestingly, The HDC BIOS checks that data status byte for
* XTC.DATA.STATUS_ERROR, but I have to wonder if it would have ever been set for this command....
* XTC.DATA.STATUS.ERROR, but I have to wonder if it would have ever been set for this command....
*
* The whole point of the HDC.XTC.DATA.CMD.REQUEST_SENSE command is to obtain details about a
* previous error, so if HDC.XTC.DATA.CMD.REQUEST_SENSE itself reports an error, what would that mean?
*/
this.pushResult(HDC.XTC.DATA.STATUS_OK | bDrive);
this.pushResult(HDC.XTC.DATA.STATUS.OK | bDrive);
bCmd = -1; // mark the command as complete
break;
@ -2042,11 +2042,11 @@ HDC.prototype.doXTC = function()
}
}
if (drive) this.verifyDrive(drive);
bDataStatus = HDC.XTC.DATA.STATUS_OK;
bDataStatus = HDC.XTC.DATA.STATUS.OK;
if (!drive && this.iDriveAllowFail == iDrive) {
this.iDriveAllowFail = -1;
if (DEBUG) this.messagePrint("HDC.doXTC(): fake failure triggered");
bDataStatus = HDC.XTC.DATA.STATUS_ERROR;
bDataStatus = HDC.XTC.DATA.STATUS.ERROR;
}
this.beginResult(bDataStatus | bDrive);
bCmd = -1; // mark the command as complete
@ -2054,7 +2054,7 @@ HDC.prototype.doXTC = function()
case HDC.XTC.DATA.CMD.RAM_DIAGNOSTIC: // 0xE0
case HDC.XTC.DATA.CMD.CTL_DIAGNOSTIC: // 0xE4
this.beginResult(HDC.XTC.DATA.STATUS_OK | bDrive);
this.beginResult(HDC.XTC.DATA.STATUS.OK | bDrive);
bCmd = -1; // mark the command as complete
break;
@ -2076,7 +2076,7 @@ HDC.prototype.doXTC = function()
}
switch (bCmd) {
case HDC.XTC.DATA.CMD.TEST_READY: // 0x00
this.beginResult(HDC.XTC.DATA.STATUS_OK | bDrive);
this.beginResult(HDC.XTC.DATA.STATUS.OK | bDrive);
break;
case HDC.XTC.DATA.CMD.RECALIBRATE: // 0x01
@ -2084,14 +2084,14 @@ HDC.prototype.doXTC = function()
if (DEBUG && this.messageEnabled()) {
this.messagePrint("HDC.doXTC(): drive " + iDrive + " control byte: 0x" + str.toHexByte(bControl));
}
this.beginResult(HDC.XTC.DATA.STATUS_OK | bDrive);
this.beginResult(HDC.XTC.DATA.STATUS.OK | bDrive);
break;
case HDC.XTC.DATA.CMD.READ_VERF: // 0x05
/*
* This is a non-DMA operation, so we simply pretend everything is OK for now. TODO: Revisit.
*/
this.beginResult(HDC.XTC.DATA.STATUS_OK | bDrive);
this.beginResult(HDC.XTC.DATA.STATUS.OK | bDrive);
break;
case HDC.XTC.DATA.CMD.READ_DATA: // 0x08
@ -2118,7 +2118,7 @@ HDC.prototype.doXTC = function()
break;
default:
this.beginResult(HDC.XTC.DATA.STATUS_ERROR | bDrive);
this.beginResult(HDC.XTC.DATA.STATUS.ERROR | bDrive);
if (DEBUG && this.messageEnabled()) {
this.messagePrint("HDC.doXTC(0x" + str.toHexByte(bCmdOrig) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation"));
if (bCmd >= 0) this.dbg.stopCPU();
@ -2269,7 +2269,7 @@ HDC.prototype.dmaWriteFormat = function(drive, b)
*
* @this {HDC}
* @param {Object} drive
* @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well)
* @param {function(number)} done (dataStatus is XTC.DATA.STATUS.OK or XTC.DATA.STATUS.ERROR; if error, then drive.errorCode should be set as well)
*/
HDC.prototype.doDMARead = function(drive, done)
{
@ -2300,12 +2300,12 @@ HDC.prototype.doDMARead = function(drive, done)
drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY;
}
}
done(drive.errorCode? HDC.XTC.DATA.STATUS_ERROR : HDC.XTC.DATA.STATUS_OK);
done(drive.errorCode? HDC.XTC.DATA.STATUS.ERROR : HDC.XTC.DATA.STATUS.OK);
});
return;
}
}
done(drive.errorCode? HDC.XTC.DATA.STATUS_ERROR : HDC.XTC.DATA.STATUS_OK);
done(drive.errorCode? HDC.XTC.DATA.STATUS.ERROR : HDC.XTC.DATA.STATUS.OK);
};
/**
@ -2313,7 +2313,7 @@ HDC.prototype.doDMARead = function(drive, done)
*
* @this {HDC}
* @param {Object} drive
* @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well)
* @param {function(number)} done (dataStatus is XTC.DATA.STATUS.OK or XTC.DATA.STATUS.ERROR; if error, then drive.errorCode should be set as well)
*/
HDC.prototype.doDMAWrite = function(drive, done)
{
@ -2351,12 +2351,12 @@ HDC.prototype.doDMAWrite = function(drive, done)
drive.errorCode = HDC.XTC.DATA.ERR.NONE;
}
}
done(drive.errorCode? HDC.XTC.DATA.STATUS_ERROR : HDC.XTC.DATA.STATUS_OK);
done(drive.errorCode? HDC.XTC.DATA.STATUS.ERROR : HDC.XTC.DATA.STATUS.OK);
});
return;
}
}
done(drive.errorCode? HDC.XTC.DATA.STATUS_ERROR : HDC.XTC.DATA.STATUS_OK);
done(drive.errorCode? HDC.XTC.DATA.STATUS.ERROR : HDC.XTC.DATA.STATUS.OK);
};
/**
@ -2364,7 +2364,7 @@ HDC.prototype.doDMAWrite = function(drive, done)
*
* @this {HDC}
* @param {Object} drive
* @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well)
* @param {function(number)} done (dataStatus is XTC.DATA.STATUS.OK or XTC.DATA.STATUS.ERROR; if error, then drive.errorCode should be set as well)
*/
HDC.prototype.doDMAWriteBuffer = function(drive, done)
{
@ -2395,11 +2395,11 @@ HDC.prototype.doDMAWriteBuffer = function(drive, done)
drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY;
}
}
done(drive.errorCode? HDC.XTC.DATA.STATUS_ERROR : HDC.XTC.DATA.STATUS_OK);
done(drive.errorCode? HDC.XTC.DATA.STATUS.ERROR : HDC.XTC.DATA.STATUS.OK);
});
return;
}
done(drive.errorCode? HDC.XTC.DATA.STATUS_ERROR : HDC.XTC.DATA.STATUS_OK);
done(drive.errorCode? HDC.XTC.DATA.STATUS.ERROR : HDC.XTC.DATA.STATUS.OK);
};
/**
@ -2418,7 +2418,7 @@ HDC.prototype.doDMAWriteBuffer = function(drive, done)
*
* @this {HDC}
* @param {Object} drive
* @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well)
* @param {function(number)} done (dataStatus is XTC.DATA.STATUS.OK or XTC.DATA.STATUS.ERROR; if error, then drive.errorCode should be set as well)
*
HDC.prototype.doDMAFormat = function(drive, done)
{
@ -2450,12 +2450,12 @@ HDC.prototype.doDMAFormat = function(drive, done)
}
}
drive.bFormatting = false;
done(drive.errorCode? HDC.XTC.DATA.STATUS_ERROR : HDC.XTC.DATA.STATUS_OK);
done(drive.errorCode? HDC.XTC.DATA.STATUS.ERROR : HDC.XTC.DATA.STATUS.OK);
});
return;
}
}
done(drive.errorCode? HDC.XTC.DATA.STATUS_ERROR : HDC.XTC.DATA.STATUS_OK);
done(drive.errorCode? HDC.XTC.DATA.STATUS.ERROR : HDC.XTC.DATA.STATUS.OK);
};
*/

View file

@ -321,7 +321,7 @@ ROM.prototype.addROM = function(addr)
this.bus.setByteDirect(addr + i, this.abROM[i]);
if (BACKTRACK) {
bto = this.bus.addBackTrackObject(this, bto, i);
this.bus.setBackTrackIndex(addr + i, bto, i);
this.bus.writeBackTrackObject(addr + i, bto, i);
}
}
return true;

View file

@ -1803,7 +1803,7 @@ X86CPU.prototype.setBinding = function(sHTMLType, sBinding, control)
X86CPU.prototype.getByte = function(addr)
{
if (BACKTRACK) {
this.backTrack.btiMemLo = this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].readBackTrack(addr & this.blockLimit);
this.backTrack.btiMemLo = this.bus.readBackTrack(addr);
}
return this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].readByte(addr & this.blockLimit);
};
@ -1819,22 +1819,20 @@ X86CPU.prototype.getWord = function(addr)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMemMask) >> this.blockShift;
/*
* On the 8088, it takes 4 cycles to read the additional byte REGARDLESS whether the address is odd or even.
*
* TODO: For the 8086, the penalty is actually "(addr & 0x1) << 2" (4 additional cycles only when the address is odd).
*/
this.nStepCycles -= this.CYCLES.nWordCyclePenalty;
if (off != this.blockLimit) {
if (BACKTRACK) {
this.backTrack.btiMemLo = this.aMemBlocks[iBlock].readBackTrack(off);
this.backTrack.btiMemHi = this.aMemBlocks[iBlock].readBackTrack(off + 1);
}
return this.aMemBlocks[iBlock].readWord(off);
}
if (BACKTRACK) {
this.backTrack.btiMemLo = this.aMemBlocks[iBlock].readBackTrack(off);
this.backTrack.btiMemHi = this.aMemBlocks[(iBlock + 1) & this.blockMask].readBackTrack(0);
this.backTrack.btiMemLo = this.bus.readBackTrack(addr);
this.backTrack.btiMemHi = this.bus.readBackTrack(addr + 1);
}
if (off != this.blockLimit) {
return this.aMemBlocks[iBlock].readWord(off);
}
return this.aMemBlocks[iBlock++].readByte(off) | (this.aMemBlocks[iBlock & this.blockMask].readByte(0) << 8);
};
@ -1849,7 +1847,7 @@ X86CPU.prototype.getWord = function(addr)
X86CPU.prototype.setByte = function(addr, b)
{
if (BACKTRACK) {
this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].writeBackTrack(addr & this.blockLimit, this.backTrack.btiMemLo);
this.bus.writeBackTrack(addr, this.backTrack.btiMemLo);
}
this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff);
};
@ -1865,24 +1863,22 @@ X86CPU.prototype.setWord = function(addr, w)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMemMask) >> this.blockShift;
/*
* On the 8088, it takes 4 cycles to write the additional byte REGARDLESS whether the address is odd or even.
*
* TODO: For the 8086, the penalty is actually "(addr & 0x1) << 2" (4 additional cycles only when the address is odd).
*/
this.nStepCycles -= this.CYCLES.nWordCyclePenalty;
if (BACKTRACK) {
this.bus.writeBackTrack(addr, this.backTrack.btiMemLo);
this.bus.writeBackTrack(addr + 1, this.backTrack.btiMemHi);
}
if (off != this.blockLimit) {
if (BACKTRACK) {
this.aMemBlocks[iBlock].writeBackTrack(off, this.backTrack.btiMemLo);
this.aMemBlocks[iBlock].writeBackTrack(off + 1, this.backTrack.btiMemHi);
}
this.aMemBlocks[iBlock].writeWord(off, w & 0xffff);
return;
}
if (BACKTRACK) {
this.aMemBlocks[iBlock].writeBackTrack(off, this.backTrack.btiMemLo);
this.aMemBlocks[(iBlock + 1) & this.blockMask].writeBackTrack(0, this.backTrack.btiMemHi);
}
this.aMemBlocks[iBlock++].writeByte(off, w & 0xff);
this.aMemBlocks[iBlock & this.blockMask].writeByte(0, (w >> 8) & 0xff);
};