little sd card cleanup

This commit is contained in:
Polprzewodnikowy 2022-09-11 10:48:44 +02:00
parent 321f3d37aa
commit e6866e8fe0
14 changed files with 320 additions and 252 deletions

View File

@ -29,8 +29,8 @@ SRC_FILES = \
io.c \ io.c \
ipl2.S \ ipl2.S \
main.c \ main.c \
menu.c \
sc64.c \ sc64.c \
storage.c \
syscalls.c \ syscalls.c \
test.c \ test.c \
version.c \ version.c \

View File

@ -4,7 +4,11 @@
#include "../sc64.h" #include "../sc64.h"
#include "../error.h" #include "../error.h"
DSTATUS status = STA_NOINIT;
#define FROM_BCD(x) ((((x >> 4) & 0x0F) * 10) + (x & 0x0F))
static DSTATUS status = STA_NOINIT;
DSTATUS disk_status (BYTE pdrv) { DSTATUS disk_status (BYTE pdrv) {
@ -18,7 +22,7 @@ DSTATUS disk_initialize (BYTE pdrv) {
if (pdrv > 0) { if (pdrv > 0) {
return STA_NODISK; return STA_NODISK;
} }
if (!sc64_sd_card_initialize()) { if (!sc64_sd_card_init()) {
status &= ~(STA_NOINIT); status &= ~(STA_NOINIT);
} }
return status; return status;
@ -28,67 +32,61 @@ DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) {
if (pdrv > 0) { if (pdrv > 0) {
return RES_PARERR; return RES_PARERR;
} }
uint32_t physical_address = ((uint32_t) (buff)) & 0x1FFFFFFF; uint32_t *physical_address = (uint32_t *) (PHYSICAL(buff));
uint32_t block = 0; if (physical_address < (uint32_t *) (N64_RAM_SIZE)) {
while (count > 0) { while (count > 0) {
if (physical_address < (8 * 1024 * 1024)) { uint32_t block = ((count > 16) ? 16 : count);
block = ((count > 16) ? 16 : count); if (sc64_sd_read_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, block)) {
if (sc64_sd_read_sectors(sector, 0x1FFE0000UL, block * 512)) {
return RES_ERROR; return RES_ERROR;
} }
for (uint32_t i = 0; i < (block * 512); i += 4) { for (uint32_t i = 0; i < (block * 512); i += 4) {
uint32_t data = pi_io_read((uint32_t *) (0x1FFE0000UL + i)); // TODO: use dma
uint32_t data = pi_io_read((uint32_t *) (&SC64_BUFFERS->BUFFER[i]));
uint8_t *ptr = (uint8_t *) (&data); uint8_t *ptr = (uint8_t *) (&data);
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) {
*buff++ = *ptr++; *buff++ = *ptr++;
} }
} }
} else {
block = ((count > 256) ? 256 : count);
if (sc64_sd_read_sectors(sector, physical_address, block * 512)) {
error_display("Kurwa 0x%08X, 0x%08X\n", physical_address, block);
return RES_ERROR;
}
physical_address += (block * 512);
}
count -= block; count -= block;
sector += block; sector += block;
} }
} else {
if (sc64_sd_read_sectors(physical_address, sector, count)) {
return RES_ERROR;
}
}
return RES_OK; return RES_OK;
} }
#if !FF_FS_READONLY #if !FF_FS_READONLY
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) { DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) {
// if (pdrv >= __DRIVE_COUNT) { if (pdrv > 0) {
// return RES_PARERR; return RES_PARERR;
// } }
// if (sc64_storage_write((drive_id_t) (pdrv), buff, sector, count)) { // TODO: write
return RES_ERROR; return RES_ERROR;
// }
// return RES_OK;
} }
#endif #endif
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void *buff) { DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void *buff) {
if (pdrv > 0) {
return RES_PARERR;
}
if (cmd == CTRL_SYNC) { if (cmd == CTRL_SYNC) {
return RES_OK; return RES_OK;
} }
return RES_PARERR; return RES_PARERR;
} }
static uint8_t from_bcd (uint8_t bcd) {
return ((((bcd >> 4) & 0x0F) * 10) + (bcd & 0x0F));
}
DWORD get_fattime(void) { DWORD get_fattime(void) {
rtc_time_t t; rtc_time_t t;
sc64_get_time(&t); sc64_get_time(&t);
return ( return (
((from_bcd(t.year) + 20) << 25) | ((FROM_BCD(t.year) + 20) << 25) |
(from_bcd(t.month) << 21) | (FROM_BCD(t.month) << 21) |
(from_bcd(t.day) << 16) | (FROM_BCD(t.day) << 16) |
(from_bcd(t.hour) << 11) | (FROM_BCD(t.hour) << 11) |
(from_bcd(t.minute) << 5) | (FROM_BCD(t.minute) << 5) |
(from_bcd(t.second) >> 1) (FROM_BCD(t.second) >> 1)
); );
} }

