MatchLib
All Classes Namespaces Files Functions Modules Pages
SubordinateFromFile.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_SUBORDINATE_FROM_FILE__
18#define __AXI_T_SUBORDINATE_FROM_FILE__
19
20#include <systemc.h>
21#include <ac_reset_signal_is.h>
22
23#include <axi/axi4.h>
24#include <axi/testbench/CSVFileReader.h>
25#include <nvhls_connections.h>
26#include <hls_globals.h>
27
28#include <queue>
29#include <map>
30#include <boost/assert.hpp>
31#include <algorithm>
32#include <string>
33#include <sstream>
34
48template <typename axiCfg> class SubordinateFromFile : public sc_module {
49 public:
50 static const int kDebugLevel = 1;
52
53 typename axi4_::read::template subordinate<> if_rd;
54 typename axi4_::write::template subordinate<> if_wr;
55
56 sc_in<bool> reset_bar;
57 sc_in<bool> clk;
58
59 std::queue <typename axi4_::ReadPayload> rd_resp;
60 std::queue <typename axi4_::Addr> rd_resp_addr;
61 std::queue <typename axi4_::AddrPayload> wr_addr;
62 std::queue <typename axi4_::WritePayload> wr_data;
63 std::queue <typename axi4_::WRespPayload> wr_resp;
64
65 std::map<typename axi4_::Addr, typename axi4_::Data> localMem;
66 std::map<typename axi4_::Addr, NVUINT8> localMem_wstrb;
67 std::vector<typename axi4_::Addr> validReadAddresses;
68
69 typename axi4_::WritePayload load_data_pld;
70
71 static const int bytesPerBeat = axi4_::DATA_WIDTH >> 3;
72
73 SC_HAS_PROCESS(SubordinateFromFile);
74
75 SubordinateFromFile(sc_module_name name_, std::string filename="mem.csv")
76 : sc_module(name_), if_rd("if_rd"), if_wr("if_wr"), reset_bar("reset_bar"), clk("clk") {
77
78 CSVFileReader reader(filename);
79 std::vector< std::vector<std::string> > dataList = reader.readCSV();
80 for (unsigned int i=0; i < dataList.size(); i++) {
81 std::vector<std::string> vec = dataList[i];
82 CMOD_ASSERT_MSG(vec.size() == 2, "Each request must have two elements");
83 std::stringstream ss;
84 sc_uint<axi4_::ADDR_WIDTH> addr_sc_uint;
85 ss << hex << vec[0];
86 ss >> addr_sc_uint;
87 std::stringstream ss_data;
88 sc_biguint<axi4_::DATA_WIDTH> data;
89 ss_data << hex << vec[1];
90 ss_data >> data;
91 load_data_pld.data = TypeToNVUINT(data);
92 typename axi4_::Addr addr = static_cast<typename axi4_::Addr>(addr_sc_uint);
93 if (axiCfg::useWriteStrobes) {
94 for (int j=0; j<axi4_::WSTRB_WIDTH; j++) {
95 localMem_wstrb[addr+j] = nvhls::get_slc<8>(load_data_pld.data, 8*j);
96 }
97 } else {
98 localMem[addr] = load_data_pld.data;
99 }
100 validReadAddresses.push_back(addr);
101 }
102
103 SC_THREAD(run_rd);
104 sensitive << clk.pos();
105 async_reset_signal_is(reset_bar, false);
106
107 SC_THREAD(run_wr);
108 sensitive << clk.pos();
109 async_reset_signal_is(reset_bar, false);
110 }
111
112protected:
113 void run_rd() {
114 if_rd.reset();
115 unsigned int rdBeatInFlight = 0;
116
117 while (1) {
118 wait();
119
120 typename axi4_::AddrPayload rd_addr_pld;
121 if (if_rd.nb_aread(rd_addr_pld)) {
122 typename axi4_::Addr addr = rd_addr_pld.addr;
123 CDCOUT(sc_time_stamp() << " " << name() << " Received read request: ["
124 << rd_addr_pld << "]"
125 << endl, kDebugLevel);
126 NVUINTW(axi4_::ALEN_WIDTH) len = (axiCfg::useBurst ? rd_addr_pld.len : NVUINTW(axi4_::ALEN_WIDTH)(0));
127 for (unsigned int i=0; i<(len+1); i++) {
128 std::ostringstream msg;
129 msg << "\nError @" << sc_time_stamp() << " from " << name()
130 << ": Received a read request from an address that has not yet been written to"
131 << ", addr=" << hex << addr
132 << endl;
133 bool validAddr = false;
134 for (unsigned int j=0; j<validReadAddresses.size(); j++) {
135 if (validReadAddresses[j] == rd_addr_pld.addr) validAddr = true;
136 }
137 BOOST_ASSERT_MSG( validAddr, msg.str().c_str() );
138 typename axi4_::ReadPayload data_pld;
139 if (axiCfg::useWriteStrobes) {
140 for (int k=0; k<axi4_::WSTRB_WIDTH; k++) {
141 if (localMem_wstrb.find(addr+k) != localMem_wstrb.end()) {
142 data_pld.data = nvhls::set_slc(data_pld.data, localMem_wstrb[addr+k], 8*k);
143 } else {
144 data_pld.data = nvhls::set_slc(data_pld.data, NVUINT8(0), 8*k);
145 }
146 }
147 } else {
148 data_pld.data = localMem[addr];
149 }
150 data_pld.resp = axi4_::Enc::XRESP::OKAY;
151 data_pld.id = rd_addr_pld.id;
152 data_pld.last = (i == len);
153 rd_resp.push(data_pld);
154 rd_resp_addr.push(addr);
155 addr += bytesPerBeat;
156 }
157 }
158
159 if (!rd_resp.empty()) {
160 typename axi4_::ReadPayload data_pld;
161 data_pld = rd_resp.front();
162 typename axi4_::Addr addr = rd_resp_addr.front();
163 if (if_rd.nb_rwrite(data_pld)) {
164 CDCOUT(sc_time_stamp() << " " << name() << " Returned read data:"
165 << " data=[" << data_pld << "]"
166 << " addr=" << hex << addr.to_uint64()
167 << " beat=" << dec << (axiCfg::useBurst ? static_cast< sc_uint<32> >(rdBeatInFlight++) : "N/A")
168 << endl, kDebugLevel);
169 if (data_pld.last == 1) {
170 rdBeatInFlight = 0;
171 }
172 rd_resp.pop();
173 rd_resp_addr.pop();
174 }
175 }
176 }
177 }
178
179 void run_wr() {
180 if_wr.reset();
181
182 typename axi4_::WRespPayload resp_pld;
183 typename axi4_::AddrPayload wr_addr_pld;
184 typename axi4_::WritePayload wr_data_pld;
185 unsigned int wrBeatInFlight = 0;
186 bool first_beat = 1;
187 typename axi4_::Addr wresp_addr;
188
189 while (1) {
190 wait();
191
192 // Send a write response out of the local queue
193 if (axiCfg::useWriteResponses) {
194 if (!wr_resp.empty()) {
195 resp_pld = wr_resp.front();
196 if (if_wr.nb_bwrite(resp_pld)) {
197 wr_resp.pop();
198 CDCOUT(sc_time_stamp() << " " << name() << " Sent write response"
199 << endl, kDebugLevel);
200 }
201 }
202 }
203
204 // Grab a write request (addr) and put it in the local queue
205 if (if_wr.aw.PopNB(wr_addr_pld)) {
206 wr_addr.push(wr_addr_pld);
207 CDCOUT(sc_time_stamp() << " " << name() << " Received write request:"
208 << wr_addr_pld << endl, kDebugLevel);
209 }
210
211 // Grab a write request (data) and put it in the local queue
212 if (if_wr.w.PopNB(wr_data_pld)) {
213 wr_data.push(wr_data_pld);
214 CDCOUT(sc_time_stamp() << " " << name() << " Received write data:"
215 << " data=[" << wr_data_pld << "]"
216 << " beat=" << dec << (axiCfg::useBurst ? static_cast< sc_uint<32> >(wrBeatInFlight++) : "N/A")
217 << endl, kDebugLevel);
218 if (wr_data_pld.last == 1) {
219 wrBeatInFlight = 0;
220 }
221 }
222
223 // Handle a write request in the local queues
224 if (!wr_addr.empty() & !wr_data.empty()) {
225 if (first_beat) {
226 wr_addr_pld = wr_addr.front();
227 wresp_addr = wr_addr_pld.addr;
228 first_beat = 0;
229 }
230 wr_data_pld = wr_data.front(); wr_data.pop();
231 // Store the data
232 if (axiCfg::useWriteStrobes) {
233 std::ostringstream msg;
234 msg << "\nError @" << sc_time_stamp() << " from " << name()
235 << ": Wstrb cannot be all zeros" << endl;
236 BOOST_ASSERT_MSG( wr_data_pld.wstrb != 0, msg.str().c_str() );
237 for (int j=0; j<axi4_::WSTRB_WIDTH; j++) {
238 if (wr_data_pld.wstrb[j] == 1) {
239 localMem_wstrb[wresp_addr+j] = nvhls::get_slc<8>(wr_data_pld.data, 8*j);
240 }
241 }
242 } else {
243 localMem[wresp_addr] = wr_data_pld.data;
244 }
245 validReadAddresses.push_back(wresp_addr);
246 wresp_addr += bytesPerBeat;
247 if (wr_data_pld.last == 1) {
248 wr_addr.pop();
249 first_beat = 1;
250 // Generate a response
251 if (axiCfg::useWriteResponses) {
252 resp_pld.resp = axi4_::Enc::XRESP::OKAY;
253 resp_pld.id = wr_addr_pld.id;
254 wr_resp.push(resp_pld);
255 }
256 }
257 }
258 }
259 }
260};
261
262#endif
A helper class to read CSV files.
An AXI subordinate with its memory prepopulated from a file for use in testbenches.
The base axi4 class parameterized according a valid config.
Definition axi4.h:64
#define CMOD_ASSERT_MSG(X, MSG)
#define CDCOUT(x, y)
Definition hls_globals.h:73
#define NVUINTW(width)
Definition nvhls_types.h:35
nvhls_t< W >::nvuint_t get_slc(type X, const unsigned int i)
Function that returns slice of bits.
Definition nvhls_int.h:437
type1 set_slc(type1 X, type2 Y, const unsigned int i)
Function that replaces slice of bits.
Definition nvhls_int.h:387
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