[SC64][FW][SW] Added command to reconfigure FPGA from software (#10)

This commit is contained in:
Mateusz Faderewski 2021-10-29 00:19:17 +02:00 committed by GitHub
parent adff845460
commit d1bf99fdf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 268 additions and 11 deletions

View File

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

View File

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

View File

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

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<system name="$${FILENAME}">
<component
name="$${FILENAME}"
displayName="$${FILENAME}"
version="1.0"
description=""
tags="INTERNAL_COMPONENT=true"
categories="System" />
<parameter name="bonusData"><![CDATA[bonusData
{
element dual_boot_0
{
datum _sortIndex
{
value = "0";
type = "int";
}
}
}
]]></parameter>
<parameter name="clockCrossingAdapter" value="HANDSHAKE" />
<parameter name="device" value="10M08SCE144C8G" />
<parameter name="deviceFamily" value="MAX 10" />
<parameter name="deviceSpeedGrade" value="8" />
<parameter name="fabricMode" value="QSYS" />
<parameter name="generateLegacySim" value="false" />
<parameter name="generationId" value="0" />
<parameter name="globalResetBus" value="false" />
<parameter name="hdlLanguage" value="VERILOG" />
<parameter name="hideFromIPCatalog" value="true" />
<parameter name="lockedInterfaceDefinition" value="" />
<parameter name="maxAdditionalLatency" value="1" />
<parameter name="projectName" value="" />
<parameter name="sopcBorderPoints" value="false" />
<parameter name="systemHash" value="0" />
<parameter name="testBenchDutName" value="" />
<parameter name="timeStamp" value="0" />
<parameter name="useTestBenchNamingPattern" value="false" />
<instanceScript></instanceScript>
<interface name="avalon" internal="dual_boot_0.avalon" type="avalon" dir="end">
<port name="avmm_rcv_address" internal="avmm_rcv_address" />
<port name="avmm_rcv_read" internal="avmm_rcv_read" />
<port name="avmm_rcv_writedata" internal="avmm_rcv_writedata" />
<port name="avmm_rcv_write" internal="avmm_rcv_write" />
<port name="avmm_rcv_readdata" internal="avmm_rcv_readdata" />
</interface>
<interface name="clk" internal="dual_boot_0.clk" type="clock" dir="end">
<port name="clk" internal="clk" />
</interface>
<interface name="nreset" internal="dual_boot_0.nreset" type="reset" dir="end">
<port name="nreset" internal="nreset" />
</interface>
<module
name="dual_boot_0"
kind="altera_dual_boot"
version="20.1"
enabled="1"
autoexport="1">
<parameter name="CLOCK_FREQUENCY" value="50.0" />
<parameter name="INTENDED_DEVICE_FAMILY" value="MAX 10" />
</module>
<interconnectRequirement for="$system" name="qsys_mm.clockCrossingAdapter" value="HANDSHAKE" />
<interconnectRequirement for="$system" name="qsys_mm.enableEccProtection" value="FALSE" />
<interconnectRequirement for="$system" name="qsys_mm.insertDefaultSlave" value="FALSE" />
<interconnectRequirement for="$system" name="qsys_mm.maxAdditionalLatency" value="1" />
</system>

3
sw/pc/.gitignore vendored
View File

@ -6,4 +6,5 @@
*.z64
*.v64
*.data
*.bak
*.bak
*.bin

97
sw/pc/update.py Normal file
View File

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

View File

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

View File

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

View File

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