megadrive_test2
changeset 0:ce1b05082ac4
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 14 Mar 2017 05:59:33 +0200 |
parents | |
children | 2560a8be8cb8 |
files | .hgignore Makefile megadrive.ldscript src/intr.s src/main.c src/romhdr.S src/startup.s src/vdp.c src/vdp.h |
diffstat | 9 files changed, 449 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.hgignore Tue Mar 14 05:59:33 2017 +0200 1.3 @@ -0,0 +1,6 @@ 1.4 +\.o$ 1.5 +\.swp$ 1.6 +\.d$ 1.7 +\.map$ 1.8 +\.elf$ 1.9 +\.bin$
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/Makefile Tue Mar 14 05:59:33 2017 +0200 2.3 @@ -0,0 +1,51 @@ 2.4 +csrc = $(wildcard src/*.c) $(wildcard src/libc/*.c) 2.5 +asrc = $(wildcard src/*.s) 2.6 +aSsrc = $(wildcard src/*.S) 2.7 +obj = $(asrc:.s=.o) $(aSsrc:.S=.o) $(csrc:.c=.o) 2.8 + 2.9 +name = test2 2.10 +elf = $(name).elf 2.11 +bin = $(name).bin 2.12 + 2.13 +warn = -pedantic -Wall 2.14 +dbg = -g 2.15 +def = -DGAMENAME=\"testgame\" -DVERSTR=\"01\" -D__NO_CTYPE 2.16 +inc = -Isrc/libc 2.17 + 2.18 +tool_prefix = m68k-linux-gnu- 2.19 + 2.20 +CC = $(tool_prefix)gcc 2.21 +AS = $(tool_prefix)as 2.22 +LD = $(tool_prefix)ld 2.23 +OBJCOPY = $(tool_prefix)objcopy 2.24 + 2.25 +CFLAGS = -m68000 -ffreestanding -fno-builtin $(warn) $(dbg) $(opt) $(def) $(inc) 2.26 +CPPFLAGS = $(def) 2.27 +ASFLAGS = -m68000 2.28 +LDFLAGS = -T megadrive.ldscript -print-gc-sections \ 2.29 + -L/usr/lib/gcc-cross/m68k-linux-gnu/6 -lgcc 2.30 + 2.31 +$(bin): $(elf) 2.32 + $(OBJCOPY) -O binary $< $@ 2.33 + 2.34 +$(elf): $(obj) 2.35 + $(LD) -o $@ $(obj) -Map link.map $(LDFLAGS) 2.36 + 2.37 +.PHONY: clean 2.38 +clean: 2.39 + rm -f $(obj) $(elf) $(bin) 2.40 + 2.41 +.PHONY: run 2.42 +run: $(bin) 2.43 + gens-sdl $< 2.44 + 2.45 +.PHONY: copy 2.46 +copy: $(bin) 2.47 + mount /media/usbmass && cp $(bin) /media/usbmass/$(bin) 2.48 + umount /media/usbmass 2.49 + 2.50 +.PHONY: install 2.51 +install: $(bin) 2.52 + mount /media/usbmass 2.53 + [ -f /media/usbmass/MEGA/MEGA.RBF ] || cp $(bin) /media/usbmass/MEGA/MEGA.BIN 2.54 + umount /media/usbmass
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/megadrive.ldscript Tue Mar 14 05:59:33 2017 +0200 3.3 @@ -0,0 +1,47 @@ 3.4 +OUTPUT_ARCH(m68k) 3.5 + 3.6 +MEMORY 3.7 +{ 3.8 + rom : ORIGIN = 0x00000000, LENGTH = 0x00a00000 3.9 + ram : ORIGIN = 0x00ff0000, LENGTH = 0x00010000 3.10 +} 3.11 + 3.12 +PROVIDE (_stacktop = 0x01000000); 3.13 + 3.14 +SECTIONS { 3.15 + /* ---- start of ROM ---- */ 3.16 + /* .vect section is used to place the m68k exception vectors at the 3.17 + * beginning of the address space 3.18 + */ 3.19 + .vect : { * (.vect); } >rom 3.20 + /* .romhdr section is used to place the SEGA ROM header at 0x100 */ 3.21 + . = 0x100; 3.22 + .romhdr : { * (.romhdr); } >rom 3.23 + .text : { * (.text); } >rom 3.24 + .rodata : { * (.rodata); } >rom 3.25 + 3.26 + /* place the load address of the .data section after .rodata */ 3.27 + . = ALIGN(4); 3.28 + _data_lma = .; 3.29 + _rom_end = _data_lma + _data_size; 3.30 + 3.31 + /* ---- start of RAM ---- */ 3.32 + . = 0xff0000; 3.33 + /* place the .data section at the start of RAM */ 3.34 + .data ALIGN(4): AT (_data_lma) { 3.35 + _data_start = .; 3.36 + * (.data); 3.37 + . = ALIGN(4); 3.38 + _data_end = .; 3.39 + } >ram 3.40 + _data_size = SIZEOF(.data); 3.41 + 3.42 + /* place the .bss section at the end */ 3.43 + .bss ALIGN(4): { 3.44 + _bss_start = .; 3.45 + * (.bss); 3.46 + . = ALIGN(4); 3.47 + _bss_end = .; 3.48 + } >ram 3.49 + _bss_size = SIZEOF(.bss); 3.50 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/intr.s Tue Mar 14 05:59:33 2017 +0200 4.3 @@ -0,0 +1,82 @@ 4.4 +| the following will go into the .vect section which will be placed at the very 4.5 +| begining of the binary at address 0 by the linker (see lnkscript). 4.6 + .section .vect,"a" 4.7 + .extern start 4.8 +| exception vectors 4.9 + .long _stacktop | 00 reset - initial SSP 4.10 + .long start | 01 reset - initial PC 4.11 + .long intr_fatal | 02 bus error 4.12 + .long intr_fatal | 03 address error 4.13 + .long intr_fatal | 04 illegal instruction 4.14 + .long intr_fatal | 05 zero divide 4.15 + .long intr_fatal | 06 chk instruction 4.16 + .long intr_fatal | 07 trapv instruction 4.17 + .long intr_fatal | 08 privilege violation 4.18 + .long intr_fatal | 09 trace 4.19 + .long intr_fatal | 0a line 1010 emulator 4.20 + .long intr_fatal | 0b line 1111 emulator 4.21 + .long intr_fatal | 0c reserved 4.22 + .long intr_fatal | 0d reserved 4.23 + .long intr_fatal | 0e format error (mc68010 only) 4.24 + .long intr_fatal | 0f uninitialized interrupt vector 4.25 + .long intr_fatal | 10 \ 4.26 + .long intr_fatal | 11 | 4.27 + .long intr_fatal | 12 | 4.28 + .long intr_fatal | 13 > reserved 4.29 + .long intr_fatal | 14 | 4.30 + .long intr_fatal | 15 | 4.31 + .long intr_fatal | 16 | 4.32 + .long intr_fatal | 17 / 4.33 + .long intr_fatal | 18 spurious interrupt 4.34 + .long intr_fatal | 19 level 1 interrupt 4.35 + .long intr_fatal | 1a level 2 interrupt 4.36 + .long intr_fatal | 1b level 3 interrupt 4.37 + .long intr_hblank | 1c level 4 interrupt (hblank in the mega drive) 4.38 + .long intr_fatal | 1d level 5 interrupt 4.39 + .long intr_vblank | 1e level 6 interrupt (vblank in the mega drive) 4.40 + .long intr_fatal | 1f level 7 interrupt 4.41 + .long intr_fatal | 20 trap 0 4.42 + .long intr_fatal | 21 trap 1 4.43 + .long intr_fatal | 22 trap 2 4.44 + .long intr_fatal | 23 trap 3 4.45 + .long intr_fatal | 24 trap 4 4.46 + .long intr_fatal | 25 trap 5 4.47 + .long intr_fatal | 26 trap 6 4.48 + .long intr_fatal | 27 trap 7 4.49 + .long intr_fatal | 28 trap 8 4.50 + .long intr_fatal | 29 trap 9 4.51 + .long intr_fatal | 2a trap a 4.52 + .long intr_fatal | 2b trap b 4.53 + .long intr_fatal | 2c trap c 4.54 + .long intr_fatal | 2d trap d 4.55 + .long intr_fatal | 2e trap e 4.56 + .long intr_fatal | 2f trap f 4.57 + .long intr_fatal | 30 \ 4.58 + .long intr_fatal | 31 | 4.59 + .long intr_fatal | 32 | 4.60 + .long intr_fatal | 33 | 4.61 + .long intr_fatal | 34 | 4.62 + .long intr_fatal | 35 | 4.63 + .long intr_fatal | 36 | 4.64 + .long intr_fatal | 37 | 4.65 + .long intr_fatal | 38 > reserved 4.66 + .long intr_fatal | 39 | 4.67 + .long intr_fatal | 3a | 4.68 + .long intr_fatal | 3b | 4.69 + .long intr_fatal | 3c | 4.70 + .long intr_fatal | 3d | 4.71 + .long intr_fatal | 3e | 4.72 + .long intr_fatal | 3f / 4.73 + 4.74 +| from here on we continue in the regular .text section since we don't care 4.75 +| where this code ends up. 4.76 + .text 4.77 +| interrupt handlers 4.78 +intr_fatal: 4.79 + stop #0x2700 4.80 + 4.81 +| TODO hblank/vblank code 4.82 +intr_hblank: 4.83 + rte 4.84 +intr_vblank: 4.85 + rte
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/main.c Tue Mar 14 05:59:33 2017 +0200 5.3 @@ -0,0 +1,13 @@ 5.4 +#include "vdp.h" 5.5 + 5.6 +int main(void) 5.7 +{ 5.8 + vdp_init(); 5.9 + 5.10 + vdp_set_pal_entry(0, 1, 7, 0, 3); 5.11 + vdp_set_bgcolor(0, 1); 5.12 + 5.13 + for(;;); 5.14 + 5.15 + return 0; 5.16 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/romhdr.S Tue Mar 14 05:59:33 2017 +0200 6.3 @@ -0,0 +1,37 @@ 6.4 +| the following will go into the custom .romhdr section which will be placed at 6.5 +| address 100h of the binary by the linker (see lnkscript). 6.6 + .section .romhdr,"a" 6.7 + 6.8 +#ifndef GAMENAME 6.9 +#define GAMENAME "unnamed" 6.10 +#endif 6.11 +#ifndef VERSTR 6.12 +#define VERSTR "00" 6.13 +#endif 6.14 + 6.15 + .ascii "SEGA MEGA DRIVE (C)MINDLAPSE2017" 6.16 +hdr_game_dom: 6.17 + .ascii GAMENAME 6.18 +hdr_game_dom_end: 6.19 + .fill 48 - (hdr_game_dom_end - hdr_game_dom),1,32 | pad to 48 bytes with spaces 6.20 +hdr_game_int: 6.21 + .ascii GAMENAME 6.22 +hdr_game_int_end: 6.23 + .fill 48 - (hdr_game_int_end - hdr_game_int),1,32 | pad to 48 bytes with spaces 6.24 + .ascii "GM" | it's a game (who cares what it is?) 6.25 + .ascii "0000000-" | product code 6.26 + .ascii VERSTR | version string 6.27 + .short 0 | checksum 6.28 + .ascii "J " | I/O support (joypad) 6.29 + .long 0 | start address of ROM 6.30 + .long _rom_end | last address of ROM 6.31 + .long 0xff0000 | start address of RAM 6.32 + .long 0xffffff | last address of RAM 6.33 + .long 0 | SRAM enabled(?) 6.34 + .long 0 | ??? 6.35 + .long 0 | start address of SRAM 6.36 + .long 0 | last address of SRAM 6.37 + .long 0 | ??? 6.38 + .long 0 | ??? 6.39 + .fill 40,1,32 | notes (fill with spaces for now TODO) 6.40 + .ascii "JUE " | country codes
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/startup.s Tue Mar 14 05:59:33 2017 +0200 7.3 @@ -0,0 +1,47 @@ 7.4 + .text 7.5 + .extern main 7.6 + 7.7 + .global start 7.8 + .global halt_cpu 7.9 +start: 7.10 + bsr.s disable_intr 7.11 + 7.12 + | copy .data section from ROM to RAM 7.13 + move.l #_data_lma, %a0 7.14 + move.l #_data_start, %a1 7.15 + move.l #_data_end, %a2 7.16 + cmp.l %a1, %a2 7.17 + beq.s 1f | skip data copy if the section is empty 7.18 +0: move.l (%a0)+, (%a1)+ 7.19 + cmp.l %a1, %a2 7.20 + bne.s 0b 7.21 +1: 7.22 + 7.23 + | zero the .bss section 7.24 + move.l #_bss_start, %a0 7.25 + move.l #_bss_end, %a1 7.26 + cmp.l %a0, %a1 7.27 + beq.s 1f | skip bss zeroing if the section is empty 7.28 +0: clr.l (%a0)+ 7.29 + cmp.l %a0, %a1 7.30 + bne.s 0b 7.31 +1: 7.32 + 7.33 + | setup the stack pointer stack 7.34 + move.l #_stacktop, %sp 7.35 + | now that we have a stack, we can enable interrupts 7.36 + bsr.s enable_intr 7.37 + 7.38 + jsr main 7.39 +halt_cpu: 7.40 + stop #0x2700 7.41 + 7.42 +.global enable_intr 7.43 +enable_intr: 7.44 + andi.w #0xf8ff, %sr 7.45 + rts 7.46 + 7.47 +.global disable_intr 7.48 +disable_intr: 7.49 + ori.w #0x0300, %sr 7.50 + rts
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/src/vdp.c Tue Mar 14 05:59:33 2017 +0200 8.3 @@ -0,0 +1,9 @@ 8.4 +#include "vdp.h" 8.5 + 8.6 +void vdp_init(void) 8.7 +{ 8.8 + vdp_setreg(VDP_REG_MODE1, VDP_MODE1_BASE); 8.9 + vdp_setreg(VDP_REG_MODE2, VDP_MODE2_BASE | VDP_MODE2_DISP); 8.10 + 8.11 + vdp_set_autoinc(2); 8.12 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/src/vdp.h Tue Mar 14 05:59:33 2017 +0200 9.3 @@ -0,0 +1,157 @@ 9.4 +#ifndef VDP_H_ 9.5 +#define VDP_H_ 9.6 + 9.7 +#include <stdint.h> 9.8 + 9.9 +#define VDP_PORT_DATA *((volatile uint16_t*)0xc00000) 9.10 +#define VDP_PORT_DATA32 *((volatile uint32_t*)0xc00000) 9.11 +#define VDP_PORT_CTL *((volatile uint16_t*)0xc00004) 9.12 +#define VDP_PORT_CTL32 *((volatile uint32_t*)0xc00004) 9.13 +#define VDP_PORT_HVCNT *((volatile uint16_t*)0xc00008) 9.14 +#define VDP_PORT_PSG *((volatile uint16_t*)0xc00010) 9.15 + 9.16 +#define VDP_PORT_STATUS *((volatile uint16_t*)0xc00004) 9.17 + 9.18 +enum { 9.19 + VDP_REG_MODE1 = 0, 9.20 + VDP_REG_MODE2 = 1, 9.21 + VDP_REG_NAMETAB_A = 2, 9.22 + VDP_REG_NAMETAB_WIN = 3, 9.23 + VDP_REG_NAMETAB_B = 4, 9.24 + VDP_REG_SPRITE_TAB = 5, 9.25 + VDP_REG_BGCOL = 7, 9.26 + VDP_REG_INTR = 10, 9.27 + VDP_REG_MODE3 = 11, 9.28 + VDP_REG_MODE4 = 12, 9.29 + VDP_REG_SCROLL_TAB = 13, 9.30 + VDP_REG_AUTOINC = 15, 9.31 + VDP_REG_SCROLL_SIZE = 16, 9.32 + VDP_REG_WIN_XPOS = 17, 9.33 + VDP_REG_WIN_YPOS = 18, 9.34 + VDP_REG_DMA_LEN_LOW = 19, 9.35 + VDP_REG_DMA_LEN_HIGH = 20, 9.36 + VDP_REG_DMA_SRC_LOW = 21, 9.37 + VDP_REG_DMA_SRC_MID = 22, 9.38 + VDP_REG_DMA_SRC_HIGH = 23, 9.39 + 9.40 + VDP_NUM_REGS 9.41 +}; 9.42 + 9.43 +uint16_t vdp_reg_shadow[VDP_NUM_REGS]; 9.44 + 9.45 +/* access VDP memory */ 9.46 +enum { VDP_MEM_READ, VDP_MEM_WRITE }; 9.47 +enum { 9.48 + VDP_MEM_VRAM = 0, 9.49 + VDP_MEM_CRAM = 0xa, /* CD5->CD0: 0 0 r 0 w 0 */ 9.50 + VDP_MEM_VSRAM = 4 /* CD5->CD0: 0 0 0 1 0 0 */ 9.51 +}; 9.52 + 9.53 +static inline void vdp_setup_access(uint16_t addr, int rw, int memid) 9.54 +{ 9.55 + uint32_t type; 9.56 + if(rw == VDP_MEM_WRITE) { 9.57 + type = (memid & 7) | 1; 9.58 + } else { 9.59 + type = memid & 0xc; 9.60 + } 9.61 + 9.62 + VDP_PORT_CTL32 = (((uint32_t)addr & 0x3fff) << 16) | ((addr >> 14) & 3) | 9.63 + ((type << 2) & 0xf0) | (type << 30); 9.64 +} 9.65 + 9.66 + 9.67 +/* mode register 1 */ 9.68 +enum { 9.69 + VDP_MODE1_BASE = 0x4, 9.70 + VDP_MODE1_HVCNT = 0x2, 9.71 + VDP_MODE1_HINTR = 0x10 9.72 +}; 9.73 + 9.74 +/* mode register 2 */ 9.75 +enum { 9.76 + VDP_MODE2_BASE = 0x4, 9.77 + VDP_MODE2_V30CELL = 0x8, 9.78 + VDP_MODE2_DMA = 0x10, 9.79 + VDP_MODE2_VINTR = 0x20, 9.80 + VDP_MODE2_DISP = 0x40 9.81 +}; 9.82 + 9.83 +/* mode register 3 */ 9.84 +enum { 9.85 + VDP_MODE3_BASE = 0, 9.86 + VDP_MODE3_HSCROLL_CELL = 2, 9.87 + VDP_MODE3_HSCROLL_LINE = 3, 9.88 + VDP_MODE3_VSCROLL_2CELL = 4, 9.89 + VDP_MODE3_EXTINTR = 8 9.90 +}; 9.91 + 9.92 +/* mode register 4 */ 9.93 +enum { 9.94 + VDP_MODE4_BASE = 0, 9.95 + VDP_MODE4_H40CELL = 0x81, 9.96 + VDP_MODE4_ILACE = 2, 9.97 + VDP_MODE4_ILACE_2XRES = 6, 9.98 + VDP_MODE4_SH = 8 /* shadow/highlight enable */ 9.99 +}; 9.100 + 9.101 +/* scroll size register */ 9.102 +enum { 9.103 + VDP_SCROLL_H32 = 0, 9.104 + VDP_SCROLL_H64 = 1, 9.105 + VDP_SCROLL_H128 = 3, 9.106 + VDP_SCROLL_V32 = 0, 9.107 + VDP_SCROLL_V64 = 0x10, 9.108 + VDP_SCROLL_V128 = 0x30 9.109 +}; 9.110 + 9.111 +/* window X/Y position register */ 9.112 +enum { 9.113 + VDP_WIN_LEFT = 0, 9.114 + VDP_WIN_UP = 0, 9.115 + VDP_WIN_RIGHT = 0x80, 9.116 + VDP_WIN_DOWN = 0x80, 9.117 + VDP_WIN_POSMASK = 0x1f 9.118 +}; 9.119 + 9.120 +#define VDP_PACK_RGB(r, g, b) \ 9.121 + ((((uint16_t)(r) & 7) << 1) | (((uint16_t)(g) & 7) << 5) | (((uint16_t)(b) & 7) << 9)) 9.122 + 9.123 + 9.124 +static inline void vdp_setreg(int reg, uint8_t value) 9.125 +{ 9.126 + /*vdp_reg_shadow[reg] = value;*/ 9.127 + VDP_PORT_CTL = (uint16_t)value | (reg << 8) | (uint16_t)0x8000; 9.128 +} 9.129 + 9.130 +static inline uint16_t vdp_getreg(int reg) 9.131 +{ 9.132 + return vdp_reg_shadow[reg]; 9.133 +} 9.134 + 9.135 +static inline uint16_t vdp_status(void) 9.136 +{ 9.137 + return VDP_PORT_CTL; 9.138 +} 9.139 + 9.140 +static inline void vdp_set_bgcolor(int palidx, int colidx) 9.141 +{ 9.142 + vdp_setreg(VDP_REG_BGCOL, (colidx & 0xf) | (palidx << 4)); 9.143 +} 9.144 + 9.145 +static inline void vdp_set_autoinc(int stride) 9.146 +{ 9.147 + vdp_setreg(VDP_REG_AUTOINC, stride); 9.148 +} 9.149 + 9.150 +static inline void vdp_set_pal_entry(int pidx, int cidx, int r, int g, int b) 9.151 +{ 9.152 + uint16_t paddr = (pidx << 5) | (cidx << 1); 9.153 + 9.154 + vdp_setup_access(paddr, VDP_MEM_WRITE, VDP_MEM_CRAM); 9.155 + VDP_PORT_DATA = VDP_PACK_RGB(r, g, b); 9.156 +} 9.157 + 9.158 +void vdp_init(void); 9.159 + 9.160 +#endif /* VDP_H_ */