aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/rfnoc/crossbar/axis_ctrl_crossbar_nxn.v
blob: 6de082b4c165b404b5d7229427023cdda0124746 (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
//
// Copyright 2018 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: axis_ctrl_crossbar_nxn
// Description: 
//   This module implements a 2-dimentional (2d) mesh network (mesh) crossbar
//   for AXIS-CTRL traffic. Supports mesh and torus topologies.
//   It uses AXI-Stream for all of its links. 
//   The torus topology, routing algorithms and the router architecture is 
//   described in README.md in this directory. 
// Parameters:
//   - WIDTH: Width of the AXI-Stream data bus
//   - NPORTS: Number of ports (maximum 1024)
//   - TOPOLOGY: Is this a mesh (MESH) or a torus (TORUS) topology
//   - INGRESS_BUFF_SIZE: log2 of the ingress terminal buffer size (in words)
//   - ROUTER_BUFF_SIZE: log2 of the ingress inter-router buffer size (in words)
//   - ROUTING_ALLOC: Algorithm to allocate routing paths between routers.
//     * WORMHOLE: Allocate route as soon as first word in pkt arrives
//     * CUT-THROUGH: Allocate route only after the full pkt arrives
//   - SWITCH_ALLOC: Algorithm to allocate the switch
//     * PRIO: Priority based. Priority: Y-dim > X-dim > Term
//     * ROUND-ROBIN: Round robin input port allocation
//   - DEADLOCK_TIMEOUT: Number of cycles to wait until a deadlock is detected
// Signals:
//   - s_axis_*: Slave port for router (flattened)
//   - m_axis_*: Master port for router (flattened)
//

module axis_ctrl_crossbar_nxn #(
  parameter WIDTH             = 32,
  parameter NPORTS            = 10,
  parameter TOPOLOGY          = "TORUS",
  parameter INGRESS_BUFF_SIZE = 5,
  parameter ROUTER_BUFF_SIZE  = 5,
  parameter ROUTING_ALLOC     = "WORMHOLE",
  parameter SWITCH_ALLOC      = "PRIO",
  parameter DEADLOCK_TIMEOUT  = 16384
) (
  input  wire                      clk,
  input  wire                      reset,
  // Inputs
  input  wire [(NPORTS*WIDTH)-1:0] s_axis_tdata,
  input  wire [NPORTS-1:0]         s_axis_tlast,
  input  wire [NPORTS-1:0]         s_axis_tvalid,
  output wire [NPORTS-1:0]         s_axis_tready,
  // Output
  output wire [(NPORTS*WIDTH)-1:0] m_axis_tdata,
  output wire [NPORTS-1:0]         m_axis_tlast,
  output wire [NPORTS-1:0]         m_axis_tvalid,
  input  wire [NPORTS-1:0]         m_axis_tready,
  // Deadlock alert
  output wire                      deadlock_detected
);

  function integer csqrt_max1024;
    input integer value;
    integer i;
  begin
    csqrt_max1024 = 1;
    for (i = 1; i <= 32; i = i + 1)  // sqrt(1024) = 32
      csqrt_max1024 = csqrt_max1024 + (i*i < value ? 1 : 0);
  end
  endfunction

  localparam integer DIM_SIZE = csqrt_max1024(NPORTS);

  wire [(DIM_SIZE*DIM_SIZE*WIDTH)-1:0] i_tdata,  o_tdata ;
  wire [DIM_SIZE*DIM_SIZE-1:0]         i_tlast,  o_tlast ;
  wire [DIM_SIZE*DIM_SIZE-1:0]         i_tvalid, o_tvalid;
  wire [DIM_SIZE*DIM_SIZE-1:0]         i_tready, o_tready;

  // axis_ctrl_crossbar_2d_mesh needs to scale up in squares
  // i.e. 4, 9, 16, 25, ... but NPORTS can be any number, so
  // instantiate the next highest square number of ports and
  // terminate the rest.
  axis_ctrl_crossbar_2d_mesh #(
    .WIDTH            (WIDTH),
    .DIM_SIZE         (DIM_SIZE),
    .TOPOLOGY         (TOPOLOGY),
    .INGRESS_BUFF_SIZE(INGRESS_BUFF_SIZE),
    .ROUTER_BUFF_SIZE (ROUTER_BUFF_SIZE),
    .ROUTING_ALLOC    (ROUTING_ALLOC),
    .SWITCH_ALLOC     (SWITCH_ALLOC),
    .DEADLOCK_TIMEOUT (DEADLOCK_TIMEOUT)
  ) router_dut_i (
    .clk              (clk),
    .reset            (reset),
    .s_axis_tdata     (i_tdata),
    .s_axis_tlast     (i_tlast),
    .s_axis_tvalid    (i_tvalid),
    .s_axis_tready    (i_tready),
    .m_axis_tdata     (o_tdata), 
    .m_axis_tlast     (o_tlast),
    .m_axis_tvalid    (o_tvalid), 
    .m_axis_tready    (o_tready),
    .deadlock_detected(deadlock_detected)
  );

  // Connect the bottom NPORTS to the IO
  assign i_tdata[(NPORTS*WIDTH)-1:0] = s_axis_tdata;
  assign i_tlast[NPORTS-1:0]         = s_axis_tlast;
  assign i_tvalid[NPORTS-1:0]        = s_axis_tvalid;
  assign s_axis_tready               = i_tready[NPORTS-1:0];

  assign m_axis_tdata                = o_tdata[(NPORTS*WIDTH)-1:0];
  assign m_axis_tlast                = o_tlast[NPORTS-1:0];
  assign m_axis_tvalid               = o_tvalid[NPORTS-1:0];
  assign o_tready[NPORTS-1:0]        = m_axis_tready;

  // Terminate the rest
  genvar i;
  generate for (i = NPORTS; i < (DIM_SIZE*DIM_SIZE); i = i + 1) begin: ports
    axis_port_terminator #(.DATA_W(WIDTH)) term_i (
      .clk          (clk),
      .reset        (reset),
      .s_axis_tdata (o_tdata[(i*WIDTH)+:WIDTH]),
      .s_axis_tlast (o_tlast[i]),
      .s_axis_tvalid(o_tvalid[i]),
      .s_axis_tready(o_tready[i]),
      .m_axis_tdata (i_tdata[(i*WIDTH)+:WIDTH]),
      .m_axis_tlast (i_tlast[i]),
      .m_axis_tvalid(i_tvalid[i]),
      .m_axis_tready(i_tready[i]),
      .pkts_dropped ()
    );
  end endgenerate

endmodule