mirror of
https://github.com/gopher64/gopher64.git
synced 2026-11-12 09:09:01 +01:00
handle address errors (#1337)
This commit is contained in:
1 parent
125c722780
commit
becc4f155c
5 files changed
+49
-8
No files matched your search
+5
-1
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in new issue
Block a user