mirror of
https://github.com/gopher64/gopher64.git
synced 2026-11-14 18:19:04 +01:00
1 parent
1937be0e7f
commit
85ad29d0c6
3 files changed
+41
-28
No files matched your search
+24
-15
@@ -12,6 +12,7 @@ pub const COP0_BADVADDR_REG: usize = 8;
|
||||
pub const COP0_COUNT_REG: usize = 9;
|
||||
pub const COP0_ENTRYHI_REG: usize = 10;
|
||||
const COP0_COMPARE_REG: usize = 11;
|
||||
const COMPARE_WRAP_PERIOD: u64 = 1 << 32;
|
||||
pub const COP0_STATUS_REG: usize = 12;
|
||||
pub const COP0_CAUSE_REG: usize = 13;
|
||||
pub const COP0_EPC_REG: usize = 14;
|
||||
@@ -191,7 +192,7 @@ pub fn emux_xdetect(_device: &mut device::Device, _opcode: u32) {}
|
||||
|
||||
fn get_control_registers(device: &device::Device, index: u32) -> u64 {
|
||||
match index as usize {
|
||||
COP0_COUNT_REG => device.cpu.cop0.regs[index as usize] >> 1,
|
||||
COP0_COUNT_REG => (device.cpu.cop0.regs[index as usize] >> 1) & 0xFFFFFFFF,
|
||||
COP0_RANDOM_REG => set_random_register(device),
|
||||
7 | 21 | 22 | 23 | 24 | 25 | 31 => device.cpu.cop0.reg_latch,
|
||||
_ => device.cpu.cop0.regs[index as usize],
|
||||
@@ -206,23 +207,14 @@ fn set_control_registers(device: &mut device::Device, index: u32, mut data: u64)
|
||||
data <<= 1;
|
||||
device::events::translate_events(device, device.cpu.cop0.regs[COP0_COUNT_REG], data);
|
||||
device.cpu.cop0.regs[COP0_COUNT_REG] = data;
|
||||
let compare = device.cpu.cop0.regs[COP0_COMPARE_REG];
|
||||
schedule_compare_event(device, compare);
|
||||
return;
|
||||
}
|
||||
COP0_WIRED_REG => device.cpu.cop0.regs[COP0_RANDOM_REG] = 31,
|
||||
COP0_COMPARE_REG => {
|
||||
data &= 0xFFFFFFFF;
|
||||
let current_count = (device.cpu.cop0.regs[COP0_COUNT_REG] >> 1) & 0xFFFFFFFF;
|
||||
let mut compare_event_diff = (data as u32).wrapping_sub(current_count as u32);
|
||||
|
||||
if compare_event_diff == 0 {
|
||||
compare_event_diff += u32::MAX;
|
||||
}
|
||||
|
||||
device::events::create_event(
|
||||
device,
|
||||
device::events::EVENT_TYPE_COMPARE,
|
||||
(compare_event_diff as u64) << 1,
|
||||
);
|
||||
schedule_compare_event(device, data);
|
||||
device.cpu.cop0.regs[COP0_CAUSE_REG] &= !COP0_CAUSE_IP7;
|
||||
}
|
||||
COP0_STATUS_REG
|
||||
@@ -240,13 +232,26 @@ fn set_control_registers(device: &mut device::Device, index: u32, mut data: u64)
|
||||
device::exceptions::check_pending_interrupts(device);
|
||||
}
|
||||
|
||||
fn schedule_compare_event(device: &mut device::Device, compare: u64) {
|
||||
let current_count = device.cpu.cop0.regs[COP0_COUNT_REG] >> 1;
|
||||
let mut diff = (compare as u32).wrapping_sub(current_count as u32) as u64;
|
||||
if diff == 0 {
|
||||
diff = COMPARE_WRAP_PERIOD;
|
||||
}
|
||||
device::events::create_event_at(
|
||||
device,
|
||||
device::events::EVENT_TYPE_COMPARE,
|
||||
(current_count + diff) << 1,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn compare_event(device: &mut device::Device) {
|
||||
device.cpu.cop0.regs[device::cop0::COP0_CAUSE_REG] |= device::cop0::COP0_CAUSE_IP7;
|
||||
|
||||
device::events::create_event_at(
|
||||
device,
|
||||
device::events::EVENT_TYPE_COMPARE,
|
||||
device.cpu.next_event_count + (u32::MAX as u64),
|
||||
device.cpu.next_event_count + (COMPARE_WRAP_PERIOD << 1),
|
||||
);
|
||||
device::exceptions::check_pending_interrupts(device);
|
||||
}
|
||||
@@ -385,5 +390,9 @@ pub fn init(device: &mut device::Device) {
|
||||
device.cpu.cop0.regs[COP0_BADVADDR_REG] = 0xFFFFFFFF;
|
||||
device.cpu.cop0.regs[COP0_CONTEXT_REG] = 0x7FFFF0;
|
||||
|
||||
device::events::create_event(device, device::events::EVENT_TYPE_COMPARE, u32::MAX as u64)
|
||||
device::events::create_event(
|
||||
device,
|
||||
device::events::EVENT_TYPE_COMPARE,
|
||||
COMPARE_WRAP_PERIOD << 1,
|
||||
)
|
||||
}
|
||||
@@ -95,7 +95,7 @@ fn set_next_event(device: &mut device::Device) {
|
||||
pub fn translate_events(device: &mut device::Device, old_count: u64, new_count: u64) {
|
||||
for i in device.cpu.events.iter_mut() {
|
||||
if i.enabled {
|
||||
i.count = i.count - old_count + new_count;
|
||||
i.count = i.count.wrapping_sub(old_count).wrapping_add(new_count);
|
||||
}
|
||||
}
|
||||
set_next_event(device);
|
||||
|
||||
+16
-12
@@ -32,43 +32,49 @@ pub fn check_pending_interrupts(device: &mut device::Device) {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_exception_cause(device: &mut device::Device, cause: u64) {
|
||||
let regs = &mut device.cpu.cop0.regs;
|
||||
regs[device::cop0::COP0_CAUSE_REG] =
|
||||
(regs[device::cop0::COP0_CAUSE_REG] & device::cop0::COP0_CAUSE_IP_MASK) | cause;
|
||||
}
|
||||
|
||||
pub fn interrupt_exception(device: &mut device::Device) {
|
||||
device.cpu.cop0.regs[device::cop0::COP0_CAUSE_REG] &= !device::cop0::COP0_CAUSE_EXCCODE_MASK;
|
||||
exception_general(device, 0x180);
|
||||
}
|
||||
|
||||
pub fn floating_point_exception(device: &mut device::Device) {
|
||||
device.cpu.cop0.regs[device::cop0::COP0_CAUSE_REG] = device::cop0::COP0_CAUSE_EXCCODE_FPE;
|
||||
set_exception_cause(device, device::cop0::COP0_CAUSE_EXCCODE_FPE);
|
||||
|
||||
exception_general(device, 0x180)
|
||||
}
|
||||
|
||||
pub fn trap_exception(device: &mut device::Device) {
|
||||
device.cpu.cop0.regs[device::cop0::COP0_CAUSE_REG] = device::cop0::COP0_CAUSE_EXCCODE_TR;
|
||||
set_exception_cause(device, device::cop0::COP0_CAUSE_EXCCODE_TR);
|
||||
|
||||
exception_general(device, 0x180)
|
||||
}
|
||||
|
||||
pub fn syscall_exception(device: &mut device::Device) {
|
||||
device.cpu.cop0.regs[device::cop0::COP0_CAUSE_REG] = device::cop0::COP0_CAUSE_EXCCODE_SYS;
|
||||
set_exception_cause(device, device::cop0::COP0_CAUSE_EXCCODE_SYS);
|
||||
|
||||
exception_general(device, 0x180)
|
||||
}
|
||||
|
||||
pub fn break_exception(device: &mut device::Device) {
|
||||
device.cpu.cop0.regs[device::cop0::COP0_CAUSE_REG] = device::cop0::COP0_CAUSE_EXCCODE_BP;
|
||||
set_exception_cause(device, device::cop0::COP0_CAUSE_EXCCODE_BP);
|
||||
|
||||
exception_general(device, 0x180)
|
||||
}
|
||||
|
||||
pub fn reserved_exception(device: &mut device::Device, cop: u64) {
|
||||
device.cpu.cop0.regs[device::cop0::COP0_CAUSE_REG] = device::cop0::COP0_CAUSE_EXCCODE_RI | cop;
|
||||
set_exception_cause(device, device::cop0::COP0_CAUSE_EXCCODE_RI | cop);
|
||||
|
||||
exception_general(device, 0x180)
|
||||
}
|
||||
|
||||
pub fn cop_unusable_exception(device: &mut device::Device, cop: u64) {
|
||||
device.cpu.cop0.regs[device::cop0::COP0_CAUSE_REG] = device::cop0::COP0_CAUSE_EXCCODE_CPU | cop;
|
||||
set_exception_cause(device, device::cop0::COP0_CAUSE_EXCCODE_CPU | cop);
|
||||
|
||||
exception_general(device, 0x180)
|
||||
}
|
||||
@@ -79,9 +85,9 @@ pub fn tlb_miss_exception(
|
||||
access_type: device::memory::AccessType,
|
||||
) {
|
||||
if access_type == device::memory::AccessType::Read {
|
||||
device.cpu.cop0.regs[device::cop0::COP0_CAUSE_REG] = device::cop0::COP0_CAUSE_EXCCODE_TLBL
|
||||
set_exception_cause(device, device::cop0::COP0_CAUSE_EXCCODE_TLBL);
|
||||
} else {
|
||||
device.cpu.cop0.regs[device::cop0::COP0_CAUSE_REG] = device::cop0::COP0_CAUSE_EXCCODE_TLBS
|
||||
set_exception_cause(device, device::cop0::COP0_CAUSE_EXCCODE_TLBS);
|
||||
}
|
||||
|
||||
device.cpu.cop0.regs[device::cop0::COP0_BADVADDR_REG] = address;
|
||||
@@ -112,8 +118,7 @@ pub fn tlb_miss_exception(
|
||||
if address & !3 >= i.start_even && address & !3 <= i.end_even {
|
||||
valid = i.v_even != 0;
|
||||
if valid && access_type == device::memory::AccessType::Write && i.d_even == 0 {
|
||||
device.cpu.cop0.regs[device::cop0::COP0_CAUSE_REG] =
|
||||
device::cop0::COP0_CAUSE_EXCCODE_MOD;
|
||||
set_exception_cause(device, device::cop0::COP0_CAUSE_EXCCODE_MOD);
|
||||
valid = false;
|
||||
}
|
||||
break;
|
||||
@@ -121,8 +126,7 @@ pub fn tlb_miss_exception(
|
||||
if address & !3 >= i.start_odd && address & !3 <= i.end_odd {
|
||||
valid = i.v_odd != 0;
|
||||
if valid && access_type == device::memory::AccessType::Write && i.d_odd == 0 {
|
||||
device.cpu.cop0.regs[device::cop0::COP0_CAUSE_REG] =
|
||||
device::cop0::COP0_CAUSE_EXCCODE_MOD;
|
||||
set_exception_cause(device, device::cop0::COP0_CAUSE_EXCCODE_MOD);
|
||||
valid = false;
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in new issue
Block a user