MatchLib
All Classes Namespaces Files Functions Modules Pages
ManagerFromFile.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_T_MANAGER_FROM_FILE__
18#define __AXI_T_MANAGER_FROM_FILE__
19
20#include <nvhls_int.h>
21#include <systemc.h>
22#include <ac_reset_signal_is.h>
23
24#include <axi/axi4.h>
25#include <axi/testbench/CSVFileReader.h>
26#include <nvhls_connections.h>
27#include <hls_globals.h>
28
29#include <queue>
30#include <string>
31#include <sstream>
32#include <vector>
33#include <math.h>
34#include <boost/assert.hpp>
35
60// Allow an sc_in to be present only if a template parameter is enabled
61template <typename T, bool enable> class sc_in_conditional : public sc_signal<T> {};
62template <typename T> class sc_in_conditional <T,1> : public sc_in<T> {};
63
64template <typename axiCfg, bool enable_interrupts = false> class ManagerFromFile : public sc_module {
65 public:
66 static const int kDebugLevel = 1;
68
69 typename axi4_::read::template manager<> if_rd;
70 typename axi4_::write::template manager<> if_wr;
71
72 sc_in<bool> reset_bar;
73 sc_in<bool> clk;
74
76
77 static const int bytesPerBeat = axi4_::DATA_WIDTH >> 3;
78 static const int bytesPerWord = axi4_::DATA_WIDTH >> 3;
79 static const int axiAddrBitsPerWord = nvhls::log2_ceil<bytesPerWord>::val;
80
81 std::queue< int > delay_q;
82 std::queue< int > req_q;
83 std::queue< typename axi4_::AddrPayload > raddr_q;
84 std::queue< typename axi4_::AddrPayload > waddr_q;
85 std::queue< typename axi4_::WritePayload > wdata_q;
86 std::queue<typename axi4_::Data> rresp_q;
87
88 typename axi4_::AddrPayload addr_pld;
89 typename axi4_::WritePayload wr_data_pld;
90 typename axi4_::ReadPayload data_pld;
91 typename axi4_::AddrPayload wr_addr_pld;
92 typename axi4_::WRespPayload wr_resp_pld;
93
94 int burst_inflight = 0;
95 sc_out<bool> done;
96
97 SC_HAS_PROCESS(ManagerFromFile);
98
99 ManagerFromFile(sc_module_name name_, std::string filename="requests.csv")
100 : sc_module(name_), if_rd("if_rd"), if_wr("if_wr"), reset_bar("reset_bar"), clk("clk") {
101
102 CDCOUT("Reading file: " << filename << endl, kDebugLevel);
103 CSVFileReader reader(filename);
104 std::vector< std::vector<std::string> > dataList = reader.readCSV();
105 for (unsigned int i=0; i < dataList.size(); i++) {
106 std::vector<std::string> vec = dataList[i];
107 CMOD_ASSERT_MSG(vec.size() == 5, "Each request must have five elements");
108 if (!burst_inflight) delay_q.push(atoi(vec[0].c_str()));
109 if (vec[1] == "R") {
110 if (!burst_inflight) {
111 req_q.push(0);
112 std::stringstream ss;
113 sc_uint<axi4_::ADDR_WIDTH> addr;
114 ss << hex << vec[2];
115 ss >> addr;
116 std::stringstream ss_len;
117 addr_pld.addr = static_cast<typename axi4_::Addr>(addr);
118 sc_uint<axi4_::ALEN_WIDTH> len;
119 ss_len << hex << vec[4];
120 ss_len >> len;
121 if (len) CMOD_ASSERT_MSG(axiCfg::useBurst, "A burst transaction was requested but the AXI config does not support bursts");
122 CMOD_ASSERT_MSG(axiCfg::maxBurstSize >= len, "A burst transaction was requested that is longer than the maximum allowed by the AXI config");
123 addr_pld.len = 0;
124 addr_pld.len = static_cast<typename axi4_::BeatNum>(len);
125 raddr_q.push(addr_pld);
126 burst_inflight = int(len);
127 } else {
128 burst_inflight--;
129 }
130 std::stringstream ss_data;
131 sc_biguint<axi4_::DATA_WIDTH> data;
132 ss_data << hex << vec[3];
133 ss_data >> data;
134 rresp_q.push(TypeToNVUINT(data));
135 } else if (vec[1] == "W") {
136 if (!burst_inflight) {
137 req_q.push(1);
138 std::stringstream ss;
139 sc_uint<axi4_::ADDR_WIDTH> addr;
140 ss << hex << vec[2];
141 ss >> addr;
142 std::stringstream ss_len;
143 addr_pld.addr = static_cast<typename axi4_::Addr>(addr);
144 sc_uint<axi4_::ALEN_WIDTH> len;
145 ss_len << hex << vec[4];
146 ss_len >> len;
147 if (len) CMOD_ASSERT_MSG(axiCfg::useBurst, "A burst transaction was requested but the AXI config does not support bursts");
148 CMOD_ASSERT_MSG(axiCfg::maxBurstSize >= len, "A burst transaction was requested that is longer than the maximum allowed by the AXI config");
149 addr_pld.len = static_cast<typename axi4_::BeatNum>(len);
150 waddr_q.push(addr_pld);
151 burst_inflight = int(len);
152 } else {
153 burst_inflight--;
154 }
155 std::stringstream ss_data;
156 sc_biguint<axi4_::DATA_WIDTH> data;
157 ss_data << hex << vec[3];
158 ss_data >> data;
159 wr_data_pld.data = TypeToNVUINT(data);
160 wr_data_pld.wstrb = ~0;
161 if (!burst_inflight) {
162 wr_data_pld.last = 1;
163 } else {
164 wr_data_pld.last = 0;
165 }
166 wdata_q.push(wr_data_pld);
167 } else if (vec[1] == "Q") {
168 CMOD_ASSERT_MSG(enable_interrupts, "Interrupt command read, but interrupts are not enabled");
169 req_q.push(2);
170 } else {
171 CMOD_ASSERT_MSG(1, "Requests must be R or W or Q");
172 }
173 }
174
175 SC_THREAD(run);
176 sensitive << clk.pos();
177 async_reset_signal_is(reset_bar, false);
178 }
179
180 protected:
181 void run() {
182
183 done = 0;
184
185 if_rd.reset();
186 if_wr.reset();
187
188 wait(20);
189
190 while (!delay_q.empty()) {
191 int delay = delay_q.front();
192 if (delay > 0) wait(delay);
193 delay_q.pop();
194 if (req_q.front() == 2) {
195 CMOD_ASSERT_MSG(enable_interrupts,"Interrupt command found, but interrupts are not enabled");
196 CDCOUT(sc_time_stamp() << " " << name() << " Beginning wait for interrupt"
197 << endl, kDebugLevel);
198 while (interrupt.read() == 0) wait();
199 CDCOUT(sc_time_stamp() << " " << name() << " Interrupt received"
200 << endl, kDebugLevel);
201 } else if (req_q.front() == 1) {
202 addr_pld = waddr_q.front();
203 if_wr.aw.Push(addr_pld);
204 waddr_q.pop();
205 CDCOUT(sc_time_stamp() << " " << name() << " Sent write request:"
206 << " addr=[" << addr_pld << "]"
207 << endl, kDebugLevel);
208 do {
209 wr_data_pld = wdata_q.front();
210 if_wr.w.Push(wr_data_pld);
211 wdata_q.pop();
212 CDCOUT(sc_time_stamp() << " " << name() << " Sent write data:"
213 << " data=[" << wr_data_pld << "]"
214 << endl, kDebugLevel);
215 } while (!wr_data_pld.last);
216 if_wr.b.Pop();
217 } else if (req_q.front() == 0) {
218 addr_pld = raddr_q.front();
219 if_rd.ar.Push(addr_pld);
220 raddr_q.pop();
221 CDCOUT(sc_time_stamp() << " " << name() << " Sent read request: "
222 << " addr=[" << addr_pld << "]"
223 << endl, kDebugLevel);
224 do {
225 data_pld = if_rd.r.Pop();
226 CDCOUT(sc_time_stamp() << " " << name() << " Received read response: ["
227 << data_pld << "]"
228 << endl, kDebugLevel);
229 CMOD_ASSERT_MSG(data_pld.data == rresp_q.front(),"Read response did not match expected value");
230 rresp_q.pop();
231 } while (!data_pld.last);
232 } else {
233 CMOD_ASSERT_MSG(0,"Unexpected value in req_q");
234 }
235 req_q.pop();
236 }
237 done = 1;
238 }
239};
240
241#endif
A helper class to read CSV files.
The base axi4 class parameterized according a valid config.
Definition axi4.h:64
An AXI manager that generates traffic according to a file for use in testbenches.
#define CMOD_ASSERT_MSG(X, MSG)
#define CDCOUT(x, y)
Definition hls_globals.h:73
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