SummerCart64/fw/rtl/flashram/flashram_controller.v
Polprzewodnikowy 790f30ae20 bug fix
2021-03-11 00:13:25 +01:00

302 lines
8.9 KiB
Verilog

`include "../constants.vh"
module flashram_controller (
input i_clk,
input i_reset,
input [23:0] i_save_address,
output o_flashram_read_mode,
input i_request,
input i_write,
output o_busy,
output reg o_ack,
input [14:0] i_address,
output reg [31:0] o_data,
input [31:0] i_data,
output reg o_mem_request,
output reg o_mem_write,
input i_mem_busy,
input i_mem_ack,
output reg [3:0] o_mem_bank,
output reg [23:0] o_mem_address,
output reg [31:0] o_mem_data,
input [31:0] i_mem_data
);
// State machine and command decoder
localparam [31:0] FLASH_TYPE_ID = 32'h1111_8001;
localparam [31:0] FLASH_MODEL_ID = 32'h00C2_001D;
localparam [7:0] CMD_STATUS_MODE = 8'hD2;
localparam [7:0] CMD_READID_MODE = 8'hE1;
localparam [7:0] CMD_READ_MODE = 8'hF0;
localparam [7:0] CMD_ERASE_SECTOR = 8'h4B;
localparam [7:0] CMD_ERASE_CHIP = 8'h3C;
localparam [7:0] CMD_WRITE_MODE = 8'hB4;
localparam [7:0] CMD_ERASE_START = 8'h78;
localparam [7:0] CMD_WRITE_START = 8'hA5;
localparam STATE_STATUS = 0;
localparam STATE_ID = 1;
localparam STATE_READ = 2;
localparam STATE_ERASE = 3;
localparam STATE_WRITE = 4;
localparam STATE_EXECUTE = 5;
localparam [1:0] EXECUTE_WRITE = 2'b00;
localparam [1:0] EXECUTE_ERASE_SECTOR = 2'b10;
localparam [1:0] EXECUTE_ERASE_CHIP = 2'b11;
reg [5:0] r_flashram_state;
reg [9:0] r_sector_offset;
reg [1:0] r_execute_mode;
reg r_execute_start;
reg r_execute_done;
assign o_flashram_read_mode = r_flashram_state[STATE_READ];
wire w_cmd_request = i_request && i_write && i_address[14] && !r_flashram_state[STATE_EXECUTE];
wire [7:0] w_cmd_op = i_data[31:24];
always @(posedge i_clk) begin
r_execute_start <= 1'b0;
if (i_reset || r_execute_done) begin
r_flashram_state <= (1'b1 << STATE_STATUS);
end else begin
if (w_cmd_request) begin
r_flashram_state <= 6'b000000;
if (w_cmd_op == CMD_STATUS_MODE) begin
r_flashram_state[STATE_STATUS] <= 1'b1;
end
if (w_cmd_op == CMD_READID_MODE) begin
r_flashram_state[STATE_ID] <= 1'b1;
end
if (w_cmd_op == CMD_READ_MODE) begin
r_flashram_state[STATE_READ] <= 1'b1;
end
if (w_cmd_op == CMD_ERASE_SECTOR) begin
r_flashram_state[STATE_ERASE] <= 1'b1;
r_sector_offset <= {i_data[9:7], 7'd0};
r_execute_mode <= EXECUTE_ERASE_SECTOR;
end
if (w_cmd_op == CMD_ERASE_CHIP) begin
r_flashram_state[STATE_ERASE] <= 1'b1;
r_sector_offset <= 10'd0;
r_execute_mode <= EXECUTE_ERASE_CHIP;
end
if (w_cmd_op == CMD_WRITE_MODE) begin
r_flashram_state[STATE_WRITE] <= 1'b1;
end
if (w_cmd_op == CMD_ERASE_START) begin
if (r_flashram_state[STATE_ERASE]) begin
r_flashram_state[STATE_EXECUTE] <= 1'b1;
r_execute_start <= 1'b1;
end
end
if (w_cmd_op == CMD_WRITE_START) begin
r_flashram_state[STATE_EXECUTE] <= 1'b1;
r_sector_offset <= i_data[9:0];
r_execute_mode <= EXECUTE_WRITE;
r_execute_start <= 1'b1;
end
end
end
end
// Status controller
reg r_erase_busy;
reg r_erase_done;
reg r_write_busy;
reg r_write_done;
wire [3:0] w_status = {r_erase_done, r_write_done, r_erase_busy, r_write_busy};
wire w_status_write_request = i_request && i_write && !i_address[14] && r_flashram_state[STATE_STATUS];
always @(posedge i_clk) begin
if (i_reset) begin
r_erase_busy <= 1'b0;
r_write_busy <= 1'b0;
r_erase_done <= 1'b0;
r_write_done <= 1'b0;
end else begin
if (w_status_write_request) begin
r_erase_done <= r_erase_done & i_data[3];
r_write_done <= r_write_done & i_data[1];
end
if (r_execute_start) begin
if (r_execute_mode == EXECUTE_WRITE) begin
r_write_busy <= 1'b1;
r_write_done <= 1'b0;
end else begin
r_erase_busy <= 1'b1;
r_erase_done <= 1'b0;
end
end
if (r_execute_done) begin
if (r_execute_mode == EXECUTE_WRITE) begin
r_write_busy <= 1'b0;
r_write_done <= 1'b1;
end else begin
r_erase_busy <= 1'b0;
r_erase_done <= 1'b1;
end
end
end
end
// Bus controller
assign o_busy = 1'b0;
wire [31:0] w_write_buffer_o_data;
wire w_flashram_controller_read_request = i_request && !i_write && !o_busy && !r_flashram_state[STATE_READ];
always @(posedge i_clk) begin
o_ack <= 1'b0;
if (w_flashram_controller_read_request) begin
o_ack <= 1'b1;
o_data <= {12'h000, w_status, 12'h000, w_status};
if (r_flashram_state[STATE_ID]) begin
o_data <= i_address[0] ? FLASH_MODEL_ID : FLASH_TYPE_ID;
end
if (r_flashram_state[STATE_WRITE]) begin
o_data <= w_write_buffer_o_data;
end
end
end
// Page write buffer
reg [4:0] r_write_buffer_address;
wire [31:0] w_write_buffer_o_mem_data;
wire w_write_buffer_request = i_request && i_write && !o_busy && !i_address[14] && r_flashram_state[STATE_WRITE];
ram_flashram_write_buffer ram_flashram_write_buffer_inst (
.clock(i_clk),
.wren_a(w_write_buffer_request),
.address_a(i_address[4:0]),
.data_a(i_data),
.q_a(w_write_buffer_o_data),
.wren_b(i_mem_ack),
.address_b(r_write_buffer_address),
.data_b(i_mem_data & w_write_buffer_o_mem_data),
.q_b(w_write_buffer_o_mem_data)
);
// Memory controller
reg [15:0] r_items_left;
wire w_in_execution = !r_execute_start && r_flashram_state[STATE_EXECUTE];
wire w_read_phase_done = w_in_execution && (r_write_buffer_address == 5'h1F) && !o_mem_write && i_mem_ack;
wire w_write_phase_done = w_in_execution && (r_items_left == 16'd0) && o_mem_write;
wire w_mem_request_successful = o_mem_request && !i_mem_busy;
wire w_address_reset = r_execute_start || w_read_phase_done;
wire w_write_buffer_address_increment = o_mem_write ? w_mem_request_successful : i_mem_ack;
always @(*) begin
r_execute_done = w_write_phase_done;
end
always @(posedge i_clk) begin
if (w_address_reset) begin
case (r_execute_mode)
EXECUTE_WRITE: r_items_left <= 16'h20;
EXECUTE_ERASE_SECTOR: r_items_left <= 16'h1000;
EXECUTE_ERASE_CHIP: r_items_left <= 16'h8000;
default: r_items_left <= 16'd0;
endcase
end
if (w_mem_request_successful) begin
r_items_left <= r_items_left - 1'd1;
end
end
always @(posedge i_clk) begin
if (i_reset) begin
o_mem_request <= 1'b0;
end else begin
if (r_items_left > 16'd0) begin
o_mem_request <= 1'b1;
end
if (w_mem_request_successful) begin
o_mem_request <= 1'b0;
end
end
end
always @(posedge i_clk) begin
if (r_execute_start) begin
if (r_execute_mode == EXECUTE_WRITE) begin
o_mem_write <= 1'b0;
end else begin
o_mem_write <= 1'b1;
end
end
if (w_read_phase_done) begin
o_mem_write <= 1'b1;
end
end
always @(posedge i_clk) begin
o_mem_bank <= `BANK_SDRAM;
end
always @(posedge i_clk) begin
if (w_address_reset) begin
o_mem_address <= i_save_address + {9'd0, r_sector_offset, 5'd0};
r_write_buffer_address <= 5'd0;
end else begin
if (w_mem_request_successful) begin
o_mem_address <= o_mem_address + 1'd1;
end
if (w_write_buffer_address_increment) begin
r_write_buffer_address <= r_write_buffer_address + 1'd1;
end
end
end
always @(*) begin
o_mem_data = 32'hFFFF_FFFF;
if (r_execute_mode == EXECUTE_WRITE) begin
o_mem_data = w_write_buffer_o_mem_data;
end
end
endmodule