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