@@ -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.
619595fn 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}
622598fn 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}
625601fn 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}
628604fn 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}
631607fn 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}
634610fn 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