scc  2022.4.0
SystemC components library
ace_target.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_TARGET_H_
18 #define _BUS_AXI_PIN_ACE_TARGET_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 <util/ities.h>
27 
29 namespace axi {
31 namespace pin {
32 
33 using namespace axi::fsm;
34 
35 template <typename CFG>
36 struct ace_target : public sc_core::sc_module,
37  public aw_ace<CFG, typename CFG::slave_types>,
38  public wdata_ace<CFG, typename CFG::slave_types>,
39  public b_ace<CFG, typename CFG::slave_types>,
40  public ar_ace<CFG, typename CFG::slave_types>,
41  public rresp_ace<CFG, typename CFG::slave_types>,
42 
43  public ac_ace<CFG, typename CFG::slave_types>,
44  public cr_ace<CFG, typename CFG::slave_types>,
45  public cd_ace<CFG, typename CFG::slave_types>,
46 
47  protected axi::fsm::base,
48  public axi::ace_bw_transport_if<axi::axi_protocol_types> {
49  SC_HAS_PROCESS(ace_target);
50 
51  using payload_type = axi::axi_protocol_types::tlm_payload_type;
52  using phase_type = axi::axi_protocol_types::tlm_phase_type;
53 
54  sc_core::sc_in<bool> clk_i{"clk_i"};
55 
57 
58  ace_target(sc_core::sc_module_name const& nm)
59  : sc_core::sc_module(nm)
60  // coherent= true
61  , base(CFG::BUSWIDTH, true) {
62  instance_name = name();
63  isckt.bind(*this);
64  SC_METHOD(clk_delay);
65  sensitive << clk_i.pos();
66  dont_initialize();
67  SC_THREAD(ar_t);
68  SC_THREAD(rresp_t);
69  SC_THREAD(aw_t);
70  SC_THREAD(wdata_t);
71  SC_THREAD(bresp_t);
72  SC_THREAD(ac_t);
73  SC_THREAD(cr_t);
74  SC_THREAD(cd_t);
75  }
76 
77 private:
78  tlm::tlm_sync_enum nb_transport_bw(payload_type& trans, phase_type& phase, sc_core::sc_time& t) override;
79  void b_snoop(payload_type& trans, sc_core::sc_time& t) override{};
80 
81  void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, sc_dt::uint64 end_range) override;
82 
83  void end_of_elaboration() override { clk_if = dynamic_cast<sc_core::sc_clock*>(clk_i.get_interface()); }
84 
85  axi::fsm::fsm_handle* create_fsm_handle() override { return new fsm_handle(); }
86 
87  void setup_callbacks(axi::fsm::fsm_handle*) override;
88 
94  unsigned snoop_latency{1};
95 
96  void clk_delay() {
97 #ifdef DELTA_SYNC
98  if(sc_core::sc_delta_count_at_current_time() < 5) {
99  clk_self.notify(sc_core::SC_ZERO_TIME);
100  next_trigger(clk_self);
101  } else
102  clk_delayed.notify(sc_core::SC_ZERO_TIME /*clk_if ? clk_if->period() - 1_ps : 1_ps*/);
103 #else
104  clk_delayed.notify(axi::CLK_DELAY);
105 #endif
106  }
107  void ar_t();
108  void rresp_t();
109  void aw_t();
110  void wdata_t();
111  void bresp_t();
112  void ac_t();
113  void cr_t();
114  void cd_t();
115  static typename CFG::data_t get_read_data_for_beat(fsm::fsm_handle* fsm_hndl);
116  struct aw_data {
117  unsigned id;
118  uint64_t addr;
119  unsigned prot;
120  unsigned size;
121  unsigned cache;
122  unsigned burst;
123  unsigned qos;
124  unsigned region;
125  unsigned len;
126  unsigned domain;
127  unsigned snoop;
128  unsigned bar;
129  unsigned unique;
130  bool lock;
131  uint64_t user;
132  };
133 
134  std::deque<axi::fsm::fsm_handle*> snp_resp_queue;
135 
136  sc_core::sc_clock* clk_if{nullptr};
137  sc_core::sc_event clk_delayed, clk_self, ar_end_req_evt, wdata_end_req_evt, ac_evt, cd_end_req_evt, cr_end_req_evt;
138  std::array<fsm_handle*, 3> active_req_beat{nullptr, nullptr, nullptr};
139  std::array<fsm_handle*, 4> active_req{nullptr, nullptr, nullptr};
140  std::array<fsm_handle*, 3> active_resp_beat{nullptr, nullptr, nullptr};
141  scc::peq<aw_data> aw_que;
144  scc::peq<std::tuple<uint8_t, fsm_handle*>> cr_vl; // snoop response
145 
146  unsigned int SNOOP = 3; // TBD??
147  void write_ac(tlm::tlm_generic_payload& trans);
148 };
149 
150 } // namespace pin
151 } // namespace axi
152 
153 template <typename CFG>
154 inline tlm::tlm_sync_enum axi::pin::ace_target<CFG>::nb_transport_bw(payload_type& trans, phase_type& phase, sc_core::sc_time& t) {
155  auto ret = tlm::TLM_ACCEPTED;
156  SCCTRACE(SCMOD) << "nb_transport_bw with " << phase << " with delay= " << t << " of trans " << trans;
157  if(phase == END_PARTIAL_REQ || phase == tlm::END_REQ) { // read/write
158  schedule(phase == tlm::END_REQ ? EndReqE : EndPartReqE, &trans, t, false);
159  } else if(phase == axi::BEGIN_PARTIAL_RESP || phase == tlm::BEGIN_RESP) { // read/write response
160  schedule(phase == tlm::BEGIN_RESP ? BegRespE : BegPartRespE, &trans, t, false);
161  } else if(phase == tlm::BEGIN_REQ) { // snoop read
162  auto fsm_hndl = find_or_create(&trans, true);
163  fsm_hndl->is_snoop = true;
164  schedule(BegReqE, &trans, t);
165  } else if(phase == END_PARTIAL_RESP || phase == tlm::END_RESP) { // snoop read response
166  schedule(phase == tlm::END_RESP ? EndRespE : EndPartRespE, &trans, t);
167  }
168  return ret;
169 }
170 
171 template <typename CFG>
172 inline void axi::pin::ace_target<CFG>::invalidate_direct_mem_ptr(sc_dt::uint64 start_range, sc_dt::uint64 end_range) {}
173 
174 template <typename CFG> typename CFG::data_t axi::pin::ace_target<CFG>::get_read_data_for_beat(fsm_handle* fsm_hndl) {
175  auto beat_count = fsm_hndl->beat_count;
176  // SCCTRACE(SCMOD) << " " ;
177  auto size = axi::get_burst_size(*fsm_hndl->trans);
178  auto byte_offset = beat_count * size;
179  auto offset = (fsm_hndl->trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
180  typename CFG::data_t data{0};
181  if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) { // un-aligned multi-beat access
182  if(beat_count == 0) {
183  auto dptr = fsm_hndl->trans->get_data_ptr();
184  for(size_t i = offset; i < size; ++i, ++dptr) {
185  auto bit_offs = i * 8;
186  data(bit_offs + 7, bit_offs) = *dptr;
187  }
188  } else {
189  auto beat_start_idx = byte_offset - offset;
190  auto data_len = fsm_hndl->trans->get_data_length();
191  auto dptr = fsm_hndl->trans->get_data_ptr() + beat_start_idx;
192  for(size_t i = offset; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr) {
193  auto bit_offs = i * 8;
194  data(bit_offs + 7, bit_offs) = *dptr;
195  }
196  }
197  } else { // aligned or single beat access
198  auto dptr = fsm_hndl->trans->get_data_ptr() + byte_offset;
199  for(size_t i = 0; i < size; ++i, ++dptr) {
200  auto bit_offs = (offset + i) * 8;
201  data(bit_offs + 7, bit_offs) = *dptr;
202  }
203  }
204  return data;
205 }
206 
207 template <typename CFG> inline void axi::pin::ace_target<CFG>::setup_callbacks(fsm_handle* fsm_hndl) {
208  fsm_hndl->fsm->cb[RequestPhaseBeg] = [this, fsm_hndl]() -> void { fsm_hndl->beat_count = 0; };
209  fsm_hndl->fsm->cb[BegPartReqE] = [this, fsm_hndl]() -> void {
210  sc_assert(fsm_hndl->trans->get_command() == tlm::TLM_WRITE_COMMAND);
211  tlm::tlm_phase phase = axi::BEGIN_PARTIAL_REQ;
212  sc_core::sc_time t(sc_core::SC_ZERO_TIME);
213  auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
214  if(ret == tlm::TLM_UPDATED) {
215  schedule(EndPartReqE, fsm_hndl->trans, t, true);
216  }
217  };
218  fsm_hndl->fsm->cb[EndPartReqE] = [this, fsm_hndl]() -> void {
219  wdata_end_req_evt.notify();
220  active_req_beat[tlm::TLM_WRITE_COMMAND] = nullptr;
221  fsm_hndl->beat_count++;
222  };
223  fsm_hndl->fsm->cb[BegReqE] = [this, fsm_hndl]() -> void {
224  if(fsm_hndl->is_snoop) {
225  SCCTRACE(SCMOD) << "in BegReq of setup_cb, call write_ac() ";
226  active_req[SNOOP] = fsm_hndl;
227  write_ac(*fsm_hndl->trans);
228  ac_evt.notify(sc_core::SC_ZERO_TIME);
229 
230  } else {
231  tlm::tlm_phase phase = tlm::BEGIN_REQ;
232  sc_core::sc_time t(sc_core::SC_ZERO_TIME);
233  auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
234  if(ret == tlm::TLM_UPDATED) {
235  schedule(EndReqE, fsm_hndl->trans, t, true);
236  }
237  }
238  };
239 
240  fsm_hndl->fsm->cb[EndReqE] = [this, fsm_hndl]() -> void {
241  if(fsm_hndl->is_snoop) {
242  SCCTRACE(SCMOD) << "snoop with EndReq evt";
243  auto latency = 0;
244  snp_resp_queue.push_back(fsm_hndl);
245  active_req[SNOOP] = nullptr;
246  tlm::tlm_phase phase = tlm::END_REQ;
247  // ?? here t(delay) should be zero or clock cycle??
248  // sc_core::sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : sc_core::SC_ZERO_TIME);
249  sc_core::sc_time t(sc_core::SC_ZERO_TIME);
250  auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
251  auto exta = fsm_hndl->trans->get_extension<ace_extension>();
252  fsm_hndl->trans->set_response_status(tlm::TLM_OK_RESPONSE);
253  } else {
254  switch(fsm_hndl->trans->get_command()) {
255  case tlm::TLM_READ_COMMAND:
256  ar_end_req_evt.notify();
257  active_req_beat[tlm::TLM_READ_COMMAND] = nullptr;
258  break;
259  case tlm::TLM_WRITE_COMMAND:
260  wdata_end_req_evt.notify();
261  active_req_beat[tlm::TLM_WRITE_COMMAND] = nullptr;
262  fsm_hndl->beat_count++;
263  break;
264  default:
265  break;
266  }
267  }
268  };
269  fsm_hndl->fsm->cb[BegPartRespE] = [this, fsm_hndl]() -> void {
270  if(fsm_hndl->is_snoop) {
271  tlm::tlm_phase phase = axi::BEGIN_PARTIAL_RESP;
272  sc_core::sc_time t;
273  auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
274 
275  } else {
276  assert(fsm_hndl->trans->is_read());
277  active_resp_beat[tlm::TLM_READ_COMMAND] = fsm_hndl;
278  rresp_vl.notify({1, fsm_hndl});
279  }
280  };
281  fsm_hndl->fsm->cb[EndPartRespE] = [this, fsm_hndl]() -> void {
282  if(fsm_hndl->is_snoop) {
283  fsm_hndl->beat_count++;
284  cd_end_req_evt.notify();
285 
286  } else {
287  // scheduling the response
288  assert(fsm_hndl->trans->is_read());
289  tlm::tlm_phase phase = axi::END_PARTIAL_RESP;
290  sc_core::sc_time t(sc_core::SC_ZERO_TIME);
291  auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
292  active_resp_beat[tlm::TLM_READ_COMMAND] = nullptr;
293  fsm_hndl->beat_count++;
294  }
295  };
296  fsm_hndl->fsm->cb[BegRespE] = [this, fsm_hndl]() -> void {
297  SCCTRACE(SCMOD) << "processing event BegRespE for trans " << *fsm_hndl->trans;
298  if(fsm_hndl->is_snoop) {
299  tlm::tlm_phase phase = tlm::BEGIN_RESP;
300  sc_core::sc_time t;
301  auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
302  } else {
303  auto size = axi::get_burst_size(*fsm_hndl->trans);
304  active_resp_beat[fsm_hndl->trans->get_command()] = fsm_hndl;
305  switch(fsm_hndl->trans->get_command()) {
306  case tlm::TLM_READ_COMMAND:
307  rresp_vl.notify({3, fsm_hndl});
308  break;
309  case tlm::TLM_WRITE_COMMAND:
310  wresp_vl.notify({3, fsm_hndl});
311  break;
312  default:
313  break;
314  }
315  }
316  };
317  fsm_hndl->fsm->cb[EndRespE] = [this, fsm_hndl]() -> void {
318  if(fsm_hndl->is_snoop) {
319  SCCTRACE(SCMOD) << " in EndRespE ";
320  cd_end_req_evt.notify();
321  cr_end_req_evt.notify(); // need to check these two event??
322  snp_resp_queue.pop_front();
323  fsm_hndl->finish.notify();
324 
325  } else {
326  // scheduling the response
327  tlm::tlm_phase phase = tlm::END_RESP;
328  sc_core::sc_time t(sc_core::SC_ZERO_TIME);
329  auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
330  SCCTRACE(SCMOD) << "EndResp of setup_cb with coherent = " << coherent;
331  if(coherent)
332  schedule(Ack, fsm_hndl->trans, t); // later can add ack_resp_delay to replace t
333  else {
334  fsm_hndl->finish.notify();
335  active_resp_beat[fsm_hndl->trans->get_command()] = nullptr;
336  }
337  }
338  };
339  fsm_hndl->fsm->cb[Ack] = [this, fsm_hndl]() -> void {
340  SCCTRACE(SCMOD) << " in Ack of setup_cb";
341  sc_core::sc_time t(sc_core::SC_ZERO_TIME);
342  tlm::tlm_phase phase = axi::ACK;
343  auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
344  fsm_hndl->finish.notify();
345  active_resp_beat[fsm_hndl->trans->get_command()] = nullptr;
346  };
347 }
348 
349 template <typename CFG> inline void axi::pin::ace_target<CFG>::ar_t() {
350  this->ar_ready.write(false);
351  wait(sc_core::SC_ZERO_TIME);
352  auto arid = 0U;
353  auto arlen = 0U;
354  auto arsize = util::ilog2(CFG::BUSWIDTH / 8);
355 
356  auto data_len = (1 << arsize) * (arlen + 1);
357  while(true) {
358  wait(this->ar_valid.posedge_event() | clk_delayed);
359  if(this->ar_valid.read()) {
360  SCCTRACE(SCMOD) << "ARVALID detected for 0x" << std::hex << this->ar_addr.read();
361  if(!CFG::IS_LITE) {
362  arid = this->ar_id->read().to_uint();
363  arlen = this->ar_len->read().to_uint();
364  arsize = this->ar_size->read().to_uint();
365  }
366  data_len = (1 << arsize) * (arlen + 1);
367  auto gp = tlm::scc::tlm_mm<>::get().allocate<axi::ace_extension>(data_len);
368  gp->set_address(this->ar_addr.read());
369  gp->set_command(tlm::TLM_READ_COMMAND);
370  gp->set_streaming_width(data_len);
371  axi::ace_extension* ext;
372  gp->get_extension(ext);
373  ext->set_id(arid);
374  ext->set_length(arlen);
375  ext->set_size(arsize);
376  if(this->ar_lock->read())
377  ext->set_exclusive(true);
378  ext->set_domain(axi::into<axi::domain_e>(this->ar_domain->read())); // ace extension
379  ext->set_snoop(axi::into<axi::snoop_e>(this->ar_snoop->read()));
380  ext->set_barrier(axi::into<axi::bar_e>(this->ar_bar->read()));
381  ext->set_burst(CFG::IS_LITE ? axi::burst_e::INCR : axi::into<axi::burst_e>(this->ar_burst->read()));
382  ext->set_cache(this->ar_cache->read());
383  ext->set_prot(this->ar_prot->read());
384  ext->set_qos(this->ar_qos->read());
385  ext->set_region(this->ar_region->read());
386 
387  active_req_beat[tlm::TLM_READ_COMMAND] = find_or_create(gp);
388  react(axi::fsm::protocol_time_point_e::BegReqE, active_req_beat[tlm::TLM_READ_COMMAND]);
389  wait(ar_end_req_evt);
390  this->ar_ready.write(true);
391  wait(clk_i.posedge_event());
392  this->ar_ready.write(false);
393  }
394  }
395 }
396 
397 template <typename CFG> inline void axi::pin::ace_target<CFG>::rresp_t() {
398  this->r_valid.write(false);
399  wait(sc_core::SC_ZERO_TIME);
400  fsm_handle* fsm_hndl;
401  uint8_t val;
402  while(true) {
403  // rresp_vl notified in BEGIN_PARTIAL_REQ ( val=1 ??)or in BEG_RESP(val=3??)
404  std::tie(val, fsm_hndl) = rresp_vl.get();
405  SCCTRACE(SCMOD) << __FUNCTION__ << " val = " << (uint16_t)val << " beat count = " << fsm_hndl->beat_count;
406  SCCTRACE(SCMOD) << __FUNCTION__ << " got read response beat of trans " << *fsm_hndl->trans;
407  auto ext = fsm_hndl->trans->get_extension<axi::ace_extension>();
408  this->r_data.write(get_read_data_for_beat(fsm_hndl));
409  this->r_resp.write(ext->get_cresp());
410  this->r_valid.write(val & 0x1);
411  if(!CFG::IS_LITE) {
412  this->r_id->write(ext->get_id());
413  this->r_last->write(val & 0x2);
414  }
415  do {
416  wait(this->r_ready.posedge_event() | clk_delayed);
417  if(this->r_ready.read()) {
418  auto evt =
419  CFG::IS_LITE || (val & 0x2) ? axi::fsm::protocol_time_point_e::EndRespE : axi::fsm::protocol_time_point_e::EndPartRespE;
420  react(evt, active_resp_beat[tlm::TLM_READ_COMMAND]);
421  }
422  } while(!this->r_ready.read());
423  SCCTRACE(SCMOD) << "finished read response beat of trans [" << fsm_hndl->trans << "]";
424  wait(clk_i.posedge_event());
425  this->r_valid.write(false);
426  if(!CFG::IS_LITE)
427  this->r_last->write(false);
428  }
429 }
430 
431 template <typename CFG> inline void axi::pin::ace_target<CFG>::aw_t() {
432  this->aw_ready.write(false);
433  wait(sc_core::SC_ZERO_TIME);
434  const auto awsize = util::ilog2(CFG::BUSWIDTH / 8);
435  while(true) {
436  wait(this->aw_valid.posedge_event() | clk_delayed);
437  if(this->aw_valid.event() || (!active_req_beat[tlm::TLM_IGNORE_COMMAND] && this->aw_valid.read())) {
438  SCCTRACE(SCMOD) << "AWVALID detected for 0x" << std::hex << this->aw_addr.read();
439  // clang-format off
440  aw_data awd = {CFG::IS_LITE ? 0U : this->aw_id->read().to_uint(),
441  this->aw_addr.read().to_uint64(),
442  this->aw_prot.read().to_uint(),
443  CFG::IS_LITE ? awsize : this->aw_size->read().to_uint(),
444  CFG::IS_LITE ? 0U : this->aw_cache->read().to_uint(),
445  CFG::IS_LITE ? 0U : this->aw_burst->read().to_uint(),
446  CFG::IS_LITE ? 0U : this->aw_qos->read().to_uint(),
447  CFG::IS_LITE ? 0U : this->aw_region->read().to_uint(),
448  CFG::IS_LITE ? 0U : this->aw_len->read().to_uint(),
449  CFG::IS_LITE ? 0U : this->aw_domain->read().to_uint(),
450  CFG::IS_LITE ? 0U : this->aw_snoop->read().to_uint(),
451  CFG::IS_LITE ? 0U : this->aw_bar->read().to_uint(),
452  CFG::IS_LITE ? 0U : this->aw_unique->read(),
453  CFG::IS_LITE ? false : this->aw_lock->read(),
454  0};
455  // clang-format on
456  aw_que.notify(awd);
457  this->aw_ready.write(true);
458  wait(clk_i.posedge_event());
459  this->aw_ready.write(false);
460  }
461  }
462 }
463 
464 template <typename CFG> inline void axi::pin::ace_target<CFG>::wdata_t() {
465  this->w_ready.write(false);
466  wait(sc_core::SC_ZERO_TIME);
467  while(true) {
468  wait(this->w_valid.posedge_event() | clk_delayed);
469  this->w_ready.write(false);
470  if(this->w_valid.event() || (!active_req_beat[tlm::TLM_WRITE_COMMAND] && this->w_valid.read())) {
471  if(!active_req[tlm::TLM_WRITE_COMMAND]) {
472  if(!aw_que.has_next())
473  wait(aw_que.event());
474  auto awd = aw_que.get();
475  auto data_len = (1 << awd.size) * (awd.len + 1);
476  auto gp = tlm::scc::tlm_mm<>::get().allocate<axi::ace_extension>(data_len, true);
477  gp->set_address(awd.addr);
478  gp->set_command(tlm::TLM_WRITE_COMMAND);
479  axi::ace_extension* ext;
480  gp->get_extension(ext);
481  ext->set_id(awd.id);
482  ext->set_length(awd.len);
483  ext->set_size(awd.size);
484  ext->set_burst(axi::into<axi::burst_e>(awd.burst));
485  ext->set_prot(awd.prot);
486  ext->set_qos(awd.qos);
487  ext->set_cache(awd.cache);
488  ext->set_region(awd.region);
489  ext->set_snoop(axi::into<axi::snoop_e>(awd.snoop));
490  ext->set_barrier(axi::into<axi::bar_e>(awd.bar));
491  ext->set_unique(awd.unique);
492  ext->set_exclusive(awd.lock);
493  if(CFG::USERWIDTH)
494  ext->set_user(axi::common::id_type::CTRL, awd.user);
495 
496  active_req_beat[tlm::TLM_WRITE_COMMAND] = find_or_create(gp);
497  active_req[tlm::TLM_WRITE_COMMAND] = active_req_beat[tlm::TLM_WRITE_COMMAND];
498  }
499  auto* fsm_hndl = active_req[tlm::TLM_WRITE_COMMAND];
500  SCCTRACE(SCMOD) << "WDATA detected for 0x" << std::hex << this->ar_addr.read();
501  auto& gp = fsm_hndl->trans;
502  auto data = this->w_data.read();
503  auto strb = this->w_strb.read();
504  auto last = CFG::IS_LITE ? true : this->w_last->read();
505  auto beat_count = fsm_hndl->beat_count;
506  auto size = axi::get_burst_size(*fsm_hndl->trans);
507  auto byte_offset = beat_count * size;
508  auto offset = (fsm_hndl->trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
509  if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) { // un-aligned multi-beat access
510  if(beat_count == 0) {
511  auto dptr = fsm_hndl->trans->get_data_ptr();
512  auto beptr = fsm_hndl->trans->get_byte_enable_ptr();
513  for(size_t i = offset; i < size; ++i, ++dptr, ++beptr) {
514  auto bit_offs = i * 8;
515  *dptr = data(bit_offs + 7, bit_offs).to_uint();
516  *beptr = strb[i] ? 0xff : 0;
517  }
518  } else {
519  auto beat_start_idx = byte_offset - offset;
520  auto data_len = fsm_hndl->trans->get_data_length();
521  auto dptr = fsm_hndl->trans->get_data_ptr() + beat_start_idx;
522  auto beptr = fsm_hndl->trans->get_byte_enable_ptr() + beat_start_idx;
523  for(size_t i = 0; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr, ++beptr) {
524  auto bit_offs = i * 8;
525  *dptr = data(bit_offs + 7, bit_offs).to_uint();
526  *beptr = strb[i] ? 0xff : 0;
527  }
528  }
529  } else { // aligned or single beat access
530  auto dptr = fsm_hndl->trans->get_data_ptr() + byte_offset;
531  auto beptr = fsm_hndl->trans->get_byte_enable_ptr() + byte_offset;
532  for(size_t i = 0; i < size; ++i, ++dptr, ++beptr) {
533  auto bit_offs = (offset + i) * 8;
534  *dptr = data(bit_offs + 7, bit_offs).to_uint();
535  *beptr = strb[offset + i] ? 0xff : 0;
536  }
537  }
538  // TODO: assuming consecutive write (not scattered)
539  auto strobe = strb.to_uint();
540  if(last) {
541  auto act_data_len = CFG::IS_LITE ? util::bit_count(strobe) : (beat_count + 1) * size;
542  // if(CFG::IS_LITE && act_data_len<CFG::BUSWIDTH/8) {
543  // std::fill(gp->get_byte_enable_ptr(), gp->get_byte_enable_ptr() + act_data_len, 0xff);
544  // std::fill(gp->get_byte_enable_ptr() + act_data_len, gp->get_byte_enable_ptr() +
545  // gp->get_byte_enable_length(), 0x0);
546  // }
547  gp->set_data_length(act_data_len);
548  gp->set_byte_enable_length(act_data_len);
549  gp->set_streaming_width(act_data_len);
550  }
551  auto tp = CFG::IS_LITE || this->w_last->read() ? axi::fsm::protocol_time_point_e::BegReqE
552  : axi::fsm::protocol_time_point_e::BegPartReqE;
553  react(tp, fsm_hndl);
554  // notifed in EndPartReqE/EndReq
555  wait(wdata_end_req_evt);
556  this->w_ready.write(true);
557  wait(clk_i.posedge_event());
558  this->w_ready.write(false);
559  if(last)
560  active_req[tlm::TLM_WRITE_COMMAND] = nullptr;
561  }
562  }
563 }
564 
565 template <typename CFG> inline void axi::pin::ace_target<CFG>::bresp_t() {
566  this->b_valid.write(false);
567  wait(sc_core::SC_ZERO_TIME);
568  fsm_handle* fsm_hndl;
569  uint8_t val;
570  while(true) {
571  std::tie(val, fsm_hndl) = wresp_vl.get();
572  SCCTRACE(SCMOD) << "got write response of trans " << *fsm_hndl->trans;
573  auto ext = fsm_hndl->trans->get_extension<axi::ace_extension>();
574  this->b_resp.write(axi::to_int(ext->get_resp()));
575  this->b_valid.write(true);
576  if(!CFG::IS_LITE)
577  this->b_id->write(ext->get_id());
578  SCCTRACE(SCMOD) << "got write response";
579  do {
580  wait(this->b_ready.posedge_event() | clk_delayed);
581  if(this->b_ready.read()) {
582  react(axi::fsm::protocol_time_point_e::EndRespE, active_resp_beat[tlm::TLM_WRITE_COMMAND]);
583  }
584  } while(!this->b_ready.read());
585  SCCTRACE(SCMOD) << "finished write response of trans [" << fsm_hndl->trans << "]";
586  wait(clk_i.posedge_event());
587  this->b_valid.write(false);
588  }
589 }
590 
591 // write snoop address
592 template <typename CFG> inline void axi::pin::ace_target<CFG>::write_ac(tlm::tlm_generic_payload& trans) {
593  sc_dt::sc_uint<CFG::ADDRWIDTH> addr = trans.get_address();
594  this->ac_addr.write(addr);
595  auto ext = trans.get_extension<ace_extension>();
596  sc_assert(ext && "No ACE extension found for snoop access");
597  this->ac_prot.write(ext->get_prot());
598  this->ac_snoop->write(sc_dt::sc_uint<4>((uint8_t)ext->get_snoop()));
599 }
600 
601 template <typename CFG> inline void axi::pin::ace_target<CFG>::ac_t() {
602  this->ac_valid.write(false);
603  wait(sc_core::SC_ZERO_TIME);
604  while(true) {
605  wait(ac_evt);
606  this->ac_valid.write(true);
607  do {
608  wait(this->ac_ready.posedge_event() | clk_delayed);
609  if(this->ac_ready.read()) {
610  SCCTRACE(SCMOD) << "in ac_t() detect ac_ready high , schedule EndReq";
611  react(axi::fsm::protocol_time_point_e::EndReqE, active_req[SNOOP]);
612  }
613  } while(!this->ac_ready.read());
614  wait(clk_i.posedge_event());
615  this->ac_valid.write(false);
616  }
617 }
618 
619 template <typename CFG> inline void axi::pin::ace_target<CFG>::cd_t() {
620  this->cd_ready.write(false);
621  wait(sc_core::SC_ZERO_TIME);
622  while(true) {
623  wait(this->cd_valid.posedge_event() | clk_delayed);
624  if(this->cd_valid.read()) {
625  SCCTRACE(SCMOD) << "in cd_t(), received cd_valid high ";
626  wait(sc_core::SC_ZERO_TIME);
627  auto data = this->cd_data.read();
628  if(snp_resp_queue.empty())
629  sc_assert(" snp_resp_queue empty");
630  auto* fsm_hndl = snp_resp_queue.front();
631  auto beat_count = fsm_hndl->beat_count;
632  SCCTRACE(SCMOD) << "in cd_t(), received beau_count = " << fsm_hndl->beat_count;
633  auto size = axi::get_burst_size(*fsm_hndl->trans);
634  auto byte_offset = beat_count * size;
635  auto offset = (fsm_hndl->trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
636  if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) { // un-aligned multi-beat access
637  if(beat_count == 0) {
638  auto dptr = fsm_hndl->trans->get_data_ptr();
639  for(size_t i = offset; i < size; ++i, ++dptr) {
640  auto bit_offs = i * 8;
641  *dptr = data(bit_offs + 7, bit_offs).to_uint();
642  }
643  } else {
644  auto beat_start_idx = beat_count * size - offset;
645  auto data_len = fsm_hndl->trans->get_data_length();
646  auto dptr = fsm_hndl->trans->get_data_ptr() + beat_start_idx;
647  for(size_t i = offset; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr) {
648  auto bit_offs = i * 8;
649  *dptr = data(bit_offs + 7, bit_offs).to_uint();
650  }
651  }
652  } else { // aligned or single beat access
653  auto dptr = fsm_hndl->trans->get_data_ptr() + beat_count * size;
654  for(size_t i = 0; i < size; ++i, ++dptr) {
655  auto bit_offs = (offset + i) * 8;
656  *dptr = data(bit_offs + 7, bit_offs).to_uint();
657  }
658  }
659  /*
660  axi::ace_extension* e;
661  fsm_hndl->trans->get_extension(e);
662  e->set_resp(axi::into<axi::resp_e>(resp));
663  e->add_to_response_array(*e);
664  */
665  auto tp = CFG::IS_LITE || this->cd_last->read() ? axi::fsm::protocol_time_point_e::BegRespE
666  : axi::fsm::protocol_time_point_e::BegPartRespE;
667  if(!this->cd_last->read()) // only react BegPartRespE
668  react(tp, fsm_hndl);
669  // cd_end_req_evt notified in EndPartRespE or EndResp
670  wait(cd_end_req_evt);
671  this->cd_ready.write(true);
672  wait(clk_i.posedge_event());
673  this->cd_ready.write(false);
674  }
675  }
676 }
677 
678 template <typename CFG> inline void axi::pin::ace_target<CFG>::cr_t() {
679  this->cr_ready.write(false);
680  wait(sc_core::SC_ZERO_TIME);
681  while(true) {
682  wait(this->cr_valid.posedge_event() | clk_delayed);
683  if(this->cr_valid.read()) {
684  SCCTRACE(SCMOD) << "in cr_t() received cr_valid high ";
685  wait(sc_core::SC_ZERO_TIME);
686 
687  auto* fsm_hndl = snp_resp_queue.front();
688  auto crresp = this->cr_resp.read();
690  fsm_hndl->trans->get_extension(e);
691  e->set_cresp(crresp);
692 
693  SCCTRACE(SCMOD) << " in cr_t() react() with BegRespE ";
694  // hongyu TBD?? schedule BegResp??
695  react(axi::fsm::protocol_time_point_e::BegRespE, fsm_hndl);
696  wait(cr_end_req_evt); // notify in EndResp
697  this->cr_ready.write(true);
698  wait(clk_i.posedge_event());
699  this->cr_ready.write(false);
700  }
701  }
702 }
703 
704 #endif /* _BUS_AXI_PIN_ACE_TARGET_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
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_barrier(bar_e)
set the AxBAR value
Definition: axi_tlm.h:1449
void set_domain(domain_e)
set the AxDOMAIN value
Definition: axi_tlm.h:1441
void set_unique(bool)
set the AxUNIQUE value
Definition: axi_tlm.h:1453
snoop_e get_snoop() const
get the AxSNOOP value return the snoop value
Definition: axi_tlm.h:1447
void set_snoop(snoop_e)
set the AxSNOOP value
Definition: axi_tlm.h:1445
void set_exclusive(bool=true)
get the exclusive bit of AxLOCK (AxLOCK[0])
Definition: axi_tlm.h:1324
snoop data(cd) channel signals
Definition: signal_if.h:658
void set_id(unsigned int value)
Definition: axi_tlm.h:1252
void set_user(id_type chnl, unsigned int value)
Definition: axi_tlm.h:1256
unsigned int get_id() const
Definition: axi_tlm.h:1254
snoop response(cr) channel signals
Definition: signal_if.h:680
base class of all AXITLM based adapters and interfaces.
Definition: base.h: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:1380
void set_qos(uint8_t)
set the AxQOS (quality of service) value
Definition: axi_tlm.h:1426
void set_cache(uint8_t)
set the AxCACHE value as POD, only value from 0..15 are allowed
Definition: axi_tlm.h:1434
void set_region(uint8_t)
set the AxREGION value
Definition: axi_tlm.h:1430
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
uint8_t get_prot() const
set the AxPROT value as POD, only values from 0...7 are allowed
Definition: axi_tlm.h:1400
void set_prot(uint8_t)
set the AxPROT value as POD, only values from 0...7 are allowed
Definition: axi_tlm.h:1395
resp_e get_resp() const
get the response status as POD
Definition: axi_tlm.h:1502