MatchLib
axi4.h
1 /*
2  * Copyright (c) 2017-2024, NVIDIA CORPORATION. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License")
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef _AXI_AXI4_H_
18 #define _AXI_AXI4_H_
19 
20 #include <systemc>
21 #include <connections/connections.h>
22 #include <connections/connections_utils.h>
23 
24 #include "auto_gen_fields.h"
25 
26 #include <nvhls_connections.h>
27 #include <nvhls_assert.h>
28 #include <nvhls_message.h>
29 #include <nvhls_module.h>
30 
31 #include <UIntOrEmpty.h>
32 
33 #include <axi/axi4_encoding.h>
34 #include <axi/axi4_configs.h>
35 
36 
41 namespace axi {
42 
63 template <typename Cfg>
64 class axi4 {
65  public:
66  typedef AXI4_Encoding Enc;
67 
68  enum {
69  DATA_WIDTH = Cfg::dataWidth,
70  ADDR_WIDTH = Cfg::addrWidth,
71  ID_WIDTH = Cfg::idWidth,
72  BID_WIDTH = (Cfg::useWriteResponses == 0 ? 0 : Cfg::idWidth),
73  ALEN_WIDTH =
74  (Cfg::useBurst != 0 ? nvhls::log2_ceil<Cfg::maxBurstSize>::val : 0),
75  ASIZE_WIDTH = (Cfg::useVariableBeatSize != 0 ? 3 : 0),
76  LAST_WIDTH = (Cfg::useLast != 0 ? 1 : 0),
77  CACHE_WIDTH = (Cfg::useCache != 0 ? Enc::ARCACHE::_WIDTH : 0),
78  BURST_WIDTH = ((Cfg::useBurst != 0 &&
79  (Cfg::useFixedBurst != 0 || Cfg::useWrapBurst != 0))
80  ? Enc::AXBURST::_WIDTH
81  : 0),
82  WSTRB_WIDTH = (Cfg::useWriteStrobes != 0 ? (DATA_WIDTH >> 3) : 0),
83  RESP_WIDTH = Enc::XRESP::_WIDTH,
84  // TODO - The B channel ought to disappear entirely if useWriteResponses is
85  // 0, but that will require substantial refactoring. For now we leave
86  // RESP_WIDTH so there is a data stub in the ready-valid interface.
87 
88  AUSER_WIDTH = Cfg::aUserWidth,
89  WUSER_WIDTH = Cfg::wUserWidth,
90  BUSER_WIDTH = (Cfg::useWriteResponses == 0 ? 0 : Cfg::bUserWidth),
91  RUSER_WIDTH = Cfg::rUserWidth,
92  };
93 
94  typedef NVUINTW(ADDR_WIDTH) Addr;
95  typedef NVUINTW(DATA_WIDTH) Data;
96  typedef typename nvhls::UIntOrEmpty<ID_WIDTH>::T Id;
97  typedef typename nvhls::UIntOrEmpty<BID_WIDTH>::T BId;
98  typedef typename nvhls::UIntOrEmpty<ALEN_WIDTH>::T BeatNum;
99  typedef typename nvhls::UIntOrEmpty<ASIZE_WIDTH>::T BeatSize;
100  typedef typename nvhls::UIntOrEmpty<LAST_WIDTH>::T Last;
101  typedef typename nvhls::UIntOrEmpty<WSTRB_WIDTH>::T Wstrb;
102  typedef typename nvhls::UIntOrEmpty<CACHE_WIDTH>::T Cache;
103  typedef typename nvhls::UIntOrEmpty<BURST_WIDTH>::T Burst;
104  typedef NVUINTW(RESP_WIDTH) Resp;
105 
106  typedef typename nvhls::UIntOrEmpty<AUSER_WIDTH>::T AUser;
107  typedef typename nvhls::UIntOrEmpty<WUSER_WIDTH>::T WUser;
108  typedef typename nvhls::UIntOrEmpty<BUSER_WIDTH>::T BUser;
109  typedef typename nvhls::UIntOrEmpty<RUSER_WIDTH>::T RUser;
110 
114  struct AddrPayload : public nvhls_message {
115  Id id;
116  Addr addr;
117  Burst burst;
118  BeatNum len; // A*LEN
119  BeatSize size; // A*SIZE
120  Cache cache;
121  AUser auser;
122 
123  AUTO_GEN_FIELD_METHODS(AddrPayload, ( \
124  id \
125  , addr \
126  , burst \
127  , len \
128  , size \
129  , cache \
130  , auser \
131  ) )
132  //
133 
134 
135  AddrPayload() {
136  if(ID_WIDTH > 0)
137  id = 0;
138  addr = 0; // NVUINT, ADDR_WIDTH always > 0
139  if(ALEN_WIDTH > 0)
140  len = 0;
141  if(ASIZE_WIDTH > 0)
142  size = 0;
143  if(BURST_WIDTH > 0)
144  burst = 0;
145  if(CACHE_WIDTH > 0)
146  cache = 0;
147  if(AUSER_WIDTH > 0)
148  auser = 0;
149  }
150 
151  };
152 
157  struct ReadPayload : public nvhls_message {
158  Id id;
159  Data data;
160  Resp resp;
161  Last last;
162  RUser ruser;
163 
164  AUTO_GEN_FIELD_METHODS(ReadPayload, ( \
165  id \
166  , data \
167  , resp \
168  , last \
169  , ruser \
170  ) )
171  //
172 
173 
174  ReadPayload() {
175  if(ID_WIDTH > 0)
176  id = 0;
177  data = 0; // NVUINT, DATA_WIDTH always > 0
178  resp = 0; // NVUINT, RESP_WIDTH always > 0
179  if(LAST_WIDTH > 0)
180  last = 0;
181  if(RUSER_WIDTH > 0)
182  ruser = 0;
183  }
184  };
185 
190  struct WRespPayload : public nvhls_message {
191  BId id;
192  Resp resp;
193  BUser buser;
194 
195  AUTO_GEN_FIELD_METHODS(WRespPayload, ( \
196  id \
197  , resp \
198  , buser \
199  ) )
200  //
201 
202  WRespPayload() {
203  if(ID_WIDTH > 0)
204  id = 0;
205  resp = 0; // NVUINT, RESP_WIDTH always > 0
206  if(BUSER_WIDTH > 0)
207  buser = 0;
208  }
209 
210  };
211 
215  struct WritePayload : public nvhls_message {
216  // no id here!
217  Data data;
218  Last last;
219  Wstrb wstrb;
220  WUser wuser;
221 
222  AUTO_GEN_FIELD_METHODS(WritePayload, ( \
223  data \
224  , last \
225  , wstrb \
226  , wuser \
227  ) )
228  //
229 
230  WritePayload() {
231  data = 0; // NVUINT, DATA_WIDTH always > 0
232  if(LAST_WIDTH > 0)
233  last = 0;
234  if(WSTRB_WIDTH > 0)
235  wstrb = ~0;
236  if(WUSER_WIDTH > 0)
237  wuser = 0;
238  }
239  };
240 
247  class read {
248  public:
252  template <Connections::connections_port_t PortType = AUTO_PORT>
253  class chan {
254  public:
255  typedef Connections::Combinational<AddrPayload, PortType> ARChan;
256  typedef Connections::Combinational<ReadPayload, PortType> RChan;
257 
258  ARChan ar; // manager to subordinate
259  RChan r; // subordinate to manager
260 
261  chan(const char *name)
262  : ar(nvhls_concat(name, "_ar")), r(nvhls_concat(name, "_r")){};
263 
264  // TODO: Implement AXI protocol checker
265  }; // read::chan
266 
270  template <Connections::connections_port_t PortType = AUTO_PORT>
271  class manager {
272  public:
273  typedef Connections::Out<AddrPayload, PortType> ARPort;
274  typedef Connections::In<ReadPayload, PortType> RPort;
275 
276  ARPort ar;
277  RPort r;
278 
279  manager(const char *name)
280  : ar(nvhls_concat(name, "_ar")), r(nvhls_concat(name, "_r")) {}
281 
282  void reset() {
283  ar.Reset();
284  r.Reset();
285  }
286 
287  ReadPayload query(const AddrPayload &addr) {
288  // TODO: add nb version with state
289  ar.Push(addr);
290  return r.Pop();
291  }
292 
293  template <class C>
294  void operator()(C &c) {
295  ar(c.ar);
296  r(c.r);
297  }
298  }; // read::manager
299 
303  template <Connections::connections_port_t PortType = AUTO_PORT>
304  class subordinate {
305  public:
306  typedef Connections::In<AddrPayload, PortType> ARPort;
307  typedef Connections::Out<ReadPayload, PortType> RPort;
308 
309  ARPort ar;
310  RPort r;
311 
312  subordinate(const char *name)
313  : ar(nvhls_concat(name, "_ar")), r(nvhls_concat(name, "_r")) {}
314 
315  void reset() {
316  ar.Reset();
317  r.Reset();
318  }
319 
320  AddrPayload aread() { return ar.Pop(); }
321 
322  bool nb_aread(AddrPayload &addr) { return ar.PopNB(addr); }
323 
324  void rwrite(const ReadPayload &data) { r.Push(data); }
325 
326  bool nb_rwrite(const ReadPayload &data) { return r.PushNB(data); }
327 
328  template <class C>
329  void operator()(C &c) {
330  ar(c.ar);
331  r(c.r);
332  }
333  }; // read::subordinate
334  }; // read
335 
342  class write {
343  public:
347  template <Connections::connections_port_t PortType = AUTO_PORT>
348  class chan {
349  public:
350  typedef Connections::Combinational<AddrPayload, PortType> AWChan;
351  typedef Connections::Combinational<WritePayload, PortType> WChan;
352  typedef Connections::Combinational<WRespPayload, PortType> BChan;
353 
354  AWChan aw; // manager to subordinate
355  WChan w; // manager to subordinate
356  BChan b; // subordinate to manager
357 
358  chan(const char *name)
359  : aw(nvhls_concat(name, "_aw")),
360  w(nvhls_concat(name, "_w")),
361  b(nvhls_concat(name, "_b")){};
362 
363  // TODO: Implement AXI protocol checker
364  }; // write::chan
365 
369  template <Connections::connections_port_t PortType = AUTO_PORT>
370  class manager {
371  public:
372  typedef Connections::Out<AddrPayload, PortType> AWPort;
373  typedef Connections::Out<WritePayload, PortType> WPort;
374  typedef Connections::In<WRespPayload, PortType> BPort;
375 
376  AWPort aw;
377  WPort w;
378  BPort b;
379 
380  manager(const char *name)
381  : aw(nvhls_concat(name, "_aw")),
382  w(nvhls_concat(name, "_w")),
383  b(nvhls_concat(name, "_b")) {}
384 
385  void reset() {
386  aw.Reset();
387  w.Reset();
388  b.Reset();
389  }
390 
391  WRespPayload write(const AddrPayload &addr, const WritePayload &data) {
392  // TODO: add nb version with state
393  aw.Push(addr);
394  w.Push(data);
395  return b.Pop();
396  }
397 
398  template <class C>
399  void operator()(C &c) {
400  aw(c.aw);
401  w(c.w);
402  b(c.b);
403  }
404  }; // write::manager
405 
409  template <Connections::connections_port_t PortType = AUTO_PORT>
410  class subordinate {
411  public:
412  typedef Connections::In<AddrPayload, PortType> AWPort;
413  typedef Connections::In<WritePayload, PortType> WPort;
414  typedef Connections::Out<WRespPayload, PortType> BPort;
415 
416  AWPort aw;
417  WPort w;
418  BPort b;
419 
420  bool got_waddr;
421  AddrPayload stored_waddr;
422 
423  subordinate(const char *name)
424  : aw(nvhls_concat(name, "_aw")),
425  w(nvhls_concat(name, "_w")),
426  b(nvhls_concat(name, "_b")),
427  got_waddr(false) {}
428 
429  void reset() {
430  aw.Reset();
431  w.Reset();
432  b.Reset();
433  }
434 
435  void wread(AddrPayload &addr, WritePayload &data) {
436  addr = aw.Pop();
437  data = w.Pop();
438  }
439 
440  bool nb_wread(AddrPayload &addr, WritePayload &data) {
441  if (!got_waddr) {
442  if (!aw.PopNB(addr)) {
443  return false;
444  } else {
445  got_waddr = true;
446  stored_waddr = addr;
447  }
448  } else {
449  addr = stored_waddr;
450  }
451 
452  if (w.PopNB(data)) {
453  got_waddr = false;
454  return true;
455  } else {
456  return false;
457  }
458  }
459 
460  void bwrite(const WRespPayload &resp) { b.Push(resp); }
461 
462  bool nb_bwrite(const WRespPayload &resp) { return b.PushNB(resp); }
463 
464  template <class C>
465  void operator()(C &c) {
466  aw(c.aw);
467  w(c.w);
468  b(c.b);
469  }
470  }; // write::subordinate
471  }; // write
472 }; // axi4
473 }; // axi
474 
475 #endif
476 
Hardcoded values associated with the AXI4 standard.
Definition: axi4_encoding.h:30
The AXI read channel, used for connecting an AXI manager and AXI subordinate.
Definition: axi4.h:253
The AXI read manager port. This port has an AR request channel as output and an R response channel as...
Definition: axi4.h:271
The AXI read subordinate port. This port has an AR request channel as input and an R response channel...
Definition: axi4.h:304
The AXI read class.
Definition: axi4.h:247
The AXI write channel, used for connecting an AXI manager and AXI subordinate.
Definition: axi4.h:348
The AXI write manager port. This port has AW and W request channels as outputs and a B response chann...
Definition: axi4.h:370
The AXI write subordinate port. This port has AW and W request channels as inputs and a B response ch...
Definition: axi4.h:410
The AXI write class.
Definition: axi4.h:342
The base axi4 class parameterized according a valid config.
Definition: axi4.h:64
#define nvhls_concat(s1, s2)
nvhls_concat define: Concatenate two strings, separate with an underscore.
Definition: nvhls_module.h:59
The axi namespace contains classes and definitions related to the AXI standard.
Definition: axi4.h:41
A struct composed of the signals associated with AXI read and write requests.
Definition: axi4.h:114
A struct composed of the signals associated with an AXI read response.
Definition: axi4.h:157
A struct composed of the signals associated with an AXI write response.
Definition: axi4.h:190
A struct composed of the signals associated with AXI write data.
Definition: axi4.h:215
Compute Celing of log2 of a constant.
Definition: nvhls_int.h:174