Added SC64 API version check

This commit is contained in:
Mateusz Faderewski 2023-02-15 00:20:17 +01:00
parent 992fcf4923
commit 22656b150c
12 changed files with 589 additions and 548 deletions

View File

@ -1,178 +1,178 @@
#include <libdragon.h> #include <libdragon.h>
#include "boot.h" #include "boot.h"
#include "boot_io.h" #include "boot_io.h"
#include "crc32.h" #include "crc32.h"
extern uint32_t ipl2 __attribute__((section(".data"))); extern uint32_t ipl2 __attribute__((section(".data")));
typedef struct { typedef struct {
const uint32_t crc32; const uint32_t crc32;
const uint8_t seed; const uint8_t seed;
} ipl3_crc32_t; } ipl3_crc32_t;
static const ipl3_crc32_t ipl3_crc32[] = { static const ipl3_crc32_t ipl3_crc32[] = {
{ .crc32 = 0x587BD543, .seed = 0xAC }, // 5101 { .crc32 = 0x587BD543, .seed = 0xAC }, // 5101
{ .crc32 = 0x6170A4A1, .seed = 0x3F }, // 6101 { .crc32 = 0x6170A4A1, .seed = 0x3F }, // 6101
{ .crc32 = 0x009E9EA3, .seed = 0x3F }, // 7102 { .crc32 = 0x009E9EA3, .seed = 0x3F }, // 7102
{ .crc32 = 0x90BB6CB5, .seed = 0x3F }, // x102 { .crc32 = 0x90BB6CB5, .seed = 0x3F }, // x102
{ .crc32 = 0x0B050EE0, .seed = 0x78 }, // x103 { .crc32 = 0x0B050EE0, .seed = 0x78 }, // x103
{ .crc32 = 0x98BC2C86, .seed = 0x91 }, // x105 { .crc32 = 0x98BC2C86, .seed = 0x91 }, // x105
{ .crc32 = 0xACC8580A, .seed = 0x85 }, // x106 { .crc32 = 0xACC8580A, .seed = 0x85 }, // x106
{ .crc32 = 0x0E018159, .seed = 0xDD }, // 5167 { .crc32 = 0x0E018159, .seed = 0xDD }, // 5167
{ .crc32 = 0x10C68B18, .seed = 0xDD }, // NDXJ0 { .crc32 = 0x10C68B18, .seed = 0xDD }, // NDXJ0
{ .crc32 = 0xBC605D0A, .seed = 0xDD }, // NDDJ0 { .crc32 = 0xBC605D0A, .seed = 0xDD }, // NDDJ0
{ .crc32 = 0x502C4466, .seed = 0xDD }, // NDDJ1 { .crc32 = 0x502C4466, .seed = 0xDD }, // NDDJ1
{ .crc32 = 0x0C965795, .seed = 0xDD }, // NDDJ2 { .crc32 = 0x0C965795, .seed = 0xDD }, // NDDJ2
{ .crc32 = 0x8FEBA21E, .seed = 0xDE }, // NDDE0 { .crc32 = 0x8FEBA21E, .seed = 0xDE }, // NDDE0
}; };
static io32_t *boot_get_device_base (boot_params_t *params) { static io32_t *boot_get_device_base (boot_params_t *params) {
io32_t *device_base_address = ROM_CART; io32_t *device_base_address = ROM_CART;
if (params->device_type == BOOT_DEVICE_TYPE_DD) { if (params->device_type == BOOT_DEVICE_TYPE_DD) {
device_base_address = ROM_DDIPL; device_base_address = ROM_DDIPL;
} }
return device_base_address; return device_base_address;
} }
static bool boot_detect_tv_type (boot_params_t *params) { static bool boot_detect_tv_type (boot_params_t *params) {
io32_t *base = boot_get_device_base(params); io32_t *base = boot_get_device_base(params);
char region = ((io_read((uint32_t) (&base[15])) >> 8) & 0xFF); char region = ((io_read((uint32_t) (&base[15])) >> 8) & 0xFF);
switch (region) { switch (region) {
case 'P': case 'P':
case 'U': case 'U':
params->tv_type = BOOT_TV_TYPE_PAL; params->tv_type = BOOT_TV_TYPE_PAL;
break; break;
case 'E': case 'E':
case 'J': case 'J':
params->tv_type = BOOT_TV_TYPE_NTSC; params->tv_type = BOOT_TV_TYPE_NTSC;
break; break;
case 'B': case 'B':
params->tv_type = BOOT_TV_TYPE_MPAL; params->tv_type = BOOT_TV_TYPE_MPAL;
break; break;
default: default:
return false; return false;
} }
return true; return true;
} }
static bool boot_detect_cic_seed (boot_params_t *params) { static bool boot_detect_cic_seed (boot_params_t *params) {
io32_t *base = boot_get_device_base(params); io32_t *base = boot_get_device_base(params);
uint32_t ipl3[1008] __attribute__((aligned(8))); uint32_t ipl3[1008] __attribute__((aligned(8)));
data_cache_hit_writeback_invalidate(ipl3, sizeof(ipl3)); data_cache_hit_writeback_invalidate(ipl3, sizeof(ipl3));
dma_read_raw_async(ipl3, (uint32_t) (&base[16]), sizeof(ipl3)); dma_read_raw_async(ipl3, (uint32_t) (&base[16]), sizeof(ipl3));
dma_wait(); dma_wait();
uint32_t crc32 = crc32_calculate(ipl3, sizeof(ipl3)); uint32_t crc32 = crc32_calculate(ipl3, sizeof(ipl3));
for (int i = 0; i < sizeof(ipl3_crc32) / sizeof(ipl3_crc32_t); i++) { for (int i = 0; i < sizeof(ipl3_crc32) / sizeof(ipl3_crc32_t); i++) {
if (ipl3_crc32[i].crc32 == crc32) { if (ipl3_crc32[i].crc32 == crc32) {
params->cic_seed = ipl3_crc32[i].seed; params->cic_seed = ipl3_crc32[i].seed;
return true; return true;
} }
} }
return false; return false;
} }
bool boot_is_warm (void) { bool boot_is_warm (void) {
return (OS_INFO->reset_type == OS_INFO_RESET_TYPE_NMI); return (OS_INFO->reset_type == OS_INFO_RESET_TYPE_NMI);
} }
void boot (boot_params_t *params) { void boot (boot_params_t *params) {
if (params->detect_tv_type) { if (params->detect_tv_type) {
if (!boot_detect_tv_type(params)) { if (!boot_detect_tv_type(params)) {
params->tv_type = OS_INFO->tv_type; params->tv_type = OS_INFO->tv_type;
} }
} }
if (params->detect_cic_seed) { if (params->detect_cic_seed) {
if (!boot_detect_cic_seed(params)) { if (!boot_detect_cic_seed(params)) {
params->cic_seed = 0x3F; params->cic_seed = 0x3F;
} }
} }
OS_INFO->mem_size_6105 = OS_INFO->mem_size; OS_INFO->mem_size_6105 = OS_INFO->mem_size;
while (!(cpu_io_read(&SP->SR) & SP_SR_HALT)); while (!(cpu_io_read(&SP->SR) & SP_SR_HALT));
cpu_io_write(&SP->SR, SP_SR_CLR_INTR | SP_SR_SET_HALT); cpu_io_write(&SP->SR, SP_SR_CLR_INTR | SP_SR_SET_HALT);
while (cpu_io_read(&SP->DMA_BUSY)); while (cpu_io_read(&SP->DMA_BUSY));
cpu_io_write(&PI->SR, PI_SR_CLR_INTR | PI_SR_RESET); cpu_io_write(&PI->SR, PI_SR_CLR_INTR | PI_SR_RESET);
cpu_io_write(&VI->V_INTR, 0x3FF); cpu_io_write(&VI->V_INTR, 0x3FF);
cpu_io_write(&VI->H_LIMITS, 0); cpu_io_write(&VI->H_LIMITS, 0);
cpu_io_write(&VI->CURR_LINE, 0); cpu_io_write(&VI->CURR_LINE, 0);
cpu_io_write(&AI->MADDR, 0); cpu_io_write(&AI->MADDR, 0);
cpu_io_write(&AI->LEN, 0); cpu_io_write(&AI->LEN, 0);
io32_t *base = boot_get_device_base(params); io32_t *base = boot_get_device_base(params);
uint32_t pi_config = io_read((uint32_t) (base)); uint32_t pi_config = io_read((uint32_t) (base));
cpu_io_write(&PI->DOM[0].LAT, pi_config & 0xFF); cpu_io_write(&PI->DOM[0].LAT, pi_config & 0xFF);
cpu_io_write(&PI->DOM[0].PWD, pi_config >> 8); cpu_io_write(&PI->DOM[0].PWD, pi_config >> 8);
cpu_io_write(&PI->DOM[0].PGS, pi_config >> 16); cpu_io_write(&PI->DOM[0].PGS, pi_config >> 16);
cpu_io_write(&PI->DOM[0].RLS, pi_config >> 20); cpu_io_write(&PI->DOM[0].RLS, pi_config >> 20);
if (cpu_io_read(&DPC->SR) & DPC_SR_XBUS_DMEM_DMA) { if (cpu_io_read(&DPC->SR) & DPC_SR_XBUS_DMEM_DMA) {
while (cpu_io_read(&DPC->SR) & DPC_SR_PIPE_BUSY); while (cpu_io_read(&DPC->SR) & DPC_SR_PIPE_BUSY);
} }
uint32_t *ipl2_src = &ipl2; uint32_t *ipl2_src = &ipl2;
io32_t *ipl2_dst = SP_MEM->IMEM; io32_t *ipl2_dst = SP_MEM->IMEM;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
cpu_io_write(&ipl2_dst[i], ipl2_src[i]); cpu_io_write(&ipl2_dst[i], ipl2_src[i]);
} }
io32_t *ipl3_src = base; io32_t *ipl3_src = base;
io32_t *ipl3_dst = SP_MEM->DMEM; io32_t *ipl3_dst = SP_MEM->DMEM;
for (int i = 16; i < 1024; i++) { for (int i = 16; i < 1024; i++) {
cpu_io_write(&ipl3_dst[i], io_read((uint32_t) (&ipl3_src[i]))); cpu_io_write(&ipl3_dst[i], io_read((uint32_t) (&ipl3_src[i])));
} }
register void (*entry_point)(void) asm ("t3"); register void (*entry_point)(void) asm ("t3");
register uint32_t boot_device asm ("s3"); register uint32_t boot_device asm ("s3");
register uint32_t tv_type asm ("s4"); register uint32_t tv_type asm ("s4");
register uint32_t reset_type asm ("s5"); register uint32_t reset_type asm ("s5");
register uint32_t cic_seed asm ("s6"); register uint32_t cic_seed asm ("s6");
register uint32_t version asm ("s7"); register uint32_t version asm ("s7");
void *stack_pointer; void *stack_pointer;
entry_point = (void (*)(void)) UNCACHED(&SP_MEM->DMEM[16]); entry_point = (void (*)(void)) UNCACHED(&SP_MEM->DMEM[16]);
boot_device = (params->device_type & 0x01); boot_device = (params->device_type & 0x01);
tv_type = (params->tv_type & 0x03); tv_type = (params->tv_type & 0x03);
reset_type = (params->reset_type & 0x01); reset_type = (params->reset_type & 0x01);
cic_seed = (params->cic_seed & 0xFF); cic_seed = (params->cic_seed & 0xFF);
version = 1; version = 1;
stack_pointer = (void *) UNCACHED(&SP_MEM->IMEM[1020]); stack_pointer = (void *) UNCACHED(&SP_MEM->IMEM[1020]);
asm volatile ( asm volatile (
"move $sp, %[stack_pointer] \n" "move $sp, %[stack_pointer] \n"
"jr %[entry_point] \n" :: "jr %[entry_point] \n" ::
[entry_point] "r" (entry_point), [entry_point] "r" (entry_point),
[boot_device] "r" (boot_device), [boot_device] "r" (boot_device),
[tv_type] "r" (tv_type), [tv_type] "r" (tv_type),
[reset_type] "r" (reset_type), [reset_type] "r" (reset_type),
[cic_seed] "r" (cic_seed), [cic_seed] "r" (cic_seed),
[version] "r" (version), [version] "r" (version),
[stack_pointer] "r" (stack_pointer) [stack_pointer] "r" (stack_pointer)
); );
while (1); while (1);
} }

