diff options
-rw-r--r-- | CHANGELOG.txt | 15 | ||||
-rw-r--r-- | README.html | 1 | ||||
-rw-r--r-- | agbx/GNUmakefile | 20 | ||||
-rw-r--r-- | agbx/include/agbx/algo.h | 14 | ||||
-rw-r--r-- | agbx/include/agbx/bs.h | 8 | ||||
-rw-r--r-- | agbx/include/agbx/gfx.h | 12 | ||||
-rw-r--r-- | agbx/source/algo/cp.c | 16 | ||||
-rw-r--r-- | agbx/source/bs/done.c | 15 | ||||
-rw-r--r-- | agbx/source/gfx/clrscrn.c | 24 | ||||
-rw-r--r-- | agbx/source/gfx/flip.s | 37 | ||||
-rw-r--r-- | agbx/source/gfx/getvbnk.s | 65 | ||||
-rw-r--r-- | agbx/source/gfx/plot.c | 19 | ||||
-rw-r--r-- | agbx/source/gfx/setpx.c | 18 | ||||
-rw-r--r-- | agbx/source/gfx/vsync.s | 38 | ||||
-rw-r--r-- | agbx/source/key/getkeymap.s | 2 | ||||
-rw-r--r-- | agbx/source/priv/init.s | 3 | ||||
-rw-r--r-- | demo/GNUmakefile | 8 | ||||
-rw-r--r-- | demo/demo.c | 14 | ||||
-rw-r--r-- | demo/hdr.s | 2 |
19 files changed, 238 insertions, 93 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt index a2da5ed..1fe72cf 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,18 @@ +# 3.0 + +* Add function for getting the current video bank (getvbnk); +* Remove debug mode; +* Update readme; +* Make error 'ok' always zero; +* Remove error 'misc'; +* Restructure assembly; +* Add more error codes; +* Add new header 'algo'; +* Add functions for copying memory sequences (cp); +* Add function for V-syncing (vsync); +* Add functions for filling the screen (clrscrn{X}); +* Make plot take the video address; + # 2.2 * Enable warnings in demo makefile; diff --git a/README.html b/README.html index e0876be..3d94aef 100644 --- a/README.html +++ b/README.html @@ -6,7 +6,6 @@ <p>As the Game Boy Advance uses an ARM (ARM7TDMI) processor, AGBx requires an ARM cross-compiler.</p> <p>For GCC, the appropriate package is <i>arm-none-eabi-gcc</i> on Arch Linux and <i>gcc-arm-none-eabi</i> on Debian. Clang supports supports cross-compilation by default, and this platform can be set via the <i>--target=arm-none-eabi</i> option.</p> <p>The used cross-compiler can be configured in the makefiles, however, it must be GCC-compatible..</p> - <p>Debug mode can be enabled by setting <i>DEBUG=true</i> when invoking make.</p> <br /> <p>The provided makefiles are for GNU Make (hence the filename of <i>GNUmakefile</i>) and depend on it's extensions.</p> <h3>Demo</h3> diff --git a/agbx/GNUmakefile b/agbx/GNUmakefile index fb83fa5..0265379 100644 --- a/agbx/GNUmakefile +++ b/agbx/GNUmakefile @@ -2,18 +2,10 @@ # This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. # If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. -ifneq ($(DEBUG),) -ifneq ($(DEBUG),false) -ifneq ($(DEBUG),true) -$(error Invalid value \"$(DEBUG)\" for DEBUG) -endif -endif -endif - # TOOLS AS := arm-none-eabi-as -CC := clang -target arm-none-eabi +CC := clang --target=arm-none-eabi #CC := arm-none-eabi-gcc OBJCOPY := arm-none-eabi-objcopy @@ -35,12 +27,6 @@ CFLAGS := \ -nostdlib \ --std=c2x -ifeq ($(DEBUG),true) -CFLAGS := \ - $(CFLAGS) \ - -D__agbx_dbg -endif - # HEADERS HDRS := \ @@ -51,12 +37,16 @@ HDRS := \ # BINARIES OBJS := \ + source/algo/cp.o \ source/bs/done.o \ source/bs/get.o \ source/bs/set.o \ + source/gfx/clrscrn.o \ source/gfx/flip.o \ + source/gfx/getvbnk.o \ source/gfx/plot.o \ source/gfx/setpx.o \ + source/gfx/vsync.o \ source/key/getkeymap.o \ source/priv/init.o diff --git a/agbx/include/agbx/algo.h b/agbx/include/agbx/algo.h new file mode 100644 index 0000000..c117e97 --- /dev/null +++ b/agbx/include/agbx/algo.h @@ -0,0 +1,14 @@ +/* + Copyright 2022 Gabriel Jensen. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +#if !defined(__agbx_hdr_algo) +#define __agbx_hdr_algo + +#include <agbx/bs.h> + +void agbx_cp(void const * src,agbx_i20 num,void * dest); + +#endif diff --git a/agbx/include/agbx/bs.h b/agbx/include/agbx/bs.h index 617e328..dde470b 100644 --- a/agbx/include/agbx/bs.h +++ b/agbx/include/agbx/bs.h @@ -18,15 +18,17 @@ typedef unsigned long long agbx_i40; typedef unsigned char agbx_i8; typedef enum { + agbx_err_ok = 0x0u, + agbx_err_badaddr, + agbx_err_badalgn, + agbx_err_badcol, agbx_err_badmd, - agbx_err_misc, - agbx_err_ok, agbx_err_pos2big, agbx_err_px2big, agbx_err_max = 0xFFu, } agbx_err; -constexpr agbx_i40 agbx_ver = 0x2u; +constexpr agbx_i40 agbx_ver = 0x3u; [[noreturn]] void agbx_done(agbx_err err); diff --git a/agbx/include/agbx/gfx.h b/agbx/include/agbx/gfx.h index 579e20a..2da8974 100644 --- a/agbx/include/agbx/gfx.h +++ b/agbx/include/agbx/gfx.h @@ -9,13 +9,19 @@ #include <agbx/bs.h> -agbx_i20 agbx_flip(void); +agbx_i20 agbx_flip( void); +agbx_i20 agbx_getvbnk(void); +void agbx_vsync( void); void agbx_setpx1(agbx_i20 vaddr,agbx_i10 px,agbx_i8 col); void agbx_setpx2(agbx_i20 vaddr,agbx_i10 px,agbx_i10 col); +void agbx_clrscrn3(agbx_i10 col); +void agbx_clrscrn4(agbx_i20 vaddr,agbx_i8 col); +void agbx_clrscrn5(agbx_i20 vaddr,agbx_i10 col); + agbx_i10 agbx_plot3(agbx_i8 x,agbx_i8 y,agbx_i10 col); -agbx_i10 agbx_plot4(agbx_i8 x,agbx_i8 y,agbx_i8 col); -agbx_i10 agbx_plot5(agbx_i8 x,agbx_i8 y,agbx_i10 col); +agbx_i10 agbx_plot4(agbx_i20 vaddr,agbx_i8 x,agbx_i8 y,agbx_i8 col); +agbx_i10 agbx_plot5(agbx_i20 vaddr,agbx_i8 x,agbx_i8 y,agbx_i10 col); #endif diff --git a/agbx/source/algo/cp.c b/agbx/source/algo/cp.c new file mode 100644 index 0000000..651abd8 --- /dev/null +++ b/agbx/source/algo/cp.c @@ -0,0 +1,16 @@ +/* + Copyright 2022 Gabriel Jensen. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +#include <agbx/priv.h> + +#include <agbx/algo.h> + +void agbx_cp(void const * const _src,agbx_i20 const _num,void * const _dest) { + unsigned char const * src = _src; + unsigned char * dest = _dest; + unsigned char const * const aftersrc = src + _num; + for (;src != aftersrc;++src,++dest) {*dest = *src;} +} diff --git a/agbx/source/bs/done.c b/agbx/source/bs/done.c index be8f423..8e3726d 100644 --- a/agbx/source/bs/done.c +++ b/agbx/source/bs/done.c @@ -11,7 +11,7 @@ void agbx_done(agbx_err const _err) { if (_err == agbx_err_ok) { __asm__ ( - "swi 0x3\n" + "svc 0x3\n" ); __builtin_unreachable(); } @@ -19,8 +19,11 @@ void agbx_done(agbx_err const _err) { agbx_set10(0x400'0000u,0x404u); agbx_set10(0x500'0000u,0x0u); agbx_set10(0x500'0002u,0x19u); - agbx_i8 err[0x8u]; + agbx_i8 err[0xBu]; for (agbx_i8 pos = 0x0u;pos != 0x8u;++pos) {err[pos] = (agbx_i8)_err >> pos & 0x1u;} + err[0x8u] = 0x0u; + err[0x9u] = 0x1u; + err[0xAu] = 0x0u; for (agbx_i10 pos = 0x0u;pos != 0x9600u;pos += 0xF0u) { agbx_setpx1(0x600'0000u,pos, err[0x0u]); agbx_setpx1(0x600'0000u,pos + 0x1u,err[0x1u]); @@ -30,12 +33,12 @@ void agbx_done(agbx_err const _err) { agbx_setpx1(0x600'0000u,pos + 0x5u,err[0x5u]); agbx_setpx1(0x600'0000u,pos + 0x6u,err[0x6u]); agbx_setpx1(0x600'0000u,pos + 0x7u,err[0x7u]); - agbx_setpx1(0x600'0000u,pos + 0x8u,0x0u); - agbx_setpx1(0x600'0000u,pos + 0x9u,0x1u); - agbx_setpx1(0x600'0000u,pos + 0xAu,0x0u); + agbx_setpx1(0x600'0000u,pos + 0x8u,err[0x8u]); + agbx_setpx1(0x600'0000u,pos + 0x9u,err[0x9u]); + agbx_setpx1(0x600'0000u,pos + 0xAu,err[0xAu]); } __asm__ ( - "swi 0x2\n" + "svc 0x2\n" ); for (;;) {} } diff --git a/agbx/source/gfx/clrscrn.c b/agbx/source/gfx/clrscrn.c new file mode 100644 index 0000000..157498c --- /dev/null +++ b/agbx/source/gfx/clrscrn.c @@ -0,0 +1,24 @@ +/* + Copyright 2022 Gabriel Jensen. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +#include <agbx/priv.h> + +#include <agbx/gfx.h> + +void agbx_clrscrn3(agbx_i10 const _col) { + agbx_i20 const val = _col | _col << 0x8u | _col << 0x10u | _col << 0x18u; + for (agbx_i20 addr = 0x400'0000u;addr != 0x401'2C00u;addr += 0x4u) {agbx_set20(addr,val);} +} + +void agbx_clrscrn4(agbx_i20 const _vaddr,agbx_i8 const _col) { + agbx_i20 const val = _col | _col << 0x8u | _col << 0x10u | _col << 0x18u; + for (agbx_i20 addr = _vaddr;addr != _vaddr + 0x9600u;addr += 0x4u) {agbx_set20(addr,val);} +} + +void agbx_clrscrn5(agbx_i20 const _vaddr,agbx_i10 const _col) { + agbx_i20 const val = _col | _col << 0x10u; + for (agbx_i20 addr = _vaddr;addr != _vaddr + 0xA000u;addr += 0x4u) {agbx_set20(addr,val);} +} diff --git a/agbx/source/gfx/flip.s b/agbx/source/gfx/flip.s index c2f4336..019289d 100644 --- a/agbx/source/gfx/flip.s +++ b/agbx/source/gfx/flip.s @@ -7,6 +7,8 @@ .cpu arm7tdmi .thumb +.extern __agbx_getvbnk + .globl agbx_flip .func @@ -14,19 +16,20 @@ .thumb_func agbx_flip: + @ Get the current value of dispcnt: ldr r0,.dispcntaddr - ldrh r1,[r0] @ Get the current value of dispcnt. - movs r2,#0b10000 - eors r1,r2 @ XOR bit five. - strh r1,[r0] @ Save dispcnt. - movs r0,#0x10 - tst r1,r0 @ Check what video bank we should return the address of. - beq .vbnk0 -.vbnk1: - ldr r0,.vbnk1addr - bx lr -.vbnk0: - ldr r0,.vbnk0addr + ldrh r1,[r0] + + @ XOR bit five: + movs r2,0b10000 + eors r1,r2 + + @ Save dispcnt: + strh r1,[r0] + + @ Get the address of the video bank: + b __agbx_getvbnk + bx lr .endfunc @@ -35,13 +38,3 @@ agbx_flip: .dispcntaddr: .long 0x4000000 - -.align - -.vbnk0addr: - .long 0x6000000 - -.align - -.vbnk1addr: - .long 0x600A000 diff --git a/agbx/source/gfx/getvbnk.s b/agbx/source/gfx/getvbnk.s new file mode 100644 index 0000000..e04a127 --- /dev/null +++ b/agbx/source/gfx/getvbnk.s @@ -0,0 +1,65 @@ +@ Copyright 2022 Gabriel Jensen. +@ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +@ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +.syntax unified + +.cpu arm7tdmi +.thumb + +.globl __agbx_getvbnk +.globl agbx_getvbnk + +.func + +.thumb_func + +agbx_getvbnk: + @ Get the current value of dispcnt: + ldr r0,.dispcntaddr + ldrh r1,[r0] + + @ Get the address: + b __agbx_getvbnk + + bx lr + +.endfunc + +.func + +.thumb_func + +__agbx_getvbnk: @ Takes the value of dispcnt in r1. + @ Check if the fifth bit is set: + movs r0,0b10000 + tst r1,r0 + + bne .vbnk1 + +.vbnk0: + @ Return the address of the first video bank: + ldr r0,.vbnk0addr + bx lr + +.vbnk1: + @ Return the address of the second video bank: + ldr r0,.vbnk1addr + bx lr + +.endfunc + +.align + +.dispcntaddr: + .long 0x4000000 + +.align + +.vbnk0addr: + .long 0x6000000 + +.align + +.vbnk1addr: + .long 0x600A000 diff --git a/agbx/source/gfx/plot.c b/agbx/source/gfx/plot.c index cc41d38..e23834c 100644 --- a/agbx/source/gfx/plot.c +++ b/agbx/source/gfx/plot.c @@ -9,30 +9,19 @@ #include <agbx/gfx.h> agbx_i10 agbx_plot3(agbx_i8 const _x,agbx_i8 const _y,agbx_i10 const _col) { -#if defined(__agbx_dbg) - if (_x >= 0xF0u || _y >= 0xA0u) {agbx_done(agbx_err_pos2big);} -#endif agbx_i10 const px = _y * 0xF0u + _x; __agbx_setpx2(0x600'0000u,px,_col) return px; } -agbx_i10 agbx_plot4(agbx_i8 const _x,agbx_i8 const _y,agbx_i8 const _col) { -#if defined(__agbx_dbg) - if (_x >= 0xF0u || _y >= 0xA0u) {agbx_done(agbx_err_pos2big);} -#endif - agbx_i20 const vaddr = 0x600'0000u + (agbx_get10(0x400'0000u) >> 0x4u & 0x1u) * 0xA000u; +agbx_i10 agbx_plot4(agbx_i20 const _vaddr,agbx_i8 const _x,agbx_i8 const _y,agbx_i8 const _col) { agbx_i10 const px = _y * 0xF0u + _x; - agbx_setpx1(vaddr,px,_col); + agbx_setpx1(_vaddr,px,_col); return px; } -agbx_i10 agbx_plot5(agbx_i8 const _x,agbx_i8 const _y,agbx_i10 const _col) { -#if defined(__agbx_dbg) - if (_x >= 0xA0u || _y >= 0x80u) {agbx_done(agbx_err_pos2big);} -#endif - agbx_i20 const vaddr = 0x600'0000u + (agbx_get10(0x400'0000u) >> 0x4u & 0x1u) * 0xA000u; +agbx_i10 agbx_plot5(agbx_i20 const _vaddr,agbx_i8 const _x,agbx_i8 const _y,agbx_i10 const _col) { agbx_i10 const px = _y * 0xF0u + _x; - __agbx_setpx2(vaddr,px,_col) + __agbx_setpx2(_vaddr,px,_col) return px; } diff --git a/agbx/source/gfx/setpx.c b/agbx/source/gfx/setpx.c index d7d3110..df3f0de 100644 --- a/agbx/source/gfx/setpx.c +++ b/agbx/source/gfx/setpx.c @@ -9,12 +9,6 @@ #include <agbx/gfx.h> void agbx_setpx1(agbx_i20 const _vaddr,agbx_i10 const _px,agbx_i8 const _col) { -#if defined(__agbx_dbg) - agbx_i10 const dispcnt = agbx_get10(0x400'0000u); - agbx_i8 const md = dispcnt & 0x7u; - if (md != 0x4u) {agbx_done(agbx_err_badmd);} - if (_px >= 0x9600u) {agbx_done(agbx_err_px2big);} -#endif /* We can only write halfwords to VRAM, so we load the adjacent pixel value and combine it into a halfword. */ agbx_i20 const addr = _vaddr + _px - (_px & 0x1u) * 0x1u; agbx_i10 col; @@ -24,17 +18,5 @@ void agbx_setpx1(agbx_i20 const _vaddr,agbx_i10 const _px,agbx_i8 const _col) { } void agbx_setpx2(agbx_i20 const _vaddr,agbx_i10 const _px,agbx_i10 const _col) { -#if defined(__agbx_dbg) - agbx_i10 const dispcnt = agbx_get10(0x400'0000u); - agbx_i8 const md = dispcnt & 0x7u; - if (md == 0x4u) {agbx_done(agbx_err_badmd);} - if (md == 0x5u) { - if (_px >= 0x5000u) {agbx_done(agbx_err_px2big);} - } - else { - if (md != 0x3u) {agbx_done(agbx_err_badmd);} - if (_px >= 0x9600u) {agbx_done(agbx_err_px2big);} - } -#endif __agbx_setpx2(_vaddr,_px,_col) } diff --git a/agbx/source/gfx/vsync.s b/agbx/source/gfx/vsync.s new file mode 100644 index 0000000..5bfbe06 --- /dev/null +++ b/agbx/source/gfx/vsync.s @@ -0,0 +1,38 @@ +@ Copyright 2022 Gabriel Jensen. +@ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +@ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +.syntax unified + +.cpu arm7tdmi +.thumb + +.globl agbx_vsync + +.func + +.thumb_func + +agbx_vsync: + @ Set the constants: + ldr r0,.scancnt @ Address of the scanline counter register. + movs r1,0xA0 @ Number of horizontal lines; + +.loop: + @ Check the scanline counter: + ldr r2,[r0] @ Load the counter. + cmp r2,r1 @ Check if it has reached the bottom. + beq .ret @ Return if so. + +.ret: + @ Return: + bx lr + +.endfunc + +.align + +.scancnt: + .long 0x4000000 + +.align diff --git a/agbx/source/key/getkeymap.s b/agbx/source/key/getkeymap.s index bb3638e..e433f04 100644 --- a/agbx/source/key/getkeymap.s +++ b/agbx/source/key/getkeymap.s @@ -14,8 +14,10 @@ .thumb_func agbx_getkeymap: + @ Load the keys: ldr r0,.addr ldrh r0,[r0] + bx lr .endfunc diff --git a/agbx/source/priv/init.s b/agbx/source/priv/init.s index ec0b6df..302cb29 100644 --- a/agbx/source/priv/init.s +++ b/agbx/source/priv/init.s @@ -17,7 +17,10 @@ .thumb_func __agbx_init: + @ Call main: bl agbx_main + + @ Call done: bl agbx_done @ The return value is already in r0, so there's no need to move it. .endfunc diff --git a/demo/GNUmakefile b/demo/GNUmakefile index 18d3083..076b19f 100644 --- a/demo/GNUmakefile +++ b/demo/GNUmakefile @@ -5,7 +5,7 @@ # TOOLS AS := arm-none-eabi-as -CC := clang -target arm-none-eabi +CC := clang --target=arm-none-eabi #CC := arm-none-eabi-gcc LD := arm-none-eabi-ld OBJCOPY := arm-none-eabi-objcopy @@ -29,13 +29,13 @@ OBJS := \ ROMHDR := hdr.o -BIN := demo.gba +IMG := demo.gba # TARGETS .PHONY: clean purge -$(BIN): $(ROMHDR) $(OBJS) +$(IMG): $(ROMHDR) $(OBJS) $(LD) -L../agbx -Tldscript -odemo.elf -znoexecstack $(^) -lagbx $(OBJCOPY) -Obinary demo.elf $(@) agbsum -psi$(@) @@ -44,5 +44,5 @@ clean: $(RM) $(OBJS) $(ROMHDR) demo.elf purge: clean - $(RM) $(BIN) + $(RM) $(IMG) diff --git a/demo/demo.c b/demo/demo.c index 94578f6..012e705 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -6,6 +6,8 @@ agbx_err agbx_main(void) { agbx_set10(0x500'0002u,0x19u); agbx_set10(0x500'0004u,0xFFFFu); agbx_set10(0x400'0000u,0x404u); + agbx_clrscrn4(0x600'0000u,0x0u); + agbx_clrscrn4(0x600'A000u,0x0u); agbx_i10 const cols[] = { 0b11111u, 0b1111100000u, @@ -17,7 +19,9 @@ agbx_err agbx_main(void) { agbx_i8 y; } pos = {.x = 0x0u,.y = 0x0u,}; agbx_setpx1(0x600'0000u,0x0u,0x2u); + agbx_i20 vaddr = 0x600'0000u; for (;;) { + agbx_vsync(); agbx_keymap const keymap = agbx_getkeymap(); if (agbx_chkkey(keymap,agbx_key_b)) { return (agbx_err)(((agbx_i10)pos.x + (agbx_i10)pos.y)/0x2u); @@ -26,9 +30,9 @@ agbx_err agbx_main(void) { return agbx_err_ok; } if (agbx_chkkey(keymap,agbx_key_l)) { - agbx_plot4(pos.x,pos.y,0x1u); - agbx_flip(); - agbx_plot4(pos.x,pos.y,0x2u); + agbx_plot4(vaddr,pos.x,pos.y,0x1u); + vaddr = agbx_flip(); + agbx_plot4(vaddr,pos.x,pos.y,0x2u); while (agbx_chkkey(agbx_getkeymap(),agbx_key_l)) {} continue; } @@ -70,8 +74,8 @@ agbx_err agbx_main(void) { } continue; drw:; - agbx_plot4(prevpos.x,prevpos.y,0x1u); - agbx_plot4(pos.x,pos.y,0x2u); + agbx_plot4(vaddr,prevpos.x,prevpos.y,0x1u); + agbx_plot4(vaddr,pos.x,pos.y,0x2u); while (agbx_chkkey(agbx_getkeymap(),key)) {} } } @@ -68,7 +68,7 @@ _start: @ We define this label to stop the linker from complaining .byte 0x0 @ Complement check (1) -@ Checksum of the header. Use agbhdrsum to patch this in the final image. +@ Checksum of the header. Use agbsum to patch this in the final image. .byte 0x0 @ Reserved area (2) |