super slow usb storage reading implemented

This commit is contained in:
Polprzewodnikowy 2022-01-21 21:29:41 +01:00
parent 388a872a8c
commit 8410cbe191
15 changed files with 405 additions and 388 deletions

View File

@ -84,7 +84,6 @@ module cpu_cfg (
end else begin end else begin
if (sys.n64_soft_reset) begin if (sys.n64_soft_reset) begin
cfg.sdram_switch <= skip_bootloader; cfg.sdram_switch <= skip_bootloader;
cfg.sdram_writable <= 1'b0;
end end
if (cfg.cmd_request) begin if (cfg.cmd_request) begin
cfg.cpu_busy <= 1'b1; cfg.cpu_busy <= 1'b1;

View File

@ -222,4 +222,5 @@ exception_disable_watchdog:
li $t1, ~(C0_SR_IM7) li $t1, ~(C0_SR_IM7)
and $t0, $t0, $t1 and $t0, $t0, $t1
mtc0 $t0, C0_STATUS mtc0 $t0, C0_STATUS
mtc0 $zero, C0_COMPARE
jr $ra jr $ra

View File

@ -217,7 +217,6 @@ static void exception_vprint (const char *fmt, va_list args) {
vsniprintf(line, sizeof(line), fmt, args); vsniprintf(line, sizeof(line), fmt, args);
exception_print_string(line); exception_print_string(line);
sc64_uart_print_string(line);
} }
static void exception_print (const char* fmt, ...) { 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 (exception_code == EXCEPTION_INTERRUPT) {
if (interrupt_mask & INTERRUPT_MASK_TIMER) { 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) { } else if (exception_code == EXCEPTION_SYSCALL) {
uint32_t code = (((*instruction_address) & SYSCALL_CODE_MASK) >> SYSCALL_CODE_BIT); uint32_t code = (((*instruction_address) & SYSCALL_CODE_MASK) >> SYSCALL_CODE_BIT);

View File

@ -3,24 +3,42 @@
#include "../sc64.h" #include "../sc64.h"
DSTATUS status[__DRIVE_COUNT] = { STA_NOINIT, STA_NOINIT };
DSTATUS disk_status (BYTE pdrv) { DSTATUS disk_status (BYTE pdrv) {
return 0; if (pdrv >= __DRIVE_COUNT) {
return STA_NODISK;
}
return status[pdrv];
} }
DSTATUS disk_initialize (BYTE 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) { 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_ERROR;
} }
return RES_OK; return RES_OK;
} }
#ifndef 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 (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_ERROR;
} }
return RES_OK; return RES_OK;

View File

@ -8,14 +8,14 @@
/ Function Configurations / 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) /* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(), / Read-only configuration removes writing API functions, f_write(), f_sync(),
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ and optional writing functions as well. */ / 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. /* This option defines minimization level to remove some basic API functions.
/ /
/ 0: Basic functions are fully enabled. / 0: Basic functions are fully enabled.
@ -34,7 +34,7 @@
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ /* 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) */ /* 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 #define FF_MAX_LFN 255
/* The FF_USE_LFN switches the support for LFN (long file name). /* The FF_USE_LFN switches the support for LFN (long file name).
/ /

View File

@ -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); 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) { static void sc64_uart_put_char (char c) {
#ifdef DEBUG #ifdef DEBUG
uint32_t args[2] = { (uint32_t) (c), 0 }; 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++); 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;
}

View File

@ -9,9 +9,10 @@
#define SC64_CMD_QUERY ('Q') #define SC64_CMD_QUERY ('Q')
#define SC64_CMD_CONFIG ('C') #define SC64_CMD_CONFIG ('C')
#define SC64_CMD_DRIVE_BUSY (0xF0) #define SC64_CMD_DRIVE_INIT (0xF0)
#define SC64_CMD_DRIVE_READ (0xF1) #define SC64_CMD_DRIVE_BUSY (0xF1)
#define SC64_CMD_DRIVE_WRITE (0xF2) #define SC64_CMD_DRIVE_READ (0xF2)
#define SC64_CMD_DRIVE_WRITE (0xF3)
#define SC64_CMD_UART_PUT (0xFF) #define SC64_CMD_UART_PUT (0xFF)
#define SC64_VERSION_2 (0x53437632) #define SC64_VERSION_2 (0x53437632)
@ -38,16 +39,6 @@ typedef enum {
CFG_ID_IS_VIEWER_ENABLE, CFG_ID_IS_VIEWER_ENABLE,
} cfg_id_t; } 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 { typedef enum {
CIC_SEED_UNKNOWN = 0xFFFF, CIC_SEED_UNKNOWN = 0xFFFF,
} cic_seed_t; } cic_seed_t;
@ -73,15 +64,22 @@ typedef struct {
tv_type_t tv_type; tv_type_t tv_type;
} sc64_info_t; } sc64_info_t;
typedef enum {
DRIVE_SD = 0,
DRIVE_USB = 1,
__DRIVE_COUNT = 2
} drive_id_t;
bool sc64_check_presence (void); bool sc64_check_presence (void);
uint32_t sc64_query_config (cfg_id_t id); uint32_t sc64_query_config (cfg_id_t id);
void sc64_change_config (cfg_id_t id, uint32_t value); void sc64_change_config (cfg_id_t id, uint32_t value);
void sc64_get_info (sc64_info_t *info); void sc64_get_info (sc64_info_t *info);
void sc64_uart_print_string (const char *text);
void sc64_init (void); void sc64_init (void);
bool sc64_storage_read (uint8_t drive, void *buffer, uint32_t sector, uint32_t count); bool sc64_storage_init (drive_id_t drive);
bool sc64_storage_write (uint8_t drive, void *buffer, uint32_t sector, uint32_t count); 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 #endif

View File

@ -19,6 +19,7 @@ class SC64Exception(Exception):
class SC64: class SC64:
__CFG_ID_SDRAM_WRITABLE = 2
__CFG_ID_DD_ENABLE = 3 __CFG_ID_DD_ENABLE = 3
__CFG_ID_SAVE_TYPE = 4 __CFG_ID_SAVE_TYPE = 4
__CFG_ID_CIC_SEED = 5 __CFG_ID_CIC_SEED = 5
@ -45,12 +46,12 @@ class SC64:
__DDIPL_ROM_LENGTH = 0x400000 __DDIPL_ROM_LENGTH = 0x400000
__DEBUG_ID_TEXT = 0x01 __DEBUG_ID_TEXT = 0x01
__DEBUG_ID_FSD_READ = 0xF1 __DEBUG_ID_EVENT = 0xFE
__DEBUG_ID_FSD_WRITE = 0xF2
__DEBUG_ID_FSD_SECTOR = 0xF3 __EVENT_ID_FSD_READ = 0
__DEBUG_ID_INTERNAL = 0xFE __EVENT_ID_FSD_WRITE = 1
__INTERNAL_ID_IS_VIEWER = 0 __EVENT_ID_DD_BLOCK = 2
__INTERNAL_ID_DD_BLOCK = 1 __EVENT_ID_IS_VIEWER = 3
__DD_DRIVE_ID_RETAIL = 3 __DD_DRIVE_ID_RETAIL = 3
__DD_DRIVE_ID_DEVELOPMENT = 4 __DD_DRIVE_ID_DEVELOPMENT = 4
@ -67,6 +68,7 @@ class SC64:
self.__fsd_file = None self.__fsd_file = None
self.__disk_file = None self.__disk_file = None
self.__disk_lba_table = [] self.__disk_lba_table = []
self.__dd_turbo = False
self.__isv_line_buffer = bytearray() self.__isv_line_buffer = bytearray()
self.__find_sc64() self.__find_sc64()
@ -187,11 +189,6 @@ class SC64:
self.__read_cmd_status("C") 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: def __read_file_from_sdram(self, file: str, offset: int, length: int, align: int = 2) -> None:
with open(file, "wb") as f: with open(file, "wb") as f:
transfer_size = self.__align(length, align) transfer_size = self.__align(length, align)
@ -543,27 +540,53 @@ class SC64:
raise SC64Exception("No DD disk file provided for disk info creation") raise SC64Exception("No DD disk file provided for disk info creation")
def __debug_process_fsd_set_sector(self, data: bytes) -> None: def __debug_process_fsd_read(self, data: bytes) -> None:
sector = int.from_bytes(data[0:4], byteorder='big') sector = int.from_bytes(data[0:4], byteorder='little')
if (self.__fsd_file): if (self.__fsd_file):
self.__fsd_file.seek(sector * 512) self.__fsd_file.seek(sector * 512)
self.__write_cmd("T", 0, 512)
self.__write(self.__fsd_file.read(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))
else: 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: def __debug_process_fsd_write(self, data: bytes) -> None:
sector = int.from_bytes(data[0:4], byteorder='little')
if (self.__fsd_file): 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: 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: try:
while (len(self.__isv_line_buffer) > 0): while (len(self.__isv_line_buffer) > 0):
line_end = self.__isv_line_buffer.index(b'\n') line_end = self.__isv_line_buffer.index(b'\n')
@ -574,48 +597,32 @@ class SC64:
pass pass
def __debug_process_dd_block(self, data: bytes) -> None: def __debug_process_event(self, event_data: bytes) -> None:
transfer_mode = int.from_bytes(data[0:4], byteorder='big') id = int.from_bytes(event_data[0:4], byteorder="big")
sdram_offset = int.from_bytes(data[4:8], byteorder='big') data = event_data[4:]
disk_file_offset = int.from_bytes(data[8:12], byteorder='big')
block_length = int.from_bytes(data[12:16], byteorder='big')
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 (id == self.__EVENT_ID_FSD_READ):
self.__debug_process_fsd_read(data)
if (self.__disk_file): elif (id == self.__EVENT_ID_FSD_WRITE):
self.__disk_file.seek(disk_file_offset) self.__debug_process_fsd_write(data)
if (transfer_mode): elif (id == self.__EVENT_ID_DD_BLOCK):
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):
self.__debug_process_dd_block(data) 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): if (fsd_file):
self.__fsd_file = open(fsd_file, "rb+") self.__fsd_file = open(fsd_file, "rb+")
if (disk_file): if (disk_file):
self.__disk_file = open(disk_file, "rb+") 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) 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") print("\r\n\033[34m --- Debug server started --- \033[0m\r\n")
start_indicator = bytearray() start_indicator = bytearray()
@ -645,14 +652,8 @@ class SC64:
else: else:
if (id == self.__DEBUG_ID_TEXT): if (id == self.__DEBUG_ID_TEXT):
print(data.decode(encoding="ascii", errors="backslashreplace"), end="") print(data.decode(encoding="ascii", errors="backslashreplace"), end="")
elif (id == self.__DEBUG_ID_FSD_READ): elif (id == self.__DEBUG_ID_EVENT):
self.__debug_process_fsd_read(data) self.__debug_process_event(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)
else: else:
print(f"\033[35mGot unknown id: {id}, length: {length}\033[0m", file=sys.stderr) 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("-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("-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("-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("-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("-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") 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) tv_type = int(args.t)
cic_seed = int(args.c, 0) cic_seed = int(args.c, 0)
dd_enable = args.d dd_enable = args.d
dd_turbo = args.df
is_read = args.r is_read = args.r
rom_length = int(args.l, 0) rom_length = int(args.l, 0)
update_file = args.u update_file = args.u
@ -818,7 +821,7 @@ if __name__ == "__main__":
sc64.reset_n64() sc64.reset_n64()
if (debug_server): 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): if (is_viewer_enabled):
print(f"Setting IS-Viewer 64 emulation to [Enabled]") print(f"Setting IS-Viewer 64 emulation to [Enabled]")
if (sd_file): if (sd_file):
@ -828,7 +831,7 @@ if __name__ == "__main__":
sc64.set_dd_configuration_for_disk(disk_file) sc64.set_dd_configuration_for_disk(disk_file)
print(f"Setting 64DD disk state to [Changed]") print(f"Setting 64DD disk state to [Changed]")
sc64.set_dd_disk_state("changed" if disk_file else "ejected") sc64.set_dd_disk_state("changed" if disk_file else "ejected")
sc64.debug_loop() sc64.debug_loop(is_viewer_enabled)
except SC64Exception as e: except SC64Exception as e:
print(f"Error: {e}") print(f"Error: {e}")

View File

@ -66,6 +66,7 @@ struct process {
uint16_t cic_seed; uint16_t cic_seed;
uint8_t tv_type; uint8_t tv_type;
enum boot_mode boot_mode; enum boot_mode boot_mode;
bool usb_drive_busy;
}; };
static struct process p; 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) { static void set_save_type (enum save_type save_type) {
uint32_t save_offset = DEFAULT_SAVE_OFFSET; uint32_t save_offset = DEFAULT_SAVE_OFFSET;
@ -252,6 +257,7 @@ void cfg_init (void) {
p.cic_seed = 0xFFFF; p.cic_seed = 0xFFFF;
p.tv_type = 0x03; p.tv_type = 0x03;
p.boot_mode = BOOT_MODE_MENU_SD; p.boot_mode = BOOT_MODE_MENU_SD;
p.usb_drive_busy = false;
} }
@ -273,38 +279,66 @@ void process_cfg (void) {
cfg_query(args); cfg_query(args);
break; break;
case 'S': case 0xF0:
args[0] = usb_debug_tx_ready(); if (args[0] == 0) {
break; change_scr_bits(CFG_SCR_CMD_ERROR, true);
} else if (args[0] == 1) {
case 'D': p.usb_drive_busy = false;
if (!usb_debug_tx_data(args[0], (size_t) args[1])) { } else {
change_scr_bits(CFG_SCR_CMD_ERROR, true); change_scr_bits(CFG_SCR_CMD_ERROR, true);
} }
break; break;
case 'A': case 0xF1:
if (!usb_debug_rx_ready(&args[0], (size_t *) (&args[1]))) { if (args[0] == 0) {
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; break;
case 'F': case 0xF2:
args[0] = usb_debug_rx_busy(); if ((args[0] & 0xFF) == 0) {
break; change_scr_bits(CFG_SCR_CMD_ERROR, true);
} else if ((args[0] & 0xFF) == 1 && (!p.usb_drive_busy)) {
case 'E': usb_event_t event;
if (!usb_debug_rx_data(args[0], (size_t) args[1])) { 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); change_scr_bits(CFG_SCR_CMD_ERROR, true);
} }
break; break;
case 'B': case 0xF3:
usb_debug_reset(); 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; break;
case 'Z': case 0xFF:
uart_put((char) (args[0] & 0xFF)); uart_put((char) (args[0] & 0xFF));
break; break;

View File

@ -84,35 +84,36 @@ static bool dd_block_valid (void) {
return (p.thb_table[dd_track_head_block()] != 0xFFFFFFFF); return (p.thb_table[dd_track_head_block()] != 0xFFFFFFFF);
} }
static bool dd_block_request (void) { static void dd_set_block_ready (void) {
if (!usb_internal_debug_tx_ready()) { p.block_ready = true;
return false; }
}
if (!(DD->SCR & DD_SCR_DISK_INSERTED)) { static bool dd_block_request (void) {
if (!(DD->SCR & DD_SCR_DISK_INSERTED)) {
return true; return true;
} }
io32_t offset = p.thb_table[dd_track_head_block()]; io32_t offset = p.thb_table[dd_track_head_block()];
uint32_t length = ((DD->SECTOR_SIZE + 1) * DD_USER_SECTORS_PER_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); usb_event_t event;
*dst++ = SWAP32((uint32_t) (p.block_buffer)); event.id = EVENT_ID_DD_BLOCK;
*dst++ = offset; event.trigger = p.transfer_mode ? CALLBACK_SDRAM_WRITE : CALLBACK_SDRAM_READ;
*dst++ = SWAP32(length); event.callback = dd_set_block_ready;
if (!p.transfer_mode) { if (usb_put_event(&event, data, sizeof(data))) {
transfer_length += length; p.block_ready = false;
return true;
} }
usb_internal_debug_tx_data(INT_DBG_ID_DD_BLOCK, DD_USB_BUFFER_OFFSET, transfer_length); return false;
p.block_ready = false;
return true;
} }
static bool dd_block_ready (void) { static bool dd_block_ready (void) {
@ -120,11 +121,7 @@ static bool dd_block_ready (void) {
return true; return true;
} }
if (p.transfer_mode) { return p.block_ready;
return p.block_ready;
} else {
return usb_internal_debug_tx_ready();
}
} }
static void dd_sector_read (void) { static void dd_sector_read (void) {
@ -191,10 +188,6 @@ uint16_t dd_get_drive_id (void) {
return DD->DRIVE_ID; return DD->DRIVE_ID;
} }
void dd_set_block_ready (bool value) {
p.block_ready = value;
}
void dd_set_thb_table_offset (uint32_t offset) { void dd_set_thb_table_offset (uint32_t offset) {
p.thb_table = (io32_t *) (SDRAM_BASE + offset); p.thb_table = (io32_t *) (SDRAM_BASE + offset);
} }

View File

@ -18,7 +18,6 @@ void dd_set_drive_id (uint16_t id);
uint16_t dd_get_drive_id (void); uint16_t dd_get_drive_id (void);
void dd_set_thb_table_offset (uint32_t offset); void dd_set_thb_table_offset (uint32_t offset);
uint32_t dd_get_thb_table_offset (void); uint32_t dd_get_thb_table_offset (void);
void dd_set_block_ready (bool value);
void dd_init (void); void dd_init (void);
void process_dd (void); void process_dd (void);

View File

@ -17,6 +17,7 @@ typedef struct {
struct process { struct process {
bool enabled; bool enabled;
bool ready;
uint32_t current_read_pointer; uint32_t current_read_pointer;
is_viewer_t *ISV; is_viewer_t *ISV;
}; };
@ -26,6 +27,7 @@ struct process p;
void isv_set_enabled (bool enabled) { void isv_set_enabled (bool enabled) {
p.enabled = enabled; p.enabled = enabled;
p.ready = true;
} }
bool isv_get_enabled (void) { bool isv_get_enabled (void) {
@ -35,10 +37,15 @@ bool isv_get_enabled (void) {
void isv_init (void) { void isv_init (void) {
p.enabled = false; p.enabled = false;
p.ready = true;
p.current_read_pointer = 0; p.current_read_pointer = 0;
p.ISV = (is_viewer_t *) (IS64_OFFSET); p.ISV = (is_viewer_t *) (IS64_OFFSET);
} }
void isv_set_ready (void) {
p.ready = true;
}
void process_isv (void) { void process_isv (void) {
if (!p.enabled || (p.ISV->ID != IS64_TOKEN)) { if (!p.enabled || (p.ISV->ID != IS64_TOKEN)) {
p.current_read_pointer = 0; p.current_read_pointer = 0;
@ -48,12 +55,19 @@ void process_isv (void) {
uint32_t read_pointer = SWAP32(p.ISV->RD_PTR); 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; bool wrap = read_pointer < p.current_read_pointer;
size_t length = ((wrap ? sizeof(p.ISV->BUFFER) : read_pointer) - p.current_read_pointer); uint32_t data[2] = {
uint32_t address = (uint32_t) (&p.ISV->BUFFER[p.current_read_pointer]); ((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; p.current_read_pointer = wrap ? 0 : read_pointer;
} }
} }

View File

@ -23,7 +23,10 @@ typedef volatile uint32_t io32_t;
#define RAM_BASE (0x00000000UL) #define RAM_BASE (0x00000000UL)
#define RAM (*((io32_t *) RAM_BASE)) #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) #define FLASH_BASE (0x10000000UL)

View File

@ -66,128 +66,52 @@ static bool tx_word (uint32_t data) {
#define USB_DMA_TOKEN (0x444D4100) #define USB_DMA_TOKEN (0x444D4100)
#define USB_ERR_TOKEN (0x45525200) #define USB_ERR_TOKEN (0x45525200)
#define DEBUG_ID_INTERNAL (0xFE) #define DEBUG_ID_EVENT (0xFE)
enum state { enum state {
STATE_IDLE, STATE_IDLE,
STATE_ARGS, STATE_ARGS,
STATE_DATA, STATE_DATA,
STATE_RESPONSE, STATE_RESPONSE,
STATE_DEBUG_TX, STATE_EVENT,
STATE_INTERNAL_DEBUG_TX_START,
STATE_INTERNAL_DEBUG_TX_DATA,
STATE_INTERNAL_DEBUG_TX_END,
}; };
struct process { struct process {
enum state state; enum state state;
uint8_t counter; uint32_t counter;
uint8_t cmd; uint8_t cmd;
uint32_t args[2]; uint32_t args[2];
bool error; bool error;
bool dma_in_progress; bool dma_in_progress;
bool queried; bool queried;
bool debug_rx_busy; bool event_pending;
uint32_t debug_rx_address; bool event_callback_pending;
size_t debug_rx_length; usb_event_t event;
uint8_t event_data[16];
bool debug_tx_busy; uint32_t event_data_length;
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;
}; };
static struct process p; static struct process p;
bool usb_debug_rx_ready (uint32_t *type, size_t *length) { bool usb_put_event (usb_event_t *event, void *data, uint32_t length) {
if (p.state != STATE_DATA || p.cmd != 'D' || p.debug_rx_busy) { if (p.event_pending || p.event_callback_pending) {
return false; return false;
} }
*type = p.args[0]; uint8_t *src = (uint8_t *) (data);
*length = (size_t) p.args[1]; uint8_t *dst = p.event_data;
return true; p.event_pending = true;
} p.event_callback_pending = false;
p.event = *event;
bool usb_debug_rx_busy (void) { p.event_data_length = length <= sizeof(p.event_data) ? length : sizeof(p.event_data);
return p.debug_rx_busy; for (int i = 0; i < p.event_data_length; i++) {
} *dst++ = *src++;
bool usb_debug_rx_data (uint32_t address, size_t length) {
if (p.debug_rx_busy) {
return false;
} }
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; return true;
} }
@ -234,12 +158,11 @@ static void handle_escape (void) {
void usb_init (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.state = STATE_IDLE;
p.debug_rx_busy = false; p.event_pending = false;
p.debug_tx_busy = false; p.event_callback_pending = false;
p.internal_debug_tx_busy = false;
rx_word_current_byte = 0; rx_word_current_byte = 0;
rx_word_buffer = 0; rx_word_buffer = 0;
@ -267,13 +190,9 @@ void process_usb (void) {
p.error = true; p.error = true;
p.state = STATE_RESPONSE; p.state = STATE_RESPONSE;
} }
} else if (p.debug_tx_busy) { } else if (p.event_pending && (!p.event_callback_pending)) {
p.state = STATE_DEBUG_TX; p.state = STATE_EVENT;
p.dma_in_progress = false; p.counter = 0;
} 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;
} }
break; break;
@ -281,6 +200,7 @@ void process_usb (void) {
if (rx_word(&p.args[p.counter])) { if (rx_word(&p.args[p.counter])) {
p.counter += 1; p.counter += 1;
if (p.counter == 2) { if (p.counter == 2) {
p.counter = 0;
p.state = STATE_DATA; p.state = STATE_DATA;
} }
} }
@ -311,6 +231,7 @@ void process_usb (void) {
case 'R': case 'R':
case 'W': case 'W':
case 'L':
case 'S': case 'S':
if (!dma_busy()) { if (!dma_busy()) {
if (!p.dma_in_progress) { 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); dma_start(p.args[0], p.args[1], DMA_ID_USB, dir);
p.dma_in_progress = true; p.dma_in_progress = true;
} else { } else {
if (p.cmd == 'S') { if (p.cmd == 'L' || p.cmd == 'S') {
dd_set_block_ready(true); 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; p.state = STATE_IDLE;
} else { } else {
p.state = STATE_RESPONSE; p.state = STATE_RESPONSE;
@ -329,18 +259,36 @@ void process_usb (void) {
} }
break; break;
case 'D': case 'F':
if (!dma_busy() && p.debug_rx_busy && p.args[1] > 0) { case 'T':
if (!p.dma_in_progress) { while ((p.args[0] + p.counter) != (p.args[0] + p.args[1])) {
dma_start(p.debug_rx_address, p.debug_rx_length, DMA_ID_USB, DMA_DIR_TO_SDRAM); uint8_t *buffer = (uint8_t *) (RAMBUFFER_BASE + p.args[0] + p.counter);
p.dma_in_progress = true; if (p.cmd == 'F') {
} else { if (tx_byte(*buffer)) {
p.args[1] -= p.debug_rx_length > p.args[1] ? p.args[1] : p.debug_rx_length; p.counter += 1;
p.dma_in_progress = false; } else {
p.debug_rx_busy = false; 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; p.state = STATE_IDLE;
} }
break; break;
@ -358,50 +306,28 @@ void process_usb (void) {
} }
break; break;
case STATE_DEBUG_TX: case STATE_EVENT:
if (!dma_busy()) { if ((p.counter == 0) && tx_word(USB_DMA_TOKEN | '@')) {
if (!p.dma_in_progress) { p.counter += 1;
dma_start(p.debug_tx_address, p.debug_tx_length, DMA_ID_USB, DMA_DIR_FROM_SDRAM); }
p.dma_in_progress = true; if ((p.counter == 1) && tx_word((DEBUG_ID_EVENT << 24) | (sizeof(p.event.id) + p.event_data_length))) {
} else { p.counter += 1;
p.debug_tx_busy = false; }
p.state = STATE_IDLE; 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; if ((p.counter == (p.event_data_length + 3)) && tx_word(USB_CMP_TOKEN | 'H')) {
if (p.event.callback != NULL) {
case STATE_INTERNAL_DEBUG_TX_START: p.event_callback_pending = true;
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;
} }
} p.event_pending = false;
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.state = STATE_IDLE; p.state = STATE_IDLE;
} }
p.state = STATE_IDLE;
break; break;
} }
} }

View File

@ -8,17 +8,33 @@
typedef enum { typedef enum {
INT_DBG_ID_IS_VIEWER = 0, INT_DBG_ID_IS_VIEWER = 0,
INT_DBG_ID_DD_BLOCK = 1, INT_DBG_ID_DD_BLOCK = 1,
INT_DBG_ID_FSD_READ = 2,
INT_DBG_ID_FSD_WRITE = 3,
} internal_debug_id_t; } 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); typedef enum {
bool usb_debug_rx_busy (void); CALLBACK_NONE = 0,
bool usb_debug_rx_data (uint32_t address, size_t length); CALLBACK_SDRAM_WRITE = 1,
bool usb_debug_tx_ready (void); CALLBACK_SDRAM_READ = 2,
bool usb_debug_tx_data (uint32_t address, size_t length); CALLBACK_BUFFER_WRITE = 3,
void usb_debug_reset (void); CALLBACK_BUFFER_READ = 4,
bool usb_internal_debug_tx_ready (void); } usb_event_callback_t;
bool usb_internal_debug_tx_data (internal_debug_id_t id, uint32_t address, size_t length);
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 usb_init (void);
void process_usb (void); void process_usb (void);