From a4cfc2a77ada634ed4bc15eecbf3037f7abea9ba Mon Sep 17 00:00:00 2001 From: ekeeke31 Date: Sat, 4 Dec 2010 17:13:55 +0000 Subject: [PATCH] [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 --- source/cart_hw/areplay.c | 29 +-- source/cart_hw/areplay.h | 2 +- source/cart_hw/cart_hw.c | 458 +++++++++++++++++++++++++----------- source/cart_hw/cart_hw.h | 10 +- source/cart_hw/ggenie.c | 121 +++++----- source/cart_hw/ggenie.h | 2 +- source/gen_input.c | 18 +- source/genesis.c | 29 ++- source/gx/gx_video.c | 35 ++- source/hvc.h | 149 +----------- source/m68k/m68kcpu.c | 2 +- source/mem68k.c | 3 +- source/render.c | 17 +- source/sound/sound.c | 29 +++ source/sound/sound.h | 2 + source/state.c | 92 +++----- source/state.h | 11 +- source/system.c | 415 +++++++++++++++++++++------------ source/vdp.c | 492 +++++++++++++++++++++++++-------------- source/vdp.h | 25 +- 20 files changed, 1146 insertions(+), 795 deletions(-) diff --git a/source/cart_hw/areplay.c b/source/cart_hw/areplay.c index 9e0c148..4dbd424 100644 --- a/source/cart_hw/areplay.c +++ b/source/cart_hw/areplay.c @@ -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); + } } } } diff --git a/source/cart_hw/areplay.h b/source/cart_hw/areplay.h index 4c11508..64ae9a8 100644 --- a/source/cart_hw/areplay.h +++ b/source/cart_hw/areplay.h @@ -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); diff --git a/source/cart_hw/cart_hw.c b/source/cart_hw/cart_hw.c index 7d57c8d..9f57438 100644 --- a/source/cart_hw/cart_hw.c +++ b/source/cart_hw/cart_hw.c @@ -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); +} diff --git a/source/cart_hw/cart_hw.h b/source/cart_hw/cart_hw.h index 60b399d..4e31406 100644 --- a/source/cart_hw/cart_hw.h +++ b/source/cart_hw/cart_hw.h @@ -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 diff --git a/source/cart_hw/ggenie.c b/source/cart_hw/ggenie.c index e4b89fe..719a079 100644 --- a/source/cart_hw/ggenie.c +++ b/source/cart_hw/ggenie.c @@ -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]; -} - diff --git a/source/cart_hw/ggenie.h b/source/cart_hw/ggenie.h index 8c30d93..cba8290 100644 --- a/source/cart_hw/ggenie.h +++ b/source/cart_hw/ggenie.h @@ -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 diff --git a/source/gen_input.c b/source/gen_input.c index 612601b..f9ba3fb 100644 --- a/source/gen_input.c +++ b/source/gen_input.c @@ -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 diff --git a/source/genesis.c b/source/genesis.c index 427cf79..a2cb0e5 100644 --- a/source/genesis.c +++ b/source/genesis.c @@ -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); } } diff --git a/source/gx/gx_video.c b/source/gx/gx_video.c index 4543568..025f07b 100644 --- a/source/gx/gx_video.c +++ b/source/gx/gx_video.c @@ -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); diff --git a/source/hvc.h b/source/hvc.h index 649441d..45758cc 100644 --- a/source/hvc.h +++ b/source/hvc.h @@ -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_ */ diff --git a/source/m68k/m68kcpu.c b/source/m68k/m68kcpu.c index 8eedbe6..2e1b3d3 100644 --- a/source/m68k/m68kcpu.c +++ b/source/m68k/m68kcpu.c @@ -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(); diff --git a/source/mem68k.c b/source/mem68k.c index 720883f..39de9ea 100644 --- a/source/mem68k.c +++ b/source/mem68k.c @@ -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; } diff --git a/source/render.c b/source/render.c index 84cfb7b..4f65e01 100644 --- a/source/render.c +++ b/source/render.c @@ -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; diff --git a/source/sound/sound.c b/source/sound/sound.c index 9c44463..3492a94 100644 --- a/source/sound/sound.c +++ b/source/sound/sound.c @@ -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) { diff --git a/source/sound/sound.h b/source/sound/sound.h index d6b3d39..90ebc05 100644 --- a/source/sound/sound.h +++ b/source/sound/sound.h @@ -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); diff --git a/source/state.c b/source/state.c index 8405ef3..f733901 100644 --- a/source/state.c +++ b/source/state.c @@ -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; diff --git a/source/state.h b/source/state.h index 9590469..ea04009 100644 --- a/source/state.h +++ b/source/state.h @@ -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); diff --git a/source/system.c b/source/system.c index a50873a..eddaaed 100644 --- a/source/system.c +++ b/source/system.c @@ -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; diff --git a/source/vdp.c b/source/vdp.c index ffaba1b..b14b652 100644 --- a/source/vdp.c +++ b/source/vdp.c @@ -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; } diff --git a/source/vdp.h b/source/vdp.h index 695c820..6d73924 100644 --- a/source/vdp.h +++ b/source/vdp.h @@ -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);