`timescale 1ns/1ps // // =========================================================================== // Copyright (c) 2011-2022 Anlogic Inc. All Right Reserved. // // TEL: 86-21-61633787 // WEB: http://www.anlogic.com/ // =========================================================================== // $Version : v1.1 // $Date : 2022/07/08 // $Description: asynchronous/synchronous FIFO rtl codes , fixed the error of // gray code // =========================================================================== //`pragma protect begin module SOFTFIFO #(parameter DATA_WIDTH_W = 16, parameter DATA_WIDTH_R = 16, parameter ADDR_WIDTH_W = 10, parameter ADDR_WIDTH_R = 10, parameter AL_FULL_NUM = 1021, parameter AL_EMPTY_NUM = 2, parameter SHOW_AHEAD_EN = 1'b1, parameter OUTREG_EN = "OUTREG") ( //SHOWAHEAD mode enable //OUTREG, NOREG //independent clock mode,fixed as asynchronous reset input rst, //asynchronous port,active hight input clkw, //write clock input clkr, //read clock input we, //write enable,active hight input [(DATA_WIDTH_W - 1):0] di, //write data input re, //read enable,active hight output [(DATA_WIDTH_R - 1):0] dout, //read data output reg valid, //read data valid flag output reg full_flag, //fifo full flag output empty_flag, //fifo empty flag output reg afull, //fifo almost full flag output aempty, //fifo almost empty flag output [(ADDR_WIDTH_W - 1):0] wrusedw, //stored data number in fifo output [(ADDR_WIDTH_R - 1):0] rdusedw //available data number for read ) ; //-------------------------------------------------------------------------------------------- //-------------internal parameter and signals definition below--------------- //-------------------------------------------------------------------------------------------- //-------------parameter definition localparam FULL_NUM = ({ADDR_WIDTH_W{1'b1}} - 1) ; //-------------signals definition reg asy_w_rst0 ; reg asy_w_rst1 ; reg asy_r_rst0 ; reg asy_r_rst1 ; wire rd_rst ; wire wr_rst ; wire [(ADDR_WIDTH_R - 1):0] rd_to_wr_addr ; // read address synchronized to write clock domain wire [(ADDR_WIDTH_W - 1):0] wr_to_rd_addr ; // write address synchronized to read clock domain reg [(ADDR_WIDTH_W - 1):0] wr_addr ; // current write address reg [(ADDR_WIDTH_R - 1):0] rd_addr ; // current write address wire wr_en_s ; wire rd_en_s ; reg [(ADDR_WIDTH_W - 1):0] shift_rdaddr ; reg [(ADDR_WIDTH_R - 1):0] shift_wraddr ; wire [(ADDR_WIDTH_W - 1):0] wr_addr_diff ; // the difference between read and write address(synchronized to write clock domain) wire [(ADDR_WIDTH_R - 1):0] rd_addr_diff ; // the difference between read and write address(synchronized to read clock domain) reg empty_flag_r1 ; reg empty_flag_r2 ; reg re_r1 ; reg re_r2 ; //-------------------------------------------------------------------------------------------- //--------------------fuctional codes below--------------------------------- //-------------------------------------------------------------------------------------------- // ============================================= // reset control logic below; // ============================================= //Asynchronous reset synchronous release on the write side always @(posedge clkw or posedge rst) begin if (rst) begin asy_w_rst0 <= 1'b1 ; asy_w_rst1 <= 1'b1 ; end else begin asy_w_rst0 <= 1'b0 ; asy_w_rst1 <= asy_w_rst0 ; end end //Asynchronous reset synchronous release on the read side always @(posedge clkr or posedge rst) begin if (rst) begin asy_r_rst0 <= 1'b1 ; asy_r_rst1 <= 1'b1 ; end else begin asy_r_rst0 <= 1'b0 ; asy_r_rst1 <= asy_r_rst0 ; end end assign rd_rst = asy_r_rst1 ; assign wr_rst = asy_w_rst1 ; // ============================================= // address generate logic below; // ============================================= // write and read ram enable assign wr_en_s = ((!full_flag) & we) ; assign rd_en_s = ((!empty_flag) & re) ; // generate write fifo address always @(posedge clkw or posedge wr_rst) begin if ((wr_rst == 1'b1)) wr_addr <= 'b0 ; else if (wr_en_s) wr_addr <= (wr_addr + 1) ; end // generate rd fifo address always @(posedge clkr or posedge rd_rst) begin if ((rd_rst == 1'b1)) rd_addr <= 'b0 ; else if (rd_en_s) rd_addr <= (rd_addr + 1) ; end always @(*) begin if ((ADDR_WIDTH_R >= ADDR_WIDTH_W)) begin shift_rdaddr = (rd_to_wr_addr >> (ADDR_WIDTH_R - ADDR_WIDTH_W)) ; shift_wraddr = (wr_to_rd_addr << (ADDR_WIDTH_R - ADDR_WIDTH_W)) ; end else begin shift_rdaddr = (rd_to_wr_addr << (ADDR_WIDTH_W - ADDR_WIDTH_R)) ; shift_wraddr = (wr_to_rd_addr >> (ADDR_WIDTH_W - ADDR_WIDTH_R)) ; end end // two's complement format assign wr_addr_diff = (wr_addr - shift_rdaddr) ; // the count of data writen to fifo assign rd_addr_diff = (shift_wraddr - rd_addr) ; // the count of data available for read // ============================================= // generate all output flag and count below; // ============================================= // generate fifo full_flag indicator always @(posedge clkw or posedge wr_rst) begin if ((wr_rst == 1'b1)) full_flag <= 1'b0 ; else if ((wr_addr_diff >= FULL_NUM)) full_flag <= 1'b1 ; else full_flag <= 1'b0 ; end // generate fifo afull indicator always @(posedge clkw or posedge wr_rst) begin if ((wr_rst == 1'b1)) afull <= 1'b0 ; else if ((wr_addr_diff >= AL_FULL_NUM)) afull <= 1'b1 ; else afull <= 1'b0 ; end // generate fifo empty_flag indicator /* verilator lint_off WIDTHEXPAND */ assign empty_flag = ((rd_addr_diff == 5'b0) ? 1'b1 : 1'b0) ; // generate fifo aempty indicator assign aempty = ((rd_addr_diff <= AL_EMPTY_NUM) ? 1'b1 : 1'b0) ; // the count of data writen to fifo assign wrusedw = wr_addr_diff ; // the count of data available for read assign rdusedw = rd_addr_diff ; // delay empty_flag for 2cycle always @(posedge clkr or posedge rd_rst) begin if ((rd_rst == 1'b1)) begin empty_flag_r1 <= 1'b1 ; empty_flag_r2 <= 1'b1 ; end else begin empty_flag_r1 <= empty_flag ; empty_flag_r2 <= empty_flag_r1 ; end end // delay rd_en_s for 2cycle always @(posedge clkr or posedge rd_rst) begin if ((rd_rst == 1'b1)) begin re_r1 <= 1'b0 ; re_r2 <= 1'b0 ; end else begin re_r1 <= rd_en_s ; re_r2 <= re_r1 ; end end // generate data output valid flag always @(*) begin if ((SHOW_AHEAD_EN && (OUTREG_EN == "NOREG"))) valid = (!empty_flag) ; else if (((!SHOW_AHEAD_EN) && (OUTREG_EN == "OUTREG"))) valid = (re_r2 & (!empty_flag_r2)) ; else valid = (re_r1 & (!empty_flag_r1)) ; end // ============================================= // instance logic below; // ============================================= // fifo read address synchronous to write clock domain using gray code fifo_cross_domain_addr_process_al_SOFTFIFO #(.ADDR_WIDTH(ADDR_WIDTH_R)) rd_to_wr_cross_inst (.primary_asreset_i(rd_rst), .secondary_asreset_i(wr_rst), .primary_clk_i(clkr), .secondary_clk_i(clkw), .primary_addr_i(rd_addr), .secondary_addr_o(rd_to_wr_addr)) ; // fifo write address synchronous to read clock domain using gray code fifo_cross_domain_addr_process_al_SOFTFIFO #(.ADDR_WIDTH(ADDR_WIDTH_W)) wr_to_rd_cross_inst (.primary_asreset_i(wr_rst), .secondary_asreset_i(rd_rst), .primary_clk_i(clkw), .secondary_clk_i(clkr), .primary_addr_i(wr_addr), .secondary_addr_o(wr_to_rd_addr)) ; ram_infer_SOFTFIFO #( .DATAWIDTH_A(DATA_WIDTH_W), .ADDRWIDTH_A(ADDR_WIDTH_W), .DATAWIDTH_B(DATA_WIDTH_R), .ADDRWIDTH_B(ADDR_WIDTH_R), .MODE("SDP"), .REGMODE_B(OUTREG_EN) /* verilator lint_off PINMISSING */ ) ram_inst ( .clka(clkw), .rsta(wr_rst), .cea(1'b1), .wea(wr_en_s), .ocea(1'b0), .dia(di), .addra(wr_addr), .clkb(clkr), .rstb(rd_rst), .ceb((SHOW_AHEAD_EN | rd_en_s)), .web(1'b0), .oceb(1'b1), /* verilator lint_off WIDTHEXPAND */ .addrb((rd_addr + (SHOW_AHEAD_EN & rd_en_s))), .dob(dout) ); endmodule `timescale 1ns/1ps // =========================================================================== // $Version : v1.0 // $Date : 2022/04/26 // $Description: fifo write and read address crocess domain process // =========================================================================== /* verilator lint_off DECLFILENAME */ module fifo_cross_domain_addr_process_al_SOFTFIFO #(parameter ADDR_WIDTH = 9) ( input primary_asreset_i, input secondary_asreset_i, input primary_clk_i, input secondary_clk_i, input [(ADDR_WIDTH - 1):0] primary_addr_i, output reg [(ADDR_WIDTH - 1):0] secondary_addr_o) ; //-------------------------------------------------------------------------------------------- //-------------internal parameter and signals definition below--------------- //-------------------------------------------------------------------------------------------- //-------------localparam definition //-------------signals definition wire [(ADDR_WIDTH - 1):0] primary_addr_gray ; reg [(ADDR_WIDTH - 1):0] primary_addr_gray_reg ; /* fehdl keep="true" */ reg [(ADDR_WIDTH - 1):0] sync_r1 ; /* fehdl keep="true" */ reg [(ADDR_WIDTH - 1):0] primary_addr_gray_sync ; //-------------------------------------------------------------------------------------------- //--------------------fuctional codes below--------------------------------- //-------------------------------------------------------------------------------------------- function [(ADDR_WIDTH - 1):0] gray2bin ; input [(ADDR_WIDTH - 1):0] gray ; integer j ; begin gray2bin[(ADDR_WIDTH - 1)] = gray[(ADDR_WIDTH - 1)] ; for (j = (ADDR_WIDTH - 1) ; (j > 0) ; j = (j - 1)) gray2bin[(j - 1)] = (gray2bin[j] ^ gray[(j - 1)]) ; end endfunction function [(ADDR_WIDTH - 1):0] bin2gray ; input [(ADDR_WIDTH - 1):0] bin ; integer j ; begin bin2gray[(ADDR_WIDTH - 1)] = bin[(ADDR_WIDTH - 1)] ; for (j = (ADDR_WIDTH - 1) ; (j > 0) ; j = (j - 1)) bin2gray[(j - 1)] = (bin[j] ^ bin[(j - 1)]) ; end endfunction // convert primary address to grey code assign primary_addr_gray = bin2gray(primary_addr_i) ; // register the primary Address Pointer gray code always @(posedge primary_clk_i or posedge primary_asreset_i) begin if ((primary_asreset_i == 1'b1)) primary_addr_gray_reg <= 0 ; else primary_addr_gray_reg <= primary_addr_gray ; end //-------------------------------------------------------------------- // secondary clock Domain //-------------------------------------------------------------------- // synchronize primary address grey code onto the secondary clock always @(posedge secondary_clk_i or posedge secondary_asreset_i) begin if ((secondary_asreset_i == 1'b1)) begin sync_r1 <= 0 ; primary_addr_gray_sync <= 0 ; end else begin sync_r1 <= primary_addr_gray_reg ; primary_addr_gray_sync <= sync_r1 ; end end // convert the synchronized primary address grey code back to binary always @(posedge secondary_clk_i or posedge secondary_asreset_i) begin if ((secondary_asreset_i == 1'b1)) secondary_addr_o <= 0 ; else secondary_addr_o <= gray2bin(primary_addr_gray_sync) ; end endmodule `timescale 1ns/1ps // =========================================================================== // $Version : v1.0 // $Date : 2022/04/26 // $Description: DRAM/ERAM infer logic // =========================================================================== module ram_infer_SOFTFIFO (clka, rsta, cea, ocea, wea, dia, addra, doa, clkb, rstb, ceb, oceb, web, dib, addrb, dob) ; //parameter parameter MODE = "SDP" ; //SP, SDP, DP parameter BYTE_SIZE = 8 ; //8, 9, 10 /* verilator lint_off UNUSEDPARAM */ parameter INIT_FILE = "" ; //memory initialization file which can be $readmemh, generated by software from .mif /* verilator lint_off UNUSEDPARAM */ parameter INIT_VALUE = 0 ; parameter USE_BYTE_WEA = 0 ; //0,1, use Byte Writes or not parameter DATAWIDTH_A = 32 ; //A WIDTH parameter WEA_WIDTH = ((USE_BYTE_WEA == 0) ? 1 : (DATAWIDTH_A / BYTE_SIZE)) ; //wea port width parameter REGMODE_A = "NOREG" ; //OUTREG, NOREG parameter RESETMODE_A = "ASYNC" ; //SYNC, ASYNC, ARSR parameter INITVAL_A = {DATAWIDTH_A{1'b0}} ; //A initial value or reset value parameter WRITEMODE_A = "NORMAL" ; //NORMAL, WRITETHROUGH, READBEFOREWRITE parameter ADDRWIDTH_A = 5 ; //A ADDR WIDTH parameter DATADEPTH_A = (2 ** ADDRWIDTH_A) ; //A DEPTH parameter SSROVERCE_A = "ENABLE" ; //ENABLE, DISABLE parameter USE_BYTE_WEB = USE_BYTE_WEA ; //0,1, use Byte Writes or not parameter DATAWIDTH_B = DATAWIDTH_A ; //B WIDTH parameter WEB_WIDTH = ((USE_BYTE_WEB == 0) ? 1 : (DATAWIDTH_B / BYTE_SIZE)) ; //web port width parameter REGMODE_B = "NOREG" ; //OUTREG, NOREG parameter RESETMODE_B = "ASYNC" ; //SYNC, ASYNC, ARSR parameter INITVAL_B = {DATAWIDTH_B{1'b0}} ; //B initial value or reset value parameter WRITEMODE_B = "NORMAL" ; //NORMAL, WRITETHROUGH, READBEFOREWRITE parameter ADDRWIDTH_B = ADDRWIDTH_A ; //B ADDR WIDTH parameter DATADEPTH_B = (2 ** ADDRWIDTH_B) ; //A DEPTH parameter SSROVERCE_B = "ENABLE" ; //ENABLE, DISABLEi //input input clka, rsta, cea, ocea ; input [(WEA_WIDTH - 1):0] wea ; input [(DATAWIDTH_A - 1):0] dia ; input [(ADDRWIDTH_A - 1):0] addra ; input clkb, rstb, ceb, oceb ; input [(WEB_WIDTH - 1):0] web ; input [(DATAWIDTH_B - 1):0] dib ; input [(ADDRWIDTH_B - 1):0] addrb ; //output output [(DATAWIDTH_A - 1):0] doa ; output [(DATAWIDTH_B - 1):0] dob ; // check parameters //integer fp; localparam MIN_WIDTH = ((DATAWIDTH_A > DATAWIDTH_B) ? DATAWIDTH_B : DATAWIDTH_A) ; localparam MAX_DEPTH = ((DATADEPTH_A > DATADEPTH_B) ? DATADEPTH_A : DATADEPTH_B) ; localparam WIDTHRATIO_A = (DATAWIDTH_A / MIN_WIDTH) ; localparam WIDTHRATIO_B = (DATAWIDTH_B / MIN_WIDTH) ; reg [(MIN_WIDTH - 1):0] memory [(MAX_DEPTH - 1):0] ; /* fehdl force_ram=1, ram_style="bram" */ reg [(DATAWIDTH_A - 1):0] doa_tmp = INITVAL_A ; reg [(DATAWIDTH_B - 1):0] dob_tmp = INITVAL_B ; reg [(DATAWIDTH_A - 1):0] doa_tmp2 = INITVAL_A ; reg [(DATAWIDTH_B - 1):0] dob_tmp2 = INITVAL_B ; /* verilator lint_off UNUSEDSIGNAL */ integer i ; //Initial value // if (INIT_FILE != "") begin // initial $readmemb(INIT_FILE, memory); // end else begin // initial begin // for(i=0; i