--- /dev/null
+*.o
+*.d
+*.swp
+cfg.mk
+*.gba
+*.elf
+pngdump
--- /dev/null
+src = $(wildcard src/*.c)
+ssrc = $(wildcard src/*.s)
+obj = $(src:.c=.o) $(ssrc:.s=.o)
+dep = $(src:.c=.d)
+name = gbajam21
+elf = $(name).elf
+bin = $(name).gba
+
+TCPREFIX = arm-none-eabi-
+
+CPP = $(TCPREFIX)cpp
+CC = $(TCPREFIX)gcc
+AS = $(TCPREFIX)as
+OBJCOPY = $(TCPREFIX)objcopy
+OBJDUMP = $(TCPREFIX)objdump
+EMU = vbam
+
+opt = -O3 -fomit-frame-pointer -mcpu=arm7tdmi -mtune=arm7tdmi -mthumb -mthumb-interwork
+#dbg = -g
+
+CFLAGS = $(opt) $(dbg) -pedantic -Wall -MMD $(def)
+ASFLAGS = -mthumb-interwork
+LDFLAGS = -mthumb -mthumb-interwork
+EMUFLAGS = -T 100 -f 1 --agb-print
+
+-include cfg.mk
+
+.PHONY: all
+all: $(bin) $(bin_mb)
+
+$(bin): $(elf)
+ $(OBJCOPY) -O binary $(elf) $(bin)
+ gbafix -r0 $(bin)
+
+$(elf): $(obj)
+ $(CC) -o $(elf) $(obj) -specs=gba.specs $(LDFLAGS)
+
+-include $(dep)
+
+tools/pngdump/pngdump:
+ $(MAKE) -C tools/pngdump
+
+#data/sprites.raw: data/sprites1.png data/sprites2.png data/sprites3.png data/sprites4.png data/sprites5.png data/sprites6.png
+# tools/pngdump/pngdump -o $@ -n $^
+
+%.raw: %.png tools/pngdump/pngdump
+ tools/pngdump/pngdump -o $@ -n $<
+
+%.pal: %.png tools/pngdump/pngdump
+ tools/pngdump/pngdump -o $@ -c $<
+
+.PHONY: clean
+clean:
+ rm -f $(obj) $(bin) $(bin_mb) $(elf) $(elf_mb)
+
+.PHONY: cleandep
+cleandep:
+ rm -f $(dep)
+
+.PHONY: install
+install: $(bin)
+ if2a -n -f -W $<
+
+.PHONY: run
+run: $(bin_mb)
+ if2a -m $<
+
+.PHONY: simrun
+simrun: $(bin)
+ $(EMU) $(EMUFLAGS) $(bin)
+
+.PHONY: disasm
+disasm: $(elf)
+ $(OBJDUMP) -d $< >$@
--- /dev/null
+#include <stdio.h>
+#include <stdarg.h>
+#include "debug.h"
+
+#ifdef EMUBUILD
+__attribute__((target("arm")))
+void emuprint(const char *fmt, ...)
+{
+ char buf[128];
+ va_list arg_list;
+
+ va_start(arg_list, fmt);
+ vsnprintf(buf, 128, fmt, arg_list);
+ va_end(arg_list);
+
+ __asm__ __volatile__(
+ "mov r0, %0\n\t"
+ "swi 0xff0000\n\t" :
+ : "r" (buf)
+ : "r0"
+ );
+}
+#else
+void emuprint(const char *fmt, ...)
+{
+}
+#endif
--- /dev/null
+#ifndef DEBUG_H_
+#define DEBUG_H_
+
+void emuprint(const char *fmt, ...);
+
+#endif /* DEBUG_H_ */
--- /dev/null
+#include "dma.h"
+
+/* DMA Options */
+#define DMA_ENABLE 0x80000000
+#define DMA_INT_ENABLE 0x40000000
+#define DMA_TIMING_IMMED 0x00000000
+#define DMA_TIMING_VBLANK 0x10000000
+#define DMA_TIMING_HBLANK 0x20000000
+#define DMA_TIMING_DISPSYNC 0x30000000
+#define DMA_16 0x00000000
+#define DMA_32 0x04000000
+#define DMA_REPEAT 0x02000000
+#define DMA_SRC_INC 0x00000000
+#define DMA_SRC_DEC 0x00800000
+#define DMA_SRC_FIX 0x01000000
+#define DMA_DST_INC 0x00000000
+#define DMA_DST_DEC 0x00200000
+#define DMA_DST_FIX1 0x00400000
+#define DMA_DST_RELOAD 0x00600000
+
+/* DMA Register Parts */
+#define DMA_SRC 0
+#define DMA_DST 1
+#define DMA_CTRL 2
+
+static volatile uint32_t *reg_dma[4] = {(void*)0x040000b0, (void*)0x040000bc, (void*)0x040000c8, (void*)0x040000d4 };
+
+/* --- perform a copy of words or halfwords using DMA --- */
+
+void dma_copy32(int channel, void *dst, void *src, int words, unsigned int flags)
+{
+ reg_dma[channel][DMA_SRC] = (uint32_t)src;
+ reg_dma[channel][DMA_DST] = (uint32_t)dst;
+ reg_dma[channel][DMA_CTRL] = words | flags | DMA_32 | DMA_ENABLE;
+}
+
+void dma_copy16(int channel, void *dst, void *src, int halfwords, unsigned int flags)
+{
+ reg_dma[channel][DMA_SRC] = (uint32_t)src;
+ reg_dma[channel][DMA_DST] = (uint32_t)dst;
+ reg_dma[channel][DMA_CTRL] = halfwords | flags | DMA_16 | DMA_ENABLE;
+}
+
+/* --- fill a buffer with an ammount of words and halfwords using DMA --- */
+
+static uint32_t fill[4];
+
+void dma_fill32(int channel, void *dst, uint32_t val, int words)
+{
+ fill[channel] = val;
+ reg_dma[channel][DMA_SRC] = (uint32_t)(fill + channel);
+ reg_dma[channel][DMA_DST] = (uint32_t)dst;
+ reg_dma[channel][DMA_CTRL] = words | DMA_SRC_FIX | DMA_TIMING_IMMED | DMA_32 | DMA_ENABLE;
+}
+
+void dma_fill16(int channel, void *dst, uint16_t val, int halfwords)
+{
+ fill[channel] = val;
+ reg_dma[channel][DMA_SRC] = (uint32_t)(fill + channel);
+ reg_dma[channel][DMA_DST] = (uint32_t)dst;
+ reg_dma[channel][DMA_CTRL] = halfwords | DMA_SRC_FIX | DMA_TIMING_IMMED | DMA_16 | DMA_ENABLE;
+}
--- /dev/null
+#ifndef DMA_H_
+#define DMA_H_
+
+#include <stdint.h>
+
+void dma_copy32(int channel, void *dst, void *src, int words, unsigned int flags);
+void dma_copy16(int channel, void *dst, void *src, int halfwords, unsigned int flags);
+
+void dma_fill32(int channel, void *dst, uint32_t val, int words);
+void dma_fill16(int channel, void *dst, uint16_t val, int halfwords);
+
+#endif /* DMA_H_ */
--- /dev/null
+#ifndef GBAREGS_H_
+#define GBAREGS_H_
+
+#include <stdint.h>
+
+#define VRAM_START_ADDR 0x6000000
+#define VRAM_BG_ADDR VRAM_START_ADDR
+#define VRAM_OBJ_ADDR 0x6010000
+#define VRAM_LFB_OBJ_ADDR 0x6014000
+#define VRAM_LFB_FB0_ADDR VRAM_START_ADDR
+#define VRAM_LFB_FB1_ADDR 0x600a000
+
+/* address of character data block x (4 possible blocks, 16k each) */
+#define VRAM_CHR_BLOCK_ADDR(x) (VRAM_START_ADDR + ((x) << 14))
+/* address of screen data block x (32 possible blocks, 2k each) */
+#define VRAM_SCR_BLOCK_ADDR(x) (VRAM_START_ADDR + ((x) << 11))
+
+/* fields of a background tile in screen memory */
+#define BGTILE_HFLIP 0x0400
+#define BGTILE_VFLIP 0x0800
+#define BGTILE_PAL(x) ((uint16_t)(x) << 12)
+
+/* color palette ram addresses for backgrounds and sprites */
+#define CRAM_BG_ADDR 0x5000000
+#define CRAM_OBJ_ADDR 0x5000200
+
+/* OAM table */
+#define OAM_ADDR 0x7000000
+
+/* interrupt handler */
+#define INTR_VECTOR (*(volatile uint32_t*)0x3007ffc)
+
+/* battery backed RAM address */
+#define SRAM_ADDR 0xe000000
+
+/* I/O space */
+
+#define REG_BASE 0x4000000
+#define REG8(x) (*(volatile uint8_t*)(REG_BASE + (x)))
+#define REG16(x) (*(volatile uint16_t*)(REG_BASE + (x)))
+#define REG32(x) (*(volatile uint32_t*)(REG_BASE + (x)))
+
+/* ---- display registers ---- */
+#define REG_DISPCNT REG16(0x00)
+#define REG_GREENSWAP REG16(0x02)
+#define REG_DISPSTAT REG16(0x04)
+#define REG_VCOUNT REG16(0x06)
+#define REG_BG0CNT REG16(0x08)
+#define REG_BG1CNT REG16(0x0a)
+#define REG_BG2CNT REG16(0x0c)
+#define REG_BG3CNT REG16(0x0e)
+/* scrolling registers */
+#define REG_BG0HOFS REG16(0x10)
+#define REG_BG0VOFS REG16(0x12)
+#define REG_BG1HOFS REG16(0x14)
+#define REG_BG1VOFS REG16(0x16)
+#define REG_BG2HOFS REG16(0x18)
+#define REG_BG2VOFS REG16(0x1a)
+#define REG_BG3HOFS REG16(0x1c)
+#define REG_BG3VOFS REG16(0x1e)
+/* BG rotation and scaling registers */
+#define REG_BG2PA REG16(0x20)
+#define REG_BG2PB REG16(0x22)
+#define REG_BG2PC REG16(0x24)
+#define REG_BG2PD REG16(0x26)
+#define REG_BG2X REG32(0x28)
+#define REG_BG2Y REG32(0x2c)
+#define REG_BG3PA REG16(0x30)
+#define REG_BG3PB REG16(0x32)
+#define REG_BG3PC REG16(0x34)
+#define REG_BG3PD REG16(0x36)
+#define REG_BG3X REG32(0x38)
+#define REG_BG3Y REG32(0x3c)
+/* window registers */
+#define REG_WIN0H REG16(0x40)
+#define REG_WIN1H REG16(0x42)
+#define REG_WIN0V REG16(0x44)
+#define REG_WIN1V REG16(0x46)
+#define REG_WININ REG16(0x48)
+#define REG_WINOUT REG16(0x4a)
+
+#define REG_MOSAIC REG16(0x4c)
+/* color effects */
+#define REG_BLDCNT REG16(0x50)
+#define REG_BLDALPHA REG16(0x52)
+#define REG_BLDY REG16(0x54)
+
+/* ---- sound registers ---- */
+#define REG_SOUND1CNT_L REG16(0x60)
+#define REG_SOUND1CNT_H REG16(0x62)
+#define REG_SOUND1CNT_X REG16(0x64)
+#define REG_SOUND2CNT_L REG16(0x68)
+#define REG_SOUND2CNT_H REG16(0x6c)
+#define REG_SOUND3CNT_L REG16(0x70)
+#define REG_SOUND3CNT_H REG16(0x72)
+#define REG_SOUND3CNT_X REG16(0x74)
+#define REG_SOUND4CNT_L REG16(0x78)
+#define REG_SOUND4CNT_H REG16(0x7c)
+#define REG_SOUNDCNT_L REG16(0x80)
+#define REG_SOUNDCNT_H REG16(0x82)
+#define REG_SOUNDCNT_X REG16(0x84)
+#define REG_SOUNDBIAS REG16(0x88)
+#define WAVE_RAM_PTR ((unsigned char*)(REG_BASE + 0x90))
+#define REG_FIFO_A REG32(0xa0)
+#define REG_FIFO_B REG32(0xa4)
+#define FIFO_A_PTR ((unsigned char*)(REG_BASE + 0xa0))
+#define FIFO_B_PTR ((unsigned char*)(REG_BASE + 0xa4))
+
+/* ---- DMA registers ---- */
+#define REG_DMA0SAD REG32(0xb0)
+#define REG_DMA0DAD REG32(0xb4)
+#define REG_DMA0CNT_L REG16(0xb8)
+#define REG_DMA0CNT_H REG16(0xba)
+#define REG_DMA1SAD REG32(0xbc)
+#define REG_DMA1DAD REG32(0xc0)
+#define REG_DMA1CNT_L REG16(0xc4)
+#define REG_DMA1CNT_H REG16(0xc6)
+#define REG_DMA2SAD REG32(0xc8)
+#define REG_DMA2DAD REG32(0xcc)
+#define REG_DMA2CNT_L REG16(0xd0)
+#define REG_DMA2CNT_H REG16(0xd2)
+#define REG_DMA3SAD REG32(0xd4)
+#define REG_DMA3DAD REG32(0xd8)
+#define REG_DMA3CNT_L REG16(0xdc)
+#define REG_DMA3CNT_H REG16(0xde)
+
+/* ---- timer registers ---- */
+#define REG_TM0CNT_L REG16(0x100)
+#define REG_TM0CNT_H REG16(0x102)
+#define REG_TM1CNT_L REG16(0x104)
+#define REG_TM1CNT_H REG16(0x106)
+#define REG_TM2CNT_L REG16(0x108)
+#define REG_TM2CNT_H REG16(0x10a)
+#define REG_TM3CNT_L REG16(0x10c)
+#define REG_TM3CNT_H REG16(0x10e)
+
+#define REG_TMCNT_L(x) REG16(0x100 + ((x) << 2))
+#define REG_TMCNT_H(x) REG16(0x102 + ((x) << 2))
+
+/* ---- communication registers (serial/joybus/gpio) ---- */
+#define REG_SIODATA32 REG32(0x120)
+#define REG_SIOMULTI0 REG16(0x120)
+#define REG_SIOMULTI1 REG16(0x122)
+#define REG_SIOMULTI2 REG16(0x124)
+#define REG_SIOMULTI3 REG16(0x126)
+#define REG_SIOCNT REG16(0x128)
+#define REG_SIOMLT_SEND REG16(0x12a)
+#define REG_SIODATA8 REG16(0x12a)
+#define REG_RCNT REG16(0x134)
+#define REG_JOYCNT REG16(0x140)
+#define REG_JOY_RECV REG32(0x150)
+#define REG_JOY_TRANS REG32(0x154)
+#define REG_JOYSTAT REG16(0x158)
+
+/* ---- keypad registers ---- */
+#define REG_KEYINPUT REG16(0x130)
+#define REG_KEYCNT REG16(0x132)
+
+/* ---- interrupts ---- */
+#define REG_IE REG16(0x200)
+#define REG_IF REG16(0x202)
+#define REG_WAITCNT REG16(0x204)
+#define REG_IME REG16(0x208)
+
+#define REG_POSTFLG REG8(0x300)
+#define REG_HALTCNT REG8(0x301)
+#define REG_INTMEMCNT REG32(0x800)
+
+/* REG_DISPSTAT bits */
+#define DISPSTAT_VBLANK 0x01
+#define DISPSTAT_HBLANK 0x02
+#define DISPSTAT_VMATCH 0x04
+#define DISPSTAT_IEN_VBLANK 0x08
+#define DISPSTAT_IEN_HBLANK 0x10
+#define DISPSTAT_IEN_VMATCH 0x20
+#define DISPSTAT_VCOUNT(x) ((uint16_t)(x) << 8)
+
+/* REG_DISPCNT bits */
+#define DISPCNT_MODE(x) (x)
+#define DISPCNT_FB1 0x0010
+#define DISPCNT_HBLANK_OBJPROC 0x0020
+#define DISPCNT_OBJMAP_1D 0x0040
+#define DISPCNT_FORCE_BLANK 0x0080
+#define DISPCNT_BG0 0x0100
+#define DISPCNT_BG1 0x0200
+#define DISPCNT_BG2 0x0400
+#define DISPCNT_BG3 0x0800
+#define DISPCNT_OBJ 0x1000
+#define DISPCNT_WIN0 0x2000
+#define DISPCNT_WIN1 0x4000
+#define DISPCNT_WINOBJ 0x8000
+
+/* REG_BGXCNT bits */
+#define BGCNT_PRIO(x) ((uint16_t)(x))
+#define BGCNT_CHR_BASE(x) ((uint16_t)(x) << 2)
+#define BGCNT_MOSAIC 0x0040
+#define BGCNT_256COL 0x0080
+#define BGCNT_SCR_BASE(x) ((uint16_t)(x) << 8)
+#define BGCNT_WRAP 0x2000
+
+#define BGCNT_SZ(x) ((uint16_t)(x) << 14)
+#define BGCNT_SZ_TX_256X256 BGCNT_SZ(0)
+#define BGCNT_SZ_RS_128X128 BGCNT_SZ(0)
+#define BGCNT_SZ_TX_512X256 BGCNT_SZ(1)
+#define BGCNT_SZ_RS_256X256 BGCNT_SZ(1)
+#define BGCNT_SZ_TX_256X512 BGCNT_SZ(2)
+#define BGCNT_SZ_RS_512X512 BGCNT_SZ(2)
+#define BGCNT_SZ_TX_512X512 BGCNT_SZ(3)
+#define BGCNT_SZ_RS_1024X1024 BGCNT_SZ(3)
+
+/* REG_BLDCNT bits */
+#define BLDCNT_A_BG0 0x0001
+#define BLDCNT_A_BG1 0x0002
+#define BLDCNT_A_BG2 0x0004
+#define BLDCNT_A_BG3 0x0008
+#define BLDCNT_A_OBJ 0x0010
+#define BLDCNT_A_BACKDROP 0x0020
+#define BLDCNT_B_BG0 0x0100
+#define BLDCNT_B_BG1 0x0200
+#define BLDCNT_B_BG2 0x0400
+#define BLDCNT_B_BG3 0x0800
+#define BLDCNT_B_OBJ 0x1000
+#define BLDCNT_B_BACKDROP 0x2000
+
+#define BLDCNT_ALPHA 0x0040
+#define BLDCNT_BRIGHTEN 0x0080
+#define BLDCNT_DARKEN 0x00c0
+
+/* REG_IF bits */
+#define IF_VBLANK 0x0001
+#define IF_HBLANK 0x0002
+#define IF_VMATCH 0x0004
+#define IF_TIMER0 0x0008
+#define IF_TIMER1 0x0010
+#define IF_TIMER2 0x0020
+#define IF_TIMER3 0x0040
+#define IF_COMM 0x0080
+#define IF_DMA0 0x0100
+#define IF_DMA1 0x0200
+#define IF_DMA2 0x0400
+#define IF_DMA3 0x0800
+#define IF_KEY 0x1000
+#define IF_GPAK 0x2000
+
+/* REG_TMXCNT bits */
+#define TMCNT_PRESCL_CLK1 0
+#define TMCNT_PRESCL_CLK64 1
+#define TMCNT_PRESCL_CLK256 2
+#define TMCNT_PRESCL_CLK1024 3
+
+#define TMCNT_CASCADE 0x04
+#define TMCNT_IE 0x40
+#define TMCNT_EN 0x80
+
+/* REG_KEY* bits */
+#define KEY_A 0x0001
+#define KEY_B 0x0002
+#define KEY_SELECT 0x0004
+#define KEY_START 0x0008
+#define KEY_RIGHT 0x0010
+#define KEY_LEFT 0x0020
+#define KEY_UP 0x0040
+#define KEY_DOWN 0x0080
+#define KEY_RT 0x0100
+#define KEY_LT 0x0200
+
+#define KEYCNT_IE 0x4000
+#define KEYCNT_IAND 0x8000
+
+/* REG_SOUNDCNT_L bits */
+#define SCNT_SS_LVOL(x) ((x) & 7)
+#define SCNT_SS_RVOL(x) (((x) & 7) << 4)
+#define SCNT_SS_VOL(x) (SCNT_SS_LVOL(x) | SCNT_SS_RVOL(x))
+#define SCNT_SS1_EN_R 0x0100
+#define SCNT_SS2_EN_R 0x0200
+#define SCNT_SS3_EN_R 0x0400
+#define SCNT_SS4_EN_R 0x0800
+#define SCNT_SS_EN_R(x) (SCNT_SS1_EN_R << (x))
+#define SCNT_SS1_EN_L 0x1000
+#define SCNT_SS2_EN_L 0x2000
+#define SCNT_SS3_EN_L 0x4000
+#define SCNT_SS4_EN_L 0x8000
+#define SCNT_SS_EN_L(x) (SCNT_SS1_EN_L << (x))
+#define SCNT_SS1_EN (SCNT_SS1_EN_R | SCNT_SS1_EN_L)
+#define SCNT_SS2_EN (SCNT_SS2_EN_R | SCNT_SS2_EN_L)
+#define SCNT_SS3_EN (SCNT_SS3_EN_R | SCNT_SS3_EN_L)
+#define SCNT_SS4_EN (SCNT_SS4_EN_R | SCNT_SS4_EN_L)
+#define SCNT_SS_EN(x) (SCNT_SS_EN_L(x) | SCNT_SS_EN_R(x))
+
+#define SCNT_SS1 0
+#define SCNT_SS2 1
+#define SCNT_SS3 2
+#define SCNT_SS4 3
+
+/* REG_SOUNDCNT_X bits */
+#define SCNT_MASTER_EN 0x0080
+
+/* REG_SOUNDCNT_H bits */
+#define SCNT_SS_VOL_QRT 0x0000
+#define SCNT_SS_VOL_HALF 0x0001
+#define SCNT_SS_VOL_FULL 0x0002
+#define SCNT_DSA_VOL_HALF 0
+#define SCNT_DSA_VOL_FULL 0x0004
+#define SCNT_DSB_VOL_HALF 0
+#define SCNT_DSB_VOL_FULL 0x0008
+#define SCNT_DSA_EN_R 0x0100
+#define SCNT_DSA_EN_L 0x0200
+#define SCNT_DSA_TIMER0 0
+#define SCNT_DSA_TIMER1 0x0400
+#define SCNT_DSA_CLRFIFO 0x0800
+#define SCNT_DSB_EN_R 0x1000
+#define SCNT_DSB_EN_L 0x2000
+#define SCNT_DSB_TIMER0 0
+#define SCNT_DSB_TIMER1 0x4000
+#define SCNT_DSB_CLRFIFO 0x8000
+
+/* REG_DMAxCNT_H bits */
+#define DMACNTH_DST_INC 0
+#define DMACNTH_DST_DEC 0x0020
+#define DMACNTH_DST_FIXED 0x0040
+#define DMACNTH_INC_RELOAD 0x0060
+#define DMACNTH_SRC_INC 0
+#define DMACNTH_SRC_DEC 0x0080
+#define DMACNTH_SRC_FIXED 0x0100
+#define DMACNTH_REPEAT 0x0200
+#define DMACNTH_16BIT 0
+#define DMACNTH_32BIT 0x0400
+#define DMACNTH_VBLANK 0x1000
+#define DMACNTH_HBLANK 0x2000
+#define DMACNTH_SOUND 0x3000
+#define DMACNTH_IEN 0x4000
+#define DMACNTH_EN 0x8000
+
+#define DMACNT_DST_INC 0
+#define DMACNT_DST_DEC 0x00200000
+#define DMACNT_DST_FIXED 0x00400000
+#define DMACNT_INC_RELOAD 0x00600000
+#define DMACNT_SRC_INC 0
+#define DMACNT_SRC_DEC 0x00800000
+#define DMACNT_SRC_FIXED 0x01000000
+#define DMACNT_REPEAT 0x02000000
+#define DMACNT_16BIT 0
+#define DMACNT_32BIT 0x04000000
+#define DMACNT_VBLANK 0x10000000
+#define DMACNT_HBLANK 0x20000000
+#define DMACNT_SOUND 0x30000000
+#define DMACNT_IEN 0x40000000
+#define DMACNT_EN 0x80000000
+
+
+#endif /* GBAREGS_H_ */
--- /dev/null
+#include "intr.h"
+
+#define MAX_INTR 14
+static void (*intr_table[MAX_INTR])(void);
+
+__attribute__ ((target("arm"), section(".iwram")))
+static void intr_handler(void)
+{
+ int i;
+ uint16_t iflags;
+
+ clr_intr();
+ iflags = REG_IF & 0x3fff;
+
+
+ for(i=0; i<MAX_INTR; i++) {
+ if((iflags & (1 << i)) && intr_table[i]) {
+ intr_table[i]();
+ }
+ }
+
+ REG_IF = iflags; /* ack intr */
+ set_intr();
+}
+
+void intr_init(void)
+{
+ INTR_VECTOR = (uint32_t)intr_handler;
+}
+
+void interrupt(int intr, void (*handler)(void))
+{
+ intr_table[intr] = handler;
+}
--- /dev/null
+#ifndef INTR_H_
+#define INTR_H_
+
+#include "gbaregs.h"
+
+/* interrupts */
+enum {
+ INTR_VBLANK,
+ INTR_HBLANK,
+ INTR_VCOUNT,
+ INTR_TIMER0,
+ INTR_TIMER1,
+ INTR_TIMER2,
+ INTR_TIMER3,
+ INTR_COMM,
+ INTR_DMA0,
+ INTR_DMA1,
+ INTR_DMA2,
+ INTR_DMA3,
+ INTR_KEY,
+ INTR_GPAK
+};
+
+void intr_init(void);
+
+/* set/clear interrupts */
+#define set_intr() \
+ do { REG_IME |= 0x0001; } while(0)
+#define clr_intr() \
+ do { REG_IME &= 0xfffe; } while(0)
+
+/* set an interrupt handler */
+void interrupt(int intr, void (*handler)(void));
+
+/* mask/unmask an interrupt */
+#define mask(intr) do {REG_IE &= ~(1 << (intr));} while(0)
+#define unmask(intr) do {REG_IE |= 1 << (intr);} while(0)
+
+#endif /* INTR_H_ */
--- /dev/null
+#include <math.h>
+#include "gbaregs.h"
+#include "intr.h"
+#include "debug.h"
+
+#define RGB15(r, g, b) \
+ (((uint16_t)(r) & 0x1f) | \
+ (((uint16_t)(g) & 0x1f) << 5) | \
+ (((uint16_t)(b) & 0x1f) << 10))
+
+int main(void)
+{
+ int i, j;
+ uint16_t *vptr;
+
+ emuprint("\nStarting GBAJAM21\n-----------------\n");
+
+ intr_init();
+
+ REG_DISPCNT = 3 | DISPCNT_BG2;
+
+ vptr = (uint16_t*)VRAM_START_ADDR;
+ for(i=0; i<160; i++) {
+ for(j=0; j<240; j++) {
+ int xor = i ^ j;
+ int r = xor >> 2;
+ int g = xor >> 1;
+ int b = xor;
+
+ *vptr++ = RGB15(r, g, b);
+ }
+ }
+
+ for(;;);
+ return 0;
+}
--- /dev/null
+#include "intr.h"
+#include "timer.h"
+
+#define F_CLK 16780000
+/* clock is 16.78MHz
+ * - no prescale: 59.595ns
+ * - prescale 64: 3.814us
+ * - prescale 256: 15.256us
+ * - prescale 1024: 61.025us
+ */
+
+static void timer_intr(void);
+
+void init_timer(int tm, unsigned long rate_hz, void (*intr)(void))
+{
+ static const unsigned long clk[] = {F_CLK, F_CLK / 64, F_CLK / 256, F_CLK / 1024};
+ unsigned long count;
+ int pscl = 0;
+
+ do {
+ count = clk[pscl] / rate_hz;
+ } while(count >= 65536 && ++pscl < 4);
+
+ if(pscl >= 4) return; /* impossible rate */
+
+ REG_TMCNT_H(tm) = 0;
+ REG_TMCNT_L(tm) = 65536 - count;
+ if(intr) {
+ interrupt(INTR_TIMER0 + tm, intr);
+ unmask(INTR_TIMER0 + tm);
+ REG_TMCNT_H(tm) = TMCNT_IE;
+ }
+ REG_TMCNT_H(tm) |= TMCNT_EN | pscl;
+}
+
+void reset_msec_timer(void)
+{
+ REG_TM0CNT_H &= ~TMCNT_EN;
+ interrupt(INTR_TIMER0, timer_intr);
+ timer_msec = 0;
+ REG_TM0CNT_L = 65535 - 16779;
+ REG_TM0CNT_H |= TMCNT_IE | TMCNT_EN;
+ unmask(INTR_TIMER0);
+}
+
+void delay(unsigned long ms)
+{
+ unsigned long end = timer_msec + ms;
+ while(timer_msec < end);
+}
+
+static void timer_intr(void)
+{
+ timer_msec++;
+}
--- /dev/null
+#ifndef TIMER_H_
+#define TIMER_H_
+
+#include "gbaregs.h"
+
+#define enable_timer(x) \
+ do { REG_TMCNT_H(x) |= TMCNT_EN; } while(0)
+
+#define disable_timer(x) \
+ do { REG_TMCNT_H(x) &= ~TMCNT_EN; } while(0)
+
+volatile unsigned long timer_msec;
+
+void init_timer(int tm, unsigned long rate_hz, void (*intr)(void));
+
+void reset_msec_timer(void);
+
+void delay(unsigned long ms);
+
+#ifdef __thumb__
+#define udelay(x) asm volatile ( \
+ "0: sub %0, %0, #1\n\t" \
+ "bne 0b\n\t" \
+ :: "r"(x) : "cc")
+#else
+#define udelay(x) asm volatile ( \
+ "0: subs %0, %0, #1\n\t" \
+ "bne 0b\n\t" \
+ :: "r"(x) : "cc")
+#endif
+
+#endif /* TIMER_H_ */
--- /dev/null
+LDFLAGS = -lpng -lz
+
+pngdump: main.o image.o
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+clean:
+ $(RM) main.o
+ $(RM) image.o
+ $(RM) pngdump
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <png.h>
+#include "image.h"
+
+int alloc_image(struct image *img, int x, int y, int bpp)
+{
+ memset(img, 0, sizeof *img);
+ img->width = x;
+ img->height = y;
+ img->bpp = bpp;
+ img->scansz = img->pitch = x * bpp / 8;
+
+ if(!(img->pixels = malloc(y * img->scansz))) {
+ fprintf(stderr, "failed to allocate %dx%d (%dbpp) pixel buffer\n", x, y, bpp);
+ return -1;
+ }
+
+ /* just a guess, assume the user will fill the details, but set up reasonable
+ * defaults just in case...
+ */
+ if(bpp <= 8) {
+ img->nchan = 1;
+ img->cmap_ncolors = 1 << bpp;
+ } else if(bpp <= 24) {
+ img->nchan = 3;
+ } else {
+ img->nchan = 4;
+ }
+ return 0;
+}
+
+int load_image(struct image *img, const char *fname)
+{
+ int i;
+ FILE *fp;
+ png_struct *png;
+ png_info *info;
+ int chan_bits, color_type;
+ png_uint_32 xsz, ysz;
+ png_color *palette;
+ unsigned char **scanline;
+ unsigned char *dptr;
+
+ if(!(fp = fopen(fname, "rb"))) {
+ fprintf(stderr, "failed to open: %s: %s\n", fname, strerror(errno));
+ return -1;
+ }
+
+ if(!(png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) {
+ fclose(fp);
+ return -1;
+ }
+ if(!(info = png_create_info_struct(png))) {
+ fclose(fp);
+ png_destroy_read_struct(&png, 0, 0);
+ return -1;
+ }
+ if(setjmp(png_jmpbuf(png))) {
+ fclose(fp);
+ png_destroy_read_struct(&png, &info, 0);
+ return -1;
+ }
+
+ png_init_io(png, fp);
+ png_read_png(png, info, 0, 0);
+
+ png_get_IHDR(png, info, &xsz, &ysz, &chan_bits, &color_type, 0, 0, 0);
+ img->width = xsz;
+ img->height = ysz;
+ img->nchan = png_get_channels(png, info);
+ img->bpp = img->nchan * chan_bits;
+ img->scansz = img->pitch = xsz * img->bpp / 8;
+ img->cmap_ncolors = 0;
+
+ if(color_type == PNG_COLOR_TYPE_PALETTE) {
+ png_get_PLTE(png, info, &palette, &img->cmap_ncolors);
+ memcpy(img->cmap, palette, img->cmap_ncolors * sizeof *img->cmap);
+ }
+
+ if(!(img->pixels = malloc(ysz * img->scansz))) {
+ perror("failed to allocate pixel buffer");
+ fclose(fp);
+ png_destroy_read_struct(&png, &info, 0);
+ return -1;
+ }
+ dptr = img->pixels;
+
+ scanline = (unsigned char**)png_get_rows(png, info);
+ for(i=0; i<ysz; i++) {
+ memcpy(dptr, scanline[i], img->scansz);
+ dptr += img->pitch;
+ }
+
+ fclose(fp);
+ png_destroy_read_struct(&png, &info, 0);
+ return 0;
+}
+
+int save_image(struct image *img, const char *fname)
+{
+ int i, chan_bits, coltype;
+ FILE *fp;
+ png_struct *png;
+ png_info *info;
+ png_text txt;
+ unsigned char **scanline = 0;
+ unsigned char *pptr;
+
+ if(!(fp = fopen(fname, "wb"))) {
+ fprintf(stderr, "save_image: failed to open: %s: %s\n", fname, strerror(errno));
+ return -1;
+ }
+
+ if(!(png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) {
+ fclose(fp);
+ return -1;
+ }
+ if(!(info = png_create_info_struct(png))) {
+ png_destroy_write_struct(&png, 0);
+ fclose(fp);
+ return -1;
+ }
+
+ txt.compression = PNG_TEXT_COMPRESSION_NONE;
+ txt.key = "Software";
+ txt.text = "img2tiles";
+ txt.text_length = 0;
+
+ if(setjmp(png_jmpbuf(png))) {
+ png_destroy_write_struct(&png, &info);
+ free(scanline);
+ fclose(fp);
+ return -1;
+ }
+
+ switch(img->nchan) {
+ case 1:
+ if(img->cmap_ncolors > 0) {
+ coltype = PNG_COLOR_TYPE_PALETTE;
+ } else {
+ coltype = PNG_COLOR_TYPE_GRAY;
+ }
+ break;
+ case 2:
+ coltype = PNG_COLOR_TYPE_GRAY_ALPHA;
+ break;
+ case 3:
+ coltype = PNG_COLOR_TYPE_RGB;
+ break;
+ case 4:
+ coltype = PNG_COLOR_TYPE_RGB_ALPHA;
+ break;
+ }
+
+ chan_bits = img->bpp / img->nchan;
+ png_set_IHDR(png, info, img->width, img->height, chan_bits, coltype, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+ png_set_text(png, info, &txt, 1);
+
+ if(img->cmap_ncolors > 0) {
+ png_set_PLTE(png, info, (png_color*)img->cmap, img->cmap_ncolors);
+ }
+
+ if(!(scanline = malloc(img->height * sizeof *scanline))) {
+ png_destroy_write_struct(&png, &info);
+ fclose(fp);
+ return -1;
+ }
+
+ pptr = img->pixels;
+ for(i=0; i<img->height; i++) {
+ scanline[i] = pptr;
+ pptr += img->pitch;
+ }
+ png_set_rows(png, info, scanline);
+
+ png_init_io(png, fp);
+ png_write_png(png, info, 0, 0);
+ png_destroy_write_struct(&png, &info);
+ free(scanline);
+ fclose(fp);
+ return 0;
+}
+
+
+int cmp_image(struct image *a, struct image *b)
+{
+ int i;
+ unsigned char *aptr = a->pixels;
+ unsigned char *bptr = b->pixels;
+
+ if(a->width != b->width || a->height != b->height || a->bpp != b->bpp || a->nchan != b->nchan) {
+ return -1;
+ }
+
+ for(i=0; i<a->height; i++) {
+ if(memcmp(aptr, bptr, a->scansz) != 0) {
+ return -1;
+ }
+ aptr += a->pitch;
+ bptr += b->pitch;
+ }
+ return 0;
+}
+
+void blit(struct image *src, int sx, int sy, int w, int h, struct image *dst, int dx, int dy)
+{
+ int i;
+ unsigned char *sptr, *dptr;
+
+ assert(src->bpp == dst->bpp);
+ assert(src->nchan == dst->nchan);
+
+ if(sx < 0) { w += sx; sx = 0; }
+ if(sy < 0) { h += sy; sy = 0; }
+ if(dx < 0) { w += dx; sx -= dx; dx = 0; }
+ if(dy < 0) { h += dy; sy -= dy; dy = 0; }
+ if(sx + w >= src->width) w = src->width - sx;
+ if(sy + h >= src->height) h = src->height - sy;
+ if(dx + w >= dst->width) w = dst->width - dx;
+ if(dy + h >= dst->height) h = dst->height - dy;
+
+ if(w <= 0 || h <= 0) return;
+
+ sptr = src->pixels + sy * src->pitch + sx * src->bpp / 8;
+ dptr = dst->pixels + dy * dst->pitch + dx * dst->bpp / 8;
+
+ for(i=0; i<h; i++) {
+ memcpy(dptr, sptr, w * dst->bpp / 8);
+ dptr += dst->pitch;
+ sptr += src->pitch;
+ }
+}
+
+static unsigned int get_pixel(struct image *img, int x, int y)
+{
+ unsigned char *pptr;
+ unsigned short *pptr16;
+
+ switch(img->bpp) {
+ case 4:
+ pptr = img->pixels + y * img->pitch + x / 2;
+ return x & 1 ? *pptr & 0xf : *pptr >> 4;
+ case 8:
+ pptr = img->pixels + y * img->pitch + x;
+ return *pptr;
+ case 16:
+ pptr16 = (unsigned short*)(img->pixels + y * img->pitch + x * 2);
+ return *pptr16;
+ default:
+ fprintf(stderr, "get_pixel not implemented for %d bpp\n", img->bpp);
+ }
+
+ return 0;
+}
+
+static void put_pixel(struct image *img, int x, int y, unsigned int pix)
+{
+ unsigned char *pptr;
+ unsigned short *pptr16;
+
+ switch(img->bpp) {
+ case 4:
+ pptr = img->pixels + y * img->pitch + x / 2;
+ if(x & 1) {
+ *pptr = (*pptr & 0xf0) | pix;
+ } else {
+ *pptr = (*pptr & 0xf) | (pix << 4);
+ }
+ break;
+
+ case 8:
+ pptr = img->pixels + y * img->pitch + x;
+ *pptr = pix;
+ break;
+
+ case 16:
+ pptr16 = (unsigned short*)(img->pixels + y * img->pitch + x * 2);
+ *pptr16 = pix;
+ break;
+
+ default:
+ fprintf(stderr, "put_pixel not implemented for %d bpp\n", img->bpp);
+ }
+}
+
+void overlay_key(struct image *src, unsigned int key, struct image *dst)
+{
+ int i, j;
+ unsigned char *sptr, *dptr;
+ unsigned int pix;
+
+ assert(src->bpp == dst->bpp);
+ assert(src->width == dst->width);
+ assert(src->height == dst->height);
+
+ sptr = src->pixels;
+ dptr = dst->pixels;
+
+ for(i=0; i<dst->height; i++) {
+ for(j=0; j<dst->width; j++) {
+ pix = get_pixel(src, j, i);
+ if(pix != key) {
+ put_pixel(dst, j, i, pix);
+ }
+ }
+ }
+}
--- /dev/null
+#ifndef IMAGE_H_
+#define IMAGE_H_
+
+struct cmapent {
+ unsigned char r, g, b;
+};
+
+struct image {
+ int width, height;
+ int bpp;
+ int nchan;
+ int scansz, pitch;
+ int cmap_ncolors;
+ struct cmapent cmap[256];
+ unsigned char *pixels;
+};
+
+int alloc_image(struct image *img, int x, int y, int bpp);
+int load_image(struct image *img, const char *fname);
+int save_image(struct image *img, const char *fname);
+
+int cmp_image(struct image *a, struct image *b);
+
+void blit(struct image *src, int sx, int sy, int w, int h, struct image *dst, int dx, int dy);
+void overlay_key(struct image *src, unsigned int key, struct image *dst);
+
+#endif /* IMAGE_H_ */
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include "image.h"
+
+void print_usage(const char *argv0);
+
+int main(int argc, char **argv)
+{
+ int i, mode = 0;
+ int text = 0;
+ int renibble = 0;
+ char *outfname = 0;
+ char *infiles[256];
+ int num_infiles = 0;
+ struct image img, tmpimg;
+ FILE *out = stdout;
+
+ for(i=1; i<argc; i++) {
+ if(argv[i][0] == '-') {
+ if(argv[i][2] == 0) {
+ switch(argv[i][1]) {
+ case 'p':
+ mode = 0;
+ break;
+
+ case 'c':
+ mode = 1;
+ break;
+
+ case 'i':
+ mode = 2;
+ break;
+
+ case 't':
+ text = 1;
+ break;
+
+ case 'n':
+ renibble = 1;
+ break;
+
+ case 'o':
+ if(!argv[++i]) {
+ fprintf(stderr, "%s must be followed by a filename\n", argv[i - 1]);
+ return 1;
+ }
+ outfname = argv[i];
+ break;
+
+ case 'h':
+ print_usage(argv[0]);
+ return 0;
+
+ default:
+ fprintf(stderr, "invalid option: %s\n", argv[i]);
+ print_usage(argv[0]);
+ return 1;
+ }
+ } else {
+ fprintf(stderr, "invalid option: %s\n", argv[i]);
+ print_usage(argv[0]);
+ return 1;
+ }
+ } else {
+ infiles[num_infiles++] = argv[i];
+ }
+ }
+
+ if(!num_infiles) {
+ fprintf(stderr, "pass the filename of a PNG file\n");
+ return 1;
+ }
+ if(load_image(&img, infiles[0]) == -1) {
+ fprintf(stderr, "failed to load PNG file: %s\n", infiles[0]);
+ return 1;
+ }
+
+ for(i=1; i<num_infiles; i++) {
+ if(load_image(&tmpimg, infiles[i]) == -1) {
+ fprintf(stderr, "failed to load PNG file: %s\n", infiles[i]);
+ return 1;
+ }
+ if(tmpimg.width != img.width || tmpimg.height != img.height) {
+ fprintf(stderr, "size mismatch: first image (%s) is %dx%d, %s is %dx%d\n",
+ infiles[0], img.width, img.height, infiles[i], tmpimg.width, tmpimg.height);
+ return 1;
+ }
+ if(tmpimg.bpp != img.bpp) {
+ fprintf(stderr, "bpp mismatch: first image (%s) is %d bpp, %s is %d bpp\n",
+ infiles[0], img.bpp, infiles[i], img.bpp);
+ return 1;
+ }
+
+ overlay_key(&tmpimg, 0, &img);
+ }
+
+ if(img.bpp == 4 && renibble) {
+ unsigned char *ptr = img.pixels;
+ for(i=0; i<img.width * img.height; i++) {
+ unsigned char p = *ptr;
+ *ptr++ = (p << 4) | (p >> 4);
+ }
+ }
+
+ if(outfname) {
+ if(!(out = fopen(outfname, "wb"))) {
+ fprintf(stderr, "failed to open output file: %s: %s\n", outfname, strerror(errno));
+ return 1;
+ }
+ }
+
+ switch(mode) {
+ case 0:
+ fwrite(img.pixels, 1, img.scansz * img.height, out);
+ break;
+
+ case 1:
+ if(text) {
+ for(i=0; i<img.cmap_ncolors; i++) {
+ printf("%d %d %d\n", img.cmap[i].r, img.cmap[i].g, img.cmap[i].b);
+ }
+ } else {
+ /*fwrite(img.cmap, sizeof img.cmap[0], img.cmap_ncolors, out);*/
+ fwrite(img.cmap, sizeof img.cmap[0], 1 << img.bpp, out);
+ }
+ break;
+
+ case 2:
+ printf("size: %dx%d\n", img.width, img.height);
+ printf("bit depth: %d\n", img.bpp);
+ printf("scanline size: %d bytes\n", img.scansz);
+ if(img.cmap_ncolors > 0) {
+ printf("colormap entries: %d\n", img.cmap_ncolors);
+ } else {
+ printf("color channels: %d\n", img.nchan);
+ }
+ break;
+ }
+
+ fclose(out);
+ return 0;
+}
+
+void print_usage(const char *argv0)
+{
+ printf("Usage: %s [options] <input file>\n", argv0);
+ printf("Options:\n");
+ printf(" -o <output file>: specify output file (default: stdout)\n");
+ printf(" -p: dump pixels (default)\n");
+ printf(" -c: dump colormap (palette) entries\n");
+ printf(" -i: print image information\n");
+ printf(" -t: dump as text\n");
+ printf(" -n: swap the order of nibbles (for 4bpp)\n");
+ printf(" -h: print usage and exit\n");
+}