rupertlssmith
Junior Member level 1

Hi,
I'm trying to produce a variation on a FIFO, that lets me consume less than the input width of the FIFO on the output end; between zero and the full width. The width of the FIFO is a multiple of a word size, and that multiple is a parameter to the module. In order to map the read and write vectors onto the FIFO registers, I wanted to make use of a generate loop. Xilinx ISE doesn't like it, and complains that multiple inputs are driving elements of the register vector. If I hand unroll the loop, its ok, just not with the loop in place.
Here's the module:
You can see I have commented out the first generated loop, for the write vector, and am using a hand unrolled version. The generate loop at the end for the read vector seem ok, so the generate loop is being used there, and the hand unrolled version is commented out. The generate loop at the start is acceptable syntax but causes the multiple inputs driving the register array error.
Is this just an ISE quirk? or am I trying to do something more fundamentally wrong in Verilog?
Hand unrolling 4 loops is ok for now, but I'd really like to get the module parametrized to generate different widths.
Thanks for any assistance.
Rupert
---------- Post added at 23:17 ---------- Previous post was at 23:12 ----------
Also, I feel like I want to do this for the write vector generate loop:
That is, to put the loop inside the always block. But that doesn't seem to be legal Verilog. Is there a way of putting a generate loop inside an always block? or do I have to generate multiple always blocks?
I'm trying to produce a variation on a FIFO, that lets me consume less than the input width of the FIFO on the output end; between zero and the full width. The width of the FIFO is a multiple of a word size, and that multiple is a parameter to the module. In order to map the read and write vectors onto the FIFO registers, I wanted to make use of a generate loop. Xilinx ISE doesn't like it, and complains that multiple inputs are driving elements of the register vector. If I hand unroll the loop, its ok, just not with the loop in place.
Here's the module:
Code:
module fifo
#(
parameter ADDR_SIZE = 4, // Address size in bits.
parameter WORD_SIZE = 8, // Word size in bits.
parameter CHNK_EXPO = 2, // Chunk factor as a power to raise 2 by to multiply the word size by.
// Derived parameters do not override.
parameter CHNK_FACT = 2 ** CHNK_EXPO,
parameter CHNK_SIZE = WORD_SIZE * CHNK_FACT,
parameter FIFO_SIZE = 2 ** ADDR_SIZE
)
(
input wire clk, reset,
input wire rd, wr,
input wire [CHNK_EXPO - 1 : 0] consume,
input wire [CHNK_SIZE - 1 : 0] w_data,
output wire empty, full,
output wire [CHNK_EXPO - 1 : 0] avail,
output wire [CHNK_SIZE - 1 : 0] r_data
);
// Signal declaration.
reg [WORD_SIZE - 1 : 0] array_reg [FIFO_SIZE - 1 : 0];
reg [ADDR_SIZE - 1 : 0] w_ptr_reg, w_ptr_next, w_ptr_succ;
reg [ADDR_SIZE - 1 : 0] r_ptr_reg, r_ptr_next, r_ptr_succ;
reg [CHNK_EXPO - 1 : 0] avail_reg, avail_next;
reg full_reg, empty_reg, full_next, empty_next;
wire wr_en;
// Synchronous state update.
genvar i;
/*
generate
for (i = 0; i < CHNK_FACT; i = i + 1) begin : gen_write
always @(posedge clk)
if (wr_en)
begin
array_reg[w_ptr_reg + i] <= w_data[WORD_SIZE * (i + 1) - 1 : WORD_SIZE * i];
end
end
endgenerate
*/
always @(posedge clk)
if (wr_en)
begin
array_reg[w_ptr_reg] <= w_data[WORD_SIZE - 1 : 0];
array_reg[w_ptr_reg + 1] <= w_data[WORD_SIZE * 2- 1 : WORD_SIZE];
array_reg[w_ptr_reg + 2] <= w_data[WORD_SIZE * 3 - 1 : WORD_SIZE * 2];
array_reg[w_ptr_reg + 3] <= w_data[WORD_SIZE * 4 - 1 : WORD_SIZE * 3];
end
always @(posedge clk, posedge reset)
if (reset)
begin
w_ptr_reg <= 0;
r_ptr_reg <= 0;
full_reg <= 1'b0;
empty_reg <= 1'b1;
avail_reg <= 0;
end
else
begin
w_ptr_reg <= w_ptr_next;
r_ptr_reg <= r_ptr_next;
full_reg <= full_next;
empty_reg <= empty_next;
avail_next <= avail_reg;
end
// Next state logic.
assign wr_en = wr & ~full_reg;
always @*
begin
w_ptr_succ = w_ptr_reg + CHNK_FACT;
r_ptr_succ = r_ptr_reg + consume + 1;
w_ptr_next = w_ptr_reg;
r_ptr_next = r_ptr_reg;
full_next = full_reg;
empty_next = empty_reg;
avail_next = avail_reg;
case ({wr, rd})
// 2'b00: no op
2'b01: // read.
if (~empty_reg)
begin
r_ptr_next = r_ptr_succ;
full_next = 1'b0;
if (r_ptr_succ == w_ptr_reg)
empty_next = 1'b1;
avail_next = avail_reg - (consume + 1);
end
2'b10: // write.
if (~full_reg)
begin
w_ptr_next = w_ptr_succ;
empty_next = 1'b0;
if (w_ptr_succ > r_ptr_reg + CHNK_FACT)
full_next = 1'b1;
avail_next = avail_reg + CHNK_FACT;
end
2'b11: // read and write.
begin
w_ptr_next = w_ptr_succ;
r_ptr_next = r_ptr_succ;
if (w_ptr_succ > r_ptr_reg + CHNK_FACT)
full_next = 1'b1;
avail_next = avail_reg - (consume + 1) + CHNK_FACT;
end
endcase
end
// Output logic.
assign full = full_reg;
assign empty = empty_reg;
generate
for (i = 0; i < CHNK_FACT; i = i + 1) begin : gen_read
assign r_data[WORD_SIZE * (i + 1) - 1 : WORD_SIZE * i] = array_reg[r_ptr_reg + i];
end
endgenerate
/*
assign r_data[WORD_SIZE - 1 : 0] = array_reg[r_ptr_reg];
assign r_data[WORD_SIZE * 2 - 1 : WORD_SIZE] = array_reg[r_ptr_reg + 1];
assign r_data[WORD_SIZE * 3 - 1 : WORD_SIZE * 2] = array_reg[r_ptr_reg + 2];
assign r_data[WORD_SIZE * 4 - 1 : WORD_SIZE * 3] = array_reg[r_ptr_reg + 3];
*/
endmodule
You can see I have commented out the first generated loop, for the write vector, and am using a hand unrolled version. The generate loop at the end for the read vector seem ok, so the generate loop is being used there, and the hand unrolled version is commented out. The generate loop at the start is acceptable syntax but causes the multiple inputs driving the register array error.
Is this just an ISE quirk? or am I trying to do something more fundamentally wrong in Verilog?
Hand unrolling 4 loops is ok for now, but I'd really like to get the module parametrized to generate different widths.
Thanks for any assistance.
Rupert
---------- Post added at 23:17 ---------- Previous post was at 23:12 ----------
Also, I feel like I want to do this for the write vector generate loop:
Code:
generate
always @(posedge clk)
if (wr_en)
begin
for (i = 0; i < CHNK_FACT; i = i + 1) begin : gen_write
array_reg[w_ptr_reg + i] <= w_data[WORD_SIZE * (i + 1) - 1 : WORD_SIZE * i];
end
end
endgenerate
That is, to put the loop inside the always block. But that doesn't seem to be legal Verilog. Is there a way of putting a generate loop inside an always block? or do I have to generate multiple always blocks?