mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 15:27:46 -04:00
new z80 scheduling method, timers are still wip
git-svn-id: file:///home/notaz/opt/svn/PicoDrive@459 be3aeb3a-fb24-0410-a615-afba39da0efa
This commit is contained in:
parent
170435846c
commit
4b9c588826
15 changed files with 377 additions and 364 deletions
171
Pico/Memory.c
171
Pico/Memory.c
|
@ -687,6 +687,168 @@ static void m68k_mem_setup(void)
|
||||||
#endif // EMU_M68K
|
#endif // EMU_M68K
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
extern const unsigned short vcounts[];
|
||||||
|
|
||||||
|
static int get_scanline(int is_from_z80)
|
||||||
|
{
|
||||||
|
if (is_from_z80) {
|
||||||
|
int cycles = z80_cyclesDone();
|
||||||
|
while (cycles - z80_scanline_cycles >= 228)
|
||||||
|
z80_scanline++, z80_scanline_cycles += 228;
|
||||||
|
return z80_scanline;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Pico.m.scanline != -1)
|
||||||
|
return Pico.m.scanline;
|
||||||
|
|
||||||
|
return vcounts[SekCyclesDone()>>8];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ym2612 DAC and timer I/O handlers for z80
|
||||||
|
int ym2612_write_local(u32 a, u32 d, int is_from_z80)
|
||||||
|
{
|
||||||
|
int addr;
|
||||||
|
|
||||||
|
a &= 3;
|
||||||
|
if (a == 1 && ym2612.OPN.ST.address == 0x2a) /* DAC data */
|
||||||
|
{
|
||||||
|
int scanline = get_scanline(is_from_z80);
|
||||||
|
//elprintf(EL_STATUS, "%03i -> %03i dac w %08x z80 %i", PsndDacLine, scanline, d, is_from_z80);
|
||||||
|
ym2612.dacout = ((int)d - 0x80) << 6;
|
||||||
|
if (PsndOut && ym2612.dacen && scanline >= PsndDacLine)
|
||||||
|
PsndDoDAC(scanline);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (a)
|
||||||
|
{
|
||||||
|
case 0: /* address port 0 */
|
||||||
|
ym2612.OPN.ST.address = d;
|
||||||
|
ym2612.addr_A1 = 0;
|
||||||
|
#ifdef __GP2X__
|
||||||
|
if (PicoOpt & POPT_EXT_FM) YM2612Write_940(a, d, -1);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case 1: /* data port 0 */
|
||||||
|
if (ym2612.addr_A1 != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
addr = ym2612.OPN.ST.address;
|
||||||
|
ym2612.REGS[addr] = d;
|
||||||
|
|
||||||
|
switch (addr)
|
||||||
|
{
|
||||||
|
case 0x24: // timer A High 8
|
||||||
|
case 0x25: { // timer A Low 2
|
||||||
|
int TAnew = (addr == 0x24) ? ((ym2612.OPN.ST.TA & 0x03)|(((int)d)<<2))
|
||||||
|
: ((ym2612.OPN.ST.TA & 0x3fc)|(d&3));
|
||||||
|
if (ym2612.OPN.ST.TA != TAnew)
|
||||||
|
{
|
||||||
|
//elprintf(EL_STATUS, "timer a set %i", TAnew);
|
||||||
|
ym2612.OPN.ST.TA = TAnew;
|
||||||
|
//ym2612.OPN.ST.TAC = (1024-TAnew)*18;
|
||||||
|
//ym2612.OPN.ST.TAT = 0;
|
||||||
|
//
|
||||||
|
timer_a_step = 16495 * (1024 - TAnew);
|
||||||
|
if ((ym2612.OPN.ST.mode & 5) == 5) {
|
||||||
|
int cycles = is_from_z80 ? z80_cyclesDone() : cycles_68k_to_z80(SekCyclesDone());
|
||||||
|
timer_a_next_oflow = (cycles << 8) + timer_a_step;
|
||||||
|
//elprintf(EL_STATUS, "set to %i @ %i", timer_a_next_oflow>>8, cycles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case 0x26: // timer B
|
||||||
|
if (ym2612.OPN.ST.TB != d) {
|
||||||
|
//elprintf(EL_STATUS, "timer b set %i", d);
|
||||||
|
ym2612.OPN.ST.TB = d;
|
||||||
|
//ym2612.OPN.ST.TBC = (256-d)<<4;
|
||||||
|
//ym2612.OPN.ST.TBC *= 18;
|
||||||
|
//ym2612.OPN.ST.TBT = 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case 0x27: { /* mode, timer control */
|
||||||
|
int old_mode = ym2612.OPN.ST.mode;
|
||||||
|
int xcycles = is_from_z80 ? z80_cyclesDone() : cycles_68k_to_z80(SekCyclesDone());
|
||||||
|
xcycles <<= 8;
|
||||||
|
|
||||||
|
//elprintf(EL_STATUS, "st mode %02x", d);
|
||||||
|
|
||||||
|
if ((ym2612.OPN.ST.mode & 5) != 5 && (d & 5) == 5) {
|
||||||
|
timer_a_next_oflow = xcycles + timer_a_step;
|
||||||
|
//elprintf(EL_STATUS, "set to %i @ %i st", timer_a_next_oflow>>8, xcycles >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reset Timer b flag */
|
||||||
|
if (d & 0x20)
|
||||||
|
ym2612.OPN.ST.status &= ~2;
|
||||||
|
|
||||||
|
/* reset Timer a flag */
|
||||||
|
if (d & 0x10) {
|
||||||
|
if (ym2612.OPN.ST.status & 1)
|
||||||
|
while (xcycles > timer_a_next_oflow)
|
||||||
|
timer_a_next_oflow += timer_a_step;
|
||||||
|
ym2612.OPN.ST.status &= ~1;
|
||||||
|
}
|
||||||
|
if (!(d & 5)) timer_a_next_oflow = 0x80000000;
|
||||||
|
ym2612.OPN.ST.mode = d;
|
||||||
|
#ifdef __GP2X__
|
||||||
|
if (PicoOpt & POPT_EXT_FM) YM2612Write_940(a, d, get_scanline(is_from_z80));
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case 0x2b: { /* DAC Sel (YM2612) */
|
||||||
|
int scanline = get_scanline(is_from_z80);
|
||||||
|
ym2612.dacen = d & 0x80;
|
||||||
|
if (d & 0x80) PsndDacLine = scanline;
|
||||||
|
#ifdef __GP2X__
|
||||||
|
if (PicoOpt & POPT_EXT_FM) YM2612Write_940(a, d, scanline);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: /* address port 1 */
|
||||||
|
ym2612.OPN.ST.address = d;
|
||||||
|
ym2612.addr_A1 = 1;
|
||||||
|
#ifdef __GP2X__
|
||||||
|
if (PicoOpt & POPT_EXT_FM) YM2612Write_940(a, d, -1);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case 3: /* data port 1 */
|
||||||
|
if (ym2612.addr_A1 != 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
addr = ym2612.OPN.ST.address | 0x100;
|
||||||
|
ym2612.REGS[addr] = d;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __GP2X__
|
||||||
|
if (PicoOpt & POPT_EXT_FM)
|
||||||
|
return YM2612Write_940(a, d, get_scanline(is_from_z80));
|
||||||
|
#endif
|
||||||
|
return YM2612Write_(a, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: timer b, 68k side + asm, savestates
|
||||||
|
u32 ym2612_read_local_z80(void)
|
||||||
|
{
|
||||||
|
int xcycles = z80_cyclesDone() << 8;
|
||||||
|
if (timer_a_next_oflow != 0x80000000 && xcycles >= timer_a_next_oflow) {
|
||||||
|
ym2612.OPN.ST.status |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//elprintf(EL_STATUS, "timer %i, sched %i, @ %i|%i", ym2612.OPN.ST.status, timer_a_next_oflow>>8,
|
||||||
|
// xcycles >> 8, (xcycles >> 8) / 228);
|
||||||
|
return ym2612.OPN.ST.status;
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
// z80 memhandlers
|
// z80 memhandlers
|
||||||
|
|
||||||
|
@ -696,7 +858,7 @@ PICO_INTERNAL unsigned char z80_read(unsigned short a)
|
||||||
|
|
||||||
if ((a>>13)==2) // 0x4000-0x5fff (Charles MacDonald)
|
if ((a>>13)==2) // 0x4000-0x5fff (Charles MacDonald)
|
||||||
{
|
{
|
||||||
if (PicoOpt&POPT_EN_FM) ret = (u8) YM2612Read();
|
if (PicoOpt&POPT_EN_FM) ret = ym2612_read_local_z80();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -710,7 +872,10 @@ PICO_INTERNAL unsigned char z80_read(unsigned short a)
|
||||||
if (PicoAHW & PAHW_MCD)
|
if (PicoAHW & PAHW_MCD)
|
||||||
ret = PicoReadM68k8(addr68k);
|
ret = PicoReadM68k8(addr68k);
|
||||||
else ret = PicoRead8(addr68k);
|
else ret = PicoRead8(addr68k);
|
||||||
elprintf(EL_Z80BNK, "z80->68k r8 [%06x] %02x", addr68k, ret);
|
if (addr68k >= 0x400000) // not many games do this
|
||||||
|
{ elprintf(EL_ANOMALY, "z80->68k upper read [%06x] %02x", addr68k, ret); }
|
||||||
|
else
|
||||||
|
{ elprintf(EL_Z80BNK, "z80->68k r8 [%06x] %02x", addr68k, ret); }
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -729,7 +894,7 @@ PICO_INTERNAL_ASM void z80_write(unsigned int a, unsigned char data)
|
||||||
{
|
{
|
||||||
if ((a>>13)==2) // 0x4000-0x5fff (Charles MacDonald)
|
if ((a>>13)==2) // 0x4000-0x5fff (Charles MacDonald)
|
||||||
{
|
{
|
||||||
if(PicoOpt&POPT_EN_FM) emustatus|=YM2612Write(a, data) & 1;
|
if(PicoOpt&POPT_EN_FM) emustatus|=ym2612_write_local(a, data, 1) & 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -879,27 +879,21 @@ m_write8_z80_not_ram:
|
||||||
and r2, r0, #0x6000
|
and r2, r0, #0x6000
|
||||||
cmp r2, #0x4000
|
cmp r2, #0x4000
|
||||||
bne m_write8_z80_not_ym2612
|
bne m_write8_z80_not_ym2612
|
||||||
ldr r2, =PicoOpt
|
ldr r3, =PicoOpt
|
||||||
and r0, r0, #3
|
and r0, r0, #3
|
||||||
ldr r2, [r2]
|
ldr r3, [r3]
|
||||||
tst r2, #1
|
mov r2, #0 @ is_from_z80 = 0
|
||||||
|
tst r3, #1
|
||||||
bxeq lr
|
bxeq lr
|
||||||
stmfd sp!,{lr}
|
stmfd sp!,{lr}
|
||||||
.if EXTERNAL_YM2612
|
and r1, r1, #0xff
|
||||||
tst r2, #0x200
|
bl ym2612_write_local
|
||||||
ldreq r2, =YM2612Write_
|
|
||||||
ldrne r2, =YM2612Write_940
|
|
||||||
mov lr, pc
|
|
||||||
bx r2
|
|
||||||
.else
|
|
||||||
bl YM2612Write_
|
|
||||||
.endif
|
|
||||||
ldr r2, =emustatus
|
ldr r2, =emustatus
|
||||||
ldmfd sp!,{lr}
|
ldmfd sp!,{lr}
|
||||||
ldr r1, [r2]
|
ldr r1, [r2]
|
||||||
and r0, r0, #1
|
and r0, r0, #1
|
||||||
orr r1, r0, r1
|
orr r1, r0, r1
|
||||||
str r1, [r2] @ emustatus|=YM2612Write(a&3, d);
|
str r1, [r2] @ emustatus|=ym2612_write_local(a&3, d);
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
m_write8_z80_not_ym2612: @ not too likely
|
m_write8_z80_not_ym2612: @ not too likely
|
||||||
|
@ -916,7 +910,7 @@ m_write8_z80_not_ym2612: @ not too likely
|
||||||
m_write8_z80_bank_reg:
|
m_write8_z80_bank_reg:
|
||||||
ldr r3, =(Pico+0x22208) @ Pico.m
|
ldr r3, =(Pico+0x22208) @ Pico.m
|
||||||
ldrh r2, [r3, #0x0a]
|
ldrh r2, [r3, #0x0a]
|
||||||
mov r1, r1, lsr #8
|
mov r1, r1, lsl #8
|
||||||
orr r2, r1, r2, lsr #1
|
orr r2, r1, r2, lsr #1
|
||||||
bic r2, r2, #0xfe00
|
bic r2, r2, #0xfe00
|
||||||
strh r2, [r3, #0x0a]
|
strh r2, [r3, #0x0a]
|
||||||
|
@ -932,7 +926,7 @@ m_write8_not_z80:
|
||||||
bne OtherWrite8
|
bne OtherWrite8
|
||||||
m_write8_psg:
|
m_write8_psg:
|
||||||
ldr r2, =PicoOpt
|
ldr r2, =PicoOpt
|
||||||
mov r0, r1
|
and r0, r1, #0xff
|
||||||
ldr r2, [r2]
|
ldr r2, [r2]
|
||||||
tst r2, #2
|
tst r2, #2
|
||||||
bxeq lr
|
bxeq lr
|
||||||
|
|
|
@ -69,25 +69,14 @@ void z80WriteBusReq(u32 d)
|
||||||
{
|
{
|
||||||
if (!d)
|
if (!d)
|
||||||
{
|
{
|
||||||
// this is for a nasty situation where Z80 was enabled and disabled in the same 68k timeslice (Golden Axe III)
|
|
||||||
if ((PicoOpt&POPT_EN_Z80) && Pico.m.z80Run)
|
if ((PicoOpt&POPT_EN_Z80) && Pico.m.z80Run)
|
||||||
{
|
{
|
||||||
int lineCycles;
|
|
||||||
z80stopCycle = SekCyclesDone();
|
z80stopCycle = SekCyclesDone();
|
||||||
if ((Pico.m.z80Run&2) && Pico.m.scanline != -1)
|
PicoSyncZ80(z80stopCycle);
|
||||||
lineCycles=(488-SekCyclesLeft)&0x1ff;
|
|
||||||
else lineCycles=z80stopCycle-z80startCycle; // z80 was started at current line
|
|
||||||
if (lineCycles > 0) { // && lineCycles <= 488) {
|
|
||||||
//dprintf("zrun: %i/%i cycles", lineCycles, (lineCycles>>1)-(lineCycles>>5));
|
|
||||||
lineCycles=(lineCycles>>1)-(lineCycles>>5);
|
|
||||||
z80_run_nr(lineCycles);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!Pico.m.z80Run)
|
if (!Pico.m.z80Run)
|
||||||
z80startCycle = SekCyclesDone();
|
z80_cycle_cnt = cycles_68k_to_z80(SekCyclesDone());
|
||||||
else
|
|
||||||
d|=Pico.m.z80Run;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elprintf(EL_BUSREQ, "set_zrun: %i->%i [%i] @%06x", Pico.m.z80Run, d, SekCyclesDone(), SekPc);
|
elprintf(EL_BUSREQ, "set_zrun: %i->%i [%i] @%06x", Pico.m.z80Run, d, SekCyclesDone(), SekPc);
|
||||||
|
@ -169,12 +158,12 @@ void OtherWrite8(u32 a,u32 d)
|
||||||
if ((a&0xff4000)==0xa00000) { // z80 RAM
|
if ((a&0xff4000)==0xa00000) { // z80 RAM
|
||||||
if (!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)d;
|
if (!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)d;
|
||||||
else {
|
else {
|
||||||
elprintf(EL_ANOMALY, "68k z80 write with no bus! [%06x] %02x @ %06x", a, d, SekPc);
|
elprintf(EL_ANOMALY, "68k z80 write with no bus! [%06x] %02x @ %06x", a, d&0xff, SekPc);
|
||||||
SekCyclesBurn(4); // hack?
|
SekCyclesBurn(4); // hack?
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((a&0xff6000)==0xa04000) { if(PicoOpt&1) emustatus|=YM2612Write(a&3, d)&1; return; } // FM Sound
|
if ((a&0xff6000)==0xa04000) { if(PicoOpt&1) emustatus|=ym2612_write_local(a&3, d&0xff, 0)&1; return; } // FM Sound
|
||||||
if ((a&0xffffe0)==0xa10000) { IoWrite8(a, d); return; } // I/O ports
|
if ((a&0xffffe0)==0xa10000) { IoWrite8(a, d); return; } // I/O ports
|
||||||
#endif
|
#endif
|
||||||
if (a==0xa11100) { z80WriteBusReq(d); return; }
|
if (a==0xa11100) { z80WriteBusReq(d); return; }
|
||||||
|
@ -185,6 +174,7 @@ void OtherWrite8(u32 a,u32 d)
|
||||||
Pico.m.z80_reset = 0;
|
Pico.m.z80_reset = 0;
|
||||||
YM2612ResetChip();
|
YM2612ResetChip();
|
||||||
z80_reset();
|
z80_reset();
|
||||||
|
timers_reset();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -204,7 +194,7 @@ void OtherWrite8(u32 a,u32 d)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PicoWrite8Hook(a, d, 8);
|
PicoWrite8Hook(a, d&0xff, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -216,10 +206,10 @@ void OtherWrite16(u32 a,u32 d)
|
||||||
if (a==0xa11100) { z80WriteBusReq(d>>8); return; }
|
if (a==0xa11100) { z80WriteBusReq(d>>8); return; }
|
||||||
if ((a&0xffffe0)==0xa10000) { IoWrite8(a, d); return; } // I/O ports
|
if ((a&0xffffe0)==0xa10000) { IoWrite8(a, d); return; } // I/O ports
|
||||||
if ((a&0xe700f8)==0xc00010||(a&0xff7ff8)==0xa07f10) { if(PicoOpt&2) SN76496Write(d); return; } // PSG Sound
|
if ((a&0xe700f8)==0xc00010||(a&0xff7ff8)==0xa07f10) { if(PicoOpt&2) SN76496Write(d); return; } // PSG Sound
|
||||||
if ((a&0xff6000)==0xa04000) { if(PicoOpt&1) emustatus|=YM2612Write(a&3, d)&1; return; } // FM Sound (??)
|
if ((a&0xff6000)==0xa04000) { if(PicoOpt&1) emustatus|=ym2612_write_local(a&3, d&0xff, 0)&1; return; } // FM Sound
|
||||||
if ((a&0xff4000)==0xa00000) { // Z80 ram (MSB only)
|
if ((a&0xff4000)==0xa00000) { // Z80 ram (MSB only)
|
||||||
if (!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)(d>>8);
|
if (!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)(d>>8);
|
||||||
else elprintf(EL_ANOMALY, "68k z80 write with no bus! [%06x] %02x @ %06x", a, d, SekPc);
|
else elprintf(EL_ANOMALY, "68k z80 write with no bus! [%06x] %02x @ %06x", a, d&0xffff, SekPc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (a==0xa11200) {
|
if (a==0xa11200) {
|
||||||
|
@ -229,6 +219,7 @@ void OtherWrite16(u32 a,u32 d)
|
||||||
Pico.m.z80_reset = 0;
|
Pico.m.z80_reset = 0;
|
||||||
YM2612ResetChip();
|
YM2612ResetChip();
|
||||||
z80_reset();
|
z80_reset();
|
||||||
|
timers_reset();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -256,6 +247,6 @@ void OtherWrite16(u32 a,u32 d)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PicoWrite16Hook(a, d, 16);
|
PicoWrite16Hook(a, d&0xffff, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
132
Pico/Pico.c
132
Pico/Pico.c
|
@ -19,7 +19,6 @@ int PicoPad[2]; // Joypads, format is SACB RLDU
|
||||||
int PicoAHW = 0; // active addon hardware: scd_active, 32x_active, svp_active, pico_active
|
int PicoAHW = 0; // active addon hardware: scd_active, 32x_active, svp_active, pico_active
|
||||||
int PicoRegionOverride = 0; // override the region detection 0: Auto, 1: Japan NTSC, 2: Japan PAL, 4: US, 8: Europe
|
int PicoRegionOverride = 0; // override the region detection 0: Auto, 1: Japan NTSC, 2: Japan PAL, 4: US, 8: Europe
|
||||||
int PicoAutoRgnOrder = 0;
|
int PicoAutoRgnOrder = 0;
|
||||||
int z80startCycle, z80stopCycle; // in 68k cycles
|
|
||||||
struct PicoSRAM SRam = {0,};
|
struct PicoSRAM SRam = {0,};
|
||||||
|
|
||||||
void (*PicoWriteSound)(int len) = NULL; // called at the best time to send sound buffer (PsndOut) to hardware
|
void (*PicoWriteSound)(int len) = NULL; // called at the best time to send sound buffer (PsndOut) to hardware
|
||||||
|
@ -307,62 +306,54 @@ static __inline void getSamples(int y)
|
||||||
|
|
||||||
#include "PicoFrameHints.c"
|
#include "PicoFrameHints.c"
|
||||||
|
|
||||||
// helper z80 runner. Runs only if z80 is enabled at this point
|
|
||||||
// (z80WriteBusReq will handle the rest)
|
int z80stopCycle;
|
||||||
static void PicoRunZ80Simple(int line_from, int line_to)
|
int z80_cycle_cnt; /* 'done' z80 cycles before z80_run() */
|
||||||
|
int z80_cycle_aim;
|
||||||
|
int z80_scanline;
|
||||||
|
int z80_scanline_cycles; /* cycles done until z80_scanline */
|
||||||
|
|
||||||
|
/* sync z80 to 68k */
|
||||||
|
PICO_INTERNAL void PicoSyncZ80(int m68k_cycles_done)
|
||||||
{
|
{
|
||||||
int line_from_r=line_from, line_to_r=line_to, line=0;
|
int cnt;
|
||||||
int line_sample = Pico.m.pal ? 68 : 93;
|
z80_cycle_aim = cycles_68k_to_z80(m68k_cycles_done);
|
||||||
|
cnt = z80_cycle_aim - z80_cycle_cnt;
|
||||||
|
|
||||||
if (!(PicoOpt&POPT_EN_Z80) || Pico.m.z80Run == 0) line_to_r = 0;
|
elprintf(EL_ANOMALY, "z80 sync %i (%i|%i -> %i|%i)", cnt, z80_cycle_cnt, z80_cycle_cnt / 228,
|
||||||
else {
|
z80_cycle_aim, z80_cycle_aim / 228);
|
||||||
extern const unsigned short vcounts[];
|
|
||||||
if (z80startCycle) {
|
|
||||||
line = vcounts[z80startCycle>>8];
|
|
||||||
if (line > line_from)
|
|
||||||
line_from_r = line;
|
|
||||||
}
|
|
||||||
z80startCycle = SekCyclesDone();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PicoOpt&POPT_EN_FM) {
|
if (cnt > 0)
|
||||||
// we have ym2612 enabled, so we have to run Z80 in lines, so we could update DAC and timers
|
z80_cycle_cnt += z80_run(cnt);
|
||||||
for (line = line_from; line < line_to; line++) {
|
|
||||||
Psnd_timers_and_dac(line);
|
|
||||||
if ((line == 224 || line == line_sample) && PsndOut) getSamples(line);
|
|
||||||
if (line == 32 && PsndOut) emustatus &= ~1;
|
|
||||||
if (line >= line_from_r && line < line_to_r)
|
|
||||||
z80_run_nr(228);
|
|
||||||
}
|
|
||||||
} else if (line_to_r-line_from_r > 0) {
|
|
||||||
z80_run_nr(228*(line_to_r-line_from_r));
|
|
||||||
// samples will be taken by caller
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Simple frame without H-Ints
|
// Simple frame without H-Ints
|
||||||
static int PicoFrameSimple(void)
|
static int PicoFrameSimple(void)
|
||||||
{
|
{
|
||||||
struct PicoVideo *pv=&Pico.video;
|
struct PicoVideo *pv=&Pico.video;
|
||||||
int y=0,line=0,lines=0,lines_step=0,sects;
|
int y=0,lines_step=0,sects,line_last;
|
||||||
int cycles_68k_vblock,cycles_68k_block;
|
int cycles_68k_vblock,cycles_68k_block;
|
||||||
|
|
||||||
// split to 16 run calls for active scan, for vblank split to 2 (ntsc), 3 (pal 240), 4 (pal 224)
|
// split to 16 run calls for active scan, for vblank split to 2 (ntsc), 3 (pal 240), 4 (pal 224)
|
||||||
if (Pico.m.pal && (pv->reg[1]&8)) {
|
if (Pico.m.pal)
|
||||||
|
{
|
||||||
if(pv->reg[1]&8) { // 240 lines
|
if(pv->reg[1]&8) { // 240 lines
|
||||||
cycles_68k_block = 7329; // (488*240+148)/16.0, -4
|
cycles_68k_block = 7308;
|
||||||
cycles_68k_vblock = 11640; // (72*488-148-68)/3.0, 0
|
cycles_68k_vblock = 11694;
|
||||||
lines_step = 15;
|
lines_step = 15;
|
||||||
} else {
|
} else {
|
||||||
cycles_68k_block = 6841; // (488*224+148)/16.0, -4
|
cycles_68k_block = 6821;
|
||||||
cycles_68k_vblock = 10682; // (88*488-148-68)/4.0, 0
|
cycles_68k_vblock = 10719;
|
||||||
lines_step = 14;
|
lines_step = 14;
|
||||||
}
|
}
|
||||||
|
line_last = 312-1;
|
||||||
} else {
|
} else {
|
||||||
// M68k cycles/frame: 127840.71
|
// M68k cycles/frame: 127840.71
|
||||||
cycles_68k_block = 6841; // (488*224+148)/16.0, -4
|
cycles_68k_block = 6841; // (488*224+148)/16.0, -4
|
||||||
cycles_68k_vblock = 9164; // (38*488-148-68)/2.0, 0
|
cycles_68k_vblock = 9164; // (38*488-148-68)/2.0, 0
|
||||||
lines_step = 14;
|
lines_step = 14;
|
||||||
|
line_last = 262-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// a hack for VR, to get it running in fast mode
|
// a hack for VR, to get it running in fast mode
|
||||||
|
@ -380,9 +371,11 @@ static int PicoFrameSimple(void)
|
||||||
Pico.video.status|=0x200;
|
Pico.video.status|=0x200;
|
||||||
|
|
||||||
Pico.m.scanline=-1;
|
Pico.m.scanline=-1;
|
||||||
z80startCycle=0;
|
PsndDacLine = 0;
|
||||||
|
|
||||||
SekCyclesReset();
|
SekCyclesReset();
|
||||||
|
z80_resetCycles();
|
||||||
|
timers_cycle();
|
||||||
|
|
||||||
// 6 button pad: let's just say it timed out now
|
// 6 button pad: let's just say it timed out now
|
||||||
Pico.m.padTHPhase[0]=Pico.m.padTHPhase[1]=0;
|
Pico.m.padTHPhase[0]=Pico.m.padTHPhase[1]=0;
|
||||||
|
@ -391,28 +384,19 @@ static int PicoFrameSimple(void)
|
||||||
pv->status&=~0x88; // clear V-Int, come out of vblank
|
pv->status&=~0x88; // clear V-Int, come out of vblank
|
||||||
|
|
||||||
// Run in sections:
|
// Run in sections:
|
||||||
for(sects=16; sects; sects--)
|
for (sects=16; sects; sects--)
|
||||||
{
|
{
|
||||||
if (CheckIdle()) break;
|
if (CheckIdle()) break;
|
||||||
|
|
||||||
lines += lines_step;
|
|
||||||
SekRunM68k(cycles_68k_block);
|
SekRunM68k(cycles_68k_block);
|
||||||
|
|
||||||
PicoRunZ80Simple(line, lines);
|
|
||||||
if (PicoLineHook) PicoLineHook(lines_step);
|
if (PicoLineHook) PicoLineHook(lines_step);
|
||||||
line=lines;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// run Z80 for remaining sections
|
// do remaining sections without 68k
|
||||||
if(sects) {
|
if (sects) {
|
||||||
int c = sects*cycles_68k_block;
|
SekCycleCnt += sects * cycles_68k_block;
|
||||||
|
SekCycleAim += sects * cycles_68k_block;
|
||||||
|
|
||||||
// this "run" is for approriate line counter, etc
|
|
||||||
SekCycleCnt += c;
|
|
||||||
SekCycleAim += c;
|
|
||||||
|
|
||||||
lines += sects*lines_step;
|
|
||||||
PicoRunZ80Simple(line, lines);
|
|
||||||
if (PicoLineHook) PicoLineHook(sects*lines_step);
|
if (PicoLineHook) PicoLineHook(sects*lines_step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,33 +430,37 @@ static int PicoFrameSimple(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// here we render sound if ym2612 is disabled
|
|
||||||
if (!(PicoOpt&POPT_EN_FM) && PsndOut) {
|
|
||||||
int len = PsndRender(0, PsndLen);
|
|
||||||
if (PicoWriteSound) PicoWriteSound(len);
|
|
||||||
// clear sound buffer
|
|
||||||
PsndClear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// a gap between flags set and vint
|
// a gap between flags set and vint
|
||||||
pv->pending_ints|=0x20;
|
pv->pending_ints|=0x20;
|
||||||
pv->status|=8; // go into vblank
|
pv->status|=8; // go into vblank
|
||||||
SekRunM68k(68+4);
|
SekRunM68k(68+4);
|
||||||
|
|
||||||
|
if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80))
|
||||||
|
PicoSyncZ80(SekCycleCnt);
|
||||||
|
|
||||||
|
// render sound
|
||||||
|
if (PsndOut)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
if (ym2612.dacen && PsndDacLine <= lines_step*16)
|
||||||
|
PsndDoDAC(lines_step*16);
|
||||||
|
len = PsndRender(0, PsndLen);
|
||||||
|
if (PicoWriteSound) PicoWriteSound(len);
|
||||||
|
// clear sound buffer
|
||||||
|
PsndClear();
|
||||||
|
}
|
||||||
|
|
||||||
// ---- V-Blanking period ----
|
// ---- V-Blanking period ----
|
||||||
// fix line counts
|
// fix line counts
|
||||||
if(Pico.m.pal) {
|
if(Pico.m.pal) {
|
||||||
if(pv->reg[1]&8) { // 240 lines
|
if(pv->reg[1]&8) { // 240 lines
|
||||||
lines = line = 240;
|
|
||||||
sects = 3;
|
sects = 3;
|
||||||
lines_step = 24;
|
lines_step = 24;
|
||||||
} else {
|
} else {
|
||||||
lines = line = 224;
|
|
||||||
sects = 4;
|
sects = 4;
|
||||||
lines_step = 22;
|
lines_step = 22;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lines = line = 224;
|
|
||||||
sects = 2;
|
sects = 2;
|
||||||
lines_step = 19;
|
lines_step = 19;
|
||||||
}
|
}
|
||||||
|
@ -481,27 +469,28 @@ static int PicoFrameSimple(void)
|
||||||
if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80))
|
if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80))
|
||||||
z80_int();
|
z80_int();
|
||||||
|
|
||||||
while (sects)
|
while (1)
|
||||||
{
|
{
|
||||||
lines += lines_step;
|
|
||||||
|
|
||||||
SekRunM68k(cycles_68k_vblock);
|
SekRunM68k(cycles_68k_vblock);
|
||||||
|
|
||||||
PicoRunZ80Simple(line, lines);
|
|
||||||
if (PicoLineHook) PicoLineHook(lines_step);
|
if (PicoLineHook) PicoLineHook(lines_step);
|
||||||
line=lines;
|
|
||||||
|
|
||||||
sects--;
|
sects--;
|
||||||
if (sects && CheckIdle()) break;
|
if (sects == 0) break;
|
||||||
|
if (CheckIdle()) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// run Z80 for remaining sections
|
|
||||||
if (sects) {
|
if (sects) {
|
||||||
lines += sects*lines_step;
|
SekCycleCnt += sects * cycles_68k_vblock;
|
||||||
PicoRunZ80Simple(line, lines);
|
SekCycleAim += sects * cycles_68k_vblock;
|
||||||
if (PicoLineHook) PicoLineHook(sects*lines_step);
|
if (PicoLineHook) PicoLineHook(sects*lines_step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// must sync z80 before return, and extend last DAC sample
|
||||||
|
if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80))
|
||||||
|
PicoSyncZ80(SekCycleCnt);
|
||||||
|
if (PsndOut && ym2612.dacen && PsndDacLine <= line_last)
|
||||||
|
PsndDoDAC(line_last);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,7 +545,6 @@ void PicoGetInternal(pint_t which, pint_ret_t *r)
|
||||||
void (*PicoMessage)(const char *msg)=NULL;
|
void (*PicoMessage)(const char *msg)=NULL;
|
||||||
|
|
||||||
#if 1 // defined(__DEBUG_PRINT)
|
#if 1 // defined(__DEBUG_PRINT)
|
||||||
// tmp debug: dump some stuff
|
|
||||||
#define bit(r, x) ((r>>x)&1)
|
#define bit(r, x) ((r>>x)&1)
|
||||||
void z80_debug(char *dstr);
|
void z80_debug(char *dstr);
|
||||||
char *debugString(void)
|
char *debugString(void)
|
||||||
|
|
|
@ -16,29 +16,10 @@
|
||||||
if(Pico.m.padDelay[1]++ > 25) Pico.m.padTHPhase[1]=0; \
|
if(Pico.m.padDelay[1]++ > 25) Pico.m.padTHPhase[1]=0; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define Z80_RUN(z80_cycles) \
|
|
||||||
{ \
|
|
||||||
if ((PicoOpt&POPT_EN_Z80) && Pico.m.z80Run) \
|
|
||||||
{ \
|
|
||||||
int cnt; \
|
|
||||||
if (Pico.m.z80Run & 2) z80CycleAim += z80_cycles; \
|
|
||||||
else { \
|
|
||||||
cnt = SekCyclesDone() - z80startCycle; \
|
|
||||||
cnt = (cnt>>1)-(cnt>>5); \
|
|
||||||
if (cnt < 0 || cnt > (z80_cycles)) cnt = z80_cycles; \
|
|
||||||
Pico.m.z80Run |= 2; \
|
|
||||||
z80CycleAim+=cnt; \
|
|
||||||
} \
|
|
||||||
cnt=z80CycleAim-total_z80; \
|
|
||||||
if (cnt > 0) total_z80+=z80_run(cnt); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
// CPUS_RUN
|
// CPUS_RUN
|
||||||
#ifndef PICO_CD
|
#ifndef PICO_CD
|
||||||
#define CPUS_RUN(m68k_cycles,z80_cycles,s68k_cycles) \
|
#define CPUS_RUN(m68k_cycles,z80_cycles,s68k_cycles) \
|
||||||
SekRunM68k(m68k_cycles); \
|
SekRunM68k(m68k_cycles);
|
||||||
Z80_RUN(z80_cycles);
|
|
||||||
#else
|
#else
|
||||||
#define CPUS_RUN(m68k_cycles,z80_cycles,s68k_cycles) \
|
#define CPUS_RUN(m68k_cycles,z80_cycles,s68k_cycles) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -49,7 +30,6 @@
|
||||||
if ((Pico_mcd->m.busreq&3) == 1) /* no busreq/no reset */ \
|
if ((Pico_mcd->m.busreq&3) == 1) /* no busreq/no reset */ \
|
||||||
SekRunS68k(s68k_cycles); \
|
SekRunS68k(s68k_cycles); \
|
||||||
} \
|
} \
|
||||||
Z80_RUN(z80_cycles); \
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -57,7 +37,7 @@
|
||||||
static int PicoFrameHints(void)
|
static int PicoFrameHints(void)
|
||||||
{
|
{
|
||||||
struct PicoVideo *pv=&Pico.video;
|
struct PicoVideo *pv=&Pico.video;
|
||||||
int lines, y, lines_vis = 224, total_z80 = 0, z80CycleAim = 0, line_sample, skip;
|
int lines, y, lines_vis = 224, line_sample, skip;
|
||||||
int hint; // Hint counter
|
int hint; // Hint counter
|
||||||
|
|
||||||
if ((PicoOpt&POPT_ALT_RENDERER) && !PicoSkipFrame && (pv->reg[1]&0x40)) { // fast rend., display enabled
|
if ((PicoOpt&POPT_ALT_RENDERER) && !PicoSkipFrame && (pv->reg[1]&0x40)) { // fast rend., display enabled
|
||||||
|
@ -72,20 +52,19 @@ static int PicoFrameHints(void)
|
||||||
else skip=PicoSkipFrame;
|
else skip=PicoSkipFrame;
|
||||||
|
|
||||||
if (Pico.m.pal) {
|
if (Pico.m.pal) {
|
||||||
//cycles_68k = (int) ((double) OSC_PAL / 7 / 50 / 312 + 0.4); // should compile to a constant (488)
|
|
||||||
//cycles_z80 = (int) ((double) OSC_PAL / 15 / 50 / 312 + 0.4); // 228
|
|
||||||
line_sample = 68;
|
line_sample = 68;
|
||||||
if(pv->reg[1]&8) lines_vis = 240;
|
if(pv->reg[1]&8) lines_vis = 240;
|
||||||
} else {
|
} else {
|
||||||
//cycles_68k = (int) ((double) OSC_NTSC / 7 / 60 / 262 + 0.4); // 488
|
|
||||||
//cycles_z80 = (int) ((double) OSC_NTSC / 15 / 60 / 262 + 0.4); // 228
|
|
||||||
line_sample = 93;
|
line_sample = 93;
|
||||||
}
|
}
|
||||||
|
|
||||||
SekCyclesReset();
|
SekCyclesReset();
|
||||||
|
z80_resetCycles();
|
||||||
#ifdef PICO_CD
|
#ifdef PICO_CD
|
||||||
SekCyclesResetS68k();
|
SekCyclesResetS68k();
|
||||||
#endif
|
#endif
|
||||||
|
timers_cycle();
|
||||||
|
PsndDacLine = 0;
|
||||||
|
|
||||||
pv->status&=~0x88; // clear V-Int, come out of vblank
|
pv->status&=~0x88; // clear V-Int, come out of vblank
|
||||||
|
|
||||||
|
@ -93,8 +72,6 @@ static int PicoFrameHints(void)
|
||||||
//dprintf("-hint: %i", hint);
|
//dprintf("-hint: %i", hint);
|
||||||
|
|
||||||
// This is to make active scan longer (needed for Double Dragon 2, mainly)
|
// This is to make active scan longer (needed for Double Dragon 2, mainly)
|
||||||
// also trying to adjust for z80 overclock here (due to int line cycle counts)
|
|
||||||
z80CycleAim = Pico.m.pal ? -40 : 7;
|
|
||||||
CPUS_RUN(CYCLES_M68K_ASD, 0, CYCLES_S68K_ASD);
|
CPUS_RUN(CYCLES_M68K_ASD, 0, CYCLES_S68K_ASD);
|
||||||
|
|
||||||
for (y=0;y<lines_vis;y++)
|
for (y=0;y<lines_vis;y++)
|
||||||
|
@ -148,15 +125,18 @@ static int PicoFrameHints(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PicoOpt&POPT_EN_FM)
|
|
||||||
Psnd_timers_and_dac(y);
|
|
||||||
|
|
||||||
#ifndef PICO_CD
|
#ifndef PICO_CD
|
||||||
// get samples from sound chips
|
// get samples from sound chips
|
||||||
if (y == 32 && PsndOut)
|
if (y == 32 && PsndOut)
|
||||||
emustatus &= ~1;
|
emustatus &= ~1;
|
||||||
else if ((y == 224 || y == line_sample) && PsndOut)
|
else if ((y == 224 || y == line_sample) && PsndOut)
|
||||||
|
{
|
||||||
|
if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80))
|
||||||
|
PicoSyncZ80(SekCycleCnt);
|
||||||
|
if (ym2612.dacen && PsndDacLine <= y)
|
||||||
|
PsndDoDAC(y);
|
||||||
getSamples(y);
|
getSamples(y);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Run scanline:
|
// Run scanline:
|
||||||
|
@ -205,24 +185,27 @@ 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)
|
||||||
SekRunM68k(CYCLES_M68K_VINT_LAG);
|
SekRunM68k(CYCLES_M68K_VINT_LAG);
|
||||||
|
|
||||||
if (pv->reg[1]&0x20) {
|
if (pv->reg[1]&0x20) {
|
||||||
elprintf(EL_INTS, "vint: @ %06x [%i]", SekPc, SekCycleCnt);
|
elprintf(EL_INTS, "vint: @ %06x [%i]", SekPc, SekCycleCnt);
|
||||||
SekInterrupt(6);
|
SekInterrupt(6);
|
||||||
}
|
}
|
||||||
if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80)) {
|
if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80)) {
|
||||||
|
PicoSyncZ80(SekCycleCnt);
|
||||||
elprintf(EL_INTS, "zint");
|
elprintf(EL_INTS, "zint");
|
||||||
z80_int();
|
z80_int();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PicoOpt&POPT_EN_FM)
|
|
||||||
Psnd_timers_and_dac(y);
|
|
||||||
|
|
||||||
// get samples from sound chips
|
// get samples from sound chips
|
||||||
#ifndef PICO_CD
|
#ifndef PICO_CD
|
||||||
if (y == 224)
|
if (y == 224)
|
||||||
#endif
|
#endif
|
||||||
if (PsndOut)
|
if (PsndOut)
|
||||||
|
{
|
||||||
|
if (ym2612.dacen && PsndDacLine <= y)
|
||||||
|
PsndDoDAC(y);
|
||||||
getSamples(y);
|
getSamples(y);
|
||||||
|
}
|
||||||
|
|
||||||
// Run scanline:
|
// Run scanline:
|
||||||
if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
|
if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
|
||||||
|
@ -247,9 +230,6 @@ static int PicoFrameHints(void)
|
||||||
check_cd_dma();
|
check_cd_dma();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (PicoOpt&POPT_EN_FM)
|
|
||||||
Psnd_timers_and_dac(y);
|
|
||||||
|
|
||||||
// Run scanline:
|
// Run scanline:
|
||||||
if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
|
if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
|
||||||
CPUS_RUN(CYCLES_M68K_LINE, CYCLES_Z80_LINE, CYCLES_S68K_LINE);
|
CPUS_RUN(CYCLES_M68K_LINE, CYCLES_Z80_LINE, CYCLES_S68K_LINE);
|
||||||
|
@ -261,6 +241,12 @@ static int PicoFrameHints(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sync z80
|
||||||
|
if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80))
|
||||||
|
PicoSyncZ80(SekCycleCnt);
|
||||||
|
if (PsndOut && ym2612.dacen && PsndDacLine <= lines-1)
|
||||||
|
PsndDoDAC(lines-1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ extern unsigned int SekCycleCntT; // total cycle counter, updated once per frame
|
||||||
SekCycleAim=0; \
|
SekCycleAim=0; \
|
||||||
}
|
}
|
||||||
#define SekCyclesBurn(c) SekCycleCnt+=c
|
#define SekCyclesBurn(c) SekCycleCnt+=c
|
||||||
#define SekCyclesDone() (SekCycleAim-SekCyclesLeft) // nuber of cycles done in this frame (can be checked anywhere)
|
#define SekCyclesDone() (SekCycleAim-SekCyclesLeft) // number of cycles done in this frame (can be checked anywhere)
|
||||||
#define SekCyclesDoneT() (SekCycleCntT+SekCyclesDone()) // total nuber of cycles done for this rom
|
#define SekCyclesDoneT() (SekCycleCntT+SekCyclesDone()) // total nuber of cycles done for this rom
|
||||||
|
|
||||||
#define SekEndRun(after) { \
|
#define SekEndRun(after) { \
|
||||||
|
@ -174,10 +174,9 @@ extern int dbg_irq_level;
|
||||||
#if defined(_USE_MZ80)
|
#if defined(_USE_MZ80)
|
||||||
#include "../cpu/mz80/mz80.h"
|
#include "../cpu/mz80/mz80.h"
|
||||||
|
|
||||||
#define z80_run(cycles) mz80_run(cycles)
|
#define z80_run(cycles) { mz80GetElapsedTicks(1); mz80_run(cycles) }
|
||||||
#define z80_run_nr(cycles) mz80_run(cycles)
|
#define z80_run_nr(cycles) mz80_run(cycles)
|
||||||
#define z80_int() mz80int(0)
|
#define z80_int() mz80int(0)
|
||||||
#define z80_resetCycles() mz80GetElapsedTicks(1)
|
|
||||||
|
|
||||||
#elif defined(_USE_DRZ80)
|
#elif defined(_USE_DRZ80)
|
||||||
#include "../cpu/DrZ80/drz80.h"
|
#include "../cpu/DrZ80/drz80.h"
|
||||||
|
@ -190,7 +189,8 @@ extern struct DrZ80 drZ80;
|
||||||
drZ80.z80irqvector = 0xFF; /* default IRQ vector RST opcode */ \
|
drZ80.z80irqvector = 0xFF; /* default IRQ vector RST opcode */ \
|
||||||
drZ80.Z80_IRQ = 1; \
|
drZ80.Z80_IRQ = 1; \
|
||||||
}
|
}
|
||||||
#define z80_resetCycles()
|
|
||||||
|
#define z80_cyclesLeft drZ80.cycles
|
||||||
|
|
||||||
#elif defined(_USE_CZ80)
|
#elif defined(_USE_CZ80)
|
||||||
#include "../cpu/cz80/cz80.h"
|
#include "../cpu/cz80/cz80.h"
|
||||||
|
@ -198,17 +198,31 @@ extern struct DrZ80 drZ80;
|
||||||
#define z80_run(cycles) Cz80_Exec(&CZ80, cycles)
|
#define z80_run(cycles) Cz80_Exec(&CZ80, cycles)
|
||||||
#define z80_run_nr(cycles) Cz80_Exec(&CZ80, cycles)
|
#define z80_run_nr(cycles) Cz80_Exec(&CZ80, cycles)
|
||||||
#define z80_int() Cz80_Set_IRQ(&CZ80, 0, HOLD_LINE)
|
#define z80_int() Cz80_Set_IRQ(&CZ80, 0, HOLD_LINE)
|
||||||
#define z80_resetCycles()
|
|
||||||
|
#define z80_cyclesLeft (CZ80.ICount - CZ80.ExtraCycles)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define z80_run(cycles) (cycles)
|
#define z80_run(cycles) (cycles)
|
||||||
#define z80_run_nr(cycles)
|
#define z80_run_nr(cycles)
|
||||||
#define z80_int()
|
#define z80_int()
|
||||||
#define z80_resetCycles()
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern int z80stopCycle; /* in 68k cycles */
|
||||||
|
extern int z80_cycle_cnt; /* 'done' z80 cycles before z80_run() */
|
||||||
|
extern int z80_cycle_aim;
|
||||||
|
extern int z80_scanline;
|
||||||
|
extern int z80_scanline_cycles; /* cycles done until z80_scanline */
|
||||||
|
|
||||||
|
#define z80_resetCycles() \
|
||||||
|
z80_cycle_cnt = z80_cycle_aim = z80_scanline = z80_scanline_cycles = 0;
|
||||||
|
|
||||||
|
#define z80_cyclesDone() \
|
||||||
|
(z80_cycle_aim - z80_cyclesLeft)
|
||||||
|
|
||||||
|
#define cycles_68k_to_z80(x) ((x)*957 >> 11)
|
||||||
|
|
||||||
// ---------------------------------------------------------
|
// ---------------------------------------------------------
|
||||||
|
|
||||||
// main oscillator clock which controls timing
|
// main oscillator clock which controls timing
|
||||||
|
@ -405,6 +419,7 @@ PICO_INTERNAL unsigned short z80_read16(unsigned short a);
|
||||||
#else
|
#else
|
||||||
PICO_INTERNAL_ASM void z80_write(unsigned int a, unsigned char data);
|
PICO_INTERNAL_ASM void z80_write(unsigned int a, unsigned char data);
|
||||||
#endif
|
#endif
|
||||||
|
PICO_INTERNAL int ym2612_write_local(unsigned int a, unsigned int d, int is_from_z80);
|
||||||
extern unsigned int (*PicoRead16Hook)(unsigned int a, int realsize);
|
extern unsigned int (*PicoRead16Hook)(unsigned int a, int realsize);
|
||||||
extern void (*PicoWrite8Hook) (unsigned int a,unsigned int d,int realsize);
|
extern void (*PicoWrite8Hook) (unsigned int a,unsigned int d,int realsize);
|
||||||
extern void (*PicoWrite16Hook)(unsigned int a,unsigned int d,int realsize);
|
extern void (*PicoWrite16Hook)(unsigned int a,unsigned int d,int realsize);
|
||||||
|
@ -421,11 +436,11 @@ PICO_INTERNAL void PicoMemSetupPico(void);
|
||||||
extern struct Pico Pico;
|
extern struct Pico Pico;
|
||||||
extern struct PicoSRAM SRam;
|
extern struct PicoSRAM SRam;
|
||||||
extern int emustatus;
|
extern int emustatus;
|
||||||
extern int z80startCycle, z80stopCycle; // in 68k cycles
|
|
||||||
extern void (*PicoResetHook)(void);
|
extern void (*PicoResetHook)(void);
|
||||||
extern void (*PicoLineHook)(int count);
|
extern void (*PicoLineHook)(int count);
|
||||||
PICO_INTERNAL int CheckDMA(void);
|
PICO_INTERNAL int CheckDMA(void);
|
||||||
PICO_INTERNAL void PicoDetectRegion(void);
|
PICO_INTERNAL void PicoDetectRegion(void);
|
||||||
|
PICO_INTERNAL void PicoSyncZ80(int m68k_cycles_done);
|
||||||
|
|
||||||
// cd/Pico.c
|
// cd/Pico.c
|
||||||
PICO_INTERNAL int PicoInitMCD(void);
|
PICO_INTERNAL int PicoInitMCD(void);
|
||||||
|
@ -459,6 +474,13 @@ PICO_INTERNAL void cdda_start_play();
|
||||||
extern short cdda_out_buffer[2*1152];
|
extern short cdda_out_buffer[2*1152];
|
||||||
extern int PsndLen_exc_cnt;
|
extern int PsndLen_exc_cnt;
|
||||||
extern int PsndLen_exc_add;
|
extern int PsndLen_exc_add;
|
||||||
|
extern int timer_a_next_oflow, timer_a_step; // in z80 cycles
|
||||||
|
|
||||||
|
#define timers_cycle() \
|
||||||
|
if (timer_a_next_oflow > 0) timer_a_next_oflow -= Pico.m.pal ? 70938*256 : 59659*256
|
||||||
|
|
||||||
|
#define timers_reset() \
|
||||||
|
timer_a_next_oflow = 0x80000000
|
||||||
|
|
||||||
// VideoPort.c
|
// VideoPort.c
|
||||||
PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d);
|
PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d);
|
||||||
|
@ -483,7 +505,7 @@ PICO_INTERNAL void PicoCDBufferRead(void *dest, int lba);
|
||||||
|
|
||||||
// sound/sound.c
|
// sound/sound.c
|
||||||
PICO_INTERNAL void PsndReset(void);
|
PICO_INTERNAL void PsndReset(void);
|
||||||
PICO_INTERNAL void Psnd_timers_and_dac(int raster);
|
PICO_INTERNAL void PsndDoDAC(int line_to);
|
||||||
PICO_INTERNAL int PsndRender(int offset, int length);
|
PICO_INTERNAL int PsndRender(int offset, int length);
|
||||||
PICO_INTERNAL void PsndClear(void);
|
PICO_INTERNAL void PsndClear(void);
|
||||||
// z80 functionality wrappers
|
// z80 functionality wrappers
|
||||||
|
@ -492,7 +514,7 @@ PICO_INTERNAL void z80_pack(unsigned char *data);
|
||||||
PICO_INTERNAL void z80_unpack(unsigned char *data);
|
PICO_INTERNAL void z80_unpack(unsigned char *data);
|
||||||
PICO_INTERNAL void z80_reset(void);
|
PICO_INTERNAL void z80_reset(void);
|
||||||
PICO_INTERNAL void z80_exit(void);
|
PICO_INTERNAL void z80_exit(void);
|
||||||
|
extern int PsndDacLine;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // End of extern "C"
|
} // End of extern "C"
|
||||||
|
|
|
@ -21,7 +21,7 @@ void (*PsndMix_32_to_16l)(short *dest, int *src, int count) = mix_32_to_16l_ster
|
||||||
static int PsndBuffer[2*44100/50];
|
static int PsndBuffer[2*44100/50];
|
||||||
|
|
||||||
// dac
|
// dac
|
||||||
static unsigned short dac_info[312]; // pppppppp ppppllll, p - pos in buff, l - length to write for this sample
|
static unsigned short dac_info[312+4]; // pppppppp ppppllll, p - pos in buff, l - length to write for this sample
|
||||||
|
|
||||||
// cdda output buffer
|
// cdda output buffer
|
||||||
short cdda_out_buffer[2*1152];
|
short cdda_out_buffer[2*1152];
|
||||||
|
@ -31,8 +31,13 @@ int PsndRate=0;
|
||||||
int PsndLen=0; // number of mono samples, multiply by 2 for stereo
|
int PsndLen=0; // number of mono samples, multiply by 2 for stereo
|
||||||
int PsndLen_exc_add=0; // this is for non-integer sample counts per line, eg. 22050/60
|
int PsndLen_exc_add=0; // this is for non-integer sample counts per line, eg. 22050/60
|
||||||
int PsndLen_exc_cnt=0;
|
int PsndLen_exc_cnt=0;
|
||||||
|
int PsndDacLine=0;
|
||||||
short *PsndOut=NULL; // PCM data buffer
|
short *PsndOut=NULL; // PCM data buffer
|
||||||
|
|
||||||
|
// timers
|
||||||
|
int timer_a_next_oflow, timer_a_step; // in z80 cycles
|
||||||
|
//int
|
||||||
|
|
||||||
// sn76496
|
// sn76496
|
||||||
extern int *sn76496_regs;
|
extern int *sn76496_regs;
|
||||||
|
|
||||||
|
@ -83,6 +88,8 @@ static void dac_recalculate(void)
|
||||||
if (PsndLen_exc_add) len++;
|
if (PsndLen_exc_add) len++;
|
||||||
dac_info[224] = (pos<<4)|len;
|
dac_info[224] = (pos<<4)|len;
|
||||||
}
|
}
|
||||||
|
for (i = lines; i < sizeof(dac_info) / sizeof(dac_info[0]); i++)
|
||||||
|
dac_info[i] = 0;
|
||||||
//for(i=len=0; i < lines; i++) {
|
//for(i=len=0; i < lines; i++) {
|
||||||
// printf("%03i : %03i : %i\n", i, dac_info[i]>>4, dac_info[i]&0xf);
|
// printf("%03i : %03i : %i\n", i, dac_info[i]>>4, dac_info[i]&0xf);
|
||||||
// len+=dac_info[i]&0xf;
|
// len+=dac_info[i]&0xf;
|
||||||
|
@ -100,7 +107,7 @@ PICO_INTERNAL void PsndReset(void)
|
||||||
// also clear the internal registers+addr line
|
// also clear the internal registers+addr line
|
||||||
ym2612_regs = YM2612GetRegs();
|
ym2612_regs = YM2612GetRegs();
|
||||||
memset(ym2612_regs, 0, 0x200+4);
|
memset(ym2612_regs, 0, 0x200+4);
|
||||||
z80startCycle = z80stopCycle = 0;
|
timers_reset();
|
||||||
|
|
||||||
PsndRerate(0);
|
PsndRerate(0);
|
||||||
}
|
}
|
||||||
|
@ -164,44 +171,25 @@ void PsndRerate(int preserve_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This is called once per raster (aka line), but not necessarily for every line
|
PICO_INTERNAL void PsndDoDAC(int line_to)
|
||||||
PICO_INTERNAL void Psnd_timers_and_dac(int raster)
|
|
||||||
{
|
{
|
||||||
int pos, len;
|
int pos, pos1, len;
|
||||||
int do_dac = PsndOut && (PicoOpt&POPT_EN_FM) && *ym2612_dacen;
|
int dout = ym2612.dacout;
|
||||||
// int do_pcm = PsndOut && (PicoAHW&1) && (PicoOpt&0x400);
|
int line_from = PsndDacLine;
|
||||||
|
|
||||||
// Our raster lasts 63.61323/64.102564 microseconds (NTSC/PAL)
|
PsndDacLine = line_to + 1;
|
||||||
YM2612PicoTick(1);
|
|
||||||
|
|
||||||
if (!do_dac /*&& !do_pcm*/) return;
|
pos =dac_info[line_from]>>4;
|
||||||
|
pos1=dac_info[line_to];
|
||||||
pos=dac_info[raster], len=pos&0xf;
|
len = ((pos1>>4)-pos) + (pos1&0xf);
|
||||||
if (!len) return;
|
if (!len) return;
|
||||||
|
|
||||||
pos>>=4;
|
if (PicoOpt & POPT_EN_STEREO) {
|
||||||
|
|
||||||
if (do_dac)
|
|
||||||
{
|
|
||||||
short *d = PsndOut + pos*2;
|
short *d = PsndOut + pos*2;
|
||||||
int dout = *ym2612_dacout;
|
for (; len > 0; len--, d+=2) *d = dout;
|
||||||
if(PicoOpt&POPT_EN_STEREO) {
|
} else {
|
||||||
// some manual loop unrolling here :)
|
short *d = PsndOut + pos;
|
||||||
d[0] = dout;
|
for (; len > 0; len--, d++) *d = dout;
|
||||||
if (len > 1) {
|
|
||||||
d[2] = dout;
|
|
||||||
if (len > 2)
|
|
||||||
d[4] = dout;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
short *d = PsndOut + pos;
|
|
||||||
d[0] = dout;
|
|
||||||
if (len > 1) {
|
|
||||||
d[1] = dout;
|
|
||||||
if (len > 2)
|
|
||||||
d[2] = dout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
|
@ -116,7 +116,7 @@
|
||||||
#ifndef EXTERNAL_YM2612
|
#ifndef EXTERNAL_YM2612
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
// let it be 1 global to simplify things
|
// let it be 1 global to simplify things
|
||||||
static YM2612 ym2612;
|
YM2612 ym2612;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
extern YM2612 *ym2612_940;
|
extern YM2612 *ym2612_940;
|
||||||
|
@ -1584,11 +1584,8 @@ static int OPNWriteReg(int r, int v)
|
||||||
/* YM2612 local section */
|
/* YM2612 local section */
|
||||||
/*******************************************************************************/
|
/*******************************************************************************/
|
||||||
|
|
||||||
int *ym2612_dacen;
|
|
||||||
INT32 *ym2612_dacout;
|
|
||||||
FM_ST *ym2612_st;
|
FM_ST *ym2612_st;
|
||||||
|
|
||||||
|
|
||||||
/* Generate samples for YM2612 */
|
/* Generate samples for YM2612 */
|
||||||
int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty)
|
int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty)
|
||||||
{
|
{
|
||||||
|
@ -1654,8 +1651,6 @@ int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty)
|
||||||
void YM2612Init_(int clock, int rate)
|
void YM2612Init_(int clock, int rate)
|
||||||
{
|
{
|
||||||
// notaz
|
// notaz
|
||||||
ym2612_dacen = &ym2612.dacen;
|
|
||||||
ym2612_dacout = &ym2612.dacout;
|
|
||||||
ym2612_st = &ym2612.OPN.ST;
|
ym2612_st = &ym2612.OPN.ST;
|
||||||
|
|
||||||
memset(&ym2612, 0, sizeof(ym2612));
|
memset(&ym2612, 0, sizeof(ym2612));
|
||||||
|
@ -1728,9 +1723,6 @@ int YM2612Write_(unsigned int a, unsigned int v)
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = ym2612.OPN.ST.address;
|
addr = ym2612.OPN.ST.address;
|
||||||
#ifndef EXTERNAL_YM2612
|
|
||||||
ym2612.REGS[addr] = v;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch( addr & 0xf0 )
|
switch( addr & 0xf0 )
|
||||||
{
|
{
|
||||||
|
@ -1747,6 +1739,7 @@ int YM2612Write_(unsigned int a, unsigned int v)
|
||||||
ym2612.OPN.lfo_inc = 0;
|
ym2612.OPN.lfo_inc = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
#if 0 // handled elsewhere
|
||||||
case 0x24: { // timer A High 8
|
case 0x24: { // timer A High 8
|
||||||
int TAnew = (ym2612.OPN.ST.TA & 0x03)|(((int)v)<<2);
|
int TAnew = (ym2612.OPN.ST.TA & 0x03)|(((int)v)<<2);
|
||||||
if(ym2612.OPN.ST.TA != TAnew) {
|
if(ym2612.OPN.ST.TA != TAnew) {
|
||||||
|
@ -1781,6 +1774,7 @@ int YM2612Write_(unsigned int a, unsigned int v)
|
||||||
set_timers( v );
|
set_timers( v );
|
||||||
ret=0;
|
ret=0;
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
case 0x28: /* key on / off */
|
case 0x28: /* key on / off */
|
||||||
{
|
{
|
||||||
UINT8 c;
|
UINT8 c;
|
||||||
|
@ -1794,6 +1788,7 @@ int YM2612Write_(unsigned int a, unsigned int v)
|
||||||
if(v&0x80) FM_KEYON(c,SLOT4); else FM_KEYOFF(c,SLOT4);
|
if(v&0x80) FM_KEYON(c,SLOT4); else FM_KEYOFF(c,SLOT4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
case 0x2a: /* DAC data (YM2612) */
|
case 0x2a: /* DAC data (YM2612) */
|
||||||
ym2612.dacout = ((int)v - 0x80) << 6; /* level unknown (notaz: 8 seems to be too much) */
|
ym2612.dacout = ((int)v - 0x80) << 6; /* level unknown (notaz: 8 seems to be too much) */
|
||||||
ret=0;
|
ret=0;
|
||||||
|
@ -1803,6 +1798,7 @@ int YM2612Write_(unsigned int a, unsigned int v)
|
||||||
ym2612.dacen = v & 0x80;
|
ym2612.dacen = v & 0x80;
|
||||||
ret=0;
|
ret=0;
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1826,9 +1822,6 @@ int YM2612Write_(unsigned int a, unsigned int v)
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = ym2612.OPN.ST.address | 0x100;
|
addr = ym2612.OPN.ST.address | 0x100;
|
||||||
#ifndef EXTERNAL_YM2612
|
|
||||||
ym2612.REGS[addr] = v;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ret = OPNWriteReg(addr, v);
|
ret = OPNWriteReg(addr, v);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -141,10 +141,10 @@ typedef struct
|
||||||
} YM2612;
|
} YM2612;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int *ym2612_dacen;
|
|
||||||
extern INT32 *ym2612_dacout;
|
|
||||||
extern FM_ST *ym2612_st;
|
extern FM_ST *ym2612_st;
|
||||||
|
#ifndef EXTERNAL_YM2612
|
||||||
|
extern YM2612 ym2612;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define YM2612Read() ym2612_st->status
|
#define YM2612Read() ym2612_st->status
|
||||||
|
|
||||||
|
@ -180,7 +180,6 @@ void *YM2612GetRegs(void);
|
||||||
#define YM2612Init YM2612Init_
|
#define YM2612Init YM2612Init_
|
||||||
#define YM2612ResetChip YM2612ResetChip_
|
#define YM2612ResetChip YM2612ResetChip_
|
||||||
#define YM2612UpdateOne YM2612UpdateOne_
|
#define YM2612UpdateOne YM2612UpdateOne_
|
||||||
#define YM2612Write YM2612Write_
|
|
||||||
#define YM2612PicoStateLoad YM2612PicoStateLoad_
|
#define YM2612PicoStateLoad YM2612PicoStateLoad_
|
||||||
#else
|
#else
|
||||||
/* GP2X specific */
|
/* GP2X specific */
|
||||||
|
@ -197,8 +196,6 @@ extern int PicoOpt;
|
||||||
#define YM2612UpdateOne(buffer,length,stereo,is_buf_empty) \
|
#define YM2612UpdateOne(buffer,length,stereo,is_buf_empty) \
|
||||||
(PicoOpt&0x200) ? YM2612UpdateOne_940(buffer, length, stereo, is_buf_empty) : \
|
(PicoOpt&0x200) ? YM2612UpdateOne_940(buffer, length, stereo, is_buf_empty) : \
|
||||||
YM2612UpdateOne_(buffer, length, stereo, is_buf_empty);
|
YM2612UpdateOne_(buffer, length, stereo, is_buf_empty);
|
||||||
#define YM2612Write(a,v) \
|
|
||||||
(PicoOpt&0x200) ? YM2612Write_940(a, v) : YM2612Write_(a, v)
|
|
||||||
#define YM2612PicoStateLoad() { \
|
#define YM2612PicoStateLoad() { \
|
||||||
if (PicoOpt&0x200) YM2612PicoStateLoad_940(); \
|
if (PicoOpt&0x200) YM2612PicoStateLoad_940(); \
|
||||||
else YM2612PicoStateLoad_(); \
|
else YM2612PicoStateLoad_(); \
|
||||||
|
|
|
@ -51,160 +51,64 @@ static FILE *loaded_mp3 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* these will be managed locally on our side */
|
/* these will be managed locally on our side */
|
||||||
static UINT8 *REGS = 0; /* we will also keep local copy of regs for savestates and such */
|
|
||||||
static INT32 *addr_A1; /* address line A1 */
|
|
||||||
|
|
||||||
static int dacen;
|
|
||||||
static INT32 dacout;
|
|
||||||
static UINT8 ST_address; /* address register */
|
static UINT8 ST_address; /* address register */
|
||||||
|
static INT32 addr_A1; /* address line A1 */
|
||||||
|
|
||||||
static int writebuff_ptr = 0;
|
static int writebuff_ptr = 0;
|
||||||
|
|
||||||
|
|
||||||
/* OPN Mode Register Write */
|
|
||||||
static int set_timers( int v )
|
|
||||||
{
|
|
||||||
int change;
|
|
||||||
|
|
||||||
/* b7 = CSM MODE */
|
|
||||||
/* b6 = 3 slot mode */
|
|
||||||
/* b5 = reset b */
|
|
||||||
/* b4 = reset a */
|
|
||||||
/* b3 = timer enable b */
|
|
||||||
/* b2 = timer enable a */
|
|
||||||
/* b1 = load b */
|
|
||||||
/* b0 = load a */
|
|
||||||
change = (ym2612_st->mode ^ v) & 0xc0;
|
|
||||||
ym2612_st->mode = v;
|
|
||||||
|
|
||||||
/* reset Timer b flag */
|
|
||||||
if( v & 0x20 )
|
|
||||||
ym2612_st->status &= ~2;
|
|
||||||
|
|
||||||
/* reset Timer a flag */
|
|
||||||
if( v & 0x10 )
|
|
||||||
ym2612_st->status &= ~1;
|
|
||||||
|
|
||||||
return change;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* YM2612 write */
|
/* YM2612 write */
|
||||||
/* a = address */
|
/* a = address */
|
||||||
/* v = value */
|
/* v = value */
|
||||||
/* returns 1 if sample affecting state changed */
|
/* returns 1 if sample affecting state changed */
|
||||||
int YM2612Write_940(unsigned int a, unsigned int v)
|
int YM2612Write_940(unsigned int a, unsigned int v, int scanline)
|
||||||
{
|
{
|
||||||
int addr;
|
|
||||||
int upd = 1; /* the write affects sample generation */
|
int upd = 1; /* the write affects sample generation */
|
||||||
|
|
||||||
v &= 0xff; /* adjust to 8 bit bus */
|
|
||||||
a &= 3;
|
a &= 3;
|
||||||
|
|
||||||
//printf("%05i:%03i: ym w ([%i] %02x)\n", Pico.m.frame_count, Pico.m.scanline, a, v);
|
//printf("%05i:%03i: ym w ([%i] %02x)\n", Pico.m.frame_count, Pico.m.scanline, a, v);
|
||||||
|
|
||||||
switch( a ) {
|
switch (a) {
|
||||||
case 0: /* address port 0 */
|
case 0: /* address port 0 */
|
||||||
if (!*addr_A1 && ST_address == v)
|
if (addr_A1 == 0 && ST_address == v)
|
||||||
return 0; /* address already selected, don't send this command to 940 */
|
return 0; /* address already selected, don't send this command to 940 */
|
||||||
ST_address = v;
|
ST_address = v;
|
||||||
/* don't send DAC or timer related address changes to 940 */
|
addr_A1 = 0;
|
||||||
if (!*addr_A1 && (v & 0xf0) == 0x20 &&
|
/* don't send DAC or timer related address changes to 940 */
|
||||||
(v == 0x24 || v == 0x25 || v == 0x26 || v == 0x2a))
|
if (v == 0x24 || v == 0x25 || v == 0x26 || v == 0x2a)
|
||||||
return 0;
|
return 0;
|
||||||
*addr_A1 = 0;
|
upd = 0;
|
||||||
upd = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1: /* data port 0 */
|
|
||||||
if (*addr_A1 != 0) {
|
|
||||||
return 0; /* verified on real YM2608 */
|
|
||||||
}
|
|
||||||
|
|
||||||
addr = ST_address;
|
|
||||||
REGS[addr] = v;
|
|
||||||
|
|
||||||
switch( addr & 0xf0 )
|
|
||||||
{
|
|
||||||
case 0x20: /* 0x20-0x2f Mode */
|
|
||||||
switch( addr )
|
|
||||||
{
|
|
||||||
case 0x24: { // timer A High 8
|
|
||||||
int TAnew = (ym2612_st->TA & 0x03)|(((int)v)<<2);
|
|
||||||
if (ym2612_st->TA != TAnew) {
|
|
||||||
// we should reset ticker only if new value is written. Outrun requires this.
|
|
||||||
ym2612_st->TA = TAnew;
|
|
||||||
ym2612_st->TAC = (1024-TAnew)*18;
|
|
||||||
ym2612_st->TAT = 0;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case 0x25: { // timer A Low 2
|
|
||||||
int TAnew = (ym2612_st->TA & 0x3fc)|(v&3);
|
|
||||||
if (ym2612_st->TA != TAnew) {
|
|
||||||
ym2612_st->TA = TAnew;
|
|
||||||
ym2612_st->TAC = (1024-TAnew)*18;
|
|
||||||
ym2612_st->TAT = 0;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case 0x26: // timer B
|
|
||||||
if (ym2612_st->TB != v) {
|
|
||||||
ym2612_st->TB = v;
|
|
||||||
ym2612_st->TBC = (256-v)<<4;
|
|
||||||
ym2612_st->TBC *= 18;
|
|
||||||
ym2612_st->TBT = 0;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
case 0x27: /* mode, timer control */
|
|
||||||
if (set_timers( v ))
|
|
||||||
break; // other side needs ST.mode for 3slot mode
|
|
||||||
return 0;
|
|
||||||
case 0x2a: /* DAC data (YM2612) */
|
|
||||||
dacout = ((int)v - 0x80) << 6; /* level unknown (notaz: 8 seems to be too much) */
|
|
||||||
return 0;
|
|
||||||
case 0x2b: /* DAC Sel (YM2612) */
|
|
||||||
/* b7 = dac enable */
|
|
||||||
dacen = v & 0x80;
|
|
||||||
upd = 0;
|
|
||||||
break; // other side has to know this
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: /* address port 1 */
|
case 1: /* data port 0 */
|
||||||
if (*addr_A1 && ST_address == v)
|
if (ST_address == 0x2b) upd = 0; /* DAC sel */
|
||||||
return 0;
|
break;
|
||||||
ST_address = v;
|
|
||||||
*addr_A1 = 1;
|
|
||||||
upd = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3: /* data port 1 */
|
case 2: /* address port 1 */
|
||||||
if (*addr_A1 != 1) {
|
if (addr_A1 == 1 && ST_address == v)
|
||||||
return 0; /* verified on real YM2608 */
|
return 0;
|
||||||
}
|
ST_address = v;
|
||||||
|
addr_A1 = 1;
|
||||||
addr = ST_address | 0x100;
|
upd = 0;
|
||||||
REGS[addr] = v;
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("ym pass\n");
|
//printf("ym pass\n");
|
||||||
|
|
||||||
if(currentConfig.EmuOpt & 4) {
|
if (currentConfig.EmuOpt & 4)
|
||||||
|
{
|
||||||
UINT16 *writebuff = shared_ctl->writebuffsel ? shared_ctl->writebuff0 : shared_ctl->writebuff1;
|
UINT16 *writebuff = shared_ctl->writebuffsel ? shared_ctl->writebuff0 : shared_ctl->writebuff1;
|
||||||
|
|
||||||
/* detect rapid ym updates */
|
/* detect rapid ym updates */
|
||||||
if (upd && !(writebuff_ptr & 0x80000000) && Pico.m.scanline < 224) {
|
if (upd && !(writebuff_ptr & 0x80000000) && scanline < 224)
|
||||||
|
{
|
||||||
int mid = Pico.m.pal ? 68 : 93;
|
int mid = Pico.m.pal ? 68 : 93;
|
||||||
if (Pico.m.scanline > mid) {
|
if (scanline > mid) {
|
||||||
//printf("%05i:%03i: rapid ym\n", Pico.m.frame_count, Pico.m.scanline);
|
//printf("%05i:%03i: rapid ym\n", Pico.m.frame_count, scanline);
|
||||||
writebuff[writebuff_ptr++ & 0xffff] = 0xfffe;
|
writebuff[writebuff_ptr++ & 0xffff] = 0xfffe;
|
||||||
writebuff_ptr |= 0x80000000;
|
writebuff_ptr |= 0x80000000;
|
||||||
//printf("%05i:%03i: ym w ([%02x] %02x, upd=%i)\n", Pico.m.frame_count, Pico.m.scanline, addr, v, upd);
|
//printf("%05i:%03i: ym w ([%02x] %02x, upd=%i)\n", Pico.m.frame_count, scanline, addr, v, upd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +176,9 @@ static void add_job_940(int job)
|
||||||
|
|
||||||
void YM2612PicoStateLoad_940(void)
|
void YM2612PicoStateLoad_940(void)
|
||||||
{
|
{
|
||||||
int i, old_A1 = *addr_A1;
|
UINT8 *REGS = YM2612GetRegs();
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
/* make sure JOB940_PICOSTATELOAD gets done before next JOB940_YM2612UPDATEONE */
|
/* make sure JOB940_PICOSTATELOAD gets done before next JOB940_YM2612UPDATEONE */
|
||||||
add_job_940(JOB940_PICOSTATELOAD);
|
add_job_940(JOB940_PICOSTATELOAD);
|
||||||
|
@ -282,32 +188,22 @@ void YM2612PicoStateLoad_940(void)
|
||||||
|
|
||||||
// feed all the registers and update internal state
|
// feed all the registers and update internal state
|
||||||
for(i = 0; i < 0x100; i++) {
|
for(i = 0; i < 0x100; i++) {
|
||||||
YM2612Write_940(0, i);
|
YM2612Write_940(0, i, -1);
|
||||||
YM2612Write_940(1, REGS[i]);
|
YM2612Write_940(1, REGS[i], -1);
|
||||||
}
|
}
|
||||||
for(i = 0; i < 0x100; i++) {
|
for(i = 0; i < 0x100; i++) {
|
||||||
YM2612Write_940(2, i);
|
YM2612Write_940(2, i, -1);
|
||||||
YM2612Write_940(3, REGS[i|0x100]);
|
YM2612Write_940(3, REGS[i|0x100], -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
*addr_A1 = old_A1;
|
addr_A1 = *(INT32 *) (REGS + 0x200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void internal_reset(void)
|
static void internal_reset(void)
|
||||||
{
|
{
|
||||||
writebuff_ptr = 0;
|
writebuff_ptr = 0;
|
||||||
ym2612_st->mode = 0;
|
ST_address = addr_A1 = -1;
|
||||||
ym2612_st->status = 0; /* normal mode */
|
|
||||||
ym2612_st->TA = 0;
|
|
||||||
ym2612_st->TAC = 0;
|
|
||||||
ym2612_st->TAT = 0;
|
|
||||||
ym2612_st->TB = 0;
|
|
||||||
ym2612_st->TBC = 0;
|
|
||||||
ym2612_st->TBT = 0;
|
|
||||||
dacen = 0;
|
|
||||||
dacout = 0;
|
|
||||||
ST_address= 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -405,12 +301,6 @@ void YM2612Init_940(int baseclock, int rate)
|
||||||
/* cause local ym2612 to init REGS */
|
/* cause local ym2612 to init REGS */
|
||||||
YM2612Init_(baseclock, rate);
|
YM2612Init_(baseclock, rate);
|
||||||
|
|
||||||
REGS = YM2612GetRegs();
|
|
||||||
addr_A1 = (INT32 *) (REGS + 0x200);
|
|
||||||
|
|
||||||
ym2612_dacen = &dacen;
|
|
||||||
ym2612_dacout = &dacout;
|
|
||||||
|
|
||||||
internal_reset();
|
internal_reset();
|
||||||
|
|
||||||
loaded_mp3 = 0;
|
loaded_mp3 = 0;
|
||||||
|
@ -440,6 +330,7 @@ void YM2612ResetChip_940(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
YM2612ResetChip_();
|
||||||
internal_reset();
|
internal_reset();
|
||||||
|
|
||||||
add_job_940(JOB940_YM2612RESETCHIP);
|
add_job_940(JOB940_YM2612RESETCHIP);
|
||||||
|
|
|
@ -5,7 +5,7 @@ void YM2612Init_940(int baseclock, int rate);
|
||||||
void YM2612ResetChip_940(void);
|
void YM2612ResetChip_940(void);
|
||||||
int YM2612UpdateOne_940(int *buffer, int length, int stereo, int is_buf_empty);
|
int YM2612UpdateOne_940(int *buffer, int length, int stereo, int is_buf_empty);
|
||||||
|
|
||||||
int YM2612Write_940(unsigned int a, unsigned int v);
|
int YM2612Write_940(unsigned int a, unsigned int v, int scanline);
|
||||||
unsigned char YM2612Read_940(void);
|
unsigned char YM2612Read_940(void);
|
||||||
|
|
||||||
int YM2612PicoTick_940(int n);
|
int YM2612PicoTick_940(int n);
|
||||||
|
|
|
@ -74,7 +74,7 @@ OBJS += ../../Pico/cd/Pico.o ../../Pico/cd/Memory.o ../../Pico/cd/Sek.o ../../Pi
|
||||||
../../Pico/cd/Area.o ../../Pico/cd/Misc.o ../../Pico/cd/pcm.o ../../Pico/cd/buffering.o
|
../../Pico/cd/Area.o ../../Pico/cd/Misc.o ../../Pico/cd/pcm.o ../../Pico/cd/buffering.o
|
||||||
endif
|
endif
|
||||||
# Pico - Pico
|
# Pico - Pico
|
||||||
OBJS += ../../Pico/Pico/Pico.o ../../Pico/Pico/Memory.o
|
OBJS += ../../Pico/Pico/Pico.o ../../Pico/Pico/Memory.o ../../Pico/Pico/xpcm.o
|
||||||
# Pico - carthw
|
# Pico - carthw
|
||||||
OBJS += ../../Pico/carthw/carthw.o ../../Pico/carthw/svp/svp.o ../../Pico/carthw/svp/Memory.o \
|
OBJS += ../../Pico/carthw/carthw.o ../../Pico/carthw/svp/svp.o ../../Pico/carthw/svp/Memory.o \
|
||||||
../../Pico/carthw/svp/ssp16.o ../../Pico/carthw/svp/compiler.o ../../Pico/carthw/svp/stub_arm.o
|
../../Pico/carthw/svp/ssp16.o ../../Pico/carthw/svp/compiler.o ../../Pico/carthw/svp/stub_arm.o
|
||||||
|
@ -203,6 +203,8 @@ up: PicoDrive.gpe
|
||||||
../../cpu/musashi/m68kops.c :
|
../../cpu/musashi/m68kops.c :
|
||||||
@make -C ../../cpu/musashi
|
@make -C ../../cpu/musashi
|
||||||
|
|
||||||
|
../../Pico/Pico.o : ../../Pico/PicoFrameHints.c ../../Pico/PicoInt.h
|
||||||
|
../../Pico/Memory.o Pico/cd/Memory.o : ../../Pico/MemoryCmn.c ../../Pico/PicoInt.h
|
||||||
|
|
||||||
# build helix libs
|
# build helix libs
|
||||||
../common/helix/helix_mp3.a:
|
../common/helix/helix_mp3.a:
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#define VERSION "1.40c"
|
#define VERSION "1.45"
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,6 @@
|
||||||
#include "../../Pico/PicoInt.h"
|
#include "../../Pico/PicoInt.h"
|
||||||
|
|
||||||
|
|
||||||
static YM2612 ym2612;
|
|
||||||
|
|
||||||
YM2612 *ym2612_940 = &ym2612;
|
|
||||||
|
|
||||||
// static _940_data_t shared_data_;
|
// static _940_data_t shared_data_;
|
||||||
static _940_ctl_t shared_ctl_;
|
static _940_ctl_t shared_ctl_;
|
||||||
// static _940_data_t *shared_data = &shared_data_;
|
// static _940_data_t *shared_data = &shared_data_;
|
||||||
|
@ -33,7 +29,7 @@ unsigned char *mp3_mem = 0;
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
|
|
||||||
|
|
||||||
int YM2612Write_940(unsigned int a, unsigned int v)
|
int YM2612Write_940(unsigned int a, unsigned int v, int scanline)
|
||||||
{
|
{
|
||||||
YM2612Write_(a, v);
|
YM2612Write_(a, v);
|
||||||
|
|
||||||
|
|
|
@ -99,8 +99,8 @@ mkdirs:
|
||||||
mkdir -p $(DIRS)
|
mkdir -p $(DIRS)
|
||||||
|
|
||||||
Pico/carthw/svp/compiler.o : ../../Pico/carthw/svp/gen_arm.c
|
Pico/carthw/svp/compiler.o : ../../Pico/carthw/svp/gen_arm.c
|
||||||
|
Pico/Pico.o : ../../Pico/PicoFrameHints.c ../../Pico/PicoInt.h
|
||||||
Pico/Pico.o : ../../Pico/PicoFrameHints.c
|
Pico/Memory.o Pico/cd/Memory.o : ../../Pico/MemoryCmn.c ../../Pico/PicoInt.h
|
||||||
|
|
||||||
../../cpu/musashi/m68kops.c :
|
../../cpu/musashi/m68kops.c :
|
||||||
@make -C ../../cpu/musashi
|
@make -C ../../cpu/musashi
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue