aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/rfnoc/crossbar/chdr_xb_routing_table.v
blob: 722c21a36bcb337ef0067ecec3ab7ec77ef20d26 (plain)
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//
// Copyright 2021 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: chdr_xb_routing_table
//
// Description:
//
//   A routing table for the CHDR crossbar. This table is designed to be shared
//   between all ports. It has an AXI-Stream lookup interface and two
//   simplified ctrlport configuration interfaces, one for crossbar (XB) ports
//   and the other for external configuration.
//
//   To insert an entry into the routing table, write the desired output port
//   number to the EPID address. That is, put the EPID for a route into the
//   req_addr field and the corresponding output port number on the req_data
//   field.
//
// Parameters:
//
//   SIZE            : The number entries to support in the routing table.
//   NPORTS          : The number of output crossbar ports.
//   EXT_INS_PORT_EN : Set to 1 to enable the external configuration interface.
//

`default_nettype none


module chdr_xb_routing_table #(
  parameter SIZE            = 6,
  parameter NPORTS          = 4,
  parameter EXT_INS_PORT_EN = 1
) (
  // Clocks and resets
  input  wire                               clk,
  input  wire                               reset,
  // Insertion Interface (for XB ports)
  input  wire [                 NPORTS-1:0] port_req_wr,
  input  wire [            (16*NPORTS)-1:0] port_req_addr,
  input  wire [            (32*NPORTS)-1:0] port_req_data,
  output wire [                 NPORTS-1:0] port_resp_ack,
  // Insertion Interface (External)
  input  wire                               ext_req_wr,
  input  wire [                       15:0] ext_req_addr,
  input  wire [                       31:0] ext_req_data,
  output wire                               ext_resp_ack,
  // Find Interface
  input  wire [            (16*NPORTS)-1:0] axis_find_tdata,
  input  wire [                 NPORTS-1:0] axis_find_tvalid,
  output wire [                 NPORTS-1:0] axis_find_tready,
  // Result Interface (for Find)
  output wire [($clog2(NPORTS)*NPORTS)-1:0] axis_result_tdata,
  output wire [                 NPORTS-1:0] axis_result_tkeep,
  output wire [                 NPORTS-1:0] axis_result_tvalid,
  input  wire [                 NPORTS-1:0] axis_result_tready
);
  localparam NPORTS_W  = $clog2(NPORTS);
  localparam CFG_W     = NPORTS_W + 16;
  localparam CFG_PORTS = NPORTS + EXT_INS_PORT_EN;

  //---------------------------------------------------------------------------
  // CAM-based lookup table
  //---------------------------------------------------------------------------

  wire [        15:0] insert_tdest;
  wire [NPORTS_W-1:0] insert_tdata;
  wire                insert_tvalid;
  wire                insert_tready;

  axis_muxed_kv_map #(
    .KEY_WIDTH(16      ),
    .VAL_WIDTH(NPORTS_W),
    .SIZE     (SIZE    ),
    .NUM_PORTS(NPORTS  )
  ) kv_map_i (
    .clk               (clk               ),
    .reset             (reset             ),
    .axis_insert_tdata (insert_tdata      ),
    .axis_insert_tdest (insert_tdest      ),
    .axis_insert_tvalid(insert_tvalid     ),
    .axis_insert_tready(insert_tready     ),
    .axis_find_tdata   (axis_find_tdata   ),
    .axis_find_tvalid  (axis_find_tvalid  ),
    .axis_find_tready  (axis_find_tready  ),
    .axis_result_tdata (axis_result_tdata ),
    .axis_result_tkeep (axis_result_tkeep ),
    .axis_result_tvalid(axis_result_tvalid),
    .axis_result_tready(axis_result_tready)
  );

  //---------------------------------------------------------------------------
  // Logic to convert from CtrlPort to AXI-Stream
  //---------------------------------------------------------------------------

  wire                ins_req_wr  [0:CFG_PORTS-1];
  wire [        15:0] ins_req_addr[0:CFG_PORTS-1];
  wire [NPORTS_W-1:0] ins_req_data[0:CFG_PORTS-1];
  wire                ins_resp_ack[0:CFG_PORTS-1];

  reg  [(CFG_PORTS*CFG_W)-1:0] cfg_tdata;
  reg  [        CFG_PORTS-1:0] cfg_tvalid = {CFG_PORTS{1'b0}};
  wire [        CFG_PORTS-1:0] cfg_tready;

  genvar i;
  generate for (i = 0; i < CFG_PORTS; i=i+1) begin : gen_cfg_ports
    assign ins_req_wr[i]   = (i < NPORTS) ? port_req_wr[i]                  : ext_req_wr;
    assign ins_req_addr[i] = (i < NPORTS) ? port_req_addr[i*16 +: 16]       : ext_req_addr;
    assign ins_req_data[i] = (i < NPORTS) ? port_req_data[i*32 +: NPORTS_W] : ext_req_data[NPORTS_W-1:0];

    if (i < NPORTS) begin : gen_port_resp
      assign port_resp_ack[i] = ins_resp_ack[i];
    end else begin : gen_ext_resp
      assign ext_resp_ack = ins_resp_ack[i];
    end

    always @(posedge clk) begin : cfg_regs
      if (reset) begin
        cfg_tvalid[i] <= 1'b0;
      end else begin
        if (~cfg_tvalid[i]) begin
          if (ins_req_wr[i]) begin
            cfg_tvalid[i]               <= 1'b1;
            cfg_tdata[(CFG_W*i)+:CFG_W] <= {ins_req_data[i], ins_req_addr[i]};
          end
        end else begin
          cfg_tvalid[i] <= ~cfg_tready[i];
        end
      end
    end
    assign ins_resp_ack[i] = cfg_tvalid[i] & cfg_tready[i];
  end endgenerate

  //---------------------------------------------------------------------------
  // Multiplexer between XB ports and external configuration
  //---------------------------------------------------------------------------

  axi_mux #(
    .WIDTH         (CFG_W    ),
    .SIZE          (CFG_PORTS),
    .PRE_FIFO_SIZE (0        ),
    .POST_FIFO_SIZE(1        )
  ) axi_mux_i (
    .clk     (clk                         ),
    .reset   (reset                       ),
    .clear   (1'b0                        ),
    .i_tdata (cfg_tdata                   ),
    .i_tlast ({CFG_PORTS{1'b1}}           ),
    .i_tvalid(cfg_tvalid                  ),
    .i_tready(cfg_tready                  ),
    .o_tdata ({insert_tdata, insert_tdest}),
    .o_tlast (                            ),
    .o_tvalid(insert_tvalid               ),
    .o_tready(insert_tready               )
  );

endmodule


`default_nettype wire