static void bank_switch(int b) { unsigned int rs, bank; if (Pico.m.ncart_in) return; bank = b << 20; if ((Pico.m.sram_reg & SRR_MAPPED) && bank == SRam.start) { bank_map_handler(); return; } if (bank >= Pico.romsize) { elprintf(EL_32X|EL_ANOMALY, "missing bank @ %06x", bank); bank_map_handler(); return; } // 32X ROM (unbanked, XXX: consider mirroring?) rs = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK; rs -= bank; if (rs > 0x100000) rs = 0x100000; cpu68k_map_set(m68k_read8_map, 0x900000, 0x900000 + rs - 1, Pico.rom + bank, 0); cpu68k_map_set(m68k_read16_map, 0x900000, 0x900000 + rs - 1, Pico.rom + bank, 0); elprintf(EL_32X, "bank %06x-%06x -> %06x", 0x900000, 0x900000 + rs - 1, bank); #ifdef EMU_F68K // setup FAME fetchmap for (rs = 0x90; rs < 0xa0; rs++) PicoCpuFM68k.Fetch[rs] = (unsigned long)Pico.rom + bank - 0x900000; #endif }
void drc_cmn_init(void) { int ret = plat_mem_set_exec(tcache, sizeof(tcache)); elprintf(EL_STATUS, "drc_cmn_init: %p, %zd bytes: %d", tcache, sizeof(tcache), ret); #ifdef __arm__ if (PicoOpt & POPT_EN_DRC) { static int test_done; if (!test_done) { int *test_out = (void *)tcache; int (*testfunc)(void) = (void *)tcache; elprintf(EL_STATUS, "testing if we can run recompiled code.."); *test_out++ = 0xe3a000dd; // mov r0, 0xdd *test_out++ = 0xe12fff1e; // bx lr cache_flush_d_inval_i(tcache, test_out); // we'll usually crash on broken platforms or bad ports, // but do a value check too just in case ret = testfunc(); elprintf(EL_STATUS, "test %s.", ret == 0xdd ? "passed" : "failed"); test_done = 1; } } #endif }
void PicoWrite8_32x(u32 a, u32 d) { if ((a & 0xffc0) == 0x5100) { // a15100 u16 *r = Pico32x.regs; elprintf(EL_32X, "m68k 32x w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); a &= 0x3f; if (a == 1) { if ((d ^ r[0]) & d & P32XS_ADEN) { Pico32xStartup(); r[0] &= ~P32XS_nRES; // causes reset if specified by this write r[0] |= P32XS_ADEN; p32x_reg_write8(a, d); // forward for reset processing } return; } // allow only COMM for now if ((a & 0x30) == 0x20) { u8 *r8 = (u8 *)r; r8[a ^ 1] = d; } return; } elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); }
static void PicoWrite16_32x_on(u32 a, u32 d) { if ((a & 0xfc00) == 0x5000) elprintf(EL_32X, "m68k 32x w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc); if ((a & 0xffc0) == 0x5100) { // a15100 p32x_reg_write16(a, d); return; } if ((a & 0xfc00) != 0x5000) { if (PicoAHW & PAHW_MCD) PicoWrite16_mcd_io(a, d); else PicoWrite16_io(a, d); if (a == 0xa130f0) bank_switch(Pico32x.regs[4 / 2]); return; } if (!(Pico32x.regs[0] & P32XS_FM)) { if ((a & 0xfff0) == 0x5180) { // a15180 p32x_vdp_write16(a, d, NULL); // FIXME? return; } if ((a & 0xfe00) == 0x5200) { // a15200 Pico32xMem->pal[(a & 0x1ff) / 2] = d; Pico32x.dirty_pal = 1; return; } } elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc); }
static int SekIntAckM68K(int level) { if (level == 4) { Pico.video.pending_ints = 0; elprintf(EL_INTS, "hack: @ %06x [%i]", SekPc, SekCycleCnt); } else if(level == 6) { Pico.video.pending_ints &= ~0x20; elprintf(EL_INTS, "vack: @ %06x [%i]", SekPc, SekCycleCnt); } CPU_INT_LEVEL = 0; return M68K_INT_ACK_AUTOVECTOR; }
// interrupt acknowledgment static int SekIntAck(int level) { // try to emulate VDP's reaction to 68000 int ack if (level == 4) { Pico.video.pending_ints = 0; elprintf(EL_INTS, "hack: @ %06x [%i]", SekPc, SekCycleCnt); } else if(level == 6) { Pico.video.pending_ints &= ~0x20; elprintf(EL_INTS, "vack: @ %06x [%i]", SekPc, SekCycleCnt); } PicoCpuCM68k.irq = 0; return CYCLONE_INT_ACK_AUTOVECTOR; }
static void SekIntAckF68K(unsigned level) { if (level == 4) { Pico.video.pending_ints = 0; elprintf(EL_INTS, "hack: @ %06x [%i]", SekPc, SekCyclesDone()); } else if(level == 6) { Pico.video.pending_ints &= ~0x20; elprintf(EL_INTS, "vack: @ %06x [%i]", SekPc, SekCyclesDone()); } PicoCpuFM68k.interrupts[0] = 0; }
static void PicoWrite16_cart(u32 a, u32 d) { elprintf(EL_UIO, "m68k w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc); a &= 0xfffff; m68k_write16(a, d); }
// 0-4, 13 static u32 read_unknown(void) { #ifdef LOG_SVP elprintf(EL_ANOMALY|EL_SVP, "ssp FIXME: unknown read @ %04x", GET_PPC_OFFS()); #endif return 0; }
PICO_INTERNAL int Open_Tray_CDD_cD(void) { CHECK_TRAY_OPEN Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read elprintf(EL_STATUS, "tray open\n"); Unload_ISO(); CD_Present = 0; if (PicoMCDopenTray != NULL) PicoMCDopenTray(); Pico_mcd->scd.Status_CDD = TRAY_OPEN; Pico_mcd->cdd.Status = 0x0E00; Pico_mcd->cdd.Minute = 0; Pico_mcd->cdd.Seconde = 0; Pico_mcd->cdd.Frame = 0; Pico_mcd->cdd.Ext = 0; Pico_mcd->scd.CDD_Complete = 1; return 0; }
static int m68k_poll_detect(u32 a, u32 cycles, u32 flags) { int ret = 0; if (a - 2 <= m68k_poll.addr && m68k_poll.addr <= a + 2 && cycles - m68k_poll.cycles <= 64 && !SekNotPolling) { if (m68k_poll.cnt++ > POLL_THRESHOLD) { if (!(Pico32x.emu_flags & flags)) { elprintf(EL_32X, "m68k poll addr %08x, cyc %u", a, cycles - m68k_poll.cycles); ret = 1; } Pico32x.emu_flags |= flags; } } else { m68k_poll.cnt = 0; m68k_poll.addr = a; SekNotPolling = 0; } m68k_poll.cycles = cycles; return ret; }
unsigned int p32x_pwm_read16(unsigned int a, SH2 *sh2, unsigned int m68k_cycles) { unsigned int d = 0; consume_fifo(sh2, m68k_cycles); a &= 0x0e; switch (a) { case 0: // control case 2: // cycle d = Pico32x.regs[(0x30 + a) / 2]; break; case 4: // L ch if (Pico32x.pwm_p[0] == 3) d |= P32XP_FULL; else if (Pico32x.pwm_p[0] == 0) d |= P32XP_EMPTY; break; case 6: // R ch case 8: // MONO if (Pico32x.pwm_p[1] == 3) d |= P32XP_FULL; else if (Pico32x.pwm_p[1] == 0) d |= P32XP_EMPTY; break; } elprintf(EL_PWM, "pwm: %u: r16 %02x %04x (p %d %d)", m68k_cycles, a, d, Pico32x.pwm_p[0], Pico32x.pwm_p[1]); return d; }
static void p32x_vdp_write8(u32 a, u32 d) { u16 *r = Pico32x.vdp_regs; a &= 0x0f; // TODO: verify what's writeable switch (a) { case 0x01: // priority inversion is handled in palette if ((r[0] ^ d) & P32XV_PRI) Pico32x.dirty_pal = 1; r[0] = (r[0] & P32XV_nPAL) | (d & 0xff); break; case 0x03: // shift (for pp mode) r[2 / 2] = d & 1; break; case 0x05: // fill len r[4 / 2] = d & 0xff; break; case 0x0b: d &= 1; Pico32x.pending_fb = d; // if we are blanking and FS bit is changing if (((r[0x0a/2] & P32XV_VBLK) || (r[0] & P32XV_Mx) == 0) && ((r[0x0a/2] ^ d) & P32XV_FS)) { r[0x0a/2] ^= P32XV_FS; Pico32xSwapDRAM(d ^ 1); elprintf(EL_32X, "VDP FS: %d", r[0x0a/2] & P32XV_FS); } break; } }
// 4 static void write_ST(u32 d) { //if ((rST ^ d) & 0x0007) elprintf(EL_SVP, "ssp RPL %i -> %i @ %04x", rST&7, d&7, GET_PPC_OFFS()); #ifdef LOG_SVP if ((rST ^ d) & 0x0f98) elprintf(EL_SVP|EL_ANOMALY, "ssp FIXME ST %04x -> %04x @ %04x", rST, d, GET_PPC_OFFS()); #endif rST = d; }
void PicoCDBufferFree(void) { if (cd_buffer) { free(cd_buffer); cd_buffer = NULL; } if (reads) elprintf(EL_STATUS, "CD buffer hits: %i/%i (%i%%)\n", hits, reads, hits * 100 / reads); }
static void PicoWrite16_bank(u32 a, u32 d) { if (!(Pico.m.sram_reg & SRR_MAPPED)) elprintf(EL_UIO, "m68k w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc); a = (Pico32x.regs[4 / 2] << 20) | (a & 0xfffff); m68k_write16(a, d); }
// hint vector is writeable static void PicoWrite8_hint(u32 a, u32 d) { if ((a & 0xfffc) == 0x0070) { Pico32xMem->m68k_rom[a ^ 1] = d; return; } elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); }
void p32x_m68k_poll_event(u32 flags) { if (Pico32x.emu_flags & flags) { elprintf(EL_32X, "m68k poll %02x -> %02x", Pico32x.emu_flags, Pico32x.emu_flags & ~flags); Pico32x.emu_flags &= ~flags; SekSetStop(0); } m68k_poll.addr = m68k_poll.cnt = 0; }
// after ADEN static u32 PicoRead8_32x_on(u32 a) { u32 d = 0; if ((a & 0xffc0) == 0x5100) { // a15100 d = p32x_reg_read16(a); goto out_16to8; } if ((a & 0xfc00) != 0x5000) { if (PicoAHW & PAHW_MCD) return PicoRead8_mcd_io(a); else return PicoRead8_io(a); } if ((a & 0xfff0) == 0x5180) { // a15180 d = p32x_vdp_read16(a); goto out_16to8; } if ((a & 0xfe00) == 0x5200) { // a15200 d = Pico32xMem->pal[(a & 0x1ff) / 2]; goto out_16to8; } if ((a & 0xfffc) == 0x30ec) { // a130ec d = str_mars[a & 3]; goto out; } elprintf(EL_UIO, "m68k unmapped r8 [%06x] @%06x", a, SekPc); return d; out_16to8: if (a & 1) d &= 0xff; else d >>= 8; out: elprintf(EL_32X, "m68k 32x r8 [%06x] %02x @%06x", a, d, SekPc); return d; }
static void PicoWrite16_hint(u32 a, u32 d) { if ((a & 0xfffc) == 0x0070) { ((u16 *)Pico32xMem->m68k_rom)[a/2] = d; return; } elprintf(EL_UIO, "m68k unmapped w16 [%06x] %04x @%06x", a, d & 0xffff, SekPc); }
static void write_STACK(u32 d) { if (rSTACK >= 6) { #ifdef LOG_SVP elprintf(EL_ANOMALY|EL_SVP, "ssp FIXME: stack overflow! (%i) @ %04x", rSTACK, GET_PPC_OFFS()); #endif rSTACK = 0; } ssp->stack[rSTACK++] = d; }
// 5 static u32 read_STACK(void) { --rSTACK; if ((short)rSTACK < 0) { rSTACK = 5; #ifdef LOG_SVP elprintf(EL_ANOMALY|EL_SVP, "ssp FIXME: stack underflow! (%i) @ %04x", rSTACK, GET_PPC_OFFS()); #endif } return ssp->stack[rSTACK]; }
u32 PicoRead16_32x(u32 a) { u32 d = 0; if ((a & 0xffc0) == 0x5100) { // a15100 d = Pico32x.regs[(a & 0x3f) / 2]; goto out; } if ((a & 0xfffc) == 0x30ec) { // a130ec d = !(a & 2) ? ('M'<<8)|'A' : ('R'<<8)|'S'; goto out; } elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc); return d; out: elprintf(EL_32X, "m68k 32x r16 [%06x] %04x @%06x", a, d, SekPc); return d; }
static int SekUnrecognizedOpcode() { unsigned int pc; pc = SekPc; elprintf(EL_ANOMALY, "Unrecognized Opcode @ %06x", pc); // see if we are still in a mapped region pc &= 0x00ffffff; if (map_flag_set(m68k_read16_map[pc >> M68K_MEM_SHIFT])) { elprintf(EL_STATUS|EL_ANOMALY, "m68k crash @%06x", pc); PicoCpuCM68k.cycles = 0; PicoCpuCM68k.state_flags |= 1; return 1; } #ifdef EMU_M68K // debugging cyclone { extern int have_illegal; have_illegal = 1; } #endif return 0; }
static void z80_md_bank_write_32x(unsigned int a, unsigned char d) { unsigned int addr68k; addr68k = Pico.m.z80_bank68k << 15; addr68k += a & 0x7fff; if ((addr68k & 0xfff000) == 0xa15000) Pico32x.emu_flags |= P32XF_Z80_32X_IO; elprintf(EL_Z80BNK, "z80->68k w8 [%06x] %02x", addr68k, d); m68k_write8(addr68k, d); }
static int do_ack(int level) { struct PicoVideo *pv = &Pico.video; elprintf(EL_INTS, "%cack: @ %06x [%u], p=%02x", level == 6 ? 'v' : 'h', SekPc, SekCyclesDone(), pv->pending_ints); // the VDP doesn't look at the 68k level if (pv->pending_ints & pv->reg[1] & 0x20) { pv->pending_ints &= ~0x20; pv->status &= ~SR_F; return (pv->reg[0] & pv->pending_ints & 0x10) >> 2; }
// before ADEN u32 PicoRead8_32x(u32 a) { u32 d = 0; if ((a & 0xffc0) == 0x5100) { // a15100 // regs are always readable d = ((u8 *)Pico32x.regs)[(a & 0x3f) ^ 1]; goto out; } if ((a & 0xfffc) == 0x30ec) { // a130ec d = str_mars[a & 3]; goto out; } elprintf(EL_UIO, "m68k unmapped r8 [%06x] @%06x", a, SekPc); return d; out: elprintf(EL_32X, "m68k 32x r8 [%06x] %02x @%06x", a, d, SekPc); return d; }
static void consume_fifo_do(SH2 *sh2, unsigned int m68k_cycles, int sh2_cycles_diff) { struct Pico32xMem *mem = Pico32xMem; unsigned short *fifo_l = mem->pwm_fifo[0]; unsigned short *fifo_r = mem->pwm_fifo[1]; int sum = 0; if (pwm_cycles == 0 || pwm_doing_fifo) return; elprintf(EL_PWM, "pwm: %u: consume %d/%d, %d,%d ptr %d", m68k_cycles, sh2_cycles_diff, sh2_cycles_diff / pwm_cycles, Pico32x.pwm_p[0], Pico32x.pwm_p[1], pwm_ptr); // this is for recursion from dreq1 writes pwm_doing_fifo = 1; for (; sh2_cycles_diff >= pwm_cycles; sh2_cycles_diff -= pwm_cycles) { if (Pico32x.pwm_p[0] > 0) { fifo_l[0] = fifo_l[1]; fifo_l[1] = fifo_l[2]; fifo_l[2] = fifo_l[3]; Pico32x.pwm_p[0]--; mem->pwm_current[0] = convert_sample(fifo_l[0]); sum += mem->pwm_current[0]; } if (Pico32x.pwm_p[1] > 0) { fifo_r[0] = fifo_r[1]; fifo_r[1] = fifo_r[2]; fifo_r[2] = fifo_r[3]; Pico32x.pwm_p[1]--; mem->pwm_current[1] = convert_sample(fifo_r[0]); sum += mem->pwm_current[1]; } mem->pwm[pwm_ptr * 2 ] = mem->pwm_current[0]; mem->pwm[pwm_ptr * 2 + 1] = mem->pwm_current[1]; pwm_ptr = (pwm_ptr + 1) & (PWM_BUFF_LEN - 1); if (--Pico32x.pwm_irq_cnt == 0) { Pico32x.pwm_irq_cnt = pwm_irq_reload; do_pwm_irq(sh2, m68k_cycles); } } Pico32x.pwm_cycle_p = m68k_cycles * 3 - sh2_cycles_diff; pwm_doing_fifo = 0; if (sum != 0) pwm_silent = 0; }
static u32 PicoRead16_32x_on(u32 a) { u32 d = 0; if ((a & 0xffc0) == 0x5100) { // a15100 d = p32x_reg_read16(a); goto out; } if ((a & 0xfc00) != 0x5000) { if (PicoAHW & PAHW_MCD) return PicoRead16_mcd_io(a); else return PicoRead16_io(a); } if ((a & 0xfff0) == 0x5180) { // a15180 d = p32x_vdp_read16(a); goto out; } if ((a & 0xfe00) == 0x5200) { // a15200 d = Pico32xMem->pal[(a & 0x1ff) / 2]; goto out; } if ((a & 0xfffc) == 0x30ec) { // a130ec d = !(a & 2) ? ('M'<<8)|'A' : ('R'<<8)|'S'; goto out; } elprintf(EL_UIO, "m68k unmapped r16 [%06x] @%06x", a, SekPc); return d; out: elprintf(EL_32X, "m68k 32x r16 [%06x] %04x @%06x", a, d, SekPc); return d; }
static void PicoWrite8_32x_on(u32 a, u32 d) { if ((a & 0xfc00) == 0x5000) elprintf(EL_32X, "m68k 32x w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); if ((a & 0xffc0) == 0x5100) { // a15100 p32x_reg_write8(a, d); return; } if ((a & 0xfc00) != 0x5000) { if (PicoAHW & PAHW_MCD) PicoWrite8_mcd_io(a, d); else PicoWrite8_io(a, d); if (a == 0xa130f1) bank_switch(Pico32x.regs[4 / 2]); return; } if (!(Pico32x.regs[0] & P32XS_FM)) { if ((a & 0xfff0) == 0x5180) { // a15180 p32x_vdp_write8(a, d); return; } // TODO: verify if ((a & 0xfe00) == 0x5200) { // a15200 elprintf(EL_32X|EL_ANOMALY, "m68k 32x PAL w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); ((u8 *)Pico32xMem->pal)[(a & 0x1ff) ^ 1] = d; Pico32x.dirty_pal = 1; return; } } elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x", a, d & 0xff, SekPc); }