[Core/VDP]

---------------
* improved VBLANK flag accuracy, as observed on real hardware.
* improved DMA operations accuracy, writes are now performed on a scanline basis: fixes Gaiares (flickering title screen).
* improved DMA Fill timing accuracy.
* fixed DMA with bad code values: fixes Williams Arcade Classics (corrupted gfx after soft reset).
* fixed horizontal resolution changes during HBLANK: fixes Bugs Bunny in Double Trouble (2nd stage).
* fixed Vertical Counter in interlace mode 1, as observed on real hardware.
* fixed horizontal border width, as observed on real hardware.
* various code improvments & optimizations.

[Core/Extra]
---------------
* improved savestate format: added DMA, SVP, cartridge mapping & internal registers state informations
* improved unlicensed ROM mappers emulation
* added Chinese Fighters III mapper support
* added Top Fighter mapper support
* fixed Barver Battle Saga mapper support
* fixed cartridge hardware soft-reset (Game Genie, SVP, ...)
* fixed Game Genie registers byte reads
This commit is contained in:
ekeeke31 2010-12-04 17:13:55 +00:00
parent edf479a257
commit a4cfc2a77a
20 changed files with 1146 additions and 795 deletions

View File

@ -151,23 +151,26 @@ void areplay_shutdown(void)
action_replay.enabled = 0;
}
void areplay_reset(int hard_reset)
void areplay_reset(int hard)
{
if (action_replay.enabled)
{
/* reset internal registers */
memset(action_replay.regs, 0, sizeof(action_replay.regs));
memset(action_replay.old, 0, sizeof(action_replay.old));
memset(action_replay.data, 0, sizeof(action_replay.data));
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;
/* internal RAM is cleared on power ON */
if (hard_reset)
if (hard || (action_replay.status == AR_SWITCH_TRAINER))
{
memset(action_replay.ram,0xff,0x10000);
/* reset internal registers */
memset(action_replay.regs, 0, sizeof(action_replay.regs));
memset(action_replay.old, 0, sizeof(action_replay.old));
memset(action_replay.data, 0, sizeof(action_replay.data));
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;
/* reset internal RAM on power-on */
if (hard)
{
memset(action_replay.ram,0xff,0x10000);
}
}
}
}

View File

@ -28,7 +28,7 @@
extern void areplay_init(void);
extern void areplay_shutdown(void);
extern void areplay_reset(int hard_reset);
extern void areplay_reset(int hard);
extern void areplay_set_status(int status);
extern int areplay_get_status(void);

View File

@ -3,7 +3,7 @@
* Genesis Plus
* Cartridge Hardware support
*
* Copyright (C) 2007, 2008, 2009 Eke-Eke (GCN/Wii port)
* Copyright (C) 2007, 2008, 2009, 2010 Eke-Eke (GCN/Wii port)
*
* Most cartridge protections documented by Haze
* (http://haze.mameworld.info/)
@ -27,7 +27,7 @@
#include "shared.h"
#define CART_CNT 28
#define CART_CNT 30
extern int emulate_address_error;
@ -45,15 +45,19 @@ typedef struct
} 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 mapper_sega_w(uint32 data);
static void mapper_ssf2_w(uint32 address, uint32 data);
static void mapper_realtec_w(uint32 address, uint32 data);
static void mapper_seganet_w(uint32 address, uint32 data);
static void mapper_32k_w(uint32 data);
static void mapper_64k_w(uint32 data);
static void mapper_64k_multi_w(uint32 address);
static uint32 mapper_radica_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);
static void custom_regs_w(uint32 address, uint32 data);
static void custom_alt_regs_w(uint32 address, uint32 data);
/* Games that need extra hardware emulation:
- copy protection device
@ -62,31 +66,37 @@ static void special_regs_w(uint32 address, uint32 data);
static const T_CART_ENTRY 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,1,NULL,NULL,NULL,realtec_mapper_w}},
{0x0000,0x06ab,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}},
/* Whac-a-Critter */
{0xffff,0xf863,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,1,NULL,NULL,NULL,realtec_mapper_w}},
{0xffff,0xf863,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}},
/* Earth Defense */
{0xffff,0x44fb,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,1,NULL,NULL,NULL,realtec_mapper_w}},
{0xffff,0x44fb,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},1,0,NULL,NULL,NULL,mapper_realtec_w}},
/* RADICA (Volume 1) (not byteswapped) */
{0x0000,0x2326,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,radica_mapper_r,NULL,NULL,NULL}},
{0x0000,0x2326,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_radica_r,NULL,NULL,NULL}},
/* RADICA (Volume 2) */
{0x4f10,0x0836,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,radica_mapper_r,NULL,NULL,NULL}},
{0x4f10,0x0836,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_radica_r,NULL,NULL,NULL}},
/* RADICA (Volume 1) */
{0xf424,0x9f82,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,radica_mapper_r,NULL,NULL,NULL}},
{0xf424,0x9f82,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,mapper_radica_r,NULL,NULL,NULL}},
/* Chinese Fighters III */
{0x9490,0x8180,0x40,0x6f,{{0x00,0x00,0x00,0x00},{0xf0000c,0xf0000c,0xf0000c,0xf0000c},{0x400000,0x400004,0x400008,0x40000c},0,1,NULL,NULL,default_regs_r,custom_alt_regs_w}},
/* Top Fighter */
{0x4eb9,0x5d8b,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}},
/* Mulan */
{0x0404,0x1b40,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,special_regs_w}},
{0x0404,0x1b40,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}},
/* Pocket Monsters II */
{0x47f9,0x17e5,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,special_regs_w}},
{0x47f9,0x17e5,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}},
/* Lion King 3 */
{0x0000,0x507c,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,special_regs_w}},
{0x0000,0x507c,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}},
/* Super King Kong 99 */
{0x0000,0x7d6e,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,special_regs_w}},
{0x0000,0x7d6e,0x60,0x7f,{{0x00,0x00,0x00,0x00},{0xf00007,0xf00007,0xf00007,0xffffff},{0x600001,0x600003,0x600005,0x000000},0,1,NULL,NULL,default_regs_r,custom_regs_w}},
/* Pokemon Stadium */
{0x0000,0x843c,0x70,0x7f,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,NULL,NULL,NULL,special_regs_w}},
{0x0000,0x843c,0x70,0x7f,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,1,NULL,NULL,NULL,custom_regs_w}},
/* Lion King 2 */
{0xffff,0x1d9b,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}},
/* Squirell King */
{0x0000,0x8ec8,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffffd,0xfffffd,0xffffff,0xffffff},{0x400000,0x400004,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}},
/* Lian Huan Pao - Barver Battle Saga */
{0x30b9,0x1c2a,0x40,0x40,{{0x00,0x00,0x00,0x00},{0xfffff4,0xffffff,0xffffff,0xffffff},{0x400004,0x000000,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,default_regs_w}},
/* Supper Bubble Bobble */
{0x0000,0x16cd,0x40,0x40,{{0x55,0x0f,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}},
/* Mahjong Lover */
@ -101,13 +111,9 @@ static const T_CART_ENTRY rom_database[CART_CNT] =
{0x0000,0x0c5b,0x40,0x40,{{0x00,0x98,0xc9,0xF0},{0xffffff,0xffffff,0xffffff,0xffffff},{0x400000,0x400002,0x400004,0x400006},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,NULL,NULL,default_regs_r,NULL}},
/* Lian Huan Pao - Barver Battle Saga */
{0x30b9,0x1c2a,0x40,0x40,{{0x00,0x00,0x00,0x00},{0x000000,0x000000,0x000000,0x000000},{0x000000,0x000000,0x000000,0x000000},0,0,NULL,NULL,default_regs_r,NULL}},
/* Rockman X3 */
{0x0000,0x9d0e,0x40,0x40,{{0x0c,0x88,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x400004,0x000000,0x000000},0,0,default_regs_r,NULL,default_regs_r,NULL}},
/* Super Mario 2 1998 */
{0xffff,0x0474,0x00,0x00,{{0x0a,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x000000,0x000000},0,0,default_regs_r,NULL,NULL,NULL}},
/* Super Mario 2 1998 */
/* Super Mario World */
{0x2020,0xb4eb,0x00,0x00,{{0x1c,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x000000,0x000000,0x000000},0,0,default_regs_r,NULL,NULL,NULL}},
/* A Bug's Life */
{0x7f7f,0x2aad,0x00,0x00,{{0x28,0x1f,0x01,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0xa13002,0xa1303e,0x000000},0,0,default_regs_r,NULL,NULL,NULL}},
@ -115,8 +121,10 @@ static const T_CART_ENTRY rom_database[CART_CNT] =
{0x0000,0x021e,0x00,0x00,{{0x00,0x01,0x1f,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0xa13002,0xa1303e,0x000000},0,0,default_regs_r,NULL,NULL,NULL}},
/* Pocket Monster */
{0xd6fc,0x1eb1,0x00,0x00,{{0x00,0x01,0x1f,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0xa13002,0xa1303e,0x000000},0,0,default_regs_r,NULL,NULL,NULL}},
/* Rockman X3 */
{0x0000,0x9d0e,0x40,0x40,{{0x0c,0x88,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0xa13000,0x400004,0x000000,0x000000},0,0,default_regs_r,NULL,default_regs_r,NULL}},
/* Game no Kanzume Otokuyou */
{0x0000,0xf9d1,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,NULL,seganet_mapper_w,NULL,NULL}}
{0x0000,0xf9d1,0x00,0x00,{{0x00,0x00,0x00,0x00},{0xffffff,0xffffff,0xffffff,0xffffff},{0x000000,0x000000,0x000000,0x000000},0,0,NULL,mapper_seganet_w,NULL,NULL}}
};
@ -311,12 +319,16 @@ void cart_hw_init()
switch (config.lock_on)
{
case TYPE_GG:
{
ggenie_init();
break;
}
case TYPE_AR:
{
areplay_init();
break;
}
case TYPE_SK:
{
@ -359,14 +371,18 @@ void cart_hw_init()
/*$000000-$1fffff is mapped to S&K ROM */
for (i=0x00; i<0x20; i++)
{
m68k_memory_map[i].base = (cart.rom + 0x600000) + (i<<16);
}
cart.lock_on = 1;
break;
}
default:
{
break;
}
}
/**********************************************
@ -408,6 +424,22 @@ void cart_hw_init()
}
}
/* Realtec mapper */
if (cart.hw.realtec)
{
/* 8k BOOT ROM */
for (i=0; i<8; i++)
{
memcpy(cart.rom + 0x900000 + i*0x2000, cart.rom + 0x7e000, 0x2000);
}
/* BOOT ROM is mapped to $000000-$3FFFFF */
for (i=0x00; i<0x40; i++)
{
m68k_memory_map[i].base = cart.rom + 0x900000;
}
}
#if M68K_EMULATE_ADDRESS_ERROR
/* default behavior */
emulate_address_error = config.addr_error;
@ -434,50 +466,42 @@ void cart_hw_init()
{
/* assume SSF2 mapper */
cart.hw.bankshift = 1;
cart.hw.time_w = sega_mapper_w;
cart.hw.time_w = mapper_ssf2_w;
}
/* default write handler for !TIME signal */
/* default write handler for !TIME range ($A130xx)*/
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()
void cart_hw_reset(int hard)
{
int i;
/* reset bankshifting */
/* reset cartridge mapping */
if (cart.hw.bankshift)
{
for (i=0x00; i<0x40; i++)
{
m68k_memory_map[i].base = cart.rom + ((i<<16) & cart.mask);
}
}
/* Realtec mapper */
if (cart.hw.realtec & 1)
{
/* enable BOOTROM */
for (i=0; i<8; i++)
memcpy(cart.rom + 0x900000 + i*0x2000, cart.rom + 0x7e000, 0x2000);
for (i=0x00; i<0x40; i++)
m68k_memory_map[i].base = cart.rom + 0x900000;
cart.hw.realtec |= 2;
}
/* SVP chip */
if (svp)
svp_reset();
if (svp) svp_reset();
/* Lock-ON */
switch (config.lock_on)
{
case TYPE_GG:
ggenie_reset();
ggenie_reset(hard);
break;
case TYPE_AR:
areplay_reset(1);
areplay_reset(hard);
break;
case TYPE_SK:
@ -497,118 +521,180 @@ void cart_hw_reset()
cart.base = m68k_memory_map[0].base;
}
int cart_hw_context_save(uint8 *state)
{
int i;
int bufferptr = 0;
uint8 *base;
/* cartridge mapping */
for (i=0; i<0x40; i++)
{
/* get base address */
base = m68k_memory_map[i].base;
if (base == sram.sram)
{
/* SRAM */
state[bufferptr++] = 0xff;
}
else
{
/* ROM */
state[bufferptr++] = ((base - cart.rom) >> 16) & 0xff;
}
}
/* hardware registers */
save_param(cart.hw.regs, sizeof(cart.hw.regs));
/* SVP */
if (svp)
{
save_param(svp->iram_rom, 0x800);
save_param(svp->dram,sizeof(svp->dram));
save_param(&svp->ssp1601,sizeof(ssp1601_t));
}
return bufferptr;
}
int cart_hw_context_load(uint8 *state, char *version)
{
int i;
int bufferptr = 0;
uint8 offset;
/* extended state */
if (version[15] > 0x30)
{
/* cartridge mapping */
for (i=0; i<0x40; i++)
{
/* get offset */
offset = state[bufferptr++];
if (offset == 0xff)
{
/* SRAM */
m68k_memory_map[i].base = sram.sram;
}
else
{
/* ROM */
m68k_memory_map[i].base = cart.rom + (offset << 16);
}
}
/* hardware registers */
load_param(cart.hw.regs, sizeof(cart.hw.regs));
/* SVP */
if (svp)
{
load_param(svp->iram_rom, 0x800);
load_param(svp->dram,sizeof(svp->dram));
load_param(&svp->ssp1601,sizeof(ssp1601_t));
}
}
return bufferptr;
}
/************************************************************
MAPPER handlers
*************************************************************/
/*
"official" ROM/RAM switch
ROM/SRAM Bankswitch (Phantasy Star IV, Story of Thor/Beyond Oasis, Sonic 3 & Knuckles)
*/
static void sega_mapper_w(uint32 address, uint32 data)
static void mapper_sega_w(uint32 data)
{
uint32 i,slot = (address >> 1) & 7;
uint8 *src;
int i;
switch (slot)
if (data & 1)
{
case 0:
/* ROM/SRAM switch (Phantasy Star IV, Story of Thor/Beyond Oasis, Sonic 3 & Knuckles) */
if (data & 1)
/* Only if SRAM is detected */
if (sram.on)
{
/* $200000-$3fffff is mapped to SRAM */
for (i=0x20; i<0x40; i++)
{
/* $200000-$3fffff is mapped to SRAM (only if SRAM exists) */
if (sram.on)
{
for (i=0x20; i<0x40; i++)
m68k_memory_map[i].base = sram.sram;
m68k_memory_map[i].base = sram.sram;
}
if (data & 2)
{
/* SRAM write disabled */
for (i=0x20; i<0x40; 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;
}
}
else
{
/* SRAM write enabled */
for (i=0x20; i<0x40; i++)
{
m68k_memory_map[i].write8 = NULL;
m68k_memory_map[i].write16 = NULL;
zbank_memory_map[i].write = NULL;
}
}
}
if (cart.lock_on)
if (data & 2)
{
/* SRAM write disabled */
for (i=0x20; i<0x40; i++)
{
/* enable UPMEM chip at $300000-$3fffff */
for (i=0x30; i<0x40; i++)
m68k_memory_map[i].base = (cart.rom + 0x800000) + ((i & 3)<<16);
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;
}
}
else
{
/* ROM enabled */
/* SRAM write enabled */
for (i=0x20; i<0x40; i++)
m68k_memory_map[i].base = cart.rom + ((i<<16) & cart.mask);
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) & cart.mask);
m68k_memory_map[i].write8 = NULL;
m68k_memory_map[i].write16 = NULL;
zbank_memory_map[i].write = NULL;
}
}
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);
break;
/* S&K lock-on chip */
if (cart.lock_on && (config.lock_on == TYPE_SK))
{
/* $300000-$3fffff is mapped to S2K upmem chip */
for (i=0x30; i<0x40; i++)
{
m68k_memory_map[i].base = (cart.rom + 0x800000) + ((i & 3)<<16);
}
}
}
else
{
/* $200000-$3fffff is mapped to ROM */
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;
zbank_memory_map[i].write = zbank_unused_w;
}
}
}
/*
custom ROM Bankswitch used by pirate "Multi-in-1" carts
/*
Super Street Fighter 2 ROM Bankswitch
documented by Bart Trzynadlowski (http://www.trzy.org/files/ssf2.txt)
*/
static void multi_mapper_w(uint32 address, uint32 data)
static void mapper_ssf2_w(uint32 address, uint32 data)
{
int i;
/* 8 x 512k banks */
uint32 dst = (address << 2) & 0x38;
/* bank 0 remains unchanged */
if (dst)
{
uint32 i;
uint8 *src = cart.rom + (data << 19);
cart.hw.bankshift = 1;
/* 64 x 64k banks */
for (i=0; i<64; i++)
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)
*/
static void special_mapper_w(uint32 address, uint32 data)
{
/* 1 x 32k bank */
memcpy(cart.rom + 0x900000, cart.rom + ((data & 0x7f) << 15), 0x8000);
memcpy(cart.rom + 0x908000, cart.rom + 0x8000, 0x8000);
m68k_memory_map[0].base = cart.rom + 0x900000;
for (i=0; i<8; i++)
{
m68k_memory_map[dst++].base = src + (i<<16);
}
}
}
/*
Realtec ROM Bankswitch (Earth Defend, Balloon Boy & Funny World, Whac-A-Critter)
(Note: register usage is inverted in TascoDlx documentation)
*/
static void realtec_mapper_w(uint32 address, uint32 data)
static void mapper_realtec_w(uint32 address, uint32 data)
{
switch (address)
{
@ -648,7 +734,7 @@ static void realtec_mapper_w(uint32 address, uint32 data)
}
/* Game no Kanzume Otokuyou ROM Mapper */
static void seganet_mapper_w(uint32 address, uint32 data)
static void mapper_seganet_w(uint32 address, uint32 data)
{
if ((address & 0xff) == 0xf1)
{
@ -676,19 +762,92 @@ static void seganet_mapper_w(uint32 address, uint32 data)
}
}
/*
RADICA ROM Bankswitch (use !TIME)
/*
Custom ROM Bankswitch used in Top Fighter, Mulan, Pocket Monsters II, Lion King 3, Super King Kong 99, Pokemon Stadium
*/
static uint32 radica_mapper_r(uint32 address)
static void mapper_32k_w(uint32 data)
{
int i;
/* 64 x 32k banks */
if (data)
{
/* unverified (Top Fighter writes $2A instead $2E) */
if (data >> 2) data |= 4;
/* bank is mapped at $000000-$0FFFFF */
for (i=0; i<16; i++)
{
memcpy(cart.rom + 0x900000 + (i<<16), cart.rom + ((data & 0x3f) << 15), 0x8000);
memcpy(cart.rom + 0x908000 + (i<<16), cart.rom + ((data & 0x3f) << 15), 0x8000);
m68k_memory_map[i].base = cart.rom + 0x900000 + (i<<16);
}
}
else
{
/* reset default $000000-$0FFFFF mapping */
for (i=0; i<16; i++)
{
m68k_memory_map[i].base = &cart.rom[i << 16];
}
}
}
/*
Custom ROM Bankswitch used in Chinese Fighter III
*/
static void mapper_64k_w(uint32 data)
{
int i;
/* 16 x 64k banks */
if (data)
{
/* bank is mapped at $000000-$0FFFFF */
for (i=0; i<16; i++)
{
m68k_memory_map[i].base = &cart.rom[(data & 0xf) << 16];
}
}
else
{
/* reset default $000000-$0FFFFF mapping */
for (i=0; i<16; i++)
{
m68k_memory_map[i].base = &cart.rom[(i & 0xf) << 16];
}
}
}
/*
Custom ROM Bankswitch used in pirate "Multi-in-1" cartridges, A Bug's Life, King of Fighter 99, Pocket Monster, Rockman X3
*/
static void mapper_64k_multi_w(uint32 address)
{
int i;
/* 64 x 64k banks */
for (i=0; i<64; i++)
{
m68k_memory_map[i].base = &cart.rom[((address++) & 0x3f) << 16];
}
}
/*
Custom ROM Bankswitch used in RADICA cartridges
*/
static uint32 mapper_radica_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];
}
return 0xff;
return 0xffff;
}
@ -696,14 +855,17 @@ static uint32 radica_mapper_r(uint32 address)
default !TIME signal handler
*************************************************************/
/* default ROM bankswitch */
static void default_time_w(uint32 address, uint32 data)
{
if ((address & 0xf1) == 0xf1)
sega_mapper_w(address, data);
if (address < 0xa13040)
{
/* unlicensed cartridges mapper (default) */
mapper_64k_multi_w(address);
return;
}
else if (address < 0xa13040)
multi_mapper_w(address, data);
/* official cartridges mapper (default) */
mapper_sega_w(data);
}
@ -717,10 +879,10 @@ static uint32 default_regs_r(uint32 address)
for (i=0; i<4; i++)
{
if ((address & cart.hw.mask[i]) == cart.hw.addr[i])
{
return cart.hw.regs[i];
}
}
/* unused */
return m68k_read_bus_8(address);
}
@ -738,22 +900,22 @@ static void default_regs_w(uint32 address, uint32 data)
m68k_unused_8_w(address, data);
}
/* special register behaviour (Lion King III, Super Donkey Kong 99, Mulan, Pocket Monsters II) */
static void special_regs_w(uint32 address, uint32 data)
/* custom register hardware (Top Fighter, Lion King III, Super Donkey Kong 99, Mulan, Pocket Monsters II, Pokemon Stadium) */
static void custom_regs_w(uint32 address, uint32 data)
{
/* ROM bankswitch */
if ((address >> 16) > 0x6f)
{
special_mapper_w(address, data);
mapper_32k_w(data);
return;
}
/* write regs */
/* write register */
default_regs_w(address, data);
/* bitswapping (documented by Haze) */
/* bitswapping */
uint32 temp = cart.hw.regs[0];
switch (cart.hw.regs[1])
switch (cart.hw.regs[1] & 3)
{
case 0:
cart.hw.regs[2] = (temp << 1);
@ -775,3 +937,17 @@ static void special_regs_w(uint32 address, uint32 data)
return;
}
}
/* alternate custom register hardware (Chinese Fighters III) */
static void custom_alt_regs_w(uint32 address, uint32 data)
{
/* ROM bankswitch */
if ((address >> 16) > 0x5f)
{
mapper_64k_w(data);
return;
}
/* write regs */
default_regs_w(address, data);
}

View File

@ -2,7 +2,7 @@
* Genesis Plus
* Cartridge Hardware support
*
* Copyright (C) 2007, 2008, 2009 Eke-Eke (GCN/Wii port)
* Copyright (C) 2007, 2008, 2009, 2010 Eke-Eke (GCN/Wii port)
*
* Lots of protection mechanism have been discovered by Haze
* (http://haze.mameworld.info/)
@ -38,8 +38,8 @@ typedef struct
uint8 regs[4]; /* internal registers (R/W) */
uint32 mask[4]; /* registers address mask */
uint32 addr[4]; /* registers address */
uint16 realtec; /* bit 0: realtec mapper detected, bit 1: bootrom enabled */
uint16 bankshift; /* cartridge with bankshift mecanism */
uint16 realtec; /* realtec mapper */
uint16 bankshift; /* cartridge with bankshift mecanism reseted on soft-reset */
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 registers read handler */
@ -63,7 +63,9 @@ extern T_CART cart;
/* Function prototypes */
extern void cart_hw_init();
extern void cart_hw_reset();
extern void cart_hw_reset(int hard);
extern int cart_hw_context_save(uint8 *state);
extern int cart_hw_context_load(uint8 *state, char *version);
#endif

View File

@ -34,10 +34,11 @@ static struct
uint32 addr[6];
} ggenie;
static void ggenie_write_byte(uint32 address, uint32 data);
static void ggenie_write_word(uint32 address, uint32 data);
static void ggenie_write_regs(uint8 offset, uint32 data, uint8 type);
static uint32 ggenie_read_regs(uint32 address);
static unsigned int ggenie_read_byte(unsigned int address);
static unsigned int ggenie_read_word(unsigned int address);
static void ggenie_write_byte(unsigned int address, unsigned int data);
static void ggenie_write_word(unsigned int address, unsigned int data);
static void ggenie_write_regs(unsigned int offset, unsigned int data);
void ggenie_init(void)
{
@ -87,29 +88,32 @@ void ggenie_shutdown(void)
}
}
void ggenie_reset(void)
void ggenie_reset(int hard)
{
if (!ggenie.enabled)
return;
/* clear codes */
ggenie_switch(0);
if (ggenie.enabled)
{
if (hard)
{
/* clear codes */
ggenie_switch(0);
/* reset internal state */
memset(ggenie.regs,0,sizeof(ggenie.regs));
memset(ggenie.old,0,sizeof(ggenie.old));
memset(ggenie.data,0,sizeof(ggenie.data));
memset(ggenie.addr,0,sizeof(ggenie.addr));
/* reset internal state */
memset(ggenie.regs,0,sizeof(ggenie.regs));
memset(ggenie.old,0,sizeof(ggenie.old));
memset(ggenie.data,0,sizeof(ggenie.data));
memset(ggenie.addr,0,sizeof(ggenie.addr));
}
/* Game Genie ROM is mapped at $000000-$007fff */
m68k_memory_map[0].base = ggenie.rom;
/* Game Genie ROM is mapped at $000000-$007fff */
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;
/* Internal registers are mapped at $000000-$00001f */
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;
/* Disable registers reads */
m68k_memory_map[0].read16 = NULL;
}
}
void ggenie_switch(int enable)
@ -156,71 +160,75 @@ void ggenie_switch(int enable)
}
}
/* Byte write handler */
/* Note: 2nd revision of the Game Genie software use byte writes to set register values on exit */
static void ggenie_write_byte(uint32 address, uint32 data)
static unsigned int ggenie_read_byte(unsigned int address)
{
unsigned int data = ggenie.regs[(address >> 1) & 0x1f];
return ((address & 1) ? (data & 0xff) : ((data >> 8) & 0xff));
}
static unsigned int ggenie_read_word(unsigned int address)
{
return ggenie.regs[(address >> 1) & 0x1f];
}
static void ggenie_write_byte(unsigned int address, unsigned int data)
{
/* Register offset */
uint8 offset = (address >> 1) & 0x1f;
/* Write internal register (lower or upper BYTE) */
ggenie_write_regs(offset,data,address & 1);
/* /LWR and /UWR are used to decode writes */
if (address & 1)
{
data = (ggenie.regs[offset] & 0xff00) | (data & 0xff);
}
else
{
data = (ggenie.regs[offset] & 0x00ff) | ((data & 0xff) << 8);
}
/* Update internal register */
ggenie_write_regs(offset,data);
}
/* Word write handler */
static void ggenie_write_word(uint32 address, uint32 data)
static void ggenie_write_word(unsigned int address, unsigned int data)
{
/* Register offset */
uint8 offset = (address >> 1) & 0x1f;
/* Write internal register (full WORD) */
ggenie_write_regs(offset,data,2);
ggenie_write_regs(offset,data);
}
static void ggenie_write_regs(uint8 offset, uint32 data, uint8 type)
static void ggenie_write_regs(unsigned int offset, unsigned int data)
{
/* access type */
switch (type)
{
case 0: /* upper byte write */
data = (ggenie.regs[offset] & 0x00ff) | ((data & 0xff) << 8);
break;
case 1: /* lower byte write */
data = (ggenie.regs[offset] & 0xff00) | (data & 0xff);
break;
default:
break;
}
/* update internal register */
ggenie.regs[offset] = data;
/* Mode Register */
if (offset == 0)
{
/* by default, registers are write only */
m68k_memory_map[0].read16 = NULL;
/* MODE bits */
/* MODE bit */
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;
}
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;
/* 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].read16 = ggenie_read_regs;
m68k_memory_map[0].read8 = ggenie_read_byte;
m68k_memory_map[0].read16 = ggenie_read_word;
}
}
@ -253,6 +261,11 @@ static void ggenie_write_regs(uint8 offset, uint32 data, uint8 type)
/* on real HW, address decoding would be done on each reads */
ggenie_switch(1);
}
else
{
m68k_memory_map[0].write8 = ggenie_write_byte;
m68k_memory_map[0].write16 = ggenie_write_word;
}
}
/* RESET register */
@ -261,9 +274,3 @@ static void ggenie_write_regs(uint8 offset, uint32 data, uint8 type)
ggenie.regs[1] |= 1;
}
}
static uint32 ggenie_read_regs(uint32 address)
{
return ggenie.regs[(address >> 1) & 0x1f];
}

View File

@ -28,7 +28,7 @@
/* Function prototypes */
extern void ggenie_init(void);
extern void ggenie_shutdown(void);
extern void ggenie_reset(void);
extern void ggenie_reset(int hard);
extern void ggenie_switch(int enable);
#endif

View File

@ -99,7 +99,9 @@ static void lightgun_update(int num)
{
/* External Interrupt ? */
if (reg[11] & 0x08)
irq_status = (irq_status & ~0x40) | 0x12;
{
irq_status = (irq_status & 4) | 0x12;
}
/* HV Counter Latch:
1) some games does not enable HVC latch but instead use bigger X offset
@ -107,11 +109,15 @@ static void lightgun_update(int num)
2) for games using H40 mode, the gun routine scales up the Hcounter value
--> H-Counter range is approx. 290 dot clocks
*/
hvc_latch = 0x10000 | (vctab[v_counter] << 8);
hvc_latch = 0x10000 | (v_counter << 8);
if (reg[12] & 1)
{
hvc_latch |= hc_320[((input.analog[num][0] * 290) / (2 * 320) + x_offset) % 210];
}
else
hvc_latch |= hc_256[(input.analog[num][0] / 2 + x_offset)%171];
{
hvc_latch |= hc_256[(input.analog[num][0] / 2 + x_offset) % 171];
}
}
}
}
@ -345,9 +351,9 @@ static inline unsigned int gamepad_read(int i)
/* 6buttons specific (taken from gen-hw.txt) */
/* A 6-button gamepad allows the extra buttons to be read based on how */
/* many times TH is switched from 1 to 0 (and not 0 to 1). Observe the */
/* following sequence */
/*
/* many times TH is switched from 1 to 0 (and not 0 to 1). Observe the */
/* following sequence */
/*
TH = 1 : ?1CBRLDU 3-button pad return value
TH = 0 : ?0SA00DU 3-button pad return value
TH = 1 : ?1CBRLDU 3-button pad return value

View File

@ -142,37 +142,44 @@ void gen_hardreset(void)
mcycles_68k = mcycles_z80 = (uint32)((MCYCLES_PER_LINE * lines_per_frame) * ((double)rand() / (double)RAND_MAX));
/* Z80 bus is released & Z80 is stopped */
zstate = 0;
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;
/* Reset 68k, Z80 & YM2612 */
/* Reset 68k & Z80 */
m68k_pulse_reset();
z80_reset();
YM2612ResetChip();
}
void gen_softreset(int state)
{
if (state)
{
/* Halt 68k, Z80 & YM2612 */
/* Halt 68k */
m68k_pulse_halt();
/* Z80 bus is released & Z80 is reseted */
zstate = 0;
YM2612ResetChip();
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;
/* Assume default bank is $000000-$007FFF */
zbank = 0;
/* Reset YM2612 */
fm_reset(0);
}
else
{
/* Reset PRO Action Replay (if switch is in TRAINER position) */
if (areplay_get_status() == AR_SWITCH_TRAINER)
{
areplay_reset(0);
}
/* Reset Cartridge Hardware */
cart_hw_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));
@ -180,7 +187,7 @@ void gen_softreset(int state)
/* Reset 68k, Z80 & YM2612 */
m68k_pulse_reset();
z80_reset();
YM2612ResetChip();
fm_reset(0);
}
}