View File

@ -12,8 +12,11 @@ typedef volatile uint32_t io32_t;
#define ALIGN(value, align) (((value) + ((typeof(value))(align) - 1)) & ~((typeof(value))(align) - 1)) #define ALIGN(value, align) (((value) + ((typeof(value))(align) - 1)) & ~((typeof(value))(align) - 1))
#define PHYSICAL(address) ((typeof(address)) (((io32_t) (address)) & (0x1FFFFFFFUL)))
#define UNCACHED(address) ((typeof(address)) (((io32_t) (address)) | (0xA0000000UL))) #define UNCACHED(address) ((typeof(address)) (((io32_t) (address)) | (0xA0000000UL)))
#define N64_RAM_SIZE (0x00800000UL)
typedef struct { typedef struct {
io32_t DMEM[1024]; io32_t DMEM[1024];

View File

@ -2,8 +2,8 @@
#include "error.h" #include "error.h"
#include "init.h" #include "init.h"
#include "io.h" #include "io.h"
#include "menu.h"
#include "sc64.h" #include "sc64.h"
#include "storage.h"
void main (void) { void main (void) {
@ -13,12 +13,8 @@ void main (void) {
sc64_get_boot_info(&sc64_boot_info); sc64_get_boot_info(&sc64_boot_info);
switch (sc64_boot_info.boot_mode) { switch (sc64_boot_info.boot_mode) {
case BOOT_MODE_MENU_SD: case BOOT_MODE_MENU:
storage_run_menu(STORAGE_BACKEND_SD); menu_load_and_run();
break;
case BOOT_MODE_MENU_USB:
storage_run_menu(STORAGE_BACKEND_USB);
break; break;
case BOOT_MODE_ROM: case BOOT_MODE_ROM:

View File

@ -1,7 +1,7 @@
#include "error.h" #include "error.h"
#include "init.h"
#include "storage.h"
#include "fatfs/ff.h" #include "fatfs/ff.h"
#include "init.h"
#include "menu.h"
#define ROM_ENTRY_OFFSET (8) #define ROM_ENTRY_OFFSET (8)
@ -41,28 +41,16 @@ static const char *fatfs_error_codes[] = {
} }
void storage_run_menu (storage_backend_t storage_backend) { void menu_load_and_run (void) {
void (* menu)(void); void (* menu)(void);
FRESULT fresult; FRESULT fresult;
FATFS fs; FATFS fs;
FIL fil; FIL fil;
UINT br; UINT br;
FSIZE_t size = ROM_MAX_LOAD_SIZE; FSIZE_t size = ROM_MAX_LOAD_SIZE;
const TCHAR *path = "";
if (storage_backend == STORAGE_BACKEND_SD) { FF_CHECK(f_mount(&fs, "", 1), "Couldn't mount drive");
path = "0:";
} else if (storage_backend == STORAGE_BACKEND_USB) {
path = "1:";
} else {
error_display("Unknown storage backend [%d]\n", storage_backend);
}
FF_CHECK(f_mount(&fs, path, 1), "Couldn't mount drive");
FF_CHECK(f_chdrive(path), "Couldn't chdrive");
FF_CHECK(f_open(&fil, "sc64menu.n64", FA_READ), "Couldn't open menu file"); FF_CHECK(f_open(&fil, "sc64menu.n64", FA_READ), "Couldn't open menu file");
FF_CHECK(f_lseek(&fil, 0), "debug 1");
FF_CHECK(f_read(&fil, (void *) (0x10000000UL), f_size(&fil), &br), "debug 2");
FF_CHECK(f_lseek(&fil, ROM_ENTRY_OFFSET), "Couldn't seek to entry point offset"); FF_CHECK(f_lseek(&fil, ROM_ENTRY_OFFSET), "Couldn't seek to entry point offset");
FF_CHECK(f_read(&fil, &menu, sizeof(menu), &br), "Couldn't read entry point"); FF_CHECK(f_read(&fil, &menu, sizeof(menu), &br), "Couldn't read entry point");
FF_CHECK(f_lseek(&fil, ROM_CODE_OFFSET), "Couldn't seek to code start offset"); FF_CHECK(f_lseek(&fil, ROM_CODE_OFFSET), "Couldn't seek to code start offset");
@ -71,8 +59,11 @@ void storage_run_menu (storage_backend_t storage_backend) {
} }
FF_CHECK(f_read(&fil, menu, size, &br), "Couldn't read menu file"); FF_CHECK(f_read(&fil, menu, size, &br), "Couldn't read menu file");
FF_CHECK(br != size, "Read size is different than expected"); FF_CHECK(br != size, "Read size is different than expected");
FF_CHECK(f_lseek(&fil, 0), "Couldn't seek to the beginning of file");
FF_CHECK(f_read(&fil, (void *) (0x10000000UL), f_size(&fil), &br), "Couldn't read file contents to SDRAM");
FF_CHECK(f_close(&fil), "Couldn't close menu file"); FF_CHECK(f_close(&fil), "Couldn't close menu file");
FF_CHECK(f_unmount(path), "Couldn't unmount drive"); FF_CHECK(f_unmount(""), "Couldn't unmount drive");
deinit(); deinit();

8
sw/bootloader/src/menu.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef MENU_H__
#define MENU_H__
void menu_load_and_run (void);
#endif

View File

@ -15,7 +15,7 @@ typedef enum {
SC64_CMD_USB_WRITE = 'M', SC64_CMD_USB_WRITE = 'M',
SC64_CMD_USB_READ_STATUS = 'u', SC64_CMD_USB_READ_STATUS = 'u',
SC64_CMD_USB_READ = 'm', SC64_CMD_USB_READ = 'm',
SC64_CMD_SD_CARD_INITIALIZE = 'i', SC64_CMD_SD_CARD_INIT = 'i',
SC64_CMD_SD_SECTOR_SET = 'I', SC64_CMD_SD_SECTOR_SET = 'I',
SC64_CMD_SD_READ = 's', SC64_CMD_SD_READ = 's',
SC64_CMD_SD_WRITE = 'S', SC64_CMD_SD_WRITE = 'S',
@ -27,7 +27,7 @@ static bool sc64_wait_cpu_busy (void) {
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);
return sr & SC64_SR_CMD_ERROR; return (sr & SC64_SR_CMD_ERROR);
} }
static bool sc64_execute_cmd (uint8_t cmd, uint32_t *args, uint32_t *result) { static bool sc64_execute_cmd (uint8_t cmd, uint32_t *args, uint32_t *result) {
@ -126,7 +126,7 @@ bool sc64_usb_read_ready (uint8_t *type, uint32_t *length) {
if (length != NULL) { if (length != NULL) {
*length = result[1]; *length = result[1];
} }
return result[1] > 0; return (result[1] > 0);
} }
bool sc64_usb_read (uint32_t *address, uint32_t length) { bool sc64_usb_read (uint32_t *address, uint32_t length) {
@ -141,16 +141,25 @@ bool sc64_usb_read (uint32_t *address, uint32_t length) {
return false; return false;
} }
bool sc64_sd_card_initialize (void) { bool sc64_sd_card_init (void) {
if (sc64_execute_cmd(SC64_CMD_SD_CARD_INITIALIZE, NULL, NULL)) { uint32_t args[2] = { 0, true };
if (sc64_execute_cmd(SC64_CMD_SD_CARD_INIT, args, NULL)) {
return true; return true;
} }
return false; return false;
} }
bool sc64_sd_read_sectors (uint32_t starting_sector, uint32_t address, uint32_t length) { bool sc64_sd_card_deinit (void) {
uint32_t sector_set_args[2] = { starting_sector, 0 }; uint32_t args[2] = { 0, false };
uint32_t read_args[2] = { address, length }; if (sc64_execute_cmd(SC64_CMD_SD_CARD_INIT, args, NULL)) {
return true;
}
return false;
}
bool sc64_sd_read_sectors (uint32_t *address, uint32_t sector, uint32_t count) {
uint32_t sector_set_args[2] = { sector, 0 };
uint32_t read_args[2] = { (uint32_t) (address), count };
if (sc64_execute_cmd(SC64_CMD_SD_SECTOR_SET, sector_set_args, NULL)) { if (sc64_execute_cmd(SC64_CMD_SD_SECTOR_SET, sector_set_args, NULL)) {
return true; return true;
} }

View File

@ -39,11 +39,10 @@ typedef enum {
} dd_mode_t; } dd_mode_t;
typedef enum { typedef enum {
BOOT_MODE_MENU_SD = 0, BOOT_MODE_MENU = 0,
BOOT_MODE_MENU_USB = 1, BOOT_MODE_ROM = 1,
BOOT_MODE_ROM = 2, BOOT_MODE_DDIPL = 2,
BOOT_MODE_DDIPL = 3, BOOT_MODE_DIRECT = 3
BOOT_MODE_DIRECT = 4
} boot_mode_t; } boot_mode_t;
typedef enum { typedef enum {
@ -104,8 +103,9 @@ bool sc64_usb_write_ready (void);
bool sc64_usb_write (uint32_t *address, uint32_t length); bool sc64_usb_write (uint32_t *address, uint32_t length);
bool sc64_usb_read_ready (uint8_t *type, uint32_t *length); bool sc64_usb_read_ready (uint8_t *type, uint32_t *length);
bool sc64_usb_read (uint32_t *address, uint32_t length); bool sc64_usb_read (uint32_t *address, uint32_t length);
bool sc64_sd_card_initialize (void); bool sc64_sd_card_init (void);
bool sc64_sd_read_sectors (uint32_t starting_sector, uint32_t address, uint32_t length); bool sc64_sd_card_deinit (void);
bool sc64_sd_read_sectors (uint32_t *address, uint32_t sector, uint32_t count);
#endif #endif

View File

@ -1,14 +0,0 @@
#ifndef STORAGE_H__
#define STORAGE_H__
typedef enum {
STORAGE_BACKEND_SD = 0,
STORAGE_BACKEND_USB = 1,
} storage_backend_t;
void storage_run_menu (storage_backend_t storage_backend);
#endif

View File

@ -35,11 +35,10 @@ typedef enum {
} dd_mode_t; } dd_mode_t;
typedef enum { typedef enum {
BOOT_MODE_MENU_SD = 0, BOOT_MODE_MENU = 0,
BOOT_MODE_MENU_USB = 1, BOOT_MODE_ROM = 1,
BOOT_MODE_ROM = 2, BOOT_MODE_DD = 2,
BOOT_MODE_DD = 3, BOOT_MODE_DIRECT = 3
BOOT_MODE_DIRECT = 4
} boot_mode_t; } boot_mode_t;
typedef enum { typedef enum {
@ -315,7 +314,7 @@ void cfg_init (void) {
p.cic_seed = CIC_SEED_UNKNOWN; p.cic_seed = CIC_SEED_UNKNOWN;
p.tv_type = TV_TYPE_UNKNOWN; p.tv_type = TV_TYPE_UNKNOWN;
p.boot_mode = BOOT_MODE_MENU_SD; p.boot_mode = BOOT_MODE_MENU;
p.usb_output_ready = true; p.usb_output_ready = true;
} }
@ -393,9 +392,13 @@ void cfg_process (void) {
break; break;
case 'i': case 'i':
if (sd_card_initialize()) { if (args[1]) {
if (sd_card_init()) {
cfg_set_error(CFG_ERROR_SD); cfg_set_error(CFG_ERROR_SD);
} }
} else {
sd_card_deinit();
}
break; break;
case 'I': case 'I':
@ -407,7 +410,7 @@ void cfg_process (void) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS); cfg_set_error(CFG_ERROR_BAD_ADDRESS);
return; return;
} }
if (sd_read_sectors(p.sd_card_sector, args[0], args[1])) { if (sd_read_sectors(args[0], p.sd_card_sector, args[1])) {
cfg_set_error(CFG_ERROR_SD); cfg_set_error(CFG_ERROR_SD);
} }
break; break;

View File

@ -55,6 +55,9 @@ typedef enum {
} fpga_reg_t; } fpga_reg_t;
#define SWAP16(x) (((x & 0xFF) << 8) | ((x & 0xFF00) >> 8))
#define SWAP32(x) ((x & 0xFF) << 24 | (x & 0xFF00) << 8 | (x & 0xFF0000) >> 8 | (x & 0xFF000000) >> 24)
#define FPGA_ID (0x64) #define FPGA_ID (0x64)
#define FPGA_MAX_MEM_TRANSFER (1024) #define FPGA_MAX_MEM_TRANSFER (1024)
@ -174,8 +177,6 @@ typedef enum {
#define DD_HEAD_TRACK_MASK (DD_HEAD_MASK | DD_TRACK_MASK) #define DD_HEAD_TRACK_MASK (DD_HEAD_MASK | DD_TRACK_MASK)
#define DD_HEAD_TRACK_INDEX_LOCK (1 << 13) #define DD_HEAD_TRACK_INDEX_LOCK (1 << 13)
#define SWAP32(x) ((x & 0xFF) << 24 | (x & 0xFF00) << 8 | (x & 0xFF0000) >> 8 | (x & 0xFF000000) >> 24)
uint8_t fpga_id_get (void); uint8_t fpga_id_get (void);
uint32_t fpga_reg_get (fpga_reg_t reg); uint32_t fpga_reg_get (fpga_reg_t reg);

View File

@ -1,22 +1,35 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "sd.h"
#include "fpga.h" #include "fpga.h"
#include "debug.h"
#include "hw.h" #include "hw.h"
#include "sd.h"
#define SD_BUFFER_ADDRESS (0x05000000UL)
#define CMD6_ARG_CHECK_HS (0x00FFFFF1UL)
#define CMD6_ARG_SWITCH_HS (0x80FFFFF1UL)
#define CMD8_ARG_SUPPLY_VOLTAGE_27_36_V (1 << 8) #define CMD8_ARG_SUPPLY_VOLTAGE_27_36_V (1 << 8)
#define CMD8_ARG_CHECK_PATTERN (0xAA << 0) #define CMD8_ARG_CHECK_PATTERN (0xAA << 0)
#define ACMD6_ARG_BUS_WIDTH_4BIT (2 << 0)
#define ACMD41_ARG_OCR (0xFF8000 << 0)
#define ACMD41_ARG_HCS (1 << 30) #define ACMD41_ARG_HCS (1 << 30)
#define R3_OCR (0xFF8000 << 0)
#define R3_CCS (1 << 30) #define R3_CCS (1 << 30)
#define R3_BUSY (1 << 31) #define R3_BUSY (1 << 31)
#define R6_RCA_MASK (0xFFFF0000UL)
#define R7_SUPPLY_VOLTAGE_27_36_V (1 << 8) #define R7_SUPPLY_VOLTAGE_27_36_V (1 << 8)
#define R7_CHECK_PATTERN (0xAA << 0) #define R7_CHECK_PATTERN (0xAA << 0)
#define SD_BLOCK_SIZE (512)
#define DAT_BLOCK_MAX_COUNT (256)
typedef enum { typedef enum {
CLOCK_STOP, CLOCK_STOP,
@ -35,15 +48,39 @@ typedef enum {
RSP_R7, RSP_R7,
} rsp_type_t; } rsp_type_t;
typedef enum {
DAT_READ,
DAT_WRITE,
} dat_mode_t;
static bool sd_card_initialized;
static bool sd_card_type_block; struct process {
static uint32_t sd_rca = 0; bool card_initialized;
static volatile bool timeout = false; bool card_type_block;
uint32_t rca;
volatile bool timeout;
};
static struct process p;
static void sd_trigger_timeout (void) { static void sd_trigger_timeout (void) {
timeout = true; p.timeout = true;
}
static void sd_prepare_timeout (uint16_t value) {
p.timeout = false;
hw_tim_setup(TIM_ID_GVR, value, sd_trigger_timeout);
}
static bool sd_did_timeout (void) {
return p.timeout;
}
static void sd_clear_timeout (void) {
hw_tim_stop(TIM_ID_GVR);
p.timeout = false;
} }
static void sd_set_clock (sd_clock_t mode) { static void sd_set_clock (sd_clock_t mode) {
@ -91,22 +128,15 @@ static bool sd_cmd (uint8_t cmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) {
} while (scr & SD_SCR_CMD_BUSY); } while (scr & SD_SCR_CMD_BUSY);
if (rsp != NULL) { if (rsp != NULL) {
fpga_reg_t rsp_regs[4] = { bool rsp_long = (cmd_data & SD_CMD_LONG_RESPONSE);
REG_SD_RSP_3,
REG_SD_RSP_2,
REG_SD_RSP_1,
REG_SD_RSP_0
};
bool rsp_long = rsp_type & SD_CMD_LONG_RESPONSE;
fpga_reg_t rsp_reg = (rsp_long ? 0 : (sizeof(rsp_regs) - 1));
uint8_t *rsp_8 = (uint8_t *) (rsp); uint8_t *rsp_8 = (uint8_t *) (rsp);
while (rsp_reg < sizeof(rsp_regs)) { for (int i = 0; i < (rsp_long ? 4 : 1); i++) {
uint32_t rsp_data = fpga_reg_get(rsp_regs[rsp_reg++]); uint32_t rsp_data = fpga_reg_get(REG_SD_RSP_0 + i);
uint8_t *rsp_data_8 = (uint8_t *) (&rsp_data); uint8_t *rsp_data_8 = (uint8_t *) (&rsp_data);
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
*rsp_8++ = *rsp_data_8++; *rsp_8++ = *rsp_data_8++;
} }
}; }
} }
if (rsp_type == RSP_R1b) { if (rsp_type == RSP_R1b) {
@ -119,7 +149,7 @@ static bool sd_cmd (uint8_t cmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) {
} }
static bool sd_acmd (uint8_t acmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) { static bool sd_acmd (uint8_t acmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) {
if (sd_cmd(55, sd_rca, RSP_R1, NULL)) { if (sd_cmd(55, p.rca, RSP_R1, NULL)) {
return true; return true;
} }
if (sd_cmd(acmd, arg, rsp_type, rsp)) { if (sd_cmd(acmd, arg, rsp_type, rsp)) {
@ -128,158 +158,201 @@ static bool sd_acmd (uint8_t acmd, uint32_t arg, rsp_type_t rsp_type, void *rsp)
return false; return false;
} }
static void sd_dat_prepare (uint32_t address, uint32_t count, dat_mode_t mode) {
uint32_t length = (count * SD_BLOCK_SIZE);
uint32_t sd_dat = (((count - 1) << SD_DAT_BLOCKS_BIT) | SD_DAT_FIFO_FLUSH);
uint32_t sd_dma_scr = DMA_SCR_START;
bool sd_read_sectors (uint32_t starting_sector, uint32_t address, uint32_t length) { if (mode == DAT_READ) {
if (!sd_card_initialized) { sd_dat |= SD_DAT_START_READ;
return true; sd_dma_scr |= DMA_SCR_DIRECTION;
} else {
sd_dat |= SD_DAT_START_WRITE;
} }
if ((length == 0) || (length % 512 != 0) || (length > (256 * 512))) { fpga_reg_set(REG_SD_DAT, sd_dat);
return true;
}
do {
uint32_t blocks = (length / 512);
timeout = false;
hw_tim_setup(TIM_ID_GVR, 5000, sd_trigger_timeout);
if (!sd_card_type_block) {
starting_sector *= 512;
}
// fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_STOP);
// fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH);
fpga_reg_set(REG_SD_DMA_ADDRESS, address); fpga_reg_set(REG_SD_DMA_ADDRESS, address);
fpga_reg_set(REG_SD_DMA_LENGTH, length); fpga_reg_set(REG_SD_DMA_LENGTH, length);
fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_DIRECTION | DMA_SCR_START); fpga_reg_set(REG_SD_DMA_SCR, sd_dma_scr);
fpga_reg_set(REG_SD_DAT, (((blocks - 1) << SD_DAT_BLOCKS_BIT) | SD_DAT_START_READ | SD_DAT_FIFO_FLUSH));
if (sd_cmd(23, blocks, RSP_R1, NULL)) {
break;
} }
if (sd_cmd(18, starting_sector, RSP_R1, NULL)) { static void sd_dat_abort (void) {
break;
}
bool error = false;
while (!timeout) {
uint32_t sd_scr = fpga_reg_get(REG_SD_SCR);
if (!(sd_scr & SD_SCR_CARD_INSERTED)) {
error = true;
break;
}
uint32_t sd_dat = fpga_reg_get(REG_SD_DAT);
uint32_t sd_dma_scr = fpga_reg_get(REG_SD_DMA_SCR);
if (sd_dat & SD_DAT_ERROR) {
error = true;
break;
}
if ((!(sd_dma_scr & DMA_SCR_BUSY)) && (!(sd_dat & SD_DAT_BUSY))) {
break;
}
}
if (timeout) {
break;
}
hw_tim_stop(TIM_ID_GVR);
if (error) {
break;
}
return false;
} while (0);
fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_STOP); fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_STOP);
fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH); fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH);
}
static bool sd_dat_wait (uint16_t timeout) {
sd_prepare_timeout(timeout);
do {
uint32_t sd_dat = fpga_reg_get(REG_SD_DAT);
uint32_t sd_dma_scr = fpga_reg_get(REG_SD_DMA_SCR);
if ((!(sd_dat & SD_DAT_BUSY)) && (!(sd_dma_scr & DMA_SCR_BUSY))) {
sd_clear_timeout();
return (sd_dat & SD_DAT_ERROR);
}
} while (!sd_did_timeout());
sd_dat_abort();
return true; return true;
} }
bool sd_card_initialize (void) {
bool error;
uint32_t arg;
uint32_t rsp;
bool version_2_or_later = false;
if (sd_card_initialized) { bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
if (!p.card_initialized || (count == 0)) {
return true;
}
if (!p.card_type_block) {
sector *= SD_BLOCK_SIZE;
}
while (count > 0) {
uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count);
sd_dat_prepare(address, blocks, DAT_READ);
if (sd_cmd(23, blocks, RSP_R1, NULL)) {
sd_dat_abort();
return true;
}
if (sd_cmd(18, sector, RSP_R1, NULL)) {
sd_dat_abort();
return true;
}
if (sd_dat_wait(1000)) {
if (sd_did_timeout()) {
sd_cmd(12, 0, RSP_R1b, NULL);
}
return true;
}
address += (blocks * SD_BLOCK_SIZE);
sector += (blocks * (p.card_type_block ? 1 : SD_BLOCK_SIZE));
count -= blocks;
}
return false; return false;
} }
bool sd_card_init (void) {
uint32_t arg;
uint32_t rsp;
uint16_t sd_function;
if (p.card_initialized) {
return false;
}
p.card_initialized = true;
p.rca = 0;
sd_set_clock(CLOCK_400KHZ); sd_set_clock(CLOCK_400KHZ);
do {
sd_cmd(0, 0, RSP_NONE, NULL); sd_cmd(0, 0, RSP_NONE, NULL);
arg = (CMD8_ARG_SUPPLY_VOLTAGE_27_36_V | CMD8_ARG_CHECK_PATTERN); arg = (CMD8_ARG_SUPPLY_VOLTAGE_27_36_V | CMD8_ARG_CHECK_PATTERN);
if (!sd_cmd(8, arg, RSP_R7, &rsp)) { if (sd_cmd(8, arg, RSP_R7, &rsp)) {
version_2_or_later = true; arg = ACMD41_ARG_OCR;
} else {
if (rsp != (R7_SUPPLY_VOLTAGE_27_36_V | R7_CHECK_PATTERN)) { if (rsp != (R7_SUPPLY_VOLTAGE_27_36_V | R7_CHECK_PATTERN)) {
break; sd_card_deinit();
return true;
} }
arg = (ACMD41_ARG_HCS | ACMD41_ARG_OCR);
} }
arg = ((version_2_or_later ? ACMD41_ARG_HCS : 0) | 0x00FF8000); sd_prepare_timeout(1000);
for (int i = 0; i < 4000; i++) { do {
error = sd_acmd(41, arg, RSP_R3, &rsp); if (sd_did_timeout()) {
if (error || (rsp & R3_BUSY)) { sd_card_deinit();
return true;
}
if (sd_acmd(41, arg, RSP_R3, &rsp)) {
sd_card_deinit();
return true;
}
if (rsp & R3_BUSY) {
if ((rsp & R3_OCR) == 0) {
sd_card_deinit();
return true;
}
p.card_type_block = (rsp & R3_CCS);
break; break;
} }
} } while (1);
if (error || ((rsp & 0x00FF8000) == 0)) { sd_clear_timeout();
break;
}
sd_card_type_block = (rsp & R3_CCS);
if (sd_cmd(2, 0, RSP_R2, NULL)) { if (sd_cmd(2, 0, RSP_R2, NULL)) {
break; sd_card_deinit();
}
if (sd_cmd(3, 0, RSP_R6, &rsp)) {
break;
}
sd_rca = rsp & 0xFFFF0000;
if (sd_cmd(7, sd_rca, RSP_R1b, NULL)) {
break;
}
if (sd_acmd(6, 2, RSP_R1, NULL)) {
break;
}
sd_set_clock(CLOCK_50MHZ);
sd_card_initialized = true;
return false;
} while (0);
sd_rca = 0;
sd_cmd(0, 0, RSP_NONE, NULL);
sd_set_clock(CLOCK_STOP);
return true; return true;
} }
if (sd_cmd(3, 0, RSP_R6, &rsp)) {
sd_card_deinit();
return true;
}
p.rca = (rsp & R6_RCA_MASK);
if (sd_cmd(7, p.rca, RSP_R1b, NULL)) {
sd_card_deinit();
return true;
}
sd_set_clock(CLOCK_25MHZ);
if (sd_acmd(6, ACMD6_ARG_BUS_WIDTH_4BIT, RSP_R1, NULL)) {
sd_card_deinit();
return true;
}
sd_dat_prepare(SD_BUFFER_ADDRESS, 1, DAT_READ);
if (sd_cmd(6, CMD6_ARG_CHECK_HS, RSP_R1, NULL)) {
sd_dat_abort();
sd_card_deinit();
return true;
}
sd_dat_wait(1000);
if (sd_did_timeout()) {
sd_card_deinit();
return true;
}
fpga_mem_read(SD_BUFFER_ADDRESS + 12, 2, (uint8_t *) (&sd_function));
if (SWAP16(sd_function) & (1 << 1)) {
sd_dat_prepare(SD_BUFFER_ADDRESS, 1, DAT_READ);
if (sd_cmd(6, CMD6_ARG_SWITCH_HS, RSP_R1, NULL)) {
sd_dat_abort();
sd_card_deinit();
return true;
}
sd_dat_wait(1000);
if (sd_did_timeout()) {
sd_card_deinit();
return true;
}
fpga_mem_read(SD_BUFFER_ADDRESS + 12, 2, (uint8_t *) (&sd_function));
if (SWAP16(sd_function) & (1 << 1)) {
sd_set_clock(CLOCK_50MHZ);
}
}
return false;
}
void sd_card_deinit (void) {
if (p.card_initialized) {
p.card_initialized = false;
sd_set_clock(CLOCK_400KHZ);
sd_cmd(0, 0, RSP_NONE, NULL);
sd_set_clock(CLOCK_STOP);
}
}
void sd_init (void) { void sd_init (void) {
sd_card_initialized = false; p.card_initialized = false;
sd_set_clock(CLOCK_STOP); sd_set_clock(CLOCK_STOP);
} }
void sd_process (void) { void sd_process (void) {
if (!(fpga_reg_get(REG_SD_SCR) & SD_SCR_CARD_INSERTED)) { if (!(fpga_reg_get(REG_SD_SCR) & SD_SCR_CARD_INSERTED)) {
if (sd_card_initialized) { sd_card_deinit();
sd_card_initialized = false;
sd_rca = 0;
sd_set_clock(CLOCK_STOP);
}
} }
} }

View File

@ -5,8 +5,9 @@
#include <stdbool.h> #include <stdbool.h>
bool sd_read_sectors (uint32_t starting_sector, uint32_t address, uint32_t length); bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count);
bool sd_card_initialize (void); bool sd_card_init (void);
void sd_card_deinit (void);
void sd_init (void); void sd_init (void);
void sd_process (void); void sd_process (void);

View File

@ -276,11 +276,10 @@ class SC64:
DD_DISK_SWAP = 3 DD_DISK_SWAP = 3
class BootMode(IntEnum): class BootMode(IntEnum):
SD = 0 MENU = 0
USB = 1 ROM = 1
ROM = 2 DDIPL = 2
DDIPL = 3 DIRECT = 3
DIRECT = 4
class SaveType(IntEnum): class SaveType(IntEnum):
NONE = 0 NONE = 0
@ -357,7 +356,7 @@ class SC64:
self.__set_config(self.__CfgId.ROM_SHADOW_ENABLE, False) self.__set_config(self.__CfgId.ROM_SHADOW_ENABLE, False)
self.__set_config(self.__CfgId.DD_MODE, self.__DDMode.NONE) self.__set_config(self.__CfgId.DD_MODE, self.__DDMode.NONE)
self.__set_config(self.__CfgId.ISV_ENABLE, False) self.__set_config(self.__CfgId.ISV_ENABLE, False)
self.__set_config(self.__CfgId.BOOT_MODE, self.BootMode.USB) self.__set_config(self.__CfgId.BOOT_MODE, self.BootMode.MENU)
self.__set_config(self.__CfgId.SAVE_TYPE, self.SaveType.NONE) self.__set_config(self.__CfgId.SAVE_TYPE, self.SaveType.NONE)
self.__set_config(self.__CfgId.CIC_SEED, self.CICSeed.AUTO) self.__set_config(self.__CfgId.CIC_SEED, self.CICSeed.AUTO)
self.__set_config(self.__CfgId.TV_TYPE, self.TVType.AUTO) self.__set_config(self.__CfgId.TV_TYPE, self.TVType.AUTO)