Files
bsnes/sfc/cpu/mmio/mmio.cpp
Tim Allen d1ffd59c29 Update to v095r04 release.
Changelog:
- S-SMP core code style updated
- S-SMP loads reset vector from IPLROM ($fffe-ffff)
- sfc/base => sfc/expansion
- system/input => system/device
- added expansion/eBoot (simulation of defparam's SNES-Boot device)
- expansion port device can now be selected from Super Famicom menu
  option
- improved GBA MROM/SRAM reading

endrift's memory test is up to 1388/1552.

Note: I added the expansion port devices to the same group as controller
ports. I also had to move "None" to the top of the list. Before v096,
I am going to have to add caching of port selections to the
configuration file, check the proper default item in the system menu,
and remove the items with no mappings from the input configuration
window. Lots of work >_>
2015-11-10 22:11:29 +11:00

520 lines
12 KiB
C++

#ifdef CPU_CPP
uint8 CPU::pio() { return status.pio; }
bool CPU::joylatch() { return status.joypad_strobe_latch; }
//WMDATA
uint8 CPU::mmio_r2180() {
return bus.read(0x7e0000 | status.wram_addr++);
}
//WMDATA
void CPU::mmio_w2180(uint8 data) {
bus.write(0x7e0000 | status.wram_addr++, data);
}
//WMADDL
void CPU::mmio_w2181(uint8 data) {
status.wram_addr = (status.wram_addr & 0x01ff00) | (data << 0);
}
//WMADDM
void CPU::mmio_w2182(uint8 data) {
status.wram_addr = (status.wram_addr & 0x0100ff) | (data << 8);
}
//WMADDH
void CPU::mmio_w2183(uint8 data) {
status.wram_addr = (status.wram_addr & 0x00ffff) | (data << 16);
}
//JOYSER0
//bit 0 is shared between JOYSER0 and JOYSER1, therefore
//strobing $4016.d0 affects both controller port latches.
//$4017 bit 0 writes are ignored.
void CPU::mmio_w4016(uint8 data) {
device.controllerPort1->latch(data & 1);
device.controllerPort2->latch(data & 1);
}
//JOYSER0
//7-2 = MDR
//1-0 = Joypad serial data
uint8 CPU::mmio_r4016() {
uint8 r = regs.mdr & 0xfc;
r |= device.controllerPort1->data();
return r;
}
//JOYSER1
//7-5 = MDR
//4-2 = Always 1 (pins are connected to GND)
//1-0 = Joypad serial data
uint8 CPU::mmio_r4017() {
uint8 r = (regs.mdr & 0xe0) | 0x1c;
r |= device.controllerPort2->data();
return r;
}
//NMITIMEN
void CPU::mmio_w4200(uint8 data) {
status.auto_joypad_poll = data & 1;
nmitimen_update(data);
}
//WRIO
void CPU::mmio_w4201(uint8 data) {
if((status.pio & 0x80) && !(data & 0x80)) ppu.latch_counters();
status.pio = data;
}
//WRMPYA
void CPU::mmio_w4202(uint8 data) {
status.wrmpya = data;
}
//WRMPYB
void CPU::mmio_w4203(uint8 data) {
status.rdmpy = 0;
if(alu.mpyctr || alu.divctr) return;
status.wrmpyb = data;
status.rddiv = (status.wrmpyb << 8) | status.wrmpya;
alu.mpyctr = 8; //perform multiplication over the next eight cycles
alu.shift = status.wrmpyb;
}
//WRDIVL
void CPU::mmio_w4204(uint8 data) {
status.wrdiva = (status.wrdiva & 0xff00) | (data << 0);
}
//WRDIVH
void CPU::mmio_w4205(uint8 data) {
status.wrdiva = (status.wrdiva & 0x00ff) | (data << 8);
}
//WRDIVB
void CPU::mmio_w4206(uint8 data) {
status.rdmpy = status.wrdiva;
if(alu.mpyctr || alu.divctr) return;
status.wrdivb = data;
alu.divctr = 16; //perform division over the next sixteen cycles
alu.shift = status.wrdivb << 16;
}
//HTIMEL
void CPU::mmio_w4207(uint8 data) {
status.hirq_pos = (status.hirq_pos & 0x0100) | (data << 0);
}
//HTIMEH
void CPU::mmio_w4208(uint8 data) {
status.hirq_pos = (status.hirq_pos & 0x00ff) | (data << 8);
}
//VTIMEL
void CPU::mmio_w4209(uint8 data) {
status.virq_pos = (status.virq_pos & 0x0100) | (data << 0);
}
//VTIMEH
void CPU::mmio_w420a(uint8 data) {
status.virq_pos = (status.virq_pos & 0x00ff) | (data << 8);
}
//DMAEN
void CPU::mmio_w420b(uint8 data) {
for(unsigned i = 0; i < 8; i++) {
channel[i].dma_enabled = data & (1 << i);
}
if(data) status.dma_pending = true;
}
//HDMAEN
void CPU::mmio_w420c(uint8 data) {
for(unsigned i = 0; i < 8; i++) {
channel[i].hdma_enabled = data & (1 << i);
}
}
//MEMSEL
void CPU::mmio_w420d(uint8 data) {
status.rom_speed = (data & 1 ? 6 : 8);
}
//RDNMI
//7 = NMI acknowledge
//6-4 = MDR
//3-0 = CPU (5a22) version
uint8 CPU::mmio_r4210() {
uint8 r = (regs.mdr & 0x70);
r |= (uint8)(rdnmi()) << 7;
r |= (cpu_version & 0x0f);
return r;
}
//TIMEUP
//7 = IRQ acknowledge
//6-0 = MDR
uint8 CPU::mmio_r4211() {
uint8 r = (regs.mdr & 0x7f);
r |= (uint8)(timeup()) << 7;
return r;
}
//HVBJOY
//7 = VBLANK acknowledge
//6 = HBLANK acknowledge
//5-1 = MDR
//0 = JOYPAD acknowledge
uint8 CPU::mmio_r4212() {
uint8 r = (regs.mdr & 0x3e);
if(status.auto_joypad_active) r |= 0x01;
if(hcounter() <= 2 || hcounter() >= 1096) r |= 0x40; //hblank
if(vcounter() >= (ppu.overscan() == false ? 225 : 240)) r |= 0x80; //vblank
return r;
}
//RDIO
uint8 CPU::mmio_r4213() {
return status.pio;
}
//RDDIVL
uint8 CPU::mmio_r4214() {
return status.rddiv >> 0;
}
//RDDIVH
uint8 CPU::mmio_r4215() {
return status.rddiv >> 8;
}
//RDMPYL
uint8 CPU::mmio_r4216() {
return status.rdmpy >> 0;
}
//RDMPYH
uint8 CPU::mmio_r4217() {
return status.rdmpy >> 8;
}
uint8 CPU::mmio_r4218() { return status.joy1 >> 0; } //JOY1L
uint8 CPU::mmio_r4219() { return status.joy1 >> 8; } //JOY1H
uint8 CPU::mmio_r421a() { return status.joy2 >> 0; } //JOY2L
uint8 CPU::mmio_r421b() { return status.joy2 >> 8; } //JOY2H
uint8 CPU::mmio_r421c() { return status.joy3 >> 0; } //JOY3L
uint8 CPU::mmio_r421d() { return status.joy3 >> 8; } //JOY3H
uint8 CPU::mmio_r421e() { return status.joy4 >> 0; } //JOY4L
uint8 CPU::mmio_r421f() { return status.joy4 >> 8; } //JOY4H
//DMAPx
uint8 CPU::mmio_r43x0(uint8 i) {
return (channel[i].direction << 7)
| (channel[i].indirect << 6)
| (channel[i].unused << 5)
| (channel[i].reverse_transfer << 4)
| (channel[i].fixed_transfer << 3)
| (channel[i].transfer_mode << 0);
}
//BBADx
uint8 CPU::mmio_r43x1(uint8 i) {
return channel[i].dest_addr;
}
//A1TxL
uint8 CPU::mmio_r43x2(uint8 i) {
return channel[i].source_addr >> 0;
}
//A1TxH
uint8 CPU::mmio_r43x3(uint8 i) {
return channel[i].source_addr >> 8;
}
//A1Bx
uint8 CPU::mmio_r43x4(uint8 i) {
return channel[i].source_bank;
}
//DASxL
//union { uint16 transfer_size; uint16 indirect_addr; };
uint8 CPU::mmio_r43x5(uint8 i) {
return channel[i].transfer_size >> 0;
}
//DASxH
//union { uint16 transfer_size; uint16 indirect_addr; };
uint8 CPU::mmio_r43x6(uint8 i) {
return channel[i].transfer_size >> 8;
}
//DASBx
uint8 CPU::mmio_r43x7(uint8 i) {
return channel[i].indirect_bank;
}
//A2AxL
uint8 CPU::mmio_r43x8(uint8 i) {
return channel[i].hdma_addr >> 0;
}
//A2AxH
uint8 CPU::mmio_r43x9(uint8 i) {
return channel[i].hdma_addr >> 8;
}
//NTRLx
uint8 CPU::mmio_r43xa(uint8 i) {
return channel[i].line_counter;
}
//???
uint8 CPU::mmio_r43xb(uint8 i) {
return channel[i].unknown;
}
//DMAPx
void CPU::mmio_w43x0(uint8 i, uint8 data) {
channel[i].direction = data & 0x80;
channel[i].indirect = data & 0x40;
channel[i].unused = data & 0x20;
channel[i].reverse_transfer = data & 0x10;
channel[i].fixed_transfer = data & 0x08;
channel[i].transfer_mode = data & 0x07;
}
//DDBADx
void CPU::mmio_w43x1(uint8 i, uint8 data) {
channel[i].dest_addr = data;
}
//A1TxL
void CPU::mmio_w43x2(uint8 i, uint8 data) {
channel[i].source_addr = (channel[i].source_addr & 0xff00) | (data << 0);
}
//A1TxH
void CPU::mmio_w43x3(uint8 i, uint8 data) {
channel[i].source_addr = (channel[i].source_addr & 0x00ff) | (data << 8);
}
//A1Bx
void CPU::mmio_w43x4(uint8 i, uint8 data) {
channel[i].source_bank = data;
}
//DASxL
//union { uint16 transfer_size; uint16 indirect_addr; };
void CPU::mmio_w43x5(uint8 i, uint8 data) {
channel[i].transfer_size = (channel[i].transfer_size & 0xff00) | (data << 0);
}
//DASxH
//union { uint16 transfer_size; uint16 indirect_addr; };
void CPU::mmio_w43x6(uint8 i, uint8 data) {
channel[i].transfer_size = (channel[i].transfer_size & 0x00ff) | (data << 8);
}
//DASBx
void CPU::mmio_w43x7(uint8 i, uint8 data) {
channel[i].indirect_bank = data;
}
//A2AxL
void CPU::mmio_w43x8(uint8 i, uint8 data) {
channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | (data << 0);
}
//A2AxH
void CPU::mmio_w43x9(uint8 i, uint8 data) {
channel[i].hdma_addr = (channel[i].hdma_addr & 0x00ff) | (data << 8);
}
//NTRLx
void CPU::mmio_w43xa(uint8 i, uint8 data) {
channel[i].line_counter = data;
}
//???
void CPU::mmio_w43xb(uint8 i, uint8 data) {
channel[i].unknown = data;
}
void CPU::mmio_power() {
}
void CPU::mmio_reset() {
//$2140-217f
for(auto& port : status.port) port = 0x00;
//$2181-$2183
status.wram_addr = 0x000000;
//$4016-$4017
status.joypad_strobe_latch = 0;
status.joypad1_bits = ~0;
status.joypad2_bits = ~0;
//$4200
status.nmi_enabled = false;
status.hirq_enabled = false;
status.virq_enabled = false;
status.auto_joypad_poll = false;
//$4201
status.pio = 0xff;
//$4202-$4203
status.wrmpya = 0xff;
status.wrmpyb = 0xff;
//$4204-$4206
status.wrdiva = 0xffff;
status.wrdivb = 0xff;
//$4207-$420a
status.hirq_pos = 0x01ff;
status.virq_pos = 0x01ff;
//$420d
status.rom_speed = 8;
//$4214-$4217
status.rddiv = 0x0000;
status.rdmpy = 0x0000;
//$4218-$421f
status.joy1 = 0x0000;
status.joy2 = 0x0000;
status.joy3 = 0x0000;
status.joy4 = 0x0000;
//ALU
alu.mpyctr = 0;
alu.divctr = 0;
alu.shift = 0;
}
uint8 CPU::mmio_read(unsigned addr) {
addr &= 0xffff;
//APU
if((addr & 0xffc0) == 0x2140) { //$2140-$217f
synchronize_smp();
return smp.portRead(addr);
}
//DMA
if((addr & 0xff80) == 0x4300) { //$4300-$437f
unsigned i = (addr >> 4) & 7;
switch(addr & 0xf) {
case 0x0: return mmio_r43x0(i);
case 0x1: return mmio_r43x1(i);
case 0x2: return mmio_r43x2(i);
case 0x3: return mmio_r43x3(i);
case 0x4: return mmio_r43x4(i);
case 0x5: return mmio_r43x5(i);
case 0x6: return mmio_r43x6(i);
case 0x7: return mmio_r43x7(i);
case 0x8: return mmio_r43x8(i);
case 0x9: return mmio_r43x9(i);
case 0xa: return mmio_r43xa(i);
case 0xb: return mmio_r43xb(i);
case 0xc: return regs.mdr; //unmapped
case 0xd: return regs.mdr; //unmapped
case 0xe: return regs.mdr; //unmapped
case 0xf: return mmio_r43xb(i); //mirror of $43xb
}
}
switch(addr) {
case 0x2180: return mmio_r2180();
case 0x4016: return mmio_r4016();
case 0x4017: return mmio_r4017();
case 0x4210: return mmio_r4210();
case 0x4211: return mmio_r4211();
case 0x4212: return mmio_r4212();
case 0x4213: return mmio_r4213();
case 0x4214: return mmio_r4214();
case 0x4215: return mmio_r4215();
case 0x4216: return mmio_r4216();
case 0x4217: return mmio_r4217();
case 0x4218: return mmio_r4218();
case 0x4219: return mmio_r4219();
case 0x421a: return mmio_r421a();
case 0x421b: return mmio_r421b();
case 0x421c: return mmio_r421c();
case 0x421d: return mmio_r421d();
case 0x421e: return mmio_r421e();
case 0x421f: return mmio_r421f();
}
return regs.mdr;
}
void CPU::mmio_write(unsigned addr, uint8 data) {
addr &= 0xffff;
//APU
if((addr & 0xffc0) == 0x2140) { //$2140-$217f
synchronize_smp();
port_write(addr, data);
return;
}
//DMA
if((addr & 0xff80) == 0x4300) { //$4300-$437f
unsigned i = (addr >> 4) & 7;
switch(addr & 0xf) {
case 0x0: mmio_w43x0(i, data); return;
case 0x1: mmio_w43x1(i, data); return;
case 0x2: mmio_w43x2(i, data); return;
case 0x3: mmio_w43x3(i, data); return;
case 0x4: mmio_w43x4(i, data); return;
case 0x5: mmio_w43x5(i, data); return;
case 0x6: mmio_w43x6(i, data); return;
case 0x7: mmio_w43x7(i, data); return;
case 0x8: mmio_w43x8(i, data); return;
case 0x9: mmio_w43x9(i, data); return;
case 0xa: mmio_w43xa(i, data); return;
case 0xb: mmio_w43xb(i, data); return;
case 0xc: return; //unmapped
case 0xd: return; //unmapped
case 0xe: return; //unmapped
case 0xf: mmio_w43xb(i, data); return; //mirror of $43xb
}
}
switch(addr) {
case 0x2180: mmio_w2180(data); return;
case 0x2181: mmio_w2181(data); return;
case 0x2182: mmio_w2182(data); return;
case 0x2183: mmio_w2183(data); return;
case 0x4016: mmio_w4016(data); return;
case 0x4017: return; //unmapped
case 0x4200: mmio_w4200(data); return;
case 0x4201: mmio_w4201(data); return;
case 0x4202: mmio_w4202(data); return;
case 0x4203: mmio_w4203(data); return;
case 0x4204: mmio_w4204(data); return;
case 0x4205: mmio_w4205(data); return;
case 0x4206: mmio_w4206(data); return;
case 0x4207: mmio_w4207(data); return;
case 0x4208: mmio_w4208(data); return;
case 0x4209: mmio_w4209(data); return;
case 0x420a: mmio_w420a(data); return;
case 0x420b: mmio_w420b(data); return;
case 0x420c: mmio_w420c(data); return;
case 0x420d: mmio_w420d(data); return;
}
}
#endif