------

* 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)
This commit is contained in:
ekeeke31 2010-01-24 11:41:53 +00:00
parent ac4de61944
commit 2b78421402
38 changed files with 1579 additions and 931 deletions

View File

@ -8,32 +8,56 @@ Genesis Plus GX 1.4.0 (??/??/????) (Eke-Eke)
* modified SN76489 cut-off frequency * modified SN76489 cut-off frequency
* added an option to boost SN76489 Noise Channel * added an option to boost SN76489 Noise Channel
* removed outdated Gens YM2612 core * 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) * improved YM2612 LFO emulation accuracy (fixes "Spider-Man & Venom : Separation Anxiety" intro music)
* fixed YM2612 context saving/loading. * fixed YM2612 context saving/loading.
* added 3-Band EQ for fully configurable sound filtering (thanks to Neil C) * added 3-Band EQ for fully configurable sound filtering (thanks to Neil C)
* implemented faster FIR resampler, dropped libsamplerate support (thanks to Blargg & AamirM) * 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. * fixed 2-Cell vertical scrolling when column 0 is shifted.
* added support for 2-Cell vertical scrolling in Interlaced 2 mode. * added support for 2-Cell vertical scrolling in Interlaced 2 mode.
* fixed lightgun auto detection: fixes cursor position in Lethal Enforcers II * 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) * 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 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 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 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 S&K "Lock-On" hardware emulation ("lock" any games to Sonic & Knuckles)
* added Cartridge "hot swap" feature (swap games without reseting the virtual console) * 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] [Gamecube/Wii]
* improved audio/video synchronization: fixes video skipping issues in 60Hz modes * improved audio/video synchronization (see above)
* fixed stability issues and some potential memory leaks * 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 * added internal screenshot feature
* improved lightgun cursors * improved lightgun cursors
* implemented new FONT & GUI engines: use internal IPL FONT, GX hardware & multithreading for fast rendering. * new FONT & GUI engines: use internal IPL FONT, GX hardware rendering, sound support & multithreading.
* implemented new interface: incl. IR pointing, game snapshots, menu effects, sound effects, BGM... * new emulator interface design: incl. IR pointing, game snapshots, menu effects, sound effects, BGM...
(check the README for more details) (check the README for more details)

View File

@ -25,28 +25,17 @@
t_input input; t_input input;
/***************************************************************************** /************************************************************************************/
* LIGHTGUN specific functions /* */
* /* H-counter values returned in H40 & H32 modes */
*****************************************************************************/ /* */
/* H counter values for a 256-pixel wide display (342 pixel max.) */ /* Inside VDP, dot counter register is 9-bit, with only upper 8 bits being returned */
static const uint8 hc_256[171] = { /* */
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* The number of dots per raster line is 342 in H32 mode and 420 in H40 mode */
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, static const uint8 hc_320[210] =
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] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 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, 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, 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 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) static inline void lightgun_reset(int num)
{ {
input.analog[num][0] = bitmap.viewport.w >> 1; input.analog[num][0] = bitmap.viewport.w >> 1;

View File

@ -23,16 +23,14 @@
#include "shared.h" #include "shared.h"
uint8 bios_rom[0x10000]; /* BIOS rom */ uint8 bios_rom[0x10000]; /* OS ROM */
uint8 work_ram[0x10000]; /* 68K work RAM */ uint8 work_ram[0x10000]; /* 68K RAM */
uint8 zram[0x2000]; /* Z80 work RAM */ uint8 zram[0x2000]; /* Z80 RAM */
uint8 zbusreq; /* /BUSREQ from Z80 */ uint32 zirq; /* /IRQ to Z80 */
uint8 zreset; /* /RESET to Z80 */ uint32 zstate; /* Z80 bus state (d0 = BUSACK, d1 = /RESET) */
uint8 zbusack; /* /BUSACK to Z80 */ uint32 zbank; /* Z80 bank window address */
uint8 zirq; /* /IRQ to Z80 */ uint32 gen_running; /* 0: cpu are in locked state */
uint32 zbank; /* Address of Z80 bank window */ int32 resetline; /* soft reset is triggered on a random line (X-Men 2, Eternal Champions) */
uint8 gen_running;
int32 resetline;
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/* Init, reset, shutdown functions */ /* Init, reset, shutdown functions */
@ -132,28 +130,24 @@ void gen_reset(uint32 hard_reset)
memset (work_ram, 0x00, sizeof (work_ram)); memset (work_ram, 0x00, sizeof (work_ram));
memset (zram, 0x00, sizeof (zram)); memset (zram, 0x00, sizeof (zram));
/* TMSS BIOS */ /* TMSS BIOS support */
if (config.bios_enabled == 3) if (config.bios_enabled == 3)
{
m68k_memory_map[0].base = bios_rom; m68k_memory_map[0].base = bios_rom;
/* Reset CPU cycle counts */
mcycles_68k = 0;
mcycles_z80 = 0;
} }
count_m68k = 0; zstate = 0; /* Z80 is reset & has control of the bus */
count_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 */ zirq = 0; /* No interrupts occuring */
zbank = 0; /* Assume default bank is $000000-$007FFF */ zbank = 0; /* Assume default bank is $000000-$007FFF */
/* reset CPUs */ /* Reset CPUs */
resetline = -1;
gen_running = 1;
m68k_pulse_reset(); m68k_pulse_reset();
z80_reset(); z80_reset();
fm_reset();
} }
void gen_shutdown(void) void gen_shutdown(void)
@ -166,74 +160,66 @@ void gen_shutdown(void)
-----------------------------------------------------------------------*/ -----------------------------------------------------------------------*/
void gen_busreq_w(uint32 state) void gen_busreq_w(uint32 state)
{ {
uint32 z80_cycles_to_run;
if (state) if (state)
{ {
/* Bus Request */ /* Bus requested */
if (!zbusreq && zreset) if (zstate == 1)
{ {
/* Z80 stopped */ /* Z80 is stopped */
/* z80 was ON during the last 68k cycles */ /* Z80 was ON during the last 68k cycles */
/* we execute the appropriate number of z80 cycles */ z80_run(mcycles_68k);
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);
} }
/* update Z80 bus status */
zstate |= 2;
} }
else else
{ {
/* Bus released */ /* Bus released */
if (zbusreq && zreset) if (zstate == 3)
{ {
/* Z80 started */ /* Z80 is restarted */
/* z80 was OFF during the last 68k cycles */ /* Z80 was OFF during the last 68k cycles */
/* we burn the appropriate number of z80 cycles */ mcycles_z80 = mcycles_68k;
z80_cycles_to_run = line_z80 + ((count_m68k - line_m68k)*7)/15;
count_z80 = z80_cycles_to_run;
}
} }
zbusreq = state; /* update Z80 bus status */
zbusack = 1 ^ (zbusreq & zreset); zstate &= 1;
}
} }
void gen_reset_w(uint32 state) void gen_reset_w(uint32 state)
{ {
uint32 z80_cycles_to_run;
if (state) if (state)
{ {
/* stop RESET process */ /* stop RESET process */
if (!zbusreq && !zreset) if (!zstate)
{ {
/* Z80 started */ /* Z80 is restarted */
/* z80 was OFF during the last 68k cycles */ /* Z80 was OFF during the last cycles */
/* we burn the appropriate number of z80 cycles */ mcycles_z80 = mcycles_68k;
z80_cycles_to_run = line_z80 + ((count_m68k - line_m68k)*7)/15;
count_z80 = z80_cycles_to_run;
} }
/* update Z80 bus status */
zstate |= 1;
} }
else else
{ {
/* start RESET process */ /* start RESET process */
if (!zbusreq && zreset) if (zstate == 1)
{ {
/* Z80 stopped */ /* Z80 stopped */
/* z80 was ON during the last 68k cycles */ /* z80 was ON during the last 68k cycles */
/* we execute the appropriate number of z80 cycles */ z80_run(mcycles_68k);
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);
} }
/* Reset Z80 & YM2612 */ /* Reset Z80 & YM2612 */
z80_reset(); z80_reset();
fm_reset(); fm_reset();
}
zreset = state; /* update Z80 bus status */
zbusack = 1 ^ (zbusreq & zreset); zstate &= 2;
}
} }
void gen_bank_w (uint32 state) void gen_bank_w (uint32 state)

View File

@ -28,12 +28,10 @@
extern uint8 bios_rom[0x10000]; extern uint8 bios_rom[0x10000];
extern uint8 work_ram[0x10000]; extern uint8 work_ram[0x10000];
extern uint8 zram[0x2000]; extern uint8 zram[0x2000];
extern uint8 zbusreq; extern uint32 zirq;
extern uint8 zbusack;
extern uint8 zreset;
extern uint8 zirq;
extern uint32 zbank; extern uint32 zbank;
extern uint8 gen_running; extern uint32 zstate;
extern uint32 gen_running;
extern int32 resetline; extern int32 resetline;
/* Function prototypes */ /* Function prototypes */

View File

@ -740,9 +740,15 @@ static void soundmenu ()
sprintf (items[0].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF"); sprintf (items[0].text, "High-Quality FM: %s", config.hq_fm ? "ON":"OFF");
if (cart.romsize) if (cart.romsize)
{ {
/* save YM2612 context */
unsigned char *temp = memalign(32,YM2612GetContextSize()); unsigned char *temp = memalign(32,YM2612GetContextSize());
if (temp) memcpy(temp, YM2612GetContextPtr(), 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) if (temp)
{ {
YM2612Restore(temp); YM2612Restore(temp);
@ -923,13 +929,26 @@ static void systemmenu ()
/* force region & cpu mode */ /* force region & cpu mode */
set_region(); set_region();
/* reinitialize timings */ /* update framerate */
system_init(); float framerate;
memfile_autoload(config.sram_auto,-1); 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()); unsigned char *temp = memalign(32,YM2612GetContextSize());
if (temp) if (temp)
memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize()); 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) if (temp)
{ {
YM2612Restore(temp); YM2612Restore(temp);
@ -937,7 +956,7 @@ static void systemmenu ()
} }
/* reinitialize HVC tables */ /* 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; hctab = (reg[12] & 1) ? cycle2hc40 : cycle2hc32;
/* reinitialize overscan area */ /* reinitialize overscan area */
@ -963,8 +982,8 @@ static void systemmenu ()
sprintf (items[3].text, "System BIOS: %s", (config.bios_enabled & 1) ? "ON":"OFF"); sprintf (items[3].text, "System BIOS: %s", (config.bios_enabled & 1) ? "ON":"OFF");
if (cart.romsize) if (cart.romsize)
{ {
system_init (); system_init();
system_reset (); system_reset();
memfile_autoload(config.sram_auto,-1); memfile_autoload(config.sram_auto,-1);
} }
break; break;
@ -984,9 +1003,9 @@ static void systemmenu ()
if (cart.romsize) if (cart.romsize)
{ {
system_reset (); /* clear any patches first */ system_reset(); /* clear any patches first */
system_init (); system_init();
system_reset (); system_reset();
memfile_autoload(config.sram_auto,-1); memfile_autoload(config.sram_auto,-1);
} }
break; break;
@ -1035,8 +1054,7 @@ static void videomenu ()
else else
sprintf (items[1].text, "TV Mode: 50/60HZ"); sprintf (items[1].text, "TV Mode: 50/60HZ");
sprintf (items[2].text, "Bilinear Filter: %s", sprintf (items[2].text, "Bilinear Filter: %s", config.bilinear ? " ON" : "OFF");
config.bilinear ? " ON" : "OFF");
if (config.ntsc == 1) if (config.ntsc == 1)
sprintf (items[3].text, "NTSC Filter: COMPOSITE"); sprintf (items[3].text, "NTSC Filter: COMPOSITE");
@ -1047,15 +1065,14 @@ static void videomenu ()
else else
sprintf (items[3].text, "NTSC Filter: OFF"); sprintf (items[3].text, "NTSC Filter: OFF");
sprintf (items[4].text, "Borders: %s", sprintf (items[4].text, "Borders: %s", config.overscan ? "ON" : "OFF");
config.overscan ? "ON" : "OFF");
if (config.aspect == 1) if (config.aspect == 1)
sprintf (items[5].text,"Aspect: ORIGINAL (4:3)"); sprintf (items[5].text,"Aspect: ORIGINAL (4:3)");
else if (config.aspect == 2) else if (config.aspect == 2)
sprintf (items[5].text, "Aspect: ORIGINAL (16:9)"); sprintf (items[5].text, "Aspect: ORIGINAL (16:9)");
else else
sprintf (items[5].text, "Aspect: SCALED"); sprintf (items[5].text, "Aspect: SCALE");
sprintf (items[6].text, "Screen Position: (%s%02d,%s%02d)", sprintf (items[6].text, "Screen Position: (%s%02d,%s%02d)",
(config.xshift < 0) ? "":"+", config.xshift, (config.xshift < 0) ? "":"+", config.xshift,
@ -1104,20 +1121,49 @@ static void videomenu ()
break; break;
case 1: /*** tv mode ***/ case 1: /*** tv mode ***/
if (config.render == 2) break; if (config.render != 2)
{
config.tv_mode = (config.tv_mode + 1) % 3; 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) if (config.tv_mode == 0)
sprintf (items[1].text, "TV Mode: 60HZ"); sprintf (items[1].text, "TV Mode: 60HZ");
else if (config.tv_mode == 1) else if (config.tv_mode == 1)
sprintf (items[1].text, "TV Mode: 50HZ"); sprintf (items[1].text, "TV Mode: 50HZ");
else else
sprintf (items[1].text, "TV Mode: 50/60HZ"); sprintf (items[1].text, "TV Mode: 50/60HZ");
}
else
{
GUI_WaitPrompt("Error","Progressive Mode is 60hz only !\n");
}
break; break;
case 2: /*** bilinear filtering ***/ case 2: /*** bilinear filtering ***/
config.bilinear ^= 1; config.bilinear ^= 1;
sprintf (items[2].text, "Bilinear Filter: %s", sprintf (items[2].text, "Bilinear Filter: %s", config.bilinear ? " ON" : "OFF");
config.bilinear ? " ON" : "OFF");
break; break;
case 3: /*** NTSC filter ***/ case 3: /*** NTSC filter ***/
@ -1134,8 +1180,7 @@ static void videomenu ()
case 4: /*** overscan emulation ***/ case 4: /*** overscan emulation ***/
config.overscan ^= 1; config.overscan ^= 1;
sprintf (items[4].text, "Overscan Color: %s", sprintf (items[4].text, "Borders: %s", config.overscan ? "ON" : "OFF");
config.overscan ? "ORIGINAL" : "BLACK");
break; break;
case 5: /*** aspect ratio ***/ case 5: /*** aspect ratio ***/
@ -1189,6 +1234,10 @@ static void videomenu ()
(config.xshift < 0) ? "":"+", config.xshift, (config.xshift < 0) ? "":"+", config.xshift,
(config.yshift < 0) ? "":"+", config.yshift); (config.yshift < 0) ? "":"+", config.yshift);
} }
else
{
GUI_WaitPrompt("Error","Please load a game first !\n");
}
break; break;
case 7: /*** screen scaling ***/ case 7: /*** screen scaling ***/
@ -1213,6 +1262,10 @@ static void videomenu ()
(config.xscale < 0) ? "":"+", config.xscale, (config.xscale < 0) ? "":"+", config.xscale,
(config.yscale < 0) ? "":"+", config.yscale); (config.yscale < 0) ? "":"+", config.yscale);
} }
else
{
GUI_WaitPrompt("Error","Please load a game first !\n");
}
break; break;
case -1: case -1:
@ -2402,8 +2455,8 @@ void MainMenu (void)
GUI_DeleteMenu(m); GUI_DeleteMenu(m);
gxClearScreen((GXColor)BLACK); gxClearScreen((GXColor)BLACK);
gxSetScreen(); gxSetScreen();
audio_init(snd.sample_rate,snd.frame_rate);
system_init(); system_init();
audio_init(48000,vdp_pal?50.0:(1000000.0/16715.0));
system_reset(); system_reset();
memfile_autoload(config.sram_auto,-1); memfile_autoload(config.sram_auto,-1);
quit = 1; quit = 1;

