diff --git a/fw/SummerCart64.qsf b/fw/SummerCart64.qsf index 283c21f..ef596f7 100644 --- a/fw/SummerCart64.qsf +++ b/fw/SummerCart64.qsf @@ -178,7 +178,7 @@ set_global_assignment -name TIMING_ANALYZER_DO_REPORT_TIMING ON # Compiler Assignments # ==================== -set_global_assignment -name OPTIMIZATION_MODE "AGGRESSIVE PERFORMANCE" +set_global_assignment -name OPTIMIZATION_MODE BALANCED # Analysis & Synthesis Assignments # ================================ @@ -266,6 +266,7 @@ set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" - set_instance_assignment -name GLOBAL_SIGNAL GLOBAL_CLOCK -to i_clk set_instance_assignment -name GLOBAL_SIGNAL GLOBAL_CLOCK -to "pll:sys_pll|altpll:altpll_component|pll_altpll:auto_generated|wire_pll1_clk[0]" set_instance_assignment -name GLOBAL_SIGNAL GLOBAL_CLOCK -to "pll:sys_pll|altpll:altpll_component|pll_altpll:auto_generated|wire_pll1_clk[1]" + set_instance_assignment -name GLOBAL_SIGNAL GLOBAL_CLOCK -to "sd_interface:sd_interface_inst|sd_clk:sd_clk_inst|o_sd_clk|q" # start DESIGN_PARTITION(Top) # --------------------------- diff --git a/fw/constraints.sdc b/fw/constraints.sdc index dedb7c0..b6f1f87 100644 --- a/fw/constraints.sdc +++ b/fw/constraints.sdc @@ -5,9 +5,25 @@ derive_pll_clocks -create_base_clocks set sys_clk {sys_pll|altpll_component|auto_generated|pll1|clk[0]} set sdram_pll_clk {sys_pll|altpll_component|auto_generated|pll1|clk[1]} -create_generated_clock -name sdram_clk -source [get_pins $sdram_pll_clk] -master_clock $sdram_pll_clk [get_ports {o_sdram_clk}] -create_generated_clock -name flash_se_neg_reg -divide_by 2 \ +create_generated_clock -name sdram_clk \ + -source [get_pins $sdram_pll_clk] \ + -master_clock $sdram_pll_clk \ + [get_ports {o_sdram_clk}] + +create_generated_clock -name sd_generated_clk \ + -source [get_pins {sd_interface_inst|sd_clk_inst|o_sd_clk|clk}] \ + -divide_by 2 \ + -master_clock $sys_clk \ + [get_pins {sd_interface_inst|sd_clk_inst|o_sd_clk|q}] + +create_generated_clock -name sd_clk \ + -source [get_pins {sd_interface_inst|sd_clk_inst|o_sd_clk|q}] \ + -master_clock [get_clocks {sd_generated_clk}] \ + [get_ports {o_sd_clk}] + +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 \ [get_pins -compatibility_mode {*altera_onchip_flash:*onchip_flash_0|altera_onchip_flash_avmm_data_controller:avmm_data_controller|flash_se_neg_reg|q}] derive_clock_uncertainty @@ -35,8 +51,17 @@ set_false_path -from [get_ports {i_ftdi_so i_ftdi_cts}] # SD card timings -set_false_path -to [get_ports {o_sd_clk io_sd_cmd io_sd_dat[*]}] -set_false_path -from [get_ports {io_sd_cmd io_sd_dat[*]}] +set_output_delay -clock [get_clocks {sd_clk}] -max 7.5 [get_ports {io_sd_cmd io_sd_dat[*]}] +set_output_delay -clock [get_clocks {sd_clk}] -min -3.5 [get_ports {io_sd_cmd io_sd_dat[*]}] + +set_input_delay -clock [get_clocks {sd_clk}] -max 15.5 [get_ports {io_sd_cmd io_sd_dat[*]}] +set_input_delay -clock [get_clocks {sd_clk}] -min 4.0 [get_ports {io_sd_cmd io_sd_dat[*]}] + +set_multicycle_path -setup -start 1 -from [get_clocks $sys_clk] -to [get_clocks {sd_clk}] +set_multicycle_path -hold -start 1 -from [get_clocks $sys_clk] -to [get_clocks {sd_clk}] + +set_multicycle_path -setup -end 3 -from [get_clocks {sd_clk}] -to [get_clocks $sys_clk] +set_multicycle_path -hold -end 2 -from [get_clocks {sd_clk}] -to [get_clocks $sys_clk] # N64, PI and SI timings diff --git a/fw/rtl/cart/cart_control.v b/fw/rtl/cart/cart_control.v index 2504b10..9819429 100644 --- a/fw/rtl/cart/cart_control.v +++ b/fw/rtl/cart/cart_control.v @@ -77,6 +77,7 @@ module cart_control ( // Registers reg [15:0] r_bootloader; + reg r_skip_bootloader; // Bus controller @@ -112,11 +113,13 @@ module cart_control ( o_debug_dma_address <= 24'hFC_0000; o_debug_dma_length <= 20'd0; r_bootloader <= 16'h0000; + r_skip_bootloader <= 1'b0; end else begin if (i_request && i_write && !o_busy) begin case (i_address[3:0]) REG_SCR: begin { + r_skip_bootloader, o_flashram_enable, o_sram_768k_mode, o_sram_enable, @@ -127,7 +130,7 @@ module cart_control ( o_ddipl_enable, o_rom_switch, o_sdram_writable - } <= i_data[9:0]; + } <= i_data[10:0]; end REG_BOOT: begin r_bootloader <= i_data[15:0]; @@ -157,7 +160,7 @@ module cart_control ( if (!r_reset_ff2 || !r_nmi_ff2) begin o_sdram_writable <= 1'b0; - o_rom_switch <= 1'b0; + o_rom_switch <= r_skip_bootloader; o_n64_reset_btn <= 1'b1; o_debug_fifo_flush <= 1'b1; end @@ -172,9 +175,12 @@ module cart_control ( if (!i_reset && i_request && !i_write && !o_busy) begin if (i_address < MEM_USB_FIFO_BASE) begin + o_data <= 32'h0000_0000; + case (i_address[3:0]) REG_SCR: begin - o_data[9:0] <= { + o_data[10:0] <= { + r_skip_bootloader, o_flashram_enable, o_sram_768k_mode, o_sram_enable, diff --git a/fw/rtl/memory/memory_embedded_flash.v b/fw/rtl/memory/memory_embedded_flash.v index 50c86ec..98c5911 100644 --- a/fw/rtl/memory/memory_embedded_flash.v +++ b/fw/rtl/memory/memory_embedded_flash.v @@ -30,7 +30,7 @@ module memory_embedded_flash ( r_onchip_flash_request = 1'b0; o_busy = 1'b0; o_data = 32'h0000_0000; - if (w_onchip_flash_in_address_range) begin + if (w_onchip_flash_in_address_range && !r_dummy_ack) begin r_onchip_flash_request = i_request; o_busy = w_onchip_flash_busy; o_data = { diff --git a/fw/rtl/n64/n64_bank_decoder.v b/fw/rtl/n64/n64_bank_decoder.v index 9929abe..ede9d99 100644 --- a/fw/rtl/n64/n64_bank_decoder.v +++ b/fw/rtl/n64/n64_bank_decoder.v @@ -1,80 +1,119 @@ `include "../constants.vh" module n64_bank_decoder ( - input [31:0] i_address, - output reg [25:0] o_translated_address, + input i_clk, + + input i_address_high_op, + input i_address_low_op, + input [15:0] i_n64_pi_ad, + output reg [3:0] o_bank, - output reg o_bank_prefetch, - output o_sram_request, + output reg o_prefetch, + output reg o_ddipl_request, + output reg o_sram_request, + input i_ddipl_enable, input i_sram_enable, input i_sram_768k_mode, input i_flashram_enable, - input i_sd_enable, input i_eeprom_enable, - input [23:0] i_ddipl_address, - input [23:0] i_sram_address + input i_sd_enable ); - localparam [31:0] DDIPL_BASE = 32'h0600_0000; - localparam [31:0] DDIPL_END = 32'h063F_FFFF; + reg r_address_high_lsb; - localparam [31:0] SRAM_BASE = 32'h0800_0000; - localparam [31:0] SRAM_END = 32'h0800_7FFF; - localparam [31:0] SRAM_768K_END = 32'h0801_7FFF; + always @(posedge i_clk) begin + if (i_address_high_op) begin + o_bank <= `BANK_INVALID; + o_prefetch <= 1'b1; + o_ddipl_request <= 1'b0; + o_sram_request <= 1'b0; - localparam [31:0] ROM_BASE = 32'h1000_0000; - localparam [31:0] ROM_END = 32'h13FF_FFFF; + casez (i_n64_pi_ad) + 16'b0000011000??????: begin // DDIPL + if (i_ddipl_enable) begin + o_bank <= `BANK_SDRAM; + o_ddipl_request <= 1'b1; + end + end - localparam [31:0] CART_BASE = 32'h1E00_0000; - localparam [31:0] CART_END = 32'h1E00_3FFF; + 16'b000010000000000?: begin // SRAM / FlashRAM + r_address_high_lsb <= i_n64_pi_ad[0]; + if (i_flashram_enable && !i_n64_pi_ad[0]) begin + o_bank <= `BANK_FLASHRAM; + end else if (i_sram_enable) begin + o_bank <= `BANK_SDRAM; + o_sram_request <= 1'b1; + end + end - localparam [31:0] EEPROM_BASE = 32'h1E00_4000; - localparam [31:0] EEPROM_END = 32'h1E00_47FF; + 16'b000100??????????: begin // ROM + o_bank <= `BANK_SDRAM; + end - localparam [31:0] SD_BASE = 32'h1E00_8000; - localparam [31:0] SD_END = 32'h1E00_83FF; + 16'b0001111000000000: begin // CART + o_bank <= `BANK_CART; + o_prefetch <= 1'b0; + end - wire [25:0] w_ddipl_translated_address = i_address[25:0] + {i_ddipl_address, 2'd0}; - wire [25:0] w_sram_translated_address = i_address[25:0] + {i_sram_address, 2'd0}; + 16'b0001111000000001: begin // EEPROM + if (i_eeprom_enable) begin + o_bank <= `BANK_EEPROM; + end + end - always @(*) begin - o_bank = `BANK_INVALID; - o_bank_prefetch = 1'b0; - o_translated_address = i_address[25:0]; - o_sram_request = 1'b0; - - if ((i_address >= DDIPL_BASE) && (i_address <= DDIPL_END) && i_ddipl_enable) begin - o_translated_address = w_ddipl_translated_address; - o_bank = `BANK_SDRAM; - o_bank_prefetch = 1'b1; + 16'b0001111000000010: begin // SD + if (i_sd_enable) begin + o_bank <= `BANK_SD; + o_prefetch <= 1'b0; + end + end + default: begin end + endcase end - if ((i_address >= SRAM_BASE) && ((i_address <= SRAM_END) || ((i_sram_768k_mode && (i_address <= SRAM_768K_END))))) begin - if (i_sram_enable && !i_flashram_enable) begin - o_translated_address = w_sram_translated_address; - o_bank = `BANK_SDRAM; - o_bank_prefetch = 1'b1; - o_sram_request = 1'b1; - end - end + if (i_address_low_op) begin + case (o_bank) + `BANK_SDRAM: begin + if (o_sram_request) begin + if (i_sram_768k_mode) begin + if (r_address_high_lsb && i_n64_pi_ad[1]) begin + o_bank <= `BANK_INVALID; + end + end else begin + if (i_n64_pi_ad[1]) begin + o_bank <= `BANK_INVALID; + end + end + end + end - if ((i_address >= ROM_BASE) && (i_address <= ROM_END)) begin - o_bank = `BANK_SDRAM; - o_bank_prefetch = 1'b1; - end + `BANK_CART: begin + if (i_n64_pi_ad[15:14] != 2'b00) begin + o_bank <= `BANK_INVALID; + end + end - if ((i_address >= CART_BASE) && (i_address <= CART_END)) begin - o_bank = `BANK_CART; - end + `BANK_EEPROM: begin + if (i_n64_pi_ad[15:11] != 5'b00000) begin + o_bank <= `BANK_INVALID; + end + end + + `BANK_FLASHRAM: begin + if (r_address_high_lsb) begin + o_bank <= `BANK_INVALID; + end + end - if ((i_address >= EEPROM_BASE) && (i_address <= EEPROM_END) && i_eeprom_enable) begin - o_bank = `BANK_EEPROM; - o_bank_prefetch = 1'b1; - end + `BANK_SD: begin + if (i_n64_pi_ad[15:10] != 6'b000000) begin + o_bank <= `BANK_INVALID; + end + end - if ((i_address >= SD_BASE) && (i_address <= SD_END) && i_sd_enable) begin - o_bank = `BANK_SD; + default: begin end + endcase end end diff --git a/fw/rtl/n64/n64_pi.v b/fw/rtl/n64/n64_pi.v index 008b2e8..39de9e8 100644 --- a/fw/rtl/n64/n64_pi.v +++ b/fw/rtl/n64/n64_pi.v @@ -1,3 +1,5 @@ +`include "../constants.vh" + module n64_pi ( input i_clk, input i_reset, @@ -39,15 +41,15 @@ module n64_pi ( // Input synchronization reg r_reset_ff1, r_reset_ff2; - reg r_alel_ff1, r_alel_ff2; - reg r_aleh_ff1, r_aleh_ff2; + reg r_alel_ff1, r_alel_ff2, r_alel_ff3; + reg r_aleh_ff1, r_aleh_ff2, r_aleh_ff3; reg r_read_ff1, r_read_ff2; reg r_write_ff1, r_write_ff2; always @(posedge i_clk) begin {r_reset_ff2, r_reset_ff1} <= {r_reset_ff1, i_n64_reset}; - {r_alel_ff2, r_alel_ff1} <= {r_alel_ff1, i_n64_pi_alel}; - {r_aleh_ff2, r_aleh_ff1} <= {r_aleh_ff1, i_n64_pi_aleh}; + {r_alel_ff3, r_alel_ff2, r_alel_ff1} <= {r_alel_ff2, r_alel_ff1, i_n64_pi_alel}; + {r_aleh_ff3, r_aleh_ff2, r_aleh_ff1} <= {r_aleh_ff2, r_aleh_ff1, i_n64_pi_aleh}; {r_read_ff2, r_read_ff1} <= {r_read_ff1, i_n64_pi_read}; {r_write_ff2, r_write_ff1} <= {r_write_ff1, i_n64_pi_write}; end @@ -55,7 +57,7 @@ module n64_pi ( // PI event signals generator - wire [1:0] w_pi_mode = {r_aleh_ff2, r_alel_ff2}; + wire [1:0] w_pi_mode = {r_aleh_ff3, r_alel_ff3}; reg [1:0] r_last_pi_mode; reg r_last_read; reg r_last_write; @@ -72,42 +74,42 @@ module n64_pi ( localparam [1:0] PI_MODE_VALID = 2'b00; wire w_address_high_op = r_reset_ff2 && (r_last_pi_mode != PI_MODE_HIGH) && (w_pi_mode == PI_MODE_HIGH); - wire w_address_low_op = r_reset_ff2 && (r_last_pi_mode != PI_MODE_LOW) && (w_pi_mode == PI_MODE_LOW); - wire w_address_valid_op = r_reset_ff2 && (r_last_pi_mode != PI_MODE_VALID) && (w_pi_mode == PI_MODE_VALID); + wire w_address_low_op = r_reset_ff2 && (r_last_pi_mode == PI_MODE_HIGH) && (w_pi_mode == PI_MODE_LOW); wire w_read_op = r_reset_ff2 && (w_pi_mode == PI_MODE_VALID) && r_last_read && !r_read_ff2; wire w_write_op = r_reset_ff2 && (w_pi_mode == PI_MODE_VALID) && r_last_write && !r_write_ff2; - - // Bus address register - - reg [31:0] r_pi_address; + reg r_address_valid_op; always @(posedge i_clk) begin - if (w_address_high_op) r_pi_address[31:16] <= io_n64_pi_ad; - if (w_address_low_op) r_pi_address[15:0] <= {io_n64_pi_ad[15:1], 1'b0}; + r_address_valid_op <= w_address_low_op; end // Bank decoder, address translator and prefetch signal - wire [25:0] w_translated_address; wire w_bank_prefetch; + wire w_ddipl_request; + wire w_prefetch = !PREFETCH_DISABLE && w_bank_prefetch; n64_bank_decoder n64_bank_decoder_inst ( - .i_address(r_pi_address), - .o_translated_address(w_translated_address), + .i_clk(i_clk), + + .i_address_high_op(w_address_high_op), + .i_address_low_op(w_address_low_op), + .i_n64_pi_ad(io_n64_pi_ad), + .o_bank(o_bank), - .o_bank_prefetch(w_bank_prefetch), + .o_prefetch(w_bank_prefetch), + .o_ddipl_request(w_ddipl_request), .o_sram_request(o_sram_request), + .i_ddipl_enable(i_ddipl_enable), .i_sram_enable(i_sram_enable), .i_sram_768k_mode(i_sram_768k_mode), .i_flashram_enable(i_flashram_enable), - .i_sd_enable(i_sd_enable), .i_eeprom_enable(i_eeprom_enable), - .i_ddipl_address(i_ddipl_address), - .i_sram_address(i_sram_address) + .i_sd_enable(i_sd_enable) ); @@ -115,9 +117,16 @@ module n64_pi ( reg r_word_counter; + wire w_bus_read_op = w_read_op && !r_word_counter; + wire w_bus_write_op = w_write_op && r_word_counter; + always @(posedge i_clk) begin - if (w_address_valid_op) r_word_counter <= 1'b0; - if (w_read_op || w_write_op) r_word_counter <= ~r_word_counter; + if (r_address_valid_op) begin + r_word_counter <= 1'b0; + end + if (w_read_op || w_write_op) begin + r_word_counter <= ~r_word_counter; + end end @@ -127,34 +136,35 @@ module n64_pi ( always @(*) begin io_n64_pi_ad = 16'hZZZZ; - if (r_reset_ff2 && !r_read_ff2 && o_bank != 4'd0) begin + if (r_reset_ff2 && !r_read_ff2 && o_bank != `BANK_INVALID) begin io_n64_pi_ad = r_word_counter ? r_pi_output_data[31:16] : r_pi_output_data[15:0]; end end - // Bus event signals generator - - wire w_bus_read_op = w_read_op && !r_word_counter; - wire w_bus_write_op = w_write_op && r_word_counter; - - // Read buffer logic - reg [31:0] r_pi_read_buffer; reg r_prefetch_read; + reg [31:0] r_pi_read_buffer; always @(posedge i_clk) begin - if (w_address_valid_op) begin + if (r_address_valid_op) begin r_prefetch_read <= w_prefetch; end if (i_ack) begin - if (w_prefetch) r_pi_read_buffer <= i_data; - else r_pi_output_data <= i_data; - if (r_prefetch_read) r_pi_output_data <= i_data; r_prefetch_read <= 1'b0; + if (w_prefetch) begin + r_pi_read_buffer <= i_data; + end else begin + r_pi_output_data <= i_data; + end + if (r_prefetch_read) begin + r_pi_output_data <= i_data; + end + end + if (w_prefetch && w_bus_read_op) begin + r_pi_output_data <= r_pi_read_buffer; end - if (w_prefetch && w_bus_read_op) r_pi_output_data <= r_pi_read_buffer; end @@ -178,15 +188,16 @@ module n64_pi ( reg r_pending_request; reg r_pending_request_write; - wire w_bus_request_op = (w_address_valid_op && w_prefetch) || w_bus_read_op || w_bus_write_op; - + wire w_bus_request_op = (r_address_valid_op && w_prefetch) || w_bus_read_op || w_bus_write_op; + wire w_request_successful = o_request && !i_busy; + always @(posedge i_clk) begin if (i_reset) begin o_request <= 1'b0; o_write <= 1'b0; r_pending_request <= 1'b0; end else begin - if (o_request && !i_busy) begin + if (w_request_successful) begin o_request <= 1'b0; o_write <= 1'b0; end @@ -208,23 +219,46 @@ module n64_pi ( end - // Address increment logic + // Address latch and increment logic + + wire [9:0] w_pi_high_address = io_n64_pi_ad[9:0]; + wire [15:0] w_pi_low_address = {io_n64_pi_ad[15:1], 1'b0}; + wire [25:0] w_ddipl_translated_address = o_address + {i_ddipl_address, 2'b00}; + wire [25:0] w_sram_translated_address = o_address + {i_sram_address, 2'b00}; reg r_first_transfer; - - wire w_address_increment_op = ( - (w_bus_read_op && (!r_first_transfer || w_prefetch)) || - (w_bus_write_op && !r_first_transfer) - ); - wire w_first_transfer_clear_op = w_bus_read_op || w_bus_write_op; + reg [14:0] r_address_low_buffer; always @(posedge i_clk) begin - if (w_address_valid_op) begin - o_address <= w_translated_address; - r_first_transfer <= 1'b1; + if (w_address_high_op) begin + o_address[25:16] <= w_pi_high_address; + end + + if (w_address_low_op) begin + o_address[15:0] <= w_pi_low_address; + end + + if (r_address_valid_op) begin + r_first_transfer <= w_prefetch; + r_address_low_buffer <= o_address[15:1]; + if (w_ddipl_request) begin + o_address <= w_ddipl_translated_address; + r_address_low_buffer <= w_ddipl_translated_address[15:1]; + end + if (o_sram_request) begin + o_address <= w_sram_translated_address; + r_address_low_buffer <= w_sram_translated_address[15:1]; + end + end + + if (w_request_successful) begin + o_address[15:2] <= o_address[15:2] + 1'd1; + end + + if (w_bus_write_op && r_first_transfer) begin + r_first_transfer <= 1'b0; + o_address[15:1] <= r_address_low_buffer; end - if (w_first_transfer_clear_op) r_first_transfer <= 1'b0; - if (w_address_increment_op) o_address[15:2] <= o_address[15:2] + 1'b1; end endmodule diff --git a/fw/rtl/top.v b/fw/rtl/top.v index 65a3cb3..634c801 100644 --- a/fw/rtl/top.v +++ b/fw/rtl/top.v @@ -83,6 +83,18 @@ module top ( ); + // SD clock output + + wire w_sd_clk; + + gpio_ddro sd_clk_ddro ( + .outclock(w_sd_clk), + .outclocken(1'b1), + .din({1'b0, 1'b1}), + .pad_out(o_sd_clk) + ); + + // N64 PI wire w_n64_request; @@ -385,7 +397,7 @@ module top ( .i_clk(w_sys_clk), .i_reset(w_sys_reset), - .o_sd_clk(o_sd_clk), + .o_sd_clk(w_sd_clk), .io_sd_cmd(io_sd_cmd), .io_sd_dat(io_sd_dat), diff --git a/sw/bootloader/Makefile b/sw/bootloader/Makefile index e217e80..4ee027b 100644 --- a/sw/bootloader/Makefile +++ b/sw/bootloader/Makefile @@ -34,6 +34,7 @@ ASFLAGS = $(COMMONFLAGS) CFLAGS = $(COMMONFLAGS) -std=gnu99 -Os -Wall -I$(ROOTDIR)/mips64-elf/include $(INC_DIRS) LINK_FLAGS = -L$(ROOTDIR)/mips64-elf/lib -ldragon -lc -lm -ldragonsys -Tn64.ld N64_FLAGS = -l $(ROM_SIZE) -h $(HEADER_PATH)/$(HEADER_NAME) -o $(BUILD_DIR)/$(PROG_NAME).z64 +N64_FLAGS_PADDED = -l 1028k -h $(HEADER_PATH)/$(HEADER_NAME) -o $(BUILD_DIR)/$(PROG_NAME)_padded.z64 all: make_output_dir $(BUILD_DIR)/$(PROG_NAME).z64 @@ -43,7 +44,9 @@ $(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 + $(N64TOOL) $(N64_FLAGS_PADDED) -t $(PROG_NAME) $(BUILD_DIR)/$(PROG_NAME).bin $(CHKSUM64) $(BUILD_DIR)/$(PROG_NAME).z64 + $(CHKSUM64) $(BUILD_DIR)/$(PROG_NAME)_padded.z64 $(OBJCOPY) $(BUILD_DIR)/$(PROG_NAME).z64 $(BUILD_DIR)/$(PROG_NAME).hex -I binary -O ihex $(BUILD_DIR)/$(PROG_NAME).elf: $(OBJ_FILES) diff --git a/sw/bootloader/src/boot/boot.c b/sw/bootloader/src/boot/boot.c index 8e47df5..dfb2f86 100644 --- a/sw/bootloader/src/boot/boot.c +++ b/sw/bootloader/src/boot/boot.c @@ -23,7 +23,7 @@ static const struct crc32_to_cic_seed { static cart_header_t global_cart_header __attribute__((aligned(16))); -cart_header_t *boot_load_cart_header(void) { +cart_header_t *boot_load_cart_header(bool ddipl) { cart_header_t *cart_header_pointer = &global_cart_header; platform_pi_dma_read(cart_header_pointer, CART_BASE, sizeof(cart_header_t)); @@ -81,10 +81,12 @@ void boot(cart_header_t *cart_header, uint16_t cic_seed, tv_type_t tv_type, uint (cic_seed == crc32_to_cic_seed[8].cic_seed) || (cic_seed == crc32_to_cic_seed[9].cic_seed) ); - tv_type_t os_tv_type = tv_type < 0 ? OS_BOOT_CONFIG->tv_type : tv_type; + tv_type_t os_tv_type = tv_type == -1 ? OS_BOOT_CONFIG->tv_type : tv_type; volatile uint64_t gpr_regs[32]; + MI->interrupt_mask = MI_INT_CLEAR_SP | MI_INT_CLEAR_SI | MI_INT_CLEAR_AI | MI_INT_CLEAR_VI | MI_INT_CLEAR_PI | MI_INT_CLEAR_DP; + while (!(SP->status & SP_STATUS_HALT)); SP->status = SP_STATUS_CLEAR_INTERRUPT | SP_STATUS_SET_HALT; @@ -117,7 +119,7 @@ void boot(cart_header_t *cart_header, uint16_t cic_seed, tv_type_t tv_type, uint SP_MEM->imem[1] = 0x8DA807FC; // lw t0, 0x07FC(t5) SP_MEM->imem[2] = 0x25AD07C0; // addiu t5, t5, 0x07C0 SP_MEM->imem[3] = 0x31080080; // andi t0, t0, 0x0080 - SP_MEM->imem[4] = 0x5500FFFC; // bnel t0, zero, &SP_MEM->imem[0] + SP_MEM->imem[4] = 0x5500FFFC; // bnel t0, zero, &SP_MEM->imem[1] SP_MEM->imem[5] = 0x3C0DBFC0; // lui t5, 0xBFC0 SP_MEM->imem[6] = 0x8DA80024; // lw t0, 0x0024(t5) SP_MEM->imem[7] = 0x3C0BB000; // lui t3, 0xB000 @@ -133,7 +135,7 @@ void boot(cart_header_t *cart_header, uint16_t cic_seed, tv_type_t tv_type, uint gpr_regs[CPU_REG_T3] = CPU_ADDRESS_IN_REG(SP_MEM->dmem[16]); gpr_regs[CPU_REG_S3] = is_ddipl_boot ? OS_BOOT_ROM_TYPE_DD : OS_BOOT_ROM_TYPE_GAME_PAK; gpr_regs[CPU_REG_S4] = os_tv_type; - gpr_regs[CPU_REG_S5] = OS_BOOT_CONFIG->reset_type; + gpr_regs[CPU_REG_S5] = OS_BOOT_RESET_TYPE_COLD; gpr_regs[CPU_REG_S6] = BOOT_SEED_IPL3(cic_seed); gpr_regs[CPU_REG_S7] = BOOT_SEED_OS_VERSION(cic_seed); gpr_regs[CPU_REG_SP] = CPU_ADDRESS_IN_REG(SP_MEM->imem[ARRAY_ITEMS(SP_MEM->imem) - 4]); diff --git a/sw/bootloader/src/boot/boot.h b/sw/bootloader/src/boot/boot.h index 36a202d..430e08c 100644 --- a/sw/bootloader/src/boot/boot.h +++ b/sw/bootloader/src/boot/boot.h @@ -46,11 +46,15 @@ typedef struct os_boot_config_s os_boot_config_t; #define OS_BOOT_ROM_TYPE_GAME_PAK (0) #define OS_BOOT_ROM_TYPE_DD (1) +#define OS_BOOT_RESET_TYPE_COLD (0) +#define OS_BOOT_RESET_TYPE_NMI (1) +#define OS_BOOT_RESET_TYPE_DISK (2) + #define BOOT_SEED_IPL3(x) (((x) & 0x000000FF) >> 0) #define BOOT_SEED_OS_VERSION(x) (((x) & 0x00000100) >> 8) -cart_header_t *boot_load_cart_header(void); +cart_header_t *boot_load_cart_header(bool ddipl); uint16_t boot_get_cic_seed(cart_header_t *cart_header); tv_type_t boot_get_tv_type(cart_header_t *cart_header); void boot(cart_header_t *cart_header, uint16_t cic_seed, tv_type_t tv_type, uint32_t ddipl_override); diff --git a/sw/bootloader/src/boot/n64_regs.h b/sw/bootloader/src/boot/n64_regs.h index c6fd559..1ac3f7d 100644 --- a/sw/bootloader/src/boot/n64_regs.h +++ b/sw/bootloader/src/boot/n64_regs.h @@ -72,6 +72,13 @@ typedef struct DP_CMD_regs_s { volatile uint32_t tmem; } DP_CMD_regs_t; +typedef struct MI_regs_s { + volatile uint32_t mode; + volatile uint32_t version; + volatile uint32_t interrupt; + volatile uint32_t interrupt_mask; +} MI_regs_t; + typedef struct VI_regs_s { volatile uint32_t control; volatile void *dram_addr; @@ -118,6 +125,7 @@ typedef struct PI_regs_s { #define SP_MEM_BASE (0xA4000000) #define SP_REGS_BASE (0xA4040000) #define DP_CMD_REGS_BASE (0xA4100000) +#define MI_REGS_BASE (0xA4300000) #define VI_REGS_BASE (0xA4400000) #define AI_REGS_BASE (0xA4500000) #define PI_REGS_BASE (0xA4600000) @@ -127,6 +135,7 @@ typedef struct PI_regs_s { #define SP_MEM ((volatile SP_MEM_t *) SP_MEM_BASE) #define SP ((volatile SP_regs_t *) SP_REGS_BASE) #define DP_CMD ((volatile DP_CMD_regs_t *) DP_CMD_REGS_BASE) +#define MI ((volatile MI_regs_t *) MI_REGS_BASE) #define VI ((volatile VI_regs_t *) VI_REGS_BASE) #define AI ((volatile AI_regs_t *) AI_REGS_BASE) #define PI ((volatile PI_regs_t *) PI_REGS_BASE) @@ -145,6 +154,13 @@ typedef struct PI_regs_s { #define DP_CMD_STATUS_CLEAR_FREEZE (1 << 2) #define DP_CMD_STATUS_CLEAR_FLUSH (1 << 4) +#define MI_INT_CLEAR_SP (1 << 0) +#define MI_INT_CLEAR_SI (1 << 2) +#define MI_INT_CLEAR_AI (1 << 4) +#define MI_INT_CLEAR_VI (1 << 6) +#define MI_INT_CLEAR_PI (1 << 8) +#define MI_INT_CLEAR_DP (1 << 10) + #define PI_STATUS_DMA_BUSY (1 << 0) #define PI_STATUS_IO_BUSY (1 << 1) #define PI_STATUS_RESET_CONTROLLER (1 << 0) diff --git a/sw/bootloader/src/fatfs/diskio.c b/sw/bootloader/src/fatfs/diskio.c index ed38e4e..b4479c3 100644 --- a/sw/bootloader/src/fatfs/diskio.c +++ b/sw/bootloader/src/fatfs/diskio.c @@ -9,7 +9,7 @@ DSTATUS disk_status(BYTE pdrv) { return STA_NOINIT; } - return sc64_sd_get_status() ? 0 : STA_NOINIT; + return sc64_sd_status_get() ? 0 : STA_NOINIT; } DSTATUS disk_initialize(BYTE pdrv) { @@ -17,7 +17,7 @@ DSTATUS disk_initialize(BYTE pdrv) { return STA_NOINIT; } - if (!sc64_sd_get_status()) { + if (!sc64_sd_status_get()) { if (sc64_sd_init()) { return 0; } @@ -31,18 +31,21 @@ DSTATUS disk_initialize(BYTE pdrv) { DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) { sc64_sd_err_t error; - if ((pdrv > 0) || (count == 0)) { + if (pdrv > 0) { return RES_PARERR; } - if (!sc64_sd_get_status()) { - return RES_NOTRDY; - } - - error = sc64_sd_read_sectors(sector, count, buff); + error = sc64_sd_sectors_read(sector, count, buff); if (error != E_OK) { - return RES_ERROR; + switch (error) { + case E_NO_INIT: + return RES_NOTRDY; + case E_PAR_ERROR: + return RES_PARERR; + default: + return RES_ERROR; + } } return RES_OK; @@ -51,7 +54,26 @@ DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) { #if !FF_FS_READONLY DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) { - return RES_ERROR; + sc64_sd_err_t error; + + if (pdrv > 0) { + return RES_PARERR; + } + + error = sc64_sd_sectors_write(sector, count, (uint8_t *) buff); + + if (error != E_OK) { + switch (error) { + case E_NO_INIT: + return RES_NOTRDY; + case E_PAR_ERROR: + return RES_PARERR; + default: + return RES_ERROR; + } + } + + return RES_OK; } #endif diff --git a/sw/bootloader/src/fatfs/ffconf.h b/sw/bootloader/src/fatfs/ffconf.h index bb5a6e0..f8b1762 100644 --- a/sw/bootloader/src/fatfs/ffconf.h +++ b/sw/bootloader/src/fatfs/ffconf.h @@ -25,7 +25,7 @@ / 3: f_lseek() function is removed in addition to 2. */ -#define FF_USE_STRFUNC 0 +#define FF_USE_STRFUNC 2 /* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). / / 0: Disable string functions. diff --git a/sw/bootloader/src/loader/loader.c b/sw/bootloader/src/loader/loader.c index fe1df90..91b3fbd 100644 --- a/sw/bootloader/src/loader/loader.c +++ b/sw/bootloader/src/loader/loader.c @@ -15,6 +15,8 @@ #define NTOA(n) ('0' + ((n) % 10)) +static bool loader_initialized = false; + static char version_string[] = "SC64 Bootloader ver. X.X"; static char error_number_string[] = "ERROR X"; static const char *error_strings[] = { @@ -31,12 +33,12 @@ static int x_offset = X_OFFSET; static int y_offset = Y_OFFSET; -static display_context_t loader_get_display(void) { +static display_context_t loader_get_display(bool lock) { display_context_t display; do { display = display_lock(); - } while (!display); + } while (!display && lock); x_offset = X_OFFSET; y_offset = Y_OFFSET; @@ -58,32 +60,71 @@ static void loader_draw_version_and_logo(display_context_t display) { graphics_draw_sprite(display, center_x, center_y, logo); } -void loader_init(void) { - display_context_t display; - +static void loader_init(void) { init_interrupts(); - + audio_init(44100, 2); audio_write_silence(); display_init(RESOLUTION_320x240, DEPTH_32_BPP, 2, GAMMA_NONE, ANTIALIAS_OFF); - display = loader_get_display(); + loader_initialized = true; +} + +void loader_cleanup(void) { + audio_close(); + + display_close(); + + disable_interrupts(); + + loader_initialized = false; +} + +void loader_display_logo(void) { + if (!loader_initialized) { + loader_init(); + } + + display_context_t display; + + display = loader_get_display(true); + + graphics_fill_screen(display, 0); loader_draw_version_and_logo(display); display_show(display); } -void loader_cleanup(void) { - audio_close(); - display_close(); -} +void loader_display_message(const char *message) { + if (!loader_initialized) { + loader_init(); + } -void loader_display_error_and_halt(menu_load_error_t error, const char *path) { display_context_t display; - display = loader_get_display(); + display = loader_get_display(true); + + graphics_fill_screen(display, 0); + + loader_draw_version_and_logo(display); + + graphics_draw_text(display, x_offset, y_offset, message); + + display_show(display); +} + +void loader_display_error_and_halt(menu_load_error_t error, const char *message) { + if (!loader_initialized) { + loader_init(); + } + + display_context_t display; + + display = loader_get_display(true); + + graphics_fill_screen(display, 0); loader_draw_version_and_logo(display); @@ -94,11 +135,9 @@ void loader_display_error_and_halt(menu_load_error_t error, const char *path) { int error_string_index = error >= E_MENU_END ? (E_MENU_END - 1) : error; const char *error_string = error_strings[error_string_index]; graphics_draw_text(display, x_offset, y_offset, error_string); - y_offset += Y_PADDING; + y_offset += Y_PADDING * 2; - if (error == E_MENU_ERROR_NO_FILE) { - graphics_draw_text(display, x_offset, y_offset, path); - } + graphics_draw_text(display, x_offset, y_offset, message); display_show(display); diff --git a/sw/bootloader/src/loader/loader.h b/sw/bootloader/src/loader/loader.h index 1379526..9cb5e90 100644 --- a/sw/bootloader/src/loader/loader.h +++ b/sw/bootloader/src/loader/loader.h @@ -5,9 +5,10 @@ #include "errors.h" -void loader_init(void); void loader_cleanup(void); -void loader_display_error_and_halt(menu_load_error_t error, const char *path); +void loader_display_logo(void); +void loader_display_message(const char *message); +void loader_display_error_and_halt(menu_load_error_t error, const char *message); #endif diff --git a/sw/bootloader/src/main.c b/sw/bootloader/src/main.c index dc84e9d..e278996 100644 --- a/sw/bootloader/src/main.c +++ b/sw/bootloader/src/main.c @@ -4,11 +4,32 @@ #include "sc64/sc64_sd_fs.h" -static const char *MENU_FILE_PATH = "SC64/MENU.z64"; +#define DEFAULT_MENU_FILE_PATH "SC64/MENU.z64\0"; + + +static const char *CONFIG_FILE_PATH = "SC64/config.txt"; + + +static menu_load_error_t convert_error(sc64_sd_fs_error_t sd_fs_error) { + switch (sd_fs_error) { + case SC64_SD_FS_NO_CARD: + return E_MENU_ERROR_NO_CARD; + case SC64_SD_FS_NO_FILESYSTEM: + return E_MENU_ERROR_NO_FILESYSTEM; + case SC64_SD_FS_NO_FILE: + return E_MENU_ERROR_NO_FILE; + case SC64_SD_FS_READ_ERROR: + return E_MENU_ERROR_READ_ERROR; + case SC64_SD_FS_OTHER_ERROR: + return E_MENU_ERROR_OTHER_ERROR; + default: + return E_MENU_OK; + } +} int main(void) { - loader_init(); + OS_BOOT_CONFIG->tv_type = TV_NTSC; if (sc64_get_version() != SC64_CART_VERSION_A) { loader_display_error_and_halt(E_MENU_ERROR_NOT_SC64, ""); @@ -18,40 +39,99 @@ int main(void) { uint32_t boot_mode = sc64_get_boot_mode(); - uint32_t skip_menu = (boot_mode & SC64_CART_BOOT_SKIP_MENU); - uint32_t cic_seed_override = (boot_mode & SC64_CART_BOOT_CIC_SEED_OVERRIDE); - uint32_t tv_type_override = (boot_mode & SC64_CART_BOOT_TV_TYPE_OVERRIDE); - uint32_t ddipl_override = (boot_mode & SC64_CART_BOOT_DDIPL_OVERRIDE); + bool skip_menu = (boot_mode & SC64_CART_BOOT_SKIP_MENU); + bool cic_seed_override = (boot_mode & SC64_CART_BOOT_CIC_SEED_OVERRIDE); + bool tv_type_override = (boot_mode & SC64_CART_BOOT_TV_TYPE_OVERRIDE); + bool ddipl_override = (boot_mode & SC64_CART_BOOT_DDIPL_OVERRIDE); + bool rom_loaded = (boot_mode & SC64_CART_BOOT_ROM_LOADED); tv_type_t tv_type = ((boot_mode & SC64_CART_BOOT_TV_TYPE_MASK) >> SC64_CART_BOOT_TV_TYPE_BIT); uint16_t cic_seed = ((boot_mode & SC64_CART_BOOT_CIC_SEED_MASK) >> SC64_CART_BOOT_CIC_SEED_BIT); if (!skip_menu) { - sc64_sd_fs_error_t sd_error = sc64_sd_fs_load_rom(MENU_FILE_PATH); + char rom_path[256] = DEFAULT_MENU_FILE_PATH; + char save_path[256] = "\0"; + sc64_sd_fs_error_t sd_fs_error; + sc64_sd_fs_config_t config = { + .rom = rom_path, + .rom_reload = false, + .save = save_path, + .save_type = 0, + .save_writeback = false, + .cic_seed = 0xFFFF, + .tv_type = -1, + }; - menu_load_error_t error = E_MENU_OK; - - switch (sd_error) { - case SC64_SD_FS_NO_CARD: - error = E_MENU_ERROR_NO_CARD; - break; - case SC64_SD_FS_NO_FILESYSTEM: - error = E_MENU_ERROR_NO_FILESYSTEM; - break; - case SC64_SD_FS_NO_FILE: - error = E_MENU_ERROR_NO_FILE; - break; - case SC64_SD_FS_READ_ERROR: - error = E_MENU_ERROR_READ_ERROR; - break; - case SC64_SD_FS_OTHER_ERROR: - error = E_MENU_ERROR_OTHER_ERROR; - break; - default: - break; + sd_fs_error = sc64_sd_fs_init(); + if (sd_fs_error != SC64_SD_FS_OK) { + loader_display_error_and_halt(convert_error(sd_fs_error), "sc64_sd_fs_init"); } - if (error != E_MENU_OK) { - loader_display_error_and_halt(error, MENU_FILE_PATH); + sd_fs_error = sc64_sd_fs_load_config(CONFIG_FILE_PATH, &config); + if ((sd_fs_error != SC64_SD_FS_OK) && (sd_fs_error != SC64_SD_FS_NO_FILE)) { + loader_display_error_and_halt(convert_error(sd_fs_error), "sc64_sd_fs_load_config"); + } + + if (config.cic_seed != 0xFFFF) { + cic_seed_override = true; + cic_seed = config.cic_seed; + } + + if (config.tv_type != -1) { + tv_type_override = true; + tv_type = config.tv_type; + } + + if (!rom_loaded || config.rom_reload) { + loader_display_logo(); + } + + if (config.save_type > 0) { + sc64_disable_eeprom(); + sc64_disable_sram(); + sc64_disable_flashram(); + + switch (config.save_type) { + case 1: sc64_enable_eeprom(false); break; + case 2: sc64_enable_eeprom(true); break; + case 3: sc64_enable_sram(false); break; + case 4: sc64_enable_sram(true); break; + case 5: sc64_enable_flashram(); break; + } + + if (config.save_type == 3) { + sc64_set_sram_address(SC64_SDRAM_SIZE - (32 * 1024)); + } else if (config.save_type == 4) { + sc64_set_sram_address(SC64_SDRAM_SIZE - (3 * 32 * 1024)); + } + + if (rom_loaded && (config.save[0] != '\0') && config.save_writeback) { + sd_fs_error = sc64_sd_fs_store_save(config.save); + if (sd_fs_error != SC64_SD_FS_OK) { + loader_display_error_and_halt(convert_error(sd_fs_error), "sc64_sd_fs_store_save"); + } + } + } + + if (!rom_loaded || config.rom_reload) { + sd_fs_error = sc64_sd_fs_load_rom(config.rom); + if (sd_fs_error != SC64_SD_FS_OK) { + loader_display_error_and_halt(convert_error(sd_fs_error), "sc64_sd_fs_load_rom"); + } + + sc64_set_boot_mode(boot_mode | SC64_CART_BOOT_ROM_LOADED); + } + + if ((config.save_type > 0) && (config.save[0] != '\0') && !rom_loaded) { + sd_fs_error = sc64_sd_fs_load_save(config.save); + if (sd_fs_error != SC64_SD_FS_OK) { + loader_display_error_and_halt(convert_error(sd_fs_error), "sc64_sd_fs_load_save"); + } + } + + sc64_sd_fs_deinit(); + + if (!rom_loaded || config.rom_reload) { + loader_cleanup(); } } @@ -61,7 +141,7 @@ int main(void) { sc64_disable_ddipl(); } - cart_header_t *cart_header = boot_load_cart_header(); + cart_header_t *cart_header = boot_load_cart_header(ddipl_override); if (!cic_seed_override) { cic_seed = boot_get_cic_seed(cart_header); @@ -71,7 +151,5 @@ int main(void) { tv_type = boot_get_tv_type(cart_header); } - loader_cleanup(); - boot(cart_header, cic_seed, tv_type, ddipl_override); } diff --git a/sw/bootloader/src/sc64/sc64.c b/sw/bootloader/src/sc64/sc64.c index aedc3b8..2dd6767 100644 --- a/sw/bootloader/src/sc64/sc64.c +++ b/sw/bootloader/src/sc64/sc64.c @@ -25,15 +25,23 @@ void sc64_set_scr(uint32_t scr) { platform_pi_io_write(&SC64_CART->SCR, scr); } +void sc64_enable_skip_bootloader(void) { + sc64_enable_peripheral(SC64_CART_SCR_SKIP_BOOTLOADER); +} + +void sc64_disable_skip_bootloader(void) { + sc64_disable_peripheral(SC64_CART_SCR_SKIP_BOOTLOADER); +} + void sc64_enable_flashram(void) { sc64_enable_peripheral(SC64_CART_SCR_FLASHRAM_ENABLE); } void sc64_disable_flashram(void) { sc64_disable_peripheral(SC64_CART_SCR_FLASHRAM_ENABLE); -} +} -void sc64_enable_sram(uint8_t mode_768k) { +void sc64_enable_sram(bool mode_768k) { sc64_enable_peripheral(SC64_CART_SCR_SRAM_ENABLE); if (mode_768k) { sc64_enable_peripheral(SC64_CART_SCR_SRAM_768K_MODE); @@ -62,7 +70,7 @@ void sc64_disable_eeprom_pi(void) { sc64_disable_peripheral(SC64_CART_SCR_EEPROM_PI_ENABLE); } -void sc64_enable_eeprom(uint8_t mode_16k) { +void sc64_enable_eeprom(bool mode_16k) { sc64_enable_peripheral(SC64_CART_SCR_EEPROM_ENABLE); if (mode_16k) { sc64_enable_peripheral(SC64_CART_SCR_EEPROM_16K_MODE); diff --git a/sw/bootloader/src/sc64/sc64.h b/sw/bootloader/src/sc64/sc64.h index c29d5ad..0b30bee 100644 --- a/sw/bootloader/src/sc64/sc64.h +++ b/sw/bootloader/src/sc64/sc64.h @@ -10,15 +10,17 @@ uint32_t sc64_get_scr(void); void sc64_set_scr(uint32_t scr); +void sc64_enable_skip_bootloader(void); +void sc64_disable_skip_bootloader(void); void sc64_enable_flashram(void); void sc64_disable_flashram(void); -void sc64_enable_sram(uint8_t mode_768k); +void sc64_enable_sram(bool mode_768k); void sc64_disable_sram(void); void sc64_enable_sd(void); void sc64_disable_sd(void); void sc64_enable_eeprom_pi(void); void sc64_disable_eeprom_pi(void); -void sc64_enable_eeprom(uint8_t mode_16k); +void sc64_enable_eeprom(bool mode_16k); void sc64_disable_eeprom(void); void sc64_enable_ddipl(void); void sc64_disable_ddipl(void); diff --git a/sw/bootloader/src/sc64/sc64_regs.h b/sw/bootloader/src/sc64/sc64_regs.h index 98869c0..03d7d53 100644 --- a/sw/bootloader/src/sc64/sc64_regs.h +++ b/sw/bootloader/src/sc64/sc64_regs.h @@ -36,6 +36,7 @@ typedef struct sc64_cart_registers { #define SC64_CART ((__IO sc64_cart_registers_t *) SC64_CART_BASE) +#define SC64_CART_SCR_SKIP_BOOTLOADER (1 << 10) #define SC64_CART_SCR_FLASHRAM_ENABLE (1 << 9) #define SC64_CART_SCR_SRAM_768K_MODE (1 << 8) #define SC64_CART_SCR_SRAM_ENABLE (1 << 7) @@ -101,7 +102,7 @@ typedef struct sc64_eeprom_registers { __IO reg_t MEM[512]; // EEPROM memory } sc64_eeprom_registers_t; -#define SC64_EEPROM_BASE (0x1E004000) +#define SC64_EEPROM_BASE (0x1E010000) #define SC64_EEPROM ((__IO sc64_eeprom_registers_t *) SC64_EEPROM_BASE) @@ -121,7 +122,7 @@ typedef struct sc64_sd_registers_s { __IO reg_t FIFO[128]; // SD data path FIFO buffer } sc64_sd_registers_t; -#define SC64_SD_BASE (0x1E008000) +#define SC64_SD_BASE (0x1E020000) #define SC64_SD ((__IO sc64_sd_registers_t *) SC64_SD_BASE) @@ -146,10 +147,12 @@ typedef struct sc64_sd_registers_s { #define SC64_SD_DAT_TX_FIFO_ITEMS_GET(dat) (((dat) >> 17) & 0x1FF) +#define SC64_SD_DAT_TX_FIFO_BYTES_GET(dat) (SC64_SD_DAT_TX_FIFO_ITEMS_GET(dat) * 4) #define SC64_SD_DAT_TX_FIFO_FULL (1 << 16) #define SC64_SD_DAT_TX_FIFO_EMPTY (1 << 15) #define SC64_SD_DAT_TX_FIFO_UNDERRUN (1 << 14) #define SC64_SD_DAT_RX_FIFO_ITEMS_GET(dat) (((dat) >> 5) & 0x1FF) +#define SC64_SD_DAT_RX_FIFO_BYTES_GET(dat) (SC64_SD_DAT_RX_FIFO_ITEMS_GET(dat) * 4) #define SC64_SD_DAT_RX_FIFO_FULL (1 << 4) #define SC64_SD_DAT_RX_FIFO_EMPTY (1 << 3) #define SC64_SD_DAT_RX_FIFO_OVERRUN (1 << 2) @@ -164,6 +167,10 @@ typedef struct sc64_sd_registers_s { #define SC64_SD_DAT_STOP (1 << 1) #define SC64_SD_DAT_START (1 << 0) +#define SC64_SD_DAT_FIFO_SIZE_BYTES (1024) +#define SC64_SD_DAT_NUM_BLOCKS_MAX (256) +#define SC64_SD_DAT_BLOCK_SIZE_MAX (512) + #define SC64_SD_DMA_SCR_BUSY (1 << 0) @@ -181,5 +188,7 @@ typedef struct sc64_sd_registers_s { #define SC64_SD_DMA_LEN(l) ((((l) / 4) - 1) & 0x7FFF) +#define SC64_SD_DMA_LEN_MAX (0x20000) + #endif diff --git a/sw/bootloader/src/sc64/sc64_sd.c b/sw/bootloader/src/sc64/sc64_sd.c index 40944f2..5c413d6 100644 --- a/sw/bootloader/src/sc64/sc64_sd.c +++ b/sw/bootloader/src/sc64/sc64_sd.c @@ -15,8 +15,6 @@ #define SD_BLOCK_SIZE (512) -#define MAX_NUM_BLOCKS (256) - typedef enum sc64_sd_clock_e { CLOCK_STOP, @@ -44,6 +42,11 @@ typedef enum sc64_sd_dat_direction_e { DAT_DIR_TX, } sc64_sd_dat_direction_t; +typedef enum sc64_sd_dma_direction_e { + DMA_DIR_MEM, + DMA_DIR_CARD, +} sc64_sd_dma_direction_t; + static bool sd_card_initialized = false; static bool sd_card_type_block = false; @@ -85,26 +88,24 @@ static void sc64_sd_set_dat_width(sc64_sd_dat_width_t dat_width) { platform_pi_io_write(&SC64_SD->SCR, scr); } -static void sc64_sd_hw_init(void) { - sc64_enable_sd(); - +static void sc64_sd_hw_reset(void) { while (platform_pi_io_read(&SC64_SD->CMD) & SC64_SD_CMD_BUSY); platform_pi_io_write(&SC64_SD->DMA_SCR, SC64_SD_DMA_SCR_STOP); platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_TX_FIFO_FLUSH | SC64_SD_DAT_RX_FIFO_FLUSH | SC64_SD_DAT_STOP); platform_pi_io_write(&SC64_SD->SCR, 0); +} +static void sc64_sd_hw_init(void) { + sc64_enable_sd(); + sc64_sd_hw_reset(); sc64_sd_set_clock(CLOCK_400_KHZ); sc64_sd_set_dat_width(DAT_WIDTH_1BIT); } static void sc64_sd_hw_deinit(void) { if (sc64_get_scr() & SC64_CART_SCR_SD_ENABLE) { - while (platform_pi_io_read(&SC64_SD->CMD) & SC64_SD_CMD_BUSY); - platform_pi_io_write(&SC64_SD->DMA_SCR, SC64_SD_DMA_SCR_STOP); - platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_TX_FIFO_FLUSH | SC64_SD_DAT_RX_FIFO_FLUSH | SC64_SD_DAT_STOP); - platform_pi_io_write(&SC64_SD->SCR, 0); + sc64_sd_hw_reset(); } - sc64_disable_sd(); } @@ -176,22 +177,24 @@ static sc64_sd_err_t sc64_sd_dat_read(size_t block_size, void *buffer) { int timeout; uint32_t reg; - timeout = 100000; + timeout = 1000000; do { reg = platform_pi_io_read(&SC64_SD->DAT); - if (SC64_SD_DAT_RX_FIFO_ITEMS_GET(reg) >= block_size) { + if (SC64_SD_DAT_RX_FIFO_BYTES_GET(reg) >= block_size) { break; } } while ((reg & SC64_SD_DAT_BUSY) && (--timeout)); - if (reg & SC64_SD_DAT_CRC_ERROR) { - return E_CRC_ERROR; - } + if (!(reg & SC64_SD_DAT_BUSY)) { + if (reg & SC64_SD_DAT_CRC_ERROR) { + return E_CRC_ERROR; + } - if (reg & SC64_SD_DAT_RX_FIFO_OVERRUN) { - platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_RX_FIFO_FLUSH); + if (reg & SC64_SD_DAT_RX_FIFO_OVERRUN) { + platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_RX_FIFO_FLUSH); - return E_FIFO_ERROR; + return E_FIFO_ERROR; + } } if (timeout == 0) { @@ -206,6 +209,64 @@ static sc64_sd_err_t sc64_sd_dat_read(size_t block_size, void *buffer) { return E_OK; } +static sc64_sd_err_t sc64_sd_dat_write(size_t block_size, void *buffer) { + int timeout; + uint32_t reg; + + timeout = 1000000; + do { + reg = platform_pi_io_read(&SC64_SD->DAT); + if ((SC64_SD_DAT_FIFO_SIZE_BYTES - SC64_SD_DAT_TX_FIFO_BYTES_GET(reg)) >= block_size) { + break; + } + } while ((reg & SC64_SD_DAT_BUSY) && (--timeout)); + + if (!(reg & SC64_SD_DAT_BUSY)) { + if (reg & SC64_SD_DAT_CRC_ERROR) { + return E_CRC_ERROR; + } + + if (reg & SC64_SD_DAT_TX_FIFO_UNDERRUN) { + platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_TX_FIFO_FLUSH); + + return E_FIFO_ERROR; + } + } + + if (timeout == 0) { + sc64_sd_dat_abort(); + + return E_TIMEOUT; + } + + platform_pi_dma_write(buffer, &SC64_SD->FIFO, block_size); + platform_cache_invalidate(buffer, block_size); + + return E_OK; +} + +static void sc64_sd_dma_prepare(size_t num_blocks, size_t block_size, sc64_sd_dma_direction_t direction, uint8_t bank, uint32_t address) { + platform_pi_io_write(&SC64_SD->DMA_ADDR, SC64_SD_DMA_BANK_ADDR(bank, address)); + platform_pi_io_write(&SC64_SD->DMA_LEN, SC64_SD_DMA_LEN(num_blocks * block_size)); + platform_pi_io_write(&SC64_SD->DMA_SCR, (direction == DMA_DIR_MEM ? SC64_SD_DMA_SCR_DIRECTION : 0) | SC64_SD_DMA_SCR_START); +} + +static void sc64_sd_dma_abort(void) { + platform_pi_io_write(&SC64_SD->DMA_SCR, SC64_SD_DMA_SCR_STOP); +} + +static sc64_sd_err_t sc64_sd_sectors_parameters_check(size_t count, uint8_t *buffer, bool check_buffer) { + if (!sd_card_initialized) { + return E_NO_INIT; + } + + if ((count == 0) || (check_buffer && (buffer == NULL))) { + return E_PAR_ERROR; + } + + return E_OK; +} + bool sc64_sd_init(void) { sc64_sd_err_t error; @@ -316,23 +377,18 @@ void sc64_sd_deinit(void) { sc64_sd_hw_deinit(); } -bool sc64_sd_get_status(void) { +bool sc64_sd_status_get(void) { return sd_card_initialized; } -sc64_sd_err_t sc64_sd_read_sectors(uint32_t starting_sector, size_t count, void *buffer) { +sc64_sd_err_t sc64_sd_sectors_read(uint32_t starting_sector, size_t count, uint8_t *buffer) { sc64_sd_err_t error; uint32_t response; uint32_t current_sector; - uint32_t reg; - int timeout; - if (!sd_card_initialized) { - return E_NO_INIT; - } - - if ((count == 0) || (buffer == NULL)) { - return E_PAR_ERROR; + error = sc64_sd_sectors_parameters_check(count, buffer, true); + if (error != E_OK) { + return error; } current_sector = starting_sector; @@ -341,39 +397,20 @@ sc64_sd_err_t sc64_sd_read_sectors(uint32_t starting_sector, size_t count, void } for (size_t i = 0; i < count; i++) { - platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_NUM_BLOCKS(1) | SC64_SD_DAT_BLOCK_SIZE(SD_BLOCK_SIZE) | SC64_SD_DAT_START); + sc64_sd_dat_prepare(1, SD_BLOCK_SIZE, DAT_DIR_RX); error = sc64_sd_cmd_send(17, current_sector, NO_FLAGS, &response); if (error != E_OK) { - platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_RX_FIFO_FLUSH | SC64_SD_DAT_STOP); + sc64_sd_dat_abort(); return error; } - timeout = 100000; - do { - reg = platform_pi_io_read(&SC64_SD->DAT); - } while ((reg & SC64_SD_DAT_BUSY) && (--timeout)); - - if (reg & SC64_SD_DAT_CRC_ERROR) { - return E_CRC_ERROR; + error = sc64_sd_dat_read(SD_BLOCK_SIZE, buffer); + if (error != E_OK) { + return error; } - if (reg & SC64_SD_DAT_RX_FIFO_OVERRUN) { - platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_RX_FIFO_FLUSH); - - return E_FIFO_ERROR; - } - - if (timeout == 0) { - platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_RX_FIFO_FLUSH | SC64_SD_DAT_STOP); - - return E_TIMEOUT; - } - - platform_pi_dma_read(buffer, &SC64_SD->FIFO, SD_BLOCK_SIZE); - platform_cache_invalidate(buffer, SD_BLOCK_SIZE); - buffer += SD_BLOCK_SIZE; current_sector += sd_card_type_block ? 1 : SD_BLOCK_SIZE; } @@ -381,7 +418,44 @@ sc64_sd_err_t sc64_sd_read_sectors(uint32_t starting_sector, size_t count, void return E_OK; } -sc64_sd_err_t sc64_sd_read_sectors_dma(uint32_t starting_sector, size_t count, uint8_t bank, uint32_t address) { +sc64_sd_err_t sc64_sd_sectors_write(uint32_t starting_sector, size_t count, uint8_t *buffer) { + sc64_sd_err_t error; + uint32_t response; + uint32_t current_sector; + + error = sc64_sd_sectors_parameters_check(count, buffer, true); + if (error != E_OK) { + return error; + } + + current_sector = starting_sector; + if (!sd_card_type_block) { + current_sector *= SD_BLOCK_SIZE; + } + + for (size_t i = 0; i < count; i++) { + sc64_sd_dat_prepare(1, SD_BLOCK_SIZE, DAT_DIR_TX); + + error = sc64_sd_cmd_send(24, current_sector, NO_FLAGS, &response); + if (error != E_OK) { + sc64_sd_dat_abort(); + + return error; + } + + error = sc64_sd_dat_write(SD_BLOCK_SIZE, buffer); + if (error != E_OK) { + return error; + } + + buffer += SD_BLOCK_SIZE; + current_sector += sd_card_type_block ? 1 : SD_BLOCK_SIZE; + } + + return E_OK; +} + +sc64_sd_err_t sc64_sd_sectors_read_dma(uint32_t starting_sector, size_t count, uint8_t bank, uint32_t address) { size_t sectors_left; uint32_t current_sector; uint32_t current_address; @@ -391,12 +465,9 @@ sc64_sd_err_t sc64_sd_read_sectors_dma(uint32_t starting_sector, size_t count, u uint32_t response; int timeout; - if (!sd_card_initialized) { - return E_NO_INIT; - } - - if (count == 0) { - return E_PAR_ERROR; + error = sc64_sd_sectors_parameters_check(count, NULL, false); + if (error != E_OK) { + return error; } sectors_left = count; @@ -407,16 +478,15 @@ sc64_sd_err_t sc64_sd_read_sectors_dma(uint32_t starting_sector, size_t count, u current_address = address; do { - num_blocks = (sectors_left > MAX_NUM_BLOCKS) ? MAX_NUM_BLOCKS : sectors_left; + num_blocks = (sectors_left > SC64_SD_DAT_NUM_BLOCKS_MAX) ? SC64_SD_DAT_NUM_BLOCKS_MAX : sectors_left; - platform_pi_io_write(&SC64_SD->DMA_ADDR, SC64_SD_DMA_BANK_ADDR(bank, current_address)); - platform_pi_io_write(&SC64_SD->DMA_LEN, SC64_SD_DMA_LEN(num_blocks * SD_BLOCK_SIZE)); - platform_pi_io_write(&SC64_SD->DMA_SCR, SC64_SD_DMA_SCR_DIRECTION | SC64_SD_DMA_SCR_START); - platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_NUM_BLOCKS(num_blocks) | SC64_SD_DAT_BLOCK_SIZE(SD_BLOCK_SIZE) | SC64_SD_DAT_START); + sc64_sd_dma_prepare(num_blocks, SD_BLOCK_SIZE, DMA_DIR_MEM, bank, current_address); + sc64_sd_dat_prepare(num_blocks, SD_BLOCK_SIZE, DAT_DIR_RX); error = sc64_sd_cmd_send(18, current_sector, NO_FLAGS, &response); if (error != E_OK) { - platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_RX_FIFO_FLUSH | SC64_SD_DAT_STOP); + sc64_sd_dat_abort(); + sc64_sd_dma_abort(); return error; } @@ -428,23 +498,28 @@ sc64_sd_err_t sc64_sd_read_sectors_dma(uint32_t starting_sector, size_t count, u error = sc64_sd_cmd_send(12, 0, NO_FLAGS, &response); if (error != E_OK) { + sc64_sd_dat_abort(); + sc64_sd_dma_abort(); + return error; } if (reg & SC64_SD_DAT_CRC_ERROR) { + sc64_sd_dma_abort(); + return E_CRC_ERROR; } if (reg & SC64_SD_DAT_RX_FIFO_OVERRUN) { platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_RX_FIFO_FLUSH); - platform_pi_io_write(&SC64_SD->DMA_SCR, SC64_SD_DMA_SCR_STOP); + sc64_sd_dma_abort(); return E_FIFO_ERROR; } if (timeout == 0) { - platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_RX_FIFO_FLUSH | SC64_SD_DAT_STOP); - platform_pi_io_write(&SC64_SD->DMA_SCR, SC64_SD_DMA_SCR_STOP); + sc64_sd_dat_abort(); + sc64_sd_dma_abort(); return E_TIMEOUT; } @@ -458,3 +533,80 @@ sc64_sd_err_t sc64_sd_read_sectors_dma(uint32_t starting_sector, size_t count, u return E_OK; } + +sc64_sd_err_t sc64_sd_sectors_write_dma(uint32_t starting_sector, size_t count, uint8_t bank, uint32_t address) { + size_t sectors_left; + uint32_t current_sector; + uint32_t current_address; + uint32_t num_blocks; + uint32_t reg; + sc64_sd_err_t error; + uint32_t response; + int timeout; + + error = sc64_sd_sectors_parameters_check(count, NULL, false); + if (error != E_OK) { + return error; + } + + sectors_left = count; + current_sector = starting_sector; + if (!sd_card_type_block) { + current_sector *= SD_BLOCK_SIZE; + } + current_address = address; + + do { + num_blocks = (sectors_left > SC64_SD_DAT_NUM_BLOCKS_MAX) ? SC64_SD_DAT_NUM_BLOCKS_MAX : sectors_left; + + sc64_sd_dat_prepare(num_blocks, SD_BLOCK_SIZE, DAT_DIR_TX); + sc64_sd_dma_prepare(num_blocks, SD_BLOCK_SIZE, DMA_DIR_CARD, bank, current_address); + + error = sc64_sd_cmd_send(25, current_sector, NO_FLAGS, &response); + if (error != E_OK) { + sc64_sd_dma_abort(); + sc64_sd_dat_abort(); + + return error; + } + + timeout = 1000000; + do { + reg = platform_pi_io_read(&SC64_SD->DAT); + } while ((reg & SC64_SD_DAT_BUSY) && (--timeout)); + + error = sc64_sd_cmd_send(12, 0, NO_FLAGS, &response); + if (error != E_OK) { + sc64_sd_dma_abort(); + sc64_sd_dat_abort(); + + return error; + } + + if (reg & SC64_SD_DAT_CRC_ERROR) { + sc64_sd_dma_abort(); + + return E_CRC_ERROR; + } + + if (reg & SC64_SD_DAT_TX_FIFO_UNDERRUN) { + sc64_sd_dma_abort(); + platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_TX_FIFO_FLUSH); + + return E_FIFO_ERROR; + } + + if (timeout == 0) { + sc64_sd_dma_abort(); + sc64_sd_dat_abort(); + + return E_TIMEOUT; + } + + sectors_left -= num_blocks; + current_sector += num_blocks * (sd_card_type_block ? 1 : SD_BLOCK_SIZE); + current_address += num_blocks * SD_BLOCK_SIZE; + } while (sectors_left > 0); + + return E_OK; +} diff --git a/sw/bootloader/src/sc64/sc64_sd.h b/sw/bootloader/src/sc64/sc64_sd.h index 131d5dc..ece6052 100644 --- a/sw/bootloader/src/sc64/sc64_sd.h +++ b/sw/bootloader/src/sc64/sc64_sd.h @@ -18,9 +18,11 @@ typedef enum sc64_sd_err_e { bool sc64_sd_init(void); void sc64_sd_deinit(void); -bool sc64_sd_get_status(void); -sc64_sd_err_t sc64_sd_read_sectors(uint32_t starting_sector, size_t count, void *buffer); -sc64_sd_err_t sc64_sd_read_sectors_dma(uint32_t starting_sector, size_t count, uint8_t bank, uint32_t address); +bool sc64_sd_status_get(void); +sc64_sd_err_t sc64_sd_sectors_read(uint32_t starting_sector, size_t count, uint8_t *buffer); +sc64_sd_err_t sc64_sd_sectors_write(uint32_t starting_sector, size_t count, uint8_t *buffer); +sc64_sd_err_t sc64_sd_sectors_read_dma(uint32_t starting_sector, size_t count, uint8_t bank, uint32_t address); +sc64_sd_err_t sc64_sd_sectors_write_dma(uint32_t starting_sector, size_t count, uint8_t bank, uint32_t address); #endif diff --git a/sw/bootloader/src/sc64/sc64_sd_fs.c b/sw/bootloader/src/sc64/sc64_sd_fs.c index 6d38ce8..e4fc0e3 100644 --- a/sw/bootloader/src/sc64/sc64_sd_fs.c +++ b/sw/bootloader/src/sc64/sc64_sd_fs.c @@ -5,69 +5,234 @@ #include "sc64_sd.h" #include "sc64_sd_fs.h" +#include +#include -static DRESULT sc64_sd_fs_load_rom_with_dma(BYTE pdrv, FSIZE_t offset, LBA_t sector, UINT count) { - if ((pdrv > 0) || (count == 0)) { + +static uint8_t current_bank = SC64_BANK_INVALID; +static uint32_t current_offset = 0; +static uint8_t save_buffer[128 * 1024] __attribute__((aligned(16))); + + +static DRESULT sc64_sd_fs_load_with_dma(BYTE pdrv, FSIZE_t offset, LBA_t sector, UINT count) { + sc64_sd_err_t error; + + if (pdrv > 0) { return RES_PARERR; } - if (!sc64_sd_get_status()) { - return RES_NOTRDY; - } - - if (sc64_sd_read_sectors_dma(sector, count, SC64_BANK_SDRAM, offset) != E_OK) { - return RES_ERROR; + error = sc64_sd_sectors_read_dma(sector, count, current_bank, current_offset + offset); + + if (error != E_OK) { + switch (error) { + case E_NO_INIT: + return RES_NOTRDY; + case E_PAR_ERROR: + return RES_PARERR; + default: + return RES_ERROR; + } } return RES_OK; } -sc64_sd_fs_error_t sc64_sd_fs_load_rom(const char *path) { + +static bool fs_initialized = false; +static FATFS fatfs; + + +sc64_sd_fs_error_t sc64_sd_fs_init(void) { FRESULT fresult; - FATFS fatfs; - - sc64_sd_fs_error_t error = SC64_SD_FS_OK; - - do { - fresult = f_mount(&fatfs, "", 1); - if (fresult != FR_OK) { - switch (fresult) { - case FR_DISK_ERR: - case FR_NOT_READY: - error = SC64_SD_FS_NO_CARD; - break; - case FR_NO_FILESYSTEM: - error = SC64_SD_FS_NO_FILESYSTEM; - break; - default: - error = SC64_SD_FS_OTHER_ERROR; - break; - } - break; + + fresult = f_mount(&fatfs, "", 1); + if (fresult != FR_OK) { + switch (fresult) { + case FR_DISK_ERR: + return SC64_SD_FS_READ_ERROR; + case FR_NOT_READY: + return SC64_SD_FS_NO_CARD; + case FR_NO_FILESYSTEM: + return SC64_SD_FS_NO_FILESYSTEM; + default: + return SC64_SD_FS_OTHER_ERROR; } + } - fresult = fe_load(path, SC64_SDRAM_SIZE, sc64_sd_fs_load_rom_with_dma); - if (fresult) { - switch (fresult) { - case FR_DISK_ERR: - case FR_NOT_READY: - error = SC64_SD_FS_READ_ERROR; - break; - case FR_NO_FILE: - case FR_NO_PATH: - error = SC64_SD_FS_NO_FILE; - break; - default: - error = SC64_SD_FS_OTHER_ERROR; - break; - } - break; - } - } while (0); + fs_initialized = true; - f_unmount(""); + return SC64_SD_FS_OK; +} + +void sc64_sd_fs_deinit(void) { + if (fs_initialized) { + f_unmount(""); + } sc64_sd_deinit(); - - return error; +} + +sc64_sd_fs_error_t sc64_sd_fs_load_config(const char *path, sc64_sd_fs_config_t *config) { + FRESULT fresult; + FIL fil; + char config_buffer[256]; + + fresult = f_open(&fil, path, FA_READ); + if (fresult != FR_OK) { + switch (fresult) { + case FR_DISK_ERR: + case FR_NOT_READY: + return SC64_SD_FS_READ_ERROR; + case FR_NO_FILE: + case FR_NO_PATH: + return SC64_SD_FS_NO_FILE; + default: + return SC64_SD_FS_OTHER_ERROR; + } + } + + while (!f_eof(&fil)) { + char *line = f_gets(config_buffer, sizeof(config_buffer), &fil); + + if (line == NULL) { + break; + } + + if (strncmp("rom=", line, 4) == 0) { + strncpy(config->rom, line + 4, sizeof(config_buffer) - 4); + } else if (strncmp("rom_reload=", line, 11) == 0) { + config->rom_reload = line[11] != '0'; + } else if (strncmp("save=", line, 5) == 0) { + strncpy(config->save, line + 5, sizeof(config_buffer) - 5); + } else if (strncmp("save_type=", line, 10) == 0) { + config->save_type = (uint8_t) strtol(line + 10, NULL, 10); + } else if (strncmp("save_writeback=", line, 15) == 0) { + config->save_writeback = line[15] != '0'; + } else if (strncmp("cic_seed=", line, 9) == 0) { + config->cic_seed = (uint16_t) strtoul(line + 9, NULL, 16); + } else if (strncmp("tv_type=", line, 8) == 0) { + config->tv_type = (tv_type_t) strtol(line + 8, NULL, 10); + } + } + + fresult = f_close(&fil); + if (fresult != FR_OK) { + return SC64_SD_FS_OTHER_ERROR; + } + + return SC64_SD_FS_OK; +} + +sc64_sd_fs_error_t sc64_sd_fs_load_rom(const char *path) { + FRESULT fresult; + + current_bank = SC64_BANK_SDRAM; + current_offset = 0; + + fresult = fe_load(path, SC64_SDRAM_SIZE, sc64_sd_fs_load_with_dma); + if (fresult != FR_OK) { + switch (fresult) { + case FR_DISK_ERR: + case FR_NOT_READY: + return SC64_SD_FS_READ_ERROR; + case FR_NO_FILE: + case FR_NO_PATH: + return SC64_SD_FS_NO_FILE; + default: + return SC64_SD_FS_OTHER_ERROR; + } + } + + return SC64_SD_FS_OK; +} + +sc64_sd_fs_error_t sc64_sd_fs_load_save(const char *path) { + FRESULT fresult; + uint32_t scr; + size_t length; + + scr = sc64_get_scr(); + length = 0; + + if (scr & SC64_CART_SCR_EEPROM_ENABLE) { + length = (scr & SC64_CART_SCR_EEPROM_16K_MODE) ? 2048 : 512; + current_bank = SC64_BANK_EEPROM; + current_offset = 0; + } else if (scr & SC64_CART_SCR_SRAM_ENABLE) { + length = ((scr & SC64_CART_SCR_SRAM_768K_MODE) ? 3 : 1) * (32 * 1024); + current_bank = SC64_BANK_SDRAM; + current_offset = sc64_get_sram_address(); + } else if (scr & SC64_CART_SCR_FLASHRAM_ENABLE) { // TODO: FlashRAM + length = 0; + current_bank = SC64_BANK_FLASHRAM; + current_offset = 0; + } + + if ((length == 0) || (path == NULL)) { + return SC64_SD_FS_OK; + } + + fresult = fe_load(path, length, sc64_sd_fs_load_with_dma); + if (fresult != FR_OK) { + switch (fresult) { + case FR_DISK_ERR: + case FR_NOT_READY: + return SC64_SD_FS_READ_ERROR; + case FR_NO_FILE: + case FR_NO_PATH: + return SC64_SD_FS_NO_FILE; + default: + return SC64_SD_FS_OTHER_ERROR; + } + } + + return SC64_SD_FS_OK; +} + +sc64_sd_fs_error_t sc64_sd_fs_store_save(const char *path) { + FRESULT fresult; + FIL fil; + UINT written; + uint32_t scr; + size_t length; + + scr = sc64_get_scr(); + length = 0; + + if (scr & SC64_CART_SCR_EEPROM_ENABLE) { + sc64_enable_eeprom_pi(); + length = (scr & SC64_CART_SCR_EEPROM_16K_MODE) ? 2048 : 512; + platform_pi_dma_read(save_buffer, &SC64_EEPROM->MEM, length); + platform_cache_invalidate(save_buffer, length); + sc64_disable_eeprom_pi(); + } else if (scr & SC64_CART_SCR_SRAM_ENABLE) { + length = ((scr & SC64_CART_SCR_SRAM_768K_MODE) ? 3 : 1) * (32 * 1024); + platform_pi_dma_read(save_buffer, sc64_get_sram_address(), length); + platform_cache_invalidate(save_buffer, length); + } else if (scr & SC64_CART_SCR_FLASHRAM_ENABLE) { // TODO: FlashRAM + length = 0; + // platform_pi_dma_read(save_buffer, 0, length); + // platform_cache_invalidate(save_buffer, length); + } + + if ((length == 0) || (path == NULL)) { + return SC64_SD_FS_OK; + } + + fresult = f_open(&fil, path, FA_CREATE_ALWAYS | FA_WRITE); + if (fresult != FR_OK) { + return SC64_SD_FS_WRITE_ERROR; + } + + fresult = f_write(&fil, save_buffer, length, &written); + if (fresult != FR_OK) { + return SC64_SD_FS_WRITE_ERROR; + } + + fresult = f_close(&fil); + if (fresult != FR_OK) { + return SC64_SD_FS_WRITE_ERROR; + } + + return SC64_SD_FS_OK; } diff --git a/sw/bootloader/src/sc64/sc64_sd_fs.h b/sw/bootloader/src/sc64/sc64_sd_fs.h index 1923cfa..95899e9 100644 --- a/sw/bootloader/src/sc64/sc64_sd_fs.h +++ b/sw/bootloader/src/sc64/sc64_sd_fs.h @@ -12,10 +12,27 @@ typedef enum sc64_sd_fs_error_e { SC64_SD_FS_NO_FILE, SC64_SD_FS_READ_ERROR, SC64_SD_FS_OTHER_ERROR, + SC64_SD_FS_WRITE_ERROR, } sc64_sd_fs_error_t; +typedef struct sc64_sd_fs_config_s { + char *rom; + char *save; + uint8_t save_type; + bool save_writeback; + bool rom_reload; + uint16_t cic_seed; + tv_type_t tv_type; +} sc64_sd_fs_config_t; + + +sc64_sd_fs_error_t sc64_sd_fs_init(void); +void sc64_sd_fs_deinit(void); +sc64_sd_fs_error_t sc64_sd_fs_load_config(const char *path, sc64_sd_fs_config_t *config); sc64_sd_fs_error_t sc64_sd_fs_load_rom(const char *path); +sc64_sd_fs_error_t sc64_sd_fs_load_save(const char *path); +sc64_sd_fs_error_t sc64_sd_fs_store_save(const char *path); #endif