First change for v1.17.6: DeskPro 386-compatible A20 management

This commit is contained in:
Jeff Parsons 2015-04-19 18:19:10 -07:00 committed by jeffpar
commit f2cb4dc18d
127 changed files with 993 additions and 1003 deletions

View file

@ -465,18 +465,43 @@ Bus.prototype.scanMemory = function(stats, addr, size)
*/
Bus.prototype.getA20 = function()
{
return this.busLimit == this.busMask;
return !this.aBlocks2Mb && this.busLimit == this.busMask;
};
/**
* setA20(fEnable)
*
* On 32-bit bus machines, I've adopted the approach that Compaq took with DeskPro 386 machines,
* which is to map the 1st Mb to the 2nd Mb whenever A20 is disabled, rather than blindly masking
* the A20 address bit from all addresses; this is what the DeskPro 386 ROM BIOS requires.
*
* For 24-bit bus machines, we take the same approach that most if not all 80286 systems took, which
* is simply masking the A20 address bit.
*
* TODO: On machines with a 32-bit bus, look into whether we can eliminate address masking altogether,
* which seems feasible, provided all incoming addresses are already pre-truncated to 32 bits. Also,
* confirm that DeskPro 386 machines mapped the ENTIRE 1st Mb to the 2nd, and not simply the first 64Kb,
* which is technically all that 8086 address wrap-around compatibility would require.
*
* @this {Bus}
* @param {boolean} fEnable is true to enable A20 (default), false to disable
*/
Bus.prototype.setA20 = function(fEnable)
{
if (this.nBusWidth > 20) {
if (this.nBusWidth == 32) {
if (fEnable) {
if (this.aBlocks2Mb) {
this.setMemoryBlocks(0x100000, 0x100000, this.aBlocks2Mb);
this.aBlocks2Mb = null;
}
} else {
if (!this.aBlocks2Mb) {
this.aBlocks2Mb = this.getMemoryBlocks(0x100000, 0x100000);
this.setMemoryBlocks(0x100000, 0x100000, this.getMemoryBlocks(0x0, 0x100000));
}
}
}
else if (this.nBusWidth > 20) {
var addrMask = (this.busMask & ~0x100000) | (fEnable? 0x100000 : 0);
if (addrMask != this.busMask) {
this.busMask = addrMask;
@ -579,6 +604,12 @@ Bus.prototype.getMemoryBlocks = function(addr, size)
/**
* setMemoryBlocks(addr, size, aBlocks, type)
*
* If no type is specified, then specified address range uses all the provided blocks as-is;
* this form of setMemoryBlocks() is used for complete physical aliases.
*
* Otherwise, new blocks are allocated with the specified type; the underlying memory from the
* provided blocks is still used, but the new blocks may have different access to that memory.
*
* @this {Bus}
* @param {number} addr is the starting physical address
* @param {number} size of the request, in bytes
@ -590,13 +621,14 @@ Bus.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
var i = 0;
var iBlock = addr >>> this.blockShift;
while (size > 0 && iBlock < this.aMemBlocks.length) {
var block;
if (type === undefined) {
block = aBlocks[i++];
} else {
block = new Memory(addr);
if (DEBUGGER) block.setDebugInfo(this.cpu, this.dbg, this.blockSize);
block.clone(aBlocks[i++], type);
var block = aBlocks[i++];
this.assert(block);
if (!block) break;
if (type !== undefined) {
var blockNew = new Memory(addr);
if (DEBUGGER) blockNew.setDebugInfo(this.cpu, this.dbg, this.blockSize);
blockNew.clone(block, type);
block = blockNew;
}
this.aMemBlocks[iBlock++] = block;
size -= this.blockSize;