64dd from sd card working

This commit is contained in:
Polprzewodnikowy 2022-09-15 19:42:46 +02:00
parent 60592dca3a
commit f701df4fbb
13 changed files with 220 additions and 50 deletions

View File

@ -34,7 +34,7 @@
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define FF_USE_FASTSEEK 1
#define FF_USE_FASTSEEK 0
/* This option switches fast seek function. (0:Disable or 1:Enable) */
@ -224,7 +224,7 @@
/ System Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_TINY 0
#define FF_FS_TINY 1
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.
/ Instead of private sector buffer eliminated from the file object, common sector

View File

@ -19,6 +19,7 @@ typedef enum {
SC64_CMD_SD_SECTOR_SET = 'I',
SC64_CMD_SD_WRITE = 'S',
SC64_CMD_SD_READ = 's',
SC64_CMD_DD_SD_DISK_INFO = 'D',
} cmd_id_t;
typedef enum {
@ -199,3 +200,11 @@ bool sc64_sd_read_sectors (uint32_t *address, uint32_t sector, uint32_t count) {
}
return sc64_execute_cmd(SC64_CMD_SD_READ, read_args, NULL);
}
bool sc64_dd_set_sd_disk_info (uint32_t *address, uint32_t count) {
uint32_t args[2] = { (uint32_t) (address), count };
if (sc64_execute_cmd(SC64_CMD_DD_SD_DISK_INFO, args, NULL)) {
return true;
}
return false;
}

View File

@ -29,6 +29,8 @@ typedef enum {
CFG_ID_DD_DISK_STATE,
CFG_ID_BUTTON_STATE,
CFG_ID_BUTTON_MODE,
CFG_ID_ROM_EXTENDED_ENABLE,
CFG_ID_DD_SD_MODE,
} cfg_id_t;
typedef enum {
@ -109,6 +111,7 @@ bool sc64_sd_card_get_status (void);
bool sc64_sd_card_get_info (uint32_t *address);
bool sc64_sd_write_sectors (uint32_t *address, uint32_t sector, uint32_t count);
bool sc64_sd_read_sectors (uint32_t *address, uint32_t sector, uint32_t count);
bool sc64_dd_set_sd_disk_info (uint32_t *address, uint32_t count);
#endif

View File

@ -13,6 +13,8 @@ bool test_check (void) {
}
void test_execute (void) {
uint8_t card_info[32] __attribute__((aligned(8)));
display_init(NULL);
display_printf("SC64 Test suite\n\n");
@ -27,18 +29,25 @@ void test_execute (void) {
while (1);
}
uint8_t card_info[32] __attribute__((aligned(8)));
pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), card_info, sizeof(card_info));
display_printf("CSD: 0x");
display_printf("SD Card registers:\n CSD: 0x");
for (int i = 0; i < 16; i++) {
display_printf("%02X", card_info[i]);
}
display_printf("\nCID: 0x");
display_printf("\n CID: 0x");
for (int i = 16; i < 32; i++) {
display_printf("%02X", card_info[i]);
}
display_printf("\n ");
for (int i = 16; i < 32; i++) {
display_printf("%c ", card_info[i] >= ' ' ? card_info[i] : 0xFF);
}
if (sc64_sd_card_deinit()) {
display_printf("SD card deinit error!\n");
while (1);
}
while (1);
}

View File

