Skip to content

Commit f7c4995

Browse files
committed
Added fifo combiner
1 parent b8af169 commit f7c4995

5 files changed

+417
-102
lines changed

fifo_combiner.sv

+174
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
//------------------------------------------------------------------------------
2+
// fifo_combiner.sv
3+
// published as part of https://github.com/pConst/basic_verilog
4+
// Konstantin Pavlov, [email protected]
5+
//------------------------------------------------------------------------------
6+
7+
// INFO ------------------------------------------------------------------------
8+
// Combines / accumulates data words from multiple FIFOs to a single output FIFO.
9+
// Features three different element enumeration strategies.
10+
// Reads if ANY input FIFO has data.
11+
//
12+
// See also fifo_operator.sv
13+
//
14+
15+
/* --- INSTANTIATION TEMPLATE BEGIN ---
16+
17+
fifo_combiner #(
18+
.WIDTH( 2 ),
19+
.ENCODER_MODE( "ROUND_ROBIN" ),
20+
.FWFT_MODE( "TRUE" ),
21+
.DATA_W( 32 )
22+
) FC1 (
23+
.clk( ),
24+
.nrst( ),
25+
26+
.r_empty( ),
27+
.r_req( ),
28+
.r_data( ),
29+
30+
.w_full( ), // connect to "almost_full" if FWFT_MODE="FALSE"
31+
.w_req( ),
32+
.w_data( )
33+
);
34+
35+
--- INSTANTIATION TEMPLATE END ---*/
36+
37+
module fifo_combiner #( parameter
38+
39+
WIDTH = 2, // number of input fifo ports to combine
40+
WIDTH_W = clogb2(WIDTH), // input port index width
41+
ENCODER_MODE = "ROUND_ROBIN", // "ROUND_ROBIN", "ROUND_ROBIN_PERFORMANCE" or "PRIORITY"
42+
FWFT_MODE = "TRUE", // "TRUE" - first word fall-trrough" mode
43+
// "FALSE" - normal fifo mode
44+
DATA_W = 32 // data field width
45+
)(
46+
47+
input clk, // clock
48+
input nrst, // inverted reset
49+
50+
// input ports
51+
input [WIDTH-1:0] r_empty,
52+
output [WIDTH-1:0] r_req,
53+
input [WIDTH-1:0][DATA_W-1:0] r_data,
54+
55+
// output port
56+
input w_full,
57+
output logic w_req,
58+
output logic [DATA_W-1:0] w_data
59+
);
60+
61+
62+
logic enc_valid;
63+
logic [WIDTH-1:0] enc_filt;
64+
logic [WIDTH_W-1:0] enc_bin;
65+
66+
logic [WIDTH-1:0] r_empty_rev;
67+
reverse_vector #(
68+
.WIDTH( WIDTH ) // WIDTH must be >=2
69+
) empty_rev (
70+
.in( r_empty[WIDTH-1:0] ),
71+
.out( r_empty_rev[WIDTH-1:0] )
72+
);
73+
74+
generate
75+
if( ENCODER_MODE == "ROUND_ROBIN" ) begin
76+
round_robin_enc #(
77+
.WIDTH( WIDTH )
78+
) rr_enc (
79+
.clk( clk ),
80+
.nrst( nrst ),
81+
.id( ~r_empty[WIDTH-1:0] ),
82+
.od_valid( enc_valid ),
83+
.od_filt( enc_filt[WIDTH-1:0] ),
84+
.od_bin( enc_bin[WIDTH_W-1:0] )
85+
);
86+
end else if( ENCODER_MODE == "ROUND_ROBIN_PERFORMANCE" ) begin
87+
round_robin_performance_enc #(
88+
.WIDTH( WIDTH )
89+
) rr_perf_enc (
90+
.clk( clk ), // !!
91+
.nrst( nrst ),
92+
.id(~r_empty[WIDTH-1:0] ),
93+
.od_valid( enc_valid ),
94+
.od_filt( enc_filt[WIDTH-1:0] ),
95+
.od_bin( enc_bin[WIDTH_W-1:0] )
96+
);
97+
end else if( ENCODER_MODE == "PRIORITY" ) begin
98+
priority_enc #(
99+
.WIDTH( WIDTH ) // WIDTH must be >=2
100+
) pri_enc (
101+
.id( ~r_empty[WIDTH-1:0] ),
102+
.od_valid( enc_valid ),
103+
.od_filt( enc_filt[WIDTH-1:0] ),
104+
.od_bin( enc_bin[WIDTH_W-1:0] )
105+
);
106+
end // ENCODER_MODE
107+
endgenerate
108+
109+
110+
logic r_valid;
111+
assign r_valid = enc_valid && ~w_full;
112+
113+
assign r_req[WIDTH-1:0] = {WIDTH{r_valid}} &&
114+
enc_filt[WIDTH-1:0];
115+
116+
// buffering read data
117+
logic r_valid_d1 = 1'b0;
118+
logic [WIDTH_W-1:0] enc_bin_d1;
119+
logic [WIDTH-1:0][DATA_W-1:0] r_data_d1 = '0;
120+
always_ff @(posedge clk) begin
121+
if ( ~nrst ) begin
122+
r_valid_d1 <= 1'b0;
123+
enc_bin_d1[WIDTH_W-1:0] <= '0;
124+
r_data_d1[WIDTH-1:0] <= '0;
125+
end else begin
126+
r_valid_d1 <= r_valid;
127+
enc_bin_d1[WIDTH_W-1:0] <= enc_bin[WIDTH_W-1:0];
128+
r_data_d1[WIDTH-1:0] <= r_data[WIDTH-1:0];
129+
end
130+
end
131+
132+
// routing data to write port
133+
generate
134+
if( FWFT_MODE == "TRUE" ) begin
135+
136+
always_comb begin
137+
if ( ~nrst ) begin
138+
w_req = 1'b0;
139+
w_data[DATA_W-1:0] = '0;
140+
end else begin
141+
if( r_valid ) begin
142+
w_req = 1'b1;
143+
w_data[DATA_W-1:0] = r_data[enc_bin[WIDTH_W-1:0]][DATA_W-1:0];
144+
end else begin
145+
w_req = 1'b0;
146+
w_data[DATA_W-1:0] = '0;
147+
end
148+
end
149+
end
150+
151+
end else if( FWFT_MODE == "FALSE" ) begin
152+
153+
always_comb begin
154+
if ( ~nrst ) begin
155+
w_req = 1'b0;
156+
w_data[DATA_W-1:0] = '0;
157+
end else begin
158+
if( r_valid_d1 ) begin
159+
w_req = 1'b1;
160+
w_data[DATA_W-1:0] = r_data_d1[enc_bin_d1[WIDTH_W-1:0]][DATA_W-1:0];
161+
end else begin
162+
w_req = 1'b0;
163+
w_data[DATA_W-1:0] = '0;
164+
end
165+
end
166+
end
167+
168+
end // FWFT_MODE
169+
endgenerate
170+
171+
`include "clogb2.svh"
172+
173+
endmodule
174+

fifo_operator.sv

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
//------------------------------------------------------------------------------
2+
// fifo_operator.sv
3+
// published as part of https://github.com/pConst/basic_verilog
4+
// Konstantin Pavlov, [email protected]
5+
//------------------------------------------------------------------------------
6+
7+
// INFO ------------------------------------------------------------------------
8+
// Performs custom operation on data words from multiple FIFOs and stores
9+
// result to a single output FIFO.
10+
// Reads only if ALL input FIFOs have data.
11+
// Source code could be easily adapted to apply any operator on input data.
12+
//
13+
// See also fifo_combiner.sv
14+
//
15+
16+
/* --- INSTANTIATION TEMPLATE BEGIN ---
17+
18+
fifo_operator #(
19+
.WIDTH( 2 ),
20+
.FWFT_MODE( "TRUE" ),
21+
.DATA_W( 32 )
22+
) FO1 (
23+
.clk( ),
24+
.nrst( ),
25+
26+
.r_empty( ),
27+
.r_req( ),
28+
.r_data( ),
29+
30+
.w_full( ), // connect to "almost_full" if FWFT_MODE="FALSE"
31+
.w_req( ),
32+
.w_data( )
33+
);
34+
35+
--- INSTANTIATION TEMPLATE END ---*/
36+
37+
module fifo_operator #( parameter
38+
39+
WIDTH = 2, // number of input fifo ports to opeate on
40+
WIDTH_W = clogb2(WIDTH), // input port index width
41+
FWFT_MODE = "TRUE", // "TRUE" - first word fall-trrough" mode
42+
// "FALSE" - normal fifo mode
43+
DATA_W = 32 // data field width
44+
)(
45+
46+
input clk, // clock
47+
input nrst, // inverted reset
48+
49+
// input ports
50+
input [WIDTH-1:0] r_empty,
51+
output [WIDTH-1:0] r_req,
52+
input [WIDTH-1:0][DATA_W-1:0] r_data,
53+
54+
// output port
55+
input w_full,
56+
output logic w_req,
57+
output logic [DATA_W-1:0] w_data
58+
);
59+
60+
61+
logic r_valid;
62+
assign r_valid = ~|r_empty && ~w_full;
63+
64+
assign r_req[WIDTH-1:0] = {WIDTH{r_valid}};
65+
66+
// buffering read data
67+
logic r_valid_d1 = 1'b0;
68+
logic [WIDTH-1:0][DATA_W-1:0] r_data_d1 = '0;
69+
always_ff @(posedge clk) begin
70+
if ( ~nrst ) begin
71+
r_valid_d1 <= 1'b0;
72+
r_data_d1[WIDTH-1:0] <= '0;
73+
end else begin
74+
r_valid_d1 <= r_valid;
75+
r_data_d1[WIDTH-1:0] <= r_data[WIDTH-1:0];
76+
end
77+
end
78+
79+
// routing data to write port
80+
generate
81+
if( FWFT_MODE == "TRUE" ) begin
82+
83+
always_comb begin
84+
if ( ~nrst ) begin
85+
w_req = 1'b0;
86+
w_data[DATA_W-1:0] = '0;
87+
end else begin
88+
if( r_valid ) begin
89+
w_req = 1'b1;
90+
w_data[DATA_W-1:0] = operator(r_data);
91+
end else begin
92+
w_req = 1'b0;
93+
w_data[DATA_W-1:0] = '0;
94+
end
95+
end
96+
end
97+
98+
end else if( FWFT_MODE == "FALSE" ) begin
99+
100+
always_comb begin
101+
if ( ~nrst ) begin
102+
w_req = 1'b0;
103+
w_data[DATA_W-1:0] = '0;
104+
end else begin
105+
if( r_valid_d1 ) begin
106+
w_req = 1'b1;
107+
w_data[DATA_W-1:0] = operator(r_data_d1);
108+
end else begin
109+
w_req = 1'b0;
110+
w_data[DATA_W-1:0] = '0;
111+
end
112+
end
113+
end
114+
115+
end // FWFT_MODE
116+
endgenerate
117+
118+
// bitwize OR operator, as an example
119+
function [DATA_W-1:0] operator (
120+
input [WIDTH-1:0][DATA_W-1:0] data
121+
);
122+
integer i;
123+
operator[DATA_W-1:0] = '0;
124+
for( i=0; i<WIDTH; i=i+1 ) begin
125+
operator[DATA_W-1:0] = operator[DATA_W-1:0] | data[i];
126+
end
127+
endfunction
128+
129+
`include "clogb2.svh"
130+
131+
endmodule
132+

priority_enc.sv

+29-26
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ priority_enc #(
2626

2727
module priority_enc #( parameter
2828
WIDTH = 32,
29-
WIDTH_W = $clog2(WIDTH)
29+
WIDTH_W = $clogb2(WIDTH)
3030
)(
3131
input [WIDTH-1:0] id, // input data bus
3232

@@ -36,34 +36,37 @@ module priority_enc #( parameter
3636
);
3737

3838

39-
// reversed id[] data
40-
// conventional operation of priority encoder is when MSB bits have a priority
41-
logic [WIDTH-1:0] id_r;
42-
reverse_vector #(
43-
.WIDTH( WIDTH ) // WIDTH must be >=2
44-
) reverse_b (
45-
.in( id[WIDTH-1:0] ),
46-
.out( id_r[WIDTH-1:0] )
47-
);
39+
// reversed id[] data
40+
// conventional operation of priority encoder is when MSB bits have a priority
41+
logic [WIDTH-1:0] id_r;
42+
reverse_vector #(
43+
.WIDTH( WIDTH ) // WIDTH must be >=2
44+
) reverse_b (
45+
.in( id[WIDTH-1:0] ),
46+
.out( id_r[WIDTH-1:0] )
47+
);
4848

49-
leave_one_hot #(
50-
.WIDTH( WIDTH )
51-
) one_hot_b (
52-
.in( id_r[WIDTH-1:0] ),
53-
.out( od_filt[WIDTH-1:0] )
54-
);
49+
leave_one_hot #(
50+
.WIDTH( WIDTH )
51+
) one_hot_b (
52+
.in( id_r[WIDTH-1:0] ),
53+
.out( od_filt[WIDTH-1:0] )
54+
);
5555

56-
logic err_no_hot;
57-
assign od_valid = ~err_no_hot;
56+
logic err_no_hot;
57+
assign od_valid = ~err_no_hot;
5858

59-
pos2bin #(
60-
.BIN_WIDTH( WIDTH_W )
61-
) pos2bin_b (
62-
.pos( od_filt[WIDTH-1:0] ),
63-
.bin( od_bin[WIDTH_W-1:0] ),
59+
pos2bin #(
60+
.BIN_WIDTH( WIDTH_W )
61+
) pos2bin_b (
62+
.pos( od_filt[WIDTH-1:0] ),
63+
.bin( od_bin[WIDTH_W-1:0] ),
6464

65-
.err_no_hot( err_no_hot ),
66-
.err_multi_hot( )
67-
);
65+
.err_no_hot( err_no_hot ),
66+
.err_multi_hot( )
67+
);
68+
69+
`include "clogb2.svh"
6870

6971
endmodule
72+

0 commit comments

Comments
 (0)