handle address errors (#1337)

This commit is contained in:
Logan McNaughton authored and GitHub committed 2026-11-03 08:51:04 +00:00
1 parent 125c722780
commit becc4f155c
5 files changed
+49 -8

No files matched your search

+5 -1
View File
@@ -49,7 +49,7 @@ pub const COP0_STATUS_CU2: u64 = 1 << 30;
pub const COP0_CAUSE_EXCCODE_MOD: u64 = 1 << 2;
pub const COP0_CAUSE_EXCCODE_TLBL: u64 = 2 << 2;
pub const COP0_CAUSE_EXCCODE_TLBS: u64 = 3 << 2;
//const COP0_CAUSE_EXCCODE_ADEL: u64 = 4 << 2;
pub const COP0_CAUSE_EXCCODE_ADEL: u64 = 4 << 2;
//const COP0_CAUSE_EXCCODE_ADES: u64 = 5 << 2;
pub const COP0_CAUSE_EXCCODE_SYS: u64 = 8 << 2;
pub const COP0_CAUSE_EXCCODE_BP: u64 = 9 << 2;
@@ -169,6 +169,10 @@ fn eret(device: &mut device::Device, _opcode: u32) {
}
device.cpu.branch_state.state = device::cpu::State::Exception;
device.cpu.llbit = false;
if device.cpu.pc & 3 != 0 {
device::exceptions::address_error_exception(device, device.cpu.pc);
return;
}
device::exceptions::check_pending_interrupts(device)
}
+20 -3
View File
@@ -9,6 +9,9 @@ pub enum State {
DelaySlotNotTaken,
Discard,
Exception,
// jr/jalr to a misaligned target: the address error is raised after the delay slot
TakeAddressError,
DelaySlotAddressError,
}
#[derive(Clone, serde::Serialize, serde::Deserialize)]
@@ -242,12 +245,17 @@ pub fn init(device: &mut device::Device) {
}
pub fn in_delay_slot(device: &device::Device) -> bool {
device.cpu.branch_state.state == State::DelaySlotTaken
|| device.cpu.branch_state.state == State::DelaySlotNotTaken
matches!(
device.cpu.branch_state.state,
State::DelaySlotTaken | State::DelaySlotNotTaken | State::DelaySlotAddressError
)
}
pub fn in_delay_slot_taken(device: &device::Device) -> bool {
device.cpu.branch_state.state == State::DelaySlotTaken
matches!(
device.cpu.branch_state.state,
State::DelaySlotTaken | State::DelaySlotAddressError
)
}
pub fn run(device: &mut device::Device) {
@@ -298,6 +306,15 @@ pub fn run(device: &mut device::Device) {
device.cpu.branch_state.state = State::Step
}
State::Exception => device.cpu.branch_state.state = State::Step,
State::TakeAddressError => {
device.cpu.pc += 4;
device.cpu.branch_state.state = State::DelaySlotAddressError
}
State::DelaySlotAddressError => {
device.cpu.pc = device.cpu.branch_state.pc;
device.cpu.branch_state.state = State::Step;
device::exceptions::address_error_exception(device, device.cpu.pc)
}
}
device::cop0::add_cycles(device, 1);
if device.cpu.cop0.regs[device::cop0::COP0_COUNT_REG] > device.cpu.next_event_count {
+14 -4
View File
@@ -964,8 +964,13 @@ pub fn srav(device: &mut device::Device, opcode: u32) {
pub fn jr(device: &mut device::Device, opcode: u32) {
if !device::cpu::in_delay_slot_taken(device) {
device.cpu.branch_state.state = device::cpu::State::Take;
device.cpu.branch_state.pc = device.cpu.gpr[rs(opcode) as usize];
let target = device.cpu.gpr[rs(opcode) as usize];
device.cpu.branch_state.state = if target & 3 == 0 {
device::cpu::State::Take
} else {
device::cpu::State::TakeAddressError
};
device.cpu.branch_state.pc = target;
} else if !device::cpu::in_delay_slot(device) {
device.cpu.branch_state.state = device::cpu::State::NotTaken;
}
@@ -975,8 +980,13 @@ pub fn jalr(device: &mut device::Device, opcode: u32) {
let in_delay_slot_taken = device::cpu::in_delay_slot_taken(device);
if !in_delay_slot_taken {
device.cpu.branch_state.state = device::cpu::State::Take;
device.cpu.branch_state.pc = device.cpu.gpr[rs(opcode) as usize];
let target = device.cpu.gpr[rs(opcode) as usize];
device.cpu.branch_state.state = if target & 3 == 0 {
device::cpu::State::Take
} else {
device::cpu::State::TakeAddressError
};
device.cpu.branch_state.pc = target;
} else if !device::cpu::in_delay_slot(device) {
device.cpu.branch_state.state = device::cpu::State::NotTaken;
}
+7
View File
@@ -79,6 +79,13 @@ pub fn cop_unusable_exception(device: &mut device::Device, cop: u64) {
exception_general(device, 0x180)
}
pub fn address_error_exception(device: &mut device::Device, address: u64) {
set_exception_cause(device, device::cop0::COP0_CAUSE_EXCCODE_ADEL);
device.cpu.cop0.regs[device::cop0::COP0_BADVADDR_REG] = address;
exception_general(device, 0x180)
}
pub fn tlb_miss_exception(
device: &mut device::Device,
address: u64,
+3
View File
@@ -170,6 +170,9 @@ pub fn run(device: &mut device::Device) -> u64 {
device::cpu::State::Exception => {
device.rsp.cpu.branch_state.state = device::cpu::State::Step
}
device::cpu::State::TakeAddressError | device::cpu::State::DelaySlotAddressError => {
unreachable!() // VR4300-only states
}
}
device.rsp.regs2[device::rsp_interface::SP_PC_REG] &= 0xFFC;