pub module slicer #(
param WIDTH : u32 = 1 ,
param TYPE : type = logic<WIDTH>,
param STAGES : u32 = 1 ,
param ASCENDING_ORDER: bbool = true ,
param FULL_BANDWIDTH : bbool = true ,
param DISABLE_MBFF : bbool = false ,
param USE_RESET : bbool = false ,
) (
i_clk : input clock,
i_rst : input reset,
o_ready: output logic,
i_valid: input logic,
i_data : input TYPE ,
i_ready: input logic,
o_valid: output logic,
o_data : output TYPE ,
) {
const W: u32 = $bits(TYPE);
var ready: logic [STAGES + 1];
var valid: logic [STAGES + 1];
var data : logic<W> [STAGES + 1];
if ASCENDING_ORDER :g {
always_comb {
o_ready = ready[0];
valid[0] = i_valid;
data[0] = i_data;
}
always_comb {
ready[STAGES] = i_ready;
o_valid = valid[STAGES];
o_data = data[STAGES];
}
for i in 0..STAGES :g {
const RESET: bbool = USE_RESET && (i == (STAGES - 1));
if FULL_BANDWIDTH :g {
inst u_slicer: slicer_unit_fb #(
WIDTH : W ,
DISABLE_MBFF: DISABLE_MBFF,
USE_RESET : RESET ,
) (
i_clk : i_clk ,
i_rst : i_rst ,
o_ready: ready[i + 0],
i_valid: valid[i + 0],
i_data : data[i + 0] ,
i_ready: ready[i + 1],
o_valid: valid[i + 1],
o_data : data[i + 1] ,
);
} else {
inst u_slicer: slicer_unit_hb #(
WIDTH : W ,
DISABLE_MBFF: DISABLE_MBFF,
USE_RESET : RESET ,
) (
i_clk : i_clk ,
i_rst : i_rst ,
o_ready: ready[i + 0],
i_valid: valid[i + 0],
i_data : data[i + 0] ,
i_ready: ready[i + 1],
o_valid: valid[i + 1],
o_data : data[i + 1] ,
);
}
}
} else {
always_comb {
o_ready = ready[STAGES];
valid[STAGES] = i_valid;
data[STAGES] = i_data;
}
always_comb {
ready[0] = i_ready;
o_valid = valid[0];
o_data = data[0];
}
for i in 0..STAGES :g {
const RESET: bbool = USE_RESET && (i == 0);
if FULL_BANDWIDTH :g {
inst u_slicer: slicer_unit_fb #(
WIDTH : W ,
DISABLE_MBFF: DISABLE_MBFF,
USE_RESET : RESET ,
) (
i_clk : i_clk ,
i_rst : i_rst ,
o_ready: ready[i + 1],
i_valid: valid[i + 1],
i_data : data[i + 1] ,
i_ready: ready[i + 0],
o_valid: valid[i + 0],
o_data : data[i + 0] ,
);
} else {
inst u_slicer: slicer_unit_hb #(
WIDTH : W ,
DISABLE_MBFF: DISABLE_MBFF,
USE_RESET : RESET ,
) (
i_clk : i_clk ,
i_rst : i_rst ,
o_ready: ready[i + 1],
i_valid: valid[i + 1],
i_data : data[i + 1] ,
i_ready: ready[i + 0],
o_valid: valid[i + 0],
o_data : data[i + 0] ,
);
}
}
}
}
#[test(test_std_slicer)]
embed (inline) sv{{{
module test_std_slicer;
`ifndef VERILATOR
timeunit 1ns/1ps;
bit clk;
bit rst_n;
always #1 begin
clk ^=1;
end
initial begin
rst_n = 1;
@(posedge clk);
rst_n = 0;
@(posedge clk);
rst_n = 1;
end
bit ready_a;
bit valid_a;
bit [7:0] data_a;
bit ack_a;
bit ready_b;
bit valid_b;
bit [7:0] data_b;
bit ready_c;
bit valid_c;
bit [7:0] data_c;
bit ack_c;
assign ack_a = ready_a && valid_a;
assign ack_c = ready_c && valid_c;
clocking cb @(posedge clk);
input ready_a;
output valid_a;
output data_a;
input ack_a;
output ready_c;
input valid_c;
input data_c;
input ack_c;
endclocking
initial begin
cb.valid_a <= '0;
cb.data_a <= '0;
@(negedge rst_n);
@(posedge rst_n);
for (int i = 0;i < 10;++i) begin
cb.valid_a <= '1;
cb.data_a <= i;
do begin
@(cb);
end while (!cb.ack_a);
end
cb.valid_a <= '0;
cb.data_a <= '0;
end
initial begin
cb.ready_c <= '0;
@(negedge rst_n);
@(posedge rst_n);
forever begin
cb.ready_c <= $urandom_range(0, 1);
@(cb);
end
end
initial begin
for (int i = 0;i < 10;++i) begin
do begin
@(cb);
end while (!cb.ack_c);
assert (cb.data_c == i)
else $error("data is not matched");
end
$finish;
end
std_slicer #(
.WIDTH (8 ),
.STAGES (2 ),
.FULL_BANDWIDTH (1 )
) u_slicer_fb (
.i_clk (clk ),
.i_rst (rst_n ),
.o_ready (ready_a ),
.i_valid (valid_a ),
.i_data (data_a ),
.i_ready (ready_b ),
.o_valid (valid_b ),
.o_data (data_b )
);
std_slicer #(
.WIDTH (8 ),
.STAGES (2 ),
.FULL_BANDWIDTH (0 )
) u_slicer_hb (
.i_clk (clk ),
.i_rst (rst_n ),
.o_ready (ready_b ),
.i_valid (valid_b ),
.i_data (data_b ),
.i_ready (ready_c ),
.o_valid (valid_c ),
.o_data (data_c )
);
`endif
endmodule
}}}