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