diff --git a/src/device.rs b/src/device.rs index 92a2b4e5..1fbc38e3 100644 --- a/src/device.rs +++ b/src/device.rs @@ -478,7 +478,6 @@ impl Device { }, broken: false, running: false, - halted: false, sync_point: false, cycle_counter: 0, gpr: [0; 32], @@ -511,6 +510,7 @@ impl Device { mem: [0; 0x2000], last_status_value: 0, run_after_dma: false, + pending_status: 0, fifo: [rsp_interface::RspDma { dir: rsp_interface::DmaDir::None, length: 0, diff --git a/src/device/ai.rs b/src/device/ai.rs index 9823aad7..1c493ffd 100644 --- a/src/device/ai.rs +++ b/src/device/ai.rs @@ -37,8 +37,10 @@ fn get_remaining_dma_length(device: &device::Device) -> u64 { return 0; } - let remaining_dma_duration = - next_ai_event.unwrap().count - device.cpu.cop0.regs[device::cop0::COP0_COUNT_REG]; + let remaining_dma_duration = next_ai_event + .unwrap() + .count + .saturating_sub(device.cpu.cop0.regs[device::cop0::COP0_COUNT_REG]); let dma_length = remaining_dma_duration * device.ai.fifo[0].length / device.ai.fifo[0].duration; dma_length & !7 diff --git a/src/device/rsp_cpu.rs b/src/device/rsp_cpu.rs index 6b7a7a53..45193b7a 100644 --- a/src/device/rsp_cpu.rs +++ b/src/device/rsp_cpu.rs @@ -35,7 +35,6 @@ pub struct Cpu { pub branch_state: BranchState, pub broken: bool, pub running: bool, - pub halted: bool, pub sync_point: bool, pub cycle_counter: u64, #[serde( diff --git a/src/device/rsp_interface.rs b/src/device/rsp_interface.rs index 1d62a69c..a426ebe3 100644 --- a/src/device/rsp_interface.rs +++ b/src/device/rsp_interface.rs @@ -86,6 +86,7 @@ pub struct Rsp { pub fifo: [RspDma; 2], pub last_status_value: u32, pub run_after_dma: bool, + pub pending_status: u32, } pub fn read_mem_fast( @@ -209,10 +210,15 @@ fn do_dma(device: &mut device::Device, dma: RspDma) { device.rsp.regs[SP_RD_LEN_REG] = 0xff8; device.rsp.regs[SP_WR_LEN_REG] = 0xff8; + let rsp_cycles = if device.rsp.cpu.running { + device::rsp_cpu::elapsed_cpu_cycles(device) + } else { + 0 + }; device::events::create_event( device, device::events::EVENT_TYPE_SPDMA, - device::rdram::rdram_calculate_cycles((count * length) as u64) + 9, + rsp_cycles + device::rdram::rdram_calculate_cycles((count * length) as u64) + 9, ); } @@ -312,7 +318,15 @@ pub fn read_regs( pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u32) { let reg = (address & 0xFFFF) >> 2; match reg as usize { - SP_STATUS_REG => update_sp_status(device, value), + SP_STATUS_REG => { + if device.rsp.cpu.running { + device.rsp.pending_status = value; + device.rsp.cpu.sync_point = true; + } else { + apply_pending_status(device); + update_sp_status(device, value) + } + } SP_RD_LEN_REG => { device::memory::masked_write_32(&mut device.rsp.regs[reg as usize], value, mask); fifo_push(device, DmaDir::Write) @@ -459,7 +473,6 @@ fn update_sp_status(device: &mut device::Device, w: u32) { if device.rsp.regs[SP_STATUS_REG] & SP_STATUS_HALT == 0 && was_halted { device.rsp.cpu.broken = false; - device.rsp.cpu.halted = false; do_task(device); } } @@ -477,7 +490,15 @@ fn do_task(device: &mut device::Device) { } } +fn apply_pending_status(device: &mut device::Device) { + let pending = std::mem::take(&mut device.rsp.pending_status); + if pending != 0 { + update_sp_status(device, pending) + } +} + pub fn rsp_event(device: &mut device::Device) { + apply_pending_status(device); if device.rsp.cpu.broken { device.rsp.regs[SP_STATUS_REG] |= SP_STATUS_HALT | SP_STATUS_BROKE; @@ -486,8 +507,7 @@ pub fn rsp_event(device: &mut device::Device) { } return; } - if device.rsp.cpu.halted { - device.rsp.regs[SP_STATUS_REG] |= SP_STATUS_HALT; + if device.rsp.regs[SP_STATUS_REG] & SP_STATUS_HALT != 0 { return; } do_task(device) diff --git a/src/device/rsp_su_instructions.rs b/src/device/rsp_su_instructions.rs index 7fcd5253..1d4d8d8f 100644 --- a/src/device/rsp_su_instructions.rs +++ b/src/device/rsp_su_instructions.rs @@ -580,13 +580,6 @@ pub fn mtc0(device: &mut device::Device, opcode: u32) { 0xFFFFFFFF, ) } - if rd(opcode) as usize == device::rsp_interface::SP_STATUS_REG - && device.rsp.cpu.gpr[rt(opcode) as usize] & device::rsp_interface::SP_SET_HALT != 0 - { - device.rsp.regs[device::rsp_interface::SP_STATUS_REG] &= - !device::rsp_interface::SP_STATUS_HALT; // set halt when event happens - device.rsp.cpu.halted = true // the RSP can halt itself by setting SP_SET_HALT - } } pub fn mfc2(device: &mut device::Device, opcode: u32) { diff --git a/src/device/vi.rs b/src/device/vi.rs index a6b593c0..dac954fe 100644 --- a/src/device/vi.rs +++ b/src/device/vi.rs @@ -51,10 +51,11 @@ fn set_vertical_interrupt(device: &mut device::Device) { fn set_current_line(device: &mut device::Device) { if let Some(next_vi) = device::events::get_event(device, device::events::EVENT_TYPE_VI) { - device.vi.regs[VI_CURRENT_REG] = - ((device.vi.delay.saturating_sub( - next_vi.count - device.cpu.cop0.regs[device::cop0::COP0_COUNT_REG], - )) / device.vi.count_per_scanline) as u32; + device.vi.regs[VI_CURRENT_REG] = ((device.vi.delay.saturating_sub( + next_vi + .count + .saturating_sub(device.cpu.cop0.regs[device::cop0::COP0_COUNT_REG]), + )) / device.vi.count_per_scanline) as u32; // wrap around VI_CURRENT_REG if needed if device.vi.regs[VI_CURRENT_REG] >= device.vi.regs[VI_V_SYNC_REG] {