More Compaq-specific tweaks

This commit is contained in:
Jeff Parsons 2015-04-15 20:40:18 -07:00 committed by jeffpar
commit b9252390bf
6 changed files with 339 additions and 179 deletions

View file

@ -476,17 +476,21 @@ Bus.prototype.getA20 = function()
*/
Bus.prototype.setA20 = function(fEnable)
{
this.assert(fEnable !== undefined);
if (fEnable !== undefined) {
if (this.nBusWidth > 20) {
var addrMask = (this.busMask & ~0x100000) | (fEnable? 0x100000 : 0);
if (addrMask != this.busMask) {
this.busMask = addrMask;
/*
* This callback is required only because the CPU "insists" on using its own memory access functions.
*/
if (this.cpu) this.cpu.setAddressMask(addrMask);
}
/*
* TODO: Until I determine why the Compaq DeskPro 386 ROM is switching to protected-mode
* with the A20 line disabled, resulting in an almost immediate crash, I'm ignoring its requests
* to turn A20 off.
*/
if (I386 && COMPAQ386) fEnable = true;
if (this.nBusWidth > 20) {
var addrMask = (this.busMask & ~0x100000) | (fEnable? 0x100000 : 0);
if (addrMask != this.busMask) {
this.busMask = addrMask;
/*
* This callback is required only because the CPU "insists" on using its own memory access functions.
*/
if (this.cpu) this.cpu.setAddressMask(addrMask);
}
}
};

View file

@ -683,8 +683,8 @@ ChipSet.PPI_SW = {
* READ WRITE REGISTER", but it is not otherwise discussed in the MODEL_5170 TechRef's 8042 documentation.
*
* There are brief references to bits 0 and 1 (KBC.RWREG.CLK_TIMER2 and KBC.RWREG.SPK_TIMER2), and the BIOS sets
* bits 2-7 to "DISABLE PARITY CHECKERS" (principally KBC.RWREG.DISABLE_CHK, which are bits 2 and 3); why the BIOS
* also sets bits 4-7 (or if those bits are even settable) is unclear, since it uses 11111100B rather than defined
* bits 2-7 to "DISABLE PARITY CHECKERS" (principally KBC.RWREG.DISABLE_NMI, which are bits 2 and 3); why the BIOS
* also sets bits 4-7 (or if those bits are even settable) is unclear, since it uses 11111100b rather than defined
* constants.
*
* The bottom line: on a MODEL_5170, port 0x61 is still used for speaker control and parity checking, so we use
@ -751,12 +751,14 @@ ChipSet.KBC = {
PORT: 0x61,
CLK_TIMER2: 0x01, // set to enable clock to TIMER2 (R/W)
SPK_TIMER2: 0x02, // set to connect output of TIMER2 to speaker (R/W)
DISABLE_CHK: 0x0C, // set to disable I/O and RAM parity checks, clear to enable (R/W)
COMPAQ_FSNMI: 0x04, // set to disable RAM/FS NMI (R/W, DESKPRO386)
COMPAQ_IONMI: 0x08, // set to disable IOCHK NMI (R/W, DESKPRO386)
DISABLE_NMI: 0x0C, // set to disable IOCHK and RAM/FS NMI, clear to enable (R/W)
REFRESH_BIT: 0x10, // 0 if RAM refresh occurring, 1 if RAM not in refresh cycle (R/O)
OUT_TIMER2: 0x20, // state of TIMER2 output signal (R/O, DESKPRO386)
IO_CHK: 0x40, // indicates I/O check (R/O); to reset, pulse bit 3 (0x08)
PARITY_CHK: 0x80, // indicates RAM parity check (R/O); to reset, pulse bit 2 (0x04)
PARITY_ERR: 0xC0
IOCHK_NMI: 0x40, // IOCHK NMI (R/O); to reset, pulse bit 3 (0x08)
RAMFS_NMI: 0x80, // RAM/FS (parity or fail-safe) NMI (R/O); to reset, pulse bit 2 (0x04)
NMI_ERROR: 0xC0
},
CMD: { // this.b8042InBuff (on write to port 0x64, interpret this as a CMD)
PORT: 0x64,
@ -4275,7 +4277,7 @@ ChipSet.prototype.in8042RWReg = function(port, addrFrom)
{
/*
* Normally, we return whatever was last written to this port, but we do need to mask the
* two upper-most bits (KBC.RWREG.PARITY_ERR), as those are output-only bits used to signal
* two upper-most bits (KBC.RWREG.NMI_ERROR), as those are output-only bits used to signal
* parity errors.
*
* Also, "TEST.09" of the MODEL_5170 BIOS expects the REFRESH_BIT to alternate, so we used to
@ -4297,7 +4299,7 @@ ChipSet.prototype.in8042RWReg = function(port, addrFrom)
* in 1us, 64 cycles represents 8us, so that might be a bit fast for "WAITF", but bit 6
* is the only choice that also satisfies the pre-"TEST.11A" test as well.
*/
var b = this.bPPIB & ~(ChipSet.KBC.RWREG.PARITY_ERR | ChipSet.KBC.RWREG.REFRESH_BIT) | ((this.cpu.getCycles() & 0x40)? ChipSet.KBC.RWREG.REFRESH_BIT : 0);
var b = this.bPPIB & ~(ChipSet.KBC.RWREG.NMI_ERROR | ChipSet.KBC.RWREG.REFRESH_BIT) | ((this.cpu.getCycles() & 0x40)? ChipSet.KBC.RWREG.REFRESH_BIT : 0);
/*
* Thanks to the WAITF function, this has become a very "busy" port, so let's not generate messages
* unless both MESSAGE_8042 *and* MESSAGE_LOG are set.

View file

@ -386,12 +386,12 @@ Memory.prototype = {
*/
setReadAccess: function(afn, fDirect) {
this.readByte = afn[0] || this.readNone;
this.readShort = afn[1] || this.readNone;
this.readLong = afn[2] || this.readNone;
this.readShort = afn[1] || this.readShortDefault;
this.readLong = afn[2] || this.readLongDefault;
if (fDirect) {
this.readByteDirect = afn[0] || this.readNone;
this.readShortDirect = afn[1] || this.readNone;
this.readLongDirect = afn[2] || this.readNone;
this.readShortDirect = afn[1] || this.readShortDefault;
this.readLongDirect = afn[2] || this.readLongDefault;
}
},
/**
@ -403,12 +403,12 @@ Memory.prototype = {
*/
setWriteAccess: function(afn, fDirect) {
this.writeByte = !this.fReadOnly && afn[3] || this.writeNone;
this.writeShort = !this.fReadOnly && afn[4] || this.writeNone;
this.writeLong = !this.fReadOnly && afn[5] || this.writeNone;
this.writeShort = !this.fReadOnly && afn[4] || this.writeShortDefault;
this.writeLong = !this.fReadOnly && afn[5] || this.writeLongDefault;
if (fDirect) {
this.writeByteDirect = afn[3] || this.writeNone;
this.writeShortDirect = afn[4] || this.writeNone;
this.writeLongDirect = afn[5] || this.writeNone;
this.writeShortDirect = afn[4] || this.writeShortDefault;
this.writeLongDirect = afn[5] || this.writeLongDefault;
}
},
/**
@ -533,6 +533,55 @@ Memory.prototype = {
this.dbg.message("attempt to write " + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr), true);
}
},
/**
* readShortDefault(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
readShortDefault: function readShortDefault(off)
{
return this.readByteDirect(off) | (this.readByteDirect(off + 1) << 8);
},
/**
* readLongDefault(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
readLongDefault: function readLongDefault(off)
{
return this.readByteDirect(off) | (this.readByteDirect(off + 1) << 8) | (this.readByteDirect(off + 2) << 16) | (this.readByteDirect(off + 3) << 24);
},
/**
* writeShortDefault(off, w)
*
* @this {Memory}
* @param {number} off
* @param {number} w
*/
writeShortDefault: function writeShortDefault(off, w)
{
Component.assert(!(w & ~0xffff));
this.writeByteDirect(off, w & 0xff);
this.writeByteDirect(off + 1, w >> 8);
},
/**
* writeLongDefault(off, w)
*
* @this {Memory}
* @param {number} off
* @param {number} w
*/
writeLongDefault: function writeLongDefault(off, w)
{
this.writeByteDirect(off, w & 0xff);
this.writeByteDirect(off + 1, (w >> 8) & 0xff);
this.writeByteDirect(off + 2, (w >> 16) & 0xff);
this.writeByteDirect(off + 3, (w >>> 24));
},
/**
* readByteMemory(off)
*

View file

@ -33,6 +33,7 @@
"use strict";
if (typeof module !== 'undefined') {
var str = require("../../shared/lib/strlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var Memory = require("./memory");
@ -80,6 +81,7 @@ RAM.prototype.initBus = function(cmp, bus, cpu, dbg)
{
this.bus = bus;
this.cpu = cpu;
this.dbg = dbg;
this.chipset = cmp.getComponentByType("ChipSet");
this.setReady();
};
@ -257,10 +259,10 @@ RAM.init = function()
* The DeskPro 386 also contained two memory-mapped registers at 0x80C00000. The first is a write-only
* mapping register that provides the ability to map the 128Kb at 0x00FE0000 to 0x000E0000, replacing
* any ROMs in the range 0x000E0000-0x000FFFFF, and optionally write-protecting that 128Kb; internally,
* this register corresponds to bMappings.
* this register corresponds to wMappings.
*
* The second register is a read-only diagnostics register that indicates jumper configuration and
* parity errors; internally, this register corresponds to bSettings.
* parity errors; internally, this register corresponds to wSettings.
*
* To emulate the memory-mapped registers at 0x80C00000, the RAM component allocates a block at that
* address using this custom controller once it sees an allocation for "ramCPQ".
@ -278,8 +280,12 @@ RAM.init = function()
function CompaqController(ram)
{
this.ram = ram;
this.bMappings = CompaqController.MAPPINGS.DEFAULT;
this.bSettings = CompaqController.SETTINGS.BASE_640KB;
this.wMappings = CompaqController.MAPPINGS.DEFAULT;
/*
* TODO: wSettings needs to reflect the actual amount of configured memory....
*/
this.wSettings = CompaqController.SETTINGS.DEFAULT;
this.wRAMSetup = CompaqController.RAMSETUP.DEFAULT;
this.aBlocksDst = null;
}
@ -289,19 +295,23 @@ CompaqController.MAP_DST = 0x000E0000;
CompaqController.MAP_SIZE = 0x00020000;
/*
* Bit definitions for the 8-bit write-only memory-mapping register (bMappings)
* Bit definitions for the 16-bit write-only memory-mapping register (wMappings)
*
* NOTE: Although Compaq says the memory at %FE0000 is "relocated", it actually remains addressable
* at %FE0000; it simply becomes addressable at %0E0000 as well, displacing any ROMs that used to be
* addressable at %0E0000 through %0FFFFF.
*/
CompaqController.MAPPINGS = {
UNMAPPED: 0x01, // is this bit is CLEAR, the last 128Kb (at 0x00FE0000) is mapped to 0x000E0000
READWRITE: 0x02, // if this bit is CLEAR, the last 128Kb (at 0x00FE0000) is read-only (ie, write-protected)
RESERVED: 0xFC, // the remaining 6 bits are reserved and should always be SET
DEFAULT: 0xFF
UNMAPPED: 0x0001, // is this bit is CLEAR, the last 128Kb (at 0x00FE0000) is mapped to 0x000E0000
READWRITE: 0x0002, // if this bit is CLEAR, the last 128Kb (at 0x00FE0000) is read-only (ie, write-protected)
RESERVED: 0xFFFC, // the remaining 6 bits are reserved and should always be SET
DEFAULT: 0xFFFF // our default settings (no mapping, no write-protection)
};
/*
* Bit definitions for the 8-bit read-only settings/diagnostics register (bSettings)
* Bit definitions for the 16-bit read-only settings/diagnostics register (wSettings)
*
* SW1-7 and SW1-8 are mapped to bits 5 and 4 of bSettings, respectively, as follows:
* SW1-7 and SW1-8 are mapped to bits 5 and 4 of wSettings, respectively, as follows:
*
* SW1-7 SW1-8 Bit5 Bit4 Amount (of base memory provided by the Compaq 32-bit memory board)
* ----- ----- ---- ---- ------
@ -330,64 +340,123 @@ CompaqController.MAPPINGS = {
* SW1-6: ChipSet.KBC.INPORT.COMPAQ_NONDUAL clear if ON, set (0x40) if OFF
*/
CompaqController.SETTINGS = {
B0_PARITY: 0x01,
B1_PARITY: 0x02,
B2_PARITY: 0x04,
B3_PARITY: 0x08,
BASE_640KB: 0x00, // SW1-7,8: ON ON Bits 5,4: 00
BASE_ERROR: 0x10, // SW1-7,8: ON OFF Bits 5,4: 01
BASE_512KB: 0x20, // SW1-7,8: OFF ON Bits 5,4: 10
BASE_256KB: 0x30, // SW1-7,8: OFF OFF Bits 5,4: 11
ADDED_1MB: 0x40,
PIGGYBACK: 0x80
B0_PARITY: 0x0001, // parity OK in byte 0
B1_PARITY: 0x0002, // parity OK in byte 1
B2_PARITY: 0x0004, // parity OK in byte 2
B3_PARITY: 0x0008, // parity OK in byte 3
BASE_640KB: 0x0000, // SW1-7,8: ON ON Bits 5,4: 00
BASE_ERROR: 0x0010, // SW1-7,8: ON OFF Bits 5,4: 01
BASE_512KB: 0x0020, // SW1-7,8: OFF ON Bits 5,4: 10
BASE_256KB: 0x0030, // SW1-7,8: OFF OFF Bits 5,4: 11
/*
* TODO: The DeskPro 386/25 TechRef says bit 6 (0x40) is always set,
* but setting it results in memory configuration errors; review.
*/
ADDED_1MB: 0x0040,
/*
* TODO: The DeskPro 386/25 TechRef says bit 7 (0x80) is always clear; review.
*/
PIGGYBACK: 0x0080,
SYS_4MB: 0x0100, // 4Mb on system board
SYS_1MB: 0x0200, // 1Mb on system board
SYS_NONE: 0x0300, // no memory on system board
MODA_4MB: 0x0400, // 4Mb on module A board
MODA_1MB: 0x0800, // 1Mb on module A board
MODA_NONE: 0x0C00, // no memory on module A board
MODB_4MB: 0x1000, // 4Mb on module B board
MODB_1MB: 0x2000, // 1Mb on module B board
MODB_NONE: 0x3000, // no memory on module B board
MODC_4MB: 0x4000, // 4Mb on module C board
MODC_1MB: 0x8000, // 1Mb on module C board
MODC_NONE: 0xC000, // no memory on module C board
/*
* NOTE: It doesn't seem to matter to the ROM whether I set any of bits 8-15 or not....
*/
DEFAULT: 0x0A0F // our default settings (ie, parity OK, 640Kb base memory, 1Mb system memory, 1Mb module A memory)
};
CompaqController.RAMSETUP = {
SETUP: 0x000F,
CACHE: 0x0040,
RESERVED: 0xFFB0,
DEFAULT: 0x0002 // our default settings (ie, 2Mb, cache disabled)
};
/**
* readByte(off)
*
* @this {Memory}
* @param {number} off
* @param {number} off (relative to 0x80C00000)
* @return {number}
*/
CompaqController.readByte = function readCompaqControllerByte(off)
{
return this.controller.bSettings;
var b = 0xff;
if (off < 0x02) {
b = (off & 0x1)? (this.controller.wSettings >> 8) : (this.controller.wSettings & 0xff);
}
else if (off < 0x4) {
b = (off & 0x1)? (this.controller.wRAMSetup >> 8) : (this.controller.wRAMSetup & 0xff);
}
if (DEBUG) {
this.controller.ram.printMessage("CompaqController.readByte(" + str.toHexWord(off) + ") returned " + str.toHexByte(b), true, true);
if (MAXDEBUG && DEBUGGER && off >= 0x2) this.cpu.stopCPU();
}
return b;
};
/**
* writeByte(off, b)
*
* @this {Memory}
* @param {number} off
* @param {number} off (relative to 0x80C00000)
* @param {number} b
*/
CompaqController.writeByte = function writeCompaqControllerByte(off, b)
{
var aBlocks;
var controller = this.controller;
var bus = controller.ram.bus;
if (b != controller.bMappings) {
if (!(b & CompaqController.MAPPINGS.UNMAPPED)) {
if (!controller.aBlocksDst) {
controller.aBlocksDst = bus.getMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE);
/*
* Check for write to 0x80C00000
*/
if (!off) {
if (b != (controller.wMappings & 0xff)) {
var bus = controller.ram.bus;
if (!(b & CompaqController.MAPPINGS.UNMAPPED)) {
if (!controller.aBlocksDst) {
controller.aBlocksDst = bus.getMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE);
}
var aBlocks = bus.getMemoryBlocks(CompaqController.MAP_SRC, CompaqController.MAP_SIZE);
var type = (b & CompaqController.MAPPINGS.READWRITE)? Memory.TYPE.RAM : Memory.TYPE.ROM;
bus.setMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE, aBlocks, type);
}
aBlocks = bus.getMemoryBlocks(CompaqController.MAP_SRC, CompaqController.MAP_SIZE);
var type = (b & CompaqController.MAPPINGS.READWRITE)? Memory.TYPE.RAM : Memory.TYPE.ROM;
bus.setMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE, aBlocks, type);
}
else {
if (controller.aBlocksDst) {
bus.setMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE, controller.aBlocksDst);
controller.aBlocksDst = null;
else {
if (controller.aBlocksDst) {
bus.setMemoryBlocks(CompaqController.MAP_DST, CompaqController.MAP_SIZE, controller.aBlocksDst);
controller.aBlocksDst = null;
}
}
controller.wMappings = (controller.wMappings & ~0xff) | b;
if (MAXDEBUG && DEBUGGER) this.cpu.stopCPU();
}
controller.bMappings = b;
if (DEBUG) this.cpu.stopCPU();
}
/*
* Check for write to 0x80C00002
*/
else if (off == 0x2) {
controller.wRAMSetup = (controller.wRAMSetup & ~0xff) | b;
if (MAXDEBUG && DEBUGGER) this.cpu.stopCPU();
}
/*
* All bits in 0x80C00001 and 0x80C00003 are reserved, so we can simply ignore those writes.
*/
if (DEBUG) {
this.controller.ram.printMessage("CompaqController.writeByte(" + str.toHexWord(off) + "," + str.toHexByte(b) + ")", true, true);
}
};
CompaqController.ACCESS = [CompaqController.readByte, CompaqController.readByte, CompaqController.readByte,
CompaqController.writeByte, CompaqController.writeByte, CompaqController.writeByte];
CompaqController.BUFFER = [null, 0];
CompaqController.ACCESS = [CompaqController.readByte, null, null, CompaqController.writeByte, null, null];
/**
* getMemoryBuffer(addr)
@ -398,7 +467,7 @@ CompaqController.ACCESS = [CompaqController.readByte, CompaqController.readByte,
*/
CompaqController.prototype.getMemoryBuffer = function(addr)
{
return [null, 0];
return CompaqController.BUFFER;
};
/**

View file

@ -1240,59 +1240,6 @@ Card.ACCESS.WRITE.MODE2OR = 0xA000;
Card.ACCESS.WRITE.MODE2XOR = 0xE000;
Card.ACCESS.WRITE.MASK = 0xff00;
/**
* readShort(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Card.ACCESS.readShort = function readShort(off)
{
return this.readByteDirect(off) | (this.readByteDirect(off + 1) << 8);
};
/**
* readLong(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Card.ACCESS.readLong = function readLong(off)
{
return this.readByteDirect(off) | (this.readByteDirect(off + 1) << 8) | (this.readByteDirect(off + 2) << 16) | (this.readByteDirect(off + 3) << 24);
};
/**
* writeShort(off, w)
*
* @this {Memory}
* @param {number} off
* @param {number} w
*/
Card.ACCESS.writeShort = function writeShort(off, w)
{
Component.assert(!(w & ~0xffff));
this.writeByteDirect(off, w & 0xff);
this.writeByteDirect(off + 1, w >> 8);
};
/**
* writeLong(off, w)
*
* @this {Memory}
* @param {number} off
* @param {number} w
*/
Card.ACCESS.writeLong = function writeLong(off, w)
{
this.writeByteDirect(off, w & 0xff);
this.writeByteDirect(off + 1, (w >> 8) & 0xff);
this.writeByteDirect(off + 2, (w >> 16) & 0xff);
this.writeByteDirect(off + 3, (w >>> 24));
};
/**
* readByteMode0(off)
*
@ -1952,9 +1899,7 @@ Card.prototype.setMemoryAccess = function(nAccess)
fnWriteByte = Card.ACCESS.afn[Card.ACCESS.WRITE.EVENODD];
}
}
if (!this.afnAccess) {
this.afnAccess = [null, Card.ACCESS.readShort, Card.ACCESS.readLong, null, Card.ACCESS.writeShort, Card.ACCESS.writeLong];
}
if (!this.afnAccess) this.afnAccess = new Array(6);
this.afnAccess[0] = fnReadByte;
this.afnAccess[3] = fnWriteByte;
this.nAccess = nAccess;