89 lines
2.3 KiB
Verilog
89 lines
2.3 KiB
Verilog
/* Ram shim. This is an interface designed for a LiteX RAM
|
|
* DMA module. It can also be connected to a simulator.
|
|
*
|
|
* The read end is implemented in C since all of this is
|
|
* backed by memory.
|
|
*
|
|
* THIS MODULE ASSUMES that RAM_WORD < DAT_WID < RAM_WORD*2.
|
|
*
|
|
* TODO: Buffer the data (using something like block ram) and
|
|
* write it out asynchronously. This will require instantiating
|
|
* the block ram primitive directly for Yosys. This should make
|
|
* writes to RAM smoother, and reads smoother when the CPU is
|
|
* reading the data.
|
|
*/
|
|
module ram_shim #(
|
|
parameter BASE_ADDR = 32'h1000000,
|
|
parameter MAX_BYTE_WID = 13,
|
|
parameter DAT_WID = 24,
|
|
parameter RAM_WORD = 16,
|
|
parameter RAM_WID = 32
|
|
) (
|
|
input clk,
|
|
input signed [DAT_WID-1:0] data,
|
|
input commit,
|
|
output reg finished,
|
|
|
|
/* Used by the kernel code to request the current
|
|
* location of the FIFO head. Used to memcpy data,
|
|
* it might better than repeatedly calling a FIFO
|
|
* read.
|
|
*/
|
|
input read_end_req_off,
|
|
output reg [RAM_WID-1:0] read_end_addr,
|
|
output reg read_end_req_valid,
|
|
|
|
output reg [RAM_WORD-1:0] word,
|
|
output [RAM_WID-1:0] addr,
|
|
output reg write,
|
|
input valid
|
|
);
|
|
|
|
localparam WAIT_ON_COMMIT = 0;
|
|
localparam HIGH_WORD_LOAD = 1;
|
|
localparam WAIT_ON_HIGH_WORD = 2;
|
|
localparam WAIT_ON_COMMIT_DEASSERT = 3;
|
|
reg [2:0] state = WAIT_ON_COMMIT;
|
|
|
|
reg [MAX_BYTE_WID-1:0] offset = 0;
|
|
assign addr = BASE_ADDR + {{(RAM_WID - MAX_BYTE_WID){1'b0}}, offset};
|
|
initial read_end_req_valid = 0;
|
|
|
|
always @ (posedge clk) begin
|
|
if (read_end_req_off && !read_end_req_valid) begin
|
|
read_end_req_valid = 1;
|
|
read_end_addr <= addr;
|
|
end else if (read_end_req_valid && !read_end_req_off) begin
|
|
read_end_req_valid <= 0;
|
|
end
|
|
end
|
|
|
|
always @ (posedge clk) begin
|
|
case (state)
|
|
WAIT_ON_COMMIT: if (commit) begin
|
|
word <= data[RAM_WORD-1:0];
|
|
write <= 1;
|
|
state <= HIGH_WORD_LOAD;
|
|
end
|
|
HIGH_WORD_LOAD: if (valid) begin
|
|
offset <= offset + (RAM_WORD/2);
|
|
write <= 0;
|
|
word <= {{(RAM_WORD*2 - DAT_WID){data[DAT_WID-1]}},
|
|
data[DAT_WID-1:RAM_WORD]};
|
|
state <= WAIT_ON_HIGH_WORD;
|
|
end
|
|
WAIT_ON_HIGH_WORD: if (!write) begin
|
|
write <= 1;
|
|
end else if (valid) begin
|
|
offset <= offset + (RAM_WORD / 2);
|
|
state <= WAIT_ON_COMMIT_DEASSERT;
|
|
finished <= 1;
|
|
end
|
|
WAIT_ON_COMMIT_DEASSERT: if (!commit) begin
|
|
finished <= 0;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
endmodule
|