From f12c3e6c5d1124ba606fa768e5ae1ba5b0ffaeb2 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Thu, 2 Feb 2017 06:35:54 +0200 Subject: [PATCH] initial commit --- .gitignore | 2 ++ Makefile | 38 ++++++++++++++++++++++++ megadrive.ldscript | 47 ++++++++++++++++++++++++++++++ src/intr.s | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/macros.inc | 16 ++++++++++ src/megadrive.c | 4 +++ src/megadrive.h | 52 +++++++++++++++++++++++++++++++++ src/romhdr.S | 37 ++++++++++++++++++++++++ src/util.s | 66 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 344 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 megadrive.ldscript create mode 100644 src/intr.s create mode 100644 src/macros.inc create mode 100644 src/megadrive.c create mode 100644 src/megadrive.h create mode 100644 src/romhdr.S create mode 100644 src/util.s diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..499a618 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +*.swp diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1114931 --- /dev/null +++ b/Makefile @@ -0,0 +1,38 @@ +csrc = $(wildcard src/*.c) +asrc = $(wildcard src/*.s) +aSsrc = $(wildcard src/*.S) +obj = $(asrc:.s=.o) $(aSsrc:.S=.o) $(csrc:.c=.o) + +name = tetris +elf = $(name).elf +bin = $(name).bin + +warn = -pedantic -Wall +dbg = -g +def = -DGAMENAME=\"tetris\" -DVERSTR=\"01\" + +tool_prefix = m68k-linux-gnu- + +CC = $(tool_prefix)gcc +AS = $(tool_prefix)as +LD = $(tool_prefix)ld +OBJCOPY = $(tool_prefix)objcopy + +CFLAGS = -m68000 -fno-builtin $(warn) $(dbg) $(opt) $(def) +CPPFLAGS = $(def) +ASFLAGS = -m68000 -Isrc +LDFLAGS = -T megadrive.ldscript -print-gc-sections + +$(bin): $(elf) + $(OBJCOPY) -O binary $< $@ + +$(elf): $(obj) + $(LD) -o $@ $(LDFLAGS) $(obj) -Map link.map + +.PHONY: clean +clean: + rm -f $(obj) $(elf) $(bin) + +.PHONY: run +run: $(bin) + gens-sdl $< diff --git a/megadrive.ldscript b/megadrive.ldscript new file mode 100644 index 0000000..dce3828 --- /dev/null +++ b/megadrive.ldscript @@ -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..485d251 --- /dev/null +++ b/src/intr.s @@ -0,0 +1,82 @@ +| 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 +| interrupt handlers +intr_fatal: + stop #0x2700 + +| TODO hblank/vblank code +intr_hblank: + rte +intr_vblank: + rte diff --git a/src/macros.inc b/src/macros.inc new file mode 100644 index 0000000..a6e2861 --- /dev/null +++ b/src/macros.inc @@ -0,0 +1,16 @@ +| Assembly macros +| --------------- + +| pseudosubroutines (leaf functions) +| ---------------------------------- + | call a leaf subroutine - use a6 for the reutrn address + .macro pseudo_call addr + move.l #0f, %a6 | a6 will hold the return address + jmp \addr +0: + .endm + + | return from a leaf subroutine + .macro pseudo_ret + jmp (%a6) | a6 better not have changed! + .endm diff --git a/src/megadrive.c b/src/megadrive.c new file mode 100644 index 0000000..45bc414 --- /dev/null +++ b/src/megadrive.c @@ -0,0 +1,4 @@ +#include "megadrive.h" + +int current_piece = 0x270; +int frame_delay = 50; diff --git a/src/megadrive.h b/src/megadrive.h new file mode 100644 index 0000000..37a8f95 --- /dev/null +++ b/src/megadrive.h @@ -0,0 +1,52 @@ +#ifndef MEGADRIVE_H_ +#define MEGADRIVE_H_ + +#include + +/* Macros for the joypad buttons */ +#define DPAD_UP 0 +#define DPAD_DOWN 1 +#define DPAD_LEFT 2 +#define DPAD_RIGHT 3 +#define DPAD_A 12 +#define DPAD_B 4 +#define DPAD_C 5 +#define DPAD_START 13 + +uint16_t dpad0; +uint16_t dpad0_prev; +uint16_t dpad0_presses; +uint16_t frame_buffer[2048]; + +int current_piece = 0x270; +int frame_delay = 50; +int frame_countdown; +int current_piece_x; +int current_piece_y; + +int tetromino_shapes[8]; +int statistics[16]; + +int last_spawned_piece_index; + +int16_t rng_state[2]; + +int auto_repeat_countdown; + + +static inline dpad0_pressed(uint16_t key) +{ + return !(dpad0 & (1 << key)); +} + +int32_t rng_next(int32_t s); + +static inline int rand(void) +{ + int32_t *s = (int32_t*)rng_state; + *s = rng_next(*s); + return ((*s) >> 24) & 0xff; +} + + +#endif /* MEGADRIVE_H_ */ diff --git a/src/romhdr.S b/src/romhdr.S new file mode 100644 index 0000000..1c1dd4f --- /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 100 of the binary by the linker (see lnkscript). + .section .romhdr,"a" + +#ifndef GAMENAME +#define GAMENAME "unnamed" +#endif +#ifndef VERSTR +#define VERSTR "00" +#endif + + .ascii "SEGA MEGA DRIVE (C)MINDLAPSE2017" +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/util.s b/src/util.s new file mode 100644 index 0000000..7b500ef --- /dev/null +++ b/src/util.s @@ -0,0 +1,66 @@ +| ------------------------------------------------------------------------ +| Utilities +| ------------------------------------------------------------------------ + + .include "macros.inc" + +| Random number generator +| ------------------------------------------------------------------------ + +| Seed random number generator, using a 32 bit seed stored in d0 (s0s1s2s3 high +| to low bytes) This needn't be a pseudoroutine, but just for symmetry with the +| following routine, we'll make it one + .text +rng_seed: + move.b %d0, %d4 + lsr.l #8, %d0 + move.b %d0, %d5 + lsr.l #8, %d0 + move.b %d0, %d6 + lsr.l #8, %d0 + move.b %d0, %d7 + pseudo_ret + +| Reverse of seed: it will collect the seed from registers d4-d7 to d0 +rng_unseed: + move.b %d7, %d0 + lsl.l #8, %d0 + move.b %d6, %d0 + lsl.l #8, %d0 + move.b %d5, %d0 + lsl.l #8, %d0 + move.b %d4, %d0 + lsl.l #8, %d0 + pseudo_ret + +| Calculate next random number, it will be stored in the low byte of d7 +rng_calc_next: + add.l #1, %d4 + eor.b %d7, %d5 + eor.b %d4, %d5 + add.b %d5, %d6 + + lsl.w #8, %d4 | Hack - shift d4 to the left, so we can use its 8 LSB for storing the intermediate value + move.b %d6, %d4 | - Tmp store d6 + lsr.b #1, %d4 | - This will produce d6>>1 in the LSB + + add.b %d4, %d7 | Yup! I remebered it! + + lsr.w #8, %d4 | Hack - Revert d4 to what it was before + + eor.b %d5, %d7 + pseudo_ret + +| Function exposed to C - 1 longword argument + .global rng_next +rng_next: + link %fp, #0 + movem %d2-%d7/%a2-%a5, -(%sp) + move.l 8(%fp), %d0 + pseudo_call rng_seed + pseudo_call rng_calc_next + pseudo_call rng_unseed + movem (%sp)+, %d2-%d7/%a2-%a5 + unlk %fp + rts + -- 1.7.10.4