Files
gopher64/src/device/cache.rs
T
Logan McNaughton 4ead0218d9 remove pub keyword where it isn't needed (#161)
* remove pub keyword where it isn't needed

* more

* Update main.rs

* more
2025-01-18 19:58:23 +01:00

283 lines
10 KiB
Rust

use crate::device;
#[derive(Copy, Clone)]
pub struct ICache {
pub valid: bool,
pub tag: u32,
pub index: u16,
pub words: [u32; 8],
pub instruction: [fn(&mut device::Device, u32); 8],
}
#[derive(Copy, Clone)]
pub struct DCache {
pub valid: bool,
pub dirty: bool,
pub tag: u32,
pub index: u16,
pub words: [u32; 4],
}
pub fn icache_hit(device: &device::Device, line_index: usize, phys_address: u64) -> bool {
device.memory.icache[line_index].valid
&& (device.memory.icache[line_index].tag & 0x1ffffffc) == (phys_address & !0xFFF) as u32
}
pub fn icache_writeback(device: &mut device::Device, line_index: usize) {
device::cop0::add_cycles(device, device::rdram::rdram_calculate_cycles(32));
let cache_address = ((device.memory.icache[line_index].tag
| (device.memory.icache[line_index].index) as u32)
& 0x1ffffffc) as u64;
device.memory.memory_map_write[(cache_address >> 16) as usize](
device,
cache_address,
device.memory.icache[line_index].words[0],
0xFFFFFFFF,
);
device.memory.memory_map_write[(cache_address >> 16) as usize](
device,
cache_address | 0x4,
device.memory.icache[line_index].words[1],
0xFFFFFFFF,
);
device.memory.memory_map_write[(cache_address >> 16) as usize](
device,
cache_address | 0x8,
device.memory.icache[line_index].words[2],
0xFFFFFFFF,
);
device.memory.memory_map_write[(cache_address >> 16) as usize](
device,
cache_address | 0xC,
device.memory.icache[line_index].words[3],
0xFFFFFFFF,
);
device.memory.memory_map_write[(cache_address >> 16) as usize](
device,
cache_address | 0x10,
device.memory.icache[line_index].words[4],
0xFFFFFFFF,
);
device.memory.memory_map_write[(cache_address >> 16) as usize](
device,
cache_address | 0x14,
device.memory.icache[line_index].words[5],
0xFFFFFFFF,
);
device.memory.memory_map_write[(cache_address >> 16) as usize](
device,
cache_address | 0x18,
device.memory.icache[line_index].words[6],
0xFFFFFFFF,
);
device.memory.memory_map_write[(cache_address >> 16) as usize](
device,
cache_address | 0x1C,
device.memory.icache[line_index].words[7],
0xFFFFFFFF,
);
}
pub fn icache_fill(device: &mut device::Device, line_index: usize, phys_address: u64) {
device::cop0::add_cycles(device, 8);
device.memory.icache[line_index].valid = true;
device.memory.icache[line_index].tag = (phys_address & !0xFFF) as u32;
let cache_address = ((device.memory.icache[line_index].tag
| (device.memory.icache[line_index].index) as u32)
& 0x1ffffffc) as u64;
device.memory.icache[line_index].words[0] = device.memory.memory_map_read
[(cache_address >> 16) as usize](
device,
cache_address,
device::memory::AccessSize::Icache,
);
device.memory.icache[line_index].words[1] = device.memory.memory_map_read
[(cache_address >> 16) as usize](
device,
cache_address | 0x4,
device::memory::AccessSize::Icache,
);
device.memory.icache[line_index].words[2] = device.memory.memory_map_read
[(cache_address >> 16) as usize](
device,
cache_address | 0x8,
device::memory::AccessSize::Icache,
);
device.memory.icache[line_index].words[3] = device.memory.memory_map_read
[(cache_address >> 16) as usize](
device,
cache_address | 0xC,
device::memory::AccessSize::Icache,
);
device.memory.icache[line_index].words[4] = device.memory.memory_map_read
[(cache_address >> 16) as usize](
device,
cache_address | 0x10,
device::memory::AccessSize::Icache,
);
device.memory.icache[line_index].words[5] = device.memory.memory_map_read
[(cache_address >> 16) as usize](
device,
cache_address | 0x14,
device::memory::AccessSize::Icache,
);
device.memory.icache[line_index].words[6] = device.memory.memory_map_read
[(cache_address >> 16) as usize](
device,
cache_address | 0x18,
device::memory::AccessSize::Icache,
);
device.memory.icache[line_index].words[7] = device.memory.memory_map_read
[(cache_address >> 16) as usize](
device,
cache_address | 0x1C,
device::memory::AccessSize::Icache,
);
device.memory.icache[line_index].instruction[0] =
device::cpu::decode_opcode(device, device.memory.icache[line_index].words[0]);
device.memory.icache[line_index].instruction[1] =
device::cpu::decode_opcode(device, device.memory.icache[line_index].words[1]);
device.memory.icache[line_index].instruction[2] =
device::cpu::decode_opcode(device, device.memory.icache[line_index].words[2]);
device.memory.icache[line_index].instruction[3] =
device::cpu::decode_opcode(device, device.memory.icache[line_index].words[3]);
device.memory.icache[line_index].instruction[4] =
device::cpu::decode_opcode(device, device.memory.icache[line_index].words[4]);
device.memory.icache[line_index].instruction[5] =
device::cpu::decode_opcode(device, device.memory.icache[line_index].words[5]);
device.memory.icache[line_index].instruction[6] =
device::cpu::decode_opcode(device, device.memory.icache[line_index].words[6]);
device.memory.icache[line_index].instruction[7] =
device::cpu::decode_opcode(device, device.memory.icache[line_index].words[7]);
}
pub fn icache_fetch(device: &mut device::Device, phys_address: u64) {
let line_index = ((phys_address >> 5) & 0x1FF) as usize;
if !icache_hit(device, line_index, phys_address) {
icache_fill(device, line_index, phys_address)
}
let item = ((phys_address >> 2) & 7) as usize;
device.memory.icache[line_index].instruction[item](
device,
device.memory.icache[line_index].words[item],
);
}
pub fn dcache_hit(device: &device::Device, line_index: usize, phys_address: u64) -> bool {
device.memory.dcache[line_index].valid
&& (device.memory.dcache[line_index].tag & 0x1ffffffc) == (phys_address & !0xFFF) as u32
}
pub fn dcache_writeback(device: &mut device::Device, line_index: usize) {
device::cop0::add_cycles(device, device::rdram::rdram_calculate_cycles(16));
device.memory.dcache[line_index].dirty = false;
let cache_address = ((device.memory.dcache[line_index].tag
| (device.memory.dcache[line_index].index) as u32)
& 0x1ffffffc) as u64;
device.memory.memory_map_write[(cache_address >> 16) as usize](
device,
cache_address,
device.memory.dcache[line_index].words[0],
0xFFFFFFFF,
);
device.memory.memory_map_write[(cache_address >> 16) as usize](
device,
cache_address | 0x4,
device.memory.dcache[line_index].words[1],
0xFFFFFFFF,
);
device.memory.memory_map_write[(cache_address >> 16) as usize](
device,
cache_address | 0x8,
device.memory.dcache[line_index].words[2],
0xFFFFFFFF,
);
device.memory.memory_map_write[(cache_address >> 16) as usize](
device,
cache_address | 0xC,
device.memory.dcache[line_index].words[3],
0xFFFFFFFF,
);
}
fn dcache_fill(device: &mut device::Device, line_index: usize, phys_address: u64) {
device::cop0::add_cycles(device, 7);
device.memory.dcache[line_index].valid = true;
device.memory.dcache[line_index].dirty = false;
device.memory.dcache[line_index].tag = (phys_address & !0xFFF) as u32;
let cache_address = ((device.memory.dcache[line_index].tag
| (device.memory.dcache[line_index].index) as u32)
& 0x1ffffffc) as u64;
device.memory.dcache[line_index].words[0] = device.memory.memory_map_read
[(cache_address >> 16) as usize](
device,
cache_address,
device::memory::AccessSize::Dcache,
);
device.memory.dcache[line_index].words[1] = device.memory.memory_map_read
[(cache_address >> 16) as usize](
device,
cache_address | 0x4,
device::memory::AccessSize::Dcache,
);
device.memory.dcache[line_index].words[2] = device.memory.memory_map_read
[(cache_address >> 16) as usize](
device,
cache_address | 0x8,
device::memory::AccessSize::Dcache,
);
device.memory.dcache[line_index].words[3] = device.memory.memory_map_read
[(cache_address >> 16) as usize](
device,
cache_address | 0xC,
device::memory::AccessSize::Dcache,
);
}
pub fn dcache_read(device: &mut device::Device, phys_address: u64) -> u32 {
let line_index = ((phys_address >> 4) & 0x1FF) as usize;
if !dcache_hit(device, line_index, phys_address) {
if device.memory.dcache[line_index].valid && device.memory.dcache[line_index].dirty {
dcache_writeback(device, line_index)
}
dcache_fill(device, line_index, phys_address)
} else {
device::cop0::add_cycles(device, 1)
}
device.memory.dcache[line_index].words[((phys_address >> 2) & 3) as usize]
}
pub fn dcache_write(device: &mut device::Device, phys_address: u64, value: u32, mask: u32) {
let line_index = ((phys_address >> 4) & 0x1FF) as usize;
if !dcache_hit(device, line_index, phys_address) {
if device.memory.dcache[line_index].valid && device.memory.dcache[line_index].dirty {
dcache_writeback(device, line_index)
}
dcache_fill(device, line_index, phys_address)
} else {
device::cop0::add_cycles(device, 1)
}
device::memory::masked_write_32(
&mut device.memory.dcache[line_index].words[((phys_address >> 2) & 3) as usize],
value,
mask,
);
device.memory.dcache[line_index].dirty = true;
}
pub fn init(device: &mut device::Device) {
for (pos, i) in device.memory.icache.iter_mut().enumerate() {
i.index = (pos << 5) as u16 & 0xFE0
}
for (pos, i) in device.memory.dcache.iter_mut().enumerate() {
i.index = (pos << 4) as u16 & 0xFF0
}
}