2021-09-25 20:00:36 +02:00
|
|
|
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
|
2021-12-04 19:34:34 +01:00
|
|
|
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
|
2021-09-25 20:00:36 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
S_WAIT: begin
|
|
|
|
bus_state <= S_IDLE;
|
|
|
|
end
|
|
|
|
endcase
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
endmodule
|