1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
//
// Copyright 2011-2012 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// FIXME ignores the AWIDTH (fifo size) parameter
module fifo_2clock
#(parameter WIDTH=36, SIZE=6)
(input wclk, input [WIDTH-1:0] datain, input src_rdy_i, output dst_rdy_o, output [15:0] space,
input rclk, output [WIDTH-1:0] dataout, output src_rdy_o, input dst_rdy_i, output [15:0] occupied,
input arst);
wire [SIZE:0] level_rclk, level_wclk; // xilinx adds an extra bit if you ask for accurate levels
wire full, empty, write, read;
assign dst_rdy_o = ~full;
assign src_rdy_o = ~empty;
assign write = src_rdy_i & dst_rdy_o;
assign read = src_rdy_o & dst_rdy_i;
generate
if((WIDTH <= 36) && (WIDTH > 19)) begin
wire [35:0] data_in_wide, data_out_wide;
assign data_in_wide[WIDTH-1:0] = datain;
assign dataout = data_out_wide[WIDTH-1:0];
if(SIZE==9)
fifo_xlnx_512x36_2clk fifo_xlnx_512x36_2clk
(.rst(arst),
.wr_clk(wclk),.din(data_in_wide),.full(full),.wr_en(write),.wr_data_count(level_wclk),
.rd_clk(rclk),.dout(data_out_wide),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
else if(SIZE==11)
fifo_xlnx_2Kx36_2clk fifo_xlnx_2Kx36_2clk
(.rst(arst),
.wr_clk(wclk),.din(data_in_wide),.full(full),.wr_en(write),.wr_data_count(level_wclk),
.rd_clk(rclk),.dout(data_out_wide),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
else if(SIZE==6)
fifo_xlnx_64x36_2clk fifo_xlnx_64x36_2clk
(.rst(arst),
.wr_clk(wclk),.din(data_in_wide),.full(full),.wr_en(write),.wr_data_count(level_wclk),
.rd_clk(rclk),.dout(data_out_wide),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
else
fifo_xlnx_512x36_2clk fifo_xlnx_512x36_2clk
(.rst(arst),
.wr_clk(wclk),.din(data_in_wide),.full(full),.wr_en(write),.wr_data_count(level_wclk),
.rd_clk(rclk),.dout(data_out_wide),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
end
else if((WIDTH <= 19) && (SIZE <= 4)) begin
wire [18:0] data_in_wide, data_out_wide;
assign data_in_wide[WIDTH-1:0] = datain;
assign dataout = data_out_wide[WIDTH-1:0];
fifo_xlnx_16x19_2clk fifo_xlnx_16x19_2clk
(.rst(arst),
.wr_clk(wclk),.din(data_in_wide),.full(full),.wr_en(write),.wr_data_count(level_wclk),
.rd_clk(rclk),.dout(data_out_wide),.empty(empty),.rd_en(read),.rd_data_count(level_rclk) );
end
endgenerate
assign occupied = {{(16-SIZE-1){1'b0}},level_rclk};
assign space = ((1<<SIZE)+1)-level_wclk;
endmodule // fifo_2clock
/*
`else
// ISE sucks, so the following doesn't work properly
reg [AWIDTH-1:0] wr_addr, rd_addr;
wire [AWIDTH-1:0] wr_addr_rclk, rd_addr_wclk;
wire [AWIDTH-1:0] next_rd_addr;
wire enb_read;
// Write side management
wire [AWIDTH-1:0] next_wr_addr = wr_addr + 1;
always @(posedge wclk or posedge arst)
if(arst)
wr_addr <= 0;
else if(write)
wr_addr <= next_wr_addr;
assign full = (next_wr_addr == rd_addr_wclk);
// RAM for data storage. Data out is registered, complicating the
// read side logic
ram_2port #(.DWIDTH(DWIDTH),.AWIDTH(AWIDTH)) mac_rx_ff_ram
(.clka(wclk),.ena(1'b1),.wea(write),.addra(wr_addr),.dia(datain),.doa(),
.clkb(rclk),.enb(enb_read),.web(1'b0),.addrb(next_rd_addr),.dib(0),.dob(dataout) );
// Read side management
reg data_valid;
assign empty = ~data_valid;
assign next_rd_addr = rd_addr + data_valid;
assign enb_read = read | ~data_valid;
always @(posedge rclk or posedge arst)
if(arst)
rd_addr <= 0;
else if(read)
rd_addr <= rd_addr + 1;
always @(posedge rclk or posedge arst)
if(arst)
data_valid <= 0;
else
if(read & (next_rd_addr == wr_addr_rclk))
data_valid <= 0;
else if(next_rd_addr != wr_addr_rclk)
data_valid <= 1;
// Send pointers across clock domains via gray code
gray_send #(.WIDTH(AWIDTH)) send_wr_addr
(.clk_in(wclk),.addr_in(wr_addr),
.clk_out(rclk),.addr_out(wr_addr_rclk) );
gray_send #(.WIDTH(AWIDTH)) send_rd_addr
(.clk_in(rclk),.addr_in(rd_addr),
.clk_out(wclk),.addr_out(rd_addr_wclk) );
// Generate fullness info, these are approximate and may be delayed
// and are only for higher-level flow control.
// Only full and empty are guaranteed exact.
always @(posedge wclk)
level_wclk <= wr_addr - rd_addr_wclk;
always @(posedge rclk)
level_rclk <= wr_addr_rclk - rd_addr;
`endif
endmodule // fifo_2clock
*/
|