initial commit
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 31 Mar 2019 22:59:21 +0000 (01:59 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 31 Mar 2019 22:59:21 +0000 (01:59 +0300)
13 files changed:
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
megadrive.ld [new file with mode: 0644]
src/intr.h [new file with mode: 0644]
src/intr.s [new file with mode: 0644]
src/io.c [new file with mode: 0644]
src/io.h [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/pad.h [new file with mode: 0644]
src/startup.s [new file with mode: 0644]
src/vdp.c [new file with mode: 0644]
src/vdp.h [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..4bc9d06
--- /dev/null
@@ -0,0 +1,6 @@
+*.o
+*.d
+*.swp
+*.map
+*.elf
+*.bin
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (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.h b/src/intr.h
new file mode 100644 (file)
index 0000000..2b5018f
--- /dev/null
@@ -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 (file)
index 0000000..38f0eb1
--- /dev/null
@@ -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 (file)
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 (file)
index 0000000..d53871b
--- /dev/null
+++ b/src/io.h
@@ -0,0 +1,106 @@
+#ifndef MEGADRIVE_IO_H_
+#define MEGADRIVE_IO_H_
+
+#include <stdint.h>
+
+#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 (file)
index 0000000..5ba9dde
--- /dev/null
@@ -0,0 +1,71 @@
+#include <stdint.h>
+#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 (file)
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 (file)
index 0000000..991211c
--- /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 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 (file)
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 (file)
index 0000000..05011eb
--- /dev/null
+++ b/src/vdp.h
@@ -0,0 +1,282 @@
+#ifndef VDP_H_
+#define VDP_H_
+
+#include <stdint.h>
+
+#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 (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