--- /dev/null
+*.o
+*.swp
--- /dev/null
+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 $<
--- /dev/null
+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);
+}
--- /dev/null
+| 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
--- /dev/null
+| 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
--- /dev/null
+#include "megadrive.h"
+
+int current_piece = 0x270;
+int frame_delay = 50;
--- /dev/null
+#ifndef MEGADRIVE_H_
+#define MEGADRIVE_H_
+
+#include <stdint.h>
+
+/* 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_ */
--- /dev/null
+| 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
--- /dev/null
+| ------------------------------------------------------------------------
+| 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
+