mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-26 07:34:15 +01:00
handle irq in the bootloader
This commit is contained in:
parent
31ea6e6016
commit
7d8614e456
@ -11,7 +11,7 @@ N64_ELFCOMPRESS = $(N64_BINDIR)/n64elfcompress
|
|||||||
N64_TOOL = $(N64_BINDIR)/n64tool
|
N64_TOOL = $(N64_BINDIR)/n64tool
|
||||||
PYTHON = python3
|
PYTHON = python3
|
||||||
|
|
||||||
FLAGS = -march=vr4300 -mtune=vr4300 $(USER_FLAGS)
|
FLAGS = -march=vr4300 -mtune=vr4300 -mfix4300 $(USER_FLAGS)
|
||||||
CFLAGS = -Os -Wall -ffunction-sections -fdata-sections -ffreestanding -MMD -MP
|
CFLAGS = -Os -Wall -ffunction-sections -fdata-sections -ffreestanding -MMD -MP
|
||||||
ASFLAGS = -Wa,-I$(N64_INST)/mips64-elf/lib
|
ASFLAGS = -Wa,-I$(N64_INST)/mips64-elf/lib
|
||||||
LDFLAGS = -lc -nostartfiles -Wl,--gc-sections
|
LDFLAGS = -lc -nostartfiles -Wl,--gc-sections
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
@ -181,6 +180,10 @@ void display_init (uint32_t *background) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool display_ready (void) {
|
||||||
|
return vi_configured;
|
||||||
|
}
|
||||||
|
|
||||||
void display_vprintf (const char *fmt, va_list args) {
|
void display_vprintf (const char *fmt, va_list args) {
|
||||||
char line[256];
|
char line[256];
|
||||||
|
|
||||||
|
@ -3,10 +3,12 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
void display_init (uint32_t *background);
|
void display_init (uint32_t *background);
|
||||||
|
bool display_ready (void);
|
||||||
void display_vprintf (const char *fmt, va_list args);
|
void display_vprintf (const char *fmt, va_list args);
|
||||||
void display_printf (const char* fmt, ...);
|
void display_printf (const char* fmt, ...);
|
||||||
|
|
||||||
|
@ -1,13 +1,23 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include "exception.h"
|
#include "display.h"
|
||||||
|
#include "init.h"
|
||||||
|
#include "version.h"
|
||||||
|
#include "../assets/assets.h"
|
||||||
|
|
||||||
|
|
||||||
void error_display (const char *fmt, ...) {
|
void error_display (const char *fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
|
deinit();
|
||||||
|
|
||||||
|
display_init((uint32_t *) (&assets_sc64_logo_640_240_dimmed));
|
||||||
|
|
||||||
|
version_print();
|
||||||
|
display_printf("[ Runtime error ]\n");
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
EXCEPTION_TRIGGER(TRIGGER_CODE_ERROR);
|
display_vprintf(fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
display_printf("\n");
|
||||||
|
|
||||||
while (1);
|
while (1);
|
||||||
}
|
}
|
||||||
|
@ -96,17 +96,11 @@ exception_handler:
|
|||||||
move $sp, $k0
|
move $sp, $k0
|
||||||
|
|
||||||
exception_check_type:
|
exception_check_type:
|
||||||
mfc0 $a0, C0_CAUSE
|
mfc0 $t0, C0_CAUSE
|
||||||
sw $a0, C0_CAUSE_OFFSET($k0)
|
sw $t0, C0_CAUSE_OFFSET($k0)
|
||||||
move $a1, $a0
|
andi $a0, $t0, C0_CR_EC_MASK
|
||||||
move $t0, $a0
|
srl $a0, C0_CR_EC_BIT
|
||||||
andi $t0, C0_CR_IP7
|
beqz $a0, exception_interrupt
|
||||||
andi $a0, C0_CR_EC_MASK
|
|
||||||
srl $a0, $a0, C0_CR_EC_BIT
|
|
||||||
andi $a1, C0_CR_IP_MASK
|
|
||||||
srl $a1, $a1, C0_CR_IP_BIT
|
|
||||||
bne $t0, $zero, exception_fatal
|
|
||||||
beq $a0, $zero, exception_interrupt
|
|
||||||
|
|
||||||
exception_fatal:
|
exception_fatal:
|
||||||
sd $k0, K0_OFFSET($k0)
|
sd $k0, K0_OFFSET($k0)
|
||||||
@ -117,16 +111,16 @@ exception_fatal:
|
|||||||
sd $t0, C0_EPC_OFFSET($k0)
|
sd $t0, C0_EPC_OFFSET($k0)
|
||||||
dmfc0 $t0, C0_BADVADDR
|
dmfc0 $t0, C0_BADVADDR
|
||||||
sd $t0, C0_BADVADDR_OFFSET($k0)
|
sd $t0, C0_BADVADDR_OFFSET($k0)
|
||||||
move $a2, $k0
|
move $a1, $k0
|
||||||
la $t1, exception_fatal_handler
|
jal exception_fatal_handler
|
||||||
jalr $t1
|
|
||||||
ld $t0, C0_EPC_OFFSET($k0)
|
ld $t0, C0_EPC_OFFSET($k0)
|
||||||
dmtc0 $t0, C0_EPC
|
dmtc0 $t0, C0_EPC
|
||||||
j exception_restore
|
j exception_restore
|
||||||
|
|
||||||
exception_interrupt:
|
exception_interrupt:
|
||||||
la $t1, exception_interrupt_handler
|
andi $a0, $t0, C0_CR_IP_MASK
|
||||||
jalr $t1
|
srl $a0, C0_CR_IP_BIT
|
||||||
|
jal exception_interrupt_handler
|
||||||
|
|
||||||
exception_restore:
|
exception_restore:
|
||||||
.set noat
|
.set noat
|
||||||
@ -169,8 +163,8 @@ exception_enable_interrupts:
|
|||||||
.type exception_enable_interrupts, %function
|
.type exception_enable_interrupts, %function
|
||||||
.global exception_enable_interrupts
|
.global exception_enable_interrupts
|
||||||
mfc0 $t0, C0_STATUS
|
mfc0 $t0, C0_STATUS
|
||||||
li $t1, C0_SR_IE
|
li $t1, (C0_SR_IM4 | C0_SR_IM3 | C0_SR_IE)
|
||||||
or $t0, $t0, $t1
|
or $t0, $t1
|
||||||
mtc0 $t0, C0_STATUS
|
mtc0 $t0, C0_STATUS
|
||||||
jr $ra
|
jr $ra
|
||||||
|
|
||||||
@ -180,8 +174,8 @@ exception_disable_interrupts:
|
|||||||
.type exception_disable_interrupts, %function
|
.type exception_disable_interrupts, %function
|
||||||
.global exception_disable_interrupts
|
.global exception_disable_interrupts
|
||||||
mfc0 $t0, C0_STATUS
|
mfc0 $t0, C0_STATUS
|
||||||
li $t1, ~(C0_SR_IE)
|
li $t1, ~(C0_SR_IM4 | C0_SR_IM3 | C0_SR_IE)
|
||||||
and $t0, $t0, $t1
|
and $t0, $t1
|
||||||
mtc0 $t0, C0_STATUS
|
mtc0 $t0, C0_STATUS
|
||||||
jr $ra
|
jr $ra
|
||||||
|
|
||||||
@ -195,7 +189,7 @@ exception_enable_watchdog:
|
|||||||
mtc0 $t1, C0_COMPARE
|
mtc0 $t1, C0_COMPARE
|
||||||
mfc0 $t0, C0_STATUS
|
mfc0 $t0, C0_STATUS
|
||||||
li $t1, C0_SR_IM7
|
li $t1, C0_SR_IM7
|
||||||
or $t0, $t0, $t1
|
or $t0, $t1
|
||||||
mtc0 $t0, C0_STATUS
|
mtc0 $t0, C0_STATUS
|
||||||
jr $ra
|
jr $ra
|
||||||
|
|
||||||
@ -206,7 +200,7 @@ exception_disable_watchdog:
|
|||||||
.global exception_disable_watchdog
|
.global exception_disable_watchdog
|
||||||
mfc0 $t0, C0_STATUS
|
mfc0 $t0, C0_STATUS
|
||||||
li $t1, ~(C0_SR_IM7)
|
li $t1, ~(C0_SR_IM7)
|
||||||
and $t0, $t0, $t1
|
and $t0, $t1
|
||||||
mtc0 $t0, C0_STATUS
|
mtc0 $t0, C0_STATUS
|
||||||
mtc0 $zero, C0_COMPARE
|
mtc0 $zero, C0_COMPARE
|
||||||
jr $ra
|
jr $ra
|
||||||
|
@ -8,15 +8,6 @@
|
|||||||
#include "../assets/assets.h"
|
#include "../assets/assets.h"
|
||||||
|
|
||||||
|
|
||||||
#define EXCEPTION_INTERRUPT (0)
|
|
||||||
#define EXCEPTION_SYSCALL (8)
|
|
||||||
|
|
||||||
#define INTERRUPT_MASK_TIMER (1 << 7)
|
|
||||||
|
|
||||||
#define SYSCALL_CODE_MASK (0x03FFFFC0UL)
|
|
||||||
#define SYSCALL_CODE_BIT (6)
|
|
||||||
|
|
||||||
|
|
||||||
static const char *exception_get_description (uint8_t exception_code) {
|
static const char *exception_get_description (uint8_t exception_code) {
|
||||||
switch (exception_code) {
|
switch (exception_code) {
|
||||||
case 0: return "Interrupt";
|
case 0: return "Interrupt";
|
||||||
@ -41,18 +32,11 @@ static const char *exception_get_description (uint8_t exception_code) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void exception_fatal_handler (uint32_t exception_code, uint32_t interrupt_mask, exception_t *e) {
|
void exception_fatal_handler (uint32_t exception_code, exception_t *e) {
|
||||||
version_t *version = version_get();
|
|
||||||
uint32_t *instruction_address = (((uint32_t *) (e->epc.u32)) + ((e->cr & C0_CR_BD) ? 1 : 0));
|
|
||||||
|
|
||||||
display_init((uint32_t *) (&assets_sc64_logo_640_240_dimmed));
|
display_init((uint32_t *) (&assets_sc64_logo_640_240_dimmed));
|
||||||
|
|
||||||
display_printf("[ SC64 bootloader metadata ]\n");
|
version_print();
|
||||||
display_printf("branch: %s | tag: %s\n", version->git_branch, version->git_tag);
|
display_printf("[ Unhandled exception ]\n");
|
||||||
display_printf("sha: %s\n", version->git_sha);
|
|
||||||
display_printf("msg: %s\n\n", version->git_message);
|
|
||||||
|
|
||||||
if (exception_code != EXCEPTION_SYSCALL) {
|
|
||||||
display_printf("%s\n", exception_get_description(exception_code));
|
display_printf("%s\n", exception_get_description(exception_code));
|
||||||
display_printf(" pc: 0x%08lX sr: 0x%08lX cr: 0x%08lX va: 0x%08lX\n", e->epc.u32, e->sr, e->cr, e->badvaddr.u32);
|
display_printf(" pc: 0x%08lX sr: 0x%08lX cr: 0x%08lX va: 0x%08lX\n", e->epc.u32, e->sr, e->cr, e->badvaddr.u32);
|
||||||
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(" 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);
|
||||||
@ -63,26 +47,6 @@ void exception_fatal_handler (uint32_t exception_code, uint32_t interrupt_mask,
|
|||||||
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(" 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(" 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);
|
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);
|
||||||
} else {
|
|
||||||
display_printf("[ Runtime error ]\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exception_code == EXCEPTION_INTERRUPT) {
|
|
||||||
if (interrupt_mask & INTERRUPT_MASK_TIMER) {
|
|
||||||
exception_disable_watchdog();
|
|
||||||
display_printf("Still loading after 5 second limit...\n\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if (exception_code == EXCEPTION_SYSCALL) {
|
|
||||||
uint32_t code = (((*instruction_address) & SYSCALL_CODE_MASK) >> SYSCALL_CODE_BIT);
|
|
||||||
|
|
||||||
if (code == TRIGGER_CODE_ERROR) {
|
|
||||||
const char *fmt = (const char *) (e->a0.u32);
|
|
||||||
va_list args = *((va_list *) (e->sp.u32));
|
|
||||||
display_vprintf(fmt, args);
|
|
||||||
display_printf("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1);
|
while (1);
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,6 @@
|
|||||||
#define EXCEPTION_H__
|
#define EXCEPTION_H__
|
||||||
|
|
||||||
|
|
||||||
#define TRIGGER_CODE_ERROR (0)
|
|
||||||
|
|
||||||
#define EXCEPTION_TRIGGER(code) { asm volatile ("syscall %[c]\n" :: [c] "i" (code)); }
|
|
||||||
|
|
||||||
|
|
||||||
void exception_enable_interrupts (void);
|
void exception_enable_interrupts (void);
|
||||||
void exception_disable_interrupts (void);
|
void exception_disable_interrupts (void);
|
||||||
void exception_enable_watchdog (void);
|
void exception_enable_watchdog (void);
|
||||||
|
@ -1,6 +1,69 @@
|
|||||||
#include "exception_regs.h"
|
#include "display.h"
|
||||||
|
#include "sc64.h"
|
||||||
|
#include "version.h"
|
||||||
|
#include "../assets/assets.h"
|
||||||
|
|
||||||
|
|
||||||
void exception_interrupt_handler (uint32_t exception_code, uint32_t interrupt_mask, exception_t *e) {
|
typedef enum {
|
||||||
|
INTERRUPT_SW_0 = (1 << 0),
|
||||||
|
INTERRUPT_SW_1 = (1 << 1),
|
||||||
|
INTERRUPT_RCP = (1 << 2),
|
||||||
|
INTERRUPT_CART = (1 << 3),
|
||||||
|
INTERRUPT_PRENMI = (1 << 4),
|
||||||
|
INTERRUPT_HW_5 = (1 << 5),
|
||||||
|
INTERRUPT_HW_6 = (1 << 6),
|
||||||
|
INTERRUPT_TIMER = (1 << 7),
|
||||||
|
} interrupt_t;
|
||||||
|
|
||||||
|
|
||||||
|
static void exception_interrupt_unhandled (uint8_t interrupt) {
|
||||||
|
display_init((uint32_t *) (&assets_sc64_logo_640_240_dimmed));
|
||||||
|
|
||||||
|
version_print();
|
||||||
|
display_printf("[ Unhandled interrupt ]\n");
|
||||||
|
display_printf("Pending (0x%02X):\n", interrupt);
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
switch (interrupt & (1 << i)) {
|
||||||
|
case INTERRUPT_SW_0: display_printf(" Software interrupt (0)\n"); break;
|
||||||
|
case INTERRUPT_SW_1: display_printf(" Software interrupt (1)\n"); break;
|
||||||
|
case INTERRUPT_RCP: display_printf(" RCP interrupt (2)\n"); break;
|
||||||
|
case INTERRUPT_CART: display_printf(" CART interrupt (3)\n"); break;
|
||||||
|
case INTERRUPT_PRENMI: display_printf(" Pre NMI interrupt (4)\n"); break;
|
||||||
|
case INTERRUPT_HW_5: display_printf(" Hardware interrupt (5)\n"); break;
|
||||||
|
case INTERRUPT_HW_6: display_printf(" Hardware interrupt (6)\n"); break;
|
||||||
|
case INTERRUPT_TIMER: display_printf(" Timer interrupt (7)\n"); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (1);
|
while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void exception_interrupt_handler (uint8_t interrupt) {
|
||||||
|
if (interrupt & INTERRUPT_CART) {
|
||||||
|
sc64_irq_t irq = sc64_irq_pending();
|
||||||
|
|
||||||
|
if (irq != SC64_IRQ_NONE) {
|
||||||
|
return sc64_irq_callback(irq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interrupt & INTERRUPT_PRENMI) {
|
||||||
|
if (display_ready()) {
|
||||||
|
display_init(NULL);
|
||||||
|
display_printf("Resetting...\n");
|
||||||
|
}
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interrupt & INTERRUPT_TIMER) {
|
||||||
|
display_init((uint32_t *) (&assets_sc64_logo_640_240_dimmed));
|
||||||
|
version_print();
|
||||||
|
display_printf("[ Watchdog ]\n");
|
||||||
|
display_printf("SC64 bootloader did not finish loading in 5 seconds\n");
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
exception_interrupt_unhandled(interrupt);
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "sc64.h"
|
#include "sc64.h"
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -7,13 +8,16 @@ typedef struct {
|
|||||||
io32_t DATA[2];
|
io32_t DATA[2];
|
||||||
io32_t IDENTIFIER;
|
io32_t IDENTIFIER;
|
||||||
io32_t KEY;
|
io32_t KEY;
|
||||||
|
io32_t IRQ;
|
||||||
} sc64_regs_t;
|
} sc64_regs_t;
|
||||||
|
|
||||||
#define SC64_REGS_BASE (0x1FFF0000UL)
|
#define SC64_REGS_BASE (0x1FFF0000UL)
|
||||||
#define SC64_REGS ((sc64_regs_t *) SC64_REGS_BASE)
|
#define SC64_REGS ((sc64_regs_t *) SC64_REGS_BASE)
|
||||||
|
|
||||||
|
|
||||||
#define SC64_SR_IRQ_PENDING (1 << 29)
|
#define SC64_SR_CMD_IRQ_REQUEST (1 << 8)
|
||||||
|
#define SC64_SR_CMD_IRQ_PENDING (1 << 28)
|
||||||
|
#define SC64_SR_MCU_IRQ_PENDING (1 << 29)
|
||||||
#define SC64_SR_CMD_ERROR (1 << 30)
|
#define SC64_SR_CMD_ERROR (1 << 30)
|
||||||
#define SC64_SR_CPU_BUSY (1 << 31)
|
#define SC64_SR_CPU_BUSY (1 << 31)
|
||||||
|
|
||||||
@ -24,6 +28,9 @@ typedef struct {
|
|||||||
#define SC64_KEY_UNLOCK_2 (0x4F434B5FUL)
|
#define SC64_KEY_UNLOCK_2 (0x4F434B5FUL)
|
||||||
#define SC64_KEY_LOCK (0xFFFFFFFFUL)
|
#define SC64_KEY_LOCK (0xFFFFFFFFUL)
|
||||||
|
|
||||||
|
#define SC64_IRQ_CMD_CLEAR (1 << 30)
|
||||||
|
#define SC64_IRQ_MCU_CLEAR (1 << 31)
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CMD_ID_IDENTIFIER_GET = 'v',
|
CMD_ID_IDENTIFIER_GET = 'v',
|
||||||
@ -67,16 +74,30 @@ typedef struct {
|
|||||||
} sc64_cmd_t;
|
} sc64_cmd_t;
|
||||||
|
|
||||||
|
|
||||||
|
static bool use_cmd_irq = false;
|
||||||
|
static volatile bool wait_cmd_irq = false;
|
||||||
|
|
||||||
|
|
||||||
static sc64_error_t sc64_execute_cmd (sc64_cmd_t *cmd) {
|
static sc64_error_t sc64_execute_cmd (sc64_cmd_t *cmd) {
|
||||||
|
uint32_t sr;
|
||||||
|
|
||||||
pi_io_write(&SC64_REGS->DATA[0], cmd->arg[0]);
|
pi_io_write(&SC64_REGS->DATA[0], cmd->arg[0]);
|
||||||
pi_io_write(&SC64_REGS->DATA[1], cmd->arg[1]);
|
pi_io_write(&SC64_REGS->DATA[1], cmd->arg[1]);
|
||||||
|
|
||||||
|
if (use_cmd_irq) {
|
||||||
|
wait_cmd_irq = true;
|
||||||
|
pi_io_write(&SC64_REGS->SR_CMD, (SC64_SR_CMD_IRQ_REQUEST | (cmd->id & 0xFF)));
|
||||||
|
while (wait_cmd_irq);
|
||||||
|
sr = pi_io_read(&SC64_REGS->SR_CMD);
|
||||||
|
if (sr & SC64_SR_CPU_BUSY) {
|
||||||
|
error_display("[Unexpected] SC64 CMD busy flag set");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
pi_io_write(&SC64_REGS->SR_CMD, (cmd->id & 0xFF));
|
pi_io_write(&SC64_REGS->SR_CMD, (cmd->id & 0xFF));
|
||||||
|
|
||||||
uint32_t sr;
|
|
||||||
do {
|
do {
|
||||||
sr = pi_io_read(&SC64_REGS->SR_CMD);
|
sr = pi_io_read(&SC64_REGS->SR_CMD);
|
||||||
} while (sr & SC64_SR_CPU_BUSY);
|
} while (sr & SC64_SR_CPU_BUSY);
|
||||||
|
}
|
||||||
|
|
||||||
if (sr & SC64_SR_CMD_ERROR) {
|
if (sr & SC64_SR_CMD_ERROR) {
|
||||||
return (sc64_error_t) (pi_io_read(&SC64_REGS->DATA[0]));
|
return (sc64_error_t) (pi_io_read(&SC64_REGS->DATA[0]));
|
||||||
@ -88,6 +109,18 @@ static sc64_error_t sc64_execute_cmd (sc64_cmd_t *cmd) {
|
|||||||
return SC64_OK;
|
return SC64_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sc64_mcu_irq_callback (void) {
|
||||||
|
error_display("[Unexpected] SC64 MCU interrupt received");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sc64_cmd_irq_callback (void) {
|
||||||
|
if (wait_cmd_irq) {
|
||||||
|
wait_cmd_irq = false;
|
||||||
|
} else {
|
||||||
|
error_display("[Unexpected] SC64 CMD interrupt received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *sc64_error_description (sc64_error_t error) {
|
const char *sc64_error_description (sc64_error_t error) {
|
||||||
sc64_error_type_t type = (sc64_error_type_t) ((error >> 24) & 0xFF);
|
sc64_error_type_t type = (sc64_error_type_t) ((error >> 24) & 0xFF);
|
||||||
@ -164,12 +197,31 @@ bool sc64_check_presence (void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool sc64_irq_pending (void) {
|
void sc64_cmd_irq_enable (bool enable) {
|
||||||
return (pi_io_read(&SC64_REGS->SR_CMD) & SC64_SR_IRQ_PENDING);
|
use_cmd_irq = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sc64_irq_clear (void) {
|
sc64_irq_t sc64_irq_pending (void) {
|
||||||
pi_io_write(&SC64_REGS->IDENTIFIER, 0);
|
uint32_t sr = pi_io_read(&SC64_REGS->SR_CMD);
|
||||||
|
sc64_irq_t irq = SC64_IRQ_NONE;
|
||||||
|
if (sr & SC64_SR_MCU_IRQ_PENDING) {
|
||||||
|
irq |= SC64_IRQ_MCU;
|
||||||
|
}
|
||||||
|
if (sr & SC64_SR_CMD_IRQ_PENDING) {
|
||||||
|
irq |= SC64_IRQ_CMD;
|
||||||
|
}
|
||||||
|
return irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sc64_irq_callback (sc64_irq_t irq) {
|
||||||
|
if (irq & SC64_IRQ_MCU) {
|
||||||
|
sc64_mcu_irq_callback();
|
||||||
|
pi_io_write(&SC64_REGS->IRQ, SC64_IRQ_MCU_CLEAR);
|
||||||
|
}
|
||||||
|
if (irq & SC64_IRQ_CMD) {
|
||||||
|
sc64_cmd_irq_callback();
|
||||||
|
pi_io_write(&SC64_REGS->IRQ, SC64_IRQ_CMD_CLEAR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -159,6 +159,12 @@ typedef enum {
|
|||||||
SD_CARD_STATUS_BYTE_SWAP = (1 << 4),
|
SD_CARD_STATUS_BYTE_SWAP = (1 << 4),
|
||||||
} sc64_sd_card_status_t;
|
} sc64_sd_card_status_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SC64_IRQ_NONE = 0,
|
||||||
|
SC64_IRQ_MCU = (1 << 0),
|
||||||
|
SC64_IRQ_CMD = (1 << 1),
|
||||||
|
} sc64_irq_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
volatile uint8_t BUFFER[8192];
|
volatile uint8_t BUFFER[8192];
|
||||||
@ -177,8 +183,9 @@ void sc64_unlock (void);
|
|||||||
void sc64_lock (void);
|
void sc64_lock (void);
|
||||||
bool sc64_check_presence (void);
|
bool sc64_check_presence (void);
|
||||||
|
|
||||||
bool sc64_irq_pending (void);
|
void sc64_cmd_irq_enable (bool enable);
|
||||||
void sc64_irq_clear (void);
|
sc64_irq_t sc64_irq_pending (void);
|
||||||
|
void sc64_irq_callback (sc64_irq_t irq);
|
||||||
|
|
||||||
sc64_error_t sc64_get_identifier (uint32_t *identifier);
|
sc64_error_t sc64_get_identifier (uint32_t *identifier);
|
||||||
sc64_error_t sc64_get_version (uint16_t *major, uint16_t *minor, uint32_t *revision);
|
sc64_error_t sc64_get_version (uint16_t *major, uint16_t *minor, uint32_t *revision);
|
||||||
|
@ -115,6 +115,22 @@ static void test_sc64_cfg (void) {
|
|||||||
display_printf("%02d:%02d:%02d", FROM_BCD(t.hour), FROM_BCD(t.minute), FROM_BCD(t.second));
|
display_printf("%02d:%02d:%02d", FROM_BCD(t.hour), FROM_BCD(t.minute), FROM_BCD(t.second));
|
||||||
display_printf(" (%s)", weekdays[FROM_BCD(t.weekday)]);
|
display_printf(" (%s)", weekdays[FROM_BCD(t.weekday)]);
|
||||||
display_printf("\n");
|
display_printf("\n");
|
||||||
|
|
||||||
|
int count = 65536;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if ((i % (count / 64)) == 0) {
|
||||||
|
display_printf(".");
|
||||||
|
}
|
||||||
|
if ((error = sc64_get_identifier(&identifier)) != SC64_OK) {
|
||||||
|
error_display("Command IDENTIFIER_GET failed\n (%08X) - %s", error, sc64_error_description(error));
|
||||||
|
}
|
||||||
|
if (identifier != 0x53437632) {
|
||||||
|
error_display("Invalid identifier received: 0x%08X", identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display_printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_pi (void) {
|
static void test_pi (void) {
|
||||||
@ -539,8 +555,18 @@ static struct {
|
|||||||
void test_execute (void) {
|
void test_execute (void) {
|
||||||
sc64_error_t error;
|
sc64_error_t error;
|
||||||
|
|
||||||
|
const int test_count = sizeof(tests) / sizeof(tests[0]);
|
||||||
|
int current = 0;
|
||||||
|
|
||||||
|
display_init(NULL);
|
||||||
|
display_printf("SC64 Test suite (%d / %d)\n\n", 0, test_count);
|
||||||
|
|
||||||
|
display_printf("Initializing...\n");
|
||||||
|
|
||||||
pi_io_config(0x0F, 0x05, 0x0C, 0x02);
|
pi_io_config(0x0F, 0x05, 0x0C, 0x02);
|
||||||
|
|
||||||
|
sc64_cmd_irq_enable(true);
|
||||||
|
|
||||||
if ((error = sc64_set_config(CFG_ID_ROM_WRITE_ENABLE, true)) != SC64_OK) {
|
if ((error = sc64_set_config(CFG_ID_ROM_WRITE_ENABLE, true)) != SC64_OK) {
|
||||||
error_display("Command CONFIG_SET [ROM_WRITE_ENABLE] failed\n (%08X) - %s", error, sc64_error_description(error));
|
error_display("Command CONFIG_SET [ROM_WRITE_ENABLE] failed\n (%08X) - %s", error, sc64_error_description(error));
|
||||||
}
|
}
|
||||||
@ -551,9 +577,6 @@ void test_execute (void) {
|
|||||||
|
|
||||||
random_seed = __entropy + c0_count();
|
random_seed = __entropy + c0_count();
|
||||||
|
|
||||||
const int test_count = sizeof(tests) / sizeof(tests[0]);
|
|
||||||
int current = 0;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
display_init(NULL);
|
display_init(NULL);
|
||||||
display_printf("SC64 Test suite (%d / %d)\n\n", current + 1, test_count);
|
display_printf("SC64 Test suite (%d / %d)\n\n", current + 1, test_count);
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
#include "version.h"
|
#include "display.h"
|
||||||
|
|
||||||
|
|
||||||
static version_t version = {
|
const struct {
|
||||||
|
const char *git_branch;
|
||||||
|
const char *git_tag;
|
||||||
|
const char *git_sha;
|
||||||
|
const char *git_message;
|
||||||
|
} version = {
|
||||||
#ifdef GIT_BRANCH
|
#ifdef GIT_BRANCH
|
||||||
.git_branch = GIT_BRANCH,
|
.git_branch = GIT_BRANCH,
|
||||||
#else
|
#else
|
||||||
@ -29,6 +34,10 @@ static version_t version = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
version_t *version_get (void) {
|
void version_print (void) {
|
||||||
return &version;
|
display_printf("[ SC64 bootloader metadata ]\n");
|
||||||
|
display_printf("branch: %s | tag: %s\n", version.git_branch, version.git_tag);
|
||||||
|
display_printf("sha: %s\n", version.git_sha);
|
||||||
|
display_printf("msg: %s\n", version.git_message);
|
||||||
|
display_printf("\n");
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,7 @@
|
|||||||
#define VERSION_H__
|
#define VERSION_H__
|
||||||
|
|
||||||
|
|
||||||
typedef const struct {
|
void version_print (void);
|
||||||
const char *git_branch;
|
|
||||||
const char *git_tag;
|
|
||||||
const char *git_sha;
|
|
||||||
const char *git_message;
|
|
||||||
} version_t;
|
|
||||||
|
|
||||||
|
|
||||||
const version_t *version_get (void);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user