#include <3ds.h> #include "../gc.h" #include "../platform.h" #include "../util.h" #include #include #include #include /** * These cache-size details are from * https://www.copetti.org/writings/consoles/nintendo-3ds/. We call the second * level of cache (only available on N3DS) L3, since the GC design only cares * about L1D and L3. */ size_t get_l1d_size(void) { return 16 * 1024; } size_t get_l3_size(void) { return 2 * 1024 * 1024; } uintptr_t alloc_gc_region(size_t size) { void *ptr = malloc(size); assume(ptr != NULL); return (uintptr_t)ptr; } void clear_gc_region(uintptr_t addr, size_t size) { memset((void *)addr, 0, size); } void panic_begin(void) { consoleInit(GFX_TOP, NULL); } noreturn void panic_end(void) { printf("\nPress Start to exit.\n"); while (aptMainLoop()) { hidScanInput(); u32 keys = hidKeysDown(); if (keys & KEY_START) break; gfxFlushBuffers(); gfxSwapBuffers(); gspWaitForVBlank(); } gfxExit(); exit(1); } int main(int argc, char **argv) { gfxInit(GSP_BGR8_OES, GSP_BGR8_OES, false); gc_init(); bootstrap(); // Initialize console on top screen. Using NULL as the second argument tells // the console library to use the internal console structure as current one consoleInit(GFX_TOP, NULL); // Move the cursor to row 15 and column 19 and then prints "Hello World!" // To move the cursor you have to print "\x1b[r;cH", where r and c are // respectively the row and column where you want your cursor to move The top // screen has 30 rows and 50 columns The bottom screen has 30 rows and 40 // columns printf("\x1b[16;20HHello World!"); printf("\x1b[29;16HPress Start to exit.\n"); // Main loop const struct value ZERO = {.bits = (0 << 2) | TAG_FIXNUM}; struct object *values = gc_alloc(64, 0); struct object *value_slot_counts = gc_alloc(64, 0); gc_root_push(&values); gc_root_push(&value_slot_counts); bool gc_test = false; while (aptMainLoop()) { // Scan all the inputs. This should be done once for each frame hidScanInput(); // hidKeysDown returns information about which buttons have been just // pressed (and they weren't in the previous frame) u32 kDown = hidKeysDown(); if (kDown & KEY_START) break; // break in order to return to hbmenu if (kDown & KEY_A) gc_test = true; circlePosition pos; hidCircleRead(&pos); printf("\x1b[0;0H\x1b[K(%" PRId16 ", %" PRId16 ")\n", pos.dx, pos.dy); if (gc_test) { for (size_t j = 0; j < 1000; j++) { if ((rand() & 0b11) == 0) { size_t value_slot_count = rand() & 7; if (!value_slot_count) value_slot_count = 1; size_t untraced_slot_count = rand() & 7; struct value value = alloc_builtin_object(ZERO, value_slot_count, untraced_slot_count); size_t i = rand() % 63; gc_write_value_slot(values, i, value); gc_write_value_slot(value_slot_counts, i, integer_of_int(value_slot_count)); } else { size_t i = rand() & 63; struct value value = gc_read_value_slot(values, i); struct value value_slot_count_value = gc_read_value_slot(value_slot_counts, i); if (!value.bits) continue; assume(get_tag(value) == TAG_BUILTIN_OBJECT); assume(get_tag(value_slot_count_value) == TAG_FIXNUM); struct object *obj = untag_ptr(value); intptr_t value_slot_count = untag_fixnum(value_slot_count_value); size_t j = rand() % value_slot_count; size_t k = rand() % 63; gc_write_value_slot(obj, j, gc_read_value_slot(values, k)); } } gc_debug(); } /* // Get the bottom screen's frame buffer u16 w, h; u8 *fb = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, &w, &h); for (u16 j = 0; j < h; j++) { for (u16 i = 0; i < w; i++) { *fb++ = (u8)(((float)i / (float)w) * 255.0); *fb++ = (u8)(((float)j / (float)h) * 255.0); *fb++ = 0x00; } } // Flush and swap framebuffers gfxFlushBuffers(); gfxSwapBuffers(); */ // Wait for VBlank gspWaitForVBlank(); } gfxExit(); return 0; }