Takes in two or more pipelines and synchronizes them so they can only complete their handshakes simultaneously, then outputs the synchronized handshakes. This forces data to be consumed in FIFO order and in lock-step for all pipelines (e.g.: addresses and data for a memory write, each from independent sources).
We synchronize by first Joining the pipelines, then re-forking them and discarding all but one copy of the data.
A consequence of the synchronization is that the ready signal of the input interfaces will only assert once all input valid lines are asserted. This is a combinational path. There is no buffering. Watch out for combinational loops.
`default_nettype none
module Pipeline_Synchronizer_Lazy
#(
parameter WORD_WIDTH = 0,
parameter PORT_COUNT = 0,
// Do not set at instantiation, except in Vivado IPI
parameter PORT_WIDTH_TOTAL = WORD_WIDTH * PORT_COUNT
)
(
output wire [PORT_COUNT-1:0] input_data_ready,
input wire [PORT_COUNT-1:0] input_data_valid,
input wire [PORT_WIDTH_TOTAL-1:0] input_data,
input wire [PORT_COUNT-1:0] output_data_ready,
output wire [PORT_COUNT-1:0] output_data_valid,
output reg [PORT_WIDTH_TOTAL-1:0] output_data
);
localparam PORT_WIDTH_TOTAL_ZERO = {PORT_WIDTH_TOTAL{1'b0}};
initial begin
output_data = PORT_WIDTH_TOTAL_ZERO;
end
wire input_data_joined_valid;
wire input_data_joined_ready;
wire [PORT_WIDTH_TOTAL-1:0] input_data_joined;
Pipeline_Join_Lazy
#(
.WORD_WIDTH (WORD_WIDTH),
.INPUT_COUNT (PORT_COUNT)
)
input_join
(
.input_valid (input_data_valid),
.input_ready (input_data_ready),
.input_data (input_data),
.output_valid (input_data_joined_valid),
.output_ready (input_data_joined_ready),
.output_data (input_data_joined)
);
We end up with duplicates of the input data since we are creating
PORT_COUNT forked copies of all the PORT_COUNT input data interfaces
joined together. So we discard all but the first copy and keep all the
control signals.
localparam PORT_WIDTH_TOTAL_WITH_DUPLICATES = PORT_WIDTH_TOTAL * PORT_COUNT;
// verilator lint_off UNUSED
wire [PORT_WIDTH_TOTAL_WITH_DUPLICATES-1:0] output_data_with_duplicates;
// verilator lint_on UNUSED
Pipeline_Fork_Lazy
#(
.WORD_WIDTH (PORT_WIDTH_TOTAL),
.OUTPUT_COUNT (PORT_COUNT)
)
output_fork
(
.input_valid (input_data_joined_valid),
.input_ready (input_data_joined_ready),
.input_data (input_data_joined),
.output_valid (output_data_valid),
.output_ready (output_data_ready),
.output_data (output_data_with_duplicates)
);
always @(*) begin
output_data = output_data_with_duplicates [0 +: PORT_WIDTH_TOTAL];
end
endmodule