psxbios: completely rework exception handling
[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         mov     x21, lr
101 1:
102         add     x0, rFP, #LO_reg_cop0           /* CP0 */
103         bl      gen_interupt
104         mov     lr, x21
105         ldr     rCC, [rFP, #LO_cycle]
106         ldr     w0, [rFP, #LO_next_interupt]
107         ldr     w1, [rFP, #LO_pending_exception]
108         ldr     w2, [rFP, #LO_stop]
109         str     w0, [rFP, #LO_last_count]
110         sub     rCC, rCC, w0
111         cbnz    w2, new_dyna_leave
112         cbnz    w1, 2f
113         ret
114 2:
115         ldr     w0, [rFP, #LO_pcaddr]
116         bl      ndrc_get_addr_ht
117         br      x0
118         .size   cc_interrupt, .-cc_interrupt
119
120         .align  2
121 FUNCTION(jump_addrerror_ds): /* R3000E_AdEL / R3000E_AdES in w0 */
122         str     w1, [rFP, #(LO_psxRegs + (34+8)*4)]  /* BadVaddr */
123         mov     w1, #1
124         b       call_psxException
125 FUNCTION(jump_addrerror):
126         str     w1, [rFP, #(LO_psxRegs + (34+8)*4)]  /* BadVaddr */
127         mov     w1, #0
128         b       call_psxException
129 FUNCTION(jump_overflow_ds):
130         mov     w0, #(12<<2)  /* R3000E_Ov */
131         mov     w1, #1
132         b       call_psxException
133 FUNCTION(jump_overflow):
134         mov     w0, #(12<<2)
135         mov     w1, #0
136         b       call_psxException
137 FUNCTION(jump_break_ds):
138         mov     w0, #(9<<2)  /* R3000E_Bp */
139         mov     w1, #1
140         b       call_psxException
141 FUNCTION(jump_break):
142         mov     w0, #(9<<2)
143         mov     w1, #0
144         b       call_psxException
145 FUNCTION(jump_syscall_ds):
146         mov     w0, #(8<<2)  /* R3000E_Syscall */
147         mov     w1, #2
148         b       call_psxException
149 FUNCTION(jump_syscall):
150         mov     w0, #(8<<2)
151         mov     w1, #0
152
153 call_psxException:
154         ldr     w3, [rFP, #LO_last_count]
155         str     w2, [rFP, #LO_pcaddr]
156         add     rCC, w3, rCC
157         str     rCC, [rFP, #LO_cycle]           /* PCSX cycles */
158         add     x2, rFP, #LO_reg_cop0           /* CP0 */
159         bl      psxException
160
161         /* note: psxException might do recursive recompiler call from it's HLE code,
162          * so be ready for this */
163 FUNCTION(jump_to_new_pc):
164         ldr     w2, [rFP, #LO_stop]
165         ldr     w1, [rFP, #LO_next_interupt]
166         ldr     rCC, [rFP, #LO_cycle]
167         ldr     w0, [rFP, #LO_pcaddr]
168         sub     rCC, rCC, w1
169         str     w1, [rFP, #LO_last_count]
170         cbnz    w2, new_dyna_leave
171         bl      ndrc_get_addr_ht
172         br      x0
173         .size   jump_to_new_pc, .-jump_to_new_pc
174
175         /* stack must be aligned by 16, and include space for save_regs() use */
176         .align  2
177 FUNCTION(new_dyna_start):
178         stp     x29, x30, [sp, #-SSP_ALL]!
179         ldr     w1,  [x0, #LO_next_interupt]
180         ldr     w2,  [x0, #LO_cycle]
181         stp     x19, x20, [sp, #16*1]
182         stp     x21, x22, [sp, #16*2]
183         stp     x23, x24, [sp, #16*3]
184         stp     x25, x26, [sp, #16*4]
185         stp     x27, x28, [sp, #16*5]
186         mov     rFP, x0
187         ldr     w0,  [rFP, #LO_pcaddr]
188         str     w1,  [rFP, #LO_last_count]
189         sub     rCC, w2, w1
190         bl      ndrc_get_addr_ht
191         br      x0
192         .size   new_dyna_start, .-new_dyna_start
193
194         .align  2
195 FUNCTION(new_dyna_leave):
196         ldr     w0,  [rFP, #LO_last_count]
197         add     rCC, rCC, w0
198         str     rCC, [rFP, #LO_cycle]
199         ldp     x19, x20, [sp, #16*1]
200         ldp     x21, x22, [sp, #16*2]
201         ldp     x23, x24, [sp, #16*3]
202         ldp     x25, x26, [sp, #16*4]
203         ldp     x27, x28, [sp, #16*5]
204         ldp     x29, x30, [sp], #SSP_ALL
205         ret
206         .size   new_dyna_leave, .-new_dyna_leave
207
208 /* --------------------------------------- */
209
210 .align  2
211
212 .macro memhandler_pre
213         /* w0 = adddr/data, x1 = rhandler, w2 = cycles, x3 = whandler */
214         ldr     w4, [rFP, #LO_last_count]
215         add     w4, w4, w2
216         str     w4, [rFP, #LO_cycle]
217 .endm
218
219 .macro memhandler_post
220         ldr     w0, [rFP, #LO_next_interupt]
221         ldr     w2, [rFP, #LO_cycle]        // memhandlers can modify cc, like dma
222         str     w0, [rFP, #LO_last_count]
223         sub     w0, w2, w0
224 .endm
225
226 FUNCTION(do_memhandler_pre):
227         memhandler_pre
228         ret
229
230 FUNCTION(do_memhandler_post):
231         memhandler_post
232         ret
233
234 .macro pcsx_read_mem readop tab_shift
235         /* w0 = address, x1 = handler_tab, w2 = cycles */
236         ubfm    w4, w0, #\tab_shift, #11
237         ldr     x3, [x1, w4, uxtw #3]
238         adds    x3, x3, x3
239         bcs     0f
240         \readop w0, [x3, w4, uxtw #\tab_shift]
241         ret
242 0:
243         stp     xzr, x30, [sp, #-16]!
244         memhandler_pre
245         blr     x3
246 .endm
247
248 FUNCTION(jump_handler_read8):
249         add     x1, x1, #0x1000/4*8 + 0x1000/2*8  /* shift to r8 part */
250         pcsx_read_mem ldrb, 0
251         b       handler_read_end
252
253 FUNCTION(jump_handler_read16):
254         add     x1, x1, #0x1000/4*8               /* shift to r16 part */
255         pcsx_read_mem ldrh, 1
256         b       handler_read_end
257
258 FUNCTION(jump_handler_read32):
259         pcsx_read_mem ldr, 2
260
261 handler_read_end:
262         ldp     xzr, x30, [sp], #16
263         ret
264
265 .macro pcsx_write_mem wrtop movop tab_shift
266         /* w0 = address, w1 = data, w2 = cycles, x3 = handler_tab */
267         ubfm    w4, w0, #\tab_shift, #11
268         ldr     x3, [x3, w4, uxtw #3]
269         adds    x3, x3, x3
270         bcs     0f
271         mov     w0, w2                    /* cycle return */
272         \wrtop  w1, [x3, w4, uxtw #\tab_shift]
273         ret
274 0:
275         stp     xzr, x30, [sp, #-16]!
276         str     w0, [rFP, #LO_address]    /* some handlers still need it... */
277         \movop  w0, w1
278         memhandler_pre
279         blr     x3
280 .endm
281
282 FUNCTION(jump_handler_write8):
283         add     x3, x3, #0x1000/4*8 + 0x1000/2*8  /* shift to r8 part */
284         pcsx_write_mem strb uxtb 0
285         b       handler_write_end
286
287 FUNCTION(jump_handler_write16):
288         add     x3, x3, #0x1000/4*8               /* shift to r16 part */
289         pcsx_write_mem strh uxth 1
290         b       handler_write_end
291
292 FUNCTION(jump_handler_write32):
293         pcsx_write_mem str mov 2
294
295 handler_write_end:
296         memhandler_post
297         ldp     xzr, x30, [sp], #16
298         ret
299
300 FUNCTION(jump_handle_swl):
301         /* w0 = address, w1 = data, w2 = cycles */
302         ldr     x3, [rFP, #LO_mem_wtab]
303         orr     w4, wzr, w0, lsr #12
304         ldr     x3, [x3, w4, uxtw #3]
305         adds    x3, x3, x3
306         bcs     jump_handle_swx_interp
307         add     x3, x0, x3
308         mov     w0, w2
309         tbz     x3, #1, 10f     // & 2
310         tbz     x3, #0, 2f      // & 1
311 3:
312         stur    w1, [x3, #-3]
313         ret
314 2:
315         lsr     w2, w1, #8
316         lsr     w1, w1, #24
317         sturh   w2, [x3, #-2]
318         strb    w1, [x3]
319         ret
320 10:
321         tbz     x3, #0, 0f      // & 1
322 1:
323         lsr     w1, w1, #16
324         sturh   w1, [x3, #-1]
325         ret
326 0:
327         lsr     w2, w1, #24
328         strb    w2, [x3]
329         ret
330
331 FUNCTION(jump_handle_swr):
332         /* w0 = address, w1 = data, w2 = cycles */
333         ldr     x3, [rFP, #LO_mem_wtab]
334         orr     w4, wzr, w0, lsr #12
335         ldr     x3, [x3, w4, uxtw #3]
336         adds    x3, x3, x3
337         bcs     jump_handle_swx_interp
338         add     x3, x0, x3
339         mov     w0, w2
340         tbz     x3, #1, 10f     // & 2
341         tbz     x3, #0, 2f      // & 1
342 3:
343         strb    w1, [x3]
344         ret
345 2:
346         strh    w1, [x3]
347         ret
348 10:
349         tbz     x3, #0, 0f      // & 1
350 1:
351         lsr     w2, w1, #8
352         strb    w1, [x3]
353         sturh   w2, [x3, #1]
354         ret
355 0:
356         str     w1, [x3]
357         ret
358
359 jump_handle_swx_interp: /* almost never happens */
360         ldr     w3, [rFP, #LO_last_count]
361         add     x0, rFP, #LO_psxRegs
362         add     w2, w3, w2
363         str     w2, [rFP, #LO_cycle]           /* PCSX cycles */
364         bl      execI
365         b       jump_to_new_pc
366
367 FUNCTION(call_gteStall):
368         /* w0 = op_cycles, w1 = cycles */
369         ldr     w2, [rFP, #LO_last_count]
370         str     lr, [rFP, #LO_saved_lr]
371         add     w1, w1, w2
372         str     w1, [rFP, #LO_cycle]
373         add     x1, rFP, #LO_psxRegs
374         bl      gteCheckStallRaw
375         ldr     lr, [rFP, #LO_saved_lr]
376         add     rCC, rCC, w0
377         ret
378
379 #ifdef DRC_DBG
380 #undef do_insn_cmp
381 FUNCTION(do_insn_cmp_arm64):
382         stp     x2,  x3,  [sp, #(SSP_CALLEE_REGS + 2*8)]
383         stp     x4,  x5,  [sp, #(SSP_CALLEE_REGS + 4*8)]
384         stp     x6,  x7,  [sp, #(SSP_CALLEE_REGS + 6*8)]
385         stp     x8,  x9,  [sp, #(SSP_CALLEE_REGS + 8*8)]
386         stp     x10, x11, [sp, #(SSP_CALLEE_REGS + 10*8)]
387         stp     x12, x13, [sp, #(SSP_CALLEE_REGS + 12*8)]
388         stp     x14, x15, [sp, #(SSP_CALLEE_REGS + 14*8)]
389         stp     x16, x17, [sp, #(SSP_CALLEE_REGS + 16*8)]
390         stp     x18, x30, [sp, #(SSP_CALLEE_REGS + 18*8)]
391         bl      do_insn_cmp
392         ldp     x2,  x3,  [sp, #(SSP_CALLEE_REGS + 2*8)]
393         ldp     x4,  x5,  [sp, #(SSP_CALLEE_REGS + 4*8)]
394         ldp     x6,  x7,  [sp, #(SSP_CALLEE_REGS + 6*8)]
395         ldp     x8,  x9,  [sp, #(SSP_CALLEE_REGS + 8*8)]
396         ldp     x10, x11, [sp, #(SSP_CALLEE_REGS + 10*8)]
397         ldp     x12, x13, [sp, #(SSP_CALLEE_REGS + 12*8)]
398         ldp     x14, x15, [sp, #(SSP_CALLEE_REGS + 14*8)]
399         ldp     x16, x17, [sp, #(SSP_CALLEE_REGS + 16*8)]
400         ldp     x18, x30, [sp, #(SSP_CALLEE_REGS + 18*8)]
401         ret
402 #endif