// Copyright 2020 ETH Zurich and University of Bologna. // Solderpad Hardware License, Version 0.51, see LICENSE for details. // SPDX-License-Identifier: SHL-0.51 /// Arbitrates request/response interface /// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch> /// Demux based on arbitration module snitch_demux #( parameter int unsigned NrPorts = 4, parameter type req_t = snitch_pkg::dreq_t, parameter type resp_t = snitch_pkg::dresp_t, parameter int unsigned RespDepth = 8, parameter bit [NrPorts-1:0] RegisterReq = '0, parameter Arbiter = "rr" // "rr" or "prio" ) ( input logic clk_i, input logic rst_ni, // request port input req_t [NrPorts-1:0] req_payload_i, input logic [NrPorts-1:0] req_valid_i, output logic [NrPorts-1:0] req_ready_o, output resp_t [NrPorts-1:0] resp_payload_o, output logic [NrPorts-1:0] resp_last_o, output logic [NrPorts-1:0] resp_valid_o, input logic [NrPorts-1:0] resp_ready_i, // response port output req_t req_payload_o, output logic req_valid_o, input logic req_ready_i, input resp_t resp_payload_i, input logic resp_last_i, input logic resp_valid_i, output logic resp_ready_o ); localparam LogNrPorts = (NrPorts > 1) ? $clog2(NrPorts) : 1; logic [NrPorts-1:0] req_valid_masked; logic [NrPorts-1:0] req_ready_masked; logic [LogNrPorts-1:0] idx, idx_rsp; logic full; req_t [NrPorts-1:0] req_payload_q; logic [NrPorts-1:0] req_valid_q; logic [NrPorts-1:0] req_ready_q; // Cut the incoming path for (genvar i = 0; i < NrPorts; i++) begin : gen_spill_regs spill_register #( .T ( req_t ), .Bypass ( !RegisterReq[i] ) ) i_spill_register_tcdm_req ( .clk_i, .rst_ni, .valid_i ( req_valid_i [i] ), .ready_o ( req_ready_o [i] ), .data_i ( req_payload_i [i] ), .valid_o ( req_valid_q [i] ), .ready_i ( req_ready_masked [i] ), .data_o ( req_payload_q [i] ) ); end for (genvar i = 0; i < NrPorts; i++) begin : gen_req_valid_masked assign req_valid_masked[i] = req_valid_q[i] & ~full; assign req_ready_masked[i] = req_ready_q[i] & ~full; end /// Arbitrate on instruction request port stream_arbiter #( .DATA_T ( req_t ), .N_INP ( NrPorts ), .ARBITER ( Arbiter ) ) i_stream_arbiter_req ( .clk_i, .rst_ni, .inp_data_i ( req_payload_q ), .inp_valid_i ( req_valid_masked ), .inp_ready_o ( req_ready_q ), .oup_data_o ( req_payload_o ), .oup_valid_o ( req_valid_o ), .oup_ready_i ( req_ready_i ) ); if (NrPorts == 1) begin assign idx_rsp = 0; assign full = 1'b0; end else begin onehot_to_bin #( .ONEHOT_WIDTH ( NrPorts ) ) i_onehot_to_bin ( .onehot ( req_valid_q & req_ready_q ), .bin ( idx ) ); fifo_v3 #( .DATA_WIDTH ( LogNrPorts ), .DEPTH ( RespDepth ) ) i_resp_fifo ( .clk_i, .rst_ni, .flush_i ( 1'b0 ), .testmode_i ( 1'b0 ), .full_o ( full ), .empty_o ( ), .usage_o ( ), .data_i ( idx ), // only reads will generate a response message .push_i ( req_valid_o & req_ready_i & ~req_payload_o.write ), .data_o ( idx_rsp ), .pop_i ( resp_ready_o & resp_valid_i & resp_last_i ) ); end stream_demux #( .N_OUP ( NrPorts ) ) i_stream_demux_resp ( .inp_valid_i ( resp_valid_i ), .inp_ready_o ( resp_ready_o ), .oup_sel_i ( idx_rsp ), .oup_valid_o ( resp_valid_o ), .oup_ready_i ( resp_ready_i ) ); for (genvar i = 0; i < NrPorts; i++) begin assign resp_payload_o[i] = resp_payload_i; assign resp_last_o[i] = resp_last_i; end endmodule