! SEGA 32X support code for SH2 ! by Chilly Willy ! Rom header and SH2 init/exception code - must be first in object list .text ! Standard MD Header at 0x000 .incbin "m68k_crt0.bin", 0, 0x3C0 ! Standard Mars Header at 0x3C0 .ascii "32X Example " /* module name (16 chars) */ .long 0x00000000 /* version */ .long __text_end-0x02000000 /* Source (in ROM) */ .long 0x00000000 /* Destination (in SDRAM) */ .long __data_size /* Size */ .long 0x06000240 /* Master SH2 Jump */ .long 0x06000244 /* Slave SH2 Jump */ .long 0x06000000 /* Master SH2 VBR */ .long 0x06000120 /* Slave SH2 VBR */ ! Standard MD startup code at 0x3F0 .incbin "m68k_crt1.bin" .data ! Master Vector Base Table at 0x06000000 .long mstart /* Cold Start PC */ .long 0x0603FC00 /* Cold Start SP */ .long mstart /* Manual Reset PC */ .long 0x0603FC00 /* Manual Reset SP */ .long main_err /* Illegal instruction */ .long 0x00000000 /* reserved */ .long main_err /* Invalid slot instruction */ .long 0x20100400 /* reserved */ .long 0x20100420 /* reserved */ .long main_err /* CPU address error */ .long main_err /* DMA address error */ .long main_err /* NMI vector */ .long main_err /* User break vector */ .space 76 /* reserved */ .long main_err /* TRAPA #32 */ .long main_err /* TRAPA #33 */ .long main_err /* TRAPA #34 */ .long main_err /* TRAPA #35 */ .long main_err /* TRAPA #36 */ .long main_err /* TRAPA #37 */ .long main_err /* TRAPA #38 */ .long main_err /* TRAPA #39 */ .long main_err /* TRAPA #40 */ .long main_err /* TRAPA #41 */ .long main_err /* TRAPA #42 */ .long main_err /* TRAPA #43 */ .long main_err /* TRAPA #44 */ .long main_err /* TRAPA #45 */ .long main_err /* TRAPA #46 */ .long main_err /* TRAPA #47 */ .long main_err /* TRAPA #48 */ .long main_err /* TRAPA #49 */ .long main_err /* TRAPA #50 */ .long main_err /* TRAPA #51 */ .long main_err /* TRAPA #52 */ .long main_err /* TRAPA #53 */ .long main_err /* TRAPA #54 */ .long main_err /* TRAPA #55 */ .long main_err /* TRAPA #56 */ .long main_err /* TRAPA #57 */ .long main_err /* TRAPA #58 */ .long main_err /* TRAPA #59 */ .long main_err /* TRAPA #60 */ .long main_err /* TRAPA #61 */ .long main_err /* TRAPA #62 */ .long main_err /* TRAPA #63 */ .long main_irq /* Level 1 IRQ */ .long main_irq /* Level 2 & 3 IRQ's */ .long main_irq /* Level 4 & 5 IRQ's */ .long main_irq /* PWM interupt */ .long main_irq /* Command interupt */ .long main_irq /* H Blank interupt */ .long main_irq /* V Blank interupt */ .long main_irq /* Reset Button */ ! Slave Vector Base Table at 0x06000120 .long sstart /* Cold Start PC */ .long 0x06040000 /* Cold Start SP */ .long sstart /* Manual Reset PC */ .long 0x06040000 /* Manual Reset SP */ .long slav_err /* Illegal instruction */ .long 0x00000000 /* reserved */ .long slav_err /* Invalid slot instruction */ .long 0x20100400 /* reserved */ .long 0x20100420 /* reserved */ .long slav_err /* CPU address error */ .long slav_err /* DMA address error */ .long slav_err /* NMI vector */ .long slav_err /* User break vector */ .space 76 /* reserved */ .long slav_err /* TRAPA #32 */ .long slav_err /* TRAPA #33 */ .long slav_err /* TRAPA #34 */ .long slav_err /* TRAPA #35 */ .long slav_err /* TRAPA #36 */ .long slav_err /* TRAPA #37 */ .long slav_err /* TRAPA #38 */ .long slav_err /* TRAPA #39 */ .long slav_err /* TRAPA #40 */ .long slav_err /* TRAPA #41 */ .long slav_err /* TRAPA #42 */ .long slav_err /* TRAPA #43 */ .long slav_err /* TRAPA #44 */ .long slav_err /* TRAPA #45 */ .long slav_err /* TRAPA #46 */ .long slav_err /* TRAPA #47 */ .long slav_err /* TRAPA #48 */ .long slav_err /* TRAPA #49 */ .long slav_err /* TRAPA #50 */ .long slav_err /* TRAPA #51 */ .long slav_err /* TRAPA #52 */ .long slav_err /* TRAPA #53 */ .long slav_err /* TRAPA #54 */ .long slav_err /* TRAPA #55 */ .long slav_err /* TRAPA #56 */ .long slav_err /* TRAPA #57 */ .long slav_err /* TRAPA #58 */ .long slav_err /* TRAPA #59 */ .long slav_err /* TRAPA #60 */ .long slav_err /* TRAPA #61 */ .long slav_err /* TRAPA #62 */ .long slav_err /* TRAPA #63 */ .long slav_irq /* Level 1 IRQ */ .long slav_irq /* Level 2 & 3 IRQ's */ .long slav_irq /* Level 4 & 5 IRQ's */ .long slav_irq /* PWM interupt */ .long slav_irq /* Command interupt */ .long slav_irq /* H Blank interupt */ .long slav_irq /* V Blank interupt */ .long slav_irq /* Reset Button */ ! The main SH2 starts here at 0x06000240 mstart: bra mcont nop ! The slave SH2 starts here at 0x06000244 sstart: bra scont nop ! Each section of code below has its own data table so that the code ! can be extended without worrying about the offsets becoming too big. ! This results in duplicate entries, but not so many that we care. :) mcont: ! clear interrupt flags mov.l _master_int_clr,r1 mov.w r0,@-r1 /* PWM INT clear */ mov.w r0,@r1 mov.w r0,@-r1 /* CMD INT clear */ mov.w r0,@r1 mov.w r0,@-r1 /* H INT clear */ mov.w r0,@r1 mov.w r0,@-r1 /* V INT clear */ mov.w r0,@r1 mov.w r0,@-r1 /* VRES INT clear */ mov.w r0,@r1 mov.l _master_stk,r15 ! purge cache and turn it off mov.l _master_cctl,r0 mov #0x10,r1 mov.b r1,@r0 ! clear bss mov #0,r0 mov.l _master_bss_start,r1 mov.l _master_bss_end,r2 0: mov.l r0,@r1 cmp/eq r1,r2 bf/s 0b add #4,r1 ! wait for 68000 to finish init mov.l _master_sts,r0 mov.l _master_ok,r1 1: mov.l @r0,r2 nop nop cmp/eq r1,r2 bt 1b ! do all initializers mov.l _master_do_init,r0 jsr @r0 nop ! let Slave SH2 run mov #0,r1 mov.l r1,@(4,r0) /* clear slave status */ mov #0x80,r0 mov.l _master_adapter,r1 mov.b r0,@r1 /* set FM */ mov #0x00,r0 mov.b r0,@(1,r1) /* set int enables */ mov #0x20,r0 ldc r0,sr /* allow ints */ ! purge cache, turn it on, and run main() mov.l _master_cctl,r0 mov #0x11,r1 mov.b r1,@r0 mov.l _master_go,r0 jsr @r0 nop ! do all finishers mov.l _master_do_fini,r0 jsr @r0 nop 2: bra 2b nop .align 2 _master_int_clr: .long 0x2000401E /* one word passed last int clr reg */ _master_stk: .long 0x0603FC00 /* Cold Start SP */ _master_sts: .long 0x20004020 _master_ok: .ascii "M_OK" _master_adapter: .long 0x20004000 _master_cctl: .long 0xFFFFFE92 _master_go: .long _main _master_bss_start: .long __bss_start _master_bss_end: .long __bss_end _master_do_init: .long __INIT_SECTION__ _master_do_fini: .long __FINI_SECTION__ scont: ! clear interrupt flags mov.l _slave_int_clr,r1 mov.w r0,@-r1 /* PWM INT clear */ mov.w r0,@r1 mov.w r0,@-r1 /* CMD INT clear */ mov.w r0,@r1 mov.w r0,@-r1 /* H INT clear */ mov.w r0,@r1 mov.w r0,@-r1 /* V INT clear */ mov.w r0,@r1 mov.w r0,@-r1 /* VRES INT clear */ mov.w r0,@r1 mov.l _slave_stk,r15 ! wait for Master SH2 and 68000 to finish init mov.l _slave_sts,r0 mov.l _slave_ok,r1 1: mov.l @r0,r2 nop nop cmp/eq r1,r2 bt 1b mov.l _slave_adapter,r1 mov #0x00,r0 mov.b r0,@(1,r1) /* set int enables (different from master despite same address!) */ mov #0x20,r0 ldc r0,sr /* allow ints */ ! purge cache, turn it on, and run slave() mov.l _slave_cctl,r0 mov #0x11,r1 mov.b r1,@r0 mov.l _slave_go,r0 jmp @r0 nop .align 2 _slave_int_clr: .long 0x2000401E /* one word passed last int clr reg */ _slave_stk: .long 0x06040000 /* Cold Start SP */ _slave_sts: .long 0x20004024 _slave_ok: .ascii "S_OK" _slave_adapter: .long 0x20004000 _slave_cctl: .long 0xFFFFFE92 _slave_go: .long _slave ! Master exception handler main_err: rte nop ! Master IRQ handler main_irq: mov.l r0,@-r15 stc sr,r0 /* SR holds IRQ level in I3-I0 */ shlr2 r0 and #0x38,r0 cmp/eq #0x28,r0 bt main_h_irq cmp/eq #0x18,r0 bt main_pwm_irq cmp/eq #0x30,r0 bt main_v_irq cmp/eq #0x20,r0 bt main_cmd_irq cmp/eq #0x38,r0 bt main_vres_irq mov.l @r15+,r0 rte nop main_v_irq: mov.l r1,@-r15 mov.l mvi_mars_adapter,r1 mov.w r0,@(0x16,r1) /* clear V IRQ */ nop nop nop nop ! handle V IRQ mov.l @r15+,r1 mov.l @r15+,r0 rte nop .align 2 mvi_mars_adapter: .long 0x20004000 main_h_irq: mov.l r1,@-r15 mov.l mhi_mars_adapter,r1 mov.w r0,@(0x18,r1) /* clear H IRQ */ nop nop nop nop ! handle H IRQ mov.l @r15+,r1 mov.l @r15+,r0 rte nop .align 2 mhi_mars_adapter: .long 0x20004000 main_cmd_irq: mov.l r1,@-r15 mov.l mci_mars_adapter,r1 mov.w r0,@(0x1A,r1) /* clear CMD IRQ */ nop nop nop nop ! handle CMD IRQ mov.l @r15+,r1 mov.l @r15+,r0 rte nop .align 2 mci_mars_adapter: .long 0x20004000 main_pwm_irq: mov.l r1,@-r15 mov.l mpi_mars_adapter,r1 mov.w r0,@(0x1C,r1) /* clear PWM IRQ */ nop nop nop nop ! handle PWM IRQ mov.l @r15+,r1 mov.l @r15+,r0 rte nop .align 2 mpi_mars_adapter: .long 0x20004000 main_vres_irq: mov.l mvri_mars_adapter,r1 mov.w r0,@(0x14,r1) /* clear VRES IRQ */ nop nop nop nop mov #0x0F,r0 shll2 r0 shll2 r0 ldc r0,sr /* disallow ints */ mov.l mvri_master_stk,r15 mov.l mvri_master_vres,r0 jmp @r0 nop .align 2 mvri_mars_adapter: .long 0x20004000 mvri_master_stk: .long 0x0603FC00 /* Cold Start SP */ mvri_master_vres: .long main_reset ! Slave exception handler slav_err: rte nop ! Slave IRQ handler slav_irq: mov.l r0,@-r15 stc sr,r0 /* SR holds IRQ level I3-I0 */ shlr2 r0 and #0x38,r0 cmp/eq #0x28,r0 bt slav_h_irq cmp/eq #0x18,r0 bt slav_pwm_irq cmp/eq #0x30,r0 bt slav_v_irq cmp/eq #0x20,r0 bt slav_cmd_irq cmp/eq #0x38,r0 bt slav_vres_irq mov.l @r15+,r0 rte nop slav_v_irq: mov.l r1,@-r15 mov.l svi_mars_adapter,r1 mov.w r0,@(0x16,r1) /* clear V IRQ */ nop nop nop nop ! handle V IRQ mov.l @r15+,r1 mov.l @r15+,r0 rte nop .align 2 svi_mars_adapter: .long 0x20004000 slav_h_irq: mov.l r1,@-r15 mov.l shi_mars_adapter,r1 mov.w r0,@(0x18,r1) /* clear H IRQ */ nop nop nop nop ! handle H IRQ mov.l @r15+,r1 mov.l @r15+,r0 rte nop .align 2 shi_mars_adapter: .long 0x20004000 slav_cmd_irq: mov.l r1,@-r15 mov.l sci_mars_adapter,r1 mov.w r0,@(0x1A,r1) /* clear CMD IRQ */ nop nop nop nop ! handle CMD IRQ mov.l @r15+,r1 mov.l @r15+,r0 rte nop .align 2 sci_mars_adapter: .long 0x20004000 slav_pwm_irq: mov.l r1,@-r15 mov.l spi_mars_adapter,r1 mov.w r0,@(0x1C,r1) /* clear PWM IRQ */ nop nop nop nop ! handle PWM IRQ mov.l @r15+,r1 mov.l @r15+,r0 rte nop .align 2 spi_mars_adapter: .long 0x20004000 slav_vres_irq: mov.l svri_mars_adapter,r1 mov.w r0,@(0x14,r1) /* clear VRES IRQ */ nop nop nop nop mov #0x0F,r0 shll2 r0 shll2 r0 ldc r0,sr /* disallow ints */ mov.l svri_slave_stk,r15 mov.l svri_slave_vres,r0 jmp @r0 nop .align 2 svri_mars_adapter: .long 0x20004000 svri_slave_stk: .long 0x06040000 /* Cold Start SP */ svri_slave_vres: .long slav_reset ! Fast memcpy function - copies longs, runs from sdram for speed ! On entry: r4 = dst, r5 = src, r6 = len (in longs) .align 4 .global _fast_memcpy _fast_memcpy: mov.l @r5+,r3 mov.l r3,@r4 dt r6 bf/s _fast_memcpy add #4,r4 rts nop ! Cache clear line function ! On entry: r4 = ptr - should be 16 byte aligned .align 4 .global _CacheClearLine _CacheClearLine: mov.l _cache_flush,r0 or r0,r4 mov #0,r0 mov.l r0,@r4 rts nop .align 2 _cache_flush: .long 0x40000000 ! Cache control function ! On entry: r4 = cache mode => 0x10 = CP, 0x08 = TW, 0x01 = CE .align 4 .global _CacheControl _CacheControl: mov.l _sh2_cctl,r0 mov.b r4,@r0 rts nop .align 2 _sh2_cctl: .long 0xFFFFFE92 ! void ScreenStretch(int src, int width, int height, int interp); ! On entry: r4 = src pointer, r5 = width, r6 = height, r7 = interpolate .align 4 .global _ScreenStretch _ScreenStretch: cmp/pl r7 bt ss_interp ! stretch screen without interpolation 0: mov r5,r3 shll r3 mov r3,r2 shll r2 add r4,r3 add r4,r2 1: add #-2,r3 mov.w @r3,r0 extu.w r0,r1 shll16 r0 or r1,r0 mov.l r0,@-r2 cmp/eq r3,r4 bf 1b /* next line */ mov.w ss_pitch,r0 dt r6 bf/s 0b add r0,r4 rts nop ss_interp: ! stretch screen with interpolation 0: mov r5,r3 shll r3 mov r3,r2 shll r2 add r4,r3 add r4,r2 mov #0,r7 1: add #-2,r3 mov.w @r3,r0 mov.w ss_mask,r1 and r0,r1 /* masked curr pixel */ shll16 r0 add r1,r7 /* add to masked prev pixel */ shlr r7 /* blended pixel */ or r7,r0 /* curr pixel << 16 | blended pixel */ mov r1,r7 /* masked prev pixel = masked curr pixel */ mov.l r0,@-r2 cmp/eq r3,r4 bf 1b /* next line */ mov.w ss_pitch,r0 dt r6 bf/s 0b add r0,r4 rts nop ss_mask: .word 0x7BDE ss_pitch: .word 640 .align 2 .text main_reset: ! do any master SH2 specific reset code here mov.l slav_st,r0 mov.l slav_ok,r1 0: mov.l @r0,r2 nop nop cmp/eq r1,r2 bf 0b /* wait for slave */ ! recopy rom data to sdram mov.l rom_header,r1 mov.l @r1,r2 /* src relative to start of rom */ mov.l @(4,r1),r3 /* dst relative to start of sdram */ mov.l @(8,r1),r4 /* size (longword aligned) */ mov.l rom_start,r1 add r1,r2 mov.l sdram_start,r1 add r1,r3 shlr2 r4 /* number of longs */ add #-1,r4 1: mov.l @r2+,r0 mov.l r0,@r3 add #4,r3 dt r4 bf 1b mov.l main_st,r0 mov.l main_ok,r1 mov.l r1,@r0 /* tell everyone reset complete */ mov.l main_go,r0 jmp @r0 nop slav_reset: ! do any slave SH2 specific reset code here mov.l slav_st,r0 mov.l slav_ok,r1 mov.l r1,@r0 /* tell master to start reset */ mov.l main_st,r0 mov.l main_ok,r1 0: mov.l @r0,r2 nop nop cmp/eq r1,r2 bf 0b /* wait for master to do the work */ mov.l slav_go,r0 jmp @r0 nop .align 2 main_st: .long 0x20004020 main_ok: .ascii "M_OK" main_go: .long mstart rom_header: .long 0x220003D4 rom_start: .long 0x22000000 sdram_start: .long 0x26000000 slav_st: .long 0x20004024 slav_ok: .ascii "S_OK" slav_go: .long sstart .global _start _start: