scc  2024.06
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 <interfaces/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(clk_delayed);
359  while(!this->ar_valid.read()) {
360  wait(this->ar_valid.posedge_event());
361  wait(CLK_DELAY); // verilator might create spurious events
362  }
363  SCCTRACE(SCMOD) << "ARVALID detected for 0x" << std::hex << this->ar_addr.read();
364  if(!CFG::IS_LITE) {
365  arid = this->ar_id->read().to_uint();
366  arlen = this->ar_len->read().to_uint();
367  arsize = this->ar_size->read().to_uint();
368  }
369  data_len = (1 << arsize) * (arlen + 1);
370  auto gp = tlm::scc::tlm_mm<>::get().allocate<axi::ace_extension>(data_len);
371  gp->set_address(this->ar_addr.read());
372  gp->set_command(tlm::TLM_READ_COMMAND);
373  gp->set_streaming_width(data_len);
374  axi::ace_extension* ext;
375  gp->get_extension(ext);
376  ext->set_id(arid);
377  ext->set_length(arlen);
378  ext->set_size(arsize);
379  if(this->ar_lock->read())
380  ext->set_exclusive(true);
381  ext->set_domain(axi::into<axi::domain_e>(this->ar_domain->read())); // ace extension
382  ext->set_snoop(axi::into<axi::snoop_e>(this->ar_snoop->read()));
383  ext->set_barrier(axi::into<axi::bar_e>(this->ar_bar->read()));
384  ext->set_burst(CFG::IS_LITE ? axi::burst_e::INCR : axi::into<axi::burst_e>(this->ar_burst->read()));
385  ext->set_cache(this->ar_cache->read());
386  ext->set_prot(this->ar_prot->read());
387  ext->set_qos(this->ar_qos->read());
388  ext->set_region(this->ar_region->read());
389 
390  active_req_beat[tlm::TLM_READ_COMMAND] = find_or_create(gp);
391  react(axi::fsm::protocol_time_point_e::BegReqE, active_req_beat[tlm::TLM_READ_COMMAND]);
392  wait(ar_end_req_evt);
393  this->ar_ready.write(true);
394  wait(clk_i.posedge_event());
395  this->ar_ready.write(false);
396  }
397 }
398 
399 template <typename CFG> inline void axi::pin::ace_target<CFG>::rresp_t() {
400  this->r_valid.write(false);
401  wait(sc_core::SC_ZERO_TIME);
402  fsm_handle* fsm_hndl;
403  uint8_t val;
404  while(true) {
405  // rresp_vl notified in BEGIN_PARTIAL_REQ ( val=1 ??)or in BEG_RESP(val=3??)
406  std::tie(val, fsm_hndl) = rresp_vl.get();
407  SCCTRACE(SCMOD) << __FUNCTION__ << " val = " << (uint16_t)val << " beat count = " << fsm_hndl->beat_count;
408  SCCTRACE(SCMOD) << __FUNCTION__ << " got read response beat of trans " << *fsm_hndl->trans;
409  auto ext = fsm_hndl->trans->get_extension<axi::ace_extension>();
410  this->r_data.write(get_read_data_for_beat(fsm_hndl));
411  this->r_resp.write(ext->get_cresp());
412  this->r_valid.write(val & 0x1);
413  if(!CFG::IS_LITE) {
414  this->r_id->write(ext->get_id());
415  this->r_last->write(val & 0x2);
416  }
417  do {
418  wait(this->r_ready.posedge_event() | clk_delayed);
419  if(this->r_ready.read()) {
420  auto evt =
421  CFG::IS_LITE || (val & 0x2) ? axi::fsm::protocol_time_point_e::EndRespE : axi::fsm::protocol_time_point_e::EndPartRespE;
422  react(evt, active_resp_beat[tlm::TLM_READ_COMMAND]);
423  }
424  } while(!this->r_ready.read());
425  SCCTRACE(SCMOD) << "finished read response beat of trans [" << fsm_hndl->trans << "]";
426  wait(clk_i.posedge_event());
427  this->r_valid.write(false);
428  if(!CFG::IS_LITE)
429  this->r_last->write(false);
430  }
431 }
432 
433 template <typename CFG> inline void axi::pin::ace_target<CFG>::aw_t() {
434  this->aw_ready.write(false);
435  wait(sc_core::SC_ZERO_TIME);
436  const auto awsize = util::ilog2(CFG::BUSWIDTH / 8);
437  while(true) {
438  wait(clk_delayed);
439  while(!this->aw_valid.read()) {
440  wait(this->aw_valid.posedge_event());
441  wait(CLK_DELAY); // verilator might create spurious events
442  }
443  SCCTRACE(SCMOD) << "AWVALID detected for 0x" << std::hex << this->aw_addr.read();
444  // clang-format off
445  aw_data awd = {CFG::IS_LITE ? 0U : this->aw_id->read().to_uint(),
446  this->aw_addr.read().to_uint64(),
447  this->aw_prot.read().to_uint(),
448  CFG::IS_LITE ? awsize : this->aw_size->read().to_uint(),
449  CFG::IS_LITE ? 0U : this->aw_cache->read().to_uint(),
450  CFG::IS_LITE ? 0U : this->aw_burst->read().to_uint(),
451  CFG::IS_LITE ? 0U : this->aw_qos->read().to_uint(),
452  CFG::IS_LITE ? 0U : this->aw_region->read().to_uint(),
453  CFG::IS_LITE ? 0U : this->aw_len->read().to_uint(),
454  CFG::IS_LITE ? 0U : this->aw_domain->read().to_uint(),
455  CFG::IS_LITE ? 0U : this->aw_snoop->read().to_uint(),
456  CFG::IS_LITE ? 0U : this->aw_bar->read().to_uint(),
457  CFG::IS_LITE ? 0U : this->aw_unique->read(),
458  CFG::IS_LITE ? false : this->aw_lock->read(),
459  0};
460  // clang-format on
461  aw_que.notify(awd);
462  this->aw_ready.write(true);
463  wait(clk_i.posedge_event());
464  this->aw_ready.write(false);
465  }
466 }
467 
468 template <typename CFG> inline void axi::pin::ace_target<CFG>::wdata_t() {
469  this->w_ready.write(false);
470  wait(sc_core::SC_ZERO_TIME);
471  while(true) {
472  wait(this->w_valid.posedge_event() | clk_delayed);
473  this->w_ready.write(false);
474  if(this->w_valid.event() || (!active_req_beat[tlm::TLM_WRITE_COMMAND] && this->w_valid.read())) {
475  if(!active_req[tlm::TLM_WRITE_COMMAND]) {
476  if(!aw_que.has_next())
477  wait(aw_que.event());
478  auto awd = aw_que.get();
479  auto data_len = (1 << awd.size) * (awd.len + 1);
480  auto gp = tlm::scc::tlm_mm<>::get().allocate<axi::ace_extension>(data_len, true);
481  gp->set_address(awd.addr);
482  gp->set_command(tlm::TLM_WRITE_COMMAND);
483  axi::ace_extension* ext;
484  gp->get_extension(ext);
485  ext->set_id(awd.id);
486  ext->set_length(awd.len);
487  ext->set_size(awd.size);
488  ext->set_burst(axi::into<axi::burst_e>(awd.burst));
489  ext->set_prot(awd.prot);
490  ext->set_qos(awd.qos);
491  ext->set_cache(awd.cache);
492  ext->set_region(awd.region);
493  ext->set_snoop(axi::into<axi::snoop_e>(awd.snoop));
494  ext->set_barrier(axi::into<axi::bar_e>(awd.bar));
495  ext->set_unique(awd.unique);
496  ext->set_exclusive(awd.lock);
497  if(CFG::USERWIDTH)
498  ext->set_user(axi::common::id_type::CTRL, awd.user);
499 
500  active_req_beat[tlm::TLM_WRITE_COMMAND] = find_or_create(gp);
501  active_req[tlm::TLM_WRITE_COMMAND] = active_req_beat[tlm::TLM_WRITE_COMMAND];
502  }
503  auto* fsm_hndl = active_req[tlm::TLM_WRITE_COMMAND];
504  SCCTRACE(SCMOD) << "WDATA detected for 0x" << std::hex << this->ar_addr.read();
505  auto& gp = fsm_hndl->trans;
506  auto data = this->w_data.read();
507  auto strb = this->w_strb.read();
508  auto last = CFG::IS_LITE ? true : this->w_last->read();
509  auto beat_count = fsm_hndl->beat_count;
510  auto size = axi::get_burst_size(*fsm_hndl->trans);
511  auto byte_offset = beat_count * size;
512  auto offset = (fsm_hndl->trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
513  if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) { // un-aligned multi-beat access
514  if(beat_count == 0) {
515  auto dptr = fsm_hndl->trans->get_data_ptr();
516  auto beptr = fsm_hndl->trans->get_byte_enable_ptr();
517  for(size_t i = offset; i < size; ++i, ++dptr, ++beptr) {
518  auto bit_offs = i * 8;
519  *dptr = data(bit_offs + 7, bit_offs).to_uint();
520  *beptr = strb[i] ? 0xff : 0;
521  }
522  } else {
523  auto beat_start_idx = byte_offset - offset;
524  auto data_len = fsm_hndl->trans->get_data_length();
525  auto dptr = fsm_hndl->trans->get_data_ptr() + beat_start_idx;
526  auto beptr = fsm_hndl->trans->get_byte_enable_ptr() + beat_start_idx;
527  for(size_t i = 0; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr, ++beptr) {
528  auto bit_offs = i * 8;
529  *dptr = data(bit_offs + 7, bit_offs).to_uint();
530  *beptr = strb[i] ? 0xff : 0;
531  }
532  }
533  } else { // aligned or single beat access
534  auto dptr = fsm_hndl->trans->get_data_ptr() + byte_offset;
535  auto beptr = fsm_hndl->trans->get_byte_enable_ptr() + byte_offset;
536  for(size_t i = 0; i < size; ++i, ++dptr, ++beptr) {
537  auto bit_offs = (offset + i) * 8;
538  *dptr = data(bit_offs + 7, bit_offs).to_uint();
539  *beptr = strb[offset + i] ? 0xff : 0;
540  }
541  }
542  // TODO: assuming consecutive write (not scattered)
543  auto strobe = strb.to_uint();
544  if(last) {
545  auto act_data_len = CFG::IS_LITE ? util::bit_count(strobe) : (beat_count + 1) * size;
546  // if(CFG::IS_LITE && act_data_len<CFG::BUSWIDTH/8) {
547  // std::fill(gp->get_byte_enable_ptr(), gp->get_byte_enable_ptr() + act_data_len, 0xff);
548  // std::fill(gp->get_byte_enable_ptr() + act_data_len, gp->get_byte_enable_ptr() +
549  // gp->get_byte_enable_length(), 0x0);
550  // }
551  gp->set_data_length(act_data_len);
552  gp->set_byte_enable_length(act_data_len);
553  gp->set_streaming_width(act_data_len);
554  }
555  auto tp = CFG::IS_LITE || this->w_last->read() ? axi::fsm::protocol_time_point_e::BegReqE
556  : axi::fsm::protocol_time_point_e::BegPartReqE;
557  react(tp, fsm_hndl);
558  // notifed in EndPartReqE/EndReq
559  wait(wdata_end_req_evt);
560  this->w_ready.write(true);
561  wait(clk_i.posedge_event());
562  this->w_ready.write(false);
563  if(last)
564  active_req[tlm::TLM_WRITE_COMMAND] = nullptr;
565  }
566  }
567 }
568 
569 template <typename CFG> inline void axi::pin::ace_target<CFG>::bresp_t() {
570  this->b_valid.write(false);
571  wait(sc_core::SC_ZERO_TIME);
572  fsm_handle* fsm_hndl;
573  uint8_t val;
574  while(true) {
575  std::tie(val, fsm_hndl) = wresp_vl.get();
576  SCCTRACE(SCMOD) << "got write response of trans " << *fsm_hndl->trans;
577  auto ext = fsm_hndl->trans->get_extension<axi::ace_extension>();
578  this->b_resp.write(axi::to_int(ext->get_resp()));
579  this->b_valid.write(true);
580  if(!CFG::IS_LITE)
581  this->b_id->write(ext->get_id());
582  SCCTRACE(SCMOD) << "got write response";
583  do {
584  wait(this->b_ready.posedge_event() | clk_delayed);
585  if(this->b_ready.read()) {
586  react(axi::fsm::protocol_time_point_e::EndRespE, active_resp_beat[tlm::TLM_WRITE_COMMAND]);
587  }
588  } while(!this->b_ready.read());
589  SCCTRACE(SCMOD) << "finished write response of trans [" << fsm_hndl->trans << "]";
590  wait(clk_i.posedge_event());
591  this->b_valid.write(false);
592  }
593 }
594 
595 // write snoop address
596 template <typename CFG> inline void axi::pin::ace_target<CFG>::write_ac(tlm::tlm_generic_payload& trans) {
597  sc_dt::sc_uint<CFG::ADDRWIDTH> addr = trans.get_address();
598  this->ac_addr.write(addr);
599  auto ext = trans.get_extension<ace_extension>();
600  sc_assert(ext && "No ACE extension found for snoop access");
601  this->ac_prot.write(ext->get_prot());
602  this->ac_snoop->write(sc_dt::sc_uint<4>((uint8_t)ext->get_snoop()));
603 }
604 
605 template <typename CFG> inline void axi::pin::ace_target<CFG>::ac_t() {
606  this->ac_valid.write(false);
607  wait(sc_core::SC_ZERO_TIME);
608  while(true) {
609  wait(ac_evt);
610  this->ac_valid.write(true);
611  do {
612  wait(this->ac_ready.posedge_event() | clk_delayed);
613  if(this->ac_ready.read()) {
614  SCCTRACE(SCMOD) << "in ac_t() detect ac_ready high , schedule EndReq";
615  react(axi::fsm::protocol_time_point_e::EndReqE, active_req[SNOOP]);
616  }
617  } while(!this->ac_ready.read());
618  wait(clk_i.posedge_event());
619  this->ac_valid.write(false);
620  }
621 }
622 
623 template <typename CFG> inline void axi::pin::ace_target<CFG>::cd_t() {
624  this->cd_ready.write(false);
625  wait(sc_core::SC_ZERO_TIME);
626  while(true) {
627  wait(this->cd_valid.posedge_event() | clk_delayed);
628  if(this->cd_valid.read()) {
629  SCCTRACE(SCMOD) << "in cd_t(), received cd_valid high ";
630  wait(sc_core::SC_ZERO_TIME);
631  auto data = this->cd_data.read();
632  if(snp_resp_queue.empty())
633  sc_assert(" snp_resp_queue empty");
634  auto* fsm_hndl = snp_resp_queue.front();
635  auto beat_count = fsm_hndl->beat_count;
636  SCCTRACE(SCMOD) << "in cd_t(), received beau_count = " << fsm_hndl->beat_count;
637  auto size = axi::get_burst_size(*fsm_hndl->trans);
638  auto byte_offset = beat_count * size;
639  auto offset = (fsm_hndl->trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
640  if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) { // un-aligned multi-beat access
641  if(beat_count == 0) {
642  auto dptr = fsm_hndl->trans->get_data_ptr();
643  for(size_t i = offset; i < size; ++i, ++dptr) {
644  auto bit_offs = i * 8;
645  *dptr = data(bit_offs + 7, bit_offs).to_uint();
646  }
647  } else {
648  auto beat_start_idx = beat_count * size - offset;
649  auto data_len = fsm_hndl->trans->get_data_length();
650  auto dptr = fsm_hndl->trans->get_data_ptr() + beat_start_idx;
651  for(size_t i = offset; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr) {
652  auto bit_offs = i * 8;
653  *dptr = data(bit_offs + 7, bit_offs).to_uint();
654  }
655  }
656  } else { // aligned or single beat access
657  auto dptr = fsm_hndl->trans->get_data_ptr() + beat_count * size;
658  for(size_t i = 0; i < size; ++i, ++dptr) {
659  auto bit_offs = (offset + i) * 8;
660  *dptr = data(bit_offs + 7, bit_offs).to_uint();
661  }
662  }
663  /*
664  axi::ace_extension* e;
665  fsm_hndl->trans->get_extension(e);
666  e->set_resp(axi::into<axi::resp_e>(resp));
667  e->add_to_response_array(*e);
668  */
669  auto tp = CFG::IS_LITE || this->cd_last->read() ? axi::fsm::protocol_time_point_e::BegRespE
670  : axi::fsm::protocol_time_point_e::BegPartRespE;
671  if(!this->cd_last->read()) // only react BegPartRespE
672  react(tp, fsm_hndl);
673  // cd_end_req_evt notified in EndPartRespE or EndResp
674  wait(cd_end_req_evt);
675  this->cd_ready.write(true);
676  wait(clk_i.posedge_event());
677  this->cd_ready.write(false);
678  }
679  }
680 }
681 
682 template <typename CFG> inline void axi::pin::ace_target<CFG>::cr_t() {
683  this->cr_ready.write(false);
684  wait(sc_core::SC_ZERO_TIME);
685  while(true) {
686  wait(this->cr_valid.posedge_event() | clk_delayed);
687  if(this->cr_valid.read()) {
688  SCCTRACE(SCMOD) << "in cr_t() received cr_valid high ";
689  wait(sc_core::SC_ZERO_TIME);
690 
691  auto* fsm_hndl = snp_resp_queue.front();
692  auto crresp = this->cr_resp.read();
694  fsm_hndl->trans->get_extension(e);
695  e->set_cresp(crresp);
696 
697  SCCTRACE(SCMOD) << " in cr_t() react() with BegRespE ";
698  // hongyu TBD?? schedule BegResp??
699  react(axi::fsm::protocol_time_point_e::BegRespE, fsm_hndl);
700  wait(cr_end_req_evt); // notify in EndResp
701  this->cr_ready.write(true);
702  wait(clk_i.posedge_event());
703  this->cr_ready.write(false);
704  }
705  }
706 }
707 
708 #endif /* _BUS_AXI_PIN_ACE_TARGET_H_ */
payload_type * allocate()
get a plain tlm_payload_type without extensions
Definition: tlm_mm.h:185
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
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_barrier(bar_e)
set the AxBAR value
Definition: axi_tlm.h:1521
void set_domain(domain_e)
set the AxDOMAIN value
Definition: axi_tlm.h:1513
void set_unique(bool)
set the AxUNIQUE value
Definition: axi_tlm.h:1525
snoop_e get_snoop() const
get the AxSNOOP value return the snoop value
Definition: axi_tlm.h:1519
void set_snoop(snoop_e)
set the AxSNOOP value
Definition: axi_tlm.h:1517
void set_exclusive(bool=true)
get the exclusive bit of AxLOCK (AxLOCK[0])
Definition: axi_tlm.h:1369
snoop data(cd) channel signals
Definition: signal_if.h:665
void set_id(unsigned int value)
Definition: axi_tlm.h:1297
void set_user(id_type chnl, unsigned int value)
Definition: axi_tlm.h:1301
unsigned int get_id() const
Definition: axi_tlm.h:1299
snoop response(cr) channel signals
Definition: signal_if.h:687
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:1452
void set_qos(uint8_t)
set the AxQOS (quality of service) value
Definition: axi_tlm.h:1498
void set_cache(uint8_t)
set the AxCACHE value as POD, only value from 0..15 are allowed
Definition: axi_tlm.h:1506
void set_region(uint8_t)
set the AxREGION value
Definition: axi_tlm.h:1502
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
uint8_t get_prot() const
set the AxPROT value as POD, only values from 0...7 are allowed
Definition: axi_tlm.h:1472
void set_prot(uint8_t)
set the AxPROT value as POD, only values from 0...7 are allowed
Definition: axi_tlm.h:1467
resp_e get_resp() const
get the response status as POD
Definition: axi_tlm.h:1574
static tlm_mm & get()
accessor function of the singleton
Definition: tlm_mm.h:293