@ -1,5 +1,6 @@
#include <stdint.h>
#include "button.h"
#include "dd.h"
#include "fpga.h"
#include "usb.h"
@ -66,7 +67,7 @@ void button_process (void) {
break;
case BUTTON_MODE_DD_DISK_SWAP:
// TODO: implement 64DD disk swapping
dd_handle_button();
p.trigger = false;
break;

View File

@ -25,6 +25,7 @@ typedef enum {
CFG_ID_BUTTON_STATE,
CFG_ID_BUTTON_MODE,
CFG_ID_ROM_EXTENDED_ENABLE,
CFG_ID_DD_SD_MODE,
} cfg_id_t;
typedef enum {
@ -106,6 +107,12 @@ static bool cfg_translate_address (uint32_t *address, uint32_t length, bool with
return false;
}
}
if (*address >= 0x1FFE2000 && *address < 0x1FFE2800) {
if ((*address + length) <= 0x1FFE2800) {
*address = *address - 0x1FFE2000 + 0x05002000;
return false;
}
}
return true;
}
@ -220,6 +227,9 @@ bool cfg_query (uint32_t *args) {
case CFG_ID_ROM_EXTENDED_ENABLE:
args[1] = (scr & CFG_SCR_ROM_EXTENDED_ENABLED);
break;
case CFG_ID_DD_SD_MODE:
args[1] = dd_get_sd_mode();
break;
default:
return true;
}
@ -285,6 +295,9 @@ bool cfg_update (uint32_t *args) {
case CFG_ID_ROM_EXTENDED_ENABLE:
cfg_change_scr_bits(CFG_SCR_ROM_EXTENDED_ENABLED, args[1]);
break;
case CFG_ID_DD_SD_MODE:
dd_set_sd_mode(args[1]);
break;
default:
return true;
}
@ -457,6 +470,14 @@ void cfg_process (void) {
return;
}
break;
case 'D':
if (cfg_translate_address(&args[0], args[1], false)) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
return;
}
dd_set_sd_disk_info(args[0], args[1]);
break;
default:
cfg_set_error(CFG_ERROR_UNKNOWN_CMD);

View File

