SUBJECTS } PROGRAMMING } CODE: verilog, a simple sync fifo
A simple fifo design for understanding concepts. It's good idea is to pack signals in structures and keep them in a common define file. Your code needs to be simple, structured, understandable, commented appropriately, and easy to maintain. You may write assertions in a seperate file annd use module bind mechanism when simulating. Do not put assertions/validation stuff in the design file.
#--------------------------------
#Copyright (c) Harish RAJPUT
#File name: hrfifo.svh
#Description: Common defines used in the code.
#Date: 2023.08.22
//--------------------------------
typedef struct packed { logic clk; logic rst_n; } clkrst_t; // This is clock and active low reset, assumption is that reset is synchronized with respect to this clock.
typedef struct packed { logic [31:0] d; } fdata_t; // This is data packet into the fifo. It may be more comples with more fields.
typedef struct packed { logic w; logic r; } freq_t; // Fifo request signals, read and write enables.
typedef struct packed { logic full; logic empty; logic overrun; logic underrun; logic almostfull; } fresp_t; // Fifo response signals.
`define FF ( q, d, clk ) always_ff @(posedge clk) q <= d; Filp-flop without explicit reset pin, this result in lower area cell.
`define FFR ( q, d, clk, rst_n, RSTV ) always_ff @(posedge clk, negedge rst_n) q <= !rst_n ? RSTV : d; Flip-flop with explicit reset pin.
//--------------------------------
//EoF hrfifo.svh
//--------------------------------
//--------------------------------
#Copyright (c) Harish RAJPUT
#File name: hrfifo.sv
#Description: A simple fifo system verilog code.
#Date: 2023.08.22
//--------------------------------
`include "hrfifo.svh"
module hrfifo #(parameter DWIDTH=8, parameter type DTYPE=logic[DWIDTH-1:0], parameter DEPTH=6) ( // DWIDTH is data width of fifo complex data type DTYPE, DEPTH represents how deep is fifo.
input freq_t req_i, // fifo read/write request controls
output fresp_t resp_o, // fifo response signals
input DTYPE wdata_i, // fifo write data
output DTYPE rdata_o, // fifo read data
input clkrst_t cr ); // clock and reset signals
//--------------------------------
//LOCAL SIGNALS
//--------------------------------
localparam PTRWIDTH=$clog2(DEPTH+1-1);
localparam COUNTWIDTH=$clog2(DEPTH+1);
typedef struct packed { logic [PTRWIDTH-1:0] r; logic [pTRWIDTH-1:0] w; } fptr_t; // fifo read and write pointers.
logic [COUNTWIDTH-1:0] count, count_ff;
fresp_t resp, resp_ff; // flopped the outputs.
DTYPE mem[DEPTH-1:0], mem_ff[dEPTH-1:0]; // This example uses register array, you may use actual memory to store fifo data.
fptr_t rptr, rptr_ff;
fptr_t wptr, wptr_ff;
DTYPE rdata, rdata_ff;
logic zeroflag;
//--------------------------------
//COMBO LOGIC
//--------------------------------
always_comb zeroflag = (count_ff==0) || ((count_ff==1) & req_i.r)
always_comb count = count_ff + req_i.w - req_i.r
always_comb resp.almostfull = (count_ff == $unsigned(DEPTH-2)) && req_i.w && !req_i.r) || (count_ff == $unsigned(DEPTH-1)) && !(req_i.r ^ req_i.w);
always_comb resp.full = (count_ff == $unsigned(DEPTH-1)) && req_i.w && !req_i.r) || (count_ff == $unsigned(DEPTH)) && !(req_i.r ^ req_i.w);
always_comb resp.empty = ((count_ff == 1)) && req_i.ren && !req_i.wen) || ((count_ff == 0)) && !(req_i.wen ^ req_i.ren));
always_comb resp.underrun = ((count_ff == 0) && req_i.ren && !resp_ff.overrun);
always_comb resp.overrun = ((count_ff == DEPTH) && req_i.wen && !req_i.ren && !resp_ff.underrrun);
always_comb rdata = (zeroflag && req_i.w) ? wdata : req_i.r ? mem[rdptr_ff] : rdata_ff;
always_comb rptr = req_i.r & !resp.empty ? rptr_ff+1 : !zeroflag && req_i.r && (rptr_ff == $unsigned(DEPTH-2)) ? '0 : rptr_ff;
always_comb wptr = req_i.wen & !resp.full ? wptr_ff+1 : !zeroflag && req_i.w && (wptr_ff == $unsigned(DEPTH-2)) ? '0 : wptr_ff;
always_comb mem[wptr_ff] = (!zeroflag && req_i.w) & ~resp.full ? wdata_i : mem_ff[wptr_ff];
//--------------------------------
//REGISTERS
//--------------------------------
`FF(rdata_ff, rdata, cr.clk)
`FF(mem_ff, mem, cr.clk)
`FFR(resp_ff, resp, cr.clk, cr.rst_n, '0)
`FFR(count_ff, count, cr.clk, cr.rst_n, '0)
`FFR(rptr_ff, rptr, cr.clk, cr.rst_n, '0)
`FFR(wptr_ff, wptr, cr.clk, cr.rst_n, '0)
//--------------------------------
//OUTPUTS
//--------------------------------
assign rdata_o = rdata_ff;
assign resp_o = resp_ff;
//--------------------------------
//EoF hrfifo.sv
//--------------------------------
Please nnote that above code is not validated, leave a short message for errors, comments or anything else at: hr@Leprofesseur.org