File: ctrlport_if_decoder.sv

package info (click to toggle)
uhd 4.9.0.0%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 184,180 kB
  • sloc: cpp: 262,887; python: 112,011; ansic: 102,670; vhdl: 57,031; tcl: 19,924; xml: 8,581; makefile: 3,028; sh: 2,812; pascal: 230; javascript: 120; csh: 94; asm: 20; perl: 11
file content (107 lines) | stat: -rw-r--r-- 3,846 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//
// Copyright 2025 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: ctrlport_if_decoder
//
// Description:
//
//   This block splits a single control port interface into multiple. It is
//   used when you have a single master that needs to access multiple slaves.
//
//   This version also implements address decoding. The request is passed to a
//   slave only if the address falls within that slave's address space. Each
//   slave can have a unique base address and address space size.
//
//   When passed to the slave, the base address is subtracted from the request
//   address.
//
// Parameters:
//
//   NUM_SLAVES : The number of slaves to connect to a master.
//   PORT_BASE  : Base addresses to use for each slave.
//   PORT_SIZE  : Size of the address space for each slave.
//

module ctrlport_if_decoder #(
  int NUM_SLAVES             = 2,
  int PORT_BASE [NUM_SLAVES] = '{'h0,   'h100},
  int PORT_SIZE [NUM_SLAVES] = '{'h100, 'h100}
) (
  // Slave Interface
  ctrlport_if.slave s_ctrlport,
  // Master Interfaces
  ctrlport_if.master m_ctrlport [NUM_SLAVES]
);

  import ctrlport_pkg::*;

  //---------------------------------------------------------------------------
  // Check the address ranges
  //---------------------------------------------------------------------------
  for (genvar i = 0; i < NUM_SLAVES; i = i+1) begin : gen_overlap_1
    for (genvar j = 0; j < NUM_SLAVES; j = j+1) begin : gen_overlap_2
      if (i != j) begin
        if ((PORT_BASE[i] >= PORT_BASE[j]) &&
            (PORT_BASE[i] < PORT_BASE[j] + PORT_SIZE[j])) begin
          $error("Port %0d overlaps with port %0d.", i, j);
        end
      end
    end
  end

  //---------------------------------------------------------------------------
  // Split the requests among the slaves
  //---------------------------------------------------------------------------
  for (genvar i = 0; i < NUM_SLAVES; i = i+1) begin : gen_split
    always_ff @(posedge s_ctrlport.clk) begin
      // unconditionally pass the request by default
      m_ctrlport[i].req <= s_ctrlport.req;
      // pass only the respective address bits
      m_ctrlport[i].req.addr <= '0;
      m_ctrlport[i].req.addr[$clog2(PORT_SIZE[i])-1:0] <= s_ctrlport.req.addr - PORT_BASE[i];

      // read and write trigger transactions and therefore need to react to reset
      if (s_ctrlport.rst) begin
        m_ctrlport[i].req.wr <= 1'b0;
        m_ctrlport[i].req.rd <= 1'b0;
      end else begin
        automatic logic address_in_range;
        address_in_range = (s_ctrlport.req.addr >= PORT_BASE[i]) &&
                           (s_ctrlport.req.addr < PORT_BASE[i] + PORT_SIZE[i]);
        m_ctrlport[i].req.wr <= s_ctrlport.req.wr & address_in_range;
        m_ctrlport[i].req.rd <= s_ctrlport.req.rd & address_in_range;
      end
    end
  end


  //---------------------------------------------------------------------------
  // Decode the responses
  //---------------------------------------------------------------------------
  // Take the responses and mask them with their respective ack
  ctrlport_response_t masked_resp [NUM_SLAVES-1:0];
  for (genvar i = 0; i < NUM_SLAVES; i++) begin : gen_mask
      assign masked_resp[i] = m_ctrlport[i].resp.ack ? m_ctrlport[i].resp : '0;
  end

  // Combine the masked responses by OR'ing them together
  ctrlport_response_t combined_resp;
  always_comb begin : response_combine
    combined_resp = '0;
    for (int i = 0; i < NUM_SLAVES; i++) begin : gen_or
      combined_resp = combined_resp | masked_resp[i];
    end
  end

  // Register the output to break combinatorial path
  always_ff @(posedge s_ctrlport.clk) begin : response_reg
    s_ctrlport.resp <= combined_resp;

    if (s_ctrlport.rst) begin
      s_ctrlport.resp.ack <= '0;
    end
  end

endmodule