@ -3,13 +3,17 @@
#include "fpga.h"
#include "hw.h"
#include "rtc.h"
#include "sd.h"
#include "usb.h"
#define DD_SECTOR_MAX_SIZE (232)
#define DD_BLOCK_DATA_SECTORS_NUM (85)
#define DD_BLOCK_BUFFER_ADDRESS (0x03BC0000UL - (DD_SECTOR_MAX_SIZE * DD_BLOCK_DATA_SECTORS_NUM))
#define DD_BLOCK_BUFFER_SIZE (ALIGN(DD_SECTOR_MAX_SIZE * DD_BLOCK_DATA_SECTORS_NUM, SD_SECTOR_SIZE) + SD_SECTOR_SIZE)
#define DD_BLOCK_BUFFER_ADDRESS (0x03BC0000UL - DD_BLOCK_BUFFER_SIZE)
#define DD_SECTOR_BUFFER_ADDRESS (0x05002800UL)
#define DD_SD_SECTOR_TABLE_SIZE (DD_BLOCK_BUFFER_SIZE / SD_SECTOR_SIZE)
#define DD_SD_MAX_DISKS (4)
#define DD_DRIVE_ID_RETAIL (0x0003)
#define DD_DRIVE_ID_DEVELOPMENT (0x0004)
@ -47,8 +51,7 @@ enum state {
STATE_NEXT_BLOCK,
};
typedef union sector_info {
typedef union {
uint32_t full;
struct {
uint8_t sector_num;
@ -58,6 +61,11 @@ typedef union sector_info {
};
} sector_info_t;
typedef struct {
uint32_t thb_table_address;
uint32_t sector_table_address;
} sd_disk_info_t;
struct process {
enum state state;
rtc_time_t time;
@ -73,7 +81,12 @@ struct process {
sector_info_t sector_info;
bool block_ready;
bool block_valid;
uint32_t block_offset;
dd_drive_type_t drive_type;
bool sd_mode;
uint8_t sd_current_disk;
sd_disk_info_t sd_disk_info[DD_SD_MAX_DISKS];
uint32_t sd_sector_table[DD_SD_SECTOR_TABLE_SIZE];
};
@ -87,28 +100,88 @@ static uint16_t dd_track_head_block (void) {
return (track | head | block);
}
static uint32_t dd_fill_sd_sector_table (uint32_t index) {
uint32_t tmp;
sd_disk_info_t info = p.sd_disk_info[p.sd_current_disk];
uint32_t thb_entry_address = (info.thb_table_address + (index * sizeof(uint32_t)));
fpga_mem_read(thb_entry_address, sizeof(uint32_t), (uint8_t *) (&tmp));
uint32_t start_offset = SWAP32(tmp);
if (start_offset == 0xFFFFFFFF) {
return 0;
}
p.block_offset = (start_offset % SD_SECTOR_SIZE);
uint32_t block_length = ((p.sector_info.sector_size + 1) * DD_BLOCK_DATA_SECTORS_NUM);
uint32_t end_offset = ((start_offset + block_length) - 1); // CHECK THIS
uint32_t starting_sector = (start_offset / SD_SECTOR_SIZE);
uint32_t sectors = (1 + ((end_offset / SD_SECTOR_SIZE) - starting_sector));
for (int i = 0; i < sectors; i++) {
uint32_t sector_entry_address = info.sector_table_address + ((starting_sector + i) * sizeof(uint32_t));
fpga_mem_read(sector_entry_address, sizeof(uint32_t), (uint8_t *) (&tmp));
p.sd_sector_table[i] = SWAP32(tmp);
}
return sectors;
}
static bool dd_block_read_request (void) {
usb_tx_info_t packet_info;
usb_create_packet(&packet_info, PACKET_CMD_DD_REQUEST);
packet_info.data_length = 12;
packet_info.data[0] = 1;
packet_info.data[1] = DD_BLOCK_BUFFER_ADDRESS;
packet_info.data[2] = dd_track_head_block();
p.block_ready = false;
return usb_enqueue_packet(&packet_info);
uint16_t index = dd_track_head_block();
uint32_t buffer_address = DD_BLOCK_BUFFER_ADDRESS;
if (p.sd_mode) {
dd_set_block_ready(false);
uint32_t sectors = dd_fill_sd_sector_table(index);
if (sectors > 0) {
for (int i = 0; i < sectors; i++) {
if (sd_read_sectors(buffer_address, p.sd_sector_table[i], 1)) {
return true;
}
buffer_address += SD_SECTOR_SIZE;
}
dd_set_block_ready(true);
}
return true;
} else {
usb_tx_info_t packet_info;
usb_create_packet(&packet_info, PACKET_CMD_DD_REQUEST);
packet_info.data_length = 12;
packet_info.data[0] = 1;
packet_info.data[1] = buffer_address;
packet_info.data[2] = index;
p.block_ready = false;
p.block_offset = 0;
return usb_enqueue_packet(&packet_info);
}
}
static bool dd_block_write_request (void) {
usb_tx_info_t packet_info;
usb_create_packet(&packet_info, PACKET_CMD_DD_REQUEST);
packet_info.data_length = 12;
packet_info.data[0] = 2;
packet_info.data[1] = DD_BLOCK_BUFFER_ADDRESS;
packet_info.data[2] = dd_track_head_block();
packet_info.dma_length = (p.sector_info.sector_size + 1) * DD_BLOCK_DATA_SECTORS_NUM;
packet_info.dma_address = DD_BLOCK_BUFFER_ADDRESS;
p.block_ready = false;
return usb_enqueue_packet(&packet_info);
uint32_t index = dd_track_head_block();
uint32_t buffer_address = DD_BLOCK_BUFFER_ADDRESS;
if (p.sd_mode) {
dd_set_block_ready(false);
uint32_t sectors = dd_fill_sd_sector_table(index);
if (sectors > 0) {
for (int i = 0; i < sectors; i++) {
if (sd_write_sectors(buffer_address, p.sd_sector_table[i], 1)) {
return true;
}
buffer_address += SD_SECTOR_SIZE;
}
dd_set_block_ready(true);
}
return true;
} else {
usb_tx_info_t packet_info;
usb_create_packet(&packet_info, PACKET_CMD_DD_REQUEST);
packet_info.data_length = 12;
packet_info.data[0] = 2;
packet_info.data[1] = buffer_address;
packet_info.data[2] = index;
packet_info.dma_length = (p.sector_info.sector_size + 1) * DD_BLOCK_DATA_SECTORS_NUM;
packet_info.dma_address = buffer_address;
p.block_ready = false;
p.block_offset = 0;
return usb_enqueue_packet(&packet_info);
}
}
static void dd_set_cmd_response_ready (void) {
@ -168,6 +241,29 @@ void dd_set_disk_state (dd_disk_state_t state) {
fpga_reg_set(REG_DD_SCR, scr);
}
bool dd_get_sd_mode (void) {
return p.sd_mode;
}
void dd_set_sd_mode (bool value) {
p.sd_mode = value;
}
void dd_set_sd_disk_info (uint32_t address, uint32_t length) {
uint32_t tmp[2];
p.sd_current_disk = 0;
for (int i = 0; i < 4; i++) {
fpga_mem_read(address, sizeof(tmp), (uint8_t *) (tmp));
p.sd_disk_info[i].thb_table_address = SWAP32(tmp[0]);
p.sd_disk_info[i].sector_table_address = SWAP32(tmp[1]);
address += sizeof(tmp);
}
}
void dd_handle_button (void) {
// TODO: disk swap
}
void dd_init (void) {
fpga_reg_set(REG_DD_SCR, 0);
fpga_reg_set(REG_DD_HEAD_TRACK, 0);
@ -178,6 +274,8 @@ void dd_init (void) {
p.disk_spinning = false;
p.bm_running = false;
p.drive_type = DD_DRIVE_TYPE_RETAIL;
p.sd_mode = false;
p.sd_current_disk = 0;
}
void dd_process (void) {
@ -365,7 +463,7 @@ void dd_process (void) {
case STATE_SECTOR_READ:
fpga_mem_copy(
DD_BLOCK_BUFFER_ADDRESS + (p.current_sector * (p.sector_info.sector_size + 1)),
DD_BLOCK_BUFFER_ADDRESS + p.block_offset + (p.current_sector * (p.sector_info.sector_size + 1)),
DD_SECTOR_BUFFER_ADDRESS,
p.sector_info.sector_size + 1
);
@ -377,7 +475,7 @@ void dd_process (void) {
case STATE_SECTOR_WRITE:
fpga_mem_copy(
DD_SECTOR_BUFFER_ADDRESS,
DD_BLOCK_BUFFER_ADDRESS + (p.current_sector * (p.sector_info.sector_size + 1)),
DD_BLOCK_BUFFER_ADDRESS + p.block_offset + (p.current_sector * (p.sector_info.sector_size + 1)),
p.sector_info.sector_size + 1
);
p.current_sector += 1;

View File

@ -17,11 +17,15 @@ typedef enum {
} dd_disk_state_t;
void dd_set_block_ready (bool valid);
dd_drive_type_t dd_get_drive_type (void);
void dd_set_drive_type (dd_drive_type_t type);
dd_disk_state_t dd_get_disk_state (void);
void dd_set_disk_state (dd_disk_state_t state);
void dd_set_block_ready (bool valid);
bool dd_get_sd_mode (void);
void dd_set_sd_mode (bool value);
void dd_set_sd_disk_info (uint32_t address, uint32_t length);
void dd_handle_button (void);
void dd_init (void);
void dd_process (void);

View File

@ -55,6 +55,7 @@ typedef enum {
} fpga_reg_t;
#define ALIGN(value, align) (((value) + ((typeof(value))(align) - 1)) & ~((typeof(value))(align) - 1))
#define SWAP16(x) ((((x) & 0xFF) << 8) | (((x) & 0xFF00) >> 8))
#define SWAP32(x) (((x) & 0xFF) << 24 | ((x) & 0xFF00) << 8 | ((x) & 0xFF0000) >> 8 | ((x) & 0xFF000000) >> 24)

View File

@ -6,7 +6,7 @@
#include "sd.h"
#define SD_BUFFER_ADDRESS (0x05000000UL)
#define SD_INIT_BUFFER_ADDRESS (0x05002800UL)
#define CMD6_ARG_CHECK_HS (0x00FFFFF1UL)
#define CMD6_ARG_SWITCH_HS (0x80FFFFF1UL)
@ -28,7 +28,10 @@
#define R7_SUPPLY_VOLTAGE_27_36_V (1 << 8)
#define R7_CHECK_PATTERN (0xAA << 0)
#define SD_BLOCK_SIZE (512)
#define SWITCH_FUNCTION_CURRENT_LIMIT (SD_INIT_BUFFER_ADDRESS + 0)
#define SWITCH_FUNCTION_GROUP_1 (SD_INIT_BUFFER_ADDRESS + 12)
#define SWITCH_FUNCTION_GROUP_1_HS (1 << 1)
#define DAT_BLOCK_MAX_COUNT (256)
@ -166,7 +169,7 @@ static bool sd_acmd (uint8_t acmd, uint32_t arg, rsp_type_t rsp_type, void *rsp)
}
static void sd_dat_prepare (uint32_t address, uint32_t count, dat_mode_t mode) {
uint32_t length = (count * SD_BLOCK_SIZE);
uint32_t length = (count * SD_SECTOR_SIZE);
uint32_t sd_dat = (((count - 1) << SD_DAT_BLOCKS_BIT) | SD_DAT_FIFO_FLUSH);
uint32_t sd_dma_scr = DMA_SCR_START;
@ -209,7 +212,7 @@ static bool sd_dat_wait (uint16_t timeout) {
bool sd_card_init (void) {
uint32_t arg;
uint32_t rsp;
uint16_t sd_function;
uint16_t tmp;
if (p.card_initialized) {
return false;
@ -289,7 +292,7 @@ bool sd_card_init (void) {
return true;
}
sd_dat_prepare(SD_BUFFER_ADDRESS, 1, DAT_READ);
sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ);
if (sd_cmd(6, CMD6_ARG_CHECK_HS, RSP_R1, NULL)) {
sd_dat_abort();
sd_card_deinit();
@ -300,9 +303,14 @@ bool sd_card_init (void) {
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);
fpga_mem_read(SWITCH_FUNCTION_CURRENT_LIMIT, 2, (uint8_t *) (&tmp));
if (SWAP16(tmp) == 0) {
sd_card_deinit();
return true;
}
fpga_mem_read(SWITCH_FUNCTION_GROUP_1, 2, (uint8_t *) (&tmp));
if (SWAP16(tmp) & SWITCH_FUNCTION_GROUP_1_HS) {
sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ);
if (sd_cmd(6, CMD6_ARG_SWITCH_HS, RSP_R1, NULL)) {
sd_dat_abort();
sd_card_deinit();
@ -313,8 +321,8 @@ bool sd_card_init (void) {
sd_card_deinit();
return true;
}
fpga_mem_read(SD_BUFFER_ADDRESS + 12, 2, (uint8_t *) (&sd_function));
if (SWAP16(sd_function) & (1 << 1)) {
fpga_mem_read(SWITCH_FUNCTION_GROUP_1, 2, (uint8_t *) (&tmp));
if (SWAP16(tmp) & SWITCH_FUNCTION_GROUP_1_HS) {
sd_set_clock(CLOCK_50MHZ);
}
}
@ -352,7 +360,7 @@ bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
}
if (!p.card_type_block) {
sector *= SD_BLOCK_SIZE;
sector *= SD_SECTOR_SIZE;
}
while (count > 0) {
@ -365,14 +373,14 @@ bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
return true;
}
sd_dat_prepare(address, blocks, DAT_WRITE);
bool error = sd_dat_wait(1000);
sd_cmd(12, 0, RSP_R1b, NULL);
if (error) {
if (sd_dat_wait(1000)) {
sd_dat_abort();
sd_cmd(12, 0, RSP_R1b, NULL);
return true;
}
address += (blocks * SD_BLOCK_SIZE);
sector += (blocks * (p.card_type_block ? 1 : SD_BLOCK_SIZE));
sd_cmd(12, 0, RSP_R1b, NULL);
address += (blocks * SD_SECTOR_SIZE);
sector += (blocks * (p.card_type_block ? 1 : SD_SECTOR_SIZE));
count -= blocks;
}
@ -385,7 +393,7 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
}
if (!p.card_type_block) {
sector *= SD_BLOCK_SIZE;
sector *= SD_SECTOR_SIZE;
}
while (count > 0) {
@ -406,8 +414,8 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
}
return true;
}
address += (blocks * SD_BLOCK_SIZE);
sector += (blocks * (p.card_type_block ? 1 : SD_BLOCK_SIZE));
address += (blocks * SD_SECTOR_SIZE);
sector += (blocks * (p.card_type_block ? 1 : SD_SECTOR_SIZE));
count -= blocks;
}

View File

@ -5,6 +5,9 @@
#include <stdbool.h>
#define SD_SECTOR_SIZE (512)
bool sd_card_init (void);
void sd_card_deinit (void);
bool sd_card_get_status (void);

View File

@ -185,6 +185,9 @@ class DD64Image:
self.__file.close()
self.__drive_type = None
def get_block_info_table(self) -> list[tuple[int, int]]:
return self.__block_info_table
def get_drive_type(self) -> str:
return self.__drive_type
@ -222,6 +225,12 @@ if __name__ == '__main__':
print(dd.read_block(track, head, block)[:4])
except BadBlockError:
print(f'Bad ID block [track: {track}, head: {head}, block: {block}]')
if (len(sys.argv) >= 3):
with open(sys.argv[2], 'wb+') as f:
block_info_table = dd.get_block_info_table()
for block in block_info_table:
offset = 0xFFFFFFFF if block == None else block[0]
f.write(offset.to_bytes(4, byteorder='big'))
dd.unload()
else:
print(f'[{sys.argv[0]}]: Expected disk image path as first argument')

View File

@ -238,6 +238,7 @@ class SC64:
BUTTON_STATE = 12
BUTTON_MODE = 13
ROM_EXTENDED_ENABLE = 14
DD_SD_MODE = 15
class __UpdateError(IntEnum):
OK = 0
@ -364,6 +365,7 @@ class SC64:
self.__set_config(self.__CfgId.DD_DISK_STATE, self.__DDDiskState.EJECTED)
self.__set_config(self.__CfgId.BUTTON_MODE, self.__ButtonMode.NONE)
self.__set_config(self.__CfgId.ROM_EXTENDED_ENABLE, False)
self.__set_config(self.__CfgId.DD_SD_MODE, False)
self.set_cic_parameters()
def get_state(self):
@ -383,6 +385,7 @@ class SC64:
'button_state': bool(self.__get_config(self.__CfgId.BUTTON_STATE)),
'button_mode': self.__ButtonMode(self.__get_config(self.__CfgId.BUTTON_MODE)),
'rom_extended_enable': bool(self.__get_config(self.__CfgId.ROM_EXTENDED_ENABLE)),
'dd_sd_mode': bool(self.__get_config(self.__CfgId.DD_SD_MODE)),
}
def download_memory(self) -> bytes:
@ -564,6 +567,7 @@ class SC64:
break
if (dd):
self.__set_config(self.__CfgId.DD_MODE, self.__DDMode.FULL)
self.__set_config(self.__CfgId.DD_SD_MODE, False)
self.__set_config(self.__CfgId.DD_DRIVE_TYPE, {
'retail': self.__DDDriveType.RETAIL,
'development': self.__DDDriveType.DEVELOPMENT