mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2025-01-24 00:51:13 +01:00
added cycle accurate sample generation
This commit is contained in:
parent
015710f3e0
commit
16cdbc33d2
@ -442,7 +442,7 @@ void m68k_write_memory_8 (unsigned int address, unsigned int value)
|
|||||||
case 0x13:
|
case 0x13:
|
||||||
case 0x15:
|
case 0x15:
|
||||||
case 0x17:
|
case 0x17:
|
||||||
psg_write (value);
|
psg_write (0, value);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x18: /* Unused */
|
case 0x18: /* Unused */
|
||||||
@ -481,7 +481,7 @@ void m68k_write_memory_8 (unsigned int address, unsigned int value)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x4000:
|
case 0x4000:
|
||||||
fm_write (address & 3, value);
|
fm_write (0, address & 3, value);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x6000:
|
case 0x6000:
|
||||||
@ -619,7 +619,7 @@ void m68k_write_memory_16 (unsigned int address, unsigned int value)
|
|||||||
|
|
||||||
case 0x10: /* PSG */
|
case 0x10: /* PSG */
|
||||||
case 0x14: /* PSG */
|
case 0x14: /* PSG */
|
||||||
psg_write (value & 0xFF);
|
psg_write (0, value & 0xFF);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x18: /* Unused */
|
case 0x18: /* Unused */
|
||||||
@ -654,7 +654,7 @@ void m68k_write_memory_16 (unsigned int address, unsigned int value)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x4000: /* YM2612 */
|
case 0x4000: /* YM2612 */
|
||||||
fm_write (address & 3, (value >> 8) & 0xFF);
|
fm_write (0, address & 3, (value >> 8) & 0xFF);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x6000: /* Bank register and VDP */
|
case 0x6000: /* Bank register and VDP */
|
||||||
|
@ -171,7 +171,7 @@ void z80bank_vdp_w(int address, int data)
|
|||||||
case 0x13:
|
case 0x13:
|
||||||
case 0x15:
|
case 0x15:
|
||||||
case 0x17:
|
case 0x17:
|
||||||
psg_write(data);
|
psg_write(1, data);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x18: /* Unused */
|
case 0x18: /* Unused */
|
||||||
|
@ -42,7 +42,7 @@ void cpu_writemem16(unsigned int address, unsigned int data)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case 2: /* YM2612 */
|
case 2: /* YM2612 */
|
||||||
fm_write(address & 3, data);
|
fm_write(1, address & 3, data);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 3: /* Bank register and VDP */
|
case 3: /* Bank register and VDP */
|
||||||
@ -164,7 +164,7 @@ void z80_vdp_w(int address, int data)
|
|||||||
case 0x13:
|
case 0x13:
|
||||||
case 0x15:
|
case 0x15:
|
||||||
case 0x17:
|
case 0x17:
|
||||||
psg_write(data);
|
psg_write(1, data);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x10: /* Unused */
|
case 0x10: /* Unused */
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
sound.c
|
sound.c
|
||||||
YM2612 and SN76489 handler
|
YM2612 and SN76489 emulation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "shared.h"
|
#include "shared.h"
|
||||||
@ -84,7 +84,7 @@ void fm_reset(void)
|
|||||||
fm_status = 0;
|
fm_status = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fm_write(int address, int data)
|
void fm_write(uint8 cpu, int address, int data)
|
||||||
{
|
{
|
||||||
int a0 = (address & 1);
|
int a0 = (address & 1);
|
||||||
int a1 = (address >> 1) & 1;
|
int a1 = (address >> 1) & 1;
|
||||||
@ -143,6 +143,10 @@ void fm_write(int address, int 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(snd.fm.curStage - snd.fm.lastStage > 0)
|
||||||
{
|
{
|
||||||
if (FM_GENS)
|
if (FM_GENS)
|
||||||
@ -159,6 +163,7 @@ void fm_write(int address, int data)
|
|||||||
tempBuffer[1] = snd.fm.buffer[1] + snd.fm.lastStage;
|
tempBuffer[1] = snd.fm.buffer[1] + snd.fm.lastStage;
|
||||||
YM2612UpdateOne(myFM, tempBuffer, snd.fm.curStage - snd.fm.lastStage);
|
YM2612UpdateOne(myFM, tempBuffer, snd.fm.curStage - snd.fm.lastStage);
|
||||||
}
|
}
|
||||||
|
|
||||||
snd.fm.lastStage = snd.fm.curStage;
|
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(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)
|
if(snd.psg.curStage - snd.psg.lastStage > 0)
|
||||||
{
|
{
|
||||||
int16 *tempBuffer;
|
int16 *tempBuffer;
|
||||||
|
@ -21,9 +21,9 @@ extern t_timer timer[2];
|
|||||||
void sound_init (void);
|
void sound_init (void);
|
||||||
void fm_reset (void);
|
void fm_reset (void);
|
||||||
void fm_restore(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);
|
int fm_read (int address);
|
||||||
void fm_update_timers (int inc);
|
void fm_update_timers (int inc);
|
||||||
void psg_write (int data);
|
void psg_write (uint8 cpu, int data);
|
||||||
|
|
||||||
#endif /* _SOUND_H_ */
|
#endif /* _SOUND_H_ */
|
||||||
|
@ -29,13 +29,14 @@ uint32 count_m68k = 0;
|
|||||||
uint32 dma_m68k = 0;
|
uint32 dma_m68k = 0;
|
||||||
uint32 aim_z80 = 0;
|
uint32 aim_z80 = 0;
|
||||||
uint32 count_z80 = 0;
|
uint32 count_z80 = 0;
|
||||||
|
int32 current_z80 = 0;
|
||||||
uint16 misc68Kcycles = 488;
|
uint16 misc68Kcycles = 488;
|
||||||
uint16 miscZ80cycles = 228;
|
uint16 miscZ80cycles = 228;
|
||||||
uint16 lines_per_frame = 262;
|
uint16 lines_per_frame = 262;
|
||||||
|
uint16 m68cyc_per_sample = 160;
|
||||||
|
uint16 z80cyc_per_sample = 75;
|
||||||
double Master_Clock = (double)CLOCK_NTSC;
|
double Master_Clock = (double)CLOCK_NTSC;
|
||||||
void *myFM = NULL;
|
void *myFM = NULL;
|
||||||
static int sound_tbl[312];
|
|
||||||
static int sound_inc[312];
|
|
||||||
uint8 alttiming = 0;
|
uint8 alttiming = 0;
|
||||||
|
|
||||||
void m68k_run (int cyc)
|
void m68k_run (int cyc)
|
||||||
@ -57,8 +58,8 @@ void m68k_run (int cyc)
|
|||||||
|
|
||||||
void z80_run (int cyc)
|
void z80_run (int cyc)
|
||||||
{
|
{
|
||||||
int cyc_do = cyc - count_z80;
|
current_z80 = cyc - count_z80;
|
||||||
if (cyc_do > 0) count_z80 += z80_execute(cyc_do);
|
if (current_z80 > 0) count_z80 += z80_execute(current_z80);
|
||||||
}
|
}
|
||||||
|
|
||||||
void m68k_freeze(int cycles)
|
void m68k_freeze(int cycles)
|
||||||
@ -77,12 +78,12 @@ void m68k_freeze(int cycles)
|
|||||||
else m68ki_remaining_cycles -= cycles; /* we burn some 68k cycles */
|
else m68ki_remaining_cycles -= cycles; /* we burn some 68k cycles */
|
||||||
}
|
}
|
||||||
|
|
||||||
extern uint8 hq_fm;
|
|
||||||
int audio_init (int rate)
|
int audio_init (int rate)
|
||||||
{
|
{
|
||||||
int i;
|
double sample_cyc;
|
||||||
int vclk = (int)(Master_Clock / 7.0); /* 68000 and YM2612 clock */
|
int vclk = (int)(Master_Clock / 7.0); /* 68000 and YM2612 clock */
|
||||||
int zclk = (int)(Master_Clock / 15.0); /* Z80 and SN76489 clock */
|
int zclk = (int)(Master_Clock / 15.0); /* Z80 and SN76489 clock */
|
||||||
|
extern uint8 hq_fm;
|
||||||
|
|
||||||
/* Clear the sound data context */
|
/* Clear the sound data context */
|
||||||
memset (&snd, 0, sizeof (snd));
|
memset (&snd, 0, sizeof (snd));
|
||||||
@ -130,14 +131,19 @@ int audio_init (int rate)
|
|||||||
if (FM_GENS) YM2612_Init(vclk, rate, hq_fm);
|
if (FM_GENS) YM2612_Init(vclk, rate, hq_fm);
|
||||||
else if (!myFM) myFM = YM2612Init (0, 0, vclk, rate, 0, 0);
|
else if (!myFM) myFM = YM2612Init (0, 0, vclk, rate, 0, 0);
|
||||||
|
|
||||||
/* Make sound table */
|
/*
|
||||||
for (i = 0; i < lines_per_frame; i++)
|
CYCLE-ACCURATE SAMPLES GENERATION:
|
||||||
{
|
|
||||||
float p = (snd.buffer_size * i) / lines_per_frame;
|
We calculate number of cpu cycles between each new sound sample generation.
|
||||||
float q = (snd.buffer_size * (i+1)) / lines_per_frame;
|
Since both 68000 and Z80 can write to the sound chips, we need the cycles step for both CPU:
|
||||||
sound_tbl[i] = p;
|
At 48kHz, one sample is produced each 160 (NTSC) or 158 (PAL) 68k cycles
|
||||||
sound_inc[i] = ((q - p) * 1000000) / snd.sample_rate;
|
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);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,10 +302,8 @@ int system_frame (int do_skip)
|
|||||||
if (zreset == 1 && zbusreq == 0) z80_run(aim_z80);
|
if (zreset == 1 && zbusreq == 0) z80_run(aim_z80);
|
||||||
else count_z80 = aim_z80;
|
else count_z80 = aim_z80;
|
||||||
|
|
||||||
/* Update sound buffers and timers */
|
/* Update FM timers (one raster takes approx. 63.7 us) */
|
||||||
fm_update_timers (sound_inc[v_counter]);
|
fm_update_timers (64);
|
||||||
snd.fm.curStage = sound_tbl[v_counter];
|
|
||||||
snd.psg.curStage = sound_tbl[v_counter];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snd.enabled) audio_update ();
|
if (snd.enabled) audio_update ();
|
||||||
|
@ -54,9 +54,12 @@ extern uint32 count_m68k;
|
|||||||
extern uint32 dma_m68k;
|
extern uint32 dma_m68k;
|
||||||
extern uint32 aim_z80;
|
extern uint32 aim_z80;
|
||||||
extern uint32 count_z80;
|
extern uint32 count_z80;
|
||||||
|
extern int32 current_z80;
|
||||||
extern uint16 misc68Kcycles;
|
extern uint16 misc68Kcycles;
|
||||||
extern uint16 miscZ80cycles;
|
extern uint16 miscZ80cycles;
|
||||||
extern uint16 lines_per_frame;
|
extern uint16 lines_per_frame;
|
||||||
|
extern uint16 m68cyc_per_sample;
|
||||||
|
extern uint16 z80cyc_per_sample;
|
||||||
extern double Master_Clock;
|
extern double Master_Clock;
|
||||||
|
|
||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user