[Core/SCD]

----------
* added Mega CD / Sega CD hardware emulation (incl. Sub 68K, CDD, CDC, PCM, GFX
rotation/scaling, etc)
* added .ISO & .BIN CD image file support
* added 512K backup cartridge RAM support
* added savestate support for CD games

NOTES:
~~~~~~
* to play CD games, original BIOS ROM files are required in /genplus/bios/
directory: unzip & rename them to bios_CD_U.bin, bios_CD_E.bin, bios_CD_J.bin
* CD audio tracks (CD-DA) are not supported (yet)

[Core/CPU]
----------
* modified 68k core for Mega CD / Sega CD support

[Core/VDP]
---------------
* improved DMA accuracy
* added support for 8-bit VRAM writes with undocumented code value (verified on
real hardware by Nemesis)

[Gamecube/Wii]
---------------
* modified Master System & Game Gear "BIOS" support (files should be named
bios_U.sms, bios_J.sms, bios_E.sms & bios.gg and copied to /genplus/bios
directory).
* replaced "Hard Reset" button by a Soft Reset for systems having a Reset button
(Mega Drive / Genesis & Master System)
* State & SRAM files are now only compressed when saving to Gamecube Memory
Cards
* various fixes & cleanup.

[Core/SCD]
----------
* added Mega CD / Sega CD hardware emulation (incl. Sub 68K, CDD, CDC, PCM, GFX
rotation/scaling, etc)
* added .ISO & .BIN CD image file support
* added 512K backup cartridge RAM support
* added savestate support for CD games

NOTES:
~~~~~~
* to play CD games, original BIOS ROM files are required in /genplus/bios/
directory: unzip & rename them to bios_CD_U.bin, bios_CD_E.bin, bios_CD_J.bin
* CD audio tracks (CD-DA) are not supported (yet)

[Core/CPU]
----------
* modified 68k core for Mega CD / Sega CD support

[Core/VDP]
---------------
* improved DMA accuracy
* added support for 8-bit VRAM writes with undocumented code value (verified on
real hardware by Nemesis)

[Gamecube/Wii]
---------------
* modified Master System & Game Gear "BIOS" support (files should be named
bios_U.sms, bios_J.sms, bios_E.sms & bios.gg and copied to /genplus/bios
directory).
* replaced "Hard Reset" button by a Soft Reset for systems having a Reset button
(Mega Drive / Genesis & Master System)
* State & SRAM files are now only compressed when saving to Gamecube Memory
Cards
* various fixes & cleanup.
This commit is contained in:
EkeEke 2012-07-05 21:22:12 +02:00
parent f502dd48c7
commit 28775cc3aa
94 changed files with 16897 additions and 6224 deletions

View File

@ -17,9 +17,9 @@ include $(DEVKITPPC)/gamecube_rules
#---------------------------------------------------------------------------------
TARGET := genplus_cube
BUILD := build_cube
SOURCES := source source/m68k source/z80 source/sound source/ntsc source/input_hw source/cart_hw source/cart_hw/svp \
SOURCES := source source/m68k source/z80 source/sound source/ntsc source/input_hw source/cd_hw source/cart_hw source/cart_hw/svp \
source/gx source/gx/utils source/gx/gui source/gx/fileio source/gx/images source/gx/sounds
INCLUDES := source source/m68k source/z80 source/sound source/ntsc source/input_hw source/cart_hw source/cart_hw/svp \
INCLUDES := source source/m68k source/z80 source/sound source/ntsc source/input_hw source/cd_hw source/cart_hw source/cart_hw/svp \
source/gx source/gx/utils source/gx/gui source/gx/fileio source/gx/images source/gx/sounds \
$(BUILD)

View File

@ -17,9 +17,9 @@ include $(DEVKITPPC)/wii_rules
#---------------------------------------------------------------------------------
TARGET := genplus_wii
BUILD := build_wii
SOURCES := source source/m68k source/z80 source/sound source/ntsc source/input_hw source/cart_hw source/cart_hw/svp \
SOURCES := source source/m68k source/z80 source/sound source/ntsc source/input_hw source/cd_hw source/cart_hw source/cart_hw/svp \
source/gx source/gx/utils source/gx/gui source/gx/fileio source/gx/images source/gx/sounds
INCLUDES := source source/m68k source/z80 source/sound source/ntsc source/input_hw source/cart_hw source/cart_hw/svp \
INCLUDES := source source/m68k source/z80 source/sound source/ntsc source/input_hw source/cd_hw source/cart_hw source/cart_hw/svp \
source/gx source/gx/utils source/gx/gui source/gx/fileio source/gx/images source/gx/sounds \
$(BUILD)

View File

@ -87,7 +87,7 @@ void areplay_init(void)
action_replay.enabled = TYPE_AR;
/* internal registers mapped at $010000-$01ffff */
m68k_memory_map[0x01].write16 = ar_write_regs;
m68k.memory_map[0x01].write16 = ar_write_regs;
break;
}
@ -106,7 +106,7 @@ void areplay_init(void)
action_replay.enabled = TYPE_PRO1;
/* internal registers mapped at $010000-$01ffff */
m68k_memory_map[0x01].write16 = ar_write_regs;
m68k.memory_map[0x01].write16 = ar_write_regs;
}
else if (sp[1] == 0x60)
{
@ -114,17 +114,17 @@ void areplay_init(void)
action_replay.enabled = TYPE_PRO2;
/* internal registers mapped at $100000-$10ffff */
m68k_memory_map[0x10].write16 = ar_write_regs_2;
m68k.memory_map[0x10].write16 = ar_write_regs_2;
}
/* internal RAM (64k), mapped at $420000-$42ffff or $600000-$60ffff */
if (action_replay.enabled)
{
m68k_memory_map[sp[1]].base = action_replay.ram;
m68k_memory_map[sp[1]].read8 = NULL;
m68k_memory_map[sp[1]].read16 = NULL;
m68k_memory_map[sp[1]].write8 = ar_write_ram_8;
m68k_memory_map[sp[1]].write16 = NULL;
m68k.memory_map[sp[1]].base = action_replay.ram;
m68k.memory_map[sp[1]].read8 = NULL;
m68k.memory_map[sp[1]].read16 = NULL;
m68k.memory_map[sp[1]].write8 = ar_write_ram_8;
m68k.memory_map[sp[1]].write16 = NULL;
}
break;
}
@ -181,7 +181,7 @@ void areplay_reset(int hard)
memset(action_replay.addr, 0, sizeof(action_replay.addr));
/* by default, internal ROM is mapped at $000000-$00FFFF */
m68k_memory_map[0].base = action_replay.rom;
m68k.memory_map[0].base = action_replay.rom;
/* reset internal RAM on power-on */
if (hard)
@ -298,7 +298,7 @@ static void ar_write_regs(uint32 address, uint32 data)
}
/* enable Cartridge ROM */
m68k_memory_map[0].base = cart.rom;
m68k.memory_map[0].base = cart.rom;
}
}
@ -307,7 +307,7 @@ static void ar_write_regs_2(uint32 address, uint32 data)
/* enable Cartridge ROM */
if (((address & 0xff) == 0x78) && (data == 0xffff))
{
m68k_memory_map[0].base = cart.rom;
m68k.memory_map[0].base = cart.rom;
}
}

View File

@ -37,6 +37,7 @@
****************************************************************************************/
#include "shared.h"
#include "gg_eeprom.h"
#define BIT_DATA (0)
#define BIT_CLK (1)

View File

@ -124,14 +124,14 @@ void ggenie_reset(int hard)
}
/* Game Genie ROM is mapped at $000000-$007fff */
m68k_memory_map[0].base = ggenie.rom;
m68k.memory_map[0].base = ggenie.rom;
/* Internal registers are mapped at $000000-$00001f */
m68k_memory_map[0].write8 = ggenie_write_byte;
m68k_memory_map[0].write16 = ggenie_write_word;
m68k.memory_map[0].write8 = ggenie_write_byte;
m68k.memory_map[0].write16 = ggenie_write_word;
/* Disable registers reads */
m68k_memory_map[0].read16 = NULL;
m68k.memory_map[0].read16 = NULL;
}
}
@ -218,24 +218,24 @@ static void ggenie_write_regs(unsigned int offset, unsigned int data)
if (data & 0x400)
{
/* $0000-$7ffff reads mapped to Cartridge ROM */
m68k_memory_map[0].base = cart.rom;
m68k_memory_map[0].read8 = NULL;
m68k_memory_map[0].read16 = NULL;
m68k.memory_map[0].base = cart.rom;
m68k.memory_map[0].read8 = NULL;
m68k.memory_map[0].read16 = NULL;
}
else
{
/* $0000-$7ffff reads mapped to Game Genie ROM */
m68k_memory_map[0].base = ggenie.rom;
m68k_memory_map[0].read8 = NULL;
m68k_memory_map[0].read16 = NULL;
m68k.memory_map[0].base = ggenie.rom;
m68k.memory_map[0].read8 = NULL;
m68k.memory_map[0].read16 = NULL;
/* READ_ENABLE bit */
if (data & 0x200)
{
/* $0000-$7ffff reads mapped to Game Genie Registers */
/* code doing this should execute in RAM so we don't need to modify base address */
m68k_memory_map[0].read8 = ggenie_read_byte;
m68k_memory_map[0].read16 = ggenie_read_word;
m68k.memory_map[0].read8 = ggenie_read_byte;
m68k.memory_map[0].read16 = ggenie_read_word;
}
}
@ -260,8 +260,8 @@ static void ggenie_write_regs(unsigned int offset, unsigned int data)
ggenie.data[5] = ggenie.regs[19];
/* disable internal registers */
m68k_memory_map[0].write8 = m68k_unused_8_w;
m68k_memory_map[0].write16 = m68k_unused_16_w;
m68k.memory_map[0].write8 = m68k_unused_8_w;
m68k.memory_map[0].write16 = m68k_unused_16_w;
/* patch ROM when GG program exits (LOCK bit set) */
/* this is done here to handle patched program reads faster & more easily */
@ -270,8 +270,8 @@ static void ggenie_write_regs(unsigned int offset, unsigned int data)
}
else
{
m68k_memory_map[0].write8 = ggenie_write_byte;
m68k_memory_map[0].write16 = ggenie_write_word;
m68k.memory_map[0].write8 = ggenie_write_byte;
m68k.memory_map[0].write16 = ggenie_write_word;
}
}

View File

@ -42,6 +42,7 @@
****************************************************************************************/
#include "shared.h"
#include "md_eeprom.h"
#include "gamepad.h"
#define CART_CNT (48)
@ -53,13 +54,8 @@ typedef struct
uint16 chk_2; /* real checksum */
uint8 bank_start; /* first mapped bank in $400000-$7fffff region */
uint8 bank_end; /* last mapped bank in $400000-$7fffff region */
T_CART_HW cart_hw; /* hardware description */
} T_CART_ENTRY;
extern int emulate_address_error;
/* Cartridge Hardware structure */
T_CART cart;
cart_hw_t cart_hw; /* hardware description */
} md_entry_t;
/* Function prototypes */
static void mapper_sega_w(uint32 data);
@ -79,14 +75,12 @@ static void custom_regs_w(uint32 address, uint32 data);
static void custom_alt_regs_w(uint32 address, uint32 data);
static uint32 topshooter_r(uint32 address);
static void topshooter_w(uint32 address, uint32 data);
static uint32 sega_channel_r(uint32 address);
static void sega_channel_w(uint32 address, uint32 data);
/* Games that need extra hardware emulation:
- copy protection device
- custom ROM banking device
*/
static const T_CART_ENTRY rom_database[CART_CNT] =
static const md_entry_t rom_database[CART_CNT] =
{
/* Funny World & Balloon Boy */
{0x0000,0x06ab,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}},
@ -265,11 +259,11 @@ void md_cart_init(void)
for (i=0; i<0x40; i++)
{
/* cartridge ROM */
m68k_memory_map[i].base = cart.rom + ((i<<16) & cart.mask);
m68k_memory_map[i].read8 = NULL;
m68k_memory_map[i].read16 = NULL;
m68k_memory_map[i].write8 = m68k_unused_8_w;
m68k_memory_map[i].write16 = m68k_unused_16_w;
m68k.memory_map[i].base = cart.rom + ((i<<16) & cart.mask);
m68k.memory_map[i].read8 = NULL;
m68k.memory_map[i].read16 = NULL;
m68k.memory_map[i].write8 = m68k_unused_8_w;
m68k.memory_map[i].write16 = m68k_unused_16_w;
zbank_memory_map[i].read = NULL;
zbank_memory_map[i].write = zbank_unused_w;
}
@ -277,11 +271,11 @@ void md_cart_init(void)
for (i=0x40; i<0x80; i++)
{
/* unused area */
m68k_memory_map[i].base = cart.rom + (i<<16);
m68k_memory_map[i].read8 = m68k_read_bus_8;
m68k_memory_map[i].read16 = m68k_read_bus_16;
m68k_memory_map[i].write8 = m68k_unused_8_w;
m68k_memory_map[i].write16 = m68k_unused_16_w;
m68k.memory_map[i].base = cart.rom + (i<<16);
m68k.memory_map[i].read8 = m68k_read_bus_8;
m68k.memory_map[i].read16 = m68k_read_bus_16;
m68k.memory_map[i].write8 = m68k_unused_8_w;
m68k.memory_map[i].write16 = m68k_unused_16_w;
zbank_memory_map[i].read = zbank_unused_r;
zbank_memory_map[i].write = zbank_unused_w;
}
@ -296,12 +290,12 @@ void md_cart_init(void)
if (sram.custom)
{
/* Serial EEPROM */
m68k_memory_map[md_eeprom.type.sda_out_adr >> 16].read8 = md_eeprom_read_byte;
m68k_memory_map[md_eeprom.type.sda_out_adr >> 16].read16 = md_eeprom_read_word;
m68k_memory_map[md_eeprom.type.sda_in_adr >> 16].read8 = md_eeprom_read_byte;
m68k_memory_map[md_eeprom.type.sda_in_adr >> 16].read16 = md_eeprom_read_word;
m68k_memory_map[md_eeprom.type.scl_adr >> 16].write8 = md_eeprom_write_byte;
m68k_memory_map[md_eeprom.type.scl_adr >> 16].write16 = md_eeprom_write_word;
m68k.memory_map[md_eeprom.type.sda_out_adr >> 16].read8 = md_eeprom_read_byte;
m68k.memory_map[md_eeprom.type.sda_out_adr >> 16].read16 = md_eeprom_read_word;
m68k.memory_map[md_eeprom.type.sda_in_adr >> 16].read8 = md_eeprom_read_byte;
m68k.memory_map[md_eeprom.type.sda_in_adr >> 16].read16 = md_eeprom_read_word;
m68k.memory_map[md_eeprom.type.scl_adr >> 16].write8 = md_eeprom_write_byte;
m68k.memory_map[md_eeprom.type.scl_adr >> 16].write16 = md_eeprom_write_word;
zbank_memory_map[md_eeprom.type.sda_out_adr >> 16].read = md_eeprom_read_byte;
zbank_memory_map[md_eeprom.type.sda_in_adr >> 16].read = md_eeprom_read_byte;
zbank_memory_map[md_eeprom.type.scl_adr >> 16].write = md_eeprom_write_byte;
@ -311,11 +305,11 @@ void md_cart_init(void)
/* Static RAM (64k max.) - disabled on reset if ROM is mapped in same area */
if (cart.romsize <= sram.start)
{
m68k_memory_map[sram.start >> 16].base = sram.sram;
m68k_memory_map[sram.start >> 16].read8 = NULL;
m68k_memory_map[sram.start >> 16].read16 = NULL;
m68k_memory_map[sram.start >> 16].write8 = NULL;
m68k_memory_map[sram.start >> 16].write16 = NULL;
m68k.memory_map[sram.start >> 16].base = sram.sram;
m68k.memory_map[sram.start >> 16].read8 = NULL;
m68k.memory_map[sram.start >> 16].read16 = NULL;
m68k.memory_map[sram.start >> 16].write8 = NULL;
m68k.memory_map[sram.start >> 16].write16 = NULL;
zbank_memory_map[sram.start >> 16].read = NULL;
zbank_memory_map[sram.start >> 16].write = NULL;
}
@ -330,32 +324,22 @@ void md_cart_init(void)
{
svp_init();
m68k_memory_map[0x30].base = svp->dram;
m68k_memory_map[0x30].read16 = NULL;
m68k_memory_map[0x30].write16 = svp_write_dram;
m68k.memory_map[0x30].base = svp->dram;
m68k.memory_map[0x30].read16 = NULL;
m68k.memory_map[0x30].write16 = svp_write_dram;
m68k_memory_map[0x31].base = svp->dram + 0x10000;
m68k_memory_map[0x31].read16 = NULL;
m68k_memory_map[0x31].write16 = svp_write_dram;
m68k.memory_map[0x31].base = svp->dram + 0x10000;
m68k.memory_map[0x31].read16 = NULL;
m68k.memory_map[0x31].write16 = svp_write_dram;
m68k_memory_map[0x39].read16 = svp_read_cell_1;
m68k_memory_map[0x3a].read16 = svp_read_cell_2;
m68k.memory_map[0x39].read16 = svp_read_cell_1;
m68k.memory_map[0x3a].read16 = svp_read_cell_2;
}
/**********************************************
SPECIFIC PERIPHERAL SUPPORT
***********************************************/
/* restore previous input settings */
if (old_system[0] != -1)
{
input.system[0] = old_system[0];
}
if (old_system[1] != -1)
{
input.system[1] = old_system[1];
}
/* default GUN settings */
input.x_offset = 0x00;
input.y_offset = 0x00;
@ -475,10 +459,10 @@ void md_cart_init(void)
}
/* extra connectors mapped at $38xxxx or $3Fxxxx */
m68k_memory_map[0x38].read16 = jcart_read;
m68k_memory_map[0x38].write16 = jcart_write;
m68k_memory_map[0x3f].read16 = jcart_read;
m68k_memory_map[0x3f].write16 = jcart_write;
m68k.memory_map[0x38].read16 = jcart_read;
m68k.memory_map[0x38].write16 = jcart_write;
m68k.memory_map[0x3f].read16 = jcart_read;
m68k.memory_map[0x3f].write16 = jcart_write;
}
}
@ -543,7 +527,7 @@ void md_cart_init(void)
/* $000000-$1FFFFF is mapped to S&K ROM */
for (i=0x00; i<0x20; i++)
{
m68k_memory_map[i].base = cart.rom + 0x600000 + (i << 16);
m68k.memory_map[i].base = cart.rom + 0x600000 + (i << 16);
}
cart.special |= HW_LOCK_ON;
@ -559,7 +543,7 @@ void md_cart_init(void)
/**********************************************
Cartridge Extra Hardware
***********************************************/
memset(&cart.hw, 0, sizeof(T_CART_HW));
memset(&cart.hw, 0, sizeof(cart.hw));
/* search for game into database */
for (i=0; i < CART_CNT + 1; i++)
@ -571,21 +555,21 @@ void md_cart_init(void)
int j = rom_database[i].bank_start;
/* retrieve hardware information */
memcpy(&cart.hw, &(rom_database[i].cart_hw), sizeof(T_CART_HW));
memcpy(&cart.hw, &(rom_database[i].cart_hw), sizeof(cart.hw));
/* initialize memory handlers for $400000-$7FFFFF region */
while (j <= rom_database[i].bank_end)
{
if (cart.hw.regs_r)
{
m68k_memory_map[j].read8 = cart.hw.regs_r;
m68k_memory_map[j].read16 = cart.hw.regs_r;
m68k.memory_map[j].read8 = cart.hw.regs_r;
m68k.memory_map[j].read16 = cart.hw.regs_r;
zbank_memory_map[j].read = cart.hw.regs_r;
}
if (cart.hw.regs_w)
{
m68k_memory_map[j].write8 = cart.hw.regs_w;
m68k_memory_map[j].write16 = cart.hw.regs_w;
m68k.memory_map[j].write8 = cart.hw.regs_w;
m68k.memory_map[j].write16 = cart.hw.regs_w;
zbank_memory_map[j].write = cart.hw.regs_w;
}
j++;
@ -608,13 +592,13 @@ void md_cart_init(void)
/* BOOT ROM is mapped to $000000-$3FFFFF */
for (i=0x00; i<0x40; i++)
{
m68k_memory_map[i].base = cart.rom + 0x900000;
m68k.memory_map[i].base = cart.rom + 0x900000;
}
}
#if M68K_EMULATE_ADDRESS_ERROR
/* default behavior */
emulate_address_error = config.addr_error;
m68k.aerr_enabled = config.addr_error;
#endif
/* detect special cartridges */
@ -623,15 +607,15 @@ void md_cart_init(void)
/* Ultimate MK3 (hack) */
for (i=0x40; i<0xA0; i++)
{
m68k_memory_map[i].base = cart.rom + (i<<16);
m68k_memory_map[i].read8 = NULL;
m68k_memory_map[i].read16 = NULL;
m68k.memory_map[i].base = cart.rom + (i<<16);
m68k.memory_map[i].read8 = NULL;
m68k.memory_map[i].read16 = NULL;
zbank_memory_map[i].read = NULL;
}
#if M68K_EMULATE_ADDRESS_ERROR
/* this game does not work properly on real hardware */
emulate_address_error = 0;
m68k.aerr_enabled = 0;
#endif
}
else if (cart.romsize > 0x400000)
@ -641,26 +625,19 @@ void md_cart_init(void)
cart.hw.time_w = mapper_ssf2_w;
}
/* Sega Channel mapped hardware (?) */
if (strstr(rominfo.international,"Sega Channel") != NULL)
{
cart.hw.time_r = sega_channel_r;
cart.hw.time_w = sega_channel_w;
}
/* Legend of Wukong mapper */
if (strstr(rominfo.international,"LEGEND OF WUKONG") != NULL)
{
/* 128K ROM Bankswitch */
m68k_memory_map[0].write8 = mapper_wukong_w;
m68k.memory_map[0].write8 = mapper_wukong_w;
zbank_memory_map[0].write = mapper_wukong_w;
/* 8K SRAM */
m68k_memory_map[0x3C].base = sram.sram;
m68k_memory_map[0x3C].read8 = NULL;
m68k_memory_map[0x3C].read16 = NULL;
m68k_memory_map[0x3C].write8 = NULL;
m68k_memory_map[0x3C].write16 = NULL;
m68k.memory_map[0x3C].base = sram.sram;
m68k.memory_map[0x3C].read8 = NULL;
m68k.memory_map[0x3C].read16 = NULL;
m68k.memory_map[0x3C].write8 = NULL;
m68k.memory_map[0x3C].write16 = NULL;
zbank_memory_map[0x3C].read = NULL;
zbank_memory_map[0x3C].write = NULL;
}
@ -682,7 +659,7 @@ void md_cart_reset(int hard_reset)
{
for (i=0x00; i<0x40; i++)
{
m68k_memory_map[i].base = cart.rom + ((i<<16) & cart.mask);
m68k.memory_map[i].base = cart.rom + ((i<<16) & cart.mask);
}
}
@ -711,7 +688,7 @@ void md_cart_reset(int hard_reset)
/* disable UPMEM chip at $300000-$3fffff */
for (i=0x30; i<0x40; i++)
{
m68k_memory_map[i].base = cart.rom + ((i<<16) & cart.mask);
m68k.memory_map[i].base = cart.rom + ((i<<16) & cart.mask);
}
}
break;
@ -734,7 +711,7 @@ int md_cart_context_save(uint8 *state)
for (i=0; i<0x40; i++)
{
/* get base address */
base = m68k_memory_map[i].base;
base = m68k.memory_map[i].base;
if (base == sram.sram)
{
@ -777,12 +754,12 @@ int md_cart_context_load(uint8 *state)
if (offset == 0xff)
{
/* SRAM */
m68k_memory_map[i].base = sram.sram;
m68k.memory_map[i].base = sram.sram;
}
else
{
/* ROM */
m68k_memory_map[i].base = cart.rom + (offset << 16);
m68k.memory_map[i].base = cart.rom + (offset << 16);
}
}
@ -816,16 +793,16 @@ static void mapper_sega_w(uint32 data)
if (sram.on)
{
/* Backup RAM mapped to $200000-$20ffff (normally mirrored up to $3fffff but this breaks Sonic Megamix and no game need it) */
m68k_memory_map[0x20].base = sram.sram;
m68k_memory_map[0x20].write8 = NULL;
m68k_memory_map[0x20].write16 = NULL;
m68k.memory_map[0x20].base = sram.sram;
m68k.memory_map[0x20].write8 = NULL;
m68k.memory_map[0x20].write16 = NULL;
zbank_memory_map[0x20].write = NULL;
/* Backup RAM write protection */
if (data & 2)
{
m68k_memory_map[0x20].write8 = m68k_unused_8_w;
m68k_memory_map[0x20].write16 = m68k_unused_16_w;
m68k.memory_map[0x20].write8 = m68k_unused_8_w;
m68k.memory_map[0x20].write16 = m68k_unused_16_w;
zbank_memory_map[0x20].write = zbank_unused_w;
}
}
@ -836,7 +813,7 @@ static void mapper_sega_w(uint32 data)
/* S2K upmem chip mapped to $300000-$3fffff (256K mirrored) */
for (i=0x30; i<0x40; i++)
{
m68k_memory_map[i].base = (cart.rom + 0x800000) + ((i & 3) << 16);
m68k.memory_map[i].base = (cart.rom + 0x800000) + ((i & 3) << 16);
}
}
}
@ -845,9 +822,9 @@ static void mapper_sega_w(uint32 data)
/* cartridge ROM mapped to $200000-$3fffff */
for (i=0x20; i<0x40; i++)
{
m68k_memory_map[i].base = cart.rom + ((i<<16) & cart.mask);
m68k_memory_map[i].write8 = m68k_unused_8_w;
m68k_memory_map[i].write16 = m68k_unused_16_w;
m68k.memory_map[i].base = cart.rom + ((i<<16) & cart.mask);
m68k.memory_map[i].write8 = m68k_unused_8_w;
m68k.memory_map[i].write16 = m68k_unused_16_w;
zbank_memory_map[i].write = zbank_unused_w;
}
}
@ -870,7 +847,7 @@ static void mapper_ssf2_w(uint32 address, uint32 data)
for (i=0; i<8; i++)
{
m68k_memory_map[address++].base = src + (i<<16);
m68k.memory_map[address++].base = src + (i<<16);
}
}
}
@ -886,7 +863,7 @@ static void mapper_wukong_w(uint32 address, uint32 data)
/* $200000-$3BFFFF mapped to $000000-$1BFFFF */
for (i=0x20; i<0x3C; i++)
{
m68k_memory_map[i].base = cart.rom + (((i&0x1F)<<16) & cart.mask);
m68k.memory_map[i].base = cart.rom + (((i&0x1F)<<16) & cart.mask);
}
}
else
@ -894,7 +871,7 @@ static void mapper_wukong_w(uint32 address, uint32 data)
/* $200000-$3BFFFF mapped to $200000-$3BFFFF */
for (i=0x20; i<0x3C; i++)
{
m68k_memory_map[i].base = cart.rom + ((i<<16) & cart.mask);
m68k.memory_map[i].base = cart.rom + ((i<<16) & cart.mask);
}
}
}
@ -936,7 +913,7 @@ static void mapper_realtec_w(uint32 address, uint32 data)
int i;
for (i=0x00; i<0x40; i++)
{
m68k_memory_map[i].base = &cart.rom[(base + (i % cart.hw.regs[2])) << 16];
m68k.memory_map[i].base = &cart.rom[(base + (i % cart.hw.regs[2])) << 16];
}
}
return;
@ -955,8 +932,8 @@ static void mapper_seganet_w(uint32 address, uint32 data)
/* ROM Write protected */
for (i=0; i<0x40; i++)
{
m68k_memory_map[i].write8 = m68k_unused_8_w;
m68k_memory_map[i].write16 = m68k_unused_16_w;
m68k.memory_map[i].write8 = m68k_unused_8_w;
m68k.memory_map[i].write16 = m68k_unused_16_w;
zbank_memory_map[i].write = zbank_unused_w;
}
}
@ -965,8 +942,8 @@ static void mapper_seganet_w(uint32 address, uint32 data)
/* ROM Write enabled */
for (i=0; i<0x40; i++)
{
m68k_memory_map[i].write8 = NULL;
m68k_memory_map[i].write16 = NULL;
m68k.memory_map[i].write8 = NULL;
m68k.memory_map[i].write16 = NULL;
zbank_memory_map[i].write = NULL;
}
}
@ -986,11 +963,11 @@ static void mapper_32k_w(uint32 data)
for (i=0; i<0x10; i++)
{
/* Remap to unused ROM area */
m68k_memory_map[i].base = &cart.rom[0x400000 + (i << 16)];
m68k.memory_map[i].base = &cart.rom[0x400000 + (i << 16)];
/* address = address OR (value << 15) */
memcpy(m68k_memory_map[i].base, cart.rom + ((i << 16) | (data & 0x3f) << 15), 0x8000);
memcpy(m68k_memory_map[i].base + 0x8000, cart.rom + ((i << 16) | ((data | 1) & 0x3f) << 15), 0x8000);
memcpy(m68k.memory_map[i].base, cart.rom + ((i << 16) | (data & 0x3f) << 15), 0x8000);
memcpy(m68k.memory_map[i].base + 0x8000, cart.rom + ((i << 16) | ((data | 1) & 0x3f) << 15), 0x8000);
}
}
else
@ -998,7 +975,7 @@ static void mapper_32k_w(uint32 data)
/* reset default $000000-$0FFFFF mapping */
for (i=0; i<16; i++)
{
m68k_memory_map[i].base = &cart.rom[i << 16];
m68k.memory_map[i].base = &cart.rom[i << 16];
}
}
}
@ -1016,7 +993,7 @@ static void mapper_64k_w(uint32 data)
/* bank is mapped at $000000-$0FFFFF */
for (i=0; i<16; i++)
{
m68k_memory_map[i].base = &cart.rom[(data & 0xf) << 16];
m68k.memory_map[i].base = &cart.rom[(data & 0xf) << 16];
}
}
else
@ -1024,7 +1001,7 @@ static void mapper_64k_w(uint32 data)
/* reset default $000000-$0FFFFF mapping */
for (i=0; i<16; i++)
{
m68k_memory_map[i].base = &cart.rom[(i & 0xf) << 16];
m68k.memory_map[i].base = &cart.rom[(i & 0xf) << 16];
}
}
}
@ -1039,7 +1016,7 @@ static void mapper_64k_multi_w(uint32 address)
/* 64 x 64k banks */
for (i=0; i<64; i++)
{
m68k_memory_map[i].base = &cart.rom[((address++) & 0x3f) << 16];
m68k.memory_map[i].base = &cart.rom[((address++) & 0x3f) << 16];
}
}
@ -1054,7 +1031,7 @@ static uint32 mapper_radica_r(uint32 address)
/* 64 x 64k banks */
for (i = 0; i < 64; i++)
{
m68k_memory_map[i].base = &cart.rom[((address++)& 0x3f)<< 16];
m68k.memory_map[i].base = &cart.rom[((address++)& 0x3f)<< 16];
}
return 0xffff;
@ -1278,7 +1255,6 @@ Unused write16 00300000 = ACDC (000057B2)
Unused write16 00380000 = 0000 (000057BC)
Unused read16 00300000 (000057C6)
*/
static uint32 sega_channel_r(uint32 address)
{
return m68k_read_bus_16(address);;
@ -1288,3 +1264,4 @@ static void sega_channel_w(uint32 address, uint32 data)
{
m68k_unused_16_w(address, data);
}
*/

View File

@ -44,6 +44,8 @@
#ifndef _MD_CART_H_
#define _MD_CART_H_
#define cart ext.md_cart
/* Lock-On cartridge type */
#define TYPE_GG 0x01 /* Game Genie */
#define TYPE_AR 0x02 /* (Pro) Action Replay */
@ -65,21 +67,19 @@ typedef struct
void (*time_w)(unsigned int address, unsigned int data); /* !TIME signal ($a130xx) write handler */
unsigned int (*regs_r)(unsigned int address); /* cart hardware registers read handler */
void (*regs_w)(unsigned int address, unsigned int data); /* cart hardware registers write handler */
} T_CART_HW;
} cart_hw_t;
/* Cartridge type */
typedef struct
{
uint8 *rom; /* ROM area */
uint8 rom[MAXROMSIZE]; /* ROM area */
uint8 *base; /* ROM base (saved for OS/Cartridge ROM swap) */
uint32 romsize; /* ROM size */
uint32 mask; /* ROM mask */
uint8 special; /* Lock-On, J-Cart or SMS 3-D glasses hardware */
T_CART_HW hw; /* Extra mapping hardware */
} T_CART;
cart_hw_t hw; /* Extra mapping hardware */
} md_cart_t;
/* global variables */
extern T_CART cart;
/* Function prototypes */
extern void md_cart_init(void);
@ -88,5 +88,3 @@ extern int md_cart_context_save(uint8 *state);
extern int md_cart_context_load(uint8 *state);
#endif

View File

@ -37,6 +37,7 @@
****************************************************************************************/
#include "shared.h"
#include "md_eeprom.h"
#define GAME_CNT 28

View File

@ -2,7 +2,7 @@
* Genesis Plus
* SG-1000, Master System & Game Gear cartridge hardware support
*
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -37,6 +37,7 @@
****************************************************************************************/
#include "shared.h"
#include "gg_eeprom.h"
#include "terebi_oekaki.h"
#define MAPPER_NONE (0x00)
@ -455,20 +456,6 @@ void sms_cart_init(void)
/* initialize SRAM */
sram_init();
/* restore previous input settings */
if (old_system[0] != -1)
{
input.system[0] = old_system[0];
}
if (old_system[1] != -1)
{
input.system[1] = old_system[1];
}
/* default gun offset */
input.x_offset = 20;
input.y_offset = 0;
/* save current settings */
if (old_system[0] == -1)
{
@ -483,6 +470,10 @@ void sms_cart_init(void)
input.system[0] = device;
input.system[1] = SYSTEM_MS_GAMEPAD;
/* default gun offset */
input.x_offset = 20;
input.y_offset = 0;
/* SpaceGun & Gangster Town use different gun offset */
if ((crc == 0x5359762D) || (crc == 0x5FC74D2A))
{
@ -490,100 +481,37 @@ void sms_cart_init(void)
}
/* BIOS support */
if (config.bios & 0x01)
if (config.bios & 1)
{
/* verify that BIOS is not already loaded */
if (!(config.bios & (system_hw & 0xF0)))
{
FILE *fp = NULL;
/* load BIOS file */
int bios_size = load_bios();
/* reset BIOS size */
int bios_size = 0;
/* mark both BIOS as unloaded */
config.bios &= ~(SYSTEM_SMS | SYSTEM_GG);
/* open BIOS file */
switch (system_hw)
{
case SYSTEM_GG:
case SYSTEM_GGMS:
fp = fopen(GG_BIOS, "rb");
break;
case SYSTEM_SMS:
case SYSTEM_SMS2:
fp = fopen(MS_BIOS, "rb");
break;
default:
break;
}
/* try to load BIOS file */
if (fp != NULL)
{
/* get file size */
int size;
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
/* BIOS ROM is stored above cartridge ROM area, into $400000-$4FFFFF (max. 1MB) */
if ((size <= 0x100000) && (cart.romsize <= 0x400000))
{
/* BIOS ROM size */
bios_size = size;
/* read bytes chunks */
while (size > 2048)
{
fread(cart.rom + 0x400000 + bios_size - size, 2048, 1, fp);
size -= 2048;
}
/* read remaining bytes */
fread(cart.rom + 0x400000 + bios_size - size, size, 1, fp);
/* mark BIOS ROM as loaded */
config.bios |= (system_hw & 0xF0);
}
/* close file */
fclose(fp);
}
/* BIOS ROM mapper */
if (bios_size > 0xC000)
{
/* assume SEGA mapper if BIOS ROM is larger than 48k */
bios_rom.mapper = MAPPER_SEGA;
bios_rom.pages = bios_size >> 14;
}
else
else if (bios_size >= 0)
{
/* default BIOS ROM mapper */
bios_rom.mapper = MAPPER_NONE;
bios_rom.pages = bios_size >> 10;
}
}
/* check if BIOS has been correctly loaded */
if (bios_rom.pages)
{
/* unload cartridge if required */
if (!(config.bios & 2))
/* unload cartridge if required & BIOS ROM is loaded */
if (!(config.bios & 2) && bios_rom.pages)
{
cart_rom.pages = 0;
}
}
}
else /* BIOS support disabled */
else
{
/* unload BIOS */
bios_rom.pages = 0;
/* mark Master System & Game Gear BIOS as unloaded */
system_bios &= ~(SYSTEM_SMS | SYSTEM_GG);
/* mark both BIOS as unloaded */
config.bios &= ~(SYSTEM_SMS | SYSTEM_GG);
/* BIOS ROM is disabled */
bios_rom.pages = 0;
}
}

View File

@ -2,7 +2,7 @@
* Genesis Plus
* SG-1000, Master System & Game Gear cartridge hardware support
*
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -51,7 +51,7 @@ typedef struct
} T_SRAM;
/* Function prototypes */
extern void sram_init ();
extern void sram_init();
/* global variables */
extern T_SRAM sram;

258
source/cd_hw/cd_cart.c Normal file
View File

@ -0,0 +1,258 @@
/***************************************************************************************
* Genesis Plus
* CD cartridge (external RAM or ROM)
*
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#include "shared.h"
/*--------------------------------------------------------------------------*/
/* cartridge backup RAM (max. 512KB) */
/*--------------------------------------------------------------------------*/
static unsigned int cart_ram_read_byte(unsigned int address)
{
/* LSB only */
if (address & 1)
{
return scd.cartridge.area[(address >> 1) & scd.cartridge.mask];
}
return 0xff;
}
static unsigned int cart_ram_read_word(unsigned int address)
{
return (scd.cartridge.area[(address >> 1) & scd.cartridge.mask] | 0xff00);
}
static void cart_ram_write_byte(unsigned int address, unsigned int data)
{
/* LSB only */
if (address & 1)
{
scd.cartridge.area[(address >> 1) & scd.cartridge.mask] = data;
}
}
static void cart_ram_write_word(unsigned int address, unsigned int data)
{
scd.cartridge.area[(address >> 1) & scd.cartridge.mask] = data & 0xff;
}
/*--------------------------------------------------------------------------*/
/* cartridge RAM ID */
/*--------------------------------------------------------------------------*/
static unsigned int cart_id_read_byte(unsigned int address)
{
/* LSB only */
if (address & 1)
{
return scd.cartridge.id;
}
return 0xff;
}
static unsigned int cart_id_read_word(unsigned int address)
{
return (scd.cartridge.id | 0xff00);
}
/*--------------------------------------------------------------------------*/
/* cartridge RAM write protection */
/*--------------------------------------------------------------------------*/
static unsigned int cart_prot_read_byte(unsigned int address)
{
/* LSB only */
if (address & 1)
{
return scd.cartridge.prot;
}
return 0xff;
}
static unsigned int cart_prot_read_word(unsigned int address)
{
return (scd.cartridge.prot | 0xff00);
}
static void cart_prot_write_byte(unsigned int address, unsigned int data)
{
/* LSB only */
if (address & 1)
{
int i;
if (data & 1)
{
/* cartridge is write enabled */
for (i=0x60; i<0x70; i++)
{
m68k.memory_map[i].write8 = cart_ram_write_byte;
m68k.memory_map[i].write16 = cart_ram_write_word;
zbank_memory_map[i].write = cart_ram_write_byte;
}
}
else
{
/* cartridge is write protected */
for (i=0x60; i<0x70; i++)
{
m68k.memory_map[i].write8 = m68k_unused_8_w;
m68k.memory_map[i].write16 = m68k_unused_16_w;
zbank_memory_map[i].write = zbank_unused_w;
}
}
scd.cartridge.prot = data;
}
}
static void cart_prot_write_word(unsigned int address, unsigned int data)
{
int i;
if (data & 1)
{
/* cartridge is write enabled */
for (i=0x60; i<0x70; i++)
{
m68k.memory_map[i].write8 = cart_ram_write_byte;
m68k.memory_map[i].write16 = cart_ram_write_word;
zbank_memory_map[i].write = cart_ram_write_byte;
}
}
else
{
/* cartridge is write protected */
for (i=0x60; i<0x70; i++)
{
m68k.memory_map[i].write8 = m68k_unused_8_w;
m68k.memory_map[i].write16 = m68k_unused_16_w;
zbank_memory_map[i].write = zbank_unused_w;
}
}
scd.cartridge.prot = data & 0xff;
}
/*--------------------------------------------------------------------------*/
/* cartridge hardware initialization */
/*--------------------------------------------------------------------------*/
void cd_cart_init(void)
{
int i;
/* System boot mode */
if (scd.cartridge.boot)
{
/* disable backup RAM Cart when booting from cartridge (Mode 1) */
scd.cartridge.id = 0;
}
else
{
/* enable 512K backup RAM Cart when booting from CD (Mode 2) */
scd.cartridge.id = 6;
}
/* RAM cart enabled ? */
if (scd.cartridge.id)
{
/* cartridge RAM size mask */
scd.cartridge.mask = (1 << (scd.cartridge.id + 13)) - 1;
/* enable cartridge RAM write access */
scd.cartridge.prot = 1;
/* cartridge ID register (read-only) */
for (i=0x40; i<0x60; i++)
{
m68k.memory_map[i].base = NULL;
m68k.memory_map[i].read8 = cart_id_read_byte;
m68k.memory_map[i].read16 = cart_id_read_word;
m68k.memory_map[i].write8 = m68k_unused_8_w;
m68k.memory_map[i].write16 = m68k_unused_16_w;
zbank_memory_map[i].read = cart_id_read_byte;
zbank_memory_map[i].write = zbank_unused_w;
}
/* cartridge RAM */
for (i=0x60; i<0x70; i++)
{
m68k.memory_map[i].base = NULL;
m68k.memory_map[i].read8 = cart_ram_read_byte;
m68k.memory_map[i].read16 = cart_ram_read_word;
m68k.memory_map[i].write8 = cart_ram_write_byte;
m68k.memory_map[i].write16 = cart_ram_write_word;
zbank_memory_map[i].read = cart_ram_read_byte;
zbank_memory_map[i].write = cart_ram_write_byte;
}
/* cartridge write protection register */
for (i=0x70; i<0x80; i++)
{
m68k.memory_map[i].base = NULL;
m68k.memory_map[i].read8 = cart_prot_read_byte;
m68k.memory_map[i].read16 = cart_prot_read_word;
m68k.memory_map[i].write8 = cart_prot_write_byte;
m68k.memory_map[i].write16 = cart_prot_write_word;
zbank_memory_map[i].read = cart_prot_read_byte;
zbank_memory_map[i].write = cart_prot_write_byte;
}
}
else
{
/* $000000-$3FFFFF (boot from cartridge) or $400000-$7FFFFF (boot from CD) */
uint8 base = scd.cartridge.boot ^ 0x40;
/* cartridge ROM */
for (i=base; i<base+0x40; i++)
{
m68k.memory_map[i].base = scd.cartridge.area + ((i & 0x3f) << 16);
m68k.memory_map[i].read8 = NULL;
m68k.memory_map[i].read16 = NULL;
m68k.memory_map[i].write8 = NULL;
m68k.memory_map[i].write16 = NULL;
zbank_memory_map[i].read = NULL;
zbank_memory_map[i].write = NULL;
}
}
}

50
source/cd_hw/cd_cart.h Normal file
View File

@ -0,0 +1,50 @@
/***************************************************************************************
* Genesis Plus
* CD cartridge (external RAM or ROM)
*
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
/* CD cartridge (backup RAM or game) */
typedef struct
{
uint8 boot; /* boot mode (0x00: boot from CD, 0x40: boot from cartridge) */
uint8 id; /* cartridge ID (indicates RAM size, 0 if disabled) */
uint8 prot; /* cartridge RAM write protection */
uint32 mask; /* cartridge RAM size mask */
uint8 area[0x400000]; /* cartridge ROM/RAM area (4MB) */
} cd_cart_t;
/* Function prototypes */
extern void cd_cart_init(void);

626
source/cd_hw/cdc.c Normal file
View File

@ -0,0 +1,626 @@
/***************************************************************************************
* Genesis Plus
* CD data controller (LC89510 compatible)
*
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#include "shared.h"
/* IFSTAT register bitmasks */
#define BIT_DTEI 0x40
#define BIT_DECI 0x20
#define BIT_DTBSY 0x08
#define BIT_DTEN 0x02
/* IFCTRL register bitmasks */
#define BIT_DTEIEN 0x40
#define BIT_DECIEN 0x20
#define BIT_DOUTEN 0x02
/* CTRL0 register bitmasks */
#define BIT_DECEN 0x80
#define BIT_E01RQ 0x20
#define BIT_AUTORQ 0x10
#define BIT_WRRQ 0x04
/* CTRL1 register bitmasks */
#define BIT_MODRQ 0x08
#define BIT_FORMRQ 0x04
#define BIT_SHDREN 0x01
/* CTRL2 register bitmask */
#define BIT_VALST 0x80
/* TODO: figure exact DMA transfer rate */
#define DMA_BYTES_PER_LINE 512
void cdc_init(void)
{
memset(&cdc, 0, sizeof(cdc_t));
}
void cdc_reset(void)
{
/* reset CDC register index */
scd.regs[0x04>>1].byte.l = 0x00;
/* reset CDC registers */
cdc.ifstat = 0xff;
cdc.ifctrl = 0x00;
cdc.ctrl[0] = 0x00;
cdc.ctrl[1] = 0x00;
cdc.stat[0] = 0x00;
cdc.stat[1] = 0x00;
cdc.stat[2] = 0x00;
cdc.stat[3] = 0x80;
cdc.head[0][0] = 0x00;
cdc.head[0][1] = 0x00;
cdc.head[0][2] = 0x00;
cdc.head[0][3] = 0x01;
cdc.head[1][0] = 0x00;
cdc.head[1][1] = 0x00;
cdc.head[1][2] = 0x00;
cdc.head[1][3] = 0x00;
/* reset CDC cycle counter */
cdc.cycles = 0;
/* DMA transfer disabled */
cdc.dma_w = 0;
/* clear any pending IRQ */
if (scd.pending & (1 << 5))
{
/* clear any pending interrupt level 5 */
scd.pending &= ~(1 << 5);
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
void cdc_dma_update(void)
{
/* maximal transfer length */
int length = DMA_BYTES_PER_LINE;
/* end of DMA transfer ? */
if (cdc.dbc.w < DMA_BYTES_PER_LINE)
{
/* transfer remaining words using 16-bit DMA */
cdc.dma_w((cdc.dbc.w + 1) >> 1);
/* reset data byte counter (DBCH bits 4-7 should be set to 1) */
cdc.dbc.w = 0xf000;
/* clear !DTEN and !DTBSY */
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
/* pending Data Transfer End interrupt */
cdc.ifstat &= ~BIT_DTEI;
/* Data Transfer End interrupt enabled ? */
if (cdc.ifctrl & BIT_DTEIEN)
{
/* pending level 5 interrupt */
scd.pending |= (1 << 5);
/* level 5 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x20)
{
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
/* clear DSR bit & set EDT bit (SCD register $04) */
scd.regs[0x04>>1].byte.h = (scd.regs[0x04>>1].byte.h & 0x07) | 0x80;
/* disable DMA transfer */
cdc.dma_w = 0;
}
else
{
/* transfer all words using 16-bit DMA */
cdc.dma_w(DMA_BYTES_PER_LINE >> 1);
/* decrement data byte counter */
cdc.dbc.w -= length;
}
}
int cdc_decoder_update(uint32 header)
{
/* data decoding enabled ? */
if (cdc.ctrl[0] & BIT_DECEN)
{
/* update HEAD registers */
*(uint32 *)(cdc.head[0]) = header;
/* set !VALST */
cdc.stat[3] = 0x00;
/* pending decoder interrupt */
cdc.ifstat &= ~BIT_DECI;
/* decoder interrupt enabled ? */
if (cdc.ifctrl & BIT_DECIEN)
{
/* pending level 5 interrupt */
scd.pending |= (1 << 5);
/* level 5 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x20)
{
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
/* buffer RAM write enabled ? */
if (cdc.ctrl[0] & BIT_WRRQ)
{
uint16 offset;
/* increment block pointer */
cdc.pt.w += 2352;
/* increment write address */
cdc.wa.w += 2352;
/* CDC buffer address */
offset = cdc.pt.w & 0x3fff;
/* write CDD block header (4 bytes) */
*(uint32 *)(cdc.ram + offset) = header;
/* write CDD block data (2048 bytes) */
cdd_read(cdc.ram + 4 + offset);
/* take care of buffer overrun */
if (offset > (0x4000 - 2048 - 4))
{
/* data should be written at the start of buffer */
memcpy(cdc.ram, cdc.ram + 0x4000, offset + 2048 + 4 - 0x4000);
}
/* read next data block */
return 1;
}
}
/* keep decoding same data block if Buffer Write is disabled */
return 0;
}
void cdc_reg_w(unsigned char data)
{
#ifdef LOG_CDC
error("CDC register %X write 0x%04x (%X)\n", scd.regs[0x04>>1].byte.l & 0x0F, data, s68k.pc);
#endif
switch (scd.regs[0x04>>1].byte.l & 0x0F)
{
case 0x01: /* IFCTRL */
{
/* pending interrupts ? */
if (((data & BIT_DTEIEN) && !(cdc.ifstat & BIT_DTEI)) ||
((data & BIT_DECIEN) && !(cdc.ifstat & BIT_DECI)))
{
/* pending level 5 interrupt */
scd.pending |= (1 << 5);
/* level 5 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x20)
{
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
else if (scd.pending & (1 << 5))
{
/* clear pending level 5 interrupts */
scd.pending &= ~(1 << 5);
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
/* abort any data transfer if data output is disabled */
if (!(data & BIT_DOUTEN))
{
/* clear !DTBSY and !DTEN */
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
}
cdc.ifctrl = data;
scd.regs[0x04>>1].byte.l = 0x02;
break;
}
case 0x02: /* DBCL */
cdc.dbc.byte.l = data;
scd.regs[0x04>>1].byte.l = 0x03;
break;
case 0x03: /* DBCH */
cdc.dbc.byte.h = data;
scd.regs[0x04>>1].byte.l = 0x04;
break;
case 0x04: /* DACL */
cdc.dac.byte.l = data;
scd.regs[0x04>>1].byte.l = 0x05;
break;
case 0x05: /* DACH */
cdc.dac.byte.h = data;
scd.regs[0x04>>1].byte.l = 0x06;
break;
case 0x06: /* DTRG */
{
/* start data transfer if data output is enabled */
if (cdc.ifctrl & BIT_DOUTEN)
{
/* set !DTBSY */
cdc.ifstat &= ~BIT_DTBSY;
/* clear DBCH bits 4-7 */
cdc.dbc.byte.h &= 0x0f;
/* clear EDT & DSR bits (SCD register $04) */
scd.regs[0x04>>1].byte.h &= 0x07;
/* setup data transfer destination */
switch (scd.regs[0x04>>1].byte.h & 0x07)
{
case 2: /* MAIN-CPU host read */
case 3: /* SUB-CPU host read */
{
/* set !DTEN */
cdc.ifstat &= ~BIT_DTEN;
/* set DSR bit (register $04) */
scd.regs[0x04>>1].byte.h |= 0x40;
break;
}
case 4: /* PCM RAM DMA */
{
cdc.dma_w = pcm_ram_dma_w;
break;
}
case 5: /* PRG-RAM DMA */
{
cdc.dma_w = prg_ram_dma_w;
break;
}
case 7: /* WORD-RAM DMA */
{
/* check memory mode */
if (scd.regs[0x02 >> 1].byte.l & 0x04)
{
/* 1M mode */
if (scd.regs[0x02 >> 1].byte.l & 0x01)
{
/* Word-RAM bank 0 is assigned to SUB-CPU */
cdc.dma_w = word_ram_0_dma_w;
}
else
{
/* Word-RAM bank 1 is assigned to SUB-CPU */
cdc.dma_w = word_ram_1_dma_w;
}
}
else
{
/* 2M mode */
if (scd.regs[0x02 >> 1].byte.l & 0x02)
{
/* only process DMA if Word-RAM is assigned to SUB-CPU */
cdc.dma_w = word_ram_2M_dma_w;
}
}
break;
}
default: /* invalid */
{
#ifdef LOG_CDC
error("invalid CDC tranfer destination (%d)\n", scd.regs[0x04>>1].byte.h & 0x07);
#endif
break;
}
}
}
scd.regs[0x04>>1].byte.l = 0x07;
break;
}
case 0x07: /* DTACK */
{
/* clear pending data transfer end interrupt */
cdc.ifstat |= BIT_DTEI;
/* clear DBCH bits 4-7 */
cdc.dbc.byte.h &= 0x0f;
#if 0
/* no pending decoder interrupt ? */
if ((cdc.ifstat | BIT_DECI) || !(cdc.ifctrl & BIT_DECIEN))
{
/* clear pending level 5 interrupt */
scd.pending &= ~(1 << 5);
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
#endif
scd.regs[0x04>>1].byte.l = 0x08;
break;
}
case 0x08: /* WAL */
cdc.wa.byte.l = data;
scd.regs[0x04>>1].byte.l = 0x09;
break;
case 0x09: /* WAH */
cdc.wa.byte.h = data;
scd.regs[0x04>>1].byte.l = 0x0a;
break;
case 0x0a: /* CTRL0 */
{
/* set CRCOK bit only if decoding is enabled */
cdc.stat[0] = data & BIT_DECEN;
/* update decoding mode */
if (data & BIT_AUTORQ)
{
/* set MODE bit according to CTRL1 register & clear FORM bit */
cdc.stat[2] = cdc.ctrl[1] & BIT_MODRQ;
}
else
{
/* set MODE & FORM bits according to CTRL1 register */
cdc.stat[2] = cdc.ctrl[1] & (BIT_MODRQ | BIT_FORMRQ);
}
cdc.ctrl[0] = data;
scd.regs[0x04>>1].byte.l = 0x0b;
break;
}
case 0x0b: /* CTRL1 */
{
/* update decoding mode */
if (cdc.ctrl[0] & BIT_AUTORQ)
{
/* set MODE bit according to CTRL1 register & clear FORM bit */
cdc.stat[2] = data & BIT_MODRQ;
}
else
{
/* set MODE & FORM bits according to CTRL1 register */
cdc.stat[2] = data & (BIT_MODRQ | BIT_FORMRQ);
}
cdc.ctrl[1] = data;
scd.regs[0x04>>1].byte.l = 0x0c;
break;
}
case 0x0c: /* PTL */
cdc.pt.byte.l = data;
scd.regs[0x04>>1].byte.l = 0x0d;
break;
case 0x0d: /* PTH */
cdc.pt.byte.h = data;
scd.regs[0x04>>1].byte.l = 0x0e;
break;
case 0x0e: /* CTRL2 (unused) */
scd.regs[0x04>>1].byte.l = 0x0f;
break;
case 0x0f: /* RESET */
cdc_reset();
break;
default: /* by default, SBOUT is not used */
break;
}
}
unsigned char cdc_reg_r(void)
{
#ifdef LOG_CDC
error("CDC register %X read (%X) ", scd.regs[0x04>>1].byte.l & 0x0F, s68k.pc);
#endif
switch (scd.regs[0x04>>1].byte.l & 0x0F)
{
case 0x01: /* IFSTAT */
scd.regs[0x04>>1].byte.l = 0x02;
return cdc.ifstat;
case 0x02: /* DBCL */
scd.regs[0x04>>1].byte.l = 0x03;
return cdc.dbc.byte.l;
case 0x03: /* DBCH */
scd.regs[0x04>>1].byte.l = 0x04;
return cdc.dbc.byte.h;
case 0x04: /* HEAD0 */
scd.regs[0x04>>1].byte.l = 0x05;
return cdc.head[cdc.ctrl[1] & BIT_SHDREN][0];
case 0x05: /* HEAD1 */
scd.regs[0x04>>1].byte.l = 0x06;
return cdc.head[cdc.ctrl[1] & BIT_SHDREN][1];
case 0x06: /* HEAD2 */
scd.regs[0x04>>1].byte.l = 0x07;
return cdc.head[cdc.ctrl[1] & BIT_SHDREN][2];
case 0x07: /* HEAD3 */
scd.regs[0x04>>1].byte.l = 0x08;
return cdc.head[cdc.ctrl[1] & BIT_SHDREN][3];
case 0x08: /* PTL */
scd.regs[0x04>>1].byte.l = 0x09;
return cdc.pt.byte.l;
case 0x09: /* PTH */
scd.regs[0x04>>1].byte.l = 0x0a;
return cdc.pt.byte.h;
case 0x0a: /* WAL */
scd.regs[0x04>>1].byte.l = 0x0b;
return cdc.wa.byte.l;
case 0x0b: /* WAH */
scd.regs[0x04>>1].byte.l = 0x0c;
return cdc.wa.byte.h;
case 0x0c: /* STAT0 */
scd.regs[0x04>>1].byte.l = 0x0d;
return cdc.stat[0];
case 0x0d: /* STAT1 (always return 0) */
scd.regs[0x04>>1].byte.l = 0x0e;
return 0x00;
case 0x0e: /* STAT2 */
scd.regs[0x04>>1].byte.l = 0x0f;
return cdc.stat[2];
case 0x0f: /* STAT3 */
{
uint8 data = cdc.stat[3];
/* clear !VALST (note: this is not 100% correct but BIOS do not seem to care) */
cdc.stat[3] = BIT_VALST;
/* clear pending decoder interrupt */
cdc.ifstat |= BIT_DECI;
#if 0
/* no pending data transfer end interrupt */
if ((cdc.ifstat | BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN))
{
/* clear pending level 5 interrupt */
scd.pending &= ~(1 << 5);
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
#endif
scd.regs[0x04>>1].byte.l = 0x00;
return data;
}
default: /* by default, COMIN is always empty */
return 0xff;
}
}
unsigned short cdc_host_r(void)
{
/* check if data is available */
if (!(cdc.ifstat & BIT_DTEN))
{
/* read data word from CDC RAM buffer */
uint16 data = *(uint16 *)(cdc.ram + (cdc.dac.w & 0x3ffe));
#ifdef LSB_FIRST
/* source data is stored in big endian format */
data = ((data >> 8) | (data << 8)) & 0xffff;
#endif
#ifdef LOG_CDC
error("CDC host read 0x%04x -> 0x%04x (dbc=0x%x) (%X)\n", cdc.dac.w, data, cdc.dbc.w, s68k.pc);
#endif
/* increment data address counter */
cdc.dac.w += 2;
/* decrement data byte counter */
cdc.dbc.w -= 2;
/* end of transfer ? */
if ((int16)cdc.dbc.w <= 0)
{
/* reset data byte counter (DBCH bits 4-7 should be set to 1) */
cdc.dbc.w = 0xf000;
/* clear !DTEN and !DTBSY */
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
/* pending Data Transfer End interrupt */
cdc.ifstat &= ~BIT_DTEI;
/* Data Transfer End interrupt enabled ? */
if (cdc.ifctrl & BIT_DTEIEN)
{
/* pending level 5 interrupt */
scd.pending |= (1 << 5);
/* level 5 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x20)
{
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
/* clear DSR bit & set EDT bit (SCD register $04) */
scd.regs[0x04>>1].byte.h = (scd.regs[0x04>>1].byte.h & 0x07) | 0x80;
}
return data;
}
#ifdef LOG_CDC
error("error reading CDC host (data transfer disabled)\n");
#endif
return 0xffff;
}

69
source/cd_hw/cdc.h Normal file
View File

@ -0,0 +1,69 @@
/***************************************************************************************
* Genesis Plus
* CD data controller (LC89510 compatible)
*
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#ifndef _HW_CDC_
#define _HW_CDC_
#define cdc scd.cdc_hw
/* CDC hardware */
typedef struct
{
uint8 ifstat;
uint8 ifctrl;
reg16_t dbc;
reg16_t dac;
reg16_t pt;
reg16_t wa;
uint8 ctrl[2];
uint8 head[2][4];
uint8 stat[4];
int cycles;
void (*dma_w)(unsigned int words); /* DMA transfer callback */
uint8 ram[0x4000 + 2352]; /* 16K external RAM (with one block overhead to handle buffer overrun) */
} cdc_t;
/* Function prototypes */
extern void cdc_init(void);
extern void cdc_reset(void);
extern void cdc_dma_update(void);
extern int cdc_decoder_update(uint32 header);
extern void cdc_reg_w(unsigned char data);
extern unsigned char cdc_reg_r(void);
extern unsigned short cdc_host_r(void);
#endif

567
source/cd_hw/cdd.c Normal file
View File

@ -0,0 +1,567 @@
/***************************************************************************************
* Genesis Plus
* CD drive processor
*
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#include "shared.h"
#define NO_DISC 0x00
#define CD_PLAY 0x01
#define CD_SEEK 0x02
#define CD_SCAN 0x03
#define CD_READY 0x04
#define CD_OPEN 0x05
#define CD_STOP 0x09
/* BCD conversion lookup tables */
static const uint8 lut_BCD_8[100] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
};
static const uint16 lut_BCD_16[100] =
{
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009,
0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109,
0x0200, 0x0201, 0x0202, 0x0203, 0x0204, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209,
0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309,
0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409,
0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509,
0x0600, 0x0601, 0x0602, 0x0603, 0x0604, 0x0605, 0x0606, 0x0607, 0x0608, 0x0609,
0x0700, 0x0701, 0x0702, 0x0703, 0x0704, 0x0705, 0x0706, 0x0707, 0x0708, 0x0709,
0x0800, 0x0801, 0x0802, 0x0803, 0x0804, 0x0805, 0x0806, 0x0807, 0x0808, 0x0809,
0x0900, 0x0901, 0x0902, 0x0903, 0x0904, 0x0905, 0x0906, 0x0907, 0x0908, 0x0909,
};
void cdd_init(void)
{
}
void cdd_reset(void)
{
/* reset cycle counter */
cdd.cycles = 0;
/* reset disc read latency */
cdd.latency = 0;
/* reset track index */
cdd.index = 0;
/* reset logical block address */
cdd.lba = 0;
/* reset status */
cdd.status = cdd.loaded ? CD_READY : NO_DISC;
}
void cdd_load(char *filename, int type_bin)
{
/* unload any disc first */
cdd_unload();
/* CD image file format */
if (type_bin)
{
/* BIN format (2352 bytes block data) */
cdd.sectorSize = 2352;
}
else
{
/* ISO format (2048 bytes block data) */
cdd.sectorSize = 2048;
}
/* load DATA track */
cdd.toc.tracks[0].fd = fopen(filename,"rb");
if (cdd.toc.tracks[0].fd)
{
/* DATA track start (logical block 0) */
cdd.toc.tracks[0].start = 0;
/* DATA track length */
fseek(cdd.toc.tracks[0].fd, 0, SEEK_END);
cdd.toc.tracks[0].end = ftell(cdd.toc.tracks[0].fd) / cdd.sectorSize;
fseek(cdd.toc.tracks[0].fd, 0, SEEK_SET);
/* initialize TOC */
/* TODO: add 2 seconds pause after data track ? */
cdd.toc.end = cdd.toc.tracks[0].end;
cdd.toc.last = 1;
/* TODO: add audio track support from BIN/CUE, ISO/WAV, MP3, OGG ? */
/* Fake audio tracks if none found */
if (cdd.toc.last == 1)
{
/* default track duration (fix Snatcher intro) */
int length = 4 * 60 * 75;
/* A-Rank Thunder Tanjouen requires shorter track duration to pass intro */
if (strstr(rominfo.product,"T-49064") != NULL)
{
length = 2 * 75;
}
/* max length = 60:02:00 */
do
{
cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
cdd.toc.tracks[cdd.toc.last].end = cdd.toc.end + length;
cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
cdd.toc.last++;
}
while (cdd.toc.last <= 54);
}
/* CD loaded */
cdd.loaded = 1;
}
}
void cdd_unload(void)
{
if (cdd.loaded)
{
int i;
/* close CD tracks */
for (i=0; i<cdd.toc.last; i++)
{
if (cdd.toc.tracks[i].fd)
{
fclose(cdd.toc.tracks[i].fd);
}
}
/* reset TOC */
memset(&cdd.toc, 0x00, sizeof(cdd.toc));
/* CD unloaded */
cdd.loaded = 0;
/* unknown CD image file format */
cdd.sectorSize = 0;
}
}
void cdd_read(uint8 *dst)
{
/* start reading from sector 0 */
if (cdd.lba >= 0)
{
/* BIN format ? */
if (cdd.sectorSize == 2352)
{
/* skip 16-byte header */
fseek(cdd.toc.tracks[0].fd, cdd.lba * 2352 + 16, SEEK_SET);
}
/* read sector data (MODE 1) */
fread(dst, 2048, 1, cdd.toc.tracks[0].fd);
}
}
void cdd_update(void)
{
#ifdef LOG_CDD
error("LBA = %d (track n°%d)\n", cdd.lba, cdd.index);
#endif
/* reading track */
if (cdd.status == CD_PLAY)
{
/* read latency */
if (cdd.latency > 0)
{
cdd.latency--;
return;
}
/* track type */
if (cdd.index)
{
/* audio track sector is sent to CD Fader/DAC but also CDD */
cdc_decoder_update(0);
/* next audio track sector is automatically read */
cdd.lba++;
/* check end of current track */
if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
{
/* next track */
cdd.index++;
}
}
else
{
/* sector header (CD-ROM Mode 1) */
uint8 header[4];
uint32 msf = cdd.lba + 150;
header[0] = lut_BCD_8[(msf / 75) / 60];
header[1] = lut_BCD_8[(msf / 75) % 60];
header[2] = lut_BCD_8[(msf % 75)];
header[3] = 0x01;
/* data track sector read is controlled by CDC */
cdd.lba += cdc_decoder_update(*(uint32 *)(header));
}
}
/* TODO: handle FAST_FW & FAST_RW commands */
}
void cdd_process(void)
{
/* Process CDD command */
switch (scd.regs[0x42>>1].byte.h & 0x0f)
{
case 0x00: /* Drive Status */
{
scd.regs[0x38>>1].byte.h = cdd.status;
break;
}
case 0x01: /* Stop Drive */
{
cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
scd.regs[0x38>>1].w = 0x0000;
scd.regs[0x3a>>1].w = 0x0000;
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].w = 0x000f;
return;
}
case 0x02: /* Read TOC */
{
switch (scd.regs[0x44>>1].byte.l)
{
case 0x00: /* Absolute position (MM:SS:FF) */
{
int lba = cdd.lba + 150;
scd.regs[0x38>>1].w = cdd.status << 8;
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
scd.regs[0x40>>1].byte.h = 0x00;
break;
}
case 0x01: /* Track relative position (MM:SS:FF) */
{
int lba = cdd.lba - cdd.toc.tracks[cdd.index].start;
scd.regs[0x38>>1].w = (cdd.status << 8) | 0x01;
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
scd.regs[0x40>>1].byte.h = 0x00;
break;
}
case 0x02: /* Current track */
{
scd.regs[0x38>>1].w = (cdd.status << 8) | 0x02;
scd.regs[0x3a>>1].w = lut_BCD_16[cdd.index + 1];
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].byte.h = 0x00;
break;
}
case 0x03: /* Total length (MM:SS:FF) */
{
int lba = cdd.toc.end + 150;
scd.regs[0x38>>1].w = (cdd.status << 8) | 0x03;
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
scd.regs[0x40>>1].byte.h = 0x00;
break;
}
case 0x04: /* Number of tracks */
{
scd.regs[0x38>>1].w = (cdd.status << 8) | 0x04;
scd.regs[0x3a>>1].w = 0x0001;
scd.regs[0x3c>>1].w = lut_BCD_16[cdd.toc.last];
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].byte.h = 0x00;
break;
}
case 0x05: /* Track start (MM:SS:FF) */
{
int track = scd.regs[0x46>>1].byte.h * 10 + scd.regs[0x46>>1].byte.l;
int lba = cdd.toc.tracks[track-1].start + 150;
scd.regs[0x38>>1].w = (cdd.status << 8) | 0x05;
scd.regs[0x3a>>1].w = lut_BCD_16[(lba/75)/60];
scd.regs[0x3c>>1].w = lut_BCD_16[(lba/75)%60];
scd.regs[0x3e>>1].w = lut_BCD_16[(lba%75)];
scd.regs[0x40>>1].byte.h = track % 10;
if (track == 1)
{
/* data track */
scd.regs[0x3e>>1].byte.h |= 0x08;
}
break;
}
default:
{
#ifdef LOG_CDD
error("Unknown Command !!!\n");
#endif
return;
}
}
break;
}
case 0x03: /* Play */
{
/* reset track index */
int index = 0;
/* new LBA position */
int lba = ((scd.regs[0x44>>1].byte.h * 10 + scd.regs[0x44>>1].byte.l) * 60 +
(scd.regs[0x46>>1].byte.h * 10 + scd.regs[0x46>>1].byte.l)) * 75 +
(scd.regs[0x48>>1].byte.h * 10 + scd.regs[0x48>>1].byte.l) - 150;
/* disc access latency */
if (!cdd.latency)
{
/* Fixes a few games hanging during intro because they expect data to be read with some delay */
/* Radical Rex needs at least one interrupt delay */
/* Wolf Team games (Anet Futatabi, Cobra Command, Road Avenger & Time Gal need at least 6 interrupts delay */
/* Jeopardy needs at least 9 interrupts delay */
cdd.latency = 9;
}
/* update current LBA */
cdd.lba = lba;
/* update current track index */
while (cdd.toc.tracks[index].end <= lba) index++;
cdd.index = index;
/* track type */
if (index)
{
/* AUDIO track */
scd.regs[0x36>>1].byte.h = 0x00;
}
else
{
/* DATA track */
scd.regs[0x36>>1].byte.h = 0x01;
/* seek to current block */
if (lba < 0) lba = 0;
fseek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
}
/* update status */
cdd.status = CD_PLAY;
scd.regs[0x38>>1].w = (CD_PLAY << 8) | 0x02;
scd.regs[0x3a>>1].w = lut_BCD_16[index + 1];
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].byte.h = 0x00;
break;
}
case 0x04: /* Seek */
{
/* reset track index */
int index = 0;
/* new LBA position */
int lba = ((scd.regs[0x44>>1].byte.h * 10 + scd.regs[0x44>>1].byte.l) * 60 +
(scd.regs[0x46>>1].byte.h * 10 + scd.regs[0x46>>1].byte.l)) * 75 +
(scd.regs[0x48>>1].byte.h * 10 + scd.regs[0x48>>1].byte.l) - 150;
/* update current LBA (TODO: add some delay ?) */
cdd.lba = lba;
/* update current track index */
while (cdd.toc.tracks[index].end <= lba) index++;
cdd.index = index;
/* DATA track */
if (!index)
{
/* seek to current block */
if (lba < 0) lba = 0;
fseek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
}
/* no audio track playing */
scd.regs[0x36>>1].byte.h = 0x01;
/* update status (TODO: figure what is returned in RS1-RS8) */
cdd.status = CD_READY;
scd.regs[0x38>>1].w = CD_SEEK << 8;
scd.regs[0x3a>>1].w = 0x0000;
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].w = ~CD_SEEK & 0x0f;
return;
}
case 0x06: /* Pause */
{
/* no audio track playing */
scd.regs[0x36>>1].byte.h = 0x01;
/* update status (TODO: figure what is returned in RS1-RS8) */
cdd.status = CD_READY;
scd.regs[0x38>>1].w = CD_READY << 8;
scd.regs[0x3a>>1].w = 0x0000;
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].w = ~CD_READY & 0x0f;
return;
}
case 0x07: /* Resume */
{
/* track type */
if (cdd.index)
{
/* AUDIO track */
scd.regs[0x36>>1].byte.h = 0x00;
}
else
{
/* DATA track */
scd.regs[0x36>>1].byte.h = 0x01;
}
/* update status */
cdd.status = CD_PLAY;
scd.regs[0x38>>1].w = (CD_PLAY << 8) | 0x02;
scd.regs[0x3a>>1].w = lut_BCD_16[cdd.index+1];
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].byte.h = 0x00;
break;
}
case 0x08: /* Forward Scan */
{
cdd.status = CD_SCAN;
scd.regs[0x38>>1].w = (CD_SCAN << 8) | 0x02;
scd.regs[0x3a>>1].w = lut_BCD_16[cdd.index+1];
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].byte.h = 0x00;
break;
}
case 0x09: /* Rewind Scan */
{
cdd.status = CD_SCAN;
scd.regs[0x38>>1].w = (CD_SCAN << 8) | 0x02;
scd.regs[0x3a>>1].w = lut_BCD_16[cdd.index+1];
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].byte.h = 0x00;
break;
}
case 0x0a: /* ??? (usually sent before first & last CD_PLAY command) */
{
/* RS0-RS8 values taken from Gens */
cdd.status = CD_READY;
scd.regs[0x38>>1].w = CD_READY << 8;
scd.regs[0x3a>>1].w = 0x0000;
scd.regs[0x3c>>1].w = 0x0001;
scd.regs[0x3e>>1].w = 0x0001;
scd.regs[0x40>>1].w = ~(CD_READY + 2) & 0x0f;
return;
}
case 0x0c: /* Close Tray */
{
cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
scd.regs[0x38>>1].w = 0x0000;
scd.regs[0x3a>>1].w = 0x0000;
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].w = 0x000f;
return;
}
case 0x0d: /* Open Tray */
{
/* no audio track playing */
scd.regs[0x36>>1].byte.h = 0x01;
cdd.status = CD_OPEN;
scd.regs[0x38>>1].w = 0x0e00;
scd.regs[0x3a>>1].w = 0x0000;
scd.regs[0x3c>>1].w = 0x0000;
scd.regs[0x3e>>1].w = 0x0000;
scd.regs[0x40>>1].w = 0x0001;
return;
}
default: /* Unknown command */
#ifdef LOG_CDD
error("Unknown CDD Command !!!\n");
#endif
scd.regs[0x38>>1].byte.h = cdd.status;
break;
}
/* only compute checksum when necessary */
scd.regs[0x40>>1].byte.l = ~(scd.regs[0x38>>1].byte.h + scd.regs[0x38>>1].byte.l +
scd.regs[0x3a>>1].byte.h + scd.regs[0x3a>>1].byte.l +
scd.regs[0x3c>>1].byte.h + scd.regs[0x3c>>1].byte.l +
scd.regs[0x3e>>1].byte.h + scd.regs[0x3e>>1].byte.l +
scd.regs[0x40>>1].byte.h) & 0x0f;
}

84
source/cd_hw/cdd.h Normal file
View File

@ -0,0 +1,84 @@
/***************************************************************************************
* Genesis Plus
* CD drive processor
*
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#ifndef _HW_CDD_
#define _HW_CDD_
#define cdd scd.cdd_hw
#define CD_MAX_TRACKS 99
/* CD track */
typedef struct
{
FILE *fd;
int start;
int end;
} track_t;
/* CD TOC */
typedef struct
{
int end;
int last;
track_t tracks[CD_MAX_TRACKS];
} toc_t;
/* CDD hardware */
typedef struct
{
uint32 cycles;
uint32 latency;
int loaded;
int index;
int lba;
uint8 status;
uint16 sectorSize;
toc_t toc;
} cdd_t;
/* Function prototypes */
extern void cdd_init(void);
extern void cdd_reset(void);
extern void cdd_load(char *filename, int type_bin);
extern void cdd_unload(void);
extern void cdd_read(uint8 *dst);
extern void cdd_update(void);
extern void cdd_process(void);
#endif

672
source/cd_hw/gfx.c Normal file
View File

@ -0,0 +1,672 @@
/***************************************************************************************
* Genesis Plus
* CD graphics processor
*
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#include "shared.h"
/***************************************************************/
/* WORD-RAM DMA interfaces (1M & 2M modes) */
/***************************************************************/
void word_ram_0_dma_w(unsigned int words)
{
uint16 data;
/* CDC buffer source address */
uint16 src_index = cdc.dac.w & 0x3ffe;
/* WORD-RAM destination address*/
uint32 dst_index = (scd.regs[0x0a>>1].w << 3) & 0x1fffe;
/* update DMA destination address */
scd.regs[0x0a>>1].w += (words >> 2);
/* update DMA source address */
cdc.dac.w += (words << 1);
/* DMA transfer */
while (words--)
{
/* read 16-bit word from CDC buffer */
data = *(uint16 *)(cdc.ram + src_index);
#ifdef LSB_FIRST
/* source data is stored in big endian format */
data = ((data >> 8) | (data << 8)) & 0xffff;
#endif
/* write 16-bit word to WORD-RAM */
*(uint16 *)(scd.word_ram[0] + dst_index) = data ;
/* increment CDC buffer source address */
src_index = (src_index + 2) & 0x3ffe;
/* increment WORD-RAM destination address */
dst_index = (dst_index + 2) & 0x1fffe;
}
}
void word_ram_1_dma_w(unsigned int words)
{
uint16 data;
/* CDC buffer source address */
uint16 src_index = cdc.dac.w & 0x3ffe;
/* WORD-RAM destination address*/
uint32 dst_index = ((scd.regs[0x0a>>1].w << 3) & 0x1fffe);
/* update DMA destination address */
scd.regs[0x0a>>1].w += (words >> 2);
/* update DMA source address */
cdc.dac.w += (words << 1);
/* DMA transfer */
while (words--)
{
/* read 16-bit word from CDC buffer */
data = *(uint16 *)(cdc.ram + src_index);
#ifdef LSB_FIRST
/* source data is stored in big endian format */
data = ((data >> 8) | (data << 8)) & 0xffff;
#endif
/* write 16-bit word to WORD-RAM */
*(uint16 *)(scd.word_ram[1] + dst_index) = data ;
/* increment CDC buffer source address */
src_index = (src_index + 2) & 0x3ffe;
/* increment WORD-RAM destination address */
dst_index = (dst_index + 2) & 0x1fffe;
}
}
void word_ram_2M_dma_w(unsigned int words)
{
uint16 data;
/* CDC buffer source address */
uint16 src_index = cdc.dac.w & 0x3ffe;
/* WORD-RAM destination address*/
uint32 dst_index = (scd.regs[0x0a>>1].w << 3) & 0x3fffe;
/* update DMA destination address */
scd.regs[0x0a>>1].w += (words >> 2);
/* update DMA source address */
cdc.dac.w += (words << 1);
/* DMA transfer */
while (words--)
{
/* read 16-bit word from CDC buffer */
data = *(uint16 *)(cdc.ram + src_index);
#ifdef LSB_FIRST
/* source data is stored in big endian format */
data = ((data >> 8) | (data << 8)) & 0xffff;
#endif
/* write 16-bit word to WORD-RAM */
*(uint16 *)(scd.word_ram_2M + dst_index) = data ;
/* increment CDC buffer source address */
src_index = (src_index + 2) & 0x3ffe;
/* increment WORD-RAM destination address */
dst_index = (dst_index + 2) & 0x3fffe;
}
}
/***************************************************************/
/* WORD-RAM 0 & 1 DOT image SUB-CPU interface (1M Mode) */
/***************************************************************/
unsigned int dot_ram_0_read16(unsigned int address)
{
uint8 data = READ_BYTE(scd.word_ram[0], (address >> 1) & 0x1ffff);
return ((data & 0x0f) | ((data << 4) & 0xf00));
}
unsigned int dot_ram_1_read16(unsigned int address)
{
uint8 data = READ_BYTE(scd.word_ram[1], (address >> 1) & 0x1ffff);
return ((data & 0x0f) | ((data << 4) & 0xf00));
}
void dot_ram_0_write16(unsigned int address, unsigned int data)
{
uint8 prev;
address = (address >> 1) & 0x1ffff;
prev = READ_BYTE(scd.word_ram[0], address);
data = (data & 0x0f) | ((data >> 4) & 0xf0);
data = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][prev][data];
WRITE_BYTE(scd.word_ram[0], address, data);
}
void dot_ram_1_write16(unsigned int address, unsigned int data)
{
uint8 prev;
address = (address >> 1) & 0x1ffff;
prev = READ_BYTE(scd.word_ram[1], address);
data = (data & 0x0f) | ((data >> 4) & 0xf0);
data = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][prev][data];
WRITE_BYTE(scd.word_ram[1], address, data);
}
unsigned int dot_ram_0_read8(unsigned int address)
{
uint8 data = READ_BYTE(scd.word_ram[0], (address >> 1) & 0x1ffff);
if (address & 1)
{
return (data & 0x0f);
}
return (data >> 4);
}
unsigned int dot_ram_1_read8(unsigned int address)
{
uint8 data = READ_BYTE(scd.word_ram[1], (address >> 1) & 0x1ffff);
if (address & 1)
{
return (data & 0x0f);
}
return (data >> 4);
}
void dot_ram_0_write8(unsigned int address, unsigned int data)
{
uint8 prev = READ_BYTE(scd.word_ram[0], (address >> 1) & 0x1ffff);
if (address & 1)
{
data = (prev & 0xf0) | (data & 0x0f);
}
else
{
data = (prev & 0x0f) | (data << 4);
}
data = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][prev][data];
WRITE_BYTE(scd.word_ram[0], (address >> 1) & 0x1ffff, data);
}
void dot_ram_1_write8(unsigned int address, unsigned int data)
{
uint8 prev = READ_BYTE(scd.word_ram[1], (address >> 1) & 0x1ffff);
if (address & 1)
{
data = (prev & 0xf0) | (data & 0x0f);
}
else
{
data = (prev & 0x0f) | (data << 4);
}
data = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][prev][data];
WRITE_BYTE(scd.word_ram[1], (address >> 1) & 0x1ffff, data);
}
/***************************************************************/
/* WORD-RAM 0 & 1 CELL image MAIN-CPU interface (1M Mode) */
/***************************************************************/
unsigned int cell_ram_0_read16(unsigned int address)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10002);
return *(uint16 *)(scd.word_ram[0] + address);
}
unsigned int cell_ram_1_read16(unsigned int address)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10002);
return *(uint16 *)(scd.word_ram[1] + address);
}
void cell_ram_0_write16(unsigned int address, unsigned int data)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10002);
*(uint16 *)(scd.word_ram[0] + address) = data;
}
void cell_ram_1_write16(unsigned int address, unsigned int data)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10002);
*(uint16 *)(scd.word_ram[1] + address) = data;
}
unsigned int cell_ram_0_read8(unsigned int address)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10003);
return READ_BYTE(scd.word_ram[0], address);
}
unsigned int cell_ram_1_read8(unsigned int address)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10003);
return READ_BYTE(scd.word_ram[1], address);
}
void cell_ram_0_write8(unsigned int address, unsigned int data)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10003);
WRITE_BYTE(scd.word_ram[0], address, data);
}
void cell_ram_1_write8(unsigned int address, unsigned int data)
{
address = gfx.lut_offset[(address >> 2) & 0x7fff] | (address & 0x10003);
WRITE_BYTE(scd.word_ram[1], address, data);
}
/***************************************************************/
/* Rotation / Scaling operation (2M Mode) */
/***************************************************************/
void gfx_init(void)
{
int i, j;
uint16 offset;
uint8 mask, row, col, temp;
memset(&gfx, 0, sizeof(gfx_t));
/* Initialize cell image lookup table */
/* $220000-$22FFFF corresponds to $200000-$20FFFF */
for (i=0; i<0x4000; i++)
{
offset = (i & 0x07) << 8; /* cell vline (0-7) */
offset = offset | (((i >> 8) & 0x3f) << 2); /* cell x offset (0-63) */
offset = offset | (((i >> 3) & 0x1f) << 11); /* cell y offset (0-31) */
gfx.lut_offset[i] = offset;
}
/* $230000-$237FFF corresponds to $210000-$217FFF */
for (i=0x4000; i<0x6000; i++)
{
offset = (i & 0x07) << 8; /* cell vline (0-7) */
offset = offset | (((i >> 7) & 0x3f) << 2); /* cell x offset (0-63) */
offset = offset | (((i >> 3) & 0x0f) << 11); /* cell y offset (0-15) */
gfx.lut_offset[i] = offset;
}
/* $238000-$23BFFF corresponds to $218000-$21BFFF */
for (i=0x6000; i<0x7000; i++)
{
offset = (i & 0x07) << 8; /* cell vline (0-7) */
offset = offset | (((i >> 6) & 0x3f) << 2); /* cell x offset (0-63) */
offset = offset | (((i >> 3) & 0x07) << 11); /* cell y offset (0-7) */
gfx.lut_offset[i] = offset | 0x8000;
}
/* $23C000-$23DFFF corresponds to $21C000-$21DFFF */
for (i=0x7000; i<0x7800; i++)
{
offset = (i & 0x07) << 8; /* cell vline (0-7) */
offset = offset | (((i >> 5) & 0x3f) << 2); /* cell x offset (0-63) */
offset = offset | (((i >> 3) & 0x03) << 11); /* cell y offset (0-3) */
gfx.lut_offset[i] = offset | 0xc000;
}
/* $23E000-$23FFFF corresponds to $21E000-$21FFFF */
for (i=0x7800; i<0x8000; i++)
{
offset = (i & 0x07) << 8; /* cell vline (0-7) */
offset = offset | (((i >> 5) & 0x3f) << 2); /* cell x offset (0-63) */
offset = offset | (((i >> 3) & 0x03) << 11); /* cell y offset (0-3) */
gfx.lut_offset[i] = offset | 0xe000;
}
/* Initialize priority modes lookup table */
for (i=0; i<0x100; i++)
{
for (j=0; j<0x100; j++)
{
/* normal */
gfx.lut_prio[0][i][j] = j;
/* underwrite */
gfx.lut_prio[1][i][j] = ((i & 0x0f) ? (i & 0x0f) : (j & 0x0f)) | ((i & 0xf0) ? (i & 0xf0) : (j & 0xf0));
/* overwrite */
gfx.lut_prio[2][i][j] = ((j & 0x0f) ? (j & 0x0f) : (i & 0x0f)) | ((j & 0xf0) ? (j & 0xf0) : (i & 0xf0));
/* invalid */
gfx.lut_prio[3][i][j] = i;
}
}
/* Initialize cell lookup table */
/* table entry = yyxxshrr (8 bits) */
/* with: yy = cell row (0-3) */
/* xx = cell column (0-3) */
/* s = stamp size (0=16x16, 1=32x32) */
/* hrr = HFLIP & ROTATION bits */
for (i=0; i<0x100; i++)
{
/* one stamp = 2x2 cells (16x16) or 4x4 cells (32x32) */
mask = (i & 8) ? 3 : 1;
row = (i >> 6) & mask;
col = (i >> 4) & mask;
if (i & 4) { col = col ^ mask; } /* HFLIP (always first) */
if (i & 2) { col = col ^ mask; row = row ^ mask; } /* ROLL1 */
if (i & 1) { temp = col; col = row ^ mask; row = temp; } /* ROLL0 */
/* cell offset (0-3 or 0-15) */
gfx.lut_cell[i] = row + col * (mask + 1);
}
/* Initialize pixel lookup table */
/* table entry = yyyxxxhrr (9 bits) */
/* with: yyy = pixel row (0-7) */
/* xxx = pixel column (0-7) */
/* hrr = HFLIP & ROTATION bits */
for (i=0; i<0x200; i++)
{
/* one cell = 8x8 pixels */
row = (i >> 6) & 7;
col = (i >> 3) & 7;
if (i & 4) { col = col ^ 7; } /* HFLIP (always first) */
if (i & 2) { col = col ^ 7; row = row ^ 7; } /* ROLL1 */
if (i & 1) { temp = col; col = row ^ 7; row = temp; } /* ROLL0 */
/* pixel offset (0-63) */
gfx.lut_pixel[i] = col + row * 8;
}
}
void gfx_reset(void)
{
/* Reset cycle counter */
gfx.cycles = 0;
}
INLINE void gfx_render(uint32 bufferIndex, uint32 width)
{
uint8 pixel_in, pixel_out;
uint16 stamp_data;
uint32 stamp_index;
/* pixel map start position for current line (13.3 format converted to 13.11) */
uint32 xpos = *gfx.tracePtr++ << 8;
uint32 ypos = *gfx.tracePtr++ << 8;
/* pixel map offset values for current line (5.11 format) */
uint32 xoffset = (int16) *gfx.tracePtr++;
uint32 yoffset = (int16) *gfx.tracePtr++;
/* process all dots */
while (width--)
{
/* check if stamp map is repeated */
if (scd.regs[0x58>>1].byte.l & 0x01)
{
/* stamp map range */
xpos &= gfx.dotMask;
ypos &= gfx.dotMask;
}
else
{
/* 24-bit range */
xpos &= 0xffffff;
ypos &= 0xffffff;
}
/* check if pixel is outside stamp map */
if ((xpos | ypos) & ~gfx.dotMask)
{
/* force pixel output to 0 */
pixel_out = 0x00;
}
else
{
/* read stamp map table data */
stamp_data = gfx.mapPtr[(xpos >> gfx.stampShift) | ((ypos >> gfx.stampShift) << gfx.mapShift)];
/* stamp generator base index */
/* sss ssssssss ccyyyxxx (16x16) or sss sssssscc ccyyyxxx (32x32) */
/* with: s = stamp number (1 stamp = 16x16 or 32x32 pixels) */
/* c = cell offset (0-3 for 16x16, 0-15 for 32x32) */
/* yyy = line offset (0-7) */
/* xxx = pixel offset (0-7) */
stamp_index = (stamp_data & 0x7ff) << 8;
if (stamp_index)
{
/* extract HFLIP & ROTATION bits */
stamp_data = (stamp_data >> 13) & 7;
/* cell offset (0-3 or 0-15) */
/* table entry = yyxxshrr (8 bits) */
/* with: yy = cell row (0-3) = (ypos >> (11 + 3)) & 3 */
/* xx = cell column (0-3) = (xpos >> (11 + 3)) & 3 */
/* s = stamp size (0=16x16, 1=32x32) */
/* hrr = HFLIP & ROTATION bits */
stamp_index |= gfx.lut_cell[stamp_data | ((scd.regs[0x58>>1].byte.l & 0x02) << 2 ) | ((ypos >> 8) & 0xc0) | ((xpos >> 10) & 0x30)] << 6;
/* pixel offset (0-63) */
/* table entry = yyyxxxhrr (9 bits) */
/* with: yyy = pixel row (0-7) = (ypos >> 11) & 7 */
/* xxx = pixel column (0-7) = (xpos >> 11) & 7 */
/* hrr = HFLIP & ROTATION bits */
stamp_index |= gfx.lut_pixel[stamp_data | ((xpos >> 8) & 0x38) | ((ypos >> 5) & 0x1c0)];
/* read pixel pair (2 pixels/byte) */
pixel_out = READ_BYTE(scd.word_ram_2M, stamp_index >> 1);
/* extract left or rigth pixel */
if (stamp_index & 1)
{
pixel_out &= 0x0f;
}
else
{
pixel_out >>= 4;
}
}
else
{
/* stamp 0 is not used: force pixel output to 0 */
pixel_out = 0x00;
}
}
/* read out paired pixel data */
pixel_in = READ_BYTE(scd.word_ram_2M, bufferIndex >> 1);
/* update left or rigth pixel */
if (bufferIndex & 1)
{
pixel_out |= (pixel_in & 0xf0);
}
else
{
pixel_out = (pixel_out << 4) | (pixel_in & 0x0f);
}
/* priority mode write */
pixel_out = gfx.lut_prio[(scd.regs[0x02>>1].w >> 3) & 0x03][pixel_in][pixel_out];
/* write data to image buffer */
WRITE_BYTE(scd.word_ram_2M, bufferIndex >> 1, pixel_out);
/* check current pixel position */
if ((bufferIndex & 7) != 7)
{
/* next pixel */
bufferIndex++;
}
else
{
/* next cell: increment image buffer offset by one column (minus 7 pixels) */
bufferIndex += gfx.bufferOffset;
}
/* increment pixel position */
xpos += xoffset;
ypos += yoffset;
}
}
void gfx_start(unsigned int base, int cycles)
{
/* make sure 2M mode is enabled */
if (!(scd.regs[0x02>>1].byte.l & 0x04))
{
uint32 mask;
/* trace vector pointer */
gfx.tracePtr = (uint16 *)(scd.word_ram_2M + ((base << 2) & 0x3fff8));
/* stamps & stamp map size */
switch ((scd.regs[0x58>>1].byte.l >> 1) & 0x03)
{
case 0:
gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
gfx.stampShift = 11 + 4; /* 16x16 dots/stamps */
gfx.mapShift = 4; /* 16x16 stamps/map */
mask = 0x3fe00; /* 512 bytes/table */
break;
case 1:
gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
gfx.stampShift = 11 + 5; /* 32x32 dots/stamps */
gfx.mapShift = 3; /* 8x8 stamps/map */
mask = 0x3ff80; /* 128 bytes/table */
break;
case 2:
gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
gfx.stampShift = 11 + 4; /* 16x16 dots/stamps */
gfx.mapShift = 8; /* 256x256 stamps/map */
mask = 0x20000; /* 131072 bytes/table */
break;
case 3:
gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
gfx.stampShift = 11 + 5; /* 32x32 dots/stamps */
gfx.mapShift = 7; /* 128x128 stamps/map */
mask = 0x38000; /* 32768 bytes/table */
break;
}
/* stamp map table base address */
gfx.mapPtr = (uint16 *)(scd.word_ram_2M + ((scd.regs[0x5a>>1].w << 2) & mask));
/* image buffer column offset (64 pixels/cell, minus 7 pixels to restart at cell beginning) */
gfx.bufferOffset = (((scd.regs[0x5c>>1].byte.l & 0x1f) + 1) << 6) - 7;
/* image buffer start index in dot units (2 pixels/byte) */
gfx.bufferStart = (scd.regs[0x5e>>1].w << 3) & 0x7ffc0;
/* add image buffer horizontal dot offset */
gfx.bufferStart += (scd.regs[0x60>>1].byte.l & 0x3f);
/* reset GFX chip cycle counter */
gfx.cycles = cycles;
/* update GFX chip timings (see AC3:Thunderhawk / Thunderstrike) */
gfx.cyclesPerLine = 4 * 5 * scd.regs[0x62>>1].w;
/* start graphics operation */
scd.regs[0x58>>1].byte.h = 0x80;
}
}
void gfx_update(int cycles)
{
/* synchronize GFX chip with SUB-CPU */
cycles -= gfx.cycles;
/* make sure SUB-CPU is ahead */
if (cycles > 0)
{
/* number of lines to process */
unsigned int lines = (cycles + gfx.cyclesPerLine - 1) / gfx.cyclesPerLine;
/* check against remaining lines */
if (lines < scd.regs[0x64>>1].byte.l)
{
/* update Vdot remaining size */
scd.regs[0x64>>1].byte.l -= lines;
/* increment cycle counter */
gfx.cycles += lines * gfx.cyclesPerLine;
}
else
{
/* process remaining lines */
lines = scd.regs[0x64>>1].byte.l;
/* clear Vdot remaining size */
scd.regs[0x64>>1].byte.l = 0;
/* end of graphics operation */
scd.regs[0x58>>1].byte.h = 0;
/* level 1 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x02)
{
/* trigger level 1 interrupt */
scd.pending |= (1 << 1);
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
/* render lines */
while (lines--)
{
/* process dots to image buffer */
gfx_render(gfx.bufferStart, scd.regs[0x62>>1].w);
/* increment image buffer start index for next line (8 pixels/line) */
gfx.bufferStart += 8;
}
}
}

114
source/cd_hw/gfx.h Normal file
View File

@ -0,0 +1,114 @@
/***************************************************************************************
* Genesis Plus
* CD graphics processor
*
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#ifndef _CD_GFX_
#define _CD_GFX_
#define gfx scd.gfx_hw
typedef struct
{
uint32 cycles; /* current cycles count for graphics operation */
uint32 cyclesPerLine; /* current graphics operation timings */
uint32 dotMask; /* stamp map size mask */
uint16 *tracePtr; /* trace vector pointer */
uint16 *mapPtr; /* stamp map table base address */
uint8 stampShift; /* stamp pixel shift value (related to stamp size) */
uint8 mapShift; /* stamp map table shift value (related to stamp map size) */
uint16 bufferOffset; /* image buffer column offset */
uint32 bufferStart; /* image buffer start index */
uint16 lut_offset[0x8000]; /* Cell Image -> WORD-RAM offset lookup table (1M Mode) */
uint8 lut_prio[4][0x100][0x100]; /* WORD-RAM data writes priority lookup table */
uint8 lut_pixel[0x200]; /* Graphics operation dot offset lookup table */
uint8 lut_cell[0x100]; /* Graphics operation stamp offset lookup table */
} gfx_t;
/***************************************************************/
/* WORD-RAM DMA interfaces (1M & 2M modes) */
/***************************************************************/
extern void word_ram_0_dma_w(unsigned int words);
extern void word_ram_1_dma_w(unsigned int words);
extern void word_ram_2M_dma_w(unsigned int words);
/***************************************************************/
/* WORD-RAM 0 & 1 CPU interfaces (1M mode) */
/***************************************************************/
extern unsigned int word_ram_0_read16(unsigned int address);
extern unsigned int word_ram_1_read16(unsigned int address);
extern void word_ram_0_write16(unsigned int address, unsigned int data);
extern void word_ram_1_write16(unsigned int address, unsigned int data);
extern unsigned int word_ram_0_read8(unsigned int address);
extern unsigned int word_ram_1_read8(unsigned int address);
extern void word_ram_0_write8(unsigned int address, unsigned int data);
extern void word_ram_1_write8(unsigned int address, unsigned int data);
/***************************************************************/
/* WORD-RAM 0 & 1 DOT image SUB-CPU interface (1M mode) */
/***************************************************************/
extern unsigned int dot_ram_0_read16(unsigned int address);
extern unsigned int dot_ram_1_read16(unsigned int address);
extern void dot_ram_0_write16(unsigned int address, unsigned int data);
extern void dot_ram_1_write16(unsigned int address, unsigned int data);
extern unsigned int dot_ram_0_read8(unsigned int address);
extern unsigned int dot_ram_1_read8(unsigned int address);
extern void dot_ram_0_write8(unsigned int address, unsigned int data);
extern void dot_ram_1_write8(unsigned int address, unsigned int data);
/***************************************************************/
/* WORD-RAM 0 & 1 CELL image MAIN-CPU interface (1M mode) */
/***************************************************************/
extern unsigned int cell_ram_0_read16(unsigned int address);
extern unsigned int cell_ram_1_read16(unsigned int address);
extern void cell_ram_0_write16(unsigned int address, unsigned int data);
extern void cell_ram_1_write16(unsigned int address, unsigned int data);
extern unsigned int cell_ram_0_read8(unsigned int address);
extern unsigned int cell_ram_1_read8(unsigned int address);
extern void cell_ram_0_write8(unsigned int address, unsigned int data);
extern void cell_ram_1_write8(unsigned int address, unsigned int data);
/***************************************************************/
/* Rotation / Scaling operation (2M mode) */
/***************************************************************/
extern void gfx_init(void);
extern void gfx_reset(void);
extern void gfx_start(unsigned int base, int cycles);
extern void gfx_update(int cycles);
#endif

341
source/cd_hw/pcm.c Normal file
View File

@ -0,0 +1,341 @@
/***************************************************************************************
* Genesis Plus
* PCM sound chip (315-5476A) (RF5C164 compatible)
*
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#include "shared.h"
#include "blip.h"
#define PCM_CLOCKS_PER_SAMPLE (384 * 4)
#define pcm scd.pcm_hw
static struct blip_buffer_t* blip[2];
void pcm_init(double clock, double samplerate)
{
pcm_shutdown();
/* allocate blip buffers */
blip[0] = blip_alloc(clock, samplerate * PCM_CLOCKS_PER_SAMPLE, samplerate / 4);
blip[1] = blip_alloc(clock, samplerate * PCM_CLOCKS_PER_SAMPLE, samplerate / 4);
}
void pcm_shutdown(void)
{
/* desallocate blip buffers */
if (blip[0]) blip_free(blip[0]);
if (blip[1]) blip_free(blip[1]);
blip[0] = blip[1] = 0;
}
void pcm_reset(void)
{
/* reset chip & clear external RAM */
memset(&pcm, 0, sizeof(pcm_t));
/* reset default bank */
pcm.bank = pcm.ram;
/* clear blip delta buffers */
blip_clear(blip[0]);
blip_clear(blip[1]);
}
void pcm_update(short *buffer, int length)
{
/* get number of clocks needed */
length = blip_clocks_needed(blip[0], length);
/* check if PCM chip is running */
if (pcm.enabled)
{
int i, j, l, r;
/* generate PCM samples */
for (i=0; i<length; i++)
{
/* clear output */
l = r = 0;
/* run eight PCM channels */
for (j=0; j<8; j++)
{
/* check if channel is enabled (bit cleared) */
if (!(pcm.status & (1 << j)))
{
/* read current WAVE RAM address */
short data = pcm.ram[(pcm.chan[j].addr >> 11) & 0xffff];
/* STOP data ? */
if (data == 0xff)
{
/* reset WAVE RAM address with loop address */
pcm.chan[j].addr = pcm.chan[j].ls.w << 11;
/* read WAVE RAM address again */
data = pcm.ram[pcm.chan[j].ls.w];
/* no output on infinite loop */
if (data == 0xff) break;
}
/* output L & R subchannels */
if (data & 0x80)
{
/* PCM data is negative */
data = -(data & 0x7f);
}
/* multiply PCM data with ENV & stereo PAN data then add to outputs (13.6 fixed point) */
l += ((data * pcm.chan[j].env * (pcm.chan[j].pan & 0x0F)) >> 6);
r += ((data * pcm.chan[j].env * (pcm.chan[j].pan >> 4)) >> 6);
/* increment WAVE RAM address */
pcm.chan[j].addr += pcm.chan[j].fd.w;
}
}
/* limiter */
if (l < -32768) l = -32768;
else if (l > 32767) l = 32767;
if (r < -32768) r = -32768;
else if (r > 32767) r = 32767;
/* check if PCM left output changed */
if (pcm.out[0] != l)
{
blip_add(blip[0], i, l-pcm.out[0]);
pcm.out[0] = l;
}
/* check if PCM right output changed */
if (pcm.out[1] != r)
{
blip_add(blip[1], i, r-pcm.out[1]);
pcm.out[1] = r;
}
}
}
else
{
/* check if PCM left output changed */
if (pcm.out[0])
{
blip_add(blip[0], 0, -pcm.out[0]);
pcm.out[0] = 0;
}
/* check if PCM right output changed */
if (pcm.out[1])
{
blip_add(blip[1], 0, -pcm.out[1]);
pcm.out[1] = 0;
}
}
/* resample to output stereo buffer */
blip_end_frame(blip[0], length);
blip_read_samples(blip[0], buffer, 1);
blip_end_frame(blip[1], length);
blip_read_samples(blip[1], buffer + 1, 1);
}
void pcm_write(unsigned int address, unsigned char data)
{
/* external RAM is mapped to $1000-$1FFF */
if (address >= 0x1000)
{
/* 4K bank access */
pcm.bank[address & 0xfff] = data;
return;
}
/* internal area si mapped to $0000-$0FFF */
switch (address)
{
case 0x00: /* ENV register */
{
/* update channel ENV multiplier */
pcm.chan[pcm.index].env = data;
return;
}
case 0x01: /* PAN register */
{
/* update channel stereo panning value */
pcm.chan[pcm.index].pan = data;
return;
}
case 0x02: /* FD register (LSB) */
{
/* update channel WAVE RAM address increment LSB */
pcm.chan[pcm.index].fd.byte.l = data;
return;
}
case 0x03: /* FD register (MSB) */
{
/* update channel WAVE RAM address increment MSB */
pcm.chan[pcm.index].fd.byte.h = data;
return;
}
case 0x04: /* LS register (LSB) */
{
/* update channel WAVE RAM loop address LSB */
pcm.chan[pcm.index].ls.byte.l = data;
return;
}
case 0x05: /* LS register (MSB) */
{
/* update channel WAVE RAM loop address MSB */
pcm.chan[pcm.index].ls.byte.h = data;
return;
}
case 0x06: /* ST register */
{
/* update channel WAVE RAM start address (16.11 fixed point) */
pcm.chan[pcm.index].st = data << (8 + 11);
return;
}
case 0x07: /* CTRL register */
{
if (data & 0x40)
{
/* channel selection (0-7) */
pcm.index = data & 0x07;
}
else
{
/* external RAM bank selection (16 x 4K) */
pcm.bank = &pcm.ram[(data & 0x0f) << 12];
}
/* update PCM chip status (bit 7) */
pcm.enabled = data & 0x80;
return;
}
case 0x08: /* ON/OFF register */
{
/* reload WAVE RAM address pointers when channels are switched ON (bit cleared) */
if ((pcm.status & 0x01) && !(data & 0x01)) pcm.chan[0].addr = pcm.chan[0].st;
if ((pcm.status & 0x02) && !(data & 0x02)) pcm.chan[1].addr = pcm.chan[1].st;
if ((pcm.status & 0x04) && !(data & 0x04)) pcm.chan[2].addr = pcm.chan[2].st;
if ((pcm.status & 0x08) && !(data & 0x08)) pcm.chan[3].addr = pcm.chan[3].st;
if ((pcm.status & 0x10) && !(data & 0x10)) pcm.chan[4].addr = pcm.chan[4].st;
if ((pcm.status & 0x20) && !(data & 0x20)) pcm.chan[5].addr = pcm.chan[5].st;
if ((pcm.status & 0x40) && !(data & 0x40)) pcm.chan[6].addr = pcm.chan[6].st;
if ((pcm.status & 0x80) && !(data & 0x80)) pcm.chan[7].addr = pcm.chan[7].st;
/* update PCM channels status */
pcm.status = data;
return;
}
default:
{
/* illegal access */
return;
}
}
}
unsigned char pcm_read(unsigned int address)
{
/* external RAM (TODO: verify if possible to read, some docs claim it's not !) */
if (address >= 0x1000)
{
/* 4K bank access */
return pcm.bank[address & 0xfff];
}
/* read WAVE RAM address pointers */
if ((address >= 0x10) && (address < 0x20))
{
int index = (address >> 1) & 0x07;
if (address & 1)
{
return pcm.chan[index].addr >> (11 + 8);
}
else
{
return (pcm.chan[index].addr >> 11) & 0xff;
}
}
/* illegal access */
return 0xff;
}
void pcm_ram_dma_w(unsigned int words)
{
uint16 data;
/* CDC buffer source address */
uint16 src_index = cdc.dac.w & 0x3ffe;
/* PCM-RAM destination address*/
uint16 dst_index = (scd.regs[0x0a>>1].w << 2) & 0xffe;
/* update DMA destination address */
scd.regs[0x0a>>1].w += (words >> 1);
/* update DMA source address */
cdc.dac.w += (words << 1);
/* DMA transfer */
while (words--)
{
/* read 16-bit word from CDC buffer */
data = *(uint16 *)(cdc.ram + src_index);
/* write 16-bit word to PCM RAM (endianness does not matter since PCM RAM is always accessed as byte)*/
*(uint16 *)(pcm.bank + dst_index) = data ;
/* increment CDC buffer source address */
src_index = (src_index + 2) & 0x3ffe;
/* increment PCM-RAM destination address */
dst_index = (dst_index + 2) & 0xffe;
}
}

73
source/cd_hw/pcm.h Normal file
View File

@ -0,0 +1,73 @@
/***************************************************************************************
* Genesis Plus
* PCM sound chip (315-5476A) (RF5C164 compatible)
*
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#ifndef _CD_PCM_
#define _CD_PCM_
/* PCM channel */
typedef struct
{
uint32 addr; /* current Wave RAM address (16.11 fixed point) */
uint32 st; /* Wave RAM start address (16.11 fixed point) */
reg16_t ls; /* Wave RAM loop address ($0000-$ffff) */
reg16_t fd; /* Wave RAM address increment (5.11 fixed point) */
uint8 env; /* enveloppe multiplier */
uint8 pan; /* stereo panning */
} chan_t;
/* PCM sound chip */
typedef struct
{
chan_t chan[8]; /* PCM channels 1-8 */
int16 out[2]; /* previous PCM stereo output */
uint8 *bank; /* external RAM bank pointer */
uint8 enabled; /* PCM chip ON/OFF status */
uint8 status; /* channels ON/OFF status */
uint8 index; /* current channel index */
uint8 ram[0x10000]; /* 64k external RAM */
} pcm_t;
/* Function prototypes */
extern void pcm_init(double clock, double samplerate);
extern void pcm_shutdown(void);
extern void pcm_reset(void);
extern void pcm_update(short *buffer, int length);
extern void pcm_write(unsigned int address, unsigned char data);
extern unsigned char pcm_read(unsigned int address);
extern void pcm_ram_dma_w(unsigned int words);
#endif

1732
source/cd_hw/scd.c Normal file

File diff suppressed because it is too large Load Diff

85
source/cd_hw/scd.h Normal file
View File

@ -0,0 +1,85 @@
/***************************************************************************************
* Genesis Plus
* Mega CD / Sega CD hardware
*
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#ifndef _HW_SCD_
#define _HW_SCD_
#include "cdd.h"
#include "cdc.h"
#include "gfx.h"
#include "pcm.h"
#include "cd_cart.h"
#define scd ext.cd_hw
/* 5000000 clocks/s = approx. 3184 clocks/line with a master clock of 53.693175 Mhz */
/* TODO: use emulated master clock as reference ? */
#define SCD_CLOCK 50000000
#define SCYCLES_PER_LINE 3184
/* CD hardware */
typedef struct
{
uint8 bootrom[0x20000]; /* 128K internal BOOTROM */
uint8 prg_ram[0x80000]; /* 512K PRG-RAM */
uint8 word_ram[2][0x20000]; /* 2 x 128K Word RAM (1M mode) */
uint8 word_ram_2M[0x40000]; /* 256K Word RAM (2M mode) */
uint8 bram[0x2000]; /* 8K Backup RAM */
reg16_t regs[0x100]; /* 256 x 16-bit ASIC registers */
uint32 cycles; /* Master clock counter */
int32 timer; /* Timer counter */
uint8 pending; /* Pending interrupts */
uint8 dmna; /* Pending DMNA write status */
gfx_t gfx_hw; /* Graphics processor */
cdc_t cdc_hw; /* CD data controller */
cdd_t cdd_hw; /* CD drive processor */
pcm_t pcm_hw; /* PCM chip */
cd_cart_t cartridge; /* Cartridge hardware */
} cd_hw_t;
/* Function prototypes */
extern void scd_init(void);
extern void scd_shutdown(void);
extern void scd_reset(int hard);
extern void scd_update(unsigned int cycles);
extern int scd_context_load(uint8 *state);
extern int scd_context_save(uint8 *state);
extern int scd_68k_irq_ack(int level);
extern void prg_ram_dma_w(unsigned int words);
#endif

View File

@ -2,10 +2,10 @@
* Genesis Plus
* Internal Hardware & Bus controllers
*
* Support for SG-1000, Mark-III, Master System, Game Gear & Mega Drive hardware
* Support for SG-1000, Mark-III, Master System, Game Gear, Mega Drive & Mega CD hardware
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -41,13 +41,13 @@
#include "shared.h"
external_t ext; /* External Hardware (Cartridge, CD unit, ...) */
uint8 boot_rom[0x800]; /* Genesis BOOT ROM */
uint8 work_ram[0x10000]; /* 68K RAM */
uint8 zram[0x2000]; /* Z80 RAM */
uint32 zbank; /* Z80 bank window address */
uint8 zstate; /* Z80 bus state (d0 = BUSACK, d1 = /RESET) */
uint8 pico_current; /* PICO current page */
uint8 pico_regs[7]; /* PICO page registers */
static uint8 tmss[4]; /* TMSS security register */
@ -59,65 +59,84 @@ void gen_init(void)
{
int i;
/* initialize 68k */
m68k_init();
/* initialize Z80 */
z80_init(0,z80_irq_callback);
/* initialize default 68k memory map */
/* 8-bit / 16-bit modes */
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
/* initialize main 68k */
m68k_init();
/* $000000-$7FFFFF : cartridge area (md_cart.c) */
/* initialize main 68k memory map */
/* $800000-$DFFFFF : illegal access by default */
for (i=0x80; i<0xe0; i++)
{
m68k_memory_map[i].base = work_ram; /* for VDP DMA */
m68k_memory_map[i].read8 = m68k_lockup_r_8;
m68k_memory_map[i].read16 = m68k_lockup_r_16;
m68k_memory_map[i].write8 = m68k_lockup_w_8;
m68k_memory_map[i].write16 = m68k_lockup_w_16;
m68k.memory_map[i].base = work_ram; /* for VDP DMA */
m68k.memory_map[i].read8 = m68k_lockup_r_8;
m68k.memory_map[i].read16 = m68k_lockup_r_16;
m68k.memory_map[i].write8 = m68k_lockup_w_8;
m68k.memory_map[i].write16 = m68k_lockup_w_16;
zbank_memory_map[i].read = zbank_lockup_r;
zbank_memory_map[i].write = zbank_lockup_w;
}
/* $E00000-$FFFFFF : Work RAM */
for (i=0xe0; i<0x100; i++)
{
m68k_memory_map[i].base = work_ram;
m68k_memory_map[i].read8 = NULL;
m68k_memory_map[i].read16 = NULL;
m68k_memory_map[i].write8 = NULL;
m68k_memory_map[i].write16 = NULL;
zbank_memory_map[i].read = zbank_unused_r;
zbank_memory_map[i].write = NULL;
}
/* $A10000-$A1FFFF : I/O & Control registers */
m68k_memory_map[0xa1].read8 = ctrl_io_read_byte;
m68k_memory_map[0xa1].read16 = ctrl_io_read_word;
m68k_memory_map[0xa1].write8 = ctrl_io_write_byte;
m68k_memory_map[0xa1].write16 = ctrl_io_write_word;
zbank_memory_map[0xa1].read = zbank_read_ctrl_io;
zbank_memory_map[0xa1].write = zbank_write_ctrl_io;
/* $C0xxxx, $C8xxxx, $D0xxxx, $D8xxxx : VDP ports */
for (i=0xc0; i<0xe0; i+=8)
{
m68k_memory_map[i].read8 = vdp_read_byte;
m68k_memory_map[i].read16 = vdp_read_word;
m68k_memory_map[i].write8 = vdp_write_byte;
m68k_memory_map[i].write16 = vdp_write_word;
m68k.memory_map[i].read8 = vdp_read_byte;
m68k.memory_map[i].read16 = vdp_read_word;
m68k.memory_map[i].write8 = vdp_write_byte;
m68k.memory_map[i].write16 = vdp_write_word;
zbank_memory_map[i].read = zbank_read_vdp;
zbank_memory_map[i].write = zbank_write_vdp;
}
/* 68k mode */
if (system_hw == SYSTEM_MD)
/* $E00000-$FFFFFF : Work RAM (64k) */
for (i=0xe0; i<0x100; i++)
{
m68k.memory_map[i].base = work_ram;
m68k.memory_map[i].read8 = NULL;
m68k.memory_map[i].read16 = NULL;
m68k.memory_map[i].write8 = NULL;
m68k.memory_map[i].write16 = NULL;
/* Z80 can ONLY write to 68k RAM, not read it */
zbank_memory_map[i].read = zbank_unused_r;
zbank_memory_map[i].write = NULL;
}
if (system_hw == SYSTEM_PICO)
{
/* additional registers mapped to $800000-$80FFFF */
m68k.memory_map[0x80].read8 = pico_read_byte;
m68k.memory_map[0x80].read16 = pico_read_word;
m68k.memory_map[0x80].write8 = m68k_unused_8_w;
m68k.memory_map[0x80].write16 = m68k_unused_16_w;
/* there is no I/O area (Notaz) */
m68k.memory_map[0xa1].read8 = m68k_read_bus_8;
m68k.memory_map[0xa1].read16 = m68k_read_bus_16;
m68k.memory_map[0xa1].write8 = m68k_unused_8_w;
m68k.memory_map[0xa1].write16 = m68k_unused_16_w;
/* initialize page index (closed) */
pico_current = 0;
}
else
{
/* $A10000-$A1FFFF : I/O & Control registers */
m68k.memory_map[0xa1].read8 = ctrl_io_read_byte;
m68k.memory_map[0xa1].read16 = ctrl_io_read_word;
m68k.memory_map[0xa1].write8 = ctrl_io_write_byte;
m68k.memory_map[0xa1].write16 = ctrl_io_write_word;
zbank_memory_map[0xa1].read = zbank_read_ctrl_io;
zbank_memory_map[0xa1].write = zbank_write_ctrl_io;
/* initialize Z80 memory map */
/* $0000-$3FFF is mapped to Z80 RAM (8K mirrored) */
/* $4000-$FFFF is mapped to hardware but Z80.PC should never point there */
/* $4000-$FFFF is mapped to hardware but Z80 PC should never point there */
for (i=0; i<64; i++)
{
z80_readmap[i] = &zram[(i & 7) << 10];
@ -130,49 +149,32 @@ void gen_init(void)
/* initialize Z80 port handlers */
z80_writeport = z80_unused_port_w;
z80_readport = z80_unused_port_r;
/* initialize MD cartridge hardware */
md_cart_init();
}
/* PICO hardware */
else if (system_hw == SYSTEM_PICO)
/* $000000-$7FFFFF : external hardware area */
if (system_hw == SYSTEM_MCD)
{
/* additional registers mapped to $800000-$80FFFF */
m68k_memory_map[0x80].read8 = pico_read_byte;
m68k_memory_map[0x80].read16 = pico_read_word;
m68k_memory_map[0x80].write8 = m68k_unused_8_w;
m68k_memory_map[0x80].write16 = m68k_unused_16_w;
/* initialize SUB-CPU */
s68k_init();
/* there is no I/O area (Notaz) */
m68k_memory_map[0xa1].read8 = m68k_read_bus_8;
m68k_memory_map[0xa1].read16 = m68k_read_bus_16;
m68k_memory_map[0xa1].write8 = m68k_unused_8_w;
m68k_memory_map[0xa1].write16 = m68k_unused_16_w;
/* page registers */
pico_current = 0x00;
pico_regs[0] = 0x00;
pico_regs[1] = 0x01;
pico_regs[2] = 0x03;
pico_regs[3] = 0x07;
pico_regs[4] = 0x0F;
pico_regs[5] = 0x1F;
pico_regs[6] = 0x3F;
/* initialize cartridge hardware */
md_cart_init();
/* initialize CD hardware */
scd_init();
}
/* Z80 mode */
else
{
/* initialize cartridge hardware (memory handlers are also initialized) */
/* Cartridge hardware */
md_cart_init();
}
}
else
{
/* initialize cartridge hardware & Z80 memory handlers */
sms_cart_init();
/* initialize Z80 ports handlers */
switch (system_hw)
{
/* Master System compatibility mode */
case SYSTEM_PBC:
{
z80_writeport = z80_md_port_w;
@ -180,14 +182,20 @@ void gen_init(void)
break;
}
/* Game Gear hardware */
case SYSTEM_GG:
case SYSTEM_GGMS:
{
/* initialize cartridge hardware & Z80 memory handlers */
sms_cart_init();
/* initialize Z80 ports handlers */
z80_writeport = z80_gg_port_w;
z80_readport = z80_gg_port_r;
break;
}
/* Master SYstem hardware */
case SYSTEM_SMS:
case SYSTEM_SMS2:
{
@ -196,6 +204,7 @@ void gen_init(void)
break;
}
/* Mark-III hardware */
case SYSTEM_MARKIII:
{
z80_writeport = z80_m3_port_w;
@ -203,6 +212,7 @@ void gen_init(void)
break;
}
/* SG-1000 hardware */
case SYSTEM_SG:
{
z80_writeport = z80_sg_port_w;
@ -213,6 +223,14 @@ void gen_init(void)
}
}
void gen_shutdown(void)
{
if (system_hw == SYSTEM_MCD)
{
scd_shutdown();
}
}
void gen_reset(int hard_reset)
{
/* System Reset */
@ -228,30 +246,33 @@ void gen_reset(int hard_reset)
fm_reset(0);
}
/* 68k & Z80 could restart anywhere in VDP frame (Bonkers, Eternal Champions, X-Men 2) */
mcycles_68k = mcycles_z80 = (uint32)((MCYCLES_PER_LINE * lines_per_frame) * ((double)rand() / (double)RAND_MAX));
/* 68k & Z80 could be anywhere in VDP frame (Bonkers, Eternal Champions, X-Men 2) */
m68k.cycles = Z80.cycles = (uint32)((MCYCLES_PER_LINE * lines_per_frame) * ((double)rand() / (double)RAND_MAX));
/* Genesis / Master System modes */
/* 68k cycles should be a multiple of 7 */
m68k.cycles = (m68k.cycles / 7) * 7;
/* Z80 cycles should be a multiple of 15 */
Z80.cycles = (Z80.cycles / 15) * 15;
/* 8-bit / 16-bit modes */
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
/* reset cartridge hardware & mapping */
md_cart_reset(hard_reset);
/* Z80 bus is released & Z80 is reseted */
m68k_memory_map[0xa0].read8 = m68k_read_bus_8;
m68k_memory_map[0xa0].read16 = m68k_read_bus_16;
m68k_memory_map[0xa0].write8 = m68k_unused_8_w;
m68k_memory_map[0xa0].write16 = m68k_unused_16_w;
m68k.memory_map[0xa0].read8 = m68k_read_bus_8;
m68k.memory_map[0xa0].read16 = m68k_read_bus_16;
m68k.memory_map[0xa0].write8 = m68k_unused_8_w;
m68k.memory_map[0xa0].write16 = m68k_unused_16_w;
zstate = 0;
/* assume default bank is $000000-$007FFF */
zbank = 0;
/* TMSS support */
if ((config.bios & 1) && (system_hw != SYSTEM_PICO))
{
/* on HW reset only */
if (hard_reset)
if ((config.bios & 1) && (system_hw == SYSTEM_MD) && hard_reset)
{
int i;
@ -261,27 +282,37 @@ void gen_reset(int hard_reset)
/* VDP access is locked by default */
for (i=0xc0; i<0xe0; i+=8)
{
m68k_memory_map[i].read8 = m68k_lockup_r_8;
m68k_memory_map[i].read16 = m68k_lockup_r_16;
m68k_memory_map[i].write8 = m68k_lockup_w_8;
m68k_memory_map[i].write16 = m68k_lockup_w_16;
m68k.memory_map[i].read8 = m68k_lockup_r_8;
m68k.memory_map[i].read16 = m68k_lockup_r_16;
m68k.memory_map[i].write8 = m68k_lockup_w_8;
m68k.memory_map[i].write16 = m68k_lockup_w_16;
zbank_memory_map[i].read = zbank_lockup_r;
zbank_memory_map[i].write = zbank_lockup_w;
}
/* check if BOOT ROM is loaded */
if (config.bios & SYSTEM_MD)
if (system_bios & SYSTEM_MD)
{
/* save default cartridge slot mapping */
cart.base = m68k_memory_map[0].base;
cart.base = m68k.memory_map[0].base;
/* BOOT ROM is mapped at $000000-$0007FF */
m68k_memory_map[0].base = boot_rom;
}
m68k.memory_map[0].base = boot_rom;
}
}
/* reset 68k */
if (system_hw == SYSTEM_MCD)
{
/* reset CD hardware */
scd_reset(1);
/* reset & halt SUB-CPU */
s68k.cycles = 0;
s68k_pulse_reset();
s68k_pulse_halt();
}
/* reset MAIN-CPU */
m68k_pulse_reset();
}
else
@ -293,9 +324,6 @@ void gen_reset(int hard_reset)
memset(work_ram, 0xf0, sizeof(work_ram));
}
/* Z80 cycles should be a multiple of 15 to avoid rounding errors */
mcycles_z80 = (mcycles_z80 / 15) * 15;
/* reset cartridge hardware */
sms_cart_reset();
@ -307,11 +335,6 @@ void gen_reset(int hard_reset)
z80_reset();
}
void gen_shutdown(void)
{
z80_exit();
}
/*-----------------------------------------------------------------------*/
/* OS ROM / TMSS register control functions (Genesis mode) */
@ -329,10 +352,10 @@ void gen_tmss_w(unsigned int offset, unsigned int data)
{
for (i=0xc0; i<0xe0; i+=8)
{
m68k_memory_map[i].read8 = vdp_read_byte;
m68k_memory_map[i].read16 = vdp_read_word;
m68k_memory_map[i].write8 = vdp_write_byte;
m68k_memory_map[i].write16 = vdp_write_word;
m68k.memory_map[i].read8 = vdp_read_byte;
m68k.memory_map[i].read16 = vdp_read_word;
m68k.memory_map[i].write8 = vdp_write_byte;
m68k.memory_map[i].write16 = vdp_write_word;
zbank_memory_map[i].read = zbank_read_vdp;
zbank_memory_map[i].write = zbank_write_vdp;
}
@ -341,10 +364,10 @@ void gen_tmss_w(unsigned int offset, unsigned int data)
{
for (i=0xc0; i<0xe0; i+=8)
{
m68k_memory_map[i].read8 = m68k_lockup_r_8;
m68k_memory_map[i].read16 = m68k_lockup_r_16;
m68k_memory_map[i].write8 = m68k_lockup_w_8;
m68k_memory_map[i].write16 = m68k_lockup_w_16;
m68k.memory_map[i].read8 = m68k_lockup_r_8;
m68k.memory_map[i].read16 = m68k_lockup_r_16;
m68k.memory_map[i].write8 = m68k_lockup_w_8;
m68k.memory_map[i].write16 = m68k_lockup_w_16;
zbank_memory_map[i].read = zbank_lockup_r;
zbank_memory_map[i].write = zbank_lockup_w;
}
@ -356,18 +379,18 @@ void gen_bankswitch_w(unsigned int data)
if (data & 1)
{
/* enable cartridge ROM */
m68k_memory_map[0].base = cart.base;
m68k.memory_map[0].base = cart.base;
}
else
{
/* enable internal BOOT ROM */
m68k_memory_map[0].base = boot_rom;
m68k.memory_map[0].base = boot_rom;
}
}
unsigned int gen_bankswitch_r(void)
{
return (m68k_memory_map[0].base == cart.base);
return (m68k.memory_map[0].base == cart.base);
}
@ -386,10 +409,10 @@ void gen_zbusreq_w(unsigned int data, unsigned int cycles)
z80_run(cycles);
/* enable 68k access to Z80 bus */
m68k_memory_map[0xa0].read8 = z80_read_byte;
m68k_memory_map[0xa0].read16 = z80_read_word;
m68k_memory_map[0xa0].write8 = z80_write_byte;
m68k_memory_map[0xa0].write16 = z80_write_word;
m68k.memory_map[0xa0].read8 = z80_read_byte;
m68k.memory_map[0xa0].read16 = z80_read_word;
m68k.memory_map[0xa0].write8 = z80_write_byte;
m68k.memory_map[0xa0].write16 = z80_write_word;
}
/* update Z80 bus status */
@ -401,13 +424,13 @@ void gen_zbusreq_w(unsigned int data, unsigned int cycles)
if (zstate == 3)
{
/* resynchronize with 68k */
mcycles_z80 = cycles;
Z80.cycles = cycles;
/* disable 68k access to Z80 bus */
m68k_memory_map[0xa0].read8 = m68k_read_bus_8;
m68k_memory_map[0xa0].read16 = m68k_read_bus_16;
m68k_memory_map[0xa0].write8 = m68k_unused_8_w;
m68k_memory_map[0xa0].write16 = m68k_unused_16_w;
m68k.memory_map[0xa0].read8 = m68k_read_bus_8;
m68k.memory_map[0xa0].read16 = m68k_read_bus_16;
m68k.memory_map[0xa0].write8 = m68k_unused_8_w;
m68k.memory_map[0xa0].write16 = m68k_unused_16_w;
}
/* update Z80 bus status */
@ -423,7 +446,7 @@ void gen_zreset_w(unsigned int data, unsigned int cycles)
if (zstate == 0)
{
/* resynchronize with 68k */
mcycles_z80 = cycles;
Z80.cycles = cycles;
/* reset Z80 & YM2612 */
z80_reset();
@ -434,10 +457,10 @@ void gen_zreset_w(unsigned int data, unsigned int cycles)
else if (zstate == 2)
{
/* enable 68k access to Z80 bus */
m68k_memory_map[0xa0].read8 = z80_read_byte;
m68k_memory_map[0xa0].read16 = z80_read_word;
m68k_memory_map[0xa0].write8 = z80_write_byte;
m68k_memory_map[0xa0].write16 = z80_write_word;
m68k.memory_map[0xa0].read8 = z80_read_byte;
m68k.memory_map[0xa0].read16 = z80_read_word;
m68k.memory_map[0xa0].write8 = z80_write_byte;
m68k.memory_map[0xa0].write16 = z80_write_word;
/* reset Z80 & YM2612 */
z80_reset();
@ -460,10 +483,10 @@ void gen_zreset_w(unsigned int data, unsigned int cycles)
else if (zstate == 3)
{
/* disable 68k access to Z80 bus */
m68k_memory_map[0xa0].read8 = m68k_read_bus_8;
m68k_memory_map[0xa0].read16 = m68k_read_bus_16;
m68k_memory_map[0xa0].write8 = m68k_unused_8_w;
m68k_memory_map[0xa0].write16 = m68k_unused_16_w;
m68k.memory_map[0xa0].read8 = m68k_read_bus_8;
m68k.memory_map[0xa0].read16 = m68k_read_bus_16;
m68k.memory_map[0xa0].write8 = m68k_unused_8_w;
m68k.memory_map[0xa0].write16 = m68k_unused_16_w;
}
/* stop YM2612 */
@ -486,5 +509,5 @@ void gen_zbank_w (unsigned int data)
int z80_irq_callback (int param)
{
return 0xFF;
return -1;
}

View File

@ -2,10 +2,10 @@
* Genesis Plus
* Internal hardware & Bus controllers
*
* Support for SG-1000, Mark-III, Master System, Game Gear & Mega Drive hardware
* Support for SG-1000, Mark-III, Master System, Game Gear, Mega Drive & Mega CD hardware
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -42,14 +42,25 @@
#ifndef _GENESIS_H_
#define _GENESIS_H_
#include "md_cart.h"
#include "sms_cart.h"
#include "scd.h"
/* External Hardware */
typedef union
{
md_cart_t md_cart;
cd_hw_t cd_hw;
} external_t;
/* Global variables */
extern external_t ext;
extern uint8 boot_rom[0x800];
extern uint8 work_ram[0x10000];
extern uint8 zram[0x2000];
extern uint32 zbank;
extern uint8 zstate;
extern uint8 pico_current;
extern uint8 pico_regs[7];
/* Function prototypes */
extern void gen_init(void);

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX configuration file support
*
* Copyright Eke-Eke (2007-2011)
* Copyright Eke-Eke (2007-2012)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -39,7 +39,6 @@
#include "shared.h"
#include "gui.h"
#include "menu.h"
#include "file_load.h"
static int config_load(void)
@ -193,23 +192,28 @@ void config_default(void)
sprintf (config.lastdir[1][TYPE_SD], "sd:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[2][TYPE_SD], "sd:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[3][TYPE_SD], "sd:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[4][TYPE_SD], "sd:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[0][TYPE_USB], "usb:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[1][TYPE_USB], "usb:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[2][TYPE_USB], "usb:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[3][TYPE_USB], "usb:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[4][TYPE_USB], "usb:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[0][TYPE_DVD], "dvd:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[1][TYPE_DVD], "dvd:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[2][TYPE_DVD], "dvd:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[3][TYPE_DVD], "dvd:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[4][TYPE_DVD], "dvd:%s/roms/", DEFAULT_PATH);
#else
sprintf (config.lastdir[0][TYPE_SD], "%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[1][TYPE_SD], "%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[2][TYPE_SD], "%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[3][TYPE_SD], "%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[4][TYPE_SD], "%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[0][TYPE_DVD], "dvd:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[1][TYPE_DVD], "dvd:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[2][TYPE_DVD], "dvd:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[3][TYPE_DVD], "dvd:%s/roms/", DEFAULT_PATH);
sprintf (config.lastdir[4][TYPE_DVD], "dvd:%s/roms/", DEFAULT_PATH);
#endif
/* try to restore user config */

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX configuration file support
*
* Copyright Eke-Eke (2007-2011)
* Copyright Eke-Eke (2007-2012)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -40,7 +40,7 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
#define CONFIG_VERSION "GENPLUS-GX 1.6.1"
#define CONFIG_VERSION "GENPLUS-GX 1.7.0"
/****************************************************************************
* Config Option
@ -107,11 +107,7 @@ typedef struct
int16 screen_w;
float bgm_volume;
float sfx_volume;
#ifdef HW_RVL
char lastdir[4][3][MAXPATHLEN];
#else
char lastdir[4][2][MAXPATHLEN];
#endif
char lastdir[FILETYPE_MAX][TYPE_RECENT][MAXPATHLEN];
} t_config;
/* Global data */

View File

@ -3,7 +3,7 @@
*
* ROM File loading support
*
* Copyright Eke-Eke (2008-2011)
* Copyright Eke-Eke (2008-2012)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -262,7 +262,7 @@ int LoadFile(int selection)
}
}
/* try to load ROM file */
/* try to load file */
int size = load_rom(filename);
if (size > 0)
@ -273,25 +273,31 @@ int LoadFile(int selection)
slot_autosave(config.s_default,config.s_device);
}
/* update ROM pathname for screenshot, save & cheat files */
if (!strnicmp(".sms", &filename[strlen(filename) - 4], 4))
/* update pathname for screenshot, save & cheat files */
if (romtype & SYSTEM_SMS)
{
/* Master System ROM file */
filetype = 1;
filetype = 2;
sprintf(rom_filename,"ms/%s",filelist[selection].filename);
}
else if (!strnicmp(".gg", &filename[strlen(filename) - 3], 3))
else if (romtype & SYSTEM_GG)
{
/* Game Gear ROM file */
filetype = 2;
filetype = 3;
sprintf(rom_filename,"gg/%s",filelist[selection].filename);
}
else if (!strnicmp(".sg", &filename[strlen(filename) - 3], 3))
else if (romtype == SYSTEM_SG)
{
/* SG-1000 ROM file */
filetype = 3;
filetype = 4;
sprintf(rom_filename,"sg/%s",filelist[selection].filename);
}
else if (romtype == SYSTEM_MCD)
{
/* CD image file */
filetype = 1;
sprintf(rom_filename,"cd/%s",filelist[selection].filename);
}
else
{
/* by default, Genesis ROM file */
@ -310,7 +316,7 @@ int LoadFile(int selection)
/* recent file list may have changed */
if (deviceType == TYPE_RECENT) deviceType = -1;
/* valid ROM has been loaded */
/* valid image has been loaded */
return 1;
}

View File

@ -3,7 +3,7 @@
*
* ROM File loading support
*
* Copyright Eke-Eke (2008-2011)
* Copyright Eke-Eke (2008-2012)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -40,18 +40,30 @@
#ifndef _FILE_FAT_H
#define _FILE_FAT_H
#define TYPE_SD (0)
#ifdef HW_RVL
#define TYPE_USB (1)
#define TYPE_DVD (2)
#else
#define TYPE_DVD (1)
#endif
#define TYPE_RECENT (TYPE_DVD + 1)
#define CHUNKSIZE (2048)
/* suppported load devices */
typedef enum
{
TYPE_SD = 0,
#ifdef HW_RVL
TYPE_USB,
#endif
TYPE_DVD,
TYPE_RECENT
}DEVTYPES;
/* supported file types */
typedef enum
{
FILETYPE_MD = 0,
FILETYPE_CD,
FILETYPE_MS,
FILETYPE_GG,
FILETYPE_SG,
FILETYPE_MAX
}FILETYPES;
extern int OpenDirectory(int device, int type);
extern int UpdateDirectory(bool go_up, char *filename);
extern int ParseDirectory(void);

View File

@ -3,7 +3,7 @@
*
* FAT and Memory Card SRAM/State slots managment
*
* Copyright Eke-Eke (2008-2011), based on original code from Softdev (2006)
* Copyright Eke-Eke (2008-2012), based on original code from Softdev (2006)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -49,6 +49,16 @@
*/
static u8 SysArea[CARD_WORKAREA] ATTRIBUTE_ALIGN (32);
/* Mega CD backup RAM stuff */
static u32 brm_crc[2];
static char brm_filename[3][32] = {CD_BRAM_JP, CD_BRAM_EU, CD_BRAM_US};
static u8 brm_format[0x40] =
{
0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x00,0x00,0x00,0x00,0x40,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x53,0x45,0x47,0x41,0x5f,0x43,0x44,0x5f,0x52,0x4f,0x4d,0x00,0x01,0x00,0x00,0x00,
0x52,0x41,0x4d,0x5f,0x43,0x41,0x52,0x54,0x52,0x49,0x44,0x47,0x45,0x5f,0x5f,0x5f
};
/****************************************************************************
* CardMount
@ -83,35 +93,130 @@ static int CardMount(int slot)
*
*
****************************************************************************/
void slot_autoload(int slot, int device)
{
if (!strlen(rom_filename))
return;
/* Mega CD backup RAM specific */
if (!slot && (system_hw == SYSTEM_MCD))
{
/* automatically load internal backup RAM */
FILE *fp = fopen(brm_filename[((region_code ^ 0x40) >> 6) - 1], "rb");
if (fp != NULL)
{
fread(scd.bram, 0x2000, 1, fp);
fclose(fp);
/* update CRC */
brm_crc[0] = crc32(0, scd.bram, 0x2000);
}
/* check if internal backup RAM is correctly formatted */
if (memcmp(scd.bram + 0x2000 - 0x20, brm_format + 0x20, 0x20))
{
/* clear internal backup RAM */
memset(scd.bram, 0x00, 0x200);
/* internal Backup RAM size fields */
brm_format[0x10] = brm_format[0x12] = brm_format[0x14] = brm_format[0x16] = 0x00;
brm_format[0x11] = brm_format[0x13] = brm_format[0x15] = brm_format[0x17] = (sizeof(scd.bram) / 64) - 3;
/* format internal backup RAM */
memcpy(scd.bram + 0x2000 - 0x40, brm_format, 0x40);
}
/* automatically load cartridge backup RAM (if enabled) */
if (scd.cartridge.id)
{
fp = fopen(CART_BRAM, "rb");
if (fp != NULL)
{
fread(scd.cartridge.area, scd.cartridge.mask + 1, 1, fp);
fclose(fp);
/* update CRC */
brm_crc[1] = crc32(0, scd.cartridge.area, scd.cartridge.mask + 1);
}
/* check if cartridge backup RAM is correctly formatted */
if (memcmp(scd.cartridge.area + scd.cartridge.mask + 1 - 0x20, brm_format + 0x20, 0x20))
{
/* clear cartridge backup RAM */
memset(scd.cartridge.area, 0x00, scd.cartridge.mask + 1);
/* Cartridge Backup RAM size fields */
brm_format[0x10] = brm_format[0x12] = brm_format[0x14] = brm_format[0x16] = (((scd.cartridge.mask + 1) / 64) - 3) >> 8;
brm_format[0x11] = brm_format[0x13] = brm_format[0x15] = brm_format[0x17] = (((scd.cartridge.mask + 1) / 64) - 3) & 0xff;
/* format cartridge backup RAM */
memcpy(scd.cartridge.area + scd.cartridge.mask + 1 - 0x40, brm_format, 0x40);
}
}
return;
}
if (strlen(rom_filename))
{
SILENT = 1;
slot_load(slot, device);
SILENT = 0;
}
}
void slot_autosave(int slot, int device)
{
if (!strlen(rom_filename))
return;
/* Mega CD backup RAM specific */
if (!slot && (system_hw == SYSTEM_MCD))
{
/* verify that internal backup RAM has been modified */
if (crc32(0, scd.bram, 0x2000) != brm_crc[0])
{
/* check if it is correctly formatted before saving */
if (!memcmp(scd.bram + 0x2000 - 0x20, brm_format + 0x20, 0x20))
{
FILE *fp = fopen(brm_filename[((region_code ^ 0x40) >> 6) - 1], "wb");
if (fp != NULL)
{
fwrite(scd.bram, 0x2000, 1, fp);
fclose(fp);
/* only save if SRAM changed */
if (!slot && (crc32(0, &sram.sram[0], 0x10000) == sram.crc))
return;
/* update CRC */
brm_crc[0] = crc32(0, scd.bram, 0x2000);
}
}
}
/* verify that cartridge backup RAM has been modified */
if (scd.cartridge.id && (crc32(0, scd.cartridge.area, scd.cartridge.mask + 1) != brm_crc[1]))
{
/* check if it is correctly formatted before saving */
if (!memcmp(scd.cartridge.area + scd.cartridge.mask + 1 - 0x20, brm_format + 0x20, 0x20))
{
FILE *fp = fopen(CART_BRAM, "wb");
if (fp != NULL)
{
fwrite(scd.cartridge.area, scd.cartridge.mask + 1, 1, fp);
fclose(fp);
/* update CRC */
brm_crc[1] = crc32(0, scd.cartridge.area, scd.cartridge.mask + 1);
}
}
}
return;
}
if (strlen(rom_filename))
{
SILENT = 1;
slot_save(slot, device);
SILENT = 0;
}
}
void slot_autodetect(int slot, int device, t_slot *ptr)
{
if (!ptr)
return;
if (!ptr) return;
char filename[MAXPATHLEN];
memset(ptr,0,sizeof(t_slot));
@ -120,9 +225,13 @@ void slot_autodetect(int slot, int device, t_slot *ptr)
{
/* FAT support */
if (slot > 0)
{
sprintf (filename,"%s/saves/%s.gp%d", DEFAULT_PATH, rom_filename, slot - 1);
}
else
{
sprintf (filename,"%s/saves/%s.srm", DEFAULT_PATH, rom_filename);
}
/* Open file */
FILE *fp = fopen(filename, "rb");
@ -236,16 +345,16 @@ int slot_load(int slot, int device)
{
char filename[MAXPATHLEN];
unsigned long filesize, done = 0;
int offset = 0;
u8 *savebuffer;
u8 *buffer;
/* File Type */
if (slot > 0)
{
GUI_MsgBoxOpen("Information","Loading State ...",1);
}
else
{
if (!sram.on)
if (!sram.on || (system_hw == SYSTEM_MCD))
{
GUI_WaitPrompt("Error","SRAM is disabled !");
return 0;
@ -254,13 +363,18 @@ int slot_load(int slot, int device)
GUI_MsgBoxOpen("Information","Loading SRAM ...",1);
}
/* Device Type */
if (!device)
{
/* FAT support */
/* FAT file */
if (slot > 0)
{
sprintf (filename,"%s/saves/%s.gp%d", DEFAULT_PATH, rom_filename, slot - 1);
}
else
{
sprintf (filename,"%s/saves/%s.srm", DEFAULT_PATH, rom_filename);
}
/* Open file */
FILE *fp = fopen(filename, "rb");
@ -270,14 +384,14 @@ int slot_load(int slot, int device)
return 0;
}
/* Read size */
/* Get file size */
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
/* allocate buffer */
savebuffer = (u8 *)memalign(32,filesize);
if (!savebuffer)
buffer = (u8 *)memalign(32,filesize);
if (!buffer)
{
GUI_WaitPrompt("Error","Unable to allocate memory !");
fclose(fp);
@ -287,23 +401,29 @@ int slot_load(int slot, int device)
/* Read into buffer (2k blocks) */
while (filesize > CHUNKSIZE)
{
fread(savebuffer + done, CHUNKSIZE, 1, fp);
fread(buffer + done, CHUNKSIZE, 1, fp);
done += CHUNKSIZE;
filesize -= CHUNKSIZE;
}
/* Read remaining bytes */
fread(savebuffer + done, filesize, 1, fp);
fread(buffer + done, filesize, 1, fp);
done += filesize;
/* Close file */
fclose(fp);
}
else
{
/* Memory Card support */
/* Memory Card file */
if (slot > 0)
{
sprintf(filename, "MD-%04X.gp%d", rominfo.realchecksum, slot - 1);
}
else
{
sprintf(filename, "MD-%04X.srm", rominfo.realchecksum);
}
/* Initialise the CARD system */
char action[64];
@ -342,7 +462,7 @@ int slot_load(int slot, int device)
return 0;
}
/* Retrieve file size */
/* Get file size */
filesize = CardFile.len;
if (filesize % SectorSize)
{
@ -350,8 +470,8 @@ int slot_load(int slot, int device)
}
/* Allocate buffer */
savebuffer = (u8 *)memalign(32,filesize);
if (!savebuffer)
u8 *in = (u8 *)memalign(32, filesize);
if (!in)
{
GUI_WaitPrompt("Error","Unable to allocate memory !");
CARD_Close(&CardFile);
@ -362,143 +482,164 @@ int slot_load(int slot, int device)
/* Read file sectors */
while (filesize > 0)
{
CARD_Read(&CardFile, &savebuffer[done], SectorSize, done);
CARD_Read(&CardFile, &in[done], SectorSize, done);
done += SectorSize;
filesize -= SectorSize;
}
/* Close file */
CARD_Close(&CardFile);
CARD_Unmount(device);
offset = 2112;
/* Uncompressed file size */
memcpy(&filesize, in + 2112, 4);
buffer = (u8 *)memalign(32, filesize);
if (!buffer)
{
free(in);
GUI_WaitPrompt("Error","Unable to allocate memory !");
return 0;
}
/* Uncompress file */
uncompress ((Bytef *)buffer, &filesize, (Bytef *)(in + 2112 + 4), done - 2112 - 4);
free(in);
}
if (slot > 0)
{
/* Uncompress state buffer */
u8 *state = (u8 *)memalign(32, STATE_SIZE);
if (!state)
{
free(savebuffer);
GUI_WaitPrompt("Error","Unable to allocate memory !");
return 0;
}
done = STATE_SIZE;
memcpy(&filesize, savebuffer + offset, 4);
uncompress ((Bytef *)state, &done, (Bytef *)(savebuffer + offset + 4), filesize);
/* Load state */
if (state_load(state) <= 0)
if (state_load(buffer) <= 0)
{
free(state);
free(savebuffer);
free(buffer);
GUI_WaitPrompt("Error","Invalid state file !");
return 0;
}
free(state);
}
else
{
/* Load SRAM & update CRC */
memcpy(sram.sram, &savebuffer[offset], 0x10000);
/* load SRAM */
memcpy(sram.sram, buffer, 0x10000);
/* update CRC */
sram.crc = crc32(0, sram.sram, 0x10000);
}
free(savebuffer);
free(buffer);
GUI_MsgBoxClose();
return 1;
}
int slot_save(int slot, int device)
{
char filename[MAXPATHLEN];
unsigned long filesize, done = 0;
int offset = device ? 2112 : 0;
u8 *savebuffer;
u8 *buffer;
if (slot > 0)
{
/* allocate buffers */
savebuffer = (u8 *)memalign(32,STATE_SIZE);
u8 *state = (u8 *)memalign(32,STATE_SIZE);
if (!savebuffer || !state)
GUI_MsgBoxOpen("Information","Saving State ...",1);
/* allocate buffer */
buffer = (u8 *)memalign(32,STATE_SIZE);
if (!buffer)
{
GUI_WaitPrompt("Error","Unable to allocate memory !");
return 0;
}
/* save state */
GUI_MsgBoxOpen("Information","Saving State ...",1);
done = state_save(state);
/* compress state file */
filesize = STATE_SIZE;
compress2 ((Bytef *)(savebuffer + offset + 4), &filesize, (Bytef *)state, done, 9);
memcpy(savebuffer + offset, &filesize, 4);
filesize += 4;
done = 0;
free(state);
filesize = state_save(buffer);
}
else
{
if (!sram.on)
/* only save if SRAM is enabled */
if (!sram.on || (system_hw == SYSTEM_MCD))
{
GUI_WaitPrompt("Error","SRAM is disabled !");
GUI_WaitPrompt("Error","SRAM disabled !");
return 0;
}
/* allocate buffer */
savebuffer = (u8 *)memalign(32,0x10000+offset);
if (!savebuffer)
/* only save if SRAM has been modified */
if (crc32(0, &sram.sram[0], 0x10000) == sram.crc)
{
GUI_WaitPrompt("Error","Unable to allocate memory !");
GUI_WaitPrompt("Warning","SRAM not modified !");
return 0;
}
GUI_MsgBoxOpen("Information","Saving SRAM ...",1);
memcpy(&savebuffer[offset], sram.sram, 0x10000);
sram.crc = crc32(0, sram.sram, 0x10000);
filesize = 0x10000;
/* allocate buffer */
buffer = (u8 *)memalign(32, 0x10000);
if (!buffer)
{
GUI_WaitPrompt("Error","Unable to allocate memory !");
return 0;
}
/* copy SRAM data */
memcpy(buffer, sram.sram, 0x10000);
filesize = 0x10000;
/* update CRC */
sram.crc = crc32(0, sram.sram, 0x10000);
}
/* Device Type */
if (!device)
{
/* FAT support */
/* FAT filename */
if (slot > 0)
{
sprintf(filename, "%s/saves/%s.gp%d", DEFAULT_PATH, rom_filename, slot - 1);
}
else
{
sprintf(filename, "%s/saves/%s.srm", DEFAULT_PATH, rom_filename);
}
/* Open file */
FILE *fp = fopen(filename, "wb");
if (!fp)
{
GUI_WaitPrompt("Error","Unable to open file !");
free(savebuffer);
free(buffer);
return 0;
}
/* Write from buffer (2k blocks) */
while (filesize > CHUNKSIZE)
{
fwrite(savebuffer + done, CHUNKSIZE, 1, fp);
fwrite(buffer + done, CHUNKSIZE, 1, fp);
done += CHUNKSIZE;
filesize -= CHUNKSIZE;
}
/* Write remaining bytes */
fwrite(savebuffer + done, filesize, 1, fp);
fwrite(buffer + done, filesize, 1, fp);
done += filesize;
/* Close file */
fclose(fp);
free(buffer);
/* Save state screenshot */
if (slot > 0)
{
sprintf(filename,"%s/saves/%s__%d.png", DEFAULT_PATH, rom_filename, slot - 1);
gxSaveScreenshot(filename);
}
}
else
{
/* Memory Card support */
/* Memory Card filename */
if (slot > 0)
{
sprintf(filename, "MD-%04X.gp%d", rominfo.realchecksum, slot - 1);
}
else
{
sprintf(filename, "MD-%04X.srm", rominfo.realchecksum);
}
/* Initialise the CARD system */
char action[64];
@ -512,11 +653,11 @@ int slot_save(int slot, int device)
if (!CardMount(device))
{
GUI_WaitPrompt("Error","Unable to mount memory card");
free(savebuffer);
free(buffer);
return 0;
}
/* Retrieve the sector size */
/* Retrieve sector size */
u32 SectorSize = 0;
int CardError = CARD_GetSectorSize(device, &SectorSize);
if (!SectorSize)
@ -524,18 +665,35 @@ int slot_save(int slot, int device)
sprintf(action, "Invalid sector size (%d)", CardError);
GUI_WaitPrompt("Error",action);
CARD_Unmount(device);
free(savebuffer);
free(buffer);
return 0;
}
/* Build the output buffer */
/* Build output buffer */
u8 *out = (u8 *)memalign(32, filesize + 2112 + 4);
if (!out)
{
GUI_WaitPrompt("Error","Unable to allocate memory !");
CARD_Unmount(device);
free(buffer);
return 0;
}
/* Memory Card file header */
char comment[2][32] = { {"Genesis Plus GX"}, {"SRAM Save"} };
strcpy (comment[1], filename);
memcpy (&savebuffer[0], &icon, 2048);
memcpy (&savebuffer[2048], &comment[0], 64);
memcpy (&out[0], &icon, 2048);
memcpy (&out[2048], &comment[0], 64);
/* uncompressed size */
done = filesize;
memcpy(&out[2112], &done, 4);
/* compress file */
compress2 ((Bytef *)&out[2112 + 4], &filesize, (Bytef *)buffer, done, 9);
/* Adjust file size */
filesize += 2112;
filesize = filesize + 4 + 2112;
if (filesize % SectorSize)
{
filesize = ((filesize / SectorSize) + 1) * SectorSize;
@ -558,7 +716,8 @@ int slot_save(int slot, int device)
sprintf(action, "Unable to increase file size (%d)", CardError);
GUI_WaitPrompt("Error",action);
CARD_Unmount(device);
free(savebuffer);
free(out);
free(buffer);
return 0;
}
@ -579,7 +738,8 @@ int slot_save(int slot, int device)
sprintf(action, "Unable to create file (%d)", CardError);
GUI_WaitPrompt("Error",action);
CARD_Unmount(device);
free(savebuffer);
free(out);
free(buffer);
return 0;
}
@ -598,7 +758,7 @@ int slot_save(int slot, int device)
/* Write file sectors */
while (filesize > 0)
{
CARD_Write(&CardFile, &savebuffer[done], SectorSize, done);
CARD_Write(&CardFile, &out[done], SectorSize, done);
filesize -= SectorSize;
done += SectorSize;
}
@ -606,17 +766,10 @@ int slot_save(int slot, int device)
/* Close file */
CARD_Close(&CardFile);
CARD_Unmount(device);
free(out);
free(buffer);
}
GUI_MsgBoxClose();
free(savebuffer);
/* Save screenshot */
if (slot && !device)
{
sprintf(filename,"%s/saves/%s__%d.png", DEFAULT_PATH, rom_filename, slot - 1);
gxSaveScreenshot(filename);
}
return 1;
}

View File

@ -3,7 +3,7 @@
*
* FAT and Memory Card SRAM/Savestate files managment
*
* Copyright Eke-Eke (2008-2011), based on original code from Softdev (2006)
* Copyright Eke-Eke (2008-2012), based on original code from Softdev (2006)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -4,7 +4,7 @@
* Load a normal file, or ZIP/GZ archive into ROM buffer.
* Returns loaded ROM size (zero if an error occured).
*
* Copyright Eke-Eke (2007-2011), based on original work from Softdev (2006)
* Copyright Eke-Eke (2007-2012), based on original work from Softdev (2006)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -113,26 +113,34 @@ void get_zipfilename(char *filename)
fclose(fd);
}
int load_archive(char *filename)
int load_archive(char *filename, unsigned char *buffer, int maxsize)
{
int size = 0;
char in[CHUNKSIZE];
char msg[64];
/* ROM buffer should be allocated first ! */
unsigned char *buf = cart.rom;
char msg[64] = "Unable to open file";
/* Open file */
FILE *fd = fopen(filename, "rb");
if (!fd)
/* Master System & Game Gear BIOS are optional files */
if (!strcmp(filename,MS_BIOS_US) || !strcmp(filename,MS_BIOS_EU) || !strcmp(filename,MS_BIOS_JP) || !strcmp(filename,GG_BIOS))
{
GUI_WaitPrompt("Error","Unable to open file !");
return 0;
/* disable all messages */
SILENT = 1;
}
/* clear existing patches before loading new ROM file */
ggenie_shutdown();
areplay_shutdown();
/* Mega CD BIOS are required files */
if (!strcmp(filename,CD_BIOS_US) || !strcmp(filename,CD_BIOS_EU) || !strcmp(filename,CD_BIOS_JP))
{
sprintf(msg,"Unable to open CD BIOS");
}
if (!fd)
{
GUI_WaitPrompt("Error", msg);
SILENT = 0;
return 0;
}
/* Read first chunk */
fread(in, CHUNKSIZE, 1, fd);
@ -150,10 +158,11 @@ int load_archive(char *filename)
size = FLIP32(pkzip->uncompressedSize);
/* Check ROM size */
if (size > MAXROMSIZE)
if (size > maxsize)
{
fclose(fd);
GUI_WaitPrompt("Error","File is too large !");
GUI_WaitPrompt("Error","File is too large");
SILENT = 0;
return 0;
}
@ -173,7 +182,8 @@ int load_archive(char *filename)
if (res != Z_OK)
{
fclose(fd);
GUI_WaitPrompt("Error","Unable to unzip file !");
GUI_WaitPrompt("Error","Unable to unzip file");
SILENT = 0;
return 0;
}
@ -184,7 +194,7 @@ int load_archive(char *filename)
/* Initial Zip remaining chunk size */
zs.avail_in = CHUNKSIZE - offset;
/* Get compressed file name */
/* Overwrite input filename with compressed filename */
offset = FLIP16(pkzip->filenameLength);
if (offset >= MAXPATHLEN) offset = MAXPATHLEN - 1;
strncpy(filename, &in[sizeof(PKZIPHEADER)], offset);
@ -204,15 +214,16 @@ int load_archive(char *filename)
{
inflateEnd(&zs);
fclose(fd);
GUI_WaitPrompt("Error","Unable to unzip file !");
GUI_WaitPrompt("Error","Unable to unzip file");
SILENT = 0;
return 0;
}
offset = CHUNKSIZE - zs.avail_out;
if (offset)
{
memcpy(buf, out, offset);
buf += offset;
memcpy(buffer, out, offset);
buffer += offset;
}
}
while (zs.avail_out == 0);
@ -232,11 +243,12 @@ int load_archive(char *filename)
size = ftell(fd);
fseek(fd, 0, SEEK_SET);
/* Check file size */
if(size > MAXROMSIZE)
/* size limit */
if(size > maxsize)
{
fclose(fd);
GUI_WaitPrompt("Error","File is too large !");
GUI_WaitPrompt("Error","File is too large");
SILENT = 0;
return 0;
}
@ -247,13 +259,13 @@ int load_archive(char *filename)
int left = size;
while (left > CHUNKSIZE)
{
fread(buf, CHUNKSIZE, 1, fd);
buf += CHUNKSIZE;
fread(buffer, CHUNKSIZE, 1, fd);
buffer += CHUNKSIZE;
left -= CHUNKSIZE;
}
/* Read remaining bytes */
fread(buf, left, 1, fd);
fread(buffer, left, 1, fd);
}
/* Close file */
@ -261,5 +273,6 @@ int load_archive(char *filename)
/* Return loaded ROM size */
GUI_MsgBoxClose();
SILENT = 0;
return size;
}

View File

@ -4,7 +4,7 @@
* Load a normal file, or ZIP/GZ archive into ROM buffer.
* Returns loaded ROM size (zero if an error occured).
*
* Copyright Eke-Eke (2007-2011), based on original work from Softdev (2006)
* Copyright Eke-Eke (2007-2012), based on original work from Softdev (2006)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -42,6 +42,6 @@
#define _FILEIO_H_
/* Function prototypes */
int load_archive(char *filename);
int load_archive(char *filename, unsigned char *buffer, int maxsize);
#endif /* _FILEIO_H_ */

View File

@ -3,7 +3,7 @@
*
* Generic ROM history list managment
*
* Copyright Eke-Eke (2008-2011), based on original code from Martin Disibio (2008)
* Copyright Eke-Eke (2008-2012), based on original code from Martin Disibio (2008)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -3,7 +3,7 @@
*
* Generic ROM history list managment
*
* Copyright Eke-Eke (2008-2011), based on original code from Martin Disibio (2008)
* Copyright Eke-Eke (2008-2012), based on original code from Martin Disibio (2008)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -3,7 +3,7 @@
*
* Cheats menu
*
* Copyright Eke-Eke (2010-2011)
* Copyright Eke-Eke (2010-2012)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -42,10 +42,6 @@
#include "font.h"
#include "gui.h"
#ifdef HW_RVL
#include <wiiuse/wpad.h>
#endif
#define BG_COLOR_1 {0x49,0x49,0x49,0xff}
#define BG_COLOR_2 {0x66,0x66,0x66,0xff}

View File

@ -3,7 +3,7 @@
*
* Cheats menu
*
* Copyright Eke-Eke (2010-2011)
* Copyright Eke-Eke (2010-2012)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -3,7 +3,7 @@
*
* ROM File Browser
*
* Copyright Eke-Eke (2009-2011)
* Copyright Eke-Eke (2009-2012)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -44,10 +44,6 @@
#include "file_load.h"
#include "history.h"
#ifdef HW_RVL
#include <wiiuse/wpad.h>
#endif
#define BG_COLOR_1 {0x49,0x49,0x49,0xff}
#define BG_COLOR_2 {0x66,0x66,0x66,0xff}
@ -107,7 +103,7 @@ static gui_item action_select =
/*****************************************************************************/
/* GUI Background images */
/*****************************************************************************/
static gui_image bg_filesel[13] =
static gui_image bg_filesel[14] =
{
{NULL,Bg_layer_png,IMAGE_VISIBLE|IMAGE_REPEAT,0,0,640,480,255},
{NULL,Bg_overlay_png,IMAGE_VISIBLE|IMAGE_REPEAT,0,0,640,480,255},
@ -119,22 +115,25 @@ static gui_image bg_filesel[13] =
{NULL,Snap_empty_png,IMAGE_VISIBLE,424,148,160,112,255},
{NULL,NULL,0,424,148,160,112,255},
{NULL,NULL,0,388,147,240,152,255},
{NULL,NULL,0,388,147,240,152,255},
{NULL,NULL,0,392,118,232,148,255},
{NULL,NULL,0,414,116,184,188,255},
{NULL,NULL,0,416,144,180,228,255}
};
static const u8 *Cart_png[4] =
static const u8 *Cart_png[FILETYPE_MAX] =
{
Cart_md_png,
Cart_md_png,
Cart_ms_png,
Cart_gg_png,
Cart_sg_png
};
static const char *Cart_dir[4] =
static const char *Cart_dir[FILETYPE_MAX] =
{
"md",
"cd",
"ms",
"gg",
"sg"
@ -147,7 +146,7 @@ static gui_menu menu_selector =
{
"Game Selection",
-1,-1,
0,0,13,0,
0,0,14,0,
NULL,
NULL,
bg_filesel,
@ -289,27 +288,27 @@ int FileSelector(int type)
}
/* Hide all cartridge labels */
bg_filesel[9].state &= ~IMAGE_VISIBLE;
bg_filesel[10].state &= ~IMAGE_VISIBLE;
bg_filesel[11].state &= ~IMAGE_VISIBLE;
bg_filesel[12].state &= ~IMAGE_VISIBLE;
for (i=0; i<FILETYPE_MAX; i++)
{
bg_filesel[9+i].state &= ~IMAGE_VISIBLE;
}
/* Cartridge type */
if (type < 0)
{
/* Recent game list -> select all cartridge type */
bg_filesel[9].data = Cart_png[0];
bg_filesel[10].data = Cart_png[1];
bg_filesel[11].data = Cart_png[2];
bg_filesel[12].data = Cart_png[3];
for (i=0; i<FILETYPE_MAX; i++)
{
bg_filesel[9+i].data = Cart_png[i];
}
}
else
{
/* Clear all cartridges type */
bg_filesel[9].data = NULL;
bg_filesel[10].data = NULL;
bg_filesel[11].data = NULL;
bg_filesel[12].data = NULL;
for (i=0; i<FILETYPE_MAX; i++)
{
bg_filesel[9+i].data = NULL;
}
/* Select cartridge type */
bg_filesel[9 + type].data = Cart_png[type];
@ -338,12 +337,12 @@ int FileSelector(int type)
if (type < 0)
{
/* hide all cartridge labels */
bg_filesel[9].state &= ~IMAGE_VISIBLE;
bg_filesel[10].state &= ~IMAGE_VISIBLE;
bg_filesel[11].state &= ~IMAGE_VISIBLE;
bg_filesel[12].state &= ~IMAGE_VISIBLE;
for (i=0; i<FILETYPE_MAX; i++)
{
bg_filesel[9+i].state &= ~IMAGE_VISIBLE;
}
/* detect cartridge type (0-3) */
/* detect cartridge type */
type = history.entries[selection].filetype;
/* show selected cartridge label */
@ -397,7 +396,7 @@ int FileSelector(int type)
else
{
/* this is a ROM file */
strcpy(action_select.comment,"Load ROM File");
strcpy(action_select.comment,"Load File");
}
/* Draw menu*/

View File

@ -3,7 +3,7 @@
*
* ROM File Browser
*
* Copyright Eke-Eke (2009-2011)
* Copyright Eke-Eke (2009-2012)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -40,10 +40,6 @@
#ifndef _GUI_H
#define _GUI_H
#ifdef HW_RVL
#include <wiiuse/wpad.h>
#endif
#define BG_COLOR_MAX 15
/*****************************************************************************/
@ -245,6 +241,5 @@ extern void GUI_WaitPrompt(char *title, char *msg);
extern void GUI_FadeOut();
extern GXColor *GUI_GetBgColor(void);
extern void GUI_SetBgColor(u8 color);
extern void GUI_Initialize(void);
#endif

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX Disclaimer
*
* Copyright Eke-Eke (2009-2011)
* Copyright Eke-Eke (2009-2012)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX menu
*
* Copyright Eke-Eke (2009-2011)
* Copyright Eke-Eke (2009-2012)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -38,21 +38,21 @@
****************************************************************************************/
#include "shared.h"
#include "menu.h"
#include "font.h"
#include "gui.h"
#include "filesel.h"
#include "cheats.h"
#include "file_load.h"
#include "file_slot.h"
#include <ogc/lwp_threads.h>
#include <ogc/lwp_watchdog.h>
#include "md_eeprom.h"
#ifdef HW_RVL
#include <ogc/usbmouse.h>
#endif
#include <ogc/lwp_threads.h>
#include <ogc/lwp_watchdog.h>
/* Credits */
extern const u8 Bg_credits_png[];
@ -84,6 +84,7 @@ extern const u8 Load_md_png[];
extern const u8 Load_ms_png[];
extern const u8 Load_gg_png[];
extern const u8 Load_sg_png[];
extern const u8 Load_cd_png[];
/* Save Manager menu */
extern const u8 Button_load_png[];
@ -280,7 +281,7 @@ static gui_item items_main[10] =
{NULL,Main_options_png ,"","",290,166,60,88},
{NULL,Main_quit_png ,"","",460,170,52,84},
{NULL,Main_file_png ,"","",114,216,80,92},
{NULL,Main_reset_png ,"","",282,224,76,84},
{NULL,Main_reset_png ,"","",294,227,52,80},
{NULL,Main_cheats_png ,"","",454,218,64,92},
{NULL,NULL ,"","", 10,334,84,32},
#ifdef HW_RVL
@ -311,13 +312,14 @@ static gui_item items_ctrls[13] =
};
/* Load menu */
static gui_item items_load[5] =
static gui_item items_load[6] =
{
{NULL,Load_recent_png,"","Load recently played games", 200,144,72, 92},
{NULL,Load_md_png, "","Load Mega Drive/Genesis games", 362,141,84, 92},
{NULL,Load_recent_png,"","Load recently played games", 119,144,72, 92},
{NULL,Load_md_png, "","Load Mega Drive/Genesis games", 278,141,84, 92},
{NULL,Load_cd_png, "","Load Sega/Mega CD games", 454,141,64, 92},
{NULL,Load_ms_png, "","Load Master System games", 114,284,84, 96},
{NULL,Load_gg_png, "","Load Game Gear games", 278,283,84,100},
{NULL,Load_sg_png, "","Load SG-1000 games", 455,281,64, 96}
{NULL,Load_sg_png, "","Load SG-1000 games", 454,281,64, 96}
};
/* Option menu */
@ -388,10 +390,10 @@ static gui_item items_video[9] =
/* Menu options */
static gui_item items_prefs[9] =
{
{NULL,NULL,"Auto ROM Load: OFF","Enable/Disable automatic ROM loading on startup", 56,132,276,48},
{NULL,NULL,"Auto ROM Load: OFF", "Enable/Disable automatic ROM loading on startup", 56,132,276,48},
{NULL,NULL,"Auto Cheats: OFF", "Enable/Disable automatic cheats activation", 56,132,276,48},
{NULL,NULL,"Auto Saves: OFF", "Enable/Disable automatic saves", 56,132,276,48},
{NULL,NULL,"ROM Device: SD", "Configure default device for ROM files", 56,132,276,48},
{NULL,NULL,"ROM Load Device: SD", "Configure default device for ROM files", 56,132,276,48},
{NULL,NULL,"Saves Device: FAT", "Configure default device for Save files", 56,132,276,48},
{NULL,NULL,"SFX Volume: 100", "Adjust sound effects volume", 56,132,276,48},
{NULL,NULL,"BGM Volume: 100", "Adjust background music volume", 56,132,276,48},
@ -464,12 +466,13 @@ static gui_butn buttons_ctrls[13] =
};
/* Load Game menu */
static gui_butn buttons_load[5] =
static gui_butn buttons_load[6] =
{
{&button_icon_data,BUTTON_VISIBLE|BUTTON_ACTIVE|BUTTON_OVER_SFX|BUTTON_SELECT_SFX,{0,2,0,1},162,120,148,132},
{&button_icon_data,BUTTON_VISIBLE|BUTTON_ACTIVE|BUTTON_OVER_SFX|BUTTON_SELECT_SFX,{0,2,1,0},330,120,148,132},
{&button_icon_data,BUTTON_VISIBLE|BUTTON_ACTIVE|BUTTON_OVER_SFX|BUTTON_SELECT_SFX,{2,0,0,1}, 80,264,148,132},
{&button_icon_data,BUTTON_VISIBLE|BUTTON_ACTIVE|BUTTON_OVER_SFX|BUTTON_SELECT_SFX,{2,0,1,1},246,264,148,132},
{&button_icon_data,BUTTON_VISIBLE|BUTTON_ACTIVE|BUTTON_OVER_SFX|BUTTON_SELECT_SFX,{0,3,0,1}, 80,120,148,132},
{&button_icon_data,BUTTON_VISIBLE|BUTTON_ACTIVE|BUTTON_OVER_SFX|BUTTON_SELECT_SFX,{0,3,1,1},246,120,148,132},
{&button_icon_data,BUTTON_VISIBLE|BUTTON_ACTIVE|BUTTON_OVER_SFX|BUTTON_SELECT_SFX,{0,3,1,0},412,120,148,132},
{&button_icon_data,BUTTON_VISIBLE|BUTTON_ACTIVE|BUTTON_OVER_SFX|BUTTON_SELECT_SFX,{3,0,0,1}, 80,264,148,132},
{&button_icon_data,BUTTON_VISIBLE|BUTTON_ACTIVE|BUTTON_OVER_SFX|BUTTON_SELECT_SFX,{3,0,1,1},246,264,148,132},
{&button_icon_data,BUTTON_VISIBLE|BUTTON_ACTIVE|BUTTON_OVER_SFX|BUTTON_SELECT_SFX,{3,0,1,0},412,264,148,132}
};
@ -534,7 +537,7 @@ static gui_menu menu_load =
{
"Load Game",
0,0,
5,5,5,0,
6,6,5,0,
items_load,
buttons_load,
bg_misc,
@ -658,12 +661,12 @@ static void prefmenu ()
else if (config.s_auto == 1) sprintf (items[2].text, "Auto Saves: SRAM ONLY");
else sprintf (items[2].text, "Auto Saves: NONE");
#ifdef HW_RVL
if (config.l_device == 1) sprintf (items[3].text, "Default ROM Device: USB");
else if (config.l_device == 2) sprintf (items[3].text, "Default ROM Device: DVD");
if (config.l_device == 1) sprintf (items[3].text, "ROM Load Device: USB");
else if (config.l_device == 2) sprintf (items[3].text, "ROM Load Device: DVD");
#else
if (config.l_device == 1) sprintf (items[3].text, "Default ROM Device: DVD");
if (config.l_device == 1) sprintf (items[3].text, "ROM Load Device: DVD");
#endif
else sprintf (items[3].text, "Default ROM Device: SD");
else sprintf (items[3].text, "ROM Load Device: SD");
if (config.s_device == 1) sprintf (items[4].text, "Saves Device: MCARD A");
else if (config.s_device == 2) sprintf (items[4].text, "Saves Device: MCARD B");
else sprintf (items[4].text, "Saves Device: FAT");
@ -702,13 +705,13 @@ static void prefmenu ()
case 3: /*** Default ROM device ***/
#ifdef HW_RVL
config.l_device = (config.l_device + 1) % 3;
if (config.l_device == 1) sprintf (items[3].text, "Default ROM Device: USB");
else if (config.l_device == 2) sprintf (items[3].text, "Default ROM Device: DVD");
if (config.l_device == 1) sprintf (items[3].text, "ROM Load Device: USB");
else if (config.l_device == 2) sprintf (items[3].text, "ROM Load Device: DVD");
#else
config.l_device ^= 1;
if (config.l_device == 1) sprintf (items[3].text, "Default ROM Device: DVD");
if (config.l_device == 1) sprintf (items[3].text, "ROM Load Device: DVD");
#endif
else sprintf (items[3].text, "Default ROM Device: SD");
else sprintf (items[3].text, "ROM Load Device: SD");
break;
case 4: /*** Default saves device ***/
@ -761,6 +764,27 @@ static void prefmenu ()
}
}
/* stop DVD drive when not in use */
if (config.l_device != 2)
{
#ifdef HW_RVL
DI_StopMotor();
#else
vu32* const dvd = (u32*)0xCC006000;
dvd[0] = 0x2e;
dvd[1] = 0;
dvd[2] = 0xe3000000;
dvd[3] = 0;
dvd[4] = 0;
dvd[5] = 0;
dvd[6] = 0;
dvd[7] = 1;
while (dvd[7] & 1);
dvd[0] = 0x14;
dvd[1] = 0;
#endif
}
GUI_DeleteMenu(m);
}
@ -894,7 +918,7 @@ static void soundmenu ()
else sprintf (items[0].text, "Master System FM: AUTO");
/* Automatic detection */
if ((config.ym2413 & 2) && cart.romsize && ((system_hw & SYSTEM_PBC) != SYSTEM_MD))
if ((config.ym2413 & 2) && system_hw && ((system_hw & SYSTEM_PBC) != SYSTEM_MD))
{
/* detect if game is using YM2413 */
sms_cart_init();
@ -1041,7 +1065,7 @@ static void soundmenu ()
}
}
if (reinit && cart.romsize)
if (reinit && system_hw)
{
audio_init(snd.sample_rate, snd.frame_rate);
sound_restore();
@ -1234,12 +1258,8 @@ static void systemmenu ()
else if (config.region_detect == 3)
sprintf (items[1].text, "Console Region: JAPAN");
if (cart.romsize)
{
/* force system reinitialization */
reinit = 1;
}
/* force system reinitialization + region BIOS */
reinit = 2;
break;
}
@ -1253,12 +1273,8 @@ static void systemmenu ()
else if (config.vdp_mode == 2)
sprintf (items[2].text, "VDP Mode: PAL");
if (cart.romsize)
{
/* force system reinitialization */
reinit = 1;
}
break;
}
@ -1272,23 +1288,18 @@ static void systemmenu ()
else if (config.master_clock == 2)
sprintf (items[3].text, "System Clock: PAL");
if (cart.romsize)
{
/* force system reinitialization */
reinit = 1;
}
break;
}
case 4: /*** BIOS support ***/
{
uint8 temp = config.bios & 3;
config.bios &= ~3;
if (temp == 0) config.bios |= 3;
else if (temp == 3) config.bios |= 1;
if (config.bios == 0) config.bios = 3;
else if (config.bios == 3) config.bios = 1;
else config.bios = 0;
sprintf (items[4].text, "System Boot: %s", (config.bios & 1) ? ((config.bios & 2) ? "BIOS&CART " : "BIOS ONLY") : "CART");
if (cart.romsize && ((system_hw == SYSTEM_MD) || (system_hw & SYSTEM_GG) || (system_hw & SYSTEM_SMS)))
if ((system_hw == SYSTEM_MD) || (system_hw & SYSTEM_GG) || (system_hw & SYSTEM_SMS))
{
/* force hard reset */
system_init();
@ -1313,7 +1324,7 @@ static void systemmenu ()
case 6: /*** 68k Address Error ***/
{
config.addr_error ^= 1;
if (cart.romsize && ((system_hw & SYSTEM_PBC) == SYSTEM_MD))
if (((system_hw & SYSTEM_PBC) == SYSTEM_MD) && (system_hw != SYSTEM_MCD))
{
/* reinitialize cartridge hardware (UMK3 hack support) */
md_cart_init();
@ -1340,7 +1351,7 @@ static void systemmenu ()
else
sprintf (items[7].text, "Lock-On: OFF");
if (cart.romsize && ((system_hw & SYSTEM_PBC) == SYSTEM_MD))
if ((system_hw == SYSTEM_MD) || (system_hw == SYSTEM_PICO))
{
/* force hard reset */
system_init();
@ -1397,16 +1408,31 @@ static void systemmenu ()
}
}
if (reinit)
if (reinit && system_hw)
{
/* reinitialize console region */
region_autodetect();
get_region(0);
/* framerate has changed, reinitialize audio timings */
audio_init(snd.sample_rate, get_framerate());
/* system with region BIOS should be reinitialized if region code has changed */
if ((reinit & 2) && ((system_hw == SYSTEM_MCD) || ((system_hw & SYSTEM_SMS) && (config.bios & 1))))
{
system_init();
system_reset();
}
else
{
/* reinitialize I/O region register */
if (system_hw == SYSTEM_MD)
{
io_reg[0x00] = 0x20 | region_code | (config.bios & 1);
}
else if (system_hw == SYSTEM_MCD)
{
io_reg[0x00] = region_code | (config.bios & 1);
}
else
{
io_reg[0x00] = 0x80 | (region_code >> 1);
@ -1438,12 +1464,10 @@ static void systemmenu ()
break;
}
/* framerate has changed, reinitialize audio timings */
audio_init(snd.sample_rate, get_framerate());
/* reinitialize sound emulation */
sound_restore();
}
}
GUI_DeleteMenu(m);
}
@ -1609,7 +1633,7 @@ static void videomenu ()
break;
case 5: /*** VIDEO Gamma correction ***/
if (cart.romsize)
if (system_hw)
{
update_gamma();
state[0] = m->arrows[0]->state;
@ -1692,7 +1716,7 @@ static void videomenu ()
break;
case VI_OFFSET+3: /*** screen position ***/
if (cart.romsize)
if (system_hw)
{
state[0] = m->arrows[0]->state;
state[1] = m->arrows[1]->state;
@ -1720,7 +1744,7 @@ static void videomenu ()
break;
case VI_OFFSET+4: /*** screen scaling ***/
if (cart.romsize)
if (system_hw)
{
state[0] = m->arrows[0]->state;
state[1] = m->arrows[1]->state;
@ -1753,7 +1777,7 @@ static void videomenu ()
}
}
if (cart.romsize && reinit)
if (reinit && system_hw)
{
/* framerate has changed, reinitialize audio timings */
audio_init(snd.sample_rate, get_framerate());
@ -2047,7 +2071,7 @@ static void ctrlmenu(void)
case 0: /* update port 1 system */
{
/* fixed configurations */
if (cart.romsize)
if (system_hw)
{
if (cart.special & HW_TEREBI_OEKAKI)
{
@ -2140,7 +2164,7 @@ static void ctrlmenu(void)
case 1: /* update port 2 system */
{
/* fixed configurations */
if (cart.romsize)
if (system_hw)
{
if (cart.special & HW_J_CART)
{
@ -3397,10 +3421,10 @@ void mainmenu(void)
char filename[MAXPATHLEN];
int status, quit = 0;
/* Autosave SRAM */
if (config.s_auto & 1)
if ((config.s_auto & 1) || (system_hw == SYSTEM_MCD))
{
slot_autosave(0,config.s_device);
/* Autosave Backup RAM */
slot_autosave(0, config.s_device);
}
#ifdef HW_RVL
@ -3438,7 +3462,7 @@ void mainmenu(void)
bg_saves[2].state &= ~IMAGE_VISIBLE;
}
if (cart.romsize)
if (system_hw)
{
m->screenshot = 128;
m->bg_images[0].state &= ~IMAGE_VISIBLE;
@ -3553,7 +3577,7 @@ void mainmenu(void)
break;
}
/*** Virtual system hard reset ***/
/*** Soft / Hard reset ***/
case 4:
{
/* check current controller configuration */
@ -3568,6 +3592,20 @@ void mainmenu(void)
GUI_DeleteMenu(m);
gxClearScreen((GXColor)BLACK);
gxSetScreen();
if (system_hw & SYSTEM_MD)
{
/* Soft Reset */
gen_reset(0);
}
else if (system_hw == SYSTEM_SMS)
{
/* assert RESET input (Master System model 1 only) */
io_reg[0x0D] &= ~IO_RESET_HI;
}
else
{
/* Hard Reset */
system_init();
system_reset();
@ -3576,6 +3614,7 @@ void mainmenu(void)
{
slot_autoload(0,config.s_device);
}
}
/* exit to game */
quit = 1;
@ -3611,7 +3650,7 @@ void mainmenu(void)
case 7:
case -1:
{
if (cart.romsize)
if (system_hw)
{
/* check current controller configuration */
if (!gx_input_FindDevices())

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX menus
*
* Copyright Eke-Eke (2009-2011)
* Copyright Eke-Eke (2009-2012)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX audio support
*
* Copyright Eke-Eke (2007-2011), based on original work from Softdev (2006)
* Copyright Eke-Eke (2007-2012), based on original work from Softdev (2006)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX audio support
*
* Copyright Eke-Eke (2007-2011), based on original work from Softdev (2006)
* Copyright Eke-Eke (2007-2012), based on original work from Softdev (2006)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX input support
*
* Copyright Eke-Eke (2007-2011)
* Copyright Eke-Eke (2007-2012)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -413,10 +413,10 @@ static void pad_update(s8 chan, u8 i)
}
/* D-PAD */
if (p & PAD_BUTTON_UP) input.pad[i] |= INPUT_UP;
else if (p & PAD_BUTTON_DOWN) input.pad[i] |= INPUT_DOWN;
if (p & PAD_BUTTON_LEFT) input.pad[i] |= INPUT_LEFT;
else if (p & PAD_BUTTON_RIGHT) input.pad[i] |= INPUT_RIGHT;
if (p & PAD_BUTTON_UP) input.pad[0] |= INPUT_UP;
else if (p & PAD_BUTTON_DOWN) input.pad[0] |= INPUT_DOWN;
if (p & PAD_BUTTON_LEFT) input.pad[0] |= INPUT_LEFT;
else if (p & PAD_BUTTON_RIGHT) input.pad[0] |= INPUT_RIGHT;
/* PEN screen position (x,y) */
input.analog[0][0] += x / ANALOG_SENSITIVITY;
@ -428,9 +428,14 @@ static void pad_update(s8 chan, u8 i)
if (input.analog[0][1] < 0x1fc) input.analog[0][1] = 0x1fc;
else if (input.analog[0][1] > 0x3f3) input.analog[0][1] = 0x3f3;
/* PEN & RED buttons */
if (p & pad_keymap[KEY_BUTTONA]) input.pad[i] |= INPUT_A;
if (p & pad_keymap[KEY_BUTTONB]) input.pad[i] |= INPUT_B;
/* PEN button */
if (p & pad_keymap[KEY_BUTTONA]) input.pad[0] |= INPUT_PICO_RED;
/* RED button */
if (p & pad_keymap[KEY_BUTTONB]) input.pad[0] |= INPUT_PICO_PEN;
/* PAGE index increment */
if (p & pad_keymap[KEY_BUTTONC]) pico_current = (pico_current + 1) & 7;
break;
}
@ -455,7 +460,7 @@ static void pad_update(s8 chan, u8 i)
else if (input.analog[0][1] > 250) input.analog[0][1] = 250;
/* PEN button */
if (p & pad_keymap[KEY_BUTTONA]) input.pad[i] |= INPUT_B;
if (p & pad_keymap[KEY_BUTTONA]) input.pad[0] |= INPUT_BUTTON1;
break;
}
@ -1016,9 +1021,14 @@ static void wpad_update(s8 chan, u8 i, u32 exp)
}
}
/* PEN & RED buttons */
if (p & wpad_keymap[KEY_BUTTONA]) input.pad[i] |= INPUT_A;
if (p & wpad_keymap[KEY_BUTTONB]) input.pad[i] |= INPUT_B;
/* PEN button */
if (p & wpad_keymap[KEY_BUTTONA]) input.pad[0] |= INPUT_PICO_PEN;
/* RED button */
if (p & wpad_keymap[KEY_BUTTONB]) input.pad[0] |= INPUT_PICO_RED;
/* PAGE index increment */
if (p & wpad_keymap[KEY_BUTTONC]) pico_current = (pico_current + 1) & 7;
break;
}
@ -1048,7 +1058,7 @@ static void wpad_update(s8 chan, u8 i, u32 exp)
}
/* PEN button */
if (p & wpad_keymap[KEY_BUTTONA]) input.pad[i] |= INPUT_B;
if (p & wpad_keymap[KEY_BUTTONA]) input.pad[0] |= INPUT_BUTTON1;
break;
}

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX input support
*
* Copyright Eke-Eke (2007-2011)
* Copyright Eke-Eke (2007-2012)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX video & rendering support
*
* Copyright Eke-Eke (2007-2011), based on original work from Softdev (2006)
* Copyright Eke-Eke (2007-2012), based on original work from Softdev (2006)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -3,7 +3,7 @@
*
* Genesis Plus GX video support
*
* Copyright Eke-Eke (2007-2011), based on original work from Softdev (2006)
* Copyright Eke-Eke (2007-2012), based on original work from Softdev (2006)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -67,6 +67,7 @@ u32 delta_time[LOGSIZE];
u32 delta_samp[LOGSIZE];
#endif
#ifdef HW_RVL
/****************************************************************************
* Power Button callback
@ -101,14 +102,11 @@ static void Reset_cb(void)
***************************************************************************/
static void init_machine(void)
{
/* allocate cartridge ROM here (10 MB) */
cart.rom = memalign(32, MAXROMSIZE);
/* system is not initialized */
config.hot_swap &= 0x01;
/* BIOS are unloaded */
config.bios &= 0x03;
/* mark all BIOS as unloaded */
system_bios = 0;
/* Genesis BOOT ROM support (2KB max) */
memset(boot_rom, 0xFF, 0x800);
@ -123,7 +121,7 @@ static void init_machine(void)
if (!strncmp((char *)(boot_rom + 0x120),"GENESIS OS", 10))
{
/* mark Genesis BIOS as loaded */
config.bios |= SYSTEM_MD;
system_bios = SYSTEM_MD;
}
}
@ -145,9 +143,60 @@ static void run_emulation(void)
while (1)
{
/* emulated system */
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
if (system_hw == SYSTEM_MCD)
{
/* Mega Drive type hardware */
/* 16-bit hardware + CD */
while (!ConfigRequested)
{
/* automatic frame skipping */
if (frameticker > 1)
{
/* skip frame */
system_frame_scd(1);
frameticker = 1;
}
else
{
/* render frame */
frameticker = 0;
system_frame_scd(0);
/* update video */
gx_video_Update();
}
/* update audio */
gx_audio_Update();
/* check interlaced mode change */
if (bitmap.viewport.changed & 4)
{
/* VSYNC "original" mode */
if (!config.render && (gc_pal == vdp_pal))
{
/* framerate has changed, reinitialize audio timings */
audio_init(SAMPLERATE_48KHZ, get_framerate());
/* reinitialize sound chips */
sound_restore();
}
/* clear flag */
bitmap.viewport.changed &= ~4;
}
#ifdef HW_RVL
/* use Wii DVD light to simulate CD Drive access led */
*(u32*)0xcd0000c0 = (*(u32*)0xcd0000c0 & ~0x20) | ((scd.regs[0x06>>1].byte.h & 0x01) << 5);
#endif
/* wait for next frame */
while (frameticker < 1) usleep(1);
}
}
else if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
/* 16-bit hardware */
while (!ConfigRequested)
{
/* automatic frame skipping (only needed when running Virtua Racing on Gamecube) */
@ -193,10 +242,10 @@ static void run_emulation(void)
}
else
{
/* Master System type hardware */
/* 8-bit hardware */
while (!ConfigRequested)
{
/* render frame (no frameskipping needed) */
/* render frame (no frame skipping needed) */
frameticker = 0;
system_frame_sms(0);
@ -206,7 +255,7 @@ static void run_emulation(void)
/* update audio */
gx_audio_Update();
/* check interlaced mode change */
/* check interlaced mode change (PBC mode only) */
if (bitmap.viewport.changed & 4)
{
/* "original" mode */
@ -228,12 +277,17 @@ static void run_emulation(void)
}
}
#ifdef HW_RVL
/* reset Wii DVD light */
*(u32*)0xcd0000c0 = (*(u32*)0xcd0000c0 & ~0x20);
#endif
/* stop video & audio */
gx_audio_Stop();
gx_video_Stop();
#ifdef LOG_TIMING
if (cart.romsize)
if (system_hw)
{
FILE *f;
char filename[64];
@ -358,8 +412,18 @@ double get_framerate(void)
********************************************/
void reloadrom(void)
{
/* restore previous input settings */
if (old_system[0] != -1)
{
input.system[0] = old_system[0];
}
if (old_system[1] != -1)
{
input.system[1] = old_system[1];
}
/* Cartridge Hot Swap (make sure system has already been inited once) */
if (config.hot_swap == 3)
if ((config.hot_swap == 3) && (system_hw != SYSTEM_MCD))
{
/* Initialize cartridge hardware only */
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
@ -388,13 +452,13 @@ void reloadrom(void)
config.hot_swap |= 2;
}
/* Auto-Load SRAM file */
if (config.s_auto & 1)
if ((config.s_auto & 1) || (system_hw == SYSTEM_MCD))
{
/* Auto-Load Backup RAM */
slot_autoload(0,config.s_device);
}
/* Auto-Load State file */
/* Auto-Load State */
if (config.s_auto & 2)
{
slot_autoload(config.s_default,config.s_device);
@ -412,16 +476,15 @@ void shutdown(void)
/* save current config */
config_save();
/* save current game state */
if (config.s_auto & 2)
{
/* Auto-Save State file */
slot_autosave(config.s_default,config.s_device);
}
/* shutdown emulation */
system_shutdown();
audio_shutdown();
free(cart.rom);
gx_audio_Shutdown();
gx_video_Shutdown();
#ifdef HW_RVL
@ -497,6 +560,10 @@ int main (int argc, char *argv[])
dir = opendir(pathname);
if (dir) closedir(dir);
else mkdir(pathname,S_IRWXU);
sprintf (pathname, "%s/saves/cd",DEFAULT_PATH);
dir = opendir(pathname);
if (dir) closedir(dir);
else mkdir(pathname,S_IRWXU);
/* default Snapshot files directories */
sprintf (pathname, "%s/snaps",DEFAULT_PATH);
@ -519,6 +586,10 @@ int main (int argc, char *argv[])
dir = opendir(pathname);
if (dir) closedir(dir);
else mkdir(pathname,S_IRWXU);
sprintf (pathname, "%s/snaps/cd",DEFAULT_PATH);
dir = opendir(pathname);
if (dir) closedir(dir);
else mkdir(pathname,S_IRWXU);
/* default Cheat files directories */
sprintf (pathname, "%s/cheats",DEFAULT_PATH);
@ -541,6 +612,22 @@ int main (int argc, char *argv[])
dir = opendir(pathname);
if (dir) closedir(dir);
else mkdir(pathname,S_IRWXU);
sprintf (pathname, "%s/cheats/cd",DEFAULT_PATH);
dir = opendir(pathname);
if (dir) closedir(dir);
else mkdir(pathname,S_IRWXU);
/* default BIOS ROM files directories */
sprintf (pathname, "%s/bios",DEFAULT_PATH);
dir = opendir(pathname);
if (dir) closedir(dir);
else mkdir(pathname,S_IRWXU);
/* default LOCK-ON ROM files directories */
sprintf (pathname, "%s/lock-on",DEFAULT_PATH);
dir = opendir(pathname);
if (dir) closedir(dir);
else mkdir(pathname,S_IRWXU);
}
/* initialize sound engine */

View File

@ -1,3 +1,6 @@
/*************************************************/
/* port specific stuff should be put there */
/*************************************************/
#ifndef _OSD_H_
#define _OSD_H_
@ -16,29 +19,47 @@
#ifdef HW_RVL
#include <di/di.h>
#include <wiiuse/wpad.h>
#include "vi_encoder.h"
#endif
#include "gx_input.h"
#include "gx_audio.h"
#include "gx_video.h"
#include "config.h"
#include "fileio.h"
#include "file_load.h"
#include "cheats.h"
/*************************************************/
/* required by Genesis Plus GX core */
/*************************************************/
#include "config.h"
#include "fileio.h"
#define DEFAULT_PATH "/genplus"
#define GG_ROM "/genplus/ggenie.bin"
#define AR_ROM "/genplus/areplay.bin"
#define SK_ROM "/genplus/sk.bin"
#define SK_UPMEM "/genplus/sk2chip.bin"
#define MD_BIOS "/genplus/bios.bin"
#define MS_BIOS "/genplus/bios.sms"
#define GG_BIOS "/genplus/bios.gg"
#define GG_ROM "/genplus/lock-on/ggenie.bin"
#define AR_ROM "/genplus/lock-on/areplay.bin"
#define SK_ROM "/genplus/lock-on/sk.bin"
#define SK_UPMEM "/genplus/lock-on/sk2chip.bin"
#define MS_BIOS_US "/genplus/bios/bios_U.sms"
#define MS_BIOS_EU "/genplus/bios/bios_E.sms"
#define MS_BIOS_JP "/genplus/bios/bios_J.sms"
#define GG_BIOS "/genplus/bios/bios.gg"
#define MD_BIOS "/genplus/bios/bios_MD.bin"
#define CD_BIOS_US "/genplus/bios/bios_CD_U.bin"
#define CD_BIOS_EU "/genplus/bios/bios_CD_E.bin"
#define CD_BIOS_JP "/genplus/bios/bios_CD_J.bin"
#define CD_BRAM_US "/genplus/saves/cd/scd_U.brm"
#define CD_BRAM_EU "/genplus/saves/cd/scd_E.brm"
#define CD_BRAM_JP "/genplus/saves/cd/scd_J.brm"
#define CART_BRAM "/genplus/saves/cd/cart.brm"
/*************************************************/
#ifdef HW_RVL
#define VERSION "Genesis Plus GX 1.6.1 (WII)"
#define VERSION "Genesis Plus GX 1.7.0 (WII)"
#else
#define VERSION "Genesis Plus GX 1.6.1 (GCN)"
#define VERSION "Genesis Plus GX 1.7.0 (GCN)"
#endif
/* globals */

View File

@ -3,7 +3,7 @@
* Input peripherals support
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -3,7 +3,7 @@
* Input peripherals support
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -90,11 +90,15 @@
#define INPUT_BUTTON2 (0x0020)
#define INPUT_BUTTON1 (0x0010)
/* Mouse specific bitmask */
/* Mega Mouse specific bitmask */
#define INPUT_MOUSE_CENTER (0x0040)
#define INPUT_MOUSE_RIGHT (0x0020)
#define INPUT_MOUSE_LEFT (0x0010)
/* Pico hardware specific bitmask */
#define INPUT_PICO_PEN (0x0080)
#define INPUT_PICO_RED (0x0010)
/* XE-1AP specific bitmask */
#define INPUT_XE_E1 (0x0800)
#define INPUT_XE_E2 (0x0400)

View File

@ -149,7 +149,7 @@ INLINE unsigned char phaser_read(int port)
if (io_reg[0x0F] & (0x02 << (port >> 1)))
{
/* Get current X position (phaser is only used in MS compatiblity mode) */
int hcounter = hctab[(mcycles_z80 + SMS_CYCLE_OFFSET) % MCYCLES_PER_LINE];
int hcounter = hctab[(Z80.cycles + SMS_CYCLE_OFFSET) % MCYCLES_PER_LINE];
/* Compare with gun position */
int dx = input.analog[port][0] - (hcounter << 1);

View File

@ -1,8 +1,8 @@
/***************************************************************************************
* Genesis Plus
* Sega Paddle Control support
* Terebi Oekaki graphic board support
*
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2011 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -5,7 +5,7 @@
* Support for Master System (315-5216, 315-5237 & 315-5297), Game Gear & Mega Drive I/O chips
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -254,9 +254,9 @@ void io_init(void)
void io_reset(void)
{
/* Reset I/O registers */
if (system_hw == SYSTEM_MD)
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
io_reg[0x00] = region_code | 0x20 | (config.bios & 1);
io_reg[0x00] = region_code | (config.bios & 1);
io_reg[0x01] = 0x00;
io_reg[0x02] = 0x00;
io_reg[0x03] = 0x00;
@ -272,6 +272,12 @@ void io_reset(void)
io_reg[0x0D] = 0xFB;
io_reg[0x0E] = 0x00;
io_reg[0x0F] = 0x00;
/* CD unit detection */
if (system_hw != SYSTEM_MCD)
{
io_reg[0x00] |= 0x20;
}
}
else
{

View File

@ -5,7 +5,7 @@
* Support for Master System (315-5216, 315-5237 & 315-5297), Game Gear & Mega Drive I/O chips
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -3,7 +3,7 @@
* ROM Loading Support
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -93,6 +93,8 @@ ROMINFO rominfo;
char rom_filename[256];
uint8 romtype;
static uint8 rom_region;
/***************************************************************************
* Genesis ROM Manufacturers
*
@ -167,7 +169,7 @@ static const COMPANYINFO companyinfo[MAXCOMPANY] =
{"---", "Unknown"}
};
/***************************************************************************
/***************************************************************************
* Genesis Peripheral Information
*
* Based on the document provided at
@ -191,7 +193,7 @@ static const PERIPHERALINFO peripheralinfo[MAXPERIPHERALS] =
{"M", "Mega Mouse"},
};
/***************************************************************************
/***************************************************************************
*
* Compute ROM real checksum.
***************************************************************************/
@ -208,107 +210,20 @@ static uint16 getchecksum(uint8 *rom, int length)
return checksum;
}
/***************************************************************************
/***************************************************************************
*
* Pass a pointer to the ROM base address.
***************************************************************************/
static void getrominfo(char *romheader)
{
uint16 offset = 0;
/* Clear ROM info structure */
memset (&rominfo, 0, sizeof (ROMINFO));
/* Look for Master System ROM header */
if (!memcmp (&cart.rom[0x1ff0], "TMR SEGA", 8))
{
offset = 0x1ff0;
}
else if (!memcmp (&cart.rom[0x3ff0], "TMR SEGA", 8))
{
offset = 0x3ff0;
}
else if (!memcmp (&cart.rom[0x7ff0], "TMR SEGA", 8))
{
offset = 0x7ff0;
}
/* If found, assume this is a SMS game */
if (offset)
{
/* checksum */
rominfo.checksum = cart.rom[offset + 0x0a] | (cart.rom[offset + 0x0b] << 8);
/* product code & version */
sprintf(&rominfo.product[0], "%02d", cart.rom[offset + 0x0e] >> 4);
sprintf(&rominfo.product[2], "%02x", cart.rom[offset + 0x0d]);
sprintf(&rominfo.product[4], "%02x", cart.rom[offset + 0x0c]);
sprintf(&rominfo.product[6], "-%d", cart.rom[offset + 0x0e] & 0x0F);
/* region code */
switch (cart.rom[offset + 0x0f] >> 4)
{
case 3:
strcpy(rominfo.country,"SMS Japan");
break;
case 4:
strcpy(rominfo.country,"SMS Export");
break;
case 5:
strcpy(rominfo.country,"GG Japan");
break;
case 6:
strcpy(rominfo.country,"GG Export");
break;
case 7:
strcpy(rominfo.country,"GG International");
break;
default:
sprintf(rominfo.country,"Unknown (%d)", cart.rom[offset + 0x0f] >> 4);
break;
}
/* ROM size */
rominfo.romstart = 0;
switch (cart.rom[offset + 0x0f] & 0x0F)
{
case 0x00:
rominfo.romend = 0x3FFFF;
break;
case 0x01:
rominfo.romend = 0x7FFFF;
break;
case 0x02:
rominfo.romend = 0xFFFFF;
break;
case 0x0a:
rominfo.romend = 0x1FFF;
break;
case 0x0b:
rominfo.romend = 0x3FFF;
break;
case 0x0c:
rominfo.romend = 0x7FFF;
break;
case 0x0d:
rominfo.romend = 0xBFFF;
break;
case 0x0e:
rominfo.romend = 0xFFFF;
break;
case 0x0f:
rominfo.romend = 0x1FFFF;
break;
}
}
else
/* Genesis ROM header support */
if (system_hw & SYSTEM_MD)
{
int i,j;
/* Some SMS games don't have any header */
if (system_hw != SYSTEM_MD) return;
/* Genesis ROM header support */
memcpy (&rominfo.consoletype, romheader + ROMCONSOLE, 16);
memcpy (&rominfo.copyright, romheader + ROMCOPYRIGHT, 16);
@ -359,9 +274,96 @@ static void getrominfo(char *romheader)
if (romheader[ROMIOSUPPORT+i] == peripheralinfo[j].pID[0])
rominfo.peripherals |= (1 << j);
}
else
{
uint16 offset = 0;
/* detect Master System ROM header */
if (!memcmp (&romheader[0x1ff0], "TMR SEGA", 8))
{
offset = 0x1ff0;
}
else if (!memcmp (&romheader[0x3ff0], "TMR SEGA", 8))
{
offset = 0x3ff0;
}
else if (!memcmp (&romheader[0x7ff0], "TMR SEGA", 8))
{
offset = 0x7ff0;
}
/* if found, get infos from header */
if (offset)
{
/* checksum */
rominfo.checksum = romheader[offset + 0x0a] | (romheader[offset + 0x0b] << 8);
/* product code & version */
sprintf(&rominfo.product[0], "%02d", romheader[offset + 0x0e] >> 4);
sprintf(&rominfo.product[2], "%02x", romheader[offset + 0x0d]);
sprintf(&rominfo.product[4], "%02x", romheader[offset + 0x0c]);
sprintf(&rominfo.product[6], "-%d", romheader[offset + 0x0e] & 0x0F);
/* region code */
switch (romheader[offset + 0x0f] >> 4)
{
case 3:
strcpy(rominfo.country,"SMS Japan");
break;
case 4:
strcpy(rominfo.country,"SMS Export");
break;
case 5:
strcpy(rominfo.country,"GG Japan");
break;
case 6:
strcpy(rominfo.country,"GG Export");
break;
case 7:
strcpy(rominfo.country,"GG International");
break;
default:
sprintf(rominfo.country,"Unknown (%d)", romheader[offset + 0x0f] >> 4);
break;
}
/* ROM size */
rominfo.romstart = 0;
switch (romheader[offset + 0x0f] & 0x0F)
{
case 0x00:
rominfo.romend = 0x3FFFF;
break;
case 0x01:
rominfo.romend = 0x7FFFF;
break;
case 0x02:
rominfo.romend = 0xFFFFF;
break;
case 0x0a:
rominfo.romend = 0x1FFF;
break;
case 0x0b:
rominfo.romend = 0x3FFF;
break;
case 0x0c:
rominfo.romend = 0x7FFF;
break;
case 0x0d:
rominfo.romend = 0xBFFF;
break;
case 0x0e:
rominfo.romend = 0xFFFF;
break;
case 0x0f:
rominfo.romend = 0x1FFFF;
break;
}
}
}
}
/***************************************************************************
/***************************************************************************
* deinterleave_block
*
* Convert interleaved (.smd) ROM files.
@ -378,7 +380,149 @@ static void deinterleave_block(uint8 * src)
}
}
/***************************************************************************
/***************************************************************************
* load_bios
*
* Load current system BIOS file.
*
* Return loaded size (-1 if already loaded)
*
***************************************************************************/
int load_bios(void)
{
int size = 0;
switch (system_hw)
{
case SYSTEM_MCD:
{
/* check if CD BOOT ROM is already loaded */
if (!(system_bios & 0x10) || ((system_bios & 0x0c) != (region_code >> 4)))
{
/* load CD BOOT ROM */
switch (region_code)
{
case REGION_USA:
size = load_archive(CD_BIOS_US, scd.bootrom, sizeof(scd.bootrom));
break;
case REGION_EUROPE:
size = load_archive(CD_BIOS_EU, scd.bootrom, sizeof(scd.bootrom));
break;
default:
size = load_archive(CD_BIOS_JP, scd.bootrom, sizeof(scd.bootrom));
break;
}
/* CD BOOT ROM loaded ? */
if (size > 0)
{
#ifdef LSB_FIRST
/* Byteswap ROM to optimize 16-bit access */
int i;
for (i = 0; i < size; i += 2)
{
uint8 temp = scd.bootrom[i];
scd.bootrom[i] = scd.bootrom[i+1];
scd.bootrom[i+1] = temp;
}
#endif
/* mark CD BIOS as being loaded */
system_bios = system_bios | 0x10;
/* loaded BIOS region */
system_bios = (system_bios & 0xf0) | (region_code >> 4);
}
else
{
/* CD BOOT ROM disabled (SYSTEM ERROR) */
memset(scd.bootrom, 0xff, sizeof(scd.bootrom));
}
return size;
}
return -1;
}
case SYSTEM_GG:
case SYSTEM_GGMS:
{
/* check if Game Gear "BIOS" is already loaded */
if (!(system_bios & SYSTEM_GG))
{
/* mark Master System & Game Gear "BIOS" as unloaded */
system_bios &= ~(SYSTEM_SMS | SYSTEM_GG);
/* "BIOS" ROM is stored above cartridge ROM area, into $400000-$4FFFFF (max. 1MB) */
if (cart.romsize <= 0x400000)
{
/* load Game Gear "BIOS" file */
size = load_archive(GG_BIOS, cart.rom + 0x400000, 0x100000);
if (size > 0)
{
/* mark Game Gear "BIOS" as loaded */
system_bios |= SYSTEM_GG;
}
}
return size;
}
return -1;
}
case SYSTEM_SMS:
case SYSTEM_SMS2:
{
/* check if Master System "BIOS" is already loaded */
if (!(system_bios & SYSTEM_SMS) || ((system_bios & 0x0c) != (region_code >> 4)))
{
/* mark Master System & Game Gear "BIOS" as unloaded */
system_bios &= ~(SYSTEM_SMS | SYSTEM_GG);
/* "BIOS" ROM is stored above cartridge ROM area, into $400000-$4FFFFF (max. 1MB) */
if (cart.romsize <= 0x400000)
{
/* load Master System "BIOS" file */
switch (region_code)
{
case REGION_USA:
size = load_archive(MS_BIOS_US, cart.rom + 0x400000, 0x100000);
break;
case REGION_EUROPE:
size = load_archive(MS_BIOS_EU, cart.rom + 0x400000, 0x100000);
break;
default:
size = load_archive(MS_BIOS_JP, cart.rom + 0x400000, 0x100000);
break;
}
if (size > 0)
{
/* mark Master System "BIOS" as loaded */
system_bios |= SYSTEM_SMS;
/* loaded "BIOS" region */
system_bios = (system_bios & 0xf0) | (region_code >> 4);
}
}
return size;
}
return -1;
}
default:
{
return 0;
}
}
}
/***************************************************************************
* load_rom
*
* Load a new ROM file.
@ -388,13 +532,65 @@ static void deinterleave_block(uint8 * src)
***************************************************************************/
int load_rom(char *filename)
{
FILE *fd;
char buf[0x220];
int i;
/* Load file into ROM buffer */
int size = load_archive(filename);
/* default ROM header */
char *header = (char *)(cart.rom);
/* clear any existing patches */
ggenie_shutdown();
areplay_shutdown();
/* unload any existing disc */
if (romtype == SYSTEM_MCD)
{
cdd_unload();
}
/* .cue file support */
if (!strncmp(".cue", &filename[strlen(filename) - 4], 4))
{
/* open associated .bin file */
strncpy(&filename[strlen(filename) - 4], ".bin", 4);
}
/* file header */
fd = fopen(filename, "rb");
if (fd)
{
fread(buf, 0x220, 1, fd);
fclose(fd);
}
/* auto-detect CD image file */
if (!strncmp("SEGADISCSYSTEM", buf + 0x10, 14))
{
/* file header pointer (BIN format) */
header = buf + 0x10;
/* enable CD hardware */
system_hw = SYSTEM_MCD;
}
else if (!strncmp("SEGADISCSYSTEM", buf, 14))
{
/* file header pointer (ISO format) */
header = buf;
/* enable CD hardware */
system_hw = SYSTEM_MCD;
}
else
{
/* load file into ROM buffer (input filename is overwritten by uncompressed filename) */
int size = load_archive(filename, cart.rom, sizeof(cart.rom));
if (!size) return(0);
/* Auto-detect system mode from ROM file extension */
/* mark CD BIOS as unloaded */
system_bios &= ~0x10;
/* Auto-detect system hardware from ROM file extension */
if (!strncmp(".sms", &filename[strlen(filename) - 4], 4))
{
/* Master System II hardware */
@ -426,9 +622,10 @@ int load_rom(char *filename)
}
}
/* Take care of 512 byte header, if present */
/* auto-detect 512 byte extra header */
if (strncmp((char *)(cart.rom + 0x100),"SEGA", 4) && ((size / 512) & 1))
{
/* remove header */
size -= 512;
memcpy (cart.rom, cart.rom + 512, size);
@ -442,23 +639,110 @@ int load_rom(char *filename)
}
}
/* max. 10 MBytes supported */
if (size > MAXROMSIZE) size = MAXROMSIZE;
/* initialize ROM size */
cart.romsize = size;
}
/* get infos from ROM header */
getrominfo((char *)cart.rom);
getrominfo(header);
/* PICO hardware */
/* set console region */
get_region(header);
/* CD image file */
if (system_hw == SYSTEM_MCD)
{
/* load CD BOOT ROM */
if (!load_bios()) return (0);
/* load CD image */
cdd_load(filename, header - buf);
/* boot from CD */
scd.cartridge.boot = 0x00;
}
/* 16-bit ROM specific */
else if (system_hw == SYSTEM_MD)
{
#ifdef LSB_FIRST
/* Byteswap ROM to optimize 16-bit access */
for (i = 0; i < cart.romsize; i += 2)
{
uint8 temp = cart.rom[i];
cart.rom[i] = cart.rom[i+1];
cart.rom[i+1] = temp;
}
#endif
/* byteswapped RADICA dumps (from Haze) */
if (((strstr(rominfo.product,"-K0101") != NULL) && (rominfo.checksum == 0xf424)) ||
((strstr(rominfo.product,"-K0109") != NULL) && (rominfo.checksum == 0x4f10)))
{
for(i = 0; i < cart.romsize; i += 2)
{
uint8 temp = cart.rom[i];
cart.rom[i] = cart.rom[i+1];
cart.rom[i+1] = temp;
}
}
}
/* auto-detected system hardware */
romtype = system_hw;
/* PICO ROM */
if (strstr(rominfo.consoletype, "SEGA PICO") != NULL)
{
/* PICO hardware */
system_hw = SYSTEM_PICO;
}
/* Save ROM type for later use */
romtype = system_hw;
/* CD BOOT ROM */
else if (strstr(rominfo.ROMType, "BR") != NULL)
{
/* enable CD hardware */
system_hw = SYSTEM_MCD;
/* Force system if requested */
/* mark CD BIOS as being loaded */
system_bios = system_bios | 0x10;
/* loaded CD BIOS region */
system_bios = (system_bios & 0xf0) | (region_code >> 4);
/* boot from CD */
scd.cartridge.boot = 0x00;
/* CD unloaded */
cdd.loaded = 0;
}
/* special ROM cartridges that use CD hardware */
else if ((strstr(rominfo.domestic,"FLUX") != NULL) || (strstr(rominfo.domestic,"WONDER LIBRARY") != NULL))
{
/* enable CD hardware */
system_hw = SYSTEM_MCD;
/* copy ROM to CD cartridge area */
memcpy(scd.cartridge.area, cart.rom, sizeof(scd.cartridge.area));
/* load CD BOOT ROM */
if (load_bios())
{
/* CD unloaded */
cdd.loaded = 0;
/* boot from cartridge */
scd.cartridge.boot = 0x40;
}
else
{
/* assume Mega Drive hardware */
system_hw = SYSTEM_MD;
}
}
/* Force system hardware if requested */
if (config.system == SYSTEM_MD)
{
if (!(system_hw & SYSTEM_MD))
@ -480,60 +764,50 @@ int load_rom(char *filename)
system_hw = config.system;
}
/* set console region */
region_autodetect();
/* Genesis mode specific */
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
#ifdef LSB_FIRST
/* Byteswap ROM to optimize 16-bit access */
uint8 temp;
for (i = 0; i < size; i += 2)
{
temp = cart.rom[i];
cart.rom[i] = cart.rom[i+1];
cart.rom[i+1] = temp;
}
#endif
/* byteswapped RADICA dumps (from Haze) */
if (((strstr(rominfo.product,"-K0101") != NULL) && (rominfo.checksum == 0xf424)) ||
((strstr(rominfo.product,"-K0109") != NULL) && (rominfo.checksum == 0x4f10)))
{
uint8 temp;
for(i = 0; i < size; i += 2)
{
temp = cart.rom[i];
cart.rom[i] = cart.rom[i+1];
cart.rom[i+1] = temp;
}
}
}
/* Master System or Game Gear BIOS ROM are loaded within $400000-$4FFFFF area */
if (size > 0x400000)
if ((cart.romsize > 0x400000) || (system_hw == SYSTEM_MCD))
{
/* Mark both BIOS as unloaded if loaded ROM is overwriting them */
config.bios &= ~(SYSTEM_SMS | SYSTEM_GG);
system_bios &= ~(SYSTEM_SMS | SYSTEM_GG);
}
return(1);
}
/****************************************************************************
* region_autodetect
* get_region
*
* Set console region upon ROM header
* Set console region from ROM header passed as parameter or
* from previous auto-detection (if NULL)
*
****************************************************************************/
void region_autodetect(void)
void get_region(char *romheader)
{
if ((system_hw & SYSTEM_PBC) != SYSTEM_MD)
/* region auto-detection ? */
if (romheader)
{
region_code = sms_cart_region_detect();
/* Mega CD image */
if (system_hw == SYSTEM_MCD)
{
/* security code */
switch (romheader[0x20b])
{
case 0x7a:
region_code = REGION_USA;
break;
case 0x64:
region_code = REGION_EUROPE;
break;
default:
region_code = REGION_JAPAN_NTSC;
break;
}
else
}
/* 16-bit cartridge */
else if (system_hw & SYSTEM_MD)
{
/* country codes used to differentiate region */
/* 0001 = japan ntsc (1) */
@ -576,7 +850,7 @@ void region_autodetect(void)
else if (country & 2) region_code = REGION_JAPAN_PAL;
else region_code = REGION_USA;
/* some games need specific REGION setting */
/* some games need specific region settings but have wrong header*/
if (((strstr(rominfo.product,"T-45033") != NULL) && (rominfo.checksum == 0x0F81)) || /* Alisia Dragon (Europe) */
(strstr(rominfo.product,"T-69046-50") != NULL) || /* Back to the Future III (Europe) */
(strstr(rominfo.product,"T-120106-00") != NULL) || /* Brian Lara Cricket (Europe) */
@ -585,14 +859,28 @@ void region_autodetect(void)
/* need PAL settings */
region_code = REGION_EUROPE;
}
if ((rominfo.realchecksum == 0x532e) && (strstr(rominfo.product,"1011-00") != NULL))
else if ((rominfo.realchecksum == 0x532e) && (strstr(rominfo.product,"1011-00") != NULL))
{
/* On Dal Jang Goon (Korea) needs JAPAN region code */
region_code = REGION_JAPAN_NTSC;
}
}
/* 8-bit cartridge */
else
{
region_code = sms_cart_region_detect();
}
/* save auto-detected region */
rom_region = region_code;
}
else
{
/* restore auto-detected region */
region_code = rom_region;
}
/* force console region if requested */
if (config.region_detect == 1) region_code = REGION_USA;
else if (config.region_detect == 2) region_code = REGION_EUROPE;

View File

@ -3,7 +3,7 @@
* ROM Loading Support
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -48,7 +48,7 @@ typedef struct
char copyright[18]; /* Copyright message */
char domestic[50]; /* Domestic name of ROM */
char international[50]; /* International name of ROM */
char ROMType[4]; /* Educational or Game */
char ROMType[4]; /* Boot ROM (BR), Educational (AL) or Game (GM) program */
char product[14]; /* Product serial number */
unsigned short checksum; /* ROM Checksum (header) */
unsigned short realchecksum; /* ROM Checksum (calculated) */
@ -65,8 +65,9 @@ extern char rom_filename[256];
extern uint8 romtype;
/* Function prototypes */
extern int load_bios(void);
extern int load_rom(char *filename);
extern void region_autodetect(void);
extern void get_region(char *romheader);
extern char *get_company(void);
extern char *get_peripheral(int index);

View File

@ -31,17 +31,108 @@
- added proper cycle use on reset
- added cycle accurate timings for MUL/DIV instructions (thanks to Jorge Cwik !)
- fixed undocumented flags for DIV instructions (Blood Shot)
- added MAIN-CPU & SUB-CPU support for Mega CD emulation
*/
/* ======================================================================== */
/* ============================= CONFIGURATION ============================ */
/* ================================ INCLUDES ============================== */
/* ======================================================================== */
/* Import the configuration for this build */
#include "m68kconf.h"
#include "macros.h"
/* ======================================================================== */
/* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */
/* ======================================================================== */
/* Check for > 32bit sizes */
#if UINT_MAX > 0xffffffff
#define M68K_INT_GT_32_BIT 1
#else
#define M68K_INT_GT_32_BIT 0
#endif
/* Data types used in this emulation core */
#undef sint8
#undef sint16
#undef sint32
#undef sint64
#undef uint8
#undef uint16
#undef uint32
#undef uint64
#undef sint
#undef uint
#define sint8 signed char /* ASG: changed from char to signed char */
#define sint16 signed short
#define sint32 signed int /* AWJ: changed from long to int */
#define uint8 unsigned char
#define uint16 unsigned short
#define uint32 unsigned int /* AWJ: changed from long to int */
/* signed and unsigned int must be at least 32 bits wide */
#define sint signed int
#define uint unsigned int
#if M68K_USE_64_BIT
#define sint64 signed long long
#define uint64 unsigned long long
#else
#define sint64 sint32
#define uint64 uint32
#endif /* M68K_USE_64_BIT */
/* Allow for architectures that don't have 8-bit sizes */
/*#if UCHAR_MAX == 0xff*/
#define MAKE_INT_8(A) (sint8)(A)
/*#else
#undef sint8
#define sint8 signed int
#undef uint8
#define uint8 unsigned int
INLINE sint MAKE_INT_8(uint value)
{
return (value & 0x80) ? value | ~0xff : value & 0xff;
}*/
/*#endif *//* UCHAR_MAX == 0xff */
/* Allow for architectures that don't have 16-bit sizes */
/*#if USHRT_MAX == 0xffff*/
#define MAKE_INT_16(A) (sint16)(A)
/*#else
#undef sint16
#define sint16 signed int
#undef uint16
#define uint16 unsigned int
INLINE sint MAKE_INT_16(uint value)
{
return (value & 0x8000) ? value | ~0xffff : value & 0xffff;
}*/
/*#endif *//* USHRT_MAX == 0xffff */
/* Allow for architectures that don't have 32-bit sizes */
/*#if UINT_MAX == 0xffffffff*/
#define MAKE_INT_32(A) (sint32)(A)
/*#else
#undef sint32
#define sint32 signed int
#undef uint32
#define uint32 unsigned int
INLINE sint MAKE_INT_32(uint value)
{
return (value & 0x80000000) ? value | ~0xffffffff : value & 0xffffffff;
}*/
/*#endif *//* UINT_MAX == 0xffffffff */
/* ======================================================================== */
/* ============================ GENERAL DEFINES =========================== */
@ -118,31 +209,85 @@ typedef enum
} m68k_register_t;
/* ======================================================================== */
/* ====================== FUNCTIONS CALLED BY THE CPU ===================== */
/* ======================================================================== */
/* 68k memory map structure */
typedef struct
{
unsigned char *base; /* direct memory access (ROM, RAM) */
unsigned char *base; /* memory-based access (ROM, RAM) */
unsigned int (*read8)(unsigned int address); /* I/O byte read access */
unsigned int (*read16)(unsigned int address); /* I/O word read access */
void (*write8)(unsigned int address, unsigned int data); /* I/O byte write access */
void (*write16)(unsigned int address, unsigned int data); /* I/O word write access */
} _m68k_memory_map;
} cpu_memory_map;
/* 68k memory map */
_m68k_memory_map m68k_memory_map[256];
/* 68k idle loop detection */
typedef struct
{
uint pc;
uint cycle;
uint detected;
} cpu_idle_t;
/* Read data immediately following the PC */
#define m68k_read_immediate_16(address) *(uint16 *)(m68k_memory_map[((address)>>16)&0xff].base + ((address) & 0xffff))
#define m68k_read_immediate_32(address) (m68k_read_immediate_16(address) << 16) | (m68k_read_immediate_16(address+2))
typedef struct
{
cpu_memory_map memory_map[256]; /* memory mapping */
/* Read data relative to the PC */
#define m68k_read_pcrelative_8(address) READ_BYTE(m68k_memory_map[((address)>>16)&0xff].base, (address) & 0xffff)
#define m68k_read_pcrelative_16(address) m68k_read_immediate_16(address)
#define m68k_read_pcrelative_32(address) m68k_read_immediate_32(address)
cpu_idle_t poll; /* polling detection */
uint cycles; /* current master cycle count */
uint cycle_end; /* aimed master cycle count for current execution frame */
uint dar[16]; /* Data and Address Registers */
uint pc; /* Program Counter */
uint sp[5]; /* User and Interrupt Stack Pointers */
uint ir; /* Instruction Register */
uint t1_flag; /* Trace 1 */
uint s_flag; /* Supervisor */
uint x_flag; /* Extend */
uint n_flag; /* Negative */
uint not_z_flag; /* Zero, inverted for speedups */
uint v_flag; /* Overflow */
uint c_flag; /* Carry */
uint int_mask; /* I0-I2 */
uint int_level; /* State of interrupt pins IPL0-IPL2 -- ASG: changed from ints_pending */
uint stopped; /* Stopped state */
#if M68K_EMULATE_PREFETCH
uint pref_addr; /* Last prefetch address */
uint pref_data; /* Data in the prefetch queue */
#endif
#if M68K_EMULATE_ADDRESS_ERROR
uint instr_mode; /* Stores whether we are in instruction mode or group 0/1 exception mode */
uint run_mode; /* Stores whether we are processing a reset, bus error, address error, or something else */
uint aerr_enabled; /* Enables/deisables address error checks at runtime */
jmp_buf aerr_trap; /* Address error jump */
uint aerr_address; /* Address error location */
uint aerr_write_mode; /* Address error write mode */
uint aerr_fc; /* Address error FC code */
#endif
#if M68K_EMULATE_TRACE
uint tracing; /* Tracing enable flag */
#endif
#if M68K_EMULATE_FC
uint address_space; /* Current FC code */
#endif
/* Callbacks to host */
#if M68K_EMULATE_INT_ACK == OPT_ON
int (*int_ack_callback)(int int_line); /* Interrupt Acknowledge */
#endif
#if M68K_EMULATE_RESET == OPT_ON
void (*reset_instr_callback)(void); /* Called when a RESET instruction is encountered */
#endif
#if M68K_TAS_HAS_CALLBACK == OPT_ON
int (*tas_instr_callback)(void); /* Called when a TAS instruction is encountered, allows / disallows writeback */
#endif
#if M68K_EMULATE_FC == OPT_ON
void (*set_fc_callback)(unsigned int new_fc); /* Called when the CPU function code changes */
#endif
} m68ki_cpu_core;
/* CPU cores */
extern m68ki_cpu_core m68k;
extern m68ki_cpu_core s68k;
/* ======================================================================== */
@ -209,25 +354,32 @@ void m68k_set_fc_callback(void (*callback)(unsigned int new_fc));
* at least once at init time.
*/
extern void m68k_init(void);
extern void s68k_init(void);
/* Pulse the RESET pin on the CPU.
* You *MUST* reset the CPU at least once to initialize the emulation
*/
extern void m68k_pulse_reset(void);
extern void s68k_pulse_reset(void);
/* Run until given cycle count is reached */
extern void m68k_run(unsigned int cycles);
extern void s68k_run(unsigned int cycles);
/* Set the IPL0-IPL2 pins on the CPU (IRQ).
* A transition from < 7 to 7 will cause a non-maskable interrupt (NMI).
* Setting IRQ to 0 will clear an interrupt request.
*/
extern void m68k_update_irq(unsigned int mask);
extern void m68k_set_irq(unsigned int int_level);
extern void m68k_set_irq_delay(unsigned int int_level);
extern void m68k_update_irq(unsigned int mask);
extern void s68k_update_irq(unsigned int mask);
/* Halt the CPU as if you pulsed the HALT pin. */
extern void m68k_pulse_halt(void);
extern void m68k_clear_halt(void);
extern void s68k_pulse_halt(void);
extern void s68k_clear_halt(void);
/* Peek at the internals of a CPU context. This can either be a context
@ -235,9 +387,11 @@ extern void m68k_pulse_halt(void);
* If context is NULL, the currently running CPU context will be used.
*/
extern unsigned int m68k_get_reg(m68k_register_t reg);
extern unsigned int s68k_get_reg(m68k_register_t reg);
/* Poke values into the internals of the currently running CPU context */
extern void m68k_set_reg(m68k_register_t reg, unsigned int value);
extern void s68k_set_reg(m68k_register_t reg, unsigned int value);
/* ======================================================================== */

View File

@ -1,40 +1,9 @@
/* ======================================================================== */
/* ========================= LICENSING & COPYRIGHT ======================== */
/* ======================================================================== */
/*
* MUSASHI
* Version 3.32
*
* A portable Motorola M680x0 processor emulation engine.
* Copyright Karl Stenerud. All rights reserved.
*
* This code may be freely used for non-commercial purposes as long as this
* copyright notice remains unaltered in the source code and any binary files
* containing this code in compiled form.
*
* All other licensing terms must be negotiated with the author
* (Karl Stenerud).
*
* The latest version of this code can be obtained at:
* http://kstenerud.cjb.net
*/
/* Modified by Eke-Eke for Genesis Plus GX:
- removed unused stuff to reduce memory usage / optimize execution (multiple CPU types support, NMI support, ...)
- moved stuff to compile statically in a single object file
- implemented support for global cycle count (shared by 68k & Z80 CPU)
- added support for interrupt latency (Sesame's Street Counting Cafe, Fatal Rewind)
- added proper cycle use on reset
- added cycle accurate timings for MUL/DIV instructions (thanks to Jorge Cwik !)
- fixed undocumented flags for DIV instructions (Blood Shot)
*/
#ifndef M68KCONF__HEADER
#define M68KCONF__HEADER
/* ======================================================================== */
/* ======================== MAIN 68K CONFIGURATION ======================== */
/* ======================================================================== */
/* Configuration switches.
* Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks.
@ -46,10 +15,6 @@
#define OPT_ON 1
#define OPT_SPECIFY_HANDLER 2
/* ======================================================================== */
/* ============================= CONFIGURATION ============================ */
/* ======================================================================== */
/* If ON, the CPU will call m68k_write_32_pd() when it executes move.l with a
* predecrement destination EA mode instead of m68k_write_32().
* To simulate real 68k behavior, m68k_write_32_pd() must first write the high

View File

@ -1,47 +1,21 @@
/* ======================================================================== */
/* ========================= LICENSING & COPYRIGHT ======================== */
/* MAIN 68K CORE */
/* ======================================================================== */
#if 0
static const char copyright_notice[] =
"MUSASHI\n"
"Version 3.32 (2007-12-15)\n"
"A portable Motorola M680x0 processor emulation engine.\n"
"Copyright Karl Stenerud. All rights reserved.\n"
"\n"
"This code may be freely used for non-commercial purpooses as long as this\n"
"copyright notice remains unaltered in the source code and any binary files\n"
"containing this code in compiled form.\n"
"\n"
"All other licensing terms must be negotiated with the author\n"
"(Karl Stenerud).\n"
"\n"
"The latest version of this code can be obtained at:\n"
"http://kstenerud.cjb.net\n"
;
#endif
extern int vdp_68k_irq_ack(int int_level);
/* ======================================================================== */
/* ================================= NOTES ================================ */
/* ======================================================================== */
/* Modified by Eke-Eke for Genesis Plus GX:
- removed unused stuff to reduce memory usage / optimize execution (multiple CPU types support, NMI support, ...)
- moved stuff to compile statically in a single object file
- implemented support for global cycle count (shared by 68k & Z80 CPU)
- added support for interrupt latency (Sesame's Street Counting Cafe, Fatal Rewind)
- added proper cycle use on reset
- added cycle accurate timings for MUL/DIV instructions (thanks to Jorge Cwik !)
- fixed undocumented flags for DIV instructions (Blood Shot)
*/
#define m68ki_cpu m68k
#define MUL (7)
/* ======================================================================== */
/* ================================ INCLUDES ============================== */
/* ======================================================================== */
#ifndef BUILD_TABLES
#include "m68ki_cycles.h"
#endif
#include "m68kconf.h"
#include "m68kcpu.h"
#include "m68kops.h"
@ -49,8 +23,15 @@ static const char copyright_notice[] =
/* ================================= DATA ================================= */
/* ======================================================================== */
#ifdef BUILD_TABLES
static unsigned char m68ki_cycles[0x10000];
#endif
static int irq_latency;
m68ki_cpu_core m68k;
/* ======================================================================== */
/* =============================== CALLBACKS ============================== */
/* ======================================================================== */
@ -222,7 +203,7 @@ void m68k_update_irq(unsigned int mask)
CPU_INT_LEVEL |= (mask << 8);
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, mcycles_68k/3420, mcycles_68k, mcycles_68k%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
#endif
/* Check interrupt mask to process IRQ */
@ -235,7 +216,7 @@ void m68k_set_irq(unsigned int int_level)
CPU_INT_LEVEL = int_level << 8;
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, mcycles_68k/3420, mcycles_68k, mcycles_68k%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
#endif
/* Check interrupt mask to process IRQ */
@ -271,20 +252,19 @@ void m68k_set_irq_delay(unsigned int int_level)
}
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, mcycles_68k/3420, mcycles_68k, mcycles_68k%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
#endif
/* Check interrupt mask to process IRQ */
m68ki_check_interrupts(); /* Level triggered (IRQ) */
}
void m68k_run(unsigned int cycles)
{
/* Make sure we're not stopped */
if (CPU_STOPPED)
{
mcycles_68k = cycles;
m68k.cycles = cycles;
return;
}
@ -292,9 +272,9 @@ void m68k_run(unsigned int cycles)
m68ki_set_address_error_trap() /* auto-disable (see m68kcpu.h) */
/* Save end cycles count for when CPU is stopped */
end_cycles = cycles;
m68k.cycle_end = cycles;
while (mcycles_68k < cycles)
while (m68k.cycles < cycles)
{
/* Set tracing accodring to T1. */
m68ki_trace_t1() /* auto-disable (see m68kcpu.h) */
@ -344,7 +324,7 @@ void m68k_init(void)
/* Pulse the RESET line on the CPU */
void m68k_pulse_reset(void)
{
/* Clear all stop levels and eat up all remaining cycles */
/* Clear all stop levels */
CPU_STOPPED = 0;
#if M68K_EMULATE_ADDRESS_ERROR
CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET;
@ -381,12 +361,17 @@ void m68k_pulse_reset(void)
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_RESET]);
}
/* Pulse the HALT line on the CPU */
void m68k_pulse_halt(void)
{
/* Pulse the HALT line on the CPU */
CPU_STOPPED |= STOP_LEVEL_HALT;
}
void m68k_clear_halt(void)
{
/* Clear the HALT line on the CPU */
CPU_STOPPED &= ~STOP_LEVEL_HALT;
}
/* ======================================================================== */
/* ============================== END OF FILE ============================= */

View File

@ -1,138 +1,19 @@
/* ======================================================================== */
/* ========================= LICENSING & COPYRIGHT ======================== */
/* ======================================================================== */
/*
* MUSASHI
* Version 3.32
*
* A portable Motorola M680x0 processor emulation engine.
* Copyright Karl Stenerud. All rights reserved.
*
* This code may be freely used for non-commercial purposes as long as this
* copyright notice remains unaltered in the source code and any binary files
* containing this code in compiled form.
*
* All other licensing terms must be negotiated with the author
* (Karl Stenerud).
*
* The latest version of this code can be obtained at:
* http://kstenerud.cjb.net
*/
/* Modified by Eke-Eke for Genesis Plus GX:
- removed unused stuff to reduce memory usage / optimize execution (multiple CPU types support, NMI support, ...)
- moved stuff to compile statically in a single object file
- implemented support for global cycle count (shared by 68k & Z80 CPU)
- added support for interrupt latency (Sesame's Street Counting Cafe, Fatal Rewind)
- added proper cycle use on reset
- added cycle accurate timings for MUL/DIV instructions (thanks to Jorge Cwik !)
- fixed undocumented flags for DIV instructions (Blood Shot)
*/
#ifndef M68KCPU__HEADER
#define M68KCPU__HEADER
/* ======================================================================== */
/* GENERIC 68K CORE */
/* ======================================================================== */
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "m68k.h"
#if M68K_EMULATE_ADDRESS_ERROR
#include <setjmp.h>
#endif /* M68K_EMULATE_ADDRESS_ERROR */
/* ======================================================================== */
/* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */
/* ======================================================================== */
/* Check for > 32bit sizes */
#if UINT_MAX > 0xffffffff
#define M68K_INT_GT_32_BIT 1
#else
#define M68K_INT_GT_32_BIT 0
#endif
/* Data types used in this emulation core */
#undef sint8
#undef sint16
#undef sint32
#undef sint64
#undef uint8
#undef uint16
#undef uint32
#undef uint64
#undef sint
#undef uint
#define sint8 signed char /* ASG: changed from char to signed char */
#define sint16 signed short
#define sint32 signed int /* AWJ: changed from long to int */
#define uint8 unsigned char
#define uint16 unsigned short
#define uint32 unsigned int /* AWJ: changed from long to int */
/* signed and unsigned int must be at least 32 bits wide */
#define sint signed int
#define uint unsigned int
#if M68K_USE_64_BIT
#define sint64 signed long long
#define uint64 unsigned long long
#else
#define sint64 sint32
#define uint64 uint32
#endif /* M68K_USE_64_BIT */
/* Allow for architectures that don't have 8-bit sizes */
#if UCHAR_MAX == 0xff
#define MAKE_INT_8(A) (sint8)(A)
#else
#undef sint8
#define sint8 signed int
#undef uint8
#define uint8 unsigned int
INLINE sint MAKE_INT_8(uint value)
{
return (value & 0x80) ? value | ~0xff : value & 0xff;
}
#endif /* UCHAR_MAX == 0xff */
/* Allow for architectures that don't have 16-bit sizes */
#if USHRT_MAX == 0xffff
#define MAKE_INT_16(A) (sint16)(A)
#else
#undef sint16
#define sint16 signed int
#undef uint16
#define uint16 unsigned int
INLINE sint MAKE_INT_16(uint value)
{
return (value & 0x8000) ? value | ~0xffff : value & 0xffff;
}
#endif /* USHRT_MAX == 0xffff */
/* Allow for architectures that don't have 32-bit sizes */
#if UINT_MAX == 0xffffffff
#define MAKE_INT_32(A) (sint32)(A)
#else
#undef sint32
#define sint32 signed int
#undef uint32
#define uint32 unsigned int
INLINE sint MAKE_INT_32(uint value)
{
return (value & 0x80000000) ? value | ~0xffffffff : value & 0xffffffff;
}
#endif /* UINT_MAX == 0xffffffff */
#include "m68k.h"
/* ======================================================================== */
@ -335,15 +216,15 @@
#define CYC_INSTRUCTION m68ki_cycles
#define CYC_EXCEPTION m68ki_exception_cycle_table
#define CYC_BCC_NOTAKE_B ( -2 * 7)
#define CYC_BCC_NOTAKE_W ( 2 * 7)
#define CYC_DBCC_F_NOEXP ( -2 * 7)
#define CYC_DBCC_F_EXP ( 2 * 7)
#define CYC_SCC_R_TRUE ( 2 * 7)
#define CYC_MOVEM_W ( 4 * 7)
#define CYC_MOVEM_L ( 8 * 7)
#define CYC_SHIFT ( 2 * 7)
#define CYC_RESET (132 * 7)
#define CYC_BCC_NOTAKE_B ( -2 * MUL)
#define CYC_BCC_NOTAKE_W ( 2 * MUL)
#define CYC_DBCC_F_NOEXP ( -2 * MUL)
#define CYC_DBCC_F_EXP ( 2 * MUL)
#define CYC_SCC_R_TRUE ( 2 * MUL)
#define CYC_MOVEM_W ( 4 * MUL)
#define CYC_MOVEM_L ( 8 * MUL)
#define CYC_SHIFT ( 2 * MUL)
#define CYC_RESET (132 * MUL)
#if M68K_EMULATE_INT_ACK == OPT_ON
#define CALLBACK_INT_ACK m68ki_cpu.int_ack_callback
@ -403,9 +284,9 @@
#else
#define m68ki_set_fc(A) CALLBACK_SET_FC(A);
#endif
#define m68ki_use_data_space() m68ki_address_space = FUNCTION_CODE_USER_DATA;
#define m68ki_use_program_space() m68ki_address_space = FUNCTION_CODE_USER_PROGRAM;
#define m68ki_get_address_space() m68ki_address_space
#define m68ki_use_data_space() m68ki_cpu.address_space = FUNCTION_CODE_USER_DATA;
#define m68ki_use_program_space() m68ki_cpu.address_space = FUNCTION_CODE_USER_PROGRAM;
#define m68ki_get_address_space() m68ki_cpu.address_space
#else
#define m68ki_set_fc(A)
#define m68ki_use_data_space()
@ -417,11 +298,11 @@
/* Enable or disable trace emulation */
#if M68K_EMULATE_TRACE
/* Initiates trace checking before each instruction (t1) */
#define m68ki_trace_t1() m68ki_tracing = FLAG_T1;
#define m68ki_trace_t1() m68ki_cpu.tracing = FLAG_T1;
/* Clear all tracing */
#define m68ki_clear_trace() m68ki_tracing = 0;
#define m68ki_clear_trace() m68ki_cpu.tracing = 0;
/* Cause a trace exception if we are tracing */
#define m68ki_exception_if_trace() if(m68ki_tracing) m68ki_exception_trace();
#define m68ki_exception_if_trace() if(m68ki_cpu.tracing) m68ki_exception_trace();
#else
#define m68ki_trace_t1()
#define m68ki_clear_trace()
@ -432,7 +313,7 @@
/* Enable or disable Address error emulation */
#if M68K_EMULATE_ADDRESS_ERROR
#define m68ki_set_address_error_trap() \
if(setjmp(m68ki_aerr_trap) != 0) \
if(setjmp(m68ki_cpu.aerr_trap) != 0) \
{ \
m68ki_exception_address_error(); \
}
@ -440,12 +321,12 @@
#define m68ki_check_address_error(ADDR, WRITE_MODE, FC) \
if((ADDR)&1) \
{ \
if (emulate_address_error) \
if (m68ki_cpu.aerr_enabled) \
{ \
m68ki_aerr_address = ADDR; \
m68ki_aerr_write_mode = WRITE_MODE; \
m68ki_aerr_fc = FC; \
longjmp(m68ki_aerr_trap, 1); \
m68ki_cpu.aerr_address = ADDR; \
m68ki_cpu.aerr_write_mode = WRITE_MODE; \
m68ki_cpu.aerr_fc = FC; \
longjmp(m68ki_cpu.aerr_trap, 1); \
} \
}
#else
@ -633,12 +514,21 @@
/* ---------------------------- Cycle Counting ---------------------------- */
#define USE_CYCLES(A) mcycles_68k += (A)
#define END_CYCLES(A) mcycles_68k = (A)
#define USE_CYCLES(A) m68ki_cpu.cycles += (A)
#define SET_CYCLES(A) m68ki_cpu.cycles = (A)
/* ----------------------------- Read / Write ----------------------------- */
/* Read data immediately following the PC */
#define m68k_read_immediate_16(address) *(uint16 *)(m68ki_cpu.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff))
#define m68k_read_immediate_32(address) (m68k_read_immediate_16(address) << 16) | (m68k_read_immediate_16(address+2))
/* Read data relative to the PC */
#define m68k_read_pcrelative_8(address) READ_BYTE(m68ki_cpu.memory_map[((address)>>16)&0xff].base, (address) & 0xffff)
#define m68k_read_pcrelative_16(address) m68k_read_immediate_16(address)
#define m68k_read_pcrelative_32(address) m68k_read_immediate_32(address)
/* Read from the current address space */
#define m68ki_read_8(A) m68ki_read_8_fc (A, FLAG_S | m68ki_get_address_space())
#define m68ki_read_16(A) m68ki_read_16_fc(A, FLAG_S | m68ki_get_address_space())
@ -673,78 +563,6 @@
/* =============================== PROTOTYPES ============================= */
/* ======================================================================== */
typedef struct
{
uint dar[16]; /* Data and Address Registers */
uint pc; /* Program Counter */
uint sp[5]; /* User and Interrupt Stack Pointers */
uint ir; /* Instruction Register */
uint t1_flag; /* Trace 1 */
uint s_flag; /* Supervisor */
uint x_flag; /* Extend */
uint n_flag; /* Negative */
uint not_z_flag; /* Zero, inverted for speedups */
uint v_flag; /* Overflow */
uint c_flag; /* Carry */
uint int_mask; /* I0-I2 */
uint int_level; /* State of interrupt pins IPL0-IPL2 -- ASG: changed from ints_pending */
uint stopped; /* Stopped state */
#if M68K_EMULATE_PREFETCH
uint pref_addr; /* Last prefetch address */
uint pref_data; /* Data in the prefetch queue */
#endif
#if M68K_EMULATE_ADDRESS_ERROR
uint instr_mode; /* Stores whether we are in instruction mode or group 0/1 exception mode */
uint run_mode; /* Stores whether we are processing a reset, bus error, address error, or something else */
#endif
/* Callbacks to host */
#if M68K_EMULATE_INT_ACK == OPT_ON
int (*int_ack_callback)(int int_line); /* Interrupt Acknowledge */
#endif
#if M68K_EMULATE_RESET == OPT_ON
void (*reset_instr_callback)(void); /* Called when a RESET instruction is encountered */
#endif
#if M68K_TAS_HAS_CALLBACK == OPT_ON
int (*tas_instr_callback)(void); /* Called when a TAS instruction is encountered, allows / disallows writeback */
#endif
#if M68K_EMULATE_FC == OPT_ON
void (*set_fc_callback)(unsigned int new_fc); /* Called when the CPU function code changes */
#endif
} m68ki_cpu_core;
/* The CPU core */
m68ki_cpu_core m68ki_cpu;
/* Prevent static data from being redefined when this file is included */
#ifndef _MEM68K_H_
#if M68K_EMULATE_TRACE
static uint m68ki_tracing;
#endif /* M68K_EMULATE_TRACE */
#if M68K_EMULATE_FC
static uint m68ki_address_space;
#endif /* M68K_EMULATE_FC */
#if M68K_EMULATE_ADDRESS_ERROR
static jmp_buf m68ki_aerr_trap;
static uint m68ki_aerr_address;
static uint m68ki_aerr_write_mode;
static uint m68ki_aerr_fc;
int emulate_address_error;
#endif /* M68K_EMULATE_ADDRESS_ERROR */
/* Current end cycle */
static unsigned int end_cycles;
/* Cycles used by CPU instructions */
#ifdef BUILD_TABLES
static unsigned char m68ki_cycles[0x10000];
#else
#include "m68ki_cycles.h"
#endif
/* Used by shift & rotate instructions */
static const uint8 m68ki_shift_8_table[65] =
{
@ -789,77 +607,77 @@ static const uint m68ki_shift_32_table[65] =
*/
static const uint16 m68ki_exception_cycle_table[256] =
{
40*7, /* 0: Reset - Initial Stack Pointer */
4*7, /* 1: Reset - Initial Program Counter */
50*7, /* 2: Bus Error (unemulated) */
50*7, /* 3: Address Error (unemulated) */
34*7, /* 4: Illegal Instruction */
38*7, /* 5: Divide by Zero -- ASG: changed from 42 */
40*7, /* 6: CHK -- ASG: chanaged from 44 */
34*7, /* 7: TRAPV */
34*7, /* 8: Privilege Violation */
34*7, /* 9: Trace */
4*7, /* 10: 1010 */
4*7, /* 11: 1111 */
4*7, /* 12: RESERVED */
4*7, /* 13: Coprocessor Protocol Violation (unemulated) */
4*7, /* 14: Format Error */
44*7, /* 15: Uninitialized Interrupt */
4*7, /* 16: RESERVED */
4*7, /* 17: RESERVED */
4*7, /* 18: RESERVED */
4*7, /* 19: RESERVED */
4*7, /* 20: RESERVED */
4*7, /* 21: RESERVED */
4*7, /* 22: RESERVED */
4*7, /* 23: RESERVED */
44*7, /* 24: Spurious Interrupt */
44*7, /* 25: Level 1 Interrupt Autovector */
44*7, /* 26: Level 2 Interrupt Autovector */
44*7, /* 27: Level 3 Interrupt Autovector */
44*7, /* 28: Level 4 Interrupt Autovector */
44*7, /* 29: Level 5 Interrupt Autovector */
44*7, /* 30: Level 6 Interrupt Autovector */
44*7, /* 31: Level 7 Interrupt Autovector */
34*7, /* 32: TRAP #0 -- ASG: chanaged from 38 */
34*7, /* 33: TRAP #1 */
34*7, /* 34: TRAP #2 */
34*7, /* 35: TRAP #3 */
34*7, /* 36: TRAP #4 */
34*7, /* 37: TRAP #5 */
34*7, /* 38: TRAP #6 */
34*7, /* 39: TRAP #7 */
34*7, /* 40: TRAP #8 */
34*7, /* 41: TRAP #9 */
34*7, /* 42: TRAP #10 */
34*7, /* 43: TRAP #11 */
34*7, /* 44: TRAP #12 */
34*7, /* 45: TRAP #13 */
34*7, /* 46: TRAP #14 */
34*7, /* 47: TRAP #15 */
4*7, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
4*7, /* 49: FP Inexact Result (unemulated) */
4*7, /* 50: FP Divide by Zero (unemulated) */
4*7, /* 51: FP Underflow (unemulated) */
4*7, /* 52: FP Operand Error (unemulated) */
4*7, /* 53: FP Overflow (unemulated) */
4*7, /* 54: FP Signaling NAN (unemulated) */
4*7, /* 55: FP Unimplemented Data Type (unemulated) */
4*7, /* 56: MMU Configuration Error (unemulated) */
4*7, /* 57: MMU Illegal Operation Error (unemulated) */
4*7, /* 58: MMU Access Level Violation Error (unemulated) */
4*7, /* 59: RESERVED */
4*7, /* 60: RESERVED */
4*7, /* 61: RESERVED */
4*7, /* 62: RESERVED */
4*7, /* 63: RESERVED */
40*MUL, /* 0: Reset - Initial Stack Pointer */
4*MUL, /* 1: Reset - Initial Program Counter */
50*MUL, /* 2: Bus Error (unemulated) */
50*MUL, /* 3: Address Error (unemulated) */
34*MUL, /* 4: Illegal Instruction */
38*MUL, /* 5: Divide by Zero -- ASG: changed from 42 */
40*MUL, /* 6: CHK -- ASG: chanaged from 44 */
34*MUL, /* 7: TRAPV */
34*MUL, /* 8: Privilege Violation */
34*MUL, /* 9: Trace */
4*MUL, /* 10: 1010 */
4*MUL, /* 11: 1111 */
4*MUL, /* 12: RESERVED */
4*MUL, /* 13: Coprocessor Protocol Violation (unemulated) */
4*MUL, /* 14: Format Error */
44*MUL, /* 15: Uninitialized Interrupt */
4*MUL, /* 16: RESERVED */
4*MUL, /* 17: RESERVED */
4*MUL, /* 18: RESERVED */
4*MUL, /* 19: RESERVED */
4*MUL, /* 20: RESERVED */
4*MUL, /* 21: RESERVED */
4*MUL, /* 22: RESERVED */
4*MUL, /* 23: RESERVED */
44*MUL, /* 24: Spurious Interrupt */
44*MUL, /* 25: Level 1 Interrupt Autovector */
44*MUL, /* 26: Level 2 Interrupt Autovector */
44*MUL, /* 27: Level 3 Interrupt Autovector */
44*MUL, /* 28: Level 4 Interrupt Autovector */
44*MUL, /* 29: Level 5 Interrupt Autovector */
44*MUL, /* 30: Level 6 Interrupt Autovector */
44*MUL, /* 31: Level 7 Interrupt Autovector */
34*MUL, /* 32: TRAP #0 -- ASG: chanaged from 38 */
34*MUL, /* 33: TRAP #1 */
34*MUL, /* 34: TRAP #2 */
34*MUL, /* 35: TRAP #3 */
34*MUL, /* 36: TRAP #4 */
34*MUL, /* 37: TRAP #5 */
34*MUL, /* 38: TRAP #6 */
34*MUL, /* 39: TRAP #7 */
34*MUL, /* 40: TRAP #8 */
34*MUL, /* 41: TRAP #9 */
34*MUL, /* 42: TRAP #10 */
34*MUL, /* 43: TRAP #11 */
34*MUL, /* 44: TRAP #12 */
34*MUL, /* 45: TRAP #13 */
34*MUL, /* 46: TRAP #14 */
34*MUL, /* 47: TRAP #15 */
4*MUL, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
4*MUL, /* 49: FP Inexact Result (unemulated) */
4*MUL, /* 50: FP Divide by Zero (unemulated) */
4*MUL, /* 51: FP Underflow (unemulated) */
4*MUL, /* 52: FP Operand Error (unemulated) */
4*MUL, /* 53: FP Overflow (unemulated) */
4*MUL, /* 54: FP Signaling NAN (unemulated) */
4*MUL, /* 55: FP Unimplemented Data Type (unemulated) */
4*MUL, /* 56: MMU Configuration Error (unemulated) */
4*MUL, /* 57: MMU Illegal Operation Error (unemulated) */
4*MUL, /* 58: MMU Access Level Violation Error (unemulated) */
4*MUL, /* 59: RESERVED */
4*MUL, /* 60: RESERVED */
4*MUL, /* 61: RESERVED */
4*MUL, /* 62: RESERVED */
4*MUL, /* 63: RESERVED */
/* 64-255: User Defined */
4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,
4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,
4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,
4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,
4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,
4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7,4*7
4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,
4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,
4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,
4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,
4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,
4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL,4*MUL
};
/* Read data immediately after the program counter */
@ -969,10 +787,6 @@ INLINE void m68ki_exception_address_error(void);
INLINE void m68ki_exception_interrupt(uint int_level);
INLINE void m68ki_check_interrupts(void); /* ASG: check for interrupts */
/* External ressources (specific to Genesis Plus GX core) */
extern int vdp_68k_irq_ack(int int_level);
extern uint32 mcycles_68k;
/* ======================================================================== */
/* =========================== UTILITY FUNCTIONS ========================== */
/* ======================================================================== */
@ -1052,74 +866,73 @@ INLINE uint m68ki_read_imm_32(void)
*/
INLINE uint m68ki_read_8_fc(uint address, uint fc)
{
_m68k_memory_map *temp;
cpu_memory_map *temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];;
m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */
temp = &m68k_memory_map[((address)>>16)&0xff];
if (temp->read8) return (*temp->read8)(ADDRESS_68K(address));
else return READ_BYTE(temp->base, (address) & 0xffff);
}
INLINE uint m68ki_read_16_fc(uint address, uint fc)
{
_m68k_memory_map *temp;
cpu_memory_map *temp;
m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */
m68ki_check_address_error(address, MODE_READ, fc) /* auto-disable (see m68kcpu.h) */
temp = &m68k_memory_map[((address)>>16)&0xff];
temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];
if (temp->read16) return (*temp->read16)(ADDRESS_68K(address));
else return *(uint16 *)(temp->base + ((address) & 0xffff));
}
INLINE uint m68ki_read_32_fc(uint address, uint fc)
{
_m68k_memory_map *temp;
cpu_memory_map *temp;
m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */
m68ki_check_address_error(address, MODE_READ, fc) /* auto-disable (see m68kcpu.h) */
temp = &m68k_memory_map[((address)>>16)&0xff];
temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];
if (temp->read16) return ((*temp->read16)(ADDRESS_68K(address)) << 16) | ((*temp->read16)(ADDRESS_68K(address + 2)));
else return m68k_read_immediate_32(address);
}
INLINE void m68ki_write_8_fc(uint address, uint fc, uint value)
{
_m68k_memory_map *temp;
cpu_memory_map *temp;
m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */
temp = &m68k_memory_map[((address)>>16)&0xff];
temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];
if (temp->write8) (*temp->write8)(ADDRESS_68K(address),value);
else WRITE_BYTE(temp->base, (address) & 0xffff, value);
}
INLINE void m68ki_write_16_fc(uint address, uint fc, uint value)
{
_m68k_memory_map *temp;
cpu_memory_map *temp;
m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */
m68ki_check_address_error(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */
temp = &m68k_memory_map[((address)>>16)&0xff];
temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];
if (temp->write16) (*temp->write16)(ADDRESS_68K(address),value);
else *(uint16 *)(temp->base + ((address) & 0xffff)) = value;
}
INLINE void m68ki_write_32_fc(uint address, uint fc, uint value)
{
_m68k_memory_map *temp;
cpu_memory_map *temp;
m68ki_set_fc(fc) /* auto-disable (see m68kcpu.h) */
m68ki_check_address_error(address, MODE_WRITE, fc) /* auto-disable (see m68kcpu.h) */
temp = &m68k_memory_map[((address)>>16)&0xff];
temp = &m68ki_cpu.memory_map[((address)>>16)&0xff];
if (temp->write16) (*temp->write16)(ADDRESS_68K(address),value>>16);
else *(uint16 *)(temp->base + ((address) & 0xffff)) = value >> 16;
temp = &m68k_memory_map[((address + 2)>>16)&0xff];
temp = &m68ki_cpu.memory_map[((address + 2)>>16)&0xff];
if (temp->write16) (*temp->write16)(ADDRESS_68K(address+2),value&0xffff);
else *(uint16 *)(temp->base + ((address + 2) & 0xffff)) = value;
}
@ -1396,13 +1209,13 @@ INLINE void m68ki_stack_frame_buserr(uint sr)
m68ki_push_32(REG_PC);
m68ki_push_16(sr);
m68ki_push_16(REG_IR);
m68ki_push_32(m68ki_aerr_address); /* access address */
m68ki_push_32(m68ki_cpu.aerr_address); /* access address */
/* 0 0 0 0 0 0 0 0 0 0 0 R/W I/N FC
* R/W 0 = write, 1 = read
* I/N 0 = instruction, 1 = not
* FC 3-bit function code
*/
m68ki_push_16(m68ki_aerr_write_mode | CPU_INSTR_MODE | m68ki_aerr_fc);
m68ki_push_16(m68ki_cpu.aerr_write_mode | CPU_INSTR_MODE | m68ki_cpu.aerr_fc);
}
#endif
@ -1520,7 +1333,7 @@ INLINE void m68ki_exception_address_error(void)
if(CPU_RUN_MODE == RUN_MODE_BERR_AERR_RESET)
{
CPU_STOPPED = STOP_LEVEL_HALT;
END_CYCLES(end_cycles);
SET_CYCLES(m68ki_cpu.cycle_end - CYC_INSTRUCTION[REG_IR]);
return;
}
CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET;
@ -1545,7 +1358,7 @@ INLINE void m68ki_exception_interrupt(uint int_level)
#endif /* M68K_EMULATE_ADDRESS_ERROR */
/* Turn off the stopped state */
CPU_STOPPED &= ~STOP_LEVEL_STOP;
CPU_STOPPED &= STOP_LEVEL_HALT;
/* If we are halted, don't do anything */
if(CPU_STOPPED)
@ -1561,7 +1374,7 @@ INLINE void m68ki_exception_interrupt(uint int_level)
FLAG_INT_MASK = int_level<<8;
/* Acknowledge the interrupt */
m68ki_int_ack(int_level)
m68ki_int_ack(int_level);
/* Get the new PC */
new_pc = m68ki_read_data_32(vector<<2);
@ -1586,8 +1399,6 @@ INLINE void m68ki_check_interrupts(void)
m68ki_exception_interrupt(CPU_INT_LEVEL>>8);
}
#endif /* _MEM68K_H_ */
/* ======================================================================== */
/* ============================== END OF FILE ============================= */

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ INLINE void UseDivuCycles(uint32 dst, uint32 src)
int i;
/* minimum cycle time */
uint mcycles = 38 * 7;
uint mcycles = 38 * MUL;
/* 16-bit divisor */
src <<= 16;
@ -27,13 +27,13 @@ INLINE void UseDivuCycles(uint32 dst, uint32 src)
{
/* shift dividend and add two cycles */
dst <<= 1;
mcycles += (2 * 7);
mcycles += (2 * MUL);
if (dst >= src)
{
/* apply divisor and remove one cycle */
dst -= src;
mcycles -= 7;
mcycles -= 1 * MUL;
}
}
}
@ -44,10 +44,10 @@ INLINE void UseDivuCycles(uint32 dst, uint32 src)
INLINE void UseDivsCycles(sint32 dst, sint16 src)
{
/* minimum cycle time */
uint mcycles = 6 * 7;
uint mcycles = 6 * MUL;
/* negative dividend */
if (dst < 0) mcycles += 7;
if (dst < 0) mcycles += 1 * MUL;
if ((abs(dst) >> 16) < abs(src))
{
@ -57,27 +57,27 @@ INLINE void UseDivsCycles(sint32 dst, sint16 src)
uint32 quotient = abs(dst) / abs(src);
/* add default cycle time */
mcycles += (55 * 7);
mcycles += (55 * MUL);
/* positive divisor */
if (src >= 0)
{
/* check dividend sign */
if (dst >= 0) mcycles -= 7;
else mcycles += 7;
if (dst >= 0) mcycles -= 1 * MUL;
else mcycles += 1 * MUL;
}
/* check higher 15-bits of quotient */
for (i=0; i<15; i++)
{
quotient >>= 1;
if (!(quotient & 1)) mcycles += 7;
if (!(quotient & 1)) mcycles += 1 * MUL;
}
}
else
{
/* absolute overflow */
mcycles += (2 * 7);
mcycles += (2 * MUL);
}
USE_CYCLES(mcycles << 1);
@ -86,12 +86,12 @@ INLINE void UseDivsCycles(sint32 dst, sint16 src)
INLINE void UseMuluCycles(uint16 src)
{
/* minimum cycle time */
uint mcycles = 38 * 7;
uint mcycles = 38 * MUL;
/* count number of bits set to 1 */
while (src)
{
if (src & 1) mcycles += (7 * 2);
if (src & 1) mcycles += (2 * MUL);
src >>= 1;
}
@ -102,7 +102,7 @@ INLINE void UseMuluCycles(uint16 src)
INLINE void UseMulsCycles(sint16 src)
{
/* minimum cycle time */
uint mcycles = 38 * 7;
uint mcycles = 38 * MUL;
/* detect 01 or 10 patterns */
sint32 tmp = src << 1;
@ -111,7 +111,7 @@ INLINE void UseMulsCycles(sint16 src)
/* count number of bits set to 1 */
while (tmp)
{
if (tmp & 1) mcycles += (7 * 2);
if (tmp & 1) mcycles += (2 * MUL);
tmp >>= 1;
}
@ -7218,8 +7218,11 @@ static void m68k_op_dbf_16(void)
{
uint* r_dst = &DY;
uint res = MASK_OUT_ABOVE_16(*r_dst - 1);
*r_dst = MASK_OUT_BELOW_16(*r_dst) | res;
/* reset idle loop detection */
m68ki_cpu.poll.detected = 0;
if(res != 0xffff)
{
uint offset = OPER_I_16();
@ -20896,7 +20899,7 @@ static void m68k_op_stop(void)
uint new_sr = OPER_I_16();
CPU_STOPPED |= STOP_LEVEL_STOP;
m68ki_set_sr(new_sr);
END_CYCLES(end_cycles - 4*7);
SET_CYCLES(m68ki_cpu.cycle_end - 4*MUL);
return;
}
m68ki_exception_privilege_violation();
@ -25345,7 +25348,7 @@ static void m68ki_build_opcode_table(void)
if((i & ostruct->mask) == ostruct->match)
{
m68ki_instruction_jump_table[i] = ostruct->opcode_handler;
m68ki_cycles[i] = ostruct->cycles * 7;
m68ki_cycles[i] = ostruct->cycles * MUL;
}
}
ostruct++;
@ -25355,7 +25358,7 @@ static void m68ki_build_opcode_table(void)
for(i = 0;i <= 0xff;i++)
{
m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler;
m68ki_cycles[ostruct->match | i] = ostruct->cycles * 7;
m68ki_cycles[ostruct->match | i] = ostruct->cycles * MUL;
}
ostruct++;
}
@ -25367,7 +25370,7 @@ static void m68ki_build_opcode_table(void)
{
instr = ostruct->match | (i << 9) | j;
m68ki_instruction_jump_table[instr] = ostruct->opcode_handler;
m68ki_cycles[instr] = ostruct->cycles * 7;
m68ki_cycles[instr] = ostruct->cycles * MUL;
}
}
ostruct++;
@ -25377,7 +25380,7 @@ static void m68ki_build_opcode_table(void)
for(i = 0;i <= 0x0f;i++)
{
m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler;
m68ki_cycles[ostruct->match | i] = ostruct->cycles * 7;
m68ki_cycles[ostruct->match | i] = ostruct->cycles * MUL;
}
ostruct++;
}
@ -25386,7 +25389,7 @@ static void m68ki_build_opcode_table(void)
for(i = 0;i <= 0x07;i++)
{
m68ki_instruction_jump_table[ostruct->match | (i << 9)] = ostruct->opcode_handler;
m68ki_cycles[ostruct->match | (i << 9)] = ostruct->cycles * 7;
m68ki_cycles[ostruct->match | (i << 9)] = ostruct->cycles * MUL;
}
ostruct++;
}
@ -25395,14 +25398,14 @@ static void m68ki_build_opcode_table(void)
for(i = 0;i <= 0x07;i++)
{
m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler;
m68ki_cycles[ostruct->match | i] = ostruct->cycles * 7;
m68ki_cycles[ostruct->match | i] = ostruct->cycles * MUL;
}
ostruct++;
}
while(ostruct->mask == 0xffff)
{
m68ki_instruction_jump_table[ostruct->match] = ostruct->opcode_handler;
m68ki_cycles[ostruct->match] = ostruct->cycles * 7;
m68ki_cycles[ostruct->match] = ostruct->cycles * MUL;
ostruct++;
}
}

93
source/m68k/s68kconf.h Normal file
View File

@ -0,0 +1,93 @@
#ifndef M68KCONF__HEADER
#define M68KCONF__HEADER
/* ======================================================================== */
/* ======================== SUB 68K CONFIGURATION ========================= */
/* ======================================================================== */
/* Configuration switches.
* Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks.
* OPT_SPECIFY_HANDLER causes the core to link directly to the function
* or macro you specify, rather than using callback functions whose pointer
* must be passed in using m68k_set_xxx_callback().
*/
#define OPT_OFF 0
#define OPT_ON 1
#define OPT_SPECIFY_HANDLER 2
/* If ON, the CPU will call m68k_write_32_pd() when it executes move.l with a
* predecrement destination EA mode instead of m68k_write_32().
* To simulate real 68k behavior, m68k_write_32_pd() must first write the high
* word to [address+2], and then write the low word to [address].
*/
#define M68K_SIMULATE_PD_WRITES OPT_OFF
/* If ON, CPU will call the interrupt acknowledge callback when it services an
* interrupt.
* If off, all interrupts will be autovectored and all interrupt requests will
* auto-clear when the interrupt is serviced.
*/
#define M68K_EMULATE_INT_ACK OPT_SPECIFY_HANDLER
#define M68K_INT_ACK_CALLBACK(A) scd_68k_irq_ack(A)
/* If ON, CPU will call the output reset callback when it encounters a reset
* instruction.
*/
#define M68K_EMULATE_RESET OPT_OFF
#define M68K_RESET_CALLBACK() your_reset_handler_function()
/* If ON, CPU will call the callback when it encounters a tas
* instruction.
*/
#define M68K_TAS_HAS_CALLBACK OPT_SPECIFY_HANDLER
#define M68K_TAS_CALLBACK() 1
/* If ON, CPU will call the set fc callback on every memory access to
* differentiate between user/supervisor, program/data access like a real
* 68000 would. This should be enabled and the callback should be set if you
* want to properly emulate the m68010 or higher. (moves uses function codes
* to read/write data from different address spaces)
*/
#define M68K_EMULATE_FC OPT_OFF
#define M68K_SET_FC_CALLBACK(A) your_set_fc_handler_function(A)
/* If ON, the CPU will monitor the trace flags and take trace exceptions
*/
#define M68K_EMULATE_TRACE OPT_OFF
/* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
#define M68K_EMULATE_PREFETCH OPT_OFF
/* If ON, the CPU will generate address error exceptions if it tries to
* access a word or longword at an odd address.
* NOTE: This is only emulated properly for 68000 mode.
*/
#define M68K_EMULATE_ADDRESS_ERROR OPT_OFF
/* If ON and previous option is also ON, address error exceptions will
also be checked when fetching instructions. Disabling this can help
speeding up emulation while still emulating address error exceptions
on other memory access if needed.
* NOTE: This is only emulated properly for 68000 mode.
*/
#define M68K_CHECK_PC_ADDRESS_ERROR OPT_OFF
/* ----------------------------- COMPATIBILITY ---------------------------- */
/* The following options set optimizations that violate the current ANSI
* standard, but will be compliant under the forthcoming C9X standard.
*/
/* If ON, the enulation core will use 64-bit integers to speed up some
* operations.
*/
#define M68K_USE_64_BIT OPT_OFF
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */
#endif /* M68KCONF__HEADER */

340
source/m68k/s68kcpu.c Normal file
View File

@ -0,0 +1,340 @@
/* ======================================================================== */
/* SUB 68K CORE */
/* ======================================================================== */
extern int scd_68k_irq_ack(int level);
#define m68ki_cpu s68k
#define MUL (4)
/* ======================================================================== */
/* ================================ INCLUDES ============================== */
/* ======================================================================== */
#ifndef BUILD_TABLES
#include "s68ki_cycles.h"
#endif
#include "s68kconf.h"
#include "m68kcpu.h"
#include "m68kops.h"
/* ======================================================================== */
/* ================================= DATA ================================= */
/* ======================================================================== */
#ifdef BUILD_TABLES
static unsigned char s68ki_cycles[0x10000];
#endif
static int irq_latency;
/* IRQ priority */
static const uint8 irq_level[0x40] =
{
0, 1, 2, 2, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6
};
m68ki_cpu_core s68k;
/* ======================================================================== */
/* =============================== CALLBACKS ============================== */
/* ======================================================================== */
/* Default callbacks used if the callback hasn't been set yet, or if the
* callback is set to NULL
*/
#if M68K_EMULATE_INT_ACK == OPT_ON
/* Interrupt acknowledge */
static int default_int_ack_callback(int int_level)
{
CPU_INT_LEVEL = 0;
return M68K_INT_ACK_AUTOVECTOR;
}
#endif
#if M68K_EMULATE_RESET == OPT_ON
/* Called when a reset instruction is executed */
static void default_reset_instr_callback(void)
{
}
#endif
#if M68K_TAS_HAS_CALLBACK == OPT_ON
/* Called when a tas instruction is executed */
static int default_tas_instr_callback(void)
{
return 1; // allow writeback
}
#endif
#if M68K_EMULATE_FC == OPT_ON
/* Called every time there's bus activity (read/write to/from memory */
static void default_set_fc_callback(unsigned int new_fc)
{
}
#endif
/* ======================================================================== */
/* ================================= API ================================== */
/* ======================================================================== */
/* Access the internals of the CPU */
unsigned int s68k_get_reg(m68k_register_t regnum)
{
switch(regnum)
{
case M68K_REG_D0: return m68ki_cpu.dar[0];
case M68K_REG_D1: return m68ki_cpu.dar[1];
case M68K_REG_D2: return m68ki_cpu.dar[2];
case M68K_REG_D3: return m68ki_cpu.dar[3];
case M68K_REG_D4: return m68ki_cpu.dar[4];
case M68K_REG_D5: return m68ki_cpu.dar[5];
case M68K_REG_D6: return m68ki_cpu.dar[6];
case M68K_REG_D7: return m68ki_cpu.dar[7];
case M68K_REG_A0: return m68ki_cpu.dar[8];
case M68K_REG_A1: return m68ki_cpu.dar[9];
case M68K_REG_A2: return m68ki_cpu.dar[10];
case M68K_REG_A3: return m68ki_cpu.dar[11];
case M68K_REG_A4: return m68ki_cpu.dar[12];
case M68K_REG_A5: return m68ki_cpu.dar[13];
case M68K_REG_A6: return m68ki_cpu.dar[14];
case M68K_REG_A7: return m68ki_cpu.dar[15];
case M68K_REG_PC: return MASK_OUT_ABOVE_32(m68ki_cpu.pc);
case M68K_REG_SR: return m68ki_cpu.t1_flag |
(m68ki_cpu.s_flag << 11) |
m68ki_cpu.int_mask |
((m68ki_cpu.x_flag & XFLAG_SET) >> 4) |
((m68ki_cpu.n_flag & NFLAG_SET) >> 4) |
((!m68ki_cpu.not_z_flag) << 2) |
((m68ki_cpu.v_flag & VFLAG_SET) >> 6) |
((m68ki_cpu.c_flag & CFLAG_SET) >> 8);
case M68K_REG_SP: return m68ki_cpu.dar[15];
case M68K_REG_USP: return m68ki_cpu.s_flag ? m68ki_cpu.sp[0] : m68ki_cpu.dar[15];
case M68K_REG_ISP: return m68ki_cpu.s_flag ? m68ki_cpu.dar[15] : m68ki_cpu.sp[4];
#if M68K_EMULATE_PREFETCH
case M68K_REG_PREF_ADDR: return m68ki_cpu.pref_addr;
case M68K_REG_PREF_DATA: return m68ki_cpu.pref_data;
#endif
case M68K_REG_IR: return m68ki_cpu.ir;
default: return 0;
}
}
void s68k_set_reg(m68k_register_t regnum, unsigned int value)
{
switch(regnum)
{
case M68K_REG_D0: REG_D[0] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_D1: REG_D[1] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_D2: REG_D[2] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_D3: REG_D[3] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_D4: REG_D[4] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_D5: REG_D[5] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_D6: REG_D[6] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_D7: REG_D[7] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A0: REG_A[0] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A1: REG_A[1] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A2: REG_A[2] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A3: REG_A[3] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A4: REG_A[4] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A5: REG_A[5] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A6: REG_A[6] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A7: REG_A[7] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_PC: m68ki_jump(MASK_OUT_ABOVE_32(value)); return;
case M68K_REG_SR: m68ki_set_sr(value); return;
case M68K_REG_SP: REG_SP = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_USP: if(FLAG_S)
REG_USP = MASK_OUT_ABOVE_32(value);
else
REG_SP = MASK_OUT_ABOVE_32(value);
return;
case M68K_REG_ISP: if(FLAG_S)
REG_SP = MASK_OUT_ABOVE_32(value);
else
REG_ISP = MASK_OUT_ABOVE_32(value);
return;
case M68K_REG_IR: REG_IR = MASK_OUT_ABOVE_16(value); return;
#if M68K_EMULATE_PREFETCH
case M68K_REG_PREF_ADDR: CPU_PREF_ADDR = MASK_OUT_ABOVE_32(value); return;
#endif
default: return;
}
}
/* Set the callbacks */
#if M68K_EMULATE_INT_ACK == OPT_ON
void s68k_set_int_ack_callback(int (*callback)(int int_level))
{
CALLBACK_INT_ACK = callback ? callback : default_int_ack_callback;
}
#endif
#if M68K_EMULATE_RESET == OPT_ON
void s68k_set_reset_instr_callback(void (*callback)(void))
{
CALLBACK_RESET_INSTR = callback ? callback : default_reset_instr_callback;
}
#endif
#if M68K_TAS_HAS_CALLBACK == OPT_ON
void s68k_set_tas_instr_callback(int (*callback)(void))
{
CALLBACK_TAS_INSTR = callback ? callback : default_tas_instr_callback;
}
#endif
#if M68K_EMULATE_FC == OPT_ON
void s68k_set_fc_callback(void (*callback)(unsigned int new_fc))
{
CALLBACK_SET_FC = callback ? callback : default_set_fc_callback;
}
#endif
extern void error(char *format, ...);
extern uint16 v_counter;
/* update IRQ level according to triggered interrupts */
void s68k_update_irq(unsigned int mask)
{
/* Get IRQ level (6 interrupt lines) */
mask = irq_level[mask];
/* Set IRQ level */
CPU_INT_LEVEL = mask << 8;
/* Check interrupt mask to process IRQ */
m68ki_check_interrupts();
#ifdef LOG_SCD
error("[%d][%d] IRQ Level = %d(0x%02x) (%x)\n", v_counter, s68k.cycles, CPU_INT_LEVEL>>8,FLAG_INT_MASK,s68k.pc);
#endif
}
void s68k_run(unsigned int cycles)
{
/* Make sure we're not stopped */
if (CPU_STOPPED)
{
s68k.cycles = cycles;
return;
}
/* Return point for when we have an address error (TODO: use goto) */
m68ki_set_address_error_trap() /* auto-disable (see m68kcpu.h) */
/* Save end cycles count for when CPU is stopped */
s68k.cycle_end = cycles;
while (s68k.cycles < cycles)
{
/* Set tracing accodring to T1. */
m68ki_trace_t1() /* auto-disable (see m68kcpu.h) */
/* Set the address space for reads */
m68ki_use_data_space() /* auto-disable (see m68kcpu.h) */
/* Decode next instruction */
REG_IR = m68ki_read_imm_16();
/* Execute instruction */
m68ki_instruction_jump_table[REG_IR](); /* TODO: use labels table with goto */
USE_CYCLES(CYC_INSTRUCTION[REG_IR]); /* TODO: move into instruction handlers */
/* Trace m68k_exception, if necessary */
m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */
}
}
void s68k_init(void)
{
#ifdef BUILD_TABLES
static uint emulation_initialized = 0;
/* The first call to this function initializes the opcode handler jump table */
if(!emulation_initialized)
{
m68ki_build_opcode_table();
emulation_initialized = 1;
}
#endif
#if M68K_EMULATE_INT_ACK == OPT_ON
s68k_set_int_ack_callback(NULL);
#endif
#if M68K_EMULATE_RESET == OPT_ON
s68k_set_reset_instr_callback(NULL);
#endif
#if M68K_TAS_HAS_CALLBACK == OPT_ON
s68k_set_tas_instr_callback(NULL);
#endif
#if M68K_EMULATE_FC == OPT_ON
s68k_set_fc_callback(NULL);
#endif
}
/* Pulse the RESET line on the CPU */
void s68k_pulse_reset(void)
{
/* Clear all stop levels */
CPU_STOPPED = 0;
#if M68K_EMULATE_ADDRESS_ERROR
CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET;
#endif
/* Turn off tracing */
FLAG_T1 = 0;
m68ki_clear_trace()
/* Interrupt mask to level 7 */
FLAG_INT_MASK = 0x0700;
CPU_INT_LEVEL = 0;
irq_latency = 0;
/* Go to supervisor mode */
m68ki_set_s_flag(SFLAG_SET);
/* Invalidate the prefetch queue */
#if M68K_EMULATE_PREFETCH
/* Set to arbitrary number since our first fetch is from 0 */
CPU_PREF_ADDR = 0x1000;
#endif /* M68K_EMULATE_PREFETCH */
/* Read the initial stack pointer and program counter */
m68ki_jump(0);
REG_SP = m68ki_read_imm_32();
REG_PC = m68ki_read_imm_32();
m68ki_jump(REG_PC);
#if M68K_EMULATE_ADDRESS_ERROR
CPU_RUN_MODE = RUN_MODE_NORMAL;
#endif
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_RESET]);
}
void s68k_pulse_halt(void)
{
/* Pulse the HALT line on the CPU */
CPU_STOPPED |= STOP_LEVEL_HALT;
}
void s68k_clear_halt()
{
/* Clear the HALT line on the CPU */
CPU_STOPPED &= ~STOP_LEVEL_HALT;
}
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */

4099
source/m68k/s68ki_cycles.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
/***************************************************************************************
* Genesis Plus
* 68k bus handlers
* Main 68k bus handlers
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -38,18 +38,18 @@
****************************************************************************************/
#include "shared.h"
#include "m68kcpu.h"
/*--------------------------------------------------------------------------*/
/* Unused area (return open bus data, i.e prefetched instruction word) */
/* Unused areas (return open bus data, i.e prefetched instruction word) */
/*--------------------------------------------------------------------------*/
unsigned int m68k_read_bus_8(unsigned int address)
{
#ifdef LOGERROR
error("Unused read8 %08X (%08X)\n", address, m68k_get_reg(M68K_REG_PC));
#endif
return m68k_read_pcrelative_8(REG_PC | (address & 1));
address = m68k.pc | (address & 1);
return READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff);
}
unsigned int m68k_read_bus_16(unsigned int address)
@ -57,18 +57,19 @@ unsigned int m68k_read_bus_16(unsigned int address)
#ifdef LOGERROR
error("Unused read16 %08X (%08X)\n", address, m68k_get_reg(M68K_REG_PC));
#endif
return m68k_read_pcrelative_16(REG_PC);
address = m68k.pc;
return *(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff));
}
void m68k_unused_8_w (unsigned int address, unsigned int data)
void m68k_unused_8_w(unsigned int address, unsigned int data)
{
#ifdef LOGERROR
error("Unused write8 %08X = %02X (%08X)\n", address, data, m68k_get_reg(M68K_REG_PC));
#endif
}
void m68k_unused_16_w (unsigned int address, unsigned int data)
void m68k_unused_16_w(unsigned int address, unsigned int data)
{
#ifdef LOGERROR
error("Unused write16 %08X = %04X (%08X)\n", address, data, m68k_get_reg(M68K_REG_PC));
@ -77,8 +78,9 @@ void m68k_unused_16_w (unsigned int address, unsigned int data)
/*--------------------------------------------------------------------------*/
/* Illegal area (cause system to lock-up since !DTACK is not returned) */
/* Illegal areas (cause system to lock-up since !DTACK is not returned) */
/*--------------------------------------------------------------------------*/
void m68k_lockup_w_8 (unsigned int address, unsigned int data)
{
#ifdef LOGERROR
@ -87,6 +89,7 @@ void m68k_lockup_w_8 (unsigned int address, unsigned int data)
if (!config.force_dtack)
{
m68k_pulse_halt();
m68k.cycles = m68k.cycle_end;
}
}
@ -98,6 +101,7 @@ void m68k_lockup_w_16 (unsigned int address, unsigned int data)
if (!config.force_dtack)
{
m68k_pulse_halt();
m68k.cycles = m68k.cycle_end;
}
}
@ -109,8 +113,10 @@ unsigned int m68k_lockup_r_8 (unsigned int address)
if (!config.force_dtack)
{
m68k_pulse_halt();
m68k.cycles = m68k.cycle_end;
}
return m68k_read_pcrelative_8(REG_PC | (address & 1));
address = m68k.pc | (address & 1);
return READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff);
}
unsigned int m68k_lockup_r_16 (unsigned int address)
@ -121,28 +127,31 @@ unsigned int m68k_lockup_r_16 (unsigned int address)
if (!config.force_dtack)
{
m68k_pulse_halt();
m68k.cycles = m68k.cycle_end;
}
return m68k_read_pcrelative_16(REG_PC);
address = m68k.pc;
return *(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff));
}
/*--------------------------------------------------------------------------*/
/* Z80 bus (accessed through I/O chip) */
/*--------------------------------------------------------------------------*/
unsigned int z80_read_byte(unsigned int address)
{
switch ((address >> 13) & 3)
{
case 2: /* YM2612 */
{
return fm_read(mcycles_68k, address & 3);
return fm_read(m68k.cycles, address & 3);
}
case 3: /* Misc */
{
/* VDP (through 68k bus) */
if ((address & 0xFF00) == 0x7F00)
{
/* VDP (through 68k bus) */
return m68k_lockup_r_8(address);
}
return (m68k_read_bus_8(address) | 0xFF);
@ -167,7 +176,7 @@ void z80_write_byte(unsigned int address, unsigned int data)
{
case 2: /* YM2612 */
{
fm_write(mcycles_68k, address & 3, data);
fm_write(m68k.cycles, address & 3, data);
return;
}
@ -198,7 +207,7 @@ void z80_write_byte(unsigned int address, unsigned int data)
default: /* ZRAM */
{
zram[address & 0x1FFF] = data;
mcycles_68k += 8; /* ZRAM access latency (fixes Pacman 2: New Adventures) */
m68k.cycles += 8; /* ZRAM access latency (fixes Pacman 2: New Adventures) */
return;
}
}
@ -213,6 +222,60 @@ void z80_write_word(unsigned int address, unsigned int data)
/*--------------------------------------------------------------------------*/
/* I/O Control */
/*--------------------------------------------------------------------------*/
INLINE void m68k_poll_detect(reg)
{
/* detect MAIN-CPU register polling */
if (m68k.poll.detected == (1 << reg))
{
if (m68k.cycles <= m68k.poll.cycle)
{
if (m68k.pc == m68k.poll.pc)
{
/* stop MAIN-CPU until register is modified by SUB-CPU */
m68k.cycles = m68k.cycle_end;
m68k.stopped = 1 << reg;
}
return;
}
}
else
{
/* set MAIN-CPU register access flag */
m68k.poll.detected = 1 << reg;
}
/* restart MAIN-CPU polling detection */
m68k.poll.cycle = m68k.cycles + 280;
m68k.poll.pc = m68k.pc;
}
INLINE void m68k_poll_sync(reg)
{
/* relative SUB-CPU cycle counter */
unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE;
/* sync SUB-CPU with MAIN-CPU */
if (!s68k.stopped && (s68k.cycles < cycles))
{
s68k_run(cycles);
}
/* SUB-CPU stopped on register polling ? */
if (s68k.stopped & (3 << reg))
{
/* sync SUB-CPU with MAIN-CPU */
s68k.cycles = cycles;
/* restart SUB-CPU */
s68k.stopped = 0;
}
/* clear CPU register(s) access flags */
m68k.poll.detected &= ~(3 << reg);
s68k.poll.detected &= ~(3 << reg);
}
unsigned int ctrl_io_read_byte(unsigned int address)
{
switch ((address >> 8) & 0xFF)
@ -226,21 +289,69 @@ unsigned int ctrl_io_read_byte(unsigned int address)
return m68k_read_bus_8(address);
}
case 0x11: /* BUSACK */
case 0x11: /* Z80 BUSACK */
{
if (!(address & 1))
{
/* Unused bits return prefetched bus data (Time Killers) */
unsigned int data = m68k_read_pcrelative_8(REG_PC) & 0xFE;
address = m68k.pc;
/* Check if bus has been requested and is not reseted */
if (zstate == 3)
{
return data;
/* D0 is cleared */
return (READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff) & 0xFE);
}
return (data | 0x01);
/* D0 is set */
return (READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff) | 0x01);
}
return m68k_read_bus_8(address);
}
case 0x20: /* MEGA-CD */
{
#ifdef LOG_SCD
error("[%d][%d]read byte CD register %X (%X)\n", v_counter, m68k.cycles, address, m68k.pc);
#endif
/* Memory Mode */
if (address == 0xa12003)
{
m68k_poll_detect(0x03);
return scd.regs[0x03>>1].byte.l;
}
/* SUB-CPU communication flags */
if (address == 0xa1200f)
{
m68k_poll_detect(0x0f);
return scd.regs[0x0f>>1].byte.l;
}
/* default registers */
if (address < 0xa12030)
{
/* SUB-CPU communication words */
if (address >= 0xa12020)
{
m68k_poll_detect((address - 0x10) & 0x1f);
}
/* register LSB */
if (address & 1)
{
return scd.regs[(address >> 1) & 0xff].byte.l;
}
/* register MSB */
return scd.regs[(address >> 1) & 0xff].byte.h;
}
/* invalid address */
return m68k_read_bus_8(address);
}
case 0x30: /* TIME */
{
if (cart.hw.time_r)
@ -259,18 +370,22 @@ unsigned int ctrl_io_read_byte(unsigned int address)
{
if ((config.bios & 1) && (address & 1))
{
unsigned int data = m68k_read_pcrelative_8(REG_PC) & 0xFE;
return (gen_bankswitch_r() | data);
unsigned int data = gen_bankswitch_r() & 1;
/* Unused bits return prefetched bus data */
address = m68k.pc;
data |= (READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff) & 0xFE);
return data;
}
return m68k_read_bus_8(address);
}
case 0x10: /* MEMORY MODE */
case 0x12: /* RESET */
case 0x20: /* MEGA-CD */
case 0x12: /* Z80 RESET */
case 0x13: /* unknown */
case 0x40: /* TMSS */
case 0x44: /* RADICA */
case 0x50: /* SVP REGISTERS */
case 0x50: /* SVP */
{
return m68k_read_bus_8(address);
}
@ -296,15 +411,60 @@ unsigned int ctrl_io_read_word(unsigned int address)
return m68k_read_bus_16(address);
}
case 0x11: /* BUSACK */
case 0x11: /* Z80 BUSACK */
{
/* Unused bits return prefetched bus data (Time Killers) */
unsigned int data = m68k_read_pcrelative_16(REG_PC) & 0xFEFF;
address = m68k.pc;
/* Check if bus has been requested and is not reseted */
if (zstate == 3)
{
return data;
/* D8 is cleared */
return (*(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff)) & 0xFEFF);
}
return (data | 0x0100);
/* D8 is set */
return (*(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff)) | 0x0100);
}
case 0x20: /* MEGA-CD */
{
#ifdef LOG_SCD
error("[%d][%d]read word CD register %X (%X)\n", v_counter, m68k.cycles, address, m68k.pc);
#endif
/* Memory Mode */
if (address == 0xa12002)
{
m68k_poll_detect(0x03);
return scd.regs[0x03>>1].w;
}
/* CDC host data (word access only ?) */
if (address == 0xa12008)
{
return cdc_host_r();
}
/* H-INT vector (word access only ?) */
if (address == 0xa12006)
{
return *(uint16 *)(m68k.memory_map[0].base + 0x72);
}
/* default registers */
if (address < 0xa12030)
{
/* SUB-CPU communication words */
if (address >= 0xa12020)
{
m68k_poll_detect((address - 0x10) & 0x1e);
}
return scd.regs[(address >> 1) & 0xff].w;
}
/* invalid address */
return m68k_read_bus_16(address);
}
case 0x30: /* TIME */
@ -334,8 +494,8 @@ unsigned int ctrl_io_read_word(unsigned int address)
}
case 0x10: /* MEMORY MODE */
case 0x12: /* RESET */
case 0x20: /* MEGA-CD */
case 0x12: /* Z80 RESET */
case 0x13: /* unknown */
case 0x40: /* TMSS */
case 0x41: /* BOOT ROM */
case 0x44: /* RADICA */
@ -366,28 +526,190 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data)
return;
}
case 0x11: /* BUSREQ */
case 0x11: /* Z80 BUSREQ */
{
if (!(address & 1))
{
gen_zbusreq_w(data & 1, mcycles_68k);
gen_zbusreq_w(data & 1, m68k.cycles);
return;
}
m68k_unused_8_w(address, data);
return;
}
case 0x12: /* RESET */
case 0x12: /* Z80 RESET */
{
if (!(address & 1))
{
gen_zreset_w(data & 1, mcycles_68k);
gen_zreset_w(data & 1, m68k.cycles);
return;
}
m68k_unused_8_w(address, data);
return;
}
case 0x20: /* MEGA-CD */
{
#ifdef LOG_SCD
error("[%d][%d]write byte CD register %X -> 0x%02X (%X)\n", v_counter, m68k.cycles, address, data, m68k.pc);
#endif
switch (address & 0xff)
{
case 0x00: /* SUB-CPU interrupt */
{
/* IFL2 bit */
if (data & 0x01)
{
/* level 2 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x04)
{
/* relative SUB-CPU cycle counter */
unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE;
/* sync SUB-CPU with MAIN-CPU */
if (!s68k.stopped && (s68k.cycles < cycles))
{
s68k_run(cycles);
}
/* set IFL2 flag */
scd.regs[0x00].byte.h |= 0x01;
/* trigger level 2 interrupt */
scd.pending |= (1 << 2);
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
/* writing 0 does nothing */
return;
}
case 0x01: /* SUB-CPU control */
{
/* RESET bit */
if (data & 0x01)
{
/* trigger reset on 0->1 transition */
if (!(scd.regs[0x00].byte.l & 0x01))
{
/* reset SUB-CPU */
s68k_pulse_reset();
}
/* BUSREQ bit */
if (data & 0x02)
{
/* SUB-CPU bus requested */
s68k_pulse_halt();
}
else
{
/* SUB-CPU bus released */
s68k_clear_halt();
}
}
else
{
/* SUB-CPU is halted while !RESET is asserted */
s68k_pulse_halt();
}
scd.regs[0x00].byte.l = data;
return;
}
case 0x03: /* Memory mode */
{
m68k_poll_sync(0x02);
/* PRG-RAM 128k bank mapped to $020000-$03FFFF (resp. $420000-$43FFFF) */
m68k.memory_map[scd.cartridge.boot + 0x02].base = scd.prg_ram + ((data & 0xc0) << 11);
m68k.memory_map[scd.cartridge.boot + 0x03].base = m68k.memory_map[scd.cartridge.boot + 0x02].base + 0x10000;
/* check current mode */
if (scd.regs[0x03>>1].byte.l & 0x04)
{
/* DMNA bit */
if (data & 0x02)
{
/* writing 1 to DMNA in 1M mode will return Word-RAM to SUB-CPU in 2M mode */
scd.dmna = 1;
}
else
{
/* writing 0 to DMNA in 1M mode actually set DMNA bit */
data |= 0x02;
/* update BK0-1 & DMNA bits */
scd.regs[0x03>>1].byte.l = (scd.regs[0x03>>1].byte.l & ~0xc2) | (data & 0xc2);
return;
}
}
else
{
/* writing 0 in 2M mode does nothing */
if (data & 0x02)
{
/* Word-RAM is assigned to SUB-CPU */
scd.dmna = 1;
/* clear RET bit */
scd.regs[0x03>>1].byte.l = (scd.regs[0x03>>1].byte.l & ~0xc3) | (data & 0xc2);
return;
}
}
/* update BK0-1 bits */
scd.regs[0x03>>1].byte.l = (scd.regs[0x02>>1].byte.l & ~0xc0) | (data & 0xc0);
return;
}
case 0x0f: /* SUB-CPU communication flags, normally read-only (Space Ace, Dragon's Lair) */
{
/* ROL8 operation */
data = (data << 1) | ((data >> 7) & 1);
}
case 0x0e: /* MAIN-CPU communication flags */
{
m68k_poll_sync(0x0e);
scd.regs[0x0e>>1].byte.h = data;
return;
}
default:
{
/* default registers */
if (address < 0xa12020)
{
/* MAIN-CPU communication words */
if (address >= 0xa12010)
{
m68k_poll_sync(address & 0x1e);
}
/* register LSB */
if (address & 1)
{
scd.regs[(address >> 1) & 0xff].byte.l = data;
return;
}
/* register MSB */
scd.regs[(address >> 1) & 0xff].byte.h = data;
return;
}
/* invalid address */
m68k_unused_8_w(address, data);
return;
}
}
}
case 0x30: /* TIME */
{
cart.hw.time_w(address, data);
@ -406,10 +728,10 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data)
}
case 0x10: /* MEMORY MODE */
case 0x20: /* MEGA-CD */
case 0x13: /* unknown */
case 0x40: /* TMSS */
case 0x44: /* RADICA */
case 0x50: /* SVP REGISTERS */
case 0x50: /* SVP */
{
m68k_unused_8_w(address, data);
return;
@ -438,18 +760,160 @@ void ctrl_io_write_word(unsigned int address, unsigned int data)
return;
}
case 0x11: /* BUSREQ */
case 0x11: /* Z80 BUSREQ */
{
gen_zbusreq_w((data >> 8) & 1, mcycles_68k);
gen_zbusreq_w((data >> 8) & 1, m68k.cycles);
return;
}
case 0x12: /* RESET */
case 0x12: /* Z80 RESET */
{
gen_zreset_w((data >> 8) & 1, mcycles_68k);
gen_zreset_w((data >> 8) & 1, m68k.cycles);
return;
}
case 0x20: /* MEGA-CD */
{
#ifdef LOG_SCD
error("[%d][%d]write word CD register %X -> 0x%04X (%X)\n", v_counter, m68k.cycles, address, data, m68k.pc);
#endif
switch (address & 0xfe)
{
case 0x00: /* SUB-CPU interrupt & control */
{
/* RESET bit */
if (data & 0x01)
{
/* trigger reset on 0->1 transition */
if (!(scd.regs[0x00].byte.l & 0x01))
{
/* reset SUB-CPU */
s68k_pulse_reset();
}
/* BUSREQ bit */
if (data & 0x02)
{
/* SUB-CPU bus requested */
s68k_pulse_halt();
}
else
{
/* SUB-CPU bus released */
s68k_clear_halt();
}
}
else
{
/* SUB-CPU is halted while !RESET is asserted */
s68k_pulse_halt();
}
/* IFL2 bit */
if (data & 0x100)
{
/* level 2 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x04)
{
/* set IFL2 flag */
scd.regs[0x00].byte.h |= 0x01;
/* trigger level 2 interrupt */
scd.pending |= (1 << 2);
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
/* update LSB only */
scd.regs[0x00].byte.l = data & 0xff;
return;
}
case 0x02: /* Memory Mode */
{
m68k_poll_sync(0x02);
/* PRG-RAM 128k bank mapped to $020000-$03FFFF (resp. $420000-$43FFFF) */
m68k.memory_map[scd.cartridge.boot + 0x02].base = scd.prg_ram + ((data & 0xc0) << 11);
m68k.memory_map[scd.cartridge.boot + 0x03].base = m68k.memory_map[scd.cartridge.boot + 0x02].base + 0x10000;
/* check current mode */
if (scd.regs[0x03>>1].byte.l & 0x04)
{
/* DMNA bit */
if (data & 0x02)
{
/* writing 1 to DMNA in 1M mode will return Word-RAM to SUB-CPU in 2M mode */
scd.dmna = 1;
}
else
{
/* writing 0 to DMNA in 1M mode actually set DMNA bit */
data |= 0x02;
/* update WP0-7, BK0-1 & DMNA bits */
scd.regs[0x02>>1].w = (scd.regs[0x02>>1].w & ~0xffc2) | (data & 0xffc2);
return;
}
}
else
{
/* writing 0 in 2M mode does nothing */
if (data & 0x02)
{
/* Word-RAM is assigned to SUB-CPU */
scd.dmna = 1;
/* clear RET bit */
scd.regs[0x02>>1].w = (scd.regs[0x02>>1].w & ~0xffc3) | (data & 0xffc2);
return;
}
}
/* update WP0-7 & BK0-1 bits */
scd.regs[0x02>>1].w = (scd.regs[0x02>>1].w & ~0xffc0) | (data & 0xffc0);
return;
}
case 0x06: /* H-INT vector (word access only ?) */
{
*(uint16 *)(m68k.memory_map[0].base + 0x72) = data;
return;
}
case 0x0e: /* MAIN-CPU communication flags */
{
m68k_poll_sync(0x0e);
/* LSB is read-only (Mortal Kombat) */
scd.regs[0x0e>>1].byte.h = data;
return;
}
default:
{
if (address < 0xa12020)
{
/* MAIN-CPU communication words */
if (address >= 0xa12010)
{
m68k_poll_sync(address & 0x1e);
}
/* default registers */
scd.regs[(address >> 1) & 0xff].w = data;
return;
}
/* invalid address */
m68k_unused_16_w (address, data);
return;
}
}
}
case 0x30: /* TIME */
{
cart.hw.time_w(address, data);
@ -467,7 +931,7 @@ void ctrl_io_write_word(unsigned int address, unsigned int data)
return;
}
case 0x50: /* SVP REGISTERS */
case 0x50: /* SVP */
{
if (!(address & 0xFD))
{
@ -481,7 +945,7 @@ void ctrl_io_write_word(unsigned int address, unsigned int data)
}
case 0x10: /* MEMORY MODE */
case 0x20: /* MEGA-CD */
case 0x13: /* unknown */
case 0x41: /* BOOT ROM */
case 0x44: /* RADICA */
{
@ -501,6 +965,7 @@ void ctrl_io_write_word(unsigned int address, unsigned int data)
/*--------------------------------------------------------------------------*/
/* VDP */
/*--------------------------------------------------------------------------*/
unsigned int vdp_read_byte(unsigned int address)
{
switch (address & 0xFD)
@ -517,25 +982,30 @@ unsigned int vdp_read_byte(unsigned int address)
case 0x04: /* CTRL */
{
unsigned int data = (vdp_68k_ctrl_r(m68k.cycles) >> 8) & 3;
/* Unused bits return prefetched bus data */
return (((vdp_68k_ctrl_r(mcycles_68k) >> 8) & 3) | (m68k_read_pcrelative_8(REG_PC) & 0xFC));
address = m68k.pc;
data |= (READ_BYTE(m68k.memory_map[((address)>>16)&0xff].base, (address) & 0xffff) & 0xFC);
return data;
}
case 0x05: /* CTRL */
{
return (vdp_68k_ctrl_r(mcycles_68k) & 0xFF);
return (vdp_68k_ctrl_r(m68k.cycles) & 0xFF);
}
case 0x08: /* HVC */
case 0x0C:
{
return (vdp_hvc_r(mcycles_68k) >> 8);
return (vdp_hvc_r(m68k.cycles) >> 8);
}
case 0x09: /* HVC */
case 0x0D:
{
return (vdp_hvc_r(mcycles_68k) & 0xFF);
return (vdp_hvc_r(m68k.cycles) & 0xFF);
}
case 0x18: /* Unused */
@ -564,14 +1034,19 @@ unsigned int vdp_read_word(unsigned int address)
case 0x04: /* CTRL */
{
unsigned int data = vdp_68k_ctrl_r(m68k.cycles) & 0x3FF;
/* Unused bits return prefetched bus data */
return ((vdp_68k_ctrl_r(mcycles_68k) & 0x3FF) | (m68k_read_pcrelative_16(REG_PC) & 0xFC00));
address = m68k.pc;
data |= (*(uint16 *)(m68k.memory_map[((address)>>16)&0xff].base + ((address) & 0xffff)) & 0xFC00);
return data;
}
case 0x08: /* HVC */
case 0x0C:
{
return vdp_hvc_r(mcycles_68k);
return vdp_hvc_r(m68k.cycles);
}
case 0x18: /* Unused */
@ -608,7 +1083,7 @@ void vdp_write_byte(unsigned int address, unsigned int data)
{
if (address & 1)
{
psg_write(mcycles_68k, data);
psg_write(m68k.cycles, data);
return;
}
m68k_unused_8_w(address, data);
@ -654,7 +1129,7 @@ void vdp_write_word(unsigned int address, unsigned int data)
case 0x10: /* PSG */
case 0x14:
{
psg_write(mcycles_68k, data & 0xFF);
psg_write(m68k.cycles, data & 0xFF);
return;
}
@ -679,58 +1154,56 @@ void vdp_write_word(unsigned int address, unsigned int data)
}
/******* PICO ************************************************/
/*--------------------------------------------------------------------------*/
/* PICO (incomplete) */
/*--------------------------------------------------------------------------*/
unsigned int pico_read_byte(unsigned int address)
{
/* PICO */
switch (address & 0xFF)
{
case 0x01: /* VERSION register */
{
return 0x40;
return (region_code >> 1);
}
case 0x03: /* IO register */
{
unsigned int retval = 0xFF;
if (input.pad[0] & INPUT_B) retval &= ~0x10;
if (input.pad[0] & INPUT_A) retval &= ~0x80;
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;
return ~input.pad[0];
}
case 0x05: /* MSB PEN X coordinate */
case 0x05: /* PEN X coordinate (MSB) */
{
return (input.analog[0][0] >> 8);
}
case 0x07: /* LSB PEN X coordinate */
case 0x07: /* PEN X coordinate (LSB) */
{
return (input.analog[0][0] & 0xFF);
}
case 0x09: /* MSB PEN Y coordinate */
case 0x09: /* PEN Y coordinate (MSB) */
{
return (input.analog[0][1] >> 8);
}
case 0x0B: /* LSB PEN Y coordinate */
case 0x0B: /* PEN Y coordinate (LSB) */
{
return (input.analog[0][1] & 0xFF);
}
case 0x0D: /* PAGE register (TODO) */
case 0x0D: /* PAGE register */
{
return pico_regs[pico_current];
return (1 << pico_current) - 1;
}
case 0x10: /* PCM registers (TODO) */
case 0x10: /* ADPCM data registers (TODO) */
case 0x11:
{
return 0xff;
}
case 0x12: /* ADPCM control registers (TODO) */
{
return 0x80;
}
@ -744,5 +1217,5 @@ unsigned int pico_read_byte(unsigned int address)
unsigned int pico_read_word(unsigned int address)
{
return (pico_read_byte(address | 1) | (m68k_read_bus_8(address) << 8));
return (pico_read_byte(address | 1) | (pico_read_byte(address) << 8));
}

View File

@ -1,9 +1,9 @@
/***************************************************************************************
* Genesis Plus
* 68k bus handlers
* Main 68k bus handlers
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -49,7 +49,7 @@ unsigned int zbank_unused_r(unsigned int address)
#ifdef LOGERROR
error("Z80 bank unused read %06X (%x)\n", address, Z80.pc.d);
#endif
return (address & 1) ? 0x00 : 0xFF;
return 0xFF;
}
void zbank_unused_w(unsigned int address, unsigned int data)
@ -66,7 +66,7 @@ unsigned int zbank_lockup_r(unsigned int address)
#endif
if (!config.force_dtack)
{
mcycles_z80 = 0xFFFFFFFF;
Z80.cycles = 0xFFFFFFFF;
zstate = 0;
}
return 0xFF;
@ -79,7 +79,7 @@ void zbank_lockup_w(unsigned int address, unsigned int data)
#endif
if (!config.force_dtack)
{
mcycles_z80 = 0xFFFFFFFF;
Z80.cycles = 0xFFFFFFFF;
zstate = 0;
}
}
@ -167,7 +167,7 @@ void zbank_write_ctrl_io(unsigned int address, unsigned int data)
{
if (!(address & 1))
{
gen_zbusreq_w(data & 1, mcycles_z80);
gen_zbusreq_w(data & 1, Z80.cycles);
return;
}
zbank_unused_w(address, data);
@ -178,7 +178,7 @@ void zbank_write_ctrl_io(unsigned int address, unsigned int data)
{
if (!(address & 1))
{
gen_zreset_w(data & 1, mcycles_z80);
gen_zreset_w(data & 1, Z80.cycles);
return;
}
zbank_unused_w(address, data);
@ -238,24 +238,24 @@ unsigned int zbank_read_vdp(unsigned int address)
case 0x04: /* CTRL */
{
return (((vdp_68k_ctrl_r(mcycles_z80) >> 8) & 3) | 0xFC);
return (((vdp_68k_ctrl_r(Z80.cycles) >> 8) & 3) | 0xFC);
}
case 0x05: /* CTRL */
{
return (vdp_68k_ctrl_r(mcycles_z80) & 0xFF);
return (vdp_68k_ctrl_r(Z80.cycles) & 0xFF);
}
case 0x08: /* HVC */
case 0x0C:
{
return (vdp_hvc_r(mcycles_z80) >> 8);
return (vdp_hvc_r(Z80.cycles) >> 8);
}
case 0x09: /* HVC */
case 0x0D:
{
return (vdp_hvc_r(mcycles_z80) & 0xFF);
return (vdp_hvc_r(Z80.cycles) & 0xFF);
}
case 0x18: /* Unused */
@ -294,7 +294,7 @@ void zbank_write_vdp(unsigned int address, unsigned int data)
{
if (address & 1)
{
psg_write(mcycles_z80, data);
psg_write(Z80.cycles, data);
return;
}
zbank_unused_w(address, data);

View File

@ -3,7 +3,7 @@
* Z80 bank access to 68k bus
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -69,7 +69,7 @@ INLINE void z80_lockup_w(unsigned int address, unsigned char data)
#endif
if (!config.force_dtack)
{
mcycles_z80 = 0xFFFFFFFF;
Z80.cycles = 0xFFFFFFFF;
zstate = 0;
}
}
@ -81,7 +81,7 @@ INLINE unsigned char z80_lockup_r(unsigned int address)
#endif
if (!config.force_dtack)
{
mcycles_z80 = 0xFFFFFFFF;
Z80.cycles = 0xFFFFFFFF;
zstate = 0;
}
return 0xFF;
@ -104,7 +104,7 @@ unsigned char z80_memory_r(unsigned int address)
case 2: /* $4000-$5FFF: YM2612 */
{
return fm_read(mcycles_z80, address & 3);
return fm_read(Z80.cycles, address & 3);
}
case 3: /* $7F00-$7FFF: VDP */
@ -123,7 +123,7 @@ unsigned char z80_memory_r(unsigned int address)
{
return (*zbank_memory_map[address >> 16].read)(address);
}
return READ_BYTE(m68k_memory_map[address >> 16].base, address & 0xFFFF);
return READ_BYTE(m68k.memory_map[address >> 16].base, address & 0xFFFF);
}
}
}
@ -142,7 +142,7 @@ void z80_memory_w(unsigned int address, unsigned char data)
case 2: /* $4000-$5FFF: YM2612 */
{
fm_write(mcycles_z80, address & 3, data);
fm_write(Z80.cycles, address & 3, data);
return;
}
@ -178,7 +178,7 @@ void z80_memory_w(unsigned int address, unsigned char data)
(*zbank_memory_map[address >> 16].write)(address, data);
return;
}
WRITE_BYTE(m68k_memory_map[address >> 16].base, address & 0xFFFF, data);
WRITE_BYTE(m68k.memory_map[address >> 16].base, address & 0xFFFF, data);
return;
}
}
@ -224,14 +224,14 @@ void z80_md_port_w(unsigned int port, unsigned char data)
{
case 0x01:
{
io_z80_write(1, data, mcycles_z80 + PBC_CYCLE_OFFSET);
io_z80_write(1, data, Z80.cycles + PBC_CYCLE_OFFSET);
return;
}
case 0x40:
case 0x41:
{
psg_write(mcycles_z80, data);
psg_write(Z80.cycles, data);
return;
}
@ -253,7 +253,7 @@ void z80_md_port_w(unsigned int port, unsigned char data)
if ((port >= 0xF0) && (config.ym2413 & 1))
{
fm_write(mcycles_z80, port&3, data);
fm_write(Z80.cycles, port&3, data);
return;
}
@ -269,12 +269,12 @@ unsigned char z80_md_port_r(unsigned int port)
{
case 0x40:
{
return ((vdp_hvc_r(mcycles_z80 - 15) >> 8) & 0xFF);
return ((vdp_hvc_r(Z80.cycles - 15) >> 8) & 0xFF);
}
case 0x41:
{
return (vdp_hvc_r(mcycles_z80 - 15) & 0xFF);
return (vdp_hvc_r(Z80.cycles - 15) & 0xFF);
}
case 0x80:
@ -284,7 +284,7 @@ unsigned char z80_md_port_r(unsigned int port)
case 0x81:
{
return vdp_z80_ctrl_r(mcycles_z80);
return vdp_z80_ctrl_r(Z80.cycles);
}
default:
@ -333,14 +333,14 @@ void z80_gg_port_w(unsigned int port, unsigned char data)
return;
}
io_z80_write(port & 1, data, mcycles_z80 + SMS_CYCLE_OFFSET);
io_z80_write(port & 1, data, Z80.cycles + SMS_CYCLE_OFFSET);
return;
}
case 0x40:
case 0x41:
{
psg_write(mcycles_z80, data);
psg_write(Z80.cycles, data);
return;
}
@ -386,12 +386,12 @@ unsigned char z80_gg_port_r(unsigned int port)
case 0x40:
{
return ((vdp_hvc_r(mcycles_z80) >> 8) & 0xFF);
return ((vdp_hvc_r(Z80.cycles) >> 8) & 0xFF);
}
case 0x41:
{
return (vdp_hvc_r(mcycles_z80) & 0xFF);
return (vdp_hvc_r(Z80.cycles) & 0xFF);
}
case 0x80:
@ -401,7 +401,7 @@ unsigned char z80_gg_port_r(unsigned int port)
case 0x81:
{
return vdp_z80_ctrl_r(mcycles_z80);
return vdp_z80_ctrl_r(Z80.cycles);
}
default:
@ -430,14 +430,14 @@ void z80_ms_port_w(unsigned int port, unsigned char data)
case 0x00:
case 0x01:
{
io_z80_write(port & 1, data, mcycles_z80 + SMS_CYCLE_OFFSET);
io_z80_write(port & 1, data, Z80.cycles + SMS_CYCLE_OFFSET);
return;
}
case 0x40:
case 0x41:
{
psg_write(mcycles_z80, data);
psg_write(Z80.cycles, data);
return;
}
@ -457,7 +457,7 @@ void z80_ms_port_w(unsigned int port, unsigned char data)
{
if (!(port & 4) && (config.ym2413 & 1))
{
fm_write(mcycles_z80, port & 3, data);
fm_write(Z80.cycles, port & 3, data);
return;
}
@ -479,12 +479,12 @@ unsigned char z80_ms_port_r(unsigned int port)
case 0x40:
{
return ((vdp_hvc_r(mcycles_z80) >> 8) & 0xFF);
return ((vdp_hvc_r(Z80.cycles) >> 8) & 0xFF);
}
case 0x41:
{
return (vdp_hvc_r(mcycles_z80) & 0xFF);
return (vdp_hvc_r(Z80.cycles) & 0xFF);
}
case 0x80:
@ -494,7 +494,7 @@ unsigned char z80_ms_port_r(unsigned int port)
case 0x81:
{
return vdp_z80_ctrl_r(mcycles_z80);
return vdp_z80_ctrl_r(Z80.cycles);
}
default:
@ -543,7 +543,7 @@ void z80_m3_port_w(unsigned int port, unsigned char data)
case 0x40:
case 0x41:
{
psg_write(mcycles_z80, data);
psg_write(Z80.cycles, data);
return;
}
@ -563,7 +563,7 @@ void z80_m3_port_w(unsigned int port, unsigned char data)
{
if (!(port & 4) && (config.ym2413 & 1))
{
fm_write(mcycles_z80, port & 3, data);
fm_write(Z80.cycles, port & 3, data);
return;
}
@ -585,12 +585,12 @@ unsigned char z80_m3_port_r(unsigned int port)
case 0x40:
{
return ((vdp_hvc_r(mcycles_z80) >> 8) & 0xFF);
return ((vdp_hvc_r(Z80.cycles) >> 8) & 0xFF);
}
case 0x41:
{
return (vdp_hvc_r(mcycles_z80) & 0xFF);
return (vdp_hvc_r(Z80.cycles) & 0xFF);
}
case 0x80:
@ -600,7 +600,7 @@ unsigned char z80_m3_port_r(unsigned int port)
case 0x81:
{
return vdp_z80_ctrl_r(mcycles_z80);
return vdp_z80_ctrl_r(Z80.cycles);
}
default:
@ -630,7 +630,7 @@ void z80_sg_port_w(unsigned int port, unsigned char data)
case 0x40:
case 0x41:
{
psg_write(mcycles_z80, data);
psg_write(Z80.cycles, data);
return;
}
@ -665,7 +665,7 @@ unsigned char z80_sg_port_r(unsigned int port)
case 0x81:
{
return vdp_z80_ctrl_r(mcycles_z80);
return vdp_z80_ctrl_r(Z80.cycles);
}
case 0xC0:

View File

@ -8,6 +8,8 @@
#include "types.h"
#include "macros.h"
#include "osd.h"
#include "loadrom.h"
#include "m68k.h"
#include "z80.h"
#include "system.h"
@ -19,21 +21,15 @@
#include "membnk.h"
#include "io_ctrl.h"
#include "input.h"
#include "state.h"
#include "sound.h"
#include "sn76489.h"
#include "ym2413.h"
#include "ym2612.h"
#include "loadrom.h"
#include "sms_cart.h"
#include "md_cart.h"
#include "md_eeprom.h"
#include "gg_eeprom.h"
#include "sram.h"
#include "ggenie.h"
#include "areplay.h"
#include "svp.h"
#include "osd.h"
#include "state.h"
#endif /* _SHARED_H_ */

View File

@ -84,10 +84,6 @@ void blip_add( blip_buffer_t* s, int clocks, int delta )
int blip_clocks_needed( const blip_buffer_t* s, int samples )
{
/*int fixed_needed;
if ( samples > s->size )
samples = s->size;*/
/* Fixed-point number of samples needed in addition to those in buffer */
int fixed_needed = samples * time_unit - s->offset;
@ -105,7 +101,7 @@ int blip_samples_avail( const blip_buffer_t* s )
return s->offset >> time_bits;
}
int blip_read_samples( blip_buffer_t* s, short out[])
int blip_read_samples( blip_buffer_t* s, short out[], int stereo)
{
int count = s->offset >> time_bits;
@ -128,7 +124,7 @@ int blip_read_samples( blip_buffer_t* s, short out[])
if ( sample < -32768 ) sample = -32768;
if ( sample > +32767 ) sample = +32767;
out [i] = sample;
out [i << stereo] = sample;
}
/* Copy remaining samples to beginning of buffer and clear the rest */

View File

@ -40,7 +40,7 @@ int blip_samples_avail( const blip_buffer_t* );
/* Reads at most n samples out of buffer into out, removing them from from
the buffer. */
int blip_read_samples( blip_buffer_t*, short out []);
int blip_read_samples( blip_buffer_t*, short out [], int stereo);
#ifdef __cplusplus
}

View File

@ -91,6 +91,12 @@ void SN76489_Init(double PSGClockValue, int SamplingRate)
blip = blip_alloc(PSGClockValue, SamplingRate * 16.0, SamplingRate / 4);
}
void SN76489_Shutdown(void)
{
if (blip) blip_free(blip);
blip = NULL;
}
void SN76489_Reset()
{
int i;
@ -125,12 +131,6 @@ void SN76489_Reset()
if (blip) blip_clear(blip);
}
void SN76489_Shutdown(void)
{
if (blip) blip_free(blip);
blip = NULL;
}
void SN76489_BoostNoise(int boost)
{
SN76489.BoostNoise = boost;
@ -322,7 +322,7 @@ int SN76489_Update(INT16 *buffer, int clock_length)
/* Read samples into output buffer */
blip_end_frame(blip, clock_length);
return blip_read_samples(blip, buffer);
return blip_read_samples(blip, buffer, 0);
}
int SN76489_Clocks(int length)

View File

@ -3,7 +3,7 @@
* Sound Hardware
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -177,6 +177,13 @@ void sound_init(void)
#endif
}
void sound_shutdown(void)
{
Fir_Resampler_shutdown();
SN76489_Shutdown();
}
/* Reset sound chips emulation */
void sound_reset(void)
{

View File

@ -3,7 +3,7 @@
* Sound Hardware
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -42,6 +42,7 @@
/* Function prototypes */
extern void sound_init(void);
extern void sound_shutdown(void);
extern void sound_reset(void);
extern void sound_restore(void);
extern int sound_context_save(uint8 *state);

View File

@ -2,7 +2,7 @@
* Genesis Plus
* Savestate support
*
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -51,8 +51,8 @@ int state_load(unsigned char *state)
return -1;
}
/* version check (1.6.0 and above) */
if ((version[11] < 0x31) || ((version[11] == 0x31) && (version[13] < 0x36)))
/* version check (support from previous 1.6.x state format) */
if ((version[11] < 0x31) || (version[13] < 0x36))
{
return -1;
}
@ -63,10 +63,10 @@ int state_load(unsigned char *state)
/* enable VDP access for TMSS systems */
for (i=0xc0; i<0xe0; i+=8)
{
m68k_memory_map[i].read8 = vdp_read_byte;
m68k_memory_map[i].read16 = vdp_read_word;
m68k_memory_map[i].write8 = vdp_write_byte;
m68k_memory_map[i].write16 = vdp_write_word;
m68k.memory_map[i].read8 = vdp_read_byte;
m68k.memory_map[i].read16 = vdp_read_word;
m68k.memory_map[i].write8 = vdp_write_byte;
m68k.memory_map[i].write16 = vdp_write_word;
zbank_memory_map[i].read = zbank_read_vdp;
zbank_memory_map[i].write = zbank_write_vdp;
}
@ -80,17 +80,17 @@ int state_load(unsigned char *state)
load_param(&zbank, sizeof(zbank));
if (zstate == 3)
{
m68k_memory_map[0xa0].read8 = z80_read_byte;
m68k_memory_map[0xa0].read16 = z80_read_word;
m68k_memory_map[0xa0].write8 = z80_write_byte;
m68k_memory_map[0xa0].write16 = z80_write_word;
m68k.memory_map[0xa0].read8 = z80_read_byte;
m68k.memory_map[0xa0].read16 = z80_read_word;
m68k.memory_map[0xa0].write8 = z80_write_byte;
m68k.memory_map[0xa0].write16 = z80_write_word;
}
else
{
m68k_memory_map[0xa0].read8 = m68k_read_bus_8;
m68k_memory_map[0xa0].read16 = m68k_read_bus_16;
m68k_memory_map[0xa0].write8 = m68k_unused_8_w;
m68k_memory_map[0xa0].write16 = m68k_unused_16_w;
m68k.memory_map[0xa0].read8 = m68k_read_bus_8;
m68k.memory_map[0xa0].read16 = m68k_read_bus_16;
m68k.memory_map[0xa0].write8 = m68k_unused_8_w;
m68k.memory_map[0xa0].write16 = m68k_unused_16_w;
}
}
else
@ -99,8 +99,8 @@ int state_load(unsigned char *state)
}
/* CPU cycles */
load_param(&mcycles_68k, sizeof(mcycles_68k));
load_param(&mcycles_z80, sizeof(mcycles_z80));
load_param(&m68k.cycles, sizeof(m68k.cycles));
load_param(&Z80.cycles, sizeof(Z80.cycles));
/* IO */
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
@ -110,8 +110,8 @@ int state_load(unsigned char *state)
}
else
{
/* 1.6.1 specific (keep support for previous state format) */
if ((version[11] == 0x31) && (version[13] == 0x36) && (version[15] == 0x31))
/* 1.6.1 or 1.7.x specific */
if ((version[15] == 0x31) || (version[13] == 0x37))
{
load_param(&io_reg[0x0E], 1);
}
@ -120,7 +120,7 @@ int state_load(unsigned char *state)
}
/* VDP */
bufferptr += vdp_context_load(&state[bufferptr]);
bufferptr += vdp_context_load(&state[bufferptr], version);
/* SOUND */
bufferptr += sound_context_load(&state[bufferptr]);
@ -150,10 +150,17 @@ int state_load(unsigned char *state)
load_param(&tmp16, 2); m68k_set_reg(M68K_REG_SR, tmp16);
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_USP,tmp32);
/* 1.6.1 specific (keep support for previous state format) */
if ((version[11] == 0x31) && (version[13] == 0x36) && (version[15] == 0x31))
/* 1.6.1 or 1.7.x specific */
if ((version[15] == 0x31) || (version[13] == 0x37))
{
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_ISP,tmp32);
/* 1.7.x specific */
if (version[13] == 0x37)
{
load_param(&m68k.int_level, sizeof(m68k.int_level));
load_param(&m68k.stopped, sizeof(m68k.stopped));
}
}
}
@ -161,17 +168,24 @@ int state_load(unsigned char *state)
load_param(&Z80, sizeof(Z80_Regs));
Z80.irq_callback = z80_irq_callback;
/* Cartridge HW */
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
/* Extra HW */
if (system_hw == SYSTEM_MCD)
{
/* CD hardware */
bufferptr += scd_context_load(&state[bufferptr]);
}
else if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
/* MD cartridge hardware */
bufferptr += md_cart_context_load(&state[bufferptr]);
}
else
{
/* MS cartridge hardware */
bufferptr += sms_cart_context_load(&state[bufferptr]);
/* 1.6.1 specific (keep support for previous state format) */
if ((version[11] == 0x31) && (version[13] == 0x36) && (version[15] == 0x31))
/* 1.6.1 or 1.7.x specific */
if ((version[15] == 0x31) || (version[13] == 0x37))
{
sms_cart_switch(~io_reg[0x0E]);
}
@ -204,8 +218,8 @@ int state_save(unsigned char *state)
}
/* CPU cycles */
save_param(&mcycles_68k, sizeof(mcycles_68k));
save_param(&mcycles_z80, sizeof(mcycles_z80));
save_param(&m68k.cycles, sizeof(m68k.cycles));
save_param(&Z80.cycles, sizeof(Z80.cycles));
/* IO */
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
@ -249,18 +263,28 @@ int state_save(unsigned char *state)
tmp16 = m68k_get_reg(M68K_REG_SR); save_param(&tmp16, 2);
tmp32 = m68k_get_reg(M68K_REG_USP); save_param(&tmp32, 4);
tmp32 = m68k_get_reg(M68K_REG_ISP); save_param(&tmp32, 4);
save_param(&m68k.int_level, sizeof(m68k.int_level));
save_param(&m68k.stopped, sizeof(m68k.stopped));
}
/* Z80 */
save_param(&Z80, sizeof(Z80_Regs));
/* Cartridge HW */
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
/* Extra HW */
if (system_hw == SYSTEM_MCD)
{
/* CD hardware */
bufferptr += scd_context_save(&state[bufferptr]);
}
else if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
/* MD cartridge hardware */
bufferptr += md_cart_context_save(&state[bufferptr]);
}
else
{
/* MS cartridge hardware */
bufferptr += sms_cart_context_save(&state[bufferptr]);
}

View File

@ -2,7 +2,7 @@
* Genesis Plus
* Savestate support
*
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -39,8 +39,8 @@
#ifndef _STATE_H_
#define _STATE_H_
#define STATE_SIZE 0x48100
#define STATE_VERSION "GENPLUS-GX 1.6.1"
#define STATE_SIZE 0xfc080
#define STATE_VERSION "GENPLUS-GX 1.7.0"
#define load_param(param, size) \
memcpy(param, &state[bufferptr], size); \

View File

@ -2,10 +2,10 @@
* Genesis Plus
* Virtual System emulation
*
* Support for Genesis & Master System compatibility modes
* Support for "Genesis", "Genesis + CD" & "Master System" modes
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -47,9 +47,8 @@
t_bitmap bitmap;
t_snd snd;
uint32 mcycles_vdp;
uint32 mcycles_z80;
uint32 mcycles_68k;
uint8 system_hw;
uint8 system_bios;
uint32 system_clock;
int16 SVP_cycles = 800;
@ -101,6 +100,13 @@ int audio_init(int samplerate, double framerate)
snd.fm.buffer = (int32 *) malloc(snd.buffer_size * sizeof(int32) * 2);
if (!snd.fm.buffer) return (-1);
/* PCM stream buffer */
if (system_hw == SYSTEM_MCD)
{
snd.pcm.buffer = (int16 *) malloc(snd.buffer_size * sizeof(int16) * 2);
if (!snd.pcm.buffer) return (-1);
}
/* Resampling buffer */
if (config.hq_fm && !Fir_Resampler_initialize(4096)) return (-1);
@ -128,8 +134,10 @@ void audio_reset(void)
/* Audio buffers */
snd.psg.pos = snd.psg.buffer;
snd.fm.pos = snd.fm.buffer;
snd.pcm.pos = snd.pcm.buffer;
if (snd.psg.buffer) memset (snd.psg.buffer, 0, snd.buffer_size * sizeof(int16));
if (snd.fm.buffer) memset (snd.fm.buffer, 0, snd.buffer_size * sizeof(int32) * 2);
if (snd.pcm.buffer) memset (snd.pcm.buffer, 0, snd.buffer_size * sizeof(int16) * 2);
}
void audio_set_equalizer(void)
@ -145,6 +153,7 @@ void audio_shutdown(void)
/* Sound buffers */
if (snd.fm.buffer) free(snd.fm.buffer);
if (snd.psg.buffer) free(snd.psg.buffer);
if (snd.pcm.buffer) free(snd.pcm.buffer);
/* Resampling buffer */
Fir_Resampler_shutdown();
@ -164,6 +173,7 @@ int audio_update(int16 *buffer)
int32 *fm = snd.fm.buffer;
int16 *psg = snd.psg.buffer;
int16 *pcm = snd.pcm.buffer;
/* get number of available samples */
int size = sound_update(mcycles_vdp);
@ -197,6 +207,13 @@ int audio_update(int16 *buffer)
error("%d PSG samples remaining\n",snd.psg.pos - snd.psg.buffer);
#endif
/* PCM sound chip */
if (pcm)
{
/* get needed samples */
pcm_update(pcm, size);
}
/* mix samples */
for (i = 0; i < size; i ++)
{
@ -207,6 +224,13 @@ int audio_update(int16 *buffer)
l += ((*fm++ * fm_preamp) / 100);
r += ((*fm++ * fm_preamp) / 100);
/* PCM samples (stereo) */
if (pcm)
{
l += *pcm++;
r += *pcm++;
}
/* filtering */
if (filter & 1)
{
@ -255,7 +279,7 @@ int audio_update(int16 *buffer)
}
/****************************************************************
* Virtual Genesis initialization
* Virtual System emulation
****************************************************************/
void system_init(void)
{
@ -266,9 +290,12 @@ void system_init(void)
sound_init();
}
/****************************************************************
* Virtual System emulation
****************************************************************/
void system_shutdown (void)
{
gen_shutdown();
sound_shutdown();
}
void system_reset(void)
{
gen_reset(1);
@ -279,12 +306,6 @@ void system_reset(void)
audio_reset();
}
void system_shutdown (void)
{
gen_shutdown();
SN76489_Shutdown();
}
void system_frame_gen(int do_skip)
{
/* line counters */
@ -296,7 +317,7 @@ void system_frame_gen(int do_skip)
/* reload H Counter */
int h_counter = reg[10];
/* reset line master cycle count */
/* reset frame cycle counter */
mcycles_vdp = 0;
/* reload V Counter */
@ -403,7 +424,7 @@ void system_frame_gen(int do_skip)
}
else
{
mcycles_z80 = MCYCLES_PER_LINE;
Z80.cycles = MCYCLES_PER_LINE;
}
/* run SVP chip */
@ -458,7 +479,7 @@ void system_frame_gen(int do_skip)
}
else
{
mcycles_z80 = mcycles_vdp + MCYCLES_PER_LINE;
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* run SVP chip */
@ -534,7 +555,7 @@ void system_frame_gen(int do_skip)
}
else
{
mcycles_z80 = mcycles_vdp + 788;
Z80.cycles = mcycles_vdp + 788;
}
/* V Interrupt */
@ -555,7 +576,7 @@ void system_frame_gen(int do_skip)
}
else
{
mcycles_z80 = mcycles_vdp + MCYCLES_PER_LINE;
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* run SVP chip */
@ -595,7 +616,7 @@ void system_frame_gen(int do_skip)
}
else
{
mcycles_z80 = mcycles_vdp + 788;
Z80.cycles = mcycles_vdp + 788;
}
/* clear Z80 interrupt */
@ -611,7 +632,7 @@ void system_frame_gen(int do_skip)
}
else
{
mcycles_z80 = mcycles_vdp + MCYCLES_PER_LINE;
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* run SVP chip */
@ -625,11 +646,346 @@ void system_frame_gen(int do_skip)
}
while (++line < (lines_per_frame - 1));
/* adjust 68k & Z80 cycle count for next frame */
mcycles_68k -= mcycles_vdp;
mcycles_z80 -= mcycles_vdp;
/* adjust CPU cycle counters for next frame */
m68k.cycles -= mcycles_vdp;
Z80.cycles -= mcycles_vdp;
}
void system_frame_scd(int do_skip)
{
/* line counters */
int start, end, line = 0;
/* Z80 interrupt flag */
int zirq = 1;
/* reload H Counter */
int h_counter = reg[10];
/* reset frame cycle counters */
mcycles_vdp = 0;
scd.cycles = 0;
/* reload V Counter */
v_counter = lines_per_frame - 1;
/* reset VDP FIFO */
fifo_write_cnt = 0;
fifo_lastwrite = 0;
/* update 6-Buttons & Lightguns */
input_refresh();
/* display changed during VBLANK */
if (bitmap.viewport.changed & 2)
{
/* interlaced modes */
int old_interlaced = interlaced;
interlaced = (reg[12] & 0x02) >> 1;
if (old_interlaced != interlaced)
{
/* double resolution mode */
im2_flag = ((reg[12] & 0x06) == 0x06);
/* reset field status flag */
odd_frame = 1;
/* video mode has changed */
bitmap.viewport.changed = 5;
/* update rendering mode */
if (reg[1] & 0x04)
{
if (im2_flag)
{
render_bg = (reg[11] & 0x04) ? render_bg_m5_im2_vs : render_bg_m5_im2;
render_obj = (reg[12] & 0x08) ? render_obj_m5_im2_ste : render_obj_m5_im2;
}
else
{
render_bg = (reg[11] & 0x04) ? render_bg_m5_vs : render_bg_m5;
render_obj = (reg[12] & 0x08) ? render_obj_m5_ste : render_obj_m5;
}
}
}
else
{
/* clear flag */
bitmap.viewport.changed &= ~2;
}
/* active screen height */
if (reg[1] & 0x04)
{
bitmap.viewport.h = 224 + ((reg[1] & 0x08) << 1);
bitmap.viewport.y = (config.overscan & 1) * ((240 + 48*vdp_pal - bitmap.viewport.h) >> 1);
}
else
{
bitmap.viewport.h = 192;
bitmap.viewport.y = (config.overscan & 1) * 24 * (vdp_pal + 1);
}
/* active screen width */
bitmap.viewport.w = 256 + ((reg[12] & 0x01) << 6);
}
/* clear VBLANK, DMA, FIFO FULL & field flags */
status &= 0xFEE5;
/* set FIFO EMPTY flag */
status |= 0x0200;
/* even/odd field flag (interlaced modes only) */
odd_frame ^= 1;
if (interlaced)
{
status |= (odd_frame << 4);
}
/* update VDP DMA */
if (dma_length)
{
vdp_dma_update(0);
}
/* render last line of overscan */
if (bitmap.viewport.y > 0)
{
blank_line(v_counter, -bitmap.viewport.x, bitmap.viewport.w + 2*bitmap.viewport.x);
}
/* parse first line of sprites */
if (reg[1] & 0x40)
{
parse_satb(-1);
}
/* run both 68k & CD hardware */
scd_update(MCYCLES_PER_LINE);
/* run Z80 */
if (zstate == 1)
{
z80_run(MCYCLES_PER_LINE);
}
else
{
Z80.cycles = MCYCLES_PER_LINE;
}
/* update line cycle count */
mcycles_vdp += MCYCLES_PER_LINE;
/* Active Display */
do
{
/* update V Counter */
v_counter = line;
/* update 6-Buttons & Lightguns */
input_refresh();
/* H Interrupt */
if(--h_counter < 0)
{
/* reload H Counter */
h_counter = reg[10];
/* interrupt level 4 */
hint_pending = 0x10;
if (reg[0] & 0x10)
{
m68k_update_irq(4);
}
}
/* update VDP DMA */
if (dma_length)
{
vdp_dma_update(mcycles_vdp);
}
/* render scanline */
if (!do_skip)
{
render_line(line);
}
/* run both 68k & CD hardware */
scd_update(mcycles_vdp + MCYCLES_PER_LINE);
/* run Z80 */
if (zstate == 1)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* update line cycle count */
mcycles_vdp += MCYCLES_PER_LINE;
}
while (++line < bitmap.viewport.h);
/* end of active display */
v_counter = line;
/* set VBLANK flag */
status |= 0x08;
/* overscan area */
start = lines_per_frame - bitmap.viewport.y;
end = bitmap.viewport.h + bitmap.viewport.y;
/* check viewport changes */
if ((bitmap.viewport.w != bitmap.viewport.ow) || (bitmap.viewport.h != bitmap.viewport.oh))
{
bitmap.viewport.ow = bitmap.viewport.w;
bitmap.viewport.oh = bitmap.viewport.h;
bitmap.viewport.changed |= 1;
}
/* update 6-Buttons & Lightguns */
input_refresh();
/* H Interrupt */
if(--h_counter < 0)
{
/* reload H Counter */
h_counter = reg[10];
/* interrupt level 4 */
hint_pending = 0x10;
if (reg[0] & 0x10)
{
m68k_update_irq(4);
}
}
/* update VDP DMA */
if (dma_length)
{
vdp_dma_update(mcycles_vdp);
}
/* render overscan */
if (line < end)
{
blank_line(line, -bitmap.viewport.x, bitmap.viewport.w + 2*bitmap.viewport.x);
}
/* update inputs before VINT (Warriors of Eternal Sun) */
osd_input_update();
/* delay between VINT flag & V Interrupt (Ex-Mutants, Tyrant) */
m68k_run(mcycles_vdp + 588);
status |= 0x80;
/* delay between VBLANK flag & V Interrupt (Dracula, OutRunners, VR Troopers) */
m68k_run(mcycles_vdp + 788);
if (zstate == 1)
{
z80_run(mcycles_vdp + 788);
}
else
{
Z80.cycles = mcycles_vdp + 788;
}
/* V Interrupt */
vint_pending = 0x20;
if (reg[1] & 0x20)
{
m68k_set_irq(6);
}
/* assert Z80 interrupt */
Z80.irq_state = ASSERT_LINE;
/* run both 68k & CD hardware */
scd_update(mcycles_vdp + MCYCLES_PER_LINE);
/* run Z80 until end of line */
if (zstate == 1)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* update line cycle count */
mcycles_vdp += MCYCLES_PER_LINE;
/* increment line count */
line++;
/* Vertical Blanking */
do
{
/* update V Counter */
v_counter = line;
/* update 6-Buttons & Lightguns */
input_refresh();
/* render overscan */
if ((line < end) || (line >= start))
{
blank_line(line, -bitmap.viewport.x, bitmap.viewport.w + 2*bitmap.viewport.x);
}
if (zirq)
{
/* Z80 interrupt is asserted exactly for one line */
m68k_run(mcycles_vdp + 788);
if (zstate == 1)
{
z80_run(mcycles_vdp + 788);
}
else
{
Z80.cycles = mcycles_vdp + 788;
}
/* clear Z80 interrupt */
Z80.irq_state = CLEAR_LINE;
zirq = 0;
}
/* run both 68k & CD hardware */
scd_update(mcycles_vdp + MCYCLES_PER_LINE);
/* run Z80 */
if (zstate == 1)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
Z80.cycles = mcycles_vdp + MCYCLES_PER_LINE;
}
/* update line cycle count */
mcycles_vdp += MCYCLES_PER_LINE;
}
while (++line < (lines_per_frame - 1));
/* reset CPU registers polling */
m68k.poll.cycle = 0;
s68k.poll.cycle = 0;
/* adjust CPU cycle counters for next frame */
Z80.cycles -= mcycles_vdp;
m68k.cycles -= mcycles_vdp;
s68k.cycles -= scd.cycles;
gfx.cycles -= scd.cycles;
}
void system_frame_sms(int do_skip)
{
@ -851,9 +1207,9 @@ void system_frame_sms(int do_skip)
/* IRQ line is latched between instructions, during instruction last cycle. */
/* This means that if Z80 cycle count is exactly a multiple of MCYCLES_PER_LINE, */
/* interrupt should be triggered AFTER the next instruction. */
if ((mcycles_z80 % MCYCLES_PER_LINE) == 0)
if ((Z80.cycles % MCYCLES_PER_LINE) == 0)
{
z80_run(mcycles_z80 + 1);
z80_run(Z80.cycles + 1);
}
Z80.irq_state = ASSERT_LINE;
@ -904,9 +1260,9 @@ void system_frame_sms(int do_skip)
if (reg[0] & 0x10)
{
/* cycle-accurate HINT */
if ((mcycles_z80 % MCYCLES_PER_LINE) == 0)
if ((Z80.cycles % MCYCLES_PER_LINE) == 0)
{
z80_run(mcycles_z80 + 1);
z80_run(Z80.cycles + 1);
}
Z80.irq_state = ASSERT_LINE;
@ -983,5 +1339,5 @@ void system_frame_sms(int do_skip)
while (++line < (lines_per_frame - 1));
/* adjust Z80 cycle count for next frame */
mcycles_z80 -= mcycles_vdp;
Z80.cycles -= mcycles_vdp;
}

View File

@ -2,10 +2,10 @@
* Genesis Plus
* Virtual System emulation
*
* Support for Genesis & Master System compatibility modes
* Support for "Genesis", "Genesis + CD" & "Master System" modes
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -52,6 +52,7 @@
#define SYSTEM_MD 0x80
#define SYSTEM_PBC 0x81
#define SYSTEM_PICO 0x82
#define SYSTEM_MCD 0x84
/* NTSC & PAL Master Clock frequencies */
#define MCLOCK_NTSC 53693175
@ -98,17 +99,21 @@ typedef struct
int16 *pos;
int16 *buffer;
} psg;
struct
{
int16 *pos;
int16 *buffer;
} pcm;
} t_snd;
/* Global variables */
extern t_bitmap bitmap;
extern t_snd snd;
extern uint32 mcycles_z80;
extern uint32 mcycles_68k;
extern uint32 mcycles_vdp;
extern int16 SVP_cycles;
extern uint8 system_hw;
extern uint8 system_bios;
extern uint32 system_clock;
/* Function prototypes */
@ -121,6 +126,7 @@ extern void system_init(void);
extern void system_reset(void);
extern void system_shutdown(void);
extern void system_frame_gen(int do_skip);
extern void system_frame_scd(int do_skip);
extern void system_frame_sms(int do_skip);
#endif /* _SYSTEM_H_ */

View File

@ -11,3 +11,19 @@
#define int8 signed char
#define int16 signed short
#define int32 signed int
typedef union
{
uint16 w;
struct
{
#ifdef LSB_FIRST
uint8 l;
uint8 h;
#else
uint8 h;
uint8 l;
#endif
} byte;
} reg16_t;

View File

@ -5,7 +5,7 @@
* Support for SG-1000, Master System (315-5124 & 315-5246), Game Gear & Mega Drive VDP
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -106,11 +106,12 @@ static uint8 border; /* Border color index */
static uint8 pending; /* Pending write flag */
static uint8 code; /* Code register */
static uint8 dma_type; /* DMA mode */
static uint16 dmafill; /* DMA Fill setup */
static uint16 addr; /* Address register */
static uint16 addr_latch; /* Latched A15, A14 of address */
static uint16 sat_base_mask; /* Base bits of SAT */
static uint16 sat_addr_mask; /* Index bits of SAT */
static uint16 dma_src; /* DMA source address */
static uint16 dmafill; /* DMA Fill setup */
static uint32 dma_endCycles; /* 68k cycles to DMA end */
static uint32 fifo_latency; /* CPU access latency */
static int cached_write; /* 2nd part of 32-bit CTRL port write (Genesis mode) or LSB of CRAM data (Game Gear mode) */
@ -156,9 +157,9 @@ static void vdp_z80_data_w_sg(unsigned int data);
static void vdp_bus_w(unsigned int data);
static void vdp_fifo_update(unsigned int cycles);
static void vdp_reg_w(unsigned int r, unsigned int d, unsigned int cycles);
static void vdp_dma_copy(int length);
static void vdp_dma_vbus(int length);
static void vdp_dma_fill(unsigned int data, int length);
static void vdp_dma_copy(unsigned int length);
static void vdp_dma_vbus(unsigned int length);
static void vdp_dma_fill(unsigned char data, unsigned int length);
/*--------------------------------------------------------------------------*/
/* Init, reset, context functions */
@ -170,24 +171,17 @@ void vdp_init(void)
lines_per_frame = vdp_pal ? 313: 262;
/* CPU interrupt line(s)*/
switch (system_hw)
{
case SYSTEM_MD:
case SYSTEM_PICO:
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
/* 68k cpu */
set_irq_line = m68k_set_irq;
set_irq_line_delay = m68k_set_irq_delay;
break;
}
default:
else
{
/* Z80 cpu */
set_irq_line = z80_set_irq_line;
set_irq_line_delay = z80_set_irq_line;
break;
}
}
}
@ -209,6 +203,7 @@ void vdp_reset(void)
hint_pending = 0;
vint_pending = 0;
dmafill = 0;
dma_src = 0;
dma_type = 0;
dma_length = 0;
dma_endCycles = 0;
@ -340,6 +335,7 @@ void vdp_reset(void)
}
}
/* SG-1000 specific */
if (system_hw == SYSTEM_SG)
{
/* 16k address decoding by default (Magical Kid Wiz) */
@ -348,9 +344,11 @@ void vdp_reset(void)
/* no H-INT on TMS9918 */
vdp_reg_w(10, 0xFF, 0);
}
else if ((system_hw & SYSTEM_SMS) && ((config.bios & (SYSTEM_SMS | 0x01)) != (SYSTEM_SMS | 0x01)))
/* Master System specific */
else if ((system_hw & SYSTEM_SMS) && (!(config.bios & 1) || !(system_bios & SYSTEM_SMS)))
{
/* force registers initialization (if not done by Master System BIOS) */
/* force registers initialization (only if Master System BIOS is disabled or not loaded) */
vdp_reg_w(0 , 0x36, 0);
vdp_reg_w(1 , 0x80, 0);
vdp_reg_w(2 , 0xFF, 0);
@ -365,9 +363,11 @@ void vdp_reset(void)
render_obj = render_obj_m4;
parse_satb = parse_satb_m4;
}
else if ((system_hw == SYSTEM_MD) && ((config.bios & (SYSTEM_MD | 0x01)) == 0x01))
/* Mega Drive specific */
else if ((system_hw == SYSTEM_MD) && (config.bios & 1) && !(system_bios & SYSTEM_MD))
{
/* force registers initialization on TMSS model (if not done by BOOT ROM) */
/* force registers initialization (only if TMSS model is emulated and BOOT ROM is not loaded) */
vdp_reg_w(0 , 0x04, 0);
vdp_reg_w(1 , 0x04, 0);
vdp_reg_w(10, 0xFF, 0);
@ -402,11 +402,12 @@ int vdp_context_save(uint8 *state)
save_param(&vint_pending, sizeof(vint_pending));
save_param(&dma_length, sizeof(dma_length));
save_param(&dma_type, sizeof(dma_type));
save_param(&dma_src, sizeof(dma_src));
save_param(&cached_write, sizeof(cached_write));
return bufferptr;
}
int vdp_context_load(uint8 *state)
int vdp_context_load(uint8 *state, char *version)
{
int i, bufferptr = 0;
uint8 temp_reg[0x20];
@ -416,27 +417,10 @@ int vdp_context_load(uint8 *state)
load_param(cram, sizeof(cram));
load_param(vsram, sizeof(vsram));
load_param(temp_reg, sizeof(temp_reg));
load_param(&addr, sizeof(addr));
load_param(&addr_latch, sizeof(addr_latch));
load_param(&code, sizeof(code));
load_param(&pending, sizeof(pending));
load_param(&status, sizeof(status));
load_param(&dmafill, sizeof(dmafill));
load_param(&hint_pending, sizeof(hint_pending));
load_param(&vint_pending, sizeof(vint_pending));
load_param(&dma_length, sizeof(dma_length));
load_param(&dma_type, sizeof(dma_type));
load_param(&cached_write, sizeof(cached_write));
/* restore VDP registers */
if (system_hw < SYSTEM_MD)
{
/* save internal data */
uint8 old_pending = pending;
uint8 old_code = code;
uint16 old_addr = addr;
uint16 old_addr_latch = addr_latch;
if (system_hw > SYSTEM_SG)
{
for (i=0;i<0x10;i++)
@ -455,12 +439,6 @@ int vdp_context_load(uint8 *state)
vdp_tms_ctrl_w(0x80 | i);
}
}
/* restore internal data */
pending = old_pending;
code = old_code;
addr = old_addr;
addr_latch = old_addr_latch;
}
else
{
@ -470,6 +448,25 @@ int vdp_context_load(uint8 *state)
}
}
load_param(&addr, sizeof(addr));
load_param(&addr_latch, sizeof(addr_latch));
load_param(&code, sizeof(code));
load_param(&pending, sizeof(pending));
load_param(&status, sizeof(status));
load_param(&dmafill, sizeof(dmafill));
load_param(&hint_pending, sizeof(hint_pending));
load_param(&vint_pending, sizeof(vint_pending));
load_param(&dma_length, sizeof(dma_length));
load_param(&dma_type, sizeof(dma_type));
/* 1.7.x specific */
if (version[13] == 0x37)
{
load_param(&dma_src, sizeof(dma_src));
}
load_param(&cached_write, sizeof(cached_write));
/* restore FIFO timings */
fifo_latency = 214 - (reg[12] & 1) * 24;
fifo_latency <<= ((code & 0x0F) == 0x01);
@ -558,9 +555,9 @@ void vdp_dma_update(unsigned int cycles)
/* Remaining DMA cycles */
if (status & 8)
{
/* Process DMA until the end of VBLANK (speed optimization) */
/* Note: This is not 100% accurate since rate could change if display width */
/* is changed during VBLANK but no games seem to do this. */
/* Process DMA until the end of VBLANK */
/* NOTE: This is not 100% accurate since rate should be recalculated if */
/* display width is changed during VBLANK but no games actually do this */
dma_cycles = (lines_per_frame * MCYCLES_PER_LINE) - cycles;
}
else
@ -573,7 +570,7 @@ void vdp_dma_update(unsigned int cycles)
dma_bytes = (dma_cycles * rate) / MCYCLES_PER_LINE;
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] DMA type %d (%d access/line)(%d cycles left)-> %d access (%d remaining) (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE,dma_type/4, rate, dma_cycles, dma_bytes, dma_length, m68k_get_reg(M68K_REG_PC));
error("[%d(%d)][%d(%d)] DMA type %d (%d access/line)(%d cycles left)-> %d access (%d remaining) (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE,dma_type, rate, dma_cycles, dma_bytes, dma_length, m68k_get_reg(M68K_REG_PC));
#endif
/* Check if DMA can be finished before the end of current line */
@ -587,11 +584,11 @@ void vdp_dma_update(unsigned int cycles)
/* Update DMA timings */
if (dma_type < 2)
{
/* 68K is frozen during DMA from V-Bus */
mcycles_68k = cycles + dma_cycles;
#ifdef LOGVDP
/* 68K is frozen during DMA from 68k bus */
m68k.cycles = cycles + dma_cycles;
#ifdef LOGVDP
error("-->CPU frozen for %d cycles\n", dma_cycles);
#endif
#endif
}
else
{
@ -614,14 +611,6 @@ void vdp_dma_update(unsigned int cycles)
/* Select DMA operation */
switch (dma_type)
{
case 0:
case 1:
{
/* 68K bus to VRAM, CRAM or VSRAM */
vdp_dma_vbus(dma_bytes);
break;
}
case 2:
{
/* VRAM Fill */
@ -635,15 +624,27 @@ void vdp_dma_update(unsigned int cycles)
vdp_dma_copy(dma_bytes);
break;
}
default:
{
/* 68K bus to VRAM, CRAM or VSRAM */
vdp_dma_vbus(dma_bytes);
break;
}
}
/* Check if DMA is finished */
if (!dma_length)
{
/* Reset DMA length registers */
/* DMA source address registers are incremented during DMA */
uint16 end = reg[21] + (reg[22] << 8) + reg[19] + (reg[20] << 8);
reg[21] = end & 0xff;
reg[22] = end >> 8;
/* DMA length registers are decremented during DMA */
reg[19] = reg[20] = 0;
/* Perform cached write, if any */
/* perform cached write, if any */
if (cached_write >= 0)
{
vdp_68k_ctrl_w(cached_write);
@ -681,7 +682,7 @@ void vdp_68k_ctrl_w(unsigned int data)
if ((data & 0xC000) == 0x8000)
{
/* VDP register write */
vdp_reg_w((data >> 8) & 0x1F, data & 0xFF, mcycles_68k);
vdp_reg_w((data >> 8) & 0x1F, data & 0xFF, m68k.cycles);
}
else
{
@ -706,26 +707,22 @@ void vdp_68k_ctrl_w(unsigned int data)
code = ((code & 0x03) | ((data >> 2) & 0x3C));
/* Detect DMA operation (CD5 bit set) */
if ((code & 0x20) && (reg[1] & 0x10))
if (code & 0x20)
{
/* DMA must be enabled */
if (reg[1] & 0x10)
{
/* DMA type */
switch (reg[23] >> 6)
{
case 2:
{
/* VRAM write operation only (Williams Greatest Hits after soft reset) */
if ((code & 0x0F) == 1)
{
/* VRAM fill will be triggered by next write to DATA port */
/* DMA Fill will be triggered by next DATA port write */
dmafill = 0x100;
}
break;
}
case 3:
{
/* VRAM read/write operation only */
if ((code & 0x1F) == 0x10)
{
/* DMA length */
dma_length = (reg[20] << 8) | reg[19];
@ -736,10 +733,12 @@ void vdp_68k_ctrl_w(unsigned int data)
dma_length = 0x10000;
}
/* VRAM copy */
/* DMA source address */
dma_src = (reg[22] << 8) | reg[21];
/* trigger DMA copy */
dma_type = 3;
vdp_dma_update(mcycles_68k);
}
vdp_dma_update(m68k.cycles);
break;
}
@ -754,17 +753,27 @@ void vdp_68k_ctrl_w(unsigned int data)
dma_length = 0x10000;
}
/* SVP RAM transfer latency */
reg[21] -= (svp && !(reg[23] & 0x60));
/* DMA source address */
dma_src = (reg[22] << 8) | reg[21];
/* 68k to VDP DMA */
/* SVP RAM or CD Word-RAM transfer */
if (((system_hw == SYSTEM_MCD) || svp) && ((reg[23] & 0x70) == 0x10))
{
/* source data is available with one cycle delay, which means the first word written by VDP is previous data being held */
/* on 68k bus at that time, then source words are written normally to VDP RAM, with only last source word being ignored */
addr += reg[15];
dma_length--;
}
/* trigger DMA from 68k bus */
dma_type = (code & 0x06) ? 0 : 1;
vdp_dma_update(mcycles_68k);
vdp_dma_update(m68k.cycles);
break;
}
}
}
}
}
/*
FIFO emulation (Chaos Engine/Soldier of Fortune, Double Clutch, Sol Deace)
@ -774,9 +783,7 @@ void vdp_68k_ctrl_w(unsigned int data)
H32: 16 access --> 3420/16 = ~214 Mcycles between access
H40: 18 access --> 3420/18 = ~190 Mcycles between access
This is an approximation, on real hardware, the delay between access is
more likely 16 pixels (128 or 160 Mcycles) with no access allowed during
HBLANK (~860 Mcycles), H40 mode being probably a little more restricted.
This is an approximation: on real hardware, access slots are fixed.
Each VRAM access is byte wide, so one VRAM write (word) need twice cycles.
@ -809,7 +816,7 @@ void vdp_z80_ctrl_w(unsigned int data)
if ((code & 0x03) == 0x02)
{
/* VDP register write */
vdp_reg_w(data & 0x1F, addr_latch, mcycles_z80);
vdp_reg_w(data & 0x1F, addr_latch, Z80.cycles);
/* Clear pending flag */
pending = 0;
@ -849,26 +856,23 @@ void vdp_z80_ctrl_w(unsigned int data)
addr = ((addr_latch & 3) << 14) | (addr & 0x3FFF);
code = ((code & 0x03) | ((addr_latch >> 2) & 0x3C));
/* Detect DMA operation */
if ((code & 0x20) && (reg[1] & 0x10))
/* Detect DMA operation (CD5 bit set) */
if (code & 0x20)
{
/* DMA should be enabled */
if (reg[1] & 0x10)
{
/* DMA type */
switch (reg[23] >> 6)
{
case 2:
{
/* VRAM write operation only */
if ((code & 0x0F) == 1)
{
/* VRAM fill will be triggered by next write to DATA port */
/* DMA Fill will be triggered by next write to DATA port */
dmafill = 0x100;
}
break;
}
case 3:
{
/* VRAM read/write operation only */
if ((code & 0x1F) == 0x10)
{
/* DMA length */
dma_length = (reg[20] << 8) | reg[19];
@ -879,21 +883,24 @@ void vdp_z80_ctrl_w(unsigned int data)
dma_length = 0x10000;
}
/* VRAM copy */
/* DMA source address */
dma_src = (reg[22] << 8) | reg[21];
/* trigger DMA copy */
dma_type = 3;
vdp_dma_update(mcycles_z80);
}
vdp_dma_update(Z80.cycles);
break;
}
default:
{
/* DMA from V-Bus does not work when Z80 is in control */
/* DMA from 68k bus does not work when Z80 is in control */
break;
}
}
}
}
}
return;
}
}
@ -937,7 +944,7 @@ void vdp_sms_ctrl_w(unsigned int data)
int mode, prev = (reg[0] & 0x06) | (reg[1] & 0x18);
/* Write VDP register 0-15 */
vdp_reg_w(data & 0x0F, addr_latch, mcycles_z80);
vdp_reg_w(data & 0x0F, addr_latch, Z80.cycles);
/* Check VDP mode changes */
mode = (reg[0] & 0x06) | (reg[1] & 0x18);
@ -1138,7 +1145,7 @@ void vdp_tms_ctrl_w(unsigned int data)
data &= 0x07;
/* Write VDP register */
vdp_reg_w(data, addr_latch, mcycles_z80);
vdp_reg_w(data, addr_latch, Z80.cycles);
/* Check VDP mode changes */
if (data < 2)
@ -1432,7 +1439,7 @@ void vdp_test_w(unsigned int data)
int vdp_68k_irq_ack(int int_level)
{
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] INT Level %d ack (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE-1, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE,int_level, m68k_get_reg(M68K_REG_PC));
error("[%d(%d)][%d(%d)] INT Level %d ack (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE,int_level, m68k_get_reg(M68K_REG_PC));
#endif
/* VINT has higher priority (Fatal Rewind) */
@ -2132,7 +2139,7 @@ static void vdp_bus_w(unsigned int data)
}
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE-1, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
break;
}
@ -2168,14 +2175,14 @@ static void vdp_bus_w(unsigned int data)
}
/* CRAM modified during HBLANK (Striker, Zero the Kamikaze, etc) */
if ((v_counter < bitmap.viewport.h) && (reg[1]& 0x40) && (mcycles_68k <= (mcycles_vdp + 860)))
if ((v_counter < bitmap.viewport.h) && (reg[1]& 0x40) && (m68k.cycles <= (mcycles_vdp + 860)))
{
/* Remap current line */
remap_line(v_counter);
}
}
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] CRAM 0x%x write -> 0x%x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE-1, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
error("[%d(%d)][%d(%d)] CRAM 0x%x write -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
break;
}
@ -2188,14 +2195,14 @@ static void vdp_bus_w(unsigned int data)
if (reg[11] & 0x04)
{
/* VSRAM writes during HBLANK (Adventures of Batman & Robin) */
if ((v_counter < bitmap.viewport.h) && (reg[1]& 0x40) && (mcycles_68k <= (mcycles_vdp + 860)))
if ((v_counter < bitmap.viewport.h) && (reg[1]& 0x40) && (m68k.cycles <= (mcycles_vdp + 860)))
{
/* Remap current line */
render_line(v_counter);
}
}
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] VSRAM 0x%x write -> 0x%x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE-1, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
error("[%d(%d)][%d(%d)] VSRAM 0x%x write -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
break;
}
@ -2203,13 +2210,13 @@ static void vdp_bus_w(unsigned int data)
default:
{
#ifdef LOGERROR
error("[%d(%d)][%d(%d)] Unknown (%d) 0x%x write -> 0x%x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE-1, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, code, addr, data, m68k_get_reg(M68K_REG_PC));
error("[%d(%d)][%d(%d)] Invalid (%d) 0x%x write -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, code, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
break;
}
}
/* Increment address register (TODO: see how address is incremented in Mode 4) */
/* Increment address register */
addr += reg[15];
}
@ -2227,12 +2234,12 @@ static void vdp_68k_data_w_m4(unsigned int data)
if (!(status & 8) && (reg[1] & 0x40))
{
/* Update VDP FIFO */
vdp_fifo_update(mcycles_68k);
vdp_fifo_update(m68k.cycles);
/* Clear FIFO empty flag */
status &= 0xFDFF;
/* 4 words can be stored */
/* up to 4 words can be stored */
if (fifo_write_cnt < 4)
{
/* Increment FIFO counter */
@ -2243,9 +2250,9 @@ static void vdp_68k_data_w_m4(unsigned int data)
}
else
{
/* CPU is locked until last FIFO entry has been processed (Chaos Engine, Soldiers of Fortune, Double Clutch) */
/* CPU is halted until last FIFO entry has been processed (Chaos Engine, Soldiers of Fortune, Double Clutch) */
fifo_lastwrite += fifo_latency;
mcycles_68k = fifo_lastwrite;
m68k.cycles = fifo_lastwrite;
}
}
@ -2304,7 +2311,7 @@ static void vdp_68k_data_w_m4(unsigned int data)
}
}
/* Increment address register */
/* Increment address register (TODO: check how address is incremented in Mode 4) */
addr += (reg[15] + 1);
}
@ -2317,12 +2324,12 @@ static void vdp_68k_data_w_m5(unsigned int data)
if (!(status & 8) && (reg[1] & 0x40))
{
/* Update VDP FIFO */
vdp_fifo_update(mcycles_68k);
vdp_fifo_update(m68k.cycles);
/* Clear FIFO empty flag */
status &= 0xFDFF;
/* 4 words can be stored */
/* up to 4 words can be stored */
if (fifo_write_cnt < 4)
{
/* Increment FIFO counter */
@ -2333,9 +2340,9 @@ static void vdp_68k_data_w_m5(unsigned int data)
}
else
{
/* CPU is locked until last FIFO entry has been processed (Chaos Engine, Soldiers of Fortune, Double Clutch) */
/* CPU is halted until last FIFO entry has been processed (Chaos Engine, Soldiers of Fortune, Double Clutch) */
fifo_lastwrite += fifo_latency;
mcycles_68k = fifo_lastwrite;
m68k.cycles = fifo_lastwrite;
}
}
@ -2345,7 +2352,7 @@ static void vdp_68k_data_w_m5(unsigned int data)
/* DMA Fill */
if (dmafill & 0x100)
{
/* Fill data (DMA fill flag is cleared) */
/* Fill data = MSB (DMA fill flag is cleared) */
dmafill = data >> 8;
/* DMA length */
@ -2357,9 +2364,9 @@ static void vdp_68k_data_w_m5(unsigned int data)
dma_length = 0x10000;
}
/* Perform DMA Fill*/
/* Process DMA Fill*/
dma_type = 2;
vdp_dma_update(mcycles_68k);
vdp_dma_update(m68k.cycles);
}
}
@ -2371,7 +2378,7 @@ static unsigned int vdp_68k_data_r_m4(void)
/* Clear pending flag */
pending = 0;
/* Increment address register */
/* Increment address register (TODO: check how address is incremented in Mode 4) */
addr += (reg[15] + 1);
/* Read VRAM data */
@ -2393,7 +2400,7 @@ static unsigned int vdp_68k_data_r_m5(void)
data = *(uint16 *)&vram[addr & 0xFFFE];
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] VRAM 0x%x read -> 0x%x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE-1, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
error("[%d(%d)][%d(%d)] VRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
break;
}
@ -2404,7 +2411,7 @@ static unsigned int vdp_68k_data_r_m5(void)
data = *(uint16 *)&vsram[addr & 0x7E];
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] VSRAM 0x%x read -> 0x%x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE-1, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
error("[%d(%d)][%d(%d)] VSRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
break;
}
@ -2418,7 +2425,18 @@ static unsigned int vdp_68k_data_r_m5(void)
data = ((data & 0x1C0) << 3) | ((data & 0x038) << 2) | ((data & 0x007) << 1);
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] CRAM 0x%x read -> 0x%x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE-1, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
error("[%d(%d)][%d(%d)] CRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
break;
}
case 0x0c: /* undocumented 8-bit VRAM read (cf. http://gendev.spritesmind.net/forum/viewtopic.php?t=790) */
{
/* Read data (MSB forced to zero) */
data = *(uint16 *)&vram[addr & 0xFFFE] & 0xff;
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] 8-bit VRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif
break;
}
@ -2427,7 +2445,7 @@ static unsigned int vdp_68k_data_r_m5(void)
{
/* Invalid code value */
#ifdef LOGERROR
error("[%d(%d)][%d(%d)] Invalid (%d) 0x%x read (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE-1, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, code, addr, m68k_get_reg(M68K_REG_PC));
error("[%d(%d)][%d(%d)] Invalid (%d) 0x%x read (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, code, addr, m68k_get_reg(M68K_REG_PC));
#endif
break;
}
@ -2442,7 +2460,7 @@ static unsigned int vdp_68k_data_r_m5(void)
/*--------------------------------------------------------------------------*/
/* Z80 data port access functions (Master System compatibilty mode) */
/* Z80 data port access functions (Master System compatibility mode) */
/*--------------------------------------------------------------------------*/
static void vdp_z80_data_w_m4(unsigned int data)
@ -2493,7 +2511,7 @@ static void vdp_z80_data_w_m4(unsigned int data)
}
}
/* Increment address register */
/* Increment address register (TODO: check how address is incremented in Mode 4) */
addr += (reg[15] + 1);
}
@ -2599,9 +2617,9 @@ static void vdp_z80_data_w_m5(unsigned int data)
dma_length = 0x10000;
}
/* Perform DMA Fill */
/* Process DMA Fill */
dma_type = 2;
vdp_dma_update(mcycles_z80);
vdp_dma_update(Z80.cycles);
}
}
@ -2616,7 +2634,7 @@ static unsigned int vdp_z80_data_r_m4(void)
/* Process next read */
fifo[0] = vram[addr & 0x3FFF];
/* Increment address register (register #15 can only be set in Mode 5) */
/* Increment address register (TODO: check how address is incremented in Mode 4) */
addr += (reg[15] + 1);
/* Return data */
@ -2687,7 +2705,7 @@ static void vdp_z80_data_w_ms(unsigned int data)
int index;
/* check if we are already on next line */
int line = (lines_per_frame + (mcycles_z80 / MCYCLES_PER_LINE) - 1) % lines_per_frame;
int line = (lines_per_frame + (Z80.cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;
if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))
{
v_counter = line;
@ -2706,7 +2724,7 @@ static void vdp_z80_data_w_ms(unsigned int data)
}
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, mcycles_z80/MCYCLES_PER_LINE-1, mcycles_z80, mcycles_z80%MCYCLES_PER_LINE, index, data, Z80.pc.w.l);
error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, Z80.cycles/MCYCLES_PER_LINE-1, Z80.cycles, Z80.cycles%MCYCLES_PER_LINE, index, data, Z80.pc.w.l);
#endif
}
else
@ -2733,7 +2751,7 @@ static void vdp_z80_data_w_ms(unsigned int data)
}
}
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] CRAM 0x%x write -> 0x%x (%x)\n", v_counter, mcycles_z80/MCYCLES_PER_LINE-1, mcycles_z80, mcycles_z80%MCYCLES_PER_LINE, addr, data, Z80.pc.w.l);
error("[%d(%d)][%d(%d)] CRAM 0x%x write -> 0x%x (%x)\n", v_counter, Z80.cycles/MCYCLES_PER_LINE-1, Z80.cycles, Z80.cycles%MCYCLES_PER_LINE, addr, data, Z80.pc.w.l);
#endif
}
@ -2754,7 +2772,7 @@ static void vdp_z80_data_w_gg(unsigned int data)
int index;
/* check if we are already on next line*/
int line = (lines_per_frame + (mcycles_z80 / MCYCLES_PER_LINE) - 1) % lines_per_frame;
int line = (lines_per_frame + (Z80.cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;
if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))
{
v_counter = line;
@ -2772,7 +2790,7 @@ static void vdp_z80_data_w_gg(unsigned int data)
MARK_BG_DIRTY(index);
}
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, mcycles_z80/MCYCLES_PER_LINE-1, mcycles_z80, mcycles_z80%MCYCLES_PER_LINE, index, data, Z80.pc.w.l);
error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, Z80.cycles/MCYCLES_PER_LINE-1, Z80.cycles, Z80.cycles%MCYCLES_PER_LINE, index, data, Z80.pc.w.l);
#endif
}
else
@ -2810,7 +2828,7 @@ static void vdp_z80_data_w_gg(unsigned int data)
cached_write = data;
}
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] CRAM 0x%x write -> 0x%x (%x)\n", v_counter, mcycles_z80/MCYCLES_PER_LINE-1, mcycles_z80, mcycles_z80%MCYCLES_PER_LINE, addr, data, Z80.pc.w.l);
error("[%d(%d)][%d(%d)] CRAM 0x%x write -> 0x%x (%x)\n", v_counter, Z80.cycles/MCYCLES_PER_LINE-1, Z80.cycles, Z80.cycles%MCYCLES_PER_LINE, addr, data, Z80.pc.w.l);
#endif
}
@ -2842,7 +2860,7 @@ static void vdp_z80_data_w_sg(unsigned int data)
addr++;
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, mcycles_z80/MCYCLES_PER_LINE-1, mcycles_z80, mcycles_z80%MCYCLES_PER_LINE, index, data, Z80.pc.w.l);
error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, Z80.cycles/MCYCLES_PER_LINE-1, Z80.cycles, Z80.cycles%MCYCLES_PER_LINE, index, data, Z80.pc.w.l);
#endif
}
@ -2851,22 +2869,23 @@ static void vdp_z80_data_w_sg(unsigned int data)
/*--------------------------------------------------------------------------*/
/* 68K bus to VRAM, VSRAM or CRAM */
static void vdp_dma_vbus(int length)
static void vdp_dma_vbus(unsigned int length)
{
unsigned int data;
unsigned int source = (reg[23] << 17 | reg[22] << 9 | reg[21] << 1) & 0xFFFFFE;
unsigned int base = source;
uint16 data;
/* DMA source */
if ((source >> 17) == 0x50)
/* 68k bus source address */
uint32 source = (reg[23] << 17) | (dma_src << 1);
/* Z80 & I/O area ($A00000-$A1FFFF) specific */
if (reg[23] == 0x50)
{
/* Z80 & I/O area ($A00000-$A1FFFF) */
do
{
/* Z80 area */
if (source <= 0xA0FFFF)
{
/* Return $FFFF only when the Z80 isn't hogging the Z-bus.
(e.g. Z80 isn't reset and 68000 has the bus) */
if (source <= 0xA0FFFF)
{
data = ((zstate ^ 3) ? *(uint16 *)(work_ram + (source & 0xFFFF)) : 0xFFFF);
}
@ -2888,10 +2907,10 @@ static void vdp_dma_vbus(int length)
/* Increment source address */
source += 2;
/* 128k DMA window (i.e reg #23 is not modified) */
source = ((base & 0xFE0000) | (source & 0x1FFFF));
/* 128k DMA window */
source = (reg[23] << 17) | (source & 0x1FFFF);
/* Write data on internal bus */
/* Write data to VRAM, CRAM or VSRAM */
vdp_bus_w(data);
}
while (--length);
@ -2900,69 +2919,82 @@ static void vdp_dma_vbus(int length)
{
do
{
/* Read from mapped memory (ROM/RAM) */
data = *(uint16 *)(m68k_memory_map[source>>16].base + (source & 0xFFFF));
/* Read data word from 68k bus */
if (m68k.memory_map[source>>16].base)
{
data = *(uint16 *)(m68k.memory_map[source>>16].base + (source & 0xFFFF));
}
else
{
data = m68k.memory_map[source>>16].read16(source);
}
/* Increment source address */
source += 2;
/* 128k DMA window (i.e reg #23 is not modified) */
source = ((base & 0xFE0000) | (source & 0x1FFFF));
/* 128k DMA window */
source = (reg[23] << 17) | (source & 0x1FFFF);
/* Write data on internal bus */
/* Write data word to VRAM, CRAM or VSRAM */
vdp_bus_w(data);
}
while (--length);
}
/* Update source address registers (reg #23 has not been modified) */
reg[21] = (source >> 1) & 0xFF;
reg[22] = (source >> 9) & 0xFF;
/* Update DMA source address */
dma_src = (source >> 1) & 0xffff;
}
/* VRAM Copy (TODO: check if CRAM or VSRAM copy is possible) */
static void vdp_dma_copy(int length)
static void vdp_dma_copy(unsigned int length)
{
/* VRAM read/write operation only */
if ((code & 0x1F) == 0x10)
{
int name;
unsigned int temp;
unsigned int source = (reg[22] << 8) | reg[21];
uint8 data;
/* VRAM source address */
uint16 source = dma_src;
do
{
/* Read byte from source address */
temp = READ_BYTE(vram, source);
data = READ_BYTE(vram, source);
/* Intercept writes to Sprite Attribute Table */
if ((addr & sat_base_mask) == satb)
{
/* Update internal SAT */
WRITE_BYTE(sat, addr & sat_addr_mask, temp);
WRITE_BYTE(sat, addr & sat_addr_mask, data);
}
/* Write byte to VRAM address */
WRITE_BYTE(vram, addr, temp);
WRITE_BYTE(vram, addr, data);
/* Update pattern cache */
MARK_BG_DIRTY(addr);
/* Increment source address */
source = (source + 1) & 0xFFFF;
source++;
/* Increment VRAM address */
addr += reg[15];
}
while (--length);
/* Update source address registers */
reg[21] = source & 0xFF;
reg[22] = (source >> 8) & 0xFF;
/* Update DMA source address */
dma_src = source;
}
}
/* VRAM Fill (TODO: check if CRAM or VSRAM fill is possible) */
static void vdp_dma_fill(unsigned int data, int length)
static void vdp_dma_fill(unsigned char data, unsigned int length)
{
/* VRAM write operation only (Williams Greatest Hits after soft reset) */
if ((code & 0x1F) == 0x01)
{
int name;
do
{
/* Intercept writes to Sprite Attribute Table */
@ -2982,4 +3014,5 @@ static void vdp_dma_fill(unsigned int data, int length)
addr += reg[15];
}
while (--length);
}
}

View File

@ -5,7 +5,7 @@
* Support for SG-1000, Master System (315-5124 & 315-5246), Game Gear & Mega Drive VDP
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -89,7 +89,7 @@ extern unsigned int (*vdp_z80_data_r)(void);
extern void vdp_init(void);
extern void vdp_reset(void);
extern int vdp_context_save(uint8 *state);
extern int vdp_context_load(uint8 *state);
extern int vdp_context_load(uint8 *state, char *version);
extern void vdp_dma_update(unsigned int cycles);
extern void vdp_68k_ctrl_w(unsigned int data);
extern void vdp_z80_ctrl_w(unsigned int data);

View File

@ -5,7 +5,7 @@
* Support for SG-1000, Master System (315-5124 & 315-5246), Game Gear & Mega Drive VDP
*
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -5,7 +5,7 @@
* Support for SG-1000, Master System (315-5124 & 315-5246), Game Gear & Mega Drive VDP
*
* Copyright (C) 1998-2007 Charles Mac Donald (original code)
* Copyright (C) 2007-2011 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:

View File

@ -47,16 +47,10 @@
static int check_zip(char *filename);
static int gzsize(gzFile *gd);
int load_archive(char *filename)
int load_archive(char *filename, unsigned char *buffer, int maxsize)
{
int size = 0;
/* ROM buffer should be allocated first */
if (cart.rom == NULL)
{
return 0;
}
if(check_zip(filename))
{
unz_file_info info;
@ -92,15 +86,14 @@ int load_archive(char *filename)
/* Retrieve uncompressed file size */
size = info.uncompressed_size;
if(size > MAXROMSIZE)
if(size > maxsize)
{
unzClose(fd);
return 0;
size = maxsize;
}
/* Read (decompress) the file */
ret = unzReadCurrentFile(fd, cart.rom, info.uncompressed_size);
if(ret != info.uncompressed_size)
ret = unzReadCurrentFile(fd, buffer, size);
if(ret != size)
{
unzCloseCurrentFile(fd);
unzClose(fd);
@ -125,18 +118,8 @@ int load_archive(char *filename)
gzFile *gd = gzopen(filename, "rb");
if (!gd) return 0;
/* Get file size */
size = gzsize(gd);
/* Check file size */
if(size > MAXROMSIZE)
{
gzclose(gd);
return 0;
}
/* Read file data */
gzread(gd, cart.rom, size);
size = gzread(gd, buffer, maxsize);
/* Close file */
gzclose(gd);

View File

@ -43,6 +43,6 @@
#define _FILEIO_H_
/* Function prototypes */
extern int load_archive(char *filename);
extern int load_archive(char *filename, unsigned char *buffer, int maxsize);
#endif /* _FILEIO_H_ */

View File

@ -30,6 +30,15 @@ struct {
} sdl_sound;
static uint8 brm_format[0x40] =
{
0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x00,0x00,0x00,0x00,0x40,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x53,0x45,0x47,0x41,0x5f,0x43,0x44,0x5f,0x52,0x4f,0x4d,0x00,0x01,0x00,0x00,0x00,
0x52,0x41,0x4d,0x5f,0x43,0x41,0x52,0x54,0x52,0x49,0x44,0x47,0x45,0x5f,0x5f,0x5f
};
static short soundframe[SOUND_SAMPLES_SIZE];
static void sdl_sound_callback(void *userdata, Uint8 *stream, int len)
@ -145,7 +154,11 @@ static int sdl_video_init()
static void sdl_video_update()
{
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
if (system_hw == SYSTEM_MCD)
{
system_frame_scd(0);
}
else if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
{
system_frame_gen(0);
}
@ -255,7 +268,7 @@ static Uint32 sdl_sync_timer_callback(Uint32 interval)
{
int fps = vdp_pal ? (sdl_video.frames_rendered / 3) : sdl_video.frames_rendered;
sdl_sync.ticks = sdl_video.frames_rendered = 0;
sprintf(caption,"%d fps - %s", fps, rominfo.international);
sprintf(caption,"%d fps - %s", fps, (rominfo.international[0] != 0x20) ? rominfo.international : rominfo.domestic);
SDL_WM_SetCaption(caption, NULL);
}
return interval;
@ -310,10 +323,8 @@ static int sdl_control_update(SDLKey keystate)
case SDLK_F3:
{
int temp = config.bios & 3;
config.bios &= ~3;
if (temp == 0) config.bios |= 3;
else if (temp == 3) config.bios |= 1;
if (config.bios == 0) config.bios = 3;
else if (config.bios == 3) config.bios = 1;
break;
}
@ -331,13 +342,17 @@ static int sdl_control_update(SDLKey keystate)
case SDLK_F6:
{
if (!use_sound) turbo_mode ^=1;
if (!use_sound)
{
turbo_mode ^=1;
sdl_sync.ticks = 0;
}
break;
}
case SDLK_F7:
{
FILE *f = fopen("game.gpz","r+b");
FILE *f = fopen("game.gp0","rb");
if (f)
{
uint8 buf[STATE_SIZE];
@ -350,7 +365,7 @@ static int sdl_control_update(SDLKey keystate)
case SDLK_F8:
{
FILE *f = fopen("game.gpz","w+b");
FILE *f = fopen("game.gp0","wb");
if (f)
{
uint8 buf[STATE_SIZE];
@ -364,7 +379,20 @@ static int sdl_control_update(SDLKey keystate)
case SDLK_F9:
{
config.region_detect = (config.region_detect + 1) % 5;
region_autodetect();
get_region(0);
/* framerate has changed, reinitialize audio timings */
audio_init(snd.sample_rate, 0);
/* system with region BIOS should be reinitialized */
if ((system_hw == SYSTEM_MCD) || ((system_hw & SYSTEM_SMS) && (config.bios & 1)))
{
system_init();
system_reset();
}
else
{
/* reinitialize I/O region register */
if (system_hw == SYSTEM_MD)
{
io_reg[0x00] = 0x20 | region_code | (config.bios & 1);
@ -374,16 +402,16 @@ static int sdl_control_update(SDLKey keystate)
io_reg[0x00] = 0x80 | (region_code >> 1);
}
/* reinitialize audio timings */
audio_init(snd.sample_rate, snd.frame_rate);
/* reintialize VDP */
vdp_init();
/* reintialize VDP Status flag */
if (system_hw & SYSTEM_MD)
/* reinitialize VDP */
if (vdp_pal)
{
status = (status & ~1) | vdp_pal;
status |= 1;
lines_per_frame = 313;
}
else
{
status &= ~1;
lines_per_frame = 262;
}
/* reinitialize VC max value */
@ -402,6 +430,7 @@ static int sdl_control_update(SDLKey keystate)
/* reinitialize sound emulation */
sound_restore();
}
break;
}
@ -581,9 +610,9 @@ int sdl_input_update(void)
input.analog[0][1] = 0x1fc + (y * (0x2f7-0x1fc+1)) / VIDEO_HEIGHT;
/* Map mouse buttons to player #1 inputs */
if(state & SDL_BUTTON_MMASK) pico_current++;
if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_B;
if(state & SDL_BUTTON_LMASK) input.pad[0] |= INPUT_A;
if(state & SDL_BUTTON_MMASK) pico_current = (pico_current + 1) & 7;
if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_PICO_RED;
if(state & SDL_BUTTON_LMASK) input.pad[0] |= INPUT_PICO_PEN;
break;
}
@ -657,19 +686,8 @@ int main (int argc, char **argv)
error_init();
set_config_defaults();
/* Load ROM file */
cart.rom = malloc(10*1024*1024);
memset(cart.rom, 0, 10*1024*1024);
if(!load_rom(argv[1]))
{
char caption[256];
sprintf(caption, "Error loading file `%s'.", argv[1]);
MessageBox(NULL, caption, "Error", 0);
exit(1);
}
/* mark all BIOS as unloaded */
config.bios &= 0x03;
system_bios = 0;
/* Genesis BOOT ROM support (2KB max) */
memset(boot_rom, 0xFF, 0x800);
@ -686,7 +704,7 @@ int main (int argc, char **argv)
if (!strncmp((char *)(boot_rom + 0x120),"GENESIS OS", 10))
{
/* mark Genesis BIOS as loaded */
config.bios |= SYSTEM_MD;
system_bios = SYSTEM_MD;
}
/* Byteswap ROM */
@ -698,7 +716,6 @@ int main (int argc, char **argv)
}
}
/* initialize SDL */
if(SDL_Init(0) < 0)
{
@ -729,10 +746,71 @@ int main (int argc, char **argv)
SDL_UnlockSurface(sdl_video.surf_bitmap);
bitmap.viewport.changed = 3;
/* initialize emulation */
/* Load game file */
if(!load_rom(argv[1]))
{
char caption[256];
sprintf(caption, "Error loading file `%s'.", argv[1]);
MessageBox(NULL, caption, "Error", 0);
exit(1);
}
/* initialize system hardware */
audio_init(SOUND_FREQUENCY, 0);
system_init();
/* Mega CD specific */
if (system_hw == SYSTEM_MCD)
{
/* load internal backup RAM */
fp = fopen("./scd.brm", "rb");
if (fp!=NULL)
{
fread(scd.bram, 0x2000, 1, fp);
fclose(fp);
}
/* check if internal backup RAM is formatted */
if (memcmp(scd.bram + 0x2000 - 0x20, brm_format + 0x20, 0x20))
{
/* clear internal backup RAM */
memset(scd.bram, 0x00, 0x200);
/* Internal Backup RAM size fields */
brm_format[0x10] = brm_format[0x12] = brm_format[0x14] = brm_format[0x16] = 0x00;
brm_format[0x11] = brm_format[0x13] = brm_format[0x15] = brm_format[0x17] = (sizeof(scd.bram) / 64) - 3;
/* format internal backup RAM */
memcpy(scd.bram + 0x2000 - 0x40, brm_format, 0x40);
}
/* load cartridge backup RAM */
if (scd.cartridge.id)
{
fp = fopen("./cart.brm", "rb");
if (fp!=NULL)
{
fread(scd.cartridge.area, scd.cartridge.mask + 1, 1, fp);
fclose(fp);
}
/* check if cartridge backup RAM is formatted */
if (memcmp(scd.cartridge.area + scd.cartridge.mask + 1 - 0x20, brm_format + 0x20, 0x20))
{
/* clear cartridge backup RAM */
memset(scd.cartridge.area, 0x00, scd.cartridge.mask + 1);
/* Cartridge Backup RAM size fields */
brm_format[0x10] = brm_format[0x12] = brm_format[0x14] = brm_format[0x16] = (((scd.cartridge.mask + 1) / 64) - 3) >> 8;
brm_format[0x11] = brm_format[0x13] = brm_format[0x15] = brm_format[0x17] = (((scd.cartridge.mask + 1) / 64) - 3) & 0xff;
/* format cartridge backup RAM */
memcpy(scd.cartridge.area + scd.cartridge.mask + 1 - sizeof(brm_format), brm_format, sizeof(brm_format));
}
}
}
else
{
/* load SRAM */
fp = fopen("./game.srm", "rb");
if (fp!=NULL)
@ -740,8 +818,9 @@ int main (int argc, char **argv)
fread(sram.sram,0x10000,1, fp);
fclose(fp);
}
}
/* reset emulation */
/* reset system hardware */
system_reset();
if(use_sound) SDL_PauseAudio(0);
@ -775,9 +854,37 @@ int main (int argc, char **argv)
{
SDL_SemWait(sdl_sync.sem_sync);
}
}
if (system_hw == SYSTEM_MCD)
{
/* save internal backup RAM (if formatted) */
if (!memcmp(scd.bram + 0x2000 - 0x20, brm_format + 0x20, 0x20))
{
fp = fopen("./scd.brm", "wb");
if (fp!=NULL)
{
fwrite(scd.bram, 0x2000, 1, fp);
fclose(fp);
}
}
/* save cartridge backup RAM (if formatted) */
if (scd.cartridge.id)
{
if (!memcmp(scd.cartridge.area + scd.cartridge.mask + 1 - 0x20, brm_format + 0x20, 0x20))
{
fp = fopen("./cart.brm", "wb");
if (fp!=NULL)
{
fwrite(scd.cartridge.area, scd.cartridge.mask + 1, 1, fp);
fclose(fp);
}
}
}
}
else
{
/* save SRAM */
fp = fopen("./game.srm", "wb");
if (fp!=NULL)
@ -785,11 +892,11 @@ int main (int argc, char **argv)
fwrite(sram.sram,0x10000,1, fp);
fclose(fp);
}
}
system_shutdown();
audio_shutdown();
error_shutdown();
free(cart.rom);
sdl_video_close();
sdl_sound_close();

View File

@ -24,8 +24,13 @@
#define AR_ROM "./areplay.bin"
#define SK_ROM "./sk.bin"
#define SK_UPMEM "./sk2chip.bin"
#define MD_BIOS "./bios.bin"
#define MS_BIOS "./bios.sms"
#define CD_BIOS_US "./bios_CD_U.bin"
#define CD_BIOS_EU "./bios_CD_E.bin"
#define CD_BIOS_JP "./bios_CD_J.bin"
#define MD_BIOS "./bios_MD.bin"
#define MS_BIOS_US "./bios_U.sms"
#define MS_BIOS_EU "./bios_E.sms"
#define MS_BIOS_JP "./bios_J.sms"
#define GG_BIOS "./bios.gg"
#endif /* _OSD_H_ */

View File

@ -36,6 +36,7 @@
* - Fixed behavior of chained FD and DD prefixes (R register should be only incremented by one
* - Implemented cycle-accurate INI/IND (needed by SMS emulation)
* - Fixed Z80 reset
* - Made SZHVC_add & SZHVC_sub tables statically allocated
* Changes in 3.9:
* - Fixed cycle counts for LD IYL/IXL/IYH/IXH,n [Marshmellow]
* - Fixed X/Y flags in CCF/SCF/BIT, ZEXALL is happy now [hap]
@ -199,8 +200,6 @@
#define IFF2 Z80.iff2
#define HALT Z80.halt
extern unsigned int mcycles_z80;
Z80_Regs Z80;
unsigned char *z80_readmap[64];
@ -219,8 +218,8 @@ static UINT8 SZP[256]; /* zero, sign and parity flags */
static UINT8 SZHV_inc[256]; /* zero, sign, half carry and overflow flags INC r8 */
static UINT8 SZHV_dec[256]; /* zero, sign, half carry and overflow flags DEC r8 */
static UINT8 *SZHVC_add = 0;
static UINT8 *SZHVC_sub = 0;
static UINT8 SZHVC_add[2*256*256]; /* flags for ADD opcode */
static UINT8 SZHVC_sub[2*256*256]; /* flags for SUB opcode */
static const UINT16 cc_op[0x100] = {
4*15,10*15, 7*15, 6*15, 4*15, 4*15, 7*15, 4*15, 4*15,11*15, 7*15, 6*15, 4*15, 4*15, 7*15, 4*15,
@ -473,7 +472,7 @@ INLINE void BURNODD(int cycles, int opcodes, int cyclesum)
if( cycles > 0 )
{
R += (cycles / cyclesum) * opcodes;
mcycles_z80 += (cycles / cyclesum) * cyclesum * 15;
Z80.cycles += (cycles / cyclesum) * cyclesum * 15;
}
}
@ -485,7 +484,7 @@ INLINE void BURNODD(int cycles, int opcodes, int cyclesum)
/***************************************************************
* adjust cycle count by n T-states
***************************************************************/
#define CC(prefix,opcode) mcycles_z80 += cc[Z80_TABLE_##prefix][opcode]
#define CC(prefix,opcode) Z80.cycles += cc[Z80_TABLE_##prefix][opcode]
/***************************************************************
* execute an opcode
@ -3228,7 +3227,7 @@ static void take_interrupt(void)
PUSH( pc );
PCD = 0x0038;
/* RST $38 + 'interrupt latency' cycles */
mcycles_z80 += cc[Z80_TABLE_op][0xff] + cc[Z80_TABLE_ex][0xff];
Z80.cycles += cc[Z80_TABLE_op][0xff] + cc[Z80_TABLE_ex][0xff];
}
else
{
@ -3243,7 +3242,7 @@ static void take_interrupt(void)
RM16( irq_vector, &Z80.pc );
LOG(("Z80 #%d IM2 [$%04x] = $%04x\n",cpu_getactivecpu() , irq_vector, PCD));
/* CALL $xxxx + 'interrupt latency' cycles */
mcycles_z80 += cc[Z80_TABLE_op][0xcd] + cc[Z80_TABLE_ex][0xff];
Z80.cycles += cc[Z80_TABLE_op][0xcd] + cc[Z80_TABLE_ex][0xff];
}
else
{
@ -3257,18 +3256,18 @@ static void take_interrupt(void)
PUSH( pc );
PCD = irq_vector & 0xffff;
/* CALL $xxxx + 'interrupt latency' cycles */
mcycles_z80 += cc[Z80_TABLE_op][0xcd] + cc[Z80_TABLE_ex][0xff];
Z80.cycles += cc[Z80_TABLE_op][0xcd] + cc[Z80_TABLE_ex][0xff];
break;
case 0xc30000: /* jump */
PCD = irq_vector & 0xffff;
/* JP $xxxx + 2 cycles */
mcycles_z80 += cc[Z80_TABLE_op][0xc3] + cc[Z80_TABLE_ex][0xff];
Z80.cycles += cc[Z80_TABLE_op][0xc3] + cc[Z80_TABLE_ex][0xff];
break;
default: /* rst (or other opcodes?) */
PUSH( pc );
PCD = irq_vector & 0x0038;
/* RST $xx + 2 cycles */
mcycles_z80 += cc[Z80_TABLE_op][0xff] + cc[Z80_TABLE_ex][0xff];
Z80.cycles += cc[Z80_TABLE_op][0xff] + cc[Z80_TABLE_ex][0xff];
break;
}
}
@ -3283,21 +3282,11 @@ void z80_init(const void *config, int (*irqcallback)(int))
{
int i, p;
if( !SZHVC_add || !SZHVC_sub )
{
int oldval, newval, val;
UINT8 *padd, *padc, *psub, *psbc;
/* allocate big flag arrays once */
SZHVC_add = (UINT8 *)malloc(2*256*256);
SZHVC_sub = (UINT8 *)malloc(2*256*256);
if( !SZHVC_add || !SZHVC_sub )
{
return;
}
padd = &SZHVC_add[ 0*256];
padc = &SZHVC_add[256*256];
psub = &SZHVC_sub[ 0*256];
psbc = &SZHVC_sub[256*256];
UINT8 *padd = &SZHVC_add[ 0*256];
UINT8 *padc = &SZHVC_add[256*256];
UINT8 *psub = &SZHVC_sub[ 0*256];
UINT8 *psbc = &SZHVC_sub[256*256];
for (oldval = 0; oldval < 256; oldval++)
{
for (newval = 0; newval < 256; newval++)
@ -3339,7 +3328,6 @@ void z80_init(const void *config, int (*irqcallback)(int))
psbc++;
}
}
}
for (i = 0; i < 256; i++)
{
@ -3403,26 +3391,18 @@ void z80_reset(void)
WZ=PCD;
}
void z80_exit(void)
{
if (SZHVC_add) free(SZHVC_add);
SZHVC_add = NULL;
if (SZHVC_sub) free(SZHVC_sub);
SZHVC_sub = NULL;
}
/****************************************************************************
* Run until given cycle count
****************************************************************************/
void z80_run(unsigned int cycles)
{
while( mcycles_z80 < cycles )
while( Z80.cycles < cycles )
{
/* check for IRQs before each instruction */
if (Z80.irq_state && IFF1 && !Z80.after_ei)
{
take_interrupt();
if (mcycles_z80 >= cycles) return;
if (Z80.cycles >= cycles) return;
}
Z80.after_ei = FALSE;
@ -3441,7 +3421,7 @@ void z80_burn(unsigned int cycles)
/* NOP takes 4 cycles per instruction */
int n = (cycles + 3) / 4;
R += n;
mcycles_z80 += 4 * n * 15;
Z80.cycles += 4 * n * 15;
}
}
@ -3484,7 +3464,7 @@ void z80_set_nmi_line(unsigned int state)
PCD = 0x0066;
WZ=PCD;
mcycles_z80 += 11*15;
Z80.cycles += 11*15;
}
Z80.nmi_state = state;

View File

@ -43,6 +43,7 @@ typedef struct
UINT8 nmi_pending; /* nmi pending */
UINT8 irq_state; /* irq line state */
UINT8 after_ei; /* are we in the EI shadow? */
UINT32 cycles; /* master clock cycles global counter */
const struct z80_irq_daisy_chain *daisy;
int (*irq_callback)(int irqline);
} Z80_Regs;
@ -60,7 +61,6 @@ extern unsigned char (*z80_readport)(unsigned int port);
extern void z80_init(const void *config, int (*irqcallback)(int));
extern void z80_reset (void);
extern void z80_exit (void);
extern void z80_run(unsigned int cycles);
extern void z80_burn(unsigned int cycles);
extern void z80_get_context (void *dst);