2 // FIXME ignores the AWIDTH (fifo size) parameter
5 #(parameter WIDTH=36, SIZE=6)
6 (input wclk, input [WIDTH-1:0] datain, input src_rdy_i, output dst_rdy_o, output [15:0] space,
7 input rclk, output [WIDTH-1:0] dataout, output src_rdy_o, input dst_rdy_i, output [15:0] occupied,
10 wire [SIZE:0] level_rclk, level_wclk; // xilinx adds an extra bit if you ask for accurate levels
11 wire full, empty, write, read;
13 assign dst_rdy_o = ~full;
14 assign src_rdy_o = ~empty;
15 assign write = src_rdy_i & dst_rdy_o;
16 assign read = src_rdy_o & dst_rdy_i;
21 fifo_xlnx_512x36_2clk fifo_xlnx_512x36_2clk
23 .wr_clk(wclk),.din(datain),.full(full),.wr_en(write),.wr_data_count(level_wclk),
24 .rd_clk(rclk),.dout(dataout),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
26 fifo_xlnx_2Kx36_2clk fifo_xlnx_2Kx36_2clk
28 .wr_clk(wclk),.din(datain),.full(full),.wr_en(write),.wr_data_count(level_wclk),
29 .rd_clk(rclk),.dout(dataout),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
31 fifo_xlnx_64x36_2clk fifo_xlnx_64x36_2clk
33 .wr_clk(wclk),.din(datain),.full(full),.wr_en(write),.wr_data_count(level_wclk),
34 .rd_clk(rclk),.dout(dataout),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
36 fifo_xlnx_512x36_2clk fifo_xlnx_512x36_2clk
38 .wr_clk(wclk),.din(datain),.full(full),.wr_en(write),.wr_data_count(level_wclk),
39 .rd_clk(rclk),.dout(dataout),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
40 else if((WIDTH==19)|(WIDTH==18))
42 fifo_xlnx_16x19_2clk fifo_xlnx_16x19_2clk
44 .wr_clk(wclk),.din(datain),.full(full),.wr_en(write),.wr_data_count(level_wclk),
45 .rd_clk(rclk),.dout(dataout),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
48 assign occupied = {{(16-SIZE-1){1'b0}},level_rclk};
49 assign space = ((1<<SIZE)+1)-level_wclk;
51 endmodule // fifo_2clock
55 // ISE sucks, so the following doesn't work properly
57 reg [AWIDTH-1:0] wr_addr, rd_addr;
58 wire [AWIDTH-1:0] wr_addr_rclk, rd_addr_wclk;
59 wire [AWIDTH-1:0] next_rd_addr;
62 // Write side management
63 wire [AWIDTH-1:0] next_wr_addr = wr_addr + 1;
64 always @(posedge wclk or posedge arst)
68 wr_addr <= next_wr_addr;
69 assign full = (next_wr_addr == rd_addr_wclk);
71 // RAM for data storage. Data out is registered, complicating the
73 ram_2port #(.DWIDTH(DWIDTH),.AWIDTH(AWIDTH)) mac_rx_ff_ram
74 (.clka(wclk),.ena(1'b1),.wea(write),.addra(wr_addr),.dia(datain),.doa(),
75 .clkb(rclk),.enb(enb_read),.web(1'b0),.addrb(next_rd_addr),.dib(0),.dob(dataout) );
77 // Read side management
79 assign empty = ~data_valid;
80 assign next_rd_addr = rd_addr + data_valid;
81 assign enb_read = read | ~data_valid;
83 always @(posedge rclk or posedge arst)
87 rd_addr <= rd_addr + 1;
89 always @(posedge rclk or posedge arst)
93 if(read & (next_rd_addr == wr_addr_rclk))
95 else if(next_rd_addr != wr_addr_rclk)
98 // Send pointers across clock domains via gray code
99 gray_send #(.WIDTH(AWIDTH)) send_wr_addr
100 (.clk_in(wclk),.addr_in(wr_addr),
101 .clk_out(rclk),.addr_out(wr_addr_rclk) );
103 gray_send #(.WIDTH(AWIDTH)) send_rd_addr
104 (.clk_in(rclk),.addr_in(rd_addr),
105 .clk_out(wclk),.addr_out(rd_addr_wclk) );
107 // Generate fullness info, these are approximate and may be delayed
108 // and are only for higher-level flow control.
109 // Only full and empty are guaranteed exact.
110 always @(posedge wclk)
111 level_wclk <= wr_addr - rd_addr_wclk;
112 always @(posedge rclk)
113 level_rclk <= wr_addr_rclk - rd_addr;
115 endmodule // fifo_2clock