1//
2// Copyright 2019 Ettus Research, A National Instruments Company
3//
4// SPDX-License-Identifier: LGPL-3.0-or-later
5//
6// Module: ctrlport_splitter
7//
8// Description:
9//
10// This block splits a single control port interface into multiple. It is used
11// when you have a single master that needs to access multiple slaves. For
12// example, a NoC block where the registers are implemented in multiple
13// submodules that must be read/written by a single NoC shell.
14//
15// Note that this block does not do any address decoding, so the connected
16// slaves must use non-overlapping address spaces.
17//
18// This module takes the request received by its single slave interface and
19// outputs it on all its master interfaces. In the opposite direction, it takes
20// the responses received by its multiple master interfaces and combines them
21// into a single response on its slave interface. This is done by using the ack
22// bit of each response to mask the other bits of the response, then OR'ing all
23// of the masked responses together onto a single response bus. This is valid
24// because only one block is allowed to respond to a single request.
25//
26// Parameters:
27//
28//   NUM_SLAVES : The number of slaves you want to connect to a master.
29//
30
31
32module ctrlport_splitter #(
33  parameter NUM_SLAVES = 2
34) (
35  input wire ctrlport_clk,
36  input wire ctrlport_rst,
37
38  // Slave Interface
39  input  wire        s_ctrlport_req_wr,
40  input  wire        s_ctrlport_req_rd,
41  input  wire [19:0] s_ctrlport_req_addr,
42  input  wire [31:0] s_ctrlport_req_data,
43  input  wire [ 3:0] s_ctrlport_req_byte_en,
44  input  wire        s_ctrlport_req_has_time,
45  input  wire [63:0] s_ctrlport_req_time,
46  output reg         s_ctrlport_resp_ack = 1'b0,
47  output reg  [ 1:0] s_ctrlport_resp_status,
48  output reg  [31:0] s_ctrlport_resp_data,
49
50  // Master Interfaces
51  output wire [   NUM_SLAVES-1:0] m_ctrlport_req_wr,
52  output wire [   NUM_SLAVES-1:0] m_ctrlport_req_rd,
53  output wire [20*NUM_SLAVES-1:0] m_ctrlport_req_addr,
54  output wire [32*NUM_SLAVES-1:0] m_ctrlport_req_data,
55  output wire [ 4*NUM_SLAVES-1:0] m_ctrlport_req_byte_en,
56  output wire [   NUM_SLAVES-1:0] m_ctrlport_req_has_time,
57  output wire [64*NUM_SLAVES-1:0] m_ctrlport_req_time,
58  input  wire [   NUM_SLAVES-1:0] m_ctrlport_resp_ack,
59  input  wire [ 2*NUM_SLAVES-1:0] m_ctrlport_resp_status,
60  input  wire [32*NUM_SLAVES-1:0] m_ctrlport_resp_data
61);
62
63  generate
64    if (NUM_SLAVES == 1) begin : gen_no_split
65      // No logic is needed if only one slave is going to be connected
66      assign m_ctrlport_req_wr       = s_ctrlport_req_wr;
67      assign m_ctrlport_req_rd       = s_ctrlport_req_rd;
68      assign m_ctrlport_req_addr     = s_ctrlport_req_addr;
69      assign m_ctrlport_req_data     = s_ctrlport_req_data;
70      assign m_ctrlport_req_byte_en  = s_ctrlport_req_byte_en;
71      assign m_ctrlport_req_has_time = s_ctrlport_req_has_time;
72      assign m_ctrlport_req_time     = s_ctrlport_req_time;
73      always @(*) begin
74        s_ctrlport_resp_ack     = m_ctrlport_resp_ack;
75        s_ctrlport_resp_status  = m_ctrlport_resp_status;
76        s_ctrlport_resp_data    = m_ctrlport_resp_data;
77      end
78
79    end else begin : gen_splitter
80      //---------------------------------------------------------------------------
81      // Split the requests among the slaves
82      //---------------------------------------------------------------------------
83
84      genvar i;
85      for (i = 0; i < NUM_SLAVES; i = i+1) begin : gen_split
86        // No special logic is required to split the requests from the master among
87        // multiple slaves.
88        assign m_ctrlport_req_wr[i]           = s_ctrlport_req_wr;
89        assign m_ctrlport_req_rd[i]           = s_ctrlport_req_rd;
90        assign m_ctrlport_req_addr[20*i+:20]  = s_ctrlport_req_addr;
91        assign m_ctrlport_req_data[32*i+:32]  = s_ctrlport_req_data;
92        assign m_ctrlport_req_byte_en[4*i+:4] = s_ctrlport_req_byte_en;
93        assign m_ctrlport_req_has_time[i]     = s_ctrlport_req_has_time;
94        assign m_ctrlport_req_time[64*i+:64]  = s_ctrlport_req_time;
95      end
96
97      //---------------------------------------------------------------------------
98      // Decode the responses
99      //---------------------------------------------------------------------------
100
101      reg [31:0] data;
102      reg [ 1:0] status;
103      reg        ack = 0;
104
105      // Take the responses and mask them with ack, then OR them together
106      always @(*) begin : comb_decode
107        integer s;
108        data   = 0;
109        status = 0;
110        ack    = 0;
111        for (s = 0; s < NUM_SLAVES; s = s+1) begin
112          data   = data   | (m_ctrlport_resp_data  [s*32 +: 32] & {32{m_ctrlport_resp_ack[s]}});
113          status = status | (m_ctrlport_resp_status[s* 2 +:  2] & { 2{m_ctrlport_resp_ack[s]}});
114          ack    = ack    | m_ctrlport_resp_ack[s];
115        end
116      end
117
118      // Register the output to break combinatorial path
119      always @(posedge ctrlport_clk) begin : response_reg
120        if (ctrlport_rst) begin
121          s_ctrlport_resp_ack  <= 0;
122        end else begin
123          s_ctrlport_resp_data   <= data;
124          s_ctrlport_resp_status <= status;
125          s_ctrlport_resp_ack    <= ack;
126        end
127      end
128    end
129  endgenerate
130endmodule
131