2019-03-01 05:21:18 +00:00
|
|
|
/* Copyright 2010-2019 Will Scullin <scullin@scullinsteel.com>
|
2013-10-10 18:03:07 +00:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
|
|
* the above copyright notice appear in all copies and that both that
|
|
|
|
* copyright notice and this permission notice appear in supporting
|
|
|
|
* documentation. No representations are made about the suitability of this
|
|
|
|
* software for any purpose. It is provided "as is" without express or
|
|
|
|
* implied warranty.
|
|
|
|
*/
|
|
|
|
|
2019-03-01 05:21:18 +00:00
|
|
|
import RAM from './ram';
|
|
|
|
import { debug, toHex } from './util';
|
2016-11-22 05:17:34 +00:00
|
|
|
|
2019-03-01 05:21:18 +00:00
|
|
|
export default function MMU(cpu, vm, lores1, lores2, hires1, hires2, io, rom)
|
2013-10-10 18:03:07 +00:00
|
|
|
{
|
|
|
|
var idx;
|
|
|
|
|
|
|
|
var _readPages = new Array(0x100);
|
|
|
|
var _writePages = new Array(0x100);
|
|
|
|
var _pages = new Array(0x100);
|
|
|
|
|
|
|
|
// Language Card RAM Softswitches
|
|
|
|
var _bank1;
|
|
|
|
var _readbsr;
|
|
|
|
var _writebsr;
|
2017-03-05 22:51:59 +00:00
|
|
|
var _prewrite;
|
2013-10-10 18:03:07 +00:00
|
|
|
|
|
|
|
// Auxilliary ROM
|
2016-11-22 05:17:34 +00:00
|
|
|
var _intcxrom;
|
2013-10-10 18:03:07 +00:00
|
|
|
var _slot3rom;
|
2017-08-20 17:46:10 +00:00
|
|
|
var _intc8rom;
|
2013-10-10 18:03:07 +00:00
|
|
|
|
|
|
|
// Auxilliary RAM
|
|
|
|
var _auxRamRead;
|
|
|
|
var _auxRamWrite;
|
|
|
|
var _altzp;
|
2016-11-22 05:17:34 +00:00
|
|
|
|
2013-10-10 18:03:07 +00:00
|
|
|
// Video
|
2017-08-20 17:46:10 +00:00
|
|
|
var _80store;
|
2013-10-10 18:03:07 +00:00
|
|
|
var _page2;
|
2017-08-20 17:46:10 +00:00
|
|
|
var _hires;
|
2013-10-10 18:03:07 +00:00
|
|
|
|
|
|
|
var _vbEnd = 0;
|
|
|
|
|
2016-11-28 01:28:49 +00:00
|
|
|
/*
|
|
|
|
* I/O Switch locations
|
|
|
|
*/
|
|
|
|
|
|
|
|
var LOC = {
|
|
|
|
// 80 Column
|
|
|
|
_80STOREOFF: 0x00,
|
|
|
|
_80STOREON: 0x01,
|
|
|
|
|
|
|
|
// Aux RAM
|
|
|
|
RAMRDOFF: 0x02,
|
|
|
|
RAMRDON: 0x03,
|
|
|
|
|
|
|
|
RAMWROFF: 0x04,
|
|
|
|
RAMWRON: 0x05,
|
|
|
|
|
|
|
|
// Bank switched ROM
|
|
|
|
INTCXROMOFF: 0x06,
|
|
|
|
INTCXROMON: 0x07,
|
|
|
|
ALTZPOFF: 0x08,
|
|
|
|
ALTZPON: 0x09,
|
|
|
|
SLOTC3ROMOFF: 0x0A,
|
|
|
|
SLOTC3ROMON: 0x0B,
|
|
|
|
|
|
|
|
// Status
|
|
|
|
BSRBANK2: 0x11,
|
|
|
|
BSRREADRAM: 0x12,
|
|
|
|
RAMRD: 0x13,
|
|
|
|
RAMWRT: 0x14,
|
|
|
|
INTCXROM: 0x15,
|
|
|
|
ALTZP: 0x16,
|
|
|
|
SLOTC3ROM: 0x17,
|
|
|
|
_80STORE: 0x18,
|
|
|
|
VERTBLANK: 0x19,
|
|
|
|
|
2017-08-20 17:46:10 +00:00
|
|
|
PAGE1: 0x54, // select text/graphics page1 main/aux
|
|
|
|
PAGE2: 0x55, // select text/graphics page2 main/aux
|
|
|
|
RESET_HIRES: 0x56,
|
|
|
|
SET_HIRES: 0x57,
|
2016-11-28 01:28:49 +00:00
|
|
|
|
|
|
|
// Bank 2
|
|
|
|
READBSR2: 0x80,
|
|
|
|
WRITEBSR2: 0x81,
|
|
|
|
OFFBSR2: 0x82,
|
|
|
|
READWRBSR2: 0x83,
|
|
|
|
|
|
|
|
// Shadow Bank 2
|
|
|
|
_READBSR2: 0x84,
|
|
|
|
_WRITEBSR2: 0x85,
|
|
|
|
_OFFBSR2: 0x86,
|
|
|
|
_READWRBSR2: 0x87,
|
|
|
|
|
|
|
|
// Bank 1
|
|
|
|
READBSR1: 0x88,
|
|
|
|
WRITEBSR1: 0x89,
|
|
|
|
OFFBSR1: 0x8a,
|
|
|
|
READWRBSR1: 0x8b,
|
|
|
|
|
|
|
|
// Shadow Bank 1
|
|
|
|
_READBSR1: 0x8c,
|
|
|
|
_WRITEBSR1: 0x8d,
|
|
|
|
_OFFBSR1: 0x8e,
|
|
|
|
_READWRBSR1: 0x8f
|
|
|
|
};
|
|
|
|
|
2013-10-10 18:03:07 +00:00
|
|
|
function _initSwitches() {
|
|
|
|
_bank1 = true;
|
|
|
|
_readbsr = false;
|
|
|
|
_writebsr = false;
|
2017-03-05 22:51:59 +00:00
|
|
|
_prewrite = false;
|
2013-10-10 18:03:07 +00:00
|
|
|
|
|
|
|
_auxRamRead = false;
|
|
|
|
_auxRamWrite = false;
|
|
|
|
_altzp = false;
|
|
|
|
|
2016-11-22 05:17:34 +00:00
|
|
|
_intcxrom = false;
|
2013-10-10 18:03:07 +00:00
|
|
|
_slot3rom = false;
|
2017-08-20 17:46:10 +00:00
|
|
|
_intc8rom = false;
|
2013-10-10 18:03:07 +00:00
|
|
|
|
|
|
|
_80store = false;
|
|
|
|
_page2 = false;
|
2017-08-20 17:46:10 +00:00
|
|
|
_hires = false;
|
2013-10-10 18:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function _debug() {
|
2020-01-02 18:57:26 +00:00
|
|
|
// debug.apply(this, arguments);
|
2013-10-10 18:03:07 +00:00
|
|
|
}
|
|
|
|
|
2016-11-28 01:28:49 +00:00
|
|
|
function Switches() {
|
|
|
|
var locs = {};
|
|
|
|
|
2020-03-27 03:01:24 +00:00
|
|
|
Object.keys(LOC).forEach(function(loc) {
|
|
|
|
locs[LOC[loc]] = loc;
|
|
|
|
});
|
2016-11-28 01:28:49 +00:00
|
|
|
|
|
|
|
return {
|
|
|
|
start: function() {
|
|
|
|
return 0xC0;
|
|
|
|
},
|
|
|
|
end: function() {
|
|
|
|
return 0xC0;
|
|
|
|
},
|
|
|
|
read: function(page, off) {
|
|
|
|
var result;
|
|
|
|
if (off in locs) {
|
|
|
|
result = _access(off);
|
|
|
|
} else {
|
2019-12-30 03:13:59 +00:00
|
|
|
result = io.ioSwitch(off, undefined);
|
2016-11-28 01:28:49 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
},
|
|
|
|
write: function(page, off, val) {
|
|
|
|
if (off in locs) {
|
|
|
|
_access(off, val);
|
|
|
|
} else {
|
|
|
|
io.ioSwitch(off, val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function AuxRom() {
|
2013-10-10 18:03:07 +00:00
|
|
|
return {
|
2016-11-28 01:28:49 +00:00
|
|
|
read: function(page, off) {
|
2017-08-20 17:46:10 +00:00
|
|
|
if (page == 0xc3) {
|
|
|
|
_intc8rom = true;
|
|
|
|
_updateBanks();
|
|
|
|
}
|
|
|
|
if (page == 0xcf && off == 0xff) {
|
|
|
|
_intc8rom = false;
|
|
|
|
_updateBanks();
|
|
|
|
}
|
2016-12-06 05:16:21 +00:00
|
|
|
return rom.read(page, off);
|
2013-10-10 18:03:07 +00:00
|
|
|
},
|
2016-11-28 01:28:49 +00:00
|
|
|
write: function() {}
|
2013-10-10 18:03:07 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-11-28 01:28:49 +00:00
|
|
|
var switches = new Switches();
|
|
|
|
var auxRom = new AuxRom();
|
2013-10-10 18:03:07 +00:00
|
|
|
|
|
|
|
var mem00_01 = [new RAM(0x0, 0x1), new RAM(0x0, 0x1)];
|
|
|
|
var mem02_03 = [new RAM(0x2, 0x3), new RAM(0x2, 0x3)];
|
|
|
|
var mem04_07 = [lores1.bank0(), lores1.bank1()];
|
|
|
|
var mem08_0B = [lores2.bank0(), lores2.bank1()];
|
|
|
|
var mem0C_1F = [new RAM(0xC, 0x1F), new RAM(0xC, 0x1F)];
|
|
|
|
var mem20_3F = [hires1.bank0(), hires1.bank1()];
|
|
|
|
var mem40_5F = [hires2.bank0(), hires2.bank1()];
|
|
|
|
var mem60_BF = [new RAM(0x60,0xBF), new RAM(0x60,0xBF)];
|
2016-11-28 01:28:49 +00:00
|
|
|
var memC0_C0 = [switches];
|
|
|
|
var memC1_CF = [io, auxRom];
|
2017-03-05 22:51:59 +00:00
|
|
|
var memD0_DF = [
|
|
|
|
rom,
|
|
|
|
new RAM(0xD0,0xDF), new RAM(0xD0,0xDF),
|
|
|
|
new RAM(0xD0,0xDF), new RAM(0xD0,0xDF)
|
|
|
|
];
|
2013-10-10 18:03:07 +00:00
|
|
|
var memE0_FF = [rom, new RAM(0xE0,0xFF), new RAM(0xE0,0xFF)];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize read/write banks
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Zero Page/Stack
|
|
|
|
for (idx = 0x0; idx < 0x2; idx++) {
|
|
|
|
_pages[idx] = mem00_01;
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
// 0x300-0x400
|
|
|
|
for (idx = 0x2; idx < 0x4; idx++) {
|
|
|
|
_pages[idx] = mem02_03;
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
// Text Page 1
|
|
|
|
for (idx = 0x4; idx < 0x8; idx++) {
|
|
|
|
_pages[idx] = mem04_07;
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
// Text Page 2
|
|
|
|
for (idx = 0x8; idx < 0xC; idx++) {
|
|
|
|
_pages[idx] = mem08_0B;
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
// 0xC00-0x2000
|
|
|
|
for (idx = 0xC; idx < 0x20; idx++) {
|
|
|
|
_pages[idx] = mem0C_1F;
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
// Hires Page 1
|
|
|
|
for (idx = 0x20; idx < 0x40; idx++) {
|
|
|
|
_pages[idx] = mem20_3F;
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
// Hires Page 2
|
|
|
|
for (idx = 0x40; idx < 0x60; idx++) {
|
|
|
|
_pages[idx] = mem40_5F;
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
// 0x6000-0xc000
|
|
|
|
for (idx = 0x60; idx < 0xc0; idx++) {
|
|
|
|
_pages[idx] = mem60_BF;
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
// I/O Switches
|
|
|
|
idx = 0xc0;
|
|
|
|
_pages[idx] = memC0_C0;
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
// Slots
|
|
|
|
for (idx = 0xc1; idx < 0xd0; idx++) {
|
2016-11-28 01:28:49 +00:00
|
|
|
_pages[idx] = memC1_CF;
|
2013-10-10 18:03:07 +00:00
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
// Basic ROM
|
|
|
|
for (idx = 0xd0; idx < 0xe0; idx++) {
|
|
|
|
_pages[idx] = memD0_DF;
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
// Monitor ROM
|
|
|
|
for (idx = 0xe0; idx < 0x100; idx++) {
|
|
|
|
_pages[idx] = memE0_FF;
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
2016-11-22 05:17:34 +00:00
|
|
|
|
2013-10-10 18:03:07 +00:00
|
|
|
function _updateBanks() {
|
|
|
|
if (_auxRamRead) {
|
|
|
|
for (idx = 0x02; idx < 0xC0; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][1];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (idx = 0x02; idx < 0xC0; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_auxRamWrite) {
|
|
|
|
for (idx = 0x02; idx < 0xC0; idx++) {
|
|
|
|
_writePages[idx] = _pages[idx][1];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (idx = 0x02; idx < 0xC0; idx++) {
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_80store) {
|
|
|
|
if (_page2) {
|
|
|
|
for (idx = 0x4; idx < 0x8; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][1];
|
|
|
|
_writePages[idx] = _pages[idx][1];
|
|
|
|
}
|
2017-08-20 17:46:10 +00:00
|
|
|
if (_hires) {
|
2013-10-10 18:03:07 +00:00
|
|
|
for (idx = 0x20; idx < 0x40; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][1];
|
|
|
|
_writePages[idx] = _pages[idx][1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (idx = 0x4; idx < 0x8; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
2017-08-20 17:46:10 +00:00
|
|
|
if (_hires) {
|
2013-10-10 18:03:07 +00:00
|
|
|
for (idx = 0x20; idx < 0x40; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_intcxrom) {
|
|
|
|
for (idx = 0xc1; idx < 0xd0; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][1];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (idx = 0xc1; idx < 0xd0; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
}
|
2017-08-20 17:46:10 +00:00
|
|
|
if (!_slot3rom) {
|
|
|
|
_readPages[0xc3] = _pages[0xc3][1];
|
|
|
|
}
|
|
|
|
if (_intc8rom) {
|
|
|
|
for (idx = 0xc8; idx < 0xd0; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][1];
|
|
|
|
}
|
|
|
|
}
|
2013-10-10 18:03:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (_altzp) {
|
|
|
|
for (idx = 0x0; idx < 0x2; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][1];
|
|
|
|
_writePages[idx] = _pages[idx][1];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (idx = 0x0; idx < 0x2; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_readbsr) {
|
|
|
|
if (_bank1) {
|
|
|
|
for (idx = 0xd0; idx < 0xe0; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][_altzp ? 2 : 1];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (idx = 0xd0; idx < 0xe0; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][_altzp ? 4 : 3];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (idx = 0xe0; idx < 0x100; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][_altzp ? 2 : 1];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (idx = 0xd0; idx < 0x100; idx++) {
|
|
|
|
_readPages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_writebsr) {
|
|
|
|
if (_bank1) {
|
|
|
|
for (idx = 0xd0; idx < 0xe0; idx++) {
|
|
|
|
_writePages[idx] = _pages[idx][_altzp ? 2 : 1];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (idx = 0xd0; idx < 0xe0; idx++) {
|
|
|
|
_writePages[idx] = _pages[idx][_altzp ? 4 : 3];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (idx = 0xe0; idx < 0x100; idx++) {
|
|
|
|
_writePages[idx] = _pages[idx][_altzp ? 2 : 1];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (idx = 0xd0; idx < 0x100; idx++) {
|
|
|
|
_writePages[idx] = _pages[idx][0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The Big Switch
|
|
|
|
*/
|
|
|
|
|
|
|
|
function _access(off, val) {
|
|
|
|
var result;
|
2017-08-20 17:46:10 +00:00
|
|
|
var readMode = val === undefined;
|
2013-10-10 18:03:07 +00:00
|
|
|
switch (off) {
|
|
|
|
|
|
|
|
// Apple //e memory management
|
|
|
|
|
|
|
|
case LOC._80STOREOFF:
|
2016-12-06 05:16:21 +00:00
|
|
|
if (val !== undefined) {
|
2013-10-10 18:03:07 +00:00
|
|
|
_80store = false;
|
2017-03-05 22:51:59 +00:00
|
|
|
_debug('80 Store Off');
|
2020-01-02 18:57:26 +00:00
|
|
|
vm.page(_page2 ? 2 : 1);
|
2013-10-10 18:03:07 +00:00
|
|
|
} else {
|
|
|
|
// Chain to io for keyboard
|
|
|
|
result = io.ioSwitch(off, val);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOC._80STOREON:
|
2016-12-06 05:16:21 +00:00
|
|
|
if (val !== undefined) {
|
2013-10-10 18:03:07 +00:00
|
|
|
_80store = true;
|
2017-03-05 22:51:59 +00:00
|
|
|
_debug('80 Store On');
|
2016-11-22 05:17:34 +00:00
|
|
|
} else
|
2013-10-10 18:03:07 +00:00
|
|
|
result = 0;
|
|
|
|
break;
|
|
|
|
case LOC.RAMRDOFF:
|
2016-12-06 05:16:21 +00:00
|
|
|
if (val !== undefined) {
|
2013-10-10 18:03:07 +00:00
|
|
|
_auxRamRead = false;
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('Aux RAM Read Off');
|
2016-11-22 05:17:34 +00:00
|
|
|
} else
|
2013-10-10 18:03:07 +00:00
|
|
|
result = 0;
|
|
|
|
break;
|
|
|
|
case LOC.RAMRDON:
|
2016-12-06 05:16:21 +00:00
|
|
|
if (val !== undefined) {
|
2013-10-10 18:03:07 +00:00
|
|
|
_auxRamRead = true;
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('Aux RAM Read On');
|
2016-11-22 05:17:34 +00:00
|
|
|
} else
|
2013-10-10 18:03:07 +00:00
|
|
|
result = 0;
|
|
|
|
break;
|
|
|
|
case LOC.RAMWROFF:
|
2016-12-06 05:16:21 +00:00
|
|
|
if (val !== undefined) {
|
2013-10-10 18:03:07 +00:00
|
|
|
_auxRamWrite = false;
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('Aux RAM Write Off');
|
2016-11-22 05:17:34 +00:00
|
|
|
} else
|
2013-10-10 18:03:07 +00:00
|
|
|
result = 0;
|
|
|
|
break;
|
|
|
|
case LOC.RAMWRON:
|
2016-12-06 05:16:21 +00:00
|
|
|
if (val !== undefined) {
|
2013-10-10 18:03:07 +00:00
|
|
|
_auxRamWrite = true;
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('Aux RAM Write On');
|
2016-11-22 05:17:34 +00:00
|
|
|
} else
|
2013-10-10 18:03:07 +00:00
|
|
|
result = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LOC.INTCXROMOFF:
|
2016-12-06 05:16:21 +00:00
|
|
|
if (val !== undefined) {
|
2013-10-10 18:03:07 +00:00
|
|
|
_intcxrom = false;
|
2017-08-20 17:46:10 +00:00
|
|
|
_intc8rom = false;
|
2017-03-05 22:51:59 +00:00
|
|
|
_debug('Int CX ROM Off');
|
2013-10-10 18:03:07 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOC.INTCXROMON:
|
2016-12-06 05:16:21 +00:00
|
|
|
if (val !== undefined) {
|
2013-10-10 18:03:07 +00:00
|
|
|
_intcxrom = true;
|
2017-03-05 22:51:59 +00:00
|
|
|
_debug('Int CX ROM On');
|
2013-10-10 18:03:07 +00:00
|
|
|
}
|
|
|
|
break;
|
2016-11-22 05:17:34 +00:00
|
|
|
case LOC.ALTZPOFF: // 0x08
|
2016-12-06 05:16:21 +00:00
|
|
|
if (val !== undefined) {
|
2013-10-10 18:03:07 +00:00
|
|
|
_altzp = false;
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('Alt ZP Off');
|
2013-10-10 18:03:07 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOC.ALTZPON: // 0x09
|
2016-12-06 05:16:21 +00:00
|
|
|
if (val !== undefined) {
|
2013-10-10 18:03:07 +00:00
|
|
|
_altzp = true;
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('Alt ZP On');
|
2013-10-10 18:03:07 +00:00
|
|
|
}
|
|
|
|
break;
|
2017-08-20 17:46:10 +00:00
|
|
|
case LOC.SLOTC3ROMOFF: // 0x0A
|
|
|
|
if (val !== undefined) {
|
2013-10-10 18:03:07 +00:00
|
|
|
_slot3rom = false;
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('Slot 3 ROM Off');
|
2013-10-10 18:03:07 +00:00
|
|
|
}
|
|
|
|
break;
|
2017-08-20 17:46:10 +00:00
|
|
|
case LOC.SLOTC3ROMON: // 0x0B
|
2016-12-06 05:16:21 +00:00
|
|
|
if (val !== undefined) {
|
2013-10-10 18:03:07 +00:00
|
|
|
_slot3rom = true;
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('Slot 3 ROM On');
|
2013-10-10 18:03:07 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2019-03-01 05:21:18 +00:00
|
|
|
// Graphics Switches
|
2013-10-10 18:03:07 +00:00
|
|
|
|
|
|
|
case LOC.PAGE1:
|
2017-08-20 17:46:10 +00:00
|
|
|
_page2 = false;
|
|
|
|
if (!_80store) {
|
2016-12-06 05:16:21 +00:00
|
|
|
result = io.ioSwitch(off, val);
|
|
|
|
}
|
2017-08-20 17:46:10 +00:00
|
|
|
_debug('Page 2 off');
|
2013-10-10 18:03:07 +00:00
|
|
|
break;
|
|
|
|
case LOC.PAGE2:
|
2017-08-20 17:46:10 +00:00
|
|
|
_page2 = true;
|
|
|
|
if (!_80store) {
|
2016-12-06 05:16:21 +00:00
|
|
|
result = io.ioSwitch(off, val);
|
|
|
|
}
|
2017-08-20 17:46:10 +00:00
|
|
|
_debug('Page 2 on');
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LOC.RESET_HIRES:
|
|
|
|
_hires = false;
|
|
|
|
result = io.ioSwitch(off, val);
|
|
|
|
_debug('Hires off');
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LOC.SET_HIRES:
|
|
|
|
_hires = true;
|
|
|
|
result = io.ioSwitch(off, val);
|
|
|
|
_debug('Hires on');
|
2013-10-10 18:03:07 +00:00
|
|
|
break;
|
|
|
|
|
2019-03-01 05:21:18 +00:00
|
|
|
// Language Card Switches
|
2013-10-10 18:03:07 +00:00
|
|
|
|
|
|
|
case LOC.READBSR2: // 0xC080
|
2017-03-05 22:51:59 +00:00
|
|
|
case LOC._READBSR2: // 0xC084
|
2013-10-10 18:03:07 +00:00
|
|
|
_bank1 = false;
|
|
|
|
_readbsr = true;
|
|
|
|
_writebsr = false;
|
2017-03-05 22:51:59 +00:00
|
|
|
_prewrite = false;
|
|
|
|
// _debug('Bank 2 Read');
|
2013-10-10 18:03:07 +00:00
|
|
|
break;
|
|
|
|
case LOC.WRITEBSR2: // 0xC081
|
2017-03-05 22:51:59 +00:00
|
|
|
case LOC._WRITEBSR2: // 0xC085
|
2013-10-10 18:03:07 +00:00
|
|
|
_bank1 = false;
|
|
|
|
_readbsr = false;
|
2017-08-20 17:46:10 +00:00
|
|
|
if (readMode) { _writebsr = _prewrite; }
|
|
|
|
_prewrite = readMode;
|
2017-03-05 22:51:59 +00:00
|
|
|
// _debug('Bank 2 Write');
|
2013-10-10 18:03:07 +00:00
|
|
|
break;
|
|
|
|
case LOC.OFFBSR2: // 0xC082
|
2017-03-05 22:51:59 +00:00
|
|
|
case LOC._OFFBSR2: // 0xC086
|
2013-10-10 18:03:07 +00:00
|
|
|
_bank1 = false;
|
|
|
|
_readbsr = false;
|
|
|
|
_writebsr = false;
|
2017-03-05 22:51:59 +00:00
|
|
|
_prewrite = false;
|
|
|
|
// _debug('Bank 2 Off');
|
2013-10-10 18:03:07 +00:00
|
|
|
break;
|
|
|
|
case LOC.READWRBSR2: // 0xC083
|
2017-03-05 22:51:59 +00:00
|
|
|
case LOC._READWRBSR2: // 0xC087
|
2013-10-10 18:03:07 +00:00
|
|
|
_bank1 = false;
|
|
|
|
_readbsr = true;
|
2017-08-20 17:46:10 +00:00
|
|
|
if (readMode) { _writebsr = _prewrite; }
|
|
|
|
_prewrite = readMode;
|
2017-03-05 22:51:59 +00:00
|
|
|
// _debug('Bank 2 Read/Write');
|
2013-10-10 18:03:07 +00:00
|
|
|
break;
|
|
|
|
case LOC.READBSR1: // 0xC088
|
2017-03-05 22:51:59 +00:00
|
|
|
case LOC._READBSR1: // 0xC08c
|
2013-10-10 18:03:07 +00:00
|
|
|
_bank1 = true;
|
|
|
|
_readbsr = true;
|
|
|
|
_writebsr = false;
|
2017-03-05 22:51:59 +00:00
|
|
|
_prewrite = false;
|
|
|
|
// _debug('Bank 1 Read');
|
2013-10-10 18:03:07 +00:00
|
|
|
break;
|
|
|
|
case LOC.WRITEBSR1: // 0xC089
|
2017-03-05 22:51:59 +00:00
|
|
|
case LOC._WRITEBSR1: // 0xC08D
|
2013-10-10 18:03:07 +00:00
|
|
|
_bank1 = true;
|
|
|
|
_readbsr = false;
|
2017-08-20 17:46:10 +00:00
|
|
|
if (readMode) { _writebsr = _prewrite; }
|
|
|
|
_prewrite = readMode;
|
2017-03-05 22:51:59 +00:00
|
|
|
// _debug('Bank 1 Write');
|
2013-10-10 18:03:07 +00:00
|
|
|
break;
|
|
|
|
case LOC.OFFBSR1: // 0xC08A
|
2017-03-05 22:51:59 +00:00
|
|
|
case LOC._OFFBSR1: // 0xC08E
|
2013-10-10 18:03:07 +00:00
|
|
|
_bank1 = true;
|
|
|
|
_readbsr = false;
|
|
|
|
_writebsr = false;
|
2017-03-05 22:51:59 +00:00
|
|
|
_prewrite = false;
|
|
|
|
// _debug('Bank 1 Off');
|
2013-10-10 18:03:07 +00:00
|
|
|
break;
|
|
|
|
case LOC.READWRBSR1: // 0xC08B
|
2017-03-05 22:51:59 +00:00
|
|
|
case LOC._READWRBSR1: // 0xC08F
|
2013-10-10 18:03:07 +00:00
|
|
|
_bank1 = true;
|
|
|
|
_readbsr = true;
|
2017-08-20 17:46:10 +00:00
|
|
|
if (readMode) { _writebsr = _prewrite; }
|
|
|
|
_prewrite = readMode;
|
2017-03-05 22:51:59 +00:00
|
|
|
//_debug('Bank 1 Read/Write');
|
2013-10-10 18:03:07 +00:00
|
|
|
break;
|
|
|
|
|
2019-03-01 05:21:18 +00:00
|
|
|
// Status registers
|
2013-10-10 18:03:07 +00:00
|
|
|
|
|
|
|
case LOC.BSRBANK2:
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('Bank 2 Read ' + !_bank1);
|
2016-11-22 05:17:34 +00:00
|
|
|
result = !_bank1 ? 0x80 : 0x00;
|
2013-10-10 18:03:07 +00:00
|
|
|
break;
|
|
|
|
case LOC.BSRREADRAM:
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('Bank SW RAM Read ' + _readbsr);
|
2013-10-10 18:03:07 +00:00
|
|
|
result = _readbsr ? 0x80 : 0x00;
|
|
|
|
break;
|
|
|
|
case LOC.RAMRD: // 0xC013
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('Aux RAM Read ' + _auxRamRead);
|
2013-10-10 18:03:07 +00:00
|
|
|
result = _auxRamRead ? 0x80 : 0x0;
|
|
|
|
break;
|
|
|
|
case LOC.RAMWRT: // 0xC014
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('Aux RAM Write ' + _auxRamWrite);
|
2013-10-10 18:03:07 +00:00
|
|
|
result = _auxRamWrite ? 0x80 : 0x0;
|
|
|
|
break;
|
|
|
|
case LOC.INTCXROM: // 0xC015
|
2016-12-06 05:16:21 +00:00
|
|
|
// _debug('Int CX ROM ' + _intcxrom);
|
2013-10-10 18:03:07 +00:00
|
|
|
result = _intcxrom ? 0x80 : 0x00;
|
|
|
|
break;
|
|
|
|
case LOC.ALTZP: // 0xC016
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('Alt ZP ' + _altzp);
|
2013-10-10 18:03:07 +00:00
|
|
|
result = _altzp ? 0x80 : 0x0;
|
|
|
|
break;
|
|
|
|
case LOC.SLOTC3ROM: // 0xC017
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('Slot C3 ROM ' + _slot3rom);
|
|
|
|
result = _slot3rom ? 0x80 : 0x00;
|
2013-10-10 18:03:07 +00:00
|
|
|
break;
|
|
|
|
case LOC._80STORE: // 0xC018
|
2016-12-06 05:16:21 +00:00
|
|
|
_debug('80 Store ' + _80store);
|
2013-10-10 18:03:07 +00:00
|
|
|
result = _80store ? 0x80 : 0x00;
|
|
|
|
break;
|
2016-11-28 01:28:49 +00:00
|
|
|
case LOC.VERTBLANK: // 0xC019
|
2013-10-10 18:03:07 +00:00
|
|
|
// result = cpu.cycles() % 20 < 5 ? 0x80 : 0x00;
|
|
|
|
result = (cpu.cycles() < _vbEnd) ? 0x80 : 0x00;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2016-12-06 05:16:21 +00:00
|
|
|
debug('MMU missing register ' + toHex(off));
|
2013-10-10 18:03:07 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-03-05 22:51:59 +00:00
|
|
|
|
2013-10-10 18:03:07 +00:00
|
|
|
if (result !== undefined)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
result = 0;
|
|
|
|
|
|
|
|
_updateBanks();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
start: function mmu_start() {
|
2017-10-01 18:19:04 +00:00
|
|
|
lores1.start();
|
|
|
|
lores2.start();
|
2013-10-10 18:03:07 +00:00
|
|
|
return 0x00;
|
|
|
|
},
|
|
|
|
end: function mmu_end() {
|
|
|
|
return 0xff;
|
|
|
|
},
|
|
|
|
reset: function() {
|
2016-12-06 05:16:21 +00:00
|
|
|
debug('reset');
|
2013-10-10 18:03:07 +00:00
|
|
|
_initSwitches();
|
|
|
|
_updateBanks();
|
2017-08-20 17:46:10 +00:00
|
|
|
vm.reset();
|
2017-03-05 22:51:59 +00:00
|
|
|
io.reset();
|
2013-10-10 18:03:07 +00:00
|
|
|
},
|
2019-12-30 03:13:59 +00:00
|
|
|
read: function mmu_read(page, off) {
|
|
|
|
return _readPages[page].read(page, off);
|
2013-10-10 18:03:07 +00:00
|
|
|
},
|
|
|
|
write: function mmu_write(page, off, val) {
|
|
|
|
_writePages[page].write(page, off, val);
|
|
|
|
},
|
|
|
|
resetVB: function mmu_resetVB() {
|
|
|
|
_vbEnd = cpu.cycles() + 1000;
|
|
|
|
},
|
|
|
|
getState: function() {
|
|
|
|
return {
|
2017-12-03 04:45:02 +00:00
|
|
|
bank1: _bank1,
|
2013-10-10 18:03:07 +00:00
|
|
|
readbsr: _readbsr,
|
|
|
|
writebsr: _writebsr,
|
2017-03-05 22:51:59 +00:00
|
|
|
prewrite: _prewrite,
|
2013-10-10 18:03:07 +00:00
|
|
|
|
|
|
|
intcxrom: _intcxrom,
|
|
|
|
slot3rom: _slot3rom,
|
2017-08-20 17:46:10 +00:00
|
|
|
intc8rom: _intc8rom,
|
2017-12-03 04:45:02 +00:00
|
|
|
|
2013-10-10 18:03:07 +00:00
|
|
|
auxRamRead: _auxRamRead,
|
|
|
|
auxRamWrite: _auxRamWrite,
|
|
|
|
altzp: _altzp,
|
2016-11-22 05:17:34 +00:00
|
|
|
|
2013-10-10 18:03:07 +00:00
|
|
|
_80store: _80store,
|
|
|
|
page2: _page2,
|
2017-12-03 04:45:02 +00:00
|
|
|
hires: _hires,
|
2013-10-10 18:03:07 +00:00
|
|
|
|
|
|
|
mem00_01: [mem00_01[0].getState(), mem00_01[1].getState()],
|
|
|
|
mem02_03: [mem02_03[0].getState(), mem02_03[1].getState()],
|
|
|
|
mem0C_1F: [mem0C_1F[0].getState(), mem0C_1F[1].getState()],
|
|
|
|
mem60_BF: [mem60_BF[0].getState(), mem60_BF[1].getState()],
|
2017-03-05 22:51:59 +00:00
|
|
|
memD0_DF: [
|
|
|
|
memD0_DF[0].getState(), memD0_DF[1].getState(),
|
|
|
|
memD0_DF[2].getState(), memD0_DF[3].getState()
|
|
|
|
],
|
2013-10-10 18:03:07 +00:00
|
|
|
memE0_FF: [memE0_FF[0].getState(), memE0_FF[1].getState()]
|
|
|
|
};
|
|
|
|
},
|
|
|
|
setState: function(state) {
|
|
|
|
_readbsr = state.readbsr;
|
|
|
|
_writebsr = state.writebsr;
|
|
|
|
_bank1 = state.bank1;
|
2017-12-03 04:45:02 +00:00
|
|
|
_prewrite = state.prewrite;
|
2016-11-22 05:17:34 +00:00
|
|
|
|
2013-10-10 18:03:07 +00:00
|
|
|
_intcxrom = state.intcxrom;
|
|
|
|
_slot3rom = state.slot3rom;
|
2017-08-20 17:46:10 +00:00
|
|
|
_intc8rom = state.intc8rom;
|
2017-12-03 04:45:02 +00:00
|
|
|
|
2013-10-10 18:03:07 +00:00
|
|
|
_auxRamRead = state.auxRamRead;
|
|
|
|
_auxRamWrite = state.auxRamWrite;
|
|
|
|
_altzp = state.altzp;
|
2016-11-22 05:17:34 +00:00
|
|
|
|
2013-10-10 18:03:07 +00:00
|
|
|
_80store = state._80store;
|
|
|
|
_page2 = state.page2;
|
2017-12-03 04:45:02 +00:00
|
|
|
_hires = state.hires;
|
2013-10-10 18:03:07 +00:00
|
|
|
|
|
|
|
mem00_01[0].setState(state.mem00_01[0]);
|
|
|
|
mem00_01[1].setState(state.mem00_01[1]);
|
|
|
|
mem02_03[0].setState(state.mem02_03[0]);
|
|
|
|
mem02_03[1].setState(state.mem02_03[1]);
|
|
|
|
mem0C_1F[0].setState(state.mem0C_1F[0]);
|
|
|
|
mem0C_1F[1].setState(state.mem0C_1F[1]);
|
|
|
|
mem60_BF[0].setState(state.mem60_BF[0]);
|
|
|
|
mem60_BF[1].setState(state.mem60_BF[1]);
|
|
|
|
memD0_DF[0].setState(state.memD0_DF[0]);
|
|
|
|
memD0_DF[1].setState(state.memD0_DF[1]);
|
|
|
|
memD0_DF[2].setState(state.memD0_DF[2]);
|
|
|
|
memD0_DF[3].setState(state.memD0_DF[3]);
|
|
|
|
memE0_FF[0].setState(state.memE0_FF[0]);
|
|
|
|
memE0_FF[1].setState(state.memE0_FF[1]);
|
|
|
|
|
2017-12-03 04:45:02 +00:00
|
|
|
_updateBanks();
|
2013-10-10 18:03:07 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|