MatchLib
All Classes Namespaces Files Functions Modules Pages
Subordinate.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__
18#define __AXI_T_SUBORDINATE__
19
20#include <systemc.h>
21#include <ac_reset_signal_is.h>
22
23#include <axi/axi4.h>
24#include <nvhls_connections.h>
25#include <hls_globals.h>
26
27#include <queue>
28#include <map>
29#include <boost/assert.hpp>
30#include <algorithm>
31
44template <typename axiCfg>
45class Subordinate : public sc_module {
46 public:
47 static const int kDebugLevel = 1;
49
50 typename axi4_::read::template subordinate<> if_rd;
51 typename axi4_::write::template subordinate<> if_wr;
52
53 sc_in<bool> reset_bar;
54 sc_in<bool> clk;
55
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;
61
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;
65
66 static const int bytesPerBeat = axi4_::DATA_WIDTH >> 3;
67
68 SC_CTOR(Subordinate)
69 : if_rd("if_rd"), if_wr("if_wr"), reset_bar("reset_bar"), clk("clk") {
70 SC_THREAD(run_rd);
71 sensitive << clk.pos();
72 async_reset_signal_is(reset_bar, false);
73
74 SC_THREAD(run_wr);
75 sensitive << clk.pos();
76 async_reset_signal_is(reset_bar, false);
77 }
78
79 protected:
80 void run_rd() {
81 if_rd.reset();
82 unsigned int rdBeatInFlight = 0;
83
84 while (1) {
85 wait();
86
87 typename axi4_::AddrPayload rd_addr_pld;
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: ["
92 << rd_addr_pld << "]"
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
100 << endl;
101 bool validAddr = false;
102 for (unsigned int j=0; j<validReadAddresses.size(); j++) {
103 if (validReadAddresses[j] == rd_addr_pld.addr) validAddr = true;
104 }
105 BOOST_ASSERT_MSG( validAddr, msg.str().c_str() );
106 typename axi4_::ReadPayload data_pld;
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);
111 } else {
112 data_pld.data = nvhls::set_slc(data_pld.data, NVUINT8(0), 8*k);
113 }
114 }
115 } else {
116 data_pld.data = localMem[addr];
117 }
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;
124 }
125 }
126
127 if (!rd_resp.empty()) {
128 typename axi4_::ReadPayload data_pld;
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) {
138 rdBeatInFlight = 0;
139 }
140 rd_resp.pop();
141 rd_resp_addr.pop();
142 }
143 }
144 }
145 }
146
147 void run_wr() {
148 if_wr.reset();
149
150 typename axi4_::WRespPayload resp_pld;
151 typename axi4_::AddrPayload wr_addr_pld;
152 typename axi4_::WritePayload wr_data_pld;
153 typename axi4_::AddrPayload wr_addr_pld_out;
154 typename axi4_::WritePayload wr_data_pld_out;
155 unsigned int wrBeatInFlight = 0;
156 bool first_beat = 1;
157 typename axi4_::Addr wresp_addr;
158
159 while (1) {
160 wait();
161
162 // Send a write response out of the local queue
163 if (axiCfg::useWriteResponses) {
164 if (!wr_resp.empty()) {
165 resp_pld = wr_resp.front();
166 if (if_wr.nb_bwrite(resp_pld)) {
167 wr_resp.pop();
168 CDCOUT(sc_time_stamp() << " " << name() << " Sent write response: ["
169 << resp_pld << "]"
170 << endl, kDebugLevel);
171 }
172 }
173 }
174
175 // Grab a write request (addr) and put it in the local queue
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);
182 }
183
184 // Grab a write request (data) and put it in the local queue
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) {
192 wrBeatInFlight = 0;
193 }
194 }
195
196 // Handle a write request in the local queues
197 if (!wr_addr.empty() & !wr_data.empty()) {
198 if (first_beat) {
199 wr_addr_pld_out = wr_addr.front();
200 wresp_addr = wr_addr_pld_out.addr;
201 first_beat = 0;
202 }
203 wr_data_pld_out = wr_data.front(); wr_data.pop();
204 // Store the data
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);
213 }
214 }
215 } else {
216 localMem[wresp_addr] = wr_data_pld_out.data;
217 }
218 validReadAddresses.push_back(wresp_addr);
219 wresp_addr += bytesPerBeat;
220 if (wr_data_pld_out.last == 1) {
221 wr_addr.pop();
222 first_beat = 1;
223 // Generate a response
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);
228 }
229 }
230 }
231 }
232 }
233};
234
235#endif
An AXI subordinate for use in a testbench.
Definition Subordinate.h:45
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