View File

@ -1,40 +1,40 @@
#ifndef BOOT_H__ #ifndef BOOT_H__
#define BOOT_H__ #define BOOT_H__
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
typedef enum { typedef enum {
BOOT_DEVICE_TYPE_ROM = 0, BOOT_DEVICE_TYPE_ROM = 0,
BOOT_DEVICE_TYPE_DD = 1, BOOT_DEVICE_TYPE_DD = 1,
} boot_device_type_t; } boot_device_type_t;
typedef enum { typedef enum {
BOOT_RESET_TYPE_COLD = 0, BOOT_RESET_TYPE_COLD = 0,
BOOT_RESET_TYPE_NMI = 1, BOOT_RESET_TYPE_NMI = 1,
} boot_reset_type_t; } boot_reset_type_t;
typedef enum { typedef enum {
BOOT_TV_TYPE_PAL = 0, BOOT_TV_TYPE_PAL = 0,
BOOT_TV_TYPE_NTSC = 1, BOOT_TV_TYPE_NTSC = 1,
BOOT_TV_TYPE_MPAL = 2, BOOT_TV_TYPE_MPAL = 2,
} boot_tv_type_t; } boot_tv_type_t;
typedef struct { typedef struct {
boot_device_type_t device_type; boot_device_type_t device_type;
boot_reset_type_t reset_type; boot_reset_type_t reset_type;
boot_tv_type_t tv_type; boot_tv_type_t tv_type;
uint8_t cic_seed; uint8_t cic_seed;
bool detect_tv_type; bool detect_tv_type;
bool detect_cic_seed; bool detect_cic_seed;
} boot_params_t; } boot_params_t;
bool boot_is_warm (void); bool boot_is_warm (void);
void boot (boot_params_t *params); void boot (boot_params_t *params);
#endif #endif

