cdrom: change pause timing again
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / linkage_arm.S
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   linkage_arm.s for PCSX                                                *
3  *   Copyright (C) 2009-2011 Ari64                                         *
4  *   Copyright (C) 2010-2013 GraÅžvydas "notaz" Ignotas                     *
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 "linkage_offsets.h"
25
26
27 #ifdef __MACH__
28 #define dynarec_local           ESYM(dynarec_local)
29 #define ndrc_add_jump_out       ESYM(ndrc_add_jump_out)
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 ndrc_write_invalidate_one ESYM(ndrc_write_invalidate_one)
33 #define gen_interupt            ESYM(gen_interupt)
34 #define gteCheckStallRaw        ESYM(gteCheckStallRaw)
35 #define psxException            ESYM(psxException)
36 #define execI                   ESYM(execI)
37 #endif
38
39         .bss
40         .align  4
41         .global dynarec_local
42         .type   dynarec_local, %object
43         .size   dynarec_local, LO_dynarec_local_size
44 dynarec_local:
45         .space  LO_dynarec_local_size
46
47 #define DRC_VAR_(name, vname, size_) \
48         vname = dynarec_local + LO_##name; \
49         .global vname; \
50         .type   vname, %object; \
51         .size   vname, size_
52
53 #define DRC_VAR(name, size_) \
54         DRC_VAR_(name, ESYM(name), size_)
55
56 DRC_VAR(next_interupt, 4)
57 DRC_VAR(cycle_count, 4)
58 DRC_VAR(last_count, 4)
59 DRC_VAR(pending_exception, 4)
60 DRC_VAR(stop, 4)
61 DRC_VAR(branch_target, 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(reg, 128)
68 DRC_VAR(lo, 4)
69 DRC_VAR(hi, 4)
70 DRC_VAR(reg_cop0, 128)
71 DRC_VAR(reg_cop2d, 128)
72 DRC_VAR(reg_cop2c, 128)
73 DRC_VAR(pcaddr, 4)
74 @DRC_VAR(code, 4)
75 @DRC_VAR(cycle, 4)
76 @DRC_VAR(interrupt, 4)
77 @DRC_VAR(intCycle, 256)
78
79 DRC_VAR(rcnts, 7*4*4)
80 DRC_VAR(inv_code_start, 4)
81 DRC_VAR(inv_code_end, 4)
82 DRC_VAR(mem_rtab, 4)
83 DRC_VAR(mem_wtab, 4)
84 DRC_VAR(psxH_ptr, 4)
85 DRC_VAR(zeromem_ptr, 4)
86 DRC_VAR(invc_ptr, 4)
87 DRC_VAR(scratch_buf_ptr, 4)
88 DRC_VAR(ram_offset, 4)
89 DRC_VAR(mini_ht, 256)
90
91
92         .syntax unified
93         .text
94         .align  2
95
96 #ifndef HAVE_ARMV5
97 .macro blx rd
98         mov     lr, pc
99         bx      \rd
100 .endm
101 #endif
102
103 .macro load_varadr reg var
104 #if defined(HAVE_ARMV7) && defined(TEXRELS_FORBIDDEN)
105         movw    \reg, #:lower16:(\var-(1678f+8))
106         movt    \reg, #:upper16:(\var-(1678f+8))
107 1678:
108         add     \reg, pc
109 #elif defined(HAVE_ARMV7) && !defined(__PIC__)
110         movw    \reg, #:lower16:\var
111         movt    \reg, #:upper16:\var
112 #else
113         ldr     \reg, =\var
114 #endif
115 .endm
116
117 .macro load_varadr_ext reg var
118 #if defined(HAVE_ARMV7) && defined(TEXRELS_FORBIDDEN)
119         movw    \reg, #:lower16:(ptr_\var-(1678f+8))
120         movt    \reg, #:upper16:(ptr_\var-(1678f+8))
121 1678:
122         ldr     \reg, [pc, \reg]
123 #else
124         load_varadr \reg \var
125 #endif
126 .endm
127
128 .macro mov_16 reg imm
129 #ifdef HAVE_ARMV7
130         movw    \reg, #\imm
131 #else
132         mov     \reg, #(\imm & 0x00ff)
133         orr     \reg, #(\imm & 0xff00)
134 #endif
135 .endm
136
137 .macro mov_24 reg imm
138 #ifdef HAVE_ARMV7
139         movw    \reg, #(\imm & 0xffff)
140         movt    \reg, #(\imm >> 16)
141 #else
142         mov     \reg, #(\imm & 0x0000ff)
143         orr     \reg, #(\imm & 0x00ff00)
144         orr     \reg, #(\imm & 0xff0000)
145 #endif
146 .endm
147
148 FUNCTION(dyna_linker):
149         /* r0 = virtual target address */
150         /* r1 = pointer to an instruction to patch */
151 #ifndef NO_WRITE_EXEC
152         ldr     r7, [r1]
153         mov     r4, r0
154         add     r6, r7, #2
155         mov     r5, r1
156         lsl     r6, r6, #8
157         /* must not compile - that might expire the caller block */
158         mov     r1, #0
159         bl      ndrc_get_addr_ht_param
160
161         movs    r8, r0
162         beq     0f
163         add     r6, r5, r6, asr #6  /* old target */
164         teq     r0, r6
165         moveq   pc, r0 /* Stale i-cache */
166         mov     r0, r4
167         mov     r1, r6
168         bl      ndrc_add_jump_out
169
170         sub     r2, r8, r5
171         and     r1, r7, #0xff000000
172         lsl     r2, r2, #6
173         sub     r1, r1, #2
174         add     r1, r1, r2, lsr #8
175         str     r1, [r5]
176         mov     pc, r8
177 0:
178         mov     r0, r4
179 #else
180         /* XXX: should be able to do better than this... */
181 #endif
182         bl      ndrc_get_addr_ht
183         mov     pc, r0
184         .size   dyna_linker, .-dyna_linker
185
186         .align  2
187 FUNCTION(jump_vaddr_r1):
188         mov     r0, r1
189         b       jump_vaddr_r0
190         .size   jump_vaddr_r1, .-jump_vaddr_r1
191 FUNCTION(jump_vaddr_r2):
192         mov     r0, r2
193         b       jump_vaddr_r0
194         .size   jump_vaddr_r2, .-jump_vaddr_r2
195 FUNCTION(jump_vaddr_r3):
196         mov     r0, r3
197         b       jump_vaddr_r0
198         .size   jump_vaddr_r3, .-jump_vaddr_r3
199 FUNCTION(jump_vaddr_r4):
200         mov     r0, r4
201         b       jump_vaddr_r0
202         .size   jump_vaddr_r4, .-jump_vaddr_r4
203 FUNCTION(jump_vaddr_r5):
204         mov     r0, r5
205         b       jump_vaddr_r0
206         .size   jump_vaddr_r5, .-jump_vaddr_r5
207 FUNCTION(jump_vaddr_r6):
208         mov     r0, r6
209         b       jump_vaddr_r0
210         .size   jump_vaddr_r6, .-jump_vaddr_r6
211 FUNCTION(jump_vaddr_r8):
212         mov     r0, r8
213         b       jump_vaddr_r0
214         .size   jump_vaddr_r8, .-jump_vaddr_r8
215 FUNCTION(jump_vaddr_r9):
216         mov     r0, r9
217         b       jump_vaddr_r0
218         .size   jump_vaddr_r9, .-jump_vaddr_r9
219 FUNCTION(jump_vaddr_r10):
220         mov     r0, r10
221         b       jump_vaddr_r0
222         .size   jump_vaddr_r10, .-jump_vaddr_r10
223 FUNCTION(jump_vaddr_r12):
224         mov     r0, r12
225         b       jump_vaddr_r0
226         .size   jump_vaddr_r12, .-jump_vaddr_r12
227 FUNCTION(jump_vaddr_r7):
228         add     r0, r7, #0
229         .size   jump_vaddr_r7, .-jump_vaddr_r7
230 FUNCTION(jump_vaddr_r0):
231         bl      ndrc_get_addr_ht
232         mov     pc, r0
233         .size   jump_vaddr_r0, .-jump_vaddr_r0
234
235         .align  2
236 FUNCTION(cc_interrupt):
237         ldr     r0, [fp, #LO_last_count]
238         mov     r1, #0
239         add     r10, r0, r10
240         str     r1, [fp, #LO_pending_exception]
241         str     r10, [fp, #LO_cycle]            /* PCSX cycles */
242         mov     r10, lr
243
244         add     r0, fp, #LO_reg_cop0            /* CP0 */
245         bl      gen_interupt
246         mov     lr, r10
247         ldr     r10, [fp, #LO_cycle]
248         ldr     r0, [fp, #LO_next_interupt]
249         ldr     r1, [fp, #LO_pending_exception]
250         ldr     r2, [fp, #LO_stop]
251         str     r0, [fp, #LO_last_count]
252         sub     r10, r10, r0
253         tst     r2, r2
254         ldmfdne sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, pc}
255         tst     r1, r1
256         moveq   pc, lr
257         ldr     r0, [fp, #LO_pcaddr]
258         bl      ndrc_get_addr_ht
259         mov     pc, r0
260         .size   cc_interrupt, .-cc_interrupt
261
262         .align  2
263 FUNCTION(jump_addrerror_ds): /* R3000E_AdEL / R3000E_AdES in r0 */
264         str     r1, [fp, #(LO_psxRegs + (34+8)*4)]  /* BadVaddr */
265         mov     r1, #1
266         b       call_psxException
267 FUNCTION(jump_addrerror):
268         str     r1, [fp, #(LO_psxRegs + (34+8)*4)]  /* BadVaddr */
269         mov     r1, #0
270         b       call_psxException
271 FUNCTION(jump_overflow_ds):
272         mov     r0, #(12<<2)  /* R3000E_Ov */
273         mov     r1, #1
274         b       call_psxException
275 FUNCTION(jump_overflow):
276         mov     r0, #(12<<2)
277         mov     r1, #0
278         b       call_psxException
279 FUNCTION(jump_break_ds):
280         mov     r0, #(9<<2)  /* R3000E_Bp */
281         mov     r1, #1
282         b       call_psxException
283 FUNCTION(jump_break):
284         mov     r0, #(9<<2)
285         mov     r1, #0
286         b       call_psxException
287 FUNCTION(jump_syscall_ds):
288         mov     r0, #(8<<2)  /* R3000E_Syscall */
289         mov     r1, #2
290         b       call_psxException
291 FUNCTION(jump_syscall):
292         mov     r0, #(8<<2)
293         mov     r1, #0
294
295 call_psxException:
296         ldr     r3, [fp, #LO_last_count]
297         str     r2, [fp, #LO_pcaddr]
298         add     r10, r3, r10
299         str     r10, [fp, #LO_cycle]            /* PCSX cycles */
300         add     r2, fp, #LO_reg_cop0            /* CP0 */
301         bl      psxException
302
303         /* note: psxException might do recursive recompiler call from it's HLE code,
304          * so be ready for this */
305 FUNCTION(jump_to_new_pc):
306         ldr     r2, [fp, #LO_stop]
307         ldr     r1, [fp, #LO_next_interupt]
308         ldr     r10, [fp, #LO_cycle]
309         ldr     r0, [fp, #LO_pcaddr]
310         tst     r2, r2
311         str     r1, [fp, #LO_last_count]
312         sub     r10, r10, r1
313         bne     new_dyna_leave
314         bl      ndrc_get_addr_ht
315         mov     pc, r0
316         .size   jump_to_new_pc, .-jump_to_new_pc
317
318         .align  2
319 FUNCTION(new_dyna_leave):
320         ldr     r0, [fp, #LO_last_count]
321         add     r10, r0, r10
322         str     r10, [fp, #LO_cycle]
323         ldmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, pc}
324         .size   new_dyna_leave, .-new_dyna_leave
325
326         .align  2
327 FUNCTION(invalidate_addr_r0):
328         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
329         b       invalidate_addr_call
330         .size   invalidate_addr_r0, .-invalidate_addr_r0
331         .align  2
332 FUNCTION(invalidate_addr_r1):
333         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
334         mov     r0, r1
335         b       invalidate_addr_call
336         .size   invalidate_addr_r1, .-invalidate_addr_r1
337         .align  2
338 FUNCTION(invalidate_addr_r2):
339         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
340         mov     r0, r2
341         b       invalidate_addr_call
342         .size   invalidate_addr_r2, .-invalidate_addr_r2
343         .align  2
344 FUNCTION(invalidate_addr_r3):
345         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
346         mov     r0, r3
347         b       invalidate_addr_call
348         .size   invalidate_addr_r3, .-invalidate_addr_r3
349         .align  2
350 FUNCTION(invalidate_addr_r4):
351         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
352         mov     r0, r4
353         b       invalidate_addr_call
354         .size   invalidate_addr_r4, .-invalidate_addr_r4
355         .align  2
356 FUNCTION(invalidate_addr_r5):
357         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
358         mov     r0, r5
359         b       invalidate_addr_call
360         .size   invalidate_addr_r5, .-invalidate_addr_r5
361         .align  2
362 FUNCTION(invalidate_addr_r6):
363         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
364         mov     r0, r6
365         b       invalidate_addr_call
366         .size   invalidate_addr_r6, .-invalidate_addr_r6
367         .align  2
368 FUNCTION(invalidate_addr_r7):
369         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
370         mov     r0, r7
371         b       invalidate_addr_call
372         .size   invalidate_addr_r7, .-invalidate_addr_r7
373         .align  2
374 FUNCTION(invalidate_addr_r8):
375         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
376         mov     r0, r8
377         b       invalidate_addr_call
378         .size   invalidate_addr_r8, .-invalidate_addr_r8
379         .align  2
380 FUNCTION(invalidate_addr_r9):
381         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
382         mov     r0, r9
383         b       invalidate_addr_call
384         .size   invalidate_addr_r9, .-invalidate_addr_r9
385         .align  2
386 FUNCTION(invalidate_addr_r10):
387         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
388         mov     r0, r10
389         b       invalidate_addr_call
390         .size   invalidate_addr_r10, .-invalidate_addr_r10
391         .align  2
392 FUNCTION(invalidate_addr_r12):
393         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
394         mov     r0, r12
395         .size   invalidate_addr_r12, .-invalidate_addr_r12
396         .align  2
397 invalidate_addr_call:
398         ldr     r12, [fp, #LO_inv_code_start]
399         ldr     lr, [fp, #LO_inv_code_end]
400         cmp     r0, r12
401         cmpcs   lr, r0
402         blcc    ndrc_write_invalidate_one
403         ldmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, pc}
404         .size   invalidate_addr_call, .-invalidate_addr_call
405
406         .align  2
407 FUNCTION(new_dyna_start):
408         /* ip is stored to conform EABI alignment */
409         stmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}
410         mov     fp, r0 /* dynarec_local */
411         ldr     r0, [fp, #LO_pcaddr]
412         bl      ndrc_get_addr_ht
413         ldr     r1, [fp, #LO_next_interupt]
414         ldr     r10, [fp, #LO_cycle]
415         str     r1, [fp, #LO_last_count]
416         sub     r10, r10, r1
417         mov     pc, r0
418         .size   new_dyna_start, .-new_dyna_start
419
420 /* --------------------------------------- */
421
422 .macro memhandler_post
423         /* r2 = cycles_out, r3 = tmp */
424         ldr     r3, [fp, #LO_next_interupt]
425         ldr     r2, [fp, #LO_cycle]        @ memhandlers can modify cc, like dma
426         str     r3, [fp, #LO_last_count]
427         sub     r2, r2, r3
428 .endm
429
430 .align 2
431
432 .macro pcsx_read_mem_part readop tab_shift
433         /* r0 = address, r1 = handler_tab, r2 = cycles */
434         lsl     r3, r0, #20
435         lsr     r3, #(20+\tab_shift)
436         ldr     r12, [fp, #LO_last_count]
437         ldr     r1, [r1, r3, lsl #2]
438         add     r12, r2, r12
439         lsls    r1, #1
440 .if \tab_shift == 1
441         lsl     r3, #1
442         \readop r0, [r1, r3]
443 .else
444         \readop r0, [r1, r3, lsl #\tab_shift]
445 .endif
446         movcc   pc, lr
447         mov     r2, r12
448         str     r12, [fp, #LO_cycle]
449 .endm
450
451 FUNCTION(jump_handler_read8):
452         add     r1, #0x1000/4*4 + 0x1000/2*4 @ shift to r8 part
453         pcsx_read_mem_part ldrbcc, 0
454         bx      r1                           @ addr, unused, cycles
455
456 FUNCTION(jump_handler_read16):
457         add     r1, #0x1000/4*4              @ shift to r16 part
458         pcsx_read_mem_part ldrhcc, 1
459         bx      r1                           @ addr, unused, cycles
460
461 FUNCTION(jump_handler_read32):
462         pcsx_read_mem_part ldrcc, 2
463         bx      r1                           @ addr, unused, cycles
464 #if 0
465         str     lr, [fp, #LO_saved_lr]
466         blx     r1
467         ldr     lr, [fp, #LO_saved_lr]
468         memhandler_post
469         bx      lr
470 #endif
471
472 .macro pcsx_write_mem wrtop tab_shift
473         /* r0 = address, r1 = data, r2 = cycles, r3 = handler_tab */
474         lsl     r12,r0, #20
475         lsr     r12, #(20+\tab_shift)
476         ldr     r3, [r3, r12, lsl #2]
477         str     r0, [fp, #LO_address]      @ some handlers still need it..
478         lsls    r3, #1
479 .if \tab_shift == 1
480         lsl     r12, #1
481         \wrtop  r1, [r3, r12]
482 .else
483         \wrtop  r1, [r3, r12, lsl #\tab_shift]
484 .endif
485         movcc   pc, lr
486         ldr     r12, [fp, #LO_last_count]
487         mov     r0, r1
488         add     r2, r2, r12
489         str     r2, [fp, #LO_cycle]
490
491         str     lr, [fp, #LO_saved_lr]
492         blx     r3
493         ldr     lr, [fp, #LO_saved_lr]
494
495         memhandler_post
496         bx      lr
497 .endm
498
499 FUNCTION(jump_handler_write8):
500         add     r3, #0x1000/4*4 + 0x1000/2*4 @ shift to r8 part
501         pcsx_write_mem strbcc, 0
502
503 FUNCTION(jump_handler_write16):
504         add     r3, #0x1000/4*4              @ shift to r16 part
505         pcsx_write_mem strhcc, 1
506
507 FUNCTION(jump_handler_write32):
508         pcsx_write_mem strcc, 2
509
510 FUNCTION(jump_handler_write_h):
511         /* r0 = address, r1 = data, r2 = cycles, r3 = handler */
512         ldr     r12, [fp, #LO_last_count]
513         str     r0, [fp, #LO_address]      @ some handlers still need it..
514         add     r2, r2, r12
515         mov     r0, r1
516         str     r2, [fp, #LO_cycle]
517
518         str     lr, [fp, #LO_saved_lr]
519         blx     r3
520         ldr     lr, [fp, #LO_saved_lr]
521
522         memhandler_post
523         bx      lr
524
525 FUNCTION(jump_handle_swl):
526         /* r0 = address, r1 = data, r2 = cycles */
527         ldr     r3, [fp, #LO_mem_wtab]
528         mov     r12,r0,lsr #12
529         ldr     r3, [r3, r12, lsl #2]
530         lsls    r3, #1
531         bcs     jump_handle_swx_interp
532         add     r3, r0, r3
533         mov     r0, r2
534         tst     r3, #2
535         beq     101f
536         tst     r3, #1
537         beq     2f
538 3:
539         str     r1, [r3, #-3]
540         bx      lr
541 2:
542         lsr     r2, r1, #8
543         lsr     r1, #24
544         strh    r2, [r3, #-2]
545         strb    r1, [r3]
546         bx      lr
547 101:
548         tst     r3, #1
549         lsrne   r1, #16         @ 1
550         lsreq   r12, r1, #24    @ 0
551         strhne  r1, [r3, #-1]
552         strbeq  r12, [r3]
553         bx      lr
554
555 FUNCTION(jump_handle_swr):
556         /* r0 = address, r1 = data, r2 = cycles */
557         ldr     r3, [fp, #LO_mem_wtab]
558         mov     r12,r0,lsr #12
559         ldr     r3, [r3, r12, lsl #2]
560         lsls    r3, #1
561         bcs     jump_handle_swx_interp
562         add     r3, r0, r3
563         and     r12,r3, #3
564         mov     r0, r2
565         cmp     r12,#2
566         strbgt  r1, [r3]        @ 3
567         strheq  r1, [r3]        @ 2
568         cmp     r12,#1
569         strlt   r1, [r3]        @ 0
570         bxne    lr
571         lsr     r2, r1, #8      @ 1
572         strb    r1, [r3]
573         strh    r2, [r3, #1]
574         bx      lr
575
576 jump_handle_swx_interp: /* almost never happens */
577         ldr     r3, [fp, #LO_last_count]
578         add     r0, fp, #LO_psxRegs
579         add     r2, r3, r2
580         str     r2, [fp, #LO_cycle]           /* PCSX cycles */
581         bl      execI
582         b       jump_to_new_pc
583
584 .macro rcntx_read_mode0 num
585         /* r0 = address, r2 = cycles */
586         ldr     r3, [fp, #LO_rcnts+6*4+7*4*\num] @ cycleStart
587         mov     r0, r2, lsl #16
588         sub     r0, r0, r3, lsl #16
589         lsr     r0, #16
590         bx      lr
591 .endm
592
593 FUNCTION(rcnt0_read_count_m0):
594         rcntx_read_mode0 0
595
596 FUNCTION(rcnt1_read_count_m0):
597         rcntx_read_mode0 1
598
599 FUNCTION(rcnt2_read_count_m0):
600         rcntx_read_mode0 2
601
602 FUNCTION(rcnt0_read_count_m1):
603         /* r0 = address, r2 = cycles */
604         ldr     r3, [fp, #LO_rcnts+6*4+7*4*0] @ cycleStart
605         mov_16  r1, 0x3334
606         sub     r2, r2, r3
607         mul     r0, r1, r2              @ /= 5
608         lsr     r0, #16
609         bx      lr
610
611 FUNCTION(rcnt1_read_count_m1):
612         /* r0 = address, r2 = cycles */
613         ldr     r3, [fp, #LO_rcnts+6*4+7*4*1]
614         mov_24  r1, 0x1e6cde
615         sub     r2, r2, r3
616         umull   r3, r0, r1, r2          @ ~ /= hsync_cycles, max ~0x1e6cdd
617         bx      lr
618
619 FUNCTION(rcnt2_read_count_m1):
620         /* r0 = address, r2 = cycles */
621         ldr     r3, [fp, #LO_rcnts+6*4+7*4*2]
622         mov     r0, r2, lsl #16-3
623         sub     r0, r0, r3, lsl #16-3
624         lsr     r0, #16                 @ /= 8
625         bx      lr
626
627 FUNCTION(call_gteStall):
628         /* r0 = op_cycles, r1 = cycles */
629         ldr     r2, [fp, #LO_last_count]
630         str     lr, [fp, #LO_saved_lr]
631         add     r1, r1, r2
632         str     r1, [fp, #LO_cycle]
633         add     r1, fp, #LO_psxRegs
634         bl      gteCheckStallRaw
635         ldr     lr, [fp, #LO_saved_lr]
636         add     r10, r10, r0
637         bx      lr
638
639 #ifdef HAVE_ARMV6
640
641 FUNCTION(get_reg):
642         ldr     r12, [r0]
643         and     r1, r1, #0xff
644         ldr     r2, [r0, #4]
645         orr     r1, r1, r1, lsl #8
646         ldr     r3, [r0, #8]
647         orr     r1, r1, r1, lsl #16   @ searched char in every byte
648         ldrb    r0, [r0, #12]         @ last byte
649         eor     r12, r12, r1
650         eor     r2, r2, r1
651         eor     r3, r3, r1
652         cmp     r0, r1, lsr #24
653         mov     r0, #12
654         mvn     r1, #0                @ r1=~0
655         bxeq    lr
656         orr     r3, r3, #0xff000000   @ EXCLUDE_REG
657         uadd8   r0, r12, r1           @ add and set GE bits when not 0 (match)
658         mov     r12, #0
659         sel     r0, r12, r1           @ 0 if no match, else ff in some byte
660         uadd8   r2, r2, r1
661         sel     r2, r12, r1
662         uadd8   r3, r3, r1
663         sel     r3, r12, r1
664         mov     r12, #3
665         clz     r0, r0                @ 0, 8, 16, 24 or 32
666         clz     r2, r2
667         clz     r3, r3
668         sub     r0, r12, r0, lsr #3   @ 3, 2, 1, 0 or -1
669         sub     r2, r12, r2, lsr #3
670         sub     r3, r12, r3, lsr #3
671         orr     r2, r2, #4
672         orr     r3, r3, #8
673         and     r0, r0, r2
674         and     r0, r0, r3
675         bx      lr
676
677 #endif /* HAVE_ARMV6 */
678
679 @ vim:filetype=armasm