scc  2024.06
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 <cci_configuration>
24 #include <interfaces/axi/signal_if.h>
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 
31 namespace axi {
33 namespace pin {
34 
35 using namespace axi::fsm;
36 
37 template <typename CFG>
38 struct 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 
87 private:
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 
205 template <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 }
230 template <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
255 template <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 
313 template <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 
346 template <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 
489 template <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 
500 template <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 
511 template <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 
528 template <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);
576  e->add_to_response_array(*e);
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 
594 template <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 
611 template <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 
646 template <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);
662  e->set_resp(axi::into<axi::resp_e>(resp));
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 
671 template <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);
693  axi::ace_extension* ext;
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 
717 template <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 }
753 template <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_ */
payload_type * allocate()
get a plain tlm_payload_type without extensions
Definition: tlm_mm.h:185
T * get() const noexcept
Return the stored pointer.
Definition: tlm_gp_shared.h:91
TLM2.0 components modeling AHB.
Definition: axi_initiator.h:30
constexpr ULT to_int(E t)
Definition: axi_tlm.h:47
unsigned get_burst_size(const request &r)
Definition: axi_tlm.h:1202
tlm::tlm_fw_transport_if< TYPES > ace_fw_transport_if
alias declaration for the ACE forward interface
Definition: axi_tlm.h:958
CONSTEXPR unsigned ilog2(uint32_t val)
Definition: ities.h:194
snoop address(AC) channel signals
Definition: signal_if.h:636
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
snoop data(cd) channel signals
Definition: signal_if.h:665
snoop response(cr) channel signals
Definition: signal_if.h:687
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
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:293