From e2e548eafdddeecb65fe8c15dbbd082bf125298d Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 1 Apr 2019 01:59:21 +0300 Subject: [PATCH] initial commit --- .gitignore | 6 ++ Makefile | 64 +++++++++++++ megadrive.ld | 47 ++++++++++ src/intr.h | 7 ++ src/intr.s | 106 +++++++++++++++++++++ src/io.c | 10 ++ src/io.h | 106 +++++++++++++++++++++ src/main.c | 71 ++++++++++++++ src/pad.h | 31 ++++++ src/startup.s | 42 +++++++++ src/vdp.c | 32 +++++++ src/vdp.h | 282 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vdpdefs.inc | 13 +++ 13 files changed, 817 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 megadrive.ld create mode 100644 src/intr.h create mode 100644 src/intr.s create mode 100644 src/io.c create mode 100644 src/io.h create mode 100644 src/main.c create mode 100644 src/pad.h create mode 100644 src/startup.s create mode 100644 src/vdp.c create mode 100644 src/vdp.h create mode 100644 src/vdpdefs.inc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4bc9d06 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.o +*.d +*.swp +*.map +*.elf +*.bin diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7229ca6 --- /dev/null +++ b/Makefile @@ -0,0 +1,64 @@ +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 = megatris +elf = $(name).elf +bin = $(name).bin + +warn = -pedantic -Wall +dbg = -g +opt = -O2 +def = -DGAMENAME=\"megatris\" -DVERSTR=\"01\" -D__NO_CTYPE +inc = -I. -Isrc -Isrc/libc + +tool_prefix = m68k-linux-gnu- + +CC = $(tool_prefix)gcc +AS = $(tool_prefix)as +LD = $(tool_prefix)ld +OBJCOPY = $(tool_prefix)objcopy + +CFLAGS = -m68000 -ffreestanding -fno-builtin $(warn) $(dbg) $(opt) $(def) $(inc) +CPPFLAGS = $(def) +ASFLAGS = -m68000 $(inc) +LDFLAGS = -T megadrive.ld -print-gc-sections -L/usr/lib/gcc-cross/m68k-linux-gnu/6 -lgcc + +$(bin): $(elf) + $(OBJCOPY) -O binary $< $@ + +$(elf): $(obj) + $(LD) -o $@ $(obj) -Map link.map $(LDFLAGS) + +#tun_data.h: tunnel.ppm +# cat $< | tools/ppm2md tun_ >$@ + +-include $(dep) + +%.d: %.c + @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ + +.PHONY: clean +clean: + rm -f $(obj) $(elf) $(bin) + +.PHONY: cleandep +cleandep: + rm -f $(dep) + +.PHONY: run +run: $(bin) + gens-sdl $< + +.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.h b/src/intr.h new file mode 100644 index 0000000..2b5018f --- /dev/null +++ b/src/intr.h @@ -0,0 +1,7 @@ +#ifndef INTR_H_ +#define INTR_H_ + +void enable_intr(void); +void disable_intr(void); + +#endif /* INTR_H_ */ diff --git a/src/intr.s b/src/intr.s new file mode 100644 index 0000000..38f0eb1 --- /dev/null +++ b/src/intr.s @@ -0,0 +1,106 @@ +| 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 + + .include "vdpdefs.inc" +| .extern vblank_handler +| .extern palval + +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/io.c b/src/io.c new file mode 100644 index 0000000..07fe948 --- /dev/null +++ b/src/io.c @@ -0,0 +1,10 @@ +#include "io.h" + +void io_init(void) +{ + io_setdir(0, 0x40); + io_setdir(1, 0x40); + + IO_REG_DATA(0) = 0; + IO_REG_DATA(1) = 0; +} diff --git a/src/io.h b/src/io.h new file mode 100644 index 0000000..d53871b --- /dev/null +++ b/src/io.h @@ -0,0 +1,106 @@ +#ifndef MEGADRIVE_IO_H_ +#define MEGADRIVE_IO_H_ + +#include + +#define IO_REG_VER *((volatile uint8_t*)0xa10001) +#define IO_REG_DATA1 *((volatile uint8_t*)0xa10003) +#define IO_REG_DATA2 *((volatile uint8_t*)0xa10005) +#define IO_REG_DATA3 *((volatile uint8_t*)0xa10007) +#define IO_REG_CTRL1 *((volatile uint8_t*)0xa10009) +#define IO_REG_CTRL2 *((volatile uint8_t*)0xa1000b) +#define IO_REG_CTRL3 *((volatile uint8_t*)0xa1000d) +#define IO_REG_TXDATA1 *((volatile uint8_t*)0xa1000f) +#define IO_REG_RXDATA1 *((volatile uint8_t*)0xa10011) +#define IO_REG_S_CTRL1 *((volatile uint8_t*)0xa10013) +#define IO_REG_TXDATA2 *((volatile uint8_t*)0xa10015) +#define IO_REG_RXDATA2 *((volatile uint8_t*)0xa10017) +#define IO_REG_S_CTRL2 *((volatile uint8_t*)0xa10013) +#define IO_REG_TXDATA3 *((volatile uint8_t*)0xa1001b) +#define IO_REG_RXDATA3 *((volatile uint8_t*)0xa1001d) +#define IO_REG_S_CTRL3 *((volatile uint8_t*)0xa1001f) +#define IO_REG_LOCK *((volatile uint8_t*)0xa14000) +#define IO_REG_TMSS *((volatile uint8_t*)0xa14101) + +#define IO_REG_DATA(x) *((volatile uint8_t*)0xa10003 + ((x) << 1)) +#define IO_REG_CTRL(x) *((volatile uint8_t*)0xa10009 + ((x) << 1)) + + +enum { + IO_VER_VERSION_MASK = 0x0f, + IO_VER_EXP = 0x20, + IO_VER_PAL = 0x40, + IO_VER_NONJP = 0x80 +}; + +enum { + IO_PAD_UP = 0x001, + IO_PAD_DOWN = 0x002, + IO_PAD_LEFT = 0x004, + IO_PAD_RIGHT = 0x008, + IO_PAD_B = 0x010, + IO_PAD_C = 0x020, + IO_PAD_A = 0x040, + IO_PAD_START = 0x080, + + IO_PAD_Z = 0x100, + IO_PAD_Y = 0x200, + IO_PAD_X = 0x400 +}; +#define IO_PAD_LOW_MASK 0x3f +#define IO_PAD_HIGH_MASK (IO_PAD_A | IO_PAD_START) + +static inline void io_setdir(int port, uint8_t dir) +{ + IO_REG_CTRL(port) = dir; +} + +static inline uint16_t io_readpad(int port) +{ + uint16_t bnstate; + + bnstate = ~(IO_REG_DATA(port) << 2) & IO_PAD_HIGH_MASK; + + IO_REG_DATA(port) = 0x40; /* select mode 1 */ + asm volatile("nop"); + asm volatile("nop"); + bnstate |= ~IO_REG_DATA(port) & IO_PAD_LOW_MASK; + + IO_REG_DATA(port) = 0; /* select mode 0 */ + return bnstate; +} + +static inline uint16_t io_readpad6(int port) +{ + uint16_t bnstate; + + IO_REG_DATA(port) = 0x40; /* start with mode 1 */ + asm volatile("nop"); + asm volatile("nop"); + bnstate = ~IO_REG_DATA(port) & IO_PAD_LOW_MASK; + + IO_REG_DATA(port) = 0; /* select mode 0 */ + asm volatile("nop"); + asm volatile("nop"); + bnstate |= ~(IO_REG_DATA(port) << 2) & IO_PAD_HIGH_MASK; + + /* then introduce two more rising edges to trigger extended mode */ + IO_REG_DATA(port) = 0x40; + asm volatile("nop"); + asm volatile("nop"); + IO_REG_DATA(port) = 0; + asm volatile("nop"); + asm volatile("nop"); + IO_REG_DATA(port) = 0x40; + asm volatile("nop"); + asm volatile("nop"); + + bnstate |= (uint16_t)(~IO_REG_DATA(port) & 0x7) << 8; + IO_REG_DATA(port) = 0; /* return mode to 0 */ + return bnstate; +} + +void io_init(void); +/*uint16_t io_readpad(int port);*/ + +#endif /* MEGADRIVE_IO_H_ */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..5ba9dde --- /dev/null +++ b/src/main.c @@ -0,0 +1,71 @@ +#include +#include "vdp.h" +#include "io.h" +#include "pad.h" +#include "intr.h" + +void load_pattern(int idx, void *data); +void set_tile(int nametab_idx, int x, int y, int tile_idx, int palidx); + + +int main(void) +{ + int i; + int bgcol = 0; + + vdp_init(); + io_init(); + + if(IO_REG_VER & IO_VER_PAL) { + vdp_setreg(VDP_REG_MODE2, vdp_getreg(VDP_REG_MODE2)); + } + + vdp_begin_palette(0, 0); + for(i=0; i<16; i++) { + int r = i; + int g = 15 - i; + int b = i - 8; + + if(r > 7) r = 7; + if(g > 7) g = 7; + if(b < 0) b = 0; + + VDP_PORT_DATA = VDP_PACK_RGB(r, g, b); + } + vdp_set_bgcolor(0, bgcol); + + for(;;) { + pad_update(0); + + if(pad_pressed(0, IO_PAD_C)) { + vdp_set_bgcolor(0, ++bgcol & 0xf); + } + + vdp_wait_vblank(); + } + + return 0; +} + +void load_pattern(int idx, void *data) +{ + int i; + uint32_t *ptr = data; + uint16_t addr = idx << 5; + vdp_setup_access(addr, VDP_MEM_WRITE, VDP_MEM_VRAM); + + for(i=0; i<16; i++) { + VDP_PORT_DATA32 = *ptr++; + } +} + +void set_tile(int nametab_idx, int x, int y, int tile_idx, int palidx) +{ + uint16_t tile_ent, addr; + + tile_ent = vdp_nametab_entry(tile_idx, palidx, VDP_TILE_LOW_PRIO); + + addr = vdp_nametab_addr(nametab_idx) + (y * 64 + x) * 2; + vdp_setup_access(addr, VDP_MEM_WRITE, VDP_MEM_VRAM); + VDP_PORT_DATA = tile_ent; +} diff --git a/src/pad.h b/src/pad.h new file mode 100644 index 0000000..03cf3a3 --- /dev/null +++ b/src/pad.h @@ -0,0 +1,31 @@ +#ifndef PAD_H_ +#define PAD_H_ + +#include "io.h" + +uint16_t pad_bnstate[2], pad_prev_bnstate[2], pad_bndiff[2]; +char pad_6bn; + +static inline void pad_update(int pad) +{ + pad_prev_bnstate[pad] = pad_bnstate[pad]; + pad_bnstate[pad] = pad_6bn ? io_readpad6(pad) : io_readpad(pad); + pad_bndiff[pad] = pad_bnstate[pad] ^ pad_prev_bnstate[pad]; +} + +static inline int pad_pressed(int pad, uint16_t mask) +{ + return (pad_bnstate[pad] & mask & pad_bndiff[pad]) != 0; +} + +static inline int pad_released(int pad, uint16_t mask) +{ + return (~pad_bnstate[pad] & mask & pad_bndiff[pad]) != 0; +} + +static inline uint16_t pad_getstate(int pad) +{ + return pad_bnstate[pad]; +} + +#endif /* PAD_H_ */ diff --git a/src/startup.s b/src/startup.s new file mode 100644 index 0000000..991211c --- /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 convience 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/vdp.c b/src/vdp.c new file mode 100644 index 0000000..115d165 --- /dev/null +++ b/src/vdp.c @@ -0,0 +1,32 @@ +#include "vdp.h" + +void vdp_init(void) +{ + int i; + + vdp_setreg(VDP_REG_MODE1, VDP_MODE1_BASE); + vdp_setreg(VDP_REG_MODE2, VDP_MODE2_BASE | VDP_MODE2_DISP); + + vdp_set_nametab_addr(VDP_PLANE_A, 0xc000); + vdp_set_nametab_addr(VDP_PLANE_B, 0xe000); + vdp_disable_layer(VDP_PLANE_WIN); + vdp_set_scroll_table(0xd000); + vdp_set_sprite_table(0xd400); + + vdp_setreg(VDP_REG_MODE3, VDP_MODE3_BASE); + vdp_setreg(VDP_REG_MODE4, VDP_MODE4_BASE | VDP_MODE4_H40CELL); + vdp_setreg(VDP_REG_SCROLL_SIZE, VDP_SCROLL_H64 | VDP_SCROLL_V32); + + vdp_set_autoinc(2); + vdp_set_bgcolor(0, 0); + + vdp_setreg(VDP_REG_HINTR, 0); + vdp_setreg(VDP_REG_WIN_XPOS, 0); + vdp_setreg(VDP_REG_WIN_YPOS, 0); + + /* clear vmem at the planes A/B name tables, scroll table, and sprite table */ + vdp_setup_access(0xd000, VDP_MEM_WRITE, VDP_MEM_VRAM); + for(i=0xd000; i<65536; i++) { + VDP_PORT_DATA = 0; + } +} diff --git a/src/vdp.h b/src/vdp.h new file mode 100644 index 0000000..05011eb --- /dev/null +++ b/src/vdp.h @@ -0,0 +1,282 @@ +#ifndef VDP_H_ +#define VDP_H_ + +#include + +#define VDP_PORT_DATA *((volatile uint16_t*)0xc00000) +#define VDP_PORT_DATA32 *((volatile uint32_t*)0xc00000) +#define VDP_PORT_CTL *((volatile uint16_t*)0xc00004) +#define VDP_PORT_CTL32 *((volatile uint32_t*)0xc00004) +#define VDP_PORT_HVCNT *((volatile uint16_t*)0xc00008) +#define VDP_PORT_PSG *((volatile uint16_t*)0xc00010) + +#define VDP_PORT_STATUS *((volatile uint16_t*)0xc00004) + +enum { + VDP_REG_MODE1 = 0, + VDP_REG_MODE2 = 1, + VDP_REG_NAMETAB_A = 2, + VDP_REG_NAMETAB_WIN = 3, + VDP_REG_NAMETAB_B = 4, + VDP_REG_SPRITE_TAB = 5, + VDP_REG_BGCOL = 7, + VDP_REG_HINTR = 10, + VDP_REG_MODE3 = 11, + VDP_REG_MODE4 = 12, + VDP_REG_SCROLL_TAB = 13, + VDP_REG_AUTOINC = 15, + VDP_REG_SCROLL_SIZE = 16, + VDP_REG_WIN_XPOS = 17, + VDP_REG_WIN_YPOS = 18, + VDP_REG_DMA_LEN_LOW = 19, + VDP_REG_DMA_LEN_HIGH = 20, + VDP_REG_DMA_SRC_LOW = 21, + VDP_REG_DMA_SRC_MID = 22, + VDP_REG_DMA_SRC_HIGH = 23, + + VDP_NUM_REGS +}; + +uint16_t vdp_reg_shadow[VDP_NUM_REGS]; + +/* access VDP memory */ +enum { VDP_MEM_READ, VDP_MEM_WRITE }; +enum { + VDP_MEM_VRAM = 0, + VDP_MEM_CRAM = 0xa, /* CD5->CD0: 0 0 r 0 w 0 */ + VDP_MEM_VSRAM = 4 /* CD5->CD0: 0 0 0 1 0 0 */ +}; + +enum { + VDP_PLANE_A, + VDP_PLANE_B, + VDP_PLANE_WIN +}; + +enum { + VDP_TILE_LOW_PRIO = 0, + VDP_TILE_HFLIP = 0x0800, + VDP_TILE_VFLIP = 0x1000, + VDP_TILE_HIGH_PRIO = 0x8000 +}; + +enum { + VDP_STAT_PAL = 0x0001, + VDP_STAT_DMABUSY = 0x0002, + VDP_STAT_HBLANK = 0x0004, + VDP_STAT_VBLANK = 0x0008, + VDP_STAT_ODDFIELD = 0x0010, + VDP_STAT_SPRITE_COL = 0x0020, + VDP_STAT_SPRITE_OVF = 0x0040, + VDP_STAT_VINTR = 0x0080, + VDP_STAT_FIFO_FULL = 0x0100, + VDP_STAT_FIFO_EMPTY = 0x0200 +}; + + +static inline void vdp_setup_access(uint16_t addr, int rw, int memid) +{ + uint32_t type; + if(rw == VDP_MEM_WRITE) { + type = (memid & 7) | 1; + } else { + type = memid & 0xc; + } + + VDP_PORT_CTL32 = (((uint32_t)addr & 0x3fff) << 16) | ((addr >> 14) & 3) | + ((type << 2) & 0xf0) | (type << 30); +} + + +/* mode register 1 */ +enum { + VDP_MODE1_BASE = 0x4, + VDP_MODE1_HVCNT = 0x2, + VDP_MODE1_HINTR = 0x10 +}; + +/* mode register 2 */ +enum { + VDP_MODE2_BASE = 0x4, + VDP_MODE2_V30CELL = 0x8, + VDP_MODE2_DMA = 0x10, + VDP_MODE2_VINTR = 0x20, + VDP_MODE2_DISP = 0x40 +}; + +/* mode register 3 */ +enum { + VDP_MODE3_BASE = 0, + VDP_MODE3_HSCROLL_CELL = 2, + VDP_MODE3_HSCROLL_LINE = 3, + VDP_MODE3_VSCROLL_2CELL = 4, + VDP_MODE3_EXTINTR = 8 +}; + +/* mode register 4 */ +enum { + VDP_MODE4_BASE = 0, + VDP_MODE4_H40CELL = 0x81, + VDP_MODE4_ILACE = 2, + VDP_MODE4_ILACE_2XRES = 6, + VDP_MODE4_SH = 8 /* shadow/highlight enable */ +}; + +/* scroll size register */ +enum { + VDP_SCROLL_H32 = 0, + VDP_SCROLL_H64 = 1, + VDP_SCROLL_H128 = 3, + VDP_SCROLL_V32 = 0, + VDP_SCROLL_V64 = 0x10, + VDP_SCROLL_V128 = 0x30 +}; + +/* window X/Y position register */ +enum { + VDP_WIN_LEFT = 0, + VDP_WIN_UP = 0, + VDP_WIN_RIGHT = 0x80, + VDP_WIN_DOWN = 0x80, + VDP_WIN_POSMASK = 0x1f +}; + +#define VDP_PACK_RGB(r, g, b) \ + ((((uint16_t)(r) & 7) << 1) | (((uint16_t)(g) & 7) << 5) | (((uint16_t)(b) & 7) << 9)) + + +static inline void vdp_setreg(int reg, uint8_t value) +{ + vdp_reg_shadow[reg] = value; + VDP_PORT_CTL = (uint16_t)value | (reg << 8) | (uint16_t)0x8000; +} + +static inline uint16_t vdp_getreg(int reg) +{ + return vdp_reg_shadow[reg]; +} + +static inline uint16_t vdp_status(void) +{ + return VDP_PORT_CTL; +} + +static inline void vdp_set_bgcolor(int palidx, int colidx) +{ + vdp_setreg(VDP_REG_BGCOL, (colidx & 0xf) | (palidx << 4)); +} + +static inline void vdp_set_autoinc(int stride) +{ + vdp_setreg(VDP_REG_AUTOINC, stride); +} + +static inline void vdp_begin_palette(int pidx, int cidx) +{ + uint16_t paddr = (pidx << 5) | (cidx << 1); + vdp_setup_access(paddr, VDP_MEM_WRITE, VDP_MEM_CRAM); +} + +static inline void vdp_set_pal_entry(int pidx, int cidx, int r, int g, int b) +{ + vdp_begin_palette(pidx, cidx); + VDP_PORT_DATA = VDP_PACK_RGB(r, g, b); +} + +static inline void vdp_enable_vintr(void) +{ + vdp_setreg(VDP_REG_MODE2, vdp_getreg(VDP_REG_MODE2) | VDP_MODE2_VINTR); +} + +static inline void vdp_disable_vintr(void) +{ + vdp_setreg(VDP_REG_MODE2, vdp_getreg(VDP_REG_MODE2) & ~VDP_MODE2_VINTR); +} + +static inline void vdp_enable_hintr(int counter) +{ + vdp_setreg(VDP_REG_HINTR, counter); + vdp_setreg(VDP_REG_MODE1, vdp_getreg(VDP_REG_MODE1) | VDP_MODE1_HINTR); +} + +static inline void vdp_disable_hintr(void) +{ + vdp_setreg(VDP_REG_MODE1, vdp_getreg(VDP_REG_MODE1) & ~VDP_MODE1_HINTR); +} + +static inline void vdp_set_nametab_addr(int plane, uint16_t addr) +{ + switch(plane) { + case VDP_PLANE_A: + vdp_setreg(VDP_REG_NAMETAB_A, (addr >> 10) & 0x38); + break; + case VDP_PLANE_B: + vdp_setreg(VDP_REG_NAMETAB_B, (addr >> 13) & 7); + break; + case VDP_PLANE_WIN: + vdp_setreg(VDP_REG_NAMETAB_WIN, (addr >> 10) & 0x7e); + default: + break; + } +} + +static inline uint16_t vdp_nametab_addr(int idx) +{ + return (uint16_t)idx << 13; +} + +static inline void vdp_set_nametab_idx(int plane, int idx) +{ + vdp_set_nametab_addr(plane, vdp_nametab_addr(idx)); +} + +static inline void vdp_disable_layer(int plane) +{ + switch(plane) { + case VDP_PLANE_A: + vdp_setreg(VDP_REG_NAMETAB_A, 0x40); + break; + case VDP_PLANE_B: + vdp_setreg(VDP_REG_NAMETAB_B, 0x08); + break; + case VDP_PLANE_WIN: + vdp_setreg(VDP_REG_NAMETAB_WIN, 0x40); + default: + break; + } +} + +static inline uint16_t vdp_nametab_entry(int tileidx, int palidx, uint16_t flags) +{ + return tileidx | (((uint16_t)palidx & 0x3) << 13) | flags; +} + +static inline void vdp_set_sprite_table(uint16_t addr) +{ + vdp_setreg(VDP_REG_SPRITE_TAB, addr >> 9); +} + +static inline void vdp_set_scroll_table(uint16_t addr) +{ + vdp_setreg(VDP_REG_SCROLL_TAB, addr >> 10); +} + +static inline void vdp_wait_vblank_start(void) +{ + while(!(VDP_PORT_STATUS & VDP_STAT_VBLANK)); +} + +static inline void vdp_wait_vblank_end(void) +{ + while(VDP_PORT_STATUS & VDP_STAT_VBLANK); +} + +static inline void vdp_wait_vblank(void) +{ + vdp_wait_vblank_start(); + vdp_wait_vblank_end(); +} + +void vdp_init(void); + +#endif /* VDP_H_ */ 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