From 8410cbe191d8f3b9cf918d59d9f8429fe4d931ba Mon Sep 17 00:00:00 2001 From: Polprzewodnikowy Date: Fri, 21 Jan 2022 21:29:41 +0100 Subject: [PATCH] super slow usb storage reading implemented --- fw/rtl/cpu/cpu_cfg.sv | 1 - sw/n64/src/exception.S | 1 + sw/n64/src/exception.c | 5 +- sw/n64/src/fatfs/diskio.c | 28 ++++- sw/n64/src/fatfs/ffconf.h | 8 +- sw/n64/src/sc64.c | 174 ++++++++++++++------------- sw/n64/src/sc64.h | 30 +++-- sw/pc/sc64.py | 129 ++++++++++---------- sw/riscv/src/cfg.c | 70 ++++++++--- sw/riscv/src/dd.c | 47 ++++---- sw/riscv/src/dd.h | 1 - sw/riscv/src/isv.c | 22 +++- sw/riscv/src/sys.h | 5 +- sw/riscv/src/usb.c | 240 +++++++++++++------------------------- sw/riscv/src/usb.h | 32 +++-- 15 files changed, 405 insertions(+), 388 deletions(-) diff --git a/fw/rtl/cpu/cpu_cfg.sv b/fw/rtl/cpu/cpu_cfg.sv index cf45e77..9686bb2 100644 --- a/fw/rtl/cpu/cpu_cfg.sv +++ b/fw/rtl/cpu/cpu_cfg.sv @@ -84,7 +84,6 @@ module cpu_cfg ( end else begin if (sys.n64_soft_reset) begin cfg.sdram_switch <= skip_bootloader; - cfg.sdram_writable <= 1'b0; end if (cfg.cmd_request) begin cfg.cpu_busy <= 1'b1; diff --git a/sw/n64/src/exception.S b/sw/n64/src/exception.S index 8203f3e..7474ba2 100644 --- a/sw/n64/src/exception.S +++ b/sw/n64/src/exception.S @@ -222,4 +222,5 @@ exception_disable_watchdog: li $t1, ~(C0_SR_IM7) and $t0, $t0, $t1 mtc0 $t0, C0_STATUS + mtc0 $zero, C0_COMPARE jr $ra diff --git a/sw/n64/src/exception.c b/sw/n64/src/exception.c index b5114ea..3614c7d 100644 --- a/sw/n64/src/exception.c +++ b/sw/n64/src/exception.c @@ -217,7 +217,6 @@ static void exception_vprint (const char *fmt, va_list args) { vsniprintf(line, sizeof(line), fmt, args); exception_print_string(line); - sc64_uart_print_string(line); } static void exception_print (const char* fmt, ...) { @@ -276,7 +275,9 @@ void exception_fatal_handler (uint32_t exception_code, uint32_t interrupt_mask, if (exception_code == EXCEPTION_INTERRUPT) { if (interrupt_mask & INTERRUPT_MASK_TIMER) { - exception_print("Bootloader did not finish within 1 second limit\n\n"); + exception_disable_watchdog(); + exception_print("Still loading after 1 second limit...\n\n"); + return; } } else if (exception_code == EXCEPTION_SYSCALL) { uint32_t code = (((*instruction_address) & SYSCALL_CODE_MASK) >> SYSCALL_CODE_BIT); diff --git a/sw/n64/src/fatfs/diskio.c b/sw/n64/src/fatfs/diskio.c index 6774919..594c9f8 100644 --- a/sw/n64/src/fatfs/diskio.c +++ b/sw/n64/src/fatfs/diskio.c @@ -3,24 +3,42 @@ #include "../sc64.h" +DSTATUS status[__DRIVE_COUNT] = { STA_NOINIT, STA_NOINIT }; + + DSTATUS disk_status (BYTE pdrv) { - return 0; + if (pdrv >= __DRIVE_COUNT) { + return STA_NODISK; + } + return status[pdrv]; } DSTATUS disk_initialize (BYTE pdrv) { - return 0; + if (pdrv >= __DRIVE_COUNT) { + return STA_NODISK; + } + if (!sc64_storage_init((drive_id_t) (pdrv))) { + status[pdrv] &= ~(STA_NOINIT); + } + return status[pdrv]; } DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) { - if (sc64_storage_read(pdrv, buff, sector, count)) { + if (pdrv >= __DRIVE_COUNT) { + return RES_PARERR; + } + if (sc64_storage_read((drive_id_t) (pdrv), buff, sector, count)) { return RES_ERROR; } return RES_OK; } -#ifndef FF_FS_READONLY +#if !FF_FS_READONLY DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) { - if (sc64_storage_write(pdrv, buff, sector, count)) { + if (pdrv >= __DRIVE_COUNT) { + return RES_PARERR; + } + if (sc64_storage_write((drive_id_t) (pdrv), buff, sector, count)) { return RES_ERROR; } return RES_OK; diff --git a/sw/n64/src/fatfs/ffconf.h b/sw/n64/src/fatfs/ffconf.h index 470b426..28460b5 100644 --- a/sw/n64/src/fatfs/ffconf.h +++ b/sw/n64/src/fatfs/ffconf.h @@ -8,14 +8,14 @@ / Function Configurations /---------------------------------------------------------------------------*/ -#define FF_FS_READONLY 1 +#define FF_FS_READONLY 0 /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) / Read-only configuration removes writing API functions, f_write(), f_sync(), / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() / and optional writing functions as well. */ -#define FF_FS_MINIMIZE 2 +#define FF_FS_MINIMIZE 1 /* This option defines minimization level to remove some basic API functions. / / 0: Basic functions are fully enabled. @@ -34,7 +34,7 @@ /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ -#define FF_USE_FASTSEEK 0 +#define FF_USE_FASTSEEK 1 /* This option switches fast seek function. (0:Disable or 1:Enable) */ @@ -113,7 +113,7 @@ */ -#define FF_USE_LFN 1 +#define FF_USE_LFN 2 #define FF_MAX_LFN 255 /* The FF_USE_LFN switches the support for LFN (long file name). / diff --git a/sw/n64/src/sc64.c b/sw/n64/src/sc64.c index 744570a..cef551c 100644 --- a/sw/n64/src/sc64.c +++ b/sw/n64/src/sc64.c @@ -56,6 +56,99 @@ void sc64_get_info (sc64_info_t *info) { info->boot_mode = (boot_mode_t) sc64_query_config(CFG_ID_BOOT_MODE); } +void sc64_init (void) { + while (!sc64_check_presence()); + sc64_wait_cpu_ready(); + sc64_change_config(CFG_ID_SDRAM_SWITCH, true); +} + +static uint32_t sc64_wait_drive_ready (drive_id_t drive) { + uint32_t args[2] = { drive, 0 }; + uint32_t result[2]; + do { + sc64_perform_cmd(SC64_CMD_DRIVE_BUSY, args, result); + } while (result[0]); + return result[1]; +} + +bool sc64_storage_init (drive_id_t drive) { + uint32_t args[2] = { drive, 0 }; + if (sc64_perform_cmd(SC64_CMD_DRIVE_INIT, args, NULL)) { + return true; + } + if (sc64_wait_drive_ready(drive) != 0) { + return true; + } + return false; +} + +static bool sc64_drive_start_read_and_wait (drive_id_t drive, uint32_t sector) { + uint32_t args[2] = { drive, sector }; + if (sc64_perform_cmd(SC64_CMD_DRIVE_READ, args, NULL)) { + return true; + } + if (sc64_wait_drive_ready(drive) != 0) { + return true; + } + return false; +} + +static bool sc64_drive_start_write_and_wait (drive_id_t drive, uint32_t sector) { + uint32_t args[2] = { drive, sector }; + if (sc64_perform_cmd(SC64_CMD_DRIVE_WRITE, args, NULL)) { + return true; + } + if (sc64_wait_drive_ready(drive) != 0) { + return true; + } + return false; +} + +bool sc64_storage_read (drive_id_t drive, void *buffer, uint32_t sector, uint32_t count) { + io32_t *src = SC64->BUFFER; + uint8_t *dst = (uint8_t *) (buffer); + + while (count > 0) { + if (sc64_drive_start_read_and_wait(drive, sector)) { + return true; + } + for (int i = 0; i < (SECTOR_SIZE / sizeof(uint32_t)); i++) { + uint32_t data = pi_io_read(src + i); + *dst++ = ((data >> 24) & 0xFF); + *dst++ = ((data >> 16) & 0xFF); + *dst++ = ((data >> 8) & 0xFF); + *dst++ = ((data >> 0) & 0xFF); + } + sector += 1; + count -= 1; + } + + return false; +} + +bool sc64_storage_write (drive_id_t drive, const void *buffer, uint32_t sector, uint32_t count) { + uint8_t *src = (uint8_t *) (buffer); + io32_t *dst = SC64->BUFFER; + + while (count > 0) { + for (int i = 0; i < (SECTOR_SIZE / sizeof(uint32_t)); i++) { + uint32_t data = 0; + data |= ((*src++) << 24); + data |= ((*src++) << 16); + data |= ((*src++) << 8); + data |= ((*src++) << 0); + pi_io_write((dst + i), data); + } + if (sc64_drive_start_write_and_wait(drive, sector)) { + return true; + } + sector += 1; + count -= 1; + } + + return false; +} + static void sc64_uart_put_char (char c) { #ifdef DEBUG uint32_t args[2] = { (uint32_t) (c), 0 }; @@ -68,84 +161,3 @@ void sc64_uart_print_string (const char *text) { sc64_uart_put_char (*text++); } } - -void sc64_init (void) { - while (!sc64_check_presence()); - sc64_wait_cpu_ready(); - sc64_change_config(CFG_ID_SDRAM_SWITCH, true); - sc64_uart_print_string("\033c"); -} - -static bool sc64_wait_drive_ready (uint8_t drive) { - bool error; - uint32_t args[2] = { drive, 0 }; - uint32_t result[2]; - do { - error = sc64_perform_cmd(SC64_CMD_DRIVE_BUSY, args, result); - } while (!result[0]); - return error; -} - -static bool sc64_drive_read_sector (uint8_t drive, void *buffer, uint32_t sector) { - io32_t *src = SC64->BUFFER; - uint8_t *dst = (uint8_t *) (buffer); - uint32_t args[2] = { drive, sector }; - if (sc64_perform_cmd(SC64_CMD_DRIVE_READ, args, NULL)) { - return true; - } - if (sc64_wait_drive_ready(drive)) { - return true; - } - for (int i = 0; i < SECTOR_SIZE; i += sizeof(uint32_t)) { - uint32_t data = pi_io_read(src++); - *dst++ = ((data >> 24) & 0xFF); - *dst++ = ((data >> 16) & 0xFF); - *dst++ = ((data >> 8) & 0xFF); - *dst++ = ((data >> 0) & 0xFF); - } - return false; -} - -bool sc64_storage_read (uint8_t drive, void *buffer, uint32_t sector, uint32_t count) { - if (sc64_wait_drive_ready(drive)) { - return true; - } - for (int i = 0; i < count; i++) { - if (sc64_drive_read_sector(drive, buffer, (sector + i))) { - return true; - } - buffer += SECTOR_SIZE; - } - return false; -} - -static bool sc64_drive_write_sector (uint8_t drive, void *buffer, uint32_t sector) { - uint8_t *src = (uint8_t *) (buffer); - io32_t *dst = SC64->BUFFER; - uint32_t args[2] = { drive, sector }; - uint32_t data; - if (sc64_wait_drive_ready(drive)) { - return true; - } - for (int i = 0; i < SECTOR_SIZE; i += sizeof(uint32_t)) { - data = ((*src++) << 24); - data |= ((*src++) << 16); - data |= ((*src++) << 8); - data |= ((*src++) << 0); - pi_io_write(dst++, data); - } - if (sc64_perform_cmd(SC64_CMD_DRIVE_WRITE, args, NULL)) { - return true; - } - return false; -} - -bool sc64_storage_write (uint8_t drive, void *buffer, uint32_t sector, uint32_t count) { - for (int i = 0; i < count; i++) { - if (sc64_drive_write_sector(drive, buffer, (sector + i))) { - return true; - } - buffer += SECTOR_SIZE; - } - return false; -} diff --git a/sw/n64/src/sc64.h b/sw/n64/src/sc64.h index 2b858f7..b43197c 100644 --- a/sw/n64/src/sc64.h +++ b/sw/n64/src/sc64.h @@ -9,9 +9,10 @@ #define SC64_CMD_QUERY ('Q') #define SC64_CMD_CONFIG ('C') -#define SC64_CMD_DRIVE_BUSY (0xF0) -#define SC64_CMD_DRIVE_READ (0xF1) -#define SC64_CMD_DRIVE_WRITE (0xF2) +#define SC64_CMD_DRIVE_INIT (0xF0) +#define SC64_CMD_DRIVE_BUSY (0xF1) +#define SC64_CMD_DRIVE_READ (0xF2) +#define SC64_CMD_DRIVE_WRITE (0xF3) #define SC64_CMD_UART_PUT (0xFF) #define SC64_VERSION_2 (0x53437632) @@ -38,16 +39,6 @@ typedef enum { CFG_ID_IS_VIEWER_ENABLE, } cfg_id_t; -typedef enum { - SAVE_TYPE_NONE = 0, - SAVE_TYPE_EEPROM_4K = 1, - SAVE_TYPE_EEPROM_16K = 2, - SAVE_TYPE_SRAM = 3, - SAVE_TYPE_FLASHRAM = 4, - SAVE_TYPE_SRAM_BANKED = 5, - SAVE_TYPE_FLASHRAM_PKST2 = 6, -} save_type_t; - typedef enum { CIC_SEED_UNKNOWN = 0xFFFF, } cic_seed_t; @@ -73,15 +64,22 @@ typedef struct { tv_type_t tv_type; } sc64_info_t; +typedef enum { + DRIVE_SD = 0, + DRIVE_USB = 1, + __DRIVE_COUNT = 2 +} drive_id_t; + bool sc64_check_presence (void); uint32_t sc64_query_config (cfg_id_t id); void sc64_change_config (cfg_id_t id, uint32_t value); void sc64_get_info (sc64_info_t *info); -void sc64_uart_print_string (const char *text); void sc64_init (void); -bool sc64_storage_read (uint8_t drive, void *buffer, uint32_t sector, uint32_t count); -bool sc64_storage_write (uint8_t drive, void *buffer, uint32_t sector, uint32_t count); +bool sc64_storage_init (drive_id_t drive); +bool sc64_storage_read (drive_id_t drive, void *buffer, uint32_t sector, uint32_t count); +bool sc64_storage_write (drive_id_t drive, const void *buffer, uint32_t sector, uint32_t count); +void sc64_uart_print_string (const char *text); #endif diff --git a/sw/pc/sc64.py b/sw/pc/sc64.py index 996f60f..d06ecbf 100644 --- a/sw/pc/sc64.py +++ b/sw/pc/sc64.py @@ -19,6 +19,7 @@ class SC64Exception(Exception): class SC64: + __CFG_ID_SDRAM_WRITABLE = 2 __CFG_ID_DD_ENABLE = 3 __CFG_ID_SAVE_TYPE = 4 __CFG_ID_CIC_SEED = 5 @@ -45,12 +46,12 @@ class SC64: __DDIPL_ROM_LENGTH = 0x400000 __DEBUG_ID_TEXT = 0x01 - __DEBUG_ID_FSD_READ = 0xF1 - __DEBUG_ID_FSD_WRITE = 0xF2 - __DEBUG_ID_FSD_SECTOR = 0xF3 - __DEBUG_ID_INTERNAL = 0xFE - __INTERNAL_ID_IS_VIEWER = 0 - __INTERNAL_ID_DD_BLOCK = 1 + __DEBUG_ID_EVENT = 0xFE + + __EVENT_ID_FSD_READ = 0 + __EVENT_ID_FSD_WRITE = 1 + __EVENT_ID_DD_BLOCK = 2 + __EVENT_ID_IS_VIEWER = 3 __DD_DRIVE_ID_RETAIL = 3 __DD_DRIVE_ID_DEVELOPMENT = 4 @@ -67,6 +68,7 @@ class SC64: self.__fsd_file = None self.__disk_file = None self.__disk_lba_table = [] + self.__dd_turbo = False self.__isv_line_buffer = bytearray() self.__find_sc64() @@ -187,11 +189,6 @@ class SC64: self.__read_cmd_status("C") - def __debug_write(self, type: int, data: bytes) -> None: - self.__write_cmd("D", type, len(data)) - self.__write(data) - - def __read_file_from_sdram(self, file: str, offset: int, length: int, align: int = 2) -> None: with open(file, "wb") as f: transfer_size = self.__align(length, align) @@ -543,27 +540,53 @@ class SC64: raise SC64Exception("No DD disk file provided for disk info creation") - def __debug_process_fsd_set_sector(self, data: bytes) -> None: - sector = int.from_bytes(data[0:4], byteorder='big') + def __debug_process_fsd_read(self, data: bytes) -> None: + sector = int.from_bytes(data[0:4], byteorder='little') if (self.__fsd_file): self.__fsd_file.seek(sector * 512) - - - def __debug_process_fsd_read(self, data: bytes) -> None: - length = int.from_bytes(data[0:4], byteorder='big') - if (self.__fsd_file): - self.__debug_write(self.__DEBUG_ID_FSD_READ, self.__fsd_file.read(length)) + self.__write_cmd("T", 0, 512) + self.__write(self.__fsd_file.read(512)) else: - self.__debug_write(self.__DEBUG_ID_FSD_READ, bytes(length)) + self.__write_cmd("T", 0, 0) def __debug_process_fsd_write(self, data: bytes) -> None: + sector = int.from_bytes(data[0:4], byteorder='little') if (self.__fsd_file): - self.__fsd_file.write(data) + self.__fsd_file.seek(sector * 512) + self.__write_cmd("F", 0, 512) + self.__fsd_file.write(self.__read(512)) + else: + self.__write_cmd("F", 0, 0) + + + def __debug_process_dd_block(self, data: bytes) -> None: + transfer_mode = int.from_bytes(data[0:4], byteorder='little') + sdram_offset = int.from_bytes(data[4:8], byteorder='little') + disk_file_offset = int.from_bytes(data[8:12], byteorder='big') + block_length = int.from_bytes(data[12:16], byteorder='little') + + if (self.__disk_file): + self.__disk_file.seek(disk_file_offset) + if (transfer_mode): + if (not self.__dd_turbo): + # Fixes weird bug in Mario Artist Paint Studio prototype minigame + time.sleep(0.016) + self.__write_cmd("S", sdram_offset, block_length) + self.__write(self.__disk_file.read(block_length)) + else: + self.__write_cmd("L", sdram_offset, block_length) + self.__disk_file.write(self.__read(block_length)) def __debug_process_is_viewer(self, data: bytes) -> None: - self.__isv_line_buffer.extend(data) + length = int.from_bytes(data[0:4], byteorder='little') + address = int.from_bytes(data[4:8], byteorder='little') + offset = (address & 0x01) + transfer_length = self.__align(length + offset, 2) + self.__write_cmd("L", (address & 0xFFFFFFFE), transfer_length) + text = self.__read(transfer_length)[offset:][:length] + self.__isv_line_buffer.extend(text) try: while (len(self.__isv_line_buffer) > 0): line_end = self.__isv_line_buffer.index(b'\n') @@ -574,48 +597,32 @@ class SC64: pass - def __debug_process_dd_block(self, data: bytes) -> None: - transfer_mode = int.from_bytes(data[0:4], byteorder='big') - sdram_offset = int.from_bytes(data[4:8], byteorder='big') - disk_file_offset = int.from_bytes(data[8:12], byteorder='big') - block_length = int.from_bytes(data[12:16], byteorder='big') + def __debug_process_event(self, event_data: bytes) -> None: + id = int.from_bytes(event_data[0:4], byteorder="big") + data = event_data[4:] - print(f"64DD Block {'R' if transfer_mode else 'W'} - LBA: {self.__disk_lba_table.index(disk_file_offset):4}, Offset: 0x{disk_file_offset:08X}") - - if (self.__disk_file): - self.__disk_file.seek(disk_file_offset) - if (transfer_mode): - time.sleep(0.016) # Fixes weird bug in Mario Artist Paint Studio minigame - self.__write_cmd("S", sdram_offset, block_length) - self.__write(self.__disk_file.read(block_length)) - else: - write_data = data[16:] - self.__disk_file.write(write_data) - - - def __debug_process_internal(self, internal_data: bytes) -> None: - id = internal_data[0] - start_alignmnet = internal_data[1] - length = int.from_bytes(internal_data[2:4], byteorder="big") - data = internal_data[(4 + start_alignmnet):][:length] - - if (id == self.__INTERNAL_ID_IS_VIEWER): - self.__debug_process_is_viewer(data) - elif (id == self.__INTERNAL_ID_DD_BLOCK): + if (id == self.__EVENT_ID_FSD_READ): + self.__debug_process_fsd_read(data) + elif (id == self.__EVENT_ID_FSD_WRITE): + self.__debug_process_fsd_write(data) + elif (id == self.__EVENT_ID_DD_BLOCK): self.__debug_process_dd_block(data) + elif (id == self.__EVENT_ID_IS_VIEWER): + self.__debug_process_is_viewer(data) - def debug_init(self, fsd_file: str = None, disk_file: str = None, is_viewer_enabled: bool = False) -> None: + def debug_init(self, fsd_file: str = None, disk_file: str = None, dd_turbo: bool = False) -> None: if (fsd_file): self.__fsd_file = open(fsd_file, "rb+") - if (disk_file): self.__disk_file = open(disk_file, "rb+") + self.__dd_turbo = dd_turbo + + def debug_loop(self, is_viewer_enabled: bool = False) -> None: + self.__change_config(self.__CFG_ID_SDRAM_WRITABLE, is_viewer_enabled) self.__change_config(self.__CFG_ID_IS_VIEWER_ENABLE, is_viewer_enabled) - - def debug_loop(self) -> None: print("\r\n\033[34m --- Debug server started --- \033[0m\r\n") start_indicator = bytearray() @@ -645,14 +652,8 @@ class SC64: else: if (id == self.__DEBUG_ID_TEXT): print(data.decode(encoding="ascii", errors="backslashreplace"), end="") - elif (id == self.__DEBUG_ID_FSD_READ): - self.__debug_process_fsd_read(data) - elif (id == self.__DEBUG_ID_FSD_WRITE): - self.__debug_process_fsd_write(data) - elif (id == self.__DEBUG_ID_FSD_SECTOR): - self.__debug_process_fsd_set_sector(data) - elif (id == self.__DEBUG_ID_INTERNAL): - self.__debug_process_internal(data) + elif (id == self.__DEBUG_ID_EVENT): + self.__debug_process_event(data) else: print(f"\033[35mGot unknown id: {id}, length: {length}\033[0m", file=sys.stderr) @@ -722,6 +723,7 @@ if __name__ == "__main__": parser.add_argument("-c", metavar="cic_seed", default="0xFFFF", required=False, help="set CIC seed") parser.add_argument("-s", metavar="save_type", default="0", required=False, help="set save type (0 - 6)") parser.add_argument("-d", default=False, action="store_true", required=False, help="enable 64DD emulation") + parser.add_argument("-df", default=False, action="store_true", required=False, help="set 64DD emulation to turbo mode") parser.add_argument("-r", default=False, action="store_true", required=False, help="perform reading operation instead of writing") parser.add_argument("-l", metavar="length", default="0x101000", required=False, help="specify ROM length to read") parser.add_argument("-u", metavar="update_path", default=None, required=False, help="path to update file") @@ -747,6 +749,7 @@ if __name__ == "__main__": tv_type = int(args.t) cic_seed = int(args.c, 0) dd_enable = args.d + dd_turbo = args.df is_read = args.r rom_length = int(args.l, 0) update_file = args.u @@ -818,7 +821,7 @@ if __name__ == "__main__": sc64.reset_n64() if (debug_server): - sc64.debug_init(sd_file, disk_file, is_viewer_enabled) + sc64.debug_init(sd_file, disk_file, dd_turbo) if (is_viewer_enabled): print(f"Setting IS-Viewer 64 emulation to [Enabled]") if (sd_file): @@ -828,7 +831,7 @@ if __name__ == "__main__": sc64.set_dd_configuration_for_disk(disk_file) print(f"Setting 64DD disk state to [Changed]") sc64.set_dd_disk_state("changed" if disk_file else "ejected") - sc64.debug_loop() + sc64.debug_loop(is_viewer_enabled) except SC64Exception as e: print(f"Error: {e}") diff --git a/sw/riscv/src/cfg.c b/sw/riscv/src/cfg.c index ce65b07..cfa0d44 100644 --- a/sw/riscv/src/cfg.c +++ b/sw/riscv/src/cfg.c @@ -66,6 +66,7 @@ struct process { uint16_t cic_seed; uint8_t tv_type; enum boot_mode boot_mode; + bool usb_drive_busy; }; static struct process p; @@ -79,6 +80,10 @@ static void change_scr_bits (uint32_t mask, bool value) { } } +static void set_usb_drive_not_busy (void) { + p.usb_drive_busy = false; +} + static void set_save_type (enum save_type save_type) { uint32_t save_offset = DEFAULT_SAVE_OFFSET; @@ -252,6 +257,7 @@ void cfg_init (void) { p.cic_seed = 0xFFFF; p.tv_type = 0x03; p.boot_mode = BOOT_MODE_MENU_SD; + p.usb_drive_busy = false; } @@ -273,38 +279,66 @@ void process_cfg (void) { cfg_query(args); break; - case 'S': - args[0] = usb_debug_tx_ready(); - break; - - case 'D': - if (!usb_debug_tx_data(args[0], (size_t) args[1])) { + case 0xF0: + if (args[0] == 0) { + change_scr_bits(CFG_SCR_CMD_ERROR, true); + } else if (args[0] == 1) { + p.usb_drive_busy = false; + } else { change_scr_bits(CFG_SCR_CMD_ERROR, true); } break; - case 'A': - if (!usb_debug_rx_ready(&args[0], (size_t *) (&args[1]))) { + case 0xF1: + if (args[0] == 0) { args[0] = 0; - args[1] = 0; + change_scr_bits(CFG_SCR_CMD_ERROR, true); + } else if (args[0] == 1) { + args[0] = p.usb_drive_busy; + } else { + args[0] = 0; + change_scr_bits(CFG_SCR_CMD_ERROR, true); } + args[1] = 0; break; - case 'F': - args[0] = usb_debug_rx_busy(); - break; - - case 'E': - if (!usb_debug_rx_data(args[0], (size_t) args[1])) { + case 0xF2: + if ((args[0] & 0xFF) == 0) { + change_scr_bits(CFG_SCR_CMD_ERROR, true); + } else if ((args[0] & 0xFF) == 1 && (!p.usb_drive_busy)) { + usb_event_t event; + event.id = EVENT_ID_FSD_READ; + event.trigger = CALLBACK_BUFFER_WRITE; + event.callback = set_usb_drive_not_busy; + if (usb_put_event(&event, &args[1], sizeof(args[1]))) { + p.usb_drive_busy = true; + } else { + return; + } + } else { change_scr_bits(CFG_SCR_CMD_ERROR, true); } break; - case 'B': - usb_debug_reset(); + case 0xF3: + if ((args[0] & 0xFF) == 0) { + change_scr_bits(CFG_SCR_CMD_ERROR, true); + } else if ((args[0] & 0xFF) == 1 && (!p.usb_drive_busy)) { + usb_event_t event; + event.id = EVENT_ID_FSD_WRITE; + event.trigger = CALLBACK_BUFFER_READ; + event.callback = set_usb_drive_not_busy; + if (usb_put_event(&event, &args[1], sizeof(args[1]))) { + p.usb_drive_busy = true; + } else { + return; + } + } else { + change_scr_bits(CFG_SCR_CMD_ERROR, true); + } break; - case 'Z': + case 0xFF: uart_put((char) (args[0] & 0xFF)); break; diff --git a/sw/riscv/src/dd.c b/sw/riscv/src/dd.c index fd4687b..c4c3985 100644 --- a/sw/riscv/src/dd.c +++ b/sw/riscv/src/dd.c @@ -84,35 +84,36 @@ static bool dd_block_valid (void) { return (p.thb_table[dd_track_head_block()] != 0xFFFFFFFF); } -static bool dd_block_request (void) { - if (!usb_internal_debug_tx_ready()) { - return false; - } +static void dd_set_block_ready (void) { + p.block_ready = true; +} - if (!(DD->SCR & DD_SCR_DISK_INSERTED)) { +static bool dd_block_request (void) { +if (!(DD->SCR & DD_SCR_DISK_INSERTED)) { return true; } io32_t offset = p.thb_table[dd_track_head_block()]; uint32_t length = ((DD->SECTOR_SIZE + 1) * DD_USER_SECTORS_PER_BLOCK); - size_t transfer_length = 16; - io32_t *dst = (io32_t *) (DD_USB_BUFFER_OFFSET); + uint32_t data[4] = { + p.transfer_mode, + (uint32_t) (p.block_buffer), + offset, + length, + }; - *dst++ = SWAP32(p.transfer_mode); - *dst++ = SWAP32((uint32_t) (p.block_buffer)); - *dst++ = offset; - *dst++ = SWAP32(length); + usb_event_t event; + event.id = EVENT_ID_DD_BLOCK; + event.trigger = p.transfer_mode ? CALLBACK_SDRAM_WRITE : CALLBACK_SDRAM_READ; + event.callback = dd_set_block_ready; - if (!p.transfer_mode) { - transfer_length += length; + if (usb_put_event(&event, data, sizeof(data))) { + p.block_ready = false; + return true; } - usb_internal_debug_tx_data(INT_DBG_ID_DD_BLOCK, DD_USB_BUFFER_OFFSET, transfer_length); - - p.block_ready = false; - - return true; + return false; } static bool dd_block_ready (void) { @@ -120,11 +121,7 @@ static bool dd_block_ready (void) { return true; } - if (p.transfer_mode) { - return p.block_ready; - } else { - return usb_internal_debug_tx_ready(); - } + return p.block_ready; } static void dd_sector_read (void) { @@ -191,10 +188,6 @@ uint16_t dd_get_drive_id (void) { return DD->DRIVE_ID; } -void dd_set_block_ready (bool value) { - p.block_ready = value; -} - void dd_set_thb_table_offset (uint32_t offset) { p.thb_table = (io32_t *) (SDRAM_BASE + offset); } diff --git a/sw/riscv/src/dd.h b/sw/riscv/src/dd.h index 3be98aa..84acf95 100644 --- a/sw/riscv/src/dd.h +++ b/sw/riscv/src/dd.h @@ -18,7 +18,6 @@ void dd_set_drive_id (uint16_t id); uint16_t dd_get_drive_id (void); void dd_set_thb_table_offset (uint32_t offset); uint32_t dd_get_thb_table_offset (void); -void dd_set_block_ready (bool value); void dd_init (void); void process_dd (void); diff --git a/sw/riscv/src/isv.c b/sw/riscv/src/isv.c index ac4f3fb..1163614 100644 --- a/sw/riscv/src/isv.c +++ b/sw/riscv/src/isv.c @@ -17,6 +17,7 @@ typedef struct { struct process { bool enabled; + bool ready; uint32_t current_read_pointer; is_viewer_t *ISV; }; @@ -26,6 +27,7 @@ struct process p; void isv_set_enabled (bool enabled) { p.enabled = enabled; + p.ready = true; } bool isv_get_enabled (void) { @@ -35,10 +37,15 @@ bool isv_get_enabled (void) { void isv_init (void) { p.enabled = false; + p.ready = true; p.current_read_pointer = 0; p.ISV = (is_viewer_t *) (IS64_OFFSET); } +void isv_set_ready (void) { + p.ready = true; +} + void process_isv (void) { if (!p.enabled || (p.ISV->ID != IS64_TOKEN)) { p.current_read_pointer = 0; @@ -48,12 +55,19 @@ void process_isv (void) { uint32_t read_pointer = SWAP32(p.ISV->RD_PTR); - if ((read_pointer != p.current_read_pointer) && usb_internal_debug_tx_ready()) { + if (p.ready && (read_pointer != p.current_read_pointer)) { bool wrap = read_pointer < p.current_read_pointer; - size_t length = ((wrap ? sizeof(p.ISV->BUFFER) : read_pointer) - p.current_read_pointer); - uint32_t address = (uint32_t) (&p.ISV->BUFFER[p.current_read_pointer]); + uint32_t data[2] = { + ((wrap ? sizeof(p.ISV->BUFFER) : read_pointer) - p.current_read_pointer), + (uint32_t) (&p.ISV->BUFFER[p.current_read_pointer]), + }; - if (usb_internal_debug_tx_data(INT_DBG_ID_IS_VIEWER, address, length)) { + usb_event_t event; + event.id = EVENT_ID_IS_VIEWER; + event.trigger = CALLBACK_SDRAM_READ; + event.callback = isv_set_ready; + if (usb_put_event(&event, data, sizeof(data))) { + p.ready = false; p.current_read_pointer = wrap ? 0 : read_pointer; } } diff --git a/sw/riscv/src/sys.h b/sw/riscv/src/sys.h index 5d0c608..ff90138 100644 --- a/sw/riscv/src/sys.h +++ b/sw/riscv/src/sys.h @@ -23,7 +23,10 @@ typedef volatile uint32_t io32_t; #define RAM_BASE (0x00000000UL) #define RAM (*((io32_t *) RAM_BASE)) -#define RAM_SIZE (16 * 1024) +#define RAM_SIZE (15 * 1024) +#define RAMBUFFER_BASE (0x00003C00UL) +#define RAMBUFFER (*((io8_t *) RAMBUFFER_BASE)) +#define RAMBUFFER_SIZE (1 * 1024) #define FLASH_BASE (0x10000000UL) diff --git a/sw/riscv/src/usb.c b/sw/riscv/src/usb.c index 1e1dff6..c7f140b 100644 --- a/sw/riscv/src/usb.c +++ b/sw/riscv/src/usb.c @@ -66,128 +66,52 @@ static bool tx_word (uint32_t data) { #define USB_DMA_TOKEN (0x444D4100) #define USB_ERR_TOKEN (0x45525200) -#define DEBUG_ID_INTERNAL (0xFE) +#define DEBUG_ID_EVENT (0xFE) + enum state { STATE_IDLE, STATE_ARGS, STATE_DATA, STATE_RESPONSE, - STATE_DEBUG_TX, - STATE_INTERNAL_DEBUG_TX_START, - STATE_INTERNAL_DEBUG_TX_DATA, - STATE_INTERNAL_DEBUG_TX_END, + STATE_EVENT, }; struct process { enum state state; - uint8_t counter; + uint32_t counter; uint8_t cmd; uint32_t args[2]; bool error; bool dma_in_progress; bool queried; - bool debug_rx_busy; - uint32_t debug_rx_address; - size_t debug_rx_length; - - bool debug_tx_busy; - uint32_t debug_tx_address; - size_t debug_tx_length; - - bool internal_debug_tx_busy; - uint8_t internal_debug_tx_step; - uint32_t internal_debug_tx_address; - size_t internal_debug_tx_length; - uint32_t internal_debug_tx_id_length; - uint32_t internal_debug_tx_info; + bool event_pending; + bool event_callback_pending; + usb_event_t event; + uint8_t event_data[16]; + uint32_t event_data_length; }; static struct process p; -bool usb_debug_rx_ready (uint32_t *type, size_t *length) { - if (p.state != STATE_DATA || p.cmd != 'D' || p.debug_rx_busy) { +bool usb_put_event (usb_event_t *event, void *data, uint32_t length) { + if (p.event_pending || p.event_callback_pending) { return false; } - *type = p.args[0]; - *length = (size_t) p.args[1]; + uint8_t *src = (uint8_t *) (data); + uint8_t *dst = p.event_data; - return true; -} - -bool usb_debug_rx_busy (void) { - return p.debug_rx_busy; -} - -bool usb_debug_rx_data (uint32_t address, size_t length) { - if (p.debug_rx_busy) { - return false; + p.event_pending = true; + p.event_callback_pending = false; + p.event = *event; + p.event_data_length = length <= sizeof(p.event_data) ? length : sizeof(p.event_data); + for (int i = 0; i < p.event_data_length; i++) { + *dst++ = *src++; } - p.debug_rx_busy = true; - p.debug_rx_address = address; - p.debug_rx_length = length; - - return true; -} - -bool usb_debug_tx_ready (void) { - return !p.debug_tx_busy; -} - -bool usb_debug_tx_data (uint32_t address, size_t length) { - if (p.debug_tx_busy) { - return false; - } - - p.debug_tx_busy = true; - p.debug_tx_address = address; - p.debug_tx_length = length; - - return true; -} - -void usb_debug_reset (void) { - uint8_t tmp; - - if (p.state == STATE_DATA && p.cmd == 'D') { - for (size_t i = 0; i < p.args[1]; i++) { - rx_byte(&tmp); - } - p.args[1] = 0; - } - if (p.state == STATE_DEBUG_TX) { - p.state = STATE_IDLE; - } - p.debug_rx_busy = false; - p.debug_tx_busy = false; - - USB->SCR = USB_SCR_ENABLED | USB_SCR_FLUSH_TX | USB_SCR_FLUSH_RX; -} - -bool usb_internal_debug_tx_ready (void) { - return !p.internal_debug_tx_busy; -} - -bool usb_internal_debug_tx_data (internal_debug_id_t id, uint32_t address, size_t length) { - if (p.internal_debug_tx_busy) { - return false; - } - - uint32_t start_address = address & 0xFFFFFFFC; - uint32_t end_address = ALIGN((address + length), 4); - size_t dma_length = end_address - start_address; - uint8_t start_alignment = address & 0x03; - - p.internal_debug_tx_busy = true; - p.internal_debug_tx_address = start_address; - p.internal_debug_tx_length = dma_length; - p.internal_debug_tx_id_length = ((DEBUG_ID_INTERNAL << 24) | (dma_length + 4)); - p.internal_debug_tx_info = ((id << 24) | (start_alignment << 16) | (length & 0xFFFF)); - return true; } @@ -234,12 +158,11 @@ static void handle_escape (void) { void usb_init (void) { - USB->SCR = USB_SCR_ENABLED | USB_SCR_FLUSH_TX | USB_SCR_FLUSH_RX; + USB->SCR = (USB_SCR_ENABLED | USB_SCR_FLUSH_TX | USB_SCR_FLUSH_RX); p.state = STATE_IDLE; - p.debug_rx_busy = false; - p.debug_tx_busy = false; - p.internal_debug_tx_busy = false; + p.event_pending = false; + p.event_callback_pending = false; rx_word_current_byte = 0; rx_word_buffer = 0; @@ -267,13 +190,9 @@ void process_usb (void) { p.error = true; p.state = STATE_RESPONSE; } - } else if (p.debug_tx_busy) { - p.state = STATE_DEBUG_TX; - p.dma_in_progress = false; - } else if (p.internal_debug_tx_busy) { - p.state = STATE_INTERNAL_DEBUG_TX_START; - p.dma_in_progress = false; - p.internal_debug_tx_step = 0; + } else if (p.event_pending && (!p.event_callback_pending)) { + p.state = STATE_EVENT; + p.counter = 0; } break; @@ -281,6 +200,7 @@ void process_usb (void) { if (rx_word(&p.args[p.counter])) { p.counter += 1; if (p.counter == 2) { + p.counter = 0; p.state = STATE_DATA; } } @@ -311,6 +231,7 @@ void process_usb (void) { case 'R': case 'W': + case 'L': case 'S': if (!dma_busy()) { if (!p.dma_in_progress) { @@ -319,8 +240,17 @@ void process_usb (void) { dma_start(p.args[0], p.args[1], DMA_ID_USB, dir); p.dma_in_progress = true; } else { - if (p.cmd == 'S') { - dd_set_block_ready(true); + if (p.cmd == 'L' || p.cmd == 'S') { + if (p.event_callback_pending) { + if (p.cmd == 'L' && p.event.trigger == CALLBACK_SDRAM_READ) { + p.event_callback_pending = false; + p.event.callback(); + } + if (p.cmd == 'S' && p.event.trigger == CALLBACK_SDRAM_WRITE) { + p.event_callback_pending = false; + p.event.callback(); + } + } p.state = STATE_IDLE; } else { p.state = STATE_RESPONSE; @@ -329,18 +259,36 @@ void process_usb (void) { } break; - case 'D': - if (!dma_busy() && p.debug_rx_busy && p.args[1] > 0) { - if (!p.dma_in_progress) { - dma_start(p.debug_rx_address, p.debug_rx_length, DMA_ID_USB, DMA_DIR_TO_SDRAM); - p.dma_in_progress = true; - } else { - p.args[1] -= p.debug_rx_length > p.args[1] ? p.args[1] : p.debug_rx_length; - p.dma_in_progress = false; - p.debug_rx_busy = false; + case 'F': + case 'T': + while ((p.args[0] + p.counter) != (p.args[0] + p.args[1])) { + uint8_t *buffer = (uint8_t *) (RAMBUFFER_BASE + p.args[0] + p.counter); + if (p.cmd == 'F') { + if (tx_byte(*buffer)) { + p.counter += 1; + } else { + break; + } + } + if (p.cmd == 'T') { + if (rx_byte(buffer)) { + p.counter += 1; + } else { + break; + } } } - if (p.args[1] == 0) { + if ((p.args[0] + p.counter) == (p.args[0] + p.args[1])) { + if (p.event_callback_pending) { + if (p.cmd == 'F' && p.event.trigger == CALLBACK_BUFFER_READ) { + p.event_callback_pending = false; + p.event.callback(); + } + if (p.cmd == 'T' && p.event.trigger == CALLBACK_BUFFER_WRITE) { + p.event_callback_pending = false; + p.event.callback(); + } + } p.state = STATE_IDLE; } break; @@ -358,50 +306,28 @@ void process_usb (void) { } break; - case STATE_DEBUG_TX: - if (!dma_busy()) { - if (!p.dma_in_progress) { - dma_start(p.debug_tx_address, p.debug_tx_length, DMA_ID_USB, DMA_DIR_FROM_SDRAM); - p.dma_in_progress = true; - } else { - p.debug_tx_busy = false; - p.state = STATE_IDLE; + case STATE_EVENT: + if ((p.counter == 0) && tx_word(USB_DMA_TOKEN | '@')) { + p.counter += 1; + } + if ((p.counter == 1) && tx_word((DEBUG_ID_EVENT << 24) | (sizeof(p.event.id) + p.event_data_length))) { + p.counter += 1; + } + if ((p.counter == 2) && tx_word(p.event.id)) { + p.counter += 1; + } + if (p.counter >= 3) { + while (((p.counter - 3) < p.event_data_length) && tx_byte(p.event_data[p.counter - 3])) { + p.counter += 1; } } - break; - - case STATE_INTERNAL_DEBUG_TX_START: - uint32_t header_data[] = { - (USB_DMA_TOKEN | '@'), - p.internal_debug_tx_id_length, - p.internal_debug_tx_info, - }; - - if (tx_word(header_data[p.internal_debug_tx_step])) { - p.internal_debug_tx_step += 1; - if (p.internal_debug_tx_step >= 3) { - p.state = STATE_INTERNAL_DEBUG_TX_DATA; + if ((p.counter == (p.event_data_length + 3)) && tx_word(USB_CMP_TOKEN | 'H')) { + if (p.event.callback != NULL) { + p.event_callback_pending = true; } - } - break; - - case STATE_INTERNAL_DEBUG_TX_DATA: - if (!dma_busy()) { - if (!p.dma_in_progress) { - dma_start(p.internal_debug_tx_address, p.internal_debug_tx_length, DMA_ID_USB, DMA_DIR_FROM_SDRAM); - p.dma_in_progress = true; - } else { - p.internal_debug_tx_busy = false; - p.state = STATE_INTERNAL_DEBUG_TX_END; - } - } - break; - - case STATE_INTERNAL_DEBUG_TX_END: - if (tx_word(USB_CMP_TOKEN | 'H')) { + p.event_pending = false; p.state = STATE_IDLE; } - p.state = STATE_IDLE; break; } } diff --git a/sw/riscv/src/usb.h b/sw/riscv/src/usb.h index 9b39757..5402f37 100644 --- a/sw/riscv/src/usb.h +++ b/sw/riscv/src/usb.h @@ -8,17 +8,33 @@ typedef enum { INT_DBG_ID_IS_VIEWER = 0, INT_DBG_ID_DD_BLOCK = 1, + INT_DBG_ID_FSD_READ = 2, + INT_DBG_ID_FSD_WRITE = 3, } internal_debug_id_t; +typedef enum { + EVENT_ID_FSD_READ = 0, + EVENT_ID_FSD_WRITE = 1, + EVENT_ID_DD_BLOCK = 2, + EVENT_ID_IS_VIEWER = 3, +} usb_event_id_t; -bool usb_debug_rx_ready (uint32_t *type, size_t *length); -bool usb_debug_rx_busy (void); -bool usb_debug_rx_data (uint32_t address, size_t length); -bool usb_debug_tx_ready (void); -bool usb_debug_tx_data (uint32_t address, size_t length); -void usb_debug_reset (void); -bool usb_internal_debug_tx_ready (void); -bool usb_internal_debug_tx_data (internal_debug_id_t id, uint32_t address, size_t length); +typedef enum { + CALLBACK_NONE = 0, + CALLBACK_SDRAM_WRITE = 1, + CALLBACK_SDRAM_READ = 2, + CALLBACK_BUFFER_WRITE = 3, + CALLBACK_BUFFER_READ = 4, +} usb_event_callback_t; + +typedef struct { + usb_event_id_t id; + usb_event_callback_t trigger; + void (*callback)(void); +} usb_event_t; + + +bool usb_put_event (usb_event_t *event, void *data, uint32_t length); void usb_init (void); void process_usb (void);