From adff84546055f44fbd0425c0a3d8a66a3027778c Mon Sep 17 00:00:00 2001 From: Mateusz Faderewski Date: Tue, 26 Oct 2021 23:44:09 +0200 Subject: [PATCH] [SC64][FW][SW] Load CPU software directly from embedded flash in FPGA (#9) --- build.sh | 10 ++- build_in_docker.sh | 5 +- fw/SummerCart64.cof | 42 ++++++++++ fw/SummerCart64.qsf | 7 +- fw/build.sh | 12 ++- fw/rtl/SummerCart64.sv | 4 + fw/rtl/cpu/cpu_cfg.sv | 6 +- fw/rtl/cpu/cpu_flash.sv | 61 ++++++++++++++ fw/rtl/cpu/cpu_soc.sv | 7 ++ fw/rtl/intel/flash/intel_flash.qsys | 34 +++++--- fw/rtl/memory/memory_flash.sv | 76 ----------------- fw/rtl/n64/n64_bootloader.sv | 124 ++++++++++++++++++++++++++-- fw/rtl/n64/n64_cfg.sv | 2 +- fw/rtl/n64/n64_soc.sv | 4 +- fw/rtl/system/config.sv | 3 - fw/rtl/system/sc64.sv | 1 + sw/n64/.gitignore | 2 +- sw/n64/Makefile | 77 ++++------------- sw/n64/build.sh | 5 +- sw/n64/src/{boot => }/boot.c | 0 sw/n64/src/{boot => }/boot.h | 0 sw/n64/src/{boot => }/crc32.c | 0 sw/n64/src/{boot => }/crc32.h | 0 sw/n64/src/main.c | 2 +- sw/n64/src/{boot => }/n64_regs.h | 0 sw/riscv/Makefile | 1 + sw/riscv/build.sh | 5 +- sw/riscv/src/cfg.c | 8 ++ sw/riscv/src/flash.c | 60 ++++++++++++++ sw/riscv/src/flash.h | 12 +++ sw/riscv/src/handlers.c | 41 ++------- sw/riscv/src/sys.h | 33 ++++++++ sw/riscv/src/uart.c | 5 +- sw/riscv/src/usb.c | 7 +- 34 files changed, 442 insertions(+), 214 deletions(-) create mode 100644 fw/SummerCart64.cof create mode 100644 fw/rtl/cpu/cpu_flash.sv delete mode 100644 fw/rtl/memory/memory_flash.sv rename sw/n64/src/{boot => }/boot.c (100%) rename sw/n64/src/{boot => }/boot.h (100%) rename sw/n64/src/{boot => }/crc32.c (100%) rename sw/n64/src/{boot => }/crc32.h (100%) rename sw/n64/src/{boot => }/n64_regs.h (100%) create mode 100644 sw/riscv/src/flash.c create mode 100644 sw/riscv/src/flash.h diff --git a/build.sh b/build.sh index d5c8053..cc036aa 100755 --- a/build.sh +++ b/build.sh @@ -3,10 +3,10 @@ PACKAGE_FILE_NAME="SummerCart64" FILES=( - "./fw/output_files/SummerCart64.pof" - "./hw/v1/ftdi-template.xml" + "./fw/output_files/SC64_update.bin" + "./fw/output_files/SC64_update.pof" + "./hw/ftdi-template.xml" "./sw/cic/UltraCIC-III.hex" - "./sw/riscv/build/controller.rom" "./LICENSE" ) @@ -35,6 +35,10 @@ popd pushd fw echo "Building FPGA firmware" quartus_sh --flow compile ./SummerCart64.qpf +quartus_cpf -c ./SummerCart64.cof +cp output_files/SC64_firmware.pof output_files/SC64_update.pof +cat output_files/sc64_firmware_ufm_auto.rpd output_files/sc64_firmware_cfm0_auto.rpd > output_files/SC64_update_LE.bin +riscv32-unknown-elf-objcopy -I binary -O binary --reverse-bytes=4 output_files/SC64_update_LE.bin output_files/SC64_update.bin popd diff --git a/build_in_docker.sh b/build_in_docker.sh index 7405b54..dded6f2 100755 --- a/build_in_docker.sh +++ b/build_in_docker.sh @@ -1,3 +1,6 @@ #!/bin/bash -docker run --mount type=bind,src="$(pwd)",target="/workdir" ghcr.io/polprzewodnikowy/sc64env:v1.0 /bin/bash ./build.sh +docker run \ + --mount type=bind,src="$(pwd)",target="/workdir" \ + ghcr.io/polprzewodnikowy/sc64env:v1.0 \ + /bin/bash -c "./build.sh" diff --git a/fw/SummerCart64.cof b/fw/SummerCart64.cof new file mode 100644 index 0000000..bf1be85 --- /dev/null +++ b/fw/SummerCart64.cof @@ -0,0 +1,42 @@ + + + output_files/SC64_firmware.pof + 1 + 1 + 14 + + Page_0 + 1 + + output_files/SummerCart64.sof1 + + + 10 + 0 + 0 + 1 + 0 + + 1 + + + 0 + 1 + 0 + 0 + 0 + 0 + 2 + ../sw/n64/build/SummerLoader64.hex + ../sw/riscv/build/controller.hex + 305152 + + + 1 + 2 + 0 + -1 + -1 + 1 + + \ No newline at end of file diff --git a/fw/SummerCart64.qsf b/fw/SummerCart64.qsf index 1987b3c..4c1f698 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 = 21:23:28 September 18, 2021 +# Date created = 22:44:04 October 26, 2021 # # -------------------------------------------------------------------------- # # @@ -58,6 +58,7 @@ set_global_assignment -name SYSTEMVERILOG_FILE ../sw/riscv/build/cpu_bootloader. set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_bus.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_cfg.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_dma.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_flash.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_flashram.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_gpio.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_i2c.sv @@ -68,7 +69,6 @@ set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_soc.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_uart.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_usb.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu/cpu_wrapper.sv -set_global_assignment -name SYSTEMVERILOG_FILE rtl/memory/memory_flash.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/memory/memory_sdram.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/n64/n64_bootloader.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/n64/n64_bus.sv @@ -86,7 +86,6 @@ 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 -set_global_assignment -name SLD_FILE db/signaltap_auto_stripped.stp # Pin & Location Assignments # ========================== @@ -225,7 +224,6 @@ set_global_assignment -name USE_CONFIGURATION_DEVICE OFF # Signal Tap Assignments # ====================== set_global_assignment -name ENABLE_SIGNALTAP ON -set_global_assignment -name USE_SIGNALTAP_FILE output_files/signaltap.stp # Power Estimation Assignments # ============================ @@ -305,7 +303,6 @@ 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/build.sh b/fw/build.sh index 4c1b7c8..c30bed2 100755 --- a/fw/build.sh +++ b/fw/build.sh @@ -1,3 +1,13 @@ #!/bin/bash -docker run --mount type=bind,src="$(pwd)/..",target="/workdir" ghcr.io/polprzewodnikowy/sc64env:v1.0 /bin/bash -c "cd fw && quartus_sh --flow compile ./SummerCart64.qpf" +docker run \ + --mount type=bind,src="$(pwd)/..",target="/workdir" \ + ghcr.io/polprzewodnikowy/sc64env:v1.0 \ + /bin/bash -c " \ + cd fw && \ + quartus_sh --flow compile ./SummerCart64.qpf && \ + quartus_cpf -c ./SummerCart64.cof && \ + cp output_files/SC64_firmware.pof output_files/SC64_update.pof && \ + cat output_files/sc64_firmware_ufm_auto.rpd output_files/sc64_firmware_cfm0_auto.rpd > output_files/SC64_update_LE.bin && \ + riscv32-unknown-elf-objcopy -I binary -O binary --reverse-bytes=4 output_files/SC64_update_LE.bin output_files/SC64_update.bin + " diff --git a/fw/rtl/SummerCart64.sv b/fw/rtl/SummerCart64.sv index 0474b97..48eea35 100644 --- a/fw/rtl/SummerCart64.sv +++ b/fw/rtl/SummerCart64.sv @@ -64,6 +64,8 @@ module SummerCart64 ( if_si si (); + if_flash flash (); + system system_inst ( .sys(sys) ); @@ -81,6 +83,7 @@ module SummerCart64 ( .sdram(sdram), .flashram(flashram), .si(si), + .flash(flash), .n64_pi_alel(i_n64_pi_alel), .n64_pi_aleh(i_n64_pi_aleh), @@ -107,6 +110,7 @@ module SummerCart64 ( .sdram(sdram), .flashram(flashram), .si(si), + .flash(flash), .gpio_o(gpio_o), .gpio_i(gpio_i), diff --git a/fw/rtl/cpu/cpu_cfg.sv b/fw/rtl/cpu/cpu_cfg.sv index 426b1b9..275ab66 100644 --- a/fw/rtl/cpu/cpu_cfg.sv +++ b/fw/rtl/cpu/cpu_cfg.sv @@ -30,7 +30,7 @@ module cpu_cfg ( R_SCR: bus.rdata = { cfg.cpu_ready, cfg.cpu_busy, - cfg.usb_waiting, + 1'b0, cfg.cmd_error, 21'd0, skip_bootloader, @@ -65,7 +65,6 @@ module cpu_cfg ( if (sys.reset) begin cfg.cpu_ready <= 1'b0; cfg.cpu_busy <= 1'b0; - cfg.usb_waiting <= 1'b0; cfg.cmd_error <= 1'b0; cfg.sdram_switch <= 1'b0; cfg.sdram_writable <= 1'b0; @@ -91,9 +90,8 @@ module cpu_cfg ( { cfg.cpu_ready, cfg.cpu_busy, - cfg.usb_waiting, cfg.cmd_error - } <= bus.wdata[31:28]; + } <= {bus.wdata[31:30], bus.wdata[28]}; end if (bus.wmask[0]) begin { diff --git a/fw/rtl/cpu/cpu_flash.sv b/fw/rtl/cpu/cpu_flash.sv new file mode 100644 index 0000000..a7c3b6f --- /dev/null +++ b/fw/rtl/cpu/cpu_flash.sv @@ -0,0 +1,61 @@ +interface if_flash (); + + logic request; + logic ack; + logic write; + logic [31:0] address; + logic [31:0] rdata; + logic [31:0] wdata; + + modport cpu ( + output request, + input ack, + output write, + output address, + input rdata, + output wdata + ); + + modport memory ( + input request, + output ack, + input write, + input address, + output rdata, + input wdata + ); + +endinterface + + +module cpu_flash ( + if_system.sys sys, + if_cpu_bus bus, + if_flash.cpu flash +); + + logic request; + + always_comb begin + bus.ack = flash.ack; + bus.rdata = flash.rdata; + flash.request = bus.request || request; + flash.write = &bus.wmask; + flash.address = bus.address; + flash.wdata = bus.wdata; + end + + always_ff @(posedge sys.clk) begin + if (sys.reset) begin + request <= 1'b0; + end else begin + if (bus.request) begin + request <= 1'b1; + end + if (flash.ack) begin + request <= 1'b0; + end + end + end + +endmodule diff --git a/fw/rtl/cpu/cpu_soc.sv b/fw/rtl/cpu/cpu_soc.sv index 5a9303a..69b4050 100644 --- a/fw/rtl/cpu/cpu_soc.sv +++ b/fw/rtl/cpu/cpu_soc.sv @@ -5,6 +5,7 @@ module cpu_soc ( if_sdram.cpu sdram, if_flashram.cpu flashram, if_si.cpu si, + if_flash.cpu flash, input [7:0] gpio_i, output [7:0] gpio_o, @@ -111,4 +112,10 @@ module cpu_soc ( .si(si) ); + cpu_flash cpu_flash_inst ( + .sys(sys), + .bus(bus.at[sc64::ID_CPU_FLASH].device), + .flash(flash) + ); + endmodule diff --git a/fw/rtl/intel/flash/intel_flash.qsys b/fw/rtl/intel/flash/intel_flash.qsys index 9aca588..ffe595d 100644 --- a/fw/rtl/intel/flash/intel_flash.qsys +++ b/fw/rtl/intel/flash/intel_flash.qsys @@ -7,17 +7,17 @@ description="" tags="INTERNAL_COMPONENT=true" categories="System" /> - @@ -41,10 +41,18 @@ - + + + + + + + + + @@ -68,7 +76,7 @@ - Read only,Read only,Hidden,Read only,Read only + Read and write,Read and write,Hidden,Read and write,Read and write $${FILENAME}_onchip_flash_0 ../sw/n64/build/SummerLoader64.hex diff --git a/fw/rtl/memory/memory_flash.sv b/fw/rtl/memory/memory_flash.sv deleted file mode 100644 index 2aefc25..0000000 --- a/fw/rtl/memory/memory_flash.sv +++ /dev/null @@ -1,76 +0,0 @@ -module memory_flash ( - if_system.sys sys, - - input request, - output ack, - input [31:0] address, - output [15:0] rdata -); - - logic flash_enable; - logic flash_request; - logic flash_busy; - logic flash_ack; - logic [31:0] flash_rdata; - - logic dummy_ack; - - always_comb begin - flash_enable = address < 32'h10016800; - - ack = flash_ack | dummy_ack; - - rdata = 16'd0; - if (ack && flash_enable) begin - if (address[1]) rdata = {flash_rdata[23:16], flash_rdata[31:24]}; - else rdata = {flash_rdata[7:0], flash_rdata[15:8]}; - end - end - - typedef enum bit [0:0] { - S_IDLE, - S_WAIT - } e_state; - - e_state state; - - always_ff @(posedge sys.clk) begin - dummy_ack <= 1'b0; - - if (sys.reset) begin - state <= S_IDLE; - flash_request <= 1'b0; - end else begin - case (state) - S_IDLE: begin - if (request) begin - state <= S_WAIT; - flash_request <= flash_enable; - dummy_ack <= !flash_enable; - end - end - - S_WAIT: begin - if (!flash_busy) begin - flash_request <= 1'b0; - end - if (ack) begin - state <= S_IDLE; - end - end - endcase - end - end - - intel_flash intel_flash_inst ( - .clock(sys.clk), - .reset_n(~sys.reset), - .avmm_data_addr(address[31:2]), - .avmm_data_read(flash_request), - .avmm_data_readdata(flash_rdata), - .avmm_data_waitrequest(flash_busy), - .avmm_data_readdatavalid(flash_ack), - .avmm_data_burstcount(2'd1) - ); - -endmodule diff --git a/fw/rtl/n64/n64_bootloader.sv b/fw/rtl/n64/n64_bootloader.sv index 2967a31..0f5942e 100644 --- a/fw/rtl/n64/n64_bootloader.sv +++ b/fw/rtl/n64/n64_bootloader.sv @@ -1,14 +1,124 @@ module n64_bootloader ( if_system.sys sys, - if_n64_bus bus + if_n64_bus bus, + if_flash.memory flash ); - memory_flash memory_flash_inst ( - .sys(sys), - .request(bus.request), - .ack(bus.ack), - .address(bus.address), - .rdata(bus.rdata) + logic mem_request; + logic csr_ack; + logic data_ack; + logic write_ack; + logic data_busy; + logic mem_write; + logic [31:0] mem_address; + logic [31:0] csr_rdata; + logic [31:0] data_rdata; + logic [31:0] mem_wdata; + + typedef enum bit [0:0] { + S_IDLE, + S_WAIT + } e_state; + + typedef enum bit [0:0] { + T_N64, + T_CPU + } e_source_request; + + e_state state; + e_source_request source_request; + + always_ff @(posedge sys.clk) begin + csr_ack <= 1'b0; + write_ack <= 1'b0; + + if (sys.reset) begin + state <= S_IDLE; + mem_request <= 1'b0; + end else begin + case (state) + S_IDLE: begin + if (bus.request || flash.request) begin + state <= S_WAIT; + mem_request <= 1'b1; + if (bus.request) begin + mem_write <= 1'b0; + mem_address <= bus.address; + mem_wdata <= bus.wdata; + source_request <= T_N64; + end else if (flash.request) begin + mem_write <= flash.write; + mem_address <= flash.address; + mem_wdata <= flash.wdata; + source_request <= T_CPU; + end + end + end + + S_WAIT: begin + if (mem_address[27] && source_request != T_N64 && !csr_ack) begin + mem_request <= 1'b0; + csr_ack <= 1'b1; + end + if ((!mem_address[27] || source_request == T_N64) && !data_busy) begin + mem_request <= 1'b0; + end + if (!mem_address[27] && mem_write && !data_busy && !write_ack) begin + write_ack <= 1'b1; + end + if (csr_ack || data_ack || write_ack) begin + state <= S_IDLE; + end + end + endcase + end + end + + logic csr_or_data; + logic csr_read; + logic csr_write; + logic data_read; + logic data_write; + + always_comb begin + csr_or_data = mem_address[27] && source_request == T_CPU; + csr_read = csr_or_data && mem_request && !mem_write; + csr_write = csr_or_data && mem_request && mem_write; + data_read = !csr_or_data && mem_request && !mem_write; + data_write = !csr_or_data && mem_request && mem_write; + + bus.ack = source_request == T_N64 && data_ack; + bus.rdata = 16'd0; + if (bus.ack && bus.address >= 32'h10000000 && bus.address < 32'h10016800) begin + if (bus.address[1]) bus.rdata = {data_rdata[23:16], data_rdata[31:24]}; + else bus.rdata = {data_rdata[7:0], data_rdata[15:8]}; + end + + flash.ack = source_request == T_CPU && (csr_ack || data_ack || write_ack); + flash.rdata = 32'd0; + if (flash.ack) begin + flash.rdata = csr_or_data ? csr_rdata : data_rdata; + end + end + + intel_flash intel_flash_inst ( + .clock(sys.clk), + .reset_n(~sys.reset), + + .avmm_csr_addr(mem_address[2]), + .avmm_csr_read(csr_read), + .avmm_csr_writedata(mem_wdata), + .avmm_csr_write(csr_write), + .avmm_csr_readdata(csr_rdata), + + .avmm_data_addr(mem_address[31:2]), + .avmm_data_read(data_read), + .avmm_data_writedata(mem_wdata), + .avmm_data_write(data_write), + .avmm_data_readdata(data_rdata), + .avmm_data_waitrequest(data_busy), + .avmm_data_readdatavalid(data_ack), + .avmm_data_burstcount(2'd1) ); endmodule diff --git a/fw/rtl/n64/n64_cfg.sv b/fw/rtl/n64/n64_cfg.sv index 49d6023..486d343 100644 --- a/fw/rtl/n64/n64_cfg.sv +++ b/fw/rtl/n64/n64_cfg.sv @@ -29,7 +29,7 @@ module n64_cfg ( R_SR: bus.rdata = { cfg.cpu_ready, cfg.cpu_busy, - cfg.usb_waiting, + 1'b0, cfg.cmd_error, 12'd0 }; diff --git a/fw/rtl/n64/n64_soc.sv b/fw/rtl/n64/n64_soc.sv index 1f38904..4e6c5a3 100644 --- a/fw/rtl/n64/n64_soc.sv +++ b/fw/rtl/n64/n64_soc.sv @@ -5,6 +5,7 @@ module n64_soc ( if_sdram.memory sdram, if_flashram.flashram flashram, if_si.si si, + if_flash.memory flash, input n64_pi_alel, input n64_pi_aleh, @@ -63,7 +64,8 @@ module n64_soc ( n64_bootloader n64_bootloader_inst ( .sys(sys), - .bus(bus.at[sc64::ID_N64_BOOTLOADER].device) + .bus(bus.at[sc64::ID_N64_BOOTLOADER].device), + .flash(flash) ); n64_flashram n64_flashram_inst ( diff --git a/fw/rtl/system/config.sv b/fw/rtl/system/config.sv index fa4b8e3..42e4820 100644 --- a/fw/rtl/system/config.sv +++ b/fw/rtl/system/config.sv @@ -2,7 +2,6 @@ interface if_config (); logic cpu_ready; logic cpu_busy; - logic usb_waiting; logic cmd_error; logic cmd_request; logic [7:0] cmd; @@ -38,7 +37,6 @@ interface if_config (); modport n64 ( input cpu_ready, input cpu_busy, - input usb_waiting, input cmd_error, output cmd_request, output cmd, @@ -50,7 +48,6 @@ interface if_config (); modport cpu ( output cpu_ready, output cpu_busy, - output usb_waiting, output cmd_error, input cmd_request, input cmd, diff --git a/fw/rtl/system/sc64.sv b/fw/rtl/system/sc64.sv index 9044d52..e8ddb03 100644 --- a/fw/rtl/system/sc64.sv +++ b/fw/rtl/system/sc64.sv @@ -21,6 +21,7 @@ package sc64; ID_CPU_SDRAM, ID_CPU_FLASHRAM, ID_CPU_SI, + ID_CPU_FLASH, __ID_CPU_END } e_cpu_id; diff --git a/sw/n64/.gitignore b/sw/n64/.gitignore index e53d106..23dcf96 100644 --- a/sw/n64/.gitignore +++ b/sw/n64/.gitignore @@ -1,2 +1,2 @@ /build -/what \ No newline at end of file +*.z64 diff --git a/sw/n64/Makefile b/sw/n64/Makefile index f835a6f..8b384cc 100644 --- a/sw/n64/Makefile +++ b/sw/n64/Makefile @@ -1,69 +1,28 @@ -ROOTDIR = $(N64_INST) - -GCCN64PREFIX = $(ROOTDIR)/bin/mips64-elf- -CC = $(GCCN64PREFIX)gcc -AS = $(GCCN64PREFIX)as -LD = $(GCCN64PREFIX)ld -OBJCOPY = $(GCCN64PREFIX)objcopy -OBJDUMP = $(GCCN64PREFIX)objdump - -CHKSUM64 = $(ROOTDIR)/bin/chksum64 -MKSPRITE = $(ROOTDIR)/bin/mksprite -N64TOOL = $(ROOTDIR)/bin/n64tool - -HEADER_PATH = $(ROOTDIR)/mips64-elf/lib -HEADER_NAME = header - -PROG_NAME = SummerLoader64 - -ROM_SIZE = 1028k - -SOURCE_DIR = src BUILD_DIR = build +SOURCE_DIR = src +PROGRAM_NAME = SummerLoader64 -SRC_DIRS = $(SOURCE_DIR) $(sort $(dir $(wildcard $(SOURCE_DIR)/*/.))) -INC_DIRS = $(addprefix -I, . $(SRC_DIRS)) -I./libsc64/inc -SRC_FILES = $(wildcard $(patsubst %, %/*.c, . $(SRC_DIRS))) -# IMG_FILES = $(wildcard $(patsubst %, %/*.png, . $(SRC_DIRS))) -OBJ_FILES = $(addprefix $(BUILD_DIR)/, $(notdir $(IMG_FILES:.png=.o) $(SRC_FILES:.c=.o))) +include $(N64_INST)/include/n64.mk -VPATH = $(SRC_DIRS) +src = main.c sc64.c boot.c crc32.c -COMMONFLAGS = -march=vr4300 -mtune=vr4300 -ASFLAGS = $(COMMONFLAGS) -CFLAGS = $(COMMONFLAGS) -std=gnu11 -Os -Wall -I$(ROOTDIR)/mips64-elf/include $(INC_DIRS) -ffunction-sections -fdata-sections -Wl,--gc-sections -LINK_FLAGS = -L$(ROOTDIR)/mips64-elf/lib -ldragon -lc -lm -ldragonsys -Tn64.ld -#-L./libsc64/lib -lsc64_libdragon -N64_FLAGS = -l $(ROM_SIZE) -h $(HEADER_PATH)/$(HEADER_NAME) -o $(BUILD_DIR)/$(PROG_NAME).z64 +all: $(BUILD_DIR)/$(PROGRAM_NAME).hex -all: make_output_dir $(BUILD_DIR)/$(PROG_NAME).z64 +$(BUILD_DIR)/$(PROGRAM_NAME).elf: $(src:%.c=$(BUILD_DIR)/%.o) -$(OBJ_FILES): Makefile +$(PROGRAM_NAME).z64: N64_ROM_TITLE="$(PROGRAM_NAME)" -$(BUILD_DIR)/$(PROG_NAME).z64: $(BUILD_DIR)/$(PROG_NAME).elf - $(OBJCOPY) $(BUILD_DIR)/$(PROG_NAME).elf $(BUILD_DIR)/$(PROG_NAME).bin -O binary - $(OBJDUMP) -S $(BUILD_DIR)/$(PROG_NAME).elf > $(BUILD_DIR)/$(PROG_NAME).lst - $(N64TOOL) $(N64_FLAGS) -t $(PROG_NAME) $(BUILD_DIR)/$(PROG_NAME).bin - $(CHKSUM64) $(BUILD_DIR)/$(PROG_NAME).z64 - truncate --size=90k $(BUILD_DIR)/$(PROG_NAME).z64 - $(OBJCOPY) $(BUILD_DIR)/$(PROG_NAME).z64 $(BUILD_DIR)/$(PROG_NAME).hex -I binary -O ihex - -$(BUILD_DIR)/$(PROG_NAME).elf: $(OBJ_FILES) - $(LD) -o $(BUILD_DIR)/$(PROG_NAME).elf $(OBJ_FILES) $(LINK_FLAGS) - -$(BUILD_DIR)/%.o: %.c - $(COMPILE.c) $(OUTPUT_OPTION) $< - -# $(BUILD_DIR)/%.sprite: $(IMG_FILES) -# $(MKSPRITE) 32 $< $@ - -# $(BUILD_DIR)/%.o: $(BUILD_DIR)/%.sprite -# $(OBJCOPY) -I binary -O elf32-bigmips -B mips:4000 --rename-section .data=.rodata $< $@ - -make_output_dir: - $(shell mkdir ./$(BUILD_DIR) 2> /dev/null) +$(BUILD_DIR)/$(PROGRAM_NAME).hex: $(PROGRAM_NAME).z64 + sed '$$ s/\x00*$$//' $(PROGRAM_NAME).z64 > $(BUILD_DIR)/$(PROGRAM_NAME)_stripped.z64 + @if [ $$(stat -L -c %s $(BUILD_DIR)/$(PROGRAM_NAME)_stripped.z64) -gt 92160 ]; then\ + echo "\n Error: stripped file size is larger than 90kB thus cannot fit inside FPGA flash.\n"; exit 1;\ + fi + truncate --size=90k $(BUILD_DIR)/$(PROGRAM_NAME)_stripped.z64 + $(N64_OBJCOPY) -I binary -O ihex $(BUILD_DIR)/$(PROGRAM_NAME)_stripped.z64 $(BUILD_DIR)/$(PROGRAM_NAME).hex clean: - $(shell rm -rf ./$(BUILD_DIR) 2> /dev/null) + rm -rf ./$(BUILD_DIR) ./$(PROGRAM_NAME).z64 -.PHONY: all clean make_output_dir +-include $(wildcard $(BUILD_DIR)/*.d) + +.PHONY: all clean diff --git a/sw/n64/build.sh b/sw/n64/build.sh index faeb3d6..a048919 100755 --- a/sw/n64/build.sh +++ b/sw/n64/build.sh @@ -1,3 +1,6 @@ #!/bin/bash -docker run --mount type=bind,src="$(pwd)",target="/workdir" ghcr.io/polprzewodnikowy/sc64env:v1.0 /bin/bash -c "make clean all" +docker run \ + --mount type=bind,src="$(pwd)",target="/workdir" \ + ghcr.io/polprzewodnikowy/sc64env:v1.0 \ + /bin/bash -c "make clean all" diff --git a/sw/n64/src/boot/boot.c b/sw/n64/src/boot.c similarity index 100% rename from sw/n64/src/boot/boot.c rename to sw/n64/src/boot.c diff --git a/sw/n64/src/boot/boot.h b/sw/n64/src/boot.h similarity index 100% rename from sw/n64/src/boot/boot.h rename to sw/n64/src/boot.h diff --git a/sw/n64/src/boot/crc32.c b/sw/n64/src/crc32.c similarity index 100% rename from sw/n64/src/boot/crc32.c rename to sw/n64/src/crc32.c diff --git a/sw/n64/src/boot/crc32.h b/sw/n64/src/crc32.h similarity index 100% rename from sw/n64/src/boot/crc32.h rename to sw/n64/src/crc32.h diff --git a/sw/n64/src/main.c b/sw/n64/src/main.c index 1e0aac6..3535426 100644 --- a/sw/n64/src/main.c +++ b/sw/n64/src/main.c @@ -1,5 +1,5 @@ #include "sc64.h" -#include "boot/boot.h" +#include "boot.h" int main(void) { diff --git a/sw/n64/src/boot/n64_regs.h b/sw/n64/src/n64_regs.h similarity index 100% rename from sw/n64/src/boot/n64_regs.h rename to sw/n64/src/n64_regs.h diff --git a/sw/riscv/Makefile b/sw/riscv/Makefile index d4db2a9..897e6c5 100644 --- a/sw/riscv/Makefile +++ b/sw/riscv/Makefile @@ -29,6 +29,7 @@ $(BUILD_DIR)/uc.elf: $(OBJS) SC64.ld $(BUILD_DIR)/controller.rom: $(BUILD_DIR)/uc.elf $(OBJCOPY) -R .bootloader $(BUILD_DIR)/uc.elf $(BUILD_DIR)/controller.elf $(OBJCOPY) -O binary --set-section-flags .bss=alloc,contents $(BUILD_DIR)/controller.elf $(BUILD_DIR)/controller.bin + $(OBJCOPY) -I binary -O ihex $(BUILD_DIR)/controller.bin $(BUILD_DIR)/controller.hex python3 tools/bin2rom.py $@ < $(BUILD_DIR)/controller.bin @echo 'Size of controller modules:' @$(SIZE) -B -t --common $(OBJS) diff --git a/sw/riscv/build.sh b/sw/riscv/build.sh index 1c0ceb8..024bdf7 100755 --- a/sw/riscv/build.sh +++ b/sw/riscv/build.sh @@ -1,3 +1,6 @@ #!/bin/bash -docker run --mount type=bind,src="$(pwd)",target="/workdir" ghcr.io/polprzewodnikowy/sc64env:v1.0 /bin/bash -c "USER_FLAGS=\"-DDEBUG\" make clean all" +docker run \ + --mount type=bind,src="$(pwd)",target="/workdir" \ + ghcr.io/polprzewodnikowy/sc64env:v1.0 \ + /bin/bash -c "USER_FLAGS=\"-DDEBUG\" make clean all" diff --git a/sw/riscv/src/cfg.c b/sw/riscv/src/cfg.c index 3b405da..cc5d8d8 100644 --- a/sw/riscv/src/cfg.c +++ b/sw/riscv/src/cfg.c @@ -1,4 +1,5 @@ #include "cfg.h" +#include "flash.h" #include "joybus.h" #include "usb.h" @@ -26,6 +27,7 @@ enum cfg_id { CFG_ID_SAVE_OFFEST, CFG_ID_DD_OFFEST, CFG_ID_SKIP_BOOTLOADER, + CFG_ID_FLASH_OPERATION, }; enum save_type { @@ -132,6 +134,9 @@ void cfg_update (uint32_t *args) { case CFG_ID_SKIP_BOOTLOADER: change_scr_bits(CFG_SCR_SKIP_BOOTLOADER, args[1]); break; + case CFG_ID_FLASH_OPERATION: + flash_program(args[1]); + break; } } @@ -167,6 +172,9 @@ void cfg_query (uint32_t *args) { case CFG_ID_SKIP_BOOTLOADER: args[1] = CFG->SCR & CFG_SCR_SKIP_BOOTLOADER; break; + case CFG_ID_FLASH_OPERATION: + args[1] = flash_read(args[1]); + break; } } diff --git a/sw/riscv/src/flash.c b/sw/riscv/src/flash.c new file mode 100644 index 0000000..bdff2d8 --- /dev/null +++ b/sw/riscv/src/flash.c @@ -0,0 +1,60 @@ +#include "flash.h" + + +uint32_t flash_read (uint32_t sdram_offset) { + io32_t *flash = (io32_t *) (FLASH_BASE); + io32_t *sdram = (io32_t *) (SDRAM_BASE + sdram_offset); + + for (size_t i = 0; i < FLASH_SIZE; i += 4) { + *sdram++ = *flash++; + } + + return FLASH_SIZE; +} + +void flash_program (uint32_t sdram_offset) { + uint32_t cr; + + io32_t *flash = (io32_t *) (FLASH_BASE); + io32_t *sdram = (io32_t *) (SDRAM_BASE + sdram_offset); + + cr = FLASH_CONFIG->CR; + for (size_t sector = 0; sector < FLASH_NUM_SECTORS; sector++) { + cr &= ~(1 << (FLASH_CR_WRITE_PROTECT_BIT + sector)); + } + FLASH_CONFIG->CR = cr; + + while ((FLASH_CONFIG->SR & FLASH_SR_STATUS_MASK) != FLASH_SR_STATUS_IDLE); + + for (size_t sector = 0; sector < FLASH_NUM_SECTORS; sector++) { + cr = FLASH_CONFIG->CR; + cr &= ~(FLASH_CR_SECTOR_ERASE_MASK); + cr |= ((sector + 1) << FLASH_CR_SECTOR_ERASE_BIT); + FLASH_CONFIG->CR = cr; + + while ((FLASH_CONFIG->SR & FLASH_SR_STATUS_MASK) == FLASH_SR_STATUS_BUSY_ERASE); + + if (!(FLASH_CONFIG->SR & FLASH_SR_ERASE_SUCCESSFUL)) { + break; + } + } + + if (FLASH_CONFIG->SR & FLASH_SR_ERASE_SUCCESSFUL) { + for (size_t word = 0; word < FLASH_SIZE; word += 4) { + *flash++ = *sdram++; + + if (!(FLASH_CONFIG->SR & FLASH_SR_WRITE_SUCCESSFUL)) { + break; + } + } + } + + cr = FLASH_CONFIG->CR; + cr |= FLASH_CR_SECTOR_ERASE_MASK; + for (size_t sector = 0; sector < FLASH_NUM_SECTORS; sector++) { + cr |= (1 << (FLASH_CR_WRITE_PROTECT_BIT + sector)); + } + FLASH_CONFIG->CR = cr; + + return; +} diff --git a/sw/riscv/src/flash.h b/sw/riscv/src/flash.h new file mode 100644 index 0000000..26916c5 --- /dev/null +++ b/sw/riscv/src/flash.h @@ -0,0 +1,12 @@ +#ifndef FLASH_H__ +#define FLASH_H__ + + +#include "sys.h" + + +uint32_t flash_read (uint32_t sdram_offset); +void flash_program (uint32_t sdram_offset); + + +#endif diff --git a/sw/riscv/src/handlers.c b/sw/riscv/src/handlers.c index a5f2895..dfc69de 100644 --- a/sw/riscv/src/handlers.c +++ b/sw/riscv/src/handlers.c @@ -2,43 +2,18 @@ #include "sys.h" -#define BOOT_UART - - __attribute__ ((naked, section(".bootloader"))) void reset_handler (void) { - register uint32_t length = 0; + io32_t *ram = (io32_t *) &RAM; + io32_t *flash = (io32_t *) (FLASH_BASE + FLASH_CPU_IMAGE_OFFSET); -#if defined(BOOT_UART) - volatile uint8_t *pointer = (volatile uint8_t *) &RAM; - for (int i = 0; i < 4; i++) { - while (!(UART->SCR & UART_SCR_RXNE)); - length |= (UART->DR << (i * 8)); + for (int i = 0; i < RAM_SIZE; i += 4) { + *ram++ = *flash++; } -#elif defined(BOOT_N64) - volatile uint32_t *pointer = (volatile uint32_t *) &RAM; - while (!(CFG->SCR & CFG_SCR_CPU_BUSY)); - length = CFG->DATA[0]; - CFG->SCR &= ~(CFG_SCR_CPU_READY); -#endif - while (1) { -#if defined(BOOT_UART) - while (!(UART->SCR & UART_SCR_RXNE)); - *pointer++ = UART->DR; - length = length - 1; -#elif defined(BOOT_N64) - while (!(CFG->SCR & CFG_SCR_CPU_BUSY)); - *pointer++ = CFG->DATA[0]; - CFG->SCR &= ~(CFG_SCR_CPU_READY); - length = length - 4; -#endif - if (length == 0) { - __asm__ volatile ( - "la t0, app_handler \n" - "jalr zero, t0 \n" - ); - } - } + __asm__ volatile ( + "la t0, app_handler \n" + "jalr zero, t0 \n" + ); } diff --git a/sw/riscv/src/sys.h b/sw/riscv/src/sys.h index 8fb9343..4d1e7e6 100644 --- a/sw/riscv/src/sys.h +++ b/sw/riscv/src/sys.h @@ -13,6 +13,7 @@ typedef volatile uint32_t io32_t; #define RAM_BASE (0x00000000UL) #define RAM (*((io32_t *) RAM_BASE)) +#define RAM_SIZE (16 * 1024) #define BOOTLOADER_BASE (0x10000000UL) @@ -153,6 +154,38 @@ typedef volatile struct joybus_regs { #define JOYBUS_SCR_TX_LENGTH_BIT (16) +#define FLASH_BASE (0xB0000000UL) +#define FLASH (*((io32_t *) FLASH_BASE)) + +#define FLASH_CPU_IMAGE_OFFSET (0x35800) +#define FLASH_SIZE (0x39800) +#define FLASH_NUM_SECTORS (4) + + +typedef volatile struct flash_config_regs { + io32_t SR; + io32_t CR; +} flash_config_regs_t; + +#define FLASH_CONFIG_BASE (0xB8000000UL) +#define FLASH_CONFIG ((flash_config_regs_t *) FLASH_CONFIG_BASE) + +#define FLASH_SR_STATUS_MASK (3 << 0) +#define FLASH_SR_STATUS_IDLE (0) +#define FLASH_SR_STATUS_BUSY_ERASE (1) +#define FLASH_SR_STATUS_BUSY_WRITE (2) +#define FLASH_SR_STATUS_BUSY_READ (3) +#define FLASH_SR_READ_SUCCESSFUL (1 << 2) +#define FLASH_SR_WRITE_SUCCESSFUL (1 << 3) +#define FLASH_SR_ERASE_SUCCESSFUL (1 << 4) +#define FLASH_SR_WRITE_PROTECT_BIT (5) + +#define FLASH_CR_PAGE_ERASE_BIT (0) +#define FLASH_CR_SECTOR_ERASE_BIT (20) +#define FLASH_CR_SECTOR_ERASE_MASK (7 << FLASH_CR_SECTOR_ERASE_BIT) +#define FLASH_CR_WRITE_PROTECT_BIT (23) + + void reset_handler (void); void app_handler (void); diff --git a/sw/riscv/src/uart.c b/sw/riscv/src/uart.c index b33d00a..47c1b70 100644 --- a/sw/riscv/src/uart.c +++ b/sw/riscv/src/uart.c @@ -38,7 +38,7 @@ void uart_print_08hex (uint32_t number) { void uart_init (void) { #ifdef DEBUG - uart_print("App ready!\n"); + uart_print("App ready from flash!\n"); #endif } @@ -72,7 +72,8 @@ void process_uart (void) { uart_print_02hex(((uint8_t *) (time))[i]); uart_print(" "); } - uart_print("\r\n"); + uart_print("\n"); + break; } } #endif diff --git a/sw/riscv/src/usb.c b/sw/riscv/src/usb.c index 4bf8f8d..49f1730 100644 --- a/sw/riscv/src/usb.c +++ b/sw/riscv/src/usb.c @@ -77,6 +77,7 @@ struct process { uint32_t args[2]; bool error; bool dma_in_progress; + bool queried; bool debug_rx_busy; uint32_t debug_rx_address; @@ -173,6 +174,7 @@ void process_usb (void) { p.counter = 0; p.error = false; p.dma_in_progress = false; + p.queried = false; p.state = STATE_ARGS; } else { p.cmd = '!'; @@ -199,7 +201,10 @@ void process_usb (void) { break; case 'Q': - cfg_query(p.args); + if (!p.queried) { + cfg_query(p.args); + p.queried = true; + } if (tx_word(p.args[1])) { p.state = STATE_RESPONSE; }