original source from gpsp09-2xb_src.tar.bz2
[gpsp.git] / x86 / x86_stub.S
CommitLineData
2823a4c8 1# gameplaySP
2#
3# Copyright (C) 2006 Exophase <exophase@gmail.com>
4#
5# This program is free software; you can redistribute it and/or
6# modify it under the terms of the GNU General Public License as
7# published by the Free Software Foundation; either version 2 of
8# the License, or (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19.align 4
20
21.global _x86_update_gba
22.global _x86_indirect_branch_arm
23.global _x86_indirect_branch_thumb
24.global _x86_indirect_branch_dual
25.global _execute_store_u8
26.global _execute_store_u16
27.global _execute_store_u32
28.global _execute_store_cpsr
29.global _execute_arm_translate
30.global _step_debug_x86
31
32.global _memory_map_read
33.global _memory_map_write
34.global _reg
35
36.global _oam_update
37
38.global _iwram
39.global _ewram
40.global _vram
41.global _oam_ram
42.global _bios_rom
43.global _io_registers
44
45.extern _spsr
46
47.equ REG_SP, (13 * 4)
48.equ REG_LR, (14 * 4)
49.equ REG_PC, (15 * 4)
50.equ REG_N_FLAG, (16 * 4)
51.equ REG_Z_FLAG, (17 * 4)
52.equ REG_C_FLAG, (18 * 4)
53.equ REG_V_FLAG, (19 * 4)
54.equ REG_CPSR, (20 * 4)
55.equ REG_SAVE, (21 * 4)
56.equ REG_SAVE2, (22 * 4)
57.equ REG_SAVE3, (23 * 4)
58.equ CPU_MODE, (29 * 4)
59.equ CPU_HALT_STATE, (30 * 4)
60.equ CHANGED_PC_STATUS, (31 * 4)
61
62# destroys ecx and edx
63
64.macro collapse_flag offset, shift
65 mov \offset(%ebx), %ecx
66 shl $\shift, %ecx
67 or %ecx, %edx
68.endm
69
70.macro collapse_flags_no_update
71 xor %edx, %edx
72 collapse_flag REG_N_FLAG, 31
73 collapse_flag REG_Z_FLAG, 30
74 collapse_flag REG_C_FLAG, 29
75 collapse_flag REG_V_FLAG, 28
76 mov REG_CPSR(%ebx), %ecx
77 and $0xFF, %ecx
78 or %ecx, %edx
79.endm
80
81
82.macro collapse_flags
83 collapse_flags_no_update
84 mov %edx, REG_CPSR(%ebx)
85.endm
86
87.macro extract_flag shift, offset
88 mov REG_CPSR(%ebx), %edx
89 shr $\shift, %edx
90 and $0x01, %edx
91 mov %edx, _reg + \offset
92.endm
93
94.macro extract_flags
95 extract_flag 31, REG_N_FLAG
96 extract_flag 30, REG_Z_FLAG
97 extract_flag 29, REG_C_FLAG
98 extract_flag 28, REG_V_FLAG
99.endm
100
101# Process a hardware event. Since an interrupt might be
102# raised we have to check if the PC has changed.
103
104# eax: current address
105
106st:
107 .asciz "u\n"
108
109_x86_update_gba:
110 mov %eax, REG_PC(%ebx) # current PC = eax
111 collapse_flags # update cpsr, trashes ecx and edx
112
113 call _update_gba # process the next event
114
115 mov %eax, %edi # edi = new cycle count
116 # did the PC change?
117 cmpl $1, CHANGED_PC_STATUS(%ebx)
118 je lookup_pc
119 ret # if not, go back to caller
120
121# Perform this on an indirect branch that will definitely go to
122# ARM code, IE anything that changes the PC in ARM mode except
123# for BX and data processing to PC with the S bit set.
124
125# eax: GBA address to branch to
126# edi: Cycle counter
127
128_x86_indirect_branch_arm:
129 call _block_lookup_address_arm
130 jmp *%eax
131
132# For indirect branches that'll definitely go to Thumb. In
133# Thumb mode any indirect branches except for BX.
134
135_x86_indirect_branch_thumb:
136 call _block_lookup_address_thumb
137 jmp *%eax
138
139# For indirect branches that can go to either Thumb or ARM,
140# mainly BX (also data processing to PC with S bit set, be
141# sure to adjust the target with a 1 in the lowest bit for this)
142
143_x86_indirect_branch_dual:
144 call _block_lookup_address_dual
145 jmp *%eax
146
147
148# General ext memory routines
149
150ext_store_ignore:
151 ret # ignore these writes
152
153write_epilogue:
154 cmp $0, %eax # 0 return means nothing happened
155 jz no_alert # if so we can leave
156
157 collapse_flags # make sure flags are good for function call
158 cmp $2, %eax # see if it was an SMC trigger
159 je smc_write
160
161alert_loop:
162 call _update_gba # process the next event
163
164 # see if the halt status has changed
165 mov CPU_HALT_STATE(%ebx), %edx
166
167 cmp $0, %edx # 0 means it has
168 jnz alert_loop # if not go again
169
170 mov %eax, %edi # edi = new cycle count
171 jmp lookup_pc # pc has definitely changed
172
173no_alert:
174 ret
175
176ext_store_eeprom:
177 jmp _write_eeprom # perform eeprom write
178
179
180# 8bit ext memory routines
181
182ext_store_io8:
183 and $0x3FF, %eax # wrap around address
184 and $0xFF, %edx
185 call _write_io_register8 # perform 8bit I/O register write
186 jmp write_epilogue # see if it requires any system update
187
188ext_store_palette8:
189 and $0x3FE, %eax # wrap around address and align to 16bits
190 jmp ext_store_palette16b # perform 16bit palette write
191
192ext_store_vram8:
193 and $0x1FFFE, %eax # wrap around address and align to 16bits
194 mov %dl, %dh # copy lower 8bits of value into full 16bits
195 cmp $0x18000, %eax # see if address is in upper region
196 jb ext_store_vram8b
197 sub $0x8000, %eax # if so wrap down
198
199ext_store_vram8b:
200 mov %dx, _vram(%eax) # perform 16bit store
201 ret
202
203ext_store_oam8:
204 movl $1, _oam_update # flag OAM update
205 and $0x3FE, %eax # wrap around address and align to 16bits
206 mov %dl, %dh # copy lower 8bits of value into full 16bits
207 mov %dx, _oam_ram(%eax) # perform 16bit store
208 ret
209
210ext_store_backup:
211 and $0xFF, %edx # make value 8bit
212 and $0xFFFF, %eax # mask address
213 jmp _write_backup # perform backup write
214
215ext_store_u8_jtable:
216 .long ext_store_ignore # 0x00 BIOS, ignore
217 .long ext_store_ignore # 0x01 invalid, ignore
218 .long ext_store_ignore # 0x02 EWRAM, should have been hit already
219 .long ext_store_ignore # 0x03 IWRAM, should have been hit already
220 .long ext_store_io8 # 0x04 I/O registers
221 .long ext_store_palette8 # 0x05 Palette RAM
222 .long ext_store_vram8 # 0x06 VRAM
223 .long ext_store_oam8 # 0x07 OAM RAM
224 .long ext_store_ignore # 0x08 gamepak (no RTC accepted in 8bit)
225 .long ext_store_ignore # 0x09 gamepak, ignore
226 .long ext_store_ignore # 0x0A gamepak, ignore
227 .long ext_store_ignore # 0x0B gamepak, ignore
228 .long ext_store_ignore # 0x0C gamepak, ignore
229 .long ext_store_eeprom # 0x0D EEPROM (possibly)
230 .long ext_store_backup # 0x0E Flash ROM/SRAM
231
232ext_store_u8:
233 mov %eax, %ecx # ecx = address
234 shr $24, %ecx # ecx = address >> 24
235 cmp $15, %ecx
236 ja ext_store_ignore
237 # ecx = ext_store_u8_jtable[address >> 24]
238 mov ext_store_u8_jtable(, %ecx, 4), %ecx
239 jmp *%ecx # jump to table index
240
241# eax: address to write to
242# edx: value to write
243# ecx: current pc
244
245_execute_store_u8:
246 mov %ecx, REG_PC(%ebx) # write out the PC
247 mov %eax, %ecx # ecx = address
248 test $0xF0000000, %ecx # check address range
249 jnz ext_store_u8 # if above perform an extended write
250 shr $15, %ecx # ecx = page number of address
251 # load the corresponding memory map offset
252 mov _memory_map_write(, %ecx, 4), %ecx
253 test %ecx, %ecx # see if it's NULL
254 jz ext_store_u8 # if so perform an extended write
255 and $0x7FFF, %eax # isolate the lower 15bits of the address
256 mov %dl, (%eax, %ecx) # store the value
257 # check for self-modifying code
258 testb $0xFF, -32768(%eax, %ecx)
259 jne smc_write
260 ret # return
261
262_execute_store_u16:
263 mov %ecx, REG_PC(%ebx) # write out the PC
264 and $~0x01, %eax # fix alignment
265 mov %eax, %ecx # ecx = address
266 test $0xF0000000, %ecx # check address range
267 jnz ext_store_u16 # if above perform an extended write
268 shr $15, %ecx # ecx = page number of address
269 # load the corresponding memory map offset
270 mov _memory_map_write(, %ecx, 4), %ecx
271 test %ecx, %ecx # see if it's NULL
272 jz ext_store_u16 # if so perform an extended write
273 and $0x7FFF, %eax # isolate the lower 15bits of the address
274 mov %dx, (%eax, %ecx) # store the value
275 # check for self-modifying code
276 testw $0xFFFF, -32768(%eax, %ecx)
277 jne smc_write
278 ret # return
279
280# 16bit ext memory routines
281
282ext_store_io16:
283 and $0x3FF, %eax # wrap around address
284 and $0xFFFF, %edx
285 call _write_io_register16 # perform 16bit I/O register write
286 jmp write_epilogue # see if it requires any system update
287
288ext_store_palette16:
289 and $0x3FF, %eax # wrap around address
290
291ext_store_palette16b: # entry point for 8bit write
292 mov %dx, _palette_ram(%eax) # write out palette value
293 mov %edx, %ecx # cx = dx
294 shl $11, %ecx # cx <<= 11 (red component is in high bits)
295 mov %dh, %cl # bottom bits of cx = top bits of dx
296 shr $2, %cl # move the blue component to the bottom of cl
297 and $0x03E0, %dx # isolate green component of dx
298 shl $1, %dx # make green component 6bits
299 or %edx, %ecx # combine green component into ecx
300 # write out the freshly converted palette value
301 mov %cx, _palette_ram_converted(%eax)
302 ret # done
303
304ext_store_vram16:
305 and $0x1FFFF, %eax # wrap around address
306 cmp $0x18000, %eax # see if address is in upper region
307 jb ext_store_vram16b
308 sub $0x8000, %eax # if so wrap down
309
310ext_store_vram16b:
311 mov %dx, _vram(%eax) # perform 16bit store
312 ret
313
314ext_store_oam16:
315 movl $1, _oam_update # flag OAM update
316 and $0x3FF, %eax # wrap around address
317 mov %dx, _oam_ram(%eax) # perform 16bit store
318 ret
319
320ext_store_rtc:
321 and $0xFFFF, %edx # make value 16bit
322 and $0xFF, %eax # mask address
323 jmp _write_rtc # write out RTC register
324
325ext_store_u16_jtable:
326 .long ext_store_ignore # 0x00 BIOS, ignore
327 .long ext_store_ignore # 0x01 invalid, ignore
328 .long ext_store_ignore # 0x02 EWRAM, should have been hit already
329 .long ext_store_ignore # 0x03 IWRAM, should have been hit already
330 .long ext_store_io16 # 0x04 I/O registers
331 .long ext_store_palette16 # 0x05 Palette RAM
332 .long ext_store_vram16 # 0x06 VRAM
333 .long ext_store_oam16 # 0x07 OAM RAM
334 .long ext_store_rtc # 0x08 gamepak or RTC
335 .long ext_store_ignore # 0x09 gamepak, ignore
336 .long ext_store_ignore # 0x0A gamepak, ignore
337 .long ext_store_ignore # 0x0B gamepak, ignore
338 .long ext_store_ignore # 0x0C gamepak, ignore
339 .long ext_store_eeprom # 0x0D EEPROM (possibly)
340 .long ext_store_ignore # 0x0E Flash ROM/SRAM must be 8bit
341
342ext_store_u16:
343 mov %eax, %ecx # ecx = address
344 shr $24, %ecx # ecx = address >> 24
345 cmp $15, %ecx
346 ja ext_store_ignore
347 # ecx = ext_store_u16_jtable[address >> 24]
348 mov ext_store_u16_jtable(, %ecx, 4), %ecx
349 jmp *%ecx # jump to table index
350
351_execute_store_u32:
352 mov %ecx, REG_PC(%ebx) # write out the PC
353 and $~0x03, %eax # fix alignment
354 mov %eax, %ecx # ecx = address
355 test $0xF0000000, %ecx # check address range
356 jnz ext_store_u32 # if above perform an extended write
357 shr $15, %ecx # ecx = page number of address
358 # load the corresponding memory map offset
359 mov _memory_map_write(, %ecx, 4), %ecx
360 test %ecx, %ecx # see if it's NULL
361 jz ext_store_u32 # if so perform an extended write
362 and $0x7FFF, %eax # isolate the lower 15bits of the address
363 mov %edx, (%eax, %ecx) # store the value
364 # check for self-modifying code
365 testl $0xFFFFFFFF, -32768(%eax, %ecx)
366 jne smc_write
367 ret # return it
368
369# 32bit ext memory routines
370
371ext_store_io32:
372 and $0x3FF, %eax # wrap around address
373 call _write_io_register32 # perform 32bit I/O register write
374 jmp write_epilogue # see if it requires any system update
375
376ext_store_palette32:
377 and $0x3FF, %eax # wrap around address
378 call ext_store_palette16b # write first 16bits
379 add $2, %eax # go to next address
380 shr $16, %edx # go to next 16bits
381 jmp ext_store_palette16b # write next 16bits
382
383ext_store_vram32:
384 and $0x1FFFF, %eax # wrap around address
385 cmp $0x18000, %eax # see if address is in upper region
386 jb ext_store_vram32b
387 sub $0x8000, %eax # if so wrap down
388
389ext_store_vram32b:
390 mov %edx, _vram(%eax) # perform 32bit store
391 ret
392
393ext_store_oam32:
394 movl $1, _oam_update # flag OAM update
395 and $0x3FF, %eax # wrap around address
396 mov %edx, _oam_ram(%eax) # perform 32bit store
397 ret
398
399ext_store_u32_jtable:
400 .long ext_store_ignore # 0x00 BIOS, ignore
401 .long ext_store_ignore # 0x01 invalid, ignore
402 .long ext_store_ignore # 0x02 EWRAM, should have been hit already
403 .long ext_store_ignore # 0x03 IWRAM, should have been hit already
404 .long ext_store_io32 # 0x04 I/O registers
405 .long ext_store_palette32 # 0x05 Palette RAM
406 .long ext_store_vram32 # 0x06 VRAM
407 .long ext_store_oam32 # 0x07 OAM RAM
408 .long ext_store_ignore # 0x08 gamepak, ignore (no RTC in 32bit)
409 .long ext_store_ignore # 0x09 gamepak, ignore
410 .long ext_store_ignore # 0x0A gamepak, ignore
411 .long ext_store_ignore # 0x0B gamepak, ignore
412 .long ext_store_ignore # 0x0C gamepak, ignore
413 .long ext_store_eeprom # 0x0D EEPROM (possibly)
414 .long ext_store_ignore # 0x0E Flash ROM/SRAM must be 8bit
415
416
417ext_store_u32:
418 mov %eax, %ecx # ecx = address
419 shr $24, %ecx # ecx = address >> 24
420 cmp $15, %ecx
421 ja ext_store_ignore
422 # ecx = ext_store_u32_jtable[address >> 24]
423 mov ext_store_u32_jtable(, %ecx, 4), %ecx
424 jmp *%ecx
425
426# %eax = new_cpsr
427# %edx = store_mask
428
429_execute_store_cpsr:
430 mov %edx, REG_SAVE(%ebx) # save store_mask
431 mov %ecx, REG_SAVE2(%ebx) # save PC too
432
433 mov %eax, %ecx # ecx = new_cpsr
434 and %edx, %ecx # ecx = new_cpsr & store_mask
435 mov REG_CPSR(%ebx), %eax # eax = cpsr
436 not %edx # edx = ~store_mask
437 and %edx, %eax # eax = cpsr & ~store_mask
438 or %ecx, %eax # eax = new cpsr combined with old
439
440 call _execute_store_cpsr_body # do the dirty work in this C function
441
442 extract_flags # pull out flag vars from new CPSR
443
444 cmp $0, %eax # see if return value is 0
445 jnz changed_pc_cpsr # might have changed the PC
446
447 ret # return
448
449changed_pc_cpsr:
450 add $4, %esp # get rid of current return address
451 call _block_lookup_address_arm # lookup new PC
452 jmp *%eax
453
454smc_write:
455 call _flush_translation_cache_ram
456
457lookup_pc:
458 add $4, %esp
459 movl $0, CHANGED_PC_STATUS(%ebx)
460 mov REG_PC(%ebx), %eax
461 testl $0x20, REG_CPSR(%ebx)
462 jz lookup_pc_arm
463
464lookup_pc_thumb:
465 call _block_lookup_address_thumb
466 jmp *%eax
467
468lookup_pc_arm:
469 call _block_lookup_address_arm
470 jmp *%eax
471
472# eax: cycle counter
473
474_execute_arm_translate:
475 movl $_reg, %ebx # load base register
476 extract_flags # load flag variables
477 movl %eax, %edi # load edi cycle counter
478
479 movl REG_PC(%ebx), %eax # load PC
480
481 testl $0x20, REG_CPSR(%ebx)
482 jnz 1f
483
484 call _block_lookup_address_arm
485 jmp *%eax # jump to it
486
4871:
488 call _block_lookup_address_thumb
489 jmp *%eax
490
491_step_debug_x86:
492 collapse_flags
493# mov $100, %edi
494 mov %edi, %edx
495 jmp _step_debug
496
497.comm _memory_map_read 0x8000
498.comm _memory_map_write 0x8000
499.comm _reg 0x100
500
501