1// 2// Copyright 2019 Ettus Research, A National Instruments Company 3// 4// SPDX-License-Identifier: LGPL-3.0-or-later 5// 6// Module: ctrlport_decoder 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// This version also implements address decoding. The request is passed to a 16// slave only if the address falls within that slave's address space. Each 17// slave is given an address space of 2**ADDR_W and the first slave starts at 18// address BASE_ADDR. In other words, the request address is partitioned as 19// shown below. 20// 21// |---------------- 32-bit -----------------| 22// | Base | Port Num | Slave Addr | 23// |-----------------------------------------| 24// 25// When passed to the slave, the base address and port number bits are stripped 26// from the request address and only the SLAVE_ADDR_W-bit address is passed 27// through. 28// 29// Parameters: 30// 31// NUM_SLAVES : Number of slave devices that you want to connect to master. 32// BASE_ADDR : Base address for slave 0. This should be a power-of-2 33// multiple of the combined slave address spaces. 34// SLAVE_ADDR_W : Number of address bits to allocate to each slave. 35// 36 37module ctrlport_decoder #( 38 parameter NUM_SLAVES = 2, 39 parameter BASE_ADDR = 0, 40 parameter SLAVE_ADDR_W = 8 41) ( 42 input wire ctrlport_clk, 43 input wire ctrlport_rst, 44 45 // Slave Interface 46 input wire s_ctrlport_req_wr, 47 input wire s_ctrlport_req_rd, 48 input wire [19:0] s_ctrlport_req_addr, 49 input wire [31:0] s_ctrlport_req_data, 50 input wire [ 3:0] s_ctrlport_req_byte_en, 51 input wire s_ctrlport_req_has_time, 52 input wire [63:0] s_ctrlport_req_time, 53 output reg s_ctrlport_resp_ack = 1'b0, 54 output reg [ 1:0] s_ctrlport_resp_status, 55 output reg [31:0] s_ctrlport_resp_data, 56 57 // Master Interfaces 58 output reg [ NUM_SLAVES-1:0] m_ctrlport_req_wr = 0, 59 output reg [ NUM_SLAVES-1:0] m_ctrlport_req_rd = 0, 60 output reg [20*NUM_SLAVES-1:0] m_ctrlport_req_addr = 0, 61 output reg [32*NUM_SLAVES-1:0] m_ctrlport_req_data, 62 output reg [ 4*NUM_SLAVES-1:0] m_ctrlport_req_byte_en, 63 output reg [ NUM_SLAVES-1:0] m_ctrlport_req_has_time, 64 output reg [64*NUM_SLAVES-1:0] m_ctrlport_req_time, 65 input wire [ NUM_SLAVES-1:0] m_ctrlport_resp_ack, 66 input wire [ 2*NUM_SLAVES-1:0] m_ctrlport_resp_status, 67 input wire [32*NUM_SLAVES-1:0] m_ctrlport_resp_data 68); 69 70 localparam PORT_NUM_W = $clog2(NUM_SLAVES); 71 localparam PORT_NUM_POS = SLAVE_ADDR_W; 72 localparam BASE_ADDR_W = 20 - (SLAVE_ADDR_W + PORT_NUM_W); 73 localparam BASE_ADDR_POS = SLAVE_ADDR_W + PORT_NUM_W; 74 localparam [19:0] BASE_ADDR_MASK = { BASE_ADDR_W {1'b1}} << BASE_ADDR_POS; 75 76 77 //--------------------------------------------------------------------------- 78 // Split the requests among the slaves 79 //--------------------------------------------------------------------------- 80 81 wire [NUM_SLAVES-1:0] decoder; 82 83 generate 84 genvar i; 85 for (i = 0; i < NUM_SLAVES; i = i+1) begin : gen_split 86 // Check if the upper bits of the request address match each slave. If the 87 // address matches, set the corresponding decoder[] bit. 88 if (PORT_NUM_W == 0) begin 89 // Only one port in this case, so there are no port number bits to check 90 assign decoder[i] = ((s_ctrlport_req_addr & BASE_ADDR_MASK) == BASE_ADDR); 91 end else begin 92 assign decoder[i] = ((s_ctrlport_req_addr & BASE_ADDR_MASK) == BASE_ADDR) && 93 (s_ctrlport_req_addr[PORT_NUM_POS +: PORT_NUM_W] == i); 94 end 95 96 always @(posedge ctrlport_clk) begin 97 if (ctrlport_rst) begin 98 m_ctrlport_req_wr[i] <= 1'b0; 99 m_ctrlport_req_rd[i] <= 1'b0; 100 end else begin 101 // Mask WR and RD based on address decoding 102 m_ctrlport_req_wr[i] <= s_ctrlport_req_wr & decoder[i]; 103 m_ctrlport_req_rd[i] <= s_ctrlport_req_rd & decoder[i]; 104 105 // Other values pass through to all slaves, but should be ignored 106 // unless the corresponding WR or RD is not asserted. 107 m_ctrlport_req_data [32*i +: 32] <= s_ctrlport_req_data; 108 m_ctrlport_req_byte_en [4*i +: 4] <= s_ctrlport_req_byte_en; 109 m_ctrlport_req_has_time[i] <= s_ctrlport_req_has_time; 110 m_ctrlport_req_time [64*i +: 64] <= s_ctrlport_req_time; 111 112 // Pass through only the relevant slave bits 113 m_ctrlport_req_addr[20*i+:20] <= 20'b0; 114 m_ctrlport_req_addr[20*i+:SLAVE_ADDR_W] <= s_ctrlport_req_addr[SLAVE_ADDR_W-1:0]; 115 end 116 end 117 end 118 endgenerate 119 120 121 //--------------------------------------------------------------------------- 122 // Decode the responses 123 //--------------------------------------------------------------------------- 124 125 reg [31:0] data; 126 reg [ 1:0] status; 127 reg ack = 0; 128 129 // Take the responses and mask them with ack, then OR them together 130 always @(*) begin : comb_decode 131 integer s; 132 data = 0; 133 status = 0; 134 ack = 0; 135 for (s = 0; s < NUM_SLAVES; s = s+1) begin 136 data = data | (m_ctrlport_resp_data [s*32 +: 32] & {32{m_ctrlport_resp_ack[s]}}); 137 status = status | (m_ctrlport_resp_status[s* 2 +: 2] & { 2{m_ctrlport_resp_ack[s]}}); 138 ack = ack | m_ctrlport_resp_ack[s]; 139 end 140 end 141 142 // Register the output to break combinatorial path 143 always @(posedge ctrlport_clk) begin 144 if (ctrlport_rst) begin 145 s_ctrlport_resp_ack <= 0; 146 end else begin 147 s_ctrlport_resp_data <= data; 148 s_ctrlport_resp_status <= status; 149 s_ctrlport_resp_ack <= ack; 150 end 151 end 152 153endmodule 154