diff options
Diffstat (limited to 'fpga/usrp3/lib/sim/fifo/axi_fifo_2clk_sim.v')
-rw-r--r-- | fpga/usrp3/lib/sim/fifo/axi_fifo_2clk_sim.v | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/sim/fifo/axi_fifo_2clk_sim.v b/fpga/usrp3/lib/sim/fifo/axi_fifo_2clk_sim.v new file mode 100644 index 000000000..cf31ae2d9 --- /dev/null +++ b/fpga/usrp3/lib/sim/fifo/axi_fifo_2clk_sim.v @@ -0,0 +1,230 @@ +// +// Copyright 2016 Ettus Research +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +module axi_fifo_2clk #( + parameter SYNC_STAGES = 2, + parameter SIZE = 10, + parameter WIDTH = 32, + parameter PIPELINE = "<UNUSED>") +( + input reset, + input i_aclk, + input [WIDTH-1:0] i_tdata, + input i_tvalid, + output reg i_tready = 1'b0, + input o_aclk, + output [WIDTH-1:0] o_tdata, + output reg o_tvalid = 1'b0, + input o_tready +); + + localparam FIFOSIZE = (SIZE < 5) ? 5 : SIZE; + + // Synchronizers + wire o_rst_sync, i_rst_sync; + synchronizer #( + .INITIAL_VAL(1'b1), + .WIDTH(1), + .STAGES(SYNC_STAGES)) + synchronizer_i_rst ( + .clk(i_aclk), .rst(1'b0), + .in(reset), .out(i_rst_sync)); + synchronizer #( + .INITIAL_VAL(1'b1), + .WIDTH(1), + .STAGES(SYNC_STAGES)) + synchronizer_o_rst ( + .clk(o_aclk), .rst(1'b0), + .in(reset), .out(o_rst_sync)); + + // Gray counter encode / decode + synchronizers + reg [FIFOSIZE-1:0] wr_addr, rd_addr; + wire [FIFOSIZE-1:0] wr_addr_sync, rd_addr_sync; + wire [FIFOSIZE-1:0] wr_addr_gray_sync, wr_addr_gray, rd_addr_gray_sync, rd_addr_gray; + synchronizer #( + .INITIAL_VAL(0), + .WIDTH(FIFOSIZE), + .STAGES(SYNC_STAGES)) + synchronizer_rd_addr_gray ( + .clk(i_aclk), .rst(o_rst_sync), + .in(rd_addr_gray), .out(rd_addr_gray_sync)); + synchronizer #( + .INITIAL_VAL(0), + .WIDTH(FIFOSIZE), + .STAGES(SYNC_STAGES)) + synchronizer_wr_addr_gray ( + .clk(o_aclk), .rst(i_rst_sync), + .in(wr_addr_gray), .out(wr_addr_gray_sync)); + bin2gray #(.WIDTH(FIFOSIZE)) + bin2gray_wr_addr (.bin(wr_addr), .gray(wr_addr_gray)); + bin2gray #(.WIDTH(FIFOSIZE)) + bin2gray_rd_addr (.bin(rd_addr), .gray(rd_addr_gray)); + gray2bin #(.WIDTH(FIFOSIZE)) + gray2bin_wr_addr (.gray(wr_addr_gray_sync), .bin(wr_addr_sync)); + gray2bin #(.WIDTH(FIFOSIZE)) + gray2bin_rd_addr (.gray(rd_addr_gray_sync), .bin(rd_addr_sync)); + + reg [FIFOSIZE:0] i_occupied; + reg [FIFOSIZE:0] i_space; + reg i_full; + reg i_empty; + reg [FIFOSIZE:0] o_occupied; + reg [FIFOSIZE:0] o_space; + reg o_full; + reg o_empty; + + reg [WIDTH:0] mem[0:2**(FIFOSIZE)-1]; + integer i; + initial begin + for (i = 0; i < 1 << FIFOSIZE; i = i + 1) begin + mem[i] = 'd0; + end + end + + // Write + always @(posedge i_aclk) begin + if (i_rst_sync) begin + wr_addr <= 'd0; + end else begin + if (i_tvalid & i_tready) begin + mem[wr_addr] <= i_tdata; + wr_addr <= wr_addr + 1'b1; + end + end + end + + // Write ready, full, empty, occupied signals + always @(posedge i_aclk) begin + if (i_rst_sync) begin + i_tready <= 1'b0; + i_full <= 1'b0; + i_empty <= 1'b1; + i_occupied <= 'd0; + i_space <= (1'b1 << FIFOSIZE); + end else begin + if ((rd_addr_sync-1'b1 == wr_addr) & i_tvalid & i_tready) begin + i_tready <= 1'b0; + i_full <= 1'b1; + end else if ((rd_addr_sync != wr_addr) & i_full) begin + i_tready <= 1'b1; + i_full <= 1'b0; + end + if ((rd_addr_sync == wr_addr) & ~i_full) begin + i_tready <= 1'b1; + if (~i_tvalid) begin + i_empty <= 1'b1; + end + end else begin + i_empty <= 1'b0; + end + if (i_tvalid) begin + if (wr_addr == rd_addr_sync) begin + if (i_full) begin + i_occupied <= 1'b1 << FIFOSIZE; + i_space <= 'd0; + end else begin + i_occupied <= 'd1; + i_space <= (1'b1 << FIFOSIZE)-1'b1; + end + end else if (wr_addr > rd_addr_sync) begin + i_occupied <= wr_addr - rd_addr_sync + 1'b1; + i_space <= (1'b1 << FIFOSIZE) - (wr_addr - rd_addr_sync + 1'b1); + end else begin + i_occupied <= wr_addr+1'b1 + (1'b1 << FIFOSIZE)-1'b1 - rd_addr_sync + 1'b1; + i_space <= rd_addr_sync - wr_addr - 1'b1; + end + end else begin + if (wr_addr == rd_addr_sync) begin + if (i_full) begin + i_occupied <= 1'b1 << FIFOSIZE; + i_space <= 'd0; + end else begin + i_occupied <= 'd0; + i_space <= 1'b1 << FIFOSIZE; + end + end else if (wr_addr > rd_addr_sync) begin + i_occupied <= wr_addr - rd_addr_sync; + i_space <= (1'b1 << FIFOSIZE) - (wr_addr - rd_addr_sync); + end else begin + i_occupied <= wr_addr+1'b1 + (1'b1 << FIFOSIZE)-1'b1 - rd_addr_sync; + i_space <= rd_addr_sync - wr_addr; + end + end + end + end + + // Read + always @(posedge o_aclk) begin + if (o_rst_sync) begin + rd_addr <= 'd0; + end else begin + if (o_tvalid & o_tready) begin + rd_addr <= rd_addr + 1'b1; + end + end + end + + assign o_tdata = mem[rd_addr]; + + // Read valid, full, empty, occupied signals + always @(posedge o_aclk) begin + if (o_rst_sync) begin + o_tvalid <= 1'b0; + o_full <= 1'b0; + o_empty <= 1'b1; + o_occupied <= 'd0; + o_space <= 'd0; + end else begin + if ((rd_addr+1'b1 == wr_addr_sync) & o_tready & o_tvalid) begin + o_tvalid <= 1'b0; + o_empty <= 1'b1; + end else if ((rd_addr != wr_addr_sync) & o_empty) begin + o_tvalid <= 1'b1; + o_empty <= 1'b0; + end + if ((rd_addr == wr_addr_sync) & ~o_empty & ~o_tready) begin + o_full <= 1'b1; + end else begin + o_full <= 1'b0; + end + if (o_tready) begin + if (wr_addr_sync == rd_addr) begin + if (~o_empty) begin + o_occupied <= (1'b1 << FIFOSIZE) - 1'b1; + o_space <= 'd1; + end else begin + o_occupied <= 'd0; + o_space <= (1'b1 << FIFOSIZE); + end + end else if (wr_addr_sync > rd_addr) begin + o_occupied <= wr_addr_sync - rd_addr - 1'b1; + o_space <= (1'b1 << FIFOSIZE) - (wr_addr_sync - rd_addr - 1'b1); + end else begin + o_occupied <= wr_addr_sync+1'b1 + (1'b1 << FIFOSIZE)-1'b1 - rd_addr - 1'b1; + o_space <= rd_addr - wr_addr_sync + 1'b1; + end + end else begin + if (wr_addr_sync == rd_addr) begin + if (~o_empty) begin + o_occupied <= 1'b1 << FIFOSIZE; + o_space <= 'd0; + end else begin + o_occupied <= 'd0; + o_space <= 1'b1 << FIFOSIZE; + end + end else if (wr_addr_sync > rd_addr) begin + o_occupied <= wr_addr_sync - rd_addr; + o_space <= (1'b1 << FIFOSIZE) - (wr_addr_sync - rd_addr); + end else begin + o_occupied <= wr_addr_sync+1'b1 + (1'b1 << FIFOSIZE)-1'b1 - rd_addr; + o_space <= rd_addr - wr_addr_sync; + end + end + end + end + +endmodule |