444545ca379f1eb1bb5457dc1b964dc892a4cd93
[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 .bss
28         .align  4
29         .global dynarec_local
30         .type   dynarec_local, %object
31         .size   dynarec_local, LO_dynarec_local_size
32 dynarec_local:
33         .space  LO_dynarec_local_size
34
35 #define DRC_VAR_(name, vname, size_) \
36         vname = dynarec_local + LO_##name; \
37         .global vname; \
38         .type   vname, %object; \
39         .size   vname, size_
40
41 #define DRC_VAR(name, size_) \
42         DRC_VAR_(name, ESYM(name), size_)
43
44 DRC_VAR(next_interupt, 4)
45 DRC_VAR(cycle_count, 4)
46 DRC_VAR(last_count, 4)
47 DRC_VAR(pending_exception, 4)
48 DRC_VAR(stop, 4)
49 DRC_VAR(branch_target, 4)
50 DRC_VAR(address, 4)
51 #DRC_VAR(align0, 16) /* unused/alignment */
52 DRC_VAR(psxRegs, LO_psxRegs_end - LO_psxRegs)
53
54 /* psxRegs */
55 #DRC_VAR(reg, 128)
56 DRC_VAR(lo, 4)
57 DRC_VAR(hi, 4)
58 DRC_VAR(reg_cop0, 128)
59 DRC_VAR(reg_cop2d, 128)
60 DRC_VAR(reg_cop2c, 128)
61 DRC_VAR(pcaddr, 4)
62 #DRC_VAR(code, 4)
63 #DRC_VAR(cycle, 4)
64 #DRC_VAR(interrupt, 4)
65 #DRC_VAR(intCycle, 256)
66
67 DRC_VAR(rcnts, 7*4*4)
68 DRC_VAR(inv_code_start, 4)
69 DRC_VAR(inv_code_end, 4)
70 DRC_VAR(mem_rtab, 8)
71 DRC_VAR(mem_wtab, 8)
72 DRC_VAR(psxH_ptr, 8)
73 DRC_VAR(invc_ptr, 8)
74 DRC_VAR(zeromem_ptr, 8)
75 DRC_VAR(scratch_buf_ptr, 8)
76 #DRC_VAR(align1, 16) /* unused/alignment */
77 DRC_VAR(mini_ht, 256)
78 DRC_VAR(restore_candidate, 512)
79
80
81         .text
82         .align  2
83
84 /* r0 = virtual target address */
85 /* r1 = instruction to patch */
86 .macro dyna_linker_main
87         /* XXX TODO: should be able to do better than this... */
88         bl      get_addr_ht
89         br      x0
90 .endm
91
92
93 FUNCTION(dyna_linker):
94         /* r0 = virtual target address */
95         /* r1 = instruction to patch */
96         dyna_linker_main
97         .size   dyna_linker, .-dyna_linker
98
99 FUNCTION(exec_pagefault):
100         /* r0 = instruction pointer */
101         /* r1 = fault address */
102         /* r2 = cause */
103         bl      abort
104         .size   exec_pagefault, .-exec_pagefault
105
106 /* Special dynamic linker for the case where a page fault
107    may occur in a branch delay slot */
108 FUNCTION(dyna_linker_ds):
109         /* r0 = virtual target address */
110         /* r1 = instruction to patch */
111         dyna_linker_main
112         .size   dyna_linker_ds, .-dyna_linker_ds
113
114         .align  2
115 FUNCTION(cc_interrupt):
116         ldr     w0, [rFP, #LO_last_count]
117         mov     w2, #0x1fc
118         add     rCC, w0, rCC
119         str     wzr, [rFP, #LO_pending_exception]
120         and     w2, w2, rCC, lsr #17
121         add     x3, rFP, #LO_restore_candidate
122         str     rCC, [rFP, #LO_cycle]           /* PCSX cycles */
123 #       str     rCC, [rFP, #LO_reg_cop0+36]     /* Count */
124         ldr     w19, [x3, w2, uxtw]
125         mov     x21, lr
126         cbnz    w19, 4f
127 1:
128         bl      gen_interupt
129         mov     lr, x21
130         ldr     rCC, [rFP, #LO_cycle]
131         ldr     w0, [rFP, #LO_next_interupt]
132         ldr     w1, [rFP, #LO_pending_exception]
133         ldr     w2, [rFP, #LO_stop]
134         str     w0, [rFP, #LO_last_count]
135         sub     rCC, rCC, w0
136         cbnz    w2, new_dyna_leave
137         cbnz    w1, 2f
138         ret
139 2:
140         ldr     w0, [rFP, #LO_pcaddr]
141         bl      get_addr_ht
142         br      x0
143 4:
144         /* Move 'dirty' blocks to the 'clean' list */
145         lsl     w20, w2, #3
146         str     wzr, [x3, w2, uxtw]
147 5:
148         mov     w0, w20
149         add     w20, w20, #1
150         tbz     w19, #0, 6f
151         bl      clean_blocks
152 6:
153         lsr     w19, w19, #1
154         tst     w20, #31
155         bne     5b
156         b       1b
157         .size   cc_interrupt, .-cc_interrupt
158
159         .align  2
160 FUNCTION(fp_exception):
161         mov     w2, #0x10000000
162 0:
163         ldr     w1, [fp, #LO_reg_cop0+48] /* Status */
164         mov     w3, #0x80000000
165         str     w0, [fp, #LO_reg_cop0+56] /* EPC */
166         orr     w1, w1, #2
167         add     w2, w2, #0x2c
168         str     w1, [fp, #LO_reg_cop0+48] /* Status */
169         str     w2, [fp, #LO_reg_cop0+52] /* Cause */
170         add     w0, w3, #0x80
171         bl      get_addr_ht
172         br      x0
173         .size   fp_exception, .-fp_exception
174         .align  2
175 FUNCTION(fp_exception_ds):
176         mov     w2, #0x90000000 /* Set high bit if delay slot */
177         b       0b
178         .size   fp_exception_ds, .-fp_exception_ds
179
180         .align  2
181 FUNCTION(jump_syscall):
182         ldr     w1, [fp, #LO_reg_cop0+48] /* Status */
183         mov     w3, #0x80000000
184         str     w0, [fp, #LO_reg_cop0+56] /* EPC */
185         orr     w1, w1, #2
186         mov     w2, #0x20
187         str     w1, [fp, #LO_reg_cop0+48] /* Status */
188         str     w2, [fp, #LO_reg_cop0+52] /* Cause */
189         add     w0, w3, #0x80
190         bl      get_addr_ht
191         br      x0
192         .size   jump_syscall, .-jump_syscall
193         .align  2
194
195         /* note: psxException might do recursive recompiler call from it's HLE code,
196          * so be ready for this */
197 FUNCTION(jump_to_new_pc):
198         ldr     w1, [fp, #LO_next_interupt]
199         ldr     rCC, [fp, #LO_cycle]
200         ldr     w0, [fp, #LO_pcaddr]
201         sub     rCC, rCC, w1
202         str     w1, [fp, #LO_last_count]
203         bl      get_addr_ht
204         br      x0
205         .size   jump_to_new_pc, .-jump_to_new_pc
206
207         /* stack must be aligned by 16, and include space for save_regs() use */
208         .align  2
209 FUNCTION(new_dyna_start):
210         stp     x29, x30, [sp, #-SSP_ALL]!
211         ldr     w1,  [x0, #LO_next_interupt]
212         ldr     w2,  [x0, #LO_cycle]
213         stp     x19, x20, [sp, #16*1]
214         stp     x21, x22, [sp, #16*2]
215         stp     x23, x24, [sp, #16*3]
216         stp     x25, x26, [sp, #16*4]
217         stp     x27, x28, [sp, #16*5]
218         mov     rFP, x0
219         ldr     w0,  [rFP, #LO_pcaddr]
220         str     w1,  [rFP, #LO_last_count]
221         sub     rCC, w2, w1
222         bl      get_addr_ht
223         br      x0
224         .size   new_dyna_start, .-new_dyna_start
225
226         .align  2
227 FUNCTION(new_dyna_leave):
228         ldr     w0,  [rFP, #LO_last_count]
229         add     rCC, rCC, w0
230         str     rCC, [rFP, #LO_cycle]
231         ldp     x19, x20, [sp, #16*1]
232         ldp     x21, x22, [sp, #16*2]
233         ldp     x23, x24, [sp, #16*3]
234         ldp     x25, x26, [sp, #16*4]
235         ldp     x27, x28, [sp, #16*5]
236         ldp     x29, x30, [sp], #SSP_ALL
237         ret
238         .size   new_dyna_leave, .-new_dyna_leave
239
240 /* --------------------------------------- */
241
242 .align  2
243
244 .macro memhandler_pre
245         /* w0 = adddr/data, x1 = rhandler, w2 = cycles, x3 = whandler */
246         ldr     w4, [rFP, #LO_last_count]
247         add     w4, w4, w2
248         str     w4, [rFP, #LO_cycle]
249 .endm
250
251 .macro memhandler_post
252         ldr     w2, [rFP, #LO_next_interupt]
253         ldr     w1, [rFP, #LO_cycle]
254         sub     w0, w1, w2
255         str     w2, [rFP, #LO_last_count]
256 .endm
257
258 FUNCTION(do_memhandler_pre):
259         memhandler_pre
260         ret
261
262 FUNCTION(do_memhandler_post):
263         memhandler_post
264         ret
265
266 .macro pcsx_read_mem readop tab_shift
267         /* w0 = address, x1 = handler_tab, w2 = cycles */
268         ubfm    w4, w0, #\tab_shift, #11
269         ldr     x3, [x1, w4, uxtw #3]
270         adds    x3, x3, x3
271         bcs     0f
272         \readop w0, [x3, w4, uxtw #\tab_shift]
273         ret
274 0:
275         stp     xzr, x30, [sp, #-16]!
276         memhandler_pre
277         blr     x3
278 .endm
279
280 FUNCTION(jump_handler_read8):
281         add     x1, x1, #0x1000/4*8 + 0x1000/2*8  /* shift to r8 part */
282         pcsx_read_mem ldrb, 0
283         b       handler_read_end
284
285 FUNCTION(jump_handler_read16):
286         add     x1, x1, #0x1000/4*8               /* shift to r16 part */
287         pcsx_read_mem ldrh, 1
288         b       handler_read_end
289
290 FUNCTION(jump_handler_read32):
291         pcsx_read_mem ldr, 2
292
293 handler_read_end:
294         ldp     xzr, x30, [sp], #16
295         ret
296
297 .macro pcsx_write_mem wrtop movop tab_shift
298         /* w0 = address, w1 = data, w2 = cycles, x3 = handler_tab */
299         ubfm    w4, w0, #\tab_shift, #11
300         ldr     x3, [x3, w4, uxtw #3]
301         adds    x3, x3, x3
302         bcs     0f
303         mov     w0, w2                    /* cycle return */
304         \wrtop  w1, [x3, w4, uxtw #\tab_shift]
305         ret
306 0:
307         stp     xzr, x30, [sp, #-16]!
308         str     w0, [rFP, #LO_address]    /* some handlers still need it... */
309         \movop  w0, w1
310         memhandler_pre
311         blr     x3
312 .endm
313
314 FUNCTION(jump_handler_write8):
315         add     x3, x3, #0x1000/4*8 + 0x1000/2*8  /* shift to r8 part */
316         pcsx_write_mem strb uxtb 0
317         b       handler_write_end
318
319 FUNCTION(jump_handler_write16):
320         add     x3, x3, #0x1000/4*8               /* shift to r16 part */
321         pcsx_write_mem strh uxth 1
322         b       handler_write_end
323
324 FUNCTION(jump_handler_write32):
325         pcsx_write_mem str mov 2
326
327 handler_write_end:
328         memhandler_post
329         ldp     xzr, x30, [sp], #16
330         ret
331
332 FUNCTION(jump_handle_swl):
333         /* w0 = address, w1 = data, w2 = cycles */
334         ldr     x3, [fp, #LO_mem_wtab]
335         mov     w4, w0, lsr #12
336         ldr     x3, [x3, w4, uxtw #3]
337         adds    x3, x3, x3
338         bcs     4f
339         add     x3, x0, x3
340         mov     w0, w2
341         tbz     x3, #1, 10f     // & 2
342         tbz     x3, #0, 2f      // & 1
343 3:
344         stur    w1, [x3, #-3]
345         ret
346 2:
347         lsr     w2, w1, #8
348         lsr     w1, w1, #24
349         sturh   w2, [x3, #-2]
350         strb    w1, [x3]
351         ret
352 10:
353         tbz     x3, #0, 0f      // & 1
354 1:
355         lsr     w1, w1, #16
356         sturh   w1, [x3, #-1]
357         ret
358 0:
359         lsr     w2, w1, #24
360         strb    w2, [x3]
361         ret
362 4:
363         mov     w0, w2          // todo
364         bl      abort
365         ret
366
367 FUNCTION(jump_handle_swr):
368         /* w0 = address, w1 = data, w2 = cycles */
369         ldr     x3, [fp, #LO_mem_wtab]
370         mov     w4, w0, lsr #12
371         ldr     x3, [x3, w4, uxtw #3]
372         adds    x3, x3, x3
373         bcs     4f
374         add     x3, x0, x3
375         mov     w0, w2
376         tbz     x3, #1, 10f     // & 2
377         tbz     x3, #0, 2f      // & 1
378 3:
379         strb    w1, [x3]
380         ret
381 2:
382         strh    w1, [x3]
383         ret
384 10:
385         tbz     x3, #0, 0f      // & 1
386 1:
387         lsr     w2, w1, #8
388         strb    w1, [x3]
389         sturh   w2, [x3, #1]
390         ret
391 0:
392         str     w1, [x3]
393         ret
394 4:
395         mov     w0, w2          // todo
396         bl      abort
397         ret
398