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