/* 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