From 2b784214022abdb66a73d41f64ff466d838ebb95 Mon Sep 17 00:00:00 2001 From: ekeeke31 Date: Sun, 24 Jan 2010 11:41:53 +0000 Subject: [PATCH] [Core] ------ * improved 68k accuracy (initial reset timing + auto-vectored interrupts handling). * modified Z80 & 68k cores to directly use external cycle count instead of intermediate counters. * improved Z80 & 68k cpu execution/synchronization accuracy, now use Master Clock as common clock reference. * improved PSG & FM chips synchronization with CPU execution (fixed point precision). * completely rewrote sound output processing & mixing: sound chips are now clocked with exact output frame rate to ensure 100% smooth video & audio playback, with no lag or skipping, while still rendering an accurate number of samples per frame. This will also make fast-forward implementation (video AND sound) more trivial. * improved color accuracy in VDP highlight mode to match results observed on real hardware. * improved sprites processing timing accuracy: fixes (un)masked sprites in Mickey Mania (3D level), Sonic 2 (VS mode). * improved horizontal blanking & HINT/VINT occurrence timing accuracy, as measured on real hardware. * improved H-Counter accuracy in 40-cell mode, as measured on real hardware. * optimized Z80 bus status signals * usual code cleanup [GCN/WII] --------- fixed ASNDLIB exit when returning to game fixed audio/video startup sync modified audio back-end engine according to new audio processing core (see above) --- HISTORY.txt | 40 ++- source/gen_input.c | 53 +-- source/genesis.c | 104 +++--- source/genesis.h | 8 +- source/gx/gui/menu.c | 109 +++++-- source/gx/gx_audio.c | 59 +--- source/gx/gx_audio.h | 2 +- source/gx/gx_video.c | 4 +- source/gx/main.c | 33 +- source/hvc.h | 613 +++++++++++++++++++++++++++-------- source/loadrom.c | 25 +- source/m68k/m68k.h | 14 +- source/m68k/m68kcpu.c | 66 ++-- source/m68k/m68kcpu.h | 22 +- source/m68k/m68kops.c | 2 +- source/mem68k.c | 141 +++++--- source/membnk.c | 41 ++- source/memz80.c | 24 +- source/render.c | 90 +++-- source/render.h | 3 + source/sound/Fir_Resampler.c | 15 +- source/sound/Fir_Resampler.h | 2 +- source/sound/sn76489.c | 4 +- source/sound/sn76489.h | 2 +- source/sound/sound.c | 252 ++++++++++---- source/sound/sound.h | 11 +- source/sound/ym2612.c | 36 +- source/sound/ym2612.h | 4 +- source/state.c | 7 +- source/system.c | 279 +++++++++------- source/system.h | 31 +- source/unused/dos/dos.c | 27 +- source/unused/win/Makefile | 2 +- source/unused/win/main.c | 27 +- source/vdp.c | 190 ++++++----- source/vdp.h | 6 +- source/z80/z80.c | 159 +++++---- source/z80/z80.h | 3 +- 38 files changed, 1579 insertions(+), 931 deletions(-) diff --git a/HISTORY.txt b/HISTORY.txt index 93b2922..4ca3d92 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -8,32 +8,56 @@ Genesis Plus GX 1.4.0 (??/??/????) (Eke-Eke) * modified SN76489 cut-off frequency * added an option to boost SN76489 Noise Channel * removed outdated Gens YM2612 core -* improved YM2612 core general accuracy (SSG-EG, CSM mode,...) (based upon Nemesis recent tests on real MD) +* improved YM2612 core general accuracy (SSG-EG, CSM mode,...) (based upon Nemesis recent tests on real hardware) * improved YM2612 LFO emulation accuracy (fixes "Spider-Man & Venom : Separation Anxiety" intro music) * fixed YM2612 context saving/loading. * added 3-Band EQ for fully configurable sound filtering (thanks to Neil C) * implemented faster FIR resampler, dropped libsamplerate support (thanks to Blargg & AamirM) -* improved VDP sprite masking emulation: fixes 3D level in Mickey Mania (thanks to Nemesis for his sprite test program) + +* improved VDP sprite masking accuracy (thanks to Nemesis for his sprite test program) +* improved HBLANK flag timing accuracy: fixes Mega Turrican (Sky level) +* added support for CRAM writes during horizontal blanking. * fixed 2-Cell vertical scrolling when column 0 is shifted. * added support for 2-Cell vertical scrolling in Interlaced 2 mode. * fixed lightgun auto detection: fixes cursor position in Lethal Enforcers II -* improved DIVU/DVIS (thanks to Jorge Cwik) & MULU/MULS 68000 instructions timing accuracy + +* improved DIVU/DVIS (thanks to Jorge Cwik) & MULU/MULS 68k instructions timing accuracy * updated Z80 core to last version (fixes interrupt Mode 0 timing and some BIT instructions) +* fixed some Z80 instructions timing + * fixed Backup Memory support in some games using serial EEPROM +* fixed Realtec mapper support: fix sound in Balloon Boy / Funny World * added Game Genie hardware emulation (Game Genie ROM is now fully supported, see README for more details) * added Action Replay hardware emulation (Action replay ROM is now fully supported, see README for more details) * added S&K "Lock-On" hardware emulation ("lock" any games to Sonic & Knuckles) * added Cartridge "hot swap" feature (swap games without reseting the virtual console) -* various code cleanup & core optimizations + +* lots of code cleanup & optimization + + +* improved 68k accuracy (initial reset timing + auto-vectored interrupts handling). +* modified Z80 & 68k cores to directly use external cycle count instead of intermediate counters. +* improved Z80 & 68k cpu execution/synchronization accuracy, now use Master Clock as common clock reference. +* improved PSG & FM chips synchronization with CPU execution (fixed point precision). + +* completely rewrote sound output processing & mixing: sound chips are now clocked with exact output framerate +to ensure 100% smooth video & audio playback, with no lag or skipping, while still rendering an accurate number +of samples per frame. This would also make fast-forward implementation (video AND sound) more trivial. + +* improved color accuracy in VDP highlight mode to match results observed on real hardware. +* improved sprites processing timing accuracy: fixes (un)masked sprites in Mickey Mania (3D level), Sonic 2 (VS mode). +* improved horizontal blanking & HINT/VINT occurence timing accuracy, as measured on real hardware. +* improved H-Counter accuraccy in 40-cell mode, as measured on real hardware. [Gamecube/Wii] -* improved audio/video synchronization: fixes video skipping issues in 60Hz modes -* fixed stability issues and some potential memory leaks +* improved audio/video synchronization (see above) +* improved reset button behavior, now works much more like the real Genesis reset button +* fixed stability issues and some memory leaks * added internal screenshot feature * improved lightgun cursors -* implemented new FONT & GUI engines: use internal IPL FONT, GX hardware & multithreading for fast rendering. -* implemented new interface: incl. IR pointing, game snapshots, menu effects, sound effects, BGM... +* new FONT & GUI engines: use internal IPL FONT, GX hardware rendering, sound support & multithreading. +* new emulator interface design: incl. IR pointing, game snapshots, menu effects, sound effects, BGM... (check the README for more details) diff --git a/source/gen_input.c b/source/gen_input.c index 52404db..58b6dbd 100644 --- a/source/gen_input.c +++ b/source/gen_input.c @@ -25,28 +25,17 @@ t_input input; -/***************************************************************************** - * LIGHTGUN specific functions - * - *****************************************************************************/ -/* H counter values for a 256-pixel wide display (342 pixel max.) */ -static const uint8 hc_256[171] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, - 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, - 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 values for a 320-pixel wide display (420 pixels max.) */ -static const uint8 hc_320[210] = { +/************************************************************************************/ +/* */ +/* H-counter values returned in H40 & H32 modes */ +/* */ +/* Inside VDP, dot counter register is 9-bit, with only upper 8 bits being returned */ +/* */ +/* The number of dots per raster line is 342 in H32 mode and 420 in H40 mode */ +/* */ +/************************************************************************************/ +static const uint8 hc_320[210] = +{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, @@ -64,6 +53,26 @@ static const uint8 hc_320[210] = { 0xFE, 0xFF }; +static const uint8 hc_256[171] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 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, + 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; + +/***************************************************************************** + * LIGHTGUN specific functions + * + *****************************************************************************/ static inline void lightgun_reset(int num) { input.analog[num][0] = bitmap.viewport.w >> 1; diff --git a/source/genesis.c b/source/genesis.c index 869afbc..abf9357 100644 --- a/source/genesis.c +++ b/source/genesis.c @@ -23,16 +23,14 @@ #include "shared.h" -uint8 bios_rom[0x10000]; /* BIOS rom */ -uint8 work_ram[0x10000]; /* 68K work RAM */ -uint8 zram[0x2000]; /* Z80 work RAM */ -uint8 zbusreq; /* /BUSREQ from Z80 */ -uint8 zreset; /* /RESET to Z80 */ -uint8 zbusack; /* /BUSACK to Z80 */ -uint8 zirq; /* /IRQ to Z80 */ -uint32 zbank; /* Address of Z80 bank window */ -uint8 gen_running; -int32 resetline; +uint8 bios_rom[0x10000]; /* OS ROM */ +uint8 work_ram[0x10000]; /* 68K RAM */ +uint8 zram[0x2000]; /* Z80 RAM */ +uint32 zirq; /* /IRQ to Z80 */ +uint32 zstate; /* Z80 bus state (d0 = BUSACK, d1 = /RESET) */ +uint32 zbank; /* Z80 bank window address */ +uint32 gen_running; /* 0: cpu are in locked state */ +int32 resetline; /* soft reset is triggered on a random line (X-Men 2, Eternal Champions) */ /*--------------------------------------------------------------------------*/ /* Init, reset, shutdown functions */ @@ -132,28 +130,24 @@ void gen_reset(uint32 hard_reset) memset (work_ram, 0x00, sizeof (work_ram)); memset (zram, 0x00, sizeof (zram)); - /* TMSS BIOS */ + /* TMSS BIOS support */ if (config.bios_enabled == 3) - { m68k_memory_map[0].base = bios_rom; - } - count_m68k = 0; - count_z80 = 0; + /* Reset CPU cycle counts */ + mcycles_68k = 0; + mcycles_z80 = 0; } - resetline = -1; /* clear !RESET */ - gen_running = 1; /* System is running */ - zreset = 0; /* Z80 is reset */ - zbusreq = 0; /* Z80 has control of the Z bus */ - zbusack = 1; /* Z80 is busy using the Z bus */ - zirq = 0; /* No interrupts occuring */ - zbank = 0; /* Assume default bank is $000000-$007FFF */ + zstate = 0; /* Z80 is reset & has control of the bus */ + zirq = 0; /* No interrupts occuring */ + zbank = 0; /* Assume default bank is $000000-$007FFF */ - /* reset CPUs */ + /* Reset CPUs */ + resetline = -1; + gen_running = 1; m68k_pulse_reset(); z80_reset(); - fm_reset(); } void gen_shutdown(void) @@ -166,74 +160,66 @@ void gen_shutdown(void) -----------------------------------------------------------------------*/ void gen_busreq_w(uint32 state) { - uint32 z80_cycles_to_run; - if (state) { - /* Bus Request */ - if (!zbusreq && zreset) + /* Bus requested */ + if (zstate == 1) { - /* Z80 stopped */ - /* z80 was ON during the last 68k cycles */ - /* we execute the appropriate number of z80 cycles */ - z80_cycles_to_run = line_z80 + ((count_m68k - line_m68k)*7)/15; - current_z80 = z80_cycles_to_run - count_z80; - if (current_z80 > 0) count_z80 += z80_execute(current_z80); + /* Z80 is stopped */ + /* Z80 was ON during the last 68k cycles */ + z80_run(mcycles_68k); } + + /* update Z80 bus status */ + zstate |= 2; } else { /* Bus released */ - if (zbusreq && zreset) + if (zstate == 3) { - /* Z80 started */ - /* z80 was OFF during the last 68k cycles */ - /* we burn the appropriate number of z80 cycles */ - z80_cycles_to_run = line_z80 + ((count_m68k - line_m68k)*7)/15; - count_z80 = z80_cycles_to_run; + /* Z80 is restarted */ + /* Z80 was OFF during the last 68k cycles */ + mcycles_z80 = mcycles_68k; } - } - zbusreq = state; - zbusack = 1 ^ (zbusreq & zreset); + /* update Z80 bus status */ + zstate &= 1; + } } void gen_reset_w(uint32 state) { - uint32 z80_cycles_to_run; - if (state) { /* stop RESET process */ - if (!zbusreq && !zreset) + if (!zstate) { - /* Z80 started */ - /* z80 was OFF during the last 68k cycles */ - /* we burn the appropriate number of z80 cycles */ - z80_cycles_to_run = line_z80 + ((count_m68k - line_m68k)*7)/15; - count_z80 = z80_cycles_to_run; + /* Z80 is restarted */ + /* Z80 was OFF during the last cycles */ + mcycles_z80 = mcycles_68k; } + + /* update Z80 bus status */ + zstate |= 1; } else { /* start RESET process */ - if (!zbusreq && zreset) + if (zstate == 1) { /* Z80 stopped */ /* z80 was ON during the last 68k cycles */ - /* we execute the appropriate number of z80 cycles */ - z80_cycles_to_run = line_z80 + ((count_m68k - line_m68k)*7)/15; - current_z80 = z80_cycles_to_run - count_z80; - if (current_z80 > 0) count_z80 += z80_execute(current_z80); + z80_run(mcycles_68k); } /* Reset Z80 & YM2612 */ z80_reset(); fm_reset(); - } - zreset = state; - zbusack = 1 ^ (zbusreq & zreset); + /* update Z80 bus status */ + zstate &= 2; + } } void gen_bank_w (uint32 state) diff --git a/source/genesis.h b/source/genesis.h index 87b9323..bc6b0e2 100644 --- a/source/genesis.h +++ b/source/genesis.h @@ -28,12 +28,10 @@ extern uint8 bios_rom[0x10000]; extern uint8 work_ram[0x10000]; extern uint8 zram[0x2000]; -extern uint8 zbusreq; -extern uint8 zbusack; -extern uint8 zreset; -extern uint8 zirq; +extern uint32 zirq; extern uint32 zbank; -extern uint8 gen_running; +extern uint32 zstate; +extern uint32 gen_running; extern int32 resetline; /* Function prototypes */ diff --git a/source/gx/gui/menu.c b/source/gx/gui/menu.c index bb8652c..a3900ae 100644 --- a/source/gx/gui/menu.c +++ b/source/gx/gui/menu.c @@ -740,9 +740,15 @@ static void soundmenu () sprintf (items[0].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF"); if (cart.romsize) { + /* save YM2612 context */ unsigned char *temp = memalign(32,YM2612GetContextSize()); if (temp) memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize()); - audio_init(48000,vdp_pal?50.0:(1000000.0/16715.0)); + + /* reinitialize audio timings */ + audio_init(snd.sample_rate,snd.frame_rate); + sound_init(); + + /* restore YM2612 context */ if (temp) { YM2612Restore(temp); @@ -923,13 +929,26 @@ static void systemmenu () /* force region & cpu mode */ set_region(); - /* reinitialize timings */ - system_init(); - memfile_autoload(config.sram_auto,-1); + /* update framerate */ + float framerate; + if (vdp_pal) + framerate = 50.0; + else + framerate = ((config.tv_mode == 0) || (config.tv_mode == 2)) ? (1000000.0/16715.0) : 60.0; + + /* save YM2612 context */ unsigned char *temp = memalign(32,YM2612GetContextSize()); if (temp) memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize()); - audio_init(48000,vdp_pal?50.0:(1000000.0/16715.0)); + + /* reinitialize all timings */ + audio_init(snd.sample_rate, framerate); + system_init(); + + /* restore SRAM */ + memfile_autoload(config.sram_auto,-1); + + /* restore YM2612 context */ if (temp) { YM2612Restore(temp); @@ -937,7 +956,7 @@ static void systemmenu () } /* reinitialize HVC tables */ - vctab = (vdp_pal) ? ((reg[1] & 8) ? vc_pal_240 : vc_pal_224) : vc_ntsc_224; + vctab = vdp_pal ? ((reg[1] & 8) ? vc_pal_240 : vc_pal_224) : vc_ntsc_224; hctab = (reg[12] & 1) ? cycle2hc40 : cycle2hc32; /* reinitialize overscan area */ @@ -963,8 +982,8 @@ static void systemmenu () sprintf (items[3].text, "System BIOS: %s", (config.bios_enabled & 1) ? "ON":"OFF"); if (cart.romsize) { - system_init (); - system_reset (); + system_init(); + system_reset(); memfile_autoload(config.sram_auto,-1); } break; @@ -984,9 +1003,9 @@ static void systemmenu () if (cart.romsize) { - system_reset (); /* clear any patches first */ - system_init (); - system_reset (); + system_reset(); /* clear any patches first */ + system_init(); + system_reset(); memfile_autoload(config.sram_auto,-1); } break; @@ -1035,8 +1054,7 @@ static void videomenu () else sprintf (items[1].text, "TV Mode: 50/60HZ"); - sprintf (items[2].text, "Bilinear Filter: %s", - config.bilinear ? " ON" : "OFF"); + sprintf (items[2].text, "Bilinear Filter: %s", config.bilinear ? " ON" : "OFF"); if (config.ntsc == 1) sprintf (items[3].text, "NTSC Filter: COMPOSITE"); @@ -1047,15 +1065,14 @@ static void videomenu () else sprintf (items[3].text, "NTSC Filter: OFF"); - sprintf (items[4].text, "Borders: %s", - config.overscan ? "ON" : "OFF"); + sprintf (items[4].text, "Borders: %s", config.overscan ? "ON" : "OFF"); if (config.aspect == 1) sprintf (items[5].text,"Aspect: ORIGINAL (4:3)"); else if (config.aspect == 2) sprintf (items[5].text, "Aspect: ORIGINAL (16:9)"); else - sprintf (items[5].text, "Aspect: SCALED"); + sprintf (items[5].text, "Aspect: SCALE"); sprintf (items[6].text, "Screen Position: (%s%02d,%s%02d)", (config.xshift < 0) ? "":"+", config.xshift, @@ -1104,20 +1121,49 @@ static void videomenu () break; case 1: /*** tv mode ***/ - if (config.render == 2) break; - config.tv_mode = (config.tv_mode + 1) % 3; - if (config.tv_mode == 0) - sprintf (items[1].text, "TV Mode: 60HZ"); - else if (config.tv_mode == 1) - sprintf (items[1].text, "TV Mode: 50HZ"); + if (config.render != 2) + { + config.tv_mode = (config.tv_mode + 1) % 3; + + /* update framerate */ + float framerate; + if (vdp_pal) + framerate = 50.0; + else + framerate = ((config.tv_mode == 0) || (config.tv_mode == 2)) ? (1000000.0/16715.0) : 60.0; + + /* save YM2612 context */ + unsigned char *temp = memalign(32,YM2612GetContextSize()); + if (temp) + memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize()); + + /* reinitialize audio timings */ + audio_init(snd.sample_rate, framerate); + sound_init(); + + /* restore YM2612 context */ + if (temp) + { + YM2612Restore(temp); + free(temp); + } + + if (config.tv_mode == 0) + sprintf (items[1].text, "TV Mode: 60HZ"); + else if (config.tv_mode == 1) + sprintf (items[1].text, "TV Mode: 50HZ"); + else + sprintf (items[1].text, "TV Mode: 50/60HZ"); + } else - sprintf (items[1].text, "TV Mode: 50/60HZ"); + { + GUI_WaitPrompt("Error","Progressive Mode is 60hz only !\n"); + } break; case 2: /*** bilinear filtering ***/ config.bilinear ^= 1; - sprintf (items[2].text, "Bilinear Filter: %s", - config.bilinear ? " ON" : "OFF"); + sprintf (items[2].text, "Bilinear Filter: %s", config.bilinear ? " ON" : "OFF"); break; case 3: /*** NTSC filter ***/ @@ -1134,8 +1180,7 @@ static void videomenu () case 4: /*** overscan emulation ***/ config.overscan ^= 1; - sprintf (items[4].text, "Overscan Color: %s", - config.overscan ? "ORIGINAL" : "BLACK"); + sprintf (items[4].text, "Borders: %s", config.overscan ? "ON" : "OFF"); break; case 5: /*** aspect ratio ***/ @@ -1189,6 +1234,10 @@ static void videomenu () (config.xshift < 0) ? "":"+", config.xshift, (config.yshift < 0) ? "":"+", config.yshift); } + else + { + GUI_WaitPrompt("Error","Please load a game first !\n"); + } break; case 7: /*** screen scaling ***/ @@ -1213,6 +1262,10 @@ static void videomenu () (config.xscale < 0) ? "":"+", config.xscale, (config.yscale < 0) ? "":"+", config.yscale); } + else + { + GUI_WaitPrompt("Error","Please load a game first !\n"); + } break; case -1: @@ -2402,8 +2455,8 @@ void MainMenu (void) GUI_DeleteMenu(m); gxClearScreen((GXColor)BLACK); gxSetScreen(); + audio_init(snd.sample_rate,snd.frame_rate); system_init(); - audio_init(48000,vdp_pal?50.0:(1000000.0/16715.0)); system_reset(); memfile_autoload(config.sram_auto,-1); quit = 1; diff --git a/source/gx/gx_audio.c b/source/gx/gx_audio.c index 9919b3e..fd21d94 100644 --- a/source/gx/gx_audio.c +++ b/source/gx/gx_audio.c @@ -25,7 +25,7 @@ #include "shared.h" /* DMA soundbuffers (required to be 32-bytes aligned) - Length is dimensionned for one frame of emulation (see below) + Length is dimensionned for one frame of emulation (800/808 samples @60hz, 960 samples@50Hz) To prevent audio clashes, we use double buffering technique: one buffer is the active DMA buffer the other one is the current work buffer (updated during frame emulation) @@ -36,15 +36,6 @@ u8 soundbuffer[2][3840] ATTRIBUTE_ALIGN(32); /* Current work soundbuffer */ u8 mixbuffer; -/* Next DMA length */ -static u32 dma_len; - -/* Current delta between output & expected sample counts */ -static int delta; - -/* Expected sample count x 100 */ -static u32 dma_sync; - /* audio DMA status */ static u8 audioStarted = 0; @@ -98,38 +89,14 @@ void gx_audio_Shutdown(void) /*** gx_audio_Update - This function is called at the end of each frame - Genesis Plus only provides sound data on completion of each frame. - DMA sync and switching ensure we never access the active DMA buffer and sound clashes never happen This function retrieves samples for the frame then set the next DMA parameters Parameters will be taken in account only when current DMA operation is over ***/ -void gx_audio_Update(void) +void gx_audio_Update(int size) { - /* current DMA length */ - u32 size = dma_len; - - /* VIDEO interrupt synchronization: we approximate next DMA length (see below) */ - /* In 50Hz mode, VSYNC period is 19967 usec which is approx 958.42 samples */ - /* In 60Hz mode, VSYNC period is 16715 usec which is approx. 802.32 samples */ - /* DMA length should be a multiple of 32 bytes so we use either 800 or 808 samples */ - if (dma_sync) - { - /* current samples delay */ - delta += (size * 100) - dma_sync; - - /* adjust next DMA length */ - if (delta < 0) dma_len = 808; - else dma_len = 800; - } - - /* retrieve audio samples */ - audio_update(size); - /* set next DMA soundbuffer */ s16 *sb = (s16 *)(soundbuffer[mixbuffer]); mixbuffer ^= 1; - size = size << 2; DCFlushRange((void *)sb, size); AUDIO_InitDMA((u32) sb, size); @@ -140,7 +107,8 @@ void gx_audio_Update(void) { audioStarted = 1; AUDIO_StartDMA(); - if (frameticker > 1) frameticker = 1; + if (frameticker > 1) + frameticker = 1; } } @@ -156,29 +124,16 @@ void gx_audio_Start(void) PauseOgg(1); StopOgg(); ASND_Pause(1); - AUDIO_StopDMA (); - AUDIO_RegisterDMACallback(NULL); + ASND_End(); audioStarted = 0; - - /* initialize default DMA length */ - /* PAL (50Hz): 20000 us period --> 960 samples/frame @48kHz */ - /* NTSC (60Hz): 16667 us period --> 800 samples/frame @48kHz */ - dma_len = vdp_pal ? 960 : 800; - dma_sync = 0; mixbuffer = 0; - delta = 0; /* reset sound buffers */ memset(soundbuffer, 0, 2 * 3840); /* By default, use audio DMA to synchronize frame emulation */ - if (gc_pal | vdp_pal) AUDIO_RegisterDMACallback(ai_callback); - - /* 60hz video mode requires synchronization with Video interrupt */ - /* VSYNC period is 16715 us which is approx. 802.32 samples */ - /* to prevent audio/video desynchronization, we approximate the exact */ - /* number of samples by changing audio DMA length on each frame */ - else dma_sync = 80232; + if (gc_pal | vdp_pal) + AUDIO_RegisterDMACallback(ai_callback); } /*** diff --git a/source/gx/gx_audio.h b/source/gx/gx_audio.h index 92938b0..1186d83 100644 --- a/source/gx/gx_audio.h +++ b/source/gx/gx_audio.h @@ -32,6 +32,6 @@ extern void gx_audio_Init(void); extern void gx_audio_Shutdown(void); extern void gx_audio_Start(void); extern void gx_audio_Stop(void); -extern void gx_audio_Update(void); +extern void gx_audio_Update(int size); #endif diff --git a/source/gx/gx_video.c b/source/gx/gx_video.c index b75ca26..cb8d912 100644 --- a/source/gx/gx_video.c +++ b/source/gx/gx_video.c @@ -1283,9 +1283,11 @@ void gx_video_Start(void) /* VSYNC callbacks */ /* in 60hz mode we use VSYNC to synchronize frame emulation */ - if (!gc_pal && !vdp_pal) VIDEO_SetPreRetraceCallback(vi_callback); + if (!gc_pal && !vdp_pal) + VIDEO_SetPreRetraceCallback(vi_callback); VIDEO_SetPostRetraceCallback(NULL); VIDEO_Flush(); + VIDEO_WaitVSync(); /* interlaced/progressive mode */ if (config.render == 2) diff --git a/source/gx/main.c b/source/gx/main.c index a278ad5..1c2f9e2 100644 --- a/source/gx/main.c +++ b/source/gx/main.c @@ -125,10 +125,20 @@ void reloadrom (int size, char *name) } else { - system_init (); /* Initialize System */ - audio_init(48000,vdp_pal?50.0:(1000000.0/16715.0)); - ClearGGCodes (); /* Clear Game Genie patches */ - system_reset (); /* System Power ON */ + /* initialize audio back-end */ + /* 60hz video mode requires synchronization with Video Interrupt. */ + /* VSYNC period is 16715 us on Wii/Gamecube (approx. 802.32 samples per frame) */ + float framerate; + if (vdp_pal) + framerate = 50.0; + else + framerate = ((config.tv_mode == 0) || (config.tv_mode == 2)) ? (1000000.0/16715.0) : 60.0; + audio_init(48000, framerate); + + /* System Power ON */ + system_init (); + ClearGGCodes (); + system_reset (); } } @@ -164,6 +174,7 @@ int main (int argc, char *argv[]) DI_Init(); #endif + int size; /* initialize hardware */ gx_video_Init(); @@ -265,9 +276,6 @@ int main (int argc, char *argv[]) /* skip frame */ frameticker-=2; system_frame (1); - - /* update audio only */ - gx_audio_Update(); } else { @@ -277,11 +285,14 @@ int main (int argc, char *argv[]) /* render frame */ system_frame (0); - - /* update video & audio */ - gx_video_Update(); - gx_audio_Update(); } + + /* retrieve audio samples */ + size = audio_update(); + + /* update video & audio */ + gx_video_Update(); + gx_audio_Update(size * 4); } return 0; diff --git a/source/hvc.h b/source/hvc.h index 727fc99..c23134b 100644 --- a/source/hvc.h +++ b/source/hvc.h @@ -261,149 +261,494 @@ uint8 vc_pal_240[313] = { 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; -/* - VDP timing for an NTSC Genesis in display mode 5. - Version 0.4 (11/29/00) +/***************************************************************/ +/* */ +/* H-counter timings in H40 & H32 modes (starts from HINT) */ +/* */ +/* There are exactly 3420 Master Clock counts per raster line. */ +/* */ +/* in H32 mode, dot clock is divided from MCLK (MCLK/10). */ +/* in H40 mode, dot clock is divided from EDCLK (EDCLK/2). */ +/* */ +/* EDCLK (external dot clock ?) is generated outside the VDP: */ +/* During HSYNC, it is oscillating between MCLK/10 and MCLK/8, */ +/* otherwise it is fixed to MCLK/8. */ +/* */ +/***************************************************************/ - by Charles MacDonald - WWW: http://cgfm2.emuviews.com +uint8 cycle2hc40[3420] = +{ + /* end of active display (16 pixels -> 128 Mcycles) , HINT triggered , Vcounter jump */ + 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, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - Unpublished work Copyright 2000 Charles MacDonald + /* right border (14 pixels -> 112 Mcycles) */ + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - Description 32-cell 40-cell - ---------------------------------------------------------------------------- - Range 00-93, E9-FF 00-B6, E4-FF - Display area 00-7F 00-9F - V counter increment 84, 85 A4, A5 - V-blanking in 86, 87 A7, A8 - V-blanking out 86, 87 A7, A8 - H-blanking in 93, E9 B2, E4 - H-blanking out 06, 07 06, 07 + /* right blanking (9 pixels -> 72 Mcycles) , VDP status HBLANK flag set */ + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, + 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, - Comma seperated values show the H counter value before an event occurs, - and then the H counter value immediately after. + /* horizontal sync (32 pixels -> 313 Mcycles) */ + 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, + 0xe6, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, + 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, + 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea, + 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, + 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, + 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee, 0xee, 0xee, + 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, + 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, + 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, + 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, + 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, + 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, + 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, + 0xf6, - These values shouldn't be considered 100% accurate, they are probably - off by one or two. + /* left blanking (32 pixels -> 259 Mcycles) */ + 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, + 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* Vertical Interrupt triggered */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, - Each H counter unit is equivalent to two pixels. + /* left border (13 pixels -> 104 Mcycles) , VDP status HBLANK flag cleared */ + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - The gaps at 93-E9 and B6-E4 are where the H counter 'jumps' ahead. - The H counter will never actually be set to the values 94-E8 or B7-E3. - Perhaps this is the horizontal retrace period. - - Interestingly enough, the timing values for the 32-cell display mode - are identical to that of the SMS. - - It would appear that in 40-cell mode, the horizontal blanking period - is shorter as the active display period takes more time. - - The V-blanking flag can also be forcibly set by disabling the display - through bit 6 of register #1. - - - -------------------------------------------------------------------------- - H counter - - Now for some additional information on the horizontal aspects of the - display, taken from the TMS9918 manual and my tests on a NTSC Genesis. - Be warned that a real SMS may have different results. - - The H counter is 9 bits, and reading it returns the upper 8 bits. This is - because a scanline consists of 342 pixels, which couldn't be represented - with an 8-bit counter. Each scanline is divided up as follows: - - Pixels H.Cnt Description - 256 : 00-7F : Active display - 15 : 80-87 : Right border - 8 : 87-8B : Right blanking - 26 : 8B-ED : Horizontal sync - 2 : ED-EE : Left blanking - 14 : EE-F5 : Color burst - 8 : F5-F9 : Left blanking - 13 : F9-FF : Left border - - Here's a description of what these areas look like: - - Active display - Where the display generated by the VDP goes. - Right border - Filled with border color from VDP register $07. - Right blanking - Filled with a light black color. (like display was blanked) - Horizontal sync - Filled with a pure black color. (like display was turned off) - Left blanking - Filled with the border color from VDP register $07. - Color burst - Filled with a dark brown/orange color. - Left blanking - Filled with a light black color. (like display was blanked) - Left border - Filled with the border color from VDP register $07. - -*/ - -uint8 cycle2hc32[488] = { - 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x8A, 0x8A, 0x8A, - 0x8B, 0x8B, 0x8B, 0x8C, 0x8C, 0x8D, 0x8D, 0x8D, 0x8E, 0x8E, 0x8E, 0x8F, 0x8F, 0x8F, 0x90, 0x90, - 0x90, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x93, 0x93, - 0xE9, 0xE9, 0xE9, 0xEA, 0xEA, 0xEA, - 0xEB, 0xEB, 0xEB, 0xEC, 0xEC, 0xEC, 0xED, 0xED, 0xED, 0xEE, 0xEE, 0xEE, 0xEF, 0xEF, 0xF0, 0xF0, - 0xF0, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, 0xF2, 0xF3, 0xF3, 0xF3, 0xF4, 0xF4, 0xF4, 0xF5, 0xF5, 0xF6, - 0xF6, 0xF6, 0xF7, 0xF7, 0xF7, 0xF8, 0xF8, 0xF8, 0xF9, 0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, - 0xFB, 0xFC, 0xFC, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, - 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, - 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, - 0x0C, 0x0C, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, - 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x17, 0x17, - 0x17, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, - 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x22, - 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x28, - 0x28, 0x29, 0x29, 0x29, 0x2A, 0x2A, 0x2A, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C, 0x2C, 0x2D, 0x2D, 0x2D, - 0x2E, 0x2E, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x33, 0x33, - 0x33, 0x34, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x39, - 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3B, 0x3B, 0x3B, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D, 0x3E, 0x3E, 0x3E, - 0x3F, 0x3F, 0x3F, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x43, 0x43, 0x44, 0x44, - 0x44, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x49, 0x49, 0x4A, - 0x4A, 0x4A, 0x4B, 0x4B, 0x4B, 0x4C, 0x4C, 0x4C, 0x4D, 0x4D, 0x4D, 0x4E, 0x4E, 0x4E, 0x4F, 0x4F, - 0x4F, 0x50, 0x50, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x55, - 0x55, 0x55, 0x56, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x5A, 0x5A, 0x5A, - 0x5B, 0x5B, 0x5B, 0x5C, 0x5C, 0x5C, 0x5D, 0x5D, 0x5E, 0x5E, 0x5E, 0x5F, 0x5F, 0x5F, 0x60, 0x60, - 0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x64, 0x64, 0x65, 0x65, 0x65, 0x66, - 0x66, 0x66, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x6A, 0x6A, 0x6A, 0x6B, 0x6B, - 0x6C, 0x6C, 0x6C, 0x6D, 0x6D, 0x6D, 0x6E, 0x6E, 0x6E, 0x6F, 0x6F, 0x6F, 0x70, 0x70, 0x70, 0x71, - 0x71, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76, - 0x77, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, 0x7C, 0x7C, - 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, - 0x82, 0x82, 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, 0x85, + /* remaining active display (304 pixels -> 2432 Mcycles) */ + 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, + 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, + 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, + 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4c, + 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d, + 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e, + 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x4f, + 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, + 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, + 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x54, + 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x56, + 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, + 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, + 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5a, + 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, + 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5e, + 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, + 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62, + 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, + 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, + 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, + 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x69, + 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, + 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, + 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6e, + 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, + 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x70, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72, + 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73, + 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x74, + 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, + 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76, 0x76, + 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, + 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7a, 0x7a, + 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, + 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 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, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, }; -uint8 cycle2hc40[488] = { - 0xA4, 0xA5, 0xA5, 0xA6, 0xA6, 0xA7, 0xA7, 0xA7, 0xA8, 0xA8, 0xA9, 0xA9, 0xAA, 0xAA, 0xAA, 0xAB, - 0xAB, 0xAC, 0xAC, 0xAD, 0xAD, 0xAD, 0xAE, 0xAE, 0xAF, 0xAF, 0xB0, 0xB0, 0xB1, 0xB1, 0xB1, 0xB2, - 0xB2, 0xB3, 0xB3, 0xB4, 0xB4, 0xB4, 0xB5, 0xB5, 0xB6, 0xB6, - 0xE4, 0xE4, 0xE4, 0xE5, 0xE5, 0xE6, 0xE6, - 0xE7, 0xE7, 0xE7, 0xE8, 0xE8, 0xE9, 0xE9, 0xEA, 0xEA, 0xEB, 0xEB, 0xEB, 0xEC, 0xEC, 0xED, 0xED, - 0xEE, 0xEE, 0xEE, 0xEF, 0xEF, 0xF0, 0xF0, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, 0xF3, 0xF3, 0xF4, 0xF4, - 0xF4, 0xF5, 0xF5, 0xF6, 0xF6, 0xF7, 0xF7, 0xF7, 0xF8, 0xF8, 0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, - 0xFB, 0xFC, 0xFC, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, - 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, - 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0E, 0x0E, 0x0F, 0x0F, 0x10, - 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x13, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15, 0x16, 0x16, 0x16, - 0x17, 0x17, 0x18, 0x18, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, - 0x1E, 0x1E, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x23, 0x24, 0x24, - 0x25, 0x25, 0x26, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, - 0x2C, 0x2C, 0x2D, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, - 0x33, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x36, 0x37, 0x37, 0x38, 0x38, 0x39, 0x39, - 0x39, 0x3A, 0x3A, 0x3B, 0x3B, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D, 0x3E, 0x3E, 0x3F, 0x3F, 0x40, 0x40, - 0x40, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43, 0x43, 0x44, 0x44, 0x45, 0x45, 0x46, 0x46, 0x46, 0x47, - 0x47, 0x48, 0x48, 0x49, 0x49, 0x4A, 0x4A, 0x4A, 0x4B, 0x4B, 0x4C, 0x4C, 0x4D, 0x4D, 0x4D, 0x4E, - 0x4E, 0x4F, 0x4F, 0x50, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52, 0x53, 0x53, 0x53, 0x54, 0x54, 0x55, - 0x55, 0x56, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58, 0x59, 0x59, 0x5A, 0x5A, 0x5A, 0x5B, 0x5B, 0x5C, - 0x5C, 0x5D, 0x5D, 0x5D, 0x5E, 0x5E, 0x5F, 0x5F, 0x60, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, 0x63, - 0x63, 0x63, 0x64, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68, 0x68, 0x69, 0x69, 0x6A, - 0x6A, 0x6A, 0x6B, 0x6B, 0x6C, 0x6C, 0x6D, 0x6D, 0x6D, 0x6E, 0x6E, 0x6F, 0x6F, 0x70, 0x70, 0x70, - 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x77, - 0x78, 0x78, 0x79, 0x79, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, - 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x81, 0x81, 0x82, 0x82, 0x83, 0x83, 0x84, 0x84, 0x84, 0x85, 0x85, - 0x86, 0x86, 0x87, 0x87, 0x87, 0x88, 0x88, 0x89, 0x89, 0x8A, 0x8A, 0x8A, 0x8B, 0x8B, 0x8C, 0x8C, - 0x8D, 0x8D, 0x8D, 0x8E, 0x8E, 0x8F, 0x8F, 0x90, 0x90, 0x90, 0x91, 0x91, 0x92, 0x92, 0x93, 0x93, - 0x94, 0x94, 0x94, 0x95, 0x95, 0x96, 0x96, 0x97, 0x97, 0x97, 0x98, 0x98, 0x99, 0x99, 0x9A, 0x9A, - 0x9A, 0x9B, 0x9B, 0x9C, 0x9C, 0x9D, 0x9D, 0x9D, 0x9E, 0x9E, 0x9F, 0x9F, 0xA0, 0xA0, 0xA1, 0xA1, - 0xA1, 0xA2, 0xA2, 0xA3, 0xA3, 0xA4, 0xA4, +uint8 cycle2hc32[3420] = +{ + /* end of active display (16 pixels -> 160 Mcycles) , HINT triggered ? , Vcounter jump */ + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 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, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + + /* right border (14 pixels -> 140 Mcycles) */ + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + + /* right blanking (9 pixels -> 90 Mcycles) , VDP status HBLANK flag set */ + 0xe9, 0xe9, 0xe9, 0xe9, + 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, + 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, + 0xea, 0xea, 0xea, 0xea, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, + 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xed, + 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, + + /* horizontal sync (26 pixels -> 260 Mcycles) */ + 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, + 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, + 0xee, 0xee, 0xee, 0xee, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, + 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf1, + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, + 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, + 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, + 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, + 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, 0xf6, + 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, + 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + + /* left blanking (24 pixels -> 240 Mcycles) */ + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + /* Vertical Interrupt triggered ? */ + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + + /* left border (13 pixels -> 130 Mcycles) , VDP status HBLANK flag cleared */ + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + + /* remaining active display (240 pixels -> 2400 Mcycles) */ + 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, + 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, + 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, + 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, + 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d, + 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, + 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, + 0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, + 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, + 0x52, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, + 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, + 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, + 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, + 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, + 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, + 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, + 0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, + 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, + 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, + 0x5e, 0x5e, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, + 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, + 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, + 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, + 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x69, + 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, + 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, + 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, + 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, + 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, + 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, + 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, + 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, + 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, + 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, + 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, + 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, + 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, + 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, + 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, + 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, }; uint8 *vctab; diff --git a/source/loadrom.c b/source/loadrom.c index c236777..68feb91 100644 --- a/source/loadrom.c +++ b/source/loadrom.c @@ -382,10 +382,27 @@ void set_region () } /* Force region setting */ - if (config.region_detect == 1) region_code = REGION_USA; - else if (config.region_detect == 2) region_code = REGION_EUROPE; - else if (config.region_detect == 3) region_code = REGION_JAPAN_NTSC; - else if (config.region_detect == 4) region_code = REGION_JAPAN_PAL; + if (config.region_detect == 1) + region_code = REGION_USA; + else if (config.region_detect == 2) + region_code = REGION_EUROPE; + else if (config.region_detect == 3) + region_code = REGION_JAPAN_NTSC; + else if (config.region_detect == 4) + region_code = REGION_JAPAN_PAL; + + /* Set VDP default mode */ + switch (region_code) + { + case REGION_EUROPE: + case REGION_JAPAN_PAL: + vdp_pal = 1; + break; + + default: + vdp_pal = 0; + break; + } } /**************************************************************************** diff --git a/source/m68k/m68k.h b/source/m68k/m68k.h index 87aa6eb..e2c7217 100644 --- a/source/m68k/m68k.h +++ b/source/m68k/m68k.h @@ -318,23 +318,25 @@ void m68k_pulse_reset(void); /* execute num_cycles worth of instructions. returns number of cycles used */ //int m68k_execute(int num_cycles); -void m68k_run (int cyc); + +/* run until global cycle count is reached */ +void m68k_run(unsigned int cycles); /* These functions let you read/write/modify the number of cycles left to run * while m68k_execute() is running. * These are useful if the 68k accesses a memory-mapped port on another device * that requires immediate processing by another CPU. */ -int m68k_cycles_run(void); /* Number of cycles run so far */ -int m68k_cycles_remaining(void); /* Number of cycles left */ -void m68k_modify_timeslice(int cycles); /* Modify cycles left */ -void m68k_end_timeslice(void); /* End timeslice now */ +//int m68k_cycles_run(void); /* Number of cycles run so far */ +//int m68k_cycles_remaining(void); /* Number of cycles left */ +//void m68k_modify_timeslice(int cycles); /* Modify cycles left */ +//void m68k_end_timeslice(void); /* End timeslice now */ /* Set the IPL0-IPL2 pins on the CPU (IRQ). * A transition from < 7 to 7 will cause a non-maskable interrupt (NMI). * Setting IRQ to 0 will clear an interrupt request. */ -//void m68k_set_irq(unsigned int int_level); +void m68k_set_irq(unsigned int int_level); /* Halt the CPU as if you pulsed the HALT pin. */ diff --git a/source/m68k/m68kcpu.c b/source/m68k/m68kcpu.c index 53aa414..81bbe1f 100644 --- a/source/m68k/m68kcpu.c +++ b/source/m68k/m68kcpu.c @@ -43,8 +43,8 @@ extern void m68040_fpu_op1(void); /* ================================= DATA ================================= */ /* ======================================================================== */ -int m68ki_initial_cycles; -int m68ki_remaining_cycles = 0; /* Number of clocks remaining */ +//int m68ki_initial_cycles; +//int m68ki_remaining_cycles = 0; /* Number of clocks remaining */ uint m68ki_tracing = 0; uint m68ki_address_space; @@ -777,10 +777,11 @@ void m68k_set_cpu_type(unsigned int cpu_type) } /* Execute a single instruction */ -INLINE int m68k_execute(void) +//INLINE int m68k_execute(void) +INLINE void m68k_execute(void) { /* Set our pool of clock cycles available */ - SET_CYCLES(0); + //SET_CYCLES(0); /* Set tracing accodring to T1. (T0 is done inside instruction) */ m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */ @@ -803,15 +804,14 @@ INLINE int m68k_execute(void) m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */ /* return how many clocks we used */ - return - GET_CYCLES(); - + //return - GET_CYCLES(); } /* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */ /* KS: Modified so that IPL* bits match with mask positions in the SR * and cleaned out remenants of the interrupt controller. */ -INLINE void m68k_set_irq(unsigned int int_level) +void m68k_set_irq(unsigned int int_level) { uint old_level = CPU_INT_LEVEL; CPU_INT_LEVEL = int_level << 8; @@ -830,50 +830,50 @@ extern void error(char *format, ...); #endif extern uint8 irq_status; -void m68k_run (int cyc) +void m68k_run (unsigned int cycles) { - int temp; + unsigned int int_level; /* Return point if we had an address error */ m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */ - while (count_m68k < cyc) + while (mcycles_68k < cycles) { + /* Make sure we're not stopped */ + if(CPU_STOPPED) + { + mcycles_68k = cycles; + return; + } + /* check interrupt updates */ if (irq_status & 0x10) { irq_status &= ~0x10; - - temp = irq_status & 6; + int_level = irq_status & 6; /* hardware latency */ if (irq_status & 0x40) - count_m68k += m68k_execute(); + m68k_execute(); #ifdef LOGVDP - error("[%d(%d)][%d(%d)] IRQ Level = %d (%d cycles)(%x)\n", v_counter, count_m68k/488, count_m68k, count_m68k%488,temp, m68ki_remaining_cycles,m68k_get_reg (NULL, M68K_REG_PC)); + error("[%d(%d)][%d(%d)] IRQ Level = %d (%x)\n", v_counter, mcycles_68k/3420, mcycles_68k, mcycles_68k%3420,int_level,m68k_get_reg (NULL, M68K_REG_PC)); #endif - /* interrupt level */ - m68k_set_irq(temp); - } + /* update IRQ level */ + CPU_INT_LEVEL = int_level << 8; + m68ki_check_interrupts(); + + if (mcycles_68k >= cycles) + return; - /* Make sure we're not stopped */ - if(CPU_STOPPED) - { - count_m68k = cyc; - REG_PPC = REG_PC; - return; } /* execute a single instruction */ - count_m68k += m68k_execute(); + m68k_execute(); } - - /* set previous PC to current PC for the next entry into the loop */ - REG_PPC = REG_PC; - } +/* int m68k_cycles_run(void) { return m68ki_initial_cycles - GET_CYCLES(); @@ -883,20 +883,22 @@ int m68k_cycles_remaining(void) { return GET_CYCLES(); } +*/ /* Change the timeslice */ +/* void m68k_modify_timeslice(int cycles) { m68ki_initial_cycles += cycles; ADD_CYCLES(cycles); } - void m68k_end_timeslice(void) { m68ki_initial_cycles = GET_CYCLES(); SET_CYCLES(0); } +*/ void m68k_init(void) { @@ -904,7 +906,7 @@ void m68k_init(void) /* The first call to this function initializes the opcode handler jump table */ if(!emulation_initialized) - { + { m68ki_build_opcode_table(); emulation_initialized = 1; } @@ -925,7 +927,7 @@ void m68k_pulse_reset(void) { /* Clear all stop levels and eat up all remaining cycles */ CPU_STOPPED = 0; - SET_CYCLES(0); + //SET_CYCLES(0); CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET; @@ -953,6 +955,8 @@ void m68k_pulse_reset(void) m68ki_jump(REG_PC); CPU_RUN_MODE = RUN_MODE_NORMAL; + + USE_CYCLES(CYC_EXCEPTION[EXCEPTION_RESET]); } /* Pulse the HALT line on the CPU */ diff --git a/source/m68k/m68kcpu.h b/source/m68k/m68kcpu.h index 3f3d08f..6ab7d6a 100644 --- a/source/m68k/m68kcpu.h +++ b/source/m68k/m68kcpu.h @@ -33,8 +33,6 @@ #include #endif /* M68K_EMULATE_ADDRESS_ERROR */ -extern unsigned int count_m68k; - /* ======================================================================== */ /* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */ /* ======================================================================== */ @@ -562,10 +560,6 @@ extern unsigned int count_m68k; if(setjmp(m68ki_aerr_trap) != 0) \ { \ m68ki_exception_address_error(); \ - if(CPU_STOPPED) \ - { \ - SET_CYCLES(0); \ - } \ } #define m68ki_check_address_error(ADDR, WRITE_MODE, FC) \ @@ -799,12 +793,15 @@ extern unsigned int count_m68k; /* ---------------------------- Cycle Counting ---------------------------- */ +/* #define ADD_CYCLES(A) m68ki_remaining_cycles += (A) #define USE_CYCLES(A) m68ki_remaining_cycles -= (A) #define SET_CYCLES(A) m68ki_remaining_cycles = A #define GET_CYCLES() m68ki_remaining_cycles #define USE_ALL_CYCLES() m68ki_remaining_cycles = 0 +*/ +#define USE_CYCLES(A) mcycles_68k += (7 * (A)) /* ----------------------------- Read / Write ----------------------------- */ @@ -917,9 +914,10 @@ typedef struct } m68ki_cpu_core; +extern unsigned int mcycles_68k; extern m68ki_cpu_core m68ki_cpu; -extern sint m68ki_remaining_cycles; +//extern sint m68ki_remaining_cycles; extern uint m68ki_tracing; extern const uint8 m68ki_shift_8_table[]; extern const uint16 m68ki_shift_16_table[]; @@ -2042,16 +2040,10 @@ INLINE void m68ki_exception_interrupt(uint int_level) m68ki_jump(new_pc); - /* Defer cycle counting until later */ - count_m68k += CYC_EXCEPTION[vector]; - -//#if !M68K_EMULATE_INT_ACK - /* Automatically clear IRQ if we are not using an acknowledge scheme */ - CPU_INT_LEVEL = 0; -//#endif /* M68K_EMULATE_INT_ACK */ + /* Update cycle count now */ + USE_CYCLES(CYC_EXCEPTION[vector]); } - /* ASG: Check for interrupts */ INLINE void m68ki_check_interrupts(void) { diff --git a/source/m68k/m68kops.c b/source/m68k/m68kops.c index e9d5fb2..2ab3a58 100644 --- a/source/m68k/m68kops.c +++ b/source/m68k/m68kops.c @@ -31065,7 +31065,7 @@ static void m68k_op_stop(void) m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ CPU_STOPPED |= STOP_LEVEL_STOP; m68ki_set_sr(new_sr); - m68ki_remaining_cycles = 0; + //m68ki_remaining_cycles = 0; return; } m68ki_exception_privilege_violation(); diff --git a/source/mem68k.c b/source/mem68k.c index 91d980a..e858b2b 100644 --- a/source/mem68k.c +++ b/source/mem68k.c @@ -68,7 +68,8 @@ void m68k_lockup_w_8 (uint32 address, uint32 data) error ("Lockup %08X = %02X (%08X)\n", address, data, m68k_get_reg (NULL, M68K_REG_PC)); #endif gen_running = config.force_dtack; - if (!gen_running) m68k_end_timeslice (); + if (!gen_running) + m68k_pulse_halt (); } void m68k_lockup_w_16 (uint32 address, uint32 data) @@ -77,7 +78,8 @@ void m68k_lockup_w_16 (uint32 address, uint32 data) error ("Lockup %08X = %04X (%08X)\n", address, data, m68k_get_reg (NULL, M68K_REG_PC)); #endif gen_running = config.force_dtack; - if (!gen_running) m68k_end_timeslice (); + if (!gen_running) + m68k_pulse_halt (); } uint32 m68k_lockup_r_8 (uint32 address) @@ -86,7 +88,8 @@ uint32 m68k_lockup_r_8 (uint32 address) error ("Lockup %08X.b (%08X)\n", address, m68k_get_reg (NULL, M68K_REG_PC)); #endif gen_running = config.force_dtack; - if (!gen_running) m68k_end_timeslice (); + if (!gen_running) + m68k_pulse_halt (); return -1; } @@ -96,7 +99,8 @@ uint32 m68k_lockup_r_16 (uint32 address) error ("Lockup %08X.w (%08X)\n", address, m68k_get_reg (NULL, M68K_REG_PC)); #endif gen_running = config.force_dtack; - if (!gen_running) m68k_end_timeslice (); + if (!gen_running) + m68k_pulse_halt (); return -1; } @@ -111,28 +115,32 @@ static int pico_page[7] = {0x00,0x01,0x03,0x07,0x0F,0x1F,0x3F}; uint32 eeprom_read_byte(uint32 address) { - if (address == eeprom.type.sda_out_adr) return eeprom_read(address, 0); - else return READ_BYTE(cart.rom, address); + if (address == eeprom.type.sda_out_adr) + return eeprom_read(address, 0); + return READ_BYTE(cart.rom, address); } uint32 eeprom_read_word(uint32 address) { - if (address == (eeprom.type.sda_out_adr & 0xfffffe)) return eeprom_read(address, 1); - else return *(uint16 *)(cart.rom + address); + if (address == (eeprom.type.sda_out_adr & 0xfffffe)) + return eeprom_read(address, 1); + return *(uint16 *)(cart.rom + address); } void eeprom_write_byte(uint32 address, uint32 data) { if ((address == eeprom.type.sda_in_adr) || (address == eeprom.type.scl_adr)) eeprom_write(address, data, 0); - else m68k_unused_8_w(address, data); + else + m68k_unused_8_w(address, data); } void eeprom_write_word(uint32 address, uint32 data) { if ((address == (eeprom.type.sda_in_adr&0xfffffe)) || (address == (eeprom.type.scl_adr&0xfffffe))) eeprom_write(address, data, 1); - else m68k_unused_16_w (address, data); + else + m68k_unused_16_w (address, data); } @@ -140,16 +148,19 @@ void eeprom_write_word(uint32 address, uint32 data) uint32 z80_read_byte(uint32 address) { - if (zbusack) return m68k_read_bus_8(address); + /* Z80 bus is available ? */ + if (zstate ^ 3) + return m68k_read_bus_8(address); switch ((address >> 13) & 3) { case 2: /* YM2612 */ - return fm_read(0, address & 3); + return fm_read(mcycles_68k, address & 3); case 3: /* MISC */ - if ((address & 0xff00) == 0x7f00) return m68k_lockup_r_8(address); /* VDP */ - else return (m68k_read_bus_8(address) | 0xff); + if ((address & 0xff00) == 0x7f00) + return m68k_lockup_r_8(address); /* VDP */ + return (m68k_read_bus_8(address) | 0xff); default: /* ZRAM */ return zram[address & 0x1fff]; @@ -158,19 +169,22 @@ uint32 z80_read_byte(uint32 address) uint32 z80_read_word(uint32 address) { - if (zbusack) return m68k_read_bus_16(address); + /* Z80 bus is available ? */ + if (zstate ^ 3) + return m68k_read_bus_16(address); switch ((address >> 13) & 3) { case 2: /* YM2612 */ { - int temp = fm_read(0, address & 3); + int temp = fm_read(mcycles_68k, address & 3); return (temp << 8 | temp); } case 3: /* MISC */ - if ((address & 0xff00) == 0x7f00) return m68k_lockup_r_16(address); /* VDP */ - else return (m68k_read_bus_16(address) | 0xffff); + if ((address & 0xff00) == 0x7f00) + return m68k_lockup_r_16(address); /* VDP */ + return (m68k_read_bus_16(address) | 0xffff); default: /* ZRAM */ { @@ -182,7 +196,8 @@ uint32 z80_read_word(uint32 address) void z80_write_byte(uint32 address, uint32 data) { - if (zbusack) + /* Z80 bus is available ? */ + if (zstate ^ 3) { m68k_unused_8_w(address, data); return; @@ -191,7 +206,7 @@ void z80_write_byte(uint32 address, uint32 data) switch ((address >> 13) & 3) { case 2: /* YM2612 */ - fm_write(0, address & 3, data); + fm_write(mcycles_68k, address & 3, data); return; case 3: @@ -212,15 +227,15 @@ void z80_write_byte(uint32 address, uint32 data) default: /* ZRAM */ zram[address & 0x1fff] = data; - count_m68k++; /* Z80 bus latency (Pacman 2: New Adventures) */ + mcycles_68k+=8; /* Z80 bus latency (Pacman 2: New Adventures) */ return; } } void z80_write_word(uint32 address, uint32 data) { - /* Z80 still hold the bus ? */ - if (zbusack) + /* Z80 bus is available ? */ + if (zstate ^ 3) { m68k_unused_16_w(address, data); return; @@ -229,7 +244,7 @@ void z80_write_word(uint32 address, uint32 data) switch ((address >> 13) & 3) { case 2: /* YM2612 */ - fm_write (0, address & 3, data >> 8); + fm_write (mcycles_68k, address & 3, data >> 8); return; case 3: @@ -262,17 +277,21 @@ uint32 ctrl_io_read_byte(uint32 address) switch ((address >> 8) & 0xff) { case 0x00: /* I/O chip */ - if (address & 0xe0) return m68k_read_bus_8(address); - else return (io_read((address >> 1) & 0x0f)); + if (address & 0xe0) + return m68k_read_bus_8(address); + return (io_read((address >> 1) & 0x0f)); case 0x11: /* BUSACK */ - if (address & 1) return m68k_read_bus_8(address); - else return ((m68k_read_pcrelative_8(REG_PC) & 0xfe) | zbusack); + if (address & 1) + return m68k_read_bus_8(address); + if (zstate ^ 3) + return (m68k_read_pcrelative_8(REG_PC) | 0x01); + return (m68k_read_pcrelative_8(REG_PC) & 0xfe); case 0x30: /* TIME */ if (cart.hw.time_r) return ((address & 1) ? (cart.hw.time_r(address) & 0xff) : (cart.hw.time_r(address) >> 8)); - else return m68k_read_bus_8(address); + return m68k_read_bus_8(address); case 0x10: /* MEMORY MODE */ case 0x12: /* RESET */ @@ -294,23 +313,28 @@ uint32 ctrl_io_read_word(uint32 address) { case 0x00: /* I/O chip */ { - if (address & 0xe0) return m68k_read_bus_16(address); + if (address & 0xe0) + return m68k_read_bus_16(address); int temp = io_read((address >> 1) & 0x0f); return (temp << 8 | temp); } case 0x11: /* BUSACK */ - return ((m68k_read_pcrelative_16(REG_PC) & 0xfeff) | (zbusack << 8)); + if (zstate ^ 3) + return (m68k_read_pcrelative_16(REG_PC) | 0x100); + return (m68k_read_pcrelative_16(REG_PC) & 0xfeff); case 0x30: /* TIME */ - if (cart.hw.time_r) return cart.hw.time_r(address); - else return m68k_read_bus_16(address); + if (cart.hw.time_r) + return cart.hw.time_r(address); + return m68k_read_bus_16(address); case 0x50: /* SVP */ if (svp) { - if ((address & 0xfd) == 0) return svp->ssp1601.gr[SSP_XST].h; - else if ((address & 0xff) == 4) + if ((address & 0xfd) == 0) + return svp->ssp1601.gr[SSP_XST].h; + if ((address & 0xff) == 4) { uint32 temp = svp->ssp1601.gr[SSP_PM0].h; svp->ssp1601.gr[SSP_PM0].h &= ~1; @@ -337,18 +361,24 @@ void ctrl_io_write_byte(uint32 address, uint32 data) switch ((address >> 8) & 0xff) { case 0x00: /* I/O chip */ - if ((address & 0xe1) == 0x01) io_write((address >> 1) & 0x0f, data); /* get /LWR only */ - else m68k_unused_8_w(address, data); + if ((address & 0xe1) == 0x01) + io_write((address >> 1) & 0x0f, data); /* get /LWR only */ + else + m68k_unused_8_w(address, data); return; case 0x11: /* BUSREQ */ - if (address & 1) m68k_unused_8_w(address, data); - else gen_busreq_w(data & 1); + if (address & 1) + m68k_unused_8_w(address, data); + else + gen_busreq_w(data & 1); return; case 0x12: /* RESET */ - if (address & 1) m68k_unused_8_w(address, data); - else gen_reset_w(data & 1); + if (address & 1) + m68k_unused_8_w(address, data); + else + gen_reset_w(data & 1); return; case 0x30: /* TIME */ @@ -368,7 +398,10 @@ void ctrl_io_write_byte(uint32 address, uint32 data) memset(cart.rom, 0xff, cart.romsize); } } - else m68k_unused_8_w (address, data); + else + { + m68k_unused_8_w (address, data); + } return; case 0x10: /* MEMORY MODE */ @@ -390,8 +423,10 @@ void ctrl_io_write_word(uint32 address, uint32 data) switch ((address >> 8) & 0xff) { case 0x00: /* I/O chip */ - if (address & 0xe0) m68k_unused_16_w (address, data); - else io_write ((address >> 1) & 0x0f, data & 0xff); + if (address & 0xe0) + m68k_unused_16_w (address, data); + else + io_write ((address >> 1) & 0x0f, data & 0xff); return; case 0x11: /* BUSREQ */ @@ -405,7 +440,10 @@ void ctrl_io_write_word(uint32 address, uint32 data) case 0x50: /* SVP REGISTERS */ if (svp) { - if (address & 0xfd) m68k_unused_16_w(address, data); + if (address & 0xfd) + { + m68k_unused_16_w(address, data); + } else { /* just guessing here (Notaz) */ @@ -414,7 +452,10 @@ void ctrl_io_write_word(uint32 address, uint32 data) svp->ssp1601.emu_status &= ~SSP_WAIT_PM0; } } - else m68k_unused_16_w (address, data); + else + { + m68k_unused_16_w (address, data); + } return; case 0x30: /* TIME */ @@ -523,8 +564,10 @@ void vdp_write_byte(uint32 address, uint32 data) case 0x10: /* PSG */ case 0x14: - if (address & 1) psg_write(0, data); - else m68k_unused_8_w(address, data); + if (address & 1) + psg_write(mcycles_68k, data); + else + m68k_unused_8_w(address, data); return; case 0x18: /* Unused */ @@ -555,7 +598,7 @@ void vdp_write_word(uint32 address, uint32 data) case 0x10: /* PSG */ case 0x14: - psg_write(0, data & 0xff); + psg_write(mcycles_68k, data & 0xff); return; case 0x18: /* Unused */ diff --git a/source/membnk.c b/source/membnk.c index 2f02eb9..b6d048f 100644 --- a/source/membnk.c +++ b/source/membnk.c @@ -65,17 +65,19 @@ uint32 zbank_read_ctrl_io(uint32 address) switch ((address >> 8) & 0xff) { case 0x00: /* I/O chip */ - if (address & 0xe0) return zbank_unused_r(address); - else return (io_read((address >> 1) & 0x0f)); + if (address & 0xe0) + return zbank_unused_r(address); + return (io_read((address >> 1) & 0x0f)); case 0x11: /* BUSACK */ - if (address & 1) return zbank_unused_r(address); - else return (0xfe | zbusack); + if (address & 1) + return zbank_unused_r(address); + return 0xff; case 0x30: /* TIME */ if (cart.hw.time_r) return ((address & 1) ? (cart.hw.time_r(address) & 0xff) : (cart.hw.time_r(address) >> 8)); - else return zbank_unused_r(address); + return zbank_unused_r(address); case 0x10: /* MEMORY MODE */ case 0x12: /* RESET */ @@ -96,18 +98,24 @@ void zbank_write_ctrl_io(uint32 address, uint32 data) switch ((address >> 8) & 0xff) { case 0x00: /* I/O chip */ - if ((address & 0xe1) == 0x01) io_write((address >> 1) & 0x0f, data); /* get /LWR only */ - else zbank_unused_w(address, data); + if ((address & 0xe1) == 0x01) + io_write((address >> 1) & 0x0f, data); /* get /LWR only */ + else + zbank_unused_w(address, data); return; case 0x11: /* BUSREQ */ - if (address & 1) zbank_unused_w(address, data); - else gen_busreq_w(data & 1); + if (address & 1) + zbank_unused_w(address, data); + else + gen_busreq_w(data & 1); return; case 0x12: /* RESET */ - if (address & 1) zbank_unused_w(address, data); - else gen_reset_w(data & 1); + if (address & 1) + zbank_unused_w(address, data); + else + gen_reset_w(data & 1); return; case 0x30: /* TIME */ @@ -127,7 +135,10 @@ void zbank_write_ctrl_io(uint32 address, uint32 data) memset(cart.rom, 0xff, cart.romsize); } } - else zbank_unused_w (address, data); + else + { + zbank_unused_w (address, data); + } return; case 0x10: /* MEMORY MODE */ @@ -195,8 +206,10 @@ void zbank_write_vdp(uint32 address, uint32 data) case 0x10: /* PSG */ case 0x14: - if (address & 1) psg_write(1, data); - else zbank_unused_w(address, data); + if (address & 1) + psg_write(mcycles_z80, data); + else + zbank_unused_w(address, data); return; case 0x18: /* Unused */ diff --git a/source/memz80.c b/source/memz80.c index fedea44..df4b628 100644 --- a/source/memz80.c +++ b/source/memz80.c @@ -109,8 +109,10 @@ static inline void z80_vdp_w(unsigned int address, unsigned int data) case 0x10: /* PSG */ case 0x14: - if (address & 1) psg_write(1, data); - else z80_unused_w(address, data); + if (address & 1) + psg_write(mcycles_z80, data); + else + z80_unused_w(address, data); return; case 0x18: /* Unused */ @@ -139,18 +141,20 @@ unsigned int cpu_readmem16(unsigned int address) return zram[address & 0x1fff]; case 2: /* YM2612 */ - return fm_read(1, address & 3); + return fm_read(mcycles_68k, address & 3); case 3: /* VDP */ - if ((address >> 8) == 0x7f) return z80_vdp_r (address); + if ((address >> 8) == 0x7f) + return z80_vdp_r (address); return z80_unused_r(address); default: /* V-bus bank */ { address = zbank | (address & 0x7fff); int slot = address >> 16; - if (zbank_memory_map[slot].read) return (*zbank_memory_map[slot].read)(address); - else return READ_BYTE(m68k_memory_map[slot].base, address&0xffff); + if (zbank_memory_map[slot].read) + return (*zbank_memory_map[slot].read)(address); + return READ_BYTE(m68k_memory_map[slot].base, address&0xffff); } } } @@ -166,7 +170,7 @@ void cpu_writemem16(unsigned int address, unsigned int data) return; case 2: /* YM2612 */ - fm_write(1, address & 3, data); + fm_write(mcycles_z80, address & 3, data); return; case 3: /* Bank register and VDP */ @@ -190,8 +194,10 @@ void cpu_writemem16(unsigned int address, unsigned int data) { address = zbank | (address & 0x7fff); int slot = address >> 16; - if (zbank_memory_map[slot].write) (*zbank_memory_map[slot].write)(address, data); - else WRITE_BYTE(m68k_memory_map[slot].base, address&0xffff, data); + if (zbank_memory_map[slot].write) + (*zbank_memory_map[slot].write)(address, data); + else + WRITE_BYTE(m68k_memory_map[slot].base, address&0xffff, data); return; } } diff --git a/source/render.c b/source/render.c index 8e437cf..c87f199 100644 --- a/source/render.c +++ b/source/render.c @@ -307,17 +307,20 @@ static __inline__ void WRITE_LONG(void *address, uint32 data) } -/**************************************************/ -/* Pixel creation macros */ -/* Input is four bits each (R,G,B), 12 bits total */ -/* Color range depends on the S/TE mode: */ -/* */ -/* normal mode : xxx0 (0-14) */ -/* shadow mode : 0xxx (0-7) */ -/* highlight mode: 1xxx - 1 (7-14) */ -/* */ -/* with xxx0 = original 4-bits CRAM value */ -/**************************************************/ +/************************************************/ +/* Pixel creation macros */ +/* each R,G,B color channel is 4-bits with a */ +/* total of 15 different intensity levels. */ +/* */ +/* Color intensity depends on the S/TE mode: */ +/* */ +/* normal : xxx0 (0-14) */ +/* shadow : 0xxx (0-7) */ +/* highlight: 1xxx - 1 (7-14) */ +/* */ +/* with xxx0 = original 4-bits CRAM value */ +/* */ +/************************************************/ #ifndef NGC /* 8:8:8 RGB */ @@ -330,7 +333,8 @@ static __inline__ void WRITE_LONG(void *address, uint32 data) #endif /* 5:6:5 RGB */ -#define MAKE_PIXEL_16(r,g,b) ((r) << 12 | (g) << 7 | (b) << 1) +/* 4-bit color intensity is dithered to match 5-bit or 6-bit equivalent */ +#define MAKE_PIXEL_16(r,g,b) ((r) << 12 | ((r) >> 3) << 11 | (g) << 7 | ((g) >> 2) << 5 | (b) << 1 | (b) >> 3) /* Clip data */ static clip_t clip[2]; @@ -383,7 +387,7 @@ static uint8 ntb_buf[0x200]; /* Plane B line buffer */ static uint8 obj_buf[0x200]; /* Object layer line buffer */ /* Sprite line buffer data */ -static uint32 object_index_count; +uint32 object_index_count; /*--------------------------------------------------------------------------*/ /* Look-up table functions (handles priority between layers pixels) */ @@ -1505,8 +1509,9 @@ static void render_obj(uint32 line, uint8 *buf, uint8 *table) { xpos = object_info[count].xpos & 0x1ff; - /* sprite masking (ignore the 1st sprite) */ - if (xpos) spr_over = 1; + /* sprite masking (requires at least one sprite with xpos > 0) */ + if (xpos) + spr_over = 1; else if (spr_over) { spr_over = 0; @@ -1517,7 +1522,7 @@ static void render_obj(uint32 line, uint8 *buf, uint8 *table) width = sizetab[(size >> 2) & 3]; /* update pixel count (off-screen sprites included) */ - pixelcount += xpos ? width : (width * 2); + pixelcount += width; if(((xpos + width) >= left) && (xpos < right) && !mask) { @@ -1595,8 +1600,9 @@ static void render_obj_im2(uint32 line, uint32 odd, uint8 *buf, uint8 *table) { xpos = object_info[count].xpos & 0x1ff; - /* sprite masking (ignore the 1st sprite) */ - if (xpos) spr_over = 1; + /* sprite masking (requires at least one sprite with xpos > 0) */ + if (xpos) + spr_over = 1; else if(spr_over) { spr_over = 0; @@ -1607,7 +1613,7 @@ static void render_obj_im2(uint32 line, uint32 odd, uint8 *buf, uint8 *table) width = sizetab[(size >> 2) & 3]; /* update pixel count (off-screen sprites included) */ - pixelcount += xpos ? width : (width * 2); + pixelcount += width; if(((xpos + width) >= left) && (xpos < right) && !mask) { @@ -1629,14 +1635,16 @@ static void render_obj_im2(uint32 line, uint32 odd, uint8 *buf, uint8 *table) /* number of tiles to draw */ /* adjusted for sprite limit */ - if (pixelcount > bitmap.viewport.w) width -= (pixelcount - bitmap.viewport.w); + if (pixelcount > bitmap.viewport.w) + width -= (pixelcount - bitmap.viewport.w); width >>= 3; for(column = 0; column < width; column += 1, lb+=8) { index = (name + s[column]) & 0x3ff; offs = index << 7 | attr_mask << 6 | v_line; - if(attr & 0x1000) offs ^= 0x40; + if(attr & 0x1000) + offs ^= 0x40; src = &bg_pattern_cache[offs]; DRAW_SPRITE_TILE; } @@ -1662,9 +1670,11 @@ void render_init(void) int bx, ax, i; /* Allocate and align pixel look-up tables */ - if (lut_base == NULL) lut_base = malloc ((LUT_MAX * LUT_SIZE) + LUT_SIZE); + if (lut_base == NULL) + lut_base = malloc ((LUT_MAX * LUT_SIZE) + LUT_SIZE); lut[0] = (uint8 *) (((uint32) lut_base + LUT_SIZE) & ~(LUT_SIZE - 1)); - for (i = 1; i < LUT_MAX; i += 1) lut[i] = lut[0] + (i * LUT_SIZE); + for (i = 1; i < LUT_MAX; i += 1) + lut[i] = lut[0] + (i * LUT_SIZE); /* Make pixel look-up table data */ for (bx = 0; bx < 0x100; bx += 1) @@ -1722,7 +1732,8 @@ void render_reset(void) void render_shutdown(void) { - if(lut_base) free(lut_base); + if(lut_base) + free(lut_base); } @@ -1736,7 +1747,8 @@ void render_line(uint32 line, uint32 overscan) uint32 x_offset = bitmap.viewport.x; /* display OFF */ - if (reg[0] & 0x01) return; + if (reg[0] & 0x01) + return; /* background color (blanked display or vertical borders) */ if (!(reg[1] & 0x40) || overscan) @@ -1761,28 +1773,32 @@ void render_line(uint32 line, uint32 overscan) uint32 odd = odd_frame; /* render BG layers */ - if(reg[11] & 4) render_bg_im2_vs(line, width, odd); - else render_bg_im2(line, width, odd); + if(reg[11] & 4) + render_bg_im2_vs(line, width, odd); + else + render_bg_im2(line, width, odd); if (reg[12] & 8) { /* Shadow & Highlight */ merge(&nta_buf[0x20], &ntb_buf[0x20], &bg_buf[0x20], lut[2], width); memset(&obj_buf[0x20], 0, width); - if (object_index_count) render_obj_im2(line, odd, obj_buf, lut[3]); + render_obj_im2(line, odd, obj_buf, lut[3]); merge(&obj_buf[0x20], &bg_buf[0x20], &lb[0x20], lut[4], width); } else { merge(&nta_buf[0x20], &ntb_buf[0x20], &lb[0x20], lut[0], width); - if (object_index_count) render_obj_im2(line, odd, lb, lut[1]); + render_obj_im2(line, odd, lb, lut[1]); } } else { /* render BG layers */ - if(reg[11] & 4) render_bg_vs(line, width); - else render_bg(line, width); + if(reg[11] & 4) + render_bg_vs(line, width); + else + render_bg(line, width); if(reg[12] & 8) { @@ -1818,13 +1834,16 @@ void remap_buffer(uint32 line, uint32 width) line = (line + bitmap.viewport.y) % lines_per_frame; /* double resolution mode */ - if (config.render && interlaced) line = (line * 2) + odd_frame; + if (config.render && interlaced) + line = (line * 2) + odd_frame; /* NTSC Filter */ if (config.ntsc) { - if (reg[12]&1) md_ntsc_blit(&md_ntsc, ( MD_NTSC_IN_T const * )pixel_16, tmp_buf+0x20-bitmap.viewport.x, width, line); - else sms_ntsc_blit(&sms_ntsc, ( SMS_NTSC_IN_T const * )pixel_16, tmp_buf+0x20-bitmap.viewport.x, width, line); + if (reg[12]&1) + md_ntsc_blit(&md_ntsc, ( MD_NTSC_IN_T const * )pixel_16, tmp_buf+0x20-bitmap.viewport.x, width, line); + else + sms_ntsc_blit(&sms_ntsc, ( SMS_NTSC_IN_T const * )pixel_16, tmp_buf+0x20-bitmap.viewport.x, width, line); return; } @@ -1928,7 +1947,8 @@ void parse_satb(uint32 line) /* sprite limit (max. 16 or 20 sprites displayed per line) */ if(object_index_count == limit) { - if(vint_pending == 0) status |= 0x40; + if(vint_pending == 0) + status |= 0x40; return; } diff --git a/source/render.h b/source/render.h index dd06829..daeb5f1 100644 --- a/source/render.h +++ b/source/render.h @@ -24,6 +24,9 @@ #ifndef _RENDER_H_ #define _RENDER_H_ +/* Global variables */ +extern uint32 object_index_count; + /* Function prototypes */ extern void render_init(void); extern void render_reset(void); diff --git a/source/sound/Fir_Resampler.c b/source/sound/Fir_Resampler.c index 5fc33a8..3c4ea57 100644 --- a/source/sound/Fir_Resampler.c +++ b/source/sound/Fir_Resampler.c @@ -104,7 +104,7 @@ void Fir_Resampler_clear() if ( buffer_size ) { write_pos = &buffer [WRITE_OFFSET]; - memset( buffer, 0, WRITE_OFFSET * sizeof (sample_t) ); + memset( buffer, 0, buffer_size * sizeof (sample_t) ); } } @@ -143,6 +143,8 @@ double Fir_Resampler_time_ratio( double new_factor ) pos = 0.0; input_per_cycle = 0; + memset(impulses, 0, MAX_RES*WIDTH*sizeof(sample_t)); + for ( i = 0; i < res; i++ ) { gen_sinc( ROLLOFF, (int) (WIDTH * filter + 1) & ~1, pos, filter, @@ -200,10 +202,9 @@ void Fir_Resampler_write( long count ) assert( write_pos <= ( buffer + buffer_size ) ); } -int Fir_Resampler_read( sample_t** out, long count ) +int Fir_Resampler_read( sample_t* out, long count ) { - sample_t* out_l = out[0]; - sample_t* out_r = out[1]; + sample_t* out_ = out; sample_t* in = buffer; sample_t* end_pos = write_pos; unsigned long skip = skip_bits >> imp_phase; @@ -258,8 +259,8 @@ int Fir_Resampler_read( sample_t** out, long count ) remain = res; } - *out_l++ = (sample_t) l; - *out_r++ = (sample_t) r; + *out++ = (sample_t) l; + *out++ = (sample_t) r; } while ( in <= end_pos ); } @@ -270,7 +271,7 @@ int Fir_Resampler_read( sample_t** out, long count ) write_pos = &buffer [left]; memmove( buffer, in, left * sizeof *in ); - return out_l - out[0]; + return out - out_; } int Fir_Resampler_input_needed( long output_count ) diff --git a/source/sound/Fir_Resampler.h b/source/sound/Fir_Resampler.h index 476839a..eb71c27 100644 --- a/source/sound/Fir_Resampler.h +++ b/source/sound/Fir_Resampler.h @@ -23,7 +23,7 @@ extern sample_t* Fir_Resampler_buffer( void ); extern int Fir_Resampler_written( void ); extern int Fir_Resampler_avail( void ); extern void Fir_Resampler_write( long count ); -extern int Fir_Resampler_read( sample_t** out, long count ); +extern int Fir_Resampler_read( sample_t* out, long count ); extern int Fir_Resampler_input_needed( long output_count ); extern int Fir_Resampler_skip_input( long count ); diff --git a/source/sound/sn76489.c b/source/sound/sn76489.c index a285500..31c5c4c 100644 --- a/source/sound/sn76489.c +++ b/source/sound/sn76489.c @@ -109,10 +109,10 @@ static const int PSGVolumeValues[2][16] = { static SN76489_Context SN76489; -void SN76489_Init(int PSGClockValue, int SamplingRate) +void SN76489_Init(float PSGClockValue, int SamplingRate) { SN76489_Context *p = &SN76489; - p->dClock=(float)PSGClockValue/16/SamplingRate; + p->dClock=PSGClockValue/16.0/SamplingRate; SN76489_Config(MUTE_ALLON, VOL_FULL, FB_SEGAVDP, SRW_SEGAVDP, config.psgBoostNoise); SN76489_Reset(); } diff --git a/source/sound/sn76489.h b/source/sound/sn76489.h index ef6b27f..958e158 100644 --- a/source/sound/sn76489.h +++ b/source/sound/sn76489.h @@ -16,7 +16,7 @@ #define _SN76489_H_ /* Function prototypes */ -extern void SN76489_Init(int PSGClockValue, int SamplingRate); +extern void SN76489_Init(float PSGClockValue, int SamplingRate); extern void SN76489_Reset(void); extern void SN76489_Shutdown(void); extern void SN76489_SetContext(uint8 *data); diff --git a/source/sound/sound.c b/source/sound/sound.c index 1f355a2..6177a74 100644 --- a/source/sound/sound.c +++ b/source/sound/sound.c @@ -24,105 +24,229 @@ #include "shared.h" #include "Fir_Resampler.h" -/* cycle-accurate samples */ -static int m68cycles_per_sample[2]; +/* Cycle-accurate samples */ +static unsigned int psg_cycles_ratio; +static unsigned int psg_cycles_count; +static unsigned int fm_cycles_ratio; +static unsigned int fm_cycles_count; -/* return the number of samples that should be retrieved */ -static inline int fm_sample_cnt(uint8 z80) +/* Run FM chip for required M-cycles */ +static inline void fm_update(unsigned int cycles) { - if (z80) return ((((count_z80 + current_z80 - z80_ICount) * 15) / (m68cycles_per_sample[0] * 7)) - snd.fm.pos); - else return ((count_m68k / m68cycles_per_sample[0]) - snd.fm.pos); -} + /* convert to 21.11 fixed point */ + cycles <<= 11; -static inline int psg_sample_cnt(uint8 z80) -{ - if (z80) return ((((count_z80 + current_z80 - z80_ICount) * 15) / (m68cycles_per_sample[1] * 7)) - snd.psg.pos); - else return ((count_m68k / m68cycles_per_sample[1]) - snd.psg.pos); -} - -/* run FM chip for n samples */ -static inline void fm_update(int cnt) -{ - if (cnt > 0) + if (cycles > fm_cycles_count) { - YM2612Update(cnt); - snd.fm.pos += cnt; + /* period to run */ + cycles -= fm_cycles_count; + + /* update cycle count */ + fm_cycles_count += cycles; + + /* number of samples during period */ + uint32 cnt = cycles / fm_cycles_ratio; + + /* remaining cycles */ + uint32 remain = cycles % fm_cycles_ratio; + if (remain) + { + /* one sample ahead */ + fm_cycles_count += fm_cycles_ratio - remain; + cnt++; + } + + /* select input sample buffer */ + int16 *buffer = Fir_Resampler_buffer(); + if (buffer) + { + Fir_Resampler_write(cnt << 1); + } + else + { + buffer = snd.fm.pos; + snd.fm.pos += (cnt << 1); + } + + /* run FM chip & get samples */ + YM2612Update(buffer, cnt); } } -/* run PSG chip for n samples */ -static inline void psg_update(int cnt) +/* Run PSG chip for required M-cycles */ +static inline void psg_update(unsigned int cycles) { - if (cnt > 0) + /* convert to 21.11 fixed point */ + cycles <<= 11; + + if (cycles > psg_cycles_count) { - SN76489_Update(snd.psg.buffer + snd.psg.pos, cnt); + /* period to run */ + cycles -= psg_cycles_count; + + /* update cycle count */ + psg_cycles_count += cycles; + + /* number of samples during period */ + uint32 cnt = cycles / psg_cycles_ratio; + + /* remaining cycles */ + uint32 remain = cycles % psg_cycles_ratio; + if (remain) + { + /* one sample ahead */ + psg_cycles_count += psg_cycles_ratio - remain; + cnt++; + } + + /* run PSG chip & get samples */ + SN76489_Update(snd.psg.pos, cnt); snd.psg.pos += cnt; } } -/* initialize sound chips emulation */ -void sound_init(int rate, double fps) +/* Initialize sound chips emulation */ +void sound_init(void) { - double vclk = (vdp_pal ? (double)CLOCK_PAL : (double)CLOCK_NTSC) / 7.0; /* 68000 and YM2612 clock */ - double zclk = (vdp_pal ? (double)CLOCK_PAL : (double)CLOCK_NTSC) / 15.0; /* Z80 and SN76489 clock */ + /* Number of M-cycles executed per second. */ + /* */ + /* The original Genesis would run exactly 53693175 M-cycles (53203424 for PAL), with */ + /* 3420 M-cycles per line and 262 (313 for PAL) lines per frame, which gives an exact */ + /* framerate of 59.92 (49.70 for PAL) fps. */ + /* */ + /* On some systems, the output framerate is not exactly 60 or 50 fps because we need */ + /* 100% smooth video and therefore frame emulation is synchronized with VSYNC, which */ + /* period is never exactly 1/60 or 1/50 seconds. */ + /* */ + /* For optimal sound rendering, input samplerate (number of samples rendered per frame) */ + /* is the exact output samplerate (number of samples played per second) divided by the */ + /* exact output framerate (number of frames emulated per seconds). */ + /* */ + /* This ensure there is no audio skipping or lag between emulated frames, while keeping */ + /* accurate timings for sound chips execution & synchronization. */ + /* */ + double mclk = MCYCLES_PER_LINE * lines_per_frame * snd.frame_rate; - /* cycle-accurate FM & PSG samples */ - m68cycles_per_sample[0] = (int)(((double)m68cycles_per_line * (double)lines_per_frame * fps/ (double)rate) + 0.5); - m68cycles_per_sample[1] = m68cycles_per_sample[0]; + /* For better accuracy, sound chips run in synchronization with 68k and Z80 cpus */ + /* These values give the exact number of M-cycles between 2 rendered samples. */ + /* we use 21.11 fixed point precision (max. mcycle value is 3420*313 i.e 21 bits max) */ + psg_cycles_ratio = (int)((mclk / (double) snd.sample_rate) * 2048.0); + fm_cycles_ratio = psg_cycles_ratio; + fm_cycles_count = 0; + psg_cycles_count = 0; - /* YM2612 is emulated at its original frequency (VLCK/144) */ + /* Initialize core emulation (input clock based on input frequency for 100% accuracy) */ + /* By default, both chips are running at the output frequency. */ + SN76489_Init(mclk/15.0,snd.sample_rate); + YM2612Init(mclk/7.0,snd.sample_rate); + + /* In HQ mode, YM2612 is running at its original rate (one sample each 144*7 M-cycles) */ + /* FM stream is resampled to the output frequency at the end of a frame. */ if (config.hq_fm) { - /* "real" ratio is (vclk/144.0)/(rate) but since we need perfect synchronization between video & audio - on the target system, we are not exactly running at the real genesis framerate but the target - framerate (which is calculated so that no video or audio frameskip occur) - */ - Fir_Resampler_time_ratio((double)m68cycles_per_line * (double)lines_per_frame * fps / 144.0 / (double)rate); - - m68cycles_per_sample[0] = 144; - + fm_cycles_ratio = 144 * 7 * (1 << 11); + Fir_Resampler_time_ratio(mclk / (double)snd.sample_rate / (144.0 * 7.0)); } - /* initialize sound chips */ - SN76489_Init((int)zclk,rate); - YM2612Init((int)vclk,rate); -} - -void sound_update(int fm_len, int psg_len) -{ - /* update last samples (if needed) */ - fm_update(fm_len - snd.fm.pos); - psg_update(psg_len - snd.psg.pos); - - /* reset samples count */ - snd.fm.pos = 0; - snd.psg.pos = 0; +#ifdef LOG_SOUND + error("%d mcycles per PSG samples\n", psg_cycles_ratio); + error("%d mcycles per FM samples\n", fm_cycles_ratio); +#endif } -/* reset FM chip */ +/* Reset sound chips emulation */ +void sound_reset(void) +{ + YM2612ResetChip(); + SN76489_Reset(); + fm_cycles_count = 0; + psg_cycles_count = 0; +} + +/* End of frame update, return the number of samples run so far. */ +int sound_update(unsigned int cycles) +{ + /* run PSG chip until end of frame */ + psg_update(cycles); + + /* number of available samples */ + int size = snd.psg.pos - snd.psg.buffer; + +#ifdef LOG_SOUND + error("%d PSG samples available\n",snd.psg.pos - snd.psg.buffer); +#endif + + /* FM resampling */ + if (config.hq_fm) + { + /* resynchronize FM & PSG chips */ + int remain = Fir_Resampler_input_needed(size << 1) >> 1; + + /* get remaining FM samples */ + if (remain > 0) + { + YM2612Update(Fir_Resampler_buffer(), remain); + Fir_Resampler_write(remain << 1); + } + + fm_cycles_count = psg_cycles_count; + +#ifdef LOG_SOUND + error("%d FM samples available\n",Fir_Resampler_written() >> 1); +#endif + } + else + { + /* run FM chip until end of frame */ + fm_update(cycles); + +#ifdef LOG_SOUND + error("%d FM samples available\n",(snd.fm.pos - snd.fm.buffer)>>1); +#endif + } + +#ifdef LOG_SOUND + error("%lu PSG cycles run\n",psg_cycles_count); + error("%lu FM cycles run \n",fm_cycles_count); +#endif + + /* adjust PSG & FM cycle counts */ + psg_cycles_count -= (cycles << 11); + fm_cycles_count -= (cycles << 11); + +#ifdef LOG_SOUND + error("%lu PSG cycles left\n",psg_cycles_count); + error("%lu FM cycles left\n",fm_cycles_count); +#endif + + return size; +} + +/* Reset FM chip during 68k execution */ void fm_reset(void) { - fm_update(fm_sample_cnt(0)); + fm_update(mcycles_68k); YM2612ResetChip(); } -/* write FM chip */ -void fm_write(unsigned int cpu, unsigned int address, unsigned int data) +/* Write FM chip */ +void fm_write(unsigned int cycles, unsigned int address, unsigned int data) { - if (address & 1) fm_update(fm_sample_cnt(cpu)); + if (address & 1) + fm_update(cycles); YM2612Write(address, data); } -/* read FM status */ -unsigned int fm_read(unsigned int cpu, unsigned int address) +/* Read FM status */ +unsigned int fm_read(unsigned int cycles, unsigned int address) { - fm_update(fm_sample_cnt(cpu)); + fm_update(cycles); return YM2612Read(); } -/* write PSG chip */ -void psg_write(unsigned int cpu, unsigned int data) +/* Write PSG chip */ +void psg_write(unsigned int cycles, unsigned int data) { - psg_update(psg_sample_cnt(cpu)); + psg_update(cycles); SN76489_Write(data); } diff --git a/source/sound/sound.h b/source/sound/sound.h index e7a77a9..d07d292 100644 --- a/source/sound/sound.h +++ b/source/sound/sound.h @@ -25,11 +25,12 @@ #define _SOUND_H_ /* Function prototypes */ -extern void sound_init(int rate, double fps); -extern void sound_update(int fm_len, int psg_len); +extern void sound_init(void); +extern void sound_reset(void); +extern int sound_update(unsigned int cycles); extern void fm_reset(void); -extern void fm_write(unsigned int cpu, unsigned int address, unsigned int data); -extern unsigned int fm_read(unsigned int cpu, unsigned int address); -extern void psg_write(unsigned int cpu, unsigned int data); +extern void fm_write(unsigned int cycles, unsigned int address, unsigned int data); +extern unsigned int fm_read(unsigned int cycles, unsigned int address); +extern void psg_write(unsigned int cycles, unsigned int data); #endif /* _SOUND_H_ */ diff --git a/source/sound/ym2612.c b/source/sound/ym2612.c index b39f6fc..9ac1bc8 100644 --- a/source/sound/ym2612.c +++ b/source/sound/ym2612.c @@ -554,7 +554,7 @@ typedef struct typedef struct { - UINT32 clock; /* master clock (Hz) */ + float clock; /* master clock (Hz) */ UINT32 rate; /* sampling rate (Hz) */ UINT16 address; /* address register */ UINT8 status; /* status flag */ @@ -1775,7 +1775,7 @@ static void init_timetables(double freqbase) static void OPNSetPres(int pres) { /* frequency base (ratio between FM original samplerate & desired output samplerate)*/ - double freqbase = ((double) ym2612.OPN.ST.clock / (double) ym2612.OPN.ST.rate) / ((double) pres); + double freqbase = ym2612.OPN.ST.clock / ym2612.OPN.ST.rate / pres; /* YM2612 running at original frequency (~53267 Hz) */ if (config.hq_fm) freqbase = 1.0; @@ -1913,7 +1913,7 @@ static void init_tables(void) /* initialize ym2612 emulator(s) */ -int YM2612Init(int clock, int rate) +int YM2612Init(float clock, int rate) { memset(&ym2612,0,sizeof(YM2612)); init_tables(); @@ -2017,24 +2017,10 @@ unsigned int YM2612Read(void) } /* Generate 16 bits samples for ym2612 */ -void YM2612Update(int length) +void YM2612Update(short int *buffer, int length) { int i; int lt,rt; - int16 *bufL = 0; - int16 *bufR = 0; - - /* Output samples buffers */ - int16 *bufFIR = Fir_Resampler_buffer(); - if (bufFIR) - { - bufFIR += (snd.fm.pos << 1); - } - else - { - bufL = snd.fm.buffer[0] + snd.fm.pos; - bufR = snd.fm.buffer[1] + snd.fm.pos; - } /* refresh PG increments and EG rates if required */ refresh_fc_eg_chan(&ym2612.CH[0]); @@ -2139,16 +2125,8 @@ void YM2612Update(int length) // Limit(rt,MAXOUT,MINOUT); /* buffering */ - if (bufFIR) - { - *bufFIR++ = lt; - *bufFIR++ = rt; - } - else - { - *bufL++ = lt; - *bufR++ = rt; - } + *buffer++ = lt; + *buffer++ = rt; /* CSM mode: if CSM Key ON has occured, CSM Key OFF need to be sent */ /* only if Timer A does not overflow again (i.e CSM Key ON not set again) */ @@ -2186,7 +2164,7 @@ unsigned int YM2612GetContextSize(void) void YM2612Restore(unsigned char *buffer) { /* save current timings */ - int clock = ym2612.OPN.ST.clock; + float clock = ym2612.OPN.ST.clock; int rate = ym2612.OPN.ST.rate; /* restore internal state */ diff --git a/source/sound/ym2612.h b/source/sound/ym2612.h index 455f106..7b901bb 100644 --- a/source/sound/ym2612.h +++ b/source/sound/ym2612.h @@ -19,9 +19,9 @@ #endif -extern int YM2612Init(int baseclock, int rate); +extern int YM2612Init(float clock, int rate); extern int YM2612ResetChip(void); -extern void YM2612Update(int length); +extern void YM2612Update(short int*buffer, int length); extern void YM2612Write(unsigned int a, unsigned int v); extern unsigned int YM2612Read(void); extern unsigned char *YM2612GetContextPtr(void); diff --git a/source/state.c b/source/state.c index 104ce45..df745ab 100644 --- a/source/state.c +++ b/source/state.c @@ -59,10 +59,8 @@ int state_load(unsigned char *buffer) // GENESIS load_param(work_ram, sizeof(work_ram)); load_param(zram, sizeof(zram)); - load_param(&zbusreq, sizeof(zbusreq)); - load_param(&zreset, sizeof(zreset)); + load_param(&zstate, sizeof(zstate)); load_param(&zbank, sizeof(zbank)); - zbusack = 1 ^(zbusreq & zreset); // IO load_param(io_reg, sizeof(io_reg)); @@ -134,8 +132,7 @@ int state_save(unsigned char *buffer) // GENESIS save_param(work_ram, sizeof(work_ram)); save_param(zram, sizeof(zram)); - save_param(&zbusreq, sizeof(zbusreq)); - save_param(&zreset, sizeof(zreset)); + save_param(&zstate, sizeof(zstate)); save_param(&zbank, sizeof(zbank)); // IO diff --git a/source/system.c b/source/system.c index fccaea4..b28b5df 100644 --- a/source/system.c +++ b/source/system.c @@ -30,12 +30,10 @@ /* Global variables */ t_bitmap bitmap; t_snd snd; -uint32 count_m68k; -uint32 line_m68k; -uint32 hint_m68k; -uint32 count_z80; -uint32 line_z80; -int32 current_z80; +uint32 mcycles_vdp; +uint32 mcycles_z80; +uint32 mcycles_68k; +uint32 hint_68k; uint8 system_hw; /**************************************************************** @@ -56,7 +54,7 @@ void audio_set_equalizer(void) ****************************************************************/ static int llp,rrp; -void audio_update (int size) +int audio_update (void) { int i, l, r; int ll = llp; @@ -68,26 +66,45 @@ void audio_update (int size) uint32 factora = (config.lp_range << 16) / 100; uint32 factorb = 0x10000 - factora; - int16 *fm[2] = {snd.fm.buffer[0],snd.fm.buffer[1]}; - int16 *psg = snd.psg.buffer; + int16 *fm = snd.fm.buffer; + int16 *psg = snd.psg.buffer; #ifdef NGC int16 *sb = (int16 *) soundbuffer[mixbuffer]; #endif - /* resampling */ + /* get number of available samples */ + int size = sound_update(mcycles_vdp); + + /* return an aligned number of samples */ + size &= ~7; + if (config.hq_fm) { - int len = Fir_Resampler_input_needed(size << 1); - sound_update(len >> 1,size); - Fir_Resampler_write(len); + /* resample into FM output buffer */ Fir_Resampler_read(fm,size); + +#ifdef LOG_SOUND + error("%d FM samples remaining\n",Fir_Resampler_written() >> 1); +#endif } else - { - sound_update(size,size); + { + /* adjust remaining samples in FM output buffer*/ + snd.fm.pos -= (size << 1); + +#ifdef LOG_SOUND + error("%d FM samples remaining\n",(snd.fm.pos - snd.fm.buffer)>>1); +#endif } + /* adjust remaining samples in PSG output buffer*/ + snd.psg.pos -= size; + +#ifdef LOG_SOUND + error("%d PSG samples remaining\n",snd.psg.pos - snd.psg.buffer); +#endif + /* mix samples */ for (i = 0; i < size; i ++) { @@ -95,8 +112,8 @@ void audio_update (int size) l = r = ((*psg++) * psg_preamp)/100; /* FM samples (stereo) */ - l += (*fm[0]++ * fm_preamp)/100; - r += (*fm[1]++ * fm_preamp)/100; + l += (*fm++ * fm_preamp)/100; + r += (*fm++ * fm_preamp)/100; /* filtering */ if (filter & 1) @@ -130,15 +147,25 @@ void audio_update (int size) #endif } - /* save delayed samples */ + /* save delayed samples for next frame */ llp = ll; rrp = rr; + + /* save remaining samples for next frame */ + memcpy(snd.fm.buffer, fm, (snd.fm.pos - snd.fm.buffer) << 1); + memcpy(snd.psg.buffer, psg, (snd.psg.pos - snd.psg.buffer) << 1); + +#ifdef LOG_SOUND + error("%d samples returned\n\n",size); +#endif + + return size; } /**************************************************************** * AUDIO System initialization ****************************************************************/ -int audio_init (int rate, double fps) +int audio_init (int samplerate, float framerate) { /* Shutdown first */ audio_shutdown(); @@ -146,61 +173,91 @@ int audio_init (int rate, double fps) /* Clear the sound data context */ memset(&snd, 0, sizeof (snd)); - /* Make sure the requested sample rate is valid */ - if (!rate || ((rate < 8000) | (rate > 48000))) return (-1); - snd.sample_rate = rate; + /* Default settings */ + snd.sample_rate = samplerate; + snd.frame_rate = framerate; + + /* Calculate the sound buffer size (for one frame) */ + snd.buffer_size = (int)(samplerate / framerate) + 32; #ifndef NGC - /* Calculate the sound buffer size (for one frame) */ - snd.buffer_size = (rate / vdp_rate); - /* Output buffers */ snd.buffer[0] = (int16 *) malloc(SND_SIZE); snd.buffer[1] = (int16 *) malloc(SND_SIZE); - if (!snd.buffer[0] || !snd.buffer[1]) return (-1); -#else - /* Calculate the sound buffer size (for one frame) */ - snd.buffer_size = (rate / vdp_rate) + 32; + if (!snd.buffer[0] || !snd.buffer[1]) + return (-1); #endif /* SN76489 stream buffers */ - snd.psg.buffer = (int16 *)malloc (SND_SIZE); - if (!snd.psg.buffer) return (-1); + snd.psg.buffer = (int16 *) malloc(SND_SIZE); + if (!snd.psg.buffer) + return (-1); /* YM2612 stream buffers */ - snd.fm.buffer[0] = (int16 *)malloc (SND_SIZE); - snd.fm.buffer[1] = (int16 *)malloc (SND_SIZE); - if (!snd.fm.buffer[0] || !snd.fm.buffer[1]) return (-1); + snd.fm.buffer = (int16 *) malloc(SND_SIZE * 2); + if (!snd.fm.buffer) + return (-1); /* Resampling buffer */ if (config.hq_fm) { - if (!Fir_Resampler_initialize(4096)) return (-1); + if (!Fir_Resampler_initialize(4096)) + return (-1); } - /* 3 band EQ */ - audio_set_equalizer(); - /* Set audio enable flag */ snd.enabled = 1; - /* Initialize Sound Chips emulation */ - sound_init(rate,fps); + /* Reset audio */ + audio_reset(); return (0); } +/**************************************************************** + * AUDIO System reset + ****************************************************************/ +void audio_reset(void) +{ + /* Low-Pass filter */ + llp = 0; + rrp = 0; + + /* 3 band EQ */ + audio_set_equalizer(); + + /* audio buffers */ + Fir_Resampler_clear(); + snd.psg.pos = snd.psg.buffer; + snd.fm.pos = snd.fm.buffer; +#ifndef NGC + if (snd.buffer[0]) + memset (snd.buffer[0], 0, SND_SIZE); + if (snd.buffer[1]) + memset (snd.buffer[1], 0, SND_SIZE); +#endif + if (snd.psg.buffer) + memset (snd.psg.buffer, 0, SND_SIZE); + if (snd.fm.buffer) + memset (snd.fm.buffer, 0, SND_SIZE * 2); +} + /**************************************************************** * AUDIO System shutdown ****************************************************************/ void audio_shutdown(void) { /* Sound buffers */ - if (snd.buffer[0]) free(snd.buffer[0]); - if (snd.buffer[1]) free(snd.buffer[1]); - if (snd.fm.buffer[0]) free(snd.fm.buffer[0]); - if (snd.fm.buffer[1]) free(snd.fm.buffer[1]); - if (snd.psg.buffer) free(snd.psg.buffer); +#ifndef NGC + if (snd.buffer[0]) + free(snd.buffer[0]); + if (snd.buffer[1]) + free(snd.buffer[1]); +#endif + if (snd.fm.buffer) + free(snd.fm.buffer); + if (snd.psg.buffer) + free(snd.psg.buffer); /* Resampling buffer */ Fir_Resampler_shutdown(); @@ -219,6 +276,9 @@ void system_init (void) /* Cartridge hardware */ cart_hw_init(); + + /* Sound Chips hardware */ + sound_init(); } /**************************************************************** @@ -231,17 +291,15 @@ void system_reset (void) /* Genesis hardware */ gen_reset(1); - SN76489_Reset(); io_reset(); vdp_reset(); render_reset(); - /* Clear Sound Buffers */ - if (snd.psg.buffer) memset (snd.psg.buffer, 0, SND_SIZE); - if (snd.fm.buffer[0]) memset (snd.fm.buffer[0], 0, SND_SIZE); - if (snd.fm.buffer[1]) memset (snd.fm.buffer[1], 0, SND_SIZE); - Fir_Resampler_clear(); - llp = rrp = 0; + /* Sound chips */ + sound_reset(); + + /* Audio System */ + audio_reset(); } /**************************************************************** @@ -265,15 +323,6 @@ int system_frame (int do_skip) return 0; } - uint32 aim_m68k = 0; - uint32 aim_z80 = 0; - - /* reset cycles counts */ - count_m68k = 0; - count_z80 = 0; - fifo_write_cnt = 0; - fifo_lastwrite = 0; - /* update display settings */ int line; int reset = resetline; @@ -291,17 +340,21 @@ int system_frame (int do_skip) odd_frame ^= 1; /* clear VBLANK and DMA flags */ - status &= 0xFFF5; + status &= 0xFFE5; /* even/odd field flag (interlaced modes only) */ - if (odd_frame && interlaced) status |= 0x0010; - else status &= 0xFFEF; + if (odd_frame && interlaced) + status |= 0x0010; /* reload HCounter */ int h_counter = reg[10]; - /* parse sprites for line 0 (done on last line) */ - parse_satb (0x80); + /* reset VDP FIFO */ + fifo_write_cnt = 0; + fifo_lastwrite = 0; + + /* reset line cycle count */ + mcycles_vdp = 0; /* process scanlines */ for (line = 0; line < lines_per_frame; line ++) @@ -312,14 +365,10 @@ int system_frame (int do_skip) /* update 6-Buttons or Menacer */ input_update(); - /* update CPU cycle counters */ - hint_m68k = count_m68k; - line_m68k = aim_m68k; - line_z80 = aim_z80; - aim_z80 += z80cycles_per_line; - aim_m68k += m68cycles_per_line; + /* 68k line cycle count */ + hint_68k = mcycles_68k; - /* Soft Reset ? */ + /* Soft Reset line */ if (line == reset) { /* Pro Action Replay (switch at "Trainer" position) */ @@ -329,6 +378,10 @@ int system_frame (int do_skip) gen_reset(0); } + /* update VDP DMA */ + if (dma_length) + vdp_update_dma(); + /* active display */ if (line <= vdp_height) { @@ -337,27 +390,16 @@ int system_frame (int do_skip) { h_counter = reg[10]; hint_pending = 1; - if (reg[0] & 0x10) irq_status = (irq_status & ~0x40) | 0x14; - - /* adjust timings to take further decrement in account (see below) */ - if ((line != 0) || (h_counter == 0)) aim_m68k += 36; + if (reg[0] & 0x10) + irq_status = (irq_status & ~0x40) | 0x14; } - /* HINT will be triggered on next line, approx. 36 cycles before VDP starts line rendering */ - /* during this period, any VRAM or VSRAM writes should NOT be taken in account before next line */ - /* as a result, line is rendered immediately after HINT and current line is shortened */ - /* CRAM and VDP register writes that could occur during HBLANK are handled separately */ - /* fix Striker, Zero the Kamikaze Squirell */ - if ((line < vdp_height) && (h_counter == 0)) aim_m68k -= 36; - - /* update DMA timings */ - if (dma_length) vdp_update_dma(); - /* vertical retrace */ if (line == vdp_height) { /* render overscan */ - if ((line < end_line) && (!do_skip)) render_line(line, 1); + if (line < end_line) + render_line(line, 1); /* update inputs (doing this here fix Warriors of Eternal Sun) */ osd_input_Update(); @@ -367,39 +409,38 @@ int system_frame (int do_skip) /* Z80 interrupt is 16ms period (one frame) and 64us length (one scanline) */ zirq = 1; - z80_set_irq_line(0, ASSERT_LINE); + z80_set_irq_line(0, ASSERT_LINE); - /* delay between HINT, VBLANK and VINT (Dracula, OutRunners, VR Troopers) */ - m68k_run(line_m68k + 84); - if (zreset && !zbusreq) - { - current_z80 = line_z80 + 39 - count_z80; - if (current_z80 > 0) count_z80 += z80_execute(current_z80); - } - else count_z80 = line_z80 + 39; - - /* V Interrupt */ + /* delay between VINT flag & V Interrupt (Ex-Mutants, Tyrant) */ + m68k_run(mcycles_vdp + 588); status |= 0x80; - /* 36 cycles latency after VINT occurence flag (Ex-Mutants, Tyrant) */ - m68k_run(line_m68k + 113); + /* 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 = 1; - if (reg[1] & 0x20) irq_status = (irq_status & ~0x40) | 0x36; + if (reg[1] & 0x20) + irq_status = (irq_status & ~0x40) | 0x36; } else if (!do_skip) { - /* render scanline and parse sprites for line n+1 */ + /* sprites are processed during horizontal blanking */ + parse_satb(0x80 + line); + + /* render scanline */ render_line(line, 0); - if (line < (vdp_height-1)) parse_satb(0x81 + line); } } else { - /* update DMA timings */ - if (dma_length) vdp_update_dma(); - /* render overscan */ - if ((!do_skip) && ((line < end_line) || (line >= start_line))) render_line(line, 1); + if ((line < end_line) || (line >= start_line)) + render_line(line, 1); /* clear any pending Z80 interrupt */ if (zirq) @@ -410,17 +451,23 @@ int system_frame (int do_skip) } /* process line */ - m68k_run(aim_m68k); - if (zreset == 1 && zbusreq == 0) - { - current_z80 = aim_z80 - count_z80; - if (current_z80 > 0) count_z80 += z80_execute(current_z80); - } - else count_z80 = aim_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; /* SVP chip */ - if (svp) ssp1601_run(SVP_cycles); + if (svp) + ssp1601_run(SVP_cycles); + + /* update line cycle count */ + mcycles_vdp += MCYCLES_PER_LINE; } + /* adjust cpu cycle count for next frame */ + mcycles_68k -= mcycles_vdp; + mcycles_z80 -= mcycles_vdp; + return gen_running; } diff --git a/source/system.h b/source/system.h index 307d7d4..1e8bc6e 100644 --- a/source/system.h +++ b/source/system.h @@ -28,12 +28,7 @@ #define SYSTEM_MEGADRIVE 1 #define SYSTEM_PICO 2 -/* CPU cycles increments */ -#define z80cycles_per_line 228 -#define m68cycles_per_line 488 - -#define CLOCK_NTSC 53693175 -#define CLOCK_PAL 53203424 +#define MCYCLES_PER_LINE 3420 typedef struct { @@ -59,18 +54,19 @@ typedef struct typedef struct { - int sample_rate; /* Sample rate (8000-48000) */ + int sample_rate; /* Output Sample rate (8000-48000) */ + float frame_rate; /* Output Frame rate (usually 50 or 60 frames per second) */ int enabled; /* 1= sound emulation is enabled */ int buffer_size; /* Size of sound buffer (in bytes) */ int16 *buffer[2]; /* Signed 16-bit stereo sound data */ struct { - int pos; - int16 *buffer[2]; + int16 *pos; + int16 *buffer; } fm; struct { - int pos; + int16 *pos; int16 *buffer; } psg; } t_snd; @@ -78,18 +74,17 @@ typedef struct /* Global variables */ extern t_bitmap bitmap; extern t_snd snd; -extern uint32 count_m68k; -extern uint32 line_m68k; -extern uint32 hint_m68k; -extern uint32 count_z80; -extern uint32 line_z80; -extern int32 current_z80; +extern uint32 mcycles_vdp; +extern uint32 mcycles_z80; +extern uint32 mcycles_68k; +extern uint32 hint_68k; extern uint8 system_hw; /* Function prototypes */ -extern int audio_init (int rate,double fps); +extern int audio_init (int samplerate,float framerate); +extern void audio_reset (void); extern void audio_shutdown (void); -extern void audio_update (int len); +extern int audio_update (void); extern void audio_set_equalizer(void); extern void system_init (void); extern void system_reset (void); diff --git a/source/unused/dos/dos.c b/source/unused/dos/dos.c index 200572e..de77f20 100644 --- a/source/unused/dos/dos.c +++ b/source/unused/dos/dos.c @@ -103,7 +103,7 @@ int main (int argc, char *argv[]) /* initialize emulation */ system_init(); - audio_init(option.sndrate); + audio_init(option.sndrate, vdp_pal ? 50 : 60); f = fopen("./game.srm", "rb"); if (f!=NULL) @@ -132,8 +132,9 @@ int main (int argc, char *argv[]) system_frame(1); } - audio_update(snd.buffer_size); - if(option.sound) dos_update_audio(); + audio_update(); + if(option.sound) + dos_update_audio(); } f = fopen("./game.srm", "wb"); @@ -366,11 +367,19 @@ void dos_update_input(void) { vdp_pal ^= 1; - /* reinitialize timings */ - system_init (); - unsigned char *temp = malloc(YM2612GetContextSize()); - if (temp) memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize()); - audio_init(48000); + /* save YM2612 context */ + unsigned char *temp = memalign(32,YM2612GetContextSize()); + if (temp) + memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize()); + + /* reinitialize all timings */ + audio_init(snd.sample_rate, framerate); + system_init(); + + /* restore SRAM */ + memfile_autoload(config.sram_auto,-1); + + /* restore YM2612 context */ if (temp) { YM2612Restore(temp); @@ -378,7 +387,7 @@ void dos_update_input(void) } /* reinitialize HVC tables */ - vctab = (vdp_pal) ? ((reg[1] & 8) ? vc_pal_240 : vc_pal_224) : vc_ntsc_224; + vctab = vdp_pal ? ((reg[1] & 8) ? vc_pal_240 : vc_pal_224) : vc_ntsc_224; hctab = (reg[12] & 1) ? cycle2hc40 : cycle2hc32; /* reinitialize overscan area */ diff --git a/source/unused/win/Makefile b/source/unused/win/Makefile index d01b540..96df525 100644 --- a/source/unused/win/Makefile +++ b/source/unused/win/Makefile @@ -12,7 +12,7 @@ NAME = gen_sdl.exe CC = gcc CFLAGS = `sdl-config --cflags` -O6 -march=i686 -fomit-frame-pointer -DEFINES = -DLSB_FIRST -DX86_ASM -DLOGERROR=1 +DEFINES = -DLSB_FIRST -DX86_ASM -DLOGERROR=1 -DLOGVDP=1 INCLUDES = -I. -I.. -I../z80 -I../m68k -I../sound -I../cart_hw -I../cart_hw/svp -I../ntsc LIBS = `sdl-config --libs` -lz -lm diff --git a/source/unused/win/main.c b/source/unused/win/main.c index 082d510..f24cfcd 100644 --- a/source/unused/win/main.c +++ b/source/unused/win/main.c @@ -304,19 +304,27 @@ static int sdl_control_update(SDLKey keystate) { vdp_pal ^= 1; - /* reinitialize timings */ - system_init (); - unsigned char *temp = malloc(YM2612GetContextSize()); - if (temp) memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize()); - audio_init(SOUND_FREQUENCY); + /* save YM2612 context */ + unsigned char *temp = memalign(32,YM2612GetContextSize()); + if (temp) + memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize()); + + /* reinitialize all timings */ + audio_init(snd.sample_rate, framerate); + system_init(); + + /* restore SRAM */ + memfile_autoload(config.sram_auto,-1); + + /* restore YM2612 context */ if (temp) { YM2612Restore(temp); free(temp); } - + /* reinitialize HVC tables */ - vctab = (vdp_pal) ? ((reg[1] & 8) ? vc_pal_240 : vc_pal_224) : vc_ntsc_224; + vctab = vdp_pal ? ((reg[1] & 8) ? vc_pal_240 : vc_pal_224) : vc_ntsc_224; hctab = (reg[12] & 1) ? cycle2hc40 : cycle2hc32; /* reinitialize overscan area */ @@ -528,8 +536,8 @@ int main (int argc, char **argv) SDL_UnlockSurface(sdl_video.surf_bitmap); /* initialize emulation */ + audio_init(SOUND_FREQUENCY, vdp_pal ? 50 : 60); system_init(); - audio_init(SOUND_FREQUENCY); /* load SRAM */ f = fopen("./game.srm", "rb"); @@ -545,8 +553,9 @@ int main (int argc, char **argv) if(use_sound) SDL_PauseAudio(0); + /* 3 frames = 50 ms (60hz) or 60 ms (50hz) */ if(sdl_sync.sem_sync) - SDL_SetTimer(vdp_pal ? 60 : 50, sdl_sync_timer_callback); /* 3 frames = 50 ms (60hz) or 60 ms (50hz) */ + SDL_SetTimer(vdp_pal ? 60 : 50, sdl_sync_timer_callback); /* emulation loop */ while(running) diff --git a/source/vdp.c b/source/vdp.c index 0cdcb33..d87d31e 100644 --- a/source/vdp.c +++ b/source/vdp.c @@ -72,12 +72,10 @@ uint16 v_counter; /* VDP scanline counter */ uint32 dma_length; /* Current DMA remaining bytes */ int32 fifo_write_cnt; /* VDP writes fifo count */ uint32 fifo_lastwrite; /* last VDP write cycle */ -uint8 fifo_latency; /* VDP write cycles latency */ uint8 odd_frame; /* 1: odd field, 0: even field */ uint8 im2_flag; /* 1= Interlace mode 2 is being used */ uint8 interlaced; /* 1: Interlaced mode 1 or 2 */ uint8 vdp_pal; /* 1: PAL , 0: NTSC (default) */ -uint8 vdp_rate; /* PAL: 50hz, NTSC: 60hz */ uint16 lines_per_frame; /* PAL: 313 lines, NTSC: 262 lines */ @@ -89,7 +87,8 @@ static const uint16 row_mask_table[] = { 0x0FF, 0x1FF, 0x2FF, 0x3FF }; static uint16 sat_base_mask; /* Base bits of SAT */ static uint16 sat_addr_mask; /* Index bits of SAT */ static uint32 dma_endCycles; /* 68k cycles to DMA end */ -static uint8 dma_type; /* DMA mode */ +static uint32 dma_type; /* DMA mode */ +static uint32 fifo_latency; /* CPU access latency */ /* DMA Timings @@ -141,21 +140,10 @@ static inline void dma_fill(unsigned int data); void vdp_init(void) { /* PAL/NTSC timings */ - switch (region_code) - { - case REGION_EUROPE: - case REGION_JAPAN_PAL: - vdp_pal = 1; - vdp_rate = 50; - lines_per_frame = 313; - break; - - default: - vdp_pal = 0; - vdp_rate = 60; - lines_per_frame = 262; - break; - } + if (vdp_pal) + lines_per_frame = 313; + else + lines_per_frame = 262; } void vdp_reset(void) @@ -233,8 +221,8 @@ void vdp_reset(void) reg_w(15, 0x02); /* auto increment */ } - /* default latency */ - fifo_latency = 27; + /* default FIFO timing */ + fifo_latency = 192; } void vdp_shutdown(void) @@ -258,9 +246,10 @@ void vdp_restore(uint8 *vdp_regs) bitmap.viewport.y = config.overscan ? (((reg[1] & 8) ? 0 : 8) + (vdp_pal ? 24 : 0)) : 0; bitmap.viewport.changed = 1; - /* restore VDP timings */ - fifo_latency = (reg[12] & 1) ? 27 : 30; - if ((code & 0x0F) == 0x01) fifo_latency = fifo_latency * 2; + /* restore FIFO timings */ + fifo_latency = (reg[12] & 1) ? 192 : 210; + if ((code & 0x0F) == 0x01) + fifo_latency = fifo_latency * 2; /* remake cache */ for (i=0;i<0x800;i++) @@ -295,21 +284,21 @@ void vdp_update_dma() int rate = dma_rates[index]; /* 68k cycles left */ - int left_cycles = (line_m68k + m68cycles_per_line) - count_m68k; + int left_cycles = (mcycles_vdp + MCYCLES_PER_LINE) - mcycles_68k; if (left_cycles < 0) left_cycles = 0; /* DMA bytes left */ - int dma_bytes = (left_cycles * rate) / m68cycles_per_line; + int dma_bytes = (left_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, count_m68k/488, count_m68k, count_m68k%488,dma_type, rate, dma_length, dma_bytes, m68k_get_reg (NULL, M68K_REG_PC)); + 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, rate, dma_length, dma_bytes, m68k_get_reg (NULL, M68K_REG_PC)); #endif /* determinate DMA length in CPU cycles */ if (dma_length < dma_bytes) { /* DMA will be finished during this line */ - dma_cycles = (dma_length * m68cycles_per_line) / rate; + dma_cycles = (dma_length * MCYCLES_PER_LINE) / rate; dma_length = 0; } else @@ -324,7 +313,7 @@ void vdp_update_dma() { /* 68K COPY to V-RAM */ /* 68K is frozen during DMA operation */ - count_m68k += dma_cycles; + mcycles_68k += dma_cycles; #ifdef LOGVDP error("-->CPU frozen for %d cycles\n", dma_cycles); @@ -334,7 +323,7 @@ void vdp_update_dma() { /* VRAM Fill or VRAM Copy */ /* set DMA end cyles count */ - dma_endCycles = count_m68k + dma_cycles; + dma_endCycles = mcycles_68k + dma_cycles; #ifdef LOGVDP error("-->DMA ends in %d cycles\n", dma_cycles); @@ -348,7 +337,6 @@ void vdp_update_dma() /*--------------------------------------------------------------------------*/ /* VDP Ports handler */ /*--------------------------------------------------------------------------*/ - void vdp_ctrl_w(unsigned int data) { if (pending == 0) @@ -398,18 +386,23 @@ void vdp_ctrl_w(unsigned int data) } } - /* FIFO emulation: - --------------- - HDISP is 256*10/7 = approx. 366 cycles (same for both modes) - this gives: - H32: 16 accesses --> 366/16 = 23 cycles per access - H40: 20 accesses --> 366/20 = 18 cycles per access + /* + FIFO emulation (Chaos Engine/Soldier of Fortune, Double Clutch) + --------------------------------------------------------------- + + HDISP is 2560 mcycles (same in both modes) + + CPU access per line is limited during active display: + H32: 16 access --> 2560/16 = 160 cycles between access + H40: 18 access --> 2560/18 = 142 cycles between access + + FIFO access seems to require some additional cyles (VDP latency). + + Also note that VRAM access are byte wide, so one VRAM write (word) + takes twice CPU cycles. - VRAM access are byte wide --> VRAM writes takes 2x CPU cycles - Memory access requires some additional cyles, the following values - seems to work fine (see Chaos Engine/Soldier of Fortune) */ - fifo_latency = (reg[12] & 1) ? 27 : 30; + fifo_latency = (reg[12] & 1) ? 192 : 210; if ((code & 0x0F) == 0x01) fifo_latency = fifo_latency * 2; } @@ -442,7 +435,7 @@ unsigned int vdp_ctrl_r(void) else status ^= 0x200; /* update DMA Busy flag */ - if ((status & 2) && !dma_length && (count_m68k >= dma_endCycles)) + if ((status & 2) && !dma_length && (mcycles_68k >= dma_endCycles)) status &= 0xFFFD; unsigned int temp = status; @@ -452,7 +445,7 @@ unsigned int vdp_ctrl_r(void) temp |= 0x08; /* HBLANK flag (Sonic 3 and Sonic 2 "VS Modes", Lemmings 2, Mega Turrican) */ - if ((count_m68k % m68cycles_per_line) < 84) + if ((mcycles_68k % MCYCLES_PER_LINE) < 588) temp |= 0x04; /* clear pending flag */ @@ -462,21 +455,21 @@ unsigned int vdp_ctrl_r(void) status &= 0xFF9F; #ifdef LOGVDP - error("[%d(%d)][%d(%d)] VDP status read -> 0x%x (%x)\n", v_counter, count_m68k/488, count_m68k, count_m68k%488, temp, m68k_get_reg (NULL, M68K_REG_PC)); + error("[%d(%d)][%d(%d)] VDP status read -> 0x%x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, temp, m68k_get_reg (NULL, M68K_REG_PC)); #endif return (temp); } unsigned int vdp_hvc_r(void) { - uint8 hc = (hc_latch & 0x100) ? (hc_latch & 0xFF) : hctab[count_m68k % m68cycles_per_line]; + uint8 hc = (hc_latch & 0x100) ? (hc_latch & 0xFF) : hctab[mcycles_68k%MCYCLES_PER_LINE]; uint8 vc = vctab[v_counter]; /* interlace mode 2 */ if (im2_flag) vc = (vc << 1) | ((vc >> 7) & 1); #ifdef LOGVDP - error("[%d(%d)][%d(%d)] VDP HVC Read -> 0x%04x (%x)\n", v_counter, count_m68k/488, count_m68k, count_m68k%488,(vc << 8) | hc, m68k_get_reg (NULL, M68K_REG_PC)); + error("[%d(%d)][%d(%d)] VDP HVC Read -> 0x%04x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE,(vc << 8) | hc, m68k_get_reg (NULL, M68K_REG_PC)); #endif return ((vc << 8) | hc); } @@ -506,13 +499,13 @@ void vdp_data_w(unsigned int data) if (fifo_write_cnt == 0) { /* reset cycle counter */ - fifo_lastwrite = count_m68k; + fifo_lastwrite = mcycles_68k; /* FIFO is not empty anymore */ status &= 0xFDFF; } - /* increase write counter */ + /* increase FIFO word count */ fifo_write_cnt ++; /* is FIFO full ? */ @@ -522,7 +515,7 @@ void vdp_data_w(unsigned int data) /* VDP latency (Chaos Engine, Soldiers of Fortune, Double Clutch) */ if (fifo_write_cnt > 4) - count_m68k = fifo_lastwrite + fifo_latency; + mcycles_68k = fifo_lastwrite + fifo_latency; } } @@ -542,7 +535,7 @@ unsigned int vdp_data_r(void) case 0x00: /* VRAM */ temp = *(uint16 *) & vram[(addr & 0xFFFE)]; #ifdef LOGVDP - error("[%d(%d)][%d(%d)] VRAM 0x%x read -> 0x%x (%x)\n", v_counter, count_m68k/488, count_m68k, count_m68k%488, addr, temp, m68k_get_reg (NULL, M68K_REG_PC)); + 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; @@ -550,14 +543,14 @@ unsigned int vdp_data_r(void) 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, count_m68k/488, count_m68k, count_m68k%488, addr, temp, m68k_get_reg (NULL, M68K_REG_PC)); + 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)); #endif break; case 0x04: /* VSRAM */ temp = *(uint16 *) & vsram[(addr & 0x7E)]; #ifdef LOGVDP - error("[%d(%d)][%d(%d)] VSRAM 0x%x read -> 0x%x (%x)\n", v_counter, count_m68k/488, count_m68k, count_m68k%488, addr, temp, m68k_get_reg (NULL, M68K_REG_PC)); + 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 break; } @@ -576,7 +569,7 @@ unsigned int vdp_data_r(void) int vdp_int_ack_callback(int int_level) { #ifdef LOGVDP - error("[%d(%d)][%d(%d)] INT Level %d ack (%x)\n", v_counter, count_m68k/488, count_m68k, count_m68k%488,int_level, m68k_get_reg (NULL, M68K_REG_PC)); + error("[%d(%d)][%d(%d)] INT Level %d ack (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE,int_level, m68k_get_reg (NULL, M68K_REG_PC)); #endif /* VINT triggered ? */ @@ -597,11 +590,13 @@ int vdp_int_ack_callback(int int_level) } /* update IRQ status */ - irq_status = 0x10; + irq_status = 0; if (vint_pending && (reg[1] & 0x20)) - irq_status |= 6; + irq_status |= 0x16; else if (hint_pending && (reg[0] & 0x10)) - irq_status |= 4; + irq_status |= 0x14; + else + m68k_set_irq(0); return M68K_INT_ACK_AUTOVECTOR; } @@ -614,14 +609,15 @@ static inline void fifo_update() if (fifo_write_cnt > 0) { /* update FIFO reads */ - uint32 fifo_read = ((count_m68k - fifo_lastwrite) / fifo_latency); + uint32 fifo_read = ((mcycles_68k - fifo_lastwrite) / fifo_latency); if (fifo_read > 0) { fifo_write_cnt -= fifo_read; - if (fifo_write_cnt < 0) fifo_write_cnt = 0; + if (fifo_write_cnt < 0) + fifo_write_cnt = 0; /* update cycle count */ - fifo_lastwrite += fifo_read*fifo_latency; + fifo_lastwrite += (fifo_read * fifo_latency); } } } @@ -636,7 +632,7 @@ static inline void data_w(unsigned int data) case 0x01: /* VRAM */ #ifdef LOGVDP - error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, count_m68k/488, count_m68k, count_m68k%488, addr, data, m68k_get_reg (NULL, M68K_REG_PC)); + error("[%d(%d)][%d(%d)] VRAM 0x%x write -> 0x%x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, addr, data, m68k_get_reg (NULL, M68K_REG_PC)); #endif /* Byte-swap data if A0 is set */ @@ -663,7 +659,7 @@ static inline void data_w(unsigned int data) case 0x03: /* CRAM */ { #ifdef LOGVDP - error("[%d(%d)][%d(%d)] CRAM 0x%x write -> 0x%x (%x)\n", v_counter, count_m68k/488, count_m68k, count_m68k%488, addr, data, m68k_get_reg (NULL, M68K_REG_PC)); + error("[%d(%d)][%d(%d)] CRAM 0x%x write -> 0x%x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, addr, data, m68k_get_reg (NULL, M68K_REG_PC)); #endif uint16 *p = (uint16 *) &cram[(addr & 0x7E)]; data = PACK_CRAM (data & 0x0EEE); @@ -681,10 +677,10 @@ static inline void data_w(unsigned int data) if (border == index) color_update (0x00, *p); - /* CRAM modified during HBLANK */ - if (!(status & 8) && (reg[1]&0x40) && (count_m68k <= (line_m68k + 84))) + /* CRAM modified during HBLANK (Striker, Zero the Kamikaze, etc) */ + if (!(status & 8) && (reg[1]& 0x40) && (mcycles_68k <= (mcycles_vdp + 860))) { - /* remap current line (Striker) */ + /* remap current line */ remap_buffer(v_counter,bitmap.viewport.w + 2*bitmap.viewport.x); #ifdef LOGVDP error("Line remapped\n"); @@ -699,7 +695,7 @@ static inline void data_w(unsigned int data) case 0x05: /* VSRAM */ #ifdef LOGVDP - error("[%d(%d)][%d(%d)] VSRAM 0x%x write -> 0x%x (%x)\n", v_counter, count_m68k/488, count_m68k, count_m68k%488, addr, data, m68k_get_reg (NULL, M68K_REG_PC)); + error("[%d(%d)][%d(%d)] VSRAM 0x%x write -> 0x%x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, addr, data, m68k_get_reg (NULL, M68K_REG_PC)); #endif *(uint16 *) &vsram[(addr & 0x7E)] = data; break; @@ -716,14 +712,15 @@ static inline void data_w(unsigned int data) static inline void reg_w(unsigned int r, unsigned int d) { #ifdef LOGVDP - error("[%d(%d)][%d(%d)] VDP register %d write -> 0x%x (%x)\n", v_counter, count_m68k/488, count_m68k, count_m68k%488, r, d, m68k_get_reg (NULL, M68K_REG_PC)); + error("[%d(%d)][%d(%d)] VDP register %d write -> 0x%x (%x)\n", v_counter, mcycles_68k/MCYCLES_PER_LINE, mcycles_68k, mcycles_68k%MCYCLES_PER_LINE, r, d, m68k_get_reg (NULL, M68K_REG_PC)); #endif /* See if Mode 4 (SMS mode) is enabled According to official doc, VDP registers #11 to #23 can not be written unless bit2 in register #1 is set Fix Captain Planet & Avengers (Alt version), Bass Master Classic Pro Edition (they incidentally activate Mode 4) */ - if (!(reg[1] & 4) && (r > 10)) return; + if (!(reg[1] & 4) && (r > 10)) + return; switch(r) { @@ -734,8 +731,10 @@ static inline void reg_w(unsigned int r, unsigned int d) { /* update IRQ status */ irq_status = 0x50; - if (vint_pending && (reg[1] & 0x20)) irq_status |= 0x26; - else if (d & 0x10) irq_status |= 4; + if (vint_pending && (reg[1] & 0x20)) + irq_status |= 0x26; + else if (d & 0x10) + irq_status |= 4; } /* Palette bit */ @@ -759,8 +758,10 @@ static inline void reg_w(unsigned int r, unsigned int d) { /* update IRQ status */ irq_status = 0x50; - if (d & 0x20) irq_status |= 0x26; - else if (hint_pending && (reg[0] & 0x10)) irq_status |= 4; + if (d & 0x20) + irq_status |= 0x26; + else if (hint_pending && (reg[0] & 0x10)) + irq_status |= 4; } /* See if the viewport height has actually been changed */ @@ -772,27 +773,34 @@ static inline void reg_w(unsigned int r, unsigned int d) if (config.overscan) bitmap.viewport.y = ((vdp_pal ? 288 : 240) - bitmap.viewport.h) / 2; /* update VC table */ - if (vdp_pal) vctab = (d & 8) ? vc_pal_240 : vc_pal_224; + if (vdp_pal) + vctab = (d & 8) ? vc_pal_240 : vc_pal_224; } - /* Display enabled/blanked during "Horizontal Blanking" */ + /* Display status modified during Horizontal Blanking (Legend of Galahad, Lemmings 2, */ + /* Nigel Mansell's World Championship Racing, Deadly Moves, Power Athlete). */ + /* */ + /* Note that this is not entirely correct since we are cheating with the HBLANK period limits */ + /* and still redrawing the whole line. This is done because some game (PAL version of Nigel */ + /* Mansell's World Championship Racing actually) appear to disable display outside HBLANK. On */ + /* real hardware, the raster line would appear partially blanked. */ if (((d&0x40) != (reg[1]&0x40)) && !(status & 8)) { - if (count_m68k <= (hint_m68k + 120)) + if (mcycles_68k <= (hint_68k + 860)) { - /* Fixes the following games : - - Legend of Galahad, Lemmings 2, Nigel Mansell's World Championship Racing (display OFF) - - Deadly Moves, Power Athlete (display ON) - */ - /* NB: This is not entirely correct since we are a little too tolerant with the HBLANK period limits - while still redrawing the whole line. This is done because some games appear to write this - register outside HBLANK: on real hardware, the line would appear partially blanked. - */ reg[1] = d; - render_line(v_counter, 0); #ifdef LOGVDP - error("Line redrawn\n"); + error("Line redrawn (%d sprites) \n",object_index_count); #endif + /* If display was disabled during HBLANK (Mickey Mania 3D level), sprite processing is limited */ + /* Below values have been deducted from testing on this game, accurate emulation would require */ + /* to know exact sprite (pre)processing timings. Hopefully, they don't seem to break any other */ + /* games, so they might not be so much inaccurate. */ + if ((d&0x40) && (mcycles_68k % MCYCLES_PER_LINE >= 360) && (object_index_count > 5)) + object_index_count = 5; + + /* re-render line */ + render_line(v_counter, 0); } #ifdef LOGVDP else @@ -837,10 +845,10 @@ static inline void reg_w(unsigned int r, unsigned int d) border = d; color_update(0x00, *(uint16 *)&cram[(border << 1)]); - /* background color modified during Horizontal Blanking */ - if (!(status & 8) && (count_m68k <= (line_m68k + 84))) + /* Background color modified during Horizontal Blanking (Road Rash 1,2,3)*/ + if (!(status & 8) && (mcycles_68k <= (mcycles_vdp + 860))) { - /* remap entire line (see Road Rash I,II,III) */ + /* remap colors */ reg[7] = d; remap_buffer(v_counter,bitmap.viewport.w + 2*bitmap.viewport.x); #ifdef LOGVDP @@ -994,7 +1002,8 @@ static inline void dma_vbus (void) { /* Return $FFFF only when the Z80 isn't hogging the Z-bus. (e.g. Z80 isn't reset and 68000 has the bus) */ - if (source <= 0xa0ffff) temp = (zbusack ? *(uint16 *)(work_ram + (source & 0xffff)) : 0xffff); + if (source <= 0xa0ffff) + temp = ((zstate ^ 3) ? *(uint16 *)(work_ram + (source & 0xffff)) : 0xffff); /* The I/O chip and work RAM try to drive the data bus which results in both values being combined in random ways when read. @@ -1006,7 +1015,8 @@ static inline void dma_vbus (void) } /* All remaining locations access work RAM */ - else temp = *(uint16 *)(work_ram + (source & 0xffff)); + else + temp = *(uint16 *)(work_ram + (source & 0xffff)); source += 2; source = ((base & 0xFE0000) | (source & 0x1FFFF)); @@ -1059,12 +1069,12 @@ static inline void dma_fill(unsigned int data) /* write MSB */ data = (data >> 8) & 0xff; - /* detect internal SAT modification */ + /* intercept SAT writes */ if ((addr & sat_base_mask) == satb) { do { - /* update internal SAT (fix Battletech) */ + /* update internal SAT copy */ WRITE_BYTE(sat, (addr & sat_addr_mask)^1, data); WRITE_BYTE(vram, addr^1, data); MARK_BG_DIRTY (addr); diff --git a/source/vdp.h b/source/vdp.h index e08c4db..125340d 100644 --- a/source/vdp.h +++ b/source/vdp.h @@ -59,12 +59,10 @@ extern uint16 v_counter; extern uint32 dma_length; extern int32 fifo_write_cnt; extern uint32 fifo_lastwrite; -extern uint8 fifo_latency; extern uint8 im2_flag; extern uint8 interlaced; extern uint8 odd_frame; extern uint8 vdp_pal; -extern uint8 vdp_rate; extern uint16 lines_per_frame; extern uint8 *vctab; @@ -72,8 +70,8 @@ extern uint8 *hctab; extern uint8 vc_ntsc_224[262]; extern uint8 vc_pal_224[313]; extern uint8 vc_pal_240[313]; -extern uint8 cycle2hc32[488]; -extern uint8 cycle2hc40[488]; +extern uint8 cycle2hc32[3420]; +extern uint8 cycle2hc40[3420]; /* Function prototypes */ extern void vdp_init(void); diff --git a/source/z80/z80.c b/source/z80/z80.c index 88ea79e..2232926 100644 --- a/source/z80/z80.c +++ b/source/z80/z80.c @@ -1,7 +1,7 @@ /***************************************************************************** * * z80.c - * Portable Z80 emulator V3.9 + * Portable Z80 emulator V3.9 * * Copyright Juergen Buchmueller, all rights reserved. * @@ -17,42 +17,42 @@ * terms of its usage and license at any time, including retroactively * - This entire notice must remain in the source code. * - * TODO: - * - If LD A,I or LD A,R is interrupted, P/V flag gets reset, even if IFF2 - * was set before this instruction - * - Ideally, the tiny differences between Z80 types should be supported, - * currently known differences: - * - LD A,I/R P/V flag reset glitch is fixed on CMOS Z80 - * - OUT (C),0 outputs 0 on NMOS Z80, $FF on CMOS Z80 - * - SCF/CCF X/Y flags is ((flags | A) & 0x28) on SGS/SHARP/ZiLOG NMOS Z80, - * (flags & A & 0x28) on NEC NMOS Z80, other models unknown. - * However, people from the Speccy scene mention that SCF/CCF X/Y results - * are inconsistant and may be influenced by I and R registers. - * This Z80 emulator assumes a ZiLOG NMOS model. + * TODO: + * - If LD A,I or LD A,R is interrupted, P/V flag gets reset, even if IFF2 + * was set before this instruction + * - Ideally, the tiny differences between Z80 types should be supported, + * currently known differences: + * - LD A,I/R P/V flag reset glitch is fixed on CMOS Z80 + * - OUT (C),0 outputs 0 on NMOS Z80, $FF on CMOS Z80 + * - SCF/CCF X/Y flags is ((flags | A) & 0x28) on SGS/SHARP/ZiLOG NMOS Z80, + * (flags & A & 0x28) on NEC NMOS Z80, other models unknown. + * However, people from the Speccy scene mention that SCF/CCF X/Y results + * are inconsistant and may be influenced by I and R registers. + * This Z80 emulator assumes a ZiLOG NMOS model. * * Additional changes [Eke-Eke]: * - Discarded multi-chip support (unused) * - Fixed cycle counting for FD and DD prefixed instructions * - Fixed behavior of chained FD and DD prefixes (R register should be only incremented by one - * - Implemented cycle-accurate INI/IND (needed by SMS emulation) - * Changes in 3.9: - * - Fixed cycle counts for LD IYL/IXL/IYH/IXH,n [Marshmellow] - * - Fixed X/Y flags in CCF/SCF/BIT, ZEXALL is happy now [hap] - * - Simplified DAA, renamed MEMPTR (3.8) to WZ, added TODO [hap] - * - Fixed IM2 interrupt cycles [eke] + * - Implemented cycle-accurate INI/IND (needed by SMS emulation) + * Changes in 3.9: + * - Fixed cycle counts for LD IYL/IXL/IYH/IXH,n [Marshmellow] + * - Fixed X/Y flags in CCF/SCF/BIT, ZEXALL is happy now [hap] + * - Simplified DAA, renamed MEMPTR (3.8) to WZ, added TODO [hap] + * - Fixed IM2 interrupt cycles [eke] * Changes in 3.8 [Miodrag Milanovic]: * - Added MEMPTR register (according to informations provided * by Vladimir Kladov * - BIT n,(HL) now return valid values due to use of MEMPTR * - Fixed BIT 6,(XY+o) undocumented instructions - * Changes in 3.7 [Aaron Giles]: + * Changes in 3.7 [Aaron Giles]: * - Changed NMI handling. NMIs are now latched in set_irq_state * but are not taken there. Instead they are taken at the start of the * execute loop. * - Changed IRQ handling. IRQ state is set in set_irq_state but not taken * except during the inner execute loop. * - Removed x86 assembly hacks and obsolete timing loop catchers. - * Changes in 3.6: + * Changes in 3.6: * - Got rid of the code that would inexactly emulate a Z80, i.e. removed * all the #if Z80_EXACT #else branches. * - Removed leading underscores from local register name shortcuts as @@ -60,23 +60,23 @@ * - Renamed the registers inside the Z80 context to lower case to avoid * ambiguities (shortcuts would have had the same names as the fields * of the structure). - * Changes in 3.5: + * Changes in 3.5: * - Implemented OTIR, INIR, etc. without look-up table for PF flag. * [Ramsoft, Sean Young] - * Changes in 3.4: + * Changes in 3.4: * - Removed Z80-MSX specific code as it's not needed any more. * - Implemented DAA without look-up table [Ramsoft, Sean Young] - * Changes in 3.3: + * Changes in 3.3: * - Fixed undocumented flags XF & YF in the non-asm versions of CP, * and all the 16 bit arithmetic instructions. [Sean Young] - * Changes in 3.2: + * Changes in 3.2: * - Fixed undocumented flags XF & YF of RRCA, and CF and HF of * INI/IND/OUTI/OUTD/INIR/INDR/OTIR/OTDR [Sean Young] - * Changes in 3.1: + * Changes in 3.1: * - removed the REPEAT_AT_ONCE execution of LDIR/CPIR etc. opcodes * for readabilities sake and because the implementation was buggy * (and I was not able to find the difference) - * Changes in 3.0: + * Changes in 3.0: * - 'finished' switch to dynamically overrideable cycle count tables * Changes in 2.9: * - added methods to access and override the cycle count tables @@ -202,7 +202,8 @@ #define IFF2 Z80.iff2 #define HALT Z80.halt -int z80_ICount; +extern unsigned int mcycles_z80; + Z80_Regs Z80; static UINT32 EA; @@ -466,7 +467,7 @@ INLINE void BURNODD(int cycles, int opcodes, int cyclesum) if( cycles > 0 ) { R += (cycles / cyclesum) * opcodes; - z80_ICount -= (cycles / cyclesum) * cyclesum; + mcycles_z80 += (cycles / cyclesum) * cyclesum * 15; } } @@ -478,7 +479,7 @@ INLINE void BURNODD(int cycles, int opcodes, int cyclesum) /*************************************************************** * adjust cycle count by n T-states ***************************************************************/ -#define CC(prefix,opcode) z80_ICount -= cc[Z80_TABLE_##prefix][opcode] +#define CC(prefix,opcode) mcycles_z80 += cc[Z80_TABLE_##prefix][opcode] * 15 /*************************************************************** * execute an opcode @@ -950,20 +951,20 @@ INLINE UINT8 DEC(UINT8 value) /*************************************************************** * DAA ***************************************************************/ -#define DAA { \ - UINT8 a = A; \ - if (F & NF) { \ - if ((F&HF) | ((A&0xf)>9)) a-=6; \ - if ((F&CF) | (A>0x99)) a-=0x60; \ - } \ - else { \ - if ((F&HF) | ((A&0xf)>9)) a+=6; \ - if ((F&CF) | (A>0x99)) a+=0x60; \ - } \ +#define DAA { \ + UINT8 a = A; \ + if (F & NF) { \ + if ((F&HF) | ((A&0xf)>9)) a-=6; \ + if ((F&CF) | (A>0x99)) a-=0x60; \ + } \ + else { \ + if ((F&HF) | ((A&0xf)>9)) a+=6; \ + if ((F&CF) | (A>0x99)) a+=0x60; \ + } \ \ - F = (F&(CF|NF)) | (A>0x99) | ((A^a)&HF) | SZP[a]; \ - A = a; \ -} + F = (F&(CF|NF)) | (A>0x99) | ((A^a)&HF) | SZP[a]; \ + A = a; \ +} /*************************************************************** * AND n @@ -2068,7 +2069,7 @@ OP(dd,1f) { illegal_1(); op_1f(); } /* DB DD OP(dd,20) { illegal_1(); op_20(); } /* DB DD */ OP(dd,21) { IX = ARG16(); } /* LD IX,w */ -OP(dd,22) { EA = ARG16(); WM16( EA, &Z80.ix ); WZ = EA+1; } /* LD (w),IX */ +OP(dd,22) { EA = ARG16(); WM16( EA, &Z80.ix ); WZ = EA+1; } /* LD (w),IX */ OP(dd,23) { IX++; } /* INC IX */ OP(dd,24) { HX = INC(HX); } /* INC HX */ OP(dd,25) { HX = DEC(HX); } /* DEC HX */ @@ -2077,7 +2078,7 @@ OP(dd,27) { illegal_1(); op_27(); } /* DB DD OP(dd,28) { illegal_1(); op_28(); } /* DB DD */ OP(dd,29) { ADD16(ix,ix); } /* ADD IX,IX */ -OP(dd,2a) { EA = ARG16(); RM16( EA, &Z80.ix ); WZ = EA+1; } /* LD IX,(w) */ +OP(dd,2a) { EA = ARG16(); RM16( EA, &Z80.ix ); WZ = EA+1; } /* LD IX,(w) */ OP(dd,2b) { IX--; } /* DEC IX */ OP(dd,2c) { LX = INC(LX); } /* INC LX */ OP(dd,2d) { LX = DEC(LX); } /* DEC LX */ @@ -2359,7 +2360,7 @@ OP(fd,1f) { illegal_1(); op_1f(); } /* DB FD OP(fd,20) { illegal_1(); op_20(); } /* DB FD */ OP(fd,21) { IY = ARG16(); } /* LD IY,w */ -OP(fd,22) { EA = ARG16(); WM16( EA, &Z80.iy ); WZ = EA+1; } /* LD (w),IY */ +OP(fd,22) { EA = ARG16(); WM16( EA, &Z80.iy ); WZ = EA+1; } /* LD (w),IY */ OP(fd,23) { IY++; } /* INC IY */ OP(fd,24) { HY = INC(HY); } /* INC HY */ OP(fd,25) { HY = DEC(HY); } /* DEC HY */ @@ -2368,7 +2369,7 @@ OP(fd,27) { illegal_1(); op_27(); } /* DB FD OP(fd,28) { illegal_1(); op_28(); } /* DB FD */ OP(fd,29) { ADD16(iy,iy); } /* ADD IY,IY */ -OP(fd,2a) { EA = ARG16(); RM16( EA, &Z80.iy ); WZ = EA+1; } /* LD IY,(w) */ +OP(fd,2a) { EA = ARG16(); RM16( EA, &Z80.iy ); WZ = EA+1; } /* LD IY,(w) */ OP(fd,2b) { IY--; } /* DEC IY */ OP(fd,2c) { LY = INC(LY); } /* INC LY */ OP(fd,2d) { LY = DEC(LY); } /* DEC LY */ @@ -2695,7 +2696,7 @@ OP(ed,3f) { illegal_2(); } /* DB ED OP(ed,40) { B = IN(BC); F = (F & CF) | SZP[B]; } /* IN B,(C) */ OP(ed,41) { OUT(BC, B); } /* OUT (C),B */ OP(ed,42) { SBC16( bc ); } /* SBC HL,BC */ -OP(ed,43) { EA = ARG16(); WM16( EA, &Z80.bc ); WZ = EA+1; } /* LD (w),BC */ +OP(ed,43) { EA = ARG16(); WM16( EA, &Z80.bc ); WZ = EA+1; } /* LD (w),BC */ OP(ed,44) { NEG; } /* NEG */ OP(ed,45) { RETN; } /* RETN; */ OP(ed,46) { IM = 0; } /* IM 0 */ @@ -2704,7 +2705,7 @@ OP(ed,47) { LD_I_A; } /* LD I,A OP(ed,48) { C = IN(BC); F = (F & CF) | SZP[C]; } /* IN C,(C) */ OP(ed,49) { OUT(BC, C); } /* OUT (C),C */ OP(ed,4a) { ADC16( bc ); } /* ADC HL,BC */ -OP(ed,4b) { EA = ARG16(); RM16( EA, &Z80.bc ); WZ = EA+1; } /* LD BC,(w) */ +OP(ed,4b) { EA = ARG16(); RM16( EA, &Z80.bc ); WZ = EA+1; } /* LD BC,(w) */ OP(ed,4c) { NEG; } /* NEG */ OP(ed,4d) { RETI; } /* RETI */ OP(ed,4e) { IM = 0; } /* IM 0 */ @@ -2713,7 +2714,7 @@ OP(ed,4f) { LD_R_A; } /* LD R,A OP(ed,50) { D = IN(BC); F = (F & CF) | SZP[D]; } /* IN D,(C) */ OP(ed,51) { OUT(BC, D); } /* OUT (C),D */ OP(ed,52) { SBC16( de ); } /* SBC HL,DE */ -OP(ed,53) { EA = ARG16(); WM16( EA, &Z80.de ); WZ = EA+1; } /* LD (w),DE */ +OP(ed,53) { EA = ARG16(); WM16( EA, &Z80.de ); WZ = EA+1; } /* LD (w),DE */ OP(ed,54) { NEG; } /* NEG */ OP(ed,55) { RETN; } /* RETN; */ OP(ed,56) { IM = 1; } /* IM 1 */ @@ -2722,7 +2723,7 @@ OP(ed,57) { LD_A_I; } /* LD A,I OP(ed,58) { E = IN(BC); F = (F & CF) | SZP[E]; } /* IN E,(C) */ OP(ed,59) { OUT(BC, E); } /* OUT (C),E */ OP(ed,5a) { ADC16( de ); } /* ADC HL,DE */ -OP(ed,5b) { EA = ARG16(); RM16( EA, &Z80.de ); WZ = EA+1; } /* LD DE,(w) */ +OP(ed,5b) { EA = ARG16(); RM16( EA, &Z80.de ); WZ = EA+1; } /* LD DE,(w) */ OP(ed,5c) { NEG; } /* NEG */ OP(ed,5d) { RETI; } /* RETI */ OP(ed,5e) { IM = 2; } /* IM 2 */ @@ -2731,7 +2732,7 @@ OP(ed,5f) { LD_A_R; } /* LD A,R OP(ed,60) { H = IN(BC); F = (F & CF) | SZP[H]; } /* IN H,(C) */ OP(ed,61) { OUT(BC, H); } /* OUT (C),H */ OP(ed,62) { SBC16( hl ); } /* SBC HL,HL */ -OP(ed,63) { EA = ARG16(); WM16( EA, &Z80.hl ); WZ = EA+1; } /* LD (w),HL */ +OP(ed,63) { EA = ARG16(); WM16( EA, &Z80.hl ); WZ = EA+1; } /* LD (w),HL */ OP(ed,64) { NEG; } /* NEG */ OP(ed,65) { RETN; } /* RETN; */ OP(ed,66) { IM = 0; } /* IM 0 */ @@ -2740,7 +2741,7 @@ OP(ed,67) { RRD; } /* RRD (HL) OP(ed,68) { L = IN(BC); F = (F & CF) | SZP[L]; } /* IN L,(C) */ OP(ed,69) { OUT(BC, L); } /* OUT (C),L */ OP(ed,6a) { ADC16( hl ); } /* ADC HL,HL */ -OP(ed,6b) { EA = ARG16(); RM16( EA, &Z80.hl ); WZ = EA+1; } /* LD HL,(w) */ +OP(ed,6b) { EA = ARG16(); RM16( EA, &Z80.hl ); WZ = EA+1; } /* LD HL,(w) */ OP(ed,6c) { NEG; } /* NEG */ OP(ed,6d) { RETI; } /* RETI */ OP(ed,6e) { IM = 0; } /* IM 0 */ @@ -2749,14 +2750,14 @@ OP(ed,6f) { RLD; } /* RLD (HL) OP(ed,70) { UINT8 res = IN(BC); F = (F & CF) | SZP[res]; } /* IN 0,(C) */ OP(ed,71) { OUT(BC, 0); } /* OUT (C),0 */ OP(ed,72) { SBC16( sp ); } /* SBC HL,SP */ -OP(ed,73) { EA = ARG16(); WM16( EA, &Z80.sp ); WZ = EA+1; } /* LD (w),SP */ +OP(ed,73) { EA = ARG16(); WM16( EA, &Z80.sp ); WZ = EA+1; } /* LD (w),SP */ OP(ed,74) { NEG; } /* NEG */ OP(ed,75) { RETN; } /* RETN; */ OP(ed,76) { IM = 1; } /* IM 1 */ OP(ed,77) { illegal_2(); } /* DB ED,77 */ -OP(ed,78) { A = IN(BC); F = (F & CF) | SZP[A]; WZ = BC+1; } /* IN E,(C) */ -OP(ed,79) { OUT(BC, A); WZ = BC + 1; } /* OUT (C),A */ +OP(ed,78) { A = IN(BC); F = (F & CF) | SZP[A]; WZ = BC+1; } /* IN E,(C) */ +OP(ed,79) { OUT(BC, A); WZ = BC + 1; } /* OUT (C),A */ OP(ed,7a) { ADC16( sp ); } /* ADC HL,SP */ OP(ed,7b) { EA = ARG16(); RM16( EA, &Z80.sp ); WZ = EA+1; } /* LD SP,(w) */ OP(ed,7c) { NEG; } /* NEG */ @@ -2914,7 +2915,7 @@ OP(ed,ff) { illegal_2(); } /* DB ED **********************************************************/ OP(op,00) { } /* NOP */ OP(op,01) { BC = ARG16(); } /* LD BC,w */ -OP(op,02) { WM( BC, A ); WZ_L = (BC + 1) & 0xFF; WZ_H = A; } /* LD (BC),A */ +OP(op,02) { WM( BC, A ); WZ_L = (BC + 1) & 0xFF; WZ_H = A; } /* LD (BC),A */ OP(op,03) { BC++; } /* INC BC */ OP(op,04) { B = INC(B); } /* INC B */ OP(op,05) { B = DEC(B); } /* DEC B */ @@ -2923,7 +2924,7 @@ OP(op,07) { RLCA; OP(op,08) { EX_AF; } /* EX AF,AF' */ OP(op,09) { ADD16(hl, bc); } /* ADD HL,BC */ -OP(op,0a) { A = RM( BC ); WZ=BC+1; } /* LD A,(BC) */ +OP(op,0a) { A = RM( BC ); WZ=BC+1; } /* LD A,(BC) */ OP(op,0b) { BC--; } /* DEC BC */ OP(op,0c) { C = INC(C); } /* INC C */ OP(op,0d) { C = DEC(C); } /* DEC C */ @@ -2932,7 +2933,7 @@ OP(op,0f) { RRCA; OP(op,10) { B--; JR_COND( B, 0x10 ); } /* DJNZ o */ OP(op,11) { DE = ARG16(); } /* LD DE,w */ -OP(op,12) { WM( DE, A ); WZ_L = (DE + 1) & 0xFF; WZ_H = A; } /* LD (DE),A */ +OP(op,12) { WM( DE, A ); WZ_L = (DE + 1) & 0xFF; WZ_H = A; } /* LD (DE),A */ OP(op,13) { DE++; } /* INC DE */ OP(op,14) { D = INC(D); } /* INC D */ OP(op,15) { D = DEC(D); } /* DEC D */ @@ -2941,7 +2942,7 @@ OP(op,17) { RLA; OP(op,18) { JR(); } /* JR o */ OP(op,19) { ADD16(hl, de); } /* ADD HL,DE */ -OP(op,1a) { A = RM( DE ); WZ=DE+1; } /* LD A,(DE) */ +OP(op,1a) { A = RM( DE ); WZ=DE+1; } /* LD A,(DE) */ OP(op,1b) { DE--; } /* DEC DE */ OP(op,1c) { E = INC(E); } /* INC E */ OP(op,1d) { E = DEC(E); } /* DEC E */ @@ -2950,7 +2951,7 @@ OP(op,1f) { RRA; OP(op,20) { JR_COND( !(F & ZF), 0x20 ); } /* JR NZ,o */ OP(op,21) { HL = ARG16(); } /* LD HL,w */ -OP(op,22) { EA = ARG16(); WM16( EA, &Z80.hl ); WZ = EA+1; } /* LD (w),HL */ +OP(op,22) { EA = ARG16(); WM16( EA, &Z80.hl ); WZ = EA+1; } /* LD (w),HL */ OP(op,23) { HL++; } /* INC HL */ OP(op,24) { H = INC(H); } /* INC H */ OP(op,25) { H = DEC(H); } /* DEC H */ @@ -2959,7 +2960,7 @@ OP(op,27) { DAA; OP(op,28) { JR_COND( F & ZF, 0x28 ); } /* JR Z,o */ OP(op,29) { ADD16(hl, hl); } /* ADD HL,HL */ -OP(op,2a) { EA = ARG16(); RM16( EA, &Z80.hl ); WZ = EA+1; } /* LD HL,(w) */ +OP(op,2a) { EA = ARG16(); RM16( EA, &Z80.hl ); WZ = EA+1; } /* LD HL,(w) */ OP(op,2b) { HL--; } /* DEC HL */ OP(op,2c) { L = INC(L); } /* INC L */ OP(op,2d) { L = DEC(L); } /* DEC L */ @@ -2968,7 +2969,7 @@ OP(op,2f) { A ^= 0xff; F = (F&(SF|ZF|PF|CF))|HF|NF|(A&(YF|XF)); OP(op,30) { JR_COND( !(F & CF), 0x30 ); } /* JR NC,o */ OP(op,31) { SP = ARG16(); } /* LD SP,w */ -OP(op,32) { EA = ARG16(); WM( EA, A ); WZ_L=(EA+1)&0xFF;WZ_H=A; } /* LD (w),A */ +OP(op,32) { EA = ARG16(); WM( EA, A ); WZ_L=(EA+1)&0xFF;WZ_H=A; } /* LD (w),A */ OP(op,33) { SP++; } /* INC SP */ OP(op,34) { WM( HL, INC(RM(HL)) ); } /* INC (HL) */ OP(op,35) { WM( HL, DEC(RM(HL)) ); } /* DEC (HL) */ @@ -2977,7 +2978,7 @@ OP(op,37) { F = (F & (SF|ZF|YF|XF|PF)) | CF | (A & (YF|XF)); OP(op,38) { JR_COND( F & CF, 0x38 ); } /* JR C,o */ OP(op,39) { ADD16(hl, sp); } /* ADD HL,SP */ -OP(op,3a) { EA = ARG16(); A = RM( EA ); WZ = EA+1; } /* LD A,(w) */ +OP(op,3a) { EA = ARG16(); A = RM( EA ); WZ = EA+1; } /* LD A,(w) */ OP(op,3b) { SP--; } /* DEC SP */ OP(op,3c) { A = INC(A); } /* INC A */ OP(op,3d) { A = DEC(A); } /* DEC A */ @@ -3138,7 +3139,7 @@ OP(op,c6) { ADD(ARG()); OP(op,c7) { RST(0x00); } /* RST 0 */ OP(op,c8) { RET_COND( F & ZF, 0xc8 ); } /* RET Z */ -OP(op,c9) { POP( pc ); WZ=PCD; } /* RET */ +OP(op,c9) { POP( pc ); WZ=PCD; } /* RET */ OP(op,ca) { JP_COND( F & ZF ); } /* JP Z,a */ OP(op,cb) { R++; EXEC(cb,ROP()); } /* **** CB xx */ OP(op,cc) { CALL_COND( F & ZF, 0xcc ); } /* CALL Z,a */ @@ -3158,7 +3159,7 @@ OP(op,d7) { RST(0x10); OP(op,d8) { RET_COND( F & CF, 0xd8 ); } /* RET C */ OP(op,d9) { EXX; } /* EXX */ OP(op,da) { JP_COND( F & CF ); } /* JP C,a */ -OP(op,db) { unsigned n = ARG() | (A << 8); A = IN( n ); WZ = n + 1; } /* IN A,(n) */ +OP(op,db) { unsigned n = ARG() | (A << 8); A = IN( n ); WZ = n + 1; } /* IN A,(n) */ OP(op,dc) { CALL_COND( F & CF, 0xdc ); } /* CALL C,a */ OP(op,dd) { R++; EXEC(dd,ROP()); } /* **** DD xx */ OP(op,de) { SBC(ARG()); } /* SBC A,n */ @@ -3224,7 +3225,7 @@ static void take_interrupt(void) RM16( irq_vector, &Z80.pc ); LOG(("Z80 #%d IM2 [$%04x] = $%04x\n",cpu_getactivecpu() , irq_vector, PCD)); /* CALL $xxxx + 'interrupt latency' cycles */ - z80_ICount -= cc[Z80_TABLE_op][0xcd] + cc[Z80_TABLE_ex][0xff]; + mcycles_z80 += (cc[Z80_TABLE_op][0xcd] + cc[Z80_TABLE_ex][0xff]) * 15; } else /* Interrupt mode 1. RST 38h */ @@ -3234,7 +3235,7 @@ static void take_interrupt(void) PUSH( pc ); PCD = 0x0038; /* RST $38 + 'interrupt latency' cycles */ - z80_ICount -= cc[Z80_TABLE_op][0xff] + cc[Z80_TABLE_ex][0xff]; + mcycles_z80 += (cc[Z80_TABLE_op][0xff] + cc[Z80_TABLE_ex][0xff]) * 15; } else { @@ -3248,18 +3249,18 @@ static void take_interrupt(void) PUSH( pc ); PCD = irq_vector & 0xffff; /* CALL $xxxx + 'interrupt latency' cycles */ - z80_ICount -= cc[Z80_TABLE_op][0xcd] + cc[Z80_TABLE_ex][0xff]; + mcycles_z80 += (cc[Z80_TABLE_op][0xcd] + cc[Z80_TABLE_ex][0xff]) * 15; break; case 0xc30000: /* jump */ PCD = irq_vector & 0xffff; /* JP $xxxx + 2 cycles */ - z80_ICount -= cc[Z80_TABLE_op][0xc3] + cc[Z80_TABLE_ex][0xff]; + mcycles_z80 += (cc[Z80_TABLE_op][0xc3] + cc[Z80_TABLE_ex][0xff]) * 15; break; default: /* rst (or other opcodes?) */ PUSH( pc ); PCD = irq_vector & 0x0038; /* RST $xx + 2 cycles */ - z80_ICount -= cc[Z80_TABLE_op][0xff] + cc[Z80_TABLE_ex][0xff]; + mcycles_z80 += (cc[Z80_TABLE_op][0xff] + cc[Z80_TABLE_ex][0xff]) * 15; break; } } @@ -3404,12 +3405,10 @@ void z80_exit(void) } /**************************************************************************** - * Execute 'cycles' T-states. Return number of T-states really executed + * Run until given cycle count ****************************************************************************/ -int z80_execute(int cycles) +void z80_run(int cycles) { - z80_ICount = cycles; - /* check for NMIs on the way in; they can only be set externally */ /* via timers, and can't be dynamically enabled, so it is safe */ /* to just check here */ @@ -3422,25 +3421,23 @@ int z80_execute(int cycles) PUSH( pc ); PCD = 0x0066; WZ=PCD; - z80_ICount -= 11; + mcycles_z80 += 11*15; Z80.nmi_pending = FALSE; } - while( z80_ICount > 0 ) + while( mcycles_z80 < cycles ) { /* check for IRQs before each instruction */ if (Z80.irq_state != CLEAR_LINE && IFF1 && !Z80.after_ei) take_interrupt(); Z80.after_ei = FALSE; - if (z80_ICount > 0) + if (mcycles_z80 < cycles) { R++; EXEC_INLINE(op,ROP()); } } - - return cycles - z80_ICount; } /**************************************************************************** @@ -3453,7 +3450,7 @@ void z80_burn(int cycles) /* NOP takes 4 cycles per instruction */ int n = (cycles + 3) / 4; R += n; - z80_ICount -= 4 * n; + mcycles_z80 += 4 * n * 15; } } diff --git a/source/z80/z80.h b/source/z80/z80.h index 7cb9eed..b9e4416 100644 --- a/source/z80/z80.h +++ b/source/z80/z80.h @@ -40,13 +40,12 @@ typedef struct } Z80_Regs; -extern int z80_ICount; extern Z80_Regs Z80; void z80_init(int index, int clock, const void *config, int (*irqcallback)(int)); void z80_reset (void); void z80_exit (void); -int z80_execute(int cycles); +void z80_run(int cycles); void z80_burn(int cycles); void z80_get_context (void *dst); void z80_set_context (void *src);