//called by ppu.tick() when Hcounter=0 void CPU::scanline() { status.lineclocks = lineclocks(); //forcefully sync S-CPU to other processors, in case chips are not communicating synchronize_ppu(); synchronize_smp(); synchronize_coprocessor(); system.scanline(); if(vcounter() == 0) { //HDMA init triggers once every frame status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter()); status.hdma_init_triggered = false; status.auto_joypad_counter = 0; } //DRAM refresh occurs once every scanline if(cpu_version == 2) status.dram_refresh_position = 530 + 8 - dma_counter(); status.dram_refreshed = false; //HDMA triggers once every visible scanline if(vcounter() <= (ppu.overscan() == false ? 224 : 239)) { status.hdma_position = 1104; status.hdma_triggered = false; } }
void CPU::scanline() { synchronize_smp(); synchronize_ppu(); synchronize_coprocessor(); system.scanline(); if(vcounter() == 0) hdma_init(); queue.enqueue(534, QueueEvent::DramRefresh); if(vcounter() <= (ppu.overscan() == false ? 224 : 239)) { queue.enqueue(1104 + 8, QueueEvent::HdmaRun); } if(vcounter() == input.latchy) { queue.enqueue(input.latchx, QueueEvent::ControllerLatch); } bool nmi_valid = status.nmi_valid; status.nmi_valid = vcounter() >= (ppu.overscan() == false ? 225 : 240); if(!nmi_valid && status.nmi_valid) { status.nmi_line = true; if(status.nmi_enabled) status.nmi_transition = true; } else if(nmi_valid && !status.nmi_valid) { status.nmi_line = false; } if(status.auto_joypad_poll_enabled && vcounter() == (ppu.overscan() == false ? 227 : 242)) { input.poll(); run_auto_joypad_poll(); } }
void CPUDebugger::op_step() { bool break_event = false; usage[regs.pc] &= ~(UsageFlagM | UsageFlagX); usage[regs.pc] |= UsageOpcode | (regs.p.m << 1) | (regs.p.x << 0); opcode_pc = regs.pc; if(debugger.step_cpu && (debugger.step_type == Debugger::StepType::StepInto || (debugger.step_type >= Debugger::StepType::StepOver && debugger.call_count < 0))) { debugger.break_event = Debugger::BreakEvent::CPUStep; debugger.step_type = Debugger::StepType::None; scheduler.exit(Scheduler::ExitReason::DebuggerEvent); } else { if (debugger.break_on_wdm) { uint8 opcode = disassembler_read(opcode_pc); if (opcode == 0x42) { debugger.breakpoint_hit = Debugger::SoftBreakCPU; debugger.break_event = Debugger::BreakEvent::BreakpointHit; scheduler.exit(Scheduler::ExitReason::DebuggerEvent); } } debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00); } if(step_event) step_event(); // adjust call count if this is a call or return // (or if we're stepping over and no call occurred) // (TODO: track interrupts as well?) if (debugger.step_cpu) { if (debugger.step_over_new && debugger.call_count == 0) { debugger.call_count = -1; debugger.step_over_new = false; } uint8 opcode = disassembler_read(opcode_pc); if (opcode == 0x20 || opcode == 0x22 || opcode == 0xfc) { debugger.call_count++; } else if (opcode == 0x60 || opcode == 0x6b) { debugger.call_count--; } } CPU::op_step(); synchronize_smp(); }
void CPUDebugger::op_step() { bool break_event = false; usage[regs.pc] &= ~(UsageFlagM | UsageFlagX); usage[regs.pc] |= UsageExec | (regs.p.m << 1) | (regs.p.x << 0); opcode_pc = regs.pc; if(debugger.step_cpu) { debugger.break_event = Debugger::BreakEvent::CPUStep; scheduler.exit(Scheduler::ExitReason::DebuggerEvent); } else { debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00); } if(step_event) step_event(); CPU::op_step(); synchronize_smp(); }
uint8 CPU::mmio_read(unsigned addr) { if((addr & 0xffc0) == 0x2140) { synchronize_smp(); return smp.port_read(addr & 3); } switch(addr & 0xffff) { case 0x2180: { uint8 result = bus.read(0x7e0000 | status.wram_addr); status.wram_addr = (status.wram_addr + 1) & 0x01ffff; return result; } case 0x4016: { uint8 result = regs.mdr & 0xfc; result |= input.port1->data() & 3; return result; } case 0x4017: { uint8 result = (regs.mdr & 0xe0) | 0x1c; result |= input.port2->data() & 3; if (!status.auto_joypad_poll_enabled) interface()->inputNotify(0x4017); return result; } case 0x4210: { uint8 result = (regs.mdr & 0x70); result |= status.nmi_line << 7; result |= 0x02; //CPU revision status.nmi_line = false; return result; } case 0x4211: { uint8 result = (regs.mdr & 0x7f); result |= status.irq_line << 7; status.irq_line = false; return result; } case 0x4212: { uint8 result = (regs.mdr & 0x3e); unsigned vbstart = ppu.overscan() == false ? 225 : 240; if(vcounter() >= vbstart && vcounter() <= vbstart + 2) result |= 0x01; if(hcounter() <= 2 || hcounter() >= 1096) result |= 0x40; if(vcounter() >= vbstart) result |= 0x80; return result; } case 0x4213: // interface()->inputNotify(0x4213); // if there are lag counter issues with super scope, uncomment this return status.pio; case 0x4214: return status.rddiv >> 0; case 0x4215: return status.rddiv >> 8; case 0x4216: return status.rdmpy >> 0; case 0x4217: return status.rdmpy >> 8; case 0x4218: interface()->inputNotify(0x4218); return status.joy1l; case 0x4219: interface()->inputNotify(0x4219); return status.joy1h; case 0x421a: interface()->inputNotify(0x421a); return status.joy2l; case 0x421b: interface()->inputNotify(0x421b); return status.joy2h; case 0x421c: interface()->inputNotify(0x421c); return status.joy3l; case 0x421d: interface()->inputNotify(0x421d); return status.joy3h; case 0x421e: interface()->inputNotify(0x421e); return status.joy4l; case 0x421f: interface()->inputNotify(0x421f); return status.joy4h; } if((addr & 0xff80) == 0x4300) { unsigned i = (addr >> 4) & 7; switch(addr & 0xff8f) { case 0x4300: { return (channel[i].direction << 7) | (channel[i].indirect << 6) | (channel[i].unused << 5) | (channel[i].reverse_transfer << 4) | (channel[i].fixed_transfer << 3) | (channel[i].transfer_mode << 0); } case 0x4301: return channel[i].dest_addr; case 0x4302: return channel[i].source_addr >> 0; case 0x4303: return channel[i].source_addr >> 8; case 0x4304: return channel[i].source_bank; case 0x4305: return channel[i].transfer_size >> 0; case 0x4306: return channel[i].transfer_size >> 8; case 0x4307: return channel[i].indirect_bank; case 0x4308: return channel[i].hdma_addr >> 0; case 0x4309: return channel[i].hdma_addr >> 8; case 0x430a: return channel[i].line_counter; case 0x430b: case 0x430f: return channel[i].unknown; } }
void DSP::tick() { step(3 * 8); synchronize_smp(); }