working with memory
This commit is contained in:
@@ -0,0 +1,422 @@
|
||||
module psram_controller #(
|
||||
parameter ADDR_WIDTH = 22,
|
||||
parameter DATA_WIDTH = 16,
|
||||
parameter CLK_FREQ_MHZ = 80
|
||||
)(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
// ============================================================
|
||||
// Memory Interface side
|
||||
// ============================================================
|
||||
|
||||
input wire mem_req,
|
||||
input wire mem_wr,
|
||||
input wire [ADDR_WIDTH-1:0] mem_addr,
|
||||
input wire [DATA_WIDTH-1:0] mem_wdata,
|
||||
input wire mem_lb_n,
|
||||
input wire mem_ub_n,
|
||||
|
||||
output reg [DATA_WIDTH-1:0] mem_rdata,
|
||||
output reg mem_ready,
|
||||
|
||||
// ============================================================
|
||||
// PSRAM physical interface
|
||||
// ============================================================
|
||||
|
||||
output reg [ADDR_WIDTH-1:0] psram_a,
|
||||
|
||||
inout wire [DATA_WIDTH-1:0] psram_dq,
|
||||
|
||||
output reg psram_ce_n,
|
||||
output reg psram_oe_n,
|
||||
output reg psram_we_n,
|
||||
output reg psram_lb_n,
|
||||
output reg psram_ub_n,
|
||||
output reg psram_zz_n
|
||||
);
|
||||
|
||||
// ============================================================
|
||||
// Timing
|
||||
// ============================================================
|
||||
|
||||
localparam integer ACCESS_CYCLES =
|
||||
((70 * CLK_FREQ_MHZ) + 999) / 1000;
|
||||
|
||||
localparam integer INIT_CYCLES =
|
||||
150 * CLK_FREQ_MHZ;
|
||||
|
||||
localparam integer COUNTER_WIDTH =
|
||||
(INIT_CYCLES <= 1) ? 1 : $clog2(INIT_CYCLES + 1);
|
||||
|
||||
// ============================================================
|
||||
// State machine
|
||||
// ============================================================
|
||||
|
||||
localparam [2:0]
|
||||
STATE_INIT = 3'd0,
|
||||
STATE_IDLE = 3'd1,
|
||||
STATE_READ = 3'd2,
|
||||
STATE_WRITE = 3'd3,
|
||||
STATE_WRITE_WAIT = 3'd4;
|
||||
|
||||
reg [2:0] state;
|
||||
reg [COUNTER_WIDTH-1:0] counter;
|
||||
|
||||
// ============================================================
|
||||
// Latched transaction
|
||||
// ============================================================
|
||||
|
||||
reg [ADDR_WIDTH-1:0] address_reg;
|
||||
reg [DATA_WIDTH-1:0] wdata_reg;
|
||||
reg wr_reg;
|
||||
|
||||
// ============================================================
|
||||
// Latched byte enables
|
||||
//
|
||||
// Active LOW:
|
||||
// 0 = byte enabled
|
||||
// 1 = byte disabled
|
||||
// ============================================================
|
||||
|
||||
reg lb_reg;
|
||||
reg ub_reg;
|
||||
|
||||
// ============================================================
|
||||
// PSRAM data bus control
|
||||
// ============================================================
|
||||
|
||||
reg [DATA_WIDTH-1:0] dq_out;
|
||||
reg dq_oe;
|
||||
|
||||
assign psram_dq =
|
||||
dq_oe ? dq_out : {DATA_WIDTH{1'bz}};
|
||||
|
||||
// ============================================================
|
||||
// Main state machine
|
||||
// ============================================================
|
||||
|
||||
always @(posedge clk) begin
|
||||
|
||||
if (rst) begin
|
||||
|
||||
// ----------------------------------------------------
|
||||
// State
|
||||
// ----------------------------------------------------
|
||||
|
||||
state <= STATE_INIT;
|
||||
counter <= 0;
|
||||
|
||||
// ----------------------------------------------------
|
||||
// Transaction registers
|
||||
// ----------------------------------------------------
|
||||
|
||||
address_reg <= {ADDR_WIDTH{1'b0}};
|
||||
wdata_reg <= {DATA_WIDTH{1'b0}};
|
||||
wr_reg <= 1'b0;
|
||||
|
||||
// Byte enables disabled during reset
|
||||
lb_reg <= 1'b1;
|
||||
ub_reg <= 1'b1;
|
||||
|
||||
// ----------------------------------------------------
|
||||
// Memory interface
|
||||
// ----------------------------------------------------
|
||||
|
||||
mem_rdata <= {DATA_WIDTH{1'b0}};
|
||||
mem_ready <= 1'b0;
|
||||
|
||||
// ----------------------------------------------------
|
||||
// PSRAM address
|
||||
// ----------------------------------------------------
|
||||
|
||||
psram_a <= {ADDR_WIDTH{1'b0}};
|
||||
|
||||
// ----------------------------------------------------
|
||||
// PSRAM control
|
||||
// ----------------------------------------------------
|
||||
|
||||
psram_ce_n <= 1'b1;
|
||||
psram_oe_n <= 1'b1;
|
||||
psram_we_n <= 1'b1;
|
||||
|
||||
psram_lb_n <= 1'b1;
|
||||
psram_ub_n <= 1'b1;
|
||||
|
||||
psram_zz_n <= 1'b1;
|
||||
|
||||
// ----------------------------------------------------
|
||||
// Data bus
|
||||
// ----------------------------------------------------
|
||||
|
||||
dq_out <= {DATA_WIDTH{1'b0}};
|
||||
dq_oe <= 1'b0;
|
||||
|
||||
end else begin
|
||||
|
||||
// mem_ready is a one-cycle pulse
|
||||
mem_ready <= 1'b0;
|
||||
|
||||
case (state)
|
||||
|
||||
// =================================================
|
||||
// PSRAM power-up initialization
|
||||
// =================================================
|
||||
|
||||
STATE_INIT: begin
|
||||
|
||||
psram_ce_n <= 1'b1;
|
||||
psram_oe_n <= 1'b1;
|
||||
psram_we_n <= 1'b1;
|
||||
|
||||
psram_lb_n <= 1'b1;
|
||||
psram_ub_n <= 1'b1;
|
||||
|
||||
psram_zz_n <= 1'b1;
|
||||
|
||||
dq_oe <= 1'b0;
|
||||
|
||||
if (counter == INIT_CYCLES - 1) begin
|
||||
|
||||
counter <= 0;
|
||||
state <= STATE_IDLE;
|
||||
|
||||
end else begin
|
||||
|
||||
counter <= counter + 1'b1;
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
// =================================================
|
||||
// Idle
|
||||
// =================================================
|
||||
|
||||
STATE_IDLE: begin
|
||||
|
||||
psram_ce_n <= 1'b1;
|
||||
psram_oe_n <= 1'b1;
|
||||
psram_we_n <= 1'b1;
|
||||
|
||||
psram_lb_n <= 1'b1;
|
||||
psram_ub_n <= 1'b1;
|
||||
|
||||
psram_zz_n <= 1'b1;
|
||||
|
||||
dq_oe <= 1'b0;
|
||||
|
||||
if (mem_req) begin
|
||||
|
||||
// ------------------------------------------------
|
||||
// Latch transaction
|
||||
// ------------------------------------------------
|
||||
|
||||
address_reg <= mem_addr;
|
||||
wdata_reg <= mem_wdata;
|
||||
wr_reg <= mem_wr;
|
||||
|
||||
// ------------------------------------------------
|
||||
// Latch byte enables
|
||||
// ------------------------------------------------
|
||||
|
||||
lb_reg <= mem_lb_n;
|
||||
ub_reg <= mem_ub_n;
|
||||
|
||||
// ------------------------------------------------
|
||||
// Address
|
||||
// ------------------------------------------------
|
||||
|
||||
psram_a <= mem_addr;
|
||||
|
||||
// ------------------------------------------------
|
||||
// Apply byte enables immediately
|
||||
// ------------------------------------------------
|
||||
|
||||
psram_lb_n <= mem_lb_n;
|
||||
psram_ub_n <= mem_ub_n;
|
||||
|
||||
psram_ce_n <= 1'b0;
|
||||
|
||||
counter <= 0;
|
||||
|
||||
// =================================================
|
||||
// WRITE
|
||||
// =================================================
|
||||
|
||||
if (mem_wr) begin
|
||||
|
||||
dq_out <= mem_wdata;
|
||||
dq_oe <= 1'b1;
|
||||
|
||||
psram_we_n <= 1'b0;
|
||||
psram_oe_n <= 1'b1;
|
||||
|
||||
state <= STATE_WRITE;
|
||||
|
||||
end
|
||||
|
||||
// =================================================
|
||||
// READ
|
||||
// =================================================
|
||||
|
||||
else begin
|
||||
|
||||
dq_oe <= 1'b0;
|
||||
|
||||
psram_we_n <= 1'b1;
|
||||
psram_oe_n <= 1'b0;
|
||||
|
||||
state <= STATE_READ;
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// =================================================
|
||||
// READ
|
||||
// =================================================
|
||||
|
||||
STATE_READ: begin
|
||||
|
||||
psram_ce_n <= 1'b0;
|
||||
psram_oe_n <= 1'b0;
|
||||
psram_we_n <= 1'b1;
|
||||
|
||||
psram_lb_n <= lb_reg;
|
||||
psram_ub_n <= ub_reg;
|
||||
|
||||
psram_zz_n <= 1'b1;
|
||||
|
||||
dq_oe <= 1'b0;
|
||||
|
||||
if (counter == ACCESS_CYCLES - 1) begin
|
||||
|
||||
// ------------------------------------------------
|
||||
// Capture PSRAM data
|
||||
// ------------------------------------------------
|
||||
|
||||
mem_rdata <= psram_dq;
|
||||
mem_ready <= 1'b1;
|
||||
|
||||
// ------------------------------------------------
|
||||
// End transaction
|
||||
// ------------------------------------------------
|
||||
|
||||
psram_ce_n <= 1'b1;
|
||||
psram_oe_n <= 1'b1;
|
||||
|
||||
psram_lb_n <= 1'b1;
|
||||
psram_ub_n <= 1'b1;
|
||||
|
||||
counter <= 0;
|
||||
state <= STATE_IDLE;
|
||||
|
||||
end else begin
|
||||
|
||||
counter <= counter + 1'b1;
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
// =================================================
|
||||
// WRITE
|
||||
// =================================================
|
||||
|
||||
STATE_WRITE: begin
|
||||
|
||||
psram_ce_n <= 1'b0;
|
||||
psram_oe_n <= 1'b1;
|
||||
psram_we_n <= 1'b0;
|
||||
|
||||
psram_lb_n <= lb_reg;
|
||||
psram_ub_n <= ub_reg;
|
||||
|
||||
psram_zz_n <= 1'b1;
|
||||
|
||||
dq_oe <= 1'b1;
|
||||
|
||||
if (counter == ACCESS_CYCLES - 1) begin
|
||||
|
||||
// ------------------------------------------------
|
||||
// End WE# pulse
|
||||
// ------------------------------------------------
|
||||
|
||||
psram_we_n <= 1'b1;
|
||||
|
||||
counter <= 0;
|
||||
state <= STATE_WRITE_WAIT;
|
||||
|
||||
end else begin
|
||||
|
||||
counter <= counter + 1'b1;
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
// =================================================
|
||||
// WRITE WAIT
|
||||
//
|
||||
// Keep CE#/LB#/UB# active for the final write hold
|
||||
// interval before releasing the transaction.
|
||||
// =================================================
|
||||
|
||||
STATE_WRITE_WAIT: begin
|
||||
|
||||
psram_ce_n <= 1'b0;
|
||||
psram_oe_n <= 1'b1;
|
||||
psram_we_n <= 1'b1;
|
||||
|
||||
psram_lb_n <= lb_reg;
|
||||
psram_ub_n <= ub_reg;
|
||||
|
||||
psram_zz_n <= 1'b1;
|
||||
|
||||
dq_oe <= 1'b0;
|
||||
|
||||
// ------------------------------------------------
|
||||
// Release PSRAM
|
||||
// ------------------------------------------------
|
||||
|
||||
psram_ce_n <= 1'b1;
|
||||
psram_lb_n <= 1'b1;
|
||||
psram_ub_n <= 1'b1;
|
||||
|
||||
// ------------------------------------------------
|
||||
// Transaction complete
|
||||
// ------------------------------------------------
|
||||
|
||||
mem_ready <= 1'b1;
|
||||
|
||||
state <= STATE_IDLE;
|
||||
end
|
||||
|
||||
// =================================================
|
||||
// Default recovery
|
||||
// =================================================
|
||||
|
||||
default: begin
|
||||
|
||||
state <= STATE_INIT;
|
||||
counter <= 0;
|
||||
|
||||
psram_ce_n <= 1'b1;
|
||||
psram_oe_n <= 1'b1;
|
||||
psram_we_n <= 1'b1;
|
||||
|
||||
psram_lb_n <= 1'b1;
|
||||
psram_ub_n <= 1'b1;
|
||||
|
||||
psram_zz_n <= 1'b1;
|
||||
|
||||
dq_oe <= 1'b0;
|
||||
|
||||
lb_reg <= 1'b1;
|
||||
ub_reg <= 1'b1;
|
||||
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user