isv support + usb/dd improvements

This commit is contained in:
Polprzewodnikowy 2021-12-27 00:01:07 +01:00
parent 92e5c5747b
commit 4b888d0f71
18 changed files with 387 additions and 114 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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
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;

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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)

View File

@ -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}")

View File

@ -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))))

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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);

60
sw/riscv/src/isv.c Normal file
View File

@ -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;
}
}
}

14
sw/riscv/src/isv.h Normal file
View File

@ -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

View File

@ -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();

View File

@ -8,11 +8,14 @@
#include <stdbool.h>
#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;

View File

@ -1,6 +1,7 @@
#include "usb.h"
#include "dma.h"
#include "cfg.h"
#include "dd.h"
static bool rx_byte (uint8_t *data) {
@ -62,14 +63,20 @@ static bool tx_word (uint32_t data) {
#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,
STATE_ARGS,
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,15 +311,22 @@ 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 {
if (p.cmd == 'S') {
dd_set_block_ready(true);
p.state = STATE_IDLE;
} else {
p.state = STATE_RESPONSE;
}
}
}
break;
case 'D':
@ -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;
}
}

View File

@ -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);