2008-08-07 14:26:07 +02:00
|
|
|
/***************************************************************************************
|
|
|
|
* Genesis Plus 1.2a
|
|
|
|
* 68k memory handlers
|
|
|
|
*
|
|
|
|
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
|
|
|
|
* modified by Eke-Eke (compatibility fixes & additional code), GC/Wii port
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
****************************************************************************************/
|
|
|
|
|
|
|
|
#include "m68kcpu.h"
|
|
|
|
#include "shared.h"
|
|
|
|
|
|
|
|
uint8 m68k_readmap_8[32];
|
|
|
|
uint8 m68k_readmap_16[32];
|
|
|
|
uint8 m68k_writemap_8[32];
|
|
|
|
uint8 m68k_writemap_16[32];
|
|
|
|
|
|
|
|
|
|
|
|
uint8 pico_current;
|
|
|
|
static uint8 pico_page[7] = {0x00,0x01,0x03,0x07,0x0F,0x1F,0x3F};
|
|
|
|
|
|
|
|
|
|
|
|
static inline unsigned int m68k_read_bus_8(unsigned int address)
|
|
|
|
{
|
|
|
|
#ifdef LOGERROR
|
|
|
|
if ((address != 0xa11100) && (address != 0xc00004) && (address != 0xc00006))
|
|
|
|
{
|
|
|
|
error("Unused read8 %08X (%08X)\n", address, m68k_get_reg (NULL, M68K_REG_PC));
|
|
|
|
error("D0 = %x \n", m68k_get_reg (NULL, M68K_REG_D0));
|
|
|
|
error("D1 = %x \n", m68k_get_reg (NULL, M68K_REG_D1));
|
|
|
|
error("D2 = %x \n", m68k_get_reg (NULL, M68K_REG_D2));
|
|
|
|
error("D3 = %x \n", m68k_get_reg (NULL, M68K_REG_D3));
|
|
|
|
error("D4 = %x \n", m68k_get_reg (NULL, M68K_REG_D4));
|
|
|
|
error("D5 = %x \n", m68k_get_reg (NULL, M68K_REG_D5));
|
|
|
|
error("D6 = %x \n", m68k_get_reg (NULL, M68K_REG_D6));
|
|
|
|
error("D7 = %x \n", m68k_get_reg (NULL, M68K_REG_D7));
|
|
|
|
error("A0 = %x \n", m68k_get_reg (NULL, M68K_REG_A0));
|
|
|
|
error("A1 = %x \n", m68k_get_reg (NULL, M68K_REG_A1));
|
|
|
|
error("A2 = %x \n", m68k_get_reg (NULL, M68K_REG_A2));
|
|
|
|
error("A3 = %x \n", m68k_get_reg (NULL, M68K_REG_A3));
|
|
|
|
error("A4 = %x \n", m68k_get_reg (NULL, M68K_REG_A4));
|
|
|
|
error("A5 = %x \n", m68k_get_reg (NULL, M68K_REG_A5));
|
|
|
|
error("A6 = %x \n", m68k_get_reg (NULL, M68K_REG_A6));
|
|
|
|
error("A7 = %x \n", m68k_get_reg (NULL, M68K_REG_A7));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
int bus_addr = (REG_PC & 0xffffe) | (address & 1);
|
|
|
|
int offset = bus_addr >> 19;
|
|
|
|
|
|
|
|
if (offset > 8) return READ_BYTE(work_ram, bus_addr & 0xffff);
|
|
|
|
else return READ_BYTE(rom_readmap[offset], bus_addr & 0x7ffff);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned int m68k_read_bus_16(unsigned int address)
|
|
|
|
{
|
|
|
|
#ifdef LOGERROR
|
|
|
|
if ((address != 0xa11100) && (address != 0xc00004) && (address != 0xc00006))
|
|
|
|
{
|
|
|
|
error("Unused read16 %08X (%08X)\n", address, m68k_get_reg (NULL, M68K_REG_PC));
|
|
|
|
error("D0 = %x \n", m68k_get_reg (NULL, M68K_REG_D0));
|
|
|
|
error("D1 = %x \n", m68k_get_reg (NULL, M68K_REG_D1));
|
|
|
|
error("D2 = %x \n", m68k_get_reg (NULL, M68K_REG_D2));
|
|
|
|
error("D3 = %x \n", m68k_get_reg (NULL, M68K_REG_D3));
|
|
|
|
error("D4 = %x \n", m68k_get_reg (NULL, M68K_REG_D4));
|
|
|
|
error("D5 = %x \n", m68k_get_reg (NULL, M68K_REG_D5));
|
|
|
|
error("D6 = %x \n", m68k_get_reg (NULL, M68K_REG_D6));
|
|
|
|
error("D7 = %x \n", m68k_get_reg (NULL, M68K_REG_D7));
|
|
|
|
error("A0 = %x \n", m68k_get_reg (NULL, M68K_REG_A0));
|
|
|
|
error("A1 = %x \n", m68k_get_reg (NULL, M68K_REG_A1));
|
|
|
|
error("A2 = %x \n", m68k_get_reg (NULL, M68K_REG_A2));
|
|
|
|
error("A3 = %x \n", m68k_get_reg (NULL, M68K_REG_A3));
|
|
|
|
error("A4 = %x \n", m68k_get_reg (NULL, M68K_REG_A4));
|
|
|
|
error("A5 = %x \n", m68k_get_reg (NULL, M68K_REG_A5));
|
|
|
|
error("A6 = %x \n", m68k_get_reg (NULL, M68K_REG_A6));
|
|
|
|
error("A7 = %x \n", m68k_get_reg (NULL, M68K_REG_A7));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
int bus_addr = REG_PC & 0xfffffe;
|
|
|
|
int offset = bus_addr >> 19;
|
|
|
|
|
|
|
|
if (offset > 8) return *(uint16 *)(work_ram + (bus_addr & 0xffff));
|
|
|
|
else return *(uint16 *)(rom_readmap[offset] + (bus_addr & 0x7ffff));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static inline void m68k_unused_8_w (unsigned int address, unsigned int value)
|
|
|
|
{
|
|
|
|
#ifdef LOGERROR
|
|
|
|
error("Unused write8 %08X = %02X (%08X)\n", address, value, m68k_get_reg (NULL, M68K_REG_PC));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void m68k_unused_16_w (unsigned int address, unsigned int value)
|
|
|
|
{
|
|
|
|
#ifdef LOGERROR
|
|
|
|
error("Unused write16 %08X = %04X (%08X)\n", address, value, m68k_get_reg (NULL, M68K_REG_PC));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Functions to handle memory accesses which cause the Genesis to halt
|
|
|
|
either temporarily (press RESET button to restart) or unrecoverably
|
|
|
|
(cycle power to restart).
|
|
|
|
*/
|
|
|
|
|
|
|
|
static inline void m68k_lockup_w_8 (unsigned int address, unsigned int value)
|
|
|
|
{
|
|
|
|
#ifdef LOGERROR
|
|
|
|
error ("Lockup %08X = %02X (%08X)\n", address, value, m68k_get_reg (NULL, M68K_REG_PC));
|
|
|
|
#endif
|
|
|
|
gen_running = config.force_dtack;
|
|
|
|
if (!gen_running) m68k_end_timeslice ();
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void m68k_lockup_w_16 (unsigned int address, unsigned int value)
|
|
|
|
{
|
|
|
|
#ifdef LOGERROR
|
|
|
|
error ("Lockup %08X = %04X (%08X)\n", address, value, m68k_get_reg (NULL, M68K_REG_PC));
|
|
|
|
#endif
|
|
|
|
gen_running = config.force_dtack;
|
|
|
|
if (!gen_running) m68k_end_timeslice ();
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned int m68k_lockup_r_8 (unsigned int address)
|
|
|
|
{
|
|
|
|
#ifdef LOGERROR
|
|
|
|
error ("Lockup %08X.b (%08X)\n", address, m68k_get_reg (NULL, M68K_REG_PC));
|
|
|
|
#endif
|
|
|
|
gen_running = config.force_dtack;
|
|
|
|
if (!gen_running) m68k_end_timeslice ();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned int m68k_lockup_r_16 (unsigned int address)
|
|
|
|
{
|
|
|
|
#ifdef LOGERROR
|
|
|
|
error ("Lockup %08X.w (%08X)\n", address, m68k_get_reg (NULL, M68K_REG_PC));
|
|
|
|
#endif
|
|
|
|
gen_running = config.force_dtack;
|
|
|
|
if (!gen_running) m68k_end_timeslice ();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/* 68000 memory handlers */
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
unsigned int m68k_read_memory_8(unsigned int address)
|
|
|
|
{
|
|
|
|
int offset = address >> 19;
|
|
|
|
|
|
|
|
switch (m68k_readmap_8[offset])
|
|
|
|
{
|
|
|
|
case WRAM:
|
|
|
|
return READ_BYTE(work_ram, address & 0xffff);
|
|
|
|
|
|
|
|
case SYSTEM_IO:
|
|
|
|
{
|
|
|
|
unsigned int base = address >> 8;
|
|
|
|
|
|
|
|
/* Z80 */
|
|
|
|
if (base <= 0xa0ff)
|
|
|
|
{
|
|
|
|
/* Z80 controls Z bus ? */
|
|
|
|
if (zbusack) return m68k_read_bus_8(address);
|
|
|
|
|
|
|
|
/* Read data from Z bus */
|
|
|
|
switch (base & 0x60)
|
|
|
|
{
|
|
|
|
case 0x40: /* YM2612 */
|
|
|
|
return fm_read(0, address & 3);
|
|
|
|
|
|
|
|
case 0x60: /* VDP */
|
|
|
|
if (base == 0xa07f) return m68k_lockup_r_8(address);
|
|
|
|
return (m68k_read_bus_8(address) | 0xff);
|
|
|
|
|
|
|
|
default: /* ZRAM */
|
|
|
|
return zram[address & 0x1fff];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* I/O & CONTROL registers */
|
|
|
|
if (base <= 0xa1ff)
|
|
|
|
{
|
|
|
|
switch (base & 0xff)
|
|
|
|
{
|
|
|
|
case 0x00: /* I/O chip */
|
|
|
|
if (address & 0xe0) return m68k_read_bus_8(address);
|
|
|
|
return (io_read((address >> 1) & 0x0f));
|
|
|
|
|
|
|
|
case 0x11: /* BUSACK */
|
|
|
|
return (zbusack | (address & 1) | (m68k_read_bus_8(address) & 0xFE));
|
|
|
|
|
|
|
|
case 0x30: /* TIME */
|
|
|
|
if (cart_hw.time_r) return cart_hw.time_r(address);
|
|
|
|
else return m68k_read_bus_8(address);
|
|
|
|
|
|
|
|
case 0x10: /* MEMORY MODE */
|
|
|
|
case 0x12: /* RESET */
|
|
|
|
case 0x20: /* MEGA-CD */
|
|
|
|
case 0x40: /* TMSS */
|
|
|
|
case 0x41: /* BOOTROM */
|
|
|
|
case 0x44: /* RADICA */
|
|
|
|
case 0x50: /* SVP REGISTERS */
|
|
|
|
return m68k_read_bus_8(address);
|
|
|
|
|
|
|
|
default: /* Invalid address */
|
|
|
|
return m68k_lockup_r_8(address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Invalid address */
|
|
|
|
return m68k_lockup_r_8(address);
|
|
|
|
}
|
|
|
|
|
|
|
|
case VDP:
|
|
|
|
|
|
|
|
/* Valid VDP addresses */
|
|
|
|
if (((address >> 16) & 0x07) == 0)
|
|
|
|
{
|
|
|
|
switch (address & 0xff)
|
|
|
|
{
|
|
|
|
case 0x00: /* DATA */
|
|
|
|
case 0x02:
|
|
|
|
return (vdp_data_r() >> 8);
|
|
|
|
|
|
|
|
case 0x01: /* DATA */
|
|
|
|
case 0x03:
|
|
|
|
return (vdp_data_r() & 0xff);
|
|
|
|
|
|
|
|
case 0x04: /* CTRL */
|
|
|
|
case 0x06:
|
|
|
|
return ((m68k_read_bus_8(address) & 0xfc) | ((vdp_ctrl_r() >> 8) & 3));
|
|
|
|
|
|
|
|
case 0x05: /* CTRL */
|
|
|
|
case 0x07:
|
|
|
|
return (vdp_ctrl_r() & 0xff);
|
|
|
|
|
|
|
|
case 0x08: /* HVC */
|
|
|
|
case 0x0a:
|
|
|
|
case 0x0c:
|
|
|
|
case 0x0e:
|
|
|
|
return (vdp_hvc_r() >> 8);
|
|
|
|
|
|
|
|
case 0x09: /* HVC */
|
|
|
|
case 0x0b:
|
|
|
|
case 0x0d:
|
|
|
|
case 0x0f:
|
|
|
|
return (vdp_hvc_r() & 0xff);
|
|
|
|
|
|
|
|
case 0x18:
|
|
|
|
case 0x19:
|
|
|
|
case 0x1a:
|
|
|
|
case 0x1b:
|
|
|
|
case 0x1c:
|
|
|
|
case 0x1d:
|
|
|
|
case 0x1e:
|
|
|
|
case 0x1f: /* Unused */
|
|
|
|
return m68k_read_bus_8(address);
|
|
|
|
|
|
|
|
default: /* Invalid address */
|
|
|
|
return m68k_lockup_r_8(address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Invalid address */
|
|
|
|
return (m68k_lockup_r_8 (address));
|
|
|
|
|
|
|
|
case SRAM:
|
|
|
|
if (address <= sram.end) return READ_BYTE(sram.sram, address - sram.start);
|
|
|
|
return READ_BYTE(rom_readmap[offset], address & 0x7ffff);
|
|
|
|
|
|
|
|
case EEPROM:
|
|
|
|
if (address == eeprom.type.sda_out_adr) return eeprom_read(address, 0);
|
|
|
|
return READ_BYTE(rom_readmap[offset], address & 0x7ffff);
|
|
|
|
|
|
|
|
case CART_HW:
|
|
|
|
return cart_hw.regs_r(address);
|
|
|
|
|
|
|
|
case UNUSED:
|
|
|
|
return m68k_read_bus_8(address);
|
|
|
|
|
|
|
|
case ILLEGAL:
|
|
|
|
return m68k_lockup_r_8(address);
|
|
|
|
|
|
|
|
case UMK3_HACK:
|
|
|
|
return READ_BYTE(&cart_rom[offset<<19], address & 0x7ffff);
|
|
|
|
|
|
|
|
case PICO_HW:
|
|
|
|
switch (address & 0xff)
|
|
|
|
{
|
|
|
|
case 0x01: /* VERSION register */
|
|
|
|
return (0x40);
|
|
|
|
|
|
|
|
case 0x03: /* IO register */
|
|
|
|
{
|
|
|
|
uint8 retval = 0xff;
|
2008-08-26 18:00:43 +02:00
|
|
|
if (input.pad[0] & INPUT_B) retval &= ~0x10;
|
|
|
|
if (input.pad[0] & INPUT_A) retval &= ~0x80;
|
2008-08-07 14:26:07 +02:00
|
|
|
if (input.pad[0] & INPUT_UP) retval &= ~0x01;
|
|
|
|
if (input.pad[0] & INPUT_DOWN) retval &= ~0x02;
|
|
|
|
if (input.pad[0] & INPUT_LEFT) retval &= ~0x04;
|
|
|
|
if (input.pad[0] & INPUT_RIGHT) retval &= ~0x08;
|
|
|
|
retval &= ~0x20;
|
|
|
|
retval &= ~0x40;
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 0x05: /* MSB PEN X coordinate */
|
|
|
|
return (input.analog[0][0] >> 8);
|
|
|
|
|
|
|
|
case 0x07: /* LSB PEN X coordinate */
|
|
|
|
return (input.analog[0][0] & 0xff);
|
|
|
|
|
|
|
|
case 0x09: /* MSB PEN Y coordinate */
|
|
|
|
return (input.analog[0][1] >> 8);
|
|
|
|
|
|
|
|
case 0x0b: /* LSB PEN Y coordinate */
|
|
|
|
return (input.analog[0][1] & 0xff);
|
|
|
|
|
|
|
|
case 0x0d: /* PAGE register */
|
|
|
|
return pico_page[pico_current]; /* TODO */
|
|
|
|
|
|
|
|
case 0x10: /* PCM registers */
|
|
|
|
case 0x11:
|
|
|
|
case 0x12:
|
|
|
|
case 0x13:
|
|
|
|
return 0x80; /* TODO */
|
|
|
|
|
|
|
|
default:
|
|
|
|
return m68k_read_bus_8(address);
|
|
|
|
}
|
|
|
|
|
|
|
|
default: /* ROM */
|
|
|
|
return READ_BYTE(rom_readmap[offset], address & 0x7ffff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
unsigned int m68k_read_memory_16 (unsigned int address)
|
|
|
|
{
|
|
|
|
int offset = address >> 19;
|
|
|
|
|
|
|
|
switch (m68k_readmap_16[offset])
|
|
|
|
{
|
|
|
|
case WRAM:
|
|
|
|
return *(uint16 *)(work_ram + (address & 0xffff));
|
|
|
|
|
|
|
|
case SVP_DRAM:
|
|
|
|
return *(uint16 *)(svp->dram + (address & 0x1fffe));
|
|
|
|
|
|
|
|
case SVP_CELL:
|
|
|
|
switch (address >> 16)
|
|
|
|
{
|
|
|
|
case 0x39:
|
|
|
|
address >>= 1;
|
|
|
|
address = (address & 0x7001) | ((address & 0x3e) << 6) | ((address & 0xfc0) >> 5);
|
|
|
|
return *(uint16 *)(svp->dram + (address & 0x1fffe));
|
|
|
|
|
|
|
|
case 0x3A:
|
|
|
|
address >>= 1;
|
|
|
|
address = (address & 0x7801) | ((address & 0x1e) << 6) | ((address & 0x7e0) >> 4);
|
|
|
|
return *(uint16 *)(svp->dram + (address & 0x1fffe));
|
|
|
|
|
|
|
|
default:
|
|
|
|
return m68k_read_bus_16(address);
|
|
|
|
}
|
|
|
|
|
|
|
|
case SYSTEM_IO:
|
|
|
|
{
|
|
|
|
unsigned int base = address >> 8;
|
|
|
|
|
|
|
|
/* Z80 */
|
|
|
|
if (base <= 0xa0ff)
|
|
|
|
{
|
|
|
|
/* Z80 controls Z bus ? */
|
|
|
|
if (zbusack) return m68k_read_bus_16(address);
|
|
|
|
|
|
|
|
/* Read data from Z bus */
|
|
|
|
switch (base & 0x60)
|
|
|
|
{
|
|
|
|
case 0x40: /* YM2612 */
|
|
|
|
{
|
|
|
|
int temp = fm_read(0, address & 3);
|
|
|
|
return (temp << 8 | temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
case 0x60: /* VDP */
|
|
|
|
if (base == 0xa07f) return m68k_lockup_r_16(address);
|
|
|
|
return (m68k_read_bus_16(address) | 0xffff);
|
|
|
|
|
|
|
|
default: /* ZRAM */
|
|
|
|
{
|
|
|
|
int temp = zram[address & 0x1fff];
|
|
|
|
return (temp << 8 | temp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* CONTROL registers */
|
|
|
|
if (base <= 0xa1ff)
|
|
|
|
{
|
|
|
|
switch (base & 0xff)
|
|
|
|
{
|
|
|
|
case 0x00: /* I/O chip */
|
|
|
|
{
|
|
|
|
if (address & 0xe0) return m68k_read_bus_16(address);
|
|
|
|
int temp = io_read((address >> 1) & 0x0f);
|
|
|
|
return (temp << 8 | temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
case 0x11: /* BUSACK */
|
|
|
|
return ((m68k_read_bus_16(address) & 0xfeff) | (zbusack << 8));
|
|
|
|
|
|
|
|
case 0x50: /* SVP */
|
|
|
|
if (svp)
|
|
|
|
{
|
|
|
|
switch (address & 0xff)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
case 2:
|
|
|
|
return svp->ssp1601.gr[SSP_XST].h;
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
{
|
|
|
|
unsigned int temp = svp->ssp1601.gr[SSP_PM0].h;
|
|
|
|
svp->ssp1601.gr[SSP_PM0].h &= ~1;
|
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return m68k_read_bus_16(address);
|
|
|
|
|
|
|
|
case 0x30: /* TIME */
|
|
|
|
if (cart_hw.time_r) return cart_hw.time_r(address);
|
|
|
|
else return m68k_read_bus_16(address);
|
|
|
|
|
|
|
|
case 0x10: /* MEMORY MODE */
|
|
|
|
case 0x12: /* RESET */
|
|
|
|
case 0x20: /* MEGA-CD */
|
|
|
|
case 0x40: /* TMSS */
|
|
|
|
case 0x41: /* BOOTROM */
|
|
|
|
case 0x44: /* RADICA */
|
|
|
|
return m68k_read_bus_16(address);
|
|
|
|
|
|
|
|
default: /* Invalid address */
|
|
|
|
return m68k_lockup_r_16(address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Invalid address */
|
|
|
|
return m68k_lockup_r_16 (address);
|
|
|
|
}
|
|
|
|
|
|
|
|
case VDP:
|
|
|
|
|
|
|
|
/* Valid VDP addresses */
|
|
|
|
if (((address >> 16) & 0x07) == 0)
|
|
|
|
{
|
|
|
|
switch (address & 0xfc)
|
|
|
|
{
|
|
|
|
case 0x00: /* DATA */
|
|
|
|
return vdp_data_r();
|
|
|
|
|
|
|
|
case 0x04: /* CTRL */
|
|
|
|
return ((vdp_ctrl_r() & 0x3FF) | (m68k_read_bus_16(address) & 0xFC00));
|
|
|
|
|
|
|
|
case 0x08: /* HVC */
|
|
|
|
case 0x0c:
|
|
|
|
return vdp_hvc_r();
|
|
|
|
|
|
|
|
case 0x18: /* Unused */
|
|
|
|
case 0x1c:
|
|
|
|
return m68k_read_bus_16(address);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return m68k_lockup_r_16(address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Invalid address */
|
|
|
|
return m68k_lockup_r_16 (address);
|
|
|
|
|
|
|
|
case SRAM:
|
|
|
|
if (address <= sram.end) return *(uint16 *)(sram.sram + (address - sram.start));
|
|
|
|
return *(uint16 *)(rom_readmap[offset] + (address & 0x7ffff));
|
|
|
|
|
|
|
|
case EEPROM:
|
|
|
|
if (address == (eeprom.type.sda_out_adr & 0xfffffe)) return eeprom_read(address, 1);
|
|
|
|
return *(uint16 *)(rom_readmap[offset] + (address & 0x7ffff));
|
|
|
|
|
|
|
|
case J_CART:
|
|
|
|
return jcart_read();
|
|
|
|
|
|
|
|
case REALTEC_ROM:
|
|
|
|
return *(uint16 *)(&cart_rom[0x7e000] + (address & 0x1fff));
|
|
|
|
|
|
|
|
case UNUSED:
|
|
|
|
return m68k_read_bus_16(address);
|
|
|
|
|
|
|
|
case ILLEGAL:
|
|
|
|
return m68k_lockup_r_16(address);
|
|
|
|
|
|
|
|
case UMK3_HACK:
|
|
|
|
return *(uint16 *)(&cart_rom[offset << 19] + (address & 0x7ffff));
|
|
|
|
|
|
|
|
case PICO_HW:
|
|
|
|
switch (address & 0xff)
|
|
|
|
{
|
|
|
|
case 0x00: /* VERSION register */
|
|
|
|
return (0x40);
|
|
|
|
|
|
|
|
case 0x02: /* IO register */
|
|
|
|
{
|
|
|
|
uint8 retval = 0xff;
|
2008-08-26 18:00:43 +02:00
|
|
|
if (input.pad[0] & INPUT_B) retval &= ~0x10;
|
|
|
|
if (input.pad[0] & INPUT_A) retval &= ~0x80;
|
2008-08-07 14:26:07 +02:00
|
|
|
if (input.pad[0] & INPUT_UP) retval &= ~0x01;
|
|
|
|
if (input.pad[0] & INPUT_DOWN) retval &= ~0x02;
|
|
|
|
if (input.pad[0] & INPUT_LEFT) retval &= ~0x04;
|
|
|
|
if (input.pad[0] & INPUT_RIGHT) retval &= ~0x08;
|
|
|
|
retval &= ~0x20;
|
|
|
|
retval &= ~0x40;
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 0x04: /* MSB PEN X coordinate */
|
|
|
|
return (input.analog[0][0] >> 8);
|
|
|
|
|
|
|
|
case 0x06: /* LSB PEN X coordinate */
|
|
|
|
return (input.analog[0][0] & 0xff);
|
|
|
|
|
|
|
|
case 0x08: /* MSB PEN Y coordinate */
|
|
|
|
return (input.analog[0][1] >> 8);
|
|
|
|
|
|
|
|
case 0x0a: /* LSB PEN Y coordinate */
|
|
|
|
return (input.analog[0][1] & 0xff);
|
|
|
|
|
|
|
|
case 0x0c: /* PAGE register */
|
|
|
|
return pico_page[pico_current]; /* TODO */
|
|
|
|
|
|
|
|
case 0x10: /* PCM data register */
|
|
|
|
return 0x8000; /* TODO */
|
|
|
|
|
|
|
|
case 0x12: /* PCM control registe */
|
|
|
|
return 0x8000; /* TODO */
|
|
|
|
|
|
|
|
default:
|
|
|
|
return m68k_read_bus_16(address);
|
|
|
|
}
|
|
|
|
|
|
|
|
default: /* ROM */
|
|
|
|
return *(uint16 *)(rom_readmap[offset] + (address & 0x7ffff));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
unsigned int m68k_read_memory_32(unsigned int address)
|
|
|
|
{
|
|
|
|
/* Split into 2 reads */
|
|
|
|
return ((m68k_read_memory_16 (address) << 16) |
|
|
|
|
(m68k_read_memory_16 ((address+ 2)&0xffffff)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void m68k_write_memory_8(unsigned int address, unsigned int value)
|
|
|
|
{
|
|
|
|
int offset = address >> 19;
|
|
|
|
|
|
|
|
switch (m68k_writemap_8[offset])
|
|
|
|
{
|
|
|
|
case VDP:
|
|
|
|
/* Valid VDP addresses */
|
|
|
|
if (((address >> 16) & 0x07) == 0)
|
|
|
|
{
|
|
|
|
switch (address & 0xff)
|
|
|
|
{
|
|
|
|
case 0x00: /* Data port */
|
|
|
|
case 0x01:
|
|
|
|
case 0x02:
|
|
|
|
case 0x03:
|
|
|
|
vdp_data_w(value << 8 | value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x04: /* Control port */
|
|
|
|
case 0x05:
|
|
|
|
case 0x06:
|
|
|
|
case 0x07:
|
|
|
|
vdp_ctrl_w(value << 8 | value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x10: /* Unused */
|
|
|
|
case 0x12:
|
|
|
|
case 0x14:
|
|
|
|
case 0x16:
|
|
|
|
m68k_unused_8_w(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x11: /* PSG */
|
|
|
|
case 0x13:
|
|
|
|
case 0x15:
|
|
|
|
case 0x17:
|
|
|
|
psg_write(0, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x18: /* Unused */
|
|
|
|
case 0x19:
|
|
|
|
case 0x1a:
|
|
|
|
case 0x1b:
|
|
|
|
m68k_unused_8_w(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x1c: /* Test register */
|
|
|
|
case 0x1d:
|
|
|
|
case 0x1e:
|
|
|
|
case 0x1f:
|
|
|
|
vdp_test_w(value << 8 | value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
default: /* Invalid address */
|
|
|
|
m68k_lockup_w_8(address, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Invalid address */
|
|
|
|
m68k_lockup_w_8(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
case SYSTEM_IO:
|
|
|
|
{
|
|
|
|
unsigned int base = address >> 8;
|
|
|
|
|
|
|
|
/* Z80 */
|
|
|
|
if (base <= 0xa0ff)
|
|
|
|
{
|
|
|
|
/* Writes are ignored when the Z80 hogs the Z-bus */
|
|
|
|
if (zbusack)
|
|
|
|
{
|
|
|
|
m68k_unused_8_w (address, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read data from Z bus */
|
|
|
|
switch (base & 0x60)
|
|
|
|
{
|
|
|
|
case 0x40: /* YM2612 */
|
|
|
|
fm_write(0, address & 3, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x60:
|
|
|
|
switch (base & 0x7f)
|
|
|
|
{
|
|
|
|
case 0x60: /* Bank register */
|
|
|
|
gen_bank_w(value & 1);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x7f: /* VDP */
|
|
|
|
m68k_lockup_w_8(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
|
|
|
m68k_unused_8_w(address, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
default: /* ZRAM */
|
|
|
|
zram[address & 0x1fff] = value;
|
|
|
|
count_m68k ++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* CONTROL registers */
|
|
|
|
if (base <= 0xa1ff)
|
|
|
|
{
|
|
|
|
switch (base & 0xff)
|
|
|
|
{
|
|
|
|
case 0x00: /* I/O chip (only gets /LWR) */
|
|
|
|
if ((address & 0xe1) == 0x01) io_write((address >> 1) & 0x0f, value);
|
|
|
|
else m68k_unused_8_w(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x11: /* BUSREQ */
|
|
|
|
if (address & 1) m68k_unused_8_w(address, value);
|
|
|
|
else gen_busreq_w(value & 1);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x12: /* RESET */
|
|
|
|
if (address & 1) m68k_unused_8_w(address, value);
|
|
|
|
else gen_reset_w(value & 1);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x30: /* TIME */
|
|
|
|
if (cart_hw.time_w) cart_hw.time_w(address, value);
|
|
|
|
else m68k_unused_8_w(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x41: /* BOOTROM */
|
|
|
|
if (address & 1)
|
|
|
|
{
|
|
|
|
if (value & 1)
|
|
|
|
{
|
|
|
|
rom_readmap[0] = &cart_rom[0];
|
|
|
|
rom_size = genromsize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rom_readmap[0] = &bios_rom[0];
|
|
|
|
rom_size = 0x800;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(config.bios_enabled & 2))
|
|
|
|
{
|
|
|
|
config.bios_enabled |= 2;
|
|
|
|
memcpy(bios_rom, cart_rom, 0x800);
|
|
|
|
memset(cart_rom, 0, 0x500000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else m68k_unused_8_w (address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x10: /* MEMORY MODE */
|
|
|
|
case 0x20: /* MEGA-CD */
|
|
|
|
case 0x40: /* TMSS */
|
|
|
|
case 0x44: /* RADICA */
|
|
|
|
case 0x50: /* SVP REGISTERS */
|
|
|
|
m68k_unused_8_w(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
default: /* Invalid address */
|
|
|
|
m68k_lockup_w_8(address, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Invalid address */
|
|
|
|
m68k_lockup_w_8(address, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ROM:
|
|
|
|
WRITE_BYTE(rom_readmap[offset], address & 0x7ffff, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case SRAM:
|
|
|
|
if (address <= sram.end) WRITE_BYTE(sram.sram, address - sram.start, value);
|
|
|
|
else m68k_unused_8_w(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case EEPROM:
|
|
|
|
if ((address == eeprom.type.sda_in_adr) || (address == eeprom.type.scl_adr)) eeprom_write(address, value, 0);
|
|
|
|
else m68k_unused_8_w(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case CART_HW:
|
|
|
|
cart_hw.regs_w(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case UNUSED:
|
|
|
|
m68k_unused_8_w(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case ILLEGAL:
|
|
|
|
m68k_lockup_w_8(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case PICO_HW:
|
|
|
|
switch (address & 0xff)
|
|
|
|
{
|
|
|
|
case 0x19:
|
|
|
|
case 0x1b:
|
|
|
|
case 0x1d:
|
|
|
|
case 0x1f: /* TMSS register */
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
|
|
|
m68k_unused_8_w(address, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
default: /* WRAM */
|
|
|
|
WRITE_BYTE(work_ram, address & 0xffff, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void m68k_write_memory_16 (unsigned int address, unsigned int value)
|
|
|
|
{
|
|
|
|
int offset = address >> 19;
|
|
|
|
|
|
|
|
switch (m68k_writemap_16[offset])
|
|
|
|
{
|
|
|
|
case SVP_DRAM:
|
|
|
|
*(uint16 *)(svp->dram + (address & 0x1fffe)) = value;
|
|
|
|
if ((address == 0x30fe06) && value) svp->ssp1601.emu_status &= ~SSP_WAIT_30FE06;
|
|
|
|
if ((address == 0x30fe08) && value) svp->ssp1601.emu_status &= ~SSP_WAIT_30FE08;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case VDP:
|
|
|
|
/* Valid VDP addresses */
|
|
|
|
if (((address >> 16) & 0x07) == 0)
|
|
|
|
{
|
|
|
|
switch (address & 0xfc)
|
|
|
|
{
|
|
|
|
case 0x00: /* DATA */
|
|
|
|
vdp_data_w(value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x04: /* CTRL */
|
|
|
|
vdp_ctrl_w(value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x10: /* PSG */
|
|
|
|
case 0x14:
|
|
|
|
psg_write(0, value & 0xff);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x18: /* Unused */
|
|
|
|
m68k_unused_16_w(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x1c: /* Test register */
|
|
|
|
vdp_test_w(value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
default: /* Invalid address */
|
|
|
|
m68k_lockup_w_16 (address, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Invalid address */
|
|
|
|
m68k_lockup_w_16 (address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
case SYSTEM_IO:
|
|
|
|
{
|
|
|
|
unsigned int base = address >> 8;
|
|
|
|
|
|
|
|
/* Z80 */
|
|
|
|
if (base <= 0xa0ff)
|
|
|
|
{
|
|
|
|
/* Writes are ignored when the Z80 hogs the Z-bus */
|
|
|
|
if (zbusack)
|
|
|
|
{
|
|
|
|
m68k_unused_16_w (address, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write into Z80 address space */
|
|
|
|
switch (base & 0x60)
|
|
|
|
{
|
|
|
|
case 0x40: /* YM2612 */
|
|
|
|
fm_write (0, address & 3, value >> 8);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x60:
|
|
|
|
switch (base & 0x7f)
|
|
|
|
{
|
|
|
|
case 0x60: /* Bank register */
|
|
|
|
gen_bank_w ((value >> 8) & 1);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x7f: /* VDP */
|
|
|
|
m68k_lockup_w_16(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
|
|
|
m68k_unused_16_w(address, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
default: /* ZRAM */
|
|
|
|
zram[address & 0x1fff] = value >> 8;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* CONTROL registers */
|
|
|
|
if (base <= 0xa1ff)
|
|
|
|
{
|
|
|
|
switch (base & 0xff)
|
|
|
|
{
|
|
|
|
case 0x00: /* I/O chip */
|
|
|
|
if (address & 0xe0) m68k_unused_16_w (address, value);
|
|
|
|
else io_write ((address >> 1) & 0x0f, value & 0xff);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x11: /* BUSREQ */
|
|
|
|
gen_busreq_w ((value >> 8) & 1);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x12: /* RESET */
|
|
|
|
gen_reset_w ((value >> 8) & 1);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x50: /* SVP REGISTERS */
|
|
|
|
if (svp && ((address & 0xfd) == 0))
|
|
|
|
{
|
|
|
|
/* just guessing here (Notaz) */
|
|
|
|
svp->ssp1601.gr[SSP_XST].h = value;
|
|
|
|
svp->ssp1601.gr[SSP_PM0].h |= 2;
|
|
|
|
svp->ssp1601.emu_status &= ~SSP_WAIT_PM0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m68k_unused_16_w(address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x30: /* TIME */
|
|
|
|
if (cart_hw.time_w)
|
|
|
|
{
|
|
|
|
cart_hw.time_w(address & 0xfe, value >> 8);
|
|
|
|
cart_hw.time_w(address, value & 0xff);
|
|
|
|
}
|
|
|
|
else m68k_unused_16_w (address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x41: /* BOOTROM */
|
|
|
|
if (value & 1)
|
|
|
|
{
|
|
|
|
rom_readmap[0] = &cart_rom[0];
|
|
|
|
rom_size = genromsize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rom_readmap[0] = &bios_rom[0];
|
|
|
|
rom_size = 0x800;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(config.bios_enabled & 2))
|
|
|
|
{
|
|
|
|
config.bios_enabled |= 2;
|
|
|
|
memcpy(bios_rom, cart_rom, 0x800);
|
|
|
|
memset(cart_rom, 0, 0x500000);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x10: /* MEMORY MODE */
|
|
|
|
case 0x20: /* MEGA-CD */
|
|
|
|
case 0x40: /* TMSS */
|
|
|
|
case 0x44: /* RADICA */
|
|
|
|
m68k_unused_16_w (address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
default: /* Unused */
|
|
|
|
m68k_lockup_w_16 (address, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Invalid address */
|
|
|
|
m68k_lockup_w_16 (address, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ROM:
|
|
|
|
*(uint16 *)(rom_readmap[offset] + (address & 0x7ffff)) = value;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case SRAM:
|
|
|
|
if (address <= sram.end) *(uint16 *)(sram.sram + (address - sram.start)) = value;
|
|
|
|
else m68k_unused_16_w (address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case EEPROM:
|
|
|
|
if ((address == (eeprom.type.sda_in_adr&0xfffffe)) || (address == (eeprom.type.scl_adr&0xfffffe)))
|
|
|
|
eeprom_write(address, value, 1);
|
|
|
|
else m68k_unused_16_w (address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case J_CART:
|
|
|
|
jcart_write(value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case UNUSED:
|
|
|
|
m68k_unused_16_w (address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case ILLEGAL:
|
|
|
|
m68k_lockup_w_16 (address, value);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case PICO_HW:
|
|
|
|
switch (address & 0xff)
|
|
|
|
{
|
|
|
|
case 0x10: /* PCM data register */
|
|
|
|
return; /* TODO */
|
|
|
|
|
|
|
|
case 0x12: /* PCM control resiter */
|
|
|
|
return; /* TODO */
|
|
|
|
|
|
|
|
case 0x18:
|
|
|
|
case 0x1a:
|
|
|
|
case 0x1c:
|
|
|
|
case 0x1e: /* TMSS register */
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
|
|
|
m68k_unused_16_w(address, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
default: /* WRAM */
|
|
|
|
*(uint16 *)(work_ram + (address & 0xffff)) = value;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void m68k_write_memory_32 (unsigned int address, unsigned int value)
|
|
|
|
{
|
|
|
|
/* Split into 2 writes */
|
|
|
|
m68k_write_memory_16 (address, value >> 16);
|
|
|
|
m68k_write_memory_16 ((address+2) & 0xffffff, value & 0xffff);
|
|
|
|
}
|