diff options
author | Ben Bridle <ben@derelict.engineering> | 2024-11-18 14:57:19 +1300 |
---|---|---|
committer | Ben Bridle <ben@derelict.engineering> | 2024-11-18 14:57:19 +1300 |
commit | 722d5509178fa5bdaa488fbbd9196f21377f8775 (patch) | |
tree | 112b39cd80cb8e074d9e71d1def4d8de33c9eefa /arm9/source | |
download | bedrock-nds-722d5509178fa5bdaa488fbbd9196f21377f8775.zip |
Initial commit
Diffstat (limited to 'arm9/source')
-rw-r--r-- | arm9/source/bang.c | 51 | ||||
-rw-r--r-- | arm9/source/bang.h | 27 | ||||
-rw-r--r-- | arm9/source/core.c | 437 | ||||
-rw-r--r-- | arm9/source/core.h | 85 | ||||
-rw-r--r-- | arm9/source/devices/clock.c | 87 | ||||
-rw-r--r-- | arm9/source/devices/clock.h | 46 | ||||
-rw-r--r-- | arm9/source/devices/input.c | 59 | ||||
-rw-r--r-- | arm9/source/devices/input.h | 16 | ||||
-rw-r--r-- | arm9/source/devices/local.c | 0 | ||||
-rw-r--r-- | arm9/source/devices/local.h | 4 | ||||
-rw-r--r-- | arm9/source/devices/math.c | 66 | ||||
-rw-r--r-- | arm9/source/devices/math.h | 19 | ||||
-rw-r--r-- | arm9/source/devices/screen.c | 284 | ||||
-rw-r--r-- | arm9/source/devices/screen.h | 66 | ||||
-rw-r--r-- | arm9/source/devices/system.c | 0 | ||||
-rw-r--r-- | arm9/source/devices/system.h | 9 | ||||
-rw-r--r-- | arm9/source/main.c | 118 | ||||
-rw-r--r-- | arm9/source/main_debug.c | 24 | ||||
-rw-r--r-- | arm9/source/main_debug.h | 7 |
19 files changed, 1405 insertions, 0 deletions
diff --git a/arm9/source/bang.c b/arm9/source/bang.c new file mode 100644 index 0000000..8686dd3 --- /dev/null +++ b/arm9/source/bang.c @@ -0,0 +1,51 @@ +#include <nds.h> +#include "bang.h" + +static const u8 rev_lookup[] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; + +u8 rev(u8 x) { + return rev_lookup[x]; +} + +u8 shc(u8 x, u8 y) { + y = (u8)(RIGHT(y) - LEFT(y)) % 8; + return ((x >> y | (x << (8-y)))); +} + +u16 shcd(u16 x, u8 y) { + y = (u16)(RIGHT(y) - LEFT(y)) % 16; + return ((x >> y | (x << (16-y)))); +} diff --git a/arm9/source/bang.h b/arm9/source/bang.h new file mode 100644 index 0000000..1e13f9f --- /dev/null +++ b/arm9/source/bang.h @@ -0,0 +1,27 @@ +#ifndef BANG_H_ + #define BANG_H_ + + #define SET_HIGH(v,high) v = high << 8 | (v & 0x00ff) + #define SET_LOW(v,low) v = (v & 0xff00) | low + #define HIGH(v) (u8)((v) >> 8) + #define LOW(v) (u8)((v) ) + + #define H_HIGH(v) (u8)((v) >> 24) + #define H_LOW(v) (u8)((v) >> 16) + #define L_HIGH(v) (u8)((v) >> 8) + #define L_LOW(v) (u8)((v) ) + + #define LEFT(x) ((x) >> 4) + #define RIGHT(x) ((x) & 0xf) + + #define SHF(x,y) (x >> RIGHT(y) << LEFT(y)) + #define TAL(x) __builtin_popcount(x) + + #define TEST(x,m) ((x & m) == m) + #define BOOL(v) ((u8)-(v)) + #define DOUBLE(h,l) ((u16)(h) << 8 | (u16)(l)) + + u8 rev(u8 x); + u8 shc(u8 x, u8 y); + u16 shcd(u16 x, u8 y); +#endif diff --git a/arm9/source/core.c b/arm9/source/core.c new file mode 100644 index 0000000..cb112e0 --- /dev/null +++ b/arm9/source/core.c @@ -0,0 +1,437 @@ +#include <nds.h> +#include "bang.h" +#include "core.h" + + +void reset_br(Bedrock *br) { + *br = (Bedrock) {0}; +} + +// Load a program into an instance. +void start_br(Bedrock *br, u8 program[], int size) { + reset_br(br); + memcpy(&br->mem, program, size); + br->alive = TRUE; + br->awake = TRUE; + // br->scr.nds = &scr_main; +} + +void rouse_br(Bedrock *br) { + if (TEST(br->sys.sleep, 0x8000)) { // SYSTEM + br->awake = TRUE; + br->sys.wake = 0x0; + return; + } + if (TEST(br->sys.sleep, 0x0800)) { // INPUT + if (br->inp.wake) { + br->inp.wake = FALSE; + br->awake = TRUE; + br->sys.wake = 0x4; + return; + } + } + if (TEST(br->sys.sleep, 0x1000)) { // CLOCK + if (check_timers(&br->clk)) { + br->awake = TRUE; + br->sys.wake = 0x3; + return; + } + } +} + +u8 dev_read(Bedrock *br, u8 port) { + switch(port) { +// SYSTEM DEVICE + // TODO: name and author + case 0x02: return 0x00; // program memory size + case 0x03: return 0x00; // program memory size + case 0x04: return 0x00; // working stack size + case 0x05: return 0x00; // return stack size + case 0x06: return 0xbc; + case 0x07: return 0x00; + + // TODO: available devices + case 0x0A: return br->sys.wake; + +// MATH DEVICE + case 0x20: return HIGH(br->math.op1); + case 0x21: return LOW(br->math.op1); + case 0x22: return HIGH(br->math.op2); + case 0x23: return LOW(br->math.op2); + case 0x24: return HIGH(get_sqrt(&br->math)); + case 0x25: return LOW(get_sqrt(&br->math)); + case 0x26: return HIGH(get_atan(&br->math)); + case 0x27: return LOW(get_atan(&br->math)); + case 0x28: return H_HIGH(get_prod(&br->math)); + case 0x29: return H_LOW(get_prod(&br->math)); + case 0x2A: return L_HIGH(get_prod(&br->math)); + case 0x2B: return L_LOW(get_prod(&br->math)); + case 0x2C: return HIGH(get_quot(&br->math)); + case 0x2D: return LOW(get_quot(&br->math)); + case 0x2E: return HIGH( get_rem(&br->math)); + case 0x2F: return LOW( get_rem(&br->math)); +// CLOCK DEVICE + case 0x30: return YEAR(get_datetime()); + case 0x31: return MONTH(get_datetime()); + case 0x32: return DAY(get_datetime()); + case 0x33: return HOUR(get_datetime()); + case 0x34: return MINUTE(get_datetime()); + case 0x35: return SECOND(get_datetime()); + case 0x36: return HIGH(get_uptime()-br->clk.start); + case 0x37: return LOW(get_uptime()-br->clk.start); + case 0x38: return get_timer1_high(&br->clk); + case 0x39: return get_timer1_low( &br->clk); + case 0x3A: return get_timer2_high(&br->clk); + case 0x3B: return get_timer2_low( &br->clk); + case 0x3C: return get_timer3_high(&br->clk); + case 0x3D: return get_timer3_low( &br->clk); + case 0x3E: return get_timer4_high(&br->clk); + case 0x3F: return get_timer4_low( &br->clk); +// INPUT DEVICE + case 0x40: return BOOL(br->inp.pointer); + case 0x41: return br->inp.pointer << 7; + case 0x44: return HIGH(br->inp.x); + case 0x45: return LOW(br->inp.x); + case 0x46: return HIGH(br->inp.y); + case 0x47: return LOW(br->inp.y); + case 0x48: return BOOL(br->inp.keyboard); + // TODO: Keyboard input + case 0x4A: return br->inp.navigation; + case 0x4C: return br->inp.gamepad; +// SCREEN DEVICE + case 0x50: return HIGH(PIXELS_WIDTH); + case 0x51: return LOW(PIXELS_WIDTH); + case 0x52: return HIGH(PIXELS_HEIGHT); + case 0x53: return LOW(PIXELS_HEIGHT); + case 0x54: return HIGH(br->scr.x); + case 0x55: return LOW(br->scr.x); + case 0x56: return HIGH(br->scr.y); + case 0x57: return LOW(br->scr.y); + + default: return 0; + } +} + +Signal dev_write(Bedrock *br, u8 port, u8 v) { + switch(port) { +// SYSTEM DEVICE + case 0x08: SET_HIGH(br->sys.sleep,v); return 0; + case 0x09: SET_LOW(br->sys.sleep,v); return SIG_SLEEP; +// MATH DEVICE + case 0x20: set_op1_high(&br->math,v); return 0; + case 0x21: set_op1_low( &br->math,v); return 0; + case 0x22: set_op2_high(&br->math,v); return 0; + case 0x23: set_op2_low( &br->math,v); return 0; +// CLOCK DEVICE + // TODO: Set time and date + case 0x38: set_timer1_high(&br->clk,v); return 0; + case 0x39: set_timer1_low( &br->clk,v); return 0; + case 0x3A: set_timer2_high(&br->clk,v); return 0; + case 0x3B: set_timer2_low( &br->clk,v); return 0; + case 0x3C: set_timer3_high(&br->clk,v); return 0; + case 0x3D: set_timer3_low( &br->clk,v); return 0; + case 0x3E: set_timer4_high(&br->clk,v); return 0; + case 0x3F: set_timer4_low( &br->clk,v); return 0; +// SCREEN DEVICE + case 0x54: SET_HIGH(br->scr.x,v); return 0; + case 0x55: SET_LOW( br->scr.x,v); return 0; + case 0x56: SET_HIGH(br->scr.y,v); return 0; + case 0x57: SET_LOW( br->scr.y,v); return 0; + case 0x58: set_palette_high(&br->scr,v); return 0; + case 0x59: set_palette_low( &br->scr,v); return 0; + case 0x5A: SET_HIGH(br->scr.colours,v); return 0; + case 0x5B: SET_LOW( br->scr.colours,v); return 0; + case 0x5C: push_sprite(&br->scr.sprite,v); return 0; + case 0x5D: push_sprite(&br->scr.sprite,v); return 0; + case 0x5E: draw_dispatch(&br->scr,v); return 0; + case 0x5F: move_cursor(&br->scr,v); return 0; +// LOCAL DEVICE + case 0x86: printf("%c", v); return 0; + case 0x87: printf("%c", v); return 0; + + default: return SIG_NONE; + } +} + +Signal dev_write_16(Bedrock *br, u8 port, u8 high, u8 low) { + Signal s1 = dev_write(br, port, high); + Signal s2 = dev_write(br, port+1, low); + if (s1) { return s1; } else { return s2; } +} + +Signal evaluate(Bedrock *br, u16 count) { + #define SIGNAL(s) if (s) { return s; } else { continue; }; + + register u8 a, b, c, d, e, f; + register u16 x, y; + register Signal sig; + + for (u16 i=0; i < count; i++) { + switch (MLIT) { +/* HLT */ case 0x00: return SIG_HALT; +/* JMP */ case 0x01: WPOP2(a,b); PC=DOUBLE(a,b); continue; +/* JCN */ case 0x02: WPOP2(b,c); WPOP1(a); if(a) PC=DOUBLE(b,c); continue; +/* JCK */ case 0x03: WPOP2(b,c); WGET1(a); if(a) PC=DOUBLE(b,c); continue; +/* LDA */ case 0x04: WPOP2(a,b); x=DOUBLE(a,b); WPSH1(MEM[x]); continue; +/* STA */ case 0x05: WPOPD(x); WPOP1(a); MEM[x]=a; continue; +/* LDD */ case 0x06: WPOP1(a); WPSH1(dev_read(br,a)); continue; +/* STD */ case 0x07: WPOP1(b); WPOP1(a); sig=dev_write(br,b,a); SIGNAL(sig); +/* PSH */ case 0x08: RPOP1(a); WPSH1(a); continue; +/* POP */ case 0x09: WST.p-=1; continue; +/* CPY */ case 0x0A: RGET1(a); WPSH1(a); continue; +/* SPL */ case 0x0B: WPOP1(a); WPSH2(LEFT(a),RIGHT(a)); continue; +/* DUP */ case 0x0C: WGET1(a); WPSH1(a); continue; +/* OVR */ case 0x0D: WPOP1(b); WGET1(a); WPSH1(b); WPSH1(a); continue; +/* SWP */ case 0x0E: WPOP1(b); WPOP1(a); WPSH1(b); WPSH1(a); continue; +/* ROT */ case 0x0F: WPOP1(c); WPOP1(b); WPOP1(a); WPSH1(b); WPSH1(c); WPSH1(a); continue; +/* ADD */ case 0x10: WPOP1(b); WSTV(-1)+=b; continue; +/* SUB */ case 0x11: WPOP1(b); WSTV(-1)-=b; continue; +/* INC */ case 0x12: WSTV(-1)+=1; continue; +/* DEC */ case 0x13: WSTV(-1)-=1; continue; +/* LTH */ case 0x14: WPOP1(b); WPOP1(a); WPSH1(BOOL(a<b)); continue; +/* GTH */ case 0x15: WPOP1(b); WPOP1(a); WPSH1(BOOL(a>b)); continue; +/* EQU */ case 0x16: WPOP1(b); WPOP1(a); WPSH1(BOOL(a==b)); continue; +/* NQK */ case 0x17: b=WSTV(-1); a=WSTV(-2); WPSH1(BOOL(a!=b)); continue; +/* IOR */ case 0x18: WPOP1(b); WSTV(-1)|=b; continue; +/* XOR */ case 0x19: WPOP1(b); WSTV(-1)^=b; continue; +/* AND */ case 0x1A: WPOP1(b); WSTV(-1)&=b; continue; +/* NOT */ case 0x1B: WSTV(-1)=~WSTV(-1); continue; +/* SHF */ case 0x1C: WPOP1(b); WPOP1(a); x=SHF(a,b); WPSH1(x); continue; +/* SHC */ case 0x1D: WPOP1(b); WPOP1(a); x=shc(a,b); WPSH1(x); continue; +/* TAL */ case 0x1E: WSTV(-1)=TAL(WSTV(-1)); continue; +/* REV */ case 0x1F: WSTV(-1)=rev(WSTV(-1)); continue; + +/* NOP */ case 0x20: continue; +/* JMS */ case 0x21: WPOP2(a,b); RPSHD(PC); PC=DOUBLE(a,b); continue; +/* JCS */ case 0x22: WPOP2(b,c); WPOP1(a); if(a) {RPSHD(PC); PC=DOUBLE(b,c);} continue; +/* JCK* */ case 0x23: WPOP2(c,d); WGETD(x); if(x) {PC=DOUBLE(c,d);} continue; +/* LDA* */ case 0x24: WPOP2(a,b); x=DOUBLE(a,b); WPSH1(MEM[x]); WPSH1(MEM[x+1]); continue; +/* STA* */ case 0x25: WPOPD(x); WPOP2(a,b); MEM[x]=a; MEM[x+1]=b; continue; +/* LDD* */ case 0x26: WPOP1(a); WPSH1(dev_read(br,a)); WPSH1(dev_read(br,a+1)); continue; +/* STD* */ case 0x27: WPOP1(c); WPOP2(a,b); sig=dev_write_16(br,c,a,b); SIGNAL(sig); +/* PSH* */ case 0x28: RPOP2(a,b); WPSH2(a,b); continue; +/* POP* */ case 0x29: WST.p-=2; continue; +/* CPY* */ case 0x2A: RGET2(a,b); WPSH2(a,b); continue; +/* SPL* */ case 0x2B: WPOP2(a,b); WPSH2(LEFT(a),RIGHT(a)); WPSH2(LEFT(b),RIGHT(b)); continue; +/* DUP* */ case 0x2C: WGET2(a,b); WPSH2(a,b); continue; +/* OVR* */ case 0x2D: WPOP2(c,d); WGET2(a,b); WPSH2(c,d); WPSH2(a,b); continue; +/* SWP* */ case 0x2E: WPOP2(c,d); WPOP2(a,b); WPSH2(c,d); WPSH2(a,b); continue; +/* ROT* */ case 0x2F: WPOP2(e,f); WPOP2(c,d); WPOP2(a,b); WPSH2(c,d); WPSH2(e,f); WPSH2(a,b); continue; +/* ADD* */ case 0x30: WPOPD(y); WPOPD(x); WPSHD(x+y); continue; +/* SUB* */ case 0x31: WPOPD(y); WPOPD(x); WPSHD(x-y); continue; +/* INC* */ case 0x32: WPOPD(x); WPSHD(x+1); continue; +/* DEC* */ case 0x33: WPOPD(x); WPSHD(x-1); continue; +/* LTH* */ case 0x34: WPOPD(y); WPOPD(x); WPSH1(BOOL(x<y)); continue; +/* GTH* */ case 0x35: WPOPD(y); WPOPD(x); WPSH1(BOOL(x>y)); continue; +/* EQU* */ case 0x36: WPOP2(c,d); WPOP2(a,b); WPSH1(BOOL(a==c && b==d)); continue; +/* NQK* */ case 0x37: d=WSTV(-1); c=WSTV(-2); b=WSTV(-3); a=WSTV(-4); WPSH1(BOOL(a!=c || b!=d)); continue; +/* IOR* */ case 0x38: WPOP2(c,d); WSTV(-1)|=d; WSTV(-2)|=c; continue; +/* XOR* */ case 0x39: WPOP2(c,d); WSTV(-1)^=d; WSTV(-2)^=c; continue; +/* AND* */ case 0x3A: WPOP2(c,d); WSTV(-1)&=d; WSTV(-2)&=c; continue; +/* NOT* */ case 0x3B: WSTV(-1)=~WSTV(-1); WSTV(-2)=~WSTV(-2); continue; +/* SHF* */ case 0x3C: WPOP1(c); WPOPD(x); x=SHF(x,c); WPSHD(x); continue; +/* SHC* */ case 0x3D: WPOP1(c); WPOPD(x); x=shcd(x,c); WPSHD(x); continue; +/* TAL* */ case 0x3E: WPOP2(a,b); WPSH1(TAL(a)+TAL(b)); continue; +/* REV* */ case 0x3F: WPOP2(a,b); WPSH1(rev(b)); WPSH1(rev(a)); continue; + +/* DB1 */ case 0x40: return SIG_DB1; +/* JMP: */ case 0x41: MLIT2(a,b); PC=DOUBLE(a,b); continue; +/* JCN: */ case 0x42: MLIT2(b,c); WPOP1(a); if(a) PC=DOUBLE(b,c); continue; +/* JCK: */ case 0x43: MLIT2(b,c); WGET1(a); if(a) PC=DOUBLE(b,c); continue; +/* LDA: */ case 0x44: MLIT2(a,b); x=DOUBLE(a,b); WPSH1(MEM[x]); continue; +/* STA: */ case 0x45: MLITD(x); WPOP1(a); MEM[x]=a; continue; +/* LDD: */ case 0x46: MLIT1(a); WPSH1(dev_read(br,a)); continue; +/* STD: */ case 0x47: MLIT1(b); WPOP1(a); sig=dev_write(br,b,a); SIGNAL(sig); +/* PSH: */ case 0x48: MLIT1(a); WPSH1(a); continue; +/* POP: */ case 0x49: PC+=1; continue; +/* CPY: */ case 0x4A: MLIT1(a); RPSH1(a); WPSH1(a); continue; +/* SPL: */ case 0x4B: MLIT1(a); WPSH2(LEFT(a),RIGHT(a)); continue; +/* DUP: */ case 0x4C: MLIT1(a); WPSH1(a); WPSH1(a); continue; +/* OVR: */ case 0x4D: MLIT1(b); WGET1(a); WPSH1(b); WPSH1(a); continue; +/* SWP: */ case 0x4E: MLIT1(b); WPOP1(a); WPSH1(b); WPSH1(a); continue; +/* ROT: */ case 0x4F: MLIT1(c); WPOP1(b); WPOP1(a); WPSH1(b); WPSH1(c); WPSH1(a); continue; +/* ADD: */ case 0x50: MLIT1(b); WSTV(-1)+=b; continue; +/* SUB: */ case 0x51: MLIT1(b); WSTV(-1)-=b; continue; +/* INC: */ case 0x52: MLIT1(a); WPSH1(a+1); continue; +/* DEC: */ case 0x53: MLIT1(a); WPSH1(a-1); continue; +/* LTH: */ case 0x54: MLIT1(b); WPOP1(a); WPSH1(BOOL(a<b)); continue; +/* GTH: */ case 0x55: MLIT1(b); WPOP1(a); WPSH1(BOOL(a>b)); continue; +/* EQU: */ case 0x56: MLIT1(b); WPOP1(a); WPSH1(BOOL(a==b)); continue; +/* NQK: */ case 0x57: MLIT1(b); WGET1(a); WPSH1(b); WPSH1(BOOL(a!=b)); continue; +/* IOR: */ case 0x58: MLIT1(b); WSTV(-1)|=b; continue; +/* XOR: */ case 0x59: MLIT1(b); WSTV(-1)^=b; continue; +/* AND: */ case 0x5A: MLIT1(b); WSTV(-1)&=b; continue; +/* NOT: */ case 0x5B: MLIT1(a); WPSH1(~a); continue; +/* SHF: */ case 0x5C: MLIT1(b); WPOP1(a); x=SHF(a,b); WPSH1(x); continue; +/* SHC: */ case 0x5D: MLIT1(b); WPOP1(a); x=shc(a,b); WPSH1(x); continue; +/* TAL: */ case 0x5E: MLIT1(a); WPSH1(TAL(a)); continue; +/* REV: */ case 0x5F: MLIT1(a); WPSH1(rev(a)); continue; + +/* DB2 */ case 0x60: return SIG_DB2; +/* JMS: */ case 0x61: MLIT2(a,b); RPSHD(PC); PC=DOUBLE(a,b); continue; +/* JCS: */ case 0x62: MLIT2(b,c); WPOP1(a); if(a) {RPSHD(PC); PC=DOUBLE(b,c);} continue; +/* JCK:* */ case 0x63: MLIT2(c,d); WGETD(x); if(x) {PC=DOUBLE(c,d);} continue; +/* LDA:* */ case 0x64: MLIT2(a,b); x=DOUBLE(a,b); WPSH1(MEM[x]); WPSH1(MEM[x+1]); continue; +/* STA:* */ case 0x65: MLITD(x); WPOP2(a,b); MEM[x]=a; MEM[x+1]=b; continue; +/* LDD:* */ case 0x66: MLIT1(a); WPSH1(dev_read(br,a)); WPSH1(dev_read(br,a+1)); continue; +/* STD:* */ case 0x67: MLIT1(c); WPOP2(a,b); sig=dev_write_16(br,c,a,b); SIGNAL(sig); +/* PSH:* */ case 0x68: MLIT2(a,b); WPSH2(a,b); continue; +/* POP:* */ case 0x69: PC+=2; continue; +/* CPY:* */ case 0x6A: MLIT2(a,b); RPSH2(a,b); WPSH2(a,b); continue; +/* SPL:* */ case 0x6B: MLIT2(a,b); WPSH2(LEFT(a),RIGHT(a)); WPSH2(LEFT(b),RIGHT(b)); continue; +/* DUP:* */ case 0x6C: MLIT2(a,b); WPSH2(a,b); WPSH2(a,b); continue; +/* OVR:* */ case 0x6D: MLIT2(c,d); WGET2(a,b); WPSH2(c,d); WPSH2(a,b); continue; +/* SWP:* */ case 0x6E: MLIT2(c,d); WPOP2(a,b); WPSH2(c,d); WPSH2(a,b); continue; +/* ROT:* */ case 0x6F: MLIT2(e,f); WPOP2(c,d); WPOP2(a,b); WPSH2(c,d); WPSH2(e,f); WPSH2(a,b); continue; +/* ADD:* */ case 0x70: MLITD(y); WPOPD(x); WPSHD(x+y); continue; +/* SUB:* */ case 0x71: MLITD(y); WPOPD(x); WPSHD(x-y); continue; +/* INC:* */ case 0x72: MLITD(x); WPSHD(x+1); continue; +/* DEC:* */ case 0x73: MLITD(x); WPSHD(x-1); continue; +/* LTH:* */ case 0x74: MLITD(y); WPOPD(x); WPSH1(BOOL(x<y)); continue; +/* GTH:* */ case 0x75: MLITD(y); WPOPD(x); WPSH1(BOOL(x>y)); continue; +/* EQU:* */ case 0x76: MLIT2(c,d); WPOP2(a,b); WPSH1(BOOL(a==c && b==d)); continue; +/* NQK:* */ case 0x77: MLIT2(c,d); WGET2(a,b); WPSH2(c,d); WPSH1(BOOL(a!=c || b!=d)); continue; +/* IOR:* */ case 0x78: MLIT2(c,d); WSTV(-1)|=d; WSTV(-2)|=c; continue; +/* XOR:* */ case 0x79: MLIT2(c,d); WSTV(-1)^=d; WSTV(-2)^=c; continue; +/* AND:* */ case 0x7A: MLIT2(c,d); WSTV(-1)&=d; WSTV(-2)&=c; continue; +/* NOT:* */ case 0x7B: MLIT2(a,b); WPSH2(~a,~b); continue; +/* SHF:* */ case 0x7C: MLIT1(c); WPOPD(x); x=SHF(x,c); WPSHD(x); continue; +/* SHC:* */ case 0x7D: MLIT1(c); WPOPD(x); x=shcd(x,c); WPSHD(x); continue; +/* TAL:* */ case 0x7E: MLIT2(a,b); WPSH1(TAL(a)+TAL(b)); continue; +/* REV:* */ case 0x7F: MLIT2(a,b); WPSH1(rev(b)); WPSH1(rev(a)); continue; + +/* DB3 */ case 0x80: return SIG_DB3; +/* JMPr */ case 0x81: RPOP2(a,b); PC=DOUBLE(a,b); continue; +/* JCNr */ case 0x82: RPOP2(b,c); RPOP1(a); if(a) PC=DOUBLE(b,c); continue; +/* JCKr */ case 0x83: RPOP2(b,c); RGET1(a); if(a) PC=DOUBLE(b,c); continue; +/* LDAr */ case 0x84: RPOP2(a,b); x=DOUBLE(a,b); RPSH1(MEM[x]); continue; +/* STAr */ case 0x85: RPOPD(x); RPOP1(a); MEM[x]=a; continue; +/* LDDr */ case 0x86: RPOP1(a); RPSH1(dev_read(br,a)); continue; +/* STDr */ case 0x87: RPOP1(b); RPOP1(a); sig=dev_write(br,b,a); SIGNAL(sig); +/* PSHr */ case 0x88: WPOP1(a); RPSH1(a); continue; +/* POPr */ case 0x89: RST.p-=1; continue; +/* CPYr */ case 0x8A: WGET1(a); RPSH1(a); continue; +/* SPLr */ case 0x8B: RPOP1(a); RPSH2(LEFT(a),RIGHT(a)); continue; +/* DUPr */ case 0x8C: RGET1(a); RPSH1(a); continue; +/* OVRr */ case 0x8D: RPOP1(b); RGET1(a); RPSH1(b); RPSH1(a); continue; +/* SWPr */ case 0x8E: RPOP1(b); RPOP1(a); RPSH1(b); RPSH1(a); continue; +/* ROTr */ case 0x8F: RPOP1(c); RPOP1(b); RPOP1(a); RPSH1(b); RPSH1(c); RPSH1(a); continue; +/* ADDr */ case 0x90: RPOP1(b); RSTV(-1)+=b; continue; +/* SUBr */ case 0x91: RPOP1(b); RSTV(-1)-=b; continue; +/* INCr */ case 0x92: RSTV(-1)+=1; continue; +/* DECr */ case 0x93: RSTV(-1)-=1; continue; +/* LTHr */ case 0x94: RPOP1(b); RPOP1(a); RPSH1(BOOL(a<b)); continue; +/* GTHr */ case 0x95: RPOP1(b); RPOP1(a); RPSH1(BOOL(a>b)); continue; +/* EQUr */ case 0x96: RPOP1(b); RPOP1(a); RPSH1(BOOL(a==b)); continue; +/* NQKr */ case 0x97: b=RSTV(-1); a=RSTV(-2); RPSH1(BOOL(a!=b)); continue; +/* IORr */ case 0x98: RPOP1(b); RSTV(-1)|=b; continue; +/* XORr */ case 0x99: RPOP1(b); RSTV(-1)^=b; continue; +/* ANDr */ case 0x9A: RPOP1(b); RSTV(-1)&=b; continue; +/* NOTr */ case 0x9B: RSTV(-1)=~RSTV(-1); continue; +/* SHFr */ case 0x9C: RPOP1(b); RPOP1(a); x=SHF(a,b); RPSH1(x); continue; +/* SHCr */ case 0x9D: RPOP1(b); RPOP1(a); x=shc(a,b); RPSH1(x); continue; +/* TALr */ case 0x9E: RSTV(-1)=TAL(RSTV(-1)); continue; +/* REVr */ case 0x9F: RSTV(-1)=rev(RSTV(-1)); continue; + +/* DB4 */ case 0xA0: return SIG_DB4; +/* JMSr */ case 0xA1: RPOP2(a,b); WPSHD(PC); PC=DOUBLE(a,b); continue; +/* JCSr */ case 0xA2: RPOP2(b,c); RPOP1(a); if(a) {WPSHD(PC); PC=DOUBLE(b,c);} continue; +/* JCKr* */ case 0xA3: RPOP2(c,d); RGETD(x); if(x) {PC=DOUBLE(c,d);} continue; +/* LDAr* */ case 0xA4: RPOP2(a,b); x=DOUBLE(a,b); RPSH1(MEM[x]); RPSH1(MEM[x+1]); continue; +/* STAr* */ case 0xA5: RPOPD(x); RPOP2(a,b); MEM[x]=a; MEM[x+1]=b; continue; +/* LDDr* */ case 0xA6: RPOP1(a); RPSH1(dev_read(br,a)); RPSH1(dev_read(br,a+1)); continue; +/* STDr* */ case 0xA7: RPOP1(c); RPOP2(a,b); sig=dev_write_16(br,c,a,b); SIGNAL(sig); +/* PSHr* */ case 0xA8: WPOP2(a,b); RPSH2(a,b); continue; +/* POPr* */ case 0xA9: RST.p-=2; continue; +/* CPYr* */ case 0xAA: WGET2(a,b); RPSH2(a,b); continue; +/* SPLr* */ case 0xAB: RPOP2(a,b); RPSH2(LEFT(a),RIGHT(a)); RPSH2(LEFT(b),RIGHT(b)); continue; +/* DUPr* */ case 0xAC: RGET2(a,b); RPSH2(a,b); continue; +/* OVRr* */ case 0xAD: RPOP2(c,d); RGET2(a,b); RPSH2(c,d); RPSH2(a,b); continue; +/* SWPr* */ case 0xAE: RPOP2(c,d); RPOP2(a,b); RPSH2(c,d); RPSH2(a,b); continue; +/* ROTr* */ case 0xAF: RPOP2(e,f); RPOP2(c,d); RPOP2(a,b); RPSH2(c,d); RPSH2(e,f); RPSH2(a,b); continue; +/* ADDr* */ case 0xB0: RPOPD(y); RPOPD(x); RPSHD(x+y); continue; +/* SUBr* */ case 0xB1: RPOPD(y); RPOPD(x); RPSHD(x-y); continue; +/* INCr* */ case 0xB2: RPOPD(x); RPSHD(x+1); continue; +/* DECr* */ case 0xB3: RPOPD(x); RPSHD(x-1); continue; +/* LTHr* */ case 0xB4: RPOPD(y); RPOPD(x); RPSH1(BOOL(x<y)); continue; +/* GTHr* */ case 0xB5: RPOPD(y); RPOPD(x); RPSH1(BOOL(x>y)); continue; +/* EQUr* */ case 0xB6: RPOP2(c,d); RPOP2(a,b); RPSH1(BOOL(a==c && b==d)); continue; +/* NQKr* */ case 0xB7: d=RSTV(-1); c=RSTV(-2); b=RSTV(-3); a=RSTV(-4); RPSH1(BOOL(a!=c || b!=d)); continue; +/* IORr* */ case 0xB8: RPOP2(c,d); RSTV(-1)|=d; RSTV(-2)|=c; continue; +/* XORr* */ case 0xB9: RPOP2(c,d); RSTV(-1)^=d; RSTV(-2)^=c; continue; +/* ANDr* */ case 0xBA: RPOP2(c,d); RSTV(-1)&=d; RSTV(-2)&=c; continue; +/* NOTr* */ case 0xBB: RSTV(-1)=~RSTV(-1); RSTV(-2)=~RSTV(-2); continue; +/* SHFr* */ case 0xBC: RPOP1(c); RPOPD(x); x=SHF(x,c); RPSHD(x); continue; +/* SHCr* */ case 0xBD: RPOP1(c); RPOPD(x); x=shcd(x,c); RPSHD(x); continue; +/* TALr* */ case 0xBE: RPOP2(a,b); RPSH1(TAL(a)+TAL(b)); continue; +/* REVr* */ case 0xBF: RPOP2(a,b); RPSH1(rev(b)); RPSH1(rev(a)); continue; + +/* DB5 */ case 0xC0: return SIG_DB5; +/* JMPr: */ case 0xC1: MLIT2(a,b); PC=DOUBLE(a,b); continue; +/* JCNr: */ case 0xC2: MLIT2(b,c); RPOP1(a); if(a) PC=DOUBLE(b,c); continue; +/* JCKr: */ case 0xC3: MLIT2(b,c); RGET1(a); if(a) PC=DOUBLE(b,c); continue; +/* LDAr: */ case 0xC4: MLIT2(a,b); x=DOUBLE(a,b); RPSH1(MEM[x]); continue; +/* STAr: */ case 0xC5: MLITD(x); RPOP1(a); MEM[x]=a; continue; +/* LDDr: */ case 0xC6: MLIT1(a); RPSH1(dev_read(br,a)); continue; +/* STDr: */ case 0xC7: MLIT1(b); RPOP1(a); sig=dev_write(br,b,a); SIGNAL(sig); +/* PSHr: */ case 0xC8: MLIT1(a); RPSH1(a); continue; +/* POPr: */ case 0xC9: PC+=1; continue; +/* CPYr: */ case 0xCA: MLIT1(a); WPSH1(a); RPSH1(a); continue; +/* SPLr: */ case 0xCB: MLIT1(a); RPSH2(LEFT(a),RIGHT(a)); continue; +/* DUPr: */ case 0xCC: MLIT1(a); RPSH1(a); RPSH1(a); continue; +/* OVRr: */ case 0xCD: MLIT1(b); RGET1(a); RPSH1(b); RPSH1(a); continue; +/* SWPr: */ case 0xCE: MLIT1(b); RPOP1(a); RPSH1(b); RPSH1(a); continue; +/* ROTr: */ case 0xCF: MLIT1(c); RPOP1(b); RPOP1(a); RPSH1(b); RPSH1(c); RPSH1(a); continue; +/* ADDr: */ case 0xD0: MLIT1(b); RSTV(-1)+=b; continue; +/* SUBr: */ case 0xD1: MLIT1(b); RSTV(-1)-=b; continue; +/* INCr: */ case 0xD2: MLIT1(a); RPSH1(a+1); continue; +/* DECr: */ case 0xD3: MLIT1(a); RPSH1(a-1); continue; +/* LTHr: */ case 0xD4: MLIT1(b); RPOP1(a); RPSH1(BOOL(a<b)); continue; +/* GTHr: */ case 0xD5: MLIT1(b); RPOP1(a); RPSH1(BOOL(a>b)); continue; +/* EQUr: */ case 0xD6: MLIT1(b); RPOP1(a); RPSH1(BOOL(a==b)); continue; +/* NQKr: */ case 0xD7: MLIT1(b); RGET1(a); RPSH1(b); RPSH1(BOOL(a!=b)); continue; +/* IORr: */ case 0xD8: MLIT1(b); RSTV(-1)|=b; continue; +/* XORr: */ case 0xD9: MLIT1(b); RSTV(-1)^=b; continue; +/* ANDr: */ case 0xDA: MLIT1(b); RSTV(-1)&=b; continue; +/* NOTr: */ case 0xDB: MLIT1(a); RPSH1(~a); continue; +/* SHFr: */ case 0xDC: MLIT1(b); RPOP1(a); x=SHF(a,b); RPSH1(x); continue; +/* SHCr: */ case 0xDD: MLIT1(b); RPOP1(a); x=shc(a,b); RPSH1(x); continue; +/* TALr: */ case 0xDE: MLIT1(a); RPSH1(TAL(a)); continue; +/* REVr: */ case 0xDF: MLIT1(a); RPSH1(rev(a)); continue; + +/* DB6 */ case 0xE0: return SIG_DB6; +/* JMSr */ case 0xE1: MLIT2(a,b); WPSHD(PC); PC=DOUBLE(a,b); continue; +/* JCSr */ case 0xE2: MLIT2(b,c); RPOP1(a); if(a) {WPSHD(PC); PC=DOUBLE(b,c);} continue; +/* JCKr* */ case 0xE3: MLIT2(c,d); RGETD(x); if(x) {PC=DOUBLE(c,d);} continue; +/* LDAr* */ case 0xE4: MLIT2(a,b); x=DOUBLE(a,b); RPSH1(MEM[x]); RPSH1(MEM[x+1]); continue; +/* STAr* */ case 0xE5: MLITD(x); RPOP2(a,b); MEM[x]=a; MEM[x+1]=b; continue; +/* LDDr* */ case 0xE6: MLIT1(a); RPSH1(dev_read(br,a)); RPSH1(dev_read(br,a+1)); continue; +/* STDr* */ case 0xE7: MLIT1(c); RPOP2(a,b); sig=dev_write_16(br,c,a,b); SIGNAL(sig); +/* PSHr* */ case 0xE8: MLIT2(a,b); RPSH2(a,b); continue; +/* POPr* */ case 0xE9: PC+=2; continue; +/* CPYr* */ case 0xEA: MLIT2(a,b); WPSH2(a,b); RPSH2(a,b); continue; +/* SPLr* */ case 0xEB: MLIT2(a,b); RPSH2(LEFT(a),RIGHT(a)); RPSH2(LEFT(b),RIGHT(b)); continue; +/* DUPr* */ case 0xEC: MLIT2(a,b); RPSH2(a,b); RPSH2(a,b); continue; +/* OVRr* */ case 0xED: MLIT2(c,d); RGET2(a,b); RPSH2(c,d); RPSH2(a,b); continue; +/* SWPr* */ case 0xEE: MLIT2(c,d); RPOP2(a,b); RPSH2(c,d); RPSH2(a,b); continue; +/* ROTr* */ case 0xEF: MLIT2(e,f); RPOP2(c,d); RPOP2(a,b); RPSH2(c,d); RPSH2(e,f); RPSH2(a,b); continue; +/* ADDr* */ case 0xF0: MLITD(y); RPOPD(x); RPSHD(x+y); continue; +/* SUBr* */ case 0xF1: MLITD(y); RPOPD(x); RPSHD(x-y); continue; +/* INCr* */ case 0xF2: MLITD(x); RPSHD(x+1); continue; +/* DECr* */ case 0xF3: MLITD(x); RPSHD(x-1); continue; +/* LTHr* */ case 0xF4: MLITD(y); RPOPD(x); RPSH1(BOOL(x<y)); continue; +/* GTHr* */ case 0xF5: MLITD(y); RPOPD(x); RPSH1(BOOL(x>y)); continue; +/* EQUr* */ case 0xF6: MLIT2(c,d); RPOP2(a,b); RPSH1(BOOL(a==c && b==d)); continue; +/* NQKr* */ case 0xF7: MLIT2(c,d); RGET2(a,b); RPSH2(c,d); RPSH1(BOOL(a!=c || b!=d)); continue; +/* IORr* */ case 0xF8: MLIT2(c,d); RSTV(-1)|=d; RSTV(-2)|=c; continue; +/* XORr* */ case 0xF9: MLIT2(c,d); RSTV(-1)^=d; RSTV(-2)^=c; continue; +/* ANDr* */ case 0xFA: MLIT2(c,d); RSTV(-1)&=d; RSTV(-2)&=c; continue; +/* NOTr* */ case 0xFB: MLIT2(a,b); RPSH2(~a,~b); continue; +/* SHFr* */ case 0xFC: MLIT1(c); RPOPD(x); x=SHF(x,c); RPSHD(x); continue; +/* SHCr* */ case 0xFD: MLIT1(c); RPOPD(x); x=shcd(x,c); RPSHD(x); continue; +/* TALr* */ case 0xFE: MLIT2(a,b); RPSH1(TAL(a)+TAL(b)); continue; +/* REVr* */ case 0xFF: MLIT2(a,b); RPSH1(rev(b)); RPSH1(rev(a)); continue; + } + } + return SIG_NONE; +} diff --git a/arm9/source/core.h b/arm9/source/core.h new file mode 100644 index 0000000..e5494ca --- /dev/null +++ b/arm9/source/core.h @@ -0,0 +1,85 @@ +#ifndef CORE_H_ + #define CORE_H_ + + #include "devices/clock.h" + #include "devices/input.h" + #include "devices/math.h" + #include "devices/screen.h" + #include "devices/system.h" + + #define WST br->wst + #define RST br->rst + #define MEM br->mem + #define PC br->pc + + #define WSTV(i) WST.mem[WST.p+(i)] + #define RSTV(i) RST.mem[RST.p+(i)] + + #define MLIT MEM[PC++] + #define MLIT1(x) x = MLIT; + #define MLIT2(x,y) x = MLIT; y = MLIT; + #define MLITD(d) d = (u16)(MEM[PC] << 8) | (u16)(MEM[PC+1]); PC+=2; + + #define WPSH WST.mem[WST.p++] + #define RPSH RST.mem[RST.p++] + #define WPSH1(x) WPSH = (x); + #define RPSH1(x) RPSH = (x); + #define WPSH2(x,y) WPSH1(x); WPSH1(y); + #define RPSH2(x,y) RPSH1(x); RPSH1(y); + #define WPSHD(d) WPSH1(HIGH((d))); WPSH1(LOW((d))); + #define RPSHD(d) RPSH1(HIGH((d))); RPSH1(LOW((d))); + + #define WPOP WST.mem[--WST.p] + #define RPOP RST.mem[--RST.p] + #define WPOP1(x) x = WPOP; + #define RPOP1(x) x = RPOP; + #define WPOP2(x,y) WPOP1(y); WPOP1(x); + #define RPOP2(x,y) RPOP1(y); RPOP1(x); + #define WPOPD(d) d = (u16)(WSTV(-2) << 8) | (u16)(WSTV(-1)); WST.p-=2; + #define RPOPD(d) d = (u16)(RSTV(-2) << 8) | (u16)(RSTV(-1)); RST.p-=2; + + #define WGET1(x) x = WSTV(-1); + #define RGET1(x) x = RSTV(-1); + #define WGET2(x,y) x = WSTV(-2); y = WSTV(-1); + #define RGET2(x,y) x = RSTV(-2); y = RSTV(-1); + #define WGETD(x) x = DOUBLE(WSTV(-2),WSTV(-1)); + #define RGETD(x) x = DOUBLE(RSTV(-2),RSTV(-1)); + + typedef enum { + SIG_NONE, + SIG_HALT, + SIG_SLEEP, + SIG_DB1, + SIG_DB2, + SIG_DB3, + SIG_DB4, + SIG_DB5, + SIG_DB6, + } Signal; + + typedef struct { + u8 mem[256]; // stack memory + u8 p; // stack pointer + } Stack; + + typedef struct { + bool alive; // true when program is loaded + bool awake; // true when program is not asleep + u8 mem[65536]; // program memory + u16 pc; // program counter + Stack wst, rst; // working and return stacks + SystemDevice sys; + MathDevice math; + ClockDevice clk; + InputDevice inp; + ScreenDevice scr; + } Bedrock; + + void reset_br(Bedrock *br); + void start_br(Bedrock *br, u8 program[], int size); + void rouse_br(Bedrock *br); + u8 dev_read(Bedrock *br, u8 port); + Signal dev_write(Bedrock *br, u8 port, u8 val); + Signal evaluate( Bedrock *br, u16 count); + +#endif diff --git a/arm9/source/devices/clock.c b/arm9/source/devices/clock.c new file mode 100644 index 0000000..6f3ce85 --- /dev/null +++ b/arm9/source/devices/clock.c @@ -0,0 +1,87 @@ +#include <nds.h> +#include <time.h> +#include "clock.h" +#include "../bang.h" + +// Uptime is the number of 1/256th second ticks since the emulator began. +static u32 uptime; +u32 get_uptime(void) { return uptime; } +void uptime_handler(void) { uptime++; } + +// Check if any timer has expired. +bool check_timers(ClockDevice *clk) { + bool output = FALSE; + if (clk->t1.end && clk->t1.end <= uptime) { + clk->t1.end = 0; + output = TRUE; + } + if (clk->t2.end && clk->t2.end <= uptime) { + clk->t2.end = 0; + output = TRUE; + } + if (clk->t3.end && clk->t3.end <= uptime) { + clk->t3.end = 0; + output = TRUE; + } + if (clk->t4.end && clk->t4.end <= uptime) { + clk->t4.end = 0; + output = TRUE; + } + return output; +} + +u8 get_timer_high(ClockTimer *t) { + if (t->end > uptime) { + t->read = t->end - uptime; + } else { + t->end = 0; + t->read = 0; + } + return HIGH(t->read); +} + +u8 get_timer_low(ClockTimer *t) { + return LOW(t->read); +} + +void set_timer_high(ClockTimer *t, u8 high) { + SET_HIGH(t->write, high); +} +void set_timer_low(ClockTimer *t, u8 low) { + SET_LOW(t->write, low); + if (t->write) { + t->end = uptime + t->write; + } else { + t->end = 0; + } +} + +u8 get_timer1_high(ClockDevice *clock) { return get_timer_high(&clock->t1); } +u8 get_timer1_low( ClockDevice *clock) { return get_timer_low( &clock->t1); } +u8 get_timer2_high(ClockDevice *clock) { return get_timer_high(&clock->t2); } +u8 get_timer2_low( ClockDevice *clock) { return get_timer_low( &clock->t2); } +u8 get_timer3_high(ClockDevice *clock) { return get_timer_high(&clock->t3); } +u8 get_timer3_low( ClockDevice *clock) { return get_timer_low( &clock->t3); } +u8 get_timer4_high(ClockDevice *clock) { return get_timer_high(&clock->t4); } +u8 get_timer4_low( ClockDevice *clock) { return get_timer_low( &clock->t4); } + +void set_timer1_high(ClockDevice *clock, u8 high) { set_timer_high(&clock->t1, high); } +void set_timer1_low( ClockDevice *clock, u8 low) { set_timer_low( &clock->t1, low); } +void set_timer2_high(ClockDevice *clock, u8 high) { set_timer_high(&clock->t2, high); } +void set_timer2_low( ClockDevice *clock, u8 low) { set_timer_low( &clock->t2, low); } +void set_timer3_high(ClockDevice *clock, u8 high) { set_timer_high(&clock->t3, high); } +void set_timer3_low( ClockDevice *clock, u8 low) { set_timer_low( &clock->t3, low); } +void set_timer4_high(ClockDevice *clock, u8 high) { set_timer_high(&clock->t4, high); } +void set_timer4_low( ClockDevice *clock, u8 low) { set_timer_low( &clock->t4, low); } + + +void init_clock(void) { + // Start a 256Hz timer to increment the uptime value. + timerStart(0, ClockDivider_1024, TIMER_FREQ_1024(256), uptime_handler); +} + +struct tm* get_datetime(void) { + time_t timestamp = time(NULL); + struct tm* datetime = localtime(×tamp); + return datetime; +} diff --git a/arm9/source/devices/clock.h b/arm9/source/devices/clock.h new file mode 100644 index 0000000..892479f --- /dev/null +++ b/arm9/source/devices/clock.h @@ -0,0 +1,46 @@ +#ifndef CLOCK_H_ + #define CLOCK_H_ + + #include <time.h> + + typedef struct { + u32 end; // real end time + u16 read, write; // read write caches + } ClockTimer; + + typedef struct { + ClockTimer t1, t2, t3, t4; // timers + u32 start; // uptime offset + } ClockDevice; + + #define YEAR(tm) (tm->tm_year - 100) + #define MONTH(tm) (tm->tm_mon) + #define DAY(tm) (tm->tm_mday - 1) + #define HOUR(tm) (tm->tm_hour) + #define MINUTE(tm) (tm->tm_min) + #define SECOND(tm) (tm->tm_sec) + + u32 get_uptime(void); + void uptime_handler(void); + void init_clock(void); + struct tm* get_datetime(void); + + bool check_timers(ClockDevice *clk); + + u8 get_timer1_high(ClockDevice *clock); + u8 get_timer1_low( ClockDevice *clock); + u8 get_timer2_high(ClockDevice *clock); + u8 get_timer2_low( ClockDevice *clock); + u8 get_timer3_high(ClockDevice *clock); + u8 get_timer3_low( ClockDevice *clock); + u8 get_timer4_high(ClockDevice *clock); + u8 get_timer4_low( ClockDevice *clock); + void set_timer1_high(ClockDevice *clock, u8 high); + void set_timer1_low( ClockDevice *clock, u8 low); + void set_timer2_high(ClockDevice *clock, u8 high); + void set_timer2_low( ClockDevice *clock, u8 low); + void set_timer3_high(ClockDevice *clock, u8 high); + void set_timer3_low( ClockDevice *clock, u8 low); + void set_timer4_high(ClockDevice *clock, u8 high); + void set_timer4_low( ClockDevice *clock, u8 low); +#endif diff --git a/arm9/source/devices/input.c b/arm9/source/devices/input.c new file mode 100644 index 0000000..a39f448 --- /dev/null +++ b/arm9/source/devices/input.c @@ -0,0 +1,59 @@ +#include <nds.h> +#include "../bang.h" +#include "input.h" + +// Read gamepad state into an input device. +void inp_read_gamepad(InputDevice *inp) { + u32 held = keysHeld(); + u8 gamepad = ( + TEST(held, KEY_UP) << 7 + | TEST(held, KEY_DOWN) << 6 + | TEST(held, KEY_LEFT) << 5 + | TEST(held, KEY_RIGHT) << 4 + | TEST(held, KEY_A) << 3 + | TEST(held, KEY_B) << 2 + | TEST(held, KEY_X) << 1 + | TEST(held, KEY_Y) << 0 + ); + if (gamepad != inp->gamepad) { + inp->wake = TRUE; + inp->gamepad = gamepad; + } +} + +// Read navigation state into an input device. +void inp_read_navigation(InputDevice *inp) { + u32 held = keysHeld(); + u8 navigation = ( + TEST(held, KEY_UP) << 7 + | TEST(held, KEY_DOWN) << 6 + | TEST(held, KEY_LEFT) << 5 + | TEST(held, KEY_RIGHT) << 4 + | TEST(held, KEY_A) << 3 + | TEST(held, KEY_B) << 2 + | TEST(held, KEY_R) << 1 + | TEST(held, KEY_L) << 0 + ); + if (navigation != inp->navigation) { + inp->wake = TRUE; + inp->navigation = navigation; + } +} + +// Read touchscreen state into an input device. +void inp_read_touch(InputDevice *inp) { + bool pointer = TEST(keysHeld(), KEY_TOUCH); + if (pointer != inp->pointer) { + inp->wake = TRUE; + inp->pointer = pointer; + } + if (pointer) { + touchPosition pos; + touchRead(&pos); + if (pos.px != inp->x || pos.py != inp->y) { + inp->wake = TRUE; + inp->x = pos.px; + inp->y = pos.py; + } + } +} diff --git a/arm9/source/devices/input.h b/arm9/source/devices/input.h new file mode 100644 index 0000000..e62bdd3 --- /dev/null +++ b/arm9/source/devices/input.h @@ -0,0 +1,16 @@ +#ifndef INPUT_H_ + #define INPUT_H_ + + typedef struct { + bool pointer; // pointer active + bool keyboard; // keyboard active + u16 x,y; // pointer position + u8 navigation; // navigation state + u8 gamepad; // gamepad state + bool wake; // wake flag + } InputDevice; + + void inp_read_gamepad(InputDevice *inp); + void inp_read_navigation(InputDevice *inp); + void inp_read_touch(InputDevice *inp); +#endif diff --git a/arm9/source/devices/local.c b/arm9/source/devices/local.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/arm9/source/devices/local.c diff --git a/arm9/source/devices/local.h b/arm9/source/devices/local.h new file mode 100644 index 0000000..bf1393c --- /dev/null +++ b/arm9/source/devices/local.h @@ -0,0 +1,4 @@ +#ifndef LOCAL_H_ + #define LOCAL_H_ + +#endif diff --git a/arm9/source/devices/math.c b/arm9/source/devices/math.c new file mode 100644 index 0000000..bb592e0 --- /dev/null +++ b/arm9/source/devices/math.c @@ -0,0 +1,66 @@ +#include <nds.h> +#include <math.h> +#include "math.h" +#include "../bang.h" + +#define CLEAR \ + math->sqrt_rc = FALSE;\ + math->atan_rc = FALSE;\ + math->prod_rc = FALSE;\ + math->quot_rc = FALSE;\ + math->rem_rc = FALSE; + +void set_op1_high(MathDevice *math, u8 high) { SET_HIGH(math->op1, high); CLEAR; } +void set_op1_low( MathDevice *math, u8 low) { SET_LOW(math->op1, low); CLEAR; } +void set_op2_high(MathDevice *math, u8 high) { SET_HIGH(math->op2, high); CLEAR; } +void set_op2_low( MathDevice *math, u8 low) { SET_LOW(math->op2, low); CLEAR; } + +u16 get_sqrt(MathDevice *math) { + if (!math->sqrt_rc) { + u32 input = math->op1 << 16 | math->op2; + math->sqrt = sqrt32(input); + math->sqrt_rc = TRUE; + } + return math->sqrt; +} + +u16 get_atan(MathDevice *math) { + if (!math->atan_rc) { + if (math->op1 || math->op2) { + double op1 = (s16) math->op1; + double op2 = (s16) math->op2; + const double scale = 10430.378350470453; // PI * 32768 + math->atan = (s32) (atan2(op1, op2) * scale); + } + math->atan_rc = TRUE; + } + return math->atan; +} + +u32 get_prod(MathDevice *math) { + if (!math->prod_rc) { + math->prod = math->op1 * math->op2; + math->prod_rc = TRUE; + } + return math->prod; +} + +u16 get_quot(MathDevice *math) { + if (!math->quot_rc) { + if (math->op2) { + math->quot = div32(math->op1, math->op2); + } + math->quot_rc = TRUE; + } + return math->quot; +} + +u16 get_rem(MathDevice *math) { + if (!math->rem_rc) { + if (math->op2) { + math->rem = mod32(math->op1, math->op2); + } + math->rem_rc = TRUE; + } + return math->rem; +} diff --git a/arm9/source/devices/math.h b/arm9/source/devices/math.h new file mode 100644 index 0000000..ae52a10 --- /dev/null +++ b/arm9/source/devices/math.h @@ -0,0 +1,19 @@ +#ifndef MATH_H_ + #define MATH_H_ + + typedef struct { + u16 op1, op2; + u16 sqrt, atan; u32 prod; u16 quot, rem; // read + bool sqrt_rc, atan_rc, prod_rc, quot_rc, rem_rc; // read cached + } MathDevice ; + + void set_op1_high(MathDevice *math, u8 high); + void set_op1_low(MathDevice *math, u8 low); + void set_op2_high(MathDevice *math, u8 high); + void set_op2_low(MathDevice *math, u8 low); + u16 get_sqrt(MathDevice *math); + u16 get_atan(MathDevice *math); + u32 get_prod(MathDevice *math); + u16 get_quot(MathDevice *math); + u16 get_rem(MathDevice *math); +#endif diff --git a/arm9/source/devices/screen.c b/arm9/source/devices/screen.c new file mode 100644 index 0000000..492bb05 --- /dev/null +++ b/arm9/source/devices/screen.c @@ -0,0 +1,284 @@ +/* +A screen layer contains 768 tiles (32*24), requiring 24KB. Each tile is 32 bytes, +holding 2 pixels per byte. The upper four bits of a tile byte represent the +colour of the right pixel, and the lower four bits the colour of the left pixel. +The colour is a 4-bit reference into a 16-colour RGB15 palette. + +Screen memory contains four layers: bg, fg, then the same but for double buffers. +Ignore double buffering for now. We keep these as u32* because a single 32-bit +integer represents a single 8-pixel row. +TODO: This needs to be updated. We have double buffering, and we use u16*. + +The tile map is shared by the foreground and background layers, and is stored +just past the first layer for both screens (at the 24KB offset). Each entry is +a 16-bit tile index (low 10 bits are tile index, then h-flip, then v-flip, then +4-bit palette identifier). +*/ + +#include <nds.h> +#include "screen.h" +#include "../bang.h" + +void init_screens(void) { + // Allocate VRAM for screens + videoSetMode(DISPLAY_BG0_ACTIVE | DISPLAY_BG1_ACTIVE | MODE_0_2D); + vramSetBankA(VRAM_A_MAIN_BG); + videoSetModeSub(DISPLAY_BG0_ACTIVE | DISPLAY_BG1_ACTIVE | MODE_0_2D); + vramSetBankC(VRAM_C_SUB_BG); + + /* Configure screen layers to use tile graphics. */ + REG_BG0CNT = BG_32x32 | BG_COLOR_16 | BG_PRIORITY_3 | BG_TILE_BASE(BG_SLOT_VIS) | BG_MAP_BASE(MAP_SLOT); + REG_BG1CNT = BG_32x32 | BG_COLOR_16 | BG_PRIORITY_2 | BG_TILE_BASE(FG_SLOT_VIS) | BG_MAP_BASE(MAP_SLOT); + REG_BG0CNT_SUB = BG_32x32 | BG_COLOR_16 | BG_PRIORITY_3 | BG_TILE_BASE(BG_SLOT_VIS) | BG_MAP_BASE(MAP_SLOT); + REG_BG1CNT_SUB = BG_32x32 | BG_COLOR_16 | BG_PRIORITY_2 | BG_TILE_BASE(FG_SLOT_VIS) | BG_MAP_BASE(MAP_SLOT); + + /* Populate tile maps with tile indices. */ + int i; + u16 *main_map = BG_MAP_RAM(12); + u16 *sub_map = BG_MAP_RAM_SUB(12); + for (i = 0; i < TILES_SIZE; i++) { + *(main_map++) = i; + *(sub_map++) = i; + } +} + + +void set_palette_high(ScreenDevice *scr, u8 high) { + SET_HIGH(scr->palette_write, high); +} +void set_palette_low(ScreenDevice *scr, u8 low) { + SET_LOW(scr->palette_write, low); + u8 i = scr->palette_write >> 12 & 0x0f; + u8 r = scr->palette_write >> 7 & 0x1e; + u8 g = scr->palette_write >> 3 & 0x1e; + u8 b = scr->palette_write << 1 & 0x1e; + // TODO: With 4-bit we multiply by 17, find equivalent + // here to get best value of least-significant bit. + scr->palette[i] = RGB15(r,g,b); + scr->nds->pal[i] = RGB15(r,g,b); +} + +void push_sprite(SpriteBuffer *b, u8 row) { + b->mem[b->p] = row; + b->p = (b->p + 1) % 16; + b->cached = FALSE; +} + +void prepare_1bit_sprite(SpriteBuffer *b, u8 draw) { + u8 l,p,x,y; + if (b->cached && draw == b->draw) return; + + switch (draw & 0x07) { + case 0x0: p=b->p+8; for (y=0;y<8;y++) { l=b->mem[p++ % 16]; for (x=0;x<8;x++) { b->sprite[y][x] = l>>(7-x) & 1; } }; break; + case 0x1: p=b->p+8; for (y=0;y<8;y++) { l=b->mem[p++ % 16]; for (x=0;x<8;x++) { b->sprite[y][x] = l>>( x) & 1; } }; break; + case 0x2: p=b->p; for (y=0;y<8;y++) { l=b->mem[--p % 16]; for (x=0;x<8;x++) { b->sprite[y][x] = l>>(7-x) & 1; } }; break; + case 0x3: p=b->p; for (y=0;y<8;y++) { l=b->mem[--p % 16]; for (x=0;x<8;x++) { b->sprite[y][x] = l>>( x) & 1; } }; break; + case 0x4: p=b->p+8; for (y=0;y<8;y++) { l=b->mem[p++ % 16]; for (x=0;x<8;x++) { b->sprite[x][y] = l>>(7-x) & 1; } }; break; + case 0x5: p=b->p+8; for (y=0;y<8;y++) { l=b->mem[p++ % 16]; for (x=0;x<8;x++) { b->sprite[x][y] = l>>( x) & 1; } }; break; + case 0x6: p=b->p; for (y=0;y<8;y++) { l=b->mem[--p % 16]; for (x=0;x<8;x++) { b->sprite[x][y] = l>>(7-x) & 1; } }; break; + case 0x7: p=b->p; for (y=0;y<8;y++) { l=b->mem[--p % 16]; for (x=0;x<8;x++) { b->sprite[x][y] = l>>( x) & 1; } }; break; + } + + b->cached = TRUE; + b->draw = draw; +} + +void prepare_2bit_sprite(SpriteBuffer *b, u8 draw) { + u8 l,h,i,p,s,x,y; + if (b->cached && draw == b->draw) return; + + switch (draw & 0x07) { + case 0x0: p=b->p+8; s=p+8; for (y=0;y<8;y++) { l=b->mem[p++ % 16]; h=b->mem[s++ % 16]; for (x=0;x<8;x++) { i=(7-x); b->sprite[y][x] = (l>>i & 1) | (h>>i & 1) << 1; } }; break; + case 0x1: p=b->p+8; s=p+8; for (y=0;y<8;y++) { l=b->mem[p++ % 16]; h=b->mem[s++ % 16]; for (x=0;x<8;x++) { i=( x); b->sprite[y][x] = (l>>i & 1) | (h>>i & 1) << 1; } }; break; + case 0x2: p=b->p; s=p+8; for (y=0;y<8;y++) { l=b->mem[--p % 16]; h=b->mem[--s % 16]; for (x=0;x<8;x++) { i=(7-x); b->sprite[y][x] = (l>>i & 1) | (h>>i & 1) << 1; } }; break; + case 0x3: p=b->p; s=p+8; for (y=0;y<8;y++) { l=b->mem[--p % 16]; h=b->mem[--s % 16]; for (x=0;x<8;x++) { i=( x); b->sprite[y][x] = (l>>i & 1) | (h>>i & 1) << 1; } }; break; + case 0x4: p=b->p+8; s=p+8; for (y=0;y<8;y++) { l=b->mem[p++ % 16]; h=b->mem[s++ % 16]; for (x=0;x<8;x++) { i=(7-x); b->sprite[x][y] = (l>>i & 1) | (h>>i & 1) << 1; } }; break; + case 0x5: p=b->p+8; s=p+8; for (y=0;y<8;y++) { l=b->mem[p++ % 16]; h=b->mem[s++ % 16]; for (x=0;x<8;x++) { i=( x); b->sprite[x][y] = (l>>i & 1) | (h>>i & 1) << 1; } }; break; + case 0x6: p=b->p; s=p+8; for (y=0;y<8;y++) { l=b->mem[--p % 16]; h=b->mem[--s % 16]; for (x=0;x<8;x++) { i=(7-x); b->sprite[x][y] = (l>>i & 1) | (h>>i & 1) << 1; } }; break; + case 0x7: p=b->p; s=p+8; for (y=0;y<8;y++) { l=b->mem[--p % 16]; h=b->mem[--s % 16]; for (x=0;x<8;x++) { i=( x); b->sprite[x][y] = (l>>i & 1) | (h>>i & 1) << 1; } }; break; + } + + b->cached = TRUE; + b->draw = draw; +} + + +// --------------------------------------------------------------------------- + +void draw_pixel(u16 *layer, u16 x, u16 y, u8 colour) { + if (x < PIXELS_WIDTH && y < PIXELS_HEIGHT) { + u32 addr = \ + (x >> 2 & 0x0001) + (x << 1 & 0xfff0) + \ + (y << 1 & 0x000f) + (y << 6 & 0xfe00); + u16 shift = (x & 0x3) << 2; + layer[addr] = (layer[addr] & ~(0xf << shift)) | (colour << shift); + } +} + +void fill_layer(u16 *layer, u8 colour) { + u8 byte = colour << 4 | colour; + u32 word = byte << 24 | byte << 16 | byte << 8 | byte; + dmaFillWords(word, layer, TILES_MEM); +} + +void erase_screen(Screen *nds) { + dmaFillWords(0, nds->bg, TILES_MEM); + dmaFillWords(0, nds->fg, TILES_MEM); +}; + +void flip_buffer(Screen *nds) { + dmaCopyWords(0, nds->bg, nds->bgv, TILES_MEM); + dmaCopyWords(0, nds->fg, nds->fgv, TILES_MEM); +} + +void black_screen(Screen *nds) { + nds->pal[0] = RGB15(8,0,0); + dmaFillWords(0, nds->bgv, TILES_MEM); + dmaFillWords(0, nds->fgv, TILES_MEM); +} +// --------------------------------------------------------------------------- + +void draw_dispatch(ScreenDevice *scr, u8 draw) { + switch (draw >> 4) { + case 0x0: scr_draw_pixel(scr, scr->nds->bg, draw); break; + case 0x1: scr_draw_sprite(scr, scr->nds->bg, draw); break; + case 0x2: scr_fill_layer(scr, scr->nds->bg, draw); break; + case 0x3: scr_draw_sprite(scr, scr->nds->bg, draw); break; + case 0x4: scr_draw_line(scr, scr->nds->bg, draw); break; + case 0x5: scr_draw_line(scr, scr->nds->bg, draw); break; + case 0x6: scr_draw_rect(scr, scr->nds->bg, draw); break; + case 0x7: scr_draw_rect(scr, scr->nds->bg, draw); break; + case 0x8: scr_draw_pixel(scr, scr->nds->fg, draw); break; + case 0x9: scr_draw_sprite(scr, scr->nds->fg, draw); break; + case 0xA: scr_fill_layer(scr, scr->nds->fg, draw); break; + case 0xB: scr_draw_sprite(scr, scr->nds->fg, draw); break; + case 0xC: scr_draw_line(scr, scr->nds->fg, draw); break; + case 0xD: scr_draw_line(scr, scr->nds->fg, draw); break; + case 0xE: scr_draw_rect(scr, scr->nds->fg, draw); break; + case 0xF: scr_draw_rect(scr, scr->nds->fg, draw); break; + } + scr->px = scr->x; + scr->py = scr->y; + scr->dirty = true; +} + +void scr_draw_pixel(ScreenDevice *scr, u16 *layer, u8 draw) { + draw_pixel(layer, scr->x, scr->y, draw&0xf); +} + +void scr_fill_layer(ScreenDevice *scr, u16 *layer, u8 draw) { + fill_layer(layer, draw&0xf); +} + +void scr_draw_sprite(ScreenDevice *scr, u16 *layer, u8 draw) { + if (draw & 0x20) { prepare_2bit_sprite(&scr->sprite, draw); } + else { prepare_1bit_sprite(&scr->sprite, draw); } + + u8 colours[4] = { + scr->colours >> 12 & 0x000f, + scr->colours >> 8 & 0x000f, + scr->colours >> 4 & 0x000f, + scr->colours & 0x000f, + }; + + if (draw & 0x08) { + // Draw sprite with transparent background + for (u8 y=0;y<8;y++) { + for (u8 x=0;x<8;x++) { + u8 i = scr->sprite.sprite[y][x]; + if (i) draw_pixel(layer, scr->x+x, scr->y+y, colours[i]); + } + } + } else { + // Draw sprite with opaque background + for (u8 y=0;y<8;y++) { + for (u8 x=0;x<8;x++) { + u8 i = scr->sprite.sprite[y][x]; + draw_pixel(layer, scr->x+x, scr->y+y, colours[i]); + } + } + } +} + +void scr_draw_line(ScreenDevice *scr, u16 *layer, u8 draw) { + s16 x = (s16) scr->x; + s16 y = (s16) scr->y; + s16 x_end = (s16) scr->px; + s16 y_end = (s16) scr->py; + + s16 dx = abs(x_end - x); + s16 dy = -abs(y_end - y); + s16 sx = x < x_end ? 1 : -1; + s16 sy = y < y_end ? 1 : -1; + s16 e1 = dx + dy; + + if (draw & 0x10) { + // Draw 1-bit textured line. + prepare_1bit_sprite(&scr->sprite, draw); + u8 c1 = scr->colours >> 8 & 0xf; + u8 c0 = scr->colours >> 12 & 0xf; + bool opaque = !(draw & 0x08); + while (1) { + if (scr->sprite.sprite[y%8][x%8]) { draw_pixel(layer, x, y, c1); } + else if (opaque) { draw_pixel(layer, x, y, c0); } + if (x == x_end && y == y_end) return; + s16 e2 = e1 << 1; + if (e2 >= dy) { e1 += dy; x += sx; } + if (e2 <= dx) { e1 += dx; y += sy; } + } + } else { + // Draw solid line. + u8 colour = draw & 0xf; + while (1) { + draw_pixel(layer, x, y, colour); + if (x == x_end && y == y_end) return; + s16 e2 = e1 << 1; + if (e2 >= dy) { e1 += dy; x += sx; } + if (e2 <= dx) { e1 += dx; y += sy; } + } + } +} + +void scr_draw_rect(ScreenDevice *scr, u16 *layer, u8 draw) { + #define SWAP(x,y) {u8 temp=x; x=y; y=temp;} + #define CLAMP(v,m) {v>0x7fff ? 0 : v>m ? m : v} + + // Get bounding box. + u16 l = CLAMP(scr->px, PIXELS_WIDTH -1); + u16 r = CLAMP(scr->x , PIXELS_WIDTH -1); + u16 t = CLAMP(scr->py, PIXELS_HEIGHT-1); + u16 b = CLAMP(scr->y , PIXELS_HEIGHT-1); + if (l>r) SWAP(l,r); + if (t>b) SWAP(t,b); + + if (draw & 0x10) { + // Draw 1-bit textured rectangle. + prepare_1bit_sprite(&scr->sprite, draw); + u8 c1 = scr->colours >> 8 & 0xf; + u8 c0 = scr->colours >> 12 & 0xf; + bool opaque = !(draw & 0x08); + for (u16 x=l; x<r+1; x++) { + for (u16 y=t; y<b+1; y++) { + if (scr->sprite.sprite[y%8][x%8]) { draw_pixel(layer, x, y, c1); } + else if (opaque) { draw_pixel(layer, x, y, c0); } + } + } + } else { + // Draw solid rectangle. + u8 colour = draw & 0xf; + for (u16 x=l; x<r+1; x++) { + for (u16 y=t; y<b+1; y++) { + draw_pixel(layer, x, y, colour); + } + } + } +} + +void move_cursor(ScreenDevice *scr, u8 move) { + switch (move >> 6) { + case 0b00: scr->x += move & 0x3f; return; + case 0b01: scr->y += move & 0x3f; return; + case 0b10: scr->x -= move & 0x3f; return; + case 0b11: scr->y -= move & 0x3f; return; + } +} diff --git a/arm9/source/devices/screen.h b/arm9/source/devices/screen.h new file mode 100644 index 0000000..a406051 --- /dev/null +++ b/arm9/source/devices/screen.h @@ -0,0 +1,66 @@ +#ifndef SCREEN_H_ + #define SCREEN_H_ + + #define PIXELS_WIDTH 256 + #define PIXELS_HEIGHT 192 + #define PIXELS_SIZE 49152 + #define TILES_WIDTH 32 + #define TILES_HEIGHT 24 + #define TILES_SIZE 768 + #define TILES_MEM 24576 // size of a screen layer in bytes + + #define BG_SLOT_VIS 0 // tile base for visible background tiles + #define FG_SLOT_VIS 2 // tile base for visible foreground tiles + #define BG_SLOT 4 // tile base for background tiles + #define FG_SLOT 6 // tile base for foreground tiles + #define MAP_SLOT 12 // map base for tile map + + typedef struct { + u8 mem[16]; // buffer memory + u8 p; // buffer pointer + u8 sprite[8][8]; // transformed sprite + bool cached; // true if sprite has been transformed + u8 draw; // the cached draw byte + } SpriteBuffer; + + typedef struct { + u16 *bgv, *fgv; // visible tile memory + u16 *bg, *fg; // tile memory + u16 *map; // tile map + u16 *pal; // colour palette + } Screen; + + typedef struct { + u16 x,y; // cursor position + u16 px,py; // previous cursor position + u16 colours; // sprite colours + SpriteBuffer sprite; // sprite buffer + u16 palette_write; // palette write cache + u16 palette[16]; // palette as RGB15 colours + Screen *nds; // NDS VRAM pointers + bool wake; // wake flag + bool dirty; // dirty flag + } ScreenDevice; + + void init_screens(void); + + void set_palette_high(ScreenDevice *scr, u8 high); + void set_palette_low(ScreenDevice *scr, u8 low); + void draw_pixel(u16 *layer, u16 x, u16 y, u8 colour); + void fill_layer(u16 *layer, u8 colour); + void erase_screen(Screen *nds); + void flip_buffer(Screen *nds); + void black_screen(Screen *nds); + + void scr_draw_pixel( ScreenDevice *scr, u16 *layer, u8 draw); + void scr_draw_sprite(ScreenDevice *scr, u16 *layer, u8 draw); + void scr_fill_layer( ScreenDevice *scr, u16 *layer, u8 draw); + void scr_draw_line( ScreenDevice *scr, u16 *layer, u8 draw); + void scr_draw_rect( ScreenDevice *scr, u16 *layer, u8 draw); + + void draw_dispatch(ScreenDevice *scr, u8 draw); + void move_cursor(ScreenDevice *scr, u8 move); + + void push_sprite(SpriteBuffer *b, u8 row); + +#endif diff --git a/arm9/source/devices/system.c b/arm9/source/devices/system.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/arm9/source/devices/system.c diff --git a/arm9/source/devices/system.h b/arm9/source/devices/system.h new file mode 100644 index 0000000..b18b5a2 --- /dev/null +++ b/arm9/source/devices/system.h @@ -0,0 +1,9 @@ +#ifndef SYSTEM_H_ + #define SYSTEM_H_ + + typedef struct { + u16 sleep; // device mask for waking + u8 wake; // ID of wake device + } SystemDevice; + +#endif diff --git a/arm9/source/main.c b/arm9/source/main.c new file mode 100644 index 0000000..a8d3273 --- /dev/null +++ b/arm9/source/main.c @@ -0,0 +1,118 @@ +#include <stdio.h> +#include <time.h> +#include <nds.h> +#include "devices/clock.h" +#include "devices/math.h" +#include "devices/screen.h" +#include "bang.h" +#include "core.h" +#include "main_debug.h" + +Bedrock br[5] = {}; +Bedrock *br_main; +Bedrock *br_sub; +bool main_on_bottom = TRUE; + +u8 main_program[] = { + #include "../include/sysinfo.br.inc" +}; +u8 keyboard_program[] = { + #include "../include/sysinfo.br.inc" +}; + +// Change to the next screen layout. +void change_layout(void) { + lcdSwap(); + main_on_bottom = !main_on_bottom; +} + +// Scan for input and handle emulator-specific keys. +void receive_input(void) { + scanKeys(); + if (keysDown() & KEY_SELECT) change_layout(); +} + + +void run_br(Bedrock *br) { + if (br->awake) { + switch (evaluate(br, 1000)) { + case SIG_HALT: br->alive = FALSE; black_screen(br->scr.nds); br = NULL; return; + case SIG_SLEEP: br->awake = FALSE; return; + case SIG_DB1: debug_stacks(br); return; + case SIG_DB4: debug_assert(br); return; + default: return; + } + } +} + +Screen scr_main = { + .bgv = BG_TILE_RAM(BG_SLOT_VIS), + .fgv = BG_TILE_RAM(FG_SLOT_VIS), + .bg = BG_TILE_RAM(BG_SLOT), + .fg = BG_TILE_RAM(FG_SLOT), + .map = BG_MAP_RAM(MAP_SLOT), + .pal = BG_PALETTE, +}; +Screen scr_sub = { + .bgv = BG_TILE_RAM_SUB(BG_SLOT_VIS), + .fgv = BG_TILE_RAM_SUB(FG_SLOT_VIS), + .bg = BG_TILE_RAM_SUB(BG_SLOT), + .fg = BG_TILE_RAM_SUB(FG_SLOT), + .map = BG_MAP_RAM_SUB(MAP_SLOT), + .pal = BG_PALETTE_SUB, +}; + +int main(void) { + #define ALIVE(br) (br && br->alive) + #define AWAKE(br) (br && br->alive && br->awake) + #define ASLEEP(br) (br && br->alive && !br->awake) + + init_screens(); + init_clock(); + lcdMainOnBottom(); + + // TODO: Remove + // consoleDemoInit(); + + // Load program + start_br(&br[0], main_program, sizeof(main_program)); + start_br(&br[1], keyboard_program, sizeof(keyboard_program)); + br_main = &br[0]; + br_sub = &br[1]; + br_main->scr.nds = &scr_main; + br_sub->scr.nds = &scr_sub; + + while (1) { + if (AWAKE(br_main)) run_br(br_main); + if (AWAKE(br_sub)) run_br(br_sub); + + bool main_flip = ASLEEP(br_main) && br_main->scr.dirty; + bool sub_flip = ASLEEP(br_sub) && br_sub->scr.dirty; + if (main_flip || sub_flip) swiWaitForVBlank(); + if (main_flip) { flip_buffer(br_main->scr.nds); br_main->scr.dirty = false; } + if (sub_flip) { flip_buffer(br_sub->scr.nds); br_sub->scr.dirty = false; } + + rouse: + receive_input(); + if (ALIVE(br_main)) { + inp_read_navigation(&br_main->inp); + inp_read_gamepad(&br_main->inp); + if (main_on_bottom) inp_read_touch(&br_main->inp); + } + if (ALIVE(br_sub)) { + inp_read_navigation(&br_sub->inp); + inp_read_gamepad(&br_sub->inp); + if (!main_on_bottom) inp_read_touch(&br_sub->inp); + } + if (ASLEEP(br_main)) rouse_br(br_main); + if (ASLEEP(br_sub)) rouse_br(br_sub); + if (ASLEEP(br_main) && ASLEEP(br_sub)) { + // Sleep until next keypad event or clock tick. + swiIntrWait(1, IRQ_KEYS | IRQ_TIMER0); + goto rouse; + } + + if (!br_main && !br_sub) return 0; + } +} + diff --git a/arm9/source/main_debug.c b/arm9/source/main_debug.c new file mode 100644 index 0000000..eae5192 --- /dev/null +++ b/arm9/source/main_debug.c @@ -0,0 +1,24 @@ +#include <nds.h> +#include "core.h" + +void debug_stacks(Bedrock *br) { + u8 i; + printf("\nP:0x%04x I:0x%02x", PC, MEM[PC]); + printf("\nW:"); + for (i=0; i<WST.p; i++) { + printf("%02x ", WST.mem[i]); + } + printf("\nR:"); + for (i=0; i<RST.p; i++) { + printf("%02x ", RST.mem[i]); + } + printf("\n"); +} + +void debug_assert(Bedrock *br) { + if (WST.mem[0] == 0xff && WST.p == 1 && RST.p == 0) { + printf("."); + } else { + printf("X"); + } +} diff --git a/arm9/source/main_debug.h b/arm9/source/main_debug.h new file mode 100644 index 0000000..55e60b9 --- /dev/null +++ b/arm9/source/main_debug.h @@ -0,0 +1,7 @@ +#ifndef MAIN_DEBUG_H_ + #define MAIN_DEBUG_H_ + + void debug_stacks(Bedrock *br); + void debug_assert(Bedrock *br); + +#endif |