cleaned up bank switching; confirmed against ITA2E and UTA2E

This commit is contained in:
Jorj Bauer 2017-02-28 13:31:30 -05:00
parent c2e117745f
commit 7293bd42e6
2 changed files with 108 additions and 92 deletions

View File

@ -101,10 +101,11 @@ void AppleMMU::write(uint16_t address, uint8_t v)
} }
// Don't allow writes to ROM // Don't allow writes to ROM
// Hard ROM, I/O, slots, whatnot
if (address >= 0xC100 && address <= 0xCFFF) if (address >= 0xC100 && address <= 0xCFFF)
return; return;
// Bank-switched ROM/RAM areas
if (address >= 0xD000 && address <= 0xFFFF && !writebsr) { if (address >= 0xD000 && address <= 0xFFFF && !writebsr) {
// memory-protected, so don't allow writes
return; return;
} }
@ -147,11 +148,9 @@ void AppleMMU::handleMemorySwitches(uint16_t address, uint16_t lastSwitch)
case 0xC000: // CLR80STORE case 0xC000: // CLR80STORE
switches &= ~S_80STORE; switches &= ~S_80STORE;
updateMemoryPages();
break; break;
case 0xC001: // SET80STORE case 0xC001: // SET80STORE
switches |= S_80STORE; switches |= S_80STORE;
updateMemoryPages();
break; break;
case 0xC002: // CLRAUXRD read from main 48k RAM case 0xC002: // CLRAUXRD read from main 48k RAM
auxRamRead = false; auxRamRead = false;
@ -184,62 +183,53 @@ void AppleMMU::handleMemorySwitches(uint16_t address, uint16_t lastSwitch)
slot3rom = true; slot3rom = true;
break; break;
// these are probably read/write ? // Registers C080 - C08F control bank switching.
case 0xC080:
case 0xC080: // READBSR2 and shadow copy case 0xC081:
case 0xC084:
bank1 = false; // LC RAM bank2, Read and Write-prot RAM
readbsr = true; // read from bank2
writebsr = false; // write-protected
break;
case 0xC081: // ROMIN
case 0xC085:
bank1 = false; // LC RAM bank2, read ROM, write-enable RAM
readbsr = false; // if it's read twice in a row
writebsr = writebsr || ((lastSwitch & 0xF3) == (address & 0xF3));
break;
case 0xC082: case 0xC082:
case 0xC083:
case 0xC084:
case 0xC085:
case 0xC086: case 0xC086:
bank1 = false; // LC RAM bank2, Read ROM instead of RAM,
readbsr = false; // WR-protect RAM
writebsr = false;
break;
case 0xC083: // READWRBSR2
case 0xC087: case 0xC087:
bank1 = false; case 0xC088:
readbsr = true; case 0xC089:
writebsr = writebsr || ((lastSwitch & 0xF3) == (address & 0xF3)); case 0xC08A:
break; case 0xC08B:
case 0xC088: // READBSR1
case 0xC08C: case 0xC08C:
bank1 = true;
readbsr = true;
writebsr = false;
break;
case 0xC089: // WRITEBSR1
case 0xC08D: case 0xC08D:
bank1 = true;
readbsr = false;
writebsr = writebsr || ((lastSwitch & 0xF3) == (address & 0xF3));
break;
case 0xC08A: // OFFBSR1
case 0xC08E: case 0xC08E:
bank1 = true;
readbsr = false;
writebsr = false;
break;
case 0xC08B: // READWRBSR1
case 0xC08F: case 0xC08F:
bank1 = true;
readbsr = true; // Per ITA2E, p. 286:
writebsr = writebsr || ((lastSwitch & 0xF3) == (address & 0xF3)); // (address & 0x08) controls whether or not we are selecting from bank2. Per table 8-2,
// bank2 is active if address & 0x08 is zero. So if the bit is on, it's bank 1.
bank2 = (address & 0x08) ? false : true;
// (address & 0x04) is unused.
// (address & 0x02) is read-select: if it is set the same as
// (address & 0x01) then readbsr is true.
readbsr = ((address & 0x02) >> 1) == (address & 0x01);
// (address & 0x01) is write-select: if 1, we write BSR RAM; if 0, we write ROM.
// But it's a little more complicated than readbsr.
// Per UTA2E p. 5-23:
// "Writing to high RAM is enabled when the HRAMWRT' soft switch
// is reset. ... It is reset by even read access or any write
// access in the $C08X range. HRAMWRT' is reset by odd read
// access in the $C08X range when PRE-WRITE is set. It is set by
// even access in the CC08X range. Any other type of access
// causes HRAMWRT' to hold its current state."
if (address & 0x01) {
if (preWriteFlag)
writebsr = 1;
// Per UTA2E, p. 5-23: any other preWriteFlag leaves writebsr unchanged.
} else {
writebsr = false;
}
break; break;
} }
@ -325,6 +315,11 @@ uint8_t AppleMMU::readSwitches(uint16_t address)
case 0xC08F: case 0xC08F:
// but read does affect these, same as write // but read does affect these, same as write
handleMemorySwitches(address, lastReadSwitch); handleMemorySwitches(address, lastReadSwitch);
// UTA2E, p. 5-23: preWrite is set by odd read access, and reset
// by even read access
preWriteFlag = (address & 0x01);
break; break;
case 0xC00C: // CLR80VID disable 80-col video mode case 0xC00C: // CLR80VID disable 80-col video mode
@ -349,7 +344,7 @@ uint8_t AppleMMU::readSwitches(uint16_t address)
case 0xC011: // RDLCBNK2 case 0xC011: // RDLCBNK2
return bank1 ? 0x00 : 0x80; return bank2 ? 0x80 : 0x00;
case 0xC012: // RDLCRAM case 0xC012: // RDLCRAM
return readbsr ? 0x80 : 0x00; return readbsr ? 0x80 : 0x00;
case 0xC013: // RDRAMRD case 0xC013: // RDRAMRD
@ -606,18 +601,6 @@ void AppleMMU::writeSwitches(uint16_t address, uint8_t v)
writePages[0xC0][0x64] = writePages[0xC0][0x65] = 0xFF; writePages[0xC0][0x64] = writePages[0xC0][0x65] = 0xFF;
break; break;
case 0xC000:
case 0xC001:
case 0xC002:
case 0xC003:
case 0xC004:
case 0xC005:
case 0xC006:
case 0xC007:
case 0xC008:
case 0xC009:
case 0xC00A:
case 0xC00B:
case 0xC080: case 0xC080:
case 0xC081: case 0xC081:
case 0xC082: case 0xC082:
@ -634,6 +617,21 @@ void AppleMMU::writeSwitches(uint16_t address, uint8_t v)
case 0xC08D: case 0xC08D:
case 0xC08E: case 0xC08E:
case 0xC08F: case 0xC08F:
// UTA2E, p. 5-23: preWrite is reset by any write access to these
preWriteFlag = 0;
// fall through...
case 0xC000:
case 0xC001:
case 0xC002:
case 0xC003:
case 0xC004:
case 0xC005:
case 0xC006:
case 0xC007:
case 0xC008:
case 0xC009:
case 0xC00A:
case 0xC00B:
handleMemorySwitches(address, lastWriteSwitch); handleMemorySwitches(address, lastWriteSwitch);
break; break;
@ -679,13 +677,19 @@ void AppleMMU::resetRAM()
{ {
switches = S_TEXT; switches = S_TEXT;
bank1 = true; // Per UTA2E, p. 5-23:
// When a system reset occurs, all MMU soft switches are reset (turned off).
bank2 = false;
auxRamRead = auxRamWrite = false; auxRamRead = auxRamWrite = false;
readbsr = writebsr = false; readbsr = writebsr = false;
altzp = false; altzp = false;
intcxrom = false; intcxrom = false;
slot3rom = false; slot3rom = false;
preWriteFlag = false;
// Clear all the pages
for (uint8_t i=0; i<0xFF; i++) { for (uint8_t i=0; i<0xFF; i++) {
for (uint8_t j=0; j<5; j++) { for (uint8_t j=0; j<5; j++) {
if (ramPages[i][j]) { if (ramPages[i][j]) {
@ -694,42 +698,42 @@ void AppleMMU::resetRAM()
} }
} }
} }
// and set our expectation of what we're reading from/writing to
readPages[i] = writePages[i] = ramPages[i][0]; readPages[i] = writePages[i] = ramPages[i][0];
} }
// Load ROM // Load system ROM
for (uint16_t i=0x80; i<=0xFF; i++) {
for (uint16_t k=0; k<0x100; k++) {
uint16_t idx = ((i-0x80) << 8) | k;
#ifdef TEENSYDUINO #ifdef TEENSYDUINO
for (uint16_t i=0x80; i<=0xFF; i++) {
for (uint16_t k=0; k<0x100; k++) {
uint16_t idx = ((i-0x80) << 8) | k;
uint8_t v = pgm_read_byte(&romData[idx]); uint8_t v = pgm_read_byte(&romData[idx]);
for (uint8_t j=0; j<5; j++) {
if (ramPages[i][j]) {
ramPages[i][j][k] = v;
}
}
}
}
#else #else
for (uint16_t i=0x80; i<=0xFF; i++) {
for (uint16_t k=0; k<0x100; k++) {
uint16_t idx = ((i-0x80) << 8) | k;
uint8_t v = romData[idx]; uint8_t v = romData[idx];
for (uint8_t j=0; j<5; j++) { #endif
for (int j=0; j<5; j++) {
// FIXME: not sure why this has to update pages [0] and [1] to
// work; find out what the //e really did
for (uint8_t j=0; j<2; j++) {
if (ramPages[i][j]) { if (ramPages[i][j]) {
ramPages[i][j][k] = v; ramPages[i][j][k] = v;
} }
} }
} }
} }
#endif }
// have each slot load its ROM
for (uint8_t slotnum = 0; slotnum <= 7; slotnum++) { for (uint8_t slotnum = 0; slotnum <= 7; slotnum++) {
if (slots[slotnum]) { if (slots[slotnum]) {
slots[slotnum]->loadROM(ramPages[0xC0 + slotnum][0]); slots[slotnum]->loadROM(ramPages[0xC0 + slotnum][0]);
} }
} }
// update the memory read/write flags &c. Not strictly necessary, if
// we're really setting all the RAM flags to the right default
// settings above - but better safe than sorry?
updateMemoryPages();
} }
void AppleMMU::setSlot(int8_t slotnum, Slot *peripheral) void AppleMMU::setSlot(int8_t slotnum, Slot *peripheral)
@ -820,6 +824,7 @@ void AppleMMU::updateMemoryPages()
} }
} }
// set zero-page & stack pages based on altzp flag
if (altzp) { if (altzp) {
for (uint8_t idx = 0x00; idx < 0x02; idx++) { for (uint8_t idx = 0x00; idx < 0x02; idx++) {
readPages[idx] = ramPages[idx][1]; readPages[idx] = ramPages[idx][1];
@ -832,33 +837,42 @@ void AppleMMU::updateMemoryPages()
} }
} }
// Set bank-switched ram reading from readbsr & bank2
if (readbsr) { if (readbsr) {
if (bank1) { // 0xD0 - 0xE0 has 4 possible banks:
if (!bank2) {
// Bank 1 RAM: either in main RAM (1) or in the extended memory
// card (3):
for (uint8_t idx = 0xd0; idx < 0xe0; idx++) { for (uint8_t idx = 0xd0; idx < 0xe0; idx++) {
readPages[idx] = ramPages[idx][altzp ? 2 : 1]; readPages[idx] = ramPages[idx][altzp ? 3 : 1];
} }
} else { } else {
// Bank 2 RAM: either in main RAM (2) or in the extended memory
// card (4):
for (uint8_t idx = 0xd0; idx < 0xe0; idx++) { for (uint8_t idx = 0xd0; idx < 0xe0; idx++) {
readPages[idx] = ramPages[idx][altzp ? 4 : 3]; readPages[idx] = ramPages[idx][altzp ? 4 : 2];
} }
} }
// ... but 0xE0 - 0xFF has just the motherboard RAM (1) and
// extended memory card RAM (2):
for (uint16_t idx = 0xe0; idx < 0x100; idx++) { for (uint16_t idx = 0xe0; idx < 0x100; idx++) {
readPages[idx] = ramPages[idx][altzp ? 2 : 1]; readPages[idx] = ramPages[idx][altzp ? 2 : 1];
} }
} else { } else {
// Built-in ROM
for (uint16_t idx = 0xd0; idx < 0x100; idx++) { for (uint16_t idx = 0xd0; idx < 0x100; idx++) {
readPages[idx] = ramPages[idx][0]; readPages[idx] = ramPages[idx][0];
} }
} }
if (writebsr) { if (writebsr) {
if (bank1) { if (!bank2) {
for (uint8_t idx = 0xd0; idx < 0xe0; idx++) { for (uint8_t idx = 0xd0; idx < 0xe0; idx++) {
writePages[idx] = ramPages[idx][altzp ? 2 : 1]; writePages[idx] = ramPages[idx][altzp ? 3 : 1];
} }
} else { } else {
for (uint8_t idx = 0xd0; idx < 0xe0; idx++) { for (uint8_t idx = 0xd0; idx < 0xe0; idx++) {
writePages[idx] = ramPages[idx][altzp ? 4 : 3]; writePages[idx] = ramPages[idx][altzp ? 4 : 2];
} }
} }
for (uint16_t idx = 0xe0; idx < 0x100; idx++) { for (uint16_t idx = 0xe0; idx < 0x100; idx++) {

View File

@ -66,13 +66,15 @@ class AppleMMU : public MMU {
public: // 'public' for debugging public: // 'public' for debugging
bool auxRamRead; bool auxRamRead;
bool auxRamWrite; bool auxRamWrite;
bool bank1; bool bank2;
bool readbsr; bool readbsr;
bool writebsr; bool writebsr;
bool altzp; bool altzp;
bool intcxrom; bool intcxrom;
bool slot3rom; bool slot3rom;
bool preWriteFlag; // see UTA2E p. 5-23
Slot *slots[8]; // slots 0-7 Slot *slots[8]; // slots 0-7
uint8_t *ramPages[0x100][5]; uint8_t *ramPages[0x100][5];