MatchLib
AxiArbiter.h
1 /*
2  * Copyright (c) 2018-2019, 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 #ifndef __AXI_ARBITER_H__
17 #define __AXI_ARBITER_H__
18 
19 #include <systemc.h>
20 #include <nvhls_connections.h>
21 #include <nvhls_serdes.h>
22 #include <nvhls_packet.h>
23 #include <nvhls_int.h>
24 #include <nvhls_array.h>
25 #include <axi/axi4.h>
26 #include "Arbiter.h"
27 #include "TypeToBits.h"
28 
57 template <typename axiCfg, int numMasters, int maxOutstandingRequests>
58 class AxiArbiter : public sc_module {
59  public:
60  static const int kDebugLevel = 5;
61  sc_in<bool> clk;
62  sc_in<bool> reset_bar;
63 
64  typedef typename axi::axi4<axiCfg> axi_;
65  static const int numMasters_width = nvhls::log2_ceil<numMasters>::val;
66 
67  typedef typename axi_::read::template slave<>::ARPort axi_rd_slave_ar;
68  typedef typename axi_::read::template slave<>::RPort axi_rd_slave_r;
69  typedef typename axi_::write::template slave<>::AWPort axi_wr_slave_aw;
70  typedef typename axi_::write::template slave<>::WPort axi_wr_slave_w;
71  typedef typename axi_::write::template slave<>::BPort axi_wr_slave_b;
72 
73  // [ben] Unfortunately HLS cannot handle an nv_array of the master/slave wrapper classes.
74  // It will work fine in C but die mysteriously in Catapult 10.1b when methods of the
75  // bundled connections are accessed.
81  typename axi_::read::template master<> axi_rd_s;
82  typename axi_::write::template master<> axi_wr_s;
83 
84  typedef NVUINTW(numMasters_width) inFlight_t;
86  Connections::Combinational<inFlight_t> read_in_flight;
88  Connections::Combinational<inFlight_t> write_in_flight;
89  Connections::Combinational<inFlight_t> active_write_master;
90  Connections::Combinational<NVUINT1> w_last; // true iff w item last bit is set
91 
92  SC_HAS_PROCESS(AxiArbiter);
93 
94  AxiArbiter(sc_module_name name)
95  : sc_module(name),
96  clk("clk"),
97  reset_bar("reset_bar"),
98  axi_rd_m_ar("axi_rd_m_ar"),
99  axi_rd_m_r("axi_rd_m_r"),
100  axi_wr_m_aw("axi_wr_m_aw"),
101  axi_wr_m_w("axi_wr_m_w"),
102  axi_wr_m_b("axi_wr_m_b"),
103  axi_rd_s("axi_rd_s"),
104  axi_wr_s("axi_wr_s") {
105 
106  SC_THREAD(run_ar);
107  sensitive << clk.pos();
108  async_reset_signal_is(reset_bar, false);
109 
110  SC_THREAD(run_r);
111  sensitive << clk.pos();
112  async_reset_signal_is(reset_bar, false);
113 
114  SC_THREAD(run_w);
115  sensitive << clk.pos();
116  async_reset_signal_is(reset_bar, false);
117 
118  SC_THREAD(run_aw);
119  sensitive << clk.pos();
120  async_reset_signal_is(reset_bar, false);
121 
122  SC_THREAD(run_b);
123  sensitive << clk.pos();
124  async_reset_signal_is(reset_bar, false);
125  }
126 
127  void run_ar() {
128  #pragma hls_unroll yes
129  for (int i = 0; i < numMasters; i++) {
130  axi_rd_m_ar[i].Reset();
131  }
132  axi_rd_s.ar.Reset();
133  read_in_flight.ResetWrite();
134 
136  NVUINTW(numMasters) valid_mask = 0;
137  NVUINTW(numMasters) select_mask = 0;
139 
140  #pragma hls_pipeline_init_interval 1
141  #pragma pipeline_stall_mode flush
142  while (1) {
143  wait();
144 
145  for (int i = 0; i < numMasters; i++) {
146  if (nvhls::get_slc<1>(valid_mask, i) == 0) {
147  if (axi_rd_m_ar[i].PopNB(AR_reg[i])) {
148  valid_mask = valid_mask | (1 << i);
149  }
150  }
151  }
152 
153  select_mask = arb.pick(valid_mask);
154 
155  for (int i = 0; i < numMasters; i++) {
156  if (nvhls::get_slc<1>(select_mask, i) == 1) {
157  axi_rd_s.ar.Push(AR_reg[i]);
158  select_mask = 0;
159  valid_mask = ~(~valid_mask | (1 << i));
160  CDCOUT(sc_time_stamp() << " " << name() << " Pushed read request:"
161  << " from_port=" << i
162  << " request=[" << AR_reg[i] << "]"
163  << endl, kDebugLevel);
164  read_in_flight.Push(i);
165  }
166  }
167  }
168  }
169 
170  void run_r() {
171  #pragma hls_unroll yes
172  for (int i = 0; i < numMasters; i++) {
173  axi_rd_m_r[i].Reset();
174  }
175  axi_rd_s.r.Reset();
176  read_in_flight.ResetRead();
177  readQ.reset();
178 
179  typename axi_::ReadPayload R_reg;
180  inFlight_t inFlight_reg;
181  inFlight_t inFlight_resp_reg;
182 
183  bool read_inProgress = 0;
184 
185  #pragma hls_pipeline_init_interval 1
186  #pragma pipeline_stall_mode flush
187  while (1) {
188  wait();
189 
190  if (!readQ.isFull()) {
191  if (read_in_flight.PopNB(inFlight_reg)) {
192  readQ.push(inFlight_reg);
193  }
194  }
195 
196  if (!read_inProgress) {
197  if (!readQ.isEmpty()) {
198  inFlight_resp_reg = readQ.pop();
199  read_inProgress = 1;
200  }
201  } else {
202  if (axi_rd_s.r.PopNB(R_reg)) {
203  axi_rd_m_r[inFlight_resp_reg].Push(R_reg);
204  CDCOUT(sc_time_stamp() << " " << name() << " Pushed read response:"
205  << " to_port=" << inFlight_resp_reg
206  << " response=[" << R_reg << "]"
207  << endl, kDebugLevel);
208  if (R_reg.last == 1)
209  read_inProgress = 0;
210  }
211  }
212  }
213  }
214 
215  void run_aw() {
216  #pragma hls_unroll yes
217  for (int i = 0; i < numMasters; i++) {
218  axi_wr_m_aw[i].Reset();
219  }
220  axi_wr_s.aw.Reset();
221  write_in_flight.ResetWrite();
222  active_write_master.ResetWrite();
223  w_last.ResetRead();
224 
225  inFlight_t active_master;
226 
228  NVUINTW(numMasters) valid_mask = 0;
229  NVUINTW(numMasters) select_mask = 0;
231 
232  while (1) {
233  wait();
234 
235  #pragma hls_unroll yes
236  for (int i = 0; i < numMasters; i++) {
237  if (nvhls::get_slc<1>(valid_mask, i) == 0) {
238  if (axi_wr_m_aw[i].PopNB(AW_reg[i])) {
239  valid_mask = valid_mask | (1 << i);
240  }
241  }
242  }
243 
244  select_mask = arb.pick(valid_mask);
245 
246  if (select_mask != 0) {
247  #pragma hls_unroll yes
248  for (int i = 0; i < numMasters; i++) {
249  if (nvhls::get_slc<1>(select_mask, i) == 1) {
250  active_master = i;
251  }
252  }
253 
254  axi_wr_s.aw.Push(AW_reg[active_master]);
255  active_write_master.Push(active_master);
256  write_in_flight.Push(active_master);
257 
258  #pragma hls_pipeline_init_interval 1
259  #pragma pipeline_stall_mode flush
260  while (w_last.Pop() == false) {
261  }
262 
263  select_mask = 0;
264  valid_mask = ~(~valid_mask | (1 << active_master));
265  }
266  }
267  }
268 
269  void run_w() {
270  typename axi_::WritePayload W_reg;
271  active_write_master.ResetRead();
272  w_last.ResetWrite();
273  axi_wr_s.w.Reset();
274  #pragma hls_unroll yes
275  for (int i = 0; i < numMasters; i++) {
276  axi_wr_m_w[i].Reset();
277  }
278 
279  wait();
280 
281  while (1) {
282  inFlight_t active_master = active_write_master.Pop();
283 
284  #pragma hls_pipeline_init_interval 1
285  #pragma pipeline_stall_mode flush
286  do {
287  W_reg = axi_wr_m_w[active_master].Pop();
288  axi_wr_s.w.Push(W_reg);
289  w_last.Push(W_reg.last.to_uint64());
290  } while (W_reg.last != 1);
291  }
292  }
293 
294  void run_b() {
295  #pragma hls_unroll yes
296  for (int i = 0; i < numMasters; i++) {
297  axi_wr_m_b[i].Reset();
298  }
299  axi_wr_s.b.Reset();
300  write_in_flight.ResetRead();
301  writeQ.reset();
302 
303  typename axi_::WRespPayload B_reg;
304  inFlight_t inFlight_reg;
305  inFlight_t inFlight_resp_reg;
306  bool write_inProgress = 0;
307 
308  #pragma hls_pipeline_init_interval 1
309  #pragma pipeline_stall_mode flush
310  while (1) {
311  wait();
312 
313  if (!writeQ.isFull()) {
314  if (write_in_flight.PopNB(inFlight_reg)) {
315  writeQ.push(inFlight_reg);
316  }
317  }
318 
319  if (!write_inProgress) {
320  if (!writeQ.isEmpty()) {
321  inFlight_resp_reg = writeQ.pop();
322  write_inProgress = 1;
323  }
324  } else {
325  if (axiCfg::useWriteResponses) {
326  if (axi_wr_s.b.PopNB(B_reg)) {
327  axi_wr_m_b[inFlight_resp_reg].Push(B_reg);
328  write_inProgress = 0;
329  }
330  } else {
331  write_inProgress = 0;
332  }
333  }
334  }
335  }
336 };
337 
338 #endif
A struct composed of the signals associated with an AXI write response.
Definition: axi4.h:236
A struct composed of the signals associated with AXI write data.
Definition: axi4.h:279
A struct composed of the signals associated with an AXI read response.
Definition: axi4.h:180
#define CDCOUT(x, y)
Definition: hls_globals.h:73
The base axi4 class parameterized according a valid config.
Definition: axi4.h:58
An n-way arbiter that connects multiple AXI master ports to a single AXI slave port.
Definition: AxiArbiter.h:58
Compute Celing of log2 of a constant.
Definition: nvhls_int.h:174
A generalized implementation of generic n-way roundrobin arbiter.
Definition: Arbiter.h:61