17 #ifndef __AXI_T_SUBORDINATE_FROM_FILE__
18 #define __AXI_T_SUBORDINATE_FROM_FILE__
21 #include <ac_reset_signal_is.h>
24 #include <axi/testbench/CSVFileReader.h>
25 #include <nvhls_connections.h>
26 #include <hls_globals.h>
30 #include <boost/assert.hpp>
50 static const int kDebugLevel = 1;
53 typename axi4_::read::template subordinate<> if_rd;
54 typename axi4_::write::template subordinate<> if_wr;
56 sc_in<bool> reset_bar;
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;
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;
71 static const int bytesPerBeat = axi4_::DATA_WIDTH >> 3;
76 : sc_module(name_), if_rd(
"if_rd"), if_wr(
"if_wr"), reset_bar(
"reset_bar"), clk(
"clk") {
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");
84 sc_uint<axi4_::ADDR_WIDTH> addr_sc_uint;
87 std::stringstream ss_data;
88 sc_biguint<axi4_::DATA_WIDTH> data;
89 ss_data << hex << vec[1];
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);
98 localMem[addr] = load_data_pld.data;
100 validReadAddresses.push_back(addr);
104 sensitive << clk.pos();
105 async_reset_signal_is(reset_bar,
false);
108 sensitive << clk.pos();
109 async_reset_signal_is(reset_bar,
false);
115 unsigned int rdBeatInFlight = 0;
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
133 bool validAddr =
false;
134 for (
unsigned int j=0; j<validReadAddresses.size(); j++) {
135 if (validReadAddresses[j] == rd_addr_pld.addr) validAddr =
true;
137 BOOST_ASSERT_MSG( validAddr, msg.str().c_str() );
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);
148 data_pld.data = localMem[addr];
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;
159 if (!rd_resp.empty()) {
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) {
185 unsigned int wrBeatInFlight = 0;
187 typename axi4_::Addr wresp_addr;
193 if (axiCfg::useWriteResponses) {
194 if (!wr_resp.empty()) {
195 resp_pld = wr_resp.front();
196 if (if_wr.nb_bwrite(resp_pld)) {
198 CDCOUT(sc_time_stamp() <<
" " << name() <<
" Sent write response"
199 << endl, kDebugLevel);
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);
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) {
224 if (!wr_addr.empty() & !wr_data.empty()) {
226 wr_addr_pld = wr_addr.front();
227 wresp_addr = wr_addr_pld.addr;
230 wr_data_pld = wr_data.front(); wr_data.pop();
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);
243 localMem[wresp_addr] = wr_data_pld.data;
245 validReadAddresses.push_back(wresp_addr);
246 wresp_addr += bytesPerBeat;
247 if (wr_data_pld.last == 1) {
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);
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.
#define CMOD_ASSERT_MSG(X, MSG)
NVUINTW(Wrapped< T >::width) TypeToNVUINT(T in)
Convert Type to NVUINT.
type1 set_slc(type1 X, type2 Y, const unsigned int i)
Function that replaces slice of bits.
A struct composed of the signals associated with AXI read and write requests.
A struct composed of the signals associated with an AXI read response.
A struct composed of the signals associated with an AXI write response.
A struct composed of the signals associated with AXI write data.