cvw/src/uncore/spi_fifo.sv

52 lines
1.9 KiB
Systemverilog

module spi_fifo #(parameter M=3, N=8)( // 2^M entries of N bits each
input logic PCLK, wen, ren, PRESETn,
input logic winc, rinc,
input logic [N-1:0] wdata,
input logic [M-1:0] wwatermarklevel, rwatermarklevel,
output logic [N-1:0] rdata,
output logic wfull, rempty,
output logic wwatermark, rwatermark);
/* Pointer FIFO using design elements from "Simulation and Synthesis Techniques
for Asynchronous FIFO Design" by Clifford E. Cummings. Namely, M bit read and write pointers
are an extra bit larger than address size to determine full/empty conditions.
Watermark comparisons use 2's complement subtraction between the M-1 bit pointers,
which are also used to address memory
*/
logic [N-1:0] mem[2**M];
logic [M:0] rptr, wptr;
logic [M:0] rptrnext, wptrnext;
logic [M-1:0] raddr;
logic [M-1:0] waddr;
assign rdata = mem[raddr];
always_ff @(posedge PCLK)
if (winc & ~wfull) mem[waddr] <= wdata;
// write and read are enabled
always_ff @(posedge PCLK)
if (~PRESETn) begin
rptr <= '0;
wptr <= '0;
wfull <= 1'b0;
rempty <= 1'b1;
end else begin
if (wen) begin
wfull <= ({~wptrnext[M], wptrnext[M-1:0]} == rptr);
wptr <= wptrnext;
end
if (ren) begin
rptr <= rptrnext;
rempty <= (wptr == rptrnext);
end
end
assign raddr = rptr[M-1:0];
assign rptrnext = rptr + {{(M){1'b0}}, (rinc & ~rempty)};
assign rwatermark = ((waddr - raddr) < rwatermarklevel) & ~wfull;
assign waddr = wptr[M-1:0];
assign wwatermark = ((waddr - raddr) > wwatermarklevel) | wfull;
assign wptrnext = wptr + {{(M){1'b0}}, (winc & ~wfull)};
endmodule