module cart_control ( input i_clk, input i_reset, input i_n64_reset, input i_n64_nmi, input i_request, input i_write, output o_busy, output reg o_ack, input [10:0] i_address, output reg [31:0] o_data, input [31:0] i_data, output reg o_sdram_writable, output reg o_rom_switch, output reg o_ddipl_enable, output reg o_sram_enable, output reg o_flashram_enable, output reg o_sd_enable, output reg o_eeprom_pi_enable, output reg o_eeprom_enable, output reg o_eeprom_16k_mode, inout [7:0] io_gpio, input i_debug_ready, output reg o_debug_dma_start, input i_debug_dma_busy, output reg [3:0] o_debug_dma_bank, output reg [23:0] o_debug_dma_address, output reg [19:0] o_debug_dma_length, output reg o_debug_fifo_request, output reg o_debug_fifo_flush, input [10:0] i_debug_fifo_items, input [31:0] i_debug_fifo_data, output reg [23:0] o_ddipl_address, output reg [23:0] o_save_address ); // Module parameters parameter byte VERSION = "a"; // Register offsets localparam [3:0] REG_SCR = 4'd0; localparam [3:0] REG_BOOT = 4'd1; localparam [3:0] REG_VERSION = 4'd2; localparam [3:0] REG_GPIO = 4'd3; localparam [3:0] REG_USB_SCR = 4'd4; localparam [3:0] REG_USB_DMA_ADDR = 4'd5; localparam [3:0] REG_USB_DMA_LEN = 4'd6; localparam [3:0] REG_DDIPL_ADDR = 4'd7; localparam [3:0] REG_SAVE_ADDR = 4'd8; localparam [10:0] MEM_USB_FIFO_BASE = 11'h400; // Input synchronization reg r_reset_ff1, r_reset_ff2; reg r_nmi_ff1, r_nmi_ff2; always @(posedge i_clk) begin {r_reset_ff2, r_reset_ff1} <= {r_reset_ff1, i_n64_reset}; {r_nmi_ff2, r_nmi_ff1} <= {r_nmi_ff1, i_n64_nmi}; end // Registers reg [15:0] r_bootloader; reg r_skip_bootloader; reg r_sram_768k_mode; reg [7:0] r_gpio_o; reg [7:0] r_gpio_i; reg [7:0] r_gpio_dir; reg [7:0] r_gpio_od; // Bus controller assign o_busy = 1'b0; always @(posedge i_clk) begin o_ack <= !i_reset && i_request && !i_write && !o_busy; end // Write logic always @(posedge i_clk) begin o_debug_dma_start <= 1'b0; o_debug_fifo_flush <= 1'b0; if (i_reset) begin o_sdram_writable <= 1'b0; o_rom_switch <= 1'b0; o_ddipl_enable <= 1'b0; o_sram_enable <= 1'b0; o_flashram_enable <= 1'b0; o_sd_enable <= 1'b0; o_eeprom_pi_enable <= 1'b0; o_eeprom_enable <= 1'b0; o_eeprom_16k_mode <= 1'b0; o_ddipl_address <= 24'hEF_8000; o_save_address <= 24'hFF_8000; o_debug_dma_bank <= 4'd1; o_debug_dma_address <= 24'hCF_8000; o_debug_dma_length <= 20'd0; r_bootloader <= 16'h0000; r_skip_bootloader <= 1'b0; r_sram_768k_mode <= 1'b0; r_gpio_o <= 8'h00; r_gpio_dir <= 8'h00; r_gpio_od <= 8'h00; end else begin if (i_request && i_write && !o_busy) begin case (i_address[3:0]) REG_SCR: begin { r_skip_bootloader, o_sd_enable, o_flashram_enable, r_sram_768k_mode, o_sram_enable, o_eeprom_pi_enable, o_eeprom_16k_mode, o_eeprom_enable, o_ddipl_enable, o_sdram_writable, o_rom_switch } <= i_data[10:0]; end REG_BOOT: begin r_bootloader <= i_data[15:0]; end REG_GPIO: begin {r_gpio_od, r_gpio_dir, r_gpio_o} <= {i_data[31:16], i_data[7:0]}; end REG_USB_SCR: begin {o_debug_fifo_flush, o_debug_dma_start} <= {i_data[2], i_data[0]}; end REG_USB_DMA_ADDR: begin {o_debug_dma_bank, o_debug_dma_address} <= {i_data[31:28], i_data[25:2]}; end REG_USB_DMA_LEN: begin o_debug_dma_length <= i_data[19:0]; end REG_DDIPL_ADDR: begin o_ddipl_address <= i_data[25:2]; end REG_SAVE_ADDR: begin o_save_address <= i_data[25:2]; end default: begin end endcase end if (!r_reset_ff2 || !r_nmi_ff2) begin o_sdram_writable <= 1'b0; o_rom_switch <= r_skip_bootloader; o_debug_fifo_flush <= 1'b1; end end end // Read logic always @(posedge i_clk) begin o_debug_fifo_request <= 1'b0; 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[10:0] <= { r_skip_bootloader, o_sd_enable, o_flashram_enable, r_sram_768k_mode, o_sram_enable, o_eeprom_pi_enable, o_eeprom_16k_mode, o_eeprom_enable, o_ddipl_enable, o_sdram_writable, o_rom_switch }; end REG_BOOT: begin o_data[15:0] <= r_bootloader; end REG_VERSION: begin o_data <= {"S", "6", "4", VERSION}; end REG_GPIO: begin o_data[31:0] <= {r_gpio_od, r_gpio_dir, io_gpio, r_gpio_o}; end REG_USB_SCR: begin {o_data[13:3], o_data[1:0]} <= {i_debug_fifo_items, i_debug_ready, i_debug_dma_busy}; end REG_DDIPL_ADDR: begin o_data[25:0] <= {o_ddipl_address, 2'b00}; end REG_SAVE_ADDR: begin o_data[25:0] <= {o_save_address, 2'b00}; end default: begin end endcase end else begin o_data <= i_debug_fifo_data; o_debug_fifo_request <= 1'b1; end end end // GPIO logic always @(*) begin for (integer i = 0; i < 8; i = i + 1) begin if (r_gpio_dir[i] && (!r_gpio_od[i] || (r_gpio_od[i] && !r_gpio_o[i]))) begin io_gpio[i] = r_gpio_o[i]; end else begin io_gpio[i] = 1'bZ; end end end endmodule