127 lines
3.1 KiB
Verilog
127 lines
3.1 KiB
Verilog
/* Copyright 2023 (C) Peter McGoron
|
|
* This file is a part of Upsilon, a free and open source software project.
|
|
* For license terms, refer to the files in `doc/copying` in the Upsilon
|
|
* source distribution.
|
|
*/
|
|
module bram_interface #(
|
|
parameter WORD_WID = 24,
|
|
parameter WORD_AMNT_WID = 11,
|
|
/* This is the last INDEX, not the LENGTH of the word array. */
|
|
parameter [WORD_AMNT_WID-1:0] WORD_AMNT = 2047,
|
|
parameter RAM_WID = 32,
|
|
parameter RAM_WORD_WID = 16,
|
|
parameter RAM_WORD_INCR = 2
|
|
) (
|
|
input clk,
|
|
input rst_L,
|
|
|
|
/* autoapproach interface */
|
|
output reg [WORD_WID-1:0] word,
|
|
input word_next,
|
|
output reg word_last,
|
|
output reg word_ok,
|
|
input word_rst,
|
|
|
|
/* User interface */
|
|
input refresh_start,
|
|
input [RAM_WID-1:0] start_addr,
|
|
output reg refresh_finished,
|
|
|
|
/* RAM interface */
|
|
output reg [RAM_WID-1:0] ram_dma_addr,
|
|
input [RAM_WORD_WID-1:0] ram_word,
|
|
output reg ram_read,
|
|
input ram_valid
|
|
);
|
|
|
|
initial word = 0;
|
|
initial word_last = 0;
|
|
initial word_ok = 0;
|
|
initial refresh_finished = 0;
|
|
initial ram_dma_addr = 0;
|
|
initial ram_read = 0;
|
|
|
|
/* TODO: how to initialize? */
|
|
reg [WORD_WID-1:0] backing_buffer [WORD_AMNT:0];
|
|
|
|
localparam WAIT_ON_REFRESH = 0;
|
|
localparam READ_LOW_WORD = 1;
|
|
localparam READ_HIGH_WORD = 2;
|
|
localparam WAIT_ON_REFRESH_DEASSERT = 3;
|
|
|
|
reg [1:0] refresh_state = WAIT_ON_REFRESH;
|
|
reg [WORD_AMNT_WID-1:0] word_cntr_refresh = 0;
|
|
|
|
always @ (posedge clk) if (!rst_L) begin
|
|
word <= 0;
|
|
word_last <= 0;
|
|
word_ok <= 0;
|
|
refresh_finished <= 0;
|
|
ram_dma_addr <= 0;
|
|
ram_read <= 0;
|
|
/* Do not reset backing buffer because that would take too long */
|
|
refresh_state <= WAIT_ON_REFRESH;
|
|
word_cntr_refresh <= 0;
|
|
end else case (refresh_state)
|
|
WAIT_ON_REFRESH: if (refresh_start) begin
|
|
ram_dma_addr <= start_addr;
|
|
refresh_state <= READ_LOW_WORD;
|
|
word_cntr_refresh <= 0;
|
|
end
|
|
READ_LOW_WORD: if (!ram_read) begin
|
|
ram_read <= 1;
|
|
end else if (ram_valid) begin
|
|
refresh_state <= READ_HIGH_WORD;
|
|
ram_dma_addr <= ram_dma_addr + RAM_WORD_INCR;
|
|
ram_read <= 0;
|
|
backing_buffer[word_cntr_refresh][RAM_WORD_WID-1:0] <= ram_word;
|
|
end
|
|
READ_HIGH_WORD: if (!ram_read) begin
|
|
ram_read <= 1;
|
|
end else if (ram_valid) begin
|
|
ram_dma_addr <= ram_dma_addr + RAM_WORD_INCR;
|
|
ram_read <= 0;
|
|
word_cntr_refresh <= word_cntr_refresh + 1;
|
|
backing_buffer[word_cntr_refresh][WORD_WID-1:RAM_WORD_WID] <= ram_word[WORD_WID-RAM_WORD_WID-1:0];
|
|
|
|
if (word_cntr_refresh == WORD_AMNT)
|
|
refresh_state <= WAIT_ON_REFRESH_DEASSERT;
|
|
else
|
|
refresh_state <= READ_LOW_WORD;
|
|
end
|
|
WAIT_ON_REFRESH_DEASSERT: begin
|
|
if (!refresh_start) begin
|
|
refresh_finished <= 0;
|
|
refresh_state <= WAIT_ON_REFRESH;
|
|
end else begin
|
|
refresh_finished <= 1;
|
|
end
|
|
end
|
|
endcase
|
|
|
|
reg [WORD_AMNT_WID-1:0] auto_cntr = 0;
|
|
|
|
always @ (posedge clk) if (word_rst || !rst_L) begin
|
|
auto_cntr <= 0;
|
|
word_ok <= 0;
|
|
word_last <= 0;
|
|
word <= 0;
|
|
end else if (word_next && !word_ok) begin
|
|
if (refresh_state == WAIT_ON_REFRESH) begin
|
|
word <= backing_buffer[auto_cntr];
|
|
word_ok <= 1;
|
|
if (auto_cntr == WORD_AMNT) begin
|
|
auto_cntr <= 0;
|
|
word_last <= 1;
|
|
end else begin
|
|
auto_cntr <= auto_cntr + 1;
|
|
word_last <= 0;
|
|
end
|
|
end
|
|
end else if (!word_next && word_ok) begin
|
|
word_ok <= 0;
|
|
end
|
|
|
|
endmodule
|
|
`undefineall
|