mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-12-25 18:51:49 +01:00
297 lines
7.3 KiB
C
297 lines
7.3 KiB
C
/*
|
|
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) io_write((address >> 1) & 0x0F, data);
|
|
else 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 0x10: /* MEMORY MODE */
|
|
case 0x13: /* TIME */
|
|
case 0x20: /* ? */
|
|
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 READ_BYTE(cart_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 io_read((address >> 1) & 0x0F);
|
|
else return z80bank_unused_r (address);
|
|
break;
|
|
|
|
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 0x10: /* Unused */
|
|
case 0x12: /* Unused */
|
|
case 0x13: /* /TIME region */
|
|
case 0x20: /* Unused */
|
|
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)
|
|
{
|
|
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)
|
|
{
|
|
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;
|
|
}
|