Skip to content

Commit 009af0b

Browse files
committed
moved nanotlb translate into mips_exec and inline it, call translate fn pointer
it is faster but will probably bite us when we will try to implement watch register support
1 parent d6af463 commit 009af0b

2 files changed

Lines changed: 39 additions & 49 deletions

File tree

TODO.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ watchhi/watchlo register support for debugging, translate variants that fire exc
3939

4040
HALF BAKED vino - all, hook up uvc camera
4141

42-
scsi - eject, load cd
42+
DONE scsi - eject, load cd
4343

4444
DONE scsi - C9 command
4545

@@ -49,7 +49,7 @@ DONE scsi - large requests fail
4949

5050
ui - file selection for cd load
5151

52-
bus - writemask on write64 and write32 for more efficient uncached store left/right?
52+
DONE bus - writemask on write64 and write32 for more efficient uncached store left/right?
5353

5454
all - examine locks, possibly switch to spin, first check peripherials then lock in hpc and ioc
5555

src/mips_exec.rs

Lines changed: 37 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -589,50 +589,26 @@ pub struct MipsExecutor<T: Tlb, C: MipsCache> {
589589
cached_pending: u64,
590590
}
591591

592-
// ---- translate_fn wrappers (one per privilege × addressing-mode combination) ---------------
592+
// ---- translate_fn slow-path wrappers (one per privilege × addressing-mode combination) ------
593593
// These are free functions so they can be stored as bare fn pointers in MipsExecutor.
594-
// Each is a thin shim that delegates to the fully monomorphised translate_32/64bit_impl.
595-
596-
// ---- nano-TLB probe/fill helper -----------------------------------------------
597-
// Shared by all 6 translate_fn wrappers. The slot index is `at as usize` (0/1/2).
598-
// On hit returns the cached TranslateResult directly.
599-
// On miss calls `slow` (the full translate), then fills the slot on success.
600-
#[inline(always)]
601-
fn nanotlb_translate<T: Tlb, C: MipsCache>(
602-
e: &mut MipsExecutor<T, C>,
603-
va: u64,
604-
at: AccessType,
605-
slow: fn(&mut MipsExecutor<T, C>, u64, AccessType) -> TranslateResult,
606-
) -> TranslateResult {
607-
let idx = at as usize; // Fetch=0, Read=1, Write=2
608-
let slot = &e.core.nanotlb[idx];
609-
if slot.matches(va) {
610-
return TranslateResult::ok(slot.phys_addr(va), slot.cache_attr_raw());
611-
}
612-
let result = slow(e, va, at);
613-
if !result.is_exception() {
614-
e.core.nanotlb[idx].fill_raw(va, result.phys as u64, result.status & 0x7);
615-
}
616-
result
617-
}
618-
594+
// They are only called on a nanotlb miss — the nanotlb probe happens before the fn-pointer call.
619595
fn translate_32_kernel<T: Tlb, C: MipsCache>(e: &mut MipsExecutor<T,C>, va: u64, at: AccessType) -> TranslateResult {
620-
nanotlb_translate(e, va, at, |e, va, at| e.translate_32bit_impl::<false, {crate::mips_core::PRIV_KERNEL}>(va, at))
596+
e.translate_32bit_impl::<false, {crate::mips_core::PRIV_KERNEL}>(va, at)
621597
}
622598
fn translate_32_supervisor<T: Tlb, C: MipsCache>(e: &mut MipsExecutor<T,C>, va: u64, at: AccessType) -> TranslateResult {
623-
nanotlb_translate(e, va, at, |e, va, at| e.translate_32bit_impl::<false, {crate::mips_core::PRIV_SUPERVISOR}>(va, at))
599+
e.translate_32bit_impl::<false, {crate::mips_core::PRIV_SUPERVISOR}>(va, at)
624600
}
625601
fn translate_32_user<T: Tlb, C: MipsCache>(e: &mut MipsExecutor<T,C>, va: u64, at: AccessType) -> TranslateResult {
626-
nanotlb_translate(e, va, at, |e, va, at| e.translate_32bit_impl::<false, {crate::mips_core::PRIV_USER}>(va, at))
602+
e.translate_32bit_impl::<false, {crate::mips_core::PRIV_USER}>(va, at)
627603
}
628604
fn translate_64_kernel<T: Tlb, C: MipsCache>(e: &mut MipsExecutor<T,C>, va: u64, at: AccessType) -> TranslateResult {
629-
nanotlb_translate(e, va, at, |e, va, at| e.translate_64bit_impl::<false, {crate::mips_core::PRIV_KERNEL}>(va, at))
605+
e.translate_64bit_impl::<false, {crate::mips_core::PRIV_KERNEL}>(va, at)
630606
}
631607
fn translate_64_supervisor<T: Tlb, C: MipsCache>(e: &mut MipsExecutor<T,C>, va: u64, at: AccessType) -> TranslateResult {
632-
nanotlb_translate(e, va, at, |e, va, at| e.translate_64bit_impl::<false, {crate::mips_core::PRIV_SUPERVISOR}>(va, at))
608+
e.translate_64bit_impl::<false, {crate::mips_core::PRIV_SUPERVISOR}>(va, at)
633609
}
634610
fn translate_64_user<T: Tlb, C: MipsCache>(e: &mut MipsExecutor<T,C>, va: u64, at: AccessType) -> TranslateResult {
635-
nanotlb_translate(e, va, at, |e, va, at| e.translate_64bit_impl::<false, {crate::mips_core::PRIV_USER}>(va, at))
611+
e.translate_64bit_impl::<false, {crate::mips_core::PRIV_USER}>(va, at)
636612
}
637613

638614
/// Free-standing trampoline for the CP0 Status callback installed by `install_status_cb`.
@@ -804,6 +780,23 @@ For R4000SC/MC CPUs:
804780
self.core.status_changed_cb = Some((mips_executor_status_cb::<T, C>, ctx));
805781
}
806782

783+
/// Probe the nanotlb for `va` using slot AT (Fetch=0, Read=1, Write=2).
784+
/// On hit: returns the cached result with no function-pointer call.
785+
/// On miss: calls `translate_fn` (the slow path) and fills the slot on success.
786+
#[inline(always)]
787+
fn nanotlb_translate<const AT: u8>(&mut self, va: u64) -> TranslateResult {
788+
let slot = &self.core.nanotlb[AT as usize];
789+
if slot.matches(va) {
790+
return TranslateResult::ok(slot.phys_addr(va), slot.cache_attr_raw());
791+
}
792+
let at = unsafe { std::mem::transmute::<u8, AccessType>(AT) };
793+
let result = (self.translate_fn)(self, va, at);
794+
if !result.is_exception() {
795+
self.core.nanotlb[AT as usize].fill_raw(va, result.phys as u64, result.status & 0x7);
796+
}
797+
result
798+
}
799+
807800
/// Re-derive `translate_fn` from the current CP0 Status register.
808801
/// Must be called after any write to Status (done automatically via the status callback)
809802
/// and at init/reset time.
@@ -1487,7 +1480,7 @@ For R4000SC/MC CPUs:
14871480
let translate_result = if DEBUG {
14881481
self.translate_impl::<true>(virt_addr, AccessType::Fetch)
14891482
} else {
1490-
(self.translate_fn)(self, virt_addr, AccessType::Fetch)
1483+
self.nanotlb_translate::<{AccessType::Fetch as u8}>(virt_addr)
14911484
};
14921485
if translate_result.is_exception() { return Err(translate_result.status); }
14931486
let phys_addr = translate_result.phys;
@@ -1563,11 +1556,10 @@ For R4000SC/MC CPUs:
15631556
return Err(exec_exception(EXC_ADEL));
15641557
}
15651558

1566-
let access_type = if DEBUG { AccessType::Debug } else { AccessType::Read };
15671559
let translate_result = if DEBUG {
1568-
self.translate_impl::<true>(virt_addr, access_type)
1560+
self.translate_impl::<true>(virt_addr, AccessType::Debug)
15691561
} else {
1570-
(self.translate_fn)(self, virt_addr, access_type)
1562+
self.nanotlb_translate::<{AccessType::Read as u8}>(virt_addr)
15711563
};
15721564
if translate_result.is_exception() { return Err(translate_result.status); }
15731565
{
@@ -1674,11 +1666,10 @@ For R4000SC/MC CPUs:
16741666
return exec_exception(EXC_ADES);
16751667
}
16761668

1677-
let access_type = if DEBUG { AccessType::Debug } else { AccessType::Write };
16781669
let translate_result = if DEBUG {
1679-
self.translate_impl::<true>(virt_addr, access_type)
1670+
self.translate_impl::<true>(virt_addr, AccessType::Debug)
16801671
} else {
1681-
(self.translate_fn)(self, virt_addr, access_type)
1672+
self.nanotlb_translate::<{AccessType::Write as u8}>(virt_addr)
16821673
};
16831674
if translate_result.is_exception() { return translate_result.status; }
16841675
let phys_addr = translate_result.phys as u64;
@@ -1747,11 +1738,10 @@ For R4000SC/MC CPUs:
17471738
}
17481739

17491740
// virt_addr is already doubleword-aligned (callers guarantee this)
1750-
let access_type = if DEBUG { AccessType::Debug } else { AccessType::Write };
17511741
let translate_result = if DEBUG {
1752-
self.translate_impl::<true>(virt_addr, access_type)
1742+
self.translate_impl::<true>(virt_addr, AccessType::Debug)
17531743
} else {
1754-
(self.translate_fn)(self, virt_addr, access_type)
1744+
self.nanotlb_translate::<{AccessType::Write as u8}>(virt_addr)
17551745
};
17561746
if translate_result.is_exception() { return translate_result.status; }
17571747
let phys_addr = translate_result.phys as u64;
@@ -2860,7 +2850,7 @@ For R4000SC/MC CPUs:
28602850

28612851
let phys_addr = if needs_translation {
28622852
// Hit operations need address translation
2863-
let tr = (self.translate_fn)(self, virt_addr, AccessType::Read);
2853+
let tr = self.nanotlb_translate::<{AccessType::Read as u8}>(virt_addr);
28642854
if tr.is_exception() { return tr.status; }
28652855
tr.phys as u64
28662856
} else {
@@ -2901,7 +2891,7 @@ For R4000SC/MC CPUs:
29012891
self.core.write_gpr(rt_reg, value as i32 as i64 as u64);
29022892
// Store physical address in LLAddr register
29032893
// The LLAddr register stores bits 35..4 of the physical address
2904-
let tr = (self.translate_fn)(self, virt_addr, AccessType::Read);
2894+
let tr = self.nanotlb_translate::<{AccessType::Read as u8}>(virt_addr);
29052895
if !tr.is_exception() {
29062896
let lladdr = (tr.phys >> 4) as u32;
29072897
self.cache.set_lladdr(lladdr);
@@ -2928,7 +2918,7 @@ For R4000SC/MC CPUs:
29282918
}
29292919

29302920
// Check if address matches the LL address
2931-
let tr = (self.translate_fn)(self, virt_addr, AccessType::Write);
2921+
let tr = self.nanotlb_translate::<{AccessType::Write as u8}>(virt_addr);
29322922
if tr.is_exception() {
29332923
self.cache.set_llbit(false);
29342924
return tr.status;
@@ -2960,7 +2950,7 @@ For R4000SC/MC CPUs:
29602950
Ok(value) => {
29612951
self.core.write_gpr(rt_reg, value);
29622952
// Store physical address in LLAddr register
2963-
let tr = (self.translate_fn)(self, virt_addr, AccessType::Read);
2953+
let tr = self.nanotlb_translate::<{AccessType::Read as u8}>(virt_addr);
29642954
if !tr.is_exception() {
29652955
let lladdr = (tr.phys >> 4) as u32;
29662956
self.cache.set_lladdr(lladdr);
@@ -2987,7 +2977,7 @@ For R4000SC/MC CPUs:
29872977
}
29882978

29892979
// Check if address matches the LLD address
2990-
let tr = (self.translate_fn)(self, virt_addr, AccessType::Write);
2980+
let tr = self.nanotlb_translate::<{AccessType::Write as u8}>(virt_addr);
29912981
if tr.is_exception() {
29922982
self.cache.set_llbit(false);
29932983
return tr.status;

0 commit comments

Comments
 (0)