View File

@ -25,7 +25,7 @@
#include "shared.h" #include "shared.h"
/* DMA soundbuffers (required to be 32-bytes aligned) /* 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: To prevent audio clashes, we use double buffering technique:
one buffer is the active DMA buffer one buffer is the active DMA buffer
the other one is the current work buffer (updated during frame emulation) 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 */ /* Current work soundbuffer */
u8 mixbuffer; 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 */ /* audio DMA status */
static u8 audioStarted = 0; static u8 audioStarted = 0;
@ -98,38 +89,14 @@ void gx_audio_Shutdown(void)
/*** /***
gx_audio_Update 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 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 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 */ /* set next DMA soundbuffer */
s16 *sb = (s16 *)(soundbuffer[mixbuffer]); s16 *sb = (s16 *)(soundbuffer[mixbuffer]);
mixbuffer ^= 1; mixbuffer ^= 1;
size = size << 2;
DCFlushRange((void *)sb, size); DCFlushRange((void *)sb, size);
AUDIO_InitDMA((u32) sb, size); AUDIO_InitDMA((u32) sb, size);
@ -140,7 +107,8 @@ void gx_audio_Update(void)
{ {
audioStarted = 1; audioStarted = 1;
AUDIO_StartDMA(); AUDIO_StartDMA();
if (frameticker > 1) frameticker = 1; if (frameticker > 1)
frameticker = 1;
} }
} }
@ -156,29 +124,16 @@ void gx_audio_Start(void)
PauseOgg(1); PauseOgg(1);
StopOgg(); StopOgg();
ASND_Pause(1); ASND_Pause(1);
AUDIO_StopDMA (); ASND_End();
AUDIO_RegisterDMACallback(NULL);
audioStarted = 0; 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; mixbuffer = 0;
delta = 0;
/* reset sound buffers */ /* reset sound buffers */
memset(soundbuffer, 0, 2 * 3840); memset(soundbuffer, 0, 2 * 3840);
/* By default, use audio DMA to synchronize frame emulation */ /* By default, use audio DMA to synchronize frame emulation */
if (gc_pal | vdp_pal) AUDIO_RegisterDMACallback(ai_callback); 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;
} }
/*** /***

View File

@ -32,6 +32,6 @@ extern void gx_audio_Init(void);
extern void gx_audio_Shutdown(void); extern void gx_audio_Shutdown(void);
extern void gx_audio_Start(void); extern void gx_audio_Start(void);
extern void gx_audio_Stop(void); extern void gx_audio_Stop(void);
extern void gx_audio_Update(void); extern void gx_audio_Update(int size);
#endif #endif

View File

@ -1283,9 +1283,11 @@ void gx_video_Start(void)
/* VSYNC callbacks */ /* VSYNC callbacks */
/* in 60hz mode we use VSYNC to synchronize frame emulation */ /* 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_SetPostRetraceCallback(NULL);
VIDEO_Flush(); VIDEO_Flush();
VIDEO_WaitVSync();
/* interlaced/progressive mode */ /* interlaced/progressive mode */
if (config.render == 2) if (config.render == 2)

View File

@ -125,10 +125,20 @@ void reloadrom (int size, char *name)
} }
else else
{ {
system_init (); /* Initialize System */ /* initialize audio back-end */
audio_init(48000,vdp_pal?50.0:(1000000.0/16715.0)); /* 60hz video mode requires synchronization with Video Interrupt. */
ClearGGCodes (); /* Clear Game Genie patches */ /* VSYNC period is 16715 us on Wii/Gamecube (approx. 802.32 samples per frame) */
system_reset (); /* System Power ON */ 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(); DI_Init();
#endif #endif
int size;
/* initialize hardware */ /* initialize hardware */
gx_video_Init(); gx_video_Init();
@ -265,9 +276,6 @@ int main (int argc, char *argv[])
/* skip frame */ /* skip frame */
frameticker-=2; frameticker-=2;
system_frame (1); system_frame (1);
/* update audio only */
gx_audio_Update();
} }
else else
{ {
@ -277,11 +285,14 @@ int main (int argc, char *argv[])
/* render frame */ /* render frame */
system_frame (0); system_frame (0);
}
/* retrieve audio samples */
size = audio_update();
/* update video & audio */ /* update video & audio */
gx_video_Update(); gx_video_Update();
gx_audio_Update(); gx_audio_Update(size * 4);
}
} }
return 0; return 0;

View File

@ -261,149 +261,494 @@ uint8 vc_pal_240[313] = {
0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF 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 uint8 cycle2hc40[3420] =
WWW: http://cgfm2.emuviews.com {
/* 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 /* 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,
Range 00-93, E9-FF 00-B6, E4-FF 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
Display area 00-7F 00-9F 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
V counter increment 84, 85 A4, A5 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
V-blanking in 86, 87 A7, A8 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
V-blanking out 86, 87 A7, A8
H-blanking in 93, E9 B2, E4
H-blanking out 06, 07 06, 07
Comma seperated values show the H counter value before an event occurs, /* horizontal sync (32 pixels -> 313 Mcycles) */
and then the H counter value immediately after. 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 /* left blanking (32 pixels -> 259 Mcycles) */
off by one or two. 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. /* remaining active display (304 pixels -> 2432 Mcycles) */
The H counter will never actually be set to the values 94-E8 or B7-E3. 0x0d, 0x0d, 0x0d, 0x0d,
Perhaps this is the horizontal retrace period. 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,
Interestingly enough, the timing values for the 32-cell display mode 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10,
are identical to that of the SMS. 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,
It would appear that in 40-cell mode, the horizontal blanking period 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
is shorter as the active display period takes more time. 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,
The V-blanking flag can also be forcibly set by disabling the display 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16,
through bit 6 of register #1. 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,
H counter 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,
Now for some additional information on the horizontal aspects of the 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d,
display, taken from the TMS9918 manual and my tests on a NTSC Genesis. 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e,
Be warned that a real SMS may have different results. 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,
The H counter is 9 bits, and reading it returns the upper 8 bits. This is 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21,
because a scanline consists of 342 pixels, which couldn't be represented 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22,
with an 8-bit counter. Each scanline is divided up as follows: 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,
Pixels H.Cnt Description 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25,
256 : 00-7F : Active display 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x26,
15 : 80-87 : Right border 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27,
8 : 87-8B : Right blanking 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28,
26 : 8B-ED : Horizontal sync 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29,
2 : ED-EE : Left blanking 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a,
14 : EE-F5 : Color burst 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b,
8 : F5-F9 : Left blanking 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c,
13 : F9-FF : Left border 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,
Here's a description of what these areas look like: 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,
Active display - Where the display generated by the VDP goes. 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31,
Right border - Filled with border color from VDP register $07. 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32,
Right blanking - Filled with a light black color. (like display was blanked) 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33,
Horizontal sync - Filled with a pure black color. (like display was turned off) 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34,
Left blanking - Filled with the border color from VDP register $07. 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35,
Color burst - Filled with a dark brown/orange color. 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36,
Left blanking - Filled with a light black color. (like display was blanked) 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x37,
Left border - Filled with the border color from VDP register $07. 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,
uint8 cycle2hc32[488] = { 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c,
0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x8A, 0x8A, 0x8A, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d,
0x8B, 0x8B, 0x8B, 0x8C, 0x8C, 0x8D, 0x8D, 0x8D, 0x8E, 0x8E, 0x8E, 0x8F, 0x8F, 0x8F, 0x90, 0x90, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e,
0x90, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x93, 0x93, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f,
0xE9, 0xE9, 0xE9, 0xEA, 0xEA, 0xEA, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x40,
0xEB, 0xEB, 0xEB, 0xEC, 0xEC, 0xEC, 0xED, 0xED, 0xED, 0xEE, 0xEE, 0xEE, 0xEF, 0xEF, 0xF0, 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x41,
0xF0, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, 0xF2, 0xF3, 0xF3, 0xF3, 0xF4, 0xF4, 0xF4, 0xF5, 0xF5, 0xF6, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42,
0xF6, 0xF6, 0xF7, 0xF7, 0xF7, 0xF8, 0xF8, 0xF8, 0xF9, 0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43,
0xFB, 0xFC, 0xFC, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x44,
0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45,
0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46, 0x46,
0x0C, 0x0C, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x47,
0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x17, 0x17, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48,
0x17, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49,
0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x22, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a,
0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x28, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b,
0x28, 0x29, 0x29, 0x29, 0x2A, 0x2A, 0x2A, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C, 0x2C, 0x2D, 0x2D, 0x2D, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4c,
0x2E, 0x2E, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x33, 0x33, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d,
0x33, 0x34, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x39, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e,
0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3B, 0x3B, 0x3B, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x4f,
0x3F, 0x3F, 0x3F, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x43, 0x43, 0x44, 0x44, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50,
0x44, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x49, 0x49, 0x4A, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, 0x51,
0x4A, 0x4A, 0x4B, 0x4B, 0x4B, 0x4C, 0x4C, 0x4C, 0x4D, 0x4D, 0x4D, 0x4E, 0x4E, 0x4E, 0x4F, 0x4F, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52,
0x4F, 0x50, 0x50, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x55, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x53,
0x55, 0x55, 0x56, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x5A, 0x5A, 0x5A, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x54,
0x5B, 0x5B, 0x5B, 0x5C, 0x5C, 0x5C, 0x5D, 0x5D, 0x5E, 0x5E, 0x5E, 0x5F, 0x5F, 0x5F, 0x60, 0x60, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55,
0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x64, 0x64, 0x65, 0x65, 0x65, 0x66, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x56,
0x66, 0x66, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x6A, 0x6A, 0x6A, 0x6B, 0x6B, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57,
0x6C, 0x6C, 0x6C, 0x6D, 0x6D, 0x6D, 0x6E, 0x6E, 0x6E, 0x6F, 0x6F, 0x6F, 0x70, 0x70, 0x70, 0x71, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58,
0x71, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x59,
0x77, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, 0x7C, 0x7C, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5a,
0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b,
0x82, 0x82, 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, 0x85, 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] = { uint8 cycle2hc32[3420] =
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, /* end of active display (16 pixels -> 160 Mcycles) , HINT triggered ? , Vcounter jump */
0xB2, 0xB3, 0xB3, 0xB4, 0xB4, 0xB4, 0xB5, 0xB5, 0xB6, 0xB6, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
0xE4, 0xE4, 0xE4, 0xE5, 0xE5, 0xE6, 0xE6, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
0xE7, 0xE7, 0xE7, 0xE8, 0xE8, 0xE9, 0xE9, 0xEA, 0xEA, 0xEB, 0xEB, 0xEB, 0xEC, 0xEC, 0xED, 0xED, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
0xEE, 0xEE, 0xEE, 0xEF, 0xEF, 0xF0, 0xF0, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, 0xF3, 0xF3, 0xF4, 0xF4, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x88,
0xF4, 0xF5, 0xF5, 0xF6, 0xF6, 0xF7, 0xF7, 0xF7, 0xF8, 0xF8, 0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0xFB, 0xFC, 0xFC, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x89, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0E, 0x0E, 0x0F, 0x0F, 0x10, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x13, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15, 0x16, 0x16, 0x16, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8c,
0x17, 0x17, 0x18, 0x18, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
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, /* right border (14 pixels -> 140 Mcycles) */
0x2C, 0x2C, 0x2D, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x33, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x36, 0x37, 0x37, 0x38, 0x38, 0x39, 0x39, 0x8d, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
0x39, 0x3A, 0x3A, 0x3B, 0x3B, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D, 0x3E, 0x3E, 0x3F, 0x3F, 0x40, 0x40, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
0x40, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43, 0x43, 0x44, 0x44, 0x45, 0x45, 0x46, 0x46, 0x46, 0x47, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x90,
0x47, 0x48, 0x48, 0x49, 0x49, 0x4A, 0x4A, 0x4A, 0x4B, 0x4B, 0x4C, 0x4C, 0x4D, 0x4D, 0x4D, 0x4E, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x4E, 0x4F, 0x4F, 0x50, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52, 0x53, 0x53, 0x53, 0x54, 0x54, 0x55, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
0x55, 0x56, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58, 0x59, 0x59, 0x5A, 0x5A, 0x5A, 0x5B, 0x5B, 0x5C, 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
0x5C, 0x5D, 0x5D, 0x5D, 0x5E, 0x5E, 0x5F, 0x5F, 0x60, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, 0x63, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
0x63, 0x63, 0x64, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68, 0x68, 0x69, 0x69, 0x6A, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
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, /* right blanking (9 pixels -> 90 Mcycles) , VDP status HBLANK flag set */
0x78, 0x78, 0x79, 0x79, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0xe9, 0xe9, 0xe9, 0xe9,
0x7F, 0x7F, 0x80, 0x80, 0x80, 0x81, 0x81, 0x82, 0x82, 0x83, 0x83, 0x84, 0x84, 0x84, 0x85, 0x85, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9,
0x86, 0x86, 0x87, 0x87, 0x87, 0x88, 0x88, 0x89, 0x89, 0x8A, 0x8A, 0x8A, 0x8B, 0x8B, 0x8C, 0x8C, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea,
0x8D, 0x8D, 0x8D, 0x8E, 0x8E, 0x8F, 0x8F, 0x90, 0x90, 0x90, 0x91, 0x91, 0x92, 0x92, 0x93, 0x93, 0xea, 0xea, 0xea, 0xea, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb,
0x94, 0x94, 0x94, 0x95, 0x95, 0x96, 0x96, 0x97, 0x97, 0x97, 0x98, 0x98, 0x99, 0x99, 0x9A, 0x9A, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec,
0x9A, 0x9B, 0x9B, 0x9C, 0x9C, 0x9D, 0x9D, 0x9D, 0x9E, 0x9E, 0x9F, 0x9F, 0xA0, 0xA0, 0xA1, 0xA1, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xed,
0xA1, 0xA2, 0xA2, 0xA3, 0xA3, 0xA4, 0xA4, 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; uint8 *vctab;

View File

@ -382,10 +382,27 @@ void set_region ()
} }
/* Force region setting */ /* Force region setting */
if (config.region_detect == 1) region_code = REGION_USA; if (config.region_detect == 1)
else if (config.region_detect == 2) region_code = REGION_EUROPE; region_code = REGION_USA;
else if (config.region_detect == 3) region_code = REGION_JAPAN_NTSC; else if (config.region_detect == 2)
else if (config.region_detect == 4) region_code = REGION_JAPAN_PAL; 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;
}
} }
/**************************************************************************** /****************************************************************************

View File

@ -318,23 +318,25 @@ void m68k_pulse_reset(void);
/* execute num_cycles worth of instructions. returns number of cycles used */ /* execute num_cycles worth of instructions. returns number of cycles used */
//int m68k_execute(int num_cycles); //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 /* These functions let you read/write/modify the number of cycles left to run
* while m68k_execute() is running. * while m68k_execute() is running.
* These are useful if the 68k accesses a memory-mapped port on another device * These are useful if the 68k accesses a memory-mapped port on another device
* that requires immediate processing by another CPU. * that requires immediate processing by another CPU.
*/ */
int m68k_cycles_run(void); /* Number of cycles run so far */ //int m68k_cycles_run(void); /* Number of cycles run so far */
int m68k_cycles_remaining(void); /* Number of cycles left */ //int m68k_cycles_remaining(void); /* Number of cycles left */
void m68k_modify_timeslice(int cycles); /* Modify cycles left */ //void m68k_modify_timeslice(int cycles); /* Modify cycles left */
void m68k_end_timeslice(void); /* End timeslice now */ //void m68k_end_timeslice(void); /* End timeslice now */
/* Set the IPL0-IPL2 pins on the CPU (IRQ). /* Set the IPL0-IPL2 pins on the CPU (IRQ).
* A transition from < 7 to 7 will cause a non-maskable interrupt (NMI). * A transition from < 7 to 7 will cause a non-maskable interrupt (NMI).
* Setting IRQ to 0 will clear an interrupt request. * 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. */ /* Halt the CPU as if you pulsed the HALT pin. */

