Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Stream fork: Connects the input stream (ready-valid) handshake to *all* of `N_OUP` output stream
// handshakes. For each input stream handshake, every output stream handshakes exactly once. The
// input stream only handshakes when all output streams have handshaked, but the output streams do
// not have to handshake simultaneously.
//
// This module has no data ports because stream data does not need to be forked: the data of the
// input stream can just be applied at all output streams.
module stream_fork #(
parameter int unsigned N_OUP = 0 // Synopsys DC requires a default value for parameters.
) (
input logic clk_i,
input logic rst_ni,
input logic valid_i,
output logic ready_o,
output logic [N_OUP-1:0] valid_o,
input logic [N_OUP-1:0] ready_i
);
typedef enum logic {READY, WAIT} state_t;
logic [N_OUP-1:0] oup_ready,
all_ones;
state_t inp_state_d, inp_state_q;
// Input control FSM
always_comb begin
// ready_o = 1'b0;
inp_state_d = inp_state_q;
unique case (inp_state_q)
READY: begin
if (valid_i) begin
if (valid_o == all_ones && ready_i == all_ones) begin
// If handshake on all outputs, handshake on input.
ready_o = 1'b1;
end else begin
ready_o = 1'b0;
// Otherwise, wait for inputs that did not handshake yet.
inp_state_d = WAIT;
end
end else begin
ready_o = 1'b0;
end
end
WAIT: begin
if (valid_i && oup_ready == all_ones) begin
ready_o = 1'b1;
inp_state_d = READY;
end else begin
ready_o = 1'b0;
end
end
default: begin
inp_state_d = READY;
ready_o = 1'b0;
end
endcase
end
always_ff @(posedge clk_i, negedge rst_ni) begin
if (!rst_ni) begin
inp_state_q <= READY;
end else begin
inp_state_q <= inp_state_d;
end
end
// Output control FSM
for (genvar i = 0; i < N_OUP; i++) begin: gen_oup_state
state_t oup_state_d, oup_state_q;
always_comb begin
oup_ready[i] = 1'b1;
valid_o[i] = 1'b0;
oup_state_d = oup_state_q;
unique case (oup_state_q)
READY: begin
if (valid_i) begin
valid_o[i] = 1'b1;
if (ready_i[i]) begin // Output handshake
if (!ready_o) begin // No input handshake yet
oup_state_d = WAIT;
end
end else begin // No output handshake
oup_ready[i] = 1'b0;
end
end
end
WAIT: begin
if (valid_i && ready_o) begin // Input handshake
oup_state_d = READY;
end
end
default: begin
oup_state_d = READY;
end
endcase
end
always_ff @(posedge clk_i, negedge rst_ni) begin
if (!rst_ni) begin
oup_state_q <= READY;
end else begin
oup_state_q <= oup_state_d;
end
end
end
assign all_ones = '1; // Synthesis fix for Vivado, which does not correctly compute the width
// of the '1 literal when assigned to a port of parametrized width.
// pragma translate_off
`ifndef VERILATOR
initial begin: p_assertions
assert (N_OUP >= 1) else $fatal(1, "Number of outputs must be at least 1!");
end
`endif
// pragma translate_on
endmodule
ae5965e0fThis file is pinned to the selected release. Download the original to open it in your design tool.