diff --git a/fw/SummerCart64.qsf b/fw/SummerCart64.qsf index 4c1f698..2dfe7e3 100644 --- a/fw/SummerCart64.qsf +++ b/fw/SummerCart64.qsf @@ -19,7 +19,7 @@ # # Quartus Prime # Version 20.1.1 Build 720 11/11/2020 SJ Lite Edition -# Date created = 22:44:04 October 26, 2021 +# Date created = 23:38:22 October 28, 2021 # # -------------------------------------------------------------------------- # # @@ -46,13 +46,13 @@ set_global_assignment -name LAST_QUARTUS_VERSION "20.1.1 Lite Edition" set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL set_global_assignment -name FLOW_ENABLE_POWER_ANALYZER ON +set_global_assignment -name QSYS_FILE rtl/intel/config/intel_config.qsys set_global_assignment -name QSYS_FILE rtl/intel/flash/intel_flash.qsys set_global_assignment -name QSYS_FILE rtl/intel/snp/intel_snp.qsys set_global_assignment -name QIP_FILE rtl/intel/fifo/intel_fifo_8.qip set_global_assignment -name QIP_FILE rtl/intel/gpio/intel_gpio_ddro.qip set_global_assignment -name QIP_FILE rtl/intel/pll/intel_pll.qip set_global_assignment -name SDC_FILE SummerCart64.sdc -set_global_assignment -name SIGNALTAP_FILE stp.stp set_global_assignment -name SYSTEMVERILOG_FILE cpu/picorv32/picorv32.v set_global_assignment -name SYSTEMVERILOG_FILE ../sw/riscv/build/cpu_bootloader.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_bus.sv @@ -85,7 +85,6 @@ set_global_assignment -name SYSTEMVERILOG_FILE rtl/system/config.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/system/sc64.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/system/system.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/usb/usb_ft1248.sv -set_global_assignment -name SIGNALTAP_FILE output_files/signaltap.stp # Pin & Location Assignments # ========================== @@ -190,7 +189,7 @@ set_global_assignment -name TIMING_ANALYZER_MULTICORNER_ANALYSIS ON # Compiler Assignments # ==================== -set_global_assignment -name OPTIMIZATION_MODE BALANCED +set_global_assignment -name OPTIMIZATION_MODE "HIGH PERFORMANCE EFFORT" # Analysis & Synthesis Assignments # ================================ @@ -221,10 +220,6 @@ set_global_assignment -name ENABLE_OCT_DONE OFF set_global_assignment -name EXTERNAL_FLASH_FALLBACK_ADDRESS 00000000 set_global_assignment -name USE_CONFIGURATION_DEVICE OFF -# Signal Tap Assignments -# ====================== -set_global_assignment -name ENABLE_SIGNALTAP ON - # Power Estimation Assignments # ============================ set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "NO HEAT SINK WITH STILL AIR" @@ -303,6 +298,7 @@ set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" - set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top + set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top # end DESIGN_PARTITION(Top) # ------------------------- diff --git a/fw/SummerCart64.sdc b/fw/SummerCart64.sdc index 15d2550..832c580 100644 --- a/fw/SummerCart64.sdc +++ b/fw/SummerCart64.sdc @@ -10,6 +10,11 @@ create_generated_clock -name sdram_clk -source [get_pins $sdram_pll_clk] [get_po # create_generated_clock -name sd_reg_clk -source [get_pins {sd_interface_inst|sd_clk_inst|o_sd_clk|clk}] -divide_by 2 [get_pins $sd_reg_clk] # create_generated_clock -name sd_clk -source [get_pins $sd_reg_clk] [get_ports {o_sd_clk}] +create_generated_clock -name config_clk \ + -source [get_pins {cpu_soc_inst|cpu_cfg_inst|reconfig_clk|clk}] \ + -divide_by 2 \ + [get_pins {cpu_soc_inst|cpu_cfg_inst|reconfig_clk|q}] + create_generated_clock -name flash_se_neg_reg \ -source [get_pins -compatibility_mode {*altera_onchip_flash:*onchip_flash_0|altera_onchip_flash_avmm_data_controller:avmm_data_controller|flash_se_neg_reg|clk}] \ -divide_by 2 \ diff --git a/fw/rtl/cpu/cpu_cfg.sv b/fw/rtl/cpu/cpu_cfg.sv index 275ab66..da2f0c1 100644 --- a/fw/rtl/cpu/cpu_cfg.sv +++ b/fw/rtl/cpu/cpu_cfg.sv @@ -5,6 +5,7 @@ module cpu_cfg ( ); logic skip_bootloader; + logic trigger_reconfiguration; typedef enum bit [2:0] { R_SCR, @@ -13,9 +14,12 @@ module cpu_cfg ( R_COMMAND, R_DATA_0, R_DATA_1, - R_VERSION + R_VERSION, + R_RECONFIGURE } e_reg_id; + const logic [31:0] RECONFIGURE_MAGIC = 32'h52535446; + always_ff @(posedge sys.clk) begin bus.ack <= 1'b0; if (bus.request) begin @@ -47,6 +51,7 @@ module cpu_cfg ( R_DATA_0: bus.rdata = cfg.data[0]; R_DATA_1: bus.rdata = cfg.data[1]; R_VERSION: bus.rdata = sc64::SC64_VER; + R_RECONFIGURE: bus.rdata = {31'd0, trigger_reconfiguration}; default: bus.rdata = 32'd0; endcase end @@ -75,6 +80,7 @@ module cpu_cfg ( cfg.dd_offset <= 26'h3BE_0000; cfg.save_offset <= 26'h3FE_0000; skip_bootloader <= 1'b0; + trigger_reconfiguration <= 1'b0; end else begin if (sys.n64_soft_reset) begin cfg.sdram_switch <= skip_bootloader; @@ -117,9 +123,51 @@ module cpu_cfg ( cfg.save_offset <= bus.wdata[25:0]; end end + + R_RECONFIGURE: begin + if (&bus.wmask && bus.wdata == RECONFIGURE_MAGIC) begin + trigger_reconfiguration <= 1'b1; + end + end endcase end end end + logic reconfig_clk; + logic reconfig_write; + logic [31:0] reconfig_rdata; + logic reconfig_write_done; + + const logic [31:0] TRIGGER_RECONFIGURATION = 32'h00000001; + + always_ff @(posedge sys.clk) begin + if (sys.reset) begin + reconfig_clk <= 1'b0; + reconfig_write <= 1'b0; + reconfig_write_done <= 1'b0; + end else begin + reconfig_clk <= ~reconfig_clk; + + if (!reconfig_clk) begin + reconfig_write <= 1'b0; + + if (trigger_reconfiguration && !reconfig_write_done) begin + reconfig_write <= 1'b1; + reconfig_write_done <= 1'b1; + end + end + end + end + + intel_config intel_config_inst ( + .clk(reconfig_clk), + .nreset(~sys.reset), + .avmm_rcv_address(3'd0), + .avmm_rcv_read(1'b0), + .avmm_rcv_writedata(TRIGGER_RECONFIGURATION), + .avmm_rcv_write(reconfig_write), + .avmm_rcv_readdata(reconfig_rdata) + ); + endmodule diff --git a/fw/rtl/intel/config/intel_config.qsys b/fw/rtl/intel/config/intel_config.qsys new file mode 100644 index 0000000..f61edb1 --- /dev/null +++ b/fw/rtl/intel/config/intel_config.qsys @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sw/pc/.gitignore b/sw/pc/.gitignore index 8fe0e3f..e393a9a 100644 --- a/sw/pc/.gitignore +++ b/sw/pc/.gitignore @@ -6,4 +6,5 @@ *.z64 *.v64 *.data -*.bak \ No newline at end of file +*.bak +*.bin diff --git a/sw/pc/update.py b/sw/pc/update.py new file mode 100644 index 0000000..1432798 --- /dev/null +++ b/sw/pc/update.py @@ -0,0 +1,97 @@ +import os +import serial +import time +import filecmp + + + +class SC64: + __CFG_ID_FLASH_OPERATION = 10 + __CFG_ID_RECONFIGURE = 11 + + + def __init__(self, port): + self.__serial = serial.Serial(port) + + + def __query_config(self, query, arg=0): + self.__serial.write(b'CMDQ') + self.__serial.write(query.to_bytes(4, byteorder='big')) + self.__serial.write(arg.to_bytes(4, byteorder='big')) + value = self.__serial.read(4) + if (self.__serial.read(4).decode() != 'CMPQ'): + raise Exception('Bad query response') + return int.from_bytes(value, byteorder='big') + + + def __change_config(self, change, arg=0, ignore_response=False): + self.__serial.write(b'CMDC') + self.__serial.write(change.to_bytes(4, byteorder='big')) + self.__serial.write(arg.to_bytes(4, byteorder='big')) + if (not ignore_response and self.__serial.read(4).decode() != 'CMPC'): + raise Exception('Bad change response') + + + def reconfigure(self): + magic = self.__query_config(self.__CFG_ID_RECONFIGURE) + self.__change_config(self.__CFG_ID_RECONFIGURE, magic, ignore_response=True) + time.sleep(1) + + + def read_flash(self, file): + size = self.__query_config(self.__CFG_ID_FLASH_OPERATION) + print('Flash size: {:08X}'.format(size)) + self.__serial.write(b'CMDR') + self.__serial.write((0).to_bytes(4, byteorder='big')) + self.__serial.write((size).to_bytes(4, byteorder='big')) + flash = self.__serial.read(size) + response = self.__serial.read(4) + if (response.decode() == 'CMPR'): + with open(file, 'wb') as f: + f.write(flash) + else: + raise Exception('There was a problem while reading flash data') + + + def program_flash(self, file): + length = os.path.getsize(file) + offset = 0 + with open(file, 'rb') as f: + self.__serial.write(b'CMDW') + self.__serial.write(offset.to_bytes(4, byteorder='big')) + self.__serial.write(length.to_bytes(4, byteorder='big')) + self.__serial.write(f.read()) + response = self.__serial.read(4) + if (response.decode() != 'CMPW'): + raise Exception('There was a problem while sending flash data') + self.__change_config(self.__CFG_ID_FLASH_OPERATION) + + + +file = '../../fw/output_files/SC64_update.bin' +backup_file = 'SC64_backup.bin' +verify_file = 'SC64_update_verify.bin' +port = 'COM7' + +sc64 = SC64(port) + +print('Making backup...') +sc64.read_flash(backup_file) +print('done\n') + +print('Flashing... ') +sc64.program_flash(file) +print('done\n') + +print('Reconfiguring... ') +sc64.reconfigure() +print('done\n') + +print('Verifying... ') +sc64.read_flash(verify_file) +if (filecmp.cmp(file, verify_file)): + print('success!\n') +else: + print('failure.\n') + +print('Update done!') diff --git a/sw/riscv/src/cfg.c b/sw/riscv/src/cfg.c index cc5d8d8..0889df0 100644 --- a/sw/riscv/src/cfg.c +++ b/sw/riscv/src/cfg.c @@ -28,6 +28,7 @@ enum cfg_id { CFG_ID_DD_OFFEST, CFG_ID_SKIP_BOOTLOADER, CFG_ID_FLASH_OPERATION, + CFG_ID_RECONFIGURE, }; enum save_type { @@ -137,6 +138,14 @@ void cfg_update (uint32_t *args) { case CFG_ID_FLASH_OPERATION: flash_program(args[1]); break; + case CFG_ID_RECONFIGURE: + if (args[1] == CFG_RECONFIGURE_MAGIC) { + CFG->RECONFIGURE = CFG_RECONFIGURE_MAGIC; + __asm__ volatile ( + "ebreak \n" + ); + } + break; } } @@ -175,6 +184,9 @@ void cfg_query (uint32_t *args) { case CFG_ID_FLASH_OPERATION: args[1] = flash_read(args[1]); break; + case CFG_ID_RECONFIGURE: + args[1] = CFG_RECONFIGURE_MAGIC; + break; } } diff --git a/sw/riscv/src/sys.h b/sw/riscv/src/sys.h index 4d1e7e6..728a894 100644 --- a/sw/riscv/src/sys.h +++ b/sw/riscv/src/sys.h @@ -96,6 +96,8 @@ typedef volatile struct cfg_regs { io8_t CMD; io8_t __padding[3]; io32_t DATA[2]; + io32_t VERSION; + io32_t RECONFIGURE; } cfg_regs_t; #define CFG_BASE (0x70000000UL) @@ -113,6 +115,8 @@ typedef volatile struct cfg_regs { #define CFG_SCR_CPU_BUSY (1 << 30) #define CFG_SCR_CPU_READY (1 << 31) +#define CFG_RECONFIGURE_MAGIC (0x52535446) + #define SDRAM_BASE (0x80000000UL) #define SDRAM (*((io32_t *) SDRAM_BASE)) diff --git a/sw/riscv/src/usb.c b/sw/riscv/src/usb.c index 49f1730..7c09afb 100644 --- a/sw/riscv/src/usb.c +++ b/sw/riscv/src/usb.c @@ -153,6 +153,33 @@ void usb_debug_reset (void) { } +static bool rx_cmd (uint32_t *data) { + static uint8_t current_byte = 0; + static uint32_t buffer = 0; + uint8_t tmp; + + while (rx_byte(&tmp)) { + current_byte += 1; + if ((current_byte != 4) && (tmp != (USB_CMD_TOKEN >> (8 * (4 - current_byte)) & 0xFF))) { + current_byte = 0; + buffer = 0; + + return false; + } + buffer = (buffer << 8) | tmp; + if (current_byte == 4) { + current_byte = 0; + *data = buffer; + buffer = 0; + + return true; + } + } + + return false; +} + + void usb_init (void) { USB->SCR = USB_SCR_FLUSH_TX | USB_SCR_FLUSH_RX; @@ -168,7 +195,7 @@ void process_usb (void) { if (p.debug_tx_busy) { p.state = STATE_DEBUG_TX; p.dma_in_progress = false; - } else if (rx_word(&p.args[0])) { + } else if (rx_cmd(&p.args[0])) { if ((p.args[0] & 0xFFFFFF00) == USB_CMD_TOKEN) { p.cmd = p.args[0] & 0xFF; p.counter = 0;