View File

@ -458,9 +458,14 @@ static void gxSetAspectRatio(int *xscale, int *yscale)
{
/* vertical borders */
if (config.overscan & 1)
{
/* Genesis outputs 288(PAL) or 243(NTSC) lines */
/* Wii & Game Cube output 286/574(PAL50) or 240/480 (PAL60 & NTSC) lines */
*yscale = vdp_pal + ((gc_pal && !config.render) ? 143 : 120);
}
else
{
/* overscan is simulated (black) */
*yscale = bitmap.viewport.h / 2;
if (vdp_pal && (!gc_pal || config.render))
*yscale = *yscale * 240 / 288;
@ -470,29 +475,45 @@ static void gxSetAspectRatio(int *xscale, int *yscale)
/* horizontal borders */
if (config.overscan & 2)
*xscale = 358 + ((reg[12] & 1)*2) - gc_pal;
{
/* max visible range is ~712 pixels, not 720 */
*xscale = 356;
}
else
*xscale = 325 + ((reg[12] & 1)*2) - gc_pal;
{
/* overscan is simulated (black) */
*xscale = 327;
}
/* 16/9 correction */
if (config.aspect & 2)
{
*xscale = (*xscale * 3) / 4;
}
}
/* manual aspect ratio (default is fullscreen) */
/* manual aspect ratio (default is unscaled raw) */
else
{
/* vertical borders */
if (config.overscan & 1)
{
*yscale = (gc_pal && !config.render) ? (vdp_pal ? (268*144 / bitmap.viewport.h):143) : (vdp_pal ? (224*144 / bitmap.viewport.h):120);
}
else
{
*yscale = (gc_pal && !config.render) ? 134 : 112;
}
/* horizontal borders */
if (config.overscan & 2)
*xscale = 352;
{
*xscale = 348;
}
else
{
*xscale = 320;
}
/* add user scaling */
*xscale += config.xscale;
@ -565,9 +586,11 @@ static void gxResetScaler(u32 width)
int xshift = (config.xshift * rmode->fbWidth) / rmode->viWidth;
int yshift = (config.yshift * rmode->efbHeight) / rmode->viHeight;
/* Configure GX vertical scaling (480i/576i/480p) */
/* Double Resolution modes (480i/576i/480p) */
if (config.render)
{
yscale = yscale * 2;
}
/* Set GX scaler (Vertex Position matrix) */
square[6] = square[3] = xshift + xscale;
@ -834,7 +857,7 @@ void gxCopyScreenshot(gx_texture *texture)
GX_InvalidateTexAll();
/* scale texture to EFB width */
s32 w = bitmap.viewport.x ? 704 : 640;
s32 w = bitmap.viewport.x ? 696 : 640;
s32 h = (bitmap.viewport.h + 2*bitmap.viewport.y) * 2;
s32 x = -w/2;
s32 y = -(240+ 2*bitmap.viewport.y);

View File

@ -123,144 +123,6 @@
#ifndef _HVC_H_
#define _HVC_H_
/* V counter values for NTSC 192-line display */
const uint8 vc_ntsc_192[262] = {
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,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
/* V counter values for NTSC 224-line display */
const uint8 vc_ntsc_224[262] = {
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,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
/* V counter values for NTSC 240-line display (invalid mode) */
const uint8 vc_ntsc_240[262] = {
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,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05
};
/* V counter values for PAL 192-line display */
const uint8 vc_pal_192[313] = {
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,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2,
0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6,
0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
/* V counter values for PAL 224-line display */
const uint8 vc_pal_224[313] = {
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,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
0x00, 0x01, 0x02,
0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
/* V counter values for PAL 240-line display */
const uint8 vc_pal_240[313] = {
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,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};
/***************************************************************/
/* */
/* H-counter timings in H40 & H32 modes (starts from HINT) */
@ -276,9 +138,9 @@ const uint8 vc_pal_240[313] = {
/* */
/***************************************************************/
const uint8 cycle2hc40[3420] =
static const uint8 cycle2hc40[3420] =
{
/* end of active display (16 pixels -> 128 Mcycles) , HINT triggered , Vcounter jump */
/* end of active display (16 pixels -> 128 Mcycles) , HINT triggered , Vcounter increment */
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
@ -513,9 +375,9 @@ const uint8 cycle2hc40[3420] =
0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
};
const uint8 cycle2hc32[3420] =
static const uint8 cycle2hc32[3420] =
{
/* end of active display (16 pixels -> 160 Mcycles) , HINT triggered ? , Vcounter jump */
/* end of active display (16 pixels -> 160 Mcycles) , HINT triggered ? , Vcounter increment */
0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
@ -752,8 +614,7 @@ const uint8 cycle2hc32[3420] =
0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
};
const uint8 *vctab;
const uint8 *hctab;
static const uint8 *hctab;
#endif /* _HVC_H_ */

View File

@ -862,7 +862,7 @@ void m68k_run (unsigned int cycles)
CPU_INT_LEVEL = (irq_status & 6) << 8;
/* IRQ was triggered during previous instruction */
if (irq_status & 0x40)
if (irq_status & 0x20)
{
/* one instruction latency */
REG_IR = m68ki_read_imm_16();

View File

@ -476,8 +476,7 @@ void ctrl_io_write_word(unsigned int address, unsigned int data)
case 0x30: /* TIME */
{
cart.hw.time_w(address & 0xfe, data >> 8);
cart.hw.time_w(address, data & 0xff);
cart.hw.time_w(address, data);
return;
}

View File

@ -1754,12 +1754,7 @@ void render_line(int line)
int width = bitmap.viewport.w;
int x_offset = bitmap.viewport.x;
/* background color (blanked display or vertical borders) */
if (!(reg[1] & 0x40) || (status & 8))
{
memset(&lb[0x20 - x_offset], 0x40, width + 2*x_offset);
}
else
if ((reg[1] & 0x40) && (line < bitmap.viewport.h))
{
/* update pattern generator */
if (bg_list_index)
@ -1826,6 +1821,11 @@ void render_line(int line)
memset(&lb[0x20 + width], 0x40, x_offset);
}
}
else
{
/* background color (blanked display or vertical borders) */
memset(&lb[0x20 - x_offset], 0x40, width + 2*x_offset);
}
/* pixel color remapping */
remap_buffer(line);
@ -1833,15 +1833,12 @@ void render_line(int line)
void remap_buffer(int line)
{
/* display disabled */
if (reg[0] & 0x01) return;
int width = bitmap.viewport.w + 2*bitmap.viewport.x;
/* get line offset from framebuffer */
line = (line + bitmap.viewport.y) % lines_per_frame;
/* double resolution mode */
/* interlaced modes */
if (config.render && interlaced)
line = (line << 1) + odd_frame;

View File

@ -157,6 +157,35 @@ void sound_reset(void)
psg_cycles_count = 0;
}
int sound_context_save(uint8 *state)
{
int bufferptr = 0;
save_param(YM2612GetContextPtr(),YM2612GetContextSize());
save_param(SN76489_GetContextPtr(),SN76489_GetContextSize());
save_param(&fm_cycles_count,sizeof(fm_cycles_count));
save_param(&psg_cycles_count,sizeof(psg_cycles_count));
return bufferptr;
}
int sound_context_load(uint8 *state, char *version)
{
int bufferptr = 0;
YM2612Restore(&state[bufferptr]);
bufferptr += YM2612GetContextSize();
load_param(SN76489_GetContextPtr(),SN76489_GetContextSize());
if (version[15] > 0x30)
{
load_param(&fm_cycles_count,sizeof(fm_cycles_count));
load_param(&psg_cycles_count,sizeof(psg_cycles_count));
}
return bufferptr;
}
/* End of frame update, return the number of samples run so far. */
int sound_update(unsigned int cycles)
{

View File

@ -27,6 +27,8 @@
/* Function prototypes */
extern void sound_init(void);
extern void sound_reset(void);
extern int sound_context_save(uint8 *state);
extern int sound_context_load(uint8 *state, char *version);
extern int sound_update(unsigned int cycles);
extern void fm_reset(unsigned int cycles);
extern void fm_write(unsigned int cycles, unsigned int address, unsigned int data);

View File

@ -22,16 +22,6 @@
#include "shared.h"
#define STATE_VERSION "GENPLUS-GX 1.4.0"
#define load_param(param, size) \
memcpy(param, &state[bufferptr], size); \
bufferptr+= size;
#define save_param(param, size) \
memcpy(&state[bufferptr], param, size); \
bufferptr+= size;
int state_load(unsigned char *buffer)
{
/* buffer size */
@ -48,9 +38,10 @@ int state_load(unsigned char *buffer)
uncompress ((Bytef *)state, &outbytes, (Bytef *)(buffer + 4), inbytes);
/* version check */
char version[16];
char version[17];
load_param(version,16);
if (strncmp(version,STATE_VERSION,16))
version[16] = 0;
if (strncmp(version,STATE_VERSION,15))
{
free(state);
return -1;
@ -58,41 +49,42 @@ int state_load(unsigned char *buffer)
/* reset system */
system_reset();
m68k_memory_map[0].base = cart.base;
// GENESIS
load_param(work_ram, sizeof(work_ram));
load_param(zram, sizeof(zram));
load_param(&zstate, sizeof(zstate));
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;
}
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;
}
if (version[15] > 0x30)
{
/* extended state */
load_param(&mcycles_68k, sizeof(mcycles_68k));
load_param(&mcycles_z80, sizeof(mcycles_z80));
}
// IO
load_param(io_reg, sizeof(io_reg));
// VDP
uint8 temp_reg[0x20];
load_param(sat, sizeof(sat));
load_param(vram, sizeof(vram));
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(&irq_status, sizeof(irq_status));
vdp_restore(temp_reg);
bufferptr += vdp_context_load(&state[bufferptr], version);
// FM
YM2612Restore(&state[bufferptr]);
bufferptr+= YM2612GetContextSize();
// PSG
load_param(SN76489_GetContextPtr(),SN76489_GetContextSize());
// SOUND
bufferptr += sound_context_load(&state[bufferptr], version);
// 68000
uint16 tmp16;
@ -120,6 +112,9 @@ int state_load(unsigned char *buffer)
// Z80
load_param(&Z80, sizeof(Z80_Regs));
// Cartridge HW
bufferptr += cart_hw_context_load(&state[bufferptr], version);
free(state);
return 1;
}
@ -143,31 +138,17 @@ int state_save(unsigned char *buffer)
save_param(zram, sizeof(zram));
save_param(&zstate, sizeof(zstate));
save_param(&zbank, sizeof(zbank));
save_param(&mcycles_68k, sizeof(mcycles_68k));
save_param(&mcycles_z80, sizeof(mcycles_z80));
// IO
save_param(io_reg, sizeof(io_reg));
// VDP
save_param(sat, sizeof(sat));
save_param(vram, sizeof(vram));
save_param(cram, sizeof(cram));
save_param(vsram, sizeof(vsram));
save_param(reg, sizeof(reg));
save_param(&addr, sizeof(addr));
save_param(&addr_latch, sizeof(addr_latch));
save_param(&code, sizeof(code));
save_param(&pending, sizeof(pending));
save_param(&status, sizeof(status));
save_param(&dmafill, sizeof(dmafill));
save_param(&hint_pending, sizeof(hint_pending));
save_param(&vint_pending, sizeof(vint_pending));
save_param(&irq_status, sizeof(irq_status));
bufferptr += vdp_context_save(&state[bufferptr]);
// FM
save_param(YM2612GetContextPtr(),YM2612GetContextSize());
// PSG
save_param(SN76489_GetContextPtr(),SN76489_GetContextSize());
// SOUND
bufferptr += sound_context_save(&state[bufferptr]);
// 68000
uint16 tmp16;
@ -195,6 +176,9 @@ int state_save(unsigned char *buffer)
// Z80
save_param(&Z80, sizeof(Z80_Regs));
// Cartridge HW
bufferptr += cart_hw_context_save(&state[bufferptr]);
/* compress state file */
unsigned long inbytes = bufferptr;
unsigned long outbytes = STATE_SIZE;

View File

@ -23,7 +23,16 @@
#ifndef _STATE_H_
#define _STATE_H_
#define STATE_SIZE 0x28000
#define STATE_SIZE 0x48100
#define STATE_VERSION "GENPLUS-GX 1.4.1"
#define load_param(param, size) \
memcpy(param, &state[bufferptr], size); \
bufferptr+= size;
#define save_param(param, size) \
memcpy(&state[bufferptr], param, size); \
bufferptr+= size;
/* Function prototypes */
extern int state_load(unsigned char *buffer);

View File

@ -288,7 +288,7 @@ void system_init (void)
void system_reset (void)
{
/* Cartridge Hardware */
cart_hw_reset();
cart_hw_reset(1);
/* Genesis hardware */
gen_hardreset();
@ -317,11 +317,30 @@ void system_shutdown (void)
/****************************************************************
* Virtual Genesis Frame emulation
****************************************************************/
void system_frame (int do_skip)
{
int start = 0;
int end = 0;
int line = 0;
/* line counter */
int line = 0;
/* Z80 interrupt flag */
int zirq = 0;
/* reload H Counter */
int h_counter = reg[10];
/* reload V Counter */
v_counter = lines_per_frame - 1;
/* reset VDP FIFO */
fifo_write_cnt = 0;
fifo_lastwrite = 0;
/* reset line cycle count */
mcycles_vdp = 0;
/* update 6-Buttons & Lightguns */
input_refresh();
/* display changed during VBLANK */
if (bitmap.viewport.changed & 2)
@ -339,33 +358,27 @@ void system_frame (int do_skip)
}
/* active screen height */
if (reg[1] & 8)
{
bitmap.viewport.h = 240;
bitmap.viewport.y = (config.overscan & 1) ? (vdp_pal ? 24 : 0) : 0;
}
else
{
bitmap.viewport.h = 224;
bitmap.viewport.y = (config.overscan & 1) ? (vdp_pal ? 32 : 8) : 0;
}
bitmap.viewport.h = 224 + ((reg[1] & 8) << 1);
bitmap.viewport.y = (config.overscan & 1) * (8 - (reg[1] & 8) + vdp_pal*24);
/* active screen width */
if (reg[12] & 1)
{
bitmap.viewport.w = 320;
bitmap.viewport.x = (config.overscan & 2) ? 16 : 0;
}
else
{
bitmap.viewport.w = 256;
bitmap.viewport.x = (config.overscan & 2) ? 12 : 0;
}
bitmap.viewport.w = 256 + ((reg[12] & 1) << 6);
bitmap.viewport.x = (config.overscan & 2) * 7;
}
/* render last line of overscan */
if (!do_skip && bitmap.viewport.y)
{
render_line(v_counter);
}
/* parse first line of sprites */
object_which = 1;
if (reg[1] & 0x40)
{
parse_satb(0x80);
}
/* Z80 interrupt flag */
int zirq = 0;
/* clear VBLANK, DMA, FIFO FULL & field flags */
status &= 0xFEE5;
@ -374,142 +387,256 @@ void system_frame (int do_skip)
/* even/odd field flag (interlaced modes only) */
odd_frame ^= 1;
if (interlaced) status |= (odd_frame << 4);
/* reload HCounter */
int h_counter = reg[10];
/* reset VDP FIFO */
fifo_write_cnt = 0;
fifo_lastwrite = 0;
/* reset line cycle count */
mcycles_vdp = 0;
/* parse sprites on line zero */
object_which = 1;
if (reg[1] & 0x40) parse_satb(0x80);
/* process scanlines */
for (line = 0; line < lines_per_frame; line ++)
if (interlaced)
{
/* update VCounter */
status |= (odd_frame << 4);
}
/* update VDP DMA */
if (dma_length)
{
vdp_update_dma(0);
}
/* run 68k & Z80 */
m68k_run(MCYCLES_PER_LINE);
if (zstate == 1)
{
z80_run(MCYCLES_PER_LINE);
}
else
{
mcycles_z80 = MCYCLES_PER_LINE;
}
/* run SVP chip */
if (svp)
{
ssp1601_run(SVP_cycles);
}
/* update line cycle count */
mcycles_vdp += MCYCLES_PER_LINE;
/* Active Display */
do
{
/* update V Counter */
v_counter = line;
/* update 6-Buttons & Lightguns */
input_refresh();
/* update VDP DMA */
if (dma_length) vdp_update_dma();
/* vertical blanking */
if (status & 8)
/* H Interrupt */
if(--h_counter < 0)
{
/* render overscan */
if (!do_skip && ((line < end) || (line >= start)))
render_line(line);
if (zirq)
/* reload H Counter */
h_counter = reg[10];
/* interrupt level 4 */
hint_pending = 0x10;
if (reg[0] & 0x10)
{
/* Z80 interrupt is asserted during one exact line */
m68k_run(mcycles_vdp + 788);
if (zstate == 1) z80_run(mcycles_vdp + 788);
else mcycles_z80 = mcycles_vdp + 788;
/* clear Z80 interrupt */
z80_set_irq_line(0, CLEAR_LINE);
zirq = 0;
irq_status = (irq_status & 2) | 0x14;
}
}
/* active display */
/* update VDP DMA */
if (dma_length)
{
vdp_update_dma(mcycles_vdp);
}
/* swap sprite line buffers */
object_which ^= 1;
/* render scanline */
if (!do_skip)
{
render_line(line);
}
/* parse next line of sprites */
if ((reg[1] & 0x40) && (line < (bitmap.viewport.h - 1)))
{
parse_satb(0x81 + line);
}
/* run 68k & Z80 */
m68k_run(mcycles_vdp + MCYCLES_PER_LINE);
if (zstate == 1)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
/* H Interrupt */
if(--h_counter < 0)
{
h_counter = reg[10];
hint_pending = 0x10;
if (reg[0] & 0x10)
irq_status = (irq_status & ~0x40) | 0x14;
}
/* end of active display */
if (line == bitmap.viewport.h)
{
/* set border area */
start = lines_per_frame - bitmap.viewport.y;
end = bitmap.viewport.h + bitmap.viewport.y;
/* check viewport changes */
if (bitmap.viewport.h != bitmap.viewport.oh)
{
bitmap.viewport.oh = bitmap.viewport.h;
bitmap.viewport.changed |= 1;
}
if (bitmap.viewport.w != bitmap.viewport.ow)
{
bitmap.viewport.ow = bitmap.viewport.w;
bitmap.viewport.changed |= 1;
}
/* set VBLANK flag */
status |= 0x08;
/* render overscan */
if (!do_skip && (line < end))
render_line(line);
/* update inputs (doing this here fix 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 mcycles_z80 = mcycles_vdp + 788;
/* V Interrupt */
vint_pending = 0x20;
if (reg[1] & 0x20)
irq_status = (irq_status & ~0x40) | 0x36;
/* Z80 interrupt */
z80_set_irq_line(0, ASSERT_LINE);
zirq = 1;
}
else
{
/* swap sprite line buffers */
object_which ^= 1;
/* render scanline */
if (!do_skip)
{
render_line(line);
/* parse sprites on next line */
if ((reg[1] & 0x40) && (line < (bitmap.viewport.h - 1)))
parse_satb(0x81 + line);
}
}
mcycles_z80 = mcycles_vdp + MCYCLES_PER_LINE;
}
/* process line */
m68k_run(mcycles_vdp + MCYCLES_PER_LINE);
if (zstate == 1) z80_run(mcycles_vdp + MCYCLES_PER_LINE);
else mcycles_z80 = mcycles_vdp + MCYCLES_PER_LINE;
/* SVP chip */
if (svp) ssp1601_run(SVP_cycles);
/* run SVP chip */
if (svp)
{
ssp1601_run(SVP_cycles);
}
/* update line cycle count */
mcycles_vdp += MCYCLES_PER_LINE;
}
while (++line < bitmap.viewport.h);
/* end of active display */
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)
{
irq_status = (irq_status & 2) | 0x14;
}
}
/* overscan area */
int start = lines_per_frame - bitmap.viewport.y;
int 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;
}
/* set VBLANK flag */
status |= 0x08;
/* update VDP DMA */
if (dma_length)
{
vdp_update_dma(mcycles_vdp);
}
/* render overscan */
if (!do_skip && (line < end))
{
render_line(line);
}
/* 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
{
mcycles_z80 = mcycles_vdp + 788;
}
/* V Interrupt */
vint_pending = 0x20;
if (reg[1] & 0x20)
{
irq_status = 0x16;
}
/* Z80 interrupt */
z80_set_irq_line(0, ASSERT_LINE);
zirq = 1;
/* run 68k & Z80 */
m68k_run(mcycles_vdp + MCYCLES_PER_LINE);
if (zstate == 1)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
mcycles_z80 = mcycles_vdp + MCYCLES_PER_LINE;
}
/* run SVP chip */
if (svp)
{
ssp1601_run(SVP_cycles);
}
/* 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 (!do_skip && ((line < end) || (line >= start)))
{
render_line(line);
}
/* Z80 interrupt is asserted for one line */
if (zirq)
{
m68k_run(mcycles_vdp + 788);
if (zstate == 1)
{
z80_run(mcycles_vdp + 788);
}
else
{
mcycles_z80 = mcycles_vdp + 788;
}
/* clear Z80 interrupt */
z80_set_irq_line(0, CLEAR_LINE);
zirq = 0;
}
/* run 68k & Z80 */
m68k_run(mcycles_vdp + MCYCLES_PER_LINE);
if (zstate == 1)
{
z80_run(mcycles_vdp + MCYCLES_PER_LINE);
}
else
{
mcycles_z80 = mcycles_vdp + MCYCLES_PER_LINE;
}
/* run SVP chip */
if (svp)
{
ssp1601_run(SVP_cycles);
}
/* update line cycle count */
mcycles_vdp += MCYCLES_PER_LINE;
}
while (++line < (lines_per_frame - 1));
/* adjust cpu cycle count for next frame */
mcycles_68k -= mcycles_vdp;

View File

@ -42,16 +42,12 @@ uint8 vram[0x10000]; /* Video RAM (64Kx8) */
uint8 cram[0x80]; /* On-chip color RAM (64x9) */
uint8 vsram[0x80]; /* On-chip vertical scroll RAM (40x11) */
uint8 reg[0x20]; /* Internal VDP registers (23x8) */
uint16 addr; /* Address register */
uint16 addr_latch; /* Latched A15, A14 of address */
uint8 code; /* Code register */
uint8 pending; /* Pending write flag */
uint16 status; /* VDP status flags */
uint8 dmafill; /* next VDP Write is DMA Fill */
uint8 hint_pending; /* 0= Line interrupt is pending */
uint8 vint_pending; /* 1= Frame interrupt is pending */
uint8 irq_status; /* 68K IRQ status */
uint16 status; /* VDP status flags */
uint32 dma_length; /* DMA remaining length */
/* Global variables */
uint16 ntab; /* Name table A base address */
uint16 ntbb; /* Name table B base address */
@ -66,16 +62,16 @@ uint8 bg_pattern_cache[0x80000]; /* Cached and flipped patterns */
uint8 playfield_shift; /* Width of planes A, B (in bits) */
uint8 playfield_col_mask; /* Vertical scroll mask */
uint16 playfield_row_mask; /* Horizontal scroll mask */
uint16 v_counter; /* VDP scanline counter */
uint32 hvc_latch; /* latched HVCounter (INT2) */
uint32 dma_length; /* Current DMA remaining bytes */
int32 fifo_write_cnt; /* VDP writes fifo count */
uint32 fifo_lastwrite; /* last VDP write cycle */
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; /* 1: PAL , 0: NTSC (default) */
uint16 v_counter; /* VDP scanline counter */
uint16 lines_per_frame; /* PAL: 313 lines, NTSC: 262 lines */
int32 fifo_write_cnt; /* VDP writes fifo count */
uint32 fifo_lastwrite; /* last VDP write cycle */
uint32 hvc_latch; /* latched HVCounter (INT2) */
uint32 vc_max; /* Vertical Counter max value */
/* Tables that define the playfield layout */
@ -84,11 +80,18 @@ static const uint8 col_mask_table[] = { 0x0F, 0x1F, 0x0F, 0x3F };
static const uint16 row_mask_table[] = { 0x0FF, 0x1FF, 0x2FF, 0x3FF };
static uint8 border; /* Border color index */
static uint8 dma_type; /* DMA mode */
static uint8 dmafill; /* next VDP Write is DMA Fill */
static uint8 pending; /* Pending write flag */
static uint8 code; /* Code register */
static uint16 addr; /* Address register */
static uint16 addr_latch; /* Latched A15, A14 of address */
static uint16 fill_data; /* VRAM Fill data */
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 uint32 dma_type; /* DMA mode */
static uint32 fifo_latency; /* CPU access latency */
static int cached_write; /* 2nd part of 32-bit CTRL port write */
/* DMA Timings
@ -120,7 +123,7 @@ static uint32 fifo_latency; /* CPU access latency */
static const uint8 dma_rates[16] = {
8, 83, 9, 102, /* 68K to VRAM (1 word = 2 bytes) */
16, 167, 18, 205, /* 68K to CRAM or VSRAM */
15, 166, 17, 204, /* DMA fill */
16, 167, 18, 205, /* DMA fill (same as above, dma length is adjusted to take first write in account)*/
8, 83, 9, 102, /* DMA Copy */
};
@ -130,9 +133,9 @@ static const uint8 dma_rates[16] = {
static void fifo_update(unsigned int cycles);
static void data_w(unsigned int data);
static void reg_w(unsigned int r, unsigned int d);
static void dma_copy(void);
static void dma_vbus (void);
static void dma_fill(unsigned int data);
static void dma_copy(int length);
static void dma_vbus (int length);
static void dma_fill(int length, unsigned int data);
/*--------------------------------------------------------------------------*/
/* Init, reset, shutdown functions */
@ -141,6 +144,7 @@ void vdp_init(void)
{
/* PAL/NTSC timings */
lines_per_frame = vdp_pal ? 313: 262;
status = (status & ~1) | vdp_pal;
}
void vdp_reset(void)
@ -161,6 +165,7 @@ void vdp_reset(void)
hvc_latch = 0;
v_counter = 0;
dmafill = 0;
fill_data = 0;
dma_length = 0;
dma_endCycles = 0;
dma_type = 0;
@ -170,8 +175,11 @@ void vdp_reset(void)
fifo_write_cnt = 0;
fifo_lastwrite = 0;
fifo_latency = 190;
cached_write = -1;
status = vdp_pal | 0x0200; /* FIFO empty */
vc_max = 0xEA + 24*vdp_pal;
status = vdp_pal | 0x200; /* FIFO empty flag */
ntab = 0;
ntbb = 0;
@ -190,27 +198,18 @@ void vdp_reset(void)
memset ((char *) bg_name_list, 0, sizeof (bg_name_list));
memset ((char *) bg_pattern_cache, 0, sizeof (bg_pattern_cache));
playfield_shift = 6;
playfield_col_mask = 0x0F;
playfield_row_mask = 0x0FF;
/* reset HVC tables */
vctab = vdp_pal ? vc_pal_224 : vc_ntsc_224;
/* default HVC tables */
hctab = cycle2hc32;
/* reset display area */
/* default display area */
bitmap.viewport.w = 256;
bitmap.viewport.h = 224;
bitmap.viewport.ow = 256;
bitmap.viewport.oh = 224;
/* reset overscan area */
bitmap.viewport.x = 0;
bitmap.viewport.y = 0;
if (config.overscan & 1)
bitmap.viewport.y = vdp_pal ? 32 : 8;
if (config.overscan & 2)
bitmap.viewport.x = 12;
/* default overscan area */
bitmap.viewport.x = (config.overscan & 2) * 7;
bitmap.viewport.y = (config.overscan & 1) * (8 + 24*vdp_pal);
/* initialize registers if OS ROM is not used */
if (config.tmss == 1)
@ -226,18 +225,76 @@ void vdp_reset(void)
void vdp_shutdown(void)
{}
void vdp_restore(uint8 *vdp_regs)
int vdp_context_save(uint8 *state)
{
int i;
int bufferptr = 0;
save_param(sat, sizeof(sat));
save_param(vram, sizeof(vram));
save_param(cram, sizeof(cram));
save_param(vsram, sizeof(vsram));
save_param(reg, sizeof(reg));
save_param(&addr, sizeof(addr));
save_param(&addr_latch, sizeof(addr_latch));
save_param(&code, sizeof(code));
save_param(&pending, sizeof(pending));
save_param(&status, sizeof(status));
save_param(&dmafill, sizeof(dmafill));
save_param(&hint_pending, sizeof(hint_pending));
save_param(&vint_pending, sizeof(vint_pending));
save_param(&irq_status, sizeof(irq_status));
/* extended state */
save_param(&dma_length, sizeof(dma_length));
save_param(&dma_type, sizeof(dma_type));
save_param(&fill_data, sizeof(fill_data));
save_param(&cached_write, sizeof(cached_write));
return bufferptr;
}
int vdp_context_load(uint8 *state, char *version)
{
int i, bufferptr = 0;
uint8 temp_reg[0x20];
load_param(sat, sizeof(sat));
load_param(vram, sizeof(vram));
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(&irq_status, sizeof(irq_status));
/* extended state */
if (version[15] > 0x30)
{
load_param(&dma_length, sizeof(dma_length));
load_param(&dma_type, sizeof(dma_type));
load_param(&fill_data, sizeof(fill_data));
load_param(&cached_write, sizeof(cached_write));
}
/* restore VDP registers */
for (i=0;i<0x20;i++)
{
reg_w(i, vdp_regs[i]);
reg_w(i, temp_reg[i]);
}
/* reinitialize HVC tables */
vctab = (vdp_pal) ? ((reg[1] & 8) ? vc_pal_240 : vc_pal_224) : vc_ntsc_224;
hctab = (reg[12] & 1) ? cycle2hc40 : cycle2hc32;
vc_max = 0xEA + 24*vdp_pal;
if (reg[1] & 8)
{
vc_max += (28 - 20*vdp_pal);
}
/* restore FIFO timings */
fifo_latency = (reg[12] & 1) ? 190 : 214;
@ -256,6 +313,8 @@ void vdp_restore(uint8 *vdp_regs)
color_update(0x00, *(uint16 *)&cram[border << 1]);
for(i = 1; i < 0x40; i += 1)
color_update(i, *(uint16 *)&cram[i << 1]);
return bufferptr;
}
@ -263,66 +322,125 @@ void vdp_restore(uint8 *vdp_regs)
/* DMA update */
/*--------------------------------------------------------------------------*/
void vdp_update_dma()
void vdp_update_dma(unsigned int cycles)
{
int dma_cycles = 0;
/* update DMA timings */
unsigned int index = dma_type;
if ((status & 8) || !(reg[1] & 0x40)) index++;
if (reg[12] & 1) index += 2;
int dma_cycles;
/* DMA transfer rate (bytes per line) */
unsigned int rate = dma_rates[index];
unsigned int rate = dma_type;
if ((status & 8) || !(reg[1] & 0x40)) rate++;
if (reg[12] & 1) rate += 2;
rate = dma_rates[rate];
/* 68k cycles left */
int left_cycles = (mcycles_vdp + MCYCLES_PER_LINE) - mcycles_68k;
if (left_cycles < 0) left_cycles = 0;
/* Remaining DMA cycles */
if (status & 8)
{
/* Process DMA until the end of VBLANK */
dma_cycles = (lines_per_frame * MCYCLES_PER_LINE) - cycles;
}
else
{
/* Process DMA until the end of current line */
dma_cycles = (mcycles_vdp + MCYCLES_PER_LINE) - cycles;
}
/* DMA bytes left */
unsigned int dma_bytes = (left_cycles * rate) / MCYCLES_PER_LINE;
/* Remaining DMA bytes */
int dma_bytes = (dma_cycles * rate) / MCYCLES_PER_LINE;
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] DMA type %d (%d access/line)-> %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_length, dma_bytes, m68k_get_reg (NULL, 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, 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 (NULL, M68K_REG_PC));
#endif
/* determinate DMA length in CPU cycles */
/* Check if DMA will be finished during current line */
if (dma_length < dma_bytes)
{
/* DMA will be finished during this line */
dma_cycles = (dma_length * MCYCLES_PER_LINE) / rate;
dma_length = 0;
}
else
{
/* DMA can not be finished until next scanline */
dma_cycles = left_cycles;
dma_length -= dma_bytes;
/* Adjust remaining DMA */
dma_bytes = dma_length;
dma_cycles = (dma_bytes * MCYCLES_PER_LINE) / rate;
}
/* update 68k cycles counter */
/* Update DMA timings */
if (dma_type < 8)
{
/* 68K to VRAM, CRAM, VSRAM */
/* 68K is frozen during DMA operation */
mcycles_68k += dma_cycles;
#ifdef LOGVDP
mcycles_68k = cycles + dma_cycles;
#ifdef LOGVDP
error("-->CPU frozen for %d cycles\n", dma_cycles);
#endif
#endif
}
else
{
/* VRAM Fill or VRAM Copy */
/* set DMA end cyles count */
dma_endCycles = mcycles_68k + dma_cycles;
/* Set DMA Busy flag */
status |= 0x0002;
/* 68K is still running, set DMA end cycle */
dma_endCycles = cycles + dma_cycles;
#ifdef LOGVDP
error("-->DMA ends in %d cycles\n", dma_cycles);
#endif
}
/* set DMA Busy flag */
status |= 0x0002;
/* Process DMA */
if (dma_bytes > 0)
{
/* Update DMA length */
dma_length -= dma_bytes;
/* Select DMA operation */
switch (dma_type >> 2)
{
case 0:
case 1:
{
/* 68K to VRAM, CRAM or VSRAM */
dma_vbus(dma_bytes);
break;
}
case 2:
{
/* VRAM Fill */
if (dmafill)
{
/* process intial write */
dmafill = 0;
data_w(fill_data);
/* adjust remaining DMA length */
dma_bytes--;
/* fill MSB */
fill_data = (fill_data >> 8) & 0xff;
/* check remaining DMA length */
if (!dma_bytes) break;
}
dma_fill(dma_bytes, fill_data);
break;
}
case 3:
{
/* VRAM Copy */
dma_copy(dma_bytes);
break;
}
}
/* Check if DMA is finished */
if (!dma_length)
{
/* Reset DMA length registers */
reg[19] = reg[20] = 0;
/* Perform cached write, if any */
if (cached_write >= 0)
{
vdp_ctrl_w(cached_write);
cached_write = -1;
}
}
}
}
@ -333,6 +451,14 @@ void vdp_ctrl_w(unsigned int data)
{
if (pending == 0)
{
/* check that DMA operation was not first triggered with the same instruction */
if (dma_length)
{
/* 2nd part of 32-bit write should be done after DMA completion (Formula One, Kawasaki Superbike Challenge) */
cached_write = data;
return;
}
if ((data & 0xC000) == 0x8000)
{
/* VDP register write */
@ -364,17 +490,47 @@ void vdp_ctrl_w(unsigned int data)
{
switch (reg[23] >> 6)
{
case 2: /* VRAM fill */
dmafill = 1;
case 2:
{
/* VRAM write operation only (Williams Greatest Hits after soft reset) */
if ((code & 0x0F) == 1)
{
/* VRAM fill is triggered next time DATA port is written */
dmafill = 1;
}
break;
}
case 3: /* VRAM copy */
dma_copy();
break;
case 3:
{
/* VRAM read/write operation only */
if ((code & 0x1F) == 0x10)
{
/* retrieve DMA length */
dma_length = (reg[20] << 8 | reg[19]) & 0xFFFF;
if (!dma_length) dma_length = 0x10000;
default: /* V bus to VDP DMA */
dma_vbus();
/* VRAM copy */
dma_type = 12;
vdp_update_dma(mcycles_68k);
}
break;
}
default:
{
/* retrieve DMA length */
dma_length = (reg[20] << 8 | reg[19]) & 0xFFFF;
if (!dma_length) dma_length = 0x10000;
/* SVP transfer latency */
if (svp && !(reg[23] & 0x60)) reg[21]--;
/* 68k to VDP DMA */
dma_type = (code & 0x06) ? 4 : 0;
vdp_update_dma(mcycles_68k);
break;
}
}
}
}
@ -431,8 +587,7 @@ unsigned int vdp_ctrl_r(unsigned int cycles)
temp |= 0x08;
/* HBLANK flag (Sonic 3 and Sonic 2 "VS Modes", Lemmings 2, Mega Turrican, V.R Troopers, Gouketsuji Ichizoku, ...) */
if ((cycles % MCYCLES_PER_LINE) < 588)
temp |= 0x04;
if ((cycles % MCYCLES_PER_LINE) < 588) temp |= 0x04;
/* clear pending flag */
pending = 0;
@ -455,16 +610,25 @@ unsigned int vdp_hvc_r(unsigned int cycles)
uint8 hc = hctab[cycles%MCYCLES_PER_LINE];
/* Vertical Counter */
uint8 vc = vctab[v_counter];
int16 vc = v_counter;
/* interlace mode 2 (Sonic the Hedgehog 2, Combat Cars) */
if (im2_flag)
vc = (vc << 1) | ((vc >> 7) & 1);
/* Check counter overflow */
if (vc > vc_max) vc -= lines_per_frame;
/* Interlaced Modes */
if (interlaced)
{
/* interlace mode 2 (Sonic the Hedgehog 2, Combat Cars) */
if (im2_flag) vc = vc << 1;
/* replace bit 0 with bit 8 */
vc = (vc & ~1) | ((vc >> 8) & 1);
}
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] VDP HVC Read -> 0x%04x (%x)\n", v_counter, cycles/MCYCLES_PER_LINE, cycles, cycles%MCYCLES_PER_LINE,(vc << 8) | hc, m68k_get_reg (NULL, M68K_REG_PC));
#endif
return ((vc << 8) | hc);
return (((vc & 0xff) << 8) | hc);
}
void vdp_test_w(unsigned int data)
@ -479,9 +643,22 @@ void vdp_data_w(unsigned int data)
/* Clear pending flag */
pending = 0;
/* DMA Fill */
if (dmafill)
{
dma_fill(data);
/* save fill data */
fill_data = data;
/* retrieve DMA length */
dma_length = (reg[20] << 8 | reg[19]) & 0xFFFF;
if (!dma_length) dma_length = 0x10000;
/* adjust DMA length (first write counts for timings) */
dma_length++;
/* perform DMA */
dma_type = 8;
vdp_update_dma(mcycles_68k);
return;
}
@ -523,14 +700,14 @@ unsigned int vdp_data_r(void)
switch (code & 0x0F)
{
case 0x00: /* VRAM */
temp = *(uint16 *) & vram[(addr & 0xFFFE)];
temp = *(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, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, addr, temp, m68k_get_reg (NULL, M68K_REG_PC));
#endif
break;
case 0x08: /* CRAM */
temp = *(uint16 *) & cram[(addr & 0x7E)];
temp = *(uint16 *) &cram[(addr & 0x7E)];
temp = UNPACK_CRAM (temp);
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] CRAM 0x%x read -> 0x%x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, addr, temp, m68k_get_reg (NULL, M68K_REG_PC));
@ -538,7 +715,7 @@ unsigned int vdp_data_r(void)
break;
case 0x04: /* VSRAM */
temp = *(uint16 *) & vsram[(addr & 0x7E)];
temp = *(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, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, addr, temp, m68k_get_reg (NULL, M68K_REG_PC));
#endif
@ -569,7 +746,7 @@ int vdp_int_ack_callback(int int_level)
#endif
/* VINT triggered ? */
if (irq_status&0x20)
if ((irq_status & 6) == 6)
{
vint_pending = 0;
status &= ~0x80; /* clear VINT flag */
@ -696,7 +873,7 @@ static void data_w(unsigned int data)
color_update (0x00, data);
/* CRAM modified during HBLANK (Striker, Zero the Kamikaze, etc) */
if (!(status & 8) && (reg[1]& 0x40) && (mcycles_68k <= (mcycles_vdp + 860)))
if ((v_counter < bitmap.viewport.h) && (reg[1]& 0x40) && (mcycles_68k <= (mcycles_vdp + 860)))
{
/* remap current line */
remap_buffer(v_counter);
@ -754,9 +931,9 @@ static void reg_w(unsigned int r, unsigned int d)
if ((r & 0x10) && hint_pending)
{
/* update IRQ status */
irq_status = 0x50;
irq_status = 0x30;
if (vint_pending & reg[1])
irq_status |= 0x26;
irq_status |= 6;
else if (d & 0x10)
irq_status |= 4;
}
@ -775,7 +952,7 @@ static void reg_w(unsigned int r, unsigned int d)
if (r & 0x02)
{
if (reg[0] & 2) /* latch current HVC */
hvc_latch = 0x10000 | (vctab[v_counter] << 8) | hctab[mcycles_68k%MCYCLES_PER_LINE];
hvc_latch = 0x10000 | vdp_hvc_r(mcycles_68k);
else /* free-running HVC */
hvc_latch = 0;
}
@ -792,9 +969,9 @@ static void reg_w(unsigned int r, unsigned int d)
if ((r & 0x20) && vint_pending)
{
/* update IRQ status */
irq_status = 0x50;
irq_status = 0x30;
if (d & 0x20)
irq_status |= 0x26;
irq_status |= 6;
else if (hint_pending & reg[0])
irq_status |= 4;
}
@ -802,35 +979,29 @@ static void reg_w(unsigned int r, unsigned int d)
/* See if the viewport height has actually been changed */
if (r & 0x08)
{
/* Update V Counter table */
if (vdp_pal)
vctab = (d & 8) ? vc_pal_240 : vc_pal_224;
/* Update viewport */
if (status & 8)
if (v_counter < bitmap.viewport.h)
{
/* Update active display */
bitmap.viewport.h = 224 + ((d & 8) << 1);
bitmap.viewport.y = (config.overscan & 1) * ( 8 - (d & 8) + vdp_pal*24);
}
else
{
/* changes should be applied on next frame */
bitmap.viewport.changed |= 2;
}
else
/* update vertical counter max value (see hvc.h) */
vc_max = 0xEA + 24*vdp_pal;
if (d & 8)
{
/* Update active display */
if (d & 8)
{
bitmap.viewport.h = 240;
bitmap.viewport.y = (config.overscan & 1) ? (vdp_pal ? 24 : 0) : 0;
}
else
{
bitmap.viewport.h = 224;
bitmap.viewport.y = (config.overscan & 1) ? (vdp_pal ? 32 : 8) : 0;
}
vc_max += (28 - 20*vdp_pal);
}
}
/* Display status modified during active display (Legend of Galahad, Lemmings 2, */
/* Formula One Championship, Nigel Mansell's World Championship Racing, ...) */
if ((r & 0x40) && !(status & 8))
if ((r & 0x40) && (v_counter < bitmap.viewport.h))
{
int offset = mcycles_68k - mcycles_vdp - 860;
if (offset <= 0)
@ -914,7 +1085,7 @@ static void reg_w(unsigned int r, unsigned int d)
color_update(0x00, *(uint16 *)&cram[(d << 1)]);
/* background color modified during Horizontal Blanking (Road Rash 1,2,3)*/
if (!(status & 8) && (mcycles_68k <= (mcycles_vdp + 860)))
if ((v_counter < bitmap.viewport.h) && (mcycles_68k <= (mcycles_vdp + 860)))
{
/* remap entire line */
remap_buffer(v_counter);
@ -962,28 +1133,33 @@ static void reg_w(unsigned int r, unsigned int d)
/* Update HC table */
hctab = cycle2hc32;
/* Update fifo timings */
/* Update FIFO timings */
fifo_latency = 214;
}
/* Adjust VRAM timings */
if ((code & 0x0F) == 0x01)
{
fifo_latency = fifo_latency * 2;
}
/* Update clipping */
window_clip();
/* display width changed during HBLANK (Bugs Bunny Double Trouble) */
if (!(status & 8))
/* Display width switched during HBLANK (Bugs Bunny Double Trouble) */
if ((v_counter < bitmap.viewport.h) && (mcycles_68k <= (mcycles_vdp + 860)))
{
if (mcycles_68k <= (mcycles_vdp + 860))
{
/* redraw entire line */
render_line(v_counter);
}
}
/* Update active display */
bitmap.viewport.w = 256 + ((d & 1) << 6);
/* changes should be applied on next frame */
bitmap.viewport.changed |= 2;
/* Redraw entire line */
render_line(v_counter);
}
else
{
/* Changes should only be applied on next frame (Golden Axe III intro) */
bitmap.viewport.changed |= 2;
}
}
/* Interlaced modes */
@ -1038,20 +1214,11 @@ static void reg_w(unsigned int r, unsigned int d)
- see how source addr is affected
(can it make high source byte inc?)
*/
static void dma_copy(void)
static void dma_copy(int length)
{
int name;
unsigned int length = (reg[20] << 8 | reg[19]) & 0xFFFF;
unsigned int source = (reg[22] << 8 | reg[21]) & 0xFFFF;
if (!length)
length = 0x10000;
dma_type = 12;
dma_length = length;
vdp_update_dma();
/* proceed DMA */
do
{
vram[addr] = vram[source];
@ -1060,29 +1227,18 @@ static void dma_copy(void)
addr += reg[15];
} while (--length);
/* update length & source address registers */
reg[19] = length & 0xFF;
reg[20] = (length >> 8) & 0xFF;
/* update source address registers */
reg[21] = source & 0xFF; /* not sure */
reg[22] = (source >> 8) & 0xFF;
}
/* 68K Copy to VRAM, VSRAM or CRAM */
static void dma_vbus (void)
static void dma_vbus (int length)
{
unsigned int source = ((reg[23] & 0x7F) << 17 | reg[22] << 9 | reg[21] << 1) & 0xFFFFFE;
unsigned int base = source;
unsigned int length = (reg[20] << 8 | reg[19]) & 0xFFFF;
uint16 temp;
if (!length)
length = 0x10000;
/* DMA timings */
dma_type = (code & 0x06) ? 4 : 0;
dma_length = length;
vdp_update_dma();
/* DMA source */
if ((source >> 17) == 0x50)
{
@ -1105,7 +1261,9 @@ static void dma_vbus (void)
/* All remaining locations access work RAM */
else
{
temp = *(uint16 *)(work_ram + (source & 0xffff));
}
source += 2;
source = ((base & 0xFE0000) | (source & 0x1FFFF));
@ -1115,12 +1273,6 @@ static void dma_vbus (void)
}
else
{
/* SVP latency */
if (svp && (source < 0x400000))
{
source = (source - 2);
}
/* ROM & RAM */
do
{
@ -1132,33 +1284,16 @@ static void dma_vbus (void)
while (--length);
}
/* update length & source address registers */
reg[19] = length & 0xFF;
reg[20] = (length >> 8) & 0xFF;
/* update source address registers */
reg[21] = (source >> 1) & 0xFF;
reg[22] = (source >> 9) & 0xFF;
reg[23] = (reg[23] & 0x80) | ((source >> 17) & 0x7F);
}
/* VRAM FILL */
static void dma_fill(unsigned int data)
static void dma_fill(int length, unsigned int data)
{
int name;
unsigned int length = (reg[20] << 8 | reg[19]) & 0xFFFF;
if (!length)
length = 0x10000;
/* DMA timings */
dma_type = 8;
dma_length = length;
vdp_update_dma();
/* proceed DMA */
data_w(data);
/* write MSB */
data = (data >> 8) & 0xff;
/* intercept SAT writes */
if ((addr & sat_base_mask) == satb)
@ -1183,9 +1318,4 @@ static void dma_fill(unsigned int data)
}
while (--length);
}
/* update length register */
reg[19] = length & 0xFF;
reg[20] = (length >> 8) & 0xFF;
dmafill = 0;
}

