summaryrefslogtreecommitdiff
path: root/source/common/drc_exec.s
blob: f6e1fe9776366922356ed0c228a3848c6abee3a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
.arm
.align 4

.data

.extern v810_state, serviceDisplayInt, serviceInt, serviceint, tVBOpt

.text

.macro ldRegs
    ldr     r11, =v810_state
    ldr     r11, [r11]

    @ Load the CPSR
    ldr     r3, [r11, #(34*4)]
    msr     cpsr_f, r3

    @ Load the address of the reg map (block+17)
    add     r3, r1, #17

    @ Load cached V810 registers
    ldrb    r2, [r3], #1
    ldr     r4, [r11, r2, lsl #2]
    ldrb    r2, [r3], #1
    ldr     r5, [r11, r2, lsl #2]
    ldrb    r2, [r3], #1
    ldr     r6, [r11, r2, lsl #2]
    ldrb    r2, [r3], #1
    ldr     r7, [r11, r2, lsl #2]
    ldrb    r2, [r3], #1
    ldr     r8, [r11, r2, lsl #2]
    ldrb    r2, [r3], #1
    ldr     r9, [r11, r2, lsl #2]
.endm

.macro stRegs
    ldr     r11, =v810_state
    ldr     r11, [r11]
    @ Load the address of the reg map (block+17)
    add     r1, r0, #17

    @ Save the CPSR
    mrs     r3, cpsr
    str     r3, [r11, #(34*4)]

    @ Store cached V810 registers
    ldrb    r2, [r1], #1
    str     r4, [r11, r2, lsl #2]
    ldrb    r2, [r1], #1
    str     r5, [r11, r2, lsl #2]
    ldrb    r2, [r1], #1
    str     r6, [r11, r2, lsl #2]
    ldrb    r2, [r1], #1
    str     r7, [r11, r2, lsl #2]
    ldrb    r2, [r1], #1
    str     r8, [r11, r2, lsl #2]
    ldrb    r2, [r1], #1
    str     r9, [r11, r2, lsl #2]
.endm

@ void drc_executeBlock(WORD* entrypoint, exec_block* block);

.globl drc_executeBlock
drc_executeBlock:
    push    {r4-r11, ip, lr}
    push    {r1}

    @ The last instruction on the block should be "pop {pc}"
    ldr     lr, =postexec
    push    {lr}

    ldRegs
    @ r10 = -MAXCYCLES
    ldr     r10, =tVBOpt
    ldr     r10, [r10]
    neg     r10, r10
    bx      r0

postexec:
    pop     {r0}
    stRegs
    @ v810_state->cycles += MAXCYCLES + r10 excess
    ldr     r0, =tVBOpt
    ldr     r0, [r0]
    add     r10, r0
    ldr     r0, [r11, #67<<2]
    add     r0, r10
    str     r0, [r11, #67<<2]
    pop     {r4-r11, ip, pc}

@ Checks for pending interrupts and exits the block if necessary
.globl drc_handleInterrupts
drc_handleInterrupts:
    push    {r4, r5, lr}

    mov     r4, r0
    mov     r5, r1

    @ Load v810_state->cycles and add it to the total number of cycles
    @ (MAXCYCLES + r10 excess)
    ldr     r0, [r11, #67<<2]
    add     r0, r10
    ldr     r2, =tVBOpt
    ldr     r2, [r2]
    add     r0, r2
    str     r0, [r11, #67<<2]

    bl      serviceDisplayInt
    cmp     r0, #0
    bne     exit_block

    ldr     r0, [r11, #67<<2]
    mov     r1, r5
    bl      serviceInt
    cmp     r0, #0
    bne     exit_block

ret_to_block:
    @ r10 = -MAXCYCLES
    ldr     r10, =tVBOpt
    ldr     r10, [r10]
    neg     r10, r10

    @ Return to the block
    mov     r0, r4
    pop     {r4, r5, pc}

exit_block:
    @ Restore CPSR
    msr     cpsr_f, r4

    @ Exit the block ignoring linked return address
    pop     {r4, r5}
    pop     {r0, pc}