From 13255f9d5ee04bbac3b9c254b5295f1eb12d4169 Mon Sep 17 00:00:00 2001 From: XProger Date: Tue, 8 Mar 2022 18:49:55 +0300 Subject: [PATCH] #407 32X use Chilly Willy's CRT code for Mars & Genesis, use preprocessor for asm files --- src/platform/32x/Makefile | 16 +- src/platform/32x/crt/m68k_crt0.s | 85 -- src/platform/32x/crt/sh2_crt0.s | 719 ---------- src/platform/32x/crt0.s | 1272 +++++++++++++++++ src/platform/32x/src-md/Makefile | 46 + src/platform/32x/src-md/cd.s | 183 +++ .../32x/{crt/m68k_crt1.s => src-md/crt0.s} | 329 +++-- src/platform/32x/src-md/kos.s | 110 ++ src/platform/32x/src-md/main.c | 130 ++ 9 files changed, 1943 insertions(+), 947 deletions(-) delete mode 100644 src/platform/32x/crt/m68k_crt0.s delete mode 100644 src/platform/32x/crt/sh2_crt0.s create mode 100644 src/platform/32x/crt0.s create mode 100644 src/platform/32x/src-md/Makefile create mode 100644 src/platform/32x/src-md/cd.s rename src/platform/32x/{crt/m68k_crt1.s => src-md/crt0.s} (67%) create mode 100644 src/platform/32x/src-md/kos.s create mode 100644 src/platform/32x/src-md/main.c diff --git a/src/platform/32x/Makefile b/src/platform/32x/Makefile index ce6c80fb..0d61b89a 100644 --- a/src/platform/32x/Makefile +++ b/src/platform/32x/Makefile @@ -13,6 +13,7 @@ LDSCRIPTSDIR = $(ROOTDIR)/ldscripts SHPREFIX = $(ROOTDIR)/sh-elf/bin/sh-elf- SHCC = $(SHPREFIX)gcc SHXX = $(SHPREFIX)g++ +SHPP = $(SHPREFIX)cpp SHAS = $(SHPREFIX)as SHLD = $(SHPREFIX)ld SHOBJC = $(SHPREFIX)objcopy @@ -41,14 +42,13 @@ FILES_CC = $(foreach dir, $(SOURCES), $(wildcard $(dir)/*.c)) FILES_XX = $(foreach dir, $(SOURCES), $(wildcard $(dir)/*.cpp)) LIBS = $(LIBPATH) -lm -lc -lgcc -lgcc-Os-4-200 -lnosys -OBJS = $(BUILD)/sh2_crt0.o -OBJS += $(addprefix $(BUILD)/, $(notdir $(FILES_AS:%.s=%.o))) +OBJS = $(addprefix $(BUILD)/, $(notdir $(FILES_AS:%.s=%.o))) OBJS += $(addprefix $(BUILD)/, $(notdir $(FILES_CC:%.c=%.o))) OBJS += $(addprefix $(BUILD)/, $(notdir $(FILES_XX:%.cpp=%.o))) .PHONY: dump clean -all: $(BUILD) m68k_crt0.bin m68k_crt1.bin $(TARGET).32x +all: $(BUILD) m68k.bin $(TARGET).32x dump: @[ -d dump ] || mkdir -p dump @@ -68,15 +68,15 @@ $(TARGET).32x: $(TARGET).elf $(TARGET).elf: $(OBJS) $(SHCC) $(SHLDFLAGS) $(OBJS) $(LIBS) -o $(TARGET).elf -%.bin: crt/%.s - $(MDAS) $(MDASFLAGS) -o $(BUILD)/$@.o $< - $(MDLD) $(MDLDFLAGS) -o $(BUILD)/$@ $(BUILD)/$@.o +m68k.bin: + make -C src-md -$(BUILD)/%.o: crt/%.s +$(BUILD)/%.o: %.s $(SHAS) $(SHASFLAGS) $(INCPATH) -o $@ $< $(BUILD)/%.o: asm/%.s - $(SHAS) $(SHASFLAGS) $(INCPATH) -o $@ $< + $(SHPP) $(INCPATH) -o $(BUILD)/$(notdir $<) $< + $(SHAS) $(SHASFLAGS) $(INCPATH) -o $@ $(BUILD)/$(notdir $<) $(BUILD)/%.o: %.c $(SHCC) $(SHCCFLAGS) $(INCPATH) -o $@ $< diff --git a/src/platform/32x/crt/m68k_crt0.s b/src/platform/32x/crt/m68k_crt0.s deleted file mode 100644 index c77c46a5..00000000 --- a/src/platform/32x/crt/m68k_crt0.s +++ /dev/null @@ -1,85 +0,0 @@ -| SEGA 32X support code for the 68000 -| by Chilly Willy -| First part of rom header - - .text - -| Initial exception vectors. When the console is first turned on, it is -| in MegaDrive mode. All vectors just point to the code to start up the -| Mars adapter. After the adapter is enabled, none of these vectors will -| appear as the adpater uses its own vector table to route exceptions to -| the jump table. 0x3F0 is where the 68000 starts at for the 32X. - - .long 0x01000000,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 - .long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 - .long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 - .long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 - .long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 - .long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 - .long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 - .long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 - -| Standard MegaDrive ROM header at 0x100 - - .ascii "SEGA 32X " /* First 4 bytes must be "SEGA" */ - .ascii "XProger (c)2022 " /* Copyright and date */ - .ascii "OpenLara Alpha " /* JP Name */ - .ascii "OpenLara Alpha " /* EN Name */ - .ascii "GM 14021968-01" /* Serial No. */ - .word 0x0000 - .ascii "J6 " - .long 0x00000000,0x003FFFFF /* ROM start, end */ - .long 0x00FF0000,0x00FFFFFF /* RAM start, end */ - -| .ascii "RA" /* External RAM */ -| .byte 0xF8 /* don't clear + odd bytes */ -| .byte 0x20 /* SRAM */ -| .long 0x00200001,0x0020FFFF /* SRAM start, end */ - - .ascii " " /* no SRAM */ - - .ascii " " - .ascii " " - .ascii " " - .ascii " " - .ascii "F " /* enable any hardware configuration */ - -| Mars exception vector jump table at 0x200 - - jmp 0x880800.l /* reset = hot start */ - jsr 0x880806.l /* EX_BusError */ - jsr 0x880806.l /* EX_AddrError */ - jsr 0x880806.l /* EX_IllInstr */ - jsr 0x880806.l /* EX_DivByZero */ - jsr 0x880806.l /* EX_CHK */ - jsr 0x880806.l /* EX_TrapV */ - jsr 0x880806.l /* EX_Priviledge */ - jsr 0x880806.l /* EX_Trace */ - jsr 0x880806.l /* EX_LineA */ - jsr 0x880806.l /* EX_LineF */ - .space 72 /* reserved */ - jsr 0x880806.l /* EX_Spurious */ - jsr 0x880806.l /* EX_Level1 */ - jsr 0x880806.l /* EX_Level2 */ - jsr 0x880806.l /* EX_Level3 */ - jmp 0x88080C.l /* EX_Level4 HBlank */ - jsr 0x880806.l /* EX_Level5 */ - jmp 0x880812.l /* EX_Level6 VBlank */ - jsr 0x880806.l /* EX_Level7 */ - jsr 0x880806.l /* EX_Trap0 */ - jsr 0x880806.l /* EX_Trap1 */ - jsr 0x880806.l /* EX_Trap2 */ - jsr 0x880806.l /* EX_Trap3 */ - jsr 0x880806.l /* EX_Trap4 */ - jsr 0x880806.l /* EX_Trap5 */ - jsr 0x880806.l /* EX_Trap6 */ - jsr 0x880806.l /* EX_Trap7 */ - jsr 0x880806.l /* EX_Trap8 */ - jsr 0x880806.l /* EX_Trap9 */ - jsr 0x880806.l /* EX_TrapA */ - jsr 0x880806.l /* EX_TrapB */ - jsr 0x880806.l /* EX_TrapC */ - jsr 0x880806.l /* EX_TrapD */ - jsr 0x880806.l /* EX_TrapE */ - jsr 0x880806.l /* EX_TrapF */ - .space 166 /* reserved */ diff --git a/src/platform/32x/crt/sh2_crt0.s b/src/platform/32x/crt/sh2_crt0.s deleted file mode 100644 index d4bdee4b..00000000 --- a/src/platform/32x/crt/sh2_crt0.s +++ /dev/null @@ -1,719 +0,0 @@ -! 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 "build/m68k_crt0.bin", 0, 0x3C0 - -! Standard Mars Header at 0x3C0 - - .ascii "OpenLara " /* module name */ - .long 0x00000000 /* version */ - .long __text_size /* 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 "build/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 - -! 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 - jmp @r0 - 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 - -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 - -! Fast memset function - sets long values, runs from sdram for speed -! On entry: r4 = dst, r5 = value, r6 = len (in longs) - - .align 4 - .global _fast_memset -_fast_memset: - mov.l r5,@r4 - dt r6 - bf/s _fast_memset - 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 - -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: - diff --git a/src/platform/32x/crt0.s b/src/platform/32x/crt0.s new file mode 100644 index 00000000..e71422f4 --- /dev/null +++ b/src/platform/32x/crt0.s @@ -0,0 +1,1272 @@ +!----------------------------------------------------------------------- +! SEGA 32X support code for SH2 +! by Chilly Willy +! Rom header and SH2 init/exception code - must be first in object list +!----------------------------------------------------------------------- + + .text + +! 68000 exception vector table at 0x000 + +!----------------------------------------------------------------------- +! Initial exception vectors - when the console is first turned on, it is +! in MegaDrive mode. All vectors just point to the code to start up the +! Mars adapter. After the adapter is enabled, none of these vectors will +! appear as the adapter uses its own vector table to route exceptions to +! the jump table at 0x200. +!----------------------------------------------------------------------- + + .long 0x01000000,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 + .long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 + .long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 + .long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 + .long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 + .long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 + .long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 + .long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0 + +! Standard MegaDrive ROM header at 0x100 + + .ascii "SEGA 32X " /* First 4 bytes must be "SEGA" */ + .ascii "XProger (c)2022 " /* Copyright and date */ + .ascii "OpenLara Alpha " /* JP Name */ + .ascii "OpenLara Alpha " /* EN Name */ + .ascii "GM 14021968-01" /* Serial No. */ + .word 0x0000 + .ascii "J6 " + .long 0x00000000,0x005FFFFF /* ROM start, end */ + .long 0x00FF0000,0x00FFFFFF /* RAM start, end */ + +! 2KB of save ram on odd byte lane + .ascii "RA" /* External RAM */ + .byte 0xF8 /* don't clear + odd bytes */ + .byte 0x20 /* SRAM */ + .long 0x00200001,0x00200FFF /* SRAM start, end */ + +! .ascii " " /* no SRAM */ + + .ascii " " + .ascii " " + .ascii " " + .ascii " " + .ascii "F " /* enable any hardware configuration */ + +! Mars 68000 exception jump table at 0x200 + + .macro jump address + .word 0x4EF9,\address>>16,\address&0xFFFF + .endm + + .macro call address + .word 0x4EB9,\address>>16,\address&0xFFFF + .endm + + jump 0x880800 /* reset = hot start */ + call 0x880840 /* EX_BusError */ + call 0x880840 /* EX_AddrError */ + call 0x880840 /* EX_IllInstr */ + call 0x880840 /* EX_DivByZero */ + call 0x880840 /* EX_CHK */ + call 0x880840 /* EX_TrapV */ + call 0x880840 /* EX_Priviledge */ + call 0x880840 /* EX_Trace */ + call 0x880840 /* EX_LineA */ + call 0x880840 /* EX_LineF */ + .space 72 /* reserved */ + call 0x880840 /* EX_Spurious */ + call 0x880840 /* EX_Level1 */ + call 0x880840 /* EX_Level2 */ + call 0x880840 /* EX_Level3 */ + jump 0x880880 /* EX_Level4 HBlank */ + call 0x880840 /* EX_Level5 */ + jump 0x8808C0 /* EX_Level6 VBlank */ + call 0x880840 /* EX_Level7 */ + call 0x880840 /* EX_Trap0 */ + call 0x880840 /* EX_Trap1 */ + call 0x880840 /* EX_Trap2 */ + call 0x880840 /* EX_Trap3 */ + call 0x880840 /* EX_Trap4 */ + call 0x880840 /* EX_Trap5 */ + call 0x880840 /* EX_Trap6 */ + call 0x880840 /* EX_Trap7 */ + call 0x880840 /* EX_Trap8 */ + call 0x880840 /* EX_Trap9 */ + call 0x880840 /* EX_TrapA */ + call 0x880840 /* EX_TrapB */ + call 0x880840 /* EX_TrapC */ + call 0x880840 /* EX_TrapD */ + call 0x880840 /* EX_TrapE */ + call 0x880840 /* EX_TrapF */ + .space 166 /* reserved */ + +! Standard Mars Header at 0x3C0 + + .ascii "OpenLara " /* module name */ + .long 0x00000000 /* version */ + .long __text_end-0x02000000 /* Source (in ROM) */ + .long 0x00000000 /* Destination (in SDRAM) */ + .long __data_size /* Size */ + .long pri_start /* Primary SH2 Jump */ + .long sec_start /* Secondary SH2 Jump */ + .long pri_vbr /* Primary SH2 VBR */ + .long sec_vbr /* Secondary SH2 VBR */ + +! Standard 32X startup code for MD side at 0x3F0 + + .word 0x287C,0xFFFF,0xFFC0,0x23FC,0x0000,0x0000,0x00A1,0x5128 + .word 0x46FC,0x2700,0x4BF9,0x00A1,0x0000,0x7001,0x0CAD,0x4D41 + .word 0x5253,0x30EC,0x6600,0x03E6,0x082D,0x0007,0x5101,0x67F8 + .word 0x4AAD,0x0008,0x6710,0x4A6D,0x000C,0x670A,0x082D,0x0000 + .word 0x5101,0x6600,0x03B8,0x102D,0x0001,0x0200,0x000F,0x6706 + .word 0x2B78,0x055A,0x4000,0x7200,0x2C41,0x4E66,0x41F9,0x0000 + .word 0x04D4,0x6100,0x0152,0x6100,0x0176,0x47F9,0x0000,0x04E8 + .word 0x43F9,0x00A0,0x0000,0x45F9,0x00C0,0x0011,0x3E3C,0x0100 + .word 0x7000,0x3B47,0x1100,0x3B47,0x1200,0x012D,0x1100,0x66FA + .word 0x7425,0x12DB,0x51CA,0xFFFC,0x3B40,0x1200,0x3B40,0x1100 + .word 0x3B47,0x1200,0x149B,0x149B,0x149B,0x149B,0x41F9,0x0000 + .word 0x04C0,0x43F9,0x00FF,0x0000,0x22D8,0x22D8,0x22D8,0x22D8 + .word 0x22D8,0x22D8,0x22D8,0x22D8,0x41F9,0x00FF,0x0000,0x4ED0 + .word 0x1B7C,0x0001,0x5101,0x41F9,0x0000,0x06BC,0xD1FC,0x0088 + .word 0x0000,0x4ED0,0x0404,0x303C,0x076C,0x0000,0x0000,0xFF00 + .word 0x8137,0x0002,0x0100,0x0000,0xAF01,0xD91F,0x1127,0x0021 + .word 0x2600,0xF977,0xEDB0,0xDDE1,0xFDE1,0xED47,0xED4F,0xD1E1 + .word 0xF108,0xD9C1,0xD1E1,0xF1F9,0xF3ED,0x5636,0xE9E9,0x9FBF + .word 0xDFFF,0x4D41,0x5253,0x2049,0x6E69,0x7469,0x616C,0x2026 + .word 0x2053,0x6563,0x7572,0x6974,0x7920,0x5072,0x6F67,0x7261 + .word 0x6D20,0x2020,0x2020,0x2020,0x2020,0x2043,0x6172,0x7472 + .word 0x6964,0x6765,0x2056,0x6572,0x7369,0x6F6E,0x2020,0x2020 + .word 0x436F,0x7079,0x7269,0x6768,0x7420,0x5345,0x4741,0x2045 + .word 0x4E54,0x4552,0x5052,0x4953,0x4553,0x2C4C,0x5444,0x2E20 + .word 0x3139,0x3934,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020 + .word 0x2020,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020 + .word 0x2020,0x2020,0x2020,0x524F,0x4D20,0x5665,0x7273,0x696F + .word 0x6E20,0x312E,0x3000,0x48E7,0xC040,0x43F9,0x00C0,0x0004 + .word 0x3011,0x303C,0x8000,0x323C,0x0100,0x3E3C,0x0012,0x1018 + .word 0x3280,0xD041,0x51CF,0xFFF8,0x4CDF,0x0203,0x4E75,0x48E7 + .word 0x81C0,0x41F9,0x0000,0x063E,0x43F9,0x00C0,0x0004,0x3298 + .word 0x3298,0x3298,0x3298,0x3298,0x3298,0x3298,0x2298,0x3341 + .word 0xFFFC,0x3011,0x0800,0x0001,0x66F8,0x3298,0x3298,0x7000 + .word 0x22BC,0xC000,0x0000,0x7E0F,0x3340,0xFFFC,0x3340,0xFFFC + .word 0x3340,0xFFFC,0x3340,0xFFFC,0x51CF,0xFFEE,0x22BC,0x4000 + .word 0x0010,0x7E09,0x3340,0xFFFC,0x3340,0xFFFC,0x3340,0xFFFC + .word 0x3340,0xFFFC,0x51CF,0xFFEE,0x4CDF,0x0381,0x4E75,0x8114 + .word 0x8F01,0x93FF,0x94FF,0x9500,0x9600,0x9780,0x4000,0x0080 + .word 0x8104,0x8F02,0x48E7,0xC140,0x43F9,0x00A1,0x5180,0x08A9 + .word 0x0007,0xFF80,0x66F8,0x3E3C,0x00FF,0x7000,0x7200,0x337C + .word 0x00FF,0x0004,0x3341,0x0006,0x3340,0x0008,0x4E71,0x0829 + .word 0x0001,0x000B,0x66F8,0x0641,0x0100,0x51CF,0xFFE8,0x4CDF + .word 0x0283,0x4E75,0x48E7,0x8180,0x41F9,0x00A1,0x5200,0x08A8 + .word 0x0007,0xFF00,0x66F8,0x3E3C,0x001F,0x20C0,0x20C0,0x20C0 + .word 0x20C0,0x51CF,0xFFF6,0x4CDF,0x0181,0x4E75,0x41F9,0x00FF + .word 0x0000,0x3E3C,0x07FF,0x7000,0x20C0,0x20C0,0x20C0,0x20C0 + .word 0x20C0,0x20C0,0x20C0,0x20C0,0x51CF,0xFFEE,0x3B7C,0x0000 + .word 0x1200,0x7E0A,0x51CF,0xFFFE,0x43F9,0x00A1,0x5100,0x7000 + .word 0x2340,0x0020,0x2340,0x0024,0x1B7C,0x0003,0x5101,0x2E79 + .word 0x0088,0x0000,0x0891,0x0007,0x66FA,0x7000,0x3340,0x0002 + .word 0x3340,0x0004,0x3340,0x0006,0x2340,0x0008,0x2340,0x000C + .word 0x3340,0x0010,0x3340,0x0030,0x3340,0x0032,0x3340,0x0038 + .word 0x3340,0x0080,0x3340,0x0082,0x08A9,0x0000,0x008B,0x66F8 + .word 0x6100,0xFF12,0x08E9,0x0000,0x008B,0x67F8,0x6100,0xFF06 + .word 0x08A9,0x0000,0x008B,0x6100,0xFF3C,0x303C,0x0040,0x2229 + .word 0x0020,0x0C81,0x5351,0x4552,0x6700,0x0092,0x303C,0x0080 + .word 0x2229,0x0020,0x0C81,0x5344,0x4552,0x6700,0x0080,0x21FC + .word 0x0088,0x02A2,0x0070,0x303C,0x0002,0x7200,0x122D,0x0001 + .word 0x1429,0x0080,0xE14A,0x8242,0x0801,0x000F,0x660A,0x0801 + .word 0x0006,0x6700,0x0058,0x6008,0x0801,0x0006,0x6600,0x004E + .word 0x7020,0x41F9,0x0088,0x0000,0x3C28,0x018E,0x4A46,0x6700 + .word 0x0010,0x3429,0x0028,0x0C42,0x0000,0x67F6,0xB446,0x662C + .word 0x7000,0x2340,0x0028,0x2340,0x002C,0x3E14,0x2C7C,0xFFFF + .word 0xFFC0,0x4CD6,0x7FF9,0x44FC,0x0000,0x6014,0x43F9,0x00A1 + .word 0x5100,0x3340,0x0006,0x303C,0x8000,0x6004,0x44FC,0x0001 + +!----------------------------------------------------------------------- +! At this point (0x800), the Work RAM is clear, the VDP initialized, the +! VRAM/VSRAM/CRAM cleared, the Z80 initialized, the 32X initialized, +! both 32X framebuffers cleared, the 32X palette cleared, the SH2s +! checked for a startup error, the adapter TV mode matches the MD TV +! mode, and the ROM checksum checked. If any error is detected, the +! carry is set, otherwise it is cleared. The 68000 main code is now +! entered. +!----------------------------------------------------------------------- + + .incbin "src-md/m68k.bin" /* all 68000 code & data, compiled to 0x880800/0xFF0000 */ + + .data + +!----------------------------------------------------------------------- +! Primary Vector Base Table +!----------------------------------------------------------------------- + + .equ pri_stack, 0x0603F800 + .equ sec_stack, 0x06040000 + + .align 4 +pri_vbr: + .long pri_start /* Cold Start PC */ + .long pri_stack /* Cold Start SP */ + .long pri_start /* Manual Reset PC */ + .long pri_stack /* Manual Reset SP */ + .long pri_err /* Illegal instruction */ + .long 0x00000000 /* reserved */ + .long pri_err /* Invalid slot instruction */ + .long 0x00000000 /* reserved */ + .long 0x00000000 /* reserved */ + .long pri_err /* CPU address error */ + .long pri_err /* DMA address error */ + .long pri_err /* NMI vector */ + .long pri_err /* User break vector */ + .space 76 /* reserved */ + .long pri_err /* TRAPA #32 */ + .long pri_err /* TRAPA #33 */ + .long pri_err /* TRAPA #34 */ + .long pri_err /* TRAPA #35 */ + .long pri_err /* TRAPA #36 */ + .long pri_err /* TRAPA #37 */ + .long pri_err /* TRAPA #38 */ + .long pri_err /* TRAPA #39 */ + .long pri_err /* TRAPA #40 */ + .long pri_err /* TRAPA #41 */ + .long pri_err /* TRAPA #42 */ + .long pri_err /* TRAPA #43 */ + .long pri_err /* TRAPA #44 */ + .long pri_err /* TRAPA #45 */ + .long pri_err /* TRAPA #46 */ + .long pri_err /* TRAPA #47 */ + .long pri_err /* TRAPA #48 */ + .long pri_err /* TRAPA #49 */ + .long pri_err /* TRAPA #50 */ + .long pri_err /* TRAPA #51 */ + .long pri_err /* TRAPA #52 */ + .long pri_err /* TRAPA #53 */ + .long pri_err /* TRAPA #54 */ + .long pri_err /* TRAPA #55 */ + .long pri_err /* TRAPA #56 */ + .long pri_err /* TRAPA #57 */ + .long pri_err /* TRAPA #58 */ + .long pri_err /* TRAPA #59 */ + .long pri_err /* TRAPA #60 */ + .long pri_err /* TRAPA #61 */ + .long pri_err /* TRAPA #62 */ + .long pri_err /* TRAPA #63 */ + .long pri_irq /* FRT interrupt (Level 1) */ + .long pri_irq /* WDT interrupt (Level 2 & 3) */ + .long pri_irq /* DMA interrupt (Level 4 & 5) */ + .long pri_irq /* PWM interupt (Level 6 & 7) */ + .long pri_irq /* Command interupt (Level 8 & 9) */ + .long pri_irq /* H Blank interupt (Level 10 & 11) */ + .long pri_irq /* V Blank interupt (Level 12 & 13) */ + .long pri_irq /* Reset Button (Level 14 & 15) */ + +!----------------------------------------------------------------------- +! Secondary Vector Base Table +!----------------------------------------------------------------------- + +sec_vbr: + .long sec_start /* Cold Start PC */ + .long sec_stack /* Cold Start SP */ + .long sec_start /* Manual Reset PC */ + .long sec_stack /* Manual Reset SP */ + .long sec_err /* Illegal instruction */ + .long 0x00000000 /* reserved */ + .long sec_err /* Invalid slot instruction */ + .long 0x00000000 /* reserved */ + .long 0x00000000 /* reserved */ + .long sec_err /* CPU address error */ + .long sec_err /* DMA address error */ + .long sec_err /* NMI vector */ + .long sec_err /* User break vector */ + .space 76 /* reserved */ + .long sec_err /* TRAPA #32 */ + .long sec_err /* TRAPA #33 */ + .long sec_err /* TRAPA #34 */ + .long sec_err /* TRAPA #35 */ + .long sec_err /* TRAPA #36 */ + .long sec_err /* TRAPA #37 */ + .long sec_err /* TRAPA #38 */ + .long sec_err /* TRAPA #39 */ + .long sec_err /* TRAPA #40 */ + .long sec_err /* TRAPA #41 */ + .long sec_err /* TRAPA #42 */ + .long sec_err /* TRAPA #43 */ + .long sec_err /* TRAPA #44 */ + .long sec_err /* TRAPA #45 */ + .long sec_err /* TRAPA #46 */ + .long sec_err /* TRAPA #47 */ + .long sec_err /* TRAPA #48 */ + .long sec_err /* TRAPA #49 */ + .long sec_err /* TRAPA #50 */ + .long sec_err /* TRAPA #51 */ + .long sec_err /* TRAPA #52 */ + .long sec_err /* TRAPA #53 */ + .long sec_err /* TRAPA #54 */ + .long sec_err /* TRAPA #55 */ + .long sec_err /* TRAPA #56 */ + .long sec_err /* TRAPA #57 */ + .long sec_err /* TRAPA #58 */ + .long sec_err /* TRAPA #59 */ + .long sec_err /* TRAPA #60 */ + .long sec_err /* TRAPA #61 */ + .long sec_err /* TRAPA #62 */ + .long sec_err /* TRAPA #63 */ + .long sec_irq /* FRT interrupt (Level 1) */ + .long sec_irq /* WDT interrupt (Level 2 & 3) */ + .long sec_irq /* DMA interrupt (Level 4 & 5) */ + .long sec_irq /* PWM interupt (Level 6 & 7) */ + .long sec_irq /* Command interupt (Level 8 & 9) */ + .long sec_irq /* H Blank interupt (Level 10 & 11 */ + .long sec_irq /* V Blank interupt (Level 12 & 13) */ + .long sec_irq /* Reset Button (Level 14 & 15) */ + +!----------------------------------------------------------------------- +! The Primary SH2 starts here +!----------------------------------------------------------------------- + +pri_start: + ! clear interrupt flags + mov.l _pri_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 _pri_sh2_frtctl,r1 /* Set Free Run Timer */ + mov #0x00,r0 + mov.b r0,@(0x00,r1) /* TIER = ints disabled */ + mov #0xE2,r0 + mov.b r0,@(0x07,r1) /* TOCR = select OCRA, output 1 on compare match */ + mov #0x00,r0 + mov.b r0,@(0x04,r1) /* OCR_H */ + mov #0x01,r0 + mov.b r0,@(0x05,r1) /* OCR_L => OCRA = 0x0001 */ + mov #0,r0 + mov.b r0,@(0x06,r1) /* TCR = input captured on falling edge, CKS = Fs/8 */ + mov #1,r0 + mov.b r0,@(0x01,r1) /* TCSR = clear FRC on match OCRA */ + mov #0x00,r0 + mov.b r0,@(0x03,r1) /* FRC_L */ + mov.b r0,@(0x02,r1) /* FRC_H => clear FRC */ + + mov.l _pri_stk,r15 + + ! purge cache and turn it off + mov.l _pri_cctl,r0 + mov #0x10,r1 /* CP = cache purge, /CE = cache disabled */ + mov.b r1,@r0 + + ! clear bss + mov #0,r0 + mov.l _bss_dst,r1 + mov.l _bss_end,r2 +0: + mov.b r0,@r1 + add #1,r1 + cmp/eq r1,r2 + bf 0b + + ! wait for 68000 to finish init + mov.l _pri_sts,r0 + mov.l _pri_ok,r1 +1: + mov.l @r0,r2 + nop + nop + cmp/eq r1,r2 + bt 1b + + ! let Secondary SH2 run + mov #0,r1 + mov.l r1,@(4,r0) /* clear secondary status */ + + mov #0x80,r0 + mov.l _pri_adapter,r1 + mov.b r0,@r1 /* set FM */ + mov #0x08,r0 /* vbi enabled */ + mov.b r0,@(1,r1) /* set int enables */ + mov #0x10,r0 + ldc r0,sr /* allow ints */ + + ! purge cache, turn it on, and run main() + mov.l _pri_cctl,r0 + mov #0x11,r1 /* CP = cache purge, CE = cache enabled */ + mov.b r1,@r0 + + mov.l _pri_go,r0 + jmp @r0 + nop + + .align 2 +_pri_int_clr: + .long 0x2000401E /* one word passed last int clr reg */ +_pri_stk: + .long pri_stack /* Cold Start SP */ +_pri_sts: + .long 0x20004020 +_pri_sh2_frtctl: + .long 0xfffffe10 +_pri_ok: + .ascii "M_OK" +_pri_adapter: + .long 0x20004000 +_pri_cctl: + .long 0xFFFFFE92 +_pri_go: + .long _main + +_bss_dst: + .long __bss_start +_bss_end: + .long __bss_end + +!----------------------------------------------------------------------- +! Primary exception handler +!----------------------------------------------------------------------- + +pri_err: + rte + nop + +!----------------------------------------------------------------------- +! Primary IRQ handler +!----------------------------------------------------------------------- + +pri_irq: + mov.l r0,@-r15 + mov.l r1,@-r15 + mov.l r2,@-r15 + + stc sr,r1 /* SR holds IRQ level in I3-I0 */ + mov.w p_int_off,r2 + ldc r2,sr /* disallow ints */ + + mov.l p_sys_frt_tocr,r2 + mov #0xE0,r0 /* TOCR = select OCRA, output 0 on compare match */ + mov.b r0,@r2 + mov.b @r2,r0 + + sts.l pr,@-r15 + mov r1,r0 + shlr2 r0 + and #0x3C,r0 /* int level to table offset */ + mov.l p_int_jtable,r1 + mov.l @(r0,r1),r0 + jsr @r0 + nop + + lds.l @r15+,pr + mov.l @r15+,r2 + mov.l @r15+,r1 + mov.l @r15+,r0 + rte + nop + + .align 2 +p_sys_frt_tocr: + .long 0xFFFFFE17 +p_int_jtable: + .long _p_int_jtable +p_int_off: + .word 0x00F0 + + .align 4 +_p_int_jtable: + .long pri_no_irq /* level 0 (ILL) */ + .long pri_no_irq /* level 1 (FRT) */ + .long pri_wdt_irq /* level 2 (WDT) */ + .long pri_wdt_irq /* level 3 (WDT) */ + .long pri_dma_irq /* level 4 (DMA) */ + .long pri_dma_irq /* level 5 (DMA) */ + .long pri_pwm_irq /* level 6 (PWM) */ + .long pri_pwm_irq /* level 7 (PWM) */ + .long pri_cmd_irq /* level 8 (CMD) */ + .long pri_cmd_irq /* level 9 (CMD) */ + .long pri_h_irq /* level 10 (HBI) */ + .long pri_h_irq /* level 11 (HBI) */ + .long pri_v_irq /* level 12 (VBI) */ + .long pri_v_irq /* level 13 (VBI) */ + .long pri_vres_irq /* level 14 (VRES) */ + .long pri_vres_irq /* level 15 (VRES) */ + +!----------------------------------------------------------------------- +! Primary No IRQ handler +!----------------------------------------------------------------------- + +pri_no_irq: + rts + nop + +!----------------------------------------------------------------------- +! Primary V Blank IRQ handler +!----------------------------------------------------------------------- + +pri_v_irq: + ! bump ints if necessary + mov.l pvi_sh2_frtctl,r1 + mov #0xE2,r0 /* TOCR = select OCRA, output 1 on compare match */ + mov.b r0,@(0x07,r1) /* write TOCR */ + mov.b @(0x07,r1),r0 /* read TOCR */ + + mov.l pvi_mars_adapter,r1 + mov.w r0,@(0x16,r1) /* clear V IRQ */ + + ! handle V IRQ - save registers + sts.l pr,@-r15 + mov.l r3,@-r15 + mov.l r4,@-r15 + mov.l r5,@-r15 + mov.l r6,@-r15 + mov.l r7,@-r15 + sts.l mach,@-r15 + sts.l macl,@-r15 + + mov.l pvbi_handler_ptr,r0 + jsr @r0 + nop + + ! restore registers + lds.l @r15+,macl + lds.l @r15+,mach + mov.l @r15+,r7 + mov.l @r15+,r6 + mov.l @r15+,r5 + mov.l @r15+,r4 + mov.l @r15+,r3 + lds.l @r15+,pr + rts + nop + + .align 2 +pvi_mars_adapter: + .long 0x20004000 +pvbi_handler_ptr: + .long _pri_vbi_handler +pvi_sh2_frtctl: + .long 0xfffffe10 + +!----------------------------------------------------------------------- +! Primary H Blank IRQ handler +!----------------------------------------------------------------------- + +pri_h_irq: + ! bump ints if necessary + mov.l phi_sh2_frtctl,r1 + mov #0xE2,r0 /* TOCR = select OCRA, output 1 on compare match */ + mov.b r0,@(0x07,r1) /* write TOCR */ + mov.b @(0x07,r1),r0 /* read TOCR */ + + mov.l phi_mars_adapter,r1 + mov.w r0,@(0x18,r1) /* clear H IRQ */ + nop + nop + nop + nop + + ! handle H IRQ (remove nops if more than 8 cycles) + + rts + nop + + .align 2 +phi_mars_adapter: + .long 0x20004000 +phi_sh2_frtctl: + .long 0xfffffe10 + +!----------------------------------------------------------------------- +! Primary Command IRQ handler +!----------------------------------------------------------------------- + +pri_cmd_irq: + ! bump ints if necessary + mov.l pci_sh2_frtctl,r1 + mov #0xE2,r0 /* TOCR = select OCRA, output 1 on compare match */ + mov.b r0,@(0x07,r1) /* write TOCR */ + mov.b @(0x07,r1),r0 /* read TOCR */ + + mov.l pci_mars_adapter,r1 + mov.w r0,@(0x1A,r1) /* clear CMD IRQ */ + nop + nop + nop + nop + + ! handle CMD IRQ (remove nops if more than 8 cycles) + + rts + nop + + .align 2 +pci_mars_adapter: + .long 0x20004000 +pci_sh2_frtctl: + .long 0xfffffe10 + +!----------------------------------------------------------------------- +! Primary PWM IRQ handler +!----------------------------------------------------------------------- + +pri_pwm_irq: + ! bump ints if necessary + mov.l ppi_sh2_frtctl,r1 + mov #0xE2,r0 /* TOCR = select OCRA, output 1 on compare match */ + mov.b r0,@(0x07,r1) /* write TOCR */ + mov.b @(0x07,r1),r0 /* read TOCR */ + + mov.l ppi_mars_adapter,r1 + mov.w r0,@(0x1C,r1) /* clear PWM IRQ */ + nop + nop + nop + nop + + ! handle PWM IRQ (remove nops if more than 8 cycles) + + rts + nop + + .align 2 +ppi_mars_adapter: + .long 0x20004000 +ppi_sh2_frtctl: + .long 0xfffffe10 + +!----------------------------------------------------------------------- +! Primary DMA IRQ handler +!----------------------------------------------------------------------- + +pri_dma_irq: + ! bump ints if necessary + mov.l pdi_sh2_frtctl,r1 + mov #0xE2,r0 /* TOCR = select OCRA, output 1 on compare match */ + mov.b r0,@(0x07,r1) /* write TOCR */ + mov.b @(0x07,r1),r0 /* read TOCR */ + + ! handle DMA IRQ + + rts + nop + + .align 2 +pdi_sh2_frtctl: + .long 0xfffffe10 + +!----------------------------------------------------------------------- +! Primary WDT IRQ handler +!----------------------------------------------------------------------- + +pri_wdt_irq: + ! bump ints if necessary + mov.l pwi_sh2_frtctl,r1 + mov #0xE2,r0 /* TOCR = select OCRA, output 1 on compare match */ + mov.b r0,@(0x07,r1) /* write TOCR */ + mov.b @(0x07,r1),r0 /* read TOCR */ + + mov.l pwi_sh2_wdtctl,r1 + mov.b @r1,r0 /* read WTCSR */ + tst #0x80,r0 /* check OVF */ + bt 1f /* no overflow */ + mov.w pwi_clr_ovf,r0 + mov.w r0,@r1 /* clear OVF */ + + ! handle WDT overflow + mov.l pwi_ovf_count,r1 + mov.l @r1,r0 + add #1,r0 + mov.l r0,@r1 +1: + rts + nop + + .align 2 +pwi_sh2_frtctl: + .long 0xfffffe10 +pwi_sh2_wdtctl: + .long 0xfffffe80 +pwi_ovf_count: + .long _mars_pwdt_ovf_count +pwi_clr_ovf: + .word 0xa53e /* A5 = sel WTCSR, 3E = clr OVF, IT mode, timer enabled, clksel = Fs/4096 */ + +!----------------------------------------------------------------------- +! Primary RESET IRQ handler +!----------------------------------------------------------------------- + +pri_vres_irq: + mov.l pvri_mars_adapter,r1 + mov.w r0,@(0x14,r1) /* clear VRES IRQ */ + + mov #0x0F,r0 + shll2 r0 + shll2 r0 + ldc r0,sr /* disallow ints */ + + mov.l pvri_pri_stk,r15 + mov.l pvri_pri_vres,r0 + jmp @r0 + nop + + .align 2 +pvri_mars_adapter: + .long 0x20004000 +pvri_pri_stk: + .long pri_stack /* Cold Start SP */ +pvri_pri_vres: + .long pri_reset + +!----------------------------------------------------------------------- +! The Secondary SH2 starts here +!----------------------------------------------------------------------- + +sec_start: + ! clear interrupt flags + mov.l _sec_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 _sec_sh2_frtctl,r1 /* Set Free Run Timer */ + mov #0x00,r0 + mov.b r0,@(0x00,r1) /* TIER = ints disabled */ + mov #0xE2,r0 + mov.b r0,@(0x07,r1) /* TOCR = select OCRA, output 1 on compare match */ + mov #0x00,r0 + mov.b r0,@(0x04,r1) /* OCR_H */ + mov #0x01,r0 + mov.b r0,@(0x05,r1) /* OCR_L => OCRA = 0x0001 */ + mov #0,r0 + mov.b r0,@(0x06,r1) /* TCR = input captured on falling edge, CKS = Fs/8 */ + mov #1,r0 + mov.b r0,@(0x01,r1) /* TCSR = clear FRC on match OCRA */ + mov #0x00,r0 + mov.b r0,@(0x03,r1) /* FRC_L */ + mov.b r0,@(0x02,r1) /* FRC_H => clear FRC */ + + mov.l _sec_stk,r15 + + ! wait for Primary SH2 and 68000 to finish init + mov.l _sec_sts,r0 + mov.l _sec_ok,r1 +1: + mov.l @r0,r2 + nop + nop + cmp/eq r1,r2 + bt 1b + + mov.l _sec_adapter,r1 + mov #0x00,r0 + mov.b r0,@(1,r1) /* set int enables (different from primary despite same address!) */ + mov #0x0F,r0 + shll2 r0 + shll2 r0 + ldc r0,sr /* disallow ints */ + +! purge cache, turn it on, and run secondary() + mov.l _sec_cctl,r0 + mov #0x11,r1 /* CP = cache purge, CE = cache enabled */ + mov.b r1,@r0 + + mov.l _sec_go,r0 + jmp @r0 + nop + + .align 2 +_sec_int_clr: + .long 0x2000401E /* one word passed last int clr reg */ +_sec_stk: + .long sec_stack /* Cold Start SP */ +_sec_sts: + .long 0x20004024 +_sec_sh2_frtctl: + .long 0xfffffe10 +_sec_ok: + .ascii "S_OK" +_sec_adapter: + .long 0x20004000 +_sec_cctl: + .long 0xFFFFFE92 +_sec_go: + .long _secondary + +!----------------------------------------------------------------------- +! Secondary exception handler +!----------------------------------------------------------------------- + +sec_err: + rte + nop + +!----------------------------------------------------------------------- +! Secondary IRQ handler +!----------------------------------------------------------------------- + +sec_irq: + mov.l r0,@-r15 + mov.l r1,@-r15 + mov.l r2,@-r15 + + stc sr,r1 /* SR holds IRQ level in I3-I0 */ + mov.w s_int_off,r2 + ldc r2,sr /* disallow ints */ + + mov.l s_sys_frt_tocr,r2 + mov #0xE0,r0 /* TOCR = select OCRA, output 0 on compare match */ + mov.b r0,@r2 + mov.b @r2,r0 + + sts.l pr,@-r15 + mov r1,r0 + shlr2 r0 + and #0x3C,r0 /* int level to table offset */ + mov.l s_int_jtable,r1 + mov.l @(r0,r1),r0 + jsr @r0 + nop + + lds.l @r15+,pr + mov.l @r15+,r2 + mov.l @r15+,r1 + mov.l @r15+,r0 + rte + nop + + .align 2 +s_sys_frt_tocr: + .long 0xFFFFFE17 +s_int_jtable: + .long _s_int_jtable +s_int_off: + .word 0x00F0 + + .align 4 +_s_int_jtable: + .long sec_no_irq /* level 0 (ILL) */ + .long sec_no_irq /* level 1 (FRT) */ + .long sec_wdt_irq /* level 2 (WDT) */ + .long sec_wdt_irq /* level 3 (WDT) */ + .long sec_dma_irq /* level 4 (DMA) */ + .long sec_dma_irq /* level 5 (DMA) */ + .long sec_pwm_irq /* level 6 (PWM) */ + .long sec_pwm_irq /* level 7 (PWM) */ + .long sec_cmd_irq /* level 8 (CMD) */ + .long sec_cmd_irq /* level 9 (CMD) */ + .long sec_h_irq /* level 10 (HBI) */ + .long sec_h_irq /* level 11 (HBI) */ + .long sec_v_irq /* level 12 (VBI) */ + .long sec_v_irq /* level 13 (VBI) */ + .long sec_vres_irq /* level 14 (VRES) */ + .long sec_vres_irq /* level 15 (VRES) */ + +!----------------------------------------------------------------------- +! Secondary No IRQ handler +!----------------------------------------------------------------------- + +sec_no_irq: + rts + nop + +!----------------------------------------------------------------------- +! Secondary V Blank IRQ handler +!----------------------------------------------------------------------- + +sec_v_irq: + ! bump ints if necessary + mov.l svi_sh2_frtctl,r1 + mov #0xE2,r0 /* TOCR = select OCRA, output 1 on compare match */ + mov.b r0,@(0x07,r1) /* write TOCR */ + mov.b @(0x07,r1),r0 /* read TOCR */ + + mov.l svi_mars_adapter,r1 + mov.w r0,@(0x16,r1) /* clear V IRQ */ + nop + nop + nop + nop + + ! handle V IRQ (remove nops if more than 8 cycles) + + rts + nop + + .align 2 +svi_mars_adapter: + .long 0x20004000 +svi_sh2_frtctl: + .long 0xfffffe10 + +!----------------------------------------------------------------------- +! Secondary H Blank IRQ handler +!----------------------------------------------------------------------- + +sec_h_irq: + ! bump ints if necessary + mov.l shi_sh2_frtctl,r1 + mov #0xE2,r0 /* TOCR = select OCRA, output 1 on compare match */ + mov.b r0,@(0x07,r1) /* write TOCR */ + mov.b @(0x07,r1),r0 /* read TOCR */ + + mov.l shi_mars_adapter,r1 + mov.w r0,@(0x18,r1) /* clear H IRQ */ + nop + nop + nop + nop + + ! handle H IRQ (remove nops if more than 8 cycles) + + rts + nop + + .align 2 +shi_mars_adapter: + .long 0x20004000 +shi_sh2_frtctl: + .long 0xfffffe10 + +!----------------------------------------------------------------------- +! Secondary Command IRQ handler +!----------------------------------------------------------------------- + +sec_cmd_irq: + ! bump ints if necessary + mov.l sci_sh2_frtctl,r1 + mov #0xE2,r0 /* TOCR = select OCRA, output 1 on compare match */ + mov.b r0,@(0x07,r1) /* write TOCR */ + mov.b @(0x07,r1),r0 /* read TOCR */ + + mov.l sci_mars_adapter,r1 + mov.w r0,@(0x1A,r1) /* clear CMD IRQ */ + nop + nop + nop + nop + + ! handle CMD IRQ (remove nops if more than 8 cycles) + + rts + nop + + .align 2 +sci_mars_adapter: + .long 0x20004000 +sci_sh2_frtctl: + .long 0xfffffe10 + +!----------------------------------------------------------------------- +! Secondary PWM IRQ handler +!----------------------------------------------------------------------- + +sec_pwm_irq: + ! bump ints if necessary + mov.l spi_sh2_frtctl,r1 + mov #0xE2,r0 /* TOCR = select OCRA, output 1 on compare match */ + mov.b r0,@(0x07,r1) /* write TOCR */ + mov.b @(0x07,r1),r0 /* read TOCR */ + + mov.l spi_mars_adapter,r1 + mov.w r0,@(0x1C,r1) /* clear PWM IRQ */ + nop + nop + nop + nop + + ! handle PWM IRQ (remove nops if more than 8 cycles) + + rts + nop + + .align 2 +spi_mars_adapter: + .long 0x20004000 +spi_sh2_frtctl: + .long 0xfffffe10 + +!----------------------------------------------------------------------- +! Secondary DMA IRQ handler +!----------------------------------------------------------------------- + +sec_dma_irq: + ! bump ints if necessary + mov.l sdi_sh2_frtctl,r1 + mov #0xE2,r0 /* TOCR = select OCRA, output 1 on compare match */ + mov.b r0,@(0x07,r1) /* write TOCR */ + mov.b @(0x07,r1),r0 /* read TOCR */ + + ! handle DMA IRQ + sts.l pr,@-r15 + mov.l r3,@-r15 + mov.l r4,@-r15 + mov.l r5,@-r15 + mov.l r6,@-r15 + mov.l r7,@-r15 + sts.l mach,@-r15 + sts.l macl,@-r15 + + mov.l sdi_dma_handler,r0 + jsr @r0 + nop + + ! restore registers + lds.l @r15+,macl + lds.l @r15+,mach + mov.l @r15+,r7 + mov.l @r15+,r6 + mov.l @r15+,r5 + mov.l @r15+,r4 + mov.l @r15+,r3 + lds.l @r15+,pr + + rts + nop + + .align 2 +sdi_sh2_frtctl: + .long 0xfffffe10 +sdi_dma_handler: + .long _sec_dma1_handler + +!----------------------------------------------------------------------- +! Secondary WDT IRQ handler +!----------------------------------------------------------------------- + +sec_wdt_irq: + ! bump ints if necessary + mov.l swi_sh2_frtctl,r1 + mov #0xE2,r0 /* TOCR = select OCRA, output 1 on compare match */ + mov.b r0,@(0x07,r1) /* write TOCR */ + mov.b @(0x07,r1),r0 /* read TOCR */ + + mov.l swi_sh2_wdtctl,r1 + mov.b @r1,r0 /* read WTCSR */ + tst #0x80,r0 /* check OVF */ + bt 1f /* no overflow */ + mov.w swi_clr_ovf,r0 + mov.w r0,@r1 /* clear OVF */ + + ! handle WDT overflow + mov.l swi_ovf_count,r1 + mov.l @r1,r0 + add #1,r0 + mov.l r0,@r1 +1: + rts + nop + + .align 2 +swi_sh2_frtctl: + .long 0xfffffe10 +swi_sh2_wdtctl: + .long 0xfffffe80 +swi_ovf_count: + .long _mars_swdt_ovf_count +swi_clr_ovf: + .word 0xa53e /* A5 = sel WTCSR, 3E = clr OVF, IT mode, timer enabled, clksel = Fs/4096 */ + +!----------------------------------------------------------------------- +! Secondary RESET IRQ handler +!----------------------------------------------------------------------- + +sec_vres_irq: + mov.l svri_mars_adapter,r1 + mov.w r0,@(0x14,r1) /* clear VRES IRQ */ + + mov #0x0F,r0 + shll2 r0 + shll2 r0 + ldc r0,sr /* disallow ints */ + + mov.l svri_sec_stk,r15 + mov.l svri_sec_vres,r0 + jmp @r0 + nop + + .align 2 +svri_mars_adapter: + .long 0x20004000 +svri_sec_stk: + .long sec_stack /* Cold Start SP */ +svri_sec_vres: + .long sec_reset + + +!----------------------------------------------------------------------- +!----------------------------------------------------------------------- +! Support Functions +!----------------------------------------------------------------------- +!----------------------------------------------------------------------- + +! void fast_memcpy(int *dst, int *src, int len); +! 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 + + +! Fast memset function - sets long values, runs from sdram for speed +! On entry: r4 = dst, r5 = value, r6 = len (in longs) + + .align 4 + .global _fast_memset +_fast_memset: + mov.l r5,@r4 + dt r6 + bf/s _fast_memset + add #4,r4 + rts + nop + + +! void CacheControl(int mode); +! 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 + + +! int SetSH2SR(int level); +! On entry: r4 = new irq level +! On exit: r0 = old irq level + .align 4 + .global _SetSH2SR +_SetSH2SR: + stc sr,r1 + mov #0x0F,r0 + shll2 r0 + shll2 r0 + and r0,r1 /* just the irq mask */ + shlr2 r1 + shlr2 r1 + not r0,r0 + stc sr,r2 + and r0,r2 + shll2 r4 + shll2 r4 + or r4,r2 + ldc r2,sr + rts + mov r1,r0 + +!----------------------------------------------------------------------- +! Primary and Secondary RESET code +!----------------------------------------------------------------------- + + .align 2 + + .text + +pri_reset: + ! do any primary SH2 specific reset code here + + mov.l sec_st,r0 + mov.l sec_ok,r1 +0: + mov.l @r0,r2 + nop + nop + cmp/eq r1,r2 + bf 0b /* wait for secondary sh2 */ + + ! 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 pri_st,r0 + mov.l pri_ok,r1 + mov.l r1,@r0 /* tell everyone reset complete */ + + mov.l pri_go,r0 + jmp @r0 + nop + +sec_reset: + ! do any secondary SH2 specific reset code here + + mov.l sec_st,r0 + mov.l sec_ok,r1 + mov.l r1,@r0 /* tell primary to start reset */ + + mov.l pri_st,r0 + mov.l pri_ok,r1 +0: + mov.l @r0,r2 + nop + nop + cmp/eq r1,r2 + bf 0b /* wait for primary to do the work */ + + mov.l sec_go,r0 + jmp @r0 + nop + + .align 2 +pri_st: + .long 0x20004020 +pri_ok: + .ascii "M_OK" +pri_go: + .long pri_start +rom_header: + .long 0x220003D4 +rom_start: + .long 0x22000000 +sdram_start: + .long 0x26000000 + +sec_st: + .long 0x20004024 +sec_ok: + .ascii "S_OK" +sec_go: + .long sec_start + + +! this suppresses a warning in the linker about missing start() + + .global _start +_start: diff --git a/src/platform/32x/src-md/Makefile b/src/platform/32x/src-md/Makefile new file mode 100644 index 00000000..b36fe662 --- /dev/null +++ b/src/platform/32x/src-md/Makefile @@ -0,0 +1,46 @@ +ifdef $(GENDEV) +ROOTDIR = $(GENDEV) +else +ROOTDIR = /opt/toolchains/sega +endif + +PREFIX = $(ROOTDIR)/m68k-elf/bin/m68k-elf- +CC = $(PREFIX)gcc +AS = $(PREFIX)as +LD = $(PREFIX)ld +OBJC = $(PREFIX)objcopy + +CC_VER := $(shell $(CC) -dumpversion) + +LDSCRIPTSDIR = $(ROOTDIR)/ldscripts + +LIBPATH = -L$(ROOTDIR)/m68k-elf/lib -L$(ROOTDIR)/m68k-elf/lib/gcc/m68k-elf/$(CC_VER) -L$(ROOTDIR)/m68k-elf/m68k-elf/lib +INCPATH = -I$. -I$(ROOTDIR)/m68k-elf/include -I$(ROOTDIR)/m68k-elf/m68k-elf/include + +CCFLAGS = -m68000 -Wall -O1 -c -fomit-frame-pointer +ASFLAGS = -m68000 --register-prefix-optional +LINKFLAGS = -T $(LDSCRIPTSDIR)/mars-md.ld -Wl,-Map=output.map -nostdlib + +DD = dd +RM = rm -f + +TARGET = m68k +LIBS = $(LIBPATH) -lc -lgcc -lnosys +OBJS = crt0.o main.o kos.o cd.o + +all: $(TARGET).bin + +$(TARGET).bin: $(TARGET).elf + $(OBJC) -O binary $< $(TARGET).bin + +$(TARGET).elf: $(OBJS) + $(CC) $(LINKFLAGS) $(OBJS) $(LIBS) -o $(TARGET).elf + +%.o: %.c + $(CC) $(CCFLAGS) $(INCPATH) $< -o $@ + +%.o: %.s + $(AS) $(ASFLAGS) $(INCPATH) $< -o $@ + +clean: + $(RM) *.o *.bin *.elf output.map diff --git a/src/platform/32x/src-md/cd.s b/src/platform/32x/src-md/cd.s new file mode 100644 index 00000000..ecf0c0e9 --- /dev/null +++ b/src/platform/32x/src-md/cd.s @@ -0,0 +1,183 @@ + + .text + + .global Sub_Start +Sub_Start: + +| Standard MegaCD Sub-CPU Program Header (copied to 0x6000) + +SPHeader: + .asciz "MAIN-SUBCPU" + .word 0x0001,0x0000 + .long 0x00000000 + .long 0x00000000 + .long SPHeaderOffsets-SPHeader + .long 0x00000000 + +SPHeaderOffsets: + .word SPInit-SPHeaderOffsets + .word SPMain-SPHeaderOffsets + .word SPInt2-SPHeaderOffsets + .word SPNull-SPHeaderOffsets + .word 0x0000 + +| Sub-CPU Program Initialization (VBlank not enabled yet) + +SPInit: + move.b #'I,0x800F.w /* sub comm port = INITIALIZING */ + andi.b #0xE2,0x8003.w /* Priority Mode = off, 2M mode, Sub-CPU has access */ + rts + +| Sub-CPU Program Main Entry Point (VBlank now enabled) + +SPMain: + move.w #0x0081,d0 /* CDBSTAT */ + jsr 0x5F22.w /* call CDBIOS function */ + move.w 0(a0),d0 /* BIOS status word */ + bmi.b 1f /* not ready */ + lsr.w #8,d0 + cmpi.b #0x40,d0 + beq.b 9f /* open */ + cmpi.b #0x10,d0 + beq.b 9f /* no disc */ +1: +| Initialize Drive + lea drive_init_parms(pc),a0 + move.w #0x0010,d0 /* DRVINIT */ + jsr 0x5F22.w /* call CDBIOS function */ + + move.w #0x0089,d0 /* CDCSTOP - stop reading data */ + jsr 0x5F22.w /* call CDBIOS function */ +9: + move.b #0,0x800F.w /* sub comm port = READY */ + +| wait for command in main comm port +WaitCmd: + tst.b 0x800E.w + beq.b WaitCmd + cmpi.b #'D,0x800E.w + beq GetDiscInfo + cmpi.b #'T,0x800E.w + beq GetTrackInfo + cmpi.b #'P,0x800E.w + beq PlayTrack + cmpi.b #'S,0x800E.w + beq StopPlaying + cmpi.b #'Z,0x800E.w + beq PauseResume + cmpi.b #'C,0x800E.w + beq CheckDisc + move.b #'E,0x800F.w /* sub comm port = ERROR */ +WaitAck: + tst.b 0x800E.w + bne.b WaitAck /* wait for result acknowledged */ + move.b #0,0x800F.w /* sub comm port = READY */ + bra.b WaitCmd + +GetDiscInfo: + move.w #0x0081,d0 /* CDBSTAT */ + jsr 0x5F22.w /* call CDBIOS function */ + move.w 0(a0),0x8020.w /* BIOS status word */ + move.w 16(a0),0x8022.w /* First song number, Last song number */ + move.w 18(a0),0x8024.w /* Drive version, Flag */ + + move.b #'D,0x800F.w /* sub comm port = DONE */ + bra WaitAck + +GetTrackInfo: + move.w 0x8010.w,d1 /* track number */ + move.w #0x0083,d0 /* CDBTOCREAD */ + jsr 0x5F22.w /* call CDBIOS function */ + move.l d0,0x8020.w /* MMSSFFTN */ + move.b d1,0x8024.w /* track type */ + + move.b #'D,0x800F.w /* sub comm port = DONE */ + bra WaitAck + +PlayTrack: + move.w #0x0002,d0 /* MSCSTOP - stop playing */ + jsr 0x5F22.w /* call CDBIOS function */ + + move.w 0x8010.w,d1 /* track number */ + move.w #0x0011,d0 /* MSCPLAY - play from track on */ + move.b 0x8012.w,d2 /* flag */ + bmi.b 2f + beq.b 1f + move.w #0x0013,d0 /* MSCPLAYR - play with repeat */ + bra.b 2f +1: + move.w #0x0012,d0 /* MSCPLAY1 - play once */ +2: + lea track_number(pc),a0 + move.w d1,(a0) + jsr 0x5F22.w /* call CDBIOS function */ + + move.b #'D,0x800F.w /* sub comm port = DONE */ + bra WaitAck + +StopPlaying: + move.w #0x0002,d0 /* MSCSTOP - stop playing */ + jsr 0x5F22.w /* call CDBIOS function */ + + move.b #'D,0x800F.w /* sub comm port = DONE */ + bra WaitAck + +PauseResume: + move.w #0x0081,d0 /* CDBSTAT */ + jsr 0x5F22.w /* call CDBIOS function */ + move.b (a0),d0 + cmpi.b #1,d0 + beq.b 1f /* playing - pause playback */ + cmpi.b #5,d0 + beq.b 2f /* paused - resume playback */ + + move.b #'E,0x800F.w /* sub comm port = ERROR */ + bra WaitAck +1: + move.w #0x0003,d0 /* MSCPAUSEON - pause playback */ + jsr 0x5F22.w /* call CDBIOS function */ + + move.b #'D,0x800F.w /* sub comm port = DONE */ + bra WaitAck +2: + move.w #0x0004,d0 /* MSCPAUSEOFF - resume playback */ + jsr 0x5F22.w /* call CDBIOS function */ + + move.b #'D,0x800F.w /* sub comm port = DONE */ + bra WaitAck + +CheckDisc: + lea drive_init_parms(pc),a0 + move.w #0x0010,d0 /* DRVINIT */ + jsr 0x5F22.w /* call CDBIOS function */ + + move.w #0x0089,d0 /* CDCSTOP - stop reading data */ + jsr 0x5F22.w /* call CDBIOS function */ + + move.b #'D,0x800F.w /* sub comm port = DONE */ + bra WaitAck + + +| Sub-CPU Program VBlank (INT02) Service Handler + +SPInt2: + rts + +| Sub-CPU program Reserved Function + +SPNull: + rts + + +| Sub-CPU variables + + .align 2 +drive_init_parms: + .byte 0x01, 0xFF /* first track (1), last track (all) */ + +track_number: + .word 0 + + + .global Sub_End +Sub_End: diff --git a/src/platform/32x/crt/m68k_crt1.s b/src/platform/32x/src-md/crt0.s similarity index 67% rename from src/platform/32x/crt/m68k_crt1.s rename to src/platform/32x/src-md/crt0.s index bfffb9ef..491799cf 100644 --- a/src/platform/32x/crt/m68k_crt1.s +++ b/src/platform/32x/src-md/crt0.s @@ -1,119 +1,65 @@ | SEGA 32X support code for the 68000 | by Chilly Willy -| Third part of rom header .text -| Standard Mars startup code at 0x3F0 - this is included as binary as SEGA -| uses this as a security key. US law allows us to include this as-is because -| it's used for security. The interoperability clauses in the law state this -| trumps copyright... and the Supreme Court agrees. :P - - .word 0x287C,0xFFFF,0xFFC0,0x23FC,0x0000,0x0000,0x00A1,0x5128 - .word 0x46FC,0x2700,0x4BF9,0x00A1,0x0000,0x7001,0x0CAD,0x4D41 - .word 0x5253,0x30EC,0x6600,0x03E6,0x082D,0x0007,0x5101,0x67F8 - .word 0x4AAD,0x0008,0x6710,0x4A6D,0x000C,0x670A,0x082D,0x0000 - .word 0x5101,0x6600,0x03B8,0x102D,0x0001,0x0200,0x000F,0x6706 - .word 0x2B78,0x055A,0x4000,0x7200,0x2C41,0x4E66,0x41F9,0x0000 - .word 0x04D4,0x6100,0x0152,0x6100,0x0176,0x47F9,0x0000,0x04E8 - .word 0x43F9,0x00A0,0x0000,0x45F9,0x00C0,0x0011,0x3E3C,0x0100 - .word 0x7000,0x3B47,0x1100,0x3B47,0x1200,0x012D,0x1100,0x66FA - .word 0x7425,0x12DB,0x51CA,0xFFFC,0x3B40,0x1200,0x3B40,0x1100 - .word 0x3B47,0x1200,0x149B,0x149B,0x149B,0x149B,0x41F9,0x0000 - .word 0x04C0,0x43F9,0x00FF,0x0000,0x22D8,0x22D8,0x22D8,0x22D8 - .word 0x22D8,0x22D8,0x22D8,0x22D8,0x41F9,0x00FF,0x0000,0x4ED0 - .word 0x1B7C,0x0001,0x5101,0x41F9,0x0000,0x06BC,0xD1FC,0x0088 - .word 0x0000,0x4ED0,0x0404,0x303C,0x076C,0x0000,0x0000,0xFF00 - .word 0x8137,0x0002,0x0100,0x0000,0xAF01,0xD91F,0x1127,0x0021 - .word 0x2600,0xF977,0xEDB0,0xDDE1,0xFDE1,0xED47,0xED4F,0xD1E1 - .word 0xF108,0xD9C1,0xD1E1,0xF1F9,0xF3ED,0x5636,0xE9E9,0x9FBF - .word 0xDFFF,0x4D41,0x5253,0x2049,0x6E69,0x7469,0x616C,0x2026 - .word 0x2053,0x6563,0x7572,0x6974,0x7920,0x5072,0x6F67,0x7261 - .word 0x6D20,0x2020,0x2020,0x2020,0x2020,0x2043,0x6172,0x7472 - .word 0x6964,0x6765,0x2056,0x6572,0x7369,0x6F6E,0x2020,0x2020 - .word 0x436F,0x7079,0x7269,0x6768,0x7420,0x5345,0x4741,0x2045 - .word 0x4E54,0x4552,0x5052,0x4953,0x4553,0x2C4C,0x5444,0x2E20 - .word 0x3139,0x3934,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020 - .word 0x2020,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020 - .word 0x2020,0x2020,0x2020,0x524F,0x4D20,0x5665,0x7273,0x696F - .word 0x6E20,0x312E,0x3000,0x48E7,0xC040,0x43F9,0x00C0,0x0004 - .word 0x3011,0x303C,0x8000,0x323C,0x0100,0x3E3C,0x0012,0x1018 - .word 0x3280,0xD041,0x51CF,0xFFF8,0x4CDF,0x0203,0x4E75,0x48E7 - .word 0x81C0,0x41F9,0x0000,0x063E,0x43F9,0x00C0,0x0004,0x3298 - .word 0x3298,0x3298,0x3298,0x3298,0x3298,0x3298,0x2298,0x3341 - .word 0xFFFC,0x3011,0x0800,0x0001,0x66F8,0x3298,0x3298,0x7000 - .word 0x22BC,0xC000,0x0000,0x7E0F,0x3340,0xFFFC,0x3340,0xFFFC - .word 0x3340,0xFFFC,0x3340,0xFFFC,0x51CF,0xFFEE,0x22BC,0x4000 - .word 0x0010,0x7E09,0x3340,0xFFFC,0x3340,0xFFFC,0x3340,0xFFFC - .word 0x3340,0xFFFC,0x51CF,0xFFEE,0x4CDF,0x0381,0x4E75,0x8114 - .word 0x8F01,0x93FF,0x94FF,0x9500,0x9600,0x9780,0x4000,0x0080 - .word 0x8104,0x8F02,0x48E7,0xC140,0x43F9,0x00A1,0x5180,0x08A9 - .word 0x0007,0xFF80,0x66F8,0x3E3C,0x00FF,0x7000,0x7200,0x337C - .word 0x00FF,0x0004,0x3341,0x0006,0x3340,0x0008,0x4E71,0x0829 - .word 0x0001,0x000B,0x66F8,0x0641,0x0100,0x51CF,0xFFE8,0x4CDF - .word 0x0283,0x4E75,0x48E7,0x8180,0x41F9,0x00A1,0x5200,0x08A8 - .word 0x0007,0xFF00,0x66F8,0x3E3C,0x001F,0x20C0,0x20C0,0x20C0 - .word 0x20C0,0x51CF,0xFFF6,0x4CDF,0x0181,0x4E75,0x41F9,0x00FF - .word 0x0000,0x3E3C,0x07FF,0x7000,0x20C0,0x20C0,0x20C0,0x20C0 - .word 0x20C0,0x20C0,0x20C0,0x20C0,0x51CF,0xFFEE,0x3B7C,0x0000 - .word 0x1200,0x7E0A,0x51CF,0xFFFE,0x43F9,0x00A1,0x5100,0x7000 - .word 0x2340,0x0020,0x2340,0x0024,0x1B7C,0x0003,0x5101,0x2E79 - .word 0x0088,0x0000,0x0891,0x0007,0x66FA,0x7000,0x3340,0x0002 - .word 0x3340,0x0004,0x3340,0x0006,0x2340,0x0008,0x2340,0x000C - .word 0x3340,0x0010,0x3340,0x0030,0x3340,0x0032,0x3340,0x0038 - .word 0x3340,0x0080,0x3340,0x0082,0x08A9,0x0000,0x008B,0x66F8 - .word 0x6100,0xFF12,0x08E9,0x0000,0x008B,0x67F8,0x6100,0xFF06 - .word 0x08A9,0x0000,0x008B,0x6100,0xFF3C,0x303C,0x0040,0x2229 - .word 0x0020,0x0C81,0x5351,0x4552,0x6700,0x0092,0x303C,0x0080 - .word 0x2229,0x0020,0x0C81,0x5344,0x4552,0x6700,0x0080,0x21FC - .word 0x0088,0x02A2,0x0070,0x303C,0x0002,0x7200,0x122D,0x0001 - .word 0x1429,0x0080,0xE14A,0x8242,0x0801,0x000F,0x660A,0x0801 - .word 0x0006,0x6700,0x0058,0x6008,0x0801,0x0006,0x6600,0x004E - .word 0x7020,0x41F9,0x0088,0x0000,0x3C28,0x018E,0x4A46,0x6700 - .word 0x0010,0x3429,0x0028,0x0C42,0x0000,0x67F6,0xB446,0x662C - .word 0x7000,0x2340,0x0028,0x2340,0x002C,0x3E14,0x2C7C,0xFFFF - .word 0xFFC0,0x4CD6,0x7FF9,0x44FC,0x0000,0x6014,0x43F9,0x00A1 - .word 0x5100,0x3340,0x0006,0x303C,0x8000,0x6004,0x44FC,0x0001 - -| At this point (0x800), the Work RAM is clear, the VDP initialized, the -| VRAM/VSRAM/CRAM cleared, the Z80 initialized, the 32X initialized, -| both 32X framebuffers cleared, the 32X palette cleared, the SH2s -| checked for a startup error, the adapter TV mode matches the MD TV -| mode, and the ROM checksum checked. If any error is detected, the -| carry is set, otherwise it is cleared. The 68000 main code is now -| entered. - - jmp __start+0x00880000+0x3F0 - -| 68000 General exception handler at 0x806 - - jmp __except+0x00880000+0x3F0 - -| 68000 Level 4 interrupt handler at 0x80C - HBlank IRQ - - jmp __hblank+0x00880000+0x3F0 - -| 68000 Level 6 interrupt handler at 0x812 - VBlank IRQ - - jmp __vblank+0x00880000+0x3F0 - -__except: +| 0x880800 - entry point for reset/cold-start + + .global _start +_start: + +| Clear Work RAM + moveq #0,d0 + move.w #0x3FFF,d1 + suba.l a1,a1 +1: + move.l d0,-(a1) + dbra d1,1b + +| Copy initialized variables from ROM to Work RAM + lea __text_end,a0 + move.w #__data_size,d0 + lsr.w #1,d0 + subq.w #1,d0 +2: + move.w (a0)+,(a1)+ + dbra d0,2b + + lea __stack,sp /* set stack pointer to top of Work RAM */ + + bsr init_hardware /* initialize the console hardware */ + + jsr main /* call program main() */ +3: + stop #0x2700 + bra.b 3b + + .align 64 + +| 0x880840 - 68000 General exception handler + move.l d0,-(sp) move.l 4(sp),d0 /* jump table return address */ sub.w #0x206,d0 /* 0 = BusError, 6 = AddrError, etc */ -| handle exception + /* handle exception here */ move.l (sp)+,d0 addq.l #4,sp /* pop jump table return address */ rte -__hblank: + .align 64 + +| 0x880880 - 68000 Level 4 interrupt handler - HBlank IRQ + rte -__vblank: + .align 64 + +| 0x8808C0 - 68000 Level 6 interrupt handler - VBlank IRQ + move.l d0,-(sp) - move.l 0xFF0FFC,d0 + move.l vblank,d0 beq.b 1f move.l a0,-(sp) movea.l d0,a0 @@ -123,14 +69,12 @@ __vblank: rte -__start: - move.b #0,0xA15107 /* clear RV - allow SH2 to access ROM */ -0: - cmp.l #0x4D5F4F4B,0xA15120 /* M_OK */ - bne.b 0b /* wait for master ok */ -1: - cmp.l #0x535F4F4B,0xA15124 /* S_OK */ - bne.b 1b /* wait for slave ok */ +| Initialize the MD side to a known state for the game + +init_hardware: + lea 0xC00004,a0 + move.w #0x8104,(a0) /* display off, vblank disabled */ + move.w (a0),d0 /* read VDP Status reg */ | init joyports move.b #0x40,0xA10009 @@ -139,7 +83,6 @@ __start: move.b #0x40,0xA10005 | init MD VDP - lea 0xC00004,a0 move.w #0x8004,(a0) /* reg. 0 - Disable HBL INT */ move.w #0x8174,(a0) /* reg. 1 - Enable display, VBL INT, DMA + 28 VCell size */ move.w #0x8230,(a0) /* reg. 2 - Plane A =$30*$400=$C000 */ @@ -160,21 +103,12 @@ __start: move.w #0x9100,(a0) /* reg 17 - window hpos */ move.w #0x92FF,(a0) /* reg 18 - window vpos */ -| Copy 68000 main loop to Work RAM to keep contention for the ROM with -| SH2s to a minimum. - lea __m68k_start(pc),a0 - lea 0x00FF1000,a1 - move.w #__m68k_end-__m68k_start-1,d0 -cpyloop: - move.b (a0)+,(a1)+ - dbra d0,cpyloop - move.w #0,0xA15128 /* controller 1 */ move.w #0,0xA1512A /* controller 2 */ | look for mouse lea 0xA10003,a0 0: - bsr get_mky + jsr get_mky cmpi.l #-2,d0 beq.b 0b /* timeout */ cmpi.l #-1,d0 @@ -183,21 +117,84 @@ cpyloop: 1: lea 2(a0),a0 2: - bsr get_mky + jsr get_mky cmpi.l #-2,d0 beq.b 2b /* timeout */ cmpi.l #-1,d0 beq.b 3f /* no mouse */ move.w #0xF001,0xA1512A /* mouse in port 2 */ 3: - move.l #0,0xA1512C /* clear the vblank count */ -| jump to main loop in Work RAM - jmp 0xFF1000.l +| allow the 68k to access the FM chip + move.w #0x0100,0xA11100 /* Z80 assert bus request */ + move.w #0x0100,0xA11200 /* Z80 deassert reset */ + +| wait on Mars side + move.b #0,0xA15107 /* clear RV - allow SH2 to access ROM */ +0: + cmp.l #0x4D5F4F4B,0xA15120 /* M_OK */ + bne.b 0b /* wait for master ok */ +1: + cmp.l #0x535F4F4B,0xA15124 /* S_OK */ + bne.b 1b /* wait for slave ok */ + + move.l #vert_blank,vblank /* set vertical blank interrupt handler */ + move.w #0x2000,sr /* enable interrupts */ + rts + + +| void write_byte(void *dst, unsigned char val) + .global write_byte +write_byte: + movea.l 4(sp),a0 + move.l 8(sp),d0 + move.b d0,(a0) + rts + +| void write_word(void *dst, unsigned short val) + .global write_word +write_word: + movea.l 4(sp),a0 + move.l 8(sp),d0 + move.w d0,(a0) + rts + +| void write_long(void *dst, unsigned int val) + .global write_long +write_long: + movea.l 4(sp),a0 + move.l 8(sp),d0 + move.l d0,(a0) + rts + +| unsigned char read_byte(void *src) + .global read_byte +read_byte: + movea.l 4(sp),a0 + move.b (a0),d0 + rts + +| unsigned short read_word(void *src) + .global read_word +read_word: + movea.l 4(sp),a0 + move.w (a0),d0 + rts + +| unsigned int read_long(void *src) + .global read_long +read_long: + movea.l 4(sp),a0 + move.l (a0),d0 + rts + + + .data -| this block of code must be pc relative as it's copied into Work RAM +| Put remaining code in data section to lower bus contention for the rom. -__m68k_start: + .global do_main +do_main: move.b #1,0xA15107 /* set RV */ move.b #2,0xA130F1 /* SRAM disabled, write protected */ move.b #0,0xA15107 /* clear RV */ @@ -207,16 +204,11 @@ __m68k_start: move.w d0,0xA15100 /* set FM - allow SH2 access to MARS hw */ move.l #0,0xA15120 /* let Master SH2 run */ - lea vert_blank(pc),a0 - move.l a0,0xFF0FFC /* set vertical blank interrupt handler */ - move.w #0x2000,sr /* enable interrupts */ - main_loop: move.w 0xA15120,d0 /* get COMM0 */ bne.b handle_req -| any other 68000 tasks here - + nop bra.b main_loop | process request from Master SH2 @@ -278,7 +270,56 @@ set_rom_bank: rts start_music: + tst.w cd_ok + beq.b 2f /* couldn't init cd */ + tst.b cd_ok + bne.b 0f /* disc found - try to play track */ + /* check for CD */ +10: + move.b 0xA1200F,d1 + bne.b 10b /* wait until Sub-CPU is ready to receive command */ + move.b #'D,0xA1200E /* set main comm port to GetDiskInfo command */ +11: + move.b 0xA1200F,d0 + beq.b 11b /* wait for acknowledge byte in sub comm port */ + move.b #0x00,0xA1200E /* acknowledge receipt of command result */ + + cmpi.b #'D,d0 + bne.b 2f /* couldn't get disk info */ + move.w 0xA12020,d0 /* BIOS status */ + cmpi.w #0x1000,d0 + bhs.b 2f /* open, busy, or no disc */ + move.b #1,cd_ok /* we have a disc - try to play track */ +0: + move.b 0xA1200F,d1 + bne.b 0b /* wait until Sub-CPU is ready to receive command */ + + move.b d0,0xA12012 /* repeat flag */ + move.w 0xA15122,d0 + addq.w #1,d0 + move.w d0,0xA12010 /* track no. */ + move.b #'P,0xA1200E /* set main comm port to PlayTrack command */ +1: + move.b 0xA1200F,d0 + beq.b 1b /* wait for acknowledge byte in sub comm port */ + move.b #0x00,0xA1200E /* acknowledge receipt of command result */ +2: + move.w #0,0xA15120 /* done */ + bra main_loop + stop_music: + tst.w cd_ok + beq.b 2f +0: + move.b 0xA1200F,d1 + bne.b 0b /* wait until Sub-CPU is ready to receive command */ + + move.b #'S,0xA1200E /* set main comm port to StopPlayback command */ +1: + move.b 0xA1200F,d0 + beq.b 1b /* wait for acknowledge byte in sub comm port */ + move.b #0x00,0xA1200E /* acknowledge receipt of command result */ +2: move.w #0,0xA15120 /* done */ bra main_loop @@ -347,10 +388,14 @@ vert_blank: bsr.b get_pad move.w d2,0xA1512A /* controller 2 current value */ 1: - move.l 0xA1512C,d0 - addq.l #1,d0 - move.l d0,0xA1512C /* increment the vblank count */ + tst.w gen_lvl2 + beq.b 2f + lea 0xA12000,a0 + move.w (a0),d0 + ori.w #0x0100,d0 + move.w d0,(a0) +2: move.l (sp)+,d2 move.l (sp)+,d1 movea.l (sp)+,a0 @@ -543,6 +588,20 @@ mky_err: moveq #-1,d0 rts -__m68k_end: - .align 4 +| Global variables for 68000 + + .align 4 + +vblank: + dc.l 0 + + .global gen_lvl2 +gen_lvl2: + dc.w 0 + + .global cd_ok +cd_ok: + dc.w 0 + + .align 4 diff --git a/src/platform/32x/src-md/kos.s b/src/platform/32x/src-md/kos.s new file mode 100644 index 00000000..c05f836f --- /dev/null +++ b/src/platform/32x/src-md/kos.s @@ -0,0 +1,110 @@ +| --------------------------------------------------------------------------- +| Kosinski decompression subroutine +| void Kos_Decomp(uint8_t *src, uint8_t *dst) +| Inputs: +| 4(sp) = compressed data location +| 8(sp) = destination +| --------------------------------------------------------------------------- + + .text + + .global Kos_Decomp +Kos_Decomp: + movea.l 4(sp),a0 + movea.l 8(sp),a1 + movem.l d2-d6,-(sp) + subq.l #2,sp /* make space for two bytes on the stack */ + move.b (a0)+,1(sp) + move.b (a0)+,(sp) + move.w (sp),d5 /* copy first description field */ + moveq #15,d4 /* 16 bits in a byte */ + +Kos_Decomp_Loop: + lsr.w #1,d5 /* bit which is shifted out goes into C flag */ + move sr,d6 + dbra d4,Kos_Decomp_ChkBit + move.b (a0)+,1(sp) + move.b (a0)+,(sp) + move.w (sp),d5 /* get next description field if needed */ + moveq #15,d4 /* reset bit counter */ + +Kos_Decomp_ChkBit: + move d6,ccr /* was the bit set? */ + bcc.b Kos_Decomp_RLE /* if not, branch (C flag clear means bit was clear) */ + move.b (a0)+,(a1)+ /* otherwise, copy byte as-is */ + bra.b Kos_Decomp_Loop + +| --------------------------------------------------------------------------- + +Kos_Decomp_RLE: + moveq #0,d3 + lsr.w #1,d5 /* get next bit */ + move sr,d6 + dbra d4,Kos_Decomp_ChkBit2 + move.b (a0)+,1(sp) + move.b (a0)+,(sp) + move.w (sp),d5 + moveq #15,d4 + +Kos_Decomp_ChkBit2: + move d6,ccr /* was the bit set? */ + bcs.b Kos_Decomp_SeparateRLE /* if it was, branch */ + lsr.w #1,d5 /* bit which is shifted out goes into X flag */ + dbra d4,1f + move.b (a0)+,1(sp) + move.b (a0)+,(sp) + move.w (sp),d5 + moveq #15,d4 +1: + roxl.w #1,d3 /* get high repeat count bit (shift X flag in) */ + lsr.w #1,d5 + dbra d4,2f + move.b (a0)+,1(sp) + move.b (a0)+,(sp) + move.w (sp),d5 + moveq #15,d4 +2: + roxl.w #1,d3 /* get low repeat count bit */ + addq.w #1,d3 /* increment repeat count */ + moveq #-1,d2 + move.b (a0)+,d2 /* calculate offset */ + bra.b Kos_Decomp_RLELoop + +| --------------------------------------------------------------------------- + +Kos_Decomp_SeparateRLE: + move.b (a0)+,d0 /* get first byte */ + move.b (a0)+,d1 /* get second byte */ + moveq #-1,d2 + move.b d1,d2 + lsl.w #5,d2 + move.b d0,d2 /* calculate offset */ + andi.w #7,d1 /* does a third byte need to be read? */ + beq.b Kos_Decomp_SeparateRLE2 /* if it does, branch */ + move.b d1,d3 /* copy repeat count */ + addq.w #1,d3 /* and increment it */ + +Kos_Decomp_RLELoop: + move.b (a1,d2.w),d0 + move.b d0,(a1)+ /* copy appropriate byte */ + dbra d3,Kos_Decomp_RLELoop /* and repeat the copying */ + bra.b Kos_Decomp_Loop + +| --------------------------------------------------------------------------- + +Kos_Decomp_SeparateRLE2: + move.b (a0)+,d1 + beq.b Kos_Decomp_Done /* 0 indicates end of compressed data */ + cmpi.b #1,d1 + beq.w Kos_Decomp_Loop /* 1 indicates a new description needs to be read */ + move.b d1,d3 /* otherwise, copy repeat count */ + bra.b Kos_Decomp_RLELoop + +| --------------------------------------------------------------------------- + +Kos_Decomp_Done: + addq.l #2,sp /* restore stack pointer to original state */ + movem.l (sp)+,d2-d6 + rts + +| End of function Kos_Decomp diff --git a/src/platform/32x/src-md/main.c b/src/platform/32x/src-md/main.c new file mode 100644 index 00000000..563c8bef --- /dev/null +++ b/src/platform/32x/src-md/main.c @@ -0,0 +1,130 @@ +/* + * SEGA CD Mode 1 Support + * by Chilly Willy + */ + +#include +#include + +extern uint32_t vblank_vector; +extern uint16_t gen_lvl2; +extern uint16_t cd_ok; + +extern uint32_t Sub_Start; +extern uint32_t Sub_End; + +extern void Kos_Decomp(uint8_t *src, uint8_t *dst); + +extern void write_byte(unsigned int dst, unsigned char val); +extern void write_word(unsigned int dst, unsigned short val); +extern void write_long(unsigned int dst, unsigned int val); +extern unsigned char read_byte(unsigned int src); +extern unsigned short read_word(unsigned int src); +extern unsigned int read_long(unsigned int src); + +extern void do_main(void); + +uint16_t InitCD(void) +{ + char *bios; + + /* + * Check for CD BIOS + * When a cart is inserted in the MD, the CD hardware is mapped to + * 0x400000 instead of 0x000000. So the BIOS ROM is at 0x400000, the + * Program RAM bank is at 0x420000, and the Word RAM is at 0x600000. + */ + bios = (char *)0x415800; + if (memcmp(bios + 0x6D, "SEGA", 4)) + { + bios = (char *)0x416000; + if (memcmp(bios + 0x6D, "SEGA", 4)) + { + // check for WonderMega/X'Eye + if (memcmp(bios + 0x6D, "WONDER", 6)) + { + bios = (char *)0x41AD00; // might also be 0x40D500 + // check for LaserActive + if (memcmp(bios + 0x6D, "SEGA", 4)) + return 0; // no CD + } + } + } + + /* + * Reset the Gate Array - this specific sequence of writes is recognized by + * the gate array as a reset sequence, clearing the entire internal state - + * this is needed for the LaserActive + */ + write_word(0xA12002, 0xFF00); + write_byte(0xA12001, 0x03); + write_byte(0xA12001, 0x02); + write_byte(0xA12001, 0x00); + + /* + * Reset the Sub-CPU, request the bus + */ + write_byte(0xA12001, 0x02); + while (!(read_byte(0xA12001) & 2)) write_byte(0xA12001, 0x02); // wait on bus acknowledge + + /* + * Decompress Sub-CPU BIOS to Program RAM at 0x00000 + */ + write_word(0xA12002, 0x0002); // no write-protection, bank 0, 2M mode, Word RAM assigned to Sub-CPU + memset((char *)0x420000, 0, 0x20000); // clear program ram first bank - needed for the LaserActive + Kos_Decomp((uint8_t *)bios, (uint8_t *)0x420000); + + /* + * Copy Sub-CPU program to Program RAM at 0x06000 + */ + memcpy((char *)0x426000, (char *)&Sub_Start, (int)&Sub_End - (int)&Sub_Start); + + write_byte(0xA1200E, 0x00); // clear main comm port + write_byte(0xA12002, 0x2A); // write-protect up to 0x05400 + write_byte(0xA12001, 0x01); // clear bus request, deassert reset - allow CD Sub-CPU to run + while (!(read_byte(0xA12001) & 1)) write_byte(0xA12001, 0x01); // wait on Sub-CPU running + + /* + * Set the vertical blank handler to generate Sub-CPU level 2 ints. + * The Sub-CPU BIOS needs these in order to run. + */ + gen_lvl2 = 1; // generate Level 2 IRQ to Sub-CPU + + /* + * Wait for Sub-CPU program to set sub comm port indicating it is running - + * note that unless there's something wrong with the hardware, a timeout isn't + * needed... just loop until the Sub-CPU program responds, but 2000000 is about + * ten times what the LaserActive needs, and the LA is the slowest unit to + * initialize + */ + while (read_byte(0xA1200F) != 'I') + { + static int timeout = 0; + timeout++; + if (timeout > 2000000) + { + gen_lvl2 = 0; + return 0; // no CD + } + } + + /* + * Wait for Sub-CPU to indicate it is ready to receive commands + */ + while (read_byte(0xA1200F) != 0x00) ; + + return 1; // CD ready to go! +} + +int main(void) +{ + cd_ok = 0; //InitCD(); + + /* + * Main loop in ram - you need to have it in ram to avoid bus contention + * for the rom with the SH2s. + */ + do_main(); // never returns + + return 0; +}