View File

@ -1,234 +1,234 @@
#ifndef BOOT_IO_H__ #ifndef BOOT_IO_H__
#define BOOT_IO_H__ #define BOOT_IO_H__
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
typedef volatile uint8_t io8_t; typedef volatile uint8_t io8_t;
typedef volatile uint32_t io32_t; typedef volatile uint32_t io32_t;
#define UNCACHED(address) ((typeof(address)) (((io32_t) (address)) | (0xA0000000UL))) #define UNCACHED(address) ((typeof(address)) (((io32_t) (address)) | (0xA0000000UL)))
typedef struct { typedef struct {
io32_t DMEM[1024]; io32_t DMEM[1024];
io32_t IMEM[1024]; io32_t IMEM[1024];
} sp_mem_t; } sp_mem_t;
#define SP_MEM_BASE (0x04000000UL) #define SP_MEM_BASE (0x04000000UL)
#define SP_MEM ((sp_mem_t *) SP_MEM_BASE) #define SP_MEM ((sp_mem_t *) SP_MEM_BASE)
typedef struct { typedef struct {
io32_t PADDR; io32_t PADDR;
io32_t MADDR; io32_t MADDR;
io32_t RD_LEN; io32_t RD_LEN;
io32_t WR_LEN; io32_t WR_LEN;
io32_t SR; io32_t SR;
io32_t DMA_FULL; io32_t DMA_FULL;
io32_t DMA_BUSY; io32_t DMA_BUSY;
io32_t SEMAPHORE; io32_t SEMAPHORE;
} sp_regs_t; } sp_regs_t;
#define SP_BASE (0x04040000UL) #define SP_BASE (0x04040000UL)
#define SP ((sp_regs_t *) SP_BASE) #define SP ((sp_regs_t *) SP_BASE)
#define SP_SR_HALT (1 << 0) #define SP_SR_HALT (1 << 0)
#define SP_SR_BROKE (1 << 1) #define SP_SR_BROKE (1 << 1)
#define SP_SR_DMA_BUSY (1 << 2) #define SP_SR_DMA_BUSY (1 << 2)
#define SP_SR_DMA_FULL (1 << 3) #define SP_SR_DMA_FULL (1 << 3)
#define SP_SR_IO_FULL (1 << 4) #define SP_SR_IO_FULL (1 << 4)
#define SP_SR_SSTEP (1 << 5) #define SP_SR_SSTEP (1 << 5)
#define SP_SR_INTR_BREAK (1 << 6) #define SP_SR_INTR_BREAK (1 << 6)
#define SP_SR_SIG0 (1 << 7) #define SP_SR_SIG0 (1 << 7)
#define SP_SR_SIG1 (1 << 8) #define SP_SR_SIG1 (1 << 8)
#define SP_SR_SIG2 (1 << 9) #define SP_SR_SIG2 (1 << 9)
#define SP_SR_SIG3 (1 << 10) #define SP_SR_SIG3 (1 << 10)
#define SP_SR_SIG4 (1 << 11) #define SP_SR_SIG4 (1 << 11)
#define SP_SR_SIG5 (1 << 12) #define SP_SR_SIG5 (1 << 12)
#define SP_SR_SIG6 (1 << 13) #define SP_SR_SIG6 (1 << 13)
#define SP_SR_SIG7 (1 << 14) #define SP_SR_SIG7 (1 << 14)
#define SP_SR_CLR_HALT (1 << 0) #define SP_SR_CLR_HALT (1 << 0)
#define SP_SR_SET_HALT (1 << 1) #define SP_SR_SET_HALT (1 << 1)
#define SP_SR_CLR_BROKE (1 << 2) #define SP_SR_CLR_BROKE (1 << 2)
#define SP_SR_CLR_INTR (1 << 3) #define SP_SR_CLR_INTR (1 << 3)
#define SP_SR_SET_INTR (1 << 4) #define SP_SR_SET_INTR (1 << 4)
#define SP_SR_CLR_SSTEP (1 << 5) #define SP_SR_CLR_SSTEP (1 << 5)
#define SP_SR_SET_SSTEP (1 << 6) #define SP_SR_SET_SSTEP (1 << 6)
#define SP_SR_CLR_INTR_BREAK (1 << 7) #define SP_SR_CLR_INTR_BREAK (1 << 7)
#define SP_SR_SET_INTR_BREAK (1 << 8) #define SP_SR_SET_INTR_BREAK (1 << 8)
#define SP_SR_CLR_SIG0 (1 << 9) #define SP_SR_CLR_SIG0 (1 << 9)
#define SP_SR_SET_SIG0 (1 << 10) #define SP_SR_SET_SIG0 (1 << 10)
#define SP_SR_CLR_SIG1 (1 << 11) #define SP_SR_CLR_SIG1 (1 << 11)
#define SP_SR_SET_SIG1 (1 << 12) #define SP_SR_SET_SIG1 (1 << 12)
#define SP_SR_CLR_SIG2 (1 << 13) #define SP_SR_CLR_SIG2 (1 << 13)
#define SP_SR_SET_SIG2 (1 << 14) #define SP_SR_SET_SIG2 (1 << 14)
#define SP_SR_CLR_SIG3 (1 << 15) #define SP_SR_CLR_SIG3 (1 << 15)
#define SP_SR_SET_SIG3 (1 << 16) #define SP_SR_SET_SIG3 (1 << 16)
#define SP_SR_CLR_SIG4 (1 << 17) #define SP_SR_CLR_SIG4 (1 << 17)
#define SP_SR_SET_SIG4 (1 << 18) #define SP_SR_SET_SIG4 (1 << 18)
#define SP_SR_CLR_SIG5 (1 << 19) #define SP_SR_CLR_SIG5 (1 << 19)
#define SP_SR_SET_SIG5 (1 << 20) #define SP_SR_SET_SIG5 (1 << 20)
#define SP_SR_CLR_SIG6 (1 << 21) #define SP_SR_CLR_SIG6 (1 << 21)
#define SP_SR_SET_SIG6 (1 << 22) #define SP_SR_SET_SIG6 (1 << 22)
#define SP_SR_CLR_SIG7 (1 << 23) #define SP_SR_CLR_SIG7 (1 << 23)
#define SP_SR_SET_SIG7 (1 << 24) #define SP_SR_SET_SIG7 (1 << 24)
typedef struct { typedef struct {
io32_t START; io32_t START;
io32_t END; io32_t END;
io32_t CURRENT; io32_t CURRENT;
io32_t SR; io32_t SR;
io32_t CLOCK; io32_t CLOCK;
io32_t BUF_BUSY; io32_t BUF_BUSY;
io32_t PIPE_BUSY; io32_t PIPE_BUSY;
io32_t TMEM; io32_t TMEM;
} dpc_regs_t; } dpc_regs_t;
#define DPC_BASE (0x04100000UL) #define DPC_BASE (0x04100000UL)
#define DPC ((dpc_regs_t *) DPC_BASE) #define DPC ((dpc_regs_t *) DPC_BASE)
#define DPC_SR_XBUS_DMEM_DMA (1 << 0) #define DPC_SR_XBUS_DMEM_DMA (1 << 0)
#define DPC_SR_FREEZE (1 << 1) #define DPC_SR_FREEZE (1 << 1)
#define DPC_SR_FLUSH (1 << 2) #define DPC_SR_FLUSH (1 << 2)
#define DPC_SR_START_GCLK (1 << 3) #define DPC_SR_START_GCLK (1 << 3)
#define DPC_SR_TMEM_BUSY (1 << 4) #define DPC_SR_TMEM_BUSY (1 << 4)
#define DPC_SR_PIPE_BUSY (1 << 5) #define DPC_SR_PIPE_BUSY (1 << 5)
#define DPC_SR_CMD_BUSY (1 << 6) #define DPC_SR_CMD_BUSY (1 << 6)
#define DPC_SR_CBUF_READY (1 << 7) #define DPC_SR_CBUF_READY (1 << 7)
#define DPC_SR_DMA_BUSY (1 << 8) #define DPC_SR_DMA_BUSY (1 << 8)
#define DPC_SR_END_VALID (1 << 9) #define DPC_SR_END_VALID (1 << 9)
#define DPC_SR_START_VALID (1 << 10) #define DPC_SR_START_VALID (1 << 10)
#define DPC_SR_CLR_XBUS_DMEM_DMA (1 << 0) #define DPC_SR_CLR_XBUS_DMEM_DMA (1 << 0)
#define DPC_SR_SET_XBUS_DMEM_DMA (1 << 1) #define DPC_SR_SET_XBUS_DMEM_DMA (1 << 1)
#define DPC_SR_CLR_FREEZE (1 << 2) #define DPC_SR_CLR_FREEZE (1 << 2)
#define DPC_SR_SET_FREEZE (1 << 3) #define DPC_SR_SET_FREEZE (1 << 3)
#define DPC_SR_CLR_FLUSH (1 << 4) #define DPC_SR_CLR_FLUSH (1 << 4)
#define DPC_SR_SET_FLUSH (1 << 5) #define DPC_SR_SET_FLUSH (1 << 5)
#define DPC_SR_CLR_TMEM_CTR (1 << 6) #define DPC_SR_CLR_TMEM_CTR (1 << 6)
#define DPC_SR_CLR_PIPE_CTR (1 << 7) #define DPC_SR_CLR_PIPE_CTR (1 << 7)
#define DPC_SR_CLR_CMD_CTR (1 << 8) #define DPC_SR_CLR_CMD_CTR (1 << 8)
#define DPC_SR_CLR_CLOCK_CTR (1 << 9) #define DPC_SR_CLR_CLOCK_CTR (1 << 9)
typedef struct { typedef struct {
io32_t CR; io32_t CR;
io32_t MADDR; io32_t MADDR;
io32_t H_WIDTH; io32_t H_WIDTH;
io32_t V_INTR; io32_t V_INTR;
io32_t CURR_LINE; io32_t CURR_LINE;
io32_t TIMING; io32_t TIMING;
io32_t V_SYNC; io32_t V_SYNC;
io32_t H_SYNC; io32_t H_SYNC;
io32_t H_SYNC_LEAP; io32_t H_SYNC_LEAP;
io32_t H_LIMITS; io32_t H_LIMITS;
io32_t V_LIMITS; io32_t V_LIMITS;
io32_t COLOR_BURST; io32_t COLOR_BURST;
io32_t H_SCALE; io32_t H_SCALE;
io32_t V_SCALE; io32_t V_SCALE;
} vi_regs_t; } vi_regs_t;
#define VI_BASE (0x04400000UL) #define VI_BASE (0x04400000UL)
#define VI ((vi_regs_t *) VI_BASE) #define VI ((vi_regs_t *) VI_BASE)
#define VI_CR_TYPE_16 (2 << 0) #define VI_CR_TYPE_16 (2 << 0)
#define VI_CR_TYPE_32 (3 << 0) #define VI_CR_TYPE_32 (3 << 0)
#define VI_CR_GAMMA_DITHER_ON (1 << 2) #define VI_CR_GAMMA_DITHER_ON (1 << 2)
#define VI_CR_GAMMA_ON (1 << 3) #define VI_CR_GAMMA_ON (1 << 3)
#define VI_CR_DIVOT_ON (1 << 4) #define VI_CR_DIVOT_ON (1 << 4)
#define VI_CR_SERRATE_ON (1 << 6) #define VI_CR_SERRATE_ON (1 << 6)
#define VI_CR_ANTIALIAS_0 (1 << 8) #define VI_CR_ANTIALIAS_0 (1 << 8)
#define VI_CR_ANTIALIAS_1 (1 << 9) #define VI_CR_ANTIALIAS_1 (1 << 9)
#define VI_CR_PIXEL_ADVANCE_0 (1 << 12) #define VI_CR_PIXEL_ADVANCE_0 (1 << 12)
#define VI_CR_PIXEL_ADVANCE_1 (1 << 13) #define VI_CR_PIXEL_ADVANCE_1 (1 << 13)
#define VI_CR_PIXEL_ADVANCE_2 (1 << 14) #define VI_CR_PIXEL_ADVANCE_2 (1 << 14)
#define VI_CR_PIXEL_ADVANCE_3 (1 << 15) #define VI_CR_PIXEL_ADVANCE_3 (1 << 15)
#define VI_CR_DITHER_FILTER_ON (1 << 16) #define VI_CR_DITHER_FILTER_ON (1 << 16)
typedef struct { typedef struct {
io32_t MADDR; io32_t MADDR;
io32_t LEN; io32_t LEN;
io32_t CR; io32_t CR;
io32_t SR; io32_t SR;
io32_t DACRATE; io32_t DACRATE;
io32_t BITRATE; io32_t BITRATE;
} ai_regs_t; } ai_regs_t;
#define AI_BASE (0x04500000UL) #define AI_BASE (0x04500000UL)
#define AI ((ai_regs_t *) AI_BASE) #define AI ((ai_regs_t *) AI_BASE)
#define AI_SR_DMA_BUSY (1 << 30) #define AI_SR_DMA_BUSY (1 << 30)
#define AI_SR_FIFO_FULL (1 << 31) #define AI_SR_FIFO_FULL (1 << 31)
#define AI_CR_DMA_ON (1 << 0) #define AI_CR_DMA_ON (1 << 0)
typedef struct { typedef struct {
io32_t MADDR; io32_t MADDR;
io32_t PADDR; io32_t PADDR;
io32_t RDMA; io32_t RDMA;
io32_t WDMA; io32_t WDMA;
io32_t SR; io32_t SR;
struct { struct {
io32_t LAT; io32_t LAT;
io32_t PWD; io32_t PWD;
io32_t PGS; io32_t PGS;
io32_t RLS; io32_t RLS;
} DOM[2]; } DOM[2];
} pi_regs_t; } pi_regs_t;
#define PI_BASE (0x04600000UL) #define PI_BASE (0x04600000UL)
#define PI ((pi_regs_t *) PI_BASE) #define PI ((pi_regs_t *) PI_BASE)
#define PI_SR_DMA_BUSY (1 << 0) #define PI_SR_DMA_BUSY (1 << 0)
#define PI_SR_IO_BUSY (1 << 1) #define PI_SR_IO_BUSY (1 << 1)
#define PI_SR_DMA_ERROR (1 << 2) #define PI_SR_DMA_ERROR (1 << 2)
#define PI_SR_RESET (1 << 0) #define PI_SR_RESET (1 << 0)
#define PI_SR_CLR_INTR (1 << 1) #define PI_SR_CLR_INTR (1 << 1)
#define ROM_DDIPL_BASE (0x06000000UL) #define ROM_DDIPL_BASE (0x06000000UL)
#define ROM_DDIPL ((io32_t *) ROM_DDIPL_BASE) #define ROM_DDIPL ((io32_t *) ROM_DDIPL_BASE)
#define ROM_CART_BASE (0x10000000UL) #define ROM_CART_BASE (0x10000000UL)
#define ROM_CART ((io32_t *) ROM_CART_BASE) #define ROM_CART ((io32_t *) ROM_CART_BASE)
typedef struct { typedef struct {
uint32_t tv_type; uint32_t tv_type;
uint32_t device_type; uint32_t device_type;
uint32_t device_base; uint32_t device_base;
uint32_t reset_type; uint32_t reset_type;
uint32_t cic_id; uint32_t cic_id;
uint32_t version; uint32_t version;
uint32_t mem_size; uint32_t mem_size;
uint8_t app_nmi_buffer[64]; uint8_t app_nmi_buffer[64];
uint32_t __reserved_1[37]; uint32_t __reserved_1[37];
uint32_t mem_size_6105; uint32_t mem_size_6105;
} os_info_t; } os_info_t;
#define OS_INFO_BASE (0x80000300UL) #define OS_INFO_BASE (0x80000300UL)
#define OS_INFO ((os_info_t *) OS_INFO_BASE) #define OS_INFO ((os_info_t *) OS_INFO_BASE)
#define OS_INFO_RESET_TYPE_COLD (0) #define OS_INFO_RESET_TYPE_COLD (0)
#define OS_INFO_RESET_TYPE_NMI (1) #define OS_INFO_RESET_TYPE_NMI (1)
static inline uint32_t cpu_io_read (io32_t *address) { static inline uint32_t cpu_io_read (io32_t *address) {
io32_t *uncached = UNCACHED(address); io32_t *uncached = UNCACHED(address);
uint32_t value = *uncached; uint32_t value = *uncached;
return value; return value;
} }
static inline void cpu_io_write (io32_t *address, uint32_t value) { static inline void cpu_io_write (io32_t *address, uint32_t value) {
io32_t *uncached = UNCACHED(address); io32_t *uncached = UNCACHED(address);
*uncached = value; *uncached = value;
} }
#endif #endif

View File

@ -1,50 +1,50 @@
#include "crc32.h" #include "crc32.h"
static const uint32_t crc32_table[256] = { static const uint32_t crc32_table[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
}; };
uint32_t crc32_calculate (void *buffer, size_t length) { uint32_t crc32_calculate (void *buffer, size_t length) {
uint32_t crc32 = 0xFFFFFFFFUL; uint32_t crc32 = 0xFFFFFFFFUL;
uint8_t *byte_pointer = (uint8_t *) (buffer); uint8_t *byte_pointer = (uint8_t *) (buffer);
while (length--) { while (length--) {
crc32 = (crc32 >> 8) ^ crc32_table[(crc32 & 0xFF) ^ (*byte_pointer++)]; crc32 = (crc32 >> 8) ^ crc32_table[(crc32 & 0xFF) ^ (*byte_pointer++)];
} }
return ~(crc32); return ~(crc32);
} }

View File

@ -1,12 +1,12 @@
#ifndef CRC32_H__ #ifndef CRC32_H__
#define CRC32_H__ #define CRC32_H__
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
uint32_t crc32_calculate (void *buffer, size_t length); uint32_t crc32_calculate (void *buffer, size_t length);
#endif #endif

View File

@ -1,17 +1,17 @@
.set noat .set noat
.set noreorder .set noreorder
.section .text.ipl2, "ax", %progbits .section .text.ipl2, "ax", %progbits
.type ipl2, %object .type ipl2, %object
ipl2: ipl2:
.global ipl2 .global ipl2
lui $t5, 0xBFC0 lui $t5, 0xBFC0
1: 1:
lw $t0, 0x7FC($t5) lw $t0, 0x7FC($t5)
addiu $t5, $t5, 0x7C0 addiu $t5, $t5, 0x7C0
andi $t0, $t0, 0x80 andi $t0, $t0, 0x80
bnel $t0, $zero, 1b bnel $t0, $zero, 1b
lui $t5, 0xBFC0 lui $t5, 0xBFC0
lw $t0, 0x24($t5) lw $t0, 0x24($t5)
lui $t3, 0xB000 lui $t3, 0xB000

View File

@ -25,21 +25,21 @@ static const size_t SAVE_SIZE[__FLASHCART_SAVE_TYPE_END] = {
static flashcart_t *flashcart; static flashcart_t *flashcart;
bool flashcart_init (void) { flashcart_error_t flashcart_init (void) {
switch (usb_getcart()) { switch (usb_getcart()) {
case CART_SC64: case CART_SC64:
flashcart = sc64_get_flashcart(); flashcart = sc64_get_flashcart();
break; break;
default: default:
return false; return FLASHCART_ERROR_UNSUPPORTED;
} }
return flashcart->init(); return flashcart->init();
} }
void flashcart_deinit (void) { flashcart_error_t flashcart_deinit (void) {
flashcart->deinit(); return flashcart->deinit();
} }
flashcart_error_t flashcart_load_rom (char *rom_path) { flashcart_error_t flashcart_load_rom (char *rom_path) {

View File

@ -8,6 +8,8 @@
typedef enum { typedef enum {
FLASHCART_OK, FLASHCART_OK,
FLASHCART_ERROR_UNSUPPORTED,
FLASHCART_ERROR_OUTDATED,
FLASHCART_ERROR_ARGS, FLASHCART_ERROR_ARGS,
FLASHCART_ERROR_LOAD, FLASHCART_ERROR_LOAD,
FLASHCART_ERROR_INT, FLASHCART_ERROR_INT,
@ -25,8 +27,8 @@ typedef enum {
} flashcart_save_type_t; } flashcart_save_type_t;
typedef struct { typedef struct {
bool (*init) (void); flashcart_error_t (*init) (void);
void (*deinit) (void); flashcart_error_t (*deinit) (void);
flashcart_error_t (*load_rom) (char *rom_path); flashcart_error_t (*load_rom) (char *rom_path);
flashcart_error_t (*load_save) (char *save_path); flashcart_error_t (*load_save) (char *save_path);
flashcart_error_t (*set_save_type) (flashcart_save_type_t save_type); flashcart_error_t (*set_save_type) (flashcart_save_type_t save_type);
@ -34,8 +36,8 @@ typedef struct {
} flashcart_t; } flashcart_t;
bool flashcart_init (void); flashcart_error_t flashcart_init (void);
void flashcart_deinit (void); flashcart_error_t flashcart_deinit (void);
flashcart_error_t flashcart_load_rom (char *rom_path); flashcart_error_t flashcart_load_rom (char *rom_path);
flashcart_error_t flashcart_load_save (char *save_path, flashcart_save_type_t save_type, bool save_writeback); flashcart_error_t flashcart_load_save (char *save_path, flashcart_save_type_t save_type, bool save_writeback);

View File

@ -12,11 +12,13 @@
#include "sc64.h" #include "sc64.h"
#define SRAM_FLASHRAM_ADDRESS (0x08000000) #define SRAM_FLASHRAM_ADDRESS (0x08000000)
#define ROM_ADDRESS (0x10000000) #define ROM_ADDRESS (0x10000000)
#define EXTENDED_ADDRESS (0x14000000) #define EXTENDED_ADDRESS (0x14000000)
#define SHADOW_ADDRESS (0x1FFC0000) #define SHADOW_ADDRESS (0x1FFC0000)
#define EEPROM_ADDRESS (0x1FFE2000) #define EEPROM_ADDRESS (0x1FFE2000)
#define MIN_SUPPORTED_API_VERSION (1)
static flashcart_error_t load_to_flash (FIL *fil, void *address, size_t size, UINT *br) { static flashcart_error_t load_to_flash (FIL *fil, void *address, size_t size, UINT *br) {
@ -49,13 +51,29 @@ static flashcart_error_t load_to_flash (FIL *fil, void *address, size_t size, UI
} }
static bool sc64_init (void) { static flashcart_error_t sc64_init (void) {
uint32_t api_version;
sc64_unlock(); sc64_unlock();
return sc64_check_presence();
if (!sc64_check_presence()) {
return FLASHCART_ERROR_UNSUPPORTED;
}
if (sc64_get_api_version(&api_version) != SC64_OK) {
return FLASHCART_ERROR_OUTDATED;
}
if (api_version < MIN_SUPPORTED_API_VERSION) {
return FLASHCART_ERROR_OUTDATED;
}
return FLASHCART_OK;
} }
static void sc64_deinit (void) { static flashcart_error_t sc64_deinit (void) {
sc64_lock(); sc64_lock();
return FLASHCART_OK;
} }
static flashcart_error_t sc64_load_rom (char *rom_path) { static flashcart_error_t sc64_load_rom (char *rom_path) {

View File

@ -26,6 +26,7 @@ typedef struct {
typedef enum { typedef enum {
CMD_ID_API_VERSION_GET = 'V',
CMD_ID_CONFIG_GET = 'c', CMD_ID_CONFIG_GET = 'c',
CMD_ID_CONFIG_SET = 'C', CMD_ID_CONFIG_SET = 'C',
CMD_ID_WRITEBACK_SD_INFO = 'W', CMD_ID_WRITEBACK_SD_INFO = 'W',
@ -89,6 +90,13 @@ void sc64_write_data (void *src, void *dst, size_t length) {
dma_wait(); dma_wait();
} }
sc64_error_t sc64_get_api_version (uint32_t *api_version) {
sc64_cmd_t cmd = { .id = CMD_ID_API_VERSION_GET };
sc64_error_t error = sc64_execute_cmd(&cmd);
*api_version = cmd.rsp[0];
return error;
}
sc64_error_t sc64_get_config (sc64_cfg_t id, void *value) { sc64_error_t sc64_get_config (sc64_cfg_t id, void *value) {
sc64_cmd_t cmd = { .id = CMD_ID_CONFIG_GET, .arg = { id } }; sc64_cmd_t cmd = { .id = CMD_ID_CONFIG_GET, .arg = { id } };
sc64_error_t error = sc64_execute_cmd(&cmd); sc64_error_t error = sc64_execute_cmd(&cmd);

View File

@ -60,6 +60,7 @@ void sc64_lock (void);
bool sc64_check_presence (void); bool sc64_check_presence (void);
void sc64_read_data (void *src, void *dst, size_t length); void sc64_read_data (void *src, void *dst, size_t length);
void sc64_write_data (void *src, void *dst, size_t length); void sc64_write_data (void *src, void *dst, size_t length);
sc64_error_t sc64_get_api_version (uint32_t *api_version);
sc64_error_t sc64_get_config (sc64_cfg_t cfg, void *value); sc64_error_t sc64_get_config (sc64_cfg_t cfg, void *value);
sc64_error_t sc64_set_config (sc64_cfg_t cfg, uint32_t value); sc64_error_t sc64_set_config (sc64_cfg_t cfg, uint32_t value);
sc64_error_t sc64_writeback_enable (void *address); sc64_error_t sc64_writeback_enable (void *address);

View File

@ -10,8 +10,20 @@
static void init (void) { static void init (void) {
assertf(usb_initialize() != CART_NONE, "No flashcart was detected"); assertf(usb_initialize() != CART_NONE, "No flashcart was detected");
switch (flashcart_init()) {
case FLASHCART_OK:
break;
case FLASHCART_ERROR_OUTDATED:
assertf(false, "Outdated flashcart firmware");
break;
case FLASHCART_ERROR_UNSUPPORTED:
assertf(false, "Unsupported flashcart");
break;
default:
assertf(false, "Unknown error while initializing flashcart");
break;
}
assertf(debug_init_sdfs("sd:/", -1), "Couldn't initialize SD card"); assertf(debug_init_sdfs("sd:/", -1), "Couldn't initialize SD card");
assertf(flashcart_init(), "Couldn't initialize flashcart");
} }
static void deinit (void) { static void deinit (void) {