diff --git a/build.sh b/build.sh index f1a4882..10e5af8 100755 --- a/build.sh +++ b/build.sh @@ -6,6 +6,7 @@ PACKAGE_FILE_NAME="SC64" FILES=( "./fw/ftdi/ft232h_config.xml" + "./fw/project/lcmxo2/impl1/sc64_impl1.mrp" "./fw/project/lcmxo2/impl1/sc64_impl1.twr" "./sw/pc/dd64.py" "./sw/pc/sc64.py" diff --git a/sw/bootloader/src/sc64.h b/sw/bootloader/src/sc64.h index 5768ff4..70e5e9e 100644 --- a/sw/bootloader/src/sc64.h +++ b/sw/bootloader/src/sc64.h @@ -24,7 +24,7 @@ typedef enum { CFG_ID_SAVE_TYPE, CFG_ID_CIC_SEED, CFG_ID_TV_TYPE, - CFG_ID_DD_SD_MODE, + CFG_ID_DD_SD_ENABLE, CFG_ID_DD_DRIVE_TYPE, CFG_ID_DD_DISK_STATE, CFG_ID_BUTTON_STATE, diff --git a/sw/controller/src/button.c b/sw/controller/src/button.c index e8b67c1..d9aa294 100644 --- a/sw/controller/src/button.c +++ b/sw/controller/src/button.c @@ -20,11 +20,15 @@ bool button_get_state (void) { return p.state; } -void button_set_mode (button_mode_t mode) { +bool button_set_mode (button_mode_t mode) { + if (mode > BUTTON_MODE_DD_DISK_SWAP) { + return true; + } p.mode = mode; if (p.mode == BUTTON_MODE_NONE) { p.trigger = false; } + return false; } button_mode_t button_get_mode (void) { diff --git a/sw/controller/src/button.h b/sw/controller/src/button.h index cf48999..3c41913 100644 --- a/sw/controller/src/button.h +++ b/sw/controller/src/button.h @@ -14,7 +14,7 @@ typedef enum { bool button_get_state (void); -void button_set_mode (button_mode_t mode); +bool button_set_mode (button_mode_t mode); button_mode_t button_get_mode (void); void button_init (void); void button_process (void); diff --git a/sw/controller/src/cfg.c b/sw/controller/src/cfg.c index bbb5fd3..f57fdc2 100644 --- a/sw/controller/src/cfg.c +++ b/sw/controller/src/cfg.c @@ -14,12 +14,12 @@ typedef enum { CFG_ID_ROM_WRITE_ENABLE, CFG_ID_ROM_SHADOW_ENABLE, CFG_ID_DD_MODE, - CFG_ID_ISV_ENABLE, + CFG_ID_ISV_ADDRESS, CFG_ID_BOOT_MODE, CFG_ID_SAVE_TYPE, CFG_ID_CIC_SEED, CFG_ID_TV_TYPE, - CFG_ID_DD_SD_MODE, + CFG_ID_DD_SD_ENABLE, CFG_ID_DD_DRIVE_TYPE, CFG_ID_DD_DISK_STATE, CFG_ID_BUTTON_STATE, @@ -172,7 +172,11 @@ static void cfg_change_scr_bits (uint32_t mask, bool value) { } } -static void cfg_set_save_type (save_type_t save_type) { +static bool cfg_set_save_type (save_type_t save_type) { + if (save_type > SAVE_TYPE_SRAM_BANKED) { + return true; + } + uint32_t save_reset_mask = ( CFG_SCR_EEPROM_16K | CFG_SCR_EEPROM_ENABLED | @@ -207,6 +211,8 @@ static void cfg_set_save_type (save_type_t save_type) { } p.save_type = save_type; + + return false; } @@ -236,8 +242,8 @@ bool cfg_query (uint32_t *args) { args[1] |= DD_MODE_REGS; } break; - case CFG_ID_ISV_ENABLE: - args[1] = isv_get_enabled(); + case CFG_ID_ISV_ADDRESS: + args[1] = isv_get_address(); break; case CFG_ID_BOOT_MODE: args[1] = p.boot_mode; @@ -251,6 +257,9 @@ bool cfg_query (uint32_t *args) { case CFG_ID_TV_TYPE: args[1] = p.tv_type; break; + case CFG_ID_DD_SD_ENABLE: + args[1] = dd_get_sd_mode(); + break; case CFG_ID_DD_DRIVE_TYPE: args[1] = dd_get_drive_type(); break; @@ -266,9 +275,6 @@ 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; } @@ -296,43 +302,55 @@ bool cfg_update (uint32_t *args) { } else if (args[1] == DD_MODE_IPL) { cfg_change_scr_bits(CFG_SCR_DD_ENABLED, false); cfg_change_scr_bits(CFG_SCR_DDIPL_ENABLED, true); - } else { + } else if (args[1] == DD_MODE_FULL) { cfg_change_scr_bits(CFG_SCR_DD_ENABLED | CFG_SCR_DDIPL_ENABLED, true); + } else { + return true; } break; - case CFG_ID_ISV_ENABLE: - isv_set_enabled(args[1]); + case CFG_ID_ISV_ADDRESS: + return isv_set_address(args[1]); break; case CFG_ID_BOOT_MODE: + if (args[1] > BOOT_MODE_DIRECT) { + return true; + } p.boot_mode = args[1]; cfg_change_scr_bits(CFG_SCR_BOOTLOADER_SKIP, (args[1] == BOOT_MODE_DIRECT)); break; case CFG_ID_SAVE_TYPE: - cfg_set_save_type((save_type_t) (args[1])); + return cfg_set_save_type((save_type_t) (args[1])); break; case CFG_ID_CIC_SEED: + if ((args[1] != 0xFFFF) && (args[1] > 0x1FF)) { + return true; + } p.cic_seed = (cic_seed_t) (args[1] & 0xFFFF); break; case CFG_ID_TV_TYPE: + if (args[1] > TV_TYPE_UNKNOWN) { + return true; + } p.tv_type = (tv_type_t) (args[1] & 0x03); break; + case CFG_ID_DD_SD_ENABLE: + dd_set_sd_mode(args[1]); + break; case CFG_ID_DD_DRIVE_TYPE: - dd_set_drive_type(args[1]); + return dd_set_drive_type(args[1]); break; case CFG_ID_DD_DISK_STATE: - dd_set_disk_state(args[1]); + return dd_set_disk_state(args[1]); break; case CFG_ID_BUTTON_STATE: return true; + break; case CFG_ID_BUTTON_MODE: - button_set_mode(args[1]); + return button_set_mode(args[1]); break; 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; } @@ -374,7 +392,7 @@ void cfg_reset_state (void) { dd_set_drive_type(DD_DRIVE_TYPE_RETAIL); dd_set_disk_state(DD_DISK_STATE_EJECTED); dd_set_sd_mode(false); - isv_set_enabled(false); + isv_set_address(0); p.cic_seed = CIC_SEED_UNKNOWN; p.tv_type = TV_TYPE_UNKNOWN; p.boot_mode = BOOT_MODE_MENU; diff --git a/sw/controller/src/dd.c b/sw/controller/src/dd.c index ee207ff..43f2ef0 100644 --- a/sw/controller/src/dd.c +++ b/sw/controller/src/dd.c @@ -209,7 +209,7 @@ dd_drive_type_t dd_get_drive_type (void) { return p.drive_type; } -void dd_set_drive_type (dd_drive_type_t type) { +bool dd_set_drive_type (dd_drive_type_t type) { switch (type) { case DD_DRIVE_TYPE_RETAIL: fpga_reg_set(REG_DD_DRIVE_ID, DD_DRIVE_ID_RETAIL); @@ -220,7 +220,11 @@ void dd_set_drive_type (dd_drive_type_t type) { fpga_reg_set(REG_DD_DRIVE_ID, DD_DRIVE_ID_DEVELOPMENT); p.drive_type = type; break; + + default: + return true; } + return false; } dd_disk_state_t dd_get_disk_state (void) { @@ -234,7 +238,10 @@ dd_disk_state_t dd_get_disk_state (void) { return DD_DISK_STATE_EJECTED; } -void dd_set_disk_state (dd_disk_state_t state) { +bool dd_set_disk_state (dd_disk_state_t state) { + if (state > DD_DISK_STATE_CHANGED) { + return true; + } uint32_t scr = fpga_reg_get(REG_DD_SCR); scr &= ~(DD_SCR_DISK_CHANGED | DD_SCR_DISK_INSERTED); switch (state) { @@ -250,6 +257,7 @@ void dd_set_disk_state (dd_disk_state_t state) { break; } fpga_reg_set(REG_DD_SCR, scr); + return false; } bool dd_get_sd_mode (void) { diff --git a/sw/controller/src/dd.h b/sw/controller/src/dd.h index 0f8d833..3bddaff 100644 --- a/sw/controller/src/dd.h +++ b/sw/controller/src/dd.h @@ -3,6 +3,7 @@ #include +#include typedef enum { @@ -19,9 +20,9 @@ typedef enum { 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); +bool 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); +bool dd_set_disk_state (dd_disk_state_t state); 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); diff --git a/sw/controller/src/isv.c b/sw/controller/src/isv.c index 6463622..2f20f6a 100644 --- a/sw/controller/src/isv.c +++ b/sw/controller/src/isv.c @@ -4,70 +4,94 @@ #include "usb.h" -#define ISV_READ_POINTER_ADDRESS (0x03FF0004) -#define ISV_WRITE_POINTER_ADDRESS (0x03FF0014) -#define ISV_BUFFER_ADDRESS (0x03FF0020) -#define ISV_BUFFER_SIZE ((64 * 1024) - 0x20) +#define ISV_TOKEN (0x49533634) + +#define ISV_SETUP_TOKEN_ADDRESS (0x00000100) +#define ISV_SETUP_OFFSET_ADDRESS (0x00000104) +#define ISV_SETUP_READY_ADDRESS (0x0000010C) + +#define ISV_TOKEN_OFFSET (0x00000000) +#define ISV_READ_POINTER_OFFSET (0x00000004) +#define ISV_WRITE_POINTER_OFFSET (0x00000014) +#define ISV_BUFFER_OFFSET (0x00000020) + +#define ISV_BUFFER_SIZE ((64 * 1024) - ISV_BUFFER_OFFSET) struct process { - bool enabled; - uint32_t current_read_pointer; + bool ready; + uint32_t address; + uint32_t next_read_pointer; }; static struct process p; -static void isv_set_pointer (uint32_t address, uint32_t data) { +static void isv_set_value (uint32_t address, uint32_t data) { data = SWAP32(data); fpga_mem_write(address, 4, (uint8_t *) (&data)); } -static uint32_t isv_get_pointer (uint32_t address) { +static uint32_t isv_get_value (uint32_t address) { uint32_t data; fpga_mem_read(address, 4, (uint8_t *) (&data)); return SWAP32(data); } static void isv_update_read_pointer (void) { - isv_set_pointer(ISV_READ_POINTER_ADDRESS, p.current_read_pointer); + p.ready = true; + isv_set_value(p.address + ISV_READ_POINTER_OFFSET, p.next_read_pointer); } -void isv_set_enabled (bool enabled) { - if (enabled) { - p.enabled = true; - p.current_read_pointer = 0; - isv_set_pointer(ISV_READ_POINTER_ADDRESS, 0); - isv_set_pointer(ISV_WRITE_POINTER_ADDRESS, 0); - } else { - p.enabled = false; +bool isv_set_address (uint32_t address) { + if ((address > 0x03FF0000) || (address % 4)) { + return true; } + p.address = address; + return false; } -bool isv_get_enabled (void) { - return p.enabled; +uint32_t isv_get_address (void) { + return p.address; } void isv_init (void) { - p.enabled = false; + p.address = 0; + p.ready = true; } void isv_process (void) { - if (p.enabled) { - uint32_t write_pointer = isv_get_pointer(ISV_WRITE_POINTER_ADDRESS); - - if (p.current_read_pointer == write_pointer) { + if ((p.address != 0) && p.ready) { + if (isv_get_value(ISV_SETUP_TOKEN_ADDRESS) == ISV_TOKEN) { + isv_set_value(ISV_SETUP_TOKEN_ADDRESS, 0); + isv_set_value(ISV_SETUP_OFFSET_ADDRESS, (p.address | 0x10000000)); + isv_set_value(ISV_SETUP_READY_ADDRESS, ISV_TOKEN); return; } + + if (isv_get_value(p.address + ISV_TOKEN_OFFSET) != ISV_TOKEN) { + return; + } + + uint32_t read_pointer = isv_get_value(p.address + ISV_READ_POINTER_OFFSET); + if (read_pointer >= ISV_BUFFER_SIZE) { + return; + } + + uint32_t write_pointer = isv_get_value(p.address + ISV_WRITE_POINTER_OFFSET); if (write_pointer >= ISV_BUFFER_SIZE) { return; } - bool wrap = write_pointer < p.current_read_pointer; - uint32_t length = (wrap ? ISV_BUFFER_SIZE : write_pointer) - p.current_read_pointer; - uint32_t offset = ISV_BUFFER_ADDRESS + p.current_read_pointer; + if (read_pointer == write_pointer) { + return; + } + + bool wrap = write_pointer < read_pointer; + uint32_t length = (wrap ? ISV_BUFFER_SIZE : write_pointer) - read_pointer; + uint32_t offset = p.address + ISV_BUFFER_OFFSET + read_pointer; usb_tx_info_t packet_info; usb_create_packet(&packet_info, PACKET_CMD_ISV_OUTPUT); @@ -75,7 +99,8 @@ void isv_process (void) { packet_info.dma_address = offset; packet_info.done_callback = isv_update_read_pointer; if (usb_enqueue_packet(&packet_info)) { - p.current_read_pointer = wrap ? 0 : write_pointer; + p.ready = false; + p.next_read_pointer = wrap ? 0 : write_pointer; } } } diff --git a/sw/controller/src/isv.h b/sw/controller/src/isv.h index 73807e2..04ae2de 100644 --- a/sw/controller/src/isv.h +++ b/sw/controller/src/isv.h @@ -3,10 +3,11 @@ #include +#include -void isv_set_enabled (bool enabled); -bool isv_get_enabled (void); +bool isv_set_address (uint32_t address); +uint32_t isv_get_address (void); void isv_init (void); void isv_process (void); diff --git a/sw/controller/src/usb.c b/sw/controller/src/usb.c index 08cec3e..e986979 100644 --- a/sw/controller/src/usb.c +++ b/sw/controller/src/usb.c @@ -203,12 +203,6 @@ static void usb_rx_process (void) { p.response_pending = true; break; - case 'd': - dd_set_block_ready(p.rx_args[0] == 0); - p.rx_state = RX_STATE_IDLE; - p.response_pending = true; - break; - case 'm': p.rx_state = RX_STATE_IDLE; p.response_pending = true; @@ -216,7 +210,6 @@ static void usb_rx_process (void) { p.response_info.dma_length = p.rx_args[1]; break; - case 'D': case 'M': if (usb_dma_ready()) { if (!p.rx_dma_running) { @@ -227,13 +220,16 @@ static void usb_rx_process (void) { } else { p.rx_state = RX_STATE_IDLE; p.response_pending = true; - if (p.rx_cmd == 'D') { - dd_set_block_ready(true); - } } } break; + case 'D': + dd_set_block_ready(p.rx_args[0] == 0); + p.rx_state = RX_STATE_IDLE; + p.response_pending = true; + break; + case 'U': if ((p.read_length > 0) && usb_dma_ready()) { uint32_t length = (p.read_length > p.rx_args[1]) ? p.rx_args[1] : p.read_length; diff --git a/sw/pc/sc64.py b/sw/pc/sc64.py index 8df32f9..8e7da1f 100755 --- a/sw/pc/sc64.py +++ b/sw/pc/sc64.py @@ -230,12 +230,12 @@ class SC64: ROM_WRITE_ENABLE = 1 ROM_SHADOW_ENABLE = 2 DD_MODE = 3 - ISV_ENABLE = 4 + ISV_ADDRESS = 4 BOOT_MODE = 5 SAVE_TYPE = 6 CIC_SEED = 7 TV_TYPE = 8 - DD_SD_MODE = 9 + DD_SD_ENABLE = 9 DD_DRIVE_TYPE = 10 DD_DISK_STATE = 11 BUTTON_STATE = 12 @@ -327,10 +327,16 @@ class SC64: return int.from_bytes(data[:4], byteorder='big') def __set_config(self, config: __CfgId, value: int) -> None: - self.__link.execute_cmd(cmd=b'C', args=[config, value]) + try: + self.__link.execute_cmd(cmd=b'C', args=[config, value]) + except ConnectionException: + raise ValueError(f'Could not set config {config.name} to {value:08X}') def __get_config(self, config: __CfgId) -> int: - data = self.__link.execute_cmd(cmd=b'c', args=[config, 0]) + try: + data = self.__link.execute_cmd(cmd=b'c', args=[config, 0]) + except ConnectionException: + raise ValueError(f'Could not get config {config.name}') return self.__get_int(data) def __write_memory(self, address: int, data: bytes) -> None: @@ -341,7 +347,10 @@ class SC64: if (length > 0): return self.__link.execute_cmd(cmd=b'm', args=[address, length], timeout=20.0) return bytes([]) - + + def __dd_set_block_ready(self, error: int) -> None: + self.__link.execute_cmd(cmd=b'D', args=[error, 0]) + def __flash_wait_busy(self) -> int: data = self.__link.execute_cmd(cmd=b'p') return self.__get_int(data[0:4]) @@ -379,7 +388,7 @@ class SC64: 'rom_write_enable': bool(self.__get_config(self.__CfgId.ROM_WRITE_ENABLE)), 'rom_shadow_enable': bool(self.__get_config(self.__CfgId.ROM_SHADOW_ENABLE)), 'dd_mode': self.__DDMode(self.__get_config(self.__CfgId.DD_MODE)), - 'isv_enable': bool(self.__get_config(self.__CfgId.ISV_ENABLE)), + 'isv_address': self.__get_config(self.__CfgId.ISV_ADDRESS), 'boot_mode': self.BootMode(self.__get_config(self.__CfgId.BOOT_MODE)), 'save_type': self.SaveType(self.__get_config(self.__CfgId.SAVE_TYPE)), 'cic_seed': self.CICSeed(self.__get_config(self.__CfgId.CIC_SEED)), @@ -537,14 +546,16 @@ class SC64: raise BadBlockError if (cmd == CMD_READ_BLOCK): block_data = dd.read_block(track, head, block) - self.__link.execute_cmd(cmd=b'D', args=[address, len(block_data)], data=block_data) + self.__write_memory(address, block_data) + self.__dd_set_block_ready(0) elif (cmd == CMD_WRITE_BLOCK): - dd.write_block(track, head, block, data[12:]) - self.__link.execute_cmd(cmd=b'd', args=[0, 0]) + block_data = data[12:] + dd.write_block(track, head, block, block_data) + self.__dd_set_block_ready(0) else: - self.__link.execute_cmd(cmd=b'd', args=[-1, 0]) + self.__dd_set_block_ready(1) except BadBlockError: - self.__link.execute_cmd(cmd=b'd', args=[1, 0]) + self.__dd_set_block_ready(1) def __handle_isv_packet(self, data: bytes) -> None: print(data.decode('EUC-JP', errors='backslashreplace'), end='') @@ -618,15 +629,15 @@ class SC64: except EOFError: running = False - def debug_loop(self, isv: bool=False, disks: Optional[list[str]]=None) -> None: + def debug_loop(self, isv: int=0, disks: Optional[list[str]]=None) -> None: dd = None current_image = 0 next_image = 0 self.__set_config(self.__CfgId.ROM_WRITE_ENABLE, isv) - self.__set_config(self.__CfgId.ISV_ENABLE, isv) - if (isv): - print('IS-Viewer64 support set to [ENABLED]') + self.__set_config(self.__CfgId.ISV_ADDRESS, isv) + if (isv != 0): + print(f'IS-Viewer64 support set to [ENABLED] at ROM offset [0x{(isv):08X}]') if (self.__get_config(self.__CfgId.ROM_SHADOW_ENABLE)): print('ROM shadow enabled - IS-Viewer64 will NOT work (use --no-shadow option to disable it)') @@ -694,8 +705,8 @@ class SC64: if (dd and dd.loaded): self.__set_config(self.__CfgId.DD_DISK_STATE, self.__DDDiskState.EJECTED) - if (isv): - self.__set_config(self.__CfgId.ISV_ENABLE, False) + if (isv != 0): + self.__set_config(self.__CfgId.ISV_ADDRESS, 0) class EnumAction(argparse.Action): @@ -735,7 +746,7 @@ if __name__ == '__main__': parser.add_argument('--backup-save', metavar='file', help='download save and write it to specified file') parser.add_argument('--ddipl', metavar='file', help='upload 64DD IPL from specified file') parser.add_argument('--disk', metavar='file', action='append', help='path to 64DD disk (.ndd format), can be specified multiple times') - parser.add_argument('--isv', action='store_true', help='enable IS-Viewer64 support') + parser.add_argument('--isv', type=lambda x: int(x, 0), default=0, help='enable IS-Viewer64 support at provided ROM offset') parser.add_argument('--debug', action='store_true', help='run debug loop (required for 64DD and IS-Viewer64)') parser.add_argument('--download-memory', metavar='file', help='download whole memory space and write it to specified file')