scc 2025.09
SystemC components library
ace_initiator.h
1/*******************************************************************************
2 * Copyright 2021-2022 MINRES Technologies GmbH
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 _BUS_AXI_PIN_ACE_INITIATOR_H_
18#define _BUS_AXI_PIN_ACE_INITIATOR_H_
19
20#include <axi/axi_tlm.h>
21#include <axi/fsm/base.h>
22#include <axi/fsm/protocol_fsm.h>
23#include <axi/signal_if.h>
24#include <cci_configuration>
25#include <scc/fifo_w_cb.h>
26#include <systemc>
27#include <tlm/scc/tlm_mm.h>
28#include <tlm_utils/peq_with_cb_and_phase.h>
29
31namespace axi {
33namespace pin {
34
35using namespace axi::fsm;
36
37template <typename CFG>
38struct ace_initiator : public sc_core::sc_module,
39 public aw_ace<CFG, typename CFG::master_types>,
40 public wdata_ace<CFG, typename CFG::master_types>,
41 public b_ace<CFG, typename CFG::master_types>,
42 public ar_ace<CFG, typename CFG::master_types>,
43 public rresp_ace<CFG, typename CFG::master_types>,
44
45 public ac_ace<CFG, typename CFG::master_types>,
46 public cr_ace<CFG, typename CFG::master_types>,
47 public cd_ace<CFG, typename CFG::master_types>,
48
49 protected axi::fsm::base,
50 public axi::ace_fw_transport_if<axi::axi_protocol_types> {
51 SC_HAS_PROCESS(ace_initiator);
52
53 enum { CACHELINE_SZ = 64 };
54
55 using payload_type = axi::axi_protocol_types::tlm_payload_type;
56 using phase_type = axi::axi_protocol_types::tlm_phase_type;
57
58 sc_core::sc_in<bool> clk_i{"clk_i"};
59
61
62 cci::cci_param<bool> pipelined_wrreq{"pipelined_wrreq", false};
63
64 cci::cci_param<bool> mask_axi_id{"mask_axi_id", false};
65
66 ace_initiator(sc_core::sc_module_name const& nm, bool pipelined_wrreq = false)
67 : sc_core::sc_module(nm)
68 // coherent= true
69 , base(CFG::BUSWIDTH, true)
70 , pipelined_wrreq("pipelined_wrreq", pipelined_wrreq) {
71 instance_name = name();
72 tsckt(*this);
73 SC_METHOD(clk_delay);
74 sensitive << clk_i.pos();
75 SC_THREAD(ar_t);
76 SC_THREAD(r_t);
77 SC_THREAD(aw_t);
78 SC_THREAD(wdata_t);
79 SC_THREAD(b_t);
80 SC_THREAD(ac_t);
81 SC_THREAD(cr_resp_t);
82 SC_THREAD(cd_t);
83 SC_THREAD(rack_t);
84 SC_THREAD(wack_t);
85 }
86
87private:
88 void b_transport(payload_type& trans, sc_core::sc_time& t) override {
89 trans.set_dmi_allowed(false);
90 trans.set_response_status(tlm::TLM_OK_RESPONSE);
91 }
92
93 tlm::tlm_sync_enum nb_transport_fw(payload_type& trans, phase_type& phase, sc_core::sc_time& t) override {
94 assert(trans.get_extension<axi::ace_extension>() && "missing ACE extension");
95 sc_core::sc_time delay; // FIXME: calculate delay correctly
96 fw_peq.notify(trans, phase, delay);
97 return tlm::TLM_ACCEPTED;
98 }
99
100 bool get_direct_mem_ptr(payload_type& trans, tlm::tlm_dmi& dmi_data) override {
101 trans.set_dmi_allowed(false);
102 return false;
103 }
104
105 unsigned int transport_dbg(payload_type& trans) override { return 0; }
106
107 void end_of_elaboration() override { clk_if = dynamic_cast<sc_core::sc_clock*>(clk_i.get_interface()); }
108
109 fsm_handle* create_fsm_handle() { return new fsm_handle(); }
110
111 void setup_callbacks(fsm_handle* fsm_hndl);
112
113 void clk_delay() { clk_delayed.notify(axi::CLK_DELAY); }
114
115 void ar_t();
116 void r_t();
117 void aw_t();
118 void wdata_t();
119 void b_t();
125 void ac_t();
126 void cr_resp_t();
127 void cd_t();
128
129 void rack_t();
130 void wack_t();
138 static typename CFG::data_t get_cache_data_for_beat(fsm::fsm_handle* fsm_hndl);
139 unsigned int SNOOP = 3; // TBD??
142 std::array<unsigned, 3> outstanding_cnt{0, 0, 0};
143 std::array<fsm_handle*, 3> active_req{nullptr, nullptr, nullptr};
144 std::array<fsm_handle*, 4> active_resp_beat{nullptr, nullptr, nullptr};
145 sc_core::sc_clock* clk_if{nullptr};
146 sc_core::sc_event clk_delayed, clk_self, r_end_resp_evt, w_end_resp_evt, ac_end_req_evt;
147 void nb_fw(payload_type& trans, const phase_type& phase) {
148 auto t = sc_core::SC_ZERO_TIME;
149 base::nb_fw(trans, phase, t);
150 }
151 tlm_utils::peq_with_cb_and_phase<ace_initiator> fw_peq{this, &ace_initiator::nb_fw};
152 std::unordered_map<unsigned, std::deque<fsm_handle*>> rd_resp_by_id, wr_resp_by_id;
153 struct fifo_entry {
154 tlm::tlm_generic_payload* gp = nullptr;
155 bool last = false;
156 bool needs_end_req = false;
157 size_t beat_num = 0;
158 fifo_entry(tlm::tlm_generic_payload* gp, bool last, bool needs_end_req, size_t beat_num)
159 : gp(gp)
160 , last(last)
161 , needs_end_req(needs_end_req)
162 , beat_num(beat_num) {
163 if(gp->has_mm())
164 gp->acquire();
165 }
166 fifo_entry(tlm::tlm_generic_payload* gp, bool needs_end_req)
167 : gp(gp)
168 , needs_end_req(needs_end_req) {
169 if(gp->has_mm())
170 gp->acquire();
171 }
172 fifo_entry(fifo_entry const& o)
173 : gp(o.gp)
174 , last(o.last)
175 , needs_end_req(o.needs_end_req)
176 , beat_num(o.beat_num) {
177 if(gp && gp->has_mm())
178 gp->acquire();
179 }
180 fifo_entry& operator=(const fifo_entry& o) {
181 gp = o.gp;
182 last = o.last;
183 needs_end_req = o.needs_end_req;
184 beat_num = o.beat_num;
185 return *this;
186 }
187 ~fifo_entry() {
188 if(gp && gp->has_mm())
189 gp->release();
190 }
191 };
192 scc::fifo_w_cb<fifo_entry> ar_fifo{"ar_fifo"};
193 scc::fifo_w_cb<fifo_entry> aw_fifo{"aw_fifo"};
194 scc::fifo_w_cb<fifo_entry> wdata_fifo{"wdata_fifo"};
195 sc_core::sc_event rack_vl;
196 sc_core::sc_event wack_vl;
197 void write_ar(tlm::tlm_generic_payload& trans);
198 void write_aw(tlm::tlm_generic_payload& trans);
199 void write_wdata(tlm::tlm_generic_payload& trans, unsigned beat);
200};
201
202} // namespace pin
203} // namespace axi
204
205template <typename CFG> inline void axi::pin::ace_initiator<CFG>::write_ar(tlm::tlm_generic_payload& trans) {
206 sc_dt::sc_uint<CFG::ADDRWIDTH> addr = trans.get_address();
207 this->ar_addr.write(addr);
208 if(auto ext = trans.get_extension<axi::ace_extension>()) {
209 this->ar_prot.write(ext->get_prot());
210 if(!CFG::IS_LITE) {
211 auto id = ext->get_id();
212 if(!mask_axi_id.get_value() && id >= (1 << CFG::IDWIDTH))
213 SCCERR(SCMOD) << "AWID value larger than signal awid with width=" << CFG::IDWIDTH << " can carry";
214 this->ar_id->write(sc_dt::sc_uint<CFG::IDWIDTH>(id));
215 this->ar_len->write(sc_dt::sc_uint<8>(ext->get_length()));
216 this->ar_size->write(sc_dt::sc_uint<3>(ext->get_size()));
217 this->ar_burst->write(sc_dt::sc_uint<2>(axi::to_int(ext->get_burst())));
218 this->ar_lock->write(ext->is_exclusive());
219 this->ar_cache->write(sc_dt::sc_uint<4>(ext->get_cache()));
220 this->ar_prot.write(ext->get_prot());
221 this->ar_qos->write(ext->get_qos());
222 this->ar_region->write(ext->get_region());
223 this->ar_domain->write(sc_dt::sc_uint<2>((uint8_t)ext->get_domain()));
224 this->ar_snoop->write(sc_dt::sc_uint<4>((uint8_t)ext->get_snoop()));
225 this->ar_bar->write(sc_dt::sc_uint<2>((uint8_t)ext->get_barrier()));
226 this->ar_user->write(ext->get_user(axi::common::id_type::CTRL));
227 }
228 }
229}
230template <typename CFG> inline void axi::pin::ace_initiator<CFG>::write_aw(tlm::tlm_generic_payload& trans) {
231 sc_dt::sc_uint<CFG::ADDRWIDTH> addr = trans.get_address();
232 this->aw_addr.write(addr);
233 if(auto ext = trans.get_extension<axi::ace_extension>()) {
234 this->aw_prot.write(ext->get_prot());
235 this->aw_lock->write(ext->is_exclusive());
236 auto id = ext->get_id();
237 if(!mask_axi_id.get_value() && id >= (1 << CFG::IDWIDTH))
238 SCCERR(SCMOD) << "AWID value larger than signal awid with width=" << CFG::IDWIDTH << " can carry";
239 this->aw_id->write(sc_dt::sc_uint<CFG::IDWIDTH>(id));
240 this->aw_len->write(sc_dt::sc_uint<8>(ext->get_length()));
241 this->aw_size->write(sc_dt::sc_uint<3>(ext->get_size()));
242 this->aw_burst->write(sc_dt::sc_uint<2>(axi::to_int(ext->get_burst())));
243 this->aw_cache->write(sc_dt::sc_uint<4>(ext->get_cache()));
244 this->aw_qos->write(sc_dt::sc_uint<4>(ext->get_qos()));
245 this->aw_region->write(sc_dt::sc_uint<4>(ext->get_region()));
246 this->aw_user->write(ext->get_user(axi::common::id_type::CTRL));
247 this->aw_domain->write(sc_dt::sc_uint<2>((uint8_t)ext->get_domain()));
248 this->aw_snoop->write(sc_dt::sc_uint<CFG::AWSNOOPWIDTH>((uint8_t)ext->get_snoop()));
249 this->aw_bar->write(sc_dt::sc_uint<2>((uint8_t)ext->get_barrier()));
250 this->aw_unique->write(ext->get_unique());
251 }
252}
253
254// FIXME: strb not yet correct
255template <typename CFG> inline void axi::pin::ace_initiator<CFG>::write_wdata(tlm::tlm_generic_payload& trans, unsigned beat) {
256 typename CFG::data_t data{0};
257 typename CFG::strb_t strb{0};
258 auto ext = trans.get_extension<axi::ace_extension>();
259 auto size = 1u << ext->get_size();
260 auto byte_offset = beat * size;
261 auto offset = (trans.get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
262 auto beptr = trans.get_byte_enable_length() ? trans.get_byte_enable_ptr() + byte_offset : nullptr;
263 if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) { // un-aligned multi-beat access
264 if(beat == 0) {
265 auto dptr = trans.get_data_ptr();
266 if(dptr)
267 for(size_t i = offset; i < size; ++i, ++dptr) {
268 auto bit_offs = i * 8;
269 data(bit_offs + 7, bit_offs) = *dptr;
270 if(beptr) {
271 strb[i] = *beptr == 0xff;
272 ++beptr;
273 } else
274 strb[i] = true;
275 }
276 } else {
277 auto beat_start_idx = byte_offset - offset;
278 auto data_len = trans.get_data_length();
279 auto dptr = trans.get_data_ptr() + beat_start_idx;
280 if(dptr)
281 for(size_t i = 0; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr) {
282 auto bit_offs = i * 8;
283 data(bit_offs + 7, bit_offs) = *dptr;
284 if(beptr) {
285 strb[i] = *beptr == 0xff;
286 ++beptr;
287 } else
288 strb[i] = true;
289 }
290 }
291 } else { // aligned or single beat access
292 auto dptr = trans.get_data_ptr() + byte_offset;
293 if(dptr)
294 for(size_t i = 0; i < size; ++i, ++dptr) {
295 auto bit_offs = (offset + i) * 8;
296 data(bit_offs + 7, bit_offs) = *dptr;
297 if(beptr) {
298 strb[offset + i] = *beptr == 0xff;
299 ++beptr;
300 } else
301 strb[offset + i] = true;
302 }
303 }
304 this->w_data.write(data);
305 this->w_strb.write(strb);
306 if(!CFG::IS_LITE) {
307 this->w_id->write(ext->get_id());
308 if(this->w_user.get_interface())
309 this->w_user->write(ext->get_user(axi::common::id_type::DATA));
310 }
311}
312
313template <typename CFG> typename CFG::data_t axi::pin::ace_initiator<CFG>::get_cache_data_for_beat(fsm_handle* fsm_hndl) {
314 auto beat_count = fsm_hndl->beat_count;
315 // SCCTRACE(SCMOD) << " " ;
316 auto size = axi::get_burst_size(*fsm_hndl->trans);
317 auto byte_offset = beat_count * size;
318 auto offset = (fsm_hndl->trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
319 typename CFG::data_t data{0};
320 if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) { // un-aligned multi-beat access
321 if(beat_count == 0) {
322 auto dptr = fsm_hndl->trans->get_data_ptr();
323 for(size_t i = offset; i < size; ++i, ++dptr) {
324 auto bit_offs = i * 8;
325 data(bit_offs + 7, bit_offs) = *dptr;
326 }
327 } else {
328 auto beat_start_idx = byte_offset - offset;
329 auto data_len = fsm_hndl->trans->get_data_length();
330 auto dptr = fsm_hndl->trans->get_data_ptr() + beat_start_idx;
331 for(size_t i = offset; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr) {
332 auto bit_offs = i * 8;
333 data(bit_offs + 7, bit_offs) = *dptr;
334 }
335 }
336 } else { // aligned or single beat access
337 auto dptr = fsm_hndl->trans->get_data_ptr() + byte_offset;
338 for(size_t i = 0; i < size; ++i, ++dptr) {
339 auto bit_offs = (offset + i) * 8;
340 data(bit_offs + 7, bit_offs) = *dptr;
341 }
342 }
343 return data;
344}
345
346template <typename CFG> inline void axi::pin::ace_initiator<CFG>::setup_callbacks(fsm_handle* fsm_hndl) {
347 fsm_hndl->fsm->cb[RequestPhaseBeg] = [this, fsm_hndl]() -> void {
348 if(fsm_hndl->is_snoop) {
349 SCCTRACE(SCMOD) << " for snoop in RequestPhaseBeg ";
350 } else {
351 fsm_hndl->beat_count = 0;
352 outstanding_cnt[fsm_hndl->trans->get_command()]++;
353 if(CFG::IS_LITE) {
354 auto offset = fsm_hndl->trans->get_address() % (CFG::BUSWIDTH / 8);
355 if(offset + fsm_hndl->trans->get_data_length() > CFG::BUSWIDTH / 8) {
356 SCCFATAL(SCMOD) << " transaction " << *fsm_hndl->trans << " is not AXI4Lite compliant";
357 }
358 }
359 }
360 };
361 fsm_hndl->fsm->cb[BegPartReqE] = [this, fsm_hndl]() -> void {
362 sc_assert(fsm_hndl->trans->is_write());
363 if(fsm_hndl->beat_count == 0) {
364 aw_fifo.push_back({fsm_hndl->trans.get(), false});
365 }
366 wdata_fifo.push_back({fsm_hndl->trans.get(), false, wdata_fifo.num_avail() > 0, fsm_hndl->beat_count});
367 if(pipelined_wrreq && !wdata_fifo.num_avail())
368 schedule(EndPartReqE, fsm_hndl->trans, sc_core::SC_ZERO_TIME);
369 };
370 fsm_hndl->fsm->cb[EndPartReqE] = [this, fsm_hndl]() -> void {
371 tlm::tlm_phase phase = axi::END_PARTIAL_REQ;
372 sc_core::sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : sc_core::SC_ZERO_TIME);
373 auto ret = tsckt->nb_transport_bw(*fsm_hndl->trans, phase, t);
374 fsm_hndl->beat_count++;
375 };
376 fsm_hndl->fsm->cb[BegReqE] = [this, fsm_hndl]() -> void {
377 if(fsm_hndl->is_snoop) {
378 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
379 tlm::tlm_phase phase = tlm::BEGIN_REQ;
380 auto ret = tsckt->nb_transport_bw(*fsm_hndl->trans, phase, t);
381 } else {
382 switch(fsm_hndl->trans->get_command()) {
383 case tlm::TLM_READ_COMMAND:
384 ar_fifo.push_back({fsm_hndl->trans.get(), false});
385 break;
386 case tlm::TLM_WRITE_COMMAND:
387 if(fsm_hndl->beat_count == 0) {
388 aw_fifo.push_back({fsm_hndl->trans.get(), false});
389 }
390 /* for Evict Trans, only addr on aw_t, response on b_t() */
391 if(!axi::is_dataless(fsm_hndl->trans->get_extension<ace_extension>())) {
392 wdata_fifo.push_back({fsm_hndl->trans.get(), true, wdata_fifo.num_avail() > 0, fsm_hndl->beat_count});
393 if(pipelined_wrreq && !wdata_fifo.num_avail())
394 schedule(EndReqE, fsm_hndl->trans, sc_core::SC_ZERO_TIME);
395 }
396 }
397 }
398 };
399 fsm_hndl->fsm->cb[EndReqE] = [this, fsm_hndl]() -> void {
400 if(fsm_hndl->is_snoop) {
401 active_req[SNOOP] = nullptr;
402 ac_end_req_evt.notify(); // if snoop
403 } else {
404 auto id = axi::get_axi_id(*fsm_hndl->trans);
405 if(mask_axi_id.get_value())
406 id &= (1UL << CFG::IDWIDTH) - 1;
407 switch(fsm_hndl->trans->get_command()) {
408 case tlm::TLM_READ_COMMAND:
409 rd_resp_by_id[id].push_back(fsm_hndl);
410 break;
411 case tlm::TLM_WRITE_COMMAND:
412 wr_resp_by_id[id].push_back(fsm_hndl);
413 fsm_hndl->beat_count++;
414 }
415 tlm::tlm_phase phase = tlm::END_REQ;
416 sc_core::sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : sc_core::SC_ZERO_TIME);
417 auto ret = tsckt->nb_transport_bw(*fsm_hndl->trans, phase, t);
418 fsm_hndl->trans->set_response_status(tlm::TLM_OK_RESPONSE);
419 }
420 };
421 fsm_hndl->fsm->cb[BegPartRespE] = [this, fsm_hndl]() -> void {
422 if(fsm_hndl->is_snoop) {
423 active_resp_beat[SNOOP] = fsm_hndl;
424 cd_vl.notify({1, fsm_hndl});
425
426 } else {
427 // scheduling the response
428 assert(fsm_hndl->trans->is_read());
429 tlm::tlm_phase phase = axi::BEGIN_PARTIAL_RESP;
430 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
431 auto ret = tsckt->nb_transport_bw(*fsm_hndl->trans, phase, t);
432 }
433 };
434 fsm_hndl->fsm->cb[EndPartRespE] = [this, fsm_hndl]() -> void {
435 if(fsm_hndl->is_snoop) {
436 tlm::tlm_phase phase = axi::END_PARTIAL_RESP;
437 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
438 auto ret = tsckt->nb_transport_bw(*fsm_hndl->trans, phase, t);
439 // why here nullptr??
440 active_resp_beat[SNOOP] = nullptr;
441 fsm_hndl->beat_count++;
442 } else {
443 fsm_hndl->beat_count++;
444 r_end_resp_evt.notify();
445 }
446 };
447 fsm_hndl->fsm->cb[BegRespE] = [this, fsm_hndl]() -> void {
448 if(fsm_hndl->is_snoop) {
449 active_resp_beat[SNOOP] = fsm_hndl;
450 cd_vl.notify({3, fsm_hndl}); // TBD??
451 cr_resp_vl.notify({3, fsm_hndl});
452
453 } else {
454 // scheduling the response
455 tlm::tlm_phase phase = tlm::BEGIN_RESP;
456 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
457 auto ret = tsckt->nb_transport_bw(*fsm_hndl->trans, phase, t);
458 }
459 };
460 fsm_hndl->fsm->cb[EndRespE] = [this, fsm_hndl]() -> void {
461 if(fsm_hndl->is_snoop) {
462 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
463 tlm::tlm_phase phase = tlm::END_RESP;
464 auto ret = tsckt->nb_transport_bw(*fsm_hndl->trans, phase, t);
465 active_resp_beat[SNOOP] = nullptr;
466 // here notify cr_evnt
467 fsm_hndl->finish.notify();
468 } else {
469 if(fsm_hndl->trans->is_read()) {
470 rd_resp_by_id[axi::get_axi_id(*fsm_hndl->trans)].pop_front();
471 r_end_resp_evt.notify();
472 } else if(fsm_hndl->trans->is_write()) {
473 wr_resp_by_id[axi::get_axi_id(*fsm_hndl->trans)].pop_front();
474 w_end_resp_evt.notify();
475 }
476 }
477 };
478 fsm_hndl->fsm->cb[Ack] = [this, fsm_hndl]() -> void {
479 SCCTRACE(SCMOD) << "in ACK of setup_cb for " << *fsm_hndl->trans;
480 if(fsm_hndl->trans->is_read()) {
481 rack_vl.notify(sc_core::SC_ZERO_TIME);
482 }
483 if(fsm_hndl->trans->is_write()) {
484 wack_vl.notify(sc_core::SC_ZERO_TIME);
485 }
486 };
487}
488
489template <typename CFG> inline void axi::pin::ace_initiator<CFG>::rack_t() {
490 this->r_ack.write(false);
491 wait(sc_core::SC_ZERO_TIME);
492 while(true) {
493 wait(rack_vl);
494 this->r_ack.write(true);
495 wait(clk_i.posedge_event());
496 this->r_ack.write(false);
497 }
498}
499
500template <typename CFG> inline void axi::pin::ace_initiator<CFG>::wack_t() {
501 this->w_ack.write(false);
502 wait(sc_core::SC_ZERO_TIME);
503 while(true) {
504 wait(wack_vl);
505 this->w_ack.write(true);
506 wait(clk_i.posedge_event());
507 this->w_ack.write(false);
508 }
509}
510
511template <typename CFG> inline void axi::pin::ace_initiator<CFG>::ar_t() {
512 this->ar_valid.write(false);
513 wait(sc_core::SC_ZERO_TIME);
514 while(true) {
515 auto val = ar_fifo.read();
516 write_ar(*val.gp);
517 this->ar_valid.write(true);
518 do {
519 wait(this->ar_ready.posedge_event() | clk_delayed);
520 if(this->ar_ready.read())
521 react(axi::fsm::protocol_time_point_e::EndReqE, val.gp);
522 } while(!this->ar_ready.read());
523 wait(clk_i.posedge_event());
524 this->ar_valid.write(false);
525 }
526}
527
528template <typename CFG> inline void axi::pin::ace_initiator<CFG>::r_t() {
529 this->r_ready.write(false);
530 wait(sc_core::SC_ZERO_TIME);
531 while(true) {
532 wait(clk_delayed);
533 while(!this->r_valid.read()) {
534 wait(this->r_valid.posedge_event());
535 wait(CLK_DELAY); // verilator might create spurious events
536 }
537 auto id = CFG::IS_LITE ? 0U : this->r_id->read().to_uint();
538 auto data = this->r_data.read();
539 auto resp = this->r_resp.read();
540 auto& q = rd_resp_by_id[id];
541 sc_assert(q.size() && "No transaction found for received id");
542 auto* fsm_hndl = q.front();
543 auto beat_count = fsm_hndl->beat_count;
544 auto size = axi::get_burst_size(*fsm_hndl->trans);
545 auto byte_offset = beat_count * size;
546 auto offset = (fsm_hndl->trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
547 if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) { // un-aligned multi-beat access
548 if(beat_count == 0) {
549 auto dptr = fsm_hndl->trans->get_data_ptr();
550 if(dptr)
551 for(size_t i = offset; i < size; ++i, ++dptr) {
552 auto bit_offs = i * 8;
553 *dptr = data(bit_offs + 7, bit_offs).to_uint();
554 }
555 } else {
556 auto beat_start_idx = beat_count * size - offset;
557 auto data_len = fsm_hndl->trans->get_data_length();
558 auto dptr = fsm_hndl->trans->get_data_ptr() + beat_start_idx;
559 if(dptr)
560 for(size_t i = 0; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr) {
561 auto bit_offs = i * 8;
562 *dptr = data(bit_offs + 7, bit_offs).to_uint();
563 }
564 }
565 } else { // aligned or single beat access
566 auto dptr = fsm_hndl->trans->get_data_ptr() + beat_count * size;
567 if(dptr)
568 for(size_t i = 0; i < size; ++i, ++dptr) {
569 auto bit_offs = (offset + i) * 8;
570 *dptr = data(bit_offs + 7, bit_offs).to_uint();
571 }
572 }
574 fsm_hndl->trans->get_extension(e);
575 e->set_cresp(resp);
577 /* for Make Trans, Clean Trans and Read barrier Trans, no read data transfer on r_t, only response on r_t
578 * */
579 if(axi::is_dataless(e)) {
580 SCCTRACE(SCMOD) << " r_t() for Make/Clean/Barrier Trans" << *fsm_hndl->trans;
581 react(axi::fsm::protocol_time_point_e::BegRespE, fsm_hndl);
582 } else {
583 auto tp = CFG::IS_LITE || this->r_last->read() ? axi::fsm::protocol_time_point_e::BegRespE
584 : axi::fsm::protocol_time_point_e::BegPartRespE;
585 react(tp, fsm_hndl);
586 }
587 wait(r_end_resp_evt);
588 this->r_ready.write(true);
589 wait(clk_i.posedge_event());
590 this->r_ready.write(false);
591 }
592}
593
594template <typename CFG> inline void axi::pin::ace_initiator<CFG>::aw_t() {
595 this->aw_valid.write(false);
596 wait(sc_core::SC_ZERO_TIME);
597 while(true) {
598 auto val = aw_fifo.read();
599 write_aw(*val.gp);
600 this->aw_valid.write(true);
601 do {
602 wait(this->aw_ready.posedge_event() | clk_delayed);
603 } while(!this->aw_ready.read());
604 if(axi::is_dataless(val.gp->template get_extension<axi::ace_extension>()))
605 schedule(axi::fsm::protocol_time_point_e::EndReqE, val.gp, sc_core::SC_ZERO_TIME);
606 wait(clk_i.posedge_event());
607 this->aw_valid.write(false);
608 }
609}
610
611template <typename CFG> inline void axi::pin::ace_initiator<CFG>::wdata_t() {
612 this->w_valid.write(false);
613 wait(sc_core::SC_ZERO_TIME);
614 while(true) {
615 if(!CFG::IS_LITE)
616 this->w_last->write(false);
617 if(pipelined_wrreq) {
618 while(!wdata_fifo.num_avail()) {
619 wait(clk_i.posedge_event());
620 }
621 } else {
622 wait(wdata_fifo.data_written_event());
623 }
624 auto val = wdata_fifo.front();
625 wdata_fifo.pop_front();
626 write_wdata(*val.gp, val.beat_num);
627 if(pipelined_wrreq && val.needs_end_req) {
628 auto evt = CFG::IS_LITE || (val.last) ? axi::fsm::protocol_time_point_e::EndReqE : axi::fsm::protocol_time_point_e::EndPartReqE;
629 schedule(evt, val.gp, sc_core::SC_ZERO_TIME);
630 }
631 this->w_valid.write(true);
632 if(!CFG::IS_LITE)
633 this->w_last->write(val.last);
634 do {
635 wait(this->w_ready.posedge_event() | clk_delayed);
636 if(!pipelined_wrreq && this->w_ready.read()) {
637 auto evt = val.last ? axi::fsm::protocol_time_point_e::EndReqE : axi::fsm::protocol_time_point_e::EndPartReqE;
638 schedule(evt, val.gp, sc_core::SC_ZERO_TIME);
639 }
640 } while(!this->w_ready.read());
641 wait(clk_i.posedge_event());
642 this->w_valid.write(false);
643 }
644}
645
646template <typename CFG> inline void axi::pin::ace_initiator<CFG>::b_t() {
647 this->b_ready.write(false);
648 wait(sc_core::SC_ZERO_TIME);
649 while(true) {
650 wait(clk_delayed);
651 while(!this->b_valid.read()) {
652 wait(this->b_valid.posedge_event());
653 wait(CLK_DELAY); // verilator might create spurious events
654 }
655 auto id = !CFG::IS_LITE ? this->b_id->read().to_uint() : 0U;
656 auto resp = this->b_resp.read();
657 auto& q = wr_resp_by_id[id];
658 sc_assert(q.size());
659 auto* fsm_hndl = q.front();
661 fsm_hndl->trans->get_extension(e);
663 react(axi::fsm::protocol_time_point_e::BegRespE, fsm_hndl);
664 wait(w_end_resp_evt);
665 this->b_ready.write(true);
666 wait(clk_i.posedge_event());
667 this->b_ready.write(false);
668 }
669}
670
671template <typename CFG> inline void axi::pin::ace_initiator<CFG>::ac_t() {
672 this->ac_ready.write(false);
673 wait(sc_core::SC_ZERO_TIME);
674 auto arid = 0U;
675 // A snoop transaction must be a full cache line in length,
676 // here cachelinesize in byte, -1 because last beat in Resp transmitted
677 auto arlen = ((CACHELINE_SZ - 1) / CFG::BUSWIDTH / 8);
678 auto arsize = util::ilog2(CFG::BUSWIDTH / 8);
679 // here +1 because last beat in Resp transmitted
680 auto data_len = (1 << arsize) * (arlen + 1);
681 while(true) {
682 wait(clk_delayed);
683 while(!this->ac_valid.read()) {
684 wait(this->ac_valid.posedge_event());
685 wait(CLK_DELAY); // verilator might create spurious events
686 }
687 SCCTRACE(SCMOD) << "ACVALID detected, for address 0x" << std::hex << this->ac_addr.read();
688 SCCTRACE(SCMOD) << "in ac_t(), create snoop trans with data_len= " << data_len;
689 auto gp = tlm::scc::tlm_mm<>::get().allocate<axi::ace_extension>(data_len, true);
690 gp->set_address(this->ac_addr.read());
691 gp->set_command(tlm::TLM_READ_COMMAND); // snoop command
692 gp->set_streaming_width(data_len);
694 gp->get_extension(ext);
695 // if cacheline smaller than buswidth, beat num=1
696 if(data_len == (CFG::BUSWIDTH / 8))
697 arlen = 1;
698 ext->set_length(arlen);
699 ext->set_size(arsize);
700 ext->set_snoop(axi::into<axi::snoop_e>(this->ac_snoop->read()));
701 ext->set_prot(this->ac_prot->read());
702 /*snoop transaction of burst length greater than one must be of burst type WRAP.
703 * A snoop transaction of burst length one must be of burst type INCR
704 */
705 ext->set_burst((CACHELINE_SZ * 8) > CFG::BUSWIDTH ? axi::burst_e::WRAP : axi::burst_e::INCR);
706 active_req[SNOOP] = find_or_create(gp, true);
707 active_req[SNOOP]->is_snoop = true;
708 react(axi::fsm::protocol_time_point_e::RequestPhaseBeg, active_req[SNOOP]);
709 // ac_end_req_evt notified in EndReqE
710 wait(ac_end_req_evt);
711 this->ac_ready.write(true);
712 wait(clk_i.posedge_event());
713 this->ac_ready.write(false);
714 }
715}
716
717template <typename CFG> inline void axi::pin::ace_initiator<CFG>::cd_t() {
718 this->cd_valid.write(false);
719 wait(sc_core::SC_ZERO_TIME);
720 fsm_handle* fsm_hndl;
721 uint8_t val;
722 while(true) {
723 // cd_vl notified in BEGIN_PARTIAL_REQ ( val=1 ??)or in BEG_RESP(val=3??)
724 std::tie(val, fsm_hndl) = cd_vl.get();
725 SCCTRACE(SCMOD) << __FUNCTION__ << " val = " << (uint16_t)val << " beat_count = " << fsm_hndl->beat_count;
726 SCCTRACE(SCMOD) << __FUNCTION__ << " got snoop beat of trans " << *fsm_hndl->trans;
727 // data already packed in Trans in END_REQ via calling operation_cb
728 auto ext = fsm_hndl->trans->get_extension<axi::ace_extension>();
729 this->cd_data.write(get_cache_data_for_beat(fsm_hndl));
730 this->cd_valid.write(val & 0x1);
731 SCCTRACE(SCMOD) << __FUNCTION__ << "() write cd_valid high ";
732 this->cd_last->write(val & 0x2);
733 do {
734 wait(this->cd_ready.posedge_event() | clk_delayed);
735 if(this->cd_ready.read()) {
736 auto evt =
737 CFG::IS_LITE || (val & 0x2) ? axi::fsm::protocol_time_point_e::EndRespE : axi::fsm::protocol_time_point_e::EndPartRespE;
738
739 // here only schedule EndPartResp for cache data because EndResp is scheduled in cr_resp_t() when last beat is transferred
740 if(!(val & 0x2)) { // BEGIN_PARTIAL_REQ ( val=1 ) or in BEG_RESP(val=3)
741 SCCTRACE(SCMOD) << __FUNCTION__ << "() receives cd_ready high, schedule evt " << evt2str(evt);
742 react(evt, active_resp_beat[SNOOP]);
743 }
744 }
745 } while(!this->cd_ready.read());
746 SCCTRACE(SCMOD) << __FUNCTION__ << " finished snoop beat of trans [" << fsm_hndl->trans << "]";
747 wait(clk_i.posedge_event());
748 this->cd_valid.write(false);
749 if(val & 0x2) // if last beat, after one clock cd_last shouldbe low
750 this->cd_last->write(false);
751 }
752}
753template <typename CFG> inline void axi::pin::ace_initiator<CFG>::cr_resp_t() {
754 this->cr_valid.write(false);
755 wait(sc_core::SC_ZERO_TIME);
756 fsm_handle* fsm_hndl;
757 uint8_t val;
758 while(true) {
759 // cr_resp_vl notified in BEG_RESP(val=3??)
760 std::tie(val, fsm_hndl) = cr_resp_vl.get();
761 SCCTRACE(SCMOD) << __FUNCTION__ << " (), generate snoop response in cr channel, val = " << (uint16_t)val
762 << " total beat_num = " << fsm_hndl->beat_count;
763 // data already packed in Trans in END_REQ via bw_o
764 auto ext = fsm_hndl->trans->get_extension<axi::ace_extension>();
765 this->cr_resp.write((ext->get_cresp()));
766 this->cr_valid.write(true);
767 do {
768 wait(this->cr_ready.posedge_event() | clk_delayed);
769 if(this->cr_ready.read()) {
770 auto evt = axi::fsm::protocol_time_point_e::EndRespE;
771 SCCTRACE(SCMOD) << __FUNCTION__ << "(), schedule EndRespE ";
772 react(evt, active_resp_beat[SNOOP]);
773 }
774 } while(!this->cr_ready.read());
775 SCCTRACE(SCMOD) << "finished snoop response ";
776 wait(clk_i.posedge_event());
777 this->cr_valid.write(false);
778 }
779}
780
781#endif /* _BUS_AXI_PIN_ACE_INITIATOR_H_ */
fifo with callbacks
Definition fifo_w_cb.h:38
payload_type * allocate()
get a plain tlm_payload_type without extensions
Definition tlm_mm.h:218
T * get() const noexcept
Return the stored pointer.
pin level adapters
TLM2.0 components modeling AHB.
E into(typename std::underlying_type< E >::type t)
tlm::tlm_fw_transport_if< TYPES > ace_fw_transport_if
alias declaration for the ACE forward interface
Definition axi_tlm.h:958
constexpr ULT to_int(E t)
Definition axi_tlm.h:47
wdata_axi< CFG, TYPES > wdata_ace
alias declaration for rresp_ch_ace, wdata_ch_ace, b_ch_ace???
Definition signal_if.h:713
unsigned get_burst_size(const request &r)
Definition axi_tlm.h:1202
CONSTEXPR unsigned ilog2(uint32_t val)
Definition ities.h:235
void set_cresp(uint8_t)
set the coherent response status
Definition axi_tlm.h:1603
uint8_t get_cresp() const
get the coherent response status
Definition axi_tlm.h:1605
void set_snoop(snoop_e)
set the AxSNOOP value
Definition axi_tlm.h:1517
void add_to_response_array(response &)
add a read response to the response array
Definition axi_tlm.h:1670
base class of all AXITLM based adapters and interfaces.
Definition base.h:43
tlm::tlm_sync_enum nb_fw(payload_type &trans, phase_type const &phase, sc_core::sc_time &t)
triggers the FSM based on TLM phases in the forward path. Should be called from np_transport_fw of th...
Definition base.cpp:190
virtual axi::fsm::fsm_handle * create_fsm_handle()=0
function to create a fsm_handle. Needs to be implemented by the derived class
base(size_t transfer_width, bool coherent=false, axi::fsm::protocol_time_point_e wr_start=axi::fsm::RequestPhaseBeg)
the constructor
Definition base.cpp:43
tlm::scc::tlm_gp_shared_ptr trans
pointer to the associated AXITLM payload
Definition types.h:62
sc_core::sc_event finish
event indicating the end of the transaction
Definition types.h:68
size_t beat_count
beat count of this transaction
Definition types.h:64
AxiProtocolFsm *const fsm
pointer to the FSM
Definition types.h:60
bool is_snoop
indicator if this is a snoop access
Definition types.h:66
void set_length(uint8_t)
set the AxLEN value of the transaction, the value denotes the burst length - 1
Definition axi_tlm.h:1452
void set_burst(burst_e)
set the AxBURST value,
Definition axi_tlm.h:1463
void set_size(uint8_t)
get the AxSIZE value of the transaction, the length is 2^size. It needs to be less than 10 (512 bit w...
Definition axi_tlm.h:1456
void set_prot(uint8_t)
set the AxPROT value as POD, only values from 0...7 are allowed
Definition axi_tlm.h:1467
void set_resp(resp_e)
set the response status as POD
Definition axi_tlm.h:1572
priority event queue
Definition peq.h:41
static tlm_mm & get()
accessor function of the singleton
Definition tlm_mm.h:338