View File

@ -30,15 +30,11 @@ extern uint8 vram[0x10000];
extern uint8 cram[0x80];
extern uint8 vsram[0x80];
extern uint8 reg[0x20];
extern uint16 addr;
extern uint16 addr_latch;
extern uint8 code;
extern uint8 pending;
extern uint16 status;
extern uint8 dmafill;
extern uint8 hint_pending;
extern uint8 vint_pending;
extern uint8 irq_status;
extern uint16 status;
extern uint32 dma_length;
/* Global variables */
extern uint16 ntab;
@ -55,8 +51,6 @@ extern uint8 playfield_shift;
extern uint8 playfield_col_mask;
extern uint16 playfield_row_mask;
extern uint16 v_counter;
extern uint32 hvc_latch;
extern uint32 dma_length;
extern int32 fifo_write_cnt;
extern uint32 fifo_lastwrite;
extern uint8 im2_flag;
@ -64,21 +58,16 @@ extern uint8 interlaced;
extern uint8 odd_frame;
extern uint8 vdp_pal;
extern uint16 lines_per_frame;
extern const uint8 vc_ntsc_224[262];
extern const uint8 vc_pal_224[313];
extern const uint8 vc_pal_240[313];
extern const uint8 cycle2hc32[3420];
extern const uint8 cycle2hc40[3420];
extern const uint8 *vctab;
extern const uint8 *hctab;
extern uint32 hvc_latch;
extern uint32 vc_max;
/* Function prototypes */
extern void vdp_init(void);
extern void vdp_reset(void);
extern void vdp_shutdown(void);
extern void vdp_restore(uint8 *vdp_regs);
extern void vdp_update_dma();
extern int vdp_context_save(uint8 *state);
extern int vdp_context_load(uint8 *state, char *version);
extern void vdp_update_dma(unsigned int cycles);
extern void vdp_ctrl_w(unsigned int data);
extern unsigned int vdp_ctrl_r(unsigned int cycles);
extern void vdp_data_w(unsigned int data);