MatchLib
All Classes Namespaces Files Functions Modules Pages
AxiManagerGate.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 __AXIMANAGERGATE_H__
18#define __AXIMANAGERGATE_H__
19
20#include <systemc.h>
21#include <ac_reset_signal_is.h>
22#include <axi/axi4.h>
23#include <mem_array.h>
24#include <fifo.h>
25#include <ReorderBuf.h>
26#include <axi/AxiManagerGate/ReorderBufWBeats.h>
27#include <nvhls_connections.h>
28#include <nvhls_assert.h>
29#include <axi/AxiManagerGate/AxiManagerGateIf.h>
30
59template <typename Cfg, int ROBDepth = 8, int MaxInFlightTrans = 4>
60class AxiManagerGate : public sc_module {
61 private:
62 typedef axi::axi4<Cfg> axi4_;
63
64 typedef NVUINTW(axi4_::DATA_WIDTH) Data;
65
66 ReorderBuf<WrResp<Cfg>, ROBDepth, MaxInFlightTrans> wr_rob;
67 ReorderBufWBeats<RdResp<Cfg>, ROBDepth, MaxInFlightTrans> rd_rob;
68
69 FIFO<RdRequest<Cfg>, 4> rdReqFifo;
70 FIFO<WrRequest<Cfg>, 4> wrReqFifo;
71
72 static_assert(MaxInFlightTrans <= (1 << axi4_::ID_WIDTH) , "Number of inflight transactions cannot exceed number of unique IDs");
73
74 public:
75 static const int kDebugLevel = 2;
76 typename axi4_::read::template manager<> if_rd;
77 typename axi4_::write::template manager<> if_wr;
78
79 sc_in<bool> reset_bar;
80 sc_in<bool> clk;
81 Connections::In<WrRequest<Cfg> > wrRequestIn;
82 Connections::Out<WrResp<Cfg> > wrRespOut;
83 Connections::In<RdRequest<Cfg> > rdRequestIn;
84 Connections::Out<RdResp<Cfg> > rdRespOut;
85
86 SC_CTOR(AxiManagerGate)
87 : if_rd("if_rd"), if_wr("if_wr"), reset_bar("reset_bar"), clk("clk") {
88 SC_THREAD(run_rd);
89 sensitive << clk.pos();
90 async_reset_signal_is(reset_bar, false);
91
92 SC_THREAD(run_wr);
93 sensitive << clk.pos();
94 async_reset_signal_is(reset_bar, false);
95 }
96
97 protected:
98 typedef sc_uint<axi4_::ID_WIDTH> Id;
99
100 void run_wr() {
101
102 if_wr.reset();
103 wrRequestIn.Reset();
104 wrRespOut.Reset();
105 wr_rob.reset();
106 wrReqFifo.reset();
107
108 bool addr_sent = false;
109 WrRequest<Cfg> wrRequest;
110 bool wrRequestValid = false;
111 Id wrRequestId;
112 bool wrRequestIdValid = false;
113 bool isBurstInFlight = false;
114
115 #pragma hls_pipeline_init_interval 1
116 #pragma pipeline_stall_mode flush
117 while (1) {
118 wait();
119 CDCOUT("@" << sc_time_stamp() << "\t wr_rob is empty? "
120 << wr_rob.isEmpty() << endl, kDebugLevel);
121 // send response
122 if (wr_rob.topResponseReady()) {
123 WrResp<Cfg> wrResp;
124 wrResp = wr_rob.popResponse();
125
126 CDCOUT("@" << sc_time_stamp()
127 << "\t\t Pop first response from rob and push it into host"
128 << "\tresp = " << wrResp.resp << endl, kDebugLevel);
129
130 wrRespOut.Push(wrResp); // I expect the other side to be always ready,
131 // therefore using blocking push here
132 CDCOUT("@" << sc_time_stamp() << "\t\t Done pushing resp to host"
133 << endl, kDebugLevel);
134 }
135
136 WrRequest<Cfg> wrRequest_local = wrRequest;
137 bool wrRequestValid_local = wrRequestValid;
138 Id wrRequestId_local = wrRequestId;
139 bool wrRequestIdValid_local = wrRequestIdValid;
140 bool wrReqFifo_isFull = wrReqFifo.isFull();
141
142 // receive requests
143 if (!wrRequestValid_local && !wrReqFifo.isEmpty()) {
144 wrRequest_local = wrReqFifo.pop();
145 wrRequestValid_local = true;
146 wrRequestIdValid_local = false;
147
148 CDCOUT("@" << sc_time_stamp() << "\t\t wr:pop wrReqFifo" << endl, kDebugLevel);
149 }
150
151 // receive responses
152 {
153 typename axi4_::WRespPayload resp_pld;
154 CDCOUT("@" << sc_time_stamp() << "\t\t Receiving resp from subordinate"
155 << endl, kDebugLevel);
156 if (if_wr.b.PopNB(resp_pld)) {
157 WrResp<Cfg> wrResp;
158 wrResp.resp = resp_pld.resp;
159
160 CDCOUT("@" << sc_time_stamp() << "\t\t wr:Post response to rob"
161 << "\tid = " << resp_pld.id << "\tresp = " << resp_pld.resp
162 << endl, kDebugLevel);
163 wr_rob.addResponse(static_cast<sc_uint<axi4_::ID_WIDTH> >(resp_pld.id), wrResp);
164 }
165 }
166
167 if (wrRequestValid_local) {
168 bool isBurstInFlight_local = isBurstInFlight;
169 wrRequestIdValid_local =
170 wrRequestIdValid_local || isBurstInFlight_local;
171
172 // allocate a new id
173 if (!wrRequestIdValid_local && wr_rob.canAcceptRequest()) {
174 wrRequestId_local = wr_rob.addRequest();
175 wrRequestIdValid_local = true;
176 CDCOUT("@" << sc_time_stamp()
177 << "\t\t wr:new id allocated = " << wrRequestId_local << endl, kDebugLevel);
178 }
179
180 if (wrRequestIdValid_local) {
181 NVHLS_ASSERT_MSG(wrRequestValid_local, "Should be impossible to reach this state");
182
183 bool addr_sent_local = addr_sent;
184 if (!addr_sent_local) {
185 // send addr
186 typename axi4_::AddrPayload addr_pld;
187 wrRequest_local.copyToAddrPayload(addr_pld);
188 addr_pld.id = static_cast<typename axi4_::Id>(wrRequestId_local);
189
190 addr_sent_local = if_wr.aw.PushNB(addr_pld);
191 CDCOUT("@" << sc_time_stamp() << "\t\t wr:sending addr pass? "
192 << addr_sent_local << "\taddr = " << wrRequest_local.addr
193 << "\tid = " << wrRequestId_local
194 << "\tlen = " << wrRequest_local.len
195 << "\tsize = " << wrRequest_local.size
196 << "\tburst = " << wrRequest_local.burst << endl, kDebugLevel);
197 } else {
198 // send data
199 typename axi4_::WritePayload write_pld;
200 write_pld.data = wrRequest_local.data;
201 write_pld.last = wrRequest_local.last;
202 write_pld.wstrb = ~0;
203
204 bool pushed;
205 pushed = if_wr.w.PushNB(write_pld);
206 wrRequestValid_local = wrRequestValid_local && !pushed;
207 wrRequestIdValid_local = wrRequestIdValid_local && !pushed;
208 CDCOUT("@" << sc_time_stamp() << "\t\t sending data pass? "
209 << !addr_sent_local << "\tdata = " << wrRequest_local.data
210 << "\tlast = " << wrRequest_local.last << endl, kDebugLevel);
211 isBurstInFlight_local = (wrRequest_local.last != 1);
212
213 // if this is a burst, and not the last beat next time we need to
214 // keep sending data, not addr yet
215 bool sendWNext = isBurstInFlight_local || !pushed;
216 // addr_sent_local==false will mean the next cycle that addr has to
217 // be sent
218 addr_sent_local = sendWNext;
219 }
220 addr_sent = addr_sent_local;
221 }
222 isBurstInFlight = isBurstInFlight_local;
223 }
224
225 wrRequest = wrRequest_local;
226 wrRequestValid = wrRequestValid_local;
227 wrRequestId = wrRequestId_local;
228 wrRequestIdValid = wrRequestIdValid_local;
229
230 if (!wrReqFifo_isFull) {
231 WrRequest<Cfg> wrRequest1;
232 // receive requests
233 if (wrRequestIn.PopNB(wrRequest1)) {
234 wrReqFifo.push(wrRequest1);
235
236 CDCOUT("@" << sc_time_stamp() << "\t\t wr:m got request!" << endl, kDebugLevel);
237 }
238 }
239 }
240 }
241
242 void run_rd() {
243 rdRequestIn.Reset();
244 rdRespOut.Reset();
245 rd_rob.reset();
246 if_rd.reset();
247 rdReqFifo.reset();
248
249 RdRequest<Cfg> rdRequest;
250 bool rdRequestValid = false;
251 Id rdRequestId;
252 bool rdRequestIdValid = false;
253 bool rdBurstInFlight = false;
254 bool rdReceivingBurstBeats = false;
255
256 #pragma hls_pipeline_init_interval 1
257 #pragma pipeline_stall_mode flush
258 while (1) {
259 wait();
260
261 CDCOUT("@" << sc_time_stamp() << "\t rd_rob is empty? "
262 << rd_rob.isEmpty() << endl, kDebugLevel);
263 // send response
264 if (rd_rob.topResponseReady()) {
265 RdResp<Cfg> rdResp;
266 rdResp = rd_rob.popResponse();
267
268 CDCOUT("@" << sc_time_stamp()
269 << "\t\t rd:Pop first response from rob and push it into host"
270 //<< "\tresp = " << rdResp
271 << endl, kDebugLevel);
272
273 rdRespOut.Push(rdResp); // I expect the other side to be always ready,
274 // therefore using blocking push here
275 CDCOUT("@" << sc_time_stamp() << "\t\t rd:Done pushing resp to host"
276 << endl, kDebugLevel);
277 }
278
279 RdRequest<Cfg> rdRequest_local = rdRequest;
280 bool rdRequestValid_local = rdRequestValid;
281 Id rdRequestId_local = rdRequestId;
282 bool rdRequestIdValid_local = rdRequestIdValid;
283 bool rdReqFifo_isFull = rdReqFifo.isFull();
284 bool rdBurstInFlight_local = rdBurstInFlight;
285
286 if (!rdRequestValid_local && !rdReqFifo.isEmpty()) {
287 rdRequest_local = rdReqFifo.pop();
288 rdRequestValid_local = true;
289 rdRequestIdValid_local = false;
290 CDCOUT("@" << sc_time_stamp() << "\t\t rd:pop rdReqFifo" << endl, kDebugLevel);
291 }
292
293 if (rdRequestValid_local) {
294
295 // rdRequest_local.len!=0 is a multi beat (burst) read
296 // we will wait for all previous read transactions to complete first
297 // otherwise we just need a slot in rob
298
299 bool isBurst = (rdRequest_local.len != 0);
300 bool robReady =
301 (isBurst ? rd_rob.isEmpty() : rd_rob.canAcceptRequest());
302
303 if (!rdRequestIdValid_local && robReady && !rdBurstInFlight_local) {
304 rdRequestId_local = rd_rob.addRequest();
305 rdRequestIdValid_local = true;
306 rdBurstInFlight_local = isBurst;
307 CDCOUT("@" << sc_time_stamp()
308 << "\t\t rd:new id allocated = " << rdRequestId << endl, kDebugLevel);
309 }
310
311 if (rdRequestIdValid_local) {
312 typename axi4_::AddrPayload addr_pld;
313 rdRequest_local.copyToAddrPayload(addr_pld);
314 addr_pld.id = static_cast<typename axi4_::Id>(rdRequestId_local);
315
316 bool pushed = if_rd.ar.PushNB(addr_pld);
317 rdRequestValid_local = !pushed;
318 rdRequestIdValid_local = !pushed;
319 }
320 }
321
322 rdRequest = rdRequest_local;
323 rdRequestValid = rdRequestValid_local;
324 rdRequestId = rdRequestId_local;
325 rdRequestIdValid = rdRequestIdValid_local;
326
327 if (!rdReqFifo_isFull) {
328 RdRequest<Cfg> rdRequest1;
329 // receive requests
330 if (rdRequestIn.PopNB(rdRequest1)) {
331 rdReqFifo.push(rdRequest1);
332
333 CDCOUT("@" << sc_time_stamp() << "\t\t rd:m got request ? "
334 << rdRequestValid << endl, kDebugLevel);
335 }
336 }
337
338 {
339 bool rdReceivingBurstBeats_local = rdReceivingBurstBeats;
340 typename axi4_::ReadPayload data_pld;
341 // for single beat transactions rob is guaranteed to have an entry for
342 // response
343 // but for multi beat, starting from the second beat we don't know and
344 // have to check it
345 if (!rdReceivingBurstBeats_local || rd_rob.canReceiveBeats()) {
346 if (if_rd.r.PopNB(data_pld)) {
347 RdResp<Cfg> rdResp;
348 rdResp.data = data_pld.data;
349 rdResp.resp = data_pld.resp;
350 rdResp.last = data_pld.last;
351
352 if (!rdReceivingBurstBeats_local) {
353 rd_rob.addResponse(static_cast<sc_uint<axi4_::ID_WIDTH> >(data_pld.id), rdResp);
354 } else {
355 rd_rob.addBeat(rdResp);
356 if (static_cast<sc_uint<1> >(data_pld.last) == 1) {
357 // if this is the last beat, return to normal operation mode
358 rdBurstInFlight_local = false;
359 }
360 }
361
362 // subsequent beats (after the first one will have to know to use a
363 // different api to be pushed into Rob)
364 rdReceivingBurstBeats_local = rdBurstInFlight_local;
365 }
366 }
367 rdReceivingBurstBeats = rdReceivingBurstBeats_local;
368 }
369 rdBurstInFlight = rdBurstInFlight_local;
370 }
371 }
372};
373
374#endif
An AXI manager that converts from a simple request/response interface to AXI with reordering support.
Configurable FIFO class.
Definition fifo.h:65
Reorder Buffer that allows out-of-order writes to queue and in-order reads.
Definition ReorderBuf.h:68
An extension of ReorderBuf that allows one entry to contain multiple beats of data.
The base axi4 class parameterized according a valid config.
Definition axi4.h:64
#define NVHLS_ASSERT_MSG(X, MSG)
#define CDCOUT(x, y)
Definition hls_globals.h:73
#define NVUINTW(width)
Definition nvhls_types.h:35
The struct for read requests for AxiManagerGate.
The struct for read responses for AxiManagerGate.
The struct for write requests for AxiManagerGate.
The struct for write responses for AxiManagerGate.
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