/* membnk.c -- Memory handlers Z80 access to the banked V-bus address space. */ #include "shared.h" void z80_write_banked_memory(unsigned int address, unsigned int data) { switch((address >> 21) & 7) { case 0: /* Cartridge ROM */ case 1: z80bank_unused_w(address, data); return; case 2: /* Unused */ case 3: z80bank_unused_w(address, data); return; case 4: /* Unused (lockup) */ z80bank_lockup_w(address, data); return; case 5: /* Z80, I/O chip, etc. */ if(address <= 0xA0FFFF) { z80bank_lockup_w(address, data); return; } else { switch((address >> 8) & 0xFF) { case 0x00: /* I/O chip */ if(address <= 0xA1001F) gen_io_w((address >> 1) & 0x0F, data); else z80bank_unused_w(address, data); return; case 0x10: /* DRAM refresh */ z80bank_unused_w(address, data); return; case 0x11: /* /BUSREQ */ if(address & 1) z80bank_unused_w(address, data); else gen_busreq_w(data & 1); return; case 0x12: /* /RESET (w) */ if(address & 1) z80bank_unused_w(address, data); else gen_reset_w(data & 1); return; case 0x13: /* /TIME region */ z80bank_unused_w(address, data); return; case 0x20: /* ? */ z80bank_unused_w(address, data); return; case 0x30: /* ? */ z80bank_unused_w(address, data); return; default: /* Invalid */ z80bank_lockup_w(address, data); return; } } return; case 6: /* VDP */ z80bank_vdp_w(address, data); return; case 7: /* Work RAM */ WRITE_BYTE(work_ram, address & 0xFFFF, data); return; } } int z80_read_banked_memory(unsigned int address) { switch((address >> 21) & 7) { case 0: /* Cartridge ROM */ case 1: return readb_swap_rom(address); case 2: /* Unused */ case 3: return z80bank_unused_r(address); case 4: /* Unused (lockup) */ return z80bank_lockup_r(address); case 5: /* Z80, I/O chip, etc.*/ if(address <= 0xA0FFFF) { return z80bank_lockup_r(address); } else { switch((address >> 8) & 0xFF) { case 0x00: /* I/O chip */ if(address <= 0xA1001F) return gen_io_r((address >> 1) & 0x0F); else return z80bank_unused_r(address); break; case 0x10: /* Unused */ return z80bank_unused_r(address); case 0x11: /* /BUSACK from Z80 */ /* The Z80 can't read this bit (it would be halted when the bit was zero) so we always return '1'. */ return 0xFF; case 0x12: /* Unused */ return z80bank_unused_r(address); case 0x13: /* /TIME region */ return z80bank_unused_r(address); case 0x20: /* Unused */ return z80bank_unused_r(address); case 0x30: /* Unused */ return z80bank_unused_r(address); default: /* Lockup */ return z80bank_lockup_r(address); } } break; case 6: /* VDP */ return z80bank_vdp_r(address); case 7: /* Work RAM - can't be read on some Genesis models (!) */ return 0xFF; } return (-1); } void z80bank_vdp_w(int address, int data) { // if((address & 0xE700E0) == 0xC00000) if((address & 0xE700E0) == 0xC0000) { switch(address & 0x1F) { case 0x00: /* Data port */ case 0x01: case 0x02: case 0x03: vdp_data_w(data << 8 | data); return; case 0x04: /* Control port */ case 0x05: case 0x06: case 0x07: vdp_ctrl_w(data << 8 | data); return; case 0x08: /* Lockup (HVC) */ case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F: z80bank_lockup_w(address, data); return; case 0x10: /* Unused */ case 0x12: case 0x14: case 0x16: z80bank_unused_w(address, data); return; case 0x11: /* PSG */ case 0x13: case 0x15: case 0x17: psg_write(data); return; case 0x18: /* Unused */ case 0x19: case 0x1A: case 0x1B: z80bank_unused_w(address, data); return; case 0x1C: /* Test register */ case 0x1D: case 0x1E: case 0x1F: vdp_test_w(data << 8 | data); return; } } else { /* Invalid VDP address */ z80bank_lockup_w(address, data); return; } } int z80bank_vdp_r(int address) { // if((address & 0xE700E0) == 0xC00000) if((address & 0xE700E0) == 0xC0000) { switch(address & 0x1F) { case 0x00: /* Data */ case 0x02: return (vdp_data_r() >> 8) & 0xFF; case 0x01: /* Data */ case 0x03: return vdp_data_r() & 0xFF; case 0x04: /* Control */ case 0x06: return (0xFC | (vdp_ctrl_r() >> 8)) & 0xFF; case 0x05: /* Control */ case 0x07: return vdp_ctrl_r() & 0xFF; case 0x08: /* HVC */ case 0x0A: case 0x0C: case 0x0E: return (vdp_hvc_r() >> 8) & 0xFF; case 0x09: /* HVC */ case 0x0B: case 0x0D: case 0x0F: return vdp_hvc_r() & 0xFF; case 0x10: /* Lockup */ case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: return z80bank_lockup_r(address); case 0x18: /* Unused */ case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: return (z80bank_unused_r(address) | 0xFF); } } else { /* Invalid VDP address */ return z80bank_lockup_r(address); } return 0xFF; } /* Handlers for access to unused addresses and those which make the machine lock up. */ void z80bank_unused_w(int address, int data) { error("Z80 bank unused write %06X = %02X (%04X)\n", address, data, z80_get_reg(Z80_PC)); } int z80bank_unused_r(int address) { error("Z80 bank unused read %06X (%04X)\n", address, z80_get_reg(Z80_PC)); return (address & 1) ? 0x00 : 0xFF; } void z80bank_lockup_w(int address, int data) { error("Z80 bank lockup write %06X = %02X (%04X)\n", address, data, z80_get_reg(Z80_PC)); gen_running = 0; z80_end_timeslice(); } int z80bank_lockup_r(int address) { error("Z80 bank lockup read %06X (%04X)\n", address, z80_get_reg(Z80_PC)); gen_running = 0; z80_end_timeslice(); return 0xFF; }