View File

@ -43,8 +43,8 @@ extern void m68040_fpu_op1(void);
/* ================================= DATA ================================= */ /* ================================= DATA ================================= */
/* ======================================================================== */ /* ======================================================================== */
int m68ki_initial_cycles; //int m68ki_initial_cycles;
int m68ki_remaining_cycles = 0; /* Number of clocks remaining */ //int m68ki_remaining_cycles = 0; /* Number of clocks remaining */
uint m68ki_tracing = 0; uint m68ki_tracing = 0;
uint m68ki_address_space; uint m68ki_address_space;
@ -777,10 +777,11 @@ void m68k_set_cpu_type(unsigned int cpu_type)
} }
/* Execute a single instruction */ /* 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 our pool of clock cycles available */
SET_CYCLES(0); //SET_CYCLES(0);
/* Set tracing accodring to T1. (T0 is done inside instruction) */ /* Set tracing accodring to T1. (T0 is done inside instruction) */
m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */ 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) */ m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */
/* return how many clocks we used */ /* 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 */ /* 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 /* KS: Modified so that IPL* bits match with mask positions in the SR
* and cleaned out remenants of the interrupt controller. * 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; uint old_level = CPU_INT_LEVEL;
CPU_INT_LEVEL = int_level << 8; CPU_INT_LEVEL = int_level << 8;
@ -830,50 +830,50 @@ extern void error(char *format, ...);
#endif #endif
extern uint8 irq_status; 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 */ /* Return point if we had an address error */
m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */ 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 */ /* check interrupt updates */
if (irq_status & 0x10) if (irq_status & 0x10)
{ {
irq_status &= ~0x10; irq_status &= ~0x10;
int_level = irq_status & 6;
temp = irq_status & 6;
/* hardware latency */ /* hardware latency */
if (irq_status & 0x40) if (irq_status & 0x40)
count_m68k += m68k_execute(); m68k_execute();
#ifdef LOGVDP #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 #endif
/* interrupt level */ /* update IRQ level */
m68k_set_irq(temp); CPU_INT_LEVEL = int_level << 8;
} m68ki_check_interrupts();
/* Make sure we're not stopped */ if (mcycles_68k >= cycles)
if(CPU_STOPPED)
{
count_m68k = cyc;
REG_PPC = REG_PC;
return; return;
} }
/* execute a single instruction */ /* 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) int m68k_cycles_run(void)
{ {
return m68ki_initial_cycles - GET_CYCLES(); return m68ki_initial_cycles - GET_CYCLES();
@ -883,20 +883,22 @@ int m68k_cycles_remaining(void)
{ {
return GET_CYCLES(); return GET_CYCLES();
} }
*/
/* Change the timeslice */ /* Change the timeslice */
/*
void m68k_modify_timeslice(int cycles) void m68k_modify_timeslice(int cycles)
{ {
m68ki_initial_cycles += cycles; m68ki_initial_cycles += cycles;
ADD_CYCLES(cycles); ADD_CYCLES(cycles);
} }
void m68k_end_timeslice(void) void m68k_end_timeslice(void)
{ {
m68ki_initial_cycles = GET_CYCLES(); m68ki_initial_cycles = GET_CYCLES();
SET_CYCLES(0); SET_CYCLES(0);
} }
*/
void m68k_init(void) void m68k_init(void)
{ {
@ -925,7 +927,7 @@ void m68k_pulse_reset(void)
{ {
/* Clear all stop levels and eat up all remaining cycles */ /* Clear all stop levels and eat up all remaining cycles */
CPU_STOPPED = 0; CPU_STOPPED = 0;
SET_CYCLES(0); //SET_CYCLES(0);
CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET; CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET;
@ -953,6 +955,8 @@ void m68k_pulse_reset(void)
m68ki_jump(REG_PC); m68ki_jump(REG_PC);
CPU_RUN_MODE = RUN_MODE_NORMAL; CPU_RUN_MODE = RUN_MODE_NORMAL;
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_RESET]);
} }
/* Pulse the HALT line on the CPU */ /* Pulse the HALT line on the CPU */

View File

@ -33,8 +33,6 @@
#include <setjmp.h> #include <setjmp.h>
#endif /* M68K_EMULATE_ADDRESS_ERROR */ #endif /* M68K_EMULATE_ADDRESS_ERROR */
extern unsigned int count_m68k;
/* ======================================================================== */ /* ======================================================================== */
/* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */ /* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */
/* ======================================================================== */ /* ======================================================================== */
@ -562,10 +560,6 @@ extern unsigned int count_m68k;
if(setjmp(m68ki_aerr_trap) != 0) \ if(setjmp(m68ki_aerr_trap) != 0) \
{ \ { \
m68ki_exception_address_error(); \ m68ki_exception_address_error(); \
if(CPU_STOPPED) \
{ \
SET_CYCLES(0); \
} \
} }
#define m68ki_check_address_error(ADDR, WRITE_MODE, FC) \ #define m68ki_check_address_error(ADDR, WRITE_MODE, FC) \
@ -799,12 +793,15 @@ extern unsigned int count_m68k;
/* ---------------------------- Cycle Counting ---------------------------- */ /* ---------------------------- Cycle Counting ---------------------------- */
/*
#define ADD_CYCLES(A) m68ki_remaining_cycles += (A) #define ADD_CYCLES(A) m68ki_remaining_cycles += (A)
#define USE_CYCLES(A) m68ki_remaining_cycles -= (A) #define USE_CYCLES(A) m68ki_remaining_cycles -= (A)
#define SET_CYCLES(A) m68ki_remaining_cycles = A #define SET_CYCLES(A) m68ki_remaining_cycles = A
#define GET_CYCLES() m68ki_remaining_cycles #define GET_CYCLES() m68ki_remaining_cycles
#define USE_ALL_CYCLES() m68ki_remaining_cycles = 0 #define USE_ALL_CYCLES() m68ki_remaining_cycles = 0
*/
#define USE_CYCLES(A) mcycles_68k += (7 * (A))
/* ----------------------------- Read / Write ----------------------------- */ /* ----------------------------- Read / Write ----------------------------- */
@ -917,9 +914,10 @@ typedef struct
} m68ki_cpu_core; } m68ki_cpu_core;
extern unsigned int mcycles_68k;
extern m68ki_cpu_core m68ki_cpu; extern m68ki_cpu_core m68ki_cpu;
extern sint m68ki_remaining_cycles; //extern sint m68ki_remaining_cycles;
extern uint m68ki_tracing; extern uint m68ki_tracing;
extern const uint8 m68ki_shift_8_table[]; extern const uint8 m68ki_shift_8_table[];
extern const uint16 m68ki_shift_16_table[]; extern const uint16 m68ki_shift_16_table[];
@ -2042,16 +2040,10 @@ INLINE void m68ki_exception_interrupt(uint int_level)
m68ki_jump(new_pc); m68ki_jump(new_pc);
/* Defer cycle counting until later */ /* Update cycle count now */
count_m68k += CYC_EXCEPTION[vector]; USE_CYCLES(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 */
} }
/* ASG: Check for interrupts */ /* ASG: Check for interrupts */
INLINE void m68ki_check_interrupts(void) INLINE void m68ki_check_interrupts(void)
{ {

View File

@ -31065,7 +31065,7 @@ static void m68k_op_stop(void)
m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
CPU_STOPPED |= STOP_LEVEL_STOP; CPU_STOPPED |= STOP_LEVEL_STOP;
m68ki_set_sr(new_sr); m68ki_set_sr(new_sr);
m68ki_remaining_cycles = 0; //m68ki_remaining_cycles = 0;
return; return;
} }
m68ki_exception_privilege_violation(); m68ki_exception_privilege_violation();

View File

