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