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