e2f795d3e108945245f198b34ba692640153bdea
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / linkage_arm64.S
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   linkage_arm.s for PCSX                                                *
3  *   Copyright (C) 2009-2011 Ari64                                         *
4  *   Copyright (C) 2021 notaz                                              *
5  *                                                                         *
6  *   This program is free software; you can redistribute it and/or modify  *
7  *   it under the terms of the GNU General Public License as published by  *
8  *   the Free Software Foundation; either version 2 of the License, or     *
9  *   (at your option) any later version.                                   *
10  *                                                                         *
11  *   This program is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14  *   GNU General Public License for more details.                          *
15  *                                                                         *
16  *   You should have received a copy of the GNU General Public License     *
17  *   along with this program; if not, write to the                         *
18  *   Free Software Foundation, Inc.,                                       *
19  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
20  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21
22 #include "arm_features.h"
23 #include "new_dynarec_config.h"
24 #include "assem_arm64.h"
25 #include "linkage_offsets.h"
26
27 #ifdef __MACH__
28 #define dynarec_local           ESYM(dynarec_local)
29 #define ndrc_patch_link         ESYM(ndrc_patch_link)
30 #define ndrc_get_addr_ht        ESYM(ndrc_get_addr_ht)
31 #define ndrc_get_addr_ht_param  ESYM(ndrc_get_addr_ht_param)
32 #define gen_interupt            ESYM(gen_interupt)
33 #define psxException            ESYM(psxException)
34 #define execI                   ESYM(execI)
35 #endif
36
37 #if (LO_mem_wtab & 7)
38 #error misligned pointers
39 #endif
40
41 .bss
42         .align  4
43         .global dynarec_local
44         EOBJECT(dynarec_local)
45         ESIZE(dynarec_local, LO_dynarec_local_size)
46 dynarec_local:
47         .space  LO_dynarec_local_size
48
49 #define DRC_VAR_(name, vname, size_) \
50         vname = dynarec_local + LO_##name ASM_SEPARATOR \
51         .globl vname; \
52         EOBJECT(vname); \
53         ESIZE(vname, LO_dynarec_local_size)
54
55 #define DRC_VAR(name, size_) \
56         DRC_VAR_(name, ESYM(name), size_)
57
58 #DRC_VAR(next_interupt, 4)
59 DRC_VAR(cycle_count, 4)
60 DRC_VAR(last_count, 4)
61 #DRC_VAR(stop, 4)
62 DRC_VAR(address, 4)
63 DRC_VAR(hack_addr, 4)
64 DRC_VAR(psxRegs, LO_psxRegs_end - LO_psxRegs)
65
66 /* psxRegs */
67 #DRC_VAR(lo, 4)
68 #DRC_VAR(hi, 4)
69 DRC_VAR(reg_cop2d, 128)
70 DRC_VAR(reg_cop2c, 128)
71 #DRC_VAR(code, 4)
72 #DRC_VAR(cycle, 4)
73 #DRC_VAR(interrupt, 4)
74 #DRC_VAR(intCycle, 256)
75
76 DRC_VAR(rcnts, 7*4*4)
77 DRC_VAR(inv_code_start, 4)
78 DRC_VAR(inv_code_end, 4)
79 DRC_VAR(mem_rtab, 8)
80 DRC_VAR(mem_wtab, 8)
81 DRC_VAR(psxH_ptr, 8)
82 DRC_VAR(invc_ptr, 8)
83 DRC_VAR(zeromem_ptr, 8)
84 DRC_VAR(scratch_buf_ptr, 8)
85 DRC_VAR(ram_offset, 8)
86 DRC_VAR(hash_table_ptr, 8)
87 DRC_VAR(mini_ht, 256)
88
89
90         .text
91         .align  2
92
93 FUNCTION(dyna_linker):
94         /* w0 = virtual target address */
95         /* x1 = instruction to patch */
96 #if 1
97         mov     w19, w0
98         mov     x20, x1
99         /* must not compile - that might expire the caller block */
100         ldr     x0, [rFP, #LO_hash_table_ptr]
101         mov     w1, w19
102         mov     w2, #0 /* ndrc_compile_mode=ndrc_cm_no_compile */
103         bl      ndrc_get_addr_ht_param
104         cbz     x0, 0f
105
106         ldr     w2, [x20]
107         mov     x3, x0
108         sbfiz   x2, x2, 2, 26
109         add     x2, x2, x20
110         mov     x1, x20
111         mov     w0, w19
112         mov     x19, x3
113         bl      ndrc_patch_link
114         br      x19
115 0:
116         mov     w0, w19
117 #endif
118         ldr     x1, [rFP, #LO_hash_table_ptr]
119         bl      ndrc_get_addr_ht
120         br      x0
121         ESIZE(dyna_linker, .-dyna_linker)
122
123         .align  2
124 FUNCTION(cc_interrupt):
125         ldr     w0, [rFP, #LO_last_count]
126         ldr     w22, [rFP, #LO_pcaddr]
127         add     rCC, w0, rCC
128         str     rCC, [rFP, #LO_cycle]           /* PCSX cycles */
129         mov     x21, lr
130 1:
131         add     x0, rFP, #LO_reg_cop0           /* CP0 */
132         bl      gen_interupt
133         mov     lr, x21
134         ldr     rCC, [rFP, #LO_cycle]
135         ldr     w0, [rFP, #LO_pcaddr]
136         ldr     w1, [rFP, #LO_next_interupt]
137         ldrb    w2, [rFP, #LO_stop]
138         str     w1, [rFP, #LO_last_count]
139         sub     rCC, rCC, w1
140         cbnz    w2, new_dyna_leave
141         cmp     w0, w22
142         bne     2f
143         ret
144 2:
145         ldr     x1, [rFP, #LO_hash_table_ptr]
146         bl      ndrc_get_addr_ht
147         br      x0
148         ESIZE(cc_interrupt, .-cc_interrupt)
149
150         .align  2
151 FUNCTION(jump_addrerror_ds): /* R3000E_AdEL / R3000E_AdES in w0 */
152         str     w1, [rFP, #(LO_psxRegs + (34+8)*4)]  /* BadVaddr */
153         mov     w1, #1
154         b       call_psxException
155 FUNCTION(jump_addrerror):
156         str     w1, [rFP, #(LO_psxRegs + (34+8)*4)]  /* BadVaddr */
157         mov     w1, #0
158         b       call_psxException
159 FUNCTION(jump_overflow_ds):
160         mov     w0, #(12<<2)  /* R3000E_Ov */
161         mov     w1, #1
162         b       call_psxException
163 FUNCTION(jump_overflow):
164         mov     w0, #(12<<2)
165         mov     w1, #0
166         b       call_psxException
167 FUNCTION(jump_break_ds):
168         mov     w0, #(9<<2)  /* R3000E_Bp */
169         mov     w1, #1
170         b       call_psxException
171 FUNCTION(jump_break):
172         mov     w0, #(9<<2)
173         mov     w1, #0
174         b       call_psxException
175 FUNCTION(jump_syscall_ds):
176         mov     w0, #(8<<2)  /* R3000E_Syscall */
177         mov     w1, #2
178         b       call_psxException
179 FUNCTION(jump_syscall):
180         mov     w0, #(8<<2)
181         mov     w1, #0
182
183 call_psxException:
184         ldr     w3, [rFP, #LO_last_count]
185         str     w2, [rFP, #LO_pcaddr]
186         add     rCC, w3, rCC
187         str     rCC, [rFP, #LO_cycle]           /* PCSX cycles */
188         add     x2, rFP, #LO_reg_cop0           /* CP0 */
189         bl      psxException
190
191         /* note: psxException might do recursive recompiler call from it's HLE code,
192          * so be ready for this */
193 FUNCTION(jump_to_new_pc):
194         ldrb    w2, [rFP, #LO_stop]
195         ldr     w1, [rFP, #LO_next_interupt]
196         ldr     rCC, [rFP, #LO_cycle]
197         ldr     w0, [rFP, #LO_pcaddr]
198         sub     rCC, rCC, w1
199         str     w1, [rFP, #LO_last_count]
200         cbnz    w2, new_dyna_leave
201         ldr     x1, [rFP, #LO_hash_table_ptr]
202         bl      ndrc_get_addr_ht
203         br      x0
204         ESIZE(jump_to_new_pc, .-jump_to_new_pc)
205
206         /* stack must be aligned by 16, and include space for save_regs() use */
207         .align  2
208 FUNCTION(new_dyna_start_at):
209         stp     x29, x30, [sp, #-SSP_ALL]!
210         mov     rFP, x0
211         b       new_dyna_start_at_e
212
213 FUNCTION(new_dyna_start):
214         stp     x29, x30, [sp, #-SSP_ALL]!
215         mov     rFP, x0
216         ldr     w0,  [rFP, #LO_pcaddr]
217         ldr     x1,  [rFP, #LO_hash_table_ptr]
218         bl      ndrc_get_addr_ht
219         mov     x1,  x0
220 new_dyna_start_at_e:
221         ldr     w3,  [rFP, #LO_next_interupt]
222         ldr     w2,  [rFP, #LO_cycle]
223         stp     x19, x20, [sp, #16*1]
224         stp     x21, x22, [sp, #16*2]
225         stp     x23, x24, [sp, #16*3]
226         stp     x25, x26, [sp, #16*4]
227         stp     x27, x28, [sp, #16*5]
228         str     w3,  [rFP, #LO_last_count]
229         sub     rCC, w2, w3
230         br      x1
231         ESIZE(new_dyna_start, .-new_dyna_start)
232
233         .align  2
234 FUNCTION(new_dyna_leave):
235         ldr     w0,  [rFP, #LO_last_count]
236         add     rCC, rCC, w0
237         str     rCC, [rFP, #LO_cycle]
238         ldp     x19, x20, [sp, #16*1]
239         ldp     x21, x22, [sp, #16*2]
240         ldp     x23, x24, [sp, #16*3]
241         ldp     x25, x26, [sp, #16*4]
242         ldp     x27, x28, [sp, #16*5]
243         ldp     x29, x30, [sp], #SSP_ALL
244         ret
245         ESIZE(new_dyna_leave, .-new_dyna_leave)
246
247 /* --------------------------------------- */
248
249 .align  2
250
251 .macro memhandler_pre
252         /* w0 = addr/data, x1 = rhandler, w2 = cycles, x3 = whandler */
253         ldr     w4, [rFP, #LO_last_count]
254         add     w4, w4, w2
255         str     w4, [rFP, #LO_cycle]
256 .endm
257
258 .macro memhandler_post
259         /* w2 = cycles_out, x3 = tmp */
260         ldr     w3, [rFP, #LO_next_interupt]
261         ldr     w2, [rFP, #LO_cycle]        // memhandlers can modify cc, like dma
262         str     w3, [rFP, #LO_last_count]
263         sub     w2, w2, w3
264 .endm
265
266 FUNCTION(do_memhandler_pre):
267         memhandler_pre
268         ret
269
270 FUNCTION(do_memhandler_post):
271         memhandler_post
272         ret
273
274 .macro pcsx_read_mem readop tab_shift
275         /* w0 = address, x1 = handler_tab, w2 = cycles */
276         ubfm    w4, w0, #\tab_shift, #11
277         ldr     x3, [x1, w4, uxtw #3]
278         adds    x3, x3, x3
279         bcs     0f
280         \readop w0, [x3, w4, uxtw #\tab_shift]
281         ret
282 0:
283         stp     xzr, x30, [sp, #-16]!
284         memhandler_pre
285         blr     x3
286 .endm
287
288 FUNCTION(jump_handler_read8):
289         add     x1, x1, #0x1000/4*8 + 0x1000/2*8  /* shift to r8 part */
290         pcsx_read_mem ldrb, 0
291         ldp     xzr, x30, [sp], #16
292         ret
293
294 FUNCTION(jump_handler_read16):
295         add     x1, x1, #0x1000/4*8               /* shift to r16 part */
296         pcsx_read_mem ldrh, 1
297         ldp     xzr, x30, [sp], #16
298         ret
299
300 FUNCTION(jump_handler_read32):
301         pcsx_read_mem ldr, 2
302         /* memhandler_post */
303         ldp     xzr, x30, [sp], #16
304         ret
305
306 .macro pcsx_write_mem wrtop movop tab_shift
307         /* w0 = address, w1 = data, w2 = cycles, x3 = handler_tab */
308         ubfm    w4, w0, #\tab_shift, #11
309         ldr     x3, [x3, w4, uxtw #3]
310         adds    x3, x3, x3
311         bcs     0f
312         \wrtop  w1, [x3, w4, uxtw #\tab_shift]
313         ret
314 0:
315         stp     xzr, x30, [sp, #-16]!
316         str     w0, [rFP, #LO_address]    /* some handlers still need it... */
317         \movop  w0, w1
318         memhandler_pre
319         blr     x3
320 .endm
321
322 FUNCTION(jump_handler_write8):
323         add     x3, x3, #0x1000/4*8 + 0x1000/2*8  /* shift to r8 part */
324         pcsx_write_mem strb, uxtb, 0
325         b       handler_write_end
326
327 FUNCTION(jump_handler_write16):
328         add     x3, x3, #0x1000/4*8               /* shift to r16 part */
329         pcsx_write_mem strh, uxth, 1
330         b       handler_write_end
331
332 FUNCTION(jump_handler_write32):
333         pcsx_write_mem str, mov, 2
334
335 handler_write_end:
336         memhandler_post
337         ldp     xzr, x30, [sp], #16
338         ret
339
340 FUNCTION(jump_handle_swl):
341         /* w0 = address, w1 = data, w2 = cycles */
342         ldr     x3, [rFP, #LO_mem_wtab]
343         orr     w4, wzr, w0, lsr #12
344         ldr     x3, [x3, w4, uxtw #3]
345         adds    x3, x3, x3
346         bcs     jump_handle_swx_interp
347         add     x3, x0, x3
348         mov     w0, w2
349         tbz     x3, #1, 10f     // & 2
350         tbz     x3, #0, 2f      // & 1
351 3:
352         stur    w1, [x3, #-3]
353         ret
354 2:
355         lsr     w2, w1, #8
356         lsr     w1, w1, #24
357         sturh   w2, [x3, #-2]
358         strb    w1, [x3]
359         ret
360 10:
361         tbz     x3, #0, 0f      // & 1
362 1:
363         lsr     w1, w1, #16
364         sturh   w1, [x3, #-1]
365         ret
366 0:
367         lsr     w2, w1, #24
368         strb    w2, [x3]
369         ret
370
371 FUNCTION(jump_handle_swr):
372         /* w0 = address, w1 = data, w2 = cycles */
373         ldr     x3, [rFP, #LO_mem_wtab]
374         orr     w4, wzr, w0, lsr #12
375         ldr     x3, [x3, w4, uxtw #3]
376         adds    x3, x3, x3
377         bcs     jump_handle_swx_interp
378         add     x3, x0, x3
379         mov     w0, w2
380         tbz     x3, #1, 10f     // & 2
381         tbz     x3, #0, 2f      // & 1
382 3:
383         strb    w1, [x3]
384         ret
385 2:
386         strh    w1, [x3]
387         ret
388 10:
389         tbz     x3, #0, 0f      // & 1
390 1:
391         lsr     w2, w1, #8
392         strb    w1, [x3]
393         sturh   w2, [x3, #1]
394         ret
395 0:
396         str     w1, [x3]
397         ret
398
399 jump_handle_swx_interp: /* almost never happens */
400         ldr     w3, [rFP, #LO_last_count]
401         add     x0, rFP, #LO_psxRegs
402         add     w2, w3, w2
403         str     w2, [rFP, #LO_cycle]           /* PCSX cycles */
404         bl      execI
405         b       jump_to_new_pc
406
407 #ifdef DRC_DBG
408 #undef do_insn_cmp
409 FUNCTION(do_insn_cmp_arm64):
410         stp     x2,  x3,  [sp, #(SSP_CALLEE_REGS + 2*8)]
411         stp     x4,  x5,  [sp, #(SSP_CALLEE_REGS + 4*8)]
412         stp     x6,  x7,  [sp, #(SSP_CALLEE_REGS + 6*8)]
413         stp     x8,  x9,  [sp, #(SSP_CALLEE_REGS + 8*8)]
414         stp     x10, x11, [sp, #(SSP_CALLEE_REGS + 10*8)]
415         stp     x12, x13, [sp, #(SSP_CALLEE_REGS + 12*8)]
416         stp     x14, x15, [sp, #(SSP_CALLEE_REGS + 14*8)]
417         stp     x16, x17, [sp, #(SSP_CALLEE_REGS + 16*8)]
418         stp     x18, x30, [sp, #(SSP_CALLEE_REGS + 18*8)]
419         bl      do_insn_cmp
420         ldp     x2,  x3,  [sp, #(SSP_CALLEE_REGS + 2*8)]
421         ldp     x4,  x5,  [sp, #(SSP_CALLEE_REGS + 4*8)]
422         ldp     x6,  x7,  [sp, #(SSP_CALLEE_REGS + 6*8)]
423         ldp     x8,  x9,  [sp, #(SSP_CALLEE_REGS + 8*8)]
424         ldp     x10, x11, [sp, #(SSP_CALLEE_REGS + 10*8)]
425         ldp     x12, x13, [sp, #(SSP_CALLEE_REGS + 12*8)]
426         ldp     x14, x15, [sp, #(SSP_CALLEE_REGS + 14*8)]
427         ldp     x16, x17, [sp, #(SSP_CALLEE_REGS + 16*8)]
428         ldp     x18, x30, [sp, #(SSP_CALLEE_REGS + 18*8)]
429         ret
430 #endif