aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/sim/fifo/axi_fifo_2clk_sim.v
diff options
context:
space:
mode:
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.v230
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