PicoDrive hacks
[picodrive.git] / Pico / cd / Pico.s
CommitLineData
7336a99a 1@ vim:filetype=armasm
2
3@ SekRunPS runs PicoCpu and PicoCpuS68k interleaved in steps of PS_STEP_M68K
4@ cycles. This is done without calling CycloneRun and jumping directly to
5@ Cyclone code to avoid pushing/popping all the registers every time.
6
7@ (c) Copyright 2007, Grazvydas "notaz" Ignotas
8@ All Rights Reserved
9
10
11.equiv PS_STEP_M68K, ((488<<16)/20) @ ~24
12
13@ .extern is ignored by gas, we add these here just to see what we depend on.
14.extern CycloneJumpTab
15.extern CycloneDoInterrupt
16.extern PicoCpu
17.extern PicoCpuS68k
18.extern SekCycleAim
19.extern SekCycleCnt
20.extern SekCycleAimS68k
21.extern SekCycleCntS68k
22
23
24.text
25.align 4
26
27
28.global SekRunPS @ cyc_m68k, cyc_s68k
29
30SekRunPS:
31 stmfd sp!, {r4-r11,lr}
32 sub sp, sp, #2*4 @ sp[0] = main_cycle_cnt, sp[4] = run_cycle_cnt
33
34 @ override CycloneEnd for both contexts
35 ldr r7, =PicoCpu
36 ldr lr, =PicoCpuS68k
37 ldr r2, =CycloneEnd_M68k
38 ldr r3, =CycloneEnd_S68k
39 str r2, [r7,#0x54]
40 str r3, [lr,#0x54]
41
42 @ update aims
43 ldr r8, =SekCycleAim
44 ldr r9, =SekCycleAimS68k
45 ldr r2, [r8]
46 ldr r3, [r9]
47 add r2, r2, r0
48 add r3, r3, r1
49 str r2, [r8]
50 str r3, [r9]
51
52 ldr r1, =SekCycleCnt
53 ldr r0, =((488<<16)-PS_STEP_M68K)
54 ldr r6, =CycloneJumpTab
55
56 @ schedule m68k for the first time..
57 ldr r1, [r1]
58 str r0, [sp] @ main target 'left cycle' counter
59 sub r1, r2, r1
60 subs r5, r1, r0, asr #16
61 ble schedule_s68k @ m68k has not enough cycles
62
63 str r5, [sp,#4] @ run_cycle_cnt
64 b CycloneRunLocal
65
66
67
68CycloneEnd_M68k:
69 ldr r3, =SekCycleCnt
70 ldr r0, [sp,#4] @ run_cycle_cnt
71 ldr r1, [r3]
72 str r4, [r7,#0x40] ;@ Save Current PC + Memory Base
73 strb r9, [r7,#0x46] ;@ Save Flags (NZCV)
74 sub r0, r0, r5 @ subtract leftover cycles (which should be negative)
75 add r0, r0, r1
76 str r0, [r3]
77
78schedule_s68k:
79 ldr r8, =SekCycleCntS68k
80 ldr r9, =SekCycleAimS68k
81 ldr r3, [sp]
82 ldr r8, [r8]
83 ldr r9, [r9]
84
85 sub r0, r9, r8
66fdc0f0 86 mov r2, r3
87 add r3, r3, r2, asr #1
88 add r3, r3, r2, asr #3 @ cycn_s68k = (cycn + cycn/2 + cycn/8)
7336a99a 89
90 subs r5, r0, r3, asr #16
91 ble schedule_m68k @ s68k has not enough cycles
92
93 ldr r7, =PicoCpuS68k
94 str r5, [sp,#4] @ run_cycle_cnt
95 b CycloneRunLocal
96
97
98
99CycloneEnd_S68k:
100 ldr r3, =SekCycleCntS68k
101 ldr r0, [sp,#4] @ run_cycle_cnt
102 ldr r1, [r3]
103 str r4, [r7,#0x40] ;@ Save Current PC + Memory Base
104 strb r9, [r7,#0x46] ;@ Save Flags (NZCV)
105 sub r0, r0, r5 @ subtract leftover cycles (should be negative)
106 add r0, r0, r1
107 str r0, [r3]
108
109schedule_m68k:
110 ldr r1, =PS_STEP_M68K
111 ldr r3, [sp] @ main_cycle_cnt
112 ldr r8, =SekCycleCnt
113 ldr r9, =SekCycleAim
114 subs r3, r3, r1
115 bmi SekRunPS_end
116
117 ldr r8, [r8]
118 ldr r9, [r9]
119 str r3, [sp] @ update main_cycle_cnt
120 sub r0, r9, r8
121
122 subs r5, r0, r3, asr #16
123 ble schedule_s68k @ m68k has not enough cycles
124
125 ldr r7, =PicoCpu
126 str r5, [sp,#4] @ run_cycle_cnt
127 b CycloneRunLocal
128
129
130
131SekRunPS_end:
132 ldr r7, =PicoCpu
133 ldr lr, =PicoCpuS68k
134 mov r0, #0
135 str r0, [r7,#0x54] @ remove CycloneEnd handler
136 str r0, [lr,#0x54]
137 @ return
138 add sp, sp, #2*4
139 ldmfd sp!, {r4-r11,pc}
140
141
142
143
144CycloneRunLocal:
145 ;@ r0-3 = Temporary registers
146 ldr r4,[r7,#0x40] ;@ r4 = Current PC + Memory Base
147 ;@ r5 = Cycles
148 ;@ r6 = Opcode Jump table
149 ;@ r7 = Pointer to Cpu Context
150 ;@ r8 = Current Opcode
151 ldrb r9,[r7,#0x46] ;@ r9 = Flags (NZCV)
66fdc0f0 152 ldr r1,[r7,#0x44] ;@ get SR high and IRQ level
153 orr r9,r9,r9,lsl #28 ;@ r9 = Flags 0xf0000000, cpsr format
7336a99a 154 ;@ r10 = Source value / Memory Base
155
156;@ CheckInterrupt:
66fdc0f0 157 movs r0,r1,lsr #24 ;@ Get IRQ level
7336a99a 158 beq NoIntsLocal
159 cmp r0,#6 ;@ irq>6 ?
7336a99a 160 andle r1,r1,#7 ;@ Get interrupt mask
161 cmple r0,r1 ;@ irq<=6: Is irq<=mask ?
66fdc0f0 162 ldrgt lr,[r7,#0x54] @ Interrupt will definitely use more cycles than our step,
163 bgt CycloneDoInterrupt @ so make this function return directly to CycloneEnd_*
7336a99a 164NoIntsLocal:
165
66fdc0f0 166 ;@ Check if our processor is in stopped state and jump to opcode handler if not
7336a99a 167 ldr r0,[r7,#0x58]
168 ldrh r8,[r4],#2 ;@ Fetch first opcode
169 tst r0,r0 ;@ stopped?
66fdc0f0 170 andeq r9,r9,#0xf0000000
7336a99a 171 ldreq pc,[r6,r8,asl #2] ;@ Jump to opcode handler
172
173 @ stopped
66fdc0f0 174 sub r4,r4,#2
7336a99a 175 ldr r1,[r7,#0x54]
176 mov r5,#0
177 bx r1
178