17 #ifndef __AXI_T_SUBORDINATE__
18 #define __AXI_T_SUBORDINATE__
21 #include <ac_reset_signal_is.h>
24 #include <nvhls_connections.h>
25 #include <hls_globals.h>
29 #include <boost/assert.hpp>
44 template <
typename axiCfg>
47 static const int kDebugLevel = 1;
50 typename axi4_::read::template subordinate<> if_rd;
51 typename axi4_::write::template subordinate<> if_wr;
53 sc_in<bool> reset_bar;
56 std::queue <typename axi4_::ReadPayload> rd_resp;
57 std::queue <typename axi4_::Addr> rd_resp_addr;
58 std::queue <typename axi4_::AddrPayload> wr_addr;
59 std::queue <typename axi4_::WritePayload> wr_data;
60 std::queue <typename axi4_::WRespPayload> wr_resp;
62 std::map<typename axi4_::Addr, typename axi4_::Data> localMem;
63 std::map<typename axi4_::Addr, NVUINT8 > localMem_wstrb;
64 std::vector<typename axi4_::Addr> validReadAddresses;
66 static const int bytesPerBeat = axi4_::DATA_WIDTH >> 3;
69 : if_rd(
"if_rd"), if_wr(
"if_wr"), reset_bar(
"reset_bar"), clk(
"clk") {
71 sensitive << clk.pos();
72 async_reset_signal_is(reset_bar,
false);
75 sensitive << clk.pos();
76 async_reset_signal_is(reset_bar,
false);
82 unsigned int rdBeatInFlight = 0;
88 if (if_rd.nb_aread(rd_addr_pld)) {
89 typename axi4_::Addr addr = rd_addr_pld.addr;
90 CMOD_ASSERT_MSG(addr % bytesPerBeat == 0,
"Addresses must be word aligned");
91 CDCOUT(sc_time_stamp() <<
" " << name() <<
" Received read request: ["
93 << endl, kDebugLevel);
94 NVUINTW(axi4_::ALEN_WIDTH) len = (axiCfg::useBurst ? rd_addr_pld.len :
NVUINTW(axi4_::ALEN_WIDTH)(0));
95 for (
unsigned int i=0; i<(len+1); i++) {
96 std::ostringstream msg;
97 msg <<
"\nError @" << sc_time_stamp() <<
" from " << name()
98 <<
": Received a read request from an address that has not yet been written to"
99 <<
", addr=" << hex << addr
101 bool validAddr =
false;
102 for (
unsigned int j=0; j<validReadAddresses.size(); j++) {
103 if (validReadAddresses[j] == rd_addr_pld.addr) validAddr =
true;
105 BOOST_ASSERT_MSG( validAddr, msg.str().c_str() );
107 if (axiCfg::useWriteStrobes) {
108 for (
int k=0; k<axi4_::WSTRB_WIDTH; k++) {
109 if (localMem_wstrb.find(addr+k) != localMem_wstrb.end()) {
110 data_pld.data =
nvhls::set_slc(data_pld.data, localMem_wstrb[addr+k], 8*k);
116 data_pld.data = localMem[addr];
118 data_pld.resp = axi4_::Enc::XRESP::OKAY;
119 data_pld.id = rd_addr_pld.id;
120 data_pld.last = (i == len);
121 rd_resp.push(data_pld);
122 rd_resp_addr.push(addr);
123 addr += bytesPerBeat;
127 if (!rd_resp.empty()) {
129 data_pld = rd_resp.front();
130 typename axi4_::Addr addr = rd_resp_addr.front();
131 if (if_rd.nb_rwrite(data_pld)) {
132 CDCOUT(sc_time_stamp() <<
" " << name() <<
" Returned read data:"
133 <<
" data=[" << data_pld <<
"]"
134 <<
" addr=" << hex << addr.to_uint64()
135 <<
" beat=" << dec << (axiCfg::useBurst ?
static_cast< sc_uint<32>
>(rdBeatInFlight++) :
"N/A")
136 << endl, kDebugLevel);
137 if (data_pld.last == 1) {
155 unsigned int wrBeatInFlight = 0;
157 typename axi4_::Addr wresp_addr;
163 if (axiCfg::useWriteResponses) {
164 if (!wr_resp.empty()) {
165 resp_pld = wr_resp.front();
166 if (if_wr.nb_bwrite(resp_pld)) {
168 CDCOUT(sc_time_stamp() <<
" " << name() <<
" Sent write response: ["
170 << endl, kDebugLevel);
176 if (if_wr.aw.PopNB(wr_addr_pld)) {
177 CMOD_ASSERT_MSG(wr_addr_pld.addr.to_uint64() % bytesPerBeat == 0,
"Addresses must be word aligned");
178 wr_addr.push(wr_addr_pld);
179 CDCOUT(sc_time_stamp() <<
" " << name() <<
" Received write request: ["
180 << wr_addr_pld <<
"]"
181 << endl, kDebugLevel);
185 if (if_wr.w.PopNB(wr_data_pld)) {
186 wr_data.push(wr_data_pld);
187 CDCOUT(sc_time_stamp() <<
" " << name() <<
" Received write data:"
188 <<
" data=[" << wr_data_pld <<
"]"
189 <<
" beat=" << dec << (axiCfg::useBurst ?
static_cast< sc_uint<32>
>(wrBeatInFlight++) :
"N/A")
190 << endl, kDebugLevel);
191 if (wr_data_pld.last == 1) {
197 if (!wr_addr.empty() & !wr_data.empty()) {
199 wr_addr_pld_out = wr_addr.front();
200 wresp_addr = wr_addr_pld_out.addr;
203 wr_data_pld_out = wr_data.front(); wr_data.pop();
205 if (axiCfg::useWriteStrobes) {
206 std::ostringstream msg;
207 msg <<
"\nError @" << sc_time_stamp() <<
" from " << name()
208 <<
": Wstrb cannot be all zeros" << endl;
209 BOOST_ASSERT_MSG( wr_data_pld_out.wstrb != 0, msg.str().c_str() );
210 for (
int j=0; j<axi4_::WSTRB_WIDTH; j++) {
211 if (wr_data_pld_out.wstrb[j] == 1) {
212 localMem_wstrb[wresp_addr+j] = nvhls::get_slc<8>(wr_data_pld_out.data, 8*j);
216 localMem[wresp_addr] = wr_data_pld_out.data;
218 validReadAddresses.push_back(wresp_addr);
219 wresp_addr += bytesPerBeat;
220 if (wr_data_pld_out.last == 1) {
224 if (axiCfg::useWriteResponses) {
225 resp_pld.resp = axi4_::Enc::XRESP::OKAY;
226 resp_pld.id = wr_addr_pld_out.id;
227 wr_resp.push(resp_pld);
An AXI subordinate for use in a testbench.
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.