module n64_flashram ( if_system.sys sys, if_n64_bus bus, if_config.flashram cfg, if_flashram.flashram flashram ); localparam [31:0] FLASH_TYPE_ID = 32'h1111_8001; localparam [31:0] FLASH_MODEL_ID = 32'h00C2_001D; typedef enum bit [7:0] { CMD_STATUS_MODE = 8'hD2, CMD_READID_MODE = 8'hE1, CMD_READ_MODE = 8'hF0, CMD_ERASE_SECTOR = 8'h4B, CMD_ERASE_CHIP = 8'h3C, CMD_BUFFER_MODE = 8'hB4, CMD_ERASE_START = 8'h78, CMD_WRITE_START = 8'hA5 } e_cmd; typedef enum bit [0:0] { S_IDLE, S_WAIT } e_bus_state; typedef enum bit [1:0] { FS_STATUS, FS_ID, FS_READ, FS_BUFFER } e_flashram_state; typedef enum bit [1:0] { B_WRITE_BUSY, B_ERASE_BUSY, B_WRITE_DONE, B_ERASE_DONE } e_flashram_status; e_bus_state bus_state; e_flashram_state flashram_state; logic [3:0] flashram_status; logic [7:0] flashram_command; logic flashram_erase_enabled; logic [31:0] write_buffer [0:31]; logic [1:0] write_buffer_wmask; logic [15:0] high_buffer; always_comb begin write_buffer_wmask = 2'b00; if (bus.request && bus.write && !bus.address[16] && flashram_state == FS_BUFFER) begin write_buffer_wmask[0] = !bus.address[1]; write_buffer_wmask[1] = bus.address[1]; end end always_ff @(posedge sys.clk) begin if (write_buffer_wmask[0]) high_buffer <= bus.wdata; end always_ff @(posedge sys.clk) begin flashram.rdata <= write_buffer[flashram.address]; if (write_buffer_wmask[1]) write_buffer[bus.address[6:2]] <= {high_buffer, bus.wdata}; end always_comb begin bus.rdata = 16'd0; if (bus.ack) begin if (bus.address[1]) begin bus.rdata = {12'd0, flashram_status}; end if (flashram_state == FS_ID) begin case (bus.address[2:1]) 0: bus.rdata = FLASH_TYPE_ID[31:16]; 1: bus.rdata = FLASH_TYPE_ID[15:0]; 2: bus.rdata = FLASH_MODEL_ID[31:16]; 3: bus.rdata = FLASH_MODEL_ID[15:0]; endcase end end cfg.flashram_read_mode = flashram_state == FS_READ; end always_ff @(posedge sys.clk) begin bus.ack <= 1'b0; if (sys.reset) begin bus_state <= S_IDLE; flashram_state <= FS_STATUS; flashram_status <= 4'b0000; flashram_erase_enabled <= 1'b0; flashram.operation_pending <= 1'b0; end else begin if (flashram.operation_done) begin flashram.operation_pending <= 1'b0; if (flashram.write_or_erase) begin flashram_status[B_ERASE_BUSY] <= 1'b0; flashram_status[B_ERASE_DONE] <= 1'b1; end else begin flashram_status[B_WRITE_BUSY] <= 1'b0; flashram_status[B_WRITE_DONE] <= 1'b1; end end case (bus_state) S_IDLE: begin if (bus.request) begin bus_state <= S_WAIT; bus.ack <= 1'b1; if (bus.write && !flashram.operation_pending) begin if (bus.address[16]) begin if (!bus.address[1]) begin flashram_command <= bus.wdata[15:8]; end else begin flashram_erase_enabled <= 1'b0; case (flashram_command) CMD_STATUS_MODE: begin flashram_state <= FS_STATUS; end CMD_READID_MODE: begin flashram_state <= FS_ID; end CMD_READ_MODE: begin flashram_state <= FS_READ; end CMD_ERASE_SECTOR: begin flashram_state <= FS_STATUS; flashram_erase_enabled <= 1'b1; flashram.sector <= bus.wdata[9:0]; flashram.sector_or_all <= 1'b0; end CMD_ERASE_CHIP: begin flashram_state <= FS_STATUS; flashram_erase_enabled <= 1'b1; flashram.sector <= 10'd0; flashram.sector_or_all <= 1'b1; end CMD_BUFFER_MODE: begin flashram_state <= FS_BUFFER; end CMD_ERASE_START: begin flashram_state <= FS_STATUS; if (flashram_erase_enabled) begin flashram_status[B_ERASE_BUSY] <= 1'b1; flashram_status[B_ERASE_DONE] <= 1'b0; flashram.operation_pending <= 1'b1; flashram.write_or_erase <= 1'b1; end end CMD_WRITE_START: begin flashram_state <= FS_STATUS; flashram_status[B_WRITE_BUSY] <= 1'b1; flashram_status[B_WRITE_DONE] <= 1'b0; flashram.sector <= bus.wdata[9:0]; flashram.operation_pending <= 1'b1; flashram.write_or_erase <= 1'b0; flashram.sector_or_all <= 1'b0; end endcase end end else begin if (bus.address[1] && flashram_state == FS_STATUS) begin flashram_status[B_ERASE_BUSY] <= bus.wdata[B_ERASE_BUSY]; flashram_status[B_WRITE_BUSY] <= bus.wdata[B_WRITE_BUSY]; end end end end end S_WAIT: begin bus_state <= S_IDLE; end endcase end end endmodule