1+ use crate :: core:: emu:: get_jit;
12use crate :: core:: CpuType ;
23use crate :: core:: CpuType :: ARM9 ;
34use crate :: jit:: assembler:: block_asm:: BlockAsm ;
5+ use crate :: jit:: assembler:: { BlockOperand , BlockReg } ;
46use crate :: jit:: inst_info:: InstInfo ;
5- use crate :: jit:: jit_asm:: JitAsm ;
7+ use crate :: jit:: jit_asm:: { JitAsm , JitRuntimeData , BLOCK_LINK_STACK_SIZE } ;
68use crate :: jit:: op:: Op ;
79use crate :: jit:: reg:: { reg_reserve, Reg , RegReserve } ;
8- use crate :: jit:: Cond ;
10+ use crate :: jit:: { jit_memory_map , Cond , MemoryAmount , ShiftType } ;
911
1012pub enum JitBranchInfo {
1113 Idle ,
@@ -80,15 +82,15 @@ impl<'a, const CPU: CpuType> JitAsm<'a, CPU> {
8082 let branch_info = Self :: analyze_branch_label :: < THUMB > ( & self . jit_buf . insts , self . jit_buf . current_index , cond, self . jit_buf . current_pc , target_pc) ;
8183
8284 if let JitBranchInfo :: Local ( target_index) = branch_info {
83- let target_pre_cycle_count_sum = if target_index == 0 { 0 } else { self . jit_buf . insts_cycle_counts [ target_index] } ;
85+ let target_pre_cycle_count_sum = self . jit_buf . insts_cycle_counts [ target_index] - self . jit_buf . insts [ target_index] . cycle as u16 ;
8486
8587 let backed_up_cpsr_reg = block_asm. new_reg ( ) ;
8688 block_asm. mrs_cpsr ( backed_up_cpsr_reg) ;
8789
8890 self . emit_flush_cycles (
8991 block_asm,
9092 target_pre_cycle_count_sum,
91- |_, block_asm| {
93+ |_, block_asm, _ , _ | {
9294 block_asm. msr_cpsr ( backed_up_cpsr_reg) ;
9395 block_asm. guest_branch ( Cond :: AL , target_pc) ;
9496 } ,
@@ -113,19 +115,105 @@ impl<'a, const CPU: CpuType> JitAsm<'a, CPU> {
113115 block_asm. epilogue ( ) ;
114116 }
115117
116- pub fn emit_branch_reg ( & mut self , block_asm : & mut BlockAsm ) {
118+ pub fn emit_bx ( & mut self , block_asm : & mut BlockAsm ) {
117119 let inst_info = self . jit_buf . current_inst ( ) ;
118120 let branch_to = * inst_info. operands ( ) [ 0 ] . as_reg_no_shift ( ) . unwrap ( ) ;
119121
120- if inst_info. op == Op :: BlxReg {
121- block_asm. mov ( Reg :: LR , self . jit_buf . current_pc + 4 ) ;
122- }
123122 block_asm. mov ( Reg :: PC , branch_to) ;
124123 block_asm. save_context ( ) ;
125124 self . emit_branch_out_metadata ( block_asm) ;
126125 block_asm. epilogue ( ) ;
127126 }
128127
128+ pub fn emit_blx ( & mut self , block_asm : & mut BlockAsm ) {
129+ let inst_info = self . jit_buf . current_inst ( ) ;
130+ let target_pc_reg = * inst_info. operands ( ) [ 0 ] . as_reg_no_shift ( ) . unwrap ( ) ;
131+
132+ block_asm. mov ( Reg :: LR , self . jit_buf . current_pc + 4 ) ;
133+ self . emit_branch_reg_common ( block_asm, target_pc_reg. into ( ) ) ;
134+ }
135+
136+ pub fn emit_branch_reg_common ( & mut self , block_asm : & mut BlockAsm , target_pc_reg : BlockReg ) {
137+ block_asm. mov ( Reg :: PC , target_pc_reg) ;
138+ block_asm. save_context ( ) ;
139+
140+ self . emit_flush_cycles (
141+ block_asm,
142+ 0 ,
143+ |asm, block_asm, breakout_label, runtime_data_addr_reg| {
144+ let block_link_ptr_reg = block_asm. new_reg ( ) ;
145+
146+ block_asm. transfer_read ( block_link_ptr_reg, runtime_data_addr_reg, JitRuntimeData :: get_block_link_ptr_offset ( ) as u32 , false , MemoryAmount :: Byte ) ;
147+
148+ block_asm. cmp ( block_link_ptr_reg, BLOCK_LINK_STACK_SIZE as u32 ) ;
149+ block_asm. branch ( breakout_label, Cond :: EQ ) ;
150+
151+ let block_link_stack_ptr_reg = block_asm. new_reg ( ) ;
152+ block_asm. add ( block_link_stack_ptr_reg, runtime_data_addr_reg, JitRuntimeData :: get_block_link_stack_offset ( ) as u32 ) ;
153+ block_asm. add ( block_link_stack_ptr_reg, block_link_stack_ptr_reg, ( block_link_ptr_reg. into ( ) , ShiftType :: Lsl , BlockOperand :: from ( 3 ) ) ) ;
154+ block_asm. transfer_write ( Reg :: LR , block_link_stack_ptr_reg, 0 , false , MemoryAmount :: Word ) ;
155+
156+ let return_pre_cycle_count_sum_reg = block_asm. new_reg ( ) ;
157+ block_asm. mov ( return_pre_cycle_count_sum_reg, asm. jit_buf . insts_cycle_counts [ asm. jit_buf . current_index ] as u32 ) ;
158+ block_asm. transfer_write ( return_pre_cycle_count_sum_reg, block_link_stack_ptr_reg, 4 , false , MemoryAmount :: Half ) ;
159+
160+ block_asm. add ( block_link_ptr_reg, block_link_ptr_reg, 1 ) ;
161+ block_asm. transfer_write ( block_link_ptr_reg, runtime_data_addr_reg, JitRuntimeData :: get_block_link_ptr_offset ( ) as u32 , false , MemoryAmount :: Byte ) ;
162+
163+ block_asm. free_reg ( return_pre_cycle_count_sum_reg) ;
164+ block_asm. free_reg ( block_link_stack_ptr_reg) ;
165+ block_asm. free_reg ( block_link_ptr_reg) ;
166+
167+ let target_addr_reg = block_asm. new_reg ( ) ;
168+ let pc_mask_reg = block_asm. new_reg ( ) ;
169+
170+ // Align pc to !1 or !3
171+ block_asm. mvn ( pc_mask_reg, 1 ) ;
172+ block_asm. tst ( target_pc_reg, 1 ) ;
173+ block_asm. start_cond_block ( Cond :: EQ ) ;
174+ block_asm. mvn ( pc_mask_reg, 3 ) ;
175+ block_asm. end_cond_block ( ) ;
176+
177+ block_asm. and ( target_addr_reg, target_pc_reg, pc_mask_reg) ;
178+
179+ let map_ptr = get_jit ! ( asm. emu) . jit_memory_map . get_map_ptr :: < CPU > ( ) ;
180+
181+ let map_ptr_reg = block_asm. new_reg ( ) ;
182+ let map_index_reg = block_asm. new_reg ( ) ;
183+ let map_entry_base_ptr_reg = block_asm. new_reg ( ) ;
184+
185+ block_asm. mov ( map_ptr_reg, map_ptr as u32 ) ;
186+ block_asm. mov ( map_index_reg, ( target_addr_reg. into ( ) , ShiftType :: Lsr , BlockOperand :: from ( jit_memory_map:: BLOCK_SHIFT as u32 + 1 ) ) ) ;
187+ block_asm. transfer_read (
188+ map_entry_base_ptr_reg,
189+ map_ptr_reg,
190+ ( map_index_reg. into ( ) , ShiftType :: Lsl , BlockOperand :: from ( 2 ) ) ,
191+ false ,
192+ MemoryAmount :: Word ,
193+ ) ;
194+ let block_size_mask_reg = map_index_reg;
195+ block_asm. mov ( block_size_mask_reg, ( jit_memory_map:: BLOCK_SIZE as u32 - 1 ) << 2 ) ;
196+ block_asm. and ( target_addr_reg, block_size_mask_reg, ( target_addr_reg. into ( ) , ShiftType :: Lsl , BlockOperand :: from ( 1 ) ) ) ;
197+
198+ let entry_fn_reg = block_asm. new_reg ( ) ;
199+ block_asm. transfer_read ( entry_fn_reg, map_entry_base_ptr_reg, target_addr_reg, false , MemoryAmount :: Word ) ;
200+
201+ block_asm. call1 ( entry_fn_reg, 0 ) ;
202+
203+ block_asm. free_reg ( entry_fn_reg) ;
204+ block_asm. free_reg ( map_entry_base_ptr_reg) ;
205+ block_asm. free_reg ( map_index_reg) ;
206+ block_asm. free_reg ( map_ptr_reg) ;
207+ block_asm. free_reg ( pc_mask_reg) ;
208+ block_asm. free_reg ( target_addr_reg) ;
209+ } ,
210+ |asm, block_asm| {
211+ asm. emit_branch_out_metadata ( block_asm) ;
212+ block_asm. epilogue ( ) ;
213+ } ,
214+ ) ;
215+ }
216+
129217 pub fn emit_blx_label ( & mut self , block_asm : & mut BlockAsm ) {
130218 if CPU != ARM9 {
131219 return ;
@@ -134,10 +222,12 @@ impl<'a, const CPU: CpuType> JitAsm<'a, CPU> {
134222 let relative_pc = * self . jit_buf . current_inst ( ) . operands ( ) [ 0 ] . as_imm ( ) . unwrap ( ) as i32 + 8 ;
135223 let target_pc = ( self . jit_buf . current_pc as i32 + relative_pc) as u32 ;
136224
225+ let target_pc_reg = block_asm. new_reg ( ) ;
226+ block_asm. mov ( target_pc_reg, target_pc | 1 ) ;
227+
137228 block_asm. mov ( Reg :: LR , self . jit_buf . current_pc + 4 ) ;
138- block_asm. mov ( Reg :: PC , target_pc | 1 ) ;
139- block_asm. save_context ( ) ;
140- self . emit_branch_out_metadata ( block_asm) ;
141- block_asm. epilogue ( ) ;
229+ self . emit_branch_reg_common ( block_asm, target_pc_reg) ;
230+
231+ block_asm. free_reg ( target_pc_reg) ;
142232 }
143233}
0 commit comments