diff --git a/sw/bootloader/Makefile b/sw/bootloader/Makefile index 5bf497b..1156cc2 100644 --- a/sw/bootloader/Makefile +++ b/sw/bootloader/Makefile @@ -19,6 +19,7 @@ SRC_FILES = \ startup.S \ boot.c \ crc32.c \ + display.c \ error.c \ exception.c \ exception.S \ @@ -31,6 +32,7 @@ SRC_FILES = \ sc64.c \ storage.c \ syscalls.c \ + test.c \ version.c \ fatfs/diskio.c \ fatfs/ff.c \ diff --git a/sw/bootloader/src/display.c b/sw/bootloader/src/display.c new file mode 100644 index 0000000..a9255e2 --- /dev/null +++ b/sw/bootloader/src/display.c @@ -0,0 +1,150 @@ +#include +#include "display.h" +#include "font.h" +#include "io.h" + + +#define SCREEN_WIDTH (640) +#define SCREEN_HEIGHT (240) +#define BORDER_WIDTH (32) +#define BORDER_HEIGHT (16) + +#define BACKGROUND_COLOR (0x00000000UL) +#define TEXT_COLOR (0xFFFFFFFFUL) +#define LINE_HEIGHT (10) + + +static io32_t display_framebuffer[SCREEN_WIDTH * SCREEN_HEIGHT] __attribute__((aligned(64))); +static int char_x; +static int char_y; +static const vi_regs_t vi_config[] = {{ + .CR = ( + VI_CR_PIXEL_ADVANCE_1 | + VI_CR_PIXEL_ADVANCE_0 | + VI_CR_ANTIALIAS_1 | + VI_CR_ANTIALIAS_0 | + VI_CR_TYPE_32 + ), + .H_WIDTH = SCREEN_WIDTH, + .V_INTR = 0x000003FF, + .CURR_LINE = 0x00000000, + .TIMING = 0x0404233A, + .V_SYNC = 0x00000271, + .H_SYNC = 0x00150C69, + .H_SYNC_LEAP = 0x0C6F0C6E, + .H_LIMITS = 0x00800300, + .V_LIMITS = 0x005D023D, + .COLOR_BURST = 0x00090268, + .H_SCALE = 0x00000400, + .V_SCALE = 0x00000400, +}, { + .CR = ( + VI_CR_PIXEL_ADVANCE_1 | + VI_CR_PIXEL_ADVANCE_0 | + VI_CR_ANTIALIAS_1 | + VI_CR_ANTIALIAS_0 | + VI_CR_TYPE_32 + ), + .H_WIDTH = SCREEN_WIDTH, + .V_INTR = 0x000003FF, + .CURR_LINE = 0x00000000, + .TIMING = 0x03E52239, + .V_SYNC = 0x0000020D, + .H_SYNC = 0x00000C15, + .H_SYNC_LEAP = 0x0C150C15, + .H_LIMITS = 0x006C02EC, + .V_LIMITS = 0x00230203, + .COLOR_BURST = 0x000E0204, + .H_SCALE = 0x00000400, + .V_SCALE = 0x00000400, +}}; + + +static void display_draw_character (char c) { + if (c == '\n') { + char_x = BORDER_WIDTH; + char_y += LINE_HEIGHT; + return; + } + + if ((char_x + FONT_WIDTH) > (SCREEN_WIDTH - BORDER_WIDTH)) { + char_x = BORDER_WIDTH; + char_y += LINE_HEIGHT; + } + + if ((c < ' ') || (c > '~')) { + c = '\x7F'; + } + + for (int i = 0; i < (FONT_WIDTH * FONT_HEIGHT); i++) { + int c_x = char_x + (i % FONT_WIDTH); + int c_y = char_y + (i / FONT_WIDTH); + + if ((c_x >= (SCREEN_WIDTH - BORDER_WIDTH)) || (c_y >= (SCREEN_HEIGHT - BORDER_HEIGHT))) { + break; + } + + if (font_data[c - ' '][i / 8] & (1 << (i % 8))) { + int screen_offset = c_x + (c_y * SCREEN_WIDTH); + io_write(&display_framebuffer[screen_offset], TEXT_COLOR); + } + } + + char_x += FONT_WIDTH; +} + +static void display_draw_string (const char *s) { + while (*s != '\0') { + display_draw_character(*s++); + } +} + + +void display_init (uint32_t *background) { + const vi_regs_t *cfg = &vi_config[OS_INFO->tv_type]; + + char_x = BORDER_WIDTH; + char_y = BORDER_HEIGHT; + + if (background == NULL) { + for (int i = 0; i < (SCREEN_WIDTH * SCREEN_HEIGHT); i += 1) { + display_framebuffer[i] = BACKGROUND_COLOR; + } + } else { + for (int i = 0; i < (SCREEN_WIDTH * SCREEN_HEIGHT); i += 2) { + display_framebuffer[i] = *background; + display_framebuffer[i + 1] = *background; + background++; + } + } + + io_write(&VI->MADDR, (uint32_t) (display_framebuffer)); + io_write(&VI->H_WIDTH, cfg->H_WIDTH); + io_write(&VI->V_INTR, cfg->V_INTR); + io_write(&VI->CURR_LINE, cfg->CURR_LINE); + io_write(&VI->TIMING, cfg->TIMING); + io_write(&VI->V_SYNC, cfg->V_SYNC); + io_write(&VI->H_SYNC, cfg->H_SYNC); + io_write(&VI->H_SYNC_LEAP, cfg->H_SYNC_LEAP); + io_write(&VI->H_LIMITS, cfg->H_LIMITS); + io_write(&VI->V_LIMITS, cfg->V_LIMITS); + io_write(&VI->COLOR_BURST, cfg->COLOR_BURST); + io_write(&VI->H_SCALE, cfg->H_SCALE); + io_write(&VI->V_SCALE, cfg->V_SCALE); + io_write(&VI->CR, cfg->CR); +} + +void display_vprintf (const char *fmt, va_list args) { + char line[256]; + + vsniprintf(line, sizeof(line), fmt, args); + display_draw_string(line); +} + +void display_printf (const char* fmt, ...) { + va_list args; + + va_start(args, fmt); + display_vprintf(fmt, args); + va_end(args); +} diff --git a/sw/bootloader/src/display.h b/sw/bootloader/src/display.h new file mode 100644 index 0000000..0ef73e3 --- /dev/null +++ b/sw/bootloader/src/display.h @@ -0,0 +1,14 @@ +#ifndef DISPLAY_H__ +#define DISPLAY_H__ + + +#include +#include + + +void display_init (uint32_t *background); +void display_vprintf (const char *fmt, va_list args); +void display_printf (const char* fmt, ...); + + +#endif diff --git a/sw/bootloader/src/exception.c b/sw/bootloader/src/exception.c index 457573a..8c85641 100644 --- a/sw/bootloader/src/exception.c +++ b/sw/bootloader/src/exception.c @@ -1,8 +1,7 @@ #include -#include +#include "display.h" #include "exception_regs.h" #include "exception.h" -#include "font.h" #include "io.h" #include "sc64.h" #include "version.h" @@ -18,143 +17,6 @@ #define SYSCALL_CODE_MASK (0x03FFFFC0UL) #define SYSCALL_CODE_BIT (6) -#define SCREEN_WIDTH (640) -#define SCREEN_HEIGHT (240) -#define BORDER_WIDTH (32) -#define BORDER_HEIGHT (16) - -#define TEXT_COLOR (0xFFFFFFFFUL) -#define LINE_HEIGHT (10) - - -static io32_t exception_framebuffer[SCREEN_WIDTH * SCREEN_HEIGHT] __attribute__((aligned(64))); -static int char_x; -static int char_y; -static const vi_regs_t vi_config[] = {{ - .CR = ( - VI_CR_PIXEL_ADVANCE_1 | - VI_CR_PIXEL_ADVANCE_0 | - VI_CR_ANTIALIAS_1 | - VI_CR_ANTIALIAS_0 | - VI_CR_TYPE_32 - ), - .H_WIDTH = SCREEN_WIDTH, - .V_INTR = 0x000003FF, - .CURR_LINE = 0x00000000, - .TIMING = 0x0404233A, - .V_SYNC = 0x00000271, - .H_SYNC = 0x00150C69, - .H_SYNC_LEAP = 0x0C6F0C6E, - .H_LIMITS = 0x00800300, - .V_LIMITS = 0x005D023D, - .COLOR_BURST = 0x00090268, - .H_SCALE = 0x00000400, - .V_SCALE = 0x00000400, -}, { - .CR = ( - VI_CR_PIXEL_ADVANCE_1 | - VI_CR_PIXEL_ADVANCE_0 | - VI_CR_ANTIALIAS_1 | - VI_CR_ANTIALIAS_0 | - VI_CR_TYPE_32 - ), - .H_WIDTH = SCREEN_WIDTH, - .V_INTR = 0x000003FF, - .CURR_LINE = 0x00000000, - .TIMING = 0x03E52239, - .V_SYNC = 0x0000020D, - .H_SYNC = 0x00000C15, - .H_SYNC_LEAP = 0x0C150C15, - .H_LIMITS = 0x006C02EC, - .V_LIMITS = 0x00230203, - .COLOR_BURST = 0x000E0204, - .H_SCALE = 0x00000400, - .V_SCALE = 0x00000400, -}}; - - -static void exception_init_screen (void) { - const vi_regs_t *cfg = &vi_config[OS_INFO->tv_type]; - uint32_t *background_data = (uint32_t *) (&assets_exception_background); - - char_x = BORDER_WIDTH; - char_y = BORDER_HEIGHT; - - for (int i = 0; i < (SCREEN_WIDTH * SCREEN_HEIGHT); i += 2) { - io_write(&exception_framebuffer[i], *background_data); - io_write(&exception_framebuffer[i + 1], *background_data); - background_data++; - } - - io_write(&VI->MADDR, (uint32_t) (exception_framebuffer)); - io_write(&VI->H_WIDTH, cfg->H_WIDTH); - io_write(&VI->V_INTR, cfg->V_INTR); - io_write(&VI->CURR_LINE, cfg->CURR_LINE); - io_write(&VI->TIMING, cfg->TIMING); - io_write(&VI->V_SYNC, cfg->V_SYNC); - io_write(&VI->H_SYNC, cfg->H_SYNC); - io_write(&VI->H_SYNC_LEAP, cfg->H_SYNC_LEAP); - io_write(&VI->H_LIMITS, cfg->H_LIMITS); - io_write(&VI->V_LIMITS, cfg->V_LIMITS); - io_write(&VI->COLOR_BURST, cfg->COLOR_BURST); - io_write(&VI->H_SCALE, cfg->H_SCALE); - io_write(&VI->V_SCALE, cfg->V_SCALE); - io_write(&VI->CR, cfg->CR); -} - -static void exception_draw_character (char c) { - if (c == '\n') { - char_x = BORDER_WIDTH; - char_y += LINE_HEIGHT; - return; - } - - if ((char_x + FONT_WIDTH) > (SCREEN_WIDTH - BORDER_WIDTH)) { - char_x = BORDER_WIDTH; - char_y += LINE_HEIGHT; - } - - if ((c < ' ') || (c > '~')) { - c = '\x7F'; - } - - for (int i = 0; i < (FONT_WIDTH * FONT_HEIGHT); i++) { - int c_x = char_x + (i % FONT_WIDTH); - int c_y = char_y + (i / FONT_WIDTH); - - if ((c_x >= (SCREEN_WIDTH - BORDER_WIDTH)) || (c_y >= (SCREEN_HEIGHT - BORDER_HEIGHT))) { - break; - } - - if (font_data[c - ' '][i / 8] & (1 << (i % 8))) { - int screen_offset = c_x + (c_y * SCREEN_WIDTH); - io_write(&exception_framebuffer[screen_offset], TEXT_COLOR); - } - } - - char_x += FONT_WIDTH; -} - -static void exception_print_string (const char *s) { - while (*s != '\0') { - exception_draw_character(*s++); - } -} - -static void exception_vprint (const char *fmt, va_list args) { - char line[256]; - - vsniprintf(line, sizeof(line), fmt, args); - exception_print_string(line); -} - -static void exception_print (const char* fmt, ...) { - va_list args; - - va_start(args, fmt); - exception_vprint(fmt, args); - va_end(args); -} static const char *exception_get_description (uint8_t exception_code) { switch (exception_code) { @@ -185,28 +47,28 @@ void exception_fatal_handler (uint32_t exception_code, uint32_t interrupt_mask, uint32_t sc64_version = pi_io_read(&SC64_REGS->VERSION); uint32_t *instruction_address = (((uint32_t *) (e->epc.u32)) + ((e->cr & C0_CR_BD) ? 1 : 0)); - exception_init_screen(); + display_init((uint32_t *) (&assets_exception_background)); - exception_print("branch: %s | tag: %s\n", version->git_branch, version->git_tag); - exception_print("sha: %s\n", version->git_sha); - exception_print("%s\n\n", version->git_message); + display_printf("branch: %s | tag: %s\n", version->git_branch, version->git_tag); + display_printf("sha: %s\n", version->git_sha); + display_printf("%s\n\n", version->git_message); - exception_print("%s\n\n", exception_get_description(exception_code)); + display_printf("%s\n\n", exception_get_description(exception_code)); - exception_print("pc: 0x%08lX sr: 0x%08lX cr: 0x%08lX hw: 0x%08lX\n", e->epc.u32, e->sr, e->cr, sc64_version); - exception_print("zr: 0x%08lX at: 0x%08lX v0: 0x%08lX v1: 0x%08lX\n", e->zr.u32, e->at.u32, e->v0.u32, e->v1.u32); - exception_print("a0: 0x%08lX a1: 0x%08lX a2: 0x%08lX a3: 0x%08lX\n", e->a0.u32, e->a1.u32, e->a2.u32, e->a3.u32); - exception_print("t0: 0x%08lX t1: 0x%08lX t2: 0x%08lX t3: 0x%08lX\n", e->t0.u32, e->t1.u32, e->t2.u32, e->t3.u32); - exception_print("t4: 0x%08lX t5: 0x%08lX t6: 0x%08lX t7: 0x%08lX\n", e->t4.u32, e->t5.u32, e->t6.u32, e->t7.u32); - exception_print("s0: 0x%08lX s1: 0x%08lX s2: 0x%08lX s3: 0x%08lX\n", e->s0.u32, e->s1.u32, e->s2.u32, e->s3.u32); - exception_print("s4: 0x%08lX s5: 0x%08lX s6: 0x%08lX s7: 0x%08lX\n", e->s4.u32, e->s5.u32, e->s6.u32, e->s7.u32); - exception_print("t8: 0x%08lX t9: 0x%08lX k0: 0x%08lX k1: 0x%08lX\n", e->t8.u32, e->t9.u32, e->k0.u32, e->k1.u32); - exception_print("gp: 0x%08lX sp: 0x%08lX s8: 0x%08lX ra: 0x%08lX\n\n", e->gp.u32, e->sp.u32, e->s8.u32, e->ra.u32); + display_printf("pc: 0x%08lX sr: 0x%08lX cr: 0x%08lX hw: 0x%08lX\n", e->epc.u32, e->sr, e->cr, sc64_version); + display_printf("zr: 0x%08lX at: 0x%08lX v0: 0x%08lX v1: 0x%08lX\n", e->zr.u32, e->at.u32, e->v0.u32, e->v1.u32); + display_printf("a0: 0x%08lX a1: 0x%08lX a2: 0x%08lX a3: 0x%08lX\n", e->a0.u32, e->a1.u32, e->a2.u32, e->a3.u32); + display_printf("t0: 0x%08lX t1: 0x%08lX t2: 0x%08lX t3: 0x%08lX\n", e->t0.u32, e->t1.u32, e->t2.u32, e->t3.u32); + display_printf("t4: 0x%08lX t5: 0x%08lX t6: 0x%08lX t7: 0x%08lX\n", e->t4.u32, e->t5.u32, e->t6.u32, e->t7.u32); + display_printf("s0: 0x%08lX s1: 0x%08lX s2: 0x%08lX s3: 0x%08lX\n", e->s0.u32, e->s1.u32, e->s2.u32, e->s3.u32); + display_printf("s4: 0x%08lX s5: 0x%08lX s6: 0x%08lX s7: 0x%08lX\n", e->s4.u32, e->s5.u32, e->s6.u32, e->s7.u32); + display_printf("t8: 0x%08lX t9: 0x%08lX k0: 0x%08lX k1: 0x%08lX\n", e->t8.u32, e->t9.u32, e->k0.u32, e->k1.u32); + display_printf("gp: 0x%08lX sp: 0x%08lX s8: 0x%08lX ra: 0x%08lX\n\n", e->gp.u32, e->sp.u32, e->s8.u32, e->ra.u32); if (exception_code == EXCEPTION_INTERRUPT) { if (interrupt_mask & INTERRUPT_MASK_TIMER) { exception_disable_watchdog(); - exception_print("Still loading after 3 second limit...\n\n"); + display_printf("Still loading after 3 second limit...\n\n"); return; } } else if (exception_code == EXCEPTION_SYSCALL) { @@ -215,8 +77,8 @@ void exception_fatal_handler (uint32_t exception_code, uint32_t interrupt_mask, if (code == TRIGGER_CODE_ERROR) { const char *fmt = (const char *) (e->a0.u32); va_list args = *((va_list *) (e->sp.u32)); - exception_vprint(fmt, args); - exception_print("\n"); + display_vprintf(fmt, args); + display_printf("\n"); } } diff --git a/sw/bootloader/src/init.c b/sw/bootloader/src/init.c index 270760f..fbe80fe 100644 --- a/sw/bootloader/src/init.c +++ b/sw/bootloader/src/init.c @@ -2,6 +2,7 @@ #include "exception.h" #include "io.h" #include "sc64.h" +#include "test.h" void init (void) { @@ -18,6 +19,11 @@ void init (void) { exception_enable_interrupts(); sc64_init(); + + if (test_check()) { + exception_disable_watchdog(); + test_execute(); + } } void deinit (void) { diff --git a/sw/bootloader/src/sc64.h b/sw/bootloader/src/sc64.h index e984747..704f3dd 100644 --- a/sw/bootloader/src/sc64.h +++ b/sw/bootloader/src/sc64.h @@ -19,6 +19,8 @@ typedef enum { CFG_ID_FLASH_ERASE_BLOCK, CFG_ID_DD_DRIVE_TYPE, CFG_ID_DD_DISK_STATE, + CFG_ID_BUTTON_STATE, + CFG_ID_BUTTON_MODE, } cfg_id_t; typedef enum { @@ -56,6 +58,13 @@ typedef enum { TV_TYPE_UNKNOWN = 3 } tv_type_t; +typedef enum { + BUTTON_MODE_NONE, + BUTTON_MODE_N64_IRQ, + BUTTON_MODE_USB_PACKET, + BUTTON_MODE_DD_DISK_SWAP, +} button_mode_t; + typedef struct { boot_mode_t boot_mode; diff --git a/sw/bootloader/src/test.c b/sw/bootloader/src/test.c new file mode 100644 index 0000000..e616be0 --- /dev/null +++ b/sw/bootloader/src/test.c @@ -0,0 +1,22 @@ +#include +#include "display.h" +#include "sc64.h" +#include "test.h" + + +bool test_check (void) { + if (sc64_query_config(CFG_ID_BUTTON_STATE)) { + return true; + } + return false; +} + +void test_execute (void) { + display_init(NULL); + + display_printf("SC64 Test suite\n"); + + // TODO: implement tests + + while (1); +} diff --git a/sw/bootloader/src/test.h b/sw/bootloader/src/test.h new file mode 100644 index 0000000..a56bcd8 --- /dev/null +++ b/sw/bootloader/src/test.h @@ -0,0 +1,12 @@ +#ifndef TEST_H__ +#define TEST_H__ + + +#include + + +bool test_check (void); +void test_execute (void); + + +#endif