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
|
||||
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
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
|
||||
|
||||
|
@ -696,7 +858,7 @@ PICO_INTERNAL unsigned char z80_read(unsigned short a)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -710,7 +872,10 @@ PICO_INTERNAL unsigned char z80_read(unsigned short a)
|
|||
if (PicoAHW & PAHW_MCD)
|
||||
ret = PicoReadM68k8(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;
|
||||
}
|
||||
|
||||
|
@ -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(PicoOpt&POPT_EN_FM) emustatus|=YM2612Write(a, data) & 1;
|
||||
if(PicoOpt&POPT_EN_FM) emustatus|=ym2612_write_local(a, data, 1) & 1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -879,27 +879,21 @@ m_write8_z80_not_ram:
|
|||
and r2, r0, #0x6000
|
||||
cmp r2, #0x4000
|
||||
bne m_write8_z80_not_ym2612
|
||||
ldr r2, =PicoOpt
|
||||
ldr r3, =PicoOpt
|
||||
and r0, r0, #3
|
||||
ldr r2, [r2]
|
||||
tst r2, #1
|
||||
ldr r3, [r3]
|
||||
mov r2, #0 @ is_from_z80 = 0
|
||||
tst r3, #1
|
||||
bxeq lr
|
||||
stmfd sp!,{lr}
|
||||
.if EXTERNAL_YM2612
|
||||
tst r2, #0x200
|
||||
ldreq r2, =YM2612Write_
|
||||
ldrne r2, =YM2612Write_940
|
||||
mov lr, pc
|
||||
bx r2
|
||||
.else
|
||||
bl YM2612Write_
|
||||
.endif
|
||||
and r1, r1, #0xff
|
||||
bl ym2612_write_local
|
||||
ldr r2, =emustatus
|
||||
ldmfd sp!,{lr}
|
||||
ldr r1, [r2]
|
||||
and r0, r0, #1
|
||||
orr r1, r0, r1
|
||||
str r1, [r2] @ emustatus|=YM2612Write(a&3, d);
|
||||
str r1, [r2] @ emustatus|=ym2612_write_local(a&3, d);
|
||||
bx lr
|
||||
|
||||
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:
|
||||
ldr r3, =(Pico+0x22208) @ Pico.m
|
||||
ldrh r2, [r3, #0x0a]
|
||||
mov r1, r1, lsr #8
|
||||
mov r1, r1, lsl #8
|
||||
orr r2, r1, r2, lsr #1
|
||||
bic r2, r2, #0xfe00
|
||||
strh r2, [r3, #0x0a]
|
||||
|
@ -932,7 +926,7 @@ m_write8_not_z80:
|
|||
bne OtherWrite8
|
||||
m_write8_psg:
|
||||
ldr r2, =PicoOpt
|
||||
mov r0, r1
|
||||
and r0, r1, #0xff
|
||||
ldr r2, [r2]
|
||||
tst r2, #2
|
||||
bxeq lr
|
||||
|
|
|
@ -69,25 +69,14 @@ void z80WriteBusReq(u32 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)
|
||||
{
|
||||
int lineCycles;
|
||||
z80stopCycle = SekCyclesDone();
|
||||
if ((Pico.m.z80Run&2) && Pico.m.scanline != -1)
|
||||
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);
|
||||
}
|
||||
PicoSyncZ80(z80stopCycle);
|
||||
}
|
||||
} else {
|
||||
if (!Pico.m.z80Run)
|
||||
z80startCycle = SekCyclesDone();
|
||||
else
|
||||
d|=Pico.m.z80Run;
|
||||
z80_cycle_cnt = cycles_68k_to_z80(SekCyclesDone());
|
||||
}
|
||||
}
|
||||
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 (!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)d;
|
||||
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?
|
||||
}
|
||||
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
|
||||
#endif
|
||||
if (a==0xa11100) { z80WriteBusReq(d); return; }
|
||||
|
@ -185,6 +174,7 @@ void OtherWrite8(u32 a,u32 d)
|
|||
Pico.m.z80_reset = 0;
|
||||
YM2612ResetChip();
|
||||
z80_reset();
|
||||
timers_reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -204,7 +194,7 @@ void OtherWrite8(u32 a,u32 d)
|
|||
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&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&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 (!(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;
|
||||
}
|
||||
if (a==0xa11200) {
|
||||
|
@ -229,6 +219,7 @@ void OtherWrite16(u32 a,u32 d)
|
|||
Pico.m.z80_reset = 0;
|
||||
YM2612ResetChip();
|
||||
z80_reset();
|
||||
timers_reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -256,6 +247,6 @@ void OtherWrite16(u32 a,u32 d)
|
|||
}
|
||||
#endif
|
||||
|
||||
PicoWrite16Hook(a, d, 16);
|
||||
PicoWrite16Hook(a, d&0xffff, 16);
|
||||
}
|
||||
|
||||
|
|
128
Pico/Pico.c
128
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 PicoRegionOverride = 0; // override the region detection 0: Auto, 1: Japan NTSC, 2: Japan PAL, 4: US, 8: Europe
|
||||
int PicoAutoRgnOrder = 0;
|
||||
int z80startCycle, z80stopCycle; // in 68k cycles
|
||||
struct PicoSRAM SRam = {0,};
|
||||
|
||||
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"
|
||||
|
||||
// helper z80 runner. Runs only if z80 is enabled at this point
|
||||
// (z80WriteBusReq will handle the rest)
|
||||
static void PicoRunZ80Simple(int line_from, int line_to)
|
||||
|
||||
int z80stopCycle;
|
||||
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 line_sample = Pico.m.pal ? 68 : 93;
|
||||
int cnt;
|
||||
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;
|
||||
else {
|
||||
extern const unsigned short vcounts[];
|
||||
if (z80startCycle) {
|
||||
line = vcounts[z80startCycle>>8];
|
||||
if (line > line_from)
|
||||
line_from_r = line;
|
||||
}
|
||||
z80startCycle = SekCyclesDone();
|
||||
elprintf(EL_ANOMALY, "z80 sync %i (%i|%i -> %i|%i)", cnt, z80_cycle_cnt, z80_cycle_cnt / 228,
|
||||
z80_cycle_aim, z80_cycle_aim / 228);
|
||||
|
||||
if (cnt > 0)
|
||||
z80_cycle_cnt += z80_run(cnt);
|
||||
}
|
||||
|
||||
if (PicoOpt&POPT_EN_FM) {
|
||||
// we have ym2612 enabled, so we have to run Z80 in lines, so we could update DAC and timers
|
||||
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
|
||||
static int PicoFrameSimple(void)
|
||||
{
|
||||
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;
|
||||
|
||||
// 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
|
||||
cycles_68k_block = 7329; // (488*240+148)/16.0, -4
|
||||
cycles_68k_vblock = 11640; // (72*488-148-68)/3.0, 0
|
||||
cycles_68k_block = 7308;
|
||||
cycles_68k_vblock = 11694;
|
||||
lines_step = 15;
|
||||
} else {
|
||||
cycles_68k_block = 6841; // (488*224+148)/16.0, -4
|
||||
cycles_68k_vblock = 10682; // (88*488-148-68)/4.0, 0
|
||||
cycles_68k_block = 6821;
|
||||
cycles_68k_vblock = 10719;
|
||||
lines_step = 14;
|
||||
}
|
||||
line_last = 312-1;
|
||||
} else {
|
||||
// M68k cycles/frame: 127840.71
|
||||
cycles_68k_block = 6841; // (488*224+148)/16.0, -4
|
||||
cycles_68k_vblock = 9164; // (38*488-148-68)/2.0, 0
|
||||
lines_step = 14;
|
||||
line_last = 262-1;
|
||||
}
|
||||
|
||||
// a hack for VR, to get it running in fast mode
|
||||
|
@ -380,9 +371,11 @@ static int PicoFrameSimple(void)
|
|||
Pico.video.status|=0x200;
|
||||
|
||||
Pico.m.scanline=-1;
|
||||
z80startCycle=0;
|
||||
PsndDacLine = 0;
|
||||
|
||||
SekCyclesReset();
|
||||
z80_resetCycles();
|
||||
timers_cycle();
|
||||
|
||||
// 6 button pad: let's just say it timed out now
|
||||
Pico.m.padTHPhase[0]=Pico.m.padTHPhase[1]=0;
|
||||
|
@ -395,24 +388,15 @@ static int PicoFrameSimple(void)
|
|||
{
|
||||
if (CheckIdle()) break;
|
||||
|
||||
lines += lines_step;
|
||||
SekRunM68k(cycles_68k_block);
|
||||
|
||||
PicoRunZ80Simple(line, lines);
|
||||
if (PicoLineHook) PicoLineHook(lines_step);
|
||||
line=lines;
|
||||
}
|
||||
|
||||
// run Z80 for remaining sections
|
||||
// do remaining sections without 68k
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -446,33 +430,37 @@ static int PicoFrameSimple(void)
|
|||
#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
|
||||
pv->pending_ints|=0x20;
|
||||
pv->status|=8; // go into vblank
|
||||
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 ----
|
||||
// fix line counts
|
||||
if(Pico.m.pal) {
|
||||
if(pv->reg[1]&8) { // 240 lines
|
||||
lines = line = 240;
|
||||
sects = 3;
|
||||
lines_step = 24;
|
||||
} else {
|
||||
lines = line = 224;
|
||||
sects = 4;
|
||||
lines_step = 22;
|
||||
}
|
||||
} else {
|
||||
lines = line = 224;
|
||||
sects = 2;
|
||||
lines_step = 19;
|
||||
}
|
||||
|
@ -481,27 +469,28 @@ static int PicoFrameSimple(void)
|
|||
if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80))
|
||||
z80_int();
|
||||
|
||||
while (sects)
|
||||
while (1)
|
||||
{
|
||||
lines += lines_step;
|
||||
|
||||
SekRunM68k(cycles_68k_vblock);
|
||||
|
||||
PicoRunZ80Simple(line, lines);
|
||||
if (PicoLineHook) PicoLineHook(lines_step);
|
||||
line=lines;
|
||||
|
||||
sects--;
|
||||
if (sects && CheckIdle()) break;
|
||||
if (sects == 0) break;
|
||||
if (CheckIdle()) break;
|
||||
}
|
||||
|
||||
// run Z80 for remaining sections
|
||||
if (sects) {
|
||||
lines += sects*lines_step;
|
||||
PicoRunZ80Simple(line, lines);
|
||||
SekCycleCnt += sects * cycles_68k_vblock;
|
||||
SekCycleAim += sects * cycles_68k_vblock;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -556,7 +545,6 @@ void PicoGetInternal(pint_t which, pint_ret_t *r)
|
|||
void (*PicoMessage)(const char *msg)=NULL;
|
||||
|
||||
#if 1 // defined(__DEBUG_PRINT)
|
||||
// tmp debug: dump some stuff
|
||||
#define bit(r, x) ((r>>x)&1)
|
||||
void z80_debug(char *dstr);
|
||||
char *debugString(void)
|
||||
|
|
|
@ -16,29 +16,10 @@
|
|||
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
|
||||
#ifndef PICO_CD
|
||||
#define CPUS_RUN(m68k_cycles,z80_cycles,s68k_cycles) \
|
||||
SekRunM68k(m68k_cycles); \
|
||||
Z80_RUN(z80_cycles);
|
||||
SekRunM68k(m68k_cycles);
|
||||
#else
|
||||
#define CPUS_RUN(m68k_cycles,z80_cycles,s68k_cycles) \
|
||||
{ \
|
||||
|
@ -49,7 +30,6 @@
|
|||
if ((Pico_mcd->m.busreq&3) == 1) /* no busreq/no reset */ \
|
||||
SekRunS68k(s68k_cycles); \
|
||||
} \
|
||||
Z80_RUN(z80_cycles); \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -57,7 +37,7 @@
|
|||
static int PicoFrameHints(void)
|
||||
{
|
||||
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
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
if(pv->reg[1]&8) lines_vis = 240;
|
||||
} 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;
|
||||
}
|
||||
|
||||
SekCyclesReset();
|
||||
z80_resetCycles();
|
||||
#ifdef PICO_CD
|
||||
SekCyclesResetS68k();
|
||||
#endif
|
||||
timers_cycle();
|
||||
PsndDacLine = 0;
|
||||
|
||||
pv->status&=~0x88; // clear V-Int, come out of vblank
|
||||
|
||||
|
@ -93,8 +72,6 @@ static int PicoFrameHints(void)
|
|||
//dprintf("-hint: %i", hint);
|
||||
|
||||
// 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);
|
||||
|
||||
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
|
||||
// get samples from sound chips
|
||||
if (y == 32 && PsndOut)
|
||||
emustatus &= ~1;
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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 last H-int and V-int (Golden Axe 3)
|
||||
SekRunM68k(CYCLES_M68K_VINT_LAG);
|
||||
|
||||
if (pv->reg[1]&0x20) {
|
||||
elprintf(EL_INTS, "vint: @ %06x [%i]", SekPc, SekCycleCnt);
|
||||
SekInterrupt(6);
|
||||
}
|
||||
if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80)) {
|
||||
PicoSyncZ80(SekCycleCnt);
|
||||
elprintf(EL_INTS, "zint");
|
||||
z80_int();
|
||||
}
|
||||
|
||||
if (PicoOpt&POPT_EN_FM)
|
||||
Psnd_timers_and_dac(y);
|
||||
|
||||
// get samples from sound chips
|
||||
#ifndef PICO_CD
|
||||
if (y == 224)
|
||||
#endif
|
||||
if (PsndOut)
|
||||
{
|
||||
if (ym2612.dacen && PsndDacLine <= y)
|
||||
PsndDoDAC(y);
|
||||
getSamples(y);
|
||||
}
|
||||
|
||||
// Run scanline:
|
||||
if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
|
||||
|
@ -247,9 +230,6 @@ static int PicoFrameHints(void)
|
|||
check_cd_dma();
|
||||
#endif
|
||||
|
||||
if (PicoOpt&POPT_EN_FM)
|
||||
Psnd_timers_and_dac(y);
|
||||
|
||||
// Run scanline:
|
||||
if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
|
||||
CPUS_RUN(CYCLES_M68K_LINE, CYCLES_Z80_LINE, CYCLES_S68K_LINE);
|
||||
|
@ -261,6 +241,12 @@ static int PicoFrameHints(void)
|
|||
#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;
|
||||
}
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ extern unsigned int SekCycleCntT; // total cycle counter, updated once per frame
|
|||
SekCycleAim=0; \
|
||||
}
|
||||
#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 SekEndRun(after) { \
|
||||
|
@ -174,10 +174,9 @@ extern int dbg_irq_level;
|
|||
#if defined(_USE_MZ80)
|
||||
#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_int() mz80int(0)
|
||||
#define z80_resetCycles() mz80GetElapsedTicks(1)
|
||||
|
||||
#elif defined(_USE_DRZ80)
|
||||
#include "../cpu/DrZ80/drz80.h"
|
||||
|
@ -190,7 +189,8 @@ extern struct DrZ80 drZ80;
|
|||
drZ80.z80irqvector = 0xFF; /* default IRQ vector RST opcode */ \
|
||||
drZ80.Z80_IRQ = 1; \
|
||||
}
|
||||
#define z80_resetCycles()
|
||||
|
||||
#define z80_cyclesLeft drZ80.cycles
|
||||
|
||||
#elif defined(_USE_CZ80)
|
||||
#include "../cpu/cz80/cz80.h"
|
||||
|
@ -198,17 +198,31 @@ extern struct DrZ80 drZ80;
|
|||
#define z80_run(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_resetCycles()
|
||||
|
||||
#define z80_cyclesLeft (CZ80.ICount - CZ80.ExtraCycles)
|
||||
|
||||
#else
|
||||
|
||||
#define z80_run(cycles) (cycles)
|
||||
#define z80_run_nr(cycles)
|
||||
#define z80_int()
|
||||
#define z80_resetCycles()
|
||||
|
||||
#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
|
||||
|
@ -405,6 +419,7 @@ PICO_INTERNAL unsigned short z80_read16(unsigned short a);
|
|||
#else
|
||||
PICO_INTERNAL_ASM void z80_write(unsigned int a, unsigned char data);
|
||||
#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 void (*PicoWrite8Hook) (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 PicoSRAM SRam;
|
||||
extern int emustatus;
|
||||
extern int z80startCycle, z80stopCycle; // in 68k cycles
|
||||
extern void (*PicoResetHook)(void);
|
||||
extern void (*PicoLineHook)(int count);
|
||||
PICO_INTERNAL int CheckDMA(void);
|
||||
PICO_INTERNAL void PicoDetectRegion(void);
|
||||
PICO_INTERNAL void PicoSyncZ80(int m68k_cycles_done);
|
||||
|
||||
// cd/Pico.c
|
||||
PICO_INTERNAL int PicoInitMCD(void);
|
||||
|
@ -459,6 +474,13 @@ PICO_INTERNAL void cdda_start_play();
|
|||
extern short cdda_out_buffer[2*1152];
|
||||
extern int PsndLen_exc_cnt;
|
||||
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
|
||||
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
|
||||
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 void PsndClear(void);
|
||||
// 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_reset(void);
|
||||
PICO_INTERNAL void z80_exit(void);
|
||||
|
||||
extern int PsndDacLine;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // 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];
|
||||
|
||||
// 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
|
||||
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_exc_add=0; // this is for non-integer sample counts per line, eg. 22050/60
|
||||
int PsndLen_exc_cnt=0;
|
||||
int PsndDacLine=0;
|
||||
short *PsndOut=NULL; // PCM data buffer
|
||||
|
||||
// timers
|
||||
int timer_a_next_oflow, timer_a_step; // in z80 cycles
|
||||
//int
|
||||
|
||||
// sn76496
|
||||
extern int *sn76496_regs;
|
||||
|
||||
|
@ -83,6 +88,8 @@ static void dac_recalculate(void)
|
|||
if (PsndLen_exc_add) 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++) {
|
||||
// printf("%03i : %03i : %i\n", i, dac_info[i]>>4, 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
|
||||
ym2612_regs = YM2612GetRegs();
|
||||
memset(ym2612_regs, 0, 0x200+4);
|
||||
z80startCycle = z80stopCycle = 0;
|
||||
timers_reset();
|
||||
|
||||
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 Psnd_timers_and_dac(int raster)
|
||||
PICO_INTERNAL void PsndDoDAC(int line_to)
|
||||
{
|
||||
int pos, len;
|
||||
int do_dac = PsndOut && (PicoOpt&POPT_EN_FM) && *ym2612_dacen;
|
||||
// int do_pcm = PsndOut && (PicoAHW&1) && (PicoOpt&0x400);
|
||||
int pos, pos1, len;
|
||||
int dout = ym2612.dacout;
|
||||
int line_from = PsndDacLine;
|
||||
|
||||
// Our raster lasts 63.61323/64.102564 microseconds (NTSC/PAL)
|
||||
YM2612PicoTick(1);
|
||||
PsndDacLine = line_to + 1;
|
||||
|
||||
if (!do_dac /*&& !do_pcm*/) return;
|
||||
|
||||
pos=dac_info[raster], len=pos&0xf;
|
||||
pos =dac_info[line_from]>>4;
|
||||
pos1=dac_info[line_to];
|
||||
len = ((pos1>>4)-pos) + (pos1&0xf);
|
||||
if (!len) return;
|
||||
|
||||
pos>>=4;
|
||||
|
||||
if (do_dac)
|
||||
{
|
||||
short *d = PsndOut + pos*2;
|
||||
int dout = *ym2612_dacout;
|
||||
if (PicoOpt & POPT_EN_STEREO) {
|
||||
// some manual loop unrolling here :)
|
||||
d[0] = dout;
|
||||
if (len > 1) {
|
||||
d[2] = dout;
|
||||
if (len > 2)
|
||||
d[4] = dout;
|
||||
}
|
||||
short *d = PsndOut + pos*2;
|
||||
for (; len > 0; len--, d+=2) *d = dout;
|
||||
} else {
|
||||
short *d = PsndOut + pos;
|
||||
d[0] = dout;
|
||||
if (len > 1) {
|
||||
d[1] = dout;
|
||||
if (len > 2)
|
||||
d[2] = dout;
|
||||
}
|
||||
}
|
||||
for (; len > 0; len--, d++) *d = dout;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
|
@ -116,7 +116,7 @@
|
|||
#ifndef EXTERNAL_YM2612
|
||||
#include <stdlib.h>
|
||||
// let it be 1 global to simplify things
|
||||
static YM2612 ym2612;
|
||||
YM2612 ym2612;
|
||||
|
||||
#else
|
||||
extern YM2612 *ym2612_940;
|
||||
|
@ -1584,11 +1584,8 @@ static int OPNWriteReg(int r, int v)
|
|||
/* YM2612 local section */
|
||||
/*******************************************************************************/
|
||||
|
||||
int *ym2612_dacen;
|
||||
INT32 *ym2612_dacout;
|
||||
FM_ST *ym2612_st;
|
||||
|
||||
|
||||
/* Generate samples for YM2612 */
|
||||
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)
|
||||
{
|
||||
// notaz
|
||||
ym2612_dacen = &ym2612.dacen;
|
||||
ym2612_dacout = &ym2612.dacout;
|
||||
ym2612_st = &ym2612.OPN.ST;
|
||||
|
||||
memset(&ym2612, 0, sizeof(ym2612));
|
||||
|
@ -1728,9 +1723,6 @@ int YM2612Write_(unsigned int a, unsigned int v)
|
|||
}
|
||||
|
||||
addr = ym2612.OPN.ST.address;
|
||||
#ifndef EXTERNAL_YM2612
|
||||
ym2612.REGS[addr] = v;
|
||||
#endif
|
||||
|
||||
switch( addr & 0xf0 )
|
||||
{
|
||||
|
@ -1747,6 +1739,7 @@ int YM2612Write_(unsigned int a, unsigned int v)
|
|||
ym2612.OPN.lfo_inc = 0;
|
||||
}
|
||||
break;
|
||||
#if 0 // handled elsewhere
|
||||
case 0x24: { // timer A High 8
|
||||
int TAnew = (ym2612.OPN.ST.TA & 0x03)|(((int)v)<<2);
|
||||
if(ym2612.OPN.ST.TA != TAnew) {
|
||||
|
@ -1781,6 +1774,7 @@ int YM2612Write_(unsigned int a, unsigned int v)
|
|||
set_timers( v );
|
||||
ret=0;
|
||||
break;
|
||||
#endif
|
||||
case 0x28: /* key on / off */
|
||||
{
|
||||
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);
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
case 0x2a: /* DAC data (YM2612) */
|
||||
ym2612.dacout = ((int)v - 0x80) << 6; /* level unknown (notaz: 8 seems to be too much) */
|
||||
ret=0;
|
||||
|
@ -1803,6 +1798,7 @@ int YM2612Write_(unsigned int a, unsigned int v)
|
|||
ym2612.dacen = v & 0x80;
|
||||
ret=0;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1826,9 +1822,6 @@ int YM2612Write_(unsigned int a, unsigned int v)
|
|||
}
|
||||
|
||||
addr = ym2612.OPN.ST.address | 0x100;
|
||||
#ifndef EXTERNAL_YM2612
|
||||
ym2612.REGS[addr] = v;
|
||||
#endif
|
||||
|
||||
ret = OPNWriteReg(addr, v);
|
||||
break;
|
||||
|
|
|
@ -141,10 +141,10 @@ typedef struct
|
|||
} YM2612;
|
||||
#endif
|
||||
|
||||
extern int *ym2612_dacen;
|
||||
extern INT32 *ym2612_dacout;
|
||||
extern FM_ST *ym2612_st;
|
||||
|
||||
#ifndef EXTERNAL_YM2612
|
||||
extern YM2612 ym2612;
|
||||
#endif
|
||||
|
||||
#define YM2612Read() ym2612_st->status
|
||||
|
||||
|
@ -180,7 +180,6 @@ void *YM2612GetRegs(void);
|
|||
#define YM2612Init YM2612Init_
|
||||
#define YM2612ResetChip YM2612ResetChip_
|
||||
#define YM2612UpdateOne YM2612UpdateOne_
|
||||
#define YM2612Write YM2612Write_
|
||||
#define YM2612PicoStateLoad YM2612PicoStateLoad_
|
||||
#else
|
||||
/* GP2X specific */
|
||||
|
@ -197,8 +196,6 @@ extern int PicoOpt;
|
|||
#define YM2612UpdateOne(buffer,length,stereo,is_buf_empty) \
|
||||
(PicoOpt&0x200) ? YM2612UpdateOne_940(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() { \
|
||||
if (PicoOpt&0x200) YM2612PicoStateLoad_940(); \
|
||||
else YM2612PicoStateLoad_(); \
|
||||
|
|
|
@ -51,160 +51,64 @@ static FILE *loaded_mp3 = 0;
|
|||
}
|
||||
|
||||
/* 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 INT32 addr_A1; /* address line A1 */
|
||||
|
||||
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 */
|
||||
/* a = address */
|
||||
/* v = value */
|
||||
/* 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 */
|
||||
|
||||
v &= 0xff; /* adjust to 8 bit bus */
|
||||
a &= 3;
|
||||
|
||||
//printf("%05i:%03i: ym w ([%i] %02x)\n", Pico.m.frame_count, Pico.m.scanline, a, v);
|
||||
|
||||
switch (a) {
|
||||
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 */
|
||||
ST_address = v;
|
||||
addr_A1 = 0;
|
||||
/* don't send DAC or timer related address changes to 940 */
|
||||
if (!*addr_A1 && (v & 0xf0) == 0x20 &&
|
||||
(v == 0x24 || v == 0x25 || v == 0x26 || v == 0x2a))
|
||||
if (v == 0x24 || v == 0x25 || v == 0x26 || v == 0x2a)
|
||||
return 0;
|
||||
*addr_A1 = 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;
|
||||
}
|
||||
if (ST_address == 0x2b) upd = 0; /* DAC sel */
|
||||
break;
|
||||
|
||||
case 2: /* address port 1 */
|
||||
if (*addr_A1 && ST_address == v)
|
||||
if (addr_A1 == 1 && ST_address == v)
|
||||
return 0;
|
||||
ST_address = v;
|
||||
*addr_A1 = 1;
|
||||
addr_A1 = 1;
|
||||
upd = 0;
|
||||
break;
|
||||
|
||||
case 3: /* data port 1 */
|
||||
if (*addr_A1 != 1) {
|
||||
return 0; /* verified on real YM2608 */
|
||||
}
|
||||
|
||||
addr = ST_address | 0x100;
|
||||
REGS[addr] = v;
|
||||
break;
|
||||
}
|
||||
|
||||
//printf("ym pass\n");
|
||||
|
||||
if(currentConfig.EmuOpt & 4) {
|
||||
if (currentConfig.EmuOpt & 4)
|
||||
{
|
||||
UINT16 *writebuff = shared_ctl->writebuffsel ? shared_ctl->writebuff0 : shared_ctl->writebuff1;
|
||||
|
||||
/* 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;
|
||||
if (Pico.m.scanline > mid) {
|
||||
//printf("%05i:%03i: rapid ym\n", Pico.m.frame_count, Pico.m.scanline);
|
||||
if (scanline > mid) {
|
||||
//printf("%05i:%03i: rapid ym\n", Pico.m.frame_count, scanline);
|
||||
writebuff[writebuff_ptr++ & 0xffff] = 0xfffe;
|
||||
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)
|
||||
{
|
||||
int i, old_A1 = *addr_A1;
|
||||
UINT8 *REGS = YM2612GetRegs();
|
||||
|
||||
int i;
|
||||
|
||||
/* make sure JOB940_PICOSTATELOAD gets done before next JOB940_YM2612UPDATEONE */
|
||||
add_job_940(JOB940_PICOSTATELOAD);
|
||||
|
@ -282,32 +188,22 @@ void YM2612PicoStateLoad_940(void)
|
|||
|
||||
// feed all the registers and update internal state
|
||||
for(i = 0; i < 0x100; i++) {
|
||||
YM2612Write_940(0, i);
|
||||
YM2612Write_940(1, REGS[i]);
|
||||
YM2612Write_940(0, i, -1);
|
||||
YM2612Write_940(1, REGS[i], -1);
|
||||
}
|
||||
for(i = 0; i < 0x100; i++) {
|
||||
YM2612Write_940(2, i);
|
||||
YM2612Write_940(3, REGS[i|0x100]);
|
||||
YM2612Write_940(2, i, -1);
|
||||
YM2612Write_940(3, REGS[i|0x100], -1);
|
||||
}
|
||||
|
||||
*addr_A1 = old_A1;
|
||||
addr_A1 = *(INT32 *) (REGS + 0x200);
|
||||
}
|
||||
|
||||
|
||||
static void internal_reset(void)
|
||||
{
|
||||
writebuff_ptr = 0;
|
||||
ym2612_st->mode = 0;
|
||||
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;
|
||||
ST_address = addr_A1 = -1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -405,12 +301,6 @@ void YM2612Init_940(int baseclock, int rate)
|
|||
/* cause local ym2612 to init REGS */
|
||||
YM2612Init_(baseclock, rate);
|
||||
|
||||
REGS = YM2612GetRegs();
|
||||
addr_A1 = (INT32 *) (REGS + 0x200);
|
||||
|
||||
ym2612_dacen = &dacen;
|
||||
ym2612_dacout = &dacout;
|
||||
|
||||
internal_reset();
|
||||
|
||||
loaded_mp3 = 0;
|
||||
|
@ -440,6 +330,7 @@ void YM2612ResetChip_940(void)
|
|||
return;
|
||||
}
|
||||
|
||||
YM2612ResetChip_();
|
||||
internal_reset();
|
||||
|
||||
add_job_940(JOB940_YM2612RESETCHIP);
|
||||
|
|
|
@ -5,7 +5,7 @@ void YM2612Init_940(int baseclock, int rate);
|
|||
void YM2612ResetChip_940(void);
|
||||
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);
|
||||
|
||||
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
|
||||
endif
|
||||
# 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
|
||||
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
|
||||
|
@ -203,6 +203,8 @@ up: PicoDrive.gpe
|
|||
../../cpu/musashi/m68kops.c :
|
||||
@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
|
||||
../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"
|
||||
|
||||
|
||||
static YM2612 ym2612;
|
||||
|
||||
YM2612 *ym2612_940 = &ym2612;
|
||||
|
||||
// static _940_data_t shared_data_;
|
||||
static _940_ctl_t shared_ctl_;
|
||||
// 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);
|
||||
|
||||
|
|
|
@ -99,8 +99,8 @@ mkdirs:
|
|||
mkdir -p $(DIRS)
|
||||
|
||||
Pico/carthw/svp/compiler.o : ../../Pico/carthw/svp/gen_arm.c
|
||||
|
||||
Pico/Pico.o : ../../Pico/PicoFrameHints.c
|
||||
Pico/Pico.o : ../../Pico/PicoFrameHints.c ../../Pico/PicoInt.h
|
||||
Pico/Memory.o Pico/cd/Memory.o : ../../Pico/MemoryCmn.c ../../Pico/PicoInt.h
|
||||
|
||||
../../cpu/musashi/m68kops.c :
|
||||
@make -C ../../cpu/musashi
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue