summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2023-05-23 18:25:10 +0200
committerBad Diode <bd@badd10de.dev>2023-05-23 18:25:10 +0200
commit4d4a94e00619f1d1effda56a904175272e23cc78 (patch)
tree2b36a3c8e269a3772a516441c8984be57f6fc558
parentbaf4091795c5a87ff286e83f012ac091bcdd5848 (diff)
downloadgba-link-cable-tester-4d4a94e00619f1d1effda56a904175272e23cc78.tar.gz
gba-link-cable-tester-4d4a94e00619f1d1effda56a904175272e23cc78.zip
Add initial link cable tester code
-rw-r--r--Makefile2
-rw-r--r--src/gba/gba.h18
-rw-r--r--src/main.c405
-rw-r--r--src/profiling.c16
4 files changed, 114 insertions, 327 deletions
diff --git a/Makefile b/Makefile
index 98fbfd1..d5112f5 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@ INC_FLAGS := $(addprefix -I,$(INC_DIRS))
27INC_FLAGS += -I$(LIBGBA_SRC) 27INC_FLAGS += -I$(LIBGBA_SRC)
28 28
29# Output library names and executables. 29# Output library names and executables.
30TARGET := rend-bench 30TARGET := link-cable-tester
31ELF := $(BUILD_DIR)/$(TARGET).elf 31ELF := $(BUILD_DIR)/$(TARGET).elf
32BIN := $(BUILD_DIR)/$(TARGET).gba 32BIN := $(BUILD_DIR)/$(TARGET).gba
33 33
diff --git a/src/gba/gba.h b/src/gba/gba.h
index 27a6a9a..1edf8a8 100644
--- a/src/gba/gba.h
+++ b/src/gba/gba.h
@@ -482,6 +482,24 @@ int bios_vblank_wait();
482int bios_div(int num, int denom); 482int bios_div(int num, int denom);
483 483
484// 484//
485// SIO Link Cable
486//
487
488#define SIO_MODE *((vu16*)(MEM_IO + 0x0134))
489#define SIO_CNT *((vu16*)(MEM_IO + 0x0128))
490
491#define SIO_MODE_GP (2 << 14)
492#define SIO_SC(X) ((X) << 0)
493#define SIO_SD(X) ((X) << 1)
494#define SIO_SI(X) ((X) << 2)
495#define SIO_SO(X) ((X) << 3)
496#define SIO_SC_OUT(X) ((X) << 4)
497#define SIO_SD_OUT(X) ((X) << 5)
498#define SIO_SI_OUT(X) ((X) << 6)
499#define SIO_SO_OUT(X) ((X) << 7)
500#define SIO_IRQ_ENABLE (1 << 8)
501
502//
485// Sound. 503// Sound.
486// 504//
487 505
diff --git a/src/main.c b/src/main.c
index 0a78367..f0be4d2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -17,343 +17,112 @@ WITH REGARD TO THIS SOFTWARE.
17// Config parameters. 17// Config parameters.
18// 18//
19 19
20#define PROF_ENABLE 1 20#define PROF_ENABLE 0
21#include "profiling.c" 21#include "profiling.c"
22 22
23void 23// void
24test_clear(void) { 24// test_text_rendering(void) {
25 for (size_t i = 0; i < 5; i++) { 25// while (true) {
26 screen_fill(4); 26// poll_keys();
27 } 27// if (key_tap(KEY_A)) {
28} 28// break;
29 29// }
30void 30// bios_vblank_wait();
31test_rect(void) { 31// FRAME_START();
32 for (size_t i = 0; i < 100; i++) { 32// PROF(flip_buffer(), flip_cycles);
33 draw_rect(0, 0, i, i, 2); 33// PROF(screen_fill(0), clear_cycles);
34 } 34// txt_color(2);
35} 35// PROF(txt_drawf("The strongest bulwark of", 4, 8 * 2, 3), txt_drawf_cycles);
36 36// PROF(txt_drawf("authority is uniformity;", 2, 8 * 3, 3), txt_drawf_cycles);
37void 37// PROF(txt_drawf("the least divergence from it", 8, 8 * 4, 3), txt_drawf_cycles);
38test_fill_rect(void) { 38// PROF(txt_drawf("it's the greatest crime", 6, 8 * 5, 3), txt_drawf_cycles);
39 for (size_t i = 0; i < 100; i++) { 39// PROF(txt_drawf("- Emma Goldman", 100, 8 * 6 + 3, 3), txt_drawf_cycles);
40 draw_filled_rect(100, 0, 100 + i, i, 3); 40// txt_position(0, 10);
41 } 41// PROF(txt_printf("The only way to deal with an\n"
42} 42// "unfree world is to become\n"
43 43// "so absolutely free,\n"
44void 44// "that your very existence\n"
45test_chr(void) { 45// "is an act of rebellion.\n"), txt_printf_cycles);
46 u8 tile[16] = { 46// PROF(txt_printf("\n - Albert Camus\n"), txt_printf_cycles);
47 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00, 0x00, 0x00, 47// PROF(txt_render(), txt_render_cycles);
48 0x00, 0x00, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x00 48// PROF(txt_clear(), txt_clear_cycles);
49 }; 49// FRAME_END();
50// PROF_SHOW();
51// }
52// }
50 53
51 for (size_t y = 10; y < 20; y++) { 54int main(void) {
52 for (size_t x = 20; x < 30; x++) { 55 // Adjust system wait times.
53 draw_chr(8 + x * 8, 2 + y * 8, tile, 0, 0, 0); 56 SYSTEM_WAIT = SYSTEM_WAIT_CARTRIDGE;
54 }
55 }
56}
57
58void
59test_icn(void) {
60 u8 tile[8] = {
61 0xf8, 0xf8, 0xf8, 0xf8 | 0x3e, 0xf8 | 0x3e, 0x3e, 0x3e, 0x00,
62 };
63 57
64 for (size_t y = 10; y < 20; y++) { 58 // Initialize renderer.
65 for (size_t x = 10; x < 20; x++) { 59 renderer_init();
66 draw_icn(8 + x * 8, 2 + y * 8, tile, 7, 0, 1);
67 }
68 }
69}
70 60
71void 61 // Register interrupts.
72test_lines(void) { 62 irq_init();
73 for (size_t i = 0; i < 20; i++) { 63 irs_set(IRQ_VBLANK, irs_stub);
74 draw_line(0, i * 8, (30 * 8 - 1), ((20 - i) * 8 - 1), 5);
75 }
76 for (size_t i = 0; i < 30; i++) {
77 draw_line(i * 8, (20 * 8 - 1), ((30 - i) * 8 - 1), 0, 5);
78 }
79}
80 64
81void 65 u8 sc = 0;
82test_moving_line(void) { 66 u8 sd = 0;
83 int x = 0; 67 u8 si = 0;
84 int y = 0; 68 u8 so = 0;
85 int inc_x = 1; 69 bool update = true;
86 int inc_y = 0;
87 int should_move = 1;
88 screen_fill(3);
89 while (true) { 70 while (true) {
90 poll_keys(); 71 poll_keys();
72 flip_buffer();
91 if (key_tap(KEY_A)) { 73 if (key_tap(KEY_A)) {
92 break; 74 so = 1;
75 update = true;
93 } 76 }
94 if (key_pressed(KEY_B)) { 77 if (key_released(KEY_A)) {
95 should_move = 0; 78 so = 0;
96 } else { 79 update = true;
97 should_move = 1;
98 } 80 }
99 bios_vblank_wait(); 81 if (key_tap(KEY_B)) {
100 FRAME_START(); 82 si = 1;
101 PROF(flip_buffer(), flip_cycles); 83 update = true;
102#if FLIP_TYPE == 0
103 PROF(screen_fill(3), clear_cycles);
104#endif
105 PROF(draw_line(x, y, 239 - x, 159 - y, 3), line_cycles);
106 x += inc_x * should_move;
107 y += inc_y * should_move;
108 if (x == 239 && inc_x == 1) {
109 inc_x = 0;
110 inc_y = 1;
111 }
112 if (y == 159 && inc_y == 1) {
113 x = 0;
114 y = 0;
115 inc_x = 1;
116 inc_y = 0;
117 }
118 PROF(draw_line(x, y, 239 - x, 159 - y, 2), line_cycles);
119 FRAME_END();
120 PROF_SHOW();
121 }
122}
123
124void
125test_all_static(void) {
126 while (true) {
127 poll_keys();
128 if (key_tap(KEY_A)) {
129 break;
130 } 84 }
131 bios_vblank_wait(); 85 if (key_released(KEY_B)) {
132 FRAME_START(); 86 si = 0;
133 PROF(flip_buffer(), flip_cycles); 87 update = true;
134 PROF(test_clear(), clear_cycles);
135 PROF(test_lines(), line_cycles);
136 PROF(test_rect(), rect_cycles);
137 PROF(test_fill_rect(), fill_rect_cycles);
138 PROF(test_chr(), chr_cycles);
139 PROF(test_icn(), icn_cycles);
140 FRAME_END();
141 PROF_SHOW();
142 }
143}
144
145void
146test_growing_rects(void) {
147 typedef struct Rect {
148 int x0;
149 int y0;
150 int x1;
151 int y1;
152 } Rect;
153 Rect rects[] = {
154 {
155 SCREEN_WIDTH / 2 - 60,
156 SCREEN_HEIGHT / 2 - 30,
157 SCREEN_WIDTH / 2 + 60,
158 SCREEN_HEIGHT / 2 + 30,
159 },
160 {
161 SCREEN_WIDTH / 2 - 30,
162 SCREEN_HEIGHT / 2 - 60,
163 SCREEN_WIDTH / 2 + 30,
164 SCREEN_HEIGHT / 2 + 60,
165 },
166 };
167 while (true) {
168 poll_keys();
169 if (key_tap(KEY_A)) {
170 break;
171 } 88 }
172 if (key_pressed(KEY_B)) { 89 if (key_tap(KEY_L)) {
173 if (key_pressed(KEY_LEFT)) { 90 sc = 1;
174 rects[0].x0 = CLAMP(rects[0].x0 - 1, 0, SCREEN_WIDTH - 1); 91 update = true;
175 rects[0].x1 = CLAMP(rects[0].x1 + 1, 0, SCREEN_WIDTH - 1);
176 } else if (key_pressed(KEY_RIGHT)){
177 rects[0].x0 = CLAMP(rects[0].x0 + 1, 0, SCREEN_WIDTH - 1);
178 rects[0].x1 = CLAMP(rects[0].x1 - 1, 0, SCREEN_WIDTH - 1);
179 } else if (key_pressed(KEY_UP)){
180 rects[0].y0 = CLAMP(rects[0].y0 - 1, 0, SCREEN_HEIGHT - 1);
181 rects[0].y1 = CLAMP(rects[0].y1 + 1, 0, SCREEN_HEIGHT - 1);
182 } else if (key_pressed(KEY_DOWN)){
183 rects[0].y0 = CLAMP(rects[0].y0 + 1, 0, SCREEN_HEIGHT - 1);
184 rects[0].y1 = CLAMP(rects[0].y1 - 1, 0, SCREEN_HEIGHT - 1);
185 }
186 } else {
187 if (key_pressed(KEY_LEFT)) {
188 rects[1].x0 = CLAMP(rects[1].x0 - 1, 0, SCREEN_WIDTH - 1);
189 rects[1].x1 = CLAMP(rects[1].x1 + 1, 0, SCREEN_WIDTH - 1);
190 } else if (key_pressed(KEY_RIGHT)){
191 rects[1].x0 = CLAMP(rects[1].x0 + 1, 0, SCREEN_WIDTH - 1);
192 rects[1].x1 = CLAMP(rects[1].x1 - 1, 0, SCREEN_WIDTH - 1);
193 } else if (key_pressed(KEY_UP)){
194 rects[1].y0 = CLAMP(rects[1].y0 - 1, 0, SCREEN_HEIGHT - 1);
195 rects[1].y1 = CLAMP(rects[1].y1 + 1, 0, SCREEN_HEIGHT - 1);
196 } else if (key_pressed(KEY_DOWN)){
197 rects[1].y0 = CLAMP(rects[1].y0 + 1, 0, SCREEN_HEIGHT - 1);
198 rects[1].y1 = CLAMP(rects[1].y1 - 1, 0, SCREEN_HEIGHT - 1);
199 }
200 } 92 }
201 bios_vblank_wait(); 93 if (key_released(KEY_L)) {
202 FRAME_START(); 94 sc = 0;
203 PROF(flip_buffer(), flip_cycles); 95 update = true;
204 PROF(screen_fill(0), clear_cycles);
205 PROF(draw_filled_rect(
206 rects[0].x0,
207 rects[0].y0,
208 rects[0].x1,
209 rects[0].y1,
210 2), rect_cycles);
211 PROF(draw_rect(
212 rects[1].x0,
213 rects[1].y0,
214 rects[1].x1,
215 rects[1].y1,
216 3), fill_rect_cycles);
217 FRAME_END();
218 PROF_SHOW();
219 }
220}
221
222void
223test_sprites_bounce(void) {
224 u8 sprite_icn[8] = {
225 0xf8, 0xf8, 0xf8, 0xf8 | 0x3e, 0xf8 | 0x3e, 0x3e, 0x3e, 0x00,
226 };
227 u8 sprite_chr[16] = {
228 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00, 0x00, 0x00,
229 0x00, 0x00, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x00,
230 };
231 typedef struct Sprite {
232 int x;
233 int y;
234 int inc_x;
235 int inc_y;
236 int clr;
237 int flip_x;
238 int flip_y;
239 } Sprite;
240 Sprite sprites[] = {
241 {50 , 50 , 1 , 1 , 0 , 0 , 0},
242 {20 , 30 , 2 , 3 , 1 , 0 , 1},
243 {10 , 100 , -2 , -1 , 2 , 1 , 0},
244 {200 , 75 , 1 , -2 , 3 , 1 , 1},
245 {55 , 45 , -1 , 1 , 4 , 0 , 0},
246 {25 , 35 , 2 , -3 , 5 , 0 , 1},
247 {15 , 95 , -2 , 1 , 6 , 1 , 0},
248 {210 , 75 , 1 , 2 , 15 , 1 , 1},
249 };
250 int should_move = 1;
251 screen_fill(8);
252 flip_buffer();
253 while (true) {
254 poll_keys();
255 if (key_tap(KEY_A)) {
256 break;
257 } 96 }
258 if (key_pressed(KEY_B)) { 97 if (key_tap(KEY_R)) {
259 should_move = 0; 98 sd = 1;
260 } else { 99 update = true;
261 should_move = 1;
262 } 100 }
263 bios_vblank_wait(); 101 if (key_released(KEY_R)) {
264 FRAME_START(); 102 sd = 0;
265 PROF(flip_buffer(), flip_cycles); 103 update = true;
266#if FLIP_TYPE == 0
267 PROF(screen_fill(8), clear_cycles);
268#endif
269 for (size_t i = 0; i < LEN(sprites) * should_move; i++) {
270 Sprite *s = &sprites[i];
271 PROF(draw_icn(
272 s->x, s->y,
273 sprite_icn,
274 8,
275 s->flip_x, s->flip_y), icn_cycles);
276 PROF(draw_chr(
277 (240 - s->x - 8), (160 - s->y - 8),
278 sprite_chr,
279 8,
280 s->flip_x, s->flip_y), chr_cycles);
281 s->x += s->inc_x;
282 s->y += s->inc_y;
283 PROF(draw_icn(
284 s->x, s->y,
285 sprite_icn,
286 s->clr,
287 s->flip_x, s->flip_y), icn_cycles);
288 PROF(draw_chr(
289 (240 - s->x - 8), (160 - s->y - 8),
290 sprite_chr,
291 s->clr,
292 s->flip_x, s->flip_y), chr_cycles);
293 if (s->x >= (240 - 8) && s->inc_x > 0) {
294 s->inc_x *= -1;
295 } else if (s->x <= 0 && s->inc_x < 0){
296 s->inc_x *= -1;
297 }
298 if (s->y >= (160 - 8) && s->inc_y > 0) {
299 s->inc_y *= -1;
300 } else if (s->y <= 0 && s->inc_y < 0){
301 s->inc_y *= -1;
302 }
303 } 104 }
304 FRAME_END(); 105 if (update) {
305 PROF_SHOW(); 106 SIO_MODE = SIO_MODE_GP
306 } 107 | SIO_SC_OUT(1)
307} 108 | SIO_SD_OUT(1)
308 109 | SIO_SI_OUT(1)
309void 110 | SIO_SO_OUT(1)
310test_text_rendering(void) { 111 | SIO_SC(sc)
311 while (true) { 112 | SIO_SD(sd)
312 poll_keys(); 113 | SIO_SI(si)
313 if (key_tap(KEY_A)) { 114 | SIO_SO(so);
314 break; 115 update = false;
315 } 116 }
117 screen_fill(0);
316 bios_vblank_wait(); 118 bios_vblank_wait();
317 FRAME_START(); 119 txt_clear();
318 PROF(flip_buffer(), flip_cycles); 120 txt_printf("----- LINK CABLE TESTER -----\n\n");
319 PROF(screen_fill(0), clear_cycles); 121 txt_printf("SC: %d\n", sc);
320 txt_color(2); 122 txt_printf("SD: %d\n", sd);
321 PROF(txt_drawf("The strongest bulwark of", 4, 8 * 2, 3), txt_drawf_cycles); 123 txt_printf("SI: %d\n", si);
322 PROF(txt_drawf("authority is uniformity;", 2, 8 * 3, 3), txt_drawf_cycles); 124 txt_printf("SO: %d\n", so);
323 PROF(txt_drawf("the least divergence from it", 8, 8 * 4, 3), txt_drawf_cycles); 125 txt_render();
324 PROF(txt_drawf("it's the greatest crime", 6, 8 * 5, 3), txt_drawf_cycles);
325 PROF(txt_drawf("- Emma Goldman", 100, 8 * 6 + 3, 3), txt_drawf_cycles);
326 txt_position(0, 10);
327 PROF(txt_printf("The only way to deal with an\n"
328 "unfree world is to become\n"
329 "so absolutely free,\n"
330 "that your very existence\n"
331 "is an act of rebellion.\n"), txt_printf_cycles);
332 PROF(txt_printf("\n - Albert Camus\n"), txt_printf_cycles);
333 PROF(txt_render(), txt_render_cycles);
334 PROF(txt_clear(), txt_clear_cycles);
335 FRAME_END();
336 PROF_SHOW();
337 }
338}
339
340int main(void) {
341 // Adjust system wait times.
342 SYSTEM_WAIT = SYSTEM_WAIT_CARTRIDGE;
343
344 // Initialize renderer.
345 renderer_init();
346
347 // Register interrupts.
348 irq_init();
349 irs_set(IRQ_VBLANK, irs_stub);
350
351 while (true) {
352 test_sprites_bounce();
353 test_text_rendering();
354 test_growing_rects();
355 test_moving_line();
356 test_all_static();
357 } 126 }
358 127
359 return 0; 128 return 0;
diff --git a/src/profiling.c b/src/profiling.c
index 90215c8..ecd7118 100644
--- a/src/profiling.c
+++ b/src/profiling.c
@@ -9,7 +9,7 @@
9#if PROF_ENABLE > 0 && PROF_ENABLE < 3 9#if PROF_ENABLE > 0 && PROF_ENABLE < 3
10 10
11#ifndef PROF_N_FRAMES 11#ifndef PROF_N_FRAMES
12#define PROF_N_FRAMES 30 12#define PROF_N_FRAMES 15
13#endif 13#endif
14 14
15// Profile method 1: Average per N frames. 15// Profile method 1: Average per N frames.
@@ -76,17 +76,17 @@ static bool profile_bg_show = true;
76 if (profile_bg_show) {\ 76 if (profile_bg_show) {\
77 u32 frame_time =\ 77 u32 frame_time =\
78 FP_DIV(\ 78 FP_DIV(\
79 FP_NUM(avg_frame_cycles + 1, 2),\ 79 FP_NUM(avg_frame_cycles + 1, 2) * 166,\
80 FP_NUM(2809, 2),\ 80 FP_NUM(280896, 2) / 100,\
81 2) * 166;\ 81 2);\
82 u32 fps =\ 82 u32 fps =\
83 FP_DIV(\ 83 FP_DIV(\
84 FP_NUM(280896 * 60, 2),\ 84 FP_NUM(280896, 2),\
85 FP_NUM(avg_frame_cycles + 1, 2),\ 85 FP_NUM(avg_frame_cycles + 1, 2),\
86 2);\ 86 2) * 60;\
87 draw_filled_rect(8 * 18, 0, 239, 16, 0);\ 87 draw_filled_rect(8 * 18, 0, 239, 16, 0);\
88 txt_drawf("TIME: %.6lu", 8 * 18, 0, 1, frame_time >> 2);\ 88 txt_drawf("TIME: %.6d", 8 * 18, 0, 1, frame_time >> 2);\
89 txt_drawf("MAX FPS:%.4lu", 8 * 18, 8, 1, (fps >> 2) + 1);\ 89 txt_drawf("MAX FPS:%.4d", 8 * 18, 8, 1, (fps >> 2) + 1);\
90 }\ 90 }\
91 } while (0) 91 } while (0)
92 92