164 lines
4.9 KiB
Rust
164 lines
4.9 KiB
Rust
use crate::device;
|
|
|
|
pub const MI_INIT_MODE_REG: usize = 0;
|
|
const MI_VERSION_REG: usize = 1;
|
|
pub const MI_INTR_REG: usize = 2;
|
|
pub const MI_INTR_MASK_REG: usize = 3;
|
|
pub const MI_REGS_COUNT: usize = 4;
|
|
|
|
/* read */
|
|
pub const MI_INTR_SP: u32 = 1 << 0;
|
|
pub const MI_INTR_SI: u32 = 1 << 1;
|
|
pub const MI_INTR_AI: u32 = 1 << 2;
|
|
pub const MI_INTR_VI: u32 = 1 << 3;
|
|
pub const MI_INTR_PI: u32 = 1 << 4;
|
|
pub const MI_INTR_DP: u32 = 1 << 5;
|
|
|
|
/* write */
|
|
const MI_CLR_SP: u32 = 1 << 0;
|
|
const MI_SET_SP: u32 = 1 << 1;
|
|
const MI_CLR_SI: u32 = 1 << 2;
|
|
const MI_SET_SI: u32 = 1 << 3;
|
|
const MI_CLR_AI: u32 = 1 << 4;
|
|
const MI_SET_AI: u32 = 1 << 5;
|
|
const MI_CLR_VI: u32 = 1 << 6;
|
|
const MI_SET_VI: u32 = 1 << 7;
|
|
const MI_CLR_PI: u32 = 1 << 8;
|
|
const MI_SET_PI: u32 = 1 << 9;
|
|
const MI_CLR_DP: u32 = 1 << 10;
|
|
const MI_SET_DP: u32 = 1 << 11;
|
|
|
|
/* mode read */
|
|
pub const MI_INIT_MODE: u32 = 1 << 7;
|
|
const MI_EBUS_MODE: u32 = 1 << 8;
|
|
const MI_RDRAM_MODE: u32 = 1 << 9;
|
|
|
|
/* mode write */
|
|
const MI_CLR_INIT: u32 = 1 << 7;
|
|
const MI_SET_INIT: u32 = 1 << 8;
|
|
const MI_CLR_EBUS: u32 = 1 << 9;
|
|
const MI_SET_EBUS: u32 = 1 << 10;
|
|
const MI_CLR_DP_INTR: u32 = 1 << 11;
|
|
const MI_CLR_RDRAM: u32 = 1 << 12;
|
|
const MI_SET_RDRAM: u32 = 1 << 13;
|
|
|
|
pub const MI_INIT_LENGTH_MASK: u32 = 0b1111111;
|
|
|
|
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
|
pub struct Mi {
|
|
pub regs: [u32; MI_REGS_COUNT],
|
|
}
|
|
|
|
pub fn read_regs(
|
|
device: &mut device::Device,
|
|
address: u64,
|
|
_access_size: device::memory::AccessSize,
|
|
) -> u32 {
|
|
device::cop0::add_cycles(device, 20);
|
|
device.mi.regs[((address & 0xFFFF) >> 2) as usize]
|
|
}
|
|
|
|
pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u32) {
|
|
let reg = (address & 0xFFFF) >> 2;
|
|
match reg as usize {
|
|
MI_INIT_MODE_REG => update_init_mode(device, value),
|
|
MI_INTR_MASK_REG => update_intr_mask(device, value),
|
|
_ => device::memory::masked_write_32(&mut device.mi.regs[reg as usize], value, mask),
|
|
}
|
|
|
|
if device.mi.regs[MI_INTR_REG] & device.mi.regs[MI_INTR_MASK_REG] == 0 {
|
|
device.cpu.cop0.regs[device::cop0::COP0_CAUSE_REG] &= !device::cop0::COP0_CAUSE_IP2;
|
|
}
|
|
device::exceptions::check_pending_interrupts(device)
|
|
}
|
|
|
|
fn update_init_mode(device: &mut device::Device, w: u32) {
|
|
device.mi.regs[MI_INIT_MODE_REG] &= !MI_INIT_LENGTH_MASK;
|
|
device.mi.regs[MI_INIT_MODE_REG] |= w & MI_INIT_LENGTH_MASK;
|
|
|
|
if w & MI_CLR_INIT != 0 {
|
|
for i in 0..(0x3F00000 >> 16) {
|
|
device.memory.memory_map_write[i] = device::rdram::write_mem;
|
|
}
|
|
device.mi.regs[MI_INIT_MODE_REG] &= !MI_INIT_MODE
|
|
}
|
|
if w & MI_SET_INIT != 0 {
|
|
for i in 0..(0x3F00000 >> 16) {
|
|
device.memory.memory_map_write[i] = device::rdram::write_mem_repeat;
|
|
}
|
|
device.mi.regs[MI_INIT_MODE_REG] |= MI_INIT_MODE
|
|
}
|
|
if w & MI_CLR_EBUS != 0 {
|
|
device.mi.regs[MI_INIT_MODE_REG] &= !MI_EBUS_MODE
|
|
}
|
|
if w & MI_SET_EBUS != 0 {
|
|
device.mi.regs[MI_INIT_MODE_REG] |= MI_EBUS_MODE
|
|
}
|
|
if w & MI_CLR_RDRAM != 0 {
|
|
device.mi.regs[MI_INIT_MODE_REG] &= !MI_RDRAM_MODE
|
|
}
|
|
if w & MI_SET_RDRAM != 0 {
|
|
device.mi.regs[MI_INIT_MODE_REG] |= MI_RDRAM_MODE
|
|
}
|
|
|
|
if w & MI_CLR_DP_INTR != 0 {
|
|
clear_rcp_interrupt(device, MI_INTR_DP)
|
|
}
|
|
}
|
|
|
|
fn update_intr_mask(device: &mut device::Device, w: u32) {
|
|
if w & MI_CLR_SP != 0 {
|
|
device.mi.regs[MI_INTR_MASK_REG] &= !MI_INTR_SP
|
|
}
|
|
if w & MI_SET_SP != 0 {
|
|
device.mi.regs[MI_INTR_MASK_REG] |= MI_INTR_SP
|
|
}
|
|
if w & MI_CLR_SI != 0 {
|
|
device.mi.regs[MI_INTR_MASK_REG] &= !MI_INTR_SI
|
|
}
|
|
if w & MI_SET_SI != 0 {
|
|
device.mi.regs[MI_INTR_MASK_REG] |= MI_INTR_SI
|
|
}
|
|
if w & MI_CLR_AI != 0 {
|
|
device.mi.regs[MI_INTR_MASK_REG] &= !MI_INTR_AI
|
|
}
|
|
if w & MI_SET_AI != 0 {
|
|
device.mi.regs[MI_INTR_MASK_REG] |= MI_INTR_AI
|
|
}
|
|
if w & MI_CLR_VI != 0 {
|
|
device.mi.regs[MI_INTR_MASK_REG] &= !MI_INTR_VI
|
|
}
|
|
if w & MI_SET_VI != 0 {
|
|
device.mi.regs[MI_INTR_MASK_REG] |= MI_INTR_VI
|
|
}
|
|
if w & MI_CLR_PI != 0 {
|
|
device.mi.regs[MI_INTR_MASK_REG] &= !MI_INTR_PI
|
|
}
|
|
if w & MI_SET_PI != 0 {
|
|
device.mi.regs[MI_INTR_MASK_REG] |= MI_INTR_PI
|
|
}
|
|
if w & MI_CLR_DP != 0 {
|
|
device.mi.regs[MI_INTR_MASK_REG] &= !MI_INTR_DP
|
|
}
|
|
if w & MI_SET_DP != 0 {
|
|
device.mi.regs[MI_INTR_MASK_REG] |= MI_INTR_DP
|
|
}
|
|
}
|
|
|
|
pub fn clear_rcp_interrupt(device: &mut device::Device, interrupt: u32) {
|
|
device.mi.regs[MI_INTR_REG] &= !interrupt;
|
|
|
|
if device.mi.regs[MI_INTR_REG] & device.mi.regs[MI_INTR_MASK_REG] == 0 {
|
|
device.cpu.cop0.regs[device::cop0::COP0_CAUSE_REG] &= !device::cop0::COP0_CAUSE_IP2;
|
|
}
|
|
}
|
|
|
|
pub fn set_rcp_interrupt(device: &mut device::Device, interrupt: u32) {
|
|
device.mi.regs[MI_INTR_REG] |= interrupt;
|
|
device::exceptions::check_pending_interrupts(device)
|
|
}
|
|
|
|
pub fn init(device: &mut device::Device) {
|
|
device.mi.regs[MI_VERSION_REG] = 0x02020102
|
|
}
|