axi_multicut.sv 7.76 KB
Newer Older
1
// Copyright (c) 2014-2019 ETH Zurich, University of Bologna
sakundu committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Authors:
// - Wolfgang Roenninger <wroennin@iis.ee.ethz.ch>
// - Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
16
// - Stefan Mach <smach@iis.ee.ethz.ch>
sakundu committed
17

18 19 20 21 22
// Multiple AXI4 cuts.
//
// These can be used to relax timing pressure on very long AXI busses.
module axi_multicut #(
  parameter int unsigned NoCuts = 32'd1, // Number of cuts.
sakundu committed
23 24 25 26 27 28 29 30 31 32
  // AXI channel structs
  parameter type aw_chan_t = logic,
  parameter type  w_chan_t = logic,
  parameter type  b_chan_t = logic,
  parameter type ar_chan_t = logic,
  parameter type  r_chan_t = logic,
  // AXI request & response structs
  parameter type     req_t = logic,
  parameter type    resp_t = logic
) (
33 34 35
  input  logic  clk_i,   // Clock
  input  logic  rst_ni,  // Asynchronous reset active low
  // slave port
sakundu committed
36 37 38 39 40 41 42
  input  req_t  slv_req_i,
  output resp_t slv_resp_o,
  // master port
  output req_t  mst_req_o,
  input  resp_t mst_resp_i
);

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
  if (NoCuts == '0) begin : gen_no_cut
    // degenerate case, connect input to output
    assign mst_req_o  = slv_req_i;
    assign slv_resp_o = mst_resp_i;
  end else begin : gen_axi_cut
    // instantiate all needed cuts
    req_t  [NoCuts:0] cut_req;
    resp_t [NoCuts:0] cut_resp;

    // connect slave to the lowest index
    assign cut_req[0] = slv_req_i;
    assign slv_resp_o = cut_resp[0];

    // AXI cuts
    for (genvar i = 0; i < NoCuts; i++) begin : gen_axi_cuts
      axi_cut #(
        .Bypass    (      1'b0 ),
        .aw_chan_t ( aw_chan_t ),
        .w_chan_t  (  w_chan_t ),
        .b_chan_t  (  b_chan_t ),
        .ar_chan_t ( ar_chan_t ),
        .r_chan_t  (  r_chan_t ),
        .req_t     (     req_t ),
        .resp_t    (    resp_t )
      ) i_cut (
        .clk_i,
        .rst_ni,
        .slv_req_i  ( cut_req[i]    ),
        .slv_resp_o ( cut_resp[i]   ),
        .mst_req_o  ( cut_req[i+1]  ),
        .mst_resp_i ( cut_resp[i+1] )
      );
    end

    // connect master to the highest index
    assign mst_req_o        = cut_req[NoCuts];
    assign cut_resp[NoCuts] = mst_resp_i;
  end
sakundu committed
81

82 83 84 85 86 87 88 89
  // Check the invariants
  // pragma translate_off
  `ifndef VERILATOR
  initial begin
    assert(NoCuts >= 0);
  end
  `endif
  // pragma translate_on
sakundu committed
90 91 92 93 94 95
endmodule

`include "axi/assign.svh"
`include "axi/typedef.svh"

// interface wrapper
96 97 98 99 100 101
module axi_multicut_intf #(
  parameter int unsigned ADDR_WIDTH = 0, // The address width.
  parameter int unsigned DATA_WIDTH = 0, // The data width.
  parameter int unsigned ID_WIDTH   = 0, // The ID width.
  parameter int unsigned USER_WIDTH = 0, // The user data width.
  parameter int unsigned NUM_CUTS   = 0  // The number of cuts.
sakundu committed
102
) (
103 104 105 106
  input logic    clk_i,
  input logic    rst_ni,
  AXI_BUS.Slave  in,
  AXI_BUS.Master out
sakundu committed
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
);

  typedef logic [ID_WIDTH-1:0]     id_t;
  typedef logic [ADDR_WIDTH-1:0]   addr_t;
  typedef logic [DATA_WIDTH-1:0]   data_t;
  typedef logic [DATA_WIDTH/8-1:0] strb_t;
  typedef logic [USER_WIDTH-1:0]   user_t;

  `AXI_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t, id_t, user_t)
  `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t)
  `AXI_TYPEDEF_B_CHAN_T(b_chan_t, id_t, user_t)
  `AXI_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t, id_t, user_t)
  `AXI_TYPEDEF_R_CHAN_T(r_chan_t, data_t, id_t, user_t)
  `AXI_TYPEDEF_REQ_T(req_t, aw_chan_t, w_chan_t, ar_chan_t)
  `AXI_TYPEDEF_RESP_T(resp_t, b_chan_t, r_chan_t)

  req_t  slv_req,  mst_req;
  resp_t slv_resp, mst_resp;

  `AXI_ASSIGN_TO_REQ(slv_req, in)
  `AXI_ASSIGN_FROM_RESP(in, slv_resp)

  `AXI_ASSIGN_FROM_REQ(out, mst_req)
  `AXI_ASSIGN_TO_RESP(mst_resp, out)

132 133
  axi_multicut #(
    .NoCuts    (  NUM_CUTS ),
sakundu committed
134 135 136 137 138 139 140
    .aw_chan_t ( aw_chan_t ),
    .w_chan_t  (  w_chan_t ),
    .b_chan_t  (  b_chan_t ),
    .ar_chan_t ( ar_chan_t ),
    .r_chan_t  (  r_chan_t ),
    .req_t     (     req_t ),
    .resp_t    (    resp_t )
141
  ) i_axi_multicut (
sakundu committed
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
    .clk_i,
    .rst_ni,
    .slv_req_i  ( slv_req  ),
    .slv_resp_o ( slv_resp ),
    .mst_req_o  ( mst_req  ),
    .mst_resp_i ( mst_resp )
  );

  // Check the invariants.
  // pragma translate_off
  `ifndef VERILATOR
  initial begin
    assert (ADDR_WIDTH > 0) else $fatal(1, "Wrong addr width parameter");
    assert (DATA_WIDTH > 0) else $fatal(1, "Wrong data width parameter");
    assert (ID_WIDTH   > 0) else $fatal(1, "Wrong id   width parameter");
    assert (USER_WIDTH > 0) else $fatal(1, "Wrong user width parameter");
    assert (in.AXI_ADDR_WIDTH  == ADDR_WIDTH) else $fatal(1, "Wrong interface definition");
    assert (in.AXI_DATA_WIDTH  == DATA_WIDTH) else $fatal(1, "Wrong interface definition");
    assert (in.AXI_ID_WIDTH    == ID_WIDTH)   else $fatal(1, "Wrong interface definition");
    assert (in.AXI_USER_WIDTH  == USER_WIDTH) else $fatal(1, "Wrong interface definition");
    assert (out.AXI_ADDR_WIDTH == ADDR_WIDTH) else $fatal(1, "Wrong interface definition");
    assert (out.AXI_DATA_WIDTH == DATA_WIDTH) else $fatal(1, "Wrong interface definition");
    assert (out.AXI_ID_WIDTH   == ID_WIDTH)   else $fatal(1, "Wrong interface definition");
    assert (out.AXI_USER_WIDTH == USER_WIDTH) else $fatal(1, "Wrong interface definition");
  end
  `endif
  // pragma translate_on
endmodule

171 172
module axi_lite_multicut_intf #(
  // The address width.
sakundu committed
173
  parameter int unsigned ADDR_WIDTH = 0,
174 175 176 177
  // The data width.
  parameter int unsigned DATA_WIDTH = 0,
  // The number of cuts.
  parameter int unsigned NUM_CUTS   = 0
sakundu committed
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
) (
  input logic     clk_i  ,
  input logic     rst_ni ,
  AXI_LITE.Slave  in     ,
  AXI_LITE.Master out
);

  typedef logic [ADDR_WIDTH-1:0]   addr_t;
  typedef logic [DATA_WIDTH-1:0]   data_t;
  typedef logic [DATA_WIDTH/8-1:0] strb_t;

  `AXI_LITE_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t)
  `AXI_LITE_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t)
  `AXI_LITE_TYPEDEF_B_CHAN_T(b_chan_t)
  `AXI_LITE_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t)
  `AXI_LITE_TYPEDEF_R_CHAN_T(r_chan_t, data_t)
  `AXI_LITE_TYPEDEF_REQ_T(req_t, aw_chan_t, w_chan_t, ar_chan_t)
  `AXI_LITE_TYPEDEF_RESP_T(resp_t, b_chan_t, r_chan_t)

197 198
  req_t  slv_req,  mst_req;
  resp_t slv_resp, mst_resp;
sakundu committed
199 200 201 202 203 204 205

  `AXI_LITE_ASSIGN_TO_REQ(slv_req, in)
  `AXI_LITE_ASSIGN_FROM_RESP(in, slv_resp)

  `AXI_LITE_ASSIGN_FROM_REQ(out, mst_req)
  `AXI_LITE_ASSIGN_TO_RESP(mst_resp, out)

206 207
  axi_multicut #(
    .NoCuts    (  NUM_CUTS ),
sakundu committed
208 209 210 211 212 213 214
    .aw_chan_t ( aw_chan_t ),
    .w_chan_t  (  w_chan_t ),
    .b_chan_t  (  b_chan_t ),
    .ar_chan_t ( ar_chan_t ),
    .r_chan_t  (  r_chan_t ),
    .req_t     (     req_t ),
    .resp_t    (    resp_t )
215
  ) i_axi_multicut (
sakundu committed
216 217 218 219 220 221 222 223 224 225 226 227 228 229
    .clk_i,
    .rst_ni,
    .slv_req_i  ( slv_req  ),
    .slv_resp_o ( slv_resp ),
    .mst_req_o  ( mst_req  ),
    .mst_resp_i ( mst_resp )
  );

  // Check the invariants.
  // pragma translate_off
  `ifndef VERILATOR
  initial begin
    assert (ADDR_WIDTH > 0) else $fatal(1, "Wrong addr width parameter");
    assert (DATA_WIDTH > 0) else $fatal(1, "Wrong data width parameter");
230 231
    assert (in.AXI_ADDR_WIDTH == ADDR_WIDTH) else $fatal(1, "Wrong interface definition");
    assert (in.AXI_DATA_WIDTH == DATA_WIDTH) else $fatal(1, "Wrong interface definition");
sakundu committed
232 233 234 235 236 237
    assert (out.AXI_ADDR_WIDTH == ADDR_WIDTH) else $fatal(1, "Wrong interface definition");
    assert (out.AXI_DATA_WIDTH == DATA_WIDTH) else $fatal(1, "Wrong interface definition");
  end
  `endif
  // pragma translate_on
endmodule