From: John Tsiombikas Date: Tue, 6 Apr 2021 19:46:11 +0000 (+0300) Subject: initial commit X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=gbajam21;a=commitdiff_plain;h=ffae5f4e018d05dac4b986497169039bbba46acf initial commit --- ffae5f4e018d05dac4b986497169039bbba46acf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b6fae84 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.o +*.d +*.swp +cfg.mk +*.gba +*.elf +pngdump diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a312a03 --- /dev/null +++ b/Makefile @@ -0,0 +1,74 @@ +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 $< >$@ diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..14e00c0 --- /dev/null +++ b/src/debug.c @@ -0,0 +1,27 @@ +#include +#include +#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 diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..41f2a23 --- /dev/null +++ b/src/debug.h @@ -0,0 +1,6 @@ +#ifndef DEBUG_H_ +#define DEBUG_H_ + +void emuprint(const char *fmt, ...); + +#endif /* DEBUG_H_ */ diff --git a/src/dma.c b/src/dma.c new file mode 100644 index 0000000..ba23ab7 --- /dev/null +++ b/src/dma.c @@ -0,0 +1,62 @@ +#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; +} diff --git a/src/dma.h b/src/dma.h new file mode 100644 index 0000000..7ff7606 --- /dev/null +++ b/src/dma.h @@ -0,0 +1,12 @@ +#ifndef DMA_H_ +#define DMA_H_ + +#include + +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_ */ diff --git a/src/gbaregs.h b/src/gbaregs.h new file mode 100644 index 0000000..78860f7 --- /dev/null +++ b/src/gbaregs.h @@ -0,0 +1,351 @@ +#ifndef GBAREGS_H_ +#define GBAREGS_H_ + +#include + +#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_ */ diff --git a/src/intr.c b/src/intr.c new file mode 100644 index 0000000..80ee066 --- /dev/null +++ b/src/intr.c @@ -0,0 +1,34 @@ +#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 +#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; +} diff --git a/src/timer.c b/src/timer.c new file mode 100644 index 0000000..f4b0c7a --- /dev/null +++ b/src/timer.c @@ -0,0 +1,55 @@ +#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++; +} diff --git a/src/timer.h b/src/timer.h new file mode 100644 index 0000000..3daed47 --- /dev/null +++ b/src/timer.h @@ -0,0 +1,32 @@ +#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_ */ diff --git a/tools/pngdump/Makefile b/tools/pngdump/Makefile new file mode 100644 index 0000000..fcd3f4b --- /dev/null +++ b/tools/pngdump/Makefile @@ -0,0 +1,9 @@ +LDFLAGS = -lpng -lz + +pngdump: main.o image.o + $(CC) -o $@ $^ $(LDFLAGS) + +clean: + $(RM) main.o + $(RM) image.o + $(RM) pngdump diff --git a/tools/pngdump/image.c b/tools/pngdump/image.c new file mode 100644 index 0000000..f276e63 --- /dev/null +++ b/tools/pngdump/image.c @@ -0,0 +1,312 @@ +#include +#include +#include +#include +#include +#include +#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; iscansz); + 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; iheight; 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; iheight; 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; ibpp / 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; iheight; i++) { + for(j=0; jwidth; j++) { + pix = get_pixel(src, j, i); + if(pix != key) { + put_pixel(dst, j, i, pix); + } + } + } +} diff --git a/tools/pngdump/image.h b/tools/pngdump/image.h new file mode 100644 index 0000000..7a42fba --- /dev/null +++ b/tools/pngdump/image.h @@ -0,0 +1,27 @@ +#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_ */ diff --git a/tools/pngdump/main.c b/tools/pngdump/main.c new file mode 100644 index 0000000..d7aba3e --- /dev/null +++ b/tools/pngdump/main.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include +#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> 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 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] \n", argv0); + printf("Options:\n"); + printf(" -o : 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"); +}