mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-09-10 16:53:15 +02:00
added proper IO initialization routines
improved cartridge structure added Lock-ON hardware emulation (Sonic & Knuckles) added cartridge ROM mirroring support (required for Lock-ON emulation)
This commit is contained in:
parent
0743df467e
commit
5b888e725b
@ -32,20 +32,7 @@
|
||||
extern int emulate_address_error;
|
||||
|
||||
/* Global Variables */
|
||||
T_CART_HW cart_hw;
|
||||
uint8 j_cart;
|
||||
uint8 *default_rom;
|
||||
int old_system[2] = {-1,-1};
|
||||
|
||||
/* Function prototypes */
|
||||
void default_time_w(uint32 address, uint32 data);
|
||||
void special_mapper_w(uint32 address, uint32 data);
|
||||
void realtec_mapper_w(uint32 address, uint32 data);
|
||||
void seganet_mapper_w(uint32 address, uint32 data);
|
||||
uint32 radica_mapper_r(uint32 address);
|
||||
void default_regs_w(uint32 address, uint32 data);
|
||||
uint32 default_regs_r(uint32 address);
|
||||
void special_regs_w(uint32 address, uint32 data);
|
||||
T_CART cart;
|
||||
|
||||
/* Cart database entry */
|
||||
typedef struct
|
||||
@ -57,64 +44,75 @@ typedef struct
|
||||
T_CART_HW cart_hw; /* hardware description */
|
||||
} T_CART_ENTRY;
|
||||
|
||||
/* Function prototypes */
|
||||
static void sega_mapper_w(uint32 address, uint32 data);
|
||||
static void special_mapper_w(uint32 address, uint32 data);
|
||||
static void realtec_mapper_w(uint32 address, uint32 data);
|
||||
static void seganet_mapper_w(uint32 address, uint32 data);
|
||||
static uint32 radica_mapper_r(uint32 address);
|
||||
static void default_time_w(uint32 address, uint32 data);
|
||||
static void default_regs_w(uint32 address, uint32 data);
|
||||
static uint32 default_regs_r(uint32 address);
|
||||
static void special_regs_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] =
|
||||
{
|
||||
/* Game no Kanzume Otokuyou */
|
||||
{0x0000,0xf9d1,0,0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,0,0,seganet_mapper_w,0,0}},
|
||||
/* RADICA (Volume 1) (not byteswapped) */
|
||||
{0x0000,0x2326,0,0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,1,radica_mapper_r,0,0,0}},
|
||||
/* RADICA (Volume 2) */
|
||||
{0x4f10,0x0836,0,0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,1,radica_mapper_r,0,0,0}},
|
||||
/* RADICA (Volume 1) */
|
||||
{0xf424,0x9f82,0,0,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,1,radica_mapper_r,0,0,0}},
|
||||
/* Funny World & Balloon Boy */
|
||||
{0x0000,0x06ab,0x40,0x40,{{0,0,0,0},{0,0,0,0},{0,0,0,0},1,1,0,0,0,realtec_mapper_w}},
|
||||
{0x0000,0x06ab,0x40,0x40,{{0x00,0x00,0x00,0x00},{0x000000,0x000000,0x000000,0x000000},{0x000000,0x000000,0x000000,0x000000},1,0,1,NULL,NULL,NULL,realtec_mapper_w}},
|
||||
/* Whac-a-Critter */
|
||||
{0xffff,0xf863,0x40,0x40,{{0,0,0,0},{0,0,0,0},{0,0,0,0},1,1,0,0,0,realtec_mapper_w}},
|
||||
{0xffff,0xf863,0x40,0x40,{{0x00,0x00,0x00,0x00},{0x000000,0x000000,0x000000,0x000000},{0x000000,0x000000,0x000000,0x000000},1,0,1,NULL,NULL,NULL,realtec_mapper_w}},
|
||||
/* Earth Defense */
|
||||
{0xffff,0x44fb,0x40,0x40,{{0,0,0,0},{0,0,0,0},{0,0,0,0},1,1,0,0,0,realtec_mapper_w}},
|
||||
/* Super Mario 2 1998 */
|
||||
{0xffff,0x0474,0,0,{{0x0a,0,0,0},{0xffffff,0,0,0},{0xa13000,0,0,0},0,0,default_regs_r,0,0,0}},
|
||||
/* Super Mario 2 1998 */
|
||||
{0x2020,0xb4eb,0,0,{{0x1c,0,0,0},{0xffffff,0,0,0},{0xa13000,0,0,0},0,0,default_regs_r,0,0,0}},
|
||||
/* Supper Bubble Bobble */
|
||||
{0x0000,0x16cd,0x40,0x40,{{0x55,0x0f,0,0},{0xffffff,0xffffff,0,0},{0x400000,0x400002,0,0},0,0,0,0,default_regs_r,0}},
|
||||
/* Mahjong Lover */
|
||||
{0x0000,0x7037,0x40,0x40,{{0x90,0xd3,0,0},{0xffffff,0xffffff,0,0},{0x400000,0x401000,0,0},0,0,0,0,default_regs_r,0}},
|
||||
/* Lion King 2 */
|
||||
{0xffff,0x1d9b,0x40,0x40,{{0,0,0,0},{0xfffffd,0xfffffd,0,0},{0x400000,0x400004,0,0},0,0,0,0,default_regs_r,default_regs_w}},
|
||||
/* Squirell King */
|
||||
{0x0000,0x8ec8,0x40,0x40,{{0,0,0,0},{0xfffffd,0xfffffd,0,0},{0x400000,0x400004,0,0},0,0,0,0,default_regs_r,default_regs_w}},
|
||||
/* Rockman X3 */
|
||||
{0x0000,0x9d0e,0x40,0x40,{{0x0c,0x88,0,0},{0xffffff,0xffffff,0,0},{0xa13000,0x400004,0,0},0,0,default_regs_r,0,default_regs_r,0}},
|
||||
/* A Bug's Life */
|
||||
{0x7f7f,0x2aad,0,0,{{0x28,0x1f,0x01,0},{0xffffff,0xffffff,0xffffff,0},{0xa13000,0xa13002,0xa1303e,0},0,0,default_regs_r,0,0,0}},
|
||||
/* King of Fighter 99 */
|
||||
{0x0000,0x21e,0,0,{{0x00,0x01,0x1f,0},{0xffffff,0xffffff,0xffffff,0},{0xa13000,0xa13002,0xa1303e,0},0,0,default_regs_r,0,0,0}},
|
||||
/* Pocket Monster */
|
||||
{0xd6fc,0x1eb1,0,0,{{0x00,0x01,0x1f,0},{0xffffff,0xffffff,0xffffff,0},{0xa13000,0xa13002,0xa1303e,0},0,0,default_regs_r,0,0,0}},
|
||||
{0xffff,0x44fb,0x40,0x40,{{0x00,0x00,0x00,0x00},{0x000000,0x000000,0x000000,0x000000},{0x000000,0x000000,0x000000,0x000000},1,0,1,NULL,NULL,NULL,realtec_mapper_w}},
|
||||
/* RADICA (Volume 1) (not byteswapped) */
|
||||
{0x0000,0x2326,0x00,0x00,{{0x00,0x00,0x00,0x00},{0x000000,0x000000,0x000000,0x000000},{0x000000,0x000000,0x000000,0x000000},0,0,1,radica_mapper_r,NULL,NULL,NULL}},
|
||||
/* RADICA (Volume 2) */
|
||||
{0x4f10,0x0836,0x00,0x00,{{0x00,0x00,0x00,0x00},{0x000000,0x000000,0x000000,0x000000},{0x000000,0x000000,0x000000,0x000000},0,0,1,radica_mapper_r,NULL,NULL,NULL}},
|
||||
/* RADICA (Volume 1) */
|
||||
{0xf424,0x9f82,0x00,0x00,{{0x00,0x00,0x00,0x00},{0x000000,0x000000,0x000000,0x000000},{0x000000,0x000000,0x000000,0x000000},0,0,1,radica_mapper_r,NULL,NULL,NULL}},
|
||||
/* Lion King 3 */
|
||||
{0x0000,0x507c,0x60,0x7f,{{0,0,0,0},{0xf0000e,0xf0000e,0xf0000e,0},{0x600000,0x600002,0x600004,0},0,1,0,0,default_regs_r,special_regs_w}},
|
||||
{0x0000,0x507c,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf0000e,0xf0000e,0xf0000e,0x000000},{0x600000,0x600002,0x600004,0x000000},0,0,1,NULL,NULL,default_regs_r,special_regs_w}},
|
||||
/* Super King Kong 99 */
|
||||
{0x0000,0x7d6e,0x60,0x7f,{{0,0,0,0},{0xf0000e,0xf0000e,0xf0000e,0},{0x600000,0x600002,0x600004,0},0,1,0,0,default_regs_r,special_regs_w}},
|
||||
{0x0000,0x7d6e,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf0000e,0xf0000e,0xf0000e,0x000000},{0x600000,0x600002,0x600004,0x000000},0,0,1,NULL,NULL,default_regs_r,special_regs_w}},
|
||||
/* Pokemon Stadium */
|
||||
{0x0000,0x843c,0x70,0x7f,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,1,0,0,0,special_regs_w}},
|
||||
{0x0000,0x843c,0x70,0x7f,{{0x00,0x00,0x00,0x00},{0x000000,0x000000,0x000000,0x000000},{0x000000,0x000000,0x000000,0x000000},0,0,1,NULL,NULL,default_regs_r,special_regs_w}},
|
||||
/* Lion King 2 */
|
||||
{0xffff,0x1d9b,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0x000000,0x000000},{0x400000,0x400004,0x000000,0x000000},0,0,0,NULL,NULL,default_regs_r,default_regs_w}},
|
||||
/* Squirell King */
|
||||
{0x0000,0x8ec8,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0x000000,0x000000},{0x400000,0x400004,0x000000,0x000000},0,0,0,NULL,NULL,default_regs_r,default_regs_w}},
|
||||
/* Supper Bubble Bobble */
|
||||
{0x0000,0x16cd,0x40,0x40,{{0x55,0x0f,0x00,0x00},{0xffffff,0xffffff,0x000000,0x000000},{0x400000,0x400002,0x000000,0x000000},0,0,0,NULL,NULL,default_regs_r,NULL}},
|
||||
/* Mahjong Lover */
|
||||
{0x0000,0x7037,0x40,0x40,{{0x90,0xd3,0x00,0x00},{0xffffff,0xffffff,0x000000,0x000000},{0x400000,0x401000,0x000000,0x000000},0,0,0,NULL,NULL,default_regs_r,NULL}},
|
||||
/* Elf Wor */
|
||||
{0x0080,0x3dba,0x40,0x40,{{0x55,0x0f,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,0,default_regs_r,0}},
|
||||
{0x0080,0x3dba,0x40,0x40,{{0x55,0x0f,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,NULL,NULL,default_regs_r,NULL}},
|
||||
/* Huan Le Tao Qi Shu - Smart Mouse */
|
||||
{0x0000,0x1a28,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,0,default_regs_r,0}},
|
||||
{0x0000,0x1a28,0x40,0x40,{{0x55,0x0f,0xaa,0xf0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,NULL,NULL,default_regs_r,NULL}},
|
||||
/* Ya-Se Chuanshuo */
|
||||
{0xffff,0xd472,0x40,0x40,{{0x63,0x98,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,0,default_regs_r,0}},
|
||||
{0xffff,0xd472,0x40,0x40,{{0x63,0x98,0xc9,0x18},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,NULL,NULL,default_regs_r,NULL}},
|
||||
/* Soul Blade */
|
||||
{0x0000,0x0c5b,0x40,0x40,{{0x00,0x98,0xc9,0xF0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,0,default_regs_r,0}},
|
||||
{0x0000,0x0c5b,0x40,0x40,{{0x00,0x98,0xc9,0xF0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},0,0,0,NULL,NULL,default_regs_r,NULL}},
|
||||
/* King of Fighter 98 */
|
||||
{0x0000,0xd0a0,0x48,0x4f,{{0xaa,0xa0,0xf0,0xa0},{0xfc0000,0xffffff,0xffffff,0xffffff},{0x480000,0x4c82c0,0x4cdda0,0x4f8820},0,0,0,0,default_regs_r,0}},
|
||||
{0x0000,0xd0a0,0x48,0x4f,{{0xaa,0xa0,0xf0,0xa0},{0xfc0000,0xffffff,0xffffff,0xffffff},{0x480000,0x4c82c0,0x4cdda0,0x4f8820},0,0,0,NULL,NULL,default_regs_r,NULL}},
|
||||
/* Lian Huan Pao - Barver Battle Saga */
|
||||
{0x30b9,0x1c2a,0x40,0x40,{{0,0,0,0},{0,0,0,0},{0,0,0,0},0,0,0,0,default_regs_r,0}}
|
||||
{0x30b9,0x1c2a,0x40,0x40,{{0x00,0x00,0x00,0x00},{0x000000,0x000000,0x000000,0x000000},{0x000000,0x000000,0x000000,0x000000},0,0,0,NULL,NULL,default_regs_r,NULL}},
|
||||
/* Rockman X3 */
|
||||
{0x0000,0x9d0e,0x40,0x40,{{0x0c,0x88,0x00,0x00},{0xffffff,0xffffff,0x000000,0x000000},{0xa13000,0x400004,0x000000,0x000000},0,0,0,default_regs_r,NULL,default_regs_r,NULL}},
|
||||
/* Super Mario 2 1998 */
|
||||
{0xffff,0x0474,0x00,0x00,{{0x0a,0x00,0x00,0x00},{0xffffff,0x000000,0x000000,0x000000},{0xa13000,0x000000,0x000000,0x000000},0,0,0,default_regs_r,NULL,NULL,NULL}},
|
||||
/* Super Mario 2 1998 */
|
||||
{0x2020,0xb4eb,0x00,0x00,{{0x1c,0x00,0x00,0x00},{0xffffff,0x000000,0x000000,0x000000},{0xa13000,0x000000,0x000000,0x000000},0,0,0,default_regs_r,NULL,NULL,NULL}},
|
||||
/* A Bug's Life */
|
||||
{0x7f7f,0x2aad,0x00,0x00,{{0x28,0x1f,0x01,0x00},{0xffffff,0xffffff,0xffffff,0x000000},{0xa13000,0xa13002,0xa1303e,0x000000},0,0,0,default_regs_r,NULL,NULL,NULL}},
|
||||
/* King of Fighter 99 */
|
||||
{0x0000,0x021e,0x00,0x00,{{0x00,0x01,0x1f,0x00},{0xffffff,0xffffff,0xffffff,0x000000},{0xa13000,0xa13002,0xa1303e,0x000000},0,0,0,default_regs_r,NULL,NULL,NULL}},
|
||||
/* Pocket Monster */
|
||||
{0xd6fc,0x1eb1,0x00,0x00,{{0x00,0x01,0x1f,0x00},{0xffffff,0xffffff,0xffffff,0x000000},{0xa13000,0xa13002,0xa1303e,0x000000},0,0,0,default_regs_r,NULL,NULL,NULL}},
|
||||
/* Game no Kanzume Otokuyou */
|
||||
{0x0000,0xf9d1,0x00,0x00,{{0x00,0x00,0x00,0x00},{0x000000,0x000000,0x000000,0x000000},{0x000000,0x000000,0x000000,0x000000},0,0,0,NULL,seganet_mapper_w,NULL,NULL}}
|
||||
};
|
||||
|
||||
/* temporary memory chunk */
|
||||
@ -125,64 +123,97 @@ static uint8 mem_chunk[0x10000];
|
||||
Cart Hardware initialization
|
||||
*************************************************************/
|
||||
|
||||
/* hardware that need to be reseted on power on */
|
||||
void cart_hw_reset()
|
||||
{
|
||||
int i;
|
||||
|
||||
/* reset bankshifting */
|
||||
if (cart_hw.bankshift)
|
||||
{
|
||||
for (i=0x00; i<0x40; i++)
|
||||
m68k_memory_map[i].base = cart_rom + (i<<16);
|
||||
}
|
||||
|
||||
/* Realtec mapper */
|
||||
if (cart_hw.realtec & 1)
|
||||
{
|
||||
/* enable BOOTROM */
|
||||
for (i=0; i<0x40; i++) m68k_memory_map[i].base = mem_chunk;
|
||||
for (i=0; i<8; i++) memcpy(mem_chunk + i*0x2000, cart_rom + 0x7e000, 0x2000);
|
||||
cart_hw.realtec |= 2;
|
||||
}
|
||||
|
||||
/* SVP chip */
|
||||
if (svp) svp_reset();
|
||||
|
||||
/* Lock-ON */
|
||||
switch (config.lock_on)
|
||||
{
|
||||
case GAME_GENIE:
|
||||
ggenie_reset();
|
||||
break;
|
||||
|
||||
case ACTION_REPLAY:
|
||||
datel_reset();
|
||||
break;
|
||||
|
||||
case SONIC_KNUCKLES:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* save default cartridge slot mapping */
|
||||
default_rom = m68k_memory_map[0].base;
|
||||
}
|
||||
|
||||
/* cart hardware detection */
|
||||
void cart_hw_init()
|
||||
{
|
||||
int i;
|
||||
/***************************************************************************************************************
|
||||
CARTRIDGE ROM MIRRORING
|
||||
***************************************************************************************************************
|
||||
|
||||
Cartridge area is mapped to $000000-$3fffff:
|
||||
|
||||
-> when accessing ROM, 68k address lines A1 to A21 are used by the internal cartridge hardware to decode the
|
||||
full 4MB address range.
|
||||
-> depending on the ROM total size, some address lines might be ignored, resulting in ROM mirroring.
|
||||
|
||||
|
||||
Cartridges can use either 8-bits (x2) or 16-bits (x1, x2) Mask ROM chips, each chip size is a factor of 2 bytes:
|
||||
|
||||
-> two 8-bits chips are equivalent to one 16-bits chip, no specific address decoding is required, needed
|
||||
address lines are simply connected to each chip, upper address lines are ignored and data lines are
|
||||
connected appropriately to each chip (D0-D7 to one chip, D8-D15 to the other one).
|
||||
ROM is mirrored each N bytes where N=2^(k+1) is the total ROM size (ROM1+ROM2,ROM1+ROM2,...).
|
||||
|
||||
-> one single 16-bits chip do not need specific address decoding, address lines are simply connected
|
||||
depending on the ROM size, upper address lines being ignored.
|
||||
ROM is mirrored each N bytes where N=2^k is the size of the ROM chip (ROM1,ROM1,ROM1,...).
|
||||
|
||||
-> two 16-bits chips of the same size are equivalent to one chip of double size, address decoding generally
|
||||
is the same except that specific hardware is used (one address line is generally used for chip selection,
|
||||
lower ones being used to address the chips and upper ones being ignored).
|
||||
ROM is mirrored continuously each N bytes where N=2^(k+1) is the total ROM size (ROM1,ROM2,ROM1,ROM2,...).
|
||||
|
||||
-> two 16-bits chips with different size are mapped differently. Address decoding is done the same way as
|
||||
above (one address line used for chip selection) but the ignored & required address lines differ from
|
||||
one chip to another, which makes ROM mirroring different.
|
||||
ROM2 size is generally half of ROM1 size and ROM are mirrored like that : ROM1,ROM2,ROM2,ROM1,ROM2,ROM2,...
|
||||
|
||||
From the emulator point of view, we only need to distinguish 3 cases:
|
||||
|
||||
1/ total ROM size is a factor of 2: ROM is mirrored each 2^k bytes.
|
||||
|
||||
2/ total ROM size is not a factor of 2 and cartridge uses one or two chips of the same size (Type A):
|
||||
ROM is padded up to 2^k and mirrored each 2^k bytes.
|
||||
|
||||
3/ total ROM size is not a factor of 2 and cartridge uses two chips of different sizes (Type B):
|
||||
ROM is not padded and the first 2^(k-1) bytes are mirrored each 2^k bytes while the next 2^(k-2) bytes are
|
||||
mirrored in the last 2^(k-2) bytes.
|
||||
|
||||
******************************************************************************************************************/
|
||||
|
||||
/* calculate nearest size with factor of 2 */
|
||||
int size = 0x10000;
|
||||
while (cart.romsize > size) size <<= 1;
|
||||
|
||||
/* total ROM size is not a factor of 2 */
|
||||
if ((size < MAXROMSIZE) && (cart.romsize < size))
|
||||
{
|
||||
/* two chips with different size */
|
||||
if (config.romtype)
|
||||
{
|
||||
/* third ROM section is mirrored in the last section */
|
||||
memcpy(cart.rom + cart.romsize, cart.rom + 2*cart.romsize - size, size - cart.romsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ROM is padded up to 2^k bytes */
|
||||
memset(cart.rom + cart.romsize, 0xff, size - cart.romsize);
|
||||
}
|
||||
}
|
||||
|
||||
/* special case: Sonic & Knuckles */
|
||||
/* $200000-$3fffff is mapped to external cartridge */
|
||||
if (strstr(rominfo.international,"SONIC & KNUCKLES") != NULL)
|
||||
{
|
||||
/* disable ROM mirroring */
|
||||
size = 0x400000;
|
||||
}
|
||||
|
||||
/* ROM is mirrored each 2^k bytes */
|
||||
int i = size;
|
||||
while (i < 0x400000)
|
||||
{
|
||||
memcpy(cart.rom + i, cart.rom, size);
|
||||
i += size;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
DEFAULT CARTRIDGE MAPPING
|
||||
***********************************************/
|
||||
for (i=0; i<0x40; i++)
|
||||
{
|
||||
/* cartridge ROM */
|
||||
m68k_memory_map[i].base = cart_rom + (i<<16);
|
||||
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].write8 = m68k_unused_8_w;
|
||||
@ -194,7 +225,7 @@ void cart_hw_init()
|
||||
for (i=0x40; i<0x80; i++)
|
||||
{
|
||||
/* unused area */
|
||||
m68k_memory_map[i].base = cart_rom + (i<<16);
|
||||
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;
|
||||
@ -203,10 +234,6 @@ void cart_hw_init()
|
||||
zbank_memory_map[i].write = zbank_unused_w;
|
||||
}
|
||||
|
||||
/* restore previous setting */
|
||||
if (old_system[0] != -1) input.system[0] = old_system[0];
|
||||
if (old_system[1] != -1) input.system[1] = old_system[1];
|
||||
|
||||
/**********************************************
|
||||
EXTERNAL RAM
|
||||
***********************************************/
|
||||
@ -240,26 +267,6 @@ void cart_hw_init()
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
CARTRIDGE LOCK-ON
|
||||
***********************************************/
|
||||
switch (config.lock_on)
|
||||
{
|
||||
case GAME_GENIE:
|
||||
ggenie_init();
|
||||
break;
|
||||
|
||||
case ACTION_REPLAY:
|
||||
datel_init();
|
||||
break;
|
||||
|
||||
case SONIC_KNUCKLES:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
SVP CHIP
|
||||
***********************************************/
|
||||
@ -268,11 +275,11 @@ void cart_hw_init()
|
||||
{
|
||||
svp_init();
|
||||
|
||||
m68k_memory_map[0x30].base = svp->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].base = svp->dram + 0x10000;
|
||||
m68k_memory_map[0x31].read16 = NULL;
|
||||
m68k_memory_map[0x31].write16 = svp_write_dram;
|
||||
|
||||
@ -280,109 +287,89 @@ void cart_hw_init()
|
||||
m68k_memory_map[0x3a].read16 = svp_read_cell_2;
|
||||
}
|
||||
|
||||
|
||||
/* default GUN settings */
|
||||
input.x_offset = 0x00;
|
||||
input.y_offset = 0x00;
|
||||
|
||||
/**********************************************
|
||||
SEGA MENACER
|
||||
***********************************************/
|
||||
if (strstr(rominfo.international,"MENACER") != NULL)
|
||||
{
|
||||
/* save current setting */
|
||||
if (old_system[0] == -1) old_system[0] = input.system[0];
|
||||
if (old_system[1] == -1) old_system[1] = input.system[1];
|
||||
|
||||
input.system[0] = NO_SYSTEM;
|
||||
input.system[1] = SYSTEM_MENACER;
|
||||
input.x_offset = 0x52;
|
||||
input.y_offset = 0x00;
|
||||
}
|
||||
else if (strstr(rominfo.international,"T2 ; THE ARCADE GAME") != NULL)
|
||||
{
|
||||
/* save current setting */
|
||||
if (old_system[0] == -1) old_system[0] = input.system[0];
|
||||
if (old_system[1] == -1) old_system[1] = input.system[1];
|
||||
|
||||
input.system[0] = SYSTEM_GAMEPAD;
|
||||
input.system[1] = SYSTEM_MENACER;
|
||||
input.x_offset = 0x84;
|
||||
input.y_offset = 0x08;
|
||||
}
|
||||
else if (strstr(rominfo.international,"BODY COUNT") != NULL)
|
||||
{
|
||||
/* save current setting */
|
||||
if (old_system[0] == -1) old_system[0] = input.system[0];
|
||||
if (old_system[1] == -1) old_system[1] = input.system[1];
|
||||
|
||||
input.system[0] = SYSTEM_MOUSE;
|
||||
input.system[1] = SYSTEM_MENACER;
|
||||
input.x_offset = 0x44;
|
||||
input.y_offset = 0x18;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
KONAMI JUSTIFIER
|
||||
***********************************************/
|
||||
else if (strstr(rominfo.international,"LETHAL ENFORCERSII") != NULL)
|
||||
{
|
||||
/* save current setting */
|
||||
if (old_system[0] == -1) old_system[0] = input.system[0];
|
||||
if (old_system[1] == -1) old_system[1] = input.system[1];
|
||||
|
||||
input.system[0] = SYSTEM_GAMEPAD;
|
||||
input.system[1] = SYSTEM_JUSTIFIER;
|
||||
input.x_offset = 0x18;
|
||||
input.y_offset = 0x00;
|
||||
}
|
||||
else if (strstr(rominfo.international,"LETHAL ENFORCERS") != NULL)
|
||||
{
|
||||
/* save current setting */
|
||||
if (old_system[0] == -1) old_system[0] = input.system[0];
|
||||
if (old_system[1] == -1) old_system[1] = input.system[1];
|
||||
|
||||
input.system[0] = SYSTEM_GAMEPAD;
|
||||
input.system[1] = SYSTEM_JUSTIFIER;
|
||||
input.x_offset = 0x00;
|
||||
input.y_offset = 0x00;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
J-CART
|
||||
***********************************************/
|
||||
j_cart = 0;
|
||||
if (((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x168b)) || /* Super Skidmarks, Micro Machines Military*/
|
||||
((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x165e)) || /* Pete Sampras Tennis (1991), Micro Machines 96 */
|
||||
((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0xcee0)) || /* Micro Machines Military (bad) */
|
||||
((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x2c41)) || /* Micro Machines 96 (bad) */
|
||||
((strstr(rominfo.product,"XXXXXXXX") != NULL) && (rominfo.checksum == 0xdf39)) || /* Sampras Tennis 96 */
|
||||
((strstr(rominfo.product,"T-123456") != NULL) && (rominfo.checksum == 0x1eae)) || /* Sampras Tennis 96 */
|
||||
((strstr(rominfo.product,"T-120066") != NULL) && (rominfo.checksum == 0x16a4)) || /* Pete Sampras Tennis (1994)*/
|
||||
(strstr(rominfo.product,"T-120096") != NULL)) /* Micro Machines 2 */
|
||||
cart.hw.jcart = 0;
|
||||
if (((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x168b)) || /* Super Skidmarks, Micro Machines Military*/
|
||||
((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x165e)) || /* Pete Sampras Tennis (1991), Micro Machines 96 */
|
||||
((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0xcee0)) || /* Micro Machines Military (bad) */
|
||||
((strstr(rominfo.product,"00000000") != NULL) && (rominfo.checksum == 0x2c41)) || /* Micro Machines 96 (bad) */
|
||||
((strstr(rominfo.product,"XXXXXXXX") != NULL) && (rominfo.checksum == 0xdf39)) || /* Sampras Tennis 96 */
|
||||
((strstr(rominfo.product,"T-123456") != NULL) && (rominfo.checksum == 0x1eae)) || /* Sampras Tennis 96 */
|
||||
((strstr(rominfo.product,"T-120066") != NULL) && (rominfo.checksum == 0x16a4)) || /* Pete Sampras Tennis (1994)*/
|
||||
(strstr(rominfo.product,"T-120096") != NULL)) /* Micro Machines 2 */
|
||||
{
|
||||
if (genromsize <= 0x380000) /* just to be sure (checksum might not be enough) */
|
||||
if (cart.romsize <= 0x380000) /* just to be sure (checksum might not be enough) */
|
||||
{
|
||||
j_cart = 1;
|
||||
cart.hw.jcart = 1;
|
||||
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;
|
||||
|
||||
/* save current setting */
|
||||
if (old_system[0] == -1) old_system[0] = input.system[0];
|
||||
if (old_system[1] == -1) old_system[1] = input.system[1];
|
||||
|
||||
/* PORT B by default */
|
||||
input.system[0] = SYSTEM_GAMEPAD;
|
||||
input.system[1] = SYSTEM_GAMEPAD;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
Mappers & HW registers
|
||||
LOCK-ON
|
||||
***********************************************/
|
||||
memset(&cart_hw, 0, sizeof(cart_hw));
|
||||
cart.lock_on = 0;
|
||||
switch (config.lock_on)
|
||||
{
|
||||
case TYPE_GG:
|
||||
ggenie_init();
|
||||
break;
|
||||
|
||||
case TYPE_AR:
|
||||
datel_init();
|
||||
break;
|
||||
|
||||
case TYPE_SK:
|
||||
/* be sure we have enough place to copy everything */
|
||||
if (cart.romsize < 0x700000)
|
||||
{
|
||||
/* load Sonic & Knuckles ROM (2 MBytes) */
|
||||
FILE *f = fopen(SK_ROM,"r+b");
|
||||
if (!f) break;
|
||||
fread(cart.rom+0x700000,1,0x200000,f);
|
||||
fclose(f);
|
||||
|
||||
/* load Sonic 2 UPMEM ROM (256 KBytes) */
|
||||
f = fopen(SK_UPMEM,"r+b");
|
||||
if (!f) break;
|
||||
fread(cart.rom+0x900000,1,0x40000,f);
|
||||
fclose(f);
|
||||
|
||||
/* ROM is mirrored each 256K */
|
||||
memcpy(cart.rom+0x940000,cart.rom+0x900000,0x40000);
|
||||
memcpy(cart.rom+0x980000,cart.rom+0x900000,0x40000);
|
||||
memcpy(cart.rom+0x9C0000,cart.rom+0x900000,0x40000);
|
||||
|
||||
#ifdef LSB_FIRST
|
||||
/* Byteswap ROM */
|
||||
int i;
|
||||
uint8 temp;
|
||||
for(i = 0; i < 0x300000; i += 2)
|
||||
{
|
||||
temp = cart.rom[i+0x700000];
|
||||
cart.rom[i+0x700000] = cart.rom[i+1+0x700000];
|
||||
cart.rom[i+1+0x700000] = temp;
|
||||
}
|
||||
#endif
|
||||
|
||||
cart.lock_on = 1;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
Cartridge Extra Hardware
|
||||
***********************************************/
|
||||
memset(&cart.hw, 0, sizeof(T_CART_HW));
|
||||
|
||||
/* search for game into database */
|
||||
for (i=0; i < CART_CNT + 1; i++)
|
||||
@ -392,23 +379,23 @@ void cart_hw_init()
|
||||
(realchecksum == rom_database[i].chk_2))
|
||||
{
|
||||
/* retrieve hardware information */
|
||||
memcpy(&cart_hw, &(rom_database[i].cart_hw), sizeof(cart_hw));
|
||||
memcpy(&cart.hw, &(rom_database[i].cart_hw), sizeof(T_CART_HW));
|
||||
|
||||
/* initialize memory handlers for $400000-$7fffff region */
|
||||
int j = rom_database[i].bank_start;
|
||||
while (j <= rom_database[i].bank_end)
|
||||
{
|
||||
if (cart_hw.regs_r)
|
||||
if (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;
|
||||
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)
|
||||
if (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;
|
||||
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++;
|
||||
}
|
||||
@ -424,12 +411,12 @@ void cart_hw_init()
|
||||
#endif
|
||||
|
||||
/* detect ROM files larger than 4MB */
|
||||
if (genromsize > 0x800000)
|
||||
if (cart.romsize > 0x800000)
|
||||
{
|
||||
/* Ultimate MK3 (hack) */
|
||||
for (i=0x40; i<0xA0; i++)
|
||||
{
|
||||
m68k_memory_map[i].base = cart_rom + (i<<16);
|
||||
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;
|
||||
@ -440,17 +427,77 @@ void cart_hw_init()
|
||||
emulate_address_error = 0;
|
||||
#endif
|
||||
}
|
||||
else if (genromsize > 0x400000)
|
||||
else if (cart.romsize > 0x400000)
|
||||
{
|
||||
/* assume SSF2 mapper */
|
||||
cart_hw.bankshift = 1;
|
||||
cart.hw.bankshift = 1;
|
||||
cart.hw.time_w = sega_mapper_w;
|
||||
}
|
||||
|
||||
/* default write handler for !TIME signal */
|
||||
/* TODO: handle Sonic & Knuckles + Sonic 2 case to prevent RAM activation */
|
||||
if (!cart_hw.time_w) cart_hw.time_w = default_time_w;
|
||||
if (!cart.hw.time_w)
|
||||
cart.hw.time_w = default_time_w;
|
||||
}
|
||||
|
||||
/* hardware that need to be reseted on power on */
|
||||
void cart_hw_reset()
|
||||
{
|
||||
int i;
|
||||
|
||||
/* reset bankshifting */
|
||||
if (cart.hw.bankshift)
|
||||
{
|
||||
for (i=0x00; i<0x40; i++)
|
||||
m68k_memory_map[i].base = cart.rom + (i<<16);
|
||||
}
|
||||
|
||||
/* Realtec mapper */
|
||||
if (cart.hw.realtec & 1)
|
||||
{
|
||||
/* enable BOOTROM */
|
||||
for (i=0; i<0x40; i++)
|
||||
m68k_memory_map[i].base = mem_chunk;
|
||||
for (i=0; i<8; i++)
|
||||
memcpy(mem_chunk + i*0x2000, cart.rom + 0x7e000, 0x2000);
|
||||
cart.hw.realtec |= 2;
|
||||
}
|
||||
|
||||
/* SVP chip */
|
||||
if (svp)
|
||||
svp_reset();
|
||||
|
||||
/* Lock-ON */
|
||||
switch (config.lock_on)
|
||||
{
|
||||
case TYPE_GG:
|
||||
ggenie_reset();
|
||||
break;
|
||||
|
||||
case TYPE_AR:
|
||||
datel_reset();
|
||||
break;
|
||||
|
||||
case TYPE_SK:
|
||||
if (cart.lock_on)
|
||||
{
|
||||
/* reset memory map */
|
||||
for (i=0x00; i<0x20; i++)
|
||||
m68k_memory_map[i].base = cart.rom + 0x700000 + (i<<16);
|
||||
for (i=0x30; i<0x40; i++)
|
||||
m68k_memory_map[i].base = cart.rom + (i<<16);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* save default cartridge slot mapping */
|
||||
cart.base = m68k_memory_map[0].base;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************
|
||||
MAPPER handlers
|
||||
*************************************************************/
|
||||
@ -458,7 +505,7 @@ void cart_hw_init()
|
||||
/*
|
||||
"official" ROM/RAM switch
|
||||
*/
|
||||
static inline void sega_mapper_w(uint32 address, uint32 data)
|
||||
static void sega_mapper_w(uint32 address, uint32 data)
|
||||
{
|
||||
uint32 i,slot = (address >> 1) & 7;
|
||||
uint8 *src;
|
||||
@ -486,21 +533,36 @@ static inline void sega_mapper_w(uint32 address, uint32 data)
|
||||
m68k_memory_map[0x20].write16 = NULL;
|
||||
zbank_memory_map[0x20].write = NULL;
|
||||
}
|
||||
|
||||
if (cart.lock_on)
|
||||
{
|
||||
/* enable UPMEM chip at $300000-$3fffff */
|
||||
for (i=0x30; i<0x40; i++)
|
||||
m68k_memory_map[i].base = cart.rom + 0x600000 + (i<<16);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ROM enabled */
|
||||
m68k_memory_map[0x20].base = cart_rom + 0x200000;
|
||||
m68k_memory_map[0x20].base = cart.rom + 0x200000;
|
||||
|
||||
if (cart.lock_on)
|
||||
{
|
||||
/* enable cartridge ROM at $300000-$3fffff */
|
||||
for (i=0x30; i<0x40; i++)
|
||||
m68k_memory_map[i].base = cart.rom + (i<<16);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
/* ROM Bankswitch (Super Street Fighter 2)
|
||||
documented by Bart Trzynadlowski (http://www.trzy.org/files/ssf2.txt)
|
||||
*/
|
||||
slot = slot << 3; /* 8 x 512k banks */
|
||||
src = cart_rom + (data << 19);
|
||||
for (i=0; i<8; i++) m68k_memory_map[slot++].base = src + (i<<16);
|
||||
src = cart.rom + (data << 19);
|
||||
for (i=0; i<8; i++)
|
||||
m68k_memory_map[slot++].base = src + (i<<16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -508,35 +570,33 @@ static inline void sega_mapper_w(uint32 address, uint32 data)
|
||||
/*
|
||||
custom ROM Bankswitch used by pirate "Multi-in-1" carts
|
||||
*/
|
||||
static inline void multi_mapper_w(uint32 address, uint32 data)
|
||||
static void multi_mapper_w(uint32 address, uint32 data)
|
||||
{
|
||||
int i;
|
||||
|
||||
cart_hw.bankshift = 1;
|
||||
cart.hw.bankshift = 1;
|
||||
|
||||
/* 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];
|
||||
}
|
||||
|
||||
/*
|
||||
Special ROM Bankswitch used for copy protection
|
||||
Used by unlicensed cartridges (Lion King III, Super King Kong 99)
|
||||
*/
|
||||
void special_mapper_w(uint32 address, uint32 data)
|
||||
static void special_mapper_w(uint32 address, uint32 data)
|
||||
{
|
||||
/* 1 x 32k bank */
|
||||
m68k_memory_map[0].base = mem_chunk;
|
||||
memcpy(mem_chunk,&cart_rom[(data & 0x7f) << 15],0x8000);
|
||||
memcpy(mem_chunk+0x8000,cart_rom + 0x8000,0x8000);
|
||||
memcpy(mem_chunk,&cart.rom[(data & 0x7f) << 15],0x8000);
|
||||
memcpy(mem_chunk+0x8000,cart.rom + 0x8000,0x8000);
|
||||
}
|
||||
|
||||
/*
|
||||
Realtec ROM Bankswitch (Earth Defend, Balloon Boy & Funny World, Whac-A-Critter)
|
||||
*/
|
||||
void realtec_mapper_w(uint32 address, uint32 data)
|
||||
static void realtec_mapper_w(uint32 address, uint32 data)
|
||||
{
|
||||
int i;
|
||||
uint32 base;
|
||||
@ -545,32 +605,32 @@ void realtec_mapper_w(uint32 address, uint32 data)
|
||||
switch (address)
|
||||
{
|
||||
case 0x404000: /* three lower bits of ROM base address */
|
||||
cart_hw.regs[0] = data & 7;
|
||||
base = ((data & 7) | (cart_hw.regs[1] << 2));
|
||||
for (i=0; i<=cart_hw.regs[2]; i++)
|
||||
cart.hw.regs[0] = data & 7;
|
||||
base = ((data & 7) | (cart.hw.regs[1] << 2));
|
||||
for (i=0; i<=cart.hw.regs[2]; i++)
|
||||
{
|
||||
m68k_memory_map[i*2].base = &cart_rom[((base + i)*2 & 0x3f) << 16];
|
||||
m68k_memory_map[i*2+1].base = &cart_rom[(((base + i)*2 + 1) & 0x3f) << 16];
|
||||
m68k_memory_map[i*2].base = &cart.rom[((base + i)*2 & 0x3f) << 16];
|
||||
m68k_memory_map[i*2+1].base = &cart.rom[(((base + i)*2 + 1) & 0x3f) << 16];
|
||||
}
|
||||
return;
|
||||
|
||||
case 0x400000: /* two higher bits of ROM base address */
|
||||
cart_hw.regs[1] = data & 6;
|
||||
base = cart_hw.regs[0] | ((data & 6) << 2);
|
||||
for (i=0; i<=cart_hw.regs[2]; i++)
|
||||
cart.hw.regs[1] = data & 6;
|
||||
base = cart.hw.regs[0] | ((data & 6) << 2);
|
||||
for (i=0; i<=cart.hw.regs[2]; i++)
|
||||
{
|
||||
m68k_memory_map[i*2].base = &cart_rom[((base + i)*2 & 0x3f) << 16];
|
||||
m68k_memory_map[i*2+1].base = &cart_rom[(((base + i)*2 + 1) & 0x3f) << 16];
|
||||
m68k_memory_map[i*2].base = &cart.rom[((base + i)*2 & 0x3f) << 16];
|
||||
m68k_memory_map[i*2+1].base = &cart.rom[(((base + i)*2 + 1) & 0x3f) << 16];
|
||||
}
|
||||
return;
|
||||
|
||||
case 0x402000: /* number of 128k blocks to map */
|
||||
cart_hw.regs[2] = data & 0x1f;
|
||||
base = cart_hw.regs[0] | (cart_hw.regs[1] << 2);
|
||||
cart.hw.regs[2] = data & 0x1f;
|
||||
base = cart.hw.regs[0] | (cart.hw.regs[1] << 2);
|
||||
for (i=0; i<=(data & 0x1f); i++)
|
||||
{
|
||||
m68k_memory_map[i*2].base = &cart_rom[((base + i)*2 & 0x3f) << 16];
|
||||
m68k_memory_map[i*2+1].base = &cart_rom[(((base + i)*2 + 1) & 0x3f) << 16];
|
||||
m68k_memory_map[i*2].base = &cart.rom[((base + i)*2 & 0x3f) << 16];
|
||||
m68k_memory_map[i*2+1].base = &cart.rom[(((base + i)*2 + 1) & 0x3f) << 16];
|
||||
}
|
||||
return;
|
||||
|
||||
@ -578,7 +638,7 @@ void realtec_mapper_w(uint32 address, uint32 data)
|
||||
}
|
||||
|
||||
/* Game no Kanzume Otokuyou ROM Mapper */
|
||||
void seganet_mapper_w(uint32 address, uint32 data)
|
||||
static void seganet_mapper_w(uint32 address, uint32 data)
|
||||
{
|
||||
if ((address & 0xff) == 0xf1)
|
||||
{
|
||||
@ -609,16 +669,15 @@ void seganet_mapper_w(uint32 address, uint32 data)
|
||||
/*
|
||||
RADICA ROM Bankswitch (use !TIME)
|
||||
*/
|
||||
uint32 radica_mapper_r(uint32 address)
|
||||
static uint32 radica_mapper_r(uint32 address)
|
||||
{
|
||||
int i = 0;
|
||||
address = (address >> 1);
|
||||
|
||||
/* 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 0xff;
|
||||
}
|
||||
|
||||
@ -628,10 +687,13 @@ uint32 radica_mapper_r(uint32 address)
|
||||
*************************************************************/
|
||||
|
||||
/* default ROM bankswitch */
|
||||
void default_time_w(uint32 address, uint32 data)
|
||||
static void default_time_w(uint32 address, uint32 data)
|
||||
{
|
||||
if ((address & 0xf1) == 0xf1) sega_mapper_w(address, data);
|
||||
else if (address < 0xa13040) multi_mapper_w(address, data);
|
||||
if ((address & 0xf1) == 0xf1)
|
||||
sega_mapper_w(address, data);
|
||||
|
||||
else if (address < 0xa13040)
|
||||
multi_mapper_w(address, data);
|
||||
}
|
||||
|
||||
|
||||
@ -639,33 +701,31 @@ void default_time_w(uint32 address, uint32 data)
|
||||
Internal register handlers
|
||||
*************************************************************/
|
||||
|
||||
uint32 default_regs_r(uint32 address)
|
||||
static uint32 default_regs_r(uint32 address)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if ((address & cart_hw.mask[i]) == cart_hw.addr[i])
|
||||
return cart_hw.regs[i];
|
||||
if ((address & cart.hw.mask[i]) == cart.hw.addr[i])
|
||||
return cart.hw.regs[i];
|
||||
}
|
||||
|
||||
/* unused */
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
void default_regs_w(uint32 address, uint32 data)
|
||||
static void default_regs_w(uint32 address, uint32 data)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if ((address & cart_hw.mask[i]) == cart_hw.addr[i])
|
||||
{
|
||||
cart_hw.regs[i] = data;
|
||||
}
|
||||
if ((address & cart.hw.mask[i]) == cart.hw.addr[i])
|
||||
cart.hw.regs[i] = data;
|
||||
}
|
||||
}
|
||||
|
||||
/* special register behaviour (Lion King III, Super Donkey Kong 99) */
|
||||
void special_regs_w(uint32 address, uint32 data)
|
||||
static void special_regs_w(uint32 address, uint32 data)
|
||||
{
|
||||
/* ROM bankswitch */
|
||||
if ((address >> 16) > 0x6f)
|
||||
@ -678,19 +738,19 @@ void special_regs_w(uint32 address, uint32 data)
|
||||
default_regs_w(address, data);
|
||||
|
||||
/* bitswapping (documented by Haze) */
|
||||
uint32 temp = cart_hw.regs[0];
|
||||
switch (cart_hw.regs[1])
|
||||
uint32 temp = cart.hw.regs[0];
|
||||
switch (cart.hw.regs[1])
|
||||
{
|
||||
case 1:
|
||||
cart_hw.regs[2] = (temp >> 1);
|
||||
cart.hw.regs[2] = (temp >> 1);
|
||||
return;
|
||||
|
||||
case 2:
|
||||
cart_hw.regs[2] = ((temp >> 4) | ((temp & 0x0F) << 4));
|
||||
cart.hw.regs[2] = ((temp >> 4) | ((temp & 0x0F) << 4));
|
||||
return;
|
||||
|
||||
default:
|
||||
cart_hw.regs[2] = (((temp >> 7) & 0x01) | ((temp >> 5) & 0x02) |
|
||||
cart.hw.regs[2] = (((temp >> 7) & 0x01) | ((temp >> 5) & 0x02) |
|
||||
((temp >> 3) & 0x04) | ((temp >> 1) & 0x08) |
|
||||
((temp << 1) & 0x10) | ((temp << 3) & 0x20) |
|
||||
((temp << 5) & 0x40) | ((temp << 7) & 0x80));
|
||||
|
@ -27,34 +27,42 @@
|
||||
#ifndef _CART_HW_H_
|
||||
#define _CART_HW_H_
|
||||
|
||||
/* Lock-ON cartridge devices */
|
||||
#define GAME_GENIE 1
|
||||
#define ACTION_REPLAY 2
|
||||
#define SONIC_KNUCKLES 3
|
||||
/* Lock-ON cartridge type */
|
||||
#define TYPE_GG 0x10 /* Game Genie */
|
||||
#define TYPE_AR 0x20 /* Action Replay (Pro) */
|
||||
#define TYPE_SK 0x40 /* Sonic & Knuckles */
|
||||
|
||||
/* Hardware description */
|
||||
/* Cartridge extra hardware */
|
||||
typedef struct
|
||||
{
|
||||
uint8 regs[4]; /* internal registers (R/W) */
|
||||
uint32 mask[4]; /* registers address mask */
|
||||
uint32 addr[4]; /* registers address */
|
||||
uint32 realtec; /* bit 0: realtec mapper detected, bit 1: bootrom enabled */
|
||||
uint32 bankshift; /* cartridge with bankshift mecanism */
|
||||
uint16 jcart; /* cartridge with JCART port */
|
||||
uint16 bankshift; /* cartridge with bankshift mecanism */
|
||||
unsigned int (*time_r)(unsigned int address); /* !TIME signal ($a130xx) read handler */
|
||||
void (*time_w)(unsigned int address, unsigned int data); /* !TIME signal ($a130xx) write handler */
|
||||
unsigned int (*regs_r)(unsigned int address); /* cart hardware region ($400000-$7fffff) read handler */
|
||||
void (*regs_w)(unsigned int address, unsigned int data); /* cart hardware region ($400000-$7fffff) 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;
|
||||
|
||||
/* Cartridge type */
|
||||
typedef struct
|
||||
{
|
||||
uint8 *rom; /* ROM data */
|
||||
uint8 *base; /* ROM area (slot 0) */
|
||||
uint32 lock_on; /* 1: Lock-On enabled */
|
||||
uint32 romsize; /* ROM size */
|
||||
T_CART_HW hw; /* Custom hardware */
|
||||
} T_CART;
|
||||
|
||||
/* global variables */
|
||||
extern T_CART_HW cart_hw;
|
||||
extern uint8 j_cart;
|
||||
extern uint8 *default_rom;
|
||||
extern int old_system[2];
|
||||
extern T_CART cart;
|
||||
|
||||
/* Function prototypes */
|
||||
extern void cart_hw_reset();
|
||||
extern void cart_hw_init();
|
||||
extern void cart_hw_reset();
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -21,9 +21,9 @@
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
#define TYPE_AR 1
|
||||
#define TYPE_PRO1 2
|
||||
#define TYPE_PRO2 3
|
||||
#define TYPE_AR 0x01
|
||||
#define TYPE_PRO1 0x02
|
||||
#define TYPE_PRO2 0x03
|
||||
|
||||
static struct
|
||||
{
|
||||
@ -145,7 +145,7 @@ void datel_switch(uint8 enable)
|
||||
offset = action_replay.addr[i] >> 16;
|
||||
|
||||
if (offset < 0x40) /* cartridge ROM */
|
||||
action_replay.old[i] = *(uint16 *)(cart_rom + action_replay.addr[i]);
|
||||
action_replay.old[i] = *(uint16 *)(cart.rom + action_replay.addr[i]);
|
||||
else if (offset >= 0xe0) /* Work RAM */
|
||||
action_replay.old[i] = *(uint16 *)(work_ram + (action_replay.addr[i]&0xffff));
|
||||
}
|
||||
@ -159,7 +159,7 @@ void datel_switch(uint8 enable)
|
||||
offset = action_replay.addr[i] >> 16;
|
||||
|
||||
if (offset < 0x40) /* cartridge ROM */
|
||||
*(uint16 *)(cart_rom + action_replay.addr[i]) = action_replay.data[i];
|
||||
*(uint16 *)(cart.rom + action_replay.addr[i]) = action_replay.data[i];
|
||||
else if (offset >= 0xe0) /* Work RAM */
|
||||
*(uint16 *)(work_ram + (action_replay.addr[i]&0xffff)) = action_replay.data[i];
|
||||
}
|
||||
@ -180,7 +180,7 @@ void datel_switch(uint8 enable)
|
||||
if (action_replay.data[i])
|
||||
{
|
||||
if (action_replay.addr[i] < 0x400000)
|
||||
*(uint16 *)(cart_rom + action_replay.addr[i]) = action_replay.old[i];
|
||||
*(uint16 *)(cart.rom + action_replay.addr[i]) = action_replay.old[i];
|
||||
else if (action_replay.addr[i] >= 0xe00000)
|
||||
*(uint16 *)(work_ram + (action_replay.addr[i]&0xffff)) = action_replay.old[i];
|
||||
}
|
||||
@ -253,6 +253,6 @@ static void ar_write_regs(uint32 address, uint32 data)
|
||||
|
||||
/* reads are mapped to Cartridge ROM */
|
||||
/* NOTE: codes should be disabled on startup */
|
||||
m68k_memory_map[0].base = cart_rom;
|
||||
m68k_memory_map[0].base = cart.rom;
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ T_EEPROM eeprom;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char game_id[14];
|
||||
char game_id[16];
|
||||
uint16 chk;
|
||||
T_EEPROM_TYPE type;
|
||||
} T_GAME_ENTRY;
|
||||
|
@ -117,8 +117,8 @@ void ggenie_switch(uint8 enable)
|
||||
/* save old value and patch ROM if enabled */
|
||||
if (ggenie.regs[0] & (1 << i))
|
||||
{
|
||||
ggenie.old[i] = *(uint16 *)(cart_rom + ggenie.addr[i]);
|
||||
*(uint16 *)(cart_rom + ggenie.addr[i]) = ggenie.data[i];
|
||||
ggenie.old[i] = *(uint16 *)(cart.rom + ggenie.addr[i]);
|
||||
*(uint16 *)(cart.rom + ggenie.addr[i]) = ggenie.data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -131,7 +131,7 @@ void ggenie_switch(uint8 enable)
|
||||
/* patch is enabled ? */
|
||||
if (ggenie.regs[0] & (1 << i))
|
||||
{
|
||||
*(uint16 *)(cart_rom + ggenie.addr[i]) = ggenie.old[i];
|
||||
*(uint16 *)(cart.rom + ggenie.addr[i]) = ggenie.old[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -203,7 +203,7 @@ static void ggenie_write_regs(uint8 offset, uint32 data, uint8 type)
|
||||
if (data & 0x400)
|
||||
{
|
||||
/* $0000-$7ffff reads mapped to Cartridge ROM */
|
||||
m68k_memory_map[0].base = cart_rom;
|
||||
m68k_memory_map[0].base = cart.rom;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -249,6 +249,6 @@ static void ggenie_write_regs(uint8 offset, uint32 data, uint8 type)
|
||||
static uint32 ggenie_read_regs(uint32 address)
|
||||
{
|
||||
if (address < 0x40) return ggenie.regs[address >> 1];
|
||||
else return *(uint16 *)(cart_rom + address); /* is that correct ? */
|
||||
else return *(uint16 *)(cart.rom + address); /* is that correct ? */
|
||||
}
|
||||
|
||||
|
@ -45,12 +45,12 @@ void sram_init()
|
||||
memset (&sram.sram[0], 0xFF, 0x10000);
|
||||
sram.crc = crc32 (0, &sram.sram[0], 0x10000);
|
||||
|
||||
if ((READ_BYTE(cart_rom,0x1b0) == 0x52) && (READ_BYTE(cart_rom,0x1b1) == 0x41))
|
||||
if ((READ_BYTE(cart.rom,0x1b0) == 0x52) && (READ_BYTE(cart.rom,0x1b1) == 0x41))
|
||||
{
|
||||
/* retrieve informations from headezr */
|
||||
sram.detected = 1;
|
||||
sram.start = READ_WORD_LONG(cart_rom, 0x1b4);
|
||||
sram.end = READ_WORD_LONG(cart_rom, 0x1b8);
|
||||
sram.start = READ_WORD_LONG(cart.rom, 0x1b4);
|
||||
sram.end = READ_WORD_LONG(cart.rom, 0x1b8);
|
||||
|
||||
/* fixe some bad header informations */
|
||||
if ((sram.start > sram.end) || ((sram.end - sram.start) >= 0x10000))
|
||||
@ -66,7 +66,7 @@ void sram_init()
|
||||
}
|
||||
|
||||
/* set SRAM ON by default when ROM is not mapped */
|
||||
if (genromsize <= sram.start)
|
||||
if (cart.romsize <= sram.start)
|
||||
{
|
||||
sram.on = 1;
|
||||
sram.write = 1;
|
||||
|
@ -262,7 +262,7 @@
|
||||
// how is low word really affected by these?
|
||||
// nearly sure 'ld A' doesn't affect flags
|
||||
#define OP_LDA(x) \
|
||||
rA = x
|
||||
rA = x
|
||||
|
||||
#define OP_LDA32(x) \
|
||||
rA32 = x
|
||||
@ -326,16 +326,16 @@
|
||||
UPD_ACC_ZN
|
||||
|
||||
|
||||
#define OP_CHECK32(OP) { \
|
||||
#define OP_CHECK32(OP) { \
|
||||
if ((op & 0x0f) == SSP_P) { /* A <- P */ \
|
||||
read_P(); /* update P */ \
|
||||
OP(rP.v); \
|
||||
break; \
|
||||
} \
|
||||
if ((op & 0x0f) == SSP_A) { /* A <- A */ \
|
||||
OP(rA32); \
|
||||
break; \
|
||||
} \
|
||||
read_P(); /* update P */ \
|
||||
OP(rP.v); \
|
||||
break; \
|
||||
} \
|
||||
if ((op & 0x0f) == SSP_A) { /* A <- A */ \
|
||||
OP(rA32); \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
@ -553,14 +553,14 @@ static u32 pm_io(int reg, int write, u32 d)
|
||||
{
|
||||
#ifdef LOG_SVP
|
||||
elprintf(EL_SVP, "ssp ROM r [%06x] %04x", CADDR,
|
||||
((unsigned short *)cart_rom)[addr|((mode&0xf)<<16)]);
|
||||
((unsigned short *)cart.rom)[addr|((mode&0xf)<<16)]);
|
||||
#endif
|
||||
/*if ((signed int)ssp->pmac_read[reg] >> 16 == -1) ssp->pmac_read[reg]++;
|
||||
ssp->pmac_read[reg] += 1<<16;*/
|
||||
if ((signed int)(ssp->pmac_read[reg] & 0xffff) == -1) ssp->pmac_read[reg] += 1<<16;
|
||||
ssp->pmac_read[reg] ++;
|
||||
|
||||
d = ((unsigned short *)cart_rom)[addr|((mode&0xf)<<16)];
|
||||
d = ((unsigned short *)cart.rom)[addr|((mode&0xf)<<16)];
|
||||
}
|
||||
else if ((mode & 0x47ff) == 0x0018) // DRAM
|
||||
{
|
||||
@ -1106,7 +1106,7 @@ void ssp1601_run(int cycles)
|
||||
if (op == ((SSP_A<<4)|SSP_P)) { // A <- P
|
||||
// not sure. MAME claims that only hi word is transfered.
|
||||
read_P(); // update P
|
||||
rA32 = rP.v;
|
||||
rA32 = rP.v;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1194,7 +1194,7 @@ void ssp1601_run(int cycles)
|
||||
if (!(op&0x100)) elprintf(EL_SVP|EL_ANOMALY, "ssp FIXME: no b bit @ %04x", GET_PPC_OFFS());
|
||||
#endif
|
||||
read_P(); // update P
|
||||
rA32 -= rP.v; // maybe only upper word?
|
||||
rA32 -= rP.v; // maybe only upper word?
|
||||
UPD_ACC_ZN // there checking flags after this
|
||||
rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
|
||||
rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
|
||||
@ -1206,7 +1206,7 @@ void ssp1601_run(int cycles)
|
||||
if (!(op&0x100)) elprintf(EL_SVP|EL_ANOMALY, "ssp FIXME: no b bit @ %04x", GET_PPC_OFFS());
|
||||
#endif
|
||||
read_P(); // update P
|
||||
rA32 += rP.v; // confirmed to be 32bit
|
||||
rA32 += rP.v; // confirmed to be 32bit
|
||||
UPD_ACC_ZN // ?
|
||||
rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
|
||||
rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
|
||||
|
@ -17,13 +17,13 @@ int16 SVP_cycles = 850;
|
||||
|
||||
void svp_init(void)
|
||||
{
|
||||
svp = (void *) ((char *)cart_rom + 0x200000);
|
||||
svp = (void *) ((char *)cart.rom + 0x200000);
|
||||
memset(svp, 0, sizeof(*svp));
|
||||
}
|
||||
|
||||
void svp_reset(void)
|
||||
{
|
||||
memcpy(svp->iram_rom + 0x800, cart_rom + 0x800, 0x20000 - 0x800);
|
||||
memcpy(svp->iram_rom + 0x800, cart.rom + 0x800, 0x20000 - 0x800);
|
||||
ssp1601_reset(&svp->ssp1601);
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ t_input input;
|
||||
*
|
||||
*****************************************************************************/
|
||||
/* H counter values for a 256-pixel wide display (342 pixel max.) */
|
||||
static uint8 hc_256[171] = {
|
||||
static const uint8 hc_256[171] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
@ -46,7 +46,7 @@ static uint8 hc_256[171] = {
|
||||
};
|
||||
|
||||
/* H counter values for a 320-pixel wide display (420 pixels max.) */
|
||||
static uint8 hc_320[210] = {
|
||||
static const uint8 hc_320[210] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
@ -80,7 +80,7 @@ static inline void lightgun_update(int num)
|
||||
/* External Interrupt ? */
|
||||
if (reg[11] & 0x08) irq_status = (irq_status & ~0x40) | 0x12;
|
||||
|
||||
/* HVC Latch:
|
||||
/* Horizontal Counter Latch:
|
||||
1) some games does not set HVC latch but instead use bigger X offset
|
||||
2) for games using H40 mode, the gun routine scales up the Hcounter value,
|
||||
H-Counter range is approx. 292 pixel clocks
|
||||
@ -136,7 +136,7 @@ uint32 justifier_read()
|
||||
* SEGA MOUSE specific functions
|
||||
*
|
||||
*****************************************************************************/
|
||||
struct mega_mouse
|
||||
static struct mega_mouse
|
||||
{
|
||||
uint8 State;
|
||||
uint8 Counter;
|
||||
@ -258,7 +258,7 @@ uint32 mouse_read()
|
||||
* GAMEPAD specific functions (2PLAYERS/4WAYPLAY)
|
||||
*
|
||||
*****************************************************************************/
|
||||
struct pad
|
||||
static struct pad
|
||||
{
|
||||
uint8 State;
|
||||
uint8 Counter;
|
||||
@ -387,22 +387,19 @@ static inline void gamepad_write(uint32 i, uint32 data)
|
||||
* TEAMPLAYER adapter
|
||||
*
|
||||
*****************************************************************************/
|
||||
struct teamplayer
|
||||
static struct teamplayer
|
||||
{
|
||||
uint8 State;
|
||||
uint8 Counter;
|
||||
uint8 Table[12];
|
||||
} teamplayer[2];
|
||||
|
||||
static inline void teamplayer_reset(uint32 port)
|
||||
static inline void teamplayer_init(uint32 port)
|
||||
{
|
||||
int i;
|
||||
int index = 0;
|
||||
int pad_input = 0;
|
||||
|
||||
teamplayer[port].State = 0x60; /* TH = 1, TR = 1 */
|
||||
teamplayer[port].Counter = 0;
|
||||
|
||||
/* this table determines which gamepad input should be returned during acquisition sequence
|
||||
index = teamplayer read table index: 0=1st read, 1=2nd read, ...
|
||||
pad_input = gamepad input 0-14: 0=P1_DIR, 1=P1_SABC, 2=P1_MXYZ, 4=P2_DIR, 5=P2_SABC, ...
|
||||
@ -424,6 +421,12 @@ static inline void teamplayer_reset(uint32 port)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void teamplayer_reset(uint32 port)
|
||||
{
|
||||
teamplayer[port].State = 0x60; /* TH = 1, TR = 1 */
|
||||
teamplayer[port].Counter = 0;
|
||||
}
|
||||
|
||||
/* SEGA teamplayer returns successively:
|
||||
- PAD1 inputs
|
||||
- PAD2 inputs
|
||||
@ -603,7 +606,7 @@ void teamplayer_2_write (uint32 data)
|
||||
|
||||
uint32 jcart_read(uint32 address)
|
||||
{
|
||||
return (gamepad_read(5) | ((gamepad_read(6)&0x3f) << 8)); /* fixes Micro Machines 2 (is it correct ?) */
|
||||
return (gamepad_read(5) | ((gamepad_read(6)&0x3f) << 8)); /* fixes Micro Machines 2 */
|
||||
}
|
||||
|
||||
void jcart_write(uint32 address, uint32 data)
|
||||
@ -617,12 +620,11 @@ void jcart_write(uint32 address, uint32 data)
|
||||
* Generic INPUTS Control
|
||||
*
|
||||
*****************************************************************************/
|
||||
void input_reset ()
|
||||
void input_init ()
|
||||
{
|
||||
int i,j;
|
||||
|
||||
input.max = 0;
|
||||
input.current = 0;
|
||||
|
||||
for (i=0; i<MAX_DEVICES; i++)
|
||||
{
|
||||
@ -636,14 +638,12 @@ void input_reset ()
|
||||
if (input.max == MAX_INPUTS) return;
|
||||
input.dev[0] = config.input[input.max].padtype;
|
||||
input.max ++;
|
||||
gamepad_reset(0);
|
||||
break;
|
||||
|
||||
case SYSTEM_MOUSE:
|
||||
if (input.max == MAX_INPUTS) return;
|
||||
input.dev[0] = DEVICE_MOUSE;
|
||||
input.max ++;
|
||||
mouse_reset();
|
||||
break;
|
||||
|
||||
case SYSTEM_WAYPLAY:
|
||||
@ -652,7 +652,6 @@ void input_reset ()
|
||||
if (input.max == MAX_INPUTS) return;
|
||||
input.dev[j] = config.input[input.max].padtype;
|
||||
input.max ++;
|
||||
gamepad_reset(j);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -663,7 +662,7 @@ void input_reset ()
|
||||
input.dev[j] = config.input[input.max].padtype;
|
||||
input.max ++;
|
||||
}
|
||||
teamplayer_reset(0);
|
||||
teamplayer_init(0);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -673,20 +672,17 @@ void input_reset ()
|
||||
if (input.max == MAX_INPUTS) return;
|
||||
input.dev[4] = config.input[input.max].padtype;
|
||||
input.max ++;
|
||||
gamepad_reset(4);
|
||||
break;
|
||||
|
||||
case SYSTEM_MOUSE:
|
||||
if (input.max == MAX_INPUTS) return;
|
||||
input.dev[4] = DEVICE_MOUSE;
|
||||
input.max ++;
|
||||
mouse_reset();
|
||||
break;
|
||||
|
||||
case SYSTEM_MENACER:
|
||||
if (input.max == MAX_INPUTS) return;
|
||||
input.dev[4] = DEVICE_LIGHTGUN;
|
||||
lightgun_reset(0);
|
||||
break;
|
||||
|
||||
case SYSTEM_JUSTIFIER:
|
||||
@ -694,7 +690,6 @@ void input_reset ()
|
||||
{
|
||||
if (input.max == MAX_INPUTS) return;
|
||||
input.dev[j] = DEVICE_LIGHTGUN;
|
||||
lightgun_reset(j - 4);
|
||||
input.max ++;
|
||||
}
|
||||
break;
|
||||
@ -706,21 +701,54 @@ void input_reset ()
|
||||
input.dev[j] = config.input[input.max].padtype;
|
||||
input.max ++;
|
||||
}
|
||||
teamplayer_reset(1);
|
||||
teamplayer_init(1);
|
||||
break;
|
||||
}
|
||||
|
||||
/* J-CART: add two gamepad inputs */
|
||||
if (j_cart)
|
||||
if (cart.hw.jcart)
|
||||
{
|
||||
input.dev[5] = config.input[2].padtype;
|
||||
input.dev[6] = config.input[3].padtype;
|
||||
gamepad_reset(5);
|
||||
gamepad_reset(6);
|
||||
}
|
||||
}
|
||||
|
||||
void input_update()
|
||||
void input_reset(void)
|
||||
{
|
||||
/* Reset Controller device */
|
||||
int i;
|
||||
for (i=0; i<MAX_INPUTS; i++)
|
||||
{
|
||||
switch (input.dev[i])
|
||||
{
|
||||
case DEVICE_3BUTTON:
|
||||
case DEVICE_6BUTTON:
|
||||
gamepad_reset(i);
|
||||
break;
|
||||
|
||||
case DEVICE_LIGHTGUN:
|
||||
lightgun_reset(i%4);
|
||||
break;
|
||||
|
||||
case DEVICE_MOUSE:
|
||||
mouse_reset();
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Team Player */
|
||||
if (input.system[0] == SYSTEM_TEAMPLAYER)
|
||||
teamplayer_reset(0);
|
||||
if (input.system[1] == SYSTEM_TEAMPLAYER)
|
||||
teamplayer_reset(1);
|
||||
|
||||
/* 4-Way Play */
|
||||
input.current = 0;
|
||||
}
|
||||
|
||||
void input_update(void)
|
||||
{
|
||||
int i;
|
||||
switch (input.system[0])
|
||||
@ -754,7 +782,7 @@ void input_update()
|
||||
}
|
||||
}
|
||||
|
||||
void input_raz()
|
||||
void input_raz(void)
|
||||
{
|
||||
int i;
|
||||
switch (input.system[0])
|
||||
|
@ -64,17 +64,18 @@ typedef struct
|
||||
uint32 pad[MAX_DEVICES]; /* Can be any of the INPUT_* bitmasks */
|
||||
uint8 system[2]; /* Can be any of the SYSTEM_* bitmasks */
|
||||
uint8 max; /* maximum number of connected devices */
|
||||
uint8 current; /* current PAD number (4WAYPLAY) */
|
||||
uint8 current; /* current PAD number (4-Way Play) */
|
||||
int analog[3][2]; /* analog devices */
|
||||
int x_offset;
|
||||
int y_offset;
|
||||
int x_offset; /* gun horizontal offset */
|
||||
int y_offset; /* gun vertical offset */
|
||||
} t_input;
|
||||
|
||||
/* Global variables */
|
||||
extern t_input input;
|
||||
|
||||
/* Function prototypes */
|
||||
extern void input_reset (void);
|
||||
extern void input_init(void);
|
||||
extern void input_reset(void);
|
||||
extern void input_update(void);
|
||||
extern void input_raz(void);
|
||||
|
||||
|
131
source/gen_io.c
131
source/gen_io.c
@ -25,34 +25,108 @@
|
||||
|
||||
uint8 io_reg[0x10];
|
||||
uint8 region_code = REGION_USA;
|
||||
int old_system[2] = {-1,-1};
|
||||
|
||||
/*****************************************************************************
|
||||
* I/O chip functions *
|
||||
* *
|
||||
*****************************************************************************/
|
||||
struct port_t
|
||||
static struct port_t
|
||||
{
|
||||
void (*data_w)(uint32 data);
|
||||
uint32 (*data_r)(void);
|
||||
} port[3];
|
||||
|
||||
void io_reset(void)
|
||||
/*****************************************************************************
|
||||
* I/O chip functions *
|
||||
* *
|
||||
*****************************************************************************/
|
||||
void io_init(void)
|
||||
{
|
||||
/* I/O register default settings */
|
||||
uint8 io_def[0x10] =
|
||||
/* restore previous setting */
|
||||
if (old_system[0] != -1) input.system[0] = old_system[0];
|
||||
if (old_system[1] != -1) input.system[1] = old_system[1];
|
||||
|
||||
/* initialize default GUN settings */
|
||||
input.x_offset = 0x00;
|
||||
input.y_offset = 0x00;
|
||||
|
||||
/**********************************************
|
||||
SEGA MENACER
|
||||
***********************************************/
|
||||
if (strstr(rominfo.international,"MENACER") != NULL)
|
||||
{
|
||||
0xA0,
|
||||
0x7F, 0x7F, 0x7F,
|
||||
0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00,
|
||||
0xFB, 0x00, 0x00,
|
||||
};
|
||||
/* save current setting */
|
||||
if (old_system[0] == -1) old_system[0] = input.system[0];
|
||||
if (old_system[1] == -1) old_system[1] = input.system[1];
|
||||
|
||||
/* Initialize I/O registers */
|
||||
memcpy (io_reg, io_def, 0x10);
|
||||
input.system[0] = NO_SYSTEM;
|
||||
input.system[1] = SYSTEM_MENACER;
|
||||
input.x_offset = 0x52;
|
||||
input.y_offset = 0x00;
|
||||
}
|
||||
else if (strstr(rominfo.international,"T2 ; THE ARCADE GAME") != NULL)
|
||||
{
|
||||
/* save current setting */
|
||||
if (old_system[0] == -1) old_system[0] = input.system[0];
|
||||
if (old_system[1] == -1) old_system[1] = input.system[1];
|
||||
|
||||
/* Initialize Port handlers */
|
||||
input.system[0] = SYSTEM_GAMEPAD;
|
||||
input.system[1] = SYSTEM_MENACER;
|
||||
input.x_offset = 0x84;
|
||||
input.y_offset = 0x08;
|
||||
}
|
||||
else if (strstr(rominfo.international,"BODY COUNT") != NULL)
|
||||
{
|
||||
/* save current setting */
|
||||
if (old_system[0] == -1) old_system[0] = input.system[0];
|
||||
if (old_system[1] == -1) old_system[1] = input.system[1];
|
||||
|
||||
input.system[0] = SYSTEM_MOUSE;
|
||||
input.system[1] = SYSTEM_MENACER;
|
||||
input.x_offset = 0x44;
|
||||
input.y_offset = 0x18;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
KONAMI JUSTIFIER
|
||||
***********************************************/
|
||||
else if (strstr(rominfo.international,"LETHAL ENFORCERSII") != NULL)
|
||||
{
|
||||
/* save current setting */
|
||||
if (old_system[0] == -1) old_system[0] = input.system[0];
|
||||
if (old_system[1] == -1) old_system[1] = input.system[1];
|
||||
|
||||
input.system[0] = SYSTEM_GAMEPAD;
|
||||
input.system[1] = SYSTEM_JUSTIFIER;
|
||||
input.x_offset = 0x18;
|
||||
input.y_offset = 0x00;
|
||||
}
|
||||
else if (strstr(rominfo.international,"LETHAL ENFORCERS") != NULL)
|
||||
{
|
||||
/* save current setting */
|
||||
if (old_system[0] == -1) old_system[0] = input.system[0];
|
||||
if (old_system[1] == -1) old_system[1] = input.system[1];
|
||||
|
||||
input.system[0] = SYSTEM_GAMEPAD;
|
||||
input.system[1] = SYSTEM_JUSTIFIER;
|
||||
input.x_offset = 0x00;
|
||||
input.y_offset = 0x00;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
J-CART
|
||||
***********************************************/
|
||||
if (cart.hw.jcart)
|
||||
{
|
||||
/* save current setting */
|
||||
if (old_system[0] == -1) old_system[0] = input.system[0];
|
||||
if (old_system[1] == -1) old_system[1] = input.system[1];
|
||||
|
||||
/* set default settings */
|
||||
input.system[0] = SYSTEM_GAMEPAD;
|
||||
input.system[1] = SYSTEM_GAMEPAD;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
Initialize IO Port handlers
|
||||
***********************************************/
|
||||
switch (input.system[0])
|
||||
{
|
||||
case SYSTEM_GAMEPAD:
|
||||
@ -124,6 +198,27 @@ void io_reset(void)
|
||||
port[2].data_r = NULL;
|
||||
|
||||
/* Initialize Input Devices */
|
||||
input_init();
|
||||
}
|
||||
|
||||
|
||||
void io_reset(void)
|
||||
{
|
||||
/* I/O register default settings */
|
||||
uint8 io_def[0x10] =
|
||||
{
|
||||
0xA0,
|
||||
0x7F, 0x7F, 0x7F,
|
||||
0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00,
|
||||
0xFB, 0x00, 0x00,
|
||||
};
|
||||
|
||||
/* Reset I/O registers */
|
||||
memcpy (io_reg, io_def, 0x10);
|
||||
|
||||
/* Reset Input Devices */
|
||||
input_reset();
|
||||
}
|
||||
|
||||
|
@ -32,9 +32,10 @@
|
||||
/* Global variables */
|
||||
extern uint8 io_reg[0x10];
|
||||
extern uint8 region_code;
|
||||
extern uint8 pad_type;
|
||||
extern int old_system[2];
|
||||
|
||||
/* Function prototypes */
|
||||
extern void io_init(void);
|
||||
extern void io_reset(void);
|
||||
extern void io_write(uint32 offset, uint32 value);
|
||||
extern uint32 io_read(uint32 offset);
|
||||
|
@ -23,7 +23,6 @@
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
uint8 *cart_rom; /* CART rom */
|
||||
uint8 bios_rom[0x10000]; /* BIOS rom */
|
||||
uint8 work_ram[0x10000]; /* 68K work RAM */
|
||||
uint8 zram[0x2000]; /* Z80 work RAM */
|
||||
@ -33,7 +32,6 @@ uint8 zbusack; /* /BUSACK to Z80 */
|
||||
uint8 zirq; /* /IRQ to Z80 */
|
||||
uint32 zbank; /* Address of Z80 bank window */
|
||||
uint8 gen_running;
|
||||
uint32 genromsize;
|
||||
int32 resetline;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@ -159,6 +157,11 @@ void gen_reset (uint32 hard_reset)
|
||||
gen_running = 1;
|
||||
resetline = -1;
|
||||
|
||||
#ifdef NGC
|
||||
/* register SOFTRESET */
|
||||
SYS_SetResetCallback(set_softreset);
|
||||
#endif
|
||||
|
||||
zreset = 0; /* Z80 is reset */
|
||||
zbusreq = 0; /* Z80 has control of the Z bus */
|
||||
zbusack = 1; /* Z80 is busy using the Z bus */
|
||||
@ -169,11 +172,7 @@ void gen_reset (uint32 hard_reset)
|
||||
m68k_pulse_reset ();
|
||||
z80_reset ();
|
||||
YM2612ResetChip();
|
||||
|
||||
#ifdef NGC
|
||||
/* register SOFTRESET */
|
||||
SYS_SetResetCallback(set_softreset);
|
||||
#endif
|
||||
SN76489_Reset();
|
||||
}
|
||||
|
||||
void gen_shutdown (void)
|
||||
|
@ -25,7 +25,6 @@
|
||||
#define _GENESIS_H_
|
||||
|
||||
/* Global variables */
|
||||
extern uint8 *cart_rom;
|
||||
extern uint8 bios_rom[0x10000];
|
||||
extern uint8 work_ram[0x10000];
|
||||
extern uint8 zram[0x2000];
|
||||
@ -35,7 +34,6 @@ extern uint8 zreset;
|
||||
extern uint8 zirq;
|
||||
extern uint32 zbank;
|
||||
extern uint8 gen_running;
|
||||
extern uint32 genromsize;
|
||||
extern int32 resetline;
|
||||
|
||||
/* Function prototypes */
|
||||
|
@ -83,6 +83,7 @@ void config_default(void)
|
||||
config.addr_error = 1;
|
||||
config.bios_enabled = 0;
|
||||
config.lock_on = 0;
|
||||
config.romtype = 0;
|
||||
|
||||
/* video options */
|
||||
config.xshift = 0;
|
||||
@ -107,12 +108,7 @@ void config_default(void)
|
||||
gx_input_SetDefault();
|
||||
|
||||
/* menu options */
|
||||
#ifdef HW_RVL
|
||||
/* let's assume we always have a FAT device by default */
|
||||
config.sram_auto = 0;
|
||||
#else
|
||||
config.sram_auto = -1;
|
||||
#endif
|
||||
config.state_auto = -1;
|
||||
config.bg_color = 0;
|
||||
config.screen_w = 658;
|
||||
|
@ -46,6 +46,7 @@ typedef struct
|
||||
uint8 addr_error;
|
||||
uint8 bios_enabled;
|
||||
uint8 lock_on;
|
||||
uint8 romtype;
|
||||
int16 xshift;
|
||||
int16 yshift;
|
||||
int16 xscale;
|
||||
|
@ -236,7 +236,7 @@ void memfile_autosave(s8 autosram, s8 autostate)
|
||||
****************************************************************************/
|
||||
int ManageSRAM (u8 direction, u8 device)
|
||||
{
|
||||
if (!genromsize) return 0;
|
||||
if (!cart.romsize) return 0;
|
||||
|
||||
char filename[MAXJOLIET];
|
||||
|
||||
@ -436,7 +436,7 @@ int ManageSRAM (u8 direction, u8 device)
|
||||
****************************************************************************/
|
||||
int ManageState (u8 direction, u8 device)
|
||||
{
|
||||
if (!genromsize) return 0;
|
||||
if (!cart.romsize) return 0;
|
||||
|
||||
char filename[MAXJOLIET];
|
||||
|
||||
|
@ -134,7 +134,7 @@ void decode_ggcodes ()
|
||||
if (ggpatch[i].address < 0x400000)
|
||||
{
|
||||
/*** Patching ROM space ONLY (Game Genie does NOT have access to other memory areas) ***/
|
||||
if (cart_rom) *(uint16 *)(cart_rom + ggpatch[i].address) = ggpatch[i].data & 0xffff;
|
||||
if (cart.rom) *(uint16 *)(cart.rom + ggpatch[i].address) = ggpatch[i].data & 0xffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -734,7 +734,7 @@ static void soundmenu ()
|
||||
case 0:
|
||||
config.hq_fm ^= 1;
|
||||
sprintf (items[0].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF");
|
||||
if (genromsize)
|
||||
if (cart.romsize)
|
||||
{
|
||||
unsigned char *temp = memalign(32,YM2612GetContextSize());
|
||||
if (temp) memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize());
|
||||
@ -850,8 +850,9 @@ static void systemmenu ()
|
||||
sprintf (items[1].text, "System Lockups: %s", config.force_dtack ? "OFF" : "ON");
|
||||
sprintf (items[2].text, "68k Address Error: %s", config.addr_error ? "ON" : "OFF");
|
||||
sprintf (items[3].text, "System BIOS: %s", (config.bios_enabled & 1) ? "ON":"OFF");
|
||||
if (config.lock_on == GAME_GENIE) sprintf (items[4].text, "Lock-On: GAME GENIE");
|
||||
else if (config.lock_on == ACTION_REPLAY) sprintf (items[4].text, "Lock-On: ACTION REPLAY");
|
||||
if (config.lock_on == TYPE_GG) sprintf (items[4].text, "Lock-On: GAME GENIE");
|
||||
else if (config.lock_on == TYPE_AR) sprintf (items[4].text, "Lock-On: ACTION REPLAY");
|
||||
else if (config.lock_on == TYPE_SK) sprintf (items[4].text, "Lock-On: SONIC & KNUCKLES");
|
||||
else sprintf (items[4].text, "Lock-On: OFF");
|
||||
|
||||
if (svp)
|
||||
@ -880,7 +881,7 @@ static void systemmenu ()
|
||||
else if (config.region_detect == 1) sprintf (items[0].text, "Console Region: USA");
|
||||
else if (config.region_detect == 2) sprintf (items[0].text, "Console Region: EUR");
|
||||
else if (config.region_detect == 3) sprintf (items[0].text, "Console Region: JAP");
|
||||
if (genromsize)
|
||||
if (cart.romsize)
|
||||
{
|
||||
/* force region & cpu mode */
|
||||
set_region();
|
||||
@ -921,7 +922,7 @@ static void systemmenu ()
|
||||
case 3: /*** BIOS support ***/
|
||||
config.bios_enabled ^= 1;
|
||||
sprintf (items[3].text, "System BIOS: %s", (config.bios_enabled & 1) ? "ON":"OFF");
|
||||
if (genromsize)
|
||||
if (cart.romsize)
|
||||
{
|
||||
system_init ();
|
||||
system_reset ();
|
||||
@ -930,10 +931,12 @@ static void systemmenu ()
|
||||
|
||||
case 4: /*** Cart Lock-On ***/
|
||||
config.lock_on++;
|
||||
if (config.lock_on == GAME_GENIE) sprintf (items[4].text, "Lock-On: GAME GENIE");
|
||||
else if (config.lock_on == ACTION_REPLAY) sprintf (items[4].text, "Lock-On: ACTION REPLAY");
|
||||
if (config.lock_on > TYPE_SK) config.lock_on = 0;
|
||||
if (config.lock_on == TYPE_GG) sprintf (items[4].text, "Lock-On: GAME GENIE");
|
||||
else if (config.lock_on == TYPE_AR) sprintf (items[4].text, "Lock-On: ACTION REPLAY");
|
||||
else if (config.lock_on == TYPE_SK) sprintf (items[4].text, "Lock-On: SONIC & KNUCKLES");
|
||||
else sprintf (items[4].text, "Lock-On: OFF");
|
||||
if (genromsize)
|
||||
if (cart.romsize)
|
||||
{
|
||||
system_reset (); /* clear any patches first */
|
||||
system_init ();
|
||||
@ -1113,7 +1116,7 @@ static void ctrlmenu_raz(void)
|
||||
m->buttons[i+2].data = &button_player_data;
|
||||
m->buttons[i+2].state |= BUTTON_ACTIVE;
|
||||
sprintf(m->items[i+2].text,"%d",max + 1);
|
||||
if (j_cart && (i > 4))
|
||||
if (cart.hw.jcart && (i > 4))
|
||||
sprintf(m->items[i+2].comment,"Configure Player %d (J-CART) settings", max + 1);
|
||||
else
|
||||
sprintf(m->items[i+2].comment,"Configure Player %d settings", max + 1);
|
||||
@ -1291,7 +1294,7 @@ static void ctrlmenu(void)
|
||||
switch (m->selected)
|
||||
{
|
||||
case 0: /* update port 1 system */
|
||||
if (j_cart) break;
|
||||
if (cart.hw.jcart) break;
|
||||
if (input.system[0] == SYSTEM_MOUSE) input.system[0] +=3; /* lightguns are never used on Port 1 */
|
||||
else input.system[0] ++;
|
||||
if ((input.system[0] == SYSTEM_MOUSE) && (input.system[1] == SYSTEM_MOUSE)) input.system[0] +=3;
|
||||
@ -1339,7 +1342,7 @@ static void ctrlmenu(void)
|
||||
break;
|
||||
|
||||
case 1: /* update port 2 system */
|
||||
if (j_cart) break;
|
||||
if (cart.hw.jcart) break;
|
||||
input.system[1] ++;
|
||||
if ((input.system[0] == SYSTEM_MOUSE) && (input.system[1] == SYSTEM_MOUSE)) input.system[1] ++;
|
||||
if (input.system[1] == SYSTEM_WAYPLAY) input.system[0] = SYSTEM_WAYPLAY;
|
||||
@ -1466,7 +1469,7 @@ static void ctrlmenu(void)
|
||||
GUI_DrawMenuFX(m, 20, 0);
|
||||
|
||||
/* update title */
|
||||
if (j_cart && (player > 1))
|
||||
if (cart.hw.jcart && (player > 1))
|
||||
sprintf(m->title,"Controller Settings (Player %d) (J-CART)",player+1);
|
||||
else
|
||||
sprintf(m->title,"Controller Settings (Player %d)",player+1);
|
||||
@ -1911,7 +1914,7 @@ static int loadmenu ()
|
||||
if (DVD_Open())
|
||||
{
|
||||
GUI_DeleteMenu(m);
|
||||
size = FileSelector(cart_rom,0);
|
||||
size = FileSelector(cart.rom,0);
|
||||
if (size) return 1;
|
||||
GUI_InitMenu(m);
|
||||
}
|
||||
@ -1922,7 +1925,7 @@ static int loadmenu ()
|
||||
if (FAT_Open(ret))
|
||||
{
|
||||
GUI_DeleteMenu(m);
|
||||
size = FileSelector(cart_rom,1);
|
||||
size = FileSelector(cart.rom,1);
|
||||
if (size) return 1;
|
||||
GUI_InitMenu(m);
|
||||
}
|
||||
@ -2095,7 +2098,7 @@ void MainMenu (void)
|
||||
if (!rom_loaded)
|
||||
{
|
||||
/* check if a game is running */
|
||||
if (genromsize)
|
||||
if (cart.romsize)
|
||||
{
|
||||
m->screenshot = 1;
|
||||
m->bg_images[0].state &= ~IMAGE_VISIBLE;
|
||||
@ -2124,7 +2127,7 @@ void MainMenu (void)
|
||||
{
|
||||
case -1: /*** Return to Game ***/
|
||||
case 6:
|
||||
if (!genromsize) break;
|
||||
if (!cart.romsize) break;
|
||||
GUI_DrawMenuFX(m,10,1);
|
||||
GUI_DeleteMenu(m);
|
||||
quit = 1;
|
||||
@ -2178,7 +2181,7 @@ void MainMenu (void)
|
||||
break;
|
||||
|
||||
case 3: /*** Memory Manager ***/
|
||||
if (!genromsize) break;
|
||||
if (!cart.romsize) break;
|
||||
GUI_DeleteMenu(m);
|
||||
quit = filemenu ();
|
||||
if (quit) break;
|
||||
@ -2186,7 +2189,7 @@ void MainMenu (void)
|
||||
break;
|
||||
|
||||
case 4: /*** Emulator Reset ***/
|
||||
if (!genromsize) break;
|
||||
if (!cart.romsize) break;
|
||||
GUI_DrawMenuFX(m,10,1);
|
||||
GUI_DeleteMenu(m);
|
||||
gxClearScreen ((GXColor)BLACK);
|
||||
@ -2196,19 +2199,19 @@ void MainMenu (void)
|
||||
break;
|
||||
|
||||
case 5: /*** Game Genie ***/
|
||||
if (!genromsize) break;
|
||||
if (!cart.romsize) break;
|
||||
GUI_DeleteMenu(m);
|
||||
GetGGEntries();
|
||||
GUI_InitMenu(m);
|
||||
break;
|
||||
|
||||
case 7: /*** ROM Captrure ***/
|
||||
if (!genromsize) break;
|
||||
if (!cart.romsize) break;
|
||||
gx_video_Capture();
|
||||
break;
|
||||
|
||||
case 8: /*** ROM Information ***/
|
||||
if (!genromsize) break;
|
||||
if (!cart.romsize) break;
|
||||
GUI_DeleteMenu(m);
|
||||
showrominfo ();
|
||||
GUI_InitMenu(m);
|
||||
|
@ -1442,11 +1442,11 @@ void gx_video_Init(void)
|
||||
*/
|
||||
int *romptr = (int *)0x80700000;
|
||||
StartARAM();
|
||||
genromsize = 0;
|
||||
cart.romsize = 0;
|
||||
if (memcmp((char *)romptr,"GENPLUSR",8) == 0)
|
||||
{
|
||||
genromsize = romptr[2];
|
||||
ARAMPut((char *) 0x80700000 + 0x20, (char *) 0x8000, genromsize);
|
||||
cart.romsize = romptr[2];
|
||||
ARAMPut((char *) 0x80700000 + 0x20, (char *) 0x8000, cart.romsize);
|
||||
}
|
||||
|
||||
/* Get the current VIDEO mode then :
|
||||
|
@ -79,8 +79,8 @@ static void load_bios(void)
|
||||
static void init_machine(void)
|
||||
{
|
||||
/* Allocate cart_rom here ( 10 MBytes ) */
|
||||
cart_rom = memalign(32, MAXROMSIZE);
|
||||
if (!cart_rom)
|
||||
cart.rom = memalign(32, MAXROMSIZE);
|
||||
if (!cart.rom)
|
||||
{
|
||||
FONT_writeCenter("Failed to allocate ROM buffer... Rebooting",18,0,640,200,(GXColor)WHITE);
|
||||
gxSetScreen();
|
||||
@ -121,7 +121,7 @@ static void init_machine(void)
|
||||
***************************************************/
|
||||
void reloadrom (int size, char *name)
|
||||
{
|
||||
genromsize = size;
|
||||
cart.romsize = size;
|
||||
load_rom(name); /* Load ROM */
|
||||
system_init (); /* Initialize System */
|
||||
audio_init(48000); /* Audio System initialization */
|
||||
@ -138,7 +138,7 @@ void shutdown(void)
|
||||
memfile_autosave(-1,config.state_auto);
|
||||
system_shutdown();
|
||||
audio_shutdown();
|
||||
free(cart_rom);
|
||||
free(cart.rom);
|
||||
gx_audio_Shutdown();
|
||||
gx_video_Shutdown();
|
||||
#ifdef HW_RVL
|
||||
@ -212,10 +212,10 @@ int main (int argc, char *argv[])
|
||||
init_machine();
|
||||
|
||||
/* run any injected rom */
|
||||
if (genromsize)
|
||||
if (cart.romsize)
|
||||
{
|
||||
ARAMFetch((char *)cart_rom, (void *)0x8000, genromsize);
|
||||
reloadrom (genromsize,"INJECT.bin");
|
||||
ARAMFetch((char *)cart.rom, (void *)0x8000, cart.romsize);
|
||||
reloadrom (cart.romsize,"INJECT.bin");
|
||||
gx_video_Start();
|
||||
gx_audio_Start();
|
||||
frameticker = 1;
|
||||
|
@ -29,11 +29,13 @@
|
||||
#define GG_ROM "/genplus/ggenie.bin"
|
||||
#define AR_ROM "/genplus/areplay.bin"
|
||||
#define OS_ROM "/genplus/bios.bin"
|
||||
#define SK_ROM "/genplus/sk.bin"
|
||||
#define SK_UPMEM "/genplus/sk2chip.bin"
|
||||
|
||||
#ifdef HW_RVL
|
||||
#define VERSION "version 1.3.3W"
|
||||
#define VERSION "version 1.4.0W"
|
||||
#else
|
||||
#define VERSION "version 1.3.3G"
|
||||
#define VERSION "version 1.4.0G"
|
||||
#endif
|
||||
|
||||
/* globals */
|
||||
|
@ -225,7 +225,7 @@ static void getrominfo (char *romheader)
|
||||
memcpy (&rominfo.memo, romheader + ROMMEMO, 40);
|
||||
memcpy (&rominfo.country, romheader + ROMCOUNTRY, 16);
|
||||
|
||||
realchecksum = GetRealChecksum (((uint8 *) cart_rom) + 0x200, genromsize - 0x200);
|
||||
realchecksum = GetRealChecksum (((uint8 *) cart.rom) + 0x200, cart.romsize - 0x200);
|
||||
#ifdef LSB_FIRST
|
||||
rominfo.checksum = (rominfo.checksum >> 8) | ((rominfo.checksum & 0xff) << 8);
|
||||
#endif
|
||||
@ -256,49 +256,49 @@ int load_rom(char *filename)
|
||||
int i, size, offset = 0;
|
||||
|
||||
#ifdef NGC
|
||||
size = genromsize;
|
||||
size = cart.romsize;
|
||||
sprintf(rom_filename,"%s",filename);
|
||||
rom_filename[strlen(rom_filename) - 4] = 0;
|
||||
#else
|
||||
uint8 *ptr;
|
||||
ptr = load_archive(filename, &size);
|
||||
if(!ptr) return (0);
|
||||
memcpy(cart_rom, ptr + offset, size);
|
||||
memcpy(cart.rom, ptr + offset, size);
|
||||
free(ptr);
|
||||
#endif
|
||||
|
||||
/* detect interleaved roms (.smd format) */
|
||||
if (strncmp((char *)(cart_rom + 0x100),"SEGA", 4) && ((size / 512) & 1))
|
||||
if (strncmp((char *)(cart.rom + 0x100),"SEGA", 4) && ((size / 512) & 1))
|
||||
{
|
||||
size -= 512;
|
||||
offset += 512;
|
||||
|
||||
for (i = 0; i < (size / 0x4000); i += 1)
|
||||
{
|
||||
deinterleave_block (cart_rom + offset + (i * 0x4000));
|
||||
deinterleave_block (cart.rom + offset + (i * 0x4000));
|
||||
}
|
||||
|
||||
memcpy(cart_rom, cart_rom + offset, size);
|
||||
memcpy(cart.rom, cart.rom + offset, size);
|
||||
}
|
||||
|
||||
/* max. 10 MBytes supported */
|
||||
if (size > MAXROMSIZE) size = MAXROMSIZE;
|
||||
genromsize = size;
|
||||
cart.romsize = size;
|
||||
|
||||
/* clear unused ROM space */
|
||||
if (size < MAXROMSIZE) memset (cart_rom + size, 0x00, MAXROMSIZE - size);
|
||||
memset (cart.rom + size, 0xff, MAXROMSIZE - size);
|
||||
|
||||
getrominfo((char *)cart_rom); /* get infos from ROM header */
|
||||
getrominfo((char *)cart.rom); /* get infos from ROM header */
|
||||
set_region(); /* set game region (PAL/NTSC, JAP/USA/EUR) */
|
||||
|
||||
#ifdef LSB_FIRST
|
||||
/* Byteswap ROM */
|
||||
uint8 temp;
|
||||
for(i = 0; i < genromsize; i += 2)
|
||||
for(i = 0; i < size; i += 2)
|
||||
{
|
||||
temp = cart_rom[i];
|
||||
cart_rom[i] = cart_rom[i+1];
|
||||
cart_rom[i+1] = temp;
|
||||
temp = cart.rom[i];
|
||||
cart.rom[i] = cart.rom[i+1];
|
||||
cart.rom[i+1] = temp;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -307,11 +307,11 @@ int load_rom(char *filename)
|
||||
((strstr(rominfo.product,"-K0109") != NULL) && (rominfo.checksum == 0x4f10)))
|
||||
{
|
||||
uint8 temp;
|
||||
for(i = 0; i < genromsize; i += 2)
|
||||
for(i = 0; i < size; i += 2)
|
||||
{
|
||||
temp = cart_rom[i];
|
||||
cart_rom[i] = cart_rom[i+1];
|
||||
cart_rom[i+1] = temp;
|
||||
temp = cart.rom[i];
|
||||
cart.rom[i] = cart.rom[i+1];
|
||||
cart.rom[i+1] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,13 +112,13 @@ static int pico_page[7] = {0x00,0x01,0x03,0x07,0x0F,0x1F,0x3F};
|
||||
uint32 eeprom_read_byte(uint32 address)
|
||||
{
|
||||
if (address == eeprom.type.sda_out_adr) return eeprom_read(address, 0);
|
||||
else return READ_BYTE(cart_rom, address);
|
||||
else return READ_BYTE(cart.rom, address);
|
||||
}
|
||||
|
||||
uint32 eeprom_read_word(uint32 address)
|
||||
{
|
||||
if (address == (eeprom.type.sda_out_adr & 0xfffffe)) return eeprom_read(address, 1);
|
||||
else return *(uint16 *)(cart_rom + address);
|
||||
else return *(uint16 *)(cart.rom + address);
|
||||
}
|
||||
|
||||
void eeprom_write_byte(uint32 address, uint32 data)
|
||||
@ -270,7 +270,8 @@ uint32 ctrl_io_read_byte(uint32 address)
|
||||
else return ((m68k_read_pcrelative_8(REG_PC) & 0xfe) | zbusack);
|
||||
|
||||
case 0x30: /* TIME */
|
||||
if (cart_hw.time_r) return cart_hw.time_r(address);
|
||||
if (cart.hw.time_r)
|
||||
return ((address & 1) ? (cart.hw.time_r(address) & 0xff) : (cart.hw.time_r(address) >> 8));
|
||||
else return m68k_read_bus_8(address);
|
||||
|
||||
case 0x10: /* MEMORY MODE */
|
||||
@ -302,7 +303,7 @@ uint32 ctrl_io_read_word(uint32 address)
|
||||
return ((m68k_read_pcrelative_16(REG_PC) & 0xfeff) | (zbusack << 8));
|
||||
|
||||
case 0x30: /* TIME */
|
||||
if (cart_hw.time_r) return cart_hw.time_r(address);
|
||||
if (cart.hw.time_r) return cart.hw.time_r(address);
|
||||
else return m68k_read_bus_16(address);
|
||||
|
||||
case 0x50: /* SVP */
|
||||
@ -351,20 +352,20 @@ void ctrl_io_write_byte(uint32 address, uint32 data)
|
||||
return;
|
||||
|
||||
case 0x30: /* TIME */
|
||||
cart_hw.time_w(address, data);
|
||||
cart.hw.time_w(address, data);
|
||||
return;
|
||||
|
||||
case 0x41: /* BOOTROM */
|
||||
if (address & 1)
|
||||
{
|
||||
m68k_memory_map[0].base = (data & 1) ? default_rom : bios_rom;
|
||||
m68k_memory_map[0].base = (data & 1) ? cart.base : bios_rom;
|
||||
|
||||
/* autodetect BIOS ROM file */
|
||||
if (!(config.bios_enabled & 2))
|
||||
{
|
||||
config.bios_enabled |= 2;
|
||||
memcpy(bios_rom, cart_rom, 0x800);
|
||||
memset(cart_rom, 0, genromsize);
|
||||
memcpy(bios_rom, cart.rom, 0x800);
|
||||
memset(cart.rom, 0xff, cart.romsize);
|
||||
}
|
||||
}
|
||||
else m68k_unused_8_w (address, data);
|
||||
@ -417,20 +418,20 @@ void ctrl_io_write_word(uint32 address, uint32 data)
|
||||
return;
|
||||
|
||||
case 0x30: /* TIME */
|
||||
cart_hw.time_w(address & 0xfe, data >> 8);
|
||||
cart_hw.time_w(address, data & 0xff);
|
||||
cart.hw.time_w(address & 0xfe, data >> 8);
|
||||
cart.hw.time_w(address, data & 0xff);
|
||||
return;
|
||||
|
||||
case 0x41: /* BOOTROM */
|
||||
|
||||
m68k_memory_map[0].base = (data & 1) ? default_rom : bios_rom;
|
||||
m68k_memory_map[0].base = (data & 1) ? cart.base : bios_rom;
|
||||
|
||||
/* autodetect BIOS ROM file */
|
||||
if (!(config.bios_enabled & 2))
|
||||
{
|
||||
config.bios_enabled |= 2;
|
||||
memcpy(bios_rom, cart_rom, 0x800);
|
||||
memset(cart_rom, 0, genromsize);
|
||||
memcpy(bios_rom, cart.rom, 0x800);
|
||||
memset(cart.rom, 0xff, cart.romsize);
|
||||
}
|
||||
return;
|
||||
|
||||
|
@ -73,7 +73,8 @@ uint32 zbank_read_ctrl_io(uint32 address)
|
||||
else return (0xfe | zbusack);
|
||||
|
||||
case 0x30: /* TIME */
|
||||
if (cart_hw.time_r) return cart_hw.time_r(address);
|
||||
if (cart.hw.time_r)
|
||||
return ((address & 1) ? (cart.hw.time_r(address) & 0xff) : (cart.hw.time_r(address) >> 8));
|
||||
else return zbank_unused_r(address);
|
||||
|
||||
case 0x10: /* MEMORY MODE */
|
||||
@ -110,21 +111,20 @@ void zbank_write_ctrl_io(uint32 address, uint32 data)
|
||||
return;
|
||||
|
||||
case 0x30: /* TIME */
|
||||
if (cart_hw.time_w) cart_hw.time_w(address, data);
|
||||
else zbank_unused_w(address, data);
|
||||
cart.hw.time_w(address, data);
|
||||
return;
|
||||
|
||||
case 0x41: /* BOOTROM */
|
||||
if (address & 1)
|
||||
{
|
||||
m68k_memory_map[0].base = (data & 1) ? default_rom : bios_rom;
|
||||
m68k_memory_map[0].base = (data & 1) ? cart.base : bios_rom;
|
||||
|
||||
/* autodetect BIOS ROM file */
|
||||
if (!(config.bios_enabled & 2))
|
||||
{
|
||||
config.bios_enabled |= 2;
|
||||
memcpy(bios_rom, cart_rom, 0x800);
|
||||
memset(cart_rom, 0, genromsize);
|
||||
memcpy(bios_rom, cart.rom, 0x800);
|
||||
memset(cart.rom, 0xff, cart.romsize);
|
||||
}
|
||||
}
|
||||
else zbank_unused_w (address, data);
|
||||
|
@ -54,7 +54,7 @@ int state_load(unsigned char *buffer)
|
||||
|
||||
/* reset system */
|
||||
system_reset();
|
||||
m68k_memory_map[0].base = default_rom;
|
||||
m68k_memory_map[0].base = cart.base;
|
||||
|
||||
// GENESIS
|
||||
load_param(work_ram, sizeof(work_ram));
|
||||
|
@ -204,10 +204,14 @@ void audio_shutdown(void)
|
||||
****************************************************************/
|
||||
void system_init (void)
|
||||
{
|
||||
/* Cartridge hardware (should be done first !) */
|
||||
cart_hw_init();
|
||||
|
||||
/* Genesis hardware */
|
||||
gen_init ();
|
||||
vdp_init ();
|
||||
render_init ();
|
||||
cart_hw_init();
|
||||
io_init();
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
@ -215,15 +219,14 @@ void system_init (void)
|
||||
****************************************************************/
|
||||
void system_reset (void)
|
||||
{
|
||||
/* Cartridge Hardware (should be done first !) */
|
||||
/* Cartridge hardware (should be done first !) */
|
||||
cart_hw_reset();
|
||||
|
||||
/* Genesis Hardware */
|
||||
/* Genesis hardware */
|
||||
gen_reset (1);
|
||||
vdp_reset ();
|
||||
render_reset ();
|
||||
io_reset();
|
||||
SN76489_Reset();
|
||||
|
||||
/* Clear Sound Buffers */
|
||||
if (snd.psg.buffer) memset (snd.psg.buffer, 0, SND_SIZE);
|
||||
|
@ -66,8 +66,8 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
error_init();
|
||||
|
||||
cart_rom = malloc(0xA00000);
|
||||
memset(cart_rom, 0, 0xA00000);
|
||||
cart.rom = malloc(0xA00000);
|
||||
memset(cart.rom, 0, 0xA00000);
|
||||
|
||||
if(!load_rom(argv[1]))
|
||||
{
|
||||
@ -146,7 +146,7 @@ int main (int argc, char *argv[])
|
||||
trash_machine();
|
||||
system_shutdown();
|
||||
error_shutdown();
|
||||
free(cart_rom);
|
||||
free(cart.rom);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -11,9 +11,11 @@ void set_config_defaults(void)
|
||||
/* sound options */
|
||||
config.psg_preamp = 150;
|
||||
config.fm_preamp = 100;
|
||||
config.hq_fm = 1;
|
||||
config.hq_fm = 0;
|
||||
config.psgBoostNoise = 0;
|
||||
config.filter = 1;
|
||||
config.low_freq = 200;
|
||||
config.high_freq = 8000;
|
||||
config.lg = 1.0;
|
||||
config.mg = 1.0;
|
||||
config.hg = 1.0;
|
||||
@ -21,11 +23,14 @@ void set_config_defaults(void)
|
||||
/* system options */
|
||||
config.region_detect = 0;
|
||||
config.force_dtack = 0;
|
||||
config.addr_error = 0;
|
||||
config.bios_enabled = 0;
|
||||
config.lock_on = 0;
|
||||
config.romtype = 0;
|
||||
|
||||
/* display options */
|
||||
config.overscan = 1;
|
||||
config.render = 1;
|
||||
config.render = 0;
|
||||
|
||||
/* controllers options */
|
||||
input.system[0] = SYSTEM_GAMEPAD;
|
||||
|
@ -18,12 +18,17 @@ typedef struct
|
||||
int32 psg_preamp;
|
||||
int32 fm_preamp;
|
||||
uint8 filter;
|
||||
uint16 low_freq;
|
||||
uint16 high_freq;
|
||||
float lg;
|
||||
float mg;
|
||||
float hg;
|
||||
uint8 region_detect;
|
||||
uint8 force_dtack;
|
||||
uint8 addr_error;
|
||||
uint8 bios_enabled;
|
||||
uint8 lock_on;
|
||||
uint8 romtype;
|
||||
uint8 overscan;
|
||||
uint8 render;
|
||||
uint8 ntsc;
|
||||
|
@ -133,7 +133,7 @@ Uint32 fps_callback(Uint32 interval)
|
||||
if (region_code == REGION_USA) sprintf(region,"USA");
|
||||
else if (region_code == REGION_EUROPE) sprintf(region,"EUR");
|
||||
else sprintf(region,"JAP");
|
||||
sprintf(caption, "Genesis Plus/SDL - %s (%s) - %d fps - xoffset = %d", rominfo.international, region, fps,input.x_offset);
|
||||
sprintf(caption, "Genesis Plus/SDL - %s (%s) - %d fps - 0x%04X", rominfo.international, region, fps, realchecksum);
|
||||
SDL_WM_SetCaption(caption, NULL);
|
||||
frame_count = 0;
|
||||
|
||||
@ -177,8 +177,8 @@ int main (int argc, char **argv)
|
||||
set_config_defaults();
|
||||
|
||||
/* Load game */
|
||||
cart_rom = malloc(10*1024*1024);
|
||||
memset(cart_rom, 0, 10*1024*1024);
|
||||
cart.rom = malloc(10*1024*1024);
|
||||
memset(cart.rom, 0, 10*1024*1024);
|
||||
if(!load_rom(argv[1]))
|
||||
{
|
||||
char caption[256];
|
||||
@ -221,7 +221,7 @@ int main (int argc, char **argv)
|
||||
|
||||
/* load BIOS */
|
||||
memset(bios_rom, 0, sizeof(bios_rom));
|
||||
FILE *f = fopen("./BIOS.bin", "rb");
|
||||
FILE *f = fopen(OS_ROM, "rb");
|
||||
if (f!=NULL)
|
||||
{
|
||||
fread(&bios_rom, 0x800,1,f);
|
||||
@ -436,8 +436,9 @@ int main (int argc, char **argv)
|
||||
SDL_FreeSurface(screen);
|
||||
SDL_Quit();
|
||||
system_shutdown();
|
||||
audio_shutdown();
|
||||
error_shutdown();
|
||||
free(cart_rom);
|
||||
free(cart.rom);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -18,4 +18,10 @@
|
||||
#include "unzip.h"
|
||||
#include "fileio.h"
|
||||
|
||||
#define GG_ROM "./ggenie.bin"
|
||||
#define AR_ROM "./areplay.bin"
|
||||
#define OS_ROM "./bios.bin"
|
||||
#define SK_ROM "./sk.bin"
|
||||
#define SK_UPMEM "./sk2chip.bin"
|
||||
|
||||
#endif /* _OSD_H_ */
|
||||
|
22
source/vdp.c
22
source/vdp.c
@ -76,21 +76,21 @@ uint8 fifo_latency; /* VDP write cycles latency */
|
||||
uint8 odd_frame; /* 1: odd field, 0: even field */
|
||||
uint8 im2_flag; /* 1= Interlace mode 2 is being used */
|
||||
uint8 interlaced; /* 1: Interlaced mode 1 or 2 */
|
||||
uint8 vdp_pal = 0; /* 1: PAL , 0: NTSC (default) */
|
||||
uint8 vdp_pal; /* 1: PAL , 0: NTSC (default) */
|
||||
uint8 vdp_rate; /* PAL: 50hz, NTSC: 60hz */
|
||||
uint16 lines_per_frame; /* PAL: 313 lines, NTSC: 262 lines */
|
||||
|
||||
|
||||
/* Tables that define the playfield layout */
|
||||
static const uint8 shift_table[] = { 6, 7, 0, 8 };
|
||||
static const uint8 col_mask_table[] = { 0x0F, 0x1F, 0x0F, 0x3F };
|
||||
static const uint16 row_mask_table[] = { 0x0FF, 0x1FF, 0x2FF, 0x3FF };
|
||||
static const uint32 y_mask_table[] = { 0x1FC0, 0x1F80, 0x1FC0, 0x1F00 };
|
||||
static const uint8 shift_table[] = { 6, 7, 0, 8 };
|
||||
static const uint8 col_mask_table[] = { 0x0F, 0x1F, 0x0F, 0x3F };
|
||||
static const uint16 row_mask_table[] = { 0x0FF, 0x1FF, 0x2FF, 0x3FF };
|
||||
static const uint32 y_mask_table[] = { 0x1FC0, 0x1F80, 0x1FC0, 0x1F00 };
|
||||
|
||||
static uint16 sat_base_mask; /* Base bits of SAT */
|
||||
static uint16 sat_addr_mask; /* Index bits of SAT */
|
||||
static uint32 dma_endCycles; /* 68k cycles to DMA end */
|
||||
static uint8 dma_type; /* Type of DMA */
|
||||
static uint16 sat_base_mask; /* Base bits of SAT */
|
||||
static uint16 sat_addr_mask; /* Index bits of SAT */
|
||||
static uint32 dma_endCycles; /* 68k cycles to DMA end */
|
||||
static uint8 dma_type; /* DMA mode */
|
||||
|
||||
/* DMA Timings
|
||||
|
||||
@ -159,8 +159,8 @@ void vdp_reset(void)
|
||||
code = 0;
|
||||
pending = 0;
|
||||
|
||||
status = 0x200; /* fifo empty */
|
||||
status |= vdp_pal;
|
||||
status = 0x200; /* fifo empty */
|
||||
status |= vdp_pal; /* PAL/NTSC flag */
|
||||
|
||||
ntab = 0;
|
||||
ntbb = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user