mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 07:17:45 -04:00
emulator timing fixes, VDP DMA fixes, improved DAC audio
This commit is contained in:
parent
b9bc876c9c
commit
43e1401008
10 changed files with 118 additions and 98 deletions
|
@ -288,6 +288,8 @@ Cz80_Exec_End:
|
||||||
#if CZ80_ENCRYPTED_ROM
|
#if CZ80_ENCRYPTED_ROM
|
||||||
CPU->OPBase = OPBase;
|
CPU->OPBase = OPBase;
|
||||||
#endif
|
#endif
|
||||||
|
if (CPU->HaltState)
|
||||||
|
CPU->ICount = 0;
|
||||||
cycles -= CPU->ICount;
|
cycles -= CPU->ICount;
|
||||||
#if !CZ80_EMULATE_R_EXACTLY
|
#if !CZ80_EMULATE_R_EXACTLY
|
||||||
zR = (zR + (cycles >> 2)) & 0x7f;
|
zR = (zR + (cycles >> 2)) & 0x7f;
|
||||||
|
|
|
@ -687,13 +687,14 @@ OP_CCF:
|
||||||
OP(0x76): // HALT
|
OP(0x76): // HALT
|
||||||
OP_HALT:
|
OP_HALT:
|
||||||
CPU->HaltState = 1;
|
CPU->HaltState = 1;
|
||||||
CPU->ICount = 0;
|
// CPU->ICount = 0;
|
||||||
goto Cz80_Check_Interrupt;
|
goto Cz80_Check_Interrupt;
|
||||||
|
|
||||||
OP(0xf3): // DI
|
OP(0xf3): // DI
|
||||||
OP_DI:
|
OP_DI:
|
||||||
zIFF = 0;
|
zIFF = 0;
|
||||||
RET(4)
|
USE_CYCLES(4)
|
||||||
|
goto Cz80_Exec_nocheck;
|
||||||
|
|
||||||
OP(0xfb): // EI
|
OP(0xfb): // EI
|
||||||
OP_EI:
|
OP_EI:
|
||||||
|
@ -712,8 +713,6 @@ OP_EI:
|
||||||
if (CPU->IRQState)
|
if (CPU->IRQState)
|
||||||
{
|
{
|
||||||
afterEI = 1;
|
afterEI = 1;
|
||||||
CPU->ExtraCycles += 1 - CPU->ICount;
|
|
||||||
CPU->ICount = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else zIFF2 = (1 << 2);
|
else zIFF2 = (1 << 2);
|
||||||
|
|
|
@ -269,7 +269,8 @@ void p32x_schedule_hint(SH2 *sh2, unsigned int m68k_cycles)
|
||||||
return; // nobody cares
|
return; // nobody cares
|
||||||
// note: when Pico.m.scanline is 224, SH2s might
|
// note: when Pico.m.scanline is 224, SH2s might
|
||||||
// still be at scanline 93 (or so)
|
// still be at scanline 93 (or so)
|
||||||
if (!(Pico32x.sh2_regs[0] & 0x80) && Pico.m.scanline > 224)
|
if (!(Pico32x.sh2_regs[0] & 0x80) &&
|
||||||
|
Pico.m.scanline > (Pico.video.reg[1] & 0x08 ? 240 : 224))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
after = (Pico32x.sh2_regs[4 / 2] + 1) * 488;
|
after = (Pico32x.sh2_regs[4 / 2] + 1) * 488;
|
||||||
|
|
22
pico/debug.c
22
pico/debug.c
|
@ -369,42 +369,32 @@ void PDebugDumpMem(void)
|
||||||
|
|
||||||
void PDebugZ80Frame(void)
|
void PDebugZ80Frame(void)
|
||||||
{
|
{
|
||||||
int lines, line_sample;
|
int lines;
|
||||||
|
|
||||||
if (PicoIn.AHW & PAHW_SMS)
|
if (PicoIn.AHW & PAHW_SMS)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Pico.m.pal) {
|
if (Pico.m.pal)
|
||||||
lines = 313;
|
lines = 313;
|
||||||
line_sample = 68;
|
else
|
||||||
} else {
|
|
||||||
lines = 262;
|
lines = 262;
|
||||||
line_sample = 93;
|
|
||||||
}
|
|
||||||
|
|
||||||
z80_resetCycles();
|
z80_resetCycles();
|
||||||
PsndStartFrame();
|
PsndStartFrame();
|
||||||
|
|
||||||
if (/*Pico.m.z80Run &&*/ !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80))
|
|
||||||
PicoSyncZ80(Pico.t.m68c_cnt + line_sample * 488);
|
|
||||||
if (PicoIn.sndOut)
|
|
||||||
PsndGetSamples(line_sample);
|
|
||||||
|
|
||||||
if (/*Pico.m.z80Run &&*/ !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
|
if (/*Pico.m.z80Run &&*/ !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
|
||||||
PicoSyncZ80(Pico.t.m68c_cnt + 224 * 488);
|
PicoSyncZ80(Pico.t.m68c_cnt + 224 * 488);
|
||||||
z80_int();
|
z80_int();
|
||||||
}
|
}
|
||||||
if (PicoIn.sndOut)
|
|
||||||
PsndGetSamples(224);
|
|
||||||
|
|
||||||
// sync z80
|
// sync z80
|
||||||
if (/*Pico.m.z80Run &&*/ !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
|
if (/*Pico.m.z80Run &&*/ !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
|
||||||
Pico.t.m68c_cnt += Pico.m.pal ? 151809 : 127671; // cycles adjusted for converter
|
Pico.t.m68c_cnt += Pico.m.pal ? 151809 : 127671; // cycles adjusted for converter
|
||||||
PicoSyncZ80(Pico.t.m68c_cnt);
|
PicoSyncZ80(Pico.t.m68c_cnt);
|
||||||
}
|
}
|
||||||
if (PicoIn.sndOut && ym2612.dacen && Pico.snd.dac_line < lines)
|
|
||||||
PsndDoDAC(lines - 1);
|
if (PicoIn.sndOut)
|
||||||
PsndDoPSG(lines - 1);
|
PsndGetSamples(lines);
|
||||||
|
|
||||||
timers_cycle();
|
timers_cycle();
|
||||||
Pico.t.m68c_aim = Pico.t.m68c_cnt;
|
Pico.t.m68c_aim = Pico.t.m68c_cnt;
|
||||||
|
|
|
@ -943,11 +943,11 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
|
||||||
a &= 3;
|
a &= 3;
|
||||||
if (a == 1 && ym2612.OPN.ST.address == 0x2a) /* DAC data */
|
if (a == 1 && ym2612.OPN.ST.address == 0x2a) /* DAC data */
|
||||||
{
|
{
|
||||||
int scanline = get_scanline(is_from_z80);
|
int cycles = is_from_z80 ? z80_cyclesDone() : z80_cycles_from_68k();
|
||||||
//elprintf(EL_STATUS, "%03i -> %03i dac w %08x z80 %i", Pico.snd.dac_line, scanline, d, is_from_z80);
|
//elprintf(EL_STATUS, "%03i dac w %08x z80 %i", cycles, d, is_from_z80);
|
||||||
ym2612.dacout = ((int)d - 0x80) << 6;
|
ym2612.dacout = ((int)d - 0x80) << 6;
|
||||||
if (ym2612.dacen)
|
if (ym2612.dacen)
|
||||||
PsndDoDAC(scanline);
|
PsndDoDAC(cycles);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1029,13 +1029,9 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case 0x2b: { /* DAC Sel (YM2612) */
|
case 0x2b: { /* DAC Sel (YM2612) */
|
||||||
int scanline = get_scanline(is_from_z80);
|
|
||||||
if (ym2612.dacen != (d & 0x80)) {
|
|
||||||
ym2612.dacen = d & 0x80;
|
ym2612.dacen = d & 0x80;
|
||||||
Pico.snd.dac_line = scanline;
|
|
||||||
}
|
|
||||||
#ifdef __GP2X__
|
#ifdef __GP2X__
|
||||||
if (PicoIn.opt & POPT_EXT_FM) YM2612Write_940(a, d, scanline);
|
if (PicoIn.opt & POPT_EXT_FM) YM2612Write_940(a, d, get_scanline(is_from_z80));
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1059,8 +1055,7 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int scanline = get_scanline(is_from_z80);
|
PsndDoFM(get_scanline(is_from_z80));
|
||||||
PsndDoFM(scanline);
|
|
||||||
#ifdef __GP2X__
|
#ifdef __GP2X__
|
||||||
if (PicoIn.opt & POPT_EXT_FM)
|
if (PicoIn.opt & POPT_EXT_FM)
|
||||||
return YM2612Write_940(a, d, get_scanline(is_from_z80));
|
return YM2612Write_940(a, d, get_scanline(is_from_z80));
|
||||||
|
|
33
pico/pico.c
33
pico/pico.c
|
@ -224,40 +224,45 @@ void PicoLoopPrepare(void)
|
||||||
|
|
||||||
// this table is wrong and should be removed
|
// this table is wrong and should be removed
|
||||||
// keeping it for now to compensate wrong timing elswhere, mainly for Outrunners
|
// keeping it for now to compensate wrong timing elswhere, mainly for Outrunners
|
||||||
static const int dma_timings[] = {
|
static const int dma_timings[] = { // Q16
|
||||||
83, 166, 83, 83, // vblank: 32cell: dma2vram dma2[vs|c]ram vram_fill vram_copy
|
// dma2vram dma2[vs|c]ram vram_fill vram_copy
|
||||||
102, 204, 102, 102, // vblank: 40cell:
|
// VRAM has half the width of VSRAM/CRAM, thus half the performance
|
||||||
8, 16, 8, 8, // active: 32cell:
|
( 83<<16)/488, (166<<16)/488, (165<<16)/488, ( 83<<16)/488, // vblank 32cell
|
||||||
17, 18, 9, 9 // ...
|
(102<<16)/488, (204<<16)/488, (203<<16)/488, (102<<16)/488, // vblank 40cell
|
||||||
|
( 8<<16)/488, ( 16<<16)/488, ( 15<<16)/488, ( 8<<16)/488, // active 32cell
|
||||||
|
( 9<<16)/488, ( 18<<16)/488, ( 17<<16)/488, ( 9<<16)/488 // active 40cell
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int dma_bsycles[] = {
|
static const int dma_bsycles[] = { // Q16
|
||||||
(488<<8)/83, (488<<8)/166, (488<<8)/83, (488<<8)/83,
|
(488<<16)/83, (488<<16)/166, (488<<16)/165, (488<<16)/83,
|
||||||
(488<<8)/102, (488<<8)/204, (488<<8)/102, (488<<8)/102,
|
(488<<16)/102, (488<<16)/204, (488<<16)/203, (488<<16)/102,
|
||||||
(488<<8)/8, (488<<8)/16, (488<<8)/8, (488<<8)/8,
|
(488<<16)/8, (488<<16)/16, (488<<16)/15, (488<<16)/8,
|
||||||
(488<<8)/9, (488<<8)/18, (488<<8)/9, (488<<8)/9
|
(488<<16)/9, (488<<16)/18, (488<<16)/17, (488<<16)/9
|
||||||
};
|
};
|
||||||
|
|
||||||
// grossly inaccurate.. FIXME FIXXXMEE
|
// grossly inaccurate.. FIXME FIXXXMEE
|
||||||
PICO_INTERNAL int CheckDMA(void)
|
PICO_INTERNAL int CheckDMA(int cycles)
|
||||||
{
|
{
|
||||||
int burn = 0, xfers_can, dma_op = Pico.video.reg[0x17]>>6; // see gens for 00 and 01 modes
|
int burn = 0, xfers_can, dma_op = Pico.video.reg[0x17]>>6; // see gens for 00 and 01 modes
|
||||||
int xfers = Pico.m.dma_xfers;
|
int xfers = Pico.m.dma_xfers;
|
||||||
int dma_op1;
|
int dma_op1;
|
||||||
|
|
||||||
|
// safety pin
|
||||||
|
if (cycles <= 0) return 0;
|
||||||
|
|
||||||
if(!(dma_op&2)) dma_op = (Pico.video.type==1) ? 0 : 1; // setting dma_timings offset here according to Gens
|
if(!(dma_op&2)) dma_op = (Pico.video.type==1) ? 0 : 1; // setting dma_timings offset here according to Gens
|
||||||
dma_op1 = dma_op;
|
dma_op1 = dma_op;
|
||||||
if(Pico.video.reg[12] & 1) dma_op |= 4; // 40 cell mode?
|
if(Pico.video.reg[12] & 1) dma_op |= 4; // 40 cell mode?
|
||||||
if(!(Pico.video.status&8)&&(Pico.video.reg[1]&0x40)) dma_op|=8; // active display?
|
if(!(Pico.video.status&8)&&(Pico.video.reg[1]&0x40)) dma_op|=8; // active display?
|
||||||
xfers_can = dma_timings[dma_op];
|
xfers_can = (dma_timings[dma_op] * cycles + 0xff) >> 16;
|
||||||
if(xfers <= xfers_can)
|
if(xfers <= xfers_can)
|
||||||
{
|
{
|
||||||
Pico.video.status &= ~SR_DMA;
|
Pico.video.status &= ~SR_DMA;
|
||||||
if (!(dma_op & 2))
|
if (!(dma_op & 2))
|
||||||
burn = xfers * dma_bsycles[dma_op] >> 8; // have to be approximate because can't afford division..
|
burn = xfers * dma_bsycles[dma_op] >> 16;
|
||||||
Pico.m.dma_xfers = 0;
|
Pico.m.dma_xfers = 0;
|
||||||
} else {
|
} else {
|
||||||
if(!(dma_op&2)) burn = 488;
|
if(!(dma_op&2)) burn = cycles;
|
||||||
Pico.m.dma_xfers -= xfers_can;
|
Pico.m.dma_xfers -= xfers_can;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,13 +22,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// sync m68k to Pico.t.m68c_aim
|
// sync m68k to Pico.t.m68c_aim
|
||||||
static void SekSyncM68k(void)
|
static void SekExecM68k(int cyc_do)
|
||||||
{
|
{
|
||||||
int cyc_do;
|
|
||||||
pprof_start(m68k);
|
|
||||||
pevt_log_m68k_o(EVT_RUN_START);
|
|
||||||
|
|
||||||
while ((cyc_do = Pico.t.m68c_aim - Pico.t.m68c_cnt) > 0) {
|
|
||||||
Pico.t.m68c_cnt += cyc_do;
|
Pico.t.m68c_cnt += cyc_do;
|
||||||
|
|
||||||
#if defined(EMU_C68K)
|
#if defined(EMU_C68K)
|
||||||
|
@ -42,6 +37,15 @@ static void SekSyncM68k(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SekSyncM68k(void)
|
||||||
|
{
|
||||||
|
int cyc_do;
|
||||||
|
pprof_start(m68k);
|
||||||
|
pevt_log_m68k_o(EVT_RUN_START);
|
||||||
|
|
||||||
|
while ((cyc_do = Pico.t.m68c_aim - Pico.t.m68c_cnt) > 0)
|
||||||
|
SekExecM68k(cyc_do);
|
||||||
|
|
||||||
SekCyclesLeft = 0;
|
SekCyclesLeft = 0;
|
||||||
|
|
||||||
SekTrace(0);
|
SekTrace(0);
|
||||||
|
@ -68,7 +72,7 @@ static void do_hint(struct PicoVideo *pv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_timing_hacks_as(struct PicoVideo *pv, int vdp_slots)
|
static void do_timing_hacks_as(struct PicoVideo *pv, int vdp_slots, int cycles)
|
||||||
{
|
{
|
||||||
pv->lwrite_cnt += vdp_slots - Pico.m.dma_xfers * 2; // wrong *2
|
pv->lwrite_cnt += vdp_slots - Pico.m.dma_xfers * 2; // wrong *2
|
||||||
if (pv->lwrite_cnt > vdp_slots)
|
if (pv->lwrite_cnt > vdp_slots)
|
||||||
|
@ -76,13 +80,13 @@ static void do_timing_hacks_as(struct PicoVideo *pv, int vdp_slots)
|
||||||
else if (pv->lwrite_cnt < 0)
|
else if (pv->lwrite_cnt < 0)
|
||||||
pv->lwrite_cnt = 0;
|
pv->lwrite_cnt = 0;
|
||||||
if (Pico.m.dma_xfers)
|
if (Pico.m.dma_xfers)
|
||||||
SekCyclesBurn(CheckDMA());
|
SekCyclesBurn(CheckDMA(cycles));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_timing_hacks_vb(void)
|
static void do_timing_hacks_vb(int cycles)
|
||||||
{
|
{
|
||||||
if (unlikely(Pico.m.dma_xfers))
|
if (unlikely(Pico.m.dma_xfers))
|
||||||
SekCyclesBurn(CheckDMA());
|
SekCyclesBurn(CheckDMA(cycles));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PicoFrameHints(void)
|
static int PicoFrameHints(void)
|
||||||
|
@ -151,7 +155,7 @@ static int PicoFrameHints(void)
|
||||||
|
|
||||||
// Run scanline:
|
// Run scanline:
|
||||||
Pico.t.m68c_line_start = Pico.t.m68c_aim;
|
Pico.t.m68c_line_start = Pico.t.m68c_aim;
|
||||||
do_timing_hacks_as(pv, vdp_slots);
|
do_timing_hacks_as(pv, vdp_slots, CYCLES_M68K_LINE);
|
||||||
CPUS_RUN(CYCLES_M68K_LINE);
|
CPUS_RUN(CYCLES_M68K_LINE);
|
||||||
|
|
||||||
if (PicoLineHook) PicoLineHook();
|
if (PicoLineHook) PicoLineHook();
|
||||||
|
@ -192,19 +196,18 @@ static int PicoFrameHints(void)
|
||||||
// also delay between F bit (bit 7) is set in SR and IRQ happens (Ex-Mutants)
|
// also delay between F bit (bit 7) is set in SR and IRQ happens (Ex-Mutants)
|
||||||
// also delay between last H-int and V-int (Golden Axe 3)
|
// also delay between last H-int and V-int (Golden Axe 3)
|
||||||
Pico.t.m68c_line_start = Pico.t.m68c_aim;
|
Pico.t.m68c_line_start = Pico.t.m68c_aim;
|
||||||
do_timing_hacks_vb();
|
do_timing_hacks_vb(CYCLES_M68K_VINT_LAG);
|
||||||
CPUS_RUN(CYCLES_M68K_VINT_LAG);
|
CPUS_RUN(CYCLES_M68K_VINT_LAG);
|
||||||
|
|
||||||
pv->status |= SR_F;
|
pv->status |= SR_F;
|
||||||
pv->pending_ints |= 0x20;
|
pv->pending_ints |= 0x20;
|
||||||
if (pv->reg[1] & 0x20) {
|
if (pv->reg[1] & 0x20) {
|
||||||
Pico.t.m68c_aim = Pico.t.m68c_cnt + 11; // HACK
|
SekExecM68k(11); // HACK
|
||||||
SekSyncM68k();
|
|
||||||
elprintf(EL_INTS, "vint: @ %06x [%u]", SekPc, SekCyclesDone());
|
elprintf(EL_INTS, "vint: @ %06x [%u]", SekPc, SekCyclesDone());
|
||||||
SekInterrupt(6);
|
SekInterrupt(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
cycles = SekCyclesDone();
|
cycles = Pico.t.m68c_aim;
|
||||||
if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
|
if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
|
||||||
PicoSyncZ80(cycles);
|
PicoSyncZ80(cycles);
|
||||||
elprintf(EL_INTS, "zint");
|
elprintf(EL_INTS, "zint");
|
||||||
|
@ -221,6 +224,7 @@ static int PicoFrameHints(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Run scanline:
|
// Run scanline:
|
||||||
|
do_timing_hacks_vb(CYCLES_M68K_LINE - CYCLES_M68K_VINT_LAG);
|
||||||
CPUS_RUN(CYCLES_M68K_LINE - CYCLES_M68K_VINT_LAG);
|
CPUS_RUN(CYCLES_M68K_LINE - CYCLES_M68K_VINT_LAG);
|
||||||
|
|
||||||
if (PicoLineHook) PicoLineHook();
|
if (PicoLineHook) PicoLineHook();
|
||||||
|
@ -256,7 +260,7 @@ static int PicoFrameHints(void)
|
||||||
|
|
||||||
// Run scanline:
|
// Run scanline:
|
||||||
Pico.t.m68c_line_start = Pico.t.m68c_aim;
|
Pico.t.m68c_line_start = Pico.t.m68c_aim;
|
||||||
do_timing_hacks_vb();
|
do_timing_hacks_vb(CYCLES_M68K_LINE);
|
||||||
CPUS_RUN(CYCLES_M68K_LINE);
|
CPUS_RUN(CYCLES_M68K_LINE);
|
||||||
|
|
||||||
if (PicoLineHook) PicoLineHook();
|
if (PicoLineHook) PicoLineHook();
|
||||||
|
@ -267,7 +271,7 @@ static int PicoFrameHints(void)
|
||||||
unsigned int l = PicoIn.overclockM68k * lines / 100;
|
unsigned int l = PicoIn.overclockM68k * lines / 100;
|
||||||
while (l-- > 0) {
|
while (l-- > 0) {
|
||||||
Pico.t.m68c_cnt -= CYCLES_M68K_LINE;
|
Pico.t.m68c_cnt -= CYCLES_M68K_LINE;
|
||||||
do_timing_hacks_vb();
|
do_timing_hacks_vb(CYCLES_M68K_LINE);
|
||||||
SekSyncM68k();
|
SekSyncM68k();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,20 +297,16 @@ static int PicoFrameHints(void)
|
||||||
|
|
||||||
// Run scanline:
|
// Run scanline:
|
||||||
Pico.t.m68c_line_start = Pico.t.m68c_aim;
|
Pico.t.m68c_line_start = Pico.t.m68c_aim;
|
||||||
do_timing_hacks_as(pv, vdp_slots);
|
do_timing_hacks_as(pv, vdp_slots, CYCLES_M68K_LINE);
|
||||||
CPUS_RUN(CYCLES_M68K_LINE);
|
CPUS_RUN(CYCLES_M68K_LINE);
|
||||||
|
|
||||||
if (PicoLineHook) PicoLineHook();
|
if (PicoLineHook) PicoLineHook();
|
||||||
pevt_log_m68k_o(EVT_NEXT_LINE);
|
pevt_log_m68k_o(EVT_NEXT_LINE);
|
||||||
|
|
||||||
// sync cpus
|
// sync cpus
|
||||||
cycles = SekCyclesDone();
|
cycles = Pico.t.m68c_aim;
|
||||||
if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80))
|
if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80))
|
||||||
PicoSyncZ80(cycles);
|
PicoSyncZ80(cycles);
|
||||||
if (PicoIn.sndOut && ym2612.dacen && Pico.snd.dac_line < lines)
|
|
||||||
PsndDoDAC(lines - 1);
|
|
||||||
if (PicoIn.sndOut && Pico.snd.psg_line < lines)
|
|
||||||
PsndDoPSG(lines - 1);
|
|
||||||
|
|
||||||
#ifdef PICO_CD
|
#ifdef PICO_CD
|
||||||
if (PicoIn.AHW & PAHW_MCD)
|
if (PicoIn.AHW & PAHW_MCD)
|
||||||
|
|
|
@ -193,7 +193,7 @@ extern struct DrZ80 drZ80;
|
||||||
#define z80_int_assert(a) Cz80_Set_IRQ(&CZ80, 0, (a) ? ASSERT_LINE : CLEAR_LINE)
|
#define z80_int_assert(a) Cz80_Set_IRQ(&CZ80, 0, (a) ? ASSERT_LINE : CLEAR_LINE)
|
||||||
#define z80_nmi() Cz80_Set_IRQ(&CZ80, IRQ_LINE_NMI, 0)
|
#define z80_nmi() Cz80_Set_IRQ(&CZ80, IRQ_LINE_NMI, 0)
|
||||||
|
|
||||||
#define z80_cyclesLeft (CZ80.ICount - CZ80.ExtraCycles)
|
#define z80_cyclesLeft CZ80.ICount
|
||||||
#define z80_subCLeft(c) CZ80.ICount -= c
|
#define z80_subCLeft(c) CZ80.ICount -= c
|
||||||
#define z80_pc() Cz80_Get_Reg(&CZ80, CZ80_PC)
|
#define z80_pc() Cz80_Get_Reg(&CZ80, CZ80_PC)
|
||||||
|
|
||||||
|
@ -431,7 +431,9 @@ struct PicoSound
|
||||||
short len_use; // adjusted
|
short len_use; // adjusted
|
||||||
int len_e_add; // for non-int samples/frame
|
int len_e_add; // for non-int samples/frame
|
||||||
int len_e_cnt;
|
int len_e_cnt;
|
||||||
short dac_line;
|
int dac_val, dac_val2; // last DAC sample
|
||||||
|
unsigned int dac_mult; // z80 clocks per line in Q16
|
||||||
|
unsigned int dac_pos; // last DAC position in Q16
|
||||||
short psg_line;
|
short psg_line;
|
||||||
unsigned int fm_mult; // samples per line in Q16
|
unsigned int fm_mult; // samples per line in Q16
|
||||||
unsigned int fm_pos; // last FM position in Q16
|
unsigned int fm_pos; // last FM position in Q16
|
||||||
|
@ -738,7 +740,7 @@ extern struct Pico Pico;
|
||||||
extern struct PicoMem PicoMem;
|
extern struct PicoMem PicoMem;
|
||||||
extern void (*PicoResetHook)(void);
|
extern void (*PicoResetHook)(void);
|
||||||
extern void (*PicoLineHook)(void);
|
extern void (*PicoLineHook)(void);
|
||||||
PICO_INTERNAL int CheckDMA(void);
|
PICO_INTERNAL int CheckDMA(int cycles);
|
||||||
PICO_INTERNAL void PicoDetectRegion(void);
|
PICO_INTERNAL void PicoDetectRegion(void);
|
||||||
PICO_INTERNAL void PicoSyncZ80(unsigned int m68k_cycles_done);
|
PICO_INTERNAL void PicoSyncZ80(unsigned int m68k_cycles_done);
|
||||||
|
|
||||||
|
@ -872,7 +874,7 @@ PICO_INTERNAL_ASM void wram_1M_to_2M(unsigned char *m);
|
||||||
// sound/sound.c
|
// sound/sound.c
|
||||||
PICO_INTERNAL void PsndReset(void);
|
PICO_INTERNAL void PsndReset(void);
|
||||||
PICO_INTERNAL void PsndStartFrame(void);
|
PICO_INTERNAL void PsndStartFrame(void);
|
||||||
PICO_INTERNAL void PsndDoDAC(int line_to);
|
PICO_INTERNAL void PsndDoDAC(int cycle_to);
|
||||||
PICO_INTERNAL void PsndDoPSG(int line_to);
|
PICO_INTERNAL void PsndDoPSG(int line_to);
|
||||||
PICO_INTERNAL void PsndDoFM(int line_to);
|
PICO_INTERNAL void PsndDoFM(int line_to);
|
||||||
PICO_INTERNAL void PsndClear(void);
|
PICO_INTERNAL void PsndClear(void);
|
||||||
|
|
|
@ -89,6 +89,8 @@ void PsndRerate(int preserve_state)
|
||||||
|
|
||||||
// samples per line (Q16)
|
// samples per line (Q16)
|
||||||
Pico.snd.fm_mult = 65536LL * PicoIn.sndRate / (target_fps*target_lines);
|
Pico.snd.fm_mult = 65536LL * PicoIn.sndRate / (target_fps*target_lines);
|
||||||
|
// samples per z80 clock (Q20)
|
||||||
|
Pico.snd.dac_mult = 16 * Pico.snd.fm_mult * 15/7 / 488;
|
||||||
|
|
||||||
// recalculate dac info
|
// recalculate dac info
|
||||||
dac_recalculate();
|
dac_recalculate();
|
||||||
|
@ -117,34 +119,46 @@ PICO_INTERNAL void PsndStartFrame(void)
|
||||||
Pico.snd.len_use++;
|
Pico.snd.len_use++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pico.snd.dac_line = Pico.snd.psg_line = 0;
|
Pico.snd.psg_line = 0;
|
||||||
Pico.snd.fm_pos = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PICO_INTERNAL void PsndDoDAC(int line_to)
|
PICO_INTERNAL void PsndDoDAC(int cyc_to)
|
||||||
{
|
{
|
||||||
int pos, pos1, len;
|
int pos, len;
|
||||||
int dout = ym2612.dacout;
|
int dout = ym2612.dacout;
|
||||||
int line_from = Pico.snd.dac_line;
|
|
||||||
|
|
||||||
pos = dac_info[line_from];
|
// number of samples to fill in buffer (Q20)
|
||||||
pos1 = dac_info[line_to + 1];
|
len = (cyc_to * Pico.snd.dac_mult) - Pico.snd.dac_pos;
|
||||||
len = pos1 - pos;
|
|
||||||
|
// update position and calculate buffer offset and length
|
||||||
|
pos = (Pico.snd.dac_pos+0x80000) >> 20;
|
||||||
|
Pico.snd.dac_pos += len;
|
||||||
|
len = ((Pico.snd.dac_pos+0x80000) >> 20) - pos;
|
||||||
|
|
||||||
|
// avoid loss of the 1st sample of a new block (Q rounding issues)
|
||||||
|
if (pos+len == 0)
|
||||||
|
len = 1, Pico.snd.dac_pos += 0x80000;
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Pico.snd.dac_line = line_to + 1;
|
|
||||||
|
|
||||||
if (!PicoIn.sndOut)
|
if (!PicoIn.sndOut)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// fill buffer, applying a rather weak order 1 bessel IIR on the way
|
||||||
|
// y[n] = (x[n] + x[n-1])*(1/2) (3dB cutoff at 11025 Hz, no gain)
|
||||||
|
// 1 sample delay for correct IIR filtering over audio frame boundaries
|
||||||
if (PicoIn.opt & POPT_EN_STEREO) {
|
if (PicoIn.opt & POPT_EN_STEREO) {
|
||||||
short *d = PicoIn.sndOut + pos*2;
|
short *d = PicoIn.sndOut + pos*2;
|
||||||
for (; len > 0; len--, d+=2) *d += dout;
|
// left channel only, mixed ro right channel in mixing phase
|
||||||
|
*d++ += Pico.snd.dac_val2; d++;
|
||||||
|
while (--len) *d++ += Pico.snd.dac_val, d++;
|
||||||
} else {
|
} else {
|
||||||
short *d = PicoIn.sndOut + pos;
|
short *d = PicoIn.sndOut + pos;
|
||||||
for (; len > 0; len--, d++) *d += dout;
|
*d++ += Pico.snd.dac_val2;
|
||||||
|
while (--len) *d++ += Pico.snd.dac_val;
|
||||||
}
|
}
|
||||||
|
Pico.snd.dac_val2 = (Pico.snd.dac_val + dout) >> 1;
|
||||||
|
Pico.snd.dac_val = dout;
|
||||||
}
|
}
|
||||||
|
|
||||||
PICO_INTERNAL void PsndDoPSG(int line_to)
|
PICO_INTERNAL void PsndDoPSG(int line_to)
|
||||||
|
@ -258,6 +272,8 @@ PICO_INTERNAL void PsndClear(void)
|
||||||
}
|
}
|
||||||
if (!(PicoIn.opt & POPT_EN_FM))
|
if (!(PicoIn.opt & POPT_EN_FM))
|
||||||
memset32(PsndBuffer, 0, PicoIn.opt & POPT_EN_STEREO ? len*2 : len);
|
memset32(PsndBuffer, 0, PicoIn.opt & POPT_EN_STEREO ? len*2 : len);
|
||||||
|
// drop pos remainder to avoid rounding errors (not entirely correct though)
|
||||||
|
Pico.snd.dac_pos = Pico.snd.fm_pos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -266,6 +282,7 @@ static int PsndRender(int offset, int length)
|
||||||
int *buf32;
|
int *buf32;
|
||||||
int stereo = (PicoIn.opt & 8) >> 3;
|
int stereo = (PicoIn.opt & 8) >> 3;
|
||||||
int fmlen = ((Pico.snd.fm_pos+0x8000) >> 16) - offset;
|
int fmlen = ((Pico.snd.fm_pos+0x8000) >> 16) - offset;
|
||||||
|
int daclen = ((Pico.snd.dac_pos+0x80000) >> 20) - offset;
|
||||||
|
|
||||||
offset <<= stereo;
|
offset <<= stereo;
|
||||||
buf32 = PsndBuffer+offset;
|
buf32 = PsndBuffer+offset;
|
||||||
|
@ -277,6 +294,15 @@ static int PsndRender(int offset, int length)
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fill up DAC output in case of missing samples (Q16 rounding errors)
|
||||||
|
if (length-daclen > 0) {
|
||||||
|
short *dacbuf = PicoIn.sndOut + (daclen << stereo);
|
||||||
|
for (; length-daclen > 0; daclen++) {
|
||||||
|
*dacbuf++ += Pico.snd.dac_val;
|
||||||
|
if (stereo) dacbuf++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add in parts of the FM buffer not yet done
|
// Add in parts of the FM buffer not yet done
|
||||||
if (length-fmlen > 0) {
|
if (length-fmlen > 0) {
|
||||||
int *fmbuf = buf32 + (fmlen << stereo);
|
int *fmbuf = buf32 + (fmlen << stereo);
|
||||||
|
@ -317,8 +343,8 @@ PICO_INTERNAL void PsndGetSamples(int y)
|
||||||
{
|
{
|
||||||
static int curr_pos = 0;
|
static int curr_pos = 0;
|
||||||
|
|
||||||
if (ym2612.dacen && Pico.snd.dac_line < y)
|
if (ym2612.dacen)
|
||||||
PsndDoDAC(y - 1);
|
PsndDoDAC(cycles_68k_to_z80(Pico.t.m68c_aim - Pico.t.m68c_frame_start));
|
||||||
PsndDoPSG(y - 1);
|
PsndDoPSG(y - 1);
|
||||||
|
|
||||||
curr_pos = PsndRender(0, Pico.snd.len_use);
|
curr_pos = PsndRender(0, Pico.snd.len_use);
|
||||||
|
@ -327,7 +353,6 @@ PICO_INTERNAL void PsndGetSamples(int y)
|
||||||
PicoIn.writeSound(curr_pos * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));
|
PicoIn.writeSound(curr_pos * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));
|
||||||
// clear sound buffer
|
// clear sound buffer
|
||||||
PsndClear();
|
PsndClear();
|
||||||
Pico.snd.dac_line = y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PICO_INTERNAL void PsndGetSamplesMS(int y)
|
PICO_INTERNAL void PsndGetSamplesMS(int y)
|
||||||
|
|
|
@ -97,7 +97,7 @@ static void DmaSlow(int len, unsigned int source)
|
||||||
Pico.m.dma_xfers = len;
|
Pico.m.dma_xfers = len;
|
||||||
if (Pico.m.dma_xfers < len) // lame 16bit var
|
if (Pico.m.dma_xfers < len) // lame 16bit var
|
||||||
Pico.m.dma_xfers = ~0;
|
Pico.m.dma_xfers = ~0;
|
||||||
SekCyclesBurnRun(CheckDMA());
|
SekCyclesBurnRun(CheckDMA(488 - (SekCyclesDone()-Pico.t.m68c_line_start)));
|
||||||
|
|
||||||
if ((source & 0xe00000) == 0xe00000) { // Ram
|
if ((source & 0xe00000) == 0xe00000) { // Ram
|
||||||
base = (u16 *)PicoMem.ram;
|
base = (u16 *)PicoMem.ram;
|
||||||
|
@ -344,7 +344,8 @@ static NOINLINE void CommandChange(void)
|
||||||
|
|
||||||
static void DrawSync(int blank_on)
|
static void DrawSync(int blank_on)
|
||||||
{
|
{
|
||||||
if (Pico.m.scanline < 224 && !(PicoIn.opt & POPT_ALT_RENDERER) &&
|
int lines = Pico.video.reg[1]&0x08 ? 240 : 224;
|
||||||
|
if (Pico.m.scanline < lines && !(PicoIn.opt & POPT_ALT_RENDERER) &&
|
||||||
!PicoIn.skipFrame && Pico.est.DrawScanline <= Pico.m.scanline) {
|
!PicoIn.skipFrame && Pico.est.DrawScanline <= Pico.m.scanline) {
|
||||||
//elprintf(EL_ANOMALY, "sync");
|
//elprintf(EL_ANOMALY, "sync");
|
||||||
PicoDrawSync(Pico.m.scanline, blank_on);
|
PicoDrawSync(Pico.m.scanline, blank_on);
|
||||||
|
@ -363,7 +364,7 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d)
|
||||||
{
|
{
|
||||||
case 0x00: // Data port 0 or 2
|
case 0x00: // Data port 0 or 2
|
||||||
// try avoiding the sync..
|
// try avoiding the sync..
|
||||||
if (Pico.m.scanline < 224 && (pvid->reg[1]&0x40) &&
|
if (Pico.m.scanline < (pvid->reg[1]&0x08 ? 240 : 224) && (pvid->reg[1]&0x40) &&
|
||||||
!(!pvid->pending &&
|
!(!pvid->pending &&
|
||||||
((pvid->command & 0xc00000f0) == 0x40000010 && PicoMem.vsram[pvid->addr>>1] == d))
|
((pvid->command & 0xc00000f0) == 0x40000010 && PicoMem.vsram[pvid->addr>>1] == d))
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue