Add copyright message to gles_video
[gpsp.git] / x86 / x86_stub.S
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
146 st:
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
190 ext_store_ignore:
191   ret                         # ignore these writes
192
193 write_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
201 alert_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
213 no_alert:
214   ret
215
216 ext_store_eeprom:
217   jmp _write_eeprom           # perform eeprom write
218
219
220 # 8bit ext memory routines
221
222 ext_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
228 ext_store_palette8:
229   and $0x3FE, %eax            # wrap around address and align to 16bits
230   jmp ext_store_palette16b    # perform 16bit palette write
231
232 ext_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
239 ext_store_vram8b:
240   mov %dx, _vram(%eax)        # perform 16bit store
241   ret
242
243 ext_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
250 ext_store_backup:
251   and $0xFF, %edx             # make value 8bit
252   and $0xFFFF, %eax           # mask address
253   jmp _write_backup           # perform backup write
254
255 ext_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
272 ext_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
322 ext_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
328 ext_store_palette16:
329   and $0x3FF, %eax            # wrap around address
330
331 ext_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
344 ext_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
350 ext_store_vram16b:
351   mov %dx, _vram(%eax)        # perform 16bit store
352   ret
353
354 ext_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
360 ext_store_rtc:
361   and $0xFFFF, %edx           # make value 16bit
362   and $0xFF, %eax             # mask address
363   jmp _write_rtc              # write out RTC register
364
365 ext_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
382 ext_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
411 ext_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
416 ext_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
423 ext_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
429 ext_store_vram32b:
430   mov %edx, _vram(%eax)       # perform 32bit store
431   ret
432
433 ext_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
439 ext_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
457 ext_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
489 changed_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
494 smc_write:
495   call _flush_translation_cache_ram
496
497 lookup_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
504 lookup_pc_thumb:
505   call _block_lookup_address_thumb
506   jmp *%eax
507
508 lookup_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
527 1:
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