From 3e2b2c146c2f341ef38e24e32e5b1fc6176e7cca Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Fri, 8 Dec 2023 18:36:49 +0200 Subject: [PATCH 1/1] initial commit --- .gitignore | 6 ++++ Makefile | 59 +++++++++++++++++++++++++++++++ megadrive.ld | 47 +++++++++++++++++++++++++ src/intr.s | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 4 +++ src/romhdr.S | 37 ++++++++++++++++++++ src/startup.s | 42 ++++++++++++++++++++++ src/vdpdefs.inc | 13 +++++++ 8 files changed, 312 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 megadrive.ld create mode 100644 src/intr.s create mode 100644 src/main.c create mode 100644 src/romhdr.S create mode 100644 src/startup.s create mode 100644 src/vdpdefs.inc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d11753f --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.o +*.swp +*.d +*.bin +*.elf +*.map diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..002cba4 --- /dev/null +++ b/Makefile @@ -0,0 +1,59 @@ +csrc = $(wildcard src/*.c) $(wildcard src/libc/*.c) +asrc = $(wildcard src/*.s) +aSsrc = $(wildcard src/*.S) +obj = $(asrc:.s=.o) $(aSsrc:.S=.o) $(csrc:.c=.o) +dep = $(csrc:.c=.d) + +name = life +elf = $(name).elf +bin = $(name).bin + +warn = -pedantic -Wall +dbg = -g +opt = -O2 +def = -D__NO_CTYPE +inc = -I. -Isrc -Isrc/libc + +TC = m68k-linux-gnu- + +CC = $(TC)gcc +AS = $(TC)as +LD = $(TC)ld +OBJCOPY = $(TC)objcopy + +CFLAGS = -m68000 -ffreestanding -fno-builtin -fcommon $(warn) $(dbg) $(opt) $(def) $(inc) -MMD +CPPFLAGS = $(def) +ASFLAGS = -m68000 $(inc) +LDFLAGS = -T megadrive.ld -print-gc-sections \ + -L/usr/lib/gcc-cross/m68k-linux-gnu/11 -lgcc + +$(bin): $(elf) + $(OBJCOPY) -O binary $< $@ + +$(elf): $(obj) + $(LD) -o $@ $(obj) -Map link.map $(LDFLAGS) + +-include $(dep) + +.PHONY: clean +clean: + rm -f $(obj) $(elf) $(bin) + +.PHONY: cleandep +cleandep: + rm -f $(dep) + +.PHONY: run +run: $(bin) + mednafen $< + +.PHONY: copy +copy: $(bin) + mount /media/usbmass && cp $(bin) /media/usbmass/$(bin) + umount /media/usbmass + +.PHONY: install +install: $(bin) + mount /media/usbmass + [ -f /media/usbmass/MEGA/MEGA.RBF ] || cp $(bin) /media/usbmass/MEGA/MEGA.BIN + umount /media/usbmass diff --git a/megadrive.ld b/megadrive.ld new file mode 100644 index 0000000..dce3828 --- /dev/null +++ b/megadrive.ld @@ -0,0 +1,47 @@ +OUTPUT_ARCH(m68k) + +MEMORY +{ + rom : ORIGIN = 0x00000000, LENGTH = 0x00a00000 + ram : ORIGIN = 0x00ff0000, LENGTH = 0x00010000 +} + +PROVIDE (_stacktop = 0x01000000); + +SECTIONS { + /* ---- start of ROM ---- */ + /* .vect section is used to place the m68k exception vectors at the + * beginning of the address space + */ + .vect : { * (.vect); } >rom + /* .romhdr section is used to place the SEGA ROM header at 0x100 */ + . = 0x100; + .romhdr : { * (.romhdr); } >rom + .text : { * (.text); } >rom + .rodata : { * (.rodata); } >rom + + /* place the load address of the .data section after .rodata */ + . = ALIGN(4); + _data_lma = .; + _rom_end = _data_lma + _data_size; + + /* ---- start of RAM ---- */ + . = 0xff0000; + /* place the .data section at the start of RAM */ + .data ALIGN(4): AT (_data_lma) { + _data_start = .; + * (.data); + . = ALIGN(4); + _data_end = .; + } >ram + _data_size = SIZEOF(.data); + + /* place the .bss section at the end */ + .bss ALIGN(4): { + _bss_start = .; + * (.bss); + . = ALIGN(4); + _bss_end = .; + } >ram + _bss_size = SIZEOF(.bss); +} diff --git a/src/intr.s b/src/intr.s new file mode 100644 index 0000000..8f4f01e --- /dev/null +++ b/src/intr.s @@ -0,0 +1,104 @@ +| vi:filetype=gas68k: +| the following will go into the .vect section which will be placed at the very +| begining of the binary at address 0 by the linker (see lnkscript). + .section .vect,"a" + .extern start +| exception vectors + .long _stacktop | 00 reset - initial SSP + .long start | 01 reset - initial PC + .long intr_fatal | 02 bus error + .long intr_fatal | 03 address error + .long intr_fatal | 04 illegal instruction + .long intr_fatal | 05 zero divide + .long intr_fatal | 06 chk instruction + .long intr_fatal | 07 trapv instruction + .long intr_fatal | 08 privilege violation + .long intr_fatal | 09 trace + .long intr_fatal | 0a line 1010 emulator + .long intr_fatal | 0b line 1111 emulator + .long intr_fatal | 0c reserved + .long intr_fatal | 0d reserved + .long intr_fatal | 0e format error (mc68010 only) + .long intr_fatal | 0f uninitialized interrupt vector + .long intr_fatal | 10 \ + .long intr_fatal | 11 | + .long intr_fatal | 12 | + .long intr_fatal | 13 > reserved + .long intr_fatal | 14 | + .long intr_fatal | 15 | + .long intr_fatal | 16 | + .long intr_fatal | 17 / + .long intr_fatal | 18 spurious interrupt + .long intr_fatal | 19 level 1 interrupt + .long intr_fatal | 1a level 2 interrupt + .long intr_fatal | 1b level 3 interrupt + .long intr_hblank | 1c level 4 interrupt (hblank in the mega drive) + .long intr_fatal | 1d level 5 interrupt + .long intr_vblank | 1e level 6 interrupt (vblank in the mega drive) + .long intr_fatal | 1f level 7 interrupt + .long intr_fatal | 20 trap 0 + .long intr_fatal | 21 trap 1 + .long intr_fatal | 22 trap 2 + .long intr_fatal | 23 trap 3 + .long intr_fatal | 24 trap 4 + .long intr_fatal | 25 trap 5 + .long intr_fatal | 26 trap 6 + .long intr_fatal | 27 trap 7 + .long intr_fatal | 28 trap 8 + .long intr_fatal | 29 trap 9 + .long intr_fatal | 2a trap a + .long intr_fatal | 2b trap b + .long intr_fatal | 2c trap c + .long intr_fatal | 2d trap d + .long intr_fatal | 2e trap e + .long intr_fatal | 2f trap f + .long intr_fatal | 30 \ + .long intr_fatal | 31 | + .long intr_fatal | 32 | + .long intr_fatal | 33 | + .long intr_fatal | 34 | + .long intr_fatal | 35 | + .long intr_fatal | 36 | + .long intr_fatal | 37 | + .long intr_fatal | 38 > reserved + .long intr_fatal | 39 | + .long intr_fatal | 3a | + .long intr_fatal | 3b | + .long intr_fatal | 3c | + .long intr_fatal | 3d | + .long intr_fatal | 3e | + .long intr_fatal | 3f / + +| from here on we continue in the regular .text section since we don't care +| where this code ends up. + .text + +.global enable_intr +enable_intr: + andi.w #0xf8ff, %sr + rts + +.global disable_intr +disable_intr: + ori.w #0x0300, %sr + rts + +| interrupt handlers +intr_fatal: + stop #0x2700 + +| .extern vblank_handler + +intr_hblank: +| move.l #0xc0020000, VDP_PORT_CTL +| +| move.w testcol, %d0 +| move.w %d0, VDP_PORT_DATA +| rol.b #4, %d0 +| move.w %d0, testcol +| + rte + +intr_vblank: +| jsr vblank_handler + rte diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..31dbf45 --- /dev/null +++ b/src/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/src/romhdr.S b/src/romhdr.S new file mode 100644 index 0000000..3b454f4 --- /dev/null +++ b/src/romhdr.S @@ -0,0 +1,37 @@ +| the following will go into the custom .romhdr section which will be placed at +| address 100h of the binary by the linker (see megadrive.ld). + .section .romhdr,"a" + +#ifndef GAMENAME +#define GAMENAME "life" +#endif +#ifndef VERSTR +#define VERSTR "01" +#endif + + .ascii "SEGA MEGA DRIVE (C)MINDLAPSE2022" +hdr_game_dom: + .ascii GAMENAME +hdr_game_dom_end: + .fill 48 - (hdr_game_dom_end - hdr_game_dom),1,32 | pad to 48 bytes with spaces +hdr_game_int: + .ascii GAMENAME +hdr_game_int_end: + .fill 48 - (hdr_game_int_end - hdr_game_int),1,32 | pad to 48 bytes with spaces + .ascii "GM" | it's a game (who cares what it is?) + .ascii "0000000-" | product code + .ascii VERSTR | version string + .short 0 | checksum + .ascii "J " | I/O support (joypad) + .long 0 | start address of ROM + .long _rom_end | last address of ROM + .long 0xff0000 | start address of RAM + .long 0xffffff | last address of RAM + .long 0 | SRAM enabled(?) + .long 0 | ??? + .long 0 | start address of SRAM + .long 0 | last address of SRAM + .long 0 | ??? + .long 0 | ??? + .fill 40,1,32 | notes (fill with spaces for now TODO) + .ascii "JUE " | country codes diff --git a/src/startup.s b/src/startup.s new file mode 100644 index 0000000..2b5b7a7 --- /dev/null +++ b/src/startup.s @@ -0,0 +1,42 @@ +| vi:filetype=gas68k: + .text + .extern main + + .global start + .global halt_cpu +start: + jsr disable_intr + + | write SEGA to 0xa14000 to convince the TMSS to run us + move.l 0x100, %d0 + move.l %d0, 0xa14000 + + | copy .data section from ROM to RAM + move.l #_data_lma, %a0 + move.l #_data_start, %a1 + move.l #_data_end, %a2 + cmp.l %a1, %a2 + beq.s 1f | skip data copy if the section is empty +0: move.l (%a0)+, (%a1)+ + cmp.l %a1, %a2 + bne.s 0b +1: + + | zero the .bss section + move.l #_bss_start, %a0 + move.l #_bss_end, %a1 + cmp.l %a0, %a1 + beq.s 1f | skip bss zeroing if the section is empty +0: clr.l (%a0)+ + cmp.l %a0, %a1 + bne.s 0b +1: + + | setup the stack pointer stack + move.l #_stacktop, %sp + | now that we have a stack, we can enable interrupts + jsr enable_intr + + jsr main +halt_cpu: + stop #0x2700 diff --git a/src/vdpdefs.inc b/src/vdpdefs.inc new file mode 100644 index 0000000..dc0848f --- /dev/null +++ b/src/vdpdefs.inc @@ -0,0 +1,13 @@ +| vi:filetype=asm68k: + .equ VDP_PORT_DATA, 0xc00000 + .equ VDP_PORT_CTL, 0xc00004 + + .equ VDP_REG_MODE1, 0 + .equ VDP_REG_MODE2, 1 + + .equ VDP_WRITE_VRAM, 0x40000000 + .equ VDP_WRITE_CRAM, 0xc0000000 + .equ VDP_WRITE_VSRAM, 0x40000010 + .equ VDP_READ_VRAM, 0 + .equ VDP_READ_CRAM, 0x00000020 + .equ VDP_READ_VSRAM, 0x00000010 -- 1.7.10.4