use crate::core::cpu::CpuCore;
use crate::core::types::CpuType;
const TTR_ENABLE: u32 = 0x8000;
const TTR_BASE_MASK: u32 = 0xFF00_0000;
const TTR_ADDR_MASK_SHIFT: u32 = 16;
const TTR_FC_BASE_SHIFT: u32 = 8;
const TTR_FC_MASK_SHIFT: u32 = 2;
pub fn ttr_matches(ttr: u32, addr: u32, fc: u8, _write: bool) -> bool {
if (ttr & TTR_ENABLE) == 0 {
return false;
}
let base = (ttr & TTR_BASE_MASK) >> 24;
let addr_mask = (ttr >> TTR_ADDR_MASK_SHIFT) & 0xFF;
let fc_base = ((ttr >> TTR_FC_BASE_SHIFT) & 0x07) as u8;
let fc_mask = ((ttr >> TTR_FC_MASK_SHIFT) & 0x07) as u8;
let addr_high = (addr >> 24) & 0xFF;
let addr_match = (addr_high & !addr_mask) == (base & !addr_mask);
let fc_match = (fc & !fc_mask) == (fc_base & !fc_mask);
addr_match && fc_match
}
pub fn check_transparent_translation(
cpu: &CpuCore,
addr: u32,
write: bool,
instruction: bool,
) -> Option<u32> {
let fc = compute_function_code(cpu, instruction);
match cpu.cpu_type {
CpuType::M68030 => {
if ttr_matches(cpu.mmu_tt0, addr, fc, write) {
return Some(addr);
}
if ttr_matches(cpu.mmu_tt1, addr, fc, write) {
return Some(addr);
}
}
CpuType::M68EC040 | CpuType::M68LC040 | CpuType::M68040 => {
if instruction {
if ttr_matches(cpu.itt0, addr, fc, write) {
return Some(addr);
}
if ttr_matches(cpu.itt1, addr, fc, write) {
return Some(addr);
}
} else {
if ttr_matches(cpu.dtt0, addr, fc, write) {
return Some(addr);
}
if ttr_matches(cpu.dtt1, addr, fc, write) {
return Some(addr);
}
}
}
_ => {
}
}
None
}
fn compute_function_code(cpu: &CpuCore, instruction: bool) -> u8 {
let is_supervisor = cpu.is_supervisor();
match (is_supervisor, instruction) {
(false, false) => 1, (false, true) => 2, (true, false) => 5, (true, true) => 6, }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ttr_disabled() {
let ttr = 0x0000_0000; assert!(!ttr_matches(ttr, 0x1000_0000, 5, false));
}
#[test]
fn test_ttr_address_match() {
let ttr = 0x4000_801C; assert!(ttr_matches(ttr, 0x4000_0000, 5, false));
assert!(ttr_matches(ttr, 0x40FF_FFFF, 5, false));
assert!(!ttr_matches(ttr, 0x4100_0000, 5, false));
assert!(!ttr_matches(ttr, 0x3F00_0000, 5, false));
}
#[test]
fn test_ttr_address_mask() {
let ttr = 0x400F_801C; assert!(ttr_matches(ttr, 0x4000_0000, 5, false));
assert!(ttr_matches(ttr, 0x4F00_0000, 5, false));
assert!(!ttr_matches(ttr, 0x5000_0000, 5, false));
}
#[test]
fn test_ttr_fc_match() {
let ttr = 0x4000_8500; assert!(ttr_matches(ttr, 0x4000_0000, 5, false));
assert!(!ttr_matches(ttr, 0x4000_0000, 1, false)); assert!(!ttr_matches(ttr, 0x4000_0000, 6, false)); }
#[test]
fn test_ttr_fc_mask() {
let ttr = 0x4000_840C; assert!(ttr_matches(ttr, 0x4000_0000, 4, false));
assert!(ttr_matches(ttr, 0x4000_0000, 5, false));
assert!(ttr_matches(ttr, 0x4000_0000, 6, false));
assert!(ttr_matches(ttr, 0x4000_0000, 7, false));
assert!(!ttr_matches(ttr, 0x4000_0000, 1, false)); }
}