mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-12-24 18:21:50 +01:00
[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:
parent
f502dd48c7
commit
28775cc3aa
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
****************************************************************************************/
|
||||
|
||||
#include "shared.h"
|
||||
#include "gg_eeprom.h"
|
||||
|
||||
#define BIT_DATA (0)
|
||||
#define BIT_CLK (1)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
*/
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
****************************************************************************************/
|
||||
|
||||
#include "shared.h"
|
||||
#include "md_eeprom.h"
|
||||
|
||||
#define GAME_CNT 28
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
258
source/cd_hw/cd_cart.c
Normal 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
50
source/cd_hw/cd_cart.h
Normal 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
626
source/cd_hw/cdc.c
Normal 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
69
source/cd_hw/cdc.h
Normal 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
567
source/cd_hw/cdd.c
Normal 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
84
source/cd_hw/cdd.h
Normal 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
672
source/cd_hw/gfx.c
Normal 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
114
source/cd_hw/gfx.h
Normal 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
341
source/cd_hw/pcm.c
Normal 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
73
source/cd_hw/pcm.h
Normal 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
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
85
source/cd_hw/scd.h
Normal 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
|
281
source/genesis.c
281
source/genesis.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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*/
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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())
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
123
source/gx/main.c
123
source/gx/main.c
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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:
|
||||
|
584
source/loadrom.c
584
source/loadrom.c
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
|
@ -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
|
||||
|
@ -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 ============================= */
|
||||
|
@ -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
@ -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
93
source/m68k/s68kconf.h
Normal 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
340
source/m68k/s68kcpu.c
Normal 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
4099
source/m68k/s68ki_cycles.h
Normal file
File diff suppressed because it is too large
Load Diff
617
source/mem68k.c
617
source/mem68k.c
@ -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));
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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_ */
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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]);
|
||||
}
|
||||
|
||||
|
@ -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); \
|
||||
|
414
source/system.c
414
source/system.c
@ -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;
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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_ */
|
||||
|
@ -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();
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user