From 6613027b353f52c37cfe6269145ccee054027422 Mon Sep 17 00:00:00 2001 From: imaandrew <14946103+imaandrew@users.noreply.github.com> Date: Mon, 5 Aug 2024 21:15:11 -0400 Subject: [PATCH] Add SC64 support --- lib/libpm-jp.a | 1 + lib/libpm-us.a | 1 + src/io/io.c | 6 +- src/io/sc64.c | 191 +++++++++++++++++++++++++++++++++++++++++++++ src/io/sc64.h | 56 +++++++++++++ src/io/sc64_io.h | 8 ++ src/pm64.h | 1 + src/sys/settings.c | 1 + 8 files changed, 261 insertions(+), 4 deletions(-) create mode 100644 src/io/sc64.c create mode 100644 src/io/sc64.h create mode 100644 src/io/sc64_io.h diff --git a/lib/libpm-jp.a b/lib/libpm-jp.a index 27b48e53..6d9e78aa 100644 --- a/lib/libpm-jp.a +++ b/lib/libpm-jp.a @@ -39,6 +39,7 @@ pm_fioFetchSavedFileInfo = 0x8002B114; pm_fioDeserializeState = 0x8002B450; pm_fioReadFlash = 0x8002B828; pm_fioWriteFlash = 0x8002B908; +pm_fioEraseFlash = 0x8002B9DC; pm_setCurtainScaleGoal = 0x8002BE9C; pm_update_cameras = 0x8002D090; pm_update_camera_zone_interp = 0x80031124; diff --git a/lib/libpm-us.a b/lib/libpm-us.a index 4de2bcd6..03a13b38 100644 --- a/lib/libpm-us.a +++ b/lib/libpm-us.a @@ -39,6 +39,7 @@ pm_fioFetchSavedFileInfo = 0x8002B154; pm_fioDeserializeState = 0x8002B490; pm_fioReadFlash = 0x8002B868; pm_fioWriteFlash = 0x8002B948; +pm_fioEraseFlash = 0x8002BA1C; pm_setCurtainScaleGoal = 0x8002BEDC; pm_setCurtainDrawCallback = 0x8002BF04; pm_setCurtainFadeGoal = 0x8002BF14; diff --git a/src/io/io.c b/src/io/io.c index 2d7ac2bb..e485fed3 100644 --- a/src/io/io.c +++ b/src/io/io.c @@ -1,6 +1,7 @@ #include "ed64_io.h" #include "hb_io.h" #include "iodev.h" +#include "sc64_io.h" #include #include @@ -18,10 +19,7 @@ static struct Iodev *currentDev; s32 ioInit(void) { struct Iodev *devs[] = { - &homeboyIodev, - &everdrive64X, - &everdrive64V2, - &everdrive64V1, + &homeboyIodev, &everdrive64X, &everdrive64V2, &everdrive64V1, &sc64, }; s32 nDevs = sizeof(devs) / sizeof(devs[0]); diff --git a/src/io/sc64.c b/src/io/sc64.c new file mode 100644 index 00000000..1f0b42d6 --- /dev/null +++ b/src/io/sc64.c @@ -0,0 +1,191 @@ +#include "sc64.h" +#include "io/iodev.h" +#include "pi.h" +#include "util/util.h" +#include + +static s32 cartIrqf; +static u32 cartLat; +static u32 cartPwd; + +_Alignas(16) static u64 cartBuf[512 / 8]; + +static void cartBufRd(const void *addr) { + const uu64 *ptr = addr; + for (s32 i = 0; i < 512 / 8; i += 2) { + u64 a = ptr[i + 0]; + u64 b = ptr[i + 1]; + cartBuf[i + 0] = a; + cartBuf[i + 1] = b; + } +} + +static void cartBufWr(void *addr) { + uu64 *ptr = addr; + for (s32 i = 0; i < 512 / 8; i += 2) { + u64 a = cartBuf[i + 0]; + u64 b = cartBuf[i + 1]; + ptr[i + 0] = a; + ptr[i + 1] = b; + } +} + +static void cartLock(void) { + __osPiGetAccess(); + + cartIrqf = setIrqf(0); + + cartLat = pi_regs.dom1_lat; + cartPwd = pi_regs.dom1_pwd; +} + +static void cartUnlock(void) { + pi_regs.dom1_lat = cartLat; + pi_regs.dom1_pwd = cartPwd; + + __osPiRelAccess(); + + setIrqf(cartIrqf); +} + +static inline u32 regRd(s32 reg) { + return __piReadRaw((u32)®S_PTR[reg]); +} + +static inline void regWr(s32 reg, u32 dat) { + return __piWriteRaw((u32)®S_PTR[reg], dat); +} + +static s32 scSync(void) { + while (regRd(SC_STATUS_REG) & SC_CMD_BUSY) { + ; + } + if (regRd(SC_STATUS_REG) & SC_CMD_ERROR) { + return -1; + } + return 0; +} + +static s32 probe(void) { + cartLock(); + + /* open registers */ + regWr(SC_KEY_REG, SC_KEY_RESET); + regWr(SC_KEY_REG, SC_KEY_UNL); + regWr(SC_KEY_REG, SC_KEY_OCK); + + /* check magic number */ + if ((regRd(SC_IDENTIFIER_REG)) != SC_IDENTIFIER) { + regWr(SC_KEY_REG, 0); + CART_ABORT(); + } + + scSync(); + cartUnlock(); + return 0; +} + +static s32 diskInit(void) { + cartLock(); + scSync(); + + regWr(SC_DATA1_REG, SC_SD_INIT); + regWr(SC_COMMAND_REG, SC_SD_OP); + + if (scSync()) { + regWr(SC_KEY_REG, 0); + CART_ABORT(); + } + + cartUnlock(); + return 0; +} + +static s32 diskRead(size_t lba, size_t nBlocks, void *dst) { + char *addr = dst; + s32 n; + cartLock(); + scSync(); + + while (nBlocks > 0) { + n = nBlocks < 16 ? nBlocks : 16; + + regWr(SC_DATA0_REG, lba); + regWr(SC_COMMAND_REG, SC_SD_SECTOR_SET); + + if (scSync()) { + CART_ABORT(); + } + + regWr(SC_DATA0_REG, SC_BUFFER_REG); + regWr(SC_DATA1_REG, n); + regWr(SC_COMMAND_REG, SC_SD_READ); + + if (scSync()) { + CART_ABORT(); + } + + if ((u32)addr & 7) { + for (s32 i = 0; i < n; i++) { + piReadLocked(SC_BUFFER_REG + 512 * i, cartBuf, 512); + cartBufWr(addr); + addr += 512; + } + } else { + piReadLocked(SC_BUFFER_REG, addr, 512 * n); + addr += 512 * n; + } + + lba += n; + nBlocks -= n; + } + + cartUnlock(); + return 0; +} + +static s32 diskWrite(size_t lba, size_t nBlocks, const void *src) { + const char *addr = src; + s32 n; + cartLock(); + scSync(); + + while (nBlocks > 0) { + n = nBlocks < 16 ? nBlocks : 16; + + if ((u32)addr & 7) { + for (s32 i = 0; i < n; i++) { + cartBufRd(addr); + piWriteLocked(SC_BUFFER_REG + 512 * i, cartBuf, 512); + addr += 512; + } + } else { + piWriteLocked(SC_BUFFER_REG, addr, 512 * n); + addr += 512 * n; + } + + scSync(); + regWr(SC_DATA0_REG, lba); + regWr(SC_COMMAND_REG, SC_SD_SECTOR_SET); + + if (scSync()) { + CART_ABORT(); + } + + regWr(SC_DATA0_REG, SC_BUFFER_REG); + regWr(SC_DATA1_REG, n); + regWr(SC_COMMAND_REG, SC_SD_WRITE); + + if (scSync()) { + CART_ABORT(); + } + + lba += n; + nBlocks -= n; + } + + cartUnlock(); + return 0; +} + +struct Iodev sc64 = {.probe = probe, .diskInit = diskInit, .diskRead = diskRead, .diskWrite = diskWrite}; diff --git a/src/io/sc64.h b/src/io/sc64.h new file mode 100644 index 00000000..ad0ce3bd --- /dev/null +++ b/src/io/sc64.h @@ -0,0 +1,56 @@ +#ifndef SC64_H +#define SC64_H + +#include "types.h" + +#define SC_BASE_REG 0xBFFF0000 +#define SC_BUFFER_REG 0xBFFE0000 +#define REGS_PTR ((volatile u32 *)SC_BASE_REG) + +#define SC_STATUS_REG 0 +#define SC_COMMAND_REG 0 +#define SC_DATA0_REG 1 +#define SC_DATA1_REG 2 +#define SC_IDENTIFIER_REG 3 +#define SC_KEY_REG 4 + +#define SC_CMD_BUSY 0x80000000 +#define SC_CMD_ERROR 0x40000000 +#define SC_IRQ_PENDING 0x20000000 + +#define SC_CONFIG_GET 'c' +#define SC_CONFIG_SET 'C' +#define SC_SD_OP 'i' +#define SC_SD_SECTOR_SET 'I' +#define SC_SD_READ 's' +#define SC_SD_WRITE 'S' + +#define SC_CFG_ROM_WRITE 1 +#define SC_CFG_DD_MODE 3 +#define SC_CFG_SAVE_TYPE 6 + +#define SC_SD_DEINIT 0 +#define SC_SD_INIT 1 +#define SC_SD_GET_STATUS 2 +#define SC_SD_GET_INFO 3 +#define SC_SD_BYTESWAP_ON 4 +#define SC_SD_BYTESWAP_OFF 5 + +#define SC_DD_MODE_REGS 1 +#define SC_DD_MODE_IPL 2 + +#define SC_IDENTIFIER 0x53437632 /* SCv2 */ + +#define SC_KEY_RESET 0x00000000 +#define SC_KEY_LOCK 0xFFFFFFFF +#define SC_KEY_UNL 0x5F554E4C /* _UNL */ +#define SC_KEY_OCK 0x4F434B5F /* OCK_ */ + +typedef u64 uu64 __attribute__((aligned(1))); // NOLINT +#define CART_ABORT() \ + { \ + cartUnlock(); \ + return -1; \ + } + +#endif diff --git a/src/io/sc64_io.h b/src/io/sc64_io.h new file mode 100644 index 00000000..269d5cc9 --- /dev/null +++ b/src/io/sc64_io.h @@ -0,0 +1,8 @@ +#ifndef SC64_IO_H +#define SC64_IO_H + +struct Iodev; + +extern struct Iodev sc64; + +#endif diff --git a/src/pm64.h b/src/pm64.h index 486d4ab0..56da2eb1 100644 --- a/src/pm64.h +++ b/src/pm64.h @@ -1248,6 +1248,7 @@ bool pm_fioFetchSavedFileInfo(void); void pm_fioDeserializeState(void); void pm_fioReadFlash(s32 slot, void *buffer, u32 size); // writes to buffer in 128-byte blocks void pm_fioWriteFlash(s32 slot, void *buffer, u32 size); +void pm_fioEraseFlash(s32 slot); void pm_setCurtainScaleGoal(f32 goal); void pm_setCurtainDrawCallback(void *callback); void pm_setCurtainFadeGoal(f32 goal); diff --git a/src/sys/settings.c b/src/sys/settings.c index 02fdce0c..182b5afa 100644 --- a/src/sys/settings.c +++ b/src/sys/settings.c @@ -96,6 +96,7 @@ void settingsSave(s32 profile) { pm_fioReadFlash(SETTINGS_FIO_PAGE, &settingsBuffer, sizeof(settingsBuffer)); settingsStore.header.dataChecksum = settingsChecksumCompute(&settingsStore); memcpy(&settingsBuffer[profile], &settingsStore, sizeof(settingsStore)); + pm_fioEraseFlash(SETTINGS_FIO_PAGE); pm_fioWriteFlash(SETTINGS_FIO_PAGE, &settingsBuffer, sizeof(settingsBuffer)); }