11use crate :: core:: emu:: { get_mmu, get_regs} ;
22use crate :: core:: CpuType ;
33use crate :: jit:: assembler:: block_asm:: BlockAsm ;
4- use crate :: jit:: assembler:: BlockOperand ;
4+ use crate :: jit:: assembler:: { BlockOperand , BlockReg } ;
55use crate :: jit:: inst_info:: Operand ;
66use crate :: jit:: inst_mem_handler:: { inst_mem_handler, inst_mem_handler_multiple, inst_mem_handler_swp} ;
77use crate :: jit:: jit_asm:: JitAsm ;
@@ -188,10 +188,14 @@ impl<const CPU: CpuType> JitAsm<'_, CPU> {
188188 block_asm. mov ( op0, ( fast_read_value_reg, ShiftType :: Ror , fast_read_addr_masked_reg) ) ;
189189 }
190190
191- block_asm. nop ( ) ;
192191 block_asm. branch_fallthrough ( continue_label, Cond :: AL ) ;
193-
194192 block_asm. label ( slow_read_label) ;
193+
194+ block_asm. restore_reg ( op0) ;
195+ if amount == MemoryAmount :: Double {
196+ block_asm. restore_reg ( Reg :: from ( op0 as u8 + 1 ) ) ;
197+ }
198+
195199 block_asm. save_context ( ) ;
196200
197201 let op0_addr = get_regs ! ( self . emu, CPU ) . get_reg ( op0) as * const _ as u32 ;
@@ -246,13 +250,76 @@ impl<const CPU: CpuType> JitAsm<'_, CPU> {
246250
247251 let mut pre = inst_info. op . mem_transfer_pre ( ) ;
248252 let decrement = inst_info. op . mem_transfer_decrement ( ) ;
249- if decrement {
250- pre = !pre;
251- }
252253 let write_back = inst_info. op . mem_transfer_write_back ( ) ;
253254
254255 let op0 = * inst_info. operands ( ) [ 0 ] . as_reg_no_shift ( ) . unwrap ( ) ;
255256
257+ let is_valid = !rlist. is_empty ( ) && ( !write_back || !rlist. is_reserved ( op0) ) ;
258+
259+ let slow_read_label = block_asm. new_label ( ) ;
260+ let continue_label = block_asm. new_label ( ) ;
261+
262+ if is_valid && !inst_info. op . mem_is_write ( ) && !inst_info. op . mem_transfer_user ( ) && rlist. len ( ) < RegReserve :: gp ( ) . len ( ) - 2 {
263+ let mut gp_regs = rlist. get_gp_regs ( ) ;
264+ let mut free_gp_regs = if gp_regs. is_empty ( ) {
265+ RegReserve :: gp ( )
266+ } else {
267+ let highest_gp_reg = gp_regs. get_highest_reg ( ) ;
268+ RegReserve :: from ( !( ( 1 << ( highest_gp_reg as u8 + 1 ) ) - 1 ) ) . get_gp_regs ( )
269+ } ;
270+ let mut non_gp_regs = rlist - gp_regs;
271+
272+ while free_gp_regs. len ( ) < non_gp_regs. len ( ) {
273+ let highest_gp_reg = gp_regs. get_highest_reg ( ) ;
274+ gp_regs -= highest_gp_reg;
275+ non_gp_regs += highest_gp_reg;
276+ free_gp_regs = if gp_regs. is_empty ( ) {
277+ RegReserve :: gp ( )
278+ } else {
279+ RegReserve :: from ( !( ( 1 << ( gp_regs. get_highest_reg ( ) as u8 + 1 ) ) - 1 ) ) . get_gp_regs ( )
280+ } ;
281+ }
282+
283+ let mut non_gp_regs_mappings = Vec :: with_capacity ( non_gp_regs. len ( ) ) ;
284+ let mut fixed_regs = RegReserve :: new ( ) ;
285+ while !free_gp_regs. is_empty ( ) && !non_gp_regs. is_empty ( ) {
286+ let fixed_reg = free_gp_regs. pop ( ) . unwrap ( ) ;
287+ fixed_regs += fixed_reg;
288+ non_gp_regs_mappings. push ( ( non_gp_regs. pop ( ) . unwrap ( ) , fixed_reg) ) ;
289+ }
290+
291+ if non_gp_regs. is_empty ( ) {
292+ block_asm. branch ( slow_read_label, Cond :: NV ) ;
293+
294+ let base_reg = block_asm. new_reg ( ) ;
295+ let base_reg_out = block_asm. new_reg ( ) ;
296+ let mmu = get_mmu ! ( self . emu, CPU ) ;
297+ let base_ptr = mmu. get_base_tcm_ptr ( ) ;
298+ block_asm. bic ( base_reg, op0, 0xF0000000 ) ;
299+ block_asm. add ( base_reg, base_reg, base_ptr as u32 ) ;
300+ block_asm. guest_transfer_read_multiple ( base_reg, base_reg_out, gp_regs, fixed_regs, write_back, pre, !decrement) ;
301+
302+ for ( guest_reg, fixed_reg) in non_gp_regs_mappings {
303+ block_asm. mov ( guest_reg, BlockReg :: Fixed ( fixed_reg) ) ;
304+ }
305+
306+ if write_back {
307+ block_asm. sub ( base_reg_out, base_reg_out, base_ptr as u32 ) ;
308+ block_asm. mov ( op0, ( op0. into ( ) , ShiftType :: Lsr , BlockOperand :: from ( 0xF0000000u32 . trailing_zeros ( ) ) ) ) ;
309+ block_asm. bfi ( base_reg_out, op0, 0xF0000000u32 . trailing_zeros ( ) as u8 , 0xF0000000u32 . leading_ones ( ) as u8 ) ;
310+ block_asm. mov ( op0, base_reg_out) ;
311+ }
312+
313+ block_asm. branch_fallthrough ( continue_label, Cond :: AL ) ;
314+
315+ block_asm. free_reg ( base_reg_out) ;
316+ block_asm. free_reg ( base_reg) ;
317+ }
318+ }
319+
320+ if decrement {
321+ pre = !pre;
322+ }
256323 let func_addr: * const ( ) = match ( inst_info. op . mem_is_write ( ) , inst_info. op . mem_transfer_user ( ) , pre, write_back, decrement) {
257324 ( false , false , false , false , false ) => inst_mem_handler_multiple :: < CPU , THUMB , false , false , false , false , false > as _ ,
258325 ( true , false , false , false , false ) => inst_mem_handler_multiple :: < CPU , THUMB , true , false , false , false , false > as _ ,
@@ -288,6 +355,7 @@ impl<const CPU: CpuType> JitAsm<'_, CPU> {
288355 ( true , true , true , true , true ) => inst_mem_handler_multiple :: < CPU , THUMB , true , true , true , true , true > as _ ,
289356 } ;
290357
358+ block_asm. label ( slow_read_label) ;
291359 block_asm. save_context ( ) ;
292360 block_asm. call3 (
293361 func_addr,
@@ -306,8 +374,9 @@ impl<const CPU: CpuType> JitAsm<'_, CPU> {
306374 for reg in restore_regs {
307375 block_asm. restore_reg ( reg) ;
308376 }
309-
310377 block_asm. restore_reg ( Reg :: CPSR ) ;
378+
379+ block_asm. label ( continue_label) ;
311380 }
312381
313382 pub fn emit_swp ( & mut self , block_asm : & mut BlockAsm ) {
0 commit comments