initial commit
authorJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 8 Dec 2023 16:36:49 +0000 (18:36 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 8 Dec 2023 16:36:49 +0000 (18:36 +0200)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
megadrive.ld [new file with mode: 0644]
src/intr.s [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/romhdr.S [new file with mode: 0644]
src/startup.s [new file with mode: 0644]
src/vdpdefs.inc [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..d11753f
--- /dev/null
@@ -0,0 +1,6 @@
+*.o
+*.swp
+*.d
+*.bin
+*.elf
+*.map
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (file)
index 0000000..dce3828
--- /dev/null
@@ -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 (file)
index 0000000..8f4f01e
--- /dev/null
@@ -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 (file)
index 0000000..31dbf45
--- /dev/null
@@ -0,0 +1,4 @@
+int main(void)
+{
+       return 0;
+}
diff --git a/src/romhdr.S b/src/romhdr.S
new file mode 100644 (file)
index 0000000..3b454f4
--- /dev/null
@@ -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 (file)
index 0000000..2b5b7a7
--- /dev/null
@@ -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 (file)
index 0000000..dc0848f
--- /dev/null
@@ -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