diff --git a/fw/rtl/n64/n64_bus.sv b/fw/rtl/n64/n64_bus.sv index e3c90aa..b09700d 100644 --- a/fw/rtl/n64/n64_bus.sv +++ b/fw/rtl/n64/n64_bus.sv @@ -9,6 +9,7 @@ interface if_n64_bus (); logic [31:0] address; logic [15:0] wdata; logic [15:0] rdata; + logic n64_active; logic [31:0] real_address; logic read_op; logic write_op; @@ -24,6 +25,10 @@ interface if_n64_bus (); ack = ack | device_ack[i]; rdata = rdata | device_rdata[i]; end + + if (id >= NUM_DEVICES) begin + ack = request; + end end modport n64 ( @@ -34,7 +39,7 @@ interface if_n64_bus (); output address, output wdata, input rdata, - + output n64_active, output real_address, output read_op, output write_op @@ -44,9 +49,11 @@ interface if_n64_bus (); generate for (n = 0; n < NUM_DEVICES; n++) begin : at logic device_request; + logic device_n64_active; always_comb begin device_request = request && id == sc64::e_n64_id'(n); + device_n64_active = n64_active && id == sc64::e_n64_id'(n); end modport device ( @@ -56,7 +63,7 @@ interface if_n64_bus (); input .address(address), input .wdata(wdata), output .rdata(device_rdata[n]), - + input .n64_active(device_n64_active), input .real_address(real_address), input .read_op(read_op), input .write_op(write_op) diff --git a/fw/rtl/n64/n64_pi.sv b/fw/rtl/n64/n64_pi.sv index 8d012c8..239628c 100644 --- a/fw/rtl/n64/n64_pi.sv +++ b/fw/rtl/n64/n64_pi.sv @@ -191,6 +191,7 @@ module n64_pi ( end always_comb begin + bus.n64_active = !pi_reset && pi_mode != PI_MODE_IDLE; bus.read_op = read_op; bus.write_op = write_op; end @@ -218,6 +219,7 @@ module n64_pi ( always_ff @(posedge sys.clk) begin if (aleh_op) begin n64_pi_address_valid <= 1'b0; + next_id <= sc64::__ID_N64_END; next_offset <= 32'd0; sram_selected <= 1'b0; cfg_selected <= 1'b0; diff --git a/fw/rtl/n64/n64_sdram.sv b/fw/rtl/n64/n64_sdram.sv index cc0e6fc..273e6b0 100644 --- a/fw/rtl/n64/n64_sdram.sv +++ b/fw/rtl/n64/n64_sdram.sv @@ -41,15 +41,17 @@ module n64_sdram ( end else begin case (state) S_IDLE: begin - if (bus.request || sdram.request || dma.request) begin + if (bus.request) begin state <= S_WAIT; mem_request <= 1'b1; - if (bus.request) begin - mem_write <= bus.write; - mem_address <= bus.address; - mem_wdata <= bus.wdata; - source_request <= T_BUS; - end else if (sdram.request) begin + mem_write <= bus.write; + mem_address <= bus.address; + mem_wdata <= bus.wdata; + source_request <= T_BUS; + end else if ((!bus.n64_active) && (sdram.request || dma.request)) begin + state <= S_WAIT; + mem_request <= 1'b1; + if (sdram.request) begin mem_write <= sdram.write; mem_address <= sdram.address; mem_wdata <= sdram.wdata; diff --git a/sw/n64/src/main.c b/sw/n64/src/main.c index cc429a9..8efaf7e 100644 --- a/sw/n64/src/main.c +++ b/sw/n64/src/main.c @@ -65,6 +65,11 @@ void main (void) { } } + if (sc64_info.is_viewer_enabled) { + LOG_I("Initializing IS-Viewer 64\r\n"); + sc64_init_is_viewer(); + } + LOG_I("Booting IPL3\033[0m\r\n\r\n"); boot(&boot_info); diff --git a/sw/n64/src/sc64.c b/sw/n64/src/sc64.c index e04bc76..5598781 100644 --- a/sw/n64/src/sc64.c +++ b/sw/n64/src/sc64.c @@ -69,6 +69,7 @@ void sc64_get_info (sc64_info_t *info) { } info->dd_enabled = (bool) sc64_get_config(CFG_ID_DD_ENABLE); + info->is_viewer_enabled = (bool) sc64_get_config(CFG_ID_IS_VIEWER_ENABLE); info->save_type = (save_type_t) sc64_get_config(CFG_ID_SAVE_TYPE); info->cic_seed = (uint16_t) sc64_get_config(CFG_ID_CIC_SEED); info->tv_type = (tv_type_t) sc64_get_config(CFG_ID_TV_TYPE); @@ -196,6 +197,11 @@ void sc64_debug_fsd_write (const void *data, uint32_t sector, uint32_t count) { sc64_debug_write(SC64_DEBUG_ID_FSD_WRITE, data, count * 512); } +void sc64_init_is_viewer (void) { + sc64_set_config(CFG_ID_SDRAM_WRITABLE, true); + pi_io_write(&ISV->ID, 0); +} + void sc64_init (void) { while (!sc64_check_presence()); sc64_wait_cpu_ready(); diff --git a/sw/n64/src/sc64.h b/sw/n64/src/sc64.h index b9ff847..7a0e5f3 100644 --- a/sw/n64/src/sc64.h +++ b/sw/n64/src/sc64.h @@ -67,6 +67,10 @@ typedef enum { CFG_ID_FLASH_READ, CFG_ID_FLASH_PROGRAM, CFG_ID_RECONFIGURE, + CFG_ID_DD_DRIVE_ID, + CFG_ID_DD_DISK_STATE, + CFG_ID_DD_THB_TABLE_OFFSET, + CFG_ID_IS_VIEWER_ENABLE, } cfg_id_t; typedef enum { @@ -95,6 +99,7 @@ typedef enum { typedef struct { bool dd_enabled; + bool is_viewer_enabled; // investigate why it breaks when put before bootloader_version save_type_t save_type; uint16_t cic_seed; tv_type_t tv_type; @@ -120,6 +125,7 @@ void sc64_usb_tx_data (io32_t *address, uint32_t length); void sc64_debug_write (uint8_t type, const void *data, uint32_t len); void sc64_debug_fsd_read (const void *data, uint32_t sector, uint32_t count); void sc64_debug_fsd_write (const void *data, uint32_t sector, uint32_t count); +void sc64_init_is_viewer (void); void sc64_init (void); diff --git a/sw/n64/src/sys.h b/sw/n64/src/sys.h index 9bf29b1..d31dfc1 100644 --- a/sw/n64/src/sys.h +++ b/sw/n64/src/sys.h @@ -249,6 +249,18 @@ typedef struct { #define ROM_CART ((io32_t *) ROM_CART_BASE) +typedef struct { + io32_t ID; + io32_t __padding_1[4]; + io32_t RD_PTR; + io32_t __padding_2[2]; + io8_t BUFFER[(64 * 1024) - 0x20]; +} is_viewer_t; + +#define ISV_BASE (0x13FF0000UL) +#define ISV ((is_viewer_t *) ISV_BASE) + + #define PIFRAM_BASE (0x1FC007C0UL) #define PIFRAM ((io8_t *) PIFRAM_BASE) diff --git a/sw/pc/sc64.py b/sw/pc/sc64.py index 93eece2..ced4e6b 100644 --- a/sw/pc/sc64.py +++ b/sw/pc/sc64.py @@ -31,8 +31,10 @@ class SC64: __CFG_ID_FLASH_READ = 11 __CFG_ID_FLASH_PROGRAM = 12 __CFG_ID_RECONFIGURE = 13 - __CFG_ID_DD_SETTING = 14 - __CFG_ID_DD_THB_TABLE_OFFSET = 15 + __CFG_ID_DD_DRIVE_ID = 14 + __CFG_ID_DD_DISK_STATE = 15 + __CFG_ID_DD_THB_TABLE_OFFSET = 16 + __CFG_ID_IS_VIEWER_ENABLE = 17 __SC64_VERSION_V2 = 0x53437632 @@ -47,14 +49,16 @@ class SC64: __DEBUG_ID_FSD_READ = 0xF1 __DEBUG_ID_FSD_WRITE = 0xF2 __DEBUG_ID_FSD_SECTOR = 0xF3 - __DEBUG_ID_DD_BLOCK = 0xF5 + __DEBUG_ID_INTERNAL = 0xFE + __INTERNAL_ID_IS_VIEWER = 0 + __INTERNAL_ID_DD_BLOCK = 1 + + __DD_DRIVE_ID_RETAIL = 3 + __DD_DRIVE_ID_DEVELOPMENT = 4 + __DD_DISK_STATE_EJECTED = 0 + __DD_DISK_STATE_INSERTED = 1 + __DD_DISK_STATE_CHANGED = 2 - __DD_SETTING_DISK_EJECTED = 0 - __DD_SETTING_DISK_INSERTED = 1 - __DD_SETTING_DISK_CHANGED = 2 - __DD_SETTING_DRIVE_RETAIL = 3 - __DD_SETTING_DRIVE_DEVELOPMENT = 4 - __DD_SETTING_SET_BLOCK_READY = 5 def __init__(self) -> None: self.__serial = None @@ -64,6 +68,7 @@ class SC64: self.__fsd_file = None self.__disk_file = None self.__disk_lba_table = [] + self.__isv_line_buffer = bytearray() self.__find_sc64() @@ -370,13 +375,14 @@ class SC64: self.__write_file_to_sdram(file, dd_ipl_offset, min_length=self.__DDIPL_ROM_LENGTH) - def set_dd_disk_state(self, state: int) -> None: - if (state == "ejected"): - self.__change_config(self.__CFG_ID_DD_SETTING, self.__DD_SETTING_DISK_EJECTED) - elif (state == "inserted"): - self.__change_config(self.__CFG_ID_DD_SETTING, self.__DD_SETTING_DISK_INSERTED) - elif (state == "changed"): - self.__change_config(self.__CFG_ID_DD_SETTING, self.__DD_SETTING_DISK_CHANGED) + def set_dd_disk_state(self, state: str) -> None: + state_mapping = { + "ejected": self.__DD_DISK_STATE_EJECTED, + "inserted": self.__DD_DISK_STATE_INSERTED, + "changed": self.__DD_DISK_STATE_CHANGED, + } + if (state in state_mapping): + self.__change_config(self.__CFG_ID_DD_DISK_STATE, state_mapping[state]) else: raise SC64Exception("DD disk state outside of supported values") @@ -530,10 +536,14 @@ class SC64: self.__write_cmd("W", thb_table_offset, len(data)) self.__write(data) self.__read_cmd_status("W") - if (disk_drive_type == "retail"): - self.__change_config(self.__CFG_ID_DD_SETTING, self.__DD_SETTING_DRIVE_RETAIL) - elif (disk_drive_type == "development"): - self.__change_config(self.__CFG_ID_DD_SETTING, self.__DD_SETTING_DRIVE_DEVELOPMENT) + id_mapping = { + "retail": self.__DD_DRIVE_ID_RETAIL, + "development": self.__DD_DRIVE_ID_DEVELOPMENT, + } + if (disk_drive_type in id_mapping): + self.__change_config(self.__CFG_ID_DD_DRIVE_ID, id_mapping[disk_drive_type]) + else: + raise SC64Exception("DD drive type outside of supported values") else: raise SC64Exception("No DD disk file provided for disk info creation") @@ -557,6 +567,18 @@ class SC64: self.__fsd_file.write(data) + def __debug_process_is_viewer(self, data: bytes) -> None: + self.__isv_line_buffer.extend(data) + try: + while (len(self.__isv_line_buffer) > 0): + line_end = self.__isv_line_buffer.index(b'\n') + line = self.__isv_line_buffer[:line_end] + self.__isv_line_buffer = self.__isv_line_buffer[line_end + 1:] + print(line.decode("EUC-JP", errors="backslashreplace")) + except ValueError: + 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') @@ -568,26 +590,39 @@ class SC64: if (self.__disk_file): self.__disk_file.seek(disk_file_offset) if (transfer_mode): - self.__write_cmd("W", sdram_offset, block_length) + time.sleep(0.01) # 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)) - self.__read_cmd_status("W") else: - self.__write_cmd("R", sdram_offset, block_length) - self.__disk_file.write(self.__read_long(block_length)) - self.__read_cmd_status("R") - - self.__change_config(self.__CFG_ID_DD_SETTING, self.__DD_SETTING_SET_BLOCK_READY) + write_data = data[16:] + self.__disk_file.write(write_data) - def debug_loop(self, fsd_file: str = None, disk_file: str = None) -> None: - print("\r\n\033[34m --- Debug server started --- \033[0m\r\n") + 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) + + + def debug_init(self, fsd_file: str = None, disk_file: str = None, is_viewer_enabled: bool = False) -> None: if (fsd_file): self.__fsd_file = open(fsd_file, "rb+") if (disk_file): self.__disk_file = open(disk_file, "rb+") + 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() dropped_bytes = 0 @@ -621,8 +656,8 @@ class SC64: 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_DD_BLOCK): - self.__debug_process_dd_block(data) + elif (id == self.__DEBUG_ID_INTERNAL): + self.__debug_process_internal(data) else: print(f"\033[35mGot unknown id: {id}, length: {length}\033[0m", file=sys.stderr) @@ -698,6 +733,7 @@ if __name__ == "__main__": parser.add_argument("-e", metavar="save_path", default=None, required=False, help="path to save file") parser.add_argument("-i", metavar="ddipl_path", default=None, required=False, help="path to DDIPL file") parser.add_argument("-q", default=None, action="store_true", required=False, help="start debug server") + parser.add_argument("-v", default=False, action="store_true", required=False, help="enable IS-Viewer64 support") parser.add_argument("-f", metavar="sd_path", default=None, required=False, help="path to disk or file for fake SD card emulation") parser.add_argument("-k", metavar="disk_path", default=None, required=False, help="path to 64DD disk file") parser.add_argument("rom", metavar="rom_path", default=None, help="path to ROM file", nargs="?") @@ -723,6 +759,7 @@ if __name__ == "__main__": dd_ipl_file = args.i rom_file = args.rom debug_server = args.q + is_viewer_enabled = args.v sd_file = args.f disk_file = args.k @@ -789,10 +826,12 @@ if __name__ == "__main__": if (disk_file): print(f"Using 64DD disk image file [{disk_file}]") sc64.set_dd_configuration_for_disk(disk_file) - if (disk_file): print(f"Setting 64DD disk state to [Changed]") sc64.set_dd_disk_state("changed" if disk_file else "ejected") - sc64.debug_loop(sd_file, disk_file) + if (is_viewer_enabled): + print(f"Setting IS-Viewer64 emulation to [Enabled]") + sc64.debug_init(sd_file, disk_file, is_viewer_enabled) + sc64.debug_loop(is_viewer_enabled) except SC64Exception as e: print(f"Error: {e}") diff --git a/sw/riscv/Makefile b/sw/riscv/Makefile index 566e32b..6ce172d 100644 --- a/sw/riscv/Makefile +++ b/sw/riscv/Makefile @@ -12,7 +12,20 @@ LDFLAGS = -nostartfiles -Wl,--gc-sections SRC_DIR = src BUILD_DIR = build -SRC_FILES = startup.S process.c usb.c cfg.c dma.c joybus.c rtc.c i2c.c flashram.c uart.c flash.c dd.c +SRC_FILES = \ + startup.S \ + process.c \ + usb.c \ + cfg.c \ + dma.c \ + joybus.c \ + rtc.c \ + i2c.c \ + flashram.c \ + uart.c \ + flash.c \ + dd.c \ + isv.c SRCS = $(addprefix $(SRC_DIR)/, $(SRC_FILES)) OBJS = $(addprefix $(BUILD_DIR)/, $(notdir $(patsubst %,%.o,$(SRCS)))) diff --git a/sw/riscv/src/cfg.c b/sw/riscv/src/cfg.c index 1232c05..e396cd7 100644 --- a/sw/riscv/src/cfg.c +++ b/sw/riscv/src/cfg.c @@ -1,6 +1,7 @@ #include "cfg.h" #include "dd.h" #include "flash.h" +#include "isv.h" #include "joybus.h" #include "usb.h" @@ -32,8 +33,10 @@ enum cfg_id { CFG_ID_FLASH_READ, CFG_ID_FLASH_PROGRAM, CFG_ID_RECONFIGURE, - CFG_ID_DD_SETTING, + CFG_ID_DD_DRIVE_ID, + CFG_ID_DD_DISK_STATE, CFG_ID_DD_THB_TABLE_OFFSET, + CFG_ID_IS_VIEWER_ENABLE, }; enum save_type { @@ -53,15 +56,6 @@ enum boot_mode { BOOT_MODE_DIRECT = 3, }; -enum dd_setting { - DD_SETTING_DISK_EJECTED = 0, - DD_SETTING_DISK_INSERTED = 1, - DD_SETTING_DISK_CHANGED = 2, - DD_SETTING_DRIVE_RETAIL = 3, - DD_SETTING_DRIVE_DEVELOPMENT = 4, - DD_SETTING_SET_BLOCK_READY = 5, -}; - struct process { enum save_type save_type; @@ -124,29 +118,6 @@ static void set_save_type (enum save_type save_type) { CFG->SAVE_OFFSET = save_offset; } -static void set_dd_setting (enum dd_setting setting) { - switch (setting) { - case DD_SETTING_DISK_EJECTED: - dd_set_disk_state(DD_DISK_EJECTED); - break; - case DD_SETTING_DISK_INSERTED: - dd_set_disk_state(DD_DISK_INSERTED); - break; - case DD_SETTING_DISK_CHANGED: - dd_set_disk_state(DD_DISK_CHANGED); - break; - case DD_SETTING_DRIVE_RETAIL: - dd_set_drive_type_development(false); - break; - case DD_SETTING_DRIVE_DEVELOPMENT: - dd_set_drive_type_development(true); - break; - case DD_SETTING_SET_BLOCK_READY: - dd_set_block_ready(true); - break; - } -} - uint32_t cfg_get_version (void) { return CFG->VERSION; @@ -199,8 +170,17 @@ void cfg_update (uint32_t *args) { ); } break; - case CFG_ID_DD_SETTING: - set_dd_setting(args[1]); + case CFG_ID_DD_DISK_STATE: + dd_set_disk_state(args[1]); + break; + case CFG_ID_DD_DRIVE_ID: + dd_set_drive_id((uint16_t) (args[1])); + break; + case CFG_ID_DD_THB_TABLE_OFFSET: + dd_set_thb_table_offset(args[1]); + break; + case CFG_ID_IS_VIEWER_ENABLE: + isv_set_enabled(args[1]); break; } } @@ -243,9 +223,18 @@ void cfg_query (uint32_t *args) { case CFG_ID_RECONFIGURE: args[1] = CFG->RECONFIGURE; break; + case CFG_ID_DD_DISK_STATE: + args[1] = dd_get_disk_state(); + break; + case CFG_ID_DD_DRIVE_ID: + args[1] = dd_get_drive_id(); + break; case CFG_ID_DD_THB_TABLE_OFFSET: args[1] = dd_get_thb_table_offset(); break; + case CFG_ID_IS_VIEWER_ENABLE: + args[1] = isv_get_enabled(); + break; } } diff --git a/sw/riscv/src/dd.c b/sw/riscv/src/dd.c index 8ea156c..fd66db1 100644 --- a/sw/riscv/src/dd.c +++ b/sw/riscv/src/dd.c @@ -8,7 +8,7 @@ #define DD_BUFFERS_OFFSET (SDRAM_BASE + 0x03BD0000UL) #define DD_THB_TABLE_OFFSET (DD_BUFFERS_OFFSET + 0x0000) #define DD_USB_BUFFER_OFFSET (DD_BUFFERS_OFFSET + 0x5000) -#define DD_BLOCK_BUFFER_OFFSET (DD_BUFFERS_OFFSET + 0x6000) +#define DD_BLOCK_BUFFER_OFFSET (DD_USB_BUFFER_OFFSET + 0x10) #define USB_DEBUG_ID_DD_BLOCK (0xF5) @@ -62,10 +62,8 @@ struct process { bool full_track_transfer; bool starting_block; uint8_t current_sector; - bool is_dev_disk; rtc_time_t time; io32_t *thb_table; - io32_t *usb_buffer; io32_t *block_buffer; bool block_ready; }; @@ -87,7 +85,7 @@ static bool dd_block_valid (void) { } static bool dd_block_request (void) { - if (!usb_debug_tx_ready()) { + if (!usb_internal_debug_tx_ready()) { return false; } @@ -95,23 +93,22 @@ static bool dd_block_request (void) { return true; } - const char *dma = "DMA@"; - const char *cmp = "CMPH"; - 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 = p.usb_buffer; + io32_t *dst = (io32_t *) (DD_USB_BUFFER_OFFSET); - *dst++ = *((uint32_t *) (dma)); - *dst++ = swap32((USB_DEBUG_ID_DD_BLOCK << 24) | 16); - *dst++ = swap32(p.transfer_mode); - *dst++ = swap32((uint32_t) (p.block_buffer)); + *dst++ = SWAP32(p.transfer_mode); + *dst++ = SWAP32((uint32_t) (p.block_buffer)); *dst++ = offset; - *dst++ = swap32(length); - *dst++ = *((uint32_t *) (cmp)); + *dst++ = SWAP32(length); - usb_debug_tx_data((uint32_t) (p.usb_buffer), 28); + if (!p.transfer_mode) { + transfer_length += length; + } + + usb_internal_debug_tx_data(INT_DBG_ID_DD_BLOCK, DD_USB_BUFFER_OFFSET, transfer_length); p.block_ready = false; @@ -119,7 +116,15 @@ static bool dd_block_request (void) { } static bool dd_block_ready (void) { - return p.block_ready || (!(DD->SCR & DD_SCR_DISK_INSERTED)); + if (!(DD->SCR & DD_SCR_DISK_INSERTED)) { + return true; + } + + if (p.transfer_mode) { + return p.block_ready; + } else { + return usb_internal_debug_tx_ready(); + } } static void dd_sector_read (void) { @@ -166,20 +171,34 @@ void dd_set_disk_state (disk_state_t disk_state) { DD->SCR = scr; } -void dd_set_drive_type_development (bool value) { - if (value) { - DD->DRIVE_ID = DD_DRIVE_ID_DEVELOPMENT; - p.is_dev_disk = true; +disk_state_t dd_get_disk_state (void) { + uint32_t scr = (DD->SCR & (DD_SCR_DISK_CHANGED | DD_SCR_DISK_INSERTED)); + + if (scr == (DD_SCR_DISK_CHANGED | DD_SCR_DISK_INSERTED)) { + return DD_DISK_CHANGED; + } else if (scr == DD_SCR_DISK_INSERTED) { + return DD_DISK_INSERTED; } else { - DD->DRIVE_ID = DD_DRIVE_ID_RETAIL; - p.is_dev_disk = false; + return DD_DISK_EJECTED; } } +void dd_set_drive_id (uint16_t id) { + DD->DRIVE_ID = id; +} + +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); +} + uint32_t dd_get_thb_table_offset (void) { return (((uint32_t) (p.thb_table)) & 0x0FFFFFFF); } @@ -194,9 +213,7 @@ void dd_init (void) { p.power_up_delay = true; p.deffered_cmd_ready = false; p.bm_running = false; - p.is_dev_disk = false; p.thb_table = (io32_t *) (DD_THB_TABLE_OFFSET); - p.usb_buffer = (io32_t *) (DD_USB_BUFFER_OFFSET); p.block_buffer = (io32_t *) (DD_BLOCK_BUFFER_OFFSET); } diff --git a/sw/riscv/src/dd.h b/sw/riscv/src/dd.h index 18a79c0..3be98aa 100644 --- a/sw/riscv/src/dd.h +++ b/sw/riscv/src/dd.h @@ -13,9 +13,12 @@ typedef enum { void dd_set_disk_state (disk_state_t disk_state); -void dd_set_drive_type_development (bool value); -void dd_set_block_ready (bool value); +disk_state_t dd_get_disk_state (void); +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 new file mode 100644 index 0000000..ac4f3fb --- /dev/null +++ b/sw/riscv/src/isv.c @@ -0,0 +1,60 @@ +#include "isv.h" +#include "usb.h" + + +#define IS64_TOKEN (0x34365349) +#define IS64_OFFSET (SDRAM_BASE + 0x03FF0000) + + +typedef struct { + uint32_t ID; + uint32_t __padding_1[4]; + uint32_t RD_PTR; + uint32_t __padding_2[2]; + uint8_t BUFFER[(64 * 1024) - 0x20]; +} is_viewer_t; + + +struct process { + bool enabled; + uint32_t current_read_pointer; + is_viewer_t *ISV; +}; + +struct process p; + + +void isv_set_enabled (bool enabled) { + p.enabled = enabled; +} + +bool isv_get_enabled (void) { + return p.enabled; +} + + +void isv_init (void) { + p.enabled = false; + p.current_read_pointer = 0; + p.ISV = (is_viewer_t *) (IS64_OFFSET); +} + +void process_isv (void) { + if (!p.enabled || (p.ISV->ID != IS64_TOKEN)) { + p.current_read_pointer = 0; + p.ISV->RD_PTR = 0; + return; + } + + uint32_t read_pointer = SWAP32(p.ISV->RD_PTR); + + if ((read_pointer != p.current_read_pointer) && usb_internal_debug_tx_ready()) { + 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]); + + if (usb_internal_debug_tx_data(INT_DBG_ID_IS_VIEWER, address, length)) { + p.current_read_pointer = wrap ? 0 : read_pointer; + } + } +} diff --git a/sw/riscv/src/isv.h b/sw/riscv/src/isv.h new file mode 100644 index 0000000..4b4a521 --- /dev/null +++ b/sw/riscv/src/isv.h @@ -0,0 +1,14 @@ +#ifndef ISV_H__ +#define ISV_H__ + + +#include "sys.h" + + +void isv_set_enabled (bool enabled); +bool isv_get_enabled (void); +void isv_init (void); +void process_isv (void); + + +#endif diff --git a/sw/riscv/src/process.c b/sw/riscv/src/process.c index 5e899d7..1b00aeb 100644 --- a/sw/riscv/src/process.c +++ b/sw/riscv/src/process.c @@ -8,6 +8,7 @@ #include "flashram.h" #include "dd.h" #include "uart.h" +#include "isv.h" static const void (*process_table[])(void) = { @@ -18,6 +19,7 @@ static const void (*process_table[])(void) = { process_flashram, process_dd, process_uart, + process_isv, NULL, }; @@ -34,6 +36,7 @@ __attribute__((naked)) void process_loop (void) { flashram_init(); dd_init(); uart_init(); + isv_init(); while (1) { process_joybus(); diff --git a/sw/riscv/src/sys.h b/sw/riscv/src/sys.h index f0ed845..5d0c608 100644 --- a/sw/riscv/src/sys.h +++ b/sw/riscv/src/sys.h @@ -8,11 +8,14 @@ #include -#define swap32(x) ((((x) & 0xFF000000UL) >> 24) | \ +#define SWAP32(x) ((((x) & 0xFF000000UL) >> 24) | \ (((x) & 0x00FF0000UL) >> 8) | \ (((x) & 0x0000FF00UL) << 8) | \ (((x) & 0x000000FFUL) << 24)) +#define ALIGN(value, align) (((value) + ((typeof(value))(align) - 1)) & ~((typeof(value))(align) - 1)) + + typedef volatile uint8_t io8_t; typedef volatile uint16_t io16_t; typedef volatile uint32_t io32_t; diff --git a/sw/riscv/src/usb.c b/sw/riscv/src/usb.c index bb66172..1e1dff6 100644 --- a/sw/riscv/src/usb.c +++ b/sw/riscv/src/usb.c @@ -1,6 +1,7 @@ #include "usb.h" #include "dma.h" #include "cfg.h" +#include "dd.h" static bool rx_byte (uint8_t *data) { @@ -60,9 +61,12 @@ static bool tx_word (uint32_t data) { } -#define USB_CMD_TOKEN (0x434D4400) -#define USB_CMP_TOKEN (0x434D5000) -#define USB_ERR_TOKEN (0x45525200) +#define USB_CMD_TOKEN (0x434D4400) +#define USB_CMP_TOKEN (0x434D5000) +#define USB_DMA_TOKEN (0x444D4100) +#define USB_ERR_TOKEN (0x45525200) + +#define DEBUG_ID_INTERNAL (0xFE) enum state { STATE_IDLE, @@ -70,6 +74,9 @@ enum state { STATE_DATA, STATE_RESPONSE, STATE_DEBUG_TX, + STATE_INTERNAL_DEBUG_TX_START, + STATE_INTERNAL_DEBUG_TX_DATA, + STATE_INTERNAL_DEBUG_TX_END, }; struct process { @@ -88,6 +95,13 @@ struct process { 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; }; static struct process p; @@ -154,6 +168,30 @@ void usb_debug_reset (void) { 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; +} + + static uint8_t rx_cmd_current_byte = 0; static uint32_t rx_cmd_buffer = 0; @@ -201,6 +239,7 @@ void usb_init (void) { p.state = STATE_IDLE; p.debug_rx_busy = false; p.debug_tx_busy = false; + p.internal_debug_tx_busy = false; rx_word_current_byte = 0; rx_word_buffer = 0; @@ -215,10 +254,7 @@ void process_usb (void) { switch (p.state) { case STATE_IDLE: - if (p.debug_tx_busy) { - p.state = STATE_DEBUG_TX; - p.dma_in_progress = false; - } else if (rx_cmd(&p.args[0])) { + if (rx_cmd(&p.args[0])) { if ((p.args[0] & 0xFFFFFF00) == USB_CMD_TOKEN) { p.cmd = p.args[0] & 0xFF; p.counter = 0; @@ -231,6 +267,13 @@ 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; } break; @@ -268,13 +311,20 @@ void process_usb (void) { case 'R': case 'W': + case 'S': if (!dma_busy()) { if (!p.dma_in_progress) { - enum dma_dir dir = p.cmd == 'W' ? DMA_DIR_TO_SDRAM : DMA_DIR_FROM_SDRAM; + bool is_write = (p.cmd == 'W') || (p.cmd == 'S'); + enum dma_dir dir = is_write ? DMA_DIR_TO_SDRAM : DMA_DIR_FROM_SDRAM; dma_start(p.args[0], p.args[1], DMA_ID_USB, dir); p.dma_in_progress = true; } else { - p.state = STATE_RESPONSE; + if (p.cmd == 'S') { + dd_set_block_ready(true); + p.state = STATE_IDLE; + } else { + p.state = STATE_RESPONSE; + } } } break; @@ -319,5 +369,39 @@ void process_usb (void) { } } 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; + } + } + 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; + break; } } diff --git a/sw/riscv/src/usb.h b/sw/riscv/src/usb.h index 28f3298..9b39757 100644 --- a/sw/riscv/src/usb.h +++ b/sw/riscv/src/usb.h @@ -5,12 +5,20 @@ #include "sys.h" +typedef enum { + INT_DBG_ID_IS_VIEWER = 0, + INT_DBG_ID_DD_BLOCK = 1, +} internal_debug_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); void usb_init (void); void process_usb (void);