From 16cdbc33d2490abfe53f310d0c54033229e1a91c Mon Sep 17 00:00:00 2001 From: ekeeke31 Date: Mon, 20 Aug 2007 19:44:24 +0000 Subject: [PATCH] added cycle accurate sample generation --- source/mem68k.c | 16 ++++++------- source/membnk.c | 2 +- source/memz80.c | 4 ++-- source/sound/sound.c | 16 +++++++++---- source/sound/sound.h | 4 ++-- source/system.c | 56 ++++++++++++++++++++++++-------------------- source/system.h | 3 +++ 7 files changed, 58 insertions(+), 43 deletions(-) diff --git a/source/mem68k.c b/source/mem68k.c index 1105177..6ee65ed 100644 --- a/source/mem68k.c +++ b/source/mem68k.c @@ -442,7 +442,7 @@ void m68k_write_memory_8 (unsigned int address, unsigned int value) case 0x13: case 0x15: case 0x17: - psg_write (value); + psg_write (0, value); return; case 0x18: /* Unused */ @@ -481,7 +481,7 @@ void m68k_write_memory_8 (unsigned int address, unsigned int value) return; case 0x4000: - fm_write (address & 3, value); + fm_write (0, address & 3, value); return; case 0x6000: @@ -619,7 +619,7 @@ void m68k_write_memory_16 (unsigned int address, unsigned int value) case 0x10: /* PSG */ case 0x14: /* PSG */ - psg_write (value & 0xFF); + psg_write (0, value & 0xFF); return; case 0x18: /* Unused */ @@ -654,7 +654,7 @@ void m68k_write_memory_16 (unsigned int address, unsigned int value) return; case 0x4000: /* YM2612 */ - fm_write (address & 3, (value >> 8) & 0xFF); + fm_write (0, address & 3, (value >> 8) & 0xFF); return; case 0x6000: /* Bank register and VDP */ @@ -676,10 +676,10 @@ void m68k_write_memory_16 (unsigned int address, unsigned int value) } } else if (address <= 0xA1001F) /* I/O */ - { - io_write ((address >> 1) & 0x0F, value & 0x00FF); - return; - } + { + io_write ((address >> 1) & 0x0F, value & 0x00FF); + return; + } else if (address <= 0xA1FFFF) /* CONTROL */ { switch ((address >> 8) & 0xFF) diff --git a/source/membnk.c b/source/membnk.c index af84dcd..7be9a3e 100644 --- a/source/membnk.c +++ b/source/membnk.c @@ -171,7 +171,7 @@ void z80bank_vdp_w(int address, int data) case 0x13: case 0x15: case 0x17: - psg_write(data); + psg_write(1, data); return; case 0x18: /* Unused */ diff --git a/source/memz80.c b/source/memz80.c index 86d0e48..00dd5ce 100644 --- a/source/memz80.c +++ b/source/memz80.c @@ -42,7 +42,7 @@ void cpu_writemem16(unsigned int address, unsigned int data) return; case 2: /* YM2612 */ - fm_write(address & 3, data); + fm_write(1, address & 3, data); return; case 3: /* Bank register and VDP */ @@ -164,7 +164,7 @@ void z80_vdp_w(int address, int data) case 0x13: case 0x15: case 0x17: - psg_write(data); + psg_write(1, data); return; case 0x10: /* Unused */ diff --git a/source/sound/sound.c b/source/sound/sound.c index 245e224..4fe8a1c 100644 --- a/source/sound/sound.c +++ b/source/sound/sound.c @@ -1,6 +1,6 @@ /* sound.c - YM2612 and SN76489 handler + YM2612 and SN76489 emulation */ #include "shared.h" @@ -84,7 +84,7 @@ void fm_reset(void) fm_status = 0; } -void fm_write(int address, int data) +void fm_write(uint8 cpu, int address, int data) { int a0 = (address & 1); int a1 = (address >> 1) & 1; @@ -141,8 +141,12 @@ void fm_write(int address, int data) fm_latch[a1] = data; } - if(snd.enabled) + if (snd.enabled) { + + if (cpu) snd.fm.curStage = (count_z80 + current_z80 - z80_ICount) / z80cyc_per_sample; /* write from Z80 */ + else snd.fm.curStage = (count_m68k + m68k_cycles_run()) / m68cyc_per_sample; /* write from 68000 */ + if(snd.fm.curStage - snd.fm.lastStage > 0) { if (FM_GENS) @@ -159,6 +163,7 @@ void fm_write(int address, int data) tempBuffer[1] = snd.fm.buffer[1] + snd.fm.lastStage; YM2612UpdateOne(myFM, tempBuffer, snd.fm.curStage - snd.fm.lastStage); } + snd.fm.lastStage = snd.fm.curStage; } @@ -205,10 +210,13 @@ void fm_update_timers(int inc) } } -void psg_write(int data) +void psg_write(uint8 cpu, int data) { if(snd.enabled) { + if (cpu) snd.psg.curStage = (count_z80 + current_z80 - z80_ICount) / z80cyc_per_sample; /* write from Z80 */ + else snd.psg.curStage = (count_m68k + m68k_cycles_run()) / m68cyc_per_sample; /* write from 68000 */ + if(snd.psg.curStage - snd.psg.lastStage > 0) { int16 *tempBuffer; diff --git a/source/sound/sound.h b/source/sound/sound.h index 7128ecf..eb93387 100644 --- a/source/sound/sound.h +++ b/source/sound/sound.h @@ -21,9 +21,9 @@ extern t_timer timer[2]; void sound_init (void); void fm_reset (void); void fm_restore(void); -void fm_write (int address, int data); +void fm_write (uint8 cpu, int address, int data); int fm_read (int address); void fm_update_timers (int inc); -void psg_write (int data); +void psg_write (uint8 cpu, int data); #endif /* _SOUND_H_ */ diff --git a/source/system.c b/source/system.c index e5e0bff..2639663 100644 --- a/source/system.c +++ b/source/system.c @@ -24,18 +24,19 @@ t_bitmap bitmap; t_snd snd; -uint32 aim_m68k = 0; +uint32 aim_m68k = 0; uint32 count_m68k = 0; -uint32 dma_m68k = 0; -uint32 aim_z80 = 0; -uint32 count_z80 = 0; -uint16 misc68Kcycles = 488; -uint16 miscZ80cycles = 228; +uint32 dma_m68k = 0; +uint32 aim_z80 = 0; +uint32 count_z80 = 0; +int32 current_z80 = 0; +uint16 misc68Kcycles = 488; +uint16 miscZ80cycles = 228; uint16 lines_per_frame = 262; -double Master_Clock = (double)CLOCK_NTSC; +uint16 m68cyc_per_sample = 160; +uint16 z80cyc_per_sample = 75; +double Master_Clock = (double)CLOCK_NTSC; void *myFM = NULL; -static int sound_tbl[312]; -static int sound_inc[312]; uint8 alttiming = 0; void m68k_run (int cyc) @@ -57,8 +58,8 @@ void m68k_run (int cyc) void z80_run (int cyc) { - int cyc_do = cyc - count_z80; - if (cyc_do > 0) count_z80 += z80_execute(cyc_do); + current_z80 = cyc - count_z80; + if (current_z80 > 0) count_z80 += z80_execute(current_z80); } void m68k_freeze(int cycles) @@ -77,12 +78,12 @@ void m68k_freeze(int cycles) else m68ki_remaining_cycles -= cycles; /* we burn some 68k cycles */ } -extern uint8 hq_fm; int audio_init (int rate) { - int i; + double sample_cyc; int vclk = (int)(Master_Clock / 7.0); /* 68000 and YM2612 clock */ int zclk = (int)(Master_Clock / 15.0); /* Z80 and SN76489 clock */ + extern uint8 hq_fm; /* Clear the sound data context */ memset (&snd, 0, sizeof (snd)); @@ -130,14 +131,19 @@ int audio_init (int rate) if (FM_GENS) YM2612_Init(vclk, rate, hq_fm); else if (!myFM) myFM = YM2612Init (0, 0, vclk, rate, 0, 0); - /* Make sound table */ - for (i = 0; i < lines_per_frame; i++) - { - float p = (snd.buffer_size * i) / lines_per_frame; - float q = (snd.buffer_size * (i+1)) / lines_per_frame; - sound_tbl[i] = p; - sound_inc[i] = ((q - p) * 1000000) / snd.sample_rate; - } + /* + CYCLE-ACCURATE SAMPLES GENERATION: + + We calculate number of cpu cycles between each new sound sample generation. + Since both 68000 and Z80 can write to the sound chips, we need the cycles step for both CPU: + At 48kHz, one sample is produced each 160 (NTSC) or 158 (PAL) 68k cycles + which is equivalent to 75 (NTSC) or 74 (PAL) Z80 cycles + */ + sample_cyc = Master_Clock / 7.0 / ((double) rate); + m68cyc_per_sample = (sample_cyc - (double)(int)sample_cyc) > 0.5 ? (int)(sample_cyc + 1) : (int)(sample_cyc); + sample_cyc = Master_Clock / 15.0 / ((double) rate); + z80cyc_per_sample = (sample_cyc - (double)(int)sample_cyc) > 0.5 ? (int)(sample_cyc + 1) : (int)(sample_cyc); + return (0); } @@ -158,7 +164,7 @@ void system_init (void) void system_reset (void) { - aim_m68k = 0; + aim_m68k = 0; count_m68k = 0; dma_m68k = 0; aim_z80 = 0; @@ -296,10 +302,8 @@ int system_frame (int do_skip) if (zreset == 1 && zbusreq == 0) z80_run(aim_z80); else count_z80 = aim_z80; - /* Update sound buffers and timers */ - fm_update_timers (sound_inc[v_counter]); - snd.fm.curStage = sound_tbl[v_counter]; - snd.psg.curStage = sound_tbl[v_counter]; + /* Update FM timers (one raster takes approx. 63.7 us) */ + fm_update_timers (64); } if (snd.enabled) audio_update (); diff --git a/source/system.h b/source/system.h index 5de31d0..b250dd3 100644 --- a/source/system.h +++ b/source/system.h @@ -54,9 +54,12 @@ extern uint32 count_m68k; extern uint32 dma_m68k; extern uint32 aim_z80; extern uint32 count_z80; +extern int32 current_z80; extern uint16 misc68Kcycles; extern uint16 miscZ80cycles; extern uint16 lines_per_frame; +extern uint16 m68cyc_per_sample; +extern uint16 z80cyc_per_sample; extern double Master_Clock; /* Function prototypes */