@ -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)); error ("Lockup %08X = %02X (%08X)\n", address, data, m68k_get_reg (NULL, M68K_REG_PC));
#endif #endif
gen_running = config.force_dtack; 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) 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)); error ("Lockup %08X = %04X (%08X)\n", address, data, m68k_get_reg (NULL, M68K_REG_PC));
#endif #endif
gen_running = config.force_dtack; gen_running = config.force_dtack;
if (!gen_running) m68k_end_timeslice (); if (!gen_running)
m68k_pulse_halt ();
} }
uint32 m68k_lockup_r_8 (uint32 address) 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)); error ("Lockup %08X.b (%08X)\n", address, m68k_get_reg (NULL, M68K_REG_PC));
#endif #endif
gen_running = config.force_dtack; gen_running = config.force_dtack;
if (!gen_running) m68k_end_timeslice (); if (!gen_running)
m68k_pulse_halt ();
return -1; 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)); error ("Lockup %08X.w (%08X)\n", address, m68k_get_reg (NULL, M68K_REG_PC));
#endif #endif
gen_running = config.force_dtack; gen_running = config.force_dtack;
if (!gen_running) m68k_end_timeslice (); if (!gen_running)
m68k_pulse_halt ();
return -1; return -1;
} }
@ -111,28 +115,32 @@ static int pico_page[7] = {0x00,0x01,0x03,0x07,0x0F,0x1F,0x3F};
uint32 eeprom_read_byte(uint32 address) uint32 eeprom_read_byte(uint32 address)
{ {
if (address == eeprom.type.sda_out_adr) return eeprom_read(address, 0); if (address == eeprom.type.sda_out_adr)
else return READ_BYTE(cart.rom, address); return eeprom_read(address, 0);
return READ_BYTE(cart.rom, address);
} }
uint32 eeprom_read_word(uint32 address) uint32 eeprom_read_word(uint32 address)
{ {
if (address == (eeprom.type.sda_out_adr & 0xfffffe)) return eeprom_read(address, 1); if (address == (eeprom.type.sda_out_adr & 0xfffffe))
else return *(uint16 *)(cart.rom + address); return eeprom_read(address, 1);
return *(uint16 *)(cart.rom + address);
} }
void eeprom_write_byte(uint32 address, uint32 data) void eeprom_write_byte(uint32 address, uint32 data)
{ {
if ((address == eeprom.type.sda_in_adr) || (address == eeprom.type.scl_adr)) if ((address == eeprom.type.sda_in_adr) || (address == eeprom.type.scl_adr))
eeprom_write(address, data, 0); 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) void eeprom_write_word(uint32 address, uint32 data)
{ {
if ((address == (eeprom.type.sda_in_adr&0xfffffe)) || (address == (eeprom.type.scl_adr&0xfffffe))) if ((address == (eeprom.type.sda_in_adr&0xfffffe)) || (address == (eeprom.type.scl_adr&0xfffffe)))
eeprom_write(address, data, 1); 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) 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) switch ((address >> 13) & 3)
{ {
case 2: /* YM2612 */ case 2: /* YM2612 */
return fm_read(0, address & 3); return fm_read(mcycles_68k, address & 3);
case 3: /* MISC */ case 3: /* MISC */
if ((address & 0xff00) == 0x7f00) return m68k_lockup_r_8(address); /* VDP */ if ((address & 0xff00) == 0x7f00)
else return (m68k_read_bus_8(address) | 0xff); return m68k_lockup_r_8(address); /* VDP */
return (m68k_read_bus_8(address) | 0xff);
default: /* ZRAM */ default: /* ZRAM */
return zram[address & 0x1fff]; return zram[address & 0x1fff];
@ -158,19 +169,22 @@ uint32 z80_read_byte(uint32 address)
uint32 z80_read_word(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) switch ((address >> 13) & 3)
{ {
case 2: /* YM2612 */ case 2: /* YM2612 */
{ {
int temp = fm_read(0, address & 3); int temp = fm_read(mcycles_68k, address & 3);
return (temp << 8 | temp); return (temp << 8 | temp);
} }
case 3: /* MISC */ case 3: /* MISC */
if ((address & 0xff00) == 0x7f00) return m68k_lockup_r_16(address); /* VDP */ if ((address & 0xff00) == 0x7f00)
else return (m68k_read_bus_16(address) | 0xffff); return m68k_lockup_r_16(address); /* VDP */
return (m68k_read_bus_16(address) | 0xffff);
default: /* ZRAM */ default: /* ZRAM */
{ {
@ -182,7 +196,8 @@ uint32 z80_read_word(uint32 address)
void z80_write_byte(uint32 address, uint32 data) void z80_write_byte(uint32 address, uint32 data)
{ {
if (zbusack) /* Z80 bus is available ? */
if (zstate ^ 3)
{ {
m68k_unused_8_w(address, data); m68k_unused_8_w(address, data);
return; return;
@ -191,7 +206,7 @@ void z80_write_byte(uint32 address, uint32 data)
switch ((address >> 13) & 3) switch ((address >> 13) & 3)
{ {
case 2: /* YM2612 */ case 2: /* YM2612 */
fm_write(0, address & 3, data); fm_write(mcycles_68k, address & 3, data);
return; return;
case 3: case 3:
@ -212,15 +227,15 @@ void z80_write_byte(uint32 address, uint32 data)
default: /* ZRAM */ default: /* ZRAM */
zram[address & 0x1fff] = data; zram[address & 0x1fff] = data;
count_m68k++; /* Z80 bus latency (Pacman 2: New Adventures) */ mcycles_68k+=8; /* Z80 bus latency (Pacman 2: New Adventures) */
return; return;
} }
} }
void z80_write_word(uint32 address, uint32 data) void z80_write_word(uint32 address, uint32 data)
{ {
/* Z80 still hold the bus ? */ /* Z80 bus is available ? */
if (zbusack) if (zstate ^ 3)
{ {
m68k_unused_16_w(address, data); m68k_unused_16_w(address, data);
return; return;
@ -229,7 +244,7 @@ void z80_write_word(uint32 address, uint32 data)
switch ((address >> 13) & 3) switch ((address >> 13) & 3)
{ {
case 2: /* YM2612 */ case 2: /* YM2612 */
fm_write (0, address & 3, data >> 8); fm_write (mcycles_68k, address & 3, data >> 8);
return; return;
case 3: case 3:
@ -262,17 +277,21 @@ uint32 ctrl_io_read_byte(uint32 address)
switch ((address >> 8) & 0xff) switch ((address >> 8) & 0xff)
{ {
case 0x00: /* I/O chip */ case 0x00: /* I/O chip */
if (address & 0xe0) return m68k_read_bus_8(address); if (address & 0xe0)
else return (io_read((address >> 1) & 0x0f)); return m68k_read_bus_8(address);
return (io_read((address >> 1) & 0x0f));
case 0x11: /* BUSACK */ case 0x11: /* BUSACK */
if (address & 1) return m68k_read_bus_8(address); if (address & 1)
else return ((m68k_read_pcrelative_8(REG_PC) & 0xfe) | zbusack); 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 */ case 0x30: /* TIME */
if (cart.hw.time_r) if (cart.hw.time_r)
return ((address & 1) ? (cart.hw.time_r(address) & 0xff) : (cart.hw.time_r(address) >> 8)); 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 0x10: /* MEMORY MODE */
case 0x12: /* RESET */ case 0x12: /* RESET */
@ -294,23 +313,28 @@ uint32 ctrl_io_read_word(uint32 address)
{ {
case 0x00: /* I/O chip */ 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); int temp = io_read((address >> 1) & 0x0f);
return (temp << 8 | temp); return (temp << 8 | temp);
} }
case 0x11: /* BUSACK */ 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 */ case 0x30: /* TIME */
if (cart.hw.time_r) return cart.hw.time_r(address); if (cart.hw.time_r)
else return m68k_read_bus_16(address); return cart.hw.time_r(address);
return m68k_read_bus_16(address);
case 0x50: /* SVP */ case 0x50: /* SVP */
if (svp) if (svp)
{ {
if ((address & 0xfd) == 0) return svp->ssp1601.gr[SSP_XST].h; if ((address & 0xfd) == 0)
else if ((address & 0xff) == 4) return svp->ssp1601.gr[SSP_XST].h;
if ((address & 0xff) == 4)
{ {
uint32 temp = svp->ssp1601.gr[SSP_PM0].h; uint32 temp = svp->ssp1601.gr[SSP_PM0].h;
svp->ssp1601.gr[SSP_PM0].h &= ~1; svp->ssp1601.gr[SSP_PM0].h &= ~1;
@ -337,18 +361,24 @@ void ctrl_io_write_byte(uint32 address, uint32 data)
switch ((address >> 8) & 0xff) switch ((address >> 8) & 0xff)
{ {
case 0x00: /* I/O chip */ case 0x00: /* I/O chip */
if ((address & 0xe1) == 0x01) io_write((address >> 1) & 0x0f, data); /* get /LWR only */ if ((address & 0xe1) == 0x01)
else m68k_unused_8_w(address, data); io_write((address >> 1) & 0x0f, data); /* get /LWR only */
else
m68k_unused_8_w(address, data);
return; return;
case 0x11: /* BUSREQ */ case 0x11: /* BUSREQ */
if (address & 1) m68k_unused_8_w(address, data); if (address & 1)
else gen_busreq_w(data & 1); m68k_unused_8_w(address, data);
else
gen_busreq_w(data & 1);
return; return;
case 0x12: /* RESET */ case 0x12: /* RESET */
if (address & 1) m68k_unused_8_w(address, data); if (address & 1)
else gen_reset_w(data & 1); m68k_unused_8_w(address, data);
else
gen_reset_w(data & 1);
return; return;
case 0x30: /* TIME */ case 0x30: /* TIME */
@ -368,7 +398,10 @@ void ctrl_io_write_byte(uint32 address, uint32 data)
memset(cart.rom, 0xff, cart.romsize); memset(cart.rom, 0xff, cart.romsize);
} }
} }
else m68k_unused_8_w (address, data); else
{
m68k_unused_8_w (address, data);
}
return; return;
case 0x10: /* MEMORY MODE */ case 0x10: /* MEMORY MODE */
@ -390,8 +423,10 @@ void ctrl_io_write_word(uint32 address, uint32 data)
switch ((address >> 8) & 0xff) switch ((address >> 8) & 0xff)
{ {
case 0x00: /* I/O chip */ case 0x00: /* I/O chip */
if (address & 0xe0) m68k_unused_16_w (address, data); if (address & 0xe0)
else io_write ((address >> 1) & 0x0f, data & 0xff); m68k_unused_16_w (address, data);
else
io_write ((address >> 1) & 0x0f, data & 0xff);
return; return;
case 0x11: /* BUSREQ */ case 0x11: /* BUSREQ */
@ -405,7 +440,10 @@ void ctrl_io_write_word(uint32 address, uint32 data)
case 0x50: /* SVP REGISTERS */ case 0x50: /* SVP REGISTERS */
if (svp) if (svp)
{ {
if (address & 0xfd) m68k_unused_16_w(address, data); if (address & 0xfd)
{
m68k_unused_16_w(address, data);
}
else else
{ {
/* just guessing here (Notaz) */ /* just guessing here (Notaz) */
@ -414,7 +452,10 @@ void ctrl_io_write_word(uint32 address, uint32 data)
svp->ssp1601.emu_status &= ~SSP_WAIT_PM0; svp->ssp1601.emu_status &= ~SSP_WAIT_PM0;
} }
} }
else m68k_unused_16_w (address, data); else
{
m68k_unused_16_w (address, data);
}
return; return;
case 0x30: /* TIME */ case 0x30: /* TIME */
@ -523,8 +564,10 @@ void vdp_write_byte(uint32 address, uint32 data)
case 0x10: /* PSG */ case 0x10: /* PSG */
case 0x14: case 0x14:
if (address & 1) psg_write(0, data); if (address & 1)
else m68k_unused_8_w(address, data); psg_write(mcycles_68k, data);
else
m68k_unused_8_w(address, data);
return; return;
case 0x18: /* Unused */ case 0x18: /* Unused */
@ -555,7 +598,7 @@ void vdp_write_word(uint32 address, uint32 data)
case 0x10: /* PSG */ case 0x10: /* PSG */
case 0x14: case 0x14:
psg_write(0, data & 0xff); psg_write(mcycles_68k, data & 0xff);
return; return;
case 0x18: /* Unused */ case 0x18: /* Unused */

View File

@ -65,17 +65,19 @@ uint32 zbank_read_ctrl_io(uint32 address)
switch ((address >> 8) & 0xff) switch ((address >> 8) & 0xff)
{ {
case 0x00: /* I/O chip */ case 0x00: /* I/O chip */
if (address & 0xe0) return zbank_unused_r(address); if (address & 0xe0)
else return (io_read((address >> 1) & 0x0f)); return zbank_unused_r(address);
return (io_read((address >> 1) & 0x0f));
case 0x11: /* BUSACK */ case 0x11: /* BUSACK */
if (address & 1) return zbank_unused_r(address); if (address & 1)
else return (0xfe | zbusack); return zbank_unused_r(address);
return 0xff;
case 0x30: /* TIME */ case 0x30: /* TIME */
if (cart.hw.time_r) if (cart.hw.time_r)
return ((address & 1) ? (cart.hw.time_r(address) & 0xff) : (cart.hw.time_r(address) >> 8)); 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 0x10: /* MEMORY MODE */
case 0x12: /* RESET */ case 0x12: /* RESET */
@ -96,18 +98,24 @@ void zbank_write_ctrl_io(uint32 address, uint32 data)
switch ((address >> 8) & 0xff) switch ((address >> 8) & 0xff)
{ {
case 0x00: /* I/O chip */ case 0x00: /* I/O chip */
if ((address & 0xe1) == 0x01) io_write((address >> 1) & 0x0f, data); /* get /LWR only */ if ((address & 0xe1) == 0x01)
else zbank_unused_w(address, data); io_write((address >> 1) & 0x0f, data); /* get /LWR only */
else
zbank_unused_w(address, data);
return; return;
case 0x11: /* BUSREQ */ case 0x11: /* BUSREQ */
if (address & 1) zbank_unused_w(address, data); if (address & 1)
else gen_busreq_w(data & 1); zbank_unused_w(address, data);
else
gen_busreq_w(data & 1);
return; return;
case 0x12: /* RESET */ case 0x12: /* RESET */
if (address & 1) zbank_unused_w(address, data); if (address & 1)
else gen_reset_w(data & 1); zbank_unused_w(address, data);
else
gen_reset_w(data & 1);
return; return;
case 0x30: /* TIME */ case 0x30: /* TIME */
@ -127,7 +135,10 @@ void zbank_write_ctrl_io(uint32 address, uint32 data)
memset(cart.rom, 0xff, cart.romsize); memset(cart.rom, 0xff, cart.romsize);
} }
} }
else zbank_unused_w (address, data); else
{
zbank_unused_w (address, data);
}
return; return;
case 0x10: /* MEMORY MODE */ case 0x10: /* MEMORY MODE */
@ -195,8 +206,10 @@ void zbank_write_vdp(uint32 address, uint32 data)
case 0x10: /* PSG */ case 0x10: /* PSG */
case 0x14: case 0x14:
if (address & 1) psg_write(1, data); if (address & 1)
else zbank_unused_w(address, data); psg_write(mcycles_z80, data);
else
zbank_unused_w(address, data);
return; return;
case 0x18: /* Unused */ case 0x18: /* Unused */

View File

@ -109,8 +109,10 @@ static inline void z80_vdp_w(unsigned int address, unsigned int data)
case 0x10: /* PSG */ case 0x10: /* PSG */
case 0x14: case 0x14:
if (address & 1) psg_write(1, data); if (address & 1)
else z80_unused_w(address, data); psg_write(mcycles_z80, data);
else
z80_unused_w(address, data);
return; return;
case 0x18: /* Unused */ case 0x18: /* Unused */
@ -139,18 +141,20 @@ unsigned int cpu_readmem16(unsigned int address)
return zram[address & 0x1fff]; return zram[address & 0x1fff];
case 2: /* YM2612 */ case 2: /* YM2612 */
return fm_read(1, address & 3); return fm_read(mcycles_68k, address & 3);
case 3: /* VDP */ 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); return z80_unused_r(address);
default: /* V-bus bank */ default: /* V-bus bank */
{ {
address = zbank | (address & 0x7fff); address = zbank | (address & 0x7fff);
int slot = address >> 16; int slot = address >> 16;
if (zbank_memory_map[slot].read) return (*zbank_memory_map[slot].read)(address); if (zbank_memory_map[slot].read)
else return READ_BYTE(m68k_memory_map[slot].base, address&0xffff); 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; return;
case 2: /* YM2612 */ case 2: /* YM2612 */
fm_write(1, address & 3, data); fm_write(mcycles_z80, address & 3, data);
return; return;
case 3: /* Bank register and VDP */ case 3: /* Bank register and VDP */
@ -190,8 +194,10 @@ void cpu_writemem16(unsigned int address, unsigned int data)
{ {
address = zbank | (address & 0x7fff); address = zbank | (address & 0x7fff);
int slot = address >> 16; int slot = address >> 16;
if (zbank_memory_map[slot].write) (*zbank_memory_map[slot].write)(address, data); if (zbank_memory_map[slot].write)
else WRITE_BYTE(m68k_memory_map[slot].base, address&0xffff, data); (*zbank_memory_map[slot].write)(address, data);
else
WRITE_BYTE(m68k_memory_map[slot].base, address&0xffff, data);
return; return;
} }
} }

View File

@ -307,17 +307,20 @@ static __inline__ void WRITE_LONG(void *address, uint32 data)
} }
/**************************************************/ /************************************************/
/* Pixel creation macros */ /* Pixel creation macros */
/* Input is four bits each (R,G,B), 12 bits total */ /* each R,G,B color channel is 4-bits with a */
/* Color range depends on the S/TE mode: */ /* total of 15 different intensity levels. */
/* */ /* */
/* normal mode : xxx0 (0-14) */ /* Color intensity depends on the S/TE mode: */
/* shadow mode : 0xxx (0-7) */ /* */
/* highlight mode: 1xxx - 1 (7-14) */ /* normal : xxx0 (0-14) */
/* shadow : 0xxx (0-7) */
/* highlight: 1xxx - 1 (7-14) */
/* */ /* */
/* with xxx0 = original 4-bits CRAM value */ /* with xxx0 = original 4-bits CRAM value */
/**************************************************/ /* */
/************************************************/
#ifndef NGC #ifndef NGC
/* 8:8:8 RGB */ /* 8:8:8 RGB */
@ -330,7 +333,8 @@ static __inline__ void WRITE_LONG(void *address, uint32 data)
#endif #endif
/* 5:6:5 RGB */ /* 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 */ /* Clip data */
static clip_t clip[2]; 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 */ static uint8 obj_buf[0x200]; /* Object layer line buffer */
/* Sprite line buffer data */ /* Sprite line buffer data */
static uint32 object_index_count; uint32 object_index_count;
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/* Look-up table functions (handles priority between layers pixels) */ /* 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; xpos = object_info[count].xpos & 0x1ff;
/* sprite masking (ignore the 1st sprite) */ /* sprite masking (requires at least one sprite with xpos > 0) */
if (xpos) spr_over = 1; if (xpos)
spr_over = 1;
else if (spr_over) else if (spr_over)
{ {
spr_over = 0; spr_over = 0;
@ -1517,7 +1522,7 @@ static void render_obj(uint32 line, uint8 *buf, uint8 *table)
width = sizetab[(size >> 2) & 3]; width = sizetab[(size >> 2) & 3];
/* update pixel count (off-screen sprites included) */ /* update pixel count (off-screen sprites included) */
pixelcount += xpos ? width : (width * 2); pixelcount += width;
if(((xpos + width) >= left) && (xpos < right) && !mask) 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; xpos = object_info[count].xpos & 0x1ff;
/* sprite masking (ignore the 1st sprite) */ /* sprite masking (requires at least one sprite with xpos > 0) */
if (xpos) spr_over = 1; if (xpos)
spr_over = 1;
else if(spr_over) else if(spr_over)
{ {
spr_over = 0; 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]; width = sizetab[(size >> 2) & 3];
/* update pixel count (off-screen sprites included) */ /* update pixel count (off-screen sprites included) */
pixelcount += xpos ? width : (width * 2); pixelcount += width;
if(((xpos + width) >= left) && (xpos < right) && !mask) 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 */ /* number of tiles to draw */
/* adjusted for sprite limit */ /* 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; width >>= 3;
for(column = 0; column < width; column += 1, lb+=8) for(column = 0; column < width; column += 1, lb+=8)
{ {
index = (name + s[column]) & 0x3ff; index = (name + s[column]) & 0x3ff;
offs = index << 7 | attr_mask << 6 | v_line; offs = index << 7 | attr_mask << 6 | v_line;
if(attr & 0x1000) offs ^= 0x40; if(attr & 0x1000)
offs ^= 0x40;
src = &bg_pattern_cache[offs]; src = &bg_pattern_cache[offs];
DRAW_SPRITE_TILE; DRAW_SPRITE_TILE;
} }
@ -1662,9 +1670,11 @@ void render_init(void)
int bx, ax, i; int bx, ax, i;
/* Allocate and align pixel look-up tables */ /* 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)); 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 */ /* Make pixel look-up table data */
for (bx = 0; bx < 0x100; bx += 1) for (bx = 0; bx < 0x100; bx += 1)
@ -1722,7 +1732,8 @@ void render_reset(void)
void render_shutdown(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; uint32 x_offset = bitmap.viewport.x;
/* display OFF */ /* display OFF */
if (reg[0] & 0x01) return; if (reg[0] & 0x01)
return;
/* background color (blanked display or vertical borders) */ /* background color (blanked display or vertical borders) */
if (!(reg[1] & 0x40) || overscan) if (!(reg[1] & 0x40) || overscan)
@ -1761,28 +1773,32 @@ void render_line(uint32 line, uint32 overscan)
uint32 odd = odd_frame; uint32 odd = odd_frame;
/* render BG layers */ /* render BG layers */
if(reg[11] & 4) render_bg_im2_vs(line, width, odd); if(reg[11] & 4)
else render_bg_im2(line, width, odd); render_bg_im2_vs(line, width, odd);
else
render_bg_im2(line, width, odd);
if (reg[12] & 8) if (reg[12] & 8)
{ {
/* Shadow & Highlight */ /* Shadow & Highlight */
merge(&nta_buf[0x20], &ntb_buf[0x20], &bg_buf[0x20], lut[2], width); merge(&nta_buf[0x20], &ntb_buf[0x20], &bg_buf[0x20], lut[2], width);
memset(&obj_buf[0x20], 0, 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); merge(&obj_buf[0x20], &bg_buf[0x20], &lb[0x20], lut[4], width);
} }
else else
{ {
merge(&nta_buf[0x20], &ntb_buf[0x20], &lb[0x20], lut[0], width); 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 else
{ {
/* render BG layers */ /* render BG layers */
if(reg[11] & 4) render_bg_vs(line, width); if(reg[11] & 4)
else render_bg(line, width); render_bg_vs(line, width);
else
render_bg(line, width);
if(reg[12] & 8) if(reg[12] & 8)
{ {
@ -1818,13 +1834,16 @@ void remap_buffer(uint32 line, uint32 width)
line = (line + bitmap.viewport.y) % lines_per_frame; line = (line + bitmap.viewport.y) % lines_per_frame;
/* double resolution mode */ /* double resolution mode */
if (config.render && interlaced) line = (line * 2) + odd_frame; if (config.render && interlaced)
line = (line * 2) + odd_frame;
/* NTSC Filter */ /* NTSC Filter */
if (config.ntsc) 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); if (reg[12]&1)
else sms_ntsc_blit(&sms_ntsc, ( SMS_NTSC_IN_T const * )pixel_16, tmp_buf+0x20-bitmap.viewport.x, width, line); 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; return;
} }
@ -1928,7 +1947,8 @@ void parse_satb(uint32 line)
/* sprite limit (max. 16 or 20 sprites displayed per line) */ /* sprite limit (max. 16 or 20 sprites displayed per line) */
if(object_index_count == limit) if(object_index_count == limit)
{ {
if(vint_pending == 0) status |= 0x40; if(vint_pending == 0)
status |= 0x40;
return; return;
} }

View File

@ -24,6 +24,9 @@
#ifndef _RENDER_H_ #ifndef _RENDER_H_
#define _RENDER_H_ #define _RENDER_H_
/* Global variables */
extern uint32 object_index_count;
/* Function prototypes */ /* Function prototypes */
extern void render_init(void); extern void render_init(void);
extern void render_reset(void); extern void render_reset(void);

View File

@ -104,7 +104,7 @@ void Fir_Resampler_clear()
if ( buffer_size ) if ( buffer_size )
{ {
write_pos = &buffer [WRITE_OFFSET]; 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; pos = 0.0;
input_per_cycle = 0; input_per_cycle = 0;
memset(impulses, 0, MAX_RES*WIDTH*sizeof(sample_t));
for ( i = 0; i < res; i++ ) for ( i = 0; i < res; i++ )
{ {
gen_sinc( ROLLOFF, (int) (WIDTH * filter + 1) & ~1, pos, filter, 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 ) ); 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_ = out;
sample_t* out_r = out[1];
sample_t* in = buffer; sample_t* in = buffer;
sample_t* end_pos = write_pos; sample_t* end_pos = write_pos;
unsigned long skip = skip_bits >> imp_phase; unsigned long skip = skip_bits >> imp_phase;
@ -258,8 +259,8 @@ int Fir_Resampler_read( sample_t** out, long count )
remain = res; remain = res;
} }
*out_l++ = (sample_t) l; *out++ = (sample_t) l;
*out_r++ = (sample_t) r; *out++ = (sample_t) r;
} }
while ( in <= end_pos ); while ( in <= end_pos );
} }
@ -270,7 +271,7 @@ int Fir_Resampler_read( sample_t** out, long count )
write_pos = &buffer [left]; write_pos = &buffer [left];
memmove( buffer, in, left * sizeof *in ); memmove( buffer, in, left * sizeof *in );
return out_l - out[0]; return out - out_;
} }
int Fir_Resampler_input_needed( long output_count ) int Fir_Resampler_input_needed( long output_count )

View File

@ -23,7 +23,7 @@ extern sample_t* Fir_Resampler_buffer( void );
extern int Fir_Resampler_written( void ); extern int Fir_Resampler_written( void );
extern int Fir_Resampler_avail( void ); extern int Fir_Resampler_avail( void );
extern void Fir_Resampler_write( long count ); 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_input_needed( long output_count );
extern int Fir_Resampler_skip_input( long count ); extern int Fir_Resampler_skip_input( long count );

View File

@ -109,10 +109,10 @@ static const int PSGVolumeValues[2][16] = {
static SN76489_Context SN76489; static SN76489_Context SN76489;
void SN76489_Init(int PSGClockValue, int SamplingRate) void SN76489_Init(float PSGClockValue, int SamplingRate)
{ {
SN76489_Context *p = &SN76489; 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_Config(MUTE_ALLON, VOL_FULL, FB_SEGAVDP, SRW_SEGAVDP, config.psgBoostNoise);
SN76489_Reset(); SN76489_Reset();
} }

View File

@ -16,7 +16,7 @@
#define _SN76489_H_ #define _SN76489_H_
/* Function prototypes */ /* 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_Reset(void);
extern void SN76489_Shutdown(void); extern void SN76489_Shutdown(void);
extern void SN76489_SetContext(uint8 *data); extern void SN76489_SetContext(uint8 *data);

View File

@ -24,105 +24,229 @@
#include "shared.h" #include "shared.h"
#include "Fir_Resampler.h" #include "Fir_Resampler.h"
/* cycle-accurate samples */ /* Cycle-accurate samples */
static int m68cycles_per_sample[2]; 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 */ /* Run FM chip for required M-cycles */
static inline int fm_sample_cnt(uint8 z80) 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); /* convert to 21.11 fixed point */
else return ((count_m68k / m68cycles_per_sample[0]) - snd.fm.pos); cycles <<= 11;
}
static inline int psg_sample_cnt(uint8 z80) if (cycles > fm_cycles_count)
{
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)
{ {
YM2612Update(cnt); /* period to run */
snd.fm.pos += cnt; 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 */ /* Run PSG chip for required M-cycles */
static inline void psg_update(int cnt) 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; snd.psg.pos += cnt;
} }
} }
/* initialize sound chips emulation */ /* Initialize sound chips emulation */
void sound_init(int rate, double fps) void sound_init(void)
{ {
double vclk = (vdp_pal ? (double)CLOCK_PAL : (double)CLOCK_NTSC) / 7.0; /* 68000 and YM2612 clock */ /* Number of M-cycles executed per second. */
double zclk = (vdp_pal ? (double)CLOCK_PAL : (double)CLOCK_NTSC) / 15.0; /* Z80 and SN76489 clock */ /* */
/* 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 */ /* For better accuracy, sound chips run in synchronization with 68k and Z80 cpus */
m68cycles_per_sample[0] = (int)(((double)m68cycles_per_line * (double)lines_per_frame * fps/ (double)rate) + 0.5); /* These values give the exact number of M-cycles between 2 rendered samples. */
m68cycles_per_sample[1] = m68cycles_per_sample[0]; /* 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) if (config.hq_fm)
{ {
/* "real" ratio is (vclk/144.0)/(rate) but since we need perfect synchronization between video & audio fm_cycles_ratio = 144 * 7 * (1 << 11);
on the target system, we are not exactly running at the real genesis framerate but the target Fir_Resampler_time_ratio(mclk / (double)snd.sample_rate / (144.0 * 7.0));
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;
} }
/* initialize sound chips */ #ifdef LOG_SOUND
SN76489_Init((int)zclk,rate); error("%d mcycles per PSG samples\n", psg_cycles_ratio);
YM2612Init((int)vclk,rate); error("%d mcycles per FM samples\n", fm_cycles_ratio);
#endif
} }
void sound_update(int fm_len, int psg_len) /* Reset sound chips emulation */
void sound_reset(void)
{ {
/* update last samples (if needed) */ YM2612ResetChip();
fm_update(fm_len - snd.fm.pos); SN76489_Reset();
psg_update(psg_len - snd.psg.pos); fm_cycles_count = 0;
psg_cycles_count = 0;
/* reset samples count */
snd.fm.pos = 0;
snd.psg.pos = 0;
} }
/* reset FM chip */ /* 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) void fm_reset(void)
{ {
fm_update(fm_sample_cnt(0)); fm_update(mcycles_68k);
YM2612ResetChip(); YM2612ResetChip();
} }
/* write FM chip */ /* Write FM chip */
void fm_write(unsigned int cpu, unsigned int address, unsigned int data) 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); YM2612Write(address, data);
} }
/* read FM status */ /* Read FM status */
unsigned int fm_read(unsigned int cpu, unsigned int address) unsigned int fm_read(unsigned int cycles, unsigned int address)
{ {
fm_update(fm_sample_cnt(cpu)); fm_update(cycles);
return YM2612Read(); return YM2612Read();
} }
/* write PSG chip */ /* Write PSG chip */
void psg_write(unsigned int cpu, unsigned int data) void psg_write(unsigned int cycles, unsigned int data)
{ {
psg_update(psg_sample_cnt(cpu)); psg_update(cycles);
SN76489_Write(data); SN76489_Write(data);
} }

View File

@ -25,11 +25,12 @@
#define _SOUND_H_ #define _SOUND_H_
/* Function prototypes */ /* Function prototypes */
extern void sound_init(int rate, double fps); extern void sound_init(void);
extern void sound_update(int fm_len, int psg_len); extern void sound_reset(void);
extern int sound_update(unsigned int cycles);
extern void fm_reset(void); extern void fm_reset(void);
extern void fm_write(unsigned int cpu, unsigned int address, unsigned int data); extern void fm_write(unsigned int cycles, unsigned int address, unsigned int data);
extern unsigned int fm_read(unsigned int cpu, unsigned int address); extern unsigned int fm_read(unsigned int cycles, unsigned int address);
extern void psg_write(unsigned int cpu, unsigned int data); extern void psg_write(unsigned int cycles, unsigned int data);
#endif /* _SOUND_H_ */ #endif /* _SOUND_H_ */

View File

@ -554,7 +554,7 @@ typedef struct
typedef struct typedef struct
{ {
UINT32 clock; /* master clock (Hz) */ float clock; /* master clock (Hz) */
UINT32 rate; /* sampling rate (Hz) */ UINT32 rate; /* sampling rate (Hz) */
UINT16 address; /* address register */ UINT16 address; /* address register */
UINT8 status; /* status flag */ UINT8 status; /* status flag */
@ -1775,7 +1775,7 @@ static void init_timetables(double freqbase)
static void OPNSetPres(int pres) static void OPNSetPres(int pres)
{ {
/* frequency base (ratio between FM original samplerate & desired output samplerate)*/ /* 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) */ /* YM2612 running at original frequency (~53267 Hz) */
if (config.hq_fm) freqbase = 1.0; if (config.hq_fm) freqbase = 1.0;
@ -1913,7 +1913,7 @@ static void init_tables(void)
/* initialize ym2612 emulator(s) */ /* initialize ym2612 emulator(s) */
int YM2612Init(int clock, int rate) int YM2612Init(float clock, int rate)
{ {
memset(&ym2612,0,sizeof(YM2612)); memset(&ym2612,0,sizeof(YM2612));
init_tables(); init_tables();
@ -2017,24 +2017,10 @@ unsigned int YM2612Read(void)
} }
/* Generate 16 bits samples for ym2612 */ /* Generate 16 bits samples for ym2612 */
void YM2612Update(int length) void YM2612Update(short int *buffer, int length)
{ {
int i; int i;
int lt,rt; 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 PG increments and EG rates if required */
refresh_fc_eg_chan(&ym2612.CH[0]); refresh_fc_eg_chan(&ym2612.CH[0]);
@ -2139,16 +2125,8 @@ void YM2612Update(int length)
// Limit(rt,MAXOUT,MINOUT); // Limit(rt,MAXOUT,MINOUT);
/* buffering */ /* buffering */
if (bufFIR) *buffer++ = lt;
{ *buffer++ = rt;
*bufFIR++ = lt;
*bufFIR++ = rt;
}
else
{
*bufL++ = lt;
*bufR++ = rt;
}
/* CSM mode: if CSM Key ON has occured, CSM Key OFF need to be sent */ /* 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) */ /* 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) void YM2612Restore(unsigned char *buffer)
{ {
/* save current timings */ /* save current timings */
int clock = ym2612.OPN.ST.clock; float clock = ym2612.OPN.ST.clock;
int rate = ym2612.OPN.ST.rate; int rate = ym2612.OPN.ST.rate;
/* restore internal state */ /* restore internal state */

View File

@ -19,9 +19,9 @@
#endif #endif
extern int YM2612Init(int baseclock, int rate); extern int YM2612Init(float clock, int rate);
extern int YM2612ResetChip(void); 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 void YM2612Write(unsigned int a, unsigned int v);
extern unsigned int YM2612Read(void); extern unsigned int YM2612Read(void);
extern unsigned char *YM2612GetContextPtr(void); extern unsigned char *YM2612GetContextPtr(void);

View File

@ -59,10 +59,8 @@ int state_load(unsigned char *buffer)
// GENESIS // GENESIS
load_param(work_ram, sizeof(work_ram)); load_param(work_ram, sizeof(work_ram));
load_param(zram, sizeof(zram)); load_param(zram, sizeof(zram));
load_param(&zbusreq, sizeof(zbusreq)); load_param(&zstate, sizeof(zstate));
load_param(&zreset, sizeof(zreset));
load_param(&zbank, sizeof(zbank)); load_param(&zbank, sizeof(zbank));
zbusack = 1 ^(zbusreq & zreset);
// IO // IO
load_param(io_reg, sizeof(io_reg)); load_param(io_reg, sizeof(io_reg));
@ -134,8 +132,7 @@ int state_save(unsigned char *buffer)
// GENESIS // GENESIS
save_param(work_ram, sizeof(work_ram)); save_param(work_ram, sizeof(work_ram));
save_param(zram, sizeof(zram)); save_param(zram, sizeof(zram));
save_param(&zbusreq, sizeof(zbusreq)); save_param(&zstate, sizeof(zstate));
save_param(&zreset, sizeof(zreset));
save_param(&zbank, sizeof(zbank)); save_param(&zbank, sizeof(zbank));
// IO // IO

View File

@ -30,12 +30,10 @@
/* Global variables */ /* Global variables */
t_bitmap bitmap; t_bitmap bitmap;
t_snd snd; t_snd snd;
uint32 count_m68k; uint32 mcycles_vdp;
uint32 line_m68k; uint32 mcycles_z80;
uint32 hint_m68k; uint32 mcycles_68k;
uint32 count_z80; uint32 hint_68k;
uint32 line_z80;
int32 current_z80;
uint8 system_hw; uint8 system_hw;
/**************************************************************** /****************************************************************
@ -56,7 +54,7 @@ void audio_set_equalizer(void)
****************************************************************/ ****************************************************************/
static int llp,rrp; static int llp,rrp;
void audio_update (int size) int audio_update (void)
{ {
int i, l, r; int i, l, r;
int ll = llp; int ll = llp;
@ -68,26 +66,45 @@ void audio_update (int size)
uint32 factora = (config.lp_range << 16) / 100; uint32 factora = (config.lp_range << 16) / 100;
uint32 factorb = 0x10000 - factora; uint32 factorb = 0x10000 - factora;
int16 *fm[2] = {snd.fm.buffer[0],snd.fm.buffer[1]}; int16 *fm = snd.fm.buffer;
int16 *psg = snd.psg.buffer; int16 *psg = snd.psg.buffer;
#ifdef NGC #ifdef NGC
int16 *sb = (int16 *) soundbuffer[mixbuffer]; int16 *sb = (int16 *) soundbuffer[mixbuffer];
#endif #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) if (config.hq_fm)
{ {
int len = Fir_Resampler_input_needed(size << 1); /* resample into FM output buffer */
sound_update(len >> 1,size);
Fir_Resampler_write(len);
Fir_Resampler_read(fm,size); Fir_Resampler_read(fm,size);
#ifdef LOG_SOUND
error("%d FM samples remaining\n",Fir_Resampler_written() >> 1);
#endif
} }
else 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 */ /* mix samples */
for (i = 0; i < size; i ++) for (i = 0; i < size; i ++)
{ {
@ -95,8 +112,8 @@ void audio_update (int size)
l = r = ((*psg++) * psg_preamp)/100; l = r = ((*psg++) * psg_preamp)/100;
/* FM samples (stereo) */ /* FM samples (stereo) */
l += (*fm[0]++ * fm_preamp)/100; l += (*fm++ * fm_preamp)/100;
r += (*fm[1]++ * fm_preamp)/100; r += (*fm++ * fm_preamp)/100;
/* filtering */ /* filtering */
if (filter & 1) if (filter & 1)
@ -130,15 +147,25 @@ void audio_update (int size)
#endif #endif
} }
/* save delayed samples */ /* save delayed samples for next frame */
llp = ll; llp = ll;
rrp = rr; 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 * AUDIO System initialization
****************************************************************/ ****************************************************************/
int audio_init (int rate, double fps) int audio_init (int samplerate, float framerate)
{ {
/* Shutdown first */ /* Shutdown first */
audio_shutdown(); audio_shutdown();
@ -146,61 +173,91 @@ int audio_init (int rate, double fps)
/* Clear the sound data context */ /* Clear the sound data context */
memset(&snd, 0, sizeof (snd)); memset(&snd, 0, sizeof (snd));
/* Make sure the requested sample rate is valid */ /* Default settings */
if (!rate || ((rate < 8000) | (rate > 48000))) return (-1); snd.sample_rate = samplerate;
snd.sample_rate = rate; snd.frame_rate = framerate;
/* Calculate the sound buffer size (for one frame) */
snd.buffer_size = (int)(samplerate / framerate) + 32;
#ifndef NGC #ifndef NGC
/* Calculate the sound buffer size (for one frame) */
snd.buffer_size = (rate / vdp_rate);
/* Output buffers */ /* Output buffers */
snd.buffer[0] = (int16 *) malloc(SND_SIZE); snd.buffer[0] = (int16 *) malloc(SND_SIZE);
snd.buffer[1] = (int16 *) malloc(SND_SIZE); snd.buffer[1] = (int16 *) malloc(SND_SIZE);
if (!snd.buffer[0] || !snd.buffer[1]) return (-1); if (!snd.buffer[0] || !snd.buffer[1])
#else return (-1);
/* Calculate the sound buffer size (for one frame) */
snd.buffer_size = (rate / vdp_rate) + 32;
#endif #endif
/* SN76489 stream buffers */ /* SN76489 stream buffers */
snd.psg.buffer = (int16 *)malloc (SND_SIZE); snd.psg.buffer = (int16 *) malloc(SND_SIZE);
if (!snd.psg.buffer) return (-1); if (!snd.psg.buffer)
return (-1);
/* YM2612 stream buffers */ /* YM2612 stream buffers */
snd.fm.buffer[0] = (int16 *)malloc (SND_SIZE); snd.fm.buffer = (int16 *) malloc(SND_SIZE * 2);
snd.fm.buffer[1] = (int16 *)malloc (SND_SIZE); if (!snd.fm.buffer)
if (!snd.fm.buffer[0] || !snd.fm.buffer[1]) return (-1); return (-1);
/* Resampling buffer */ /* Resampling buffer */
if (config.hq_fm) 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 */ /* Set audio enable flag */
snd.enabled = 1; snd.enabled = 1;
/* Initialize Sound Chips emulation */ /* Reset audio */
sound_init(rate,fps); audio_reset();
return (0); 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 * AUDIO System shutdown
****************************************************************/ ****************************************************************/
void audio_shutdown(void) void audio_shutdown(void)
{ {
/* Sound buffers */ /* Sound buffers */
if (snd.buffer[0]) free(snd.buffer[0]); #ifndef NGC
if (snd.buffer[1]) free(snd.buffer[1]); if (snd.buffer[0])
if (snd.fm.buffer[0]) free(snd.fm.buffer[0]); free(snd.buffer[0]);
if (snd.fm.buffer[1]) free(snd.fm.buffer[1]); if (snd.buffer[1])
if (snd.psg.buffer) free(snd.psg.buffer); free(snd.buffer[1]);
#endif
if (snd.fm.buffer)
free(snd.fm.buffer);
if (snd.psg.buffer)
free(snd.psg.buffer);
/* Resampling buffer */ /* Resampling buffer */
Fir_Resampler_shutdown(); Fir_Resampler_shutdown();
@ -219,6 +276,9 @@ void system_init (void)
/* Cartridge hardware */ /* Cartridge hardware */
cart_hw_init(); cart_hw_init();
/* Sound Chips hardware */
sound_init();
} }
/**************************************************************** /****************************************************************
@ -231,17 +291,15 @@ void system_reset (void)
/* Genesis hardware */ /* Genesis hardware */
gen_reset(1); gen_reset(1);
SN76489_Reset();
io_reset(); io_reset();
vdp_reset(); vdp_reset();
render_reset(); render_reset();
/* Clear Sound Buffers */ /* Sound chips */
if (snd.psg.buffer) memset (snd.psg.buffer, 0, SND_SIZE); sound_reset();
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); /* Audio System */
Fir_Resampler_clear(); audio_reset();
llp = rrp = 0;
} }
/**************************************************************** /****************************************************************
@ -265,15 +323,6 @@ int system_frame (int do_skip)
return 0; 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 */ /* update display settings */
int line; int line;
int reset = resetline; int reset = resetline;
@ -291,17 +340,21 @@ int system_frame (int do_skip)
odd_frame ^= 1; odd_frame ^= 1;
/* clear VBLANK and DMA flags */ /* clear VBLANK and DMA flags */
status &= 0xFFF5; status &= 0xFFE5;
/* even/odd field flag (interlaced modes only) */ /* even/odd field flag (interlaced modes only) */
if (odd_frame && interlaced) status |= 0x0010; if (odd_frame && interlaced)
else status &= 0xFFEF; status |= 0x0010;
/* reload HCounter */ /* reload HCounter */
int h_counter = reg[10]; int h_counter = reg[10];
/* parse sprites for line 0 (done on last line) */ /* reset VDP FIFO */
parse_satb (0x80); fifo_write_cnt = 0;
fifo_lastwrite = 0;
/* reset line cycle count */
mcycles_vdp = 0;
/* process scanlines */ /* process scanlines */
for (line = 0; line < lines_per_frame; line ++) for (line = 0; line < lines_per_frame; line ++)
@ -312,14 +365,10 @@ int system_frame (int do_skip)
/* update 6-Buttons or Menacer */ /* update 6-Buttons or Menacer */
input_update(); input_update();
/* update CPU cycle counters */ /* 68k line cycle count */
hint_m68k = count_m68k; hint_68k = mcycles_68k;
line_m68k = aim_m68k;
line_z80 = aim_z80;
aim_z80 += z80cycles_per_line;
aim_m68k += m68cycles_per_line;
/* Soft Reset ? */ /* Soft Reset line */
if (line == reset) if (line == reset)
{ {
/* Pro Action Replay (switch at "Trainer" position) */ /* Pro Action Replay (switch at "Trainer" position) */
@ -329,6 +378,10 @@ int system_frame (int do_skip)
gen_reset(0); gen_reset(0);
} }
/* update VDP DMA */
if (dma_length)
vdp_update_dma();
/* active display */ /* active display */
if (line <= vdp_height) if (line <= vdp_height)
{ {
@ -337,27 +390,16 @@ int system_frame (int do_skip)
{ {
h_counter = reg[10]; h_counter = reg[10];
hint_pending = 1; hint_pending = 1;
if (reg[0] & 0x10) irq_status = (irq_status & ~0x40) | 0x14; 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;
} }
/* 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 */ /* vertical retrace */
if (line == vdp_height) if (line == vdp_height)
{ {
/* render overscan */ /* 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) */ /* update inputs (doing this here fix Warriors of Eternal Sun) */
osd_input_Update(); osd_input_Update();
@ -369,37 +411,36 @@ int system_frame (int do_skip)
zirq = 1; 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) */ /* delay between VINT flag & V Interrupt (Ex-Mutants, Tyrant) */
m68k_run(line_m68k + 84); m68k_run(mcycles_vdp + 588);
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 */
status |= 0x80; status |= 0x80;
/* 36 cycles latency after VINT occurence flag (Ex-Mutants, Tyrant) */ /* delay between VBLANK flag & V Interrupt (Dracula, OutRunners, VR Troopers) */
m68k_run(line_m68k + 113); m68k_run(mcycles_vdp + 788);
if (zstate == 1)
z80_run(mcycles_vdp + 788);
else
mcycles_z80 = mcycles_vdp + 788;
/* V Interrupt */
vint_pending = 1; 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) 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); render_line(line, 0);
if (line < (vdp_height-1)) parse_satb(0x81 + line);
} }
} }
else else
{ {
/* update DMA timings */
if (dma_length) vdp_update_dma();
/* render overscan */ /* 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 */ /* clear any pending Z80 interrupt */
if (zirq) if (zirq)
@ -410,17 +451,23 @@ int system_frame (int do_skip)
} }
/* process line */ /* process line */
m68k_run(aim_m68k); m68k_run(mcycles_vdp + MCYCLES_PER_LINE);
if (zreset == 1 && zbusreq == 0) if (zstate == 1)
{ z80_run(mcycles_vdp + MCYCLES_PER_LINE);
current_z80 = aim_z80 - count_z80; else
if (current_z80 > 0) count_z80 += z80_execute(current_z80); mcycles_z80 = mcycles_vdp + MCYCLES_PER_LINE;
}
else count_z80 = aim_z80;
/* SVP chip */ /* 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; return gen_running;
} }

View File

@ -28,12 +28,7 @@
#define SYSTEM_MEGADRIVE 1 #define SYSTEM_MEGADRIVE 1
#define SYSTEM_PICO 2 #define SYSTEM_PICO 2
/* CPU cycles increments */ #define MCYCLES_PER_LINE 3420
#define z80cycles_per_line 228
#define m68cycles_per_line 488
#define CLOCK_NTSC 53693175
#define CLOCK_PAL 53203424
typedef struct typedef struct
{ {
@ -59,18 +54,19 @@ typedef struct
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 enabled; /* 1= sound emulation is enabled */
int buffer_size; /* Size of sound buffer (in bytes) */ int buffer_size; /* Size of sound buffer (in bytes) */
int16 *buffer[2]; /* Signed 16-bit stereo sound data */ int16 *buffer[2]; /* Signed 16-bit stereo sound data */
struct struct
{ {
int pos; int16 *pos;
int16 *buffer[2]; int16 *buffer;
} fm; } fm;
struct struct
{ {
int pos; int16 *pos;
int16 *buffer; int16 *buffer;
} psg; } psg;
} t_snd; } t_snd;
@ -78,18 +74,17 @@ typedef struct
/* Global variables */ /* Global variables */
extern t_bitmap bitmap; extern t_bitmap bitmap;
extern t_snd snd; extern t_snd snd;
extern uint32 count_m68k; extern uint32 mcycles_vdp;
extern uint32 line_m68k; extern uint32 mcycles_z80;
extern uint32 hint_m68k; extern uint32 mcycles_68k;
extern uint32 count_z80; extern uint32 hint_68k;
extern uint32 line_z80;
extern int32 current_z80;
extern uint8 system_hw; extern uint8 system_hw;
/* Function prototypes */ /* 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_shutdown (void);
extern void audio_update (int len); extern int audio_update (void);
extern void audio_set_equalizer(void); extern void audio_set_equalizer(void);
extern void system_init (void); extern void system_init (void);
extern void system_reset (void); extern void system_reset (void);

View File

@ -103,7 +103,7 @@ int main (int argc, char *argv[])
/* initialize emulation */ /* initialize emulation */
system_init(); system_init();
audio_init(option.sndrate); audio_init(option.sndrate, vdp_pal ? 50 : 60);
f = fopen("./game.srm", "rb"); f = fopen("./game.srm", "rb");
if (f!=NULL) if (f!=NULL)
@ -132,8 +132,9 @@ int main (int argc, char *argv[])
system_frame(1); system_frame(1);
} }
audio_update(snd.buffer_size); audio_update();
if(option.sound) dos_update_audio(); if(option.sound)
dos_update_audio();
} }
f = fopen("./game.srm", "wb"); f = fopen("./game.srm", "wb");
@ -366,11 +367,19 @@ void dos_update_input(void)
{ {
vdp_pal ^= 1; vdp_pal ^= 1;
/* reinitialize timings */ /* save YM2612 context */
system_init (); unsigned char *temp = memalign(32,YM2612GetContextSize());
unsigned char *temp = malloc(YM2612GetContextSize()); if (temp)
if (temp) memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize()); memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize());
audio_init(48000);
/* reinitialize all timings */
audio_init(snd.sample_rate, framerate);
system_init();
/* restore SRAM */
memfile_autoload(config.sram_auto,-1);
/* restore YM2612 context */
if (temp) if (temp)
{ {
YM2612Restore(temp); YM2612Restore(temp);
@ -378,7 +387,7 @@ void dos_update_input(void)
} }
/* reinitialize HVC tables */ /* 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; hctab = (reg[12] & 1) ? cycle2hc40 : cycle2hc32;
/* reinitialize overscan area */ /* reinitialize overscan area */

View File

@ -12,7 +12,7 @@ NAME = gen_sdl.exe
CC = gcc CC = gcc
CFLAGS = `sdl-config --cflags` -O6 -march=i686 -fomit-frame-pointer 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 INCLUDES = -I. -I.. -I../z80 -I../m68k -I../sound -I../cart_hw -I../cart_hw/svp -I../ntsc
LIBS = `sdl-config --libs` -lz -lm LIBS = `sdl-config --libs` -lz -lm

View File

@ -304,11 +304,19 @@ static int sdl_control_update(SDLKey keystate)
{ {
vdp_pal ^= 1; vdp_pal ^= 1;
/* reinitialize timings */ /* save YM2612 context */
system_init (); unsigned char *temp = memalign(32,YM2612GetContextSize());
unsigned char *temp = malloc(YM2612GetContextSize()); if (temp)
if (temp) memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize()); memcpy(temp, YM2612GetContextPtr(), YM2612GetContextSize());
audio_init(SOUND_FREQUENCY);
/* reinitialize all timings */
audio_init(snd.sample_rate, framerate);
system_init();
/* restore SRAM */
memfile_autoload(config.sram_auto,-1);
/* restore YM2612 context */
if (temp) if (temp)
{ {
YM2612Restore(temp); YM2612Restore(temp);
@ -316,7 +324,7 @@ static int sdl_control_update(SDLKey keystate)
} }
/* reinitialize HVC tables */ /* 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; hctab = (reg[12] & 1) ? cycle2hc40 : cycle2hc32;
/* reinitialize overscan area */ /* reinitialize overscan area */
@ -528,8 +536,8 @@ int main (int argc, char **argv)
SDL_UnlockSurface(sdl_video.surf_bitmap); SDL_UnlockSurface(sdl_video.surf_bitmap);
/* initialize emulation */ /* initialize emulation */
audio_init(SOUND_FREQUENCY, vdp_pal ? 50 : 60);
system_init(); system_init();
audio_init(SOUND_FREQUENCY);
/* load SRAM */ /* load SRAM */
f = fopen("./game.srm", "rb"); f = fopen("./game.srm", "rb");
@ -545,8 +553,9 @@ int main (int argc, char **argv)
if(use_sound) if(use_sound)
SDL_PauseAudio(0); SDL_PauseAudio(0);
/* 3 frames = 50 ms (60hz) or 60 ms (50hz) */
if(sdl_sync.sem_sync) 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 */ /* emulation loop */
while(running) while(running)

View File

@ -72,12 +72,10 @@ uint16 v_counter; /* VDP scanline counter */
uint32 dma_length; /* Current DMA remaining bytes */ uint32 dma_length; /* Current DMA remaining bytes */
int32 fifo_write_cnt; /* VDP writes fifo count */ int32 fifo_write_cnt; /* VDP writes fifo count */
uint32 fifo_lastwrite; /* last VDP write cycle */ uint32 fifo_lastwrite; /* last VDP write cycle */
uint8 fifo_latency; /* VDP write cycles latency */
uint8 odd_frame; /* 1: odd field, 0: even field */ uint8 odd_frame; /* 1: odd field, 0: even field */
uint8 im2_flag; /* 1= Interlace mode 2 is being used */ uint8 im2_flag; /* 1= Interlace mode 2 is being used */
uint8 interlaced; /* 1: Interlaced mode 1 or 2 */ uint8 interlaced; /* 1: Interlaced mode 1 or 2 */
uint8 vdp_pal; /* 1: PAL , 0: NTSC (default) */ uint8 vdp_pal; /* 1: PAL , 0: NTSC (default) */
uint8 vdp_rate; /* PAL: 50hz, NTSC: 60hz */
uint16 lines_per_frame; /* PAL: 313 lines, NTSC: 262 lines */ 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_base_mask; /* Base bits of SAT */
static uint16 sat_addr_mask; /* Index bits of SAT */ static uint16 sat_addr_mask; /* Index bits of SAT */
static uint32 dma_endCycles; /* 68k cycles to DMA end */ 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 /* DMA Timings
@ -141,21 +140,10 @@ static inline void dma_fill(unsigned int data);
void vdp_init(void) void vdp_init(void)
{ {
/* PAL/NTSC timings */ /* PAL/NTSC timings */
switch (region_code) if (vdp_pal)
{
case REGION_EUROPE:
case REGION_JAPAN_PAL:
vdp_pal = 1;
vdp_rate = 50;
lines_per_frame = 313; lines_per_frame = 313;
break; else
default:
vdp_pal = 0;
vdp_rate = 60;
lines_per_frame = 262; lines_per_frame = 262;
break;
}
} }
void vdp_reset(void) void vdp_reset(void)
@ -233,8 +221,8 @@ void vdp_reset(void)
reg_w(15, 0x02); /* auto increment */ reg_w(15, 0x02); /* auto increment */
} }
/* default latency */ /* default FIFO timing */
fifo_latency = 27; fifo_latency = 192;
} }
void vdp_shutdown(void) 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.y = config.overscan ? (((reg[1] & 8) ? 0 : 8) + (vdp_pal ? 24 : 0)) : 0;
bitmap.viewport.changed = 1; bitmap.viewport.changed = 1;
/* restore VDP timings */ /* restore FIFO timings */
fifo_latency = (reg[12] & 1) ? 27 : 30; fifo_latency = (reg[12] & 1) ? 192 : 210;
if ((code & 0x0F) == 0x01) fifo_latency = fifo_latency * 2; if ((code & 0x0F) == 0x01)
fifo_latency = fifo_latency * 2;
/* remake cache */ /* remake cache */
for (i=0;i<0x800;i++) for (i=0;i<0x800;i++)
@ -295,21 +284,21 @@ void vdp_update_dma()
int rate = dma_rates[index]; int rate = dma_rates[index];
/* 68k cycles left */ /* 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; if (left_cycles < 0) left_cycles = 0;
/* DMA bytes left */ /* DMA bytes left */
int dma_bytes = (left_cycles * rate) / m68cycles_per_line; int dma_bytes = (left_cycles * rate) / MCYCLES_PER_LINE;
#ifdef LOGVDP #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 #endif
/* determinate DMA length in CPU cycles */ /* determinate DMA length in CPU cycles */
if (dma_length < dma_bytes) if (dma_length < dma_bytes)
{ {
/* DMA will be finished during this line */ /* 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; dma_length = 0;
} }
else else
@ -324,7 +313,7 @@ void vdp_update_dma()
{ {
/* 68K COPY to V-RAM */ /* 68K COPY to V-RAM */
/* 68K is frozen during DMA operation */ /* 68K is frozen during DMA operation */
count_m68k += dma_cycles; mcycles_68k += dma_cycles;
#ifdef LOGVDP #ifdef LOGVDP
error("-->CPU frozen for %d cycles\n", dma_cycles); error("-->CPU frozen for %d cycles\n", dma_cycles);
@ -334,7 +323,7 @@ void vdp_update_dma()
{ {
/* VRAM Fill or VRAM Copy */ /* VRAM Fill or VRAM Copy */
/* set DMA end cyles count */ /* set DMA end cyles count */
dma_endCycles = count_m68k + dma_cycles; dma_endCycles = mcycles_68k + dma_cycles;
#ifdef LOGVDP #ifdef LOGVDP
error("-->DMA ends in %d cycles\n", dma_cycles); error("-->DMA ends in %d cycles\n", dma_cycles);
@ -348,7 +337,6 @@ void vdp_update_dma()
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/* VDP Ports handler */ /* VDP Ports handler */
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
void vdp_ctrl_w(unsigned int data) void vdp_ctrl_w(unsigned int data)
{ {
if (pending == 0) if (pending == 0)
@ -398,18 +386,23 @@ void vdp_ctrl_w(unsigned int data)
} }
} }
/* FIFO emulation: /*
--------------- FIFO emulation (Chaos Engine/Soldier of Fortune, Double Clutch)
HDISP is 256*10/7 = approx. 366 cycles (same for both modes) ---------------------------------------------------------------
this gives:
H32: 16 accesses --> 366/16 = 23 cycles per access HDISP is 2560 mcycles (same in both modes)
H40: 20 accesses --> 366/20 = 18 cycles per access
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) if ((code & 0x0F) == 0x01)
fifo_latency = fifo_latency * 2; fifo_latency = fifo_latency * 2;
} }
@ -442,7 +435,7 @@ unsigned int vdp_ctrl_r(void)
else status ^= 0x200; else status ^= 0x200;
/* update DMA Busy flag */ /* update DMA Busy flag */
if ((status & 2) && !dma_length && (count_m68k >= dma_endCycles)) if ((status & 2) && !dma_length && (mcycles_68k >= dma_endCycles))
status &= 0xFFFD; status &= 0xFFFD;
unsigned int temp = status; unsigned int temp = status;
@ -452,7 +445,7 @@ unsigned int vdp_ctrl_r(void)
temp |= 0x08; temp |= 0x08;
/* HBLANK flag (Sonic 3 and Sonic 2 "VS Modes", Lemmings 2, Mega Turrican) */ /* 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; temp |= 0x04;
/* clear pending flag */ /* clear pending flag */
@ -462,21 +455,21 @@ unsigned int vdp_ctrl_r(void)
status &= 0xFF9F; status &= 0xFF9F;
#ifdef LOGVDP #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 #endif
return (temp); return (temp);
} }
unsigned int vdp_hvc_r(void) 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]; uint8 vc = vctab[v_counter];
/* interlace mode 2 */ /* interlace mode 2 */
if (im2_flag) vc = (vc << 1) | ((vc >> 7) & 1); if (im2_flag) vc = (vc << 1) | ((vc >> 7) & 1);
#ifdef LOGVDP #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 #endif
return ((vc << 8) | hc); return ((vc << 8) | hc);
} }
@ -506,13 +499,13 @@ void vdp_data_w(unsigned int data)
if (fifo_write_cnt == 0) if (fifo_write_cnt == 0)
{ {
/* reset cycle counter */ /* reset cycle counter */
fifo_lastwrite = count_m68k; fifo_lastwrite = mcycles_68k;
/* FIFO is not empty anymore */ /* FIFO is not empty anymore */
status &= 0xFDFF; status &= 0xFDFF;
} }
/* increase write counter */ /* increase FIFO word count */
fifo_write_cnt ++; fifo_write_cnt ++;
/* is FIFO full ? */ /* is FIFO full ? */
@ -522,7 +515,7 @@ void vdp_data_w(unsigned int data)
/* VDP latency (Chaos Engine, Soldiers of Fortune, Double Clutch) */ /* VDP latency (Chaos Engine, Soldiers of Fortune, Double Clutch) */
if (fifo_write_cnt > 4) 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 */ case 0x00: /* VRAM */
temp = *(uint16 *) & vram[(addr & 0xFFFE)]; temp = *(uint16 *) & vram[(addr & 0xFFFE)];
#ifdef LOGVDP #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 #endif
break; break;
@ -550,14 +543,14 @@ unsigned int vdp_data_r(void)
temp = *(uint16 *) & cram[(addr & 0x7E)]; temp = *(uint16 *) & cram[(addr & 0x7E)];
temp = UNPACK_CRAM (temp); temp = UNPACK_CRAM (temp);
#ifdef LOGVDP #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 #endif
break; break;
case 0x04: /* VSRAM */ case 0x04: /* VSRAM */
temp = *(uint16 *) & vsram[(addr & 0x7E)]; temp = *(uint16 *) & vsram[(addr & 0x7E)];
#ifdef LOGVDP #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 #endif
break; break;
} }
@ -576,7 +569,7 @@ unsigned int vdp_data_r(void)
int vdp_int_ack_callback(int int_level) int vdp_int_ack_callback(int int_level)
{ {
#ifdef LOGVDP #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 #endif
/* VINT triggered ? */ /* VINT triggered ? */
@ -597,11 +590,13 @@ int vdp_int_ack_callback(int int_level)
} }
/* update IRQ status */ /* update IRQ status */
irq_status = 0x10; irq_status = 0;
if (vint_pending && (reg[1] & 0x20)) if (vint_pending && (reg[1] & 0x20))
irq_status |= 6; irq_status |= 0x16;
else if (hint_pending && (reg[0] & 0x10)) else if (hint_pending && (reg[0] & 0x10))
irq_status |= 4; irq_status |= 0x14;
else
m68k_set_irq(0);
return M68K_INT_ACK_AUTOVECTOR; return M68K_INT_ACK_AUTOVECTOR;
} }
@ -614,14 +609,15 @@ static inline void fifo_update()
if (fifo_write_cnt > 0) if (fifo_write_cnt > 0)
{ {
/* update FIFO reads */ /* 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) if (fifo_read > 0)
{ {
fifo_write_cnt -= fifo_read; 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 */ /* 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 */ case 0x01: /* VRAM */
#ifdef LOGVDP #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 #endif
/* Byte-swap data if A0 is set */ /* Byte-swap data if A0 is set */
@ -663,7 +659,7 @@ static inline void data_w(unsigned int data)
case 0x03: /* CRAM */ case 0x03: /* CRAM */
{ {
#ifdef LOGVDP #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 #endif
uint16 *p = (uint16 *) &cram[(addr & 0x7E)]; uint16 *p = (uint16 *) &cram[(addr & 0x7E)];
data = PACK_CRAM (data & 0x0EEE); data = PACK_CRAM (data & 0x0EEE);
@ -681,10 +677,10 @@ static inline void data_w(unsigned int data)
if (border == index) if (border == index)
color_update (0x00, *p); color_update (0x00, *p);
/* CRAM modified during HBLANK */ /* CRAM modified during HBLANK (Striker, Zero the Kamikaze, etc) */
if (!(status & 8) && (reg[1]&0x40) && (count_m68k <= (line_m68k + 84))) 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); remap_buffer(v_counter,bitmap.viewport.w + 2*bitmap.viewport.x);
#ifdef LOGVDP #ifdef LOGVDP
error("Line remapped\n"); error("Line remapped\n");
@ -699,7 +695,7 @@ static inline void data_w(unsigned int data)
case 0x05: /* VSRAM */ case 0x05: /* VSRAM */
#ifdef LOGVDP #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 #endif
*(uint16 *) &vsram[(addr & 0x7E)] = data; *(uint16 *) &vsram[(addr & 0x7E)] = data;
break; break;
@ -716,14 +712,15 @@ static inline void data_w(unsigned int data)
static inline void reg_w(unsigned int r, unsigned int d) static inline void reg_w(unsigned int r, unsigned int d)
{ {
#ifdef LOGVDP #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 #endif
/* See if Mode 4 (SMS mode) is enabled /* 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 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) 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) switch(r)
{ {
@ -734,8 +731,10 @@ static inline void reg_w(unsigned int r, unsigned int d)
{ {
/* update IRQ status */ /* update IRQ status */
irq_status = 0x50; irq_status = 0x50;
if (vint_pending && (reg[1] & 0x20)) irq_status |= 0x26; if (vint_pending && (reg[1] & 0x20))
else if (d & 0x10) irq_status |= 4; irq_status |= 0x26;
else if (d & 0x10)
irq_status |= 4;
} }
/* Palette bit */ /* Palette bit */
@ -759,8 +758,10 @@ static inline void reg_w(unsigned int r, unsigned int d)
{ {
/* update IRQ status */ /* update IRQ status */
irq_status = 0x50; irq_status = 0x50;
if (d & 0x20) irq_status |= 0x26; if (d & 0x20)
else if (hint_pending && (reg[0] & 0x10)) irq_status |= 4; irq_status |= 0x26;
else if (hint_pending && (reg[0] & 0x10))
irq_status |= 4;
} }
/* See if the viewport height has actually been changed */ /* 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; if (config.overscan) bitmap.viewport.y = ((vdp_pal ? 288 : 240) - bitmap.viewport.h) / 2;
/* update VC table */ /* 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 (((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; reg[1] = d;
render_line(v_counter, 0);
#ifdef LOGVDP #ifdef LOGVDP
error("Line redrawn\n"); error("Line redrawn (%d sprites) \n",object_index_count);
#endif #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 #ifdef LOGVDP
else else
@ -837,10 +845,10 @@ static inline void reg_w(unsigned int r, unsigned int d)
border = d; border = d;
color_update(0x00, *(uint16 *)&cram[(border << 1)]); color_update(0x00, *(uint16 *)&cram[(border << 1)]);
/* background color modified during Horizontal Blanking */ /* Background color modified during Horizontal Blanking (Road Rash 1,2,3)*/
if (!(status & 8) && (count_m68k <= (line_m68k + 84))) if (!(status & 8) && (mcycles_68k <= (mcycles_vdp + 860)))
{ {
/* remap entire line (see Road Rash I,II,III) */ /* remap colors */
reg[7] = d; reg[7] = d;
remap_buffer(v_counter,bitmap.viewport.w + 2*bitmap.viewport.x); remap_buffer(v_counter,bitmap.viewport.w + 2*bitmap.viewport.x);
#ifdef LOGVDP #ifdef LOGVDP
@ -994,7 +1002,8 @@ static inline void dma_vbus (void)
{ {
/* Return $FFFF only when the Z80 isn't hogging the Z-bus. /* Return $FFFF only when the Z80 isn't hogging the Z-bus.
(e.g. Z80 isn't reset and 68000 has the 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 /* 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. 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 */ /* All remaining locations access work RAM */
else temp = *(uint16 *)(work_ram + (source & 0xffff)); else
temp = *(uint16 *)(work_ram + (source & 0xffff));
source += 2; source += 2;
source = ((base & 0xFE0000) | (source & 0x1FFFF)); source = ((base & 0xFE0000) | (source & 0x1FFFF));
@ -1059,12 +1069,12 @@ static inline void dma_fill(unsigned int data)
/* write MSB */ /* write MSB */
data = (data >> 8) & 0xff; data = (data >> 8) & 0xff;
/* detect internal SAT modification */ /* intercept SAT writes */
if ((addr & sat_base_mask) == satb) if ((addr & sat_base_mask) == satb)
{ {
do do
{ {
/* update internal SAT (fix Battletech) */ /* update internal SAT copy */
WRITE_BYTE(sat, (addr & sat_addr_mask)^1, data); WRITE_BYTE(sat, (addr & sat_addr_mask)^1, data);
WRITE_BYTE(vram, addr^1, data); WRITE_BYTE(vram, addr^1, data);
MARK_BG_DIRTY (addr); MARK_BG_DIRTY (addr);

View File

@ -59,12 +59,10 @@ extern uint16 v_counter;
extern uint32 dma_length; extern uint32 dma_length;
extern int32 fifo_write_cnt; extern int32 fifo_write_cnt;
extern uint32 fifo_lastwrite; extern uint32 fifo_lastwrite;
extern uint8 fifo_latency;
extern uint8 im2_flag; extern uint8 im2_flag;
extern uint8 interlaced; extern uint8 interlaced;
extern uint8 odd_frame; extern uint8 odd_frame;
extern uint8 vdp_pal; extern uint8 vdp_pal;
extern uint8 vdp_rate;
extern uint16 lines_per_frame; extern uint16 lines_per_frame;
extern uint8 *vctab; extern uint8 *vctab;
@ -72,8 +70,8 @@ extern uint8 *hctab;
extern uint8 vc_ntsc_224[262]; extern uint8 vc_ntsc_224[262];
extern uint8 vc_pal_224[313]; extern uint8 vc_pal_224[313];
extern uint8 vc_pal_240[313]; extern uint8 vc_pal_240[313];
extern uint8 cycle2hc32[488]; extern uint8 cycle2hc32[3420];
extern uint8 cycle2hc40[488]; extern uint8 cycle2hc40[3420];
/* Function prototypes */ /* Function prototypes */
extern void vdp_init(void); extern void vdp_init(void);

View File

@ -202,7 +202,8 @@
#define IFF2 Z80.iff2 #define IFF2 Z80.iff2
#define HALT Z80.halt #define HALT Z80.halt
int z80_ICount; extern unsigned int mcycles_z80;
Z80_Regs Z80; Z80_Regs Z80;
static UINT32 EA; static UINT32 EA;
@ -466,7 +467,7 @@ INLINE void BURNODD(int cycles, int opcodes, int cyclesum)
if( cycles > 0 ) if( cycles > 0 )
{ {
R += (cycles / cyclesum) * opcodes; 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 * 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 * execute an opcode
@ -3224,7 +3225,7 @@ static void take_interrupt(void)
RM16( irq_vector, &Z80.pc ); RM16( irq_vector, &Z80.pc );
LOG(("Z80 #%d IM2 [$%04x] = $%04x\n",cpu_getactivecpu() , irq_vector, PCD)); LOG(("Z80 #%d IM2 [$%04x] = $%04x\n",cpu_getactivecpu() , irq_vector, PCD));
/* CALL $xxxx + 'interrupt latency' cycles */ /* 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 else
/* Interrupt mode 1. RST 38h */ /* Interrupt mode 1. RST 38h */
@ -3234,7 +3235,7 @@ static void take_interrupt(void)
PUSH( pc ); PUSH( pc );
PCD = 0x0038; PCD = 0x0038;
/* RST $38 + 'interrupt latency' cycles */ /* 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 else
{ {
@ -3248,18 +3249,18 @@ static void take_interrupt(void)
PUSH( pc ); PUSH( pc );
PCD = irq_vector & 0xffff; PCD = irq_vector & 0xffff;
/* CALL $xxxx + 'interrupt latency' cycles */ /* 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; break;
case 0xc30000: /* jump */ case 0xc30000: /* jump */
PCD = irq_vector & 0xffff; PCD = irq_vector & 0xffff;
/* JP $xxxx + 2 cycles */ /* 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; break;
default: /* rst (or other opcodes?) */ default: /* rst (or other opcodes?) */
PUSH( pc ); PUSH( pc );
PCD = irq_vector & 0x0038; PCD = irq_vector & 0x0038;
/* RST $xx + 2 cycles */ /* 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; 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 */ /* 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 */ /* via timers, and can't be dynamically enabled, so it is safe */
/* to just check here */ /* to just check here */
@ -3422,25 +3421,23 @@ int z80_execute(int cycles)
PUSH( pc ); PUSH( pc );
PCD = 0x0066; PCD = 0x0066;
WZ=PCD; WZ=PCD;
z80_ICount -= 11; mcycles_z80 += 11*15;
Z80.nmi_pending = FALSE; Z80.nmi_pending = FALSE;
} }
while( z80_ICount > 0 ) while( mcycles_z80 < cycles )
{ {
/* check for IRQs before each instruction */ /* check for IRQs before each instruction */
if (Z80.irq_state != CLEAR_LINE && IFF1 && !Z80.after_ei) if (Z80.irq_state != CLEAR_LINE && IFF1 && !Z80.after_ei)
take_interrupt(); take_interrupt();
Z80.after_ei = FALSE; Z80.after_ei = FALSE;
if (z80_ICount > 0) if (mcycles_z80 < cycles)
{ {
R++; R++;
EXEC_INLINE(op,ROP()); EXEC_INLINE(op,ROP());
} }
} }
return cycles - z80_ICount;
} }
/**************************************************************************** /****************************************************************************
@ -3453,7 +3450,7 @@ void z80_burn(int cycles)
/* NOP takes 4 cycles per instruction */ /* NOP takes 4 cycles per instruction */
int n = (cycles + 3) / 4; int n = (cycles + 3) / 4;
R += n; R += n;
z80_ICount -= 4 * n; mcycles_z80 += 4 * n * 15;
} }
} }

View File

@ -40,13 +40,12 @@ typedef struct
} Z80_Regs; } Z80_Regs;
extern int z80_ICount;
extern Z80_Regs Z80; extern Z80_Regs Z80;
void z80_init(int index, int clock, const void *config, int (*irqcallback)(int)); void z80_init(int index, int clock, const void *config, int (*irqcallback)(int));
void z80_reset (void); void z80_reset (void);
void z80_exit (void); void z80_exit (void);
int z80_execute(int cycles); void z80_run(int cycles);
void z80_burn(int cycles); void z80_burn(int cycles);
void z80_get_context (void *dst); void z80_get_context (void *dst);
void z80_set_context (void *src); void z80_set_context (void *src);