16 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
17 #define SC_INCLUDE_DYNAMIC_PROCESSES
19 #include <atp/timing_params.h>
20 #include <axi/axi_tlm.h>
21 #include <axi/pe/axi_initiator.h>
22 #include <scc/report.h>
23 #include <tlm/scc/tlm_gp_shared.h>
25 using namespace sc_core;
32 uint8_t log2n(uint8_t siz) {
return ((siz > 1) ? 1 + log2n(siz >> 1) : 0); }
36 SC_HAS_PROCESS(axi_initiator_b);
38 axi_initiator_b::axi_initiator_b(sc_core::sc_module_name nm,
40 size_t transfer_width, flavor_e flavor)
43 , transfer_width_in_bytes(transfer_width / 8)
46 SC_METHOD(clk_counter);
47 sensitive << clk_i.pos();
49 if(flavor == flavor_e::AXI)
50 for(
auto i = 0u; i < 16; i++)
51 sc_core::sc_spawn([
this]() { snoop_thread(); });
54 axi_initiator_b::~axi_initiator_b() {
55 for(
auto& e : tx_state_by_tx)
59 void axi_initiator_b::end_of_elaboration() {
60 clk_if =
dynamic_cast<sc_core::sc_clock*
>(clk_i.get_interface());
61 for(
auto i = 0U; i < outstanding_snoops.get_value(); ++i) {
62 sc_spawn(sc_bind(&axi_initiator_b::snoop_thread,
this));
66 void axi_initiator_b::b_snoop(payload_type& trans, sc_core::sc_time& t) {
67 if(bw_o.get_interface()) {
68 auto latency = bw_o->transport(trans);
69 if(latency < std::numeric_limits<unsigned>::max())
70 t += latency * clk_period;
74 tlm::tlm_sync_enum axi_initiator_b::nb_transport_bw(payload_type& trans, phase_type& phase, sc_core::sc_time& t) {
75 SCCTRACE(SCMOD) << __FUNCTION__ <<
" received with phase " << phase <<
" with delay = " << t <<
" with trans " << trans;
76 if(phase == tlm::BEGIN_REQ) {
77 snp_peq.notify(trans, t);
78 }
else if(phase == END_PARTIAL_RESP || phase == tlm::END_RESP) {
79 auto it = snp_state_by_id.find(&trans);
80 sc_assert(it != snp_state_by_id.end());
81 it->second->peq.notify(std::make_tuple(&trans, phase), t);
83 auto it = tx_state_by_tx.find(&trans);
84 sc_assert(it != tx_state_by_tx.end());
85 auto txs = it->second;
86 txs->peq.notify(std::make_tuple(&trans, phase), t);
88 return tlm::TLM_ACCEPTED;
91 void axi_initiator_b::invalidate_direct_mem_ptr(sc_dt::uint64 start_range, sc_dt::uint64 end_range) {}
93 tlm::tlm_phase axi_initiator_b::send(payload_type& trans, axi_initiator_b::tx_state* txs, tlm::tlm_phase phase) {
94 sc_core::sc_time delay;
95 SCCTRACE(SCMOD) <<
"Send " << phase <<
" of " << trans;
96 tlm::tlm_sync_enum ret = socket_fw->nb_transport_fw(trans, phase, delay);
97 if(ret == tlm::TLM_UPDATED) {
99 SCCTRACE(SCMOD) <<
"Received " << phase <<
" for " << trans;
102 auto waiting = txs->peq.has_next();
103 auto entry = txs->peq.get();
105 SCCFATAL(SCMOD) <<
"there is a waiting " << std::get<0>(entry) <<
" with phase " << std::get<1>(entry);
106 sc_assert(!txs->peq.has_next());
107 sc_assert(std::get<0>(entry) == &trans);
108 SCCTRACE(SCMOD) <<
"in send() Received " << std::get<1>(entry) <<
" for " << trans;
109 return std::get<1>(entry);
113 void axi_initiator_b::transport(payload_type& trans,
bool blocking) {
114 auto axi_id = get_axi_id(trans);
115 if(flavor == flavor_e::AXI) {
118 sc_assert(
ace &&
"No valid extension found in transaction");
122 trans.set_extension(
axi4);
126 sc_assert(trans.get_extension<
axi::ace_extension>() &&
"No ACE extension found in transaction");
128 SCCTRACE(SCMOD) <<
"got transport req for " << trans;
131 socket_fw->b_transport(trans, t);
133 auto it = tx_state_by_tx.find(&trans);
134 if(it == tx_state_by_tx.end()) {
136 std::tie(it, success) = tx_state_by_tx.insert(std::make_pair(&trans,
new tx_state()));
138 if(trans.is_read()) rd_waiting++;
140 auto& txs = it->second;
141 auto timing_e = trans.set_auto_extension<atp::timing_params>(
nullptr);
143 if(enable_id_serializing.get_value()) {
144 if(!id_mtx[axi_id]) {
147 id_mtx[axi_id]->wait();
149 txs->active_tx = &trans;
150 auto burst_length = 0;
152 burst_length = is_dataless(e) ? 1 : e->get_length() + 1;
154 burst_length = e->get_length() + 1;
156 burst_length = e->get_length() + 1;
158 SCCTRACE(SCMOD) <<
"start transport " << trans;
159 tlm::tlm_phase next_phase{tlm::UNINITIALIZED_PHASE};
160 if(!trans.is_read()) {
161 if(!data_interleaving.get_value()) {
166 for(
unsigned i = 1; i < (timing_e ? timing_e->awtv : awtv.get_value()); ++i) {
167 wait(clk_i.posedge_event());
169 SCCTRACE(SCMOD) <<
"starting " << burst_length <<
" write beats of " << trans;
170 for(
unsigned i = 0; i < burst_length - 1; ++i) {
171 if(protocol_cb[axi::fsm::BegPartReqE])
172 protocol_cb[axi::fsm::BegPartReqE](trans,
false);
173 auto res = send(trans, txs, axi::BEGIN_PARTIAL_REQ);
174 if(axi::END_PARTIAL_REQ != res)
175 SCCFATAL(SCMOD) <<
"target responded with " << res <<
" for the " << i <<
"th beat of "
176 << burst_length <<
" beats in transaction " << trans;
177 for(
unsigned i = 0; i < (timing_e ? timing_e->wbv : wbv.get_value()); ++i)
178 wait(clk_i.posedge_event());
179 if(protocol_cb[axi::fsm::EndPartReqE])
180 protocol_cb[axi::fsm::EndPartReqE](trans,
false);
182 auto res = send(trans, txs, tlm::BEGIN_REQ);
183 if(res == axi::BEGIN_PARTIAL_RESP || res == tlm::BEGIN_RESP)
185 else if(res != tlm::END_REQ)
186 SCCERR(SCMOD) <<
"target did not repsond with END_REQ to a BEGIN_REQ";
187 wait(clk_i.posedge_event());
189 SCCTRACE(SCMOD) <<
"starting " << burst_length <<
" write beats of " << trans;
190 for(
unsigned i = 0; i < burst_length - 1; ++i) {
196 for(
unsigned i = 1; i < (timing_e ? timing_e->awtv : awtv.get_value()); ++i)
197 wait(clk_i.posedge_event());
199 auto res = send(trans, txs, axi::BEGIN_PARTIAL_REQ);
200 sc_assert(axi::END_PARTIAL_REQ == res);
201 for(
unsigned i = 1; i < (timing_e ? timing_e->wbv : wbv.get_value()); ++i)
202 wait(clk_i.posedge_event());
209 if(protocol_cb[axi::fsm::BegReqE])
210 protocol_cb[axi::fsm::BegReqE](trans,
false);
211 auto res = send(trans, txs, tlm::BEGIN_REQ);
212 if(res == axi::BEGIN_PARTIAL_RESP || res == tlm::BEGIN_RESP)
214 else if(res != tlm::END_REQ)
215 SCCERR(SCMOD) <<
"target did not repsond with END_REQ to a BEGIN_REQ";
216 wait(clk_i.posedge_event());
217 if(protocol_cb[axi::fsm::EndReqE])
218 protocol_cb[axi::fsm::EndReqE](trans,
false);
225 for(
unsigned i = 1; i < (timing_e ? timing_e->artv : artv.get_value()); ++i)
226 wait(clk_i.posedge_event());
227 SCCTRACE(SCMOD) <<
"starting address phase of " << trans;
228 if(protocol_cb[axi::fsm::BegPartReqE])
229 protocol_cb[axi::fsm::BegPartReqE](trans,
false);
230 auto res = send(trans, txs, tlm::BEGIN_REQ);
231 if(res == axi::BEGIN_PARTIAL_RESP || res == tlm::BEGIN_RESP)
233 else if(res != tlm::END_REQ)
234 SCCERR(SCMOD) <<
"target did not repsond with END_REQ to a BEGIN_REQ";
235 wait(clk_i.posedge_event());
236 if(protocol_cb[axi::fsm::EndReqE])
237 protocol_cb[axi::fsm::EndReqE](trans,
false);
239 auto finished =
false;
240 if(!trans.is_read() || !trans.get_data_length())
242 const auto exp_burst_length = burst_length;
245 auto entry = next_phase == tlm::UNINITIALIZED_PHASE ? txs->peq.get() : std::make_tuple(&trans, next_phase);
246 next_phase = tlm::UNINITIALIZED_PHASE;
248 if(std::get<0>(entry) == &trans && std::get<1>(entry) == tlm::BEGIN_RESP) {
249 if(protocol_cb[axi::fsm::BegRespE])
250 protocol_cb[axi::fsm::BegRespE](trans,
false);
251 SCCTRACE(SCMOD) <<
"received last beat of " << trans;
252 auto delay_in_cycles = timing_e ? (trans.is_read() ? timing_e->rbr : timing_e->br) : br.get_value();
253 for(
unsigned i = 0; i < delay_in_cycles; ++i)
254 wait(clk_i.posedge_event());
256 tlm::tlm_phase phase = tlm::END_RESP;
257 sc_time delay = clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : SC_ZERO_TIME;
258 socket_fw->nb_transport_fw(trans, phase, delay);
260 SCCWARN(SCMOD) <<
"got wrong number of burst beats, expected " << exp_burst_length <<
", got "
261 << exp_burst_length - burst_length;
262 wait(clk_i.posedge_event());
263 if(protocol_cb[axi::fsm::EndRespE])
264 protocol_cb[axi::fsm::EndRespE](trans,
false);
266 }
else if(std::get<0>(entry) == &trans &&
267 std::get<1>(entry) == axi::BEGIN_PARTIAL_RESP) {
268 SCCTRACE(SCMOD) <<
"received beat = "<< burst_length<<
" with trans " << trans;
269 auto delay_in_cycles = timing_e ? timing_e->rbr : rbr.get_value();
270 for(
unsigned i = 0; i < delay_in_cycles; ++i)
271 wait(clk_i.posedge_event());
273 if(protocol_cb[axi::fsm::BegPartRespE])
274 protocol_cb[axi::fsm::BegPartRespE](trans,
false);
275 tlm::tlm_phase phase = axi::END_PARTIAL_RESP;
276 sc_time delay = clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : SC_ZERO_TIME;
277 auto res = socket_fw->nb_transport_fw(trans, phase, delay);
278 if(res == tlm::TLM_UPDATED) {
282 if(protocol_cb[axi::fsm::EndPartRespE])
283 protocol_cb[axi::fsm::EndPartRespE](trans,
false);
286 if(flavor == flavor_e::ACE) {
287 if(trans.is_read() && rla.get_value() != std::numeric_limits<unsigned>::max()) {
288 for(
unsigned i = 0; i < rla.get_value(); ++i)
289 wait(clk_i.posedge_event());
290 tlm::tlm_phase phase = axi::ACK;
291 sc_time delay = SC_ZERO_TIME;
292 socket_fw->nb_transport_fw(trans, phase, delay);
293 wait(clk_i.posedge_event());
295 }
else if(trans.is_write() && ba.get_value() != std::numeric_limits<unsigned>::max()) {
296 for(
unsigned i = 0; i < ba.get_value(); ++i)
297 wait(clk_i.posedge_event());
298 tlm::tlm_phase phase = axi::ACK;
299 sc_time delay = SC_ZERO_TIME;
300 socket_fw->nb_transport_fw(trans, phase, delay);
301 wait(clk_i.posedge_event());
304 if(trans.is_read()) rd_outstanding--;
305 else wr_outstanding--;
306 SCCTRACE(SCMOD) <<
"finished non-blocking protocol";
307 if(enable_id_serializing.get_value()) {
308 id_mtx[axi_id]->post();
310 txs->active_tx =
nullptr;
311 any_tx_finished.notify(SC_ZERO_TIME);
313 SCCTRACE(SCMOD) <<
"finished transport req for " << trans;
317 void axi_initiator_b::snoop_thread() {
320 while(!(trans = snp_peq.get_next_transaction())) {
321 wait(snp_peq.get_event());
324 SCCDEBUG(SCMOD) <<
"start snoop #" << snoops_in_flight;
325 auto req_ext = trans->get_extension<ace_extension>();
326 sc_assert(req_ext !=
nullptr);
328 auto it = snp_state_by_id.find(&trans);
329 if(it == snp_state_by_id.end()) {
331 std::tie(it, success) = snp_state_by_id.insert(std::make_pair(trans.get(),
new tx_state()));
334 sc_time delay = clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : SC_ZERO_TIME;
335 tlm::tlm_phase phase = tlm::END_REQ;
338 if(protocol_cb[axi::fsm::BegReqE])
339 protocol_cb[axi::fsm::BegReqE](*trans,
true);
340 socket_fw->nb_transport_fw(*trans, phase, delay);
342 if(bw_o.get_interface())
343 cycles = bw_o->transport(*trans);
344 if(protocol_cb[axi::fsm::EndReqE])
345 protocol_cb[axi::fsm::EndReqE](*trans,
true);
346 if(cycles < std::numeric_limits<unsigned>::max()) {
348 for(
size_t i = 0; i <= cycles; ++i)
349 wait(clk_i.posedge_event());
353 SCCTRACE(SCMOD)<<
" finish snoop response, release gp_shared_ptr";
359 void axi_initiator_b::snoop_resp(payload_type& trans,
bool sync) {
360 auto it = snp_state_by_id.find(&trans);
361 sc_assert(it != snp_state_by_id.end());
362 auto& txs = it->second;
363 auto data_len=trans.get_data_length();
364 auto burst_length = data_len/transfer_width_in_bytes;
367 tlm::tlm_phase next_phase{tlm::UNINITIALIZED_PHASE};
368 auto delay_in_cycles = wbv.get_value();
374 SCCTRACE(SCMOD) <<
"starting snoop resp with " << burst_length <<
" beats of " << trans;
375 for(
unsigned i = 0; i < burst_length - 1; ++i) {
376 if(protocol_cb[axi::fsm::BegPartRespE])
377 protocol_cb[axi::fsm::BegPartRespE](trans,
true);
378 auto res = send(trans, txs, axi::BEGIN_PARTIAL_RESP);
379 sc_assert(axi::END_PARTIAL_RESP == res);
380 wait(clk_i.posedge_event());
381 if(protocol_cb[axi::fsm::EndPartRespE])
382 protocol_cb[axi::fsm::EndPartRespE](trans,
true);
383 for(
unsigned i = 1; i < delay_in_cycles; ++i)
384 wait(clk_i.posedge_event());
386 if(protocol_cb[axi::fsm::BegRespE])
387 protocol_cb[axi::fsm::BegRespE](trans,
true);
388 auto res = send(trans, txs, tlm::BEGIN_RESP);
389 if(res != tlm::END_RESP)
390 SCCERR(SCMOD) <<
"target did not respond with END_RESP to a BEGIN_RESP";
391 wait(clk_i.posedge_event());
392 if(protocol_cb[axi::fsm::EndRespE])
393 protocol_cb[axi::fsm::EndRespE](trans,
true);
The ordered_semaphore primitive channel class.
TLM2.0 components modeling AHB.
tlm::tlm_fw_transport_if< TYPES > axi_fw_transport_if
alias declaration for the forward interface