GSjs/apple_iic_memory.js

300 lines
10 KiB
JavaScript

function AppleIIcMemory() {
this.bank0 = new Array(65536);
this.bank1 = new Array(65536);
this.rom = new Array(12288);
this.lastRead = 0x0000; // used to detect write protection disable
// (requires two subsequent reads at the same address)
this.hardReset(); // set the default states
}
AppleIIcMemory.prototype.hardReset = function() {
// Soft switches - start in default state
this.altzp = this.bank0; // altzp = 0; use main bank
this.enlcram = false; // read rom
this.offset = 0x1000; // offset (for upper bank switched ROM/RAM)
// offset for bank 1 = 0x0000, offset for bank2 = 0x1000
this.nowrite = false; // write upper 16Kram
this.ramrd = this.bank0; // read from main 48K bank
this.ramwrt = this.bank0; // write to main 48K bank
this.store80 = false; // RAMRD/RAMWRT controls lower 48K
this.page2 = this.bank0; // text/graphics on main bank (if store80 enabled)
this.hires = false; // text display mode
this.altchar = false; // display primary character set
this.col80 = false; // 40 character text
this.textmode = true; // display text
this.mixed = false; // display only text
this.ioudis = true; // disable access to IOU (mouse hardware)
this.dhires = false; // double high resolution off
};
AppleIIcMemory.prototype.setData = function(addr, data) {
if (addr < 0x0200) {
// Switched zero page and stack: controlled by ALTZP
this.altzp[addr] = data;
} else if (addr < 0xC000) {
// 48K bank switched RAM: controlled by 80STORE & RAMWRT
var ram = this.ramwrt;
if (this.store80) {
// 80STORE is enabled: this affects the text page separately
if (addr >= 0x0300 && addr < 0x0700) {
ram = this.page2;
} else if (this.hires && addr >= 0x2000 && add < 0x3F00) {
ram = this.page2;
}
}
ram[addr] = data;
} else if (addr < 0xC100) {
// Hardware page
switch(addr) {
case 0xC000: // action:W - 80STORE Off: RAMRD and RAMWRT determine RAM locations
this.store80 = false;
break;
case 0xC001: // action:W - 80STORE On: PAGE2 switches between TLP1 and TLP1X
this.store80 = true;
break;
case 0xC002: // action:W - RAMRD Off: read main 48K bank
this.ramrd = this.bank0;
break;
case 0xC003: // action:W - RAMRD On: read auxiliary 48K bank
this.ramrd = this.bank1;
break;
case 0xC004: // action:W - RAMWRT Off: write to main 48K bank
this.ramwrt = this.bank0;
break;
case 0xC005: // action:W - RAMWRT On: write to auxiliary 48K bank
this.ramwrt = this.bank1;
break;
case 0xC008: // action:W - ALTZP Off: use main 16K bank, page 0 and page 1
this.altzp = this.bank0;
break;
case 0xC00D: // action:W - 80COL Off: display 40 columns
this.col80 = false;
break;
case 0xC00E: // action:W - 80COL On: display 80 columns
this.col80 = true;
break;
case 0xC00E: // action:W - ALTCHAR Off: display text using primary character set
this.altchar = false;
break;
case 0xC00E: // action:W - ALTCHAR On: display text using alternate character set
this.altchar = true;
break;
case 0xC010: // action:W - ALTZP On: use auxiliary 16K bank, page 0 and page 1
this.altzp = this.bank1;
break;
case 0xC050: // action:RW - TXTCLR, display graphics
this.textmode = false;
break;
case 0xC051: // action:RW - TXTSET, display text
this.textmode = true;
break;
case 0xC052: // action:RW - MIXCLR, display full screen
this.mixed = false;
break;
case 0xC053: // action:RW - MIXSET, display split screen
this.mixed = true;
break;
case 0xC054: // action:RW - PAGE2 Off: Select TLP1 and HRP1
this.page2 = this.bank0;
break;
case 0xC055: // action:RW - PAGE2 On: Select TLP2 and HRP2 (or TLP1X and HRP1X if 80STORE on)
this.page2 = this.bank1;
break;
case 0xC056: // action:RW - HIRES Off: Display text and lo resolution page
this.hires = false;
break;
case 0xC057: // action:RW - HIRES On: Display high resolution pages, switch with PAGE2
this.hires = true;
break;
case 0xC05E: // action:RW - DHIRES On: Turn on double high resolution
if (this.iodis) this.dhires = true;
break;
case 0xC05F: // action:RW - DHIRES Off: Turn off double high resolution
if (this.ioudis) this.dhires = false;
break;
case 0xC078:
case 0xC07E: // action:W - IOUDIS On: enable access to DIHRES switch; disable IOU access to $C058-$C05F
this.ioudis = true;
break;
case 0xC079:
case 0xC07F: // action:W - IOUDIS Off: disable access to DIHRES switch; enable IOU access to $C058-$C05F
this.ioudis = false;
break;
default:
}
} else if (addr < 0xD000) {
// I/O Firmware
} else {
// 12K ROM & 16K bank switched RAM
if (! this.nowrite) {
// only take action if write protection is disabled
this.altzp[addr-this.offset] = data;
}
}
};
// Return an 8-bit chuck of data at a given address
AppleIIcMemory.prototype.getData = function(addr) {
var data, ram;
if (addr < 0x0200) {
// Switched zero page and stack: controlled by ALTZP
data = this.altzp[addr];
} else if (addr < 0xC000) {
// 48K bank switched RAM: controlled by RAMRD
ram = this.ramrd;
if (this.store80) {
// 80STORE is enabled: this affects the text page separately
if (addr >= 0x0300 && addr < 0x0700) {
ram = this.page2;
} else if (this.hires && addr >= 0x2000 && add < 0x3F00) {
ram = this.page2;
}
}
data = ram[addr];
} else if (addr < 0xC100) {
// Hardware page
switch(addr) {
case 0xC011: // action:R7 - RDBNK2, read whether $D000 bank 2 (1) or bank 1 (0)
data = (this.offset === 0x1000) << 7;
break;
case 0xC012: // action:R - RDLCRAM, reading RAM (1) or ROM (0)
data = this.enlcram << 7;
break;
case 0xC013: // action:R7 - RDRAMRD, reading auxiliary (1) or main (0) 48K bank
data = (this.ramrd === this.bank1) << 7;
break;
case 0xC014: // action:R7 - RDRAMWRT, writing auxiliary (1) or main (0) 48K bank
data = (this.ramwrt === this.bank1) << 7;
break;
case 0xC017: // action:R7 - RDALTZP, read whether auxiliary (1) or main (0) bank
data = (this.altzp === this.bank1) << 7;
break;
case 0xC018: // action:R7 - RD80STORE, read whether 80STORE is on (1) or off (0);
data = this.store80 << 7;
break;
case 0xC01A: // action:R7 - RDTEXT, read whether TEXT is on (1) or off (0);
data = this.textmode << 7;
break;
case 0xC01B: // action:R7 - RDMIXED, read whether MIXED is on (1) or off (0);
data = this.mixed << 7;
break;
case 0xC01C: // action:R7 - RDPAGE2, read whether PAGE2 is on (1) or off (0);
data = (this.page2 === this.bank1) << 7;
break;
case 0xC01D: // action:R7 - RDHIRES, read whether HIRES is on (1) or off (0);
data = this.hires << 7;
break;
case 0xC01E: // action:R7 - RDALTCHAR, read whether ALTCHAR is on (1) of off (0)
data = this.altchar << 7;
break;
case 0xC01F: // action:R7 - RD80COL, read whether 80COL is on (1) or off (0)
data = this.col80 << 7;
break;
case 0xC050: // action:RW - TXTCLR, display graphics
this.textmode = false;
break;
case 0xC051: // action:RW - TXTSET, display text
this.textmode = true;
break;
case 0xC052: // action:RW - MIXCLR, display full screen
this.mixed = false;
break;
case 0xC053: // action:RW - MIXSET, display split screen
this.mixed = true;
break;
case 0xC054: // action:RW - PAGE2 Off: Select TLP1 and HRP1
this.page2 = this.bank0;
break;
case 0xC055: // action:RW - PAGE2 On: Select TLP2 and HRP2 (or TLP1X and HRP1X if 80STORE on)
this.page2 = this.bank1;
break;
case 0xC056: // action:RW - HIRES Off: Display text and lo resolution page
this.hires = false;
break;
case 0xC057: // action:RW - HIRES On: Display high resolution pages, switch with PAGE2
this.hires = true;
break;
case 0xC05E: // action:RW - DHIRES On: Turn on double high resolution
if (this.ioudis) this.dhires = true;
break;
case 0xC05F: // action:RW - DHIRES Off: Turn off double high resolution
if (this.ioudis) this.dhires = false;
break;
case 0xC07E: // action:R7 - RIOUDIS, read whether IOUDIS is on (0) or off (1)
data = this.ioudis << 7;
break;
case 0xC07F: // action:R7 - RDDHIRES, read whether DHIRES is on (1) or off (0)
data = this.dhires << 7;
break;
case 0xC080: // action:R - read RAM, no write; use $D000 bank 2
this.enlcram = true;
this.offset = 0x1000;
this.nowrite = true;
break;
case 0xC081: // action:RR - read ROM, write RAM; use $D000 bank 2
this.enlcram = false;
this.offset = 0x1000;
this.nowrite = (this.lastRead !== 0xC081);
break;
case 0xC082: // action:R - read ROM, no write; use $D000 bank 2
this.enlcram = false;
this.offset = 0x1000;
this.nowrite = true;
break;
case 0xC083: // action:RR - read and write RAM; use $D000 bank 2
this.enlcram = true;
this.offset = 0x1000;
this.nowrite = (this.lastRead !== 0xC083);
break;
case 0xC088: // action:R - read RAM, no write; use $D000 bank 1
this.enlcram = true;
this.offset = 0x0000;
this.nowrite = true;
break;
case 0xC089: // action:RR - read ROM, write RAM; use $D000 bank 1
this.enlcram = false;
this.offset = 0x0000;
this.nowrite = (this.lastRead !== 0xC089);
break;
case 0xC08A: // action:R - read ROM, no write; use $D000 bank 1
this.enlcram = false;
this.offset = 0x0000;
this.nowrite = true;
break;
case 0xC08B: // action:RR - read and write RAM; use $D000 bank 1
this.enlcram = true;
this.offset = 0x0000;
this.nowrite = (this.lastRead !== 0xC08B);
break;
default:
data = 0x00;
}
} else if (addr < 0xD000) {
// I/O Firmware
} else {
// 12K ROM & 16K bank switched RAM
if (! this.enlcram) {
// Read ROM
data = this.rom[addr - 0xD000];
} else {
data = this.altzp[addr-this.offset];
}
}
this.lastRead = addr;
return data;
};
// Return a 16-bit chuck of data at a given address
AppleIIcMemory.prototype.getAddr = function(addr) {
return this.getData(addr) | this.getData[(addr+1) & 0xFFFF] << 8;
};