scc  2022.4.0
SystemC components library
axi_initiator.cpp
1 /*
2  * Copyright 2021 Arteris IP
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 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
17 #define SC_INCLUDE_DYNAMIC_PROCESSES
18 #endif
19 #include <atp/timing_params.h>
20 #include <axi/axi_tlm.h>
21 #include <axi/pe/axi_initiator.h>
22 #include <scc/report.h>
23 #include <tlm/scc/tlm_gp_shared.h>
24 
25 using namespace sc_core;
27 
28 namespace axi {
29 namespace pe {
30 
31 namespace {
32 uint8_t log2n(uint8_t siz) { return ((siz > 1) ? 1 + log2n(siz >> 1) : 0); }
33 
34 } // anonymous namespace
35 
36 SC_HAS_PROCESS(axi_initiator_b);
37 
38 axi_initiator_b::axi_initiator_b(sc_core::sc_module_name nm,
39  sc_core::sc_port_b<axi::axi_fw_transport_if<axi_protocol_types>>& port,
40  size_t transfer_width, flavor_e flavor)
41 : sc_module(nm)
42 , socket_fw(port)
43 , transfer_width_in_bytes(transfer_width / 8)
44 , flavor(flavor) {
45  add_attribute(data_interleaving);
46  add_attribute(artv);
47  add_attribute(awtv);
48  add_attribute(wbv);
49  add_attribute(rbr);
50  add_attribute(br);
51  add_attribute(ba);
52  add_attribute(rla);
53  add_attribute(enable_id_serializing);
54  fw_i.bind(*this);
55  SC_METHOD(clk_counter);
56  sensitive << clk_i.pos();
57 
58  if(flavor == flavor_e::AXI)
59  for(auto i = 0u; i < 16; i++)
60  sc_core::sc_spawn([this]() { snoop_thread(); });
61 }
62 
63 axi_initiator_b::~axi_initiator_b() {
64  for(auto& e : tx_state_by_tx)
65  delete e.second;
66 }
67 
68 void axi_initiator_b::end_of_elaboration() {
69  clk_if = dynamic_cast<sc_core::sc_clock*>(clk_i.get_interface());
70  for(auto i = 0U; i < outstanding_snoops.value; ++i) {
71  sc_spawn(sc_bind(&axi_initiator_b::snoop_thread, this));
72  }
73 }
74 
75 void axi_initiator_b::b_snoop(payload_type& trans, sc_core::sc_time& t) {
76  if(bw_o.get_interface()) {
77  auto latency = bw_o->transport(trans);
78  if(latency < std::numeric_limits<unsigned>::max())
79  t += latency * clk_period;
80  }
81 }
82 
83 tlm::tlm_sync_enum axi_initiator_b::nb_transport_bw(payload_type& trans, phase_type& phase, sc_core::sc_time& t) {
84  SCCTRACE(SCMOD) << __FUNCTION__ << " received with phase " << phase << " with delay = " << t << " with trans " << trans;
85  if(phase == tlm::BEGIN_REQ) { // snoop
86  snp_peq.notify(trans, t);
87  } else if(phase == END_PARTIAL_RESP || phase == tlm::END_RESP) { //snoop
88  auto it = snp_state_by_id.find(&trans);
89  sc_assert(it != snp_state_by_id.end());
90  it->second->peq.notify(std::make_tuple(&trans, phase), t);
91  } else { // read/write
92  auto it = tx_state_by_tx.find(&trans);
93  sc_assert(it != tx_state_by_tx.end());
94  auto txs = it->second;
95  txs->peq.notify(std::make_tuple(&trans, phase), t);
96  }
97  return tlm::TLM_ACCEPTED;
98 }
99 
100 void axi_initiator_b::invalidate_direct_mem_ptr(sc_dt::uint64 start_range, sc_dt::uint64 end_range) {}
101 
102 tlm::tlm_phase axi_initiator_b::send(payload_type& trans, axi_initiator_b::tx_state* txs, tlm::tlm_phase phase) {
103  sc_core::sc_time delay;
104  SCCTRACE(SCMOD) << "Send " << phase << " of " << trans;
105  tlm::tlm_sync_enum ret = socket_fw->nb_transport_fw(trans, phase, delay);
106  if(ret == tlm::TLM_UPDATED) {
107  wait(delay);
108  SCCTRACE(SCMOD) << "Received " << phase << " for " << trans;
109  return phase;
110  } else {
111  auto waiting = txs->peq.has_next();
112  auto entry = txs->peq.get();
113  if(waiting)
114  SCCFATAL(SCMOD) << "there is a waiting " << std::get<0>(entry) << " with phase " << std::get<1>(entry);
115  sc_assert(!txs->peq.has_next());
116  sc_assert(std::get<0>(entry) == &trans);
117  SCCTRACE(SCMOD) << "in send() Received " << std::get<1>(entry) << " for " << trans;
118  return std::get<1>(entry);
119  }
120 }
121 
122 void axi_initiator_b::transport(payload_type& trans, bool blocking) {
123  auto axi_id = get_axi_id(trans);
124  if(flavor == flavor_e::AXI) {
125  if(!trans.get_extension<axi::axi4_extension>() && !trans.get_extension<axi::axi3_extension>()) {
126  auto ace = trans.set_extension<axi::ace_extension>(nullptr);
127  sc_assert(ace && "No valid extension found in transaction");
128  auto axi4 = new axi::axi4_extension();
129  *static_cast<axi::axi4*>(axi4) = *static_cast<axi::axi4*>(ace);
130  *static_cast<axi::common*>(axi4) = *static_cast<axi::common*>(ace);
131  trans.set_extension(axi4);
132  delete ace;
133  }
134  } else {
135  sc_assert(trans.get_extension<axi::ace_extension>() && "No ACE extension found in transaction");
136  }
137  SCCTRACE(SCMOD) << "got transport req for " << trans;
138  if(blocking) {
139  sc_time t;
140  socket_fw->b_transport(trans, t);
141  } else {
142  auto it = tx_state_by_tx.find(&trans);
143  if(it == tx_state_by_tx.end()) {
144  bool success;
145  std::tie(it, success) = tx_state_by_tx.insert(std::make_pair(&trans, new tx_state()));
146  }
147  auto& txs = it->second;
148  auto timing_e = trans.set_auto_extension<atp::timing_params>(nullptr);
149 
150  if(enable_id_serializing.value) {
151  if(!id_mtx[axi_id]) {
152  id_mtx[axi_id] = new scc::ordered_semaphore(1);
153  }
154  id_mtx[axi_id]->wait(); // wait until running tx with same id is over
155  }
156  txs->active_tx = &trans;
157  auto burst_length = 0;
158  if(auto e = trans.get_extension<axi::ace_extension>()) {
159  burst_length = is_dataless(e) ? 1 : e->get_length() + 1;
160  } else if(auto e = trans.get_extension<axi::axi4_extension>()) {
161  burst_length = e->get_length() + 1;
162  } else if(auto e = trans.get_extension<axi::axi3_extension>()) {
163  burst_length = e->get_length() + 1;
164  }
165  SCCTRACE(SCMOD) << "start transport " << trans;
166  tlm::tlm_phase next_phase{tlm::UNINITIALIZED_PHASE};
167  if(!trans.is_read()) { // data less via write channel
168  if(!data_interleaving
169  .value) { // Note that AXI4 does not allow write data interleaving, and ncore3 only supports AXI4.
170  sem_lock lck(wr_chnl);
172  for(unsigned i = 1; i < (timing_e ? timing_e->awtv : awtv.value); ++i) {
173  wait(clk_i.posedge_event());
174  }
175  SCCTRACE(SCMOD) << "starting " << burst_length << " write beats of " << trans;
176  for(unsigned i = 0; i < burst_length - 1; ++i) {
177  if(protocol_cb[axi::fsm::BegPartReqE])
178  protocol_cb[axi::fsm::BegPartReqE](trans, false);
179  auto res = send(trans, txs, axi::BEGIN_PARTIAL_REQ);
180  if(axi::END_PARTIAL_REQ != res)
181  SCCFATAL(SCMOD) << "target responded with " << res << " for the " << i << "th beat of "
182  << burst_length << " beats in transaction " << trans;
183  for(unsigned i = 0; i < (timing_e ? timing_e->wbv : wbv.value); ++i)
184  wait(clk_i.posedge_event());
185  if(protocol_cb[axi::fsm::EndPartReqE])
186  protocol_cb[axi::fsm::EndPartReqE](trans, false);
187  }
188  auto res = send(trans, txs, tlm::BEGIN_REQ);
189  if(res == axi::BEGIN_PARTIAL_RESP || res == tlm::BEGIN_RESP)
190  next_phase = res;
191  else if(res != tlm::END_REQ)
192  SCCERR(SCMOD) << "target did not repsond with END_REQ to a BEGIN_REQ";
193  wait(clk_i.posedge_event());
194  } else { // AXI3 allows data interleaving and there may be support for AXI3 in Symphony
195  SCCTRACE(SCMOD) << "starting " << burst_length << " write beats of " << trans;
196  for(unsigned i = 0; i < burst_length - 1; ++i) {
197  sem_lock lck(wr_chnl);
198  if(i == 0)
200  for(unsigned i = 1; i < (timing_e ? timing_e->awtv : awtv.value); ++i)
201  wait(clk_i.posedge_event());
202  auto res = send(trans, txs, axi::BEGIN_PARTIAL_REQ);
203  sc_assert(axi::END_PARTIAL_REQ == res);
204  for(unsigned i = 1; i < (timing_e ? timing_e->wbv : wbv.value); ++i)
205  wait(clk_i.posedge_event());
206  }
207  sem_lock lck(wr_chnl);
208  if(protocol_cb[axi::fsm::BegReqE])
209  protocol_cb[axi::fsm::BegReqE](trans, false);
210  auto res = send(trans, txs, tlm::BEGIN_REQ);
211  if(res == axi::BEGIN_PARTIAL_RESP || res == tlm::BEGIN_RESP)
212  next_phase = res;
213  else if(res != tlm::END_REQ)
214  SCCERR(SCMOD) << "target did not repsond with END_REQ to a BEGIN_REQ";
215  wait(clk_i.posedge_event());
216  if(protocol_cb[axi::fsm::EndReqE])
217  protocol_cb[axi::fsm::EndReqE](trans, false);
218  }
219  } else {
220  sem_lock lck(rd_chnl);
222  for(unsigned i = 1; i < (timing_e ? timing_e->artv : artv.value); ++i)
223  wait(clk_i.posedge_event());
224  SCCTRACE(SCMOD) << "starting address phase of " << trans;
225  if(protocol_cb[axi::fsm::BegPartReqE])
226  protocol_cb[axi::fsm::BegPartReqE](trans, false);
227  auto res = send(trans, txs, tlm::BEGIN_REQ);
228  if(res == axi::BEGIN_PARTIAL_RESP || res == tlm::BEGIN_RESP)
229  next_phase = res;
230  else if(res != tlm::END_REQ)
231  SCCERR(SCMOD) << "target did not repsond with END_REQ to a BEGIN_REQ";
232  wait(clk_i.posedge_event());
233  if(protocol_cb[axi::fsm::EndReqE])
234  protocol_cb[axi::fsm::EndReqE](trans, false);
235  }
236  auto finished = false;
237  if(!trans.is_read() || !trans.get_data_length())
238  burst_length = 1;
239  const auto exp_burst_length = burst_length;
240  do {
241  // waiting for response
242  auto entry = next_phase == tlm::UNINITIALIZED_PHASE ? txs->peq.get() : std::make_tuple(&trans, next_phase);
243  next_phase = tlm::UNINITIALIZED_PHASE;
244  // Handle optional CRESP response
245  if(std::get<0>(entry) == &trans && std::get<1>(entry) == tlm::BEGIN_RESP) {
246  if(protocol_cb[axi::fsm::BegRespE])
247  protocol_cb[axi::fsm::BegRespE](trans, false);
248  SCCTRACE(SCMOD) << "received last beat of " << trans;
249  auto delay_in_cycles = timing_e ? (trans.is_read() ? timing_e->rbr : timing_e->br) : br.value;
250  for(unsigned i = 0; i < delay_in_cycles; ++i)
251  wait(clk_i.posedge_event());
252  burst_length--;
253  tlm::tlm_phase phase = tlm::END_RESP;
254  sc_time delay = clk_if ? clk_if->period() - 1_ps : SC_ZERO_TIME;
255  socket_fw->nb_transport_fw(trans, phase, delay);
256  if(burst_length)
257  SCCWARN(SCMOD) << "got wrong number of burst beats, expected " << exp_burst_length << ", got "
258  << exp_burst_length - burst_length;
259  wait(clk_i.posedge_event());
260  if(protocol_cb[axi::fsm::EndRespE])
261  protocol_cb[axi::fsm::EndRespE](trans, false);
262  finished = true;
263  } else if(std::get<0>(entry) == &trans &&
264  std::get<1>(entry) == axi::BEGIN_PARTIAL_RESP) { // RDAT without CRESP case
265  SCCTRACE(SCMOD) << "received beat = "<< burst_length<<" with trans " << trans;
266  auto delay_in_cycles = timing_e ? timing_e->rbr : rbr.value;
267  for(unsigned i = 0; i < delay_in_cycles; ++i)
268  wait(clk_i.posedge_event());
269  burst_length--;
270  if(protocol_cb[axi::fsm::BegPartRespE])
271  protocol_cb[axi::fsm::BegPartRespE](trans, false);
272  tlm::tlm_phase phase = axi::END_PARTIAL_RESP;
273  sc_time delay = clk_if ? clk_if->period() - 1_ps : SC_ZERO_TIME;
274  auto res = socket_fw->nb_transport_fw(trans, phase, delay);
275  if(res == tlm::TLM_UPDATED) {
276  next_phase = phase;
277  wait(delay);
278  }
279  if(protocol_cb[axi::fsm::EndPartRespE])
280  protocol_cb[axi::fsm::EndPartRespE](trans, false);
281  }
282  } while(!finished);
283  if(flavor == flavor_e::ACE) {
284  if(trans.is_read() && rla.value != std::numeric_limits<unsigned>::max()) {
285  for(unsigned i = 0; i < rla.value; ++i)
286  wait(clk_i.posedge_event());
287  tlm::tlm_phase phase = axi::ACK;
288  sc_time delay = SC_ZERO_TIME;
289  socket_fw->nb_transport_fw(trans, phase, delay);
290  wait(clk_i.posedge_event());
291 
292  } else if(trans.is_write() && ba.value != std::numeric_limits<unsigned>::max()) {
293  for(unsigned i = 0; i < ba.value; ++i)
294  wait(clk_i.posedge_event());
295  tlm::tlm_phase phase = axi::ACK;
296  sc_time delay = SC_ZERO_TIME;
297  socket_fw->nb_transport_fw(trans, phase, delay);
298  wait(clk_i.posedge_event());
299  }
300  }
301  SCCTRACE(SCMOD) << "finished non-blocking protocol";
302  if(enable_id_serializing.value) {
303  id_mtx[axi_id]->post();
304  }
305  txs->active_tx = nullptr;
306  any_tx_finished.notify(SC_ZERO_TIME);
307  }
308  SCCTRACE(SCMOD) << "finished transport req for " << trans;
309 }
310 
311 // This process handles the SNOOP request received
312 void axi_initiator_b::snoop_thread() {
313  tlm::scc::tlm_gp_shared_ptr trans{nullptr};
314  while(true) {
315  while(!(trans = snp_peq.get_next_transaction())) {
316  wait(snp_peq.get_event());
317  }
318  snoops_in_flight++;
319  SCCDEBUG(SCMOD) << "start snoop #" << snoops_in_flight;
320  auto req_ext = trans->get_extension<ace_extension>();
321  sc_assert(req_ext != nullptr);
322 
323  auto it = snp_state_by_id.find(&trans);
324  if(it == snp_state_by_id.end()) {
325  bool success;
326  std::tie(it, success) = snp_state_by_id.insert(std::make_pair(trans.get(), new tx_state()));
327  }
328 
329  sc_time delay = clk_if ? clk_if->period() - 1_ps : SC_ZERO_TIME;
330  tlm::tlm_phase phase = tlm::END_REQ;
331  // here delay is not used in nb_fw of following module
332  // therefore one cycle delay between BEG_REQ and END_REQ should be explicitly called here??
333  if(protocol_cb[axi::fsm::BegReqE])
334  protocol_cb[axi::fsm::BegReqE](*trans, true);
335  socket_fw->nb_transport_fw(*trans, phase, delay);
336  auto cycles = 0U;
337  if(bw_o.get_interface())
338  cycles = bw_o->transport(*trans);
339  if(protocol_cb[axi::fsm::EndReqE])
340  protocol_cb[axi::fsm::EndReqE](*trans, true);
341  if(cycles < std::numeric_limits<unsigned>::max()) {
342  // we handle the snoop access ourselfs
343  for(size_t i = 0; i <= cycles; ++i)
344  wait(clk_i.posedge_event());
345  snoop_resp(*trans);
346  }
347  // finish snoop response, should release tlm gp_shared_ptr
348  SCCTRACE(SCMOD)<<" finish snoop response, release gp_shared_ptr";
349  snoops_in_flight--;
350  trans=nullptr;
351  }
352 }
353 
354 void axi_initiator_b::snoop_resp(payload_type& trans, bool sync) {
355  auto it = snp_state_by_id.find(&trans);
356  sc_assert(it != snp_state_by_id.end());
357  auto& txs = it->second;
358  auto data_len=trans.get_data_length();
359  auto burst_length = data_len/transfer_width_in_bytes;
360  if(burst_length<1)
361  burst_length=1;
362  tlm::tlm_phase next_phase{tlm::UNINITIALIZED_PHASE};
363  auto delay_in_cycles = wbv.value;
364  sem_lock lck(sresp_chnl);
365  /*
366  * here according to spec, ccresp should first be checked to see whether there is data transfer( decided by TC)
367  * if there is data to transfer, start cache data transfer, otherwise only crresp
368  * */
369  SCCTRACE(SCMOD) << "starting snoop resp with " << burst_length << " beats of " << trans;
370  for(unsigned i = 0; i < burst_length - 1; ++i) {
371  if(protocol_cb[axi::fsm::BegPartRespE])
372  protocol_cb[axi::fsm::BegPartRespE](trans, true);
373  auto res = send(trans, txs, axi::BEGIN_PARTIAL_RESP);
374  sc_assert(axi::END_PARTIAL_RESP == res);
375  wait(clk_i.posedge_event());
376  if(protocol_cb[axi::fsm::EndPartRespE])
377  protocol_cb[axi::fsm::EndPartRespE](trans, true);
378  for(unsigned i = 1; i < delay_in_cycles; ++i)
379  wait(clk_i.posedge_event());
380  }
381  if(protocol_cb[axi::fsm::BegRespE])
382  protocol_cb[axi::fsm::BegRespE](trans, true);
383  auto res = send(trans, txs, tlm::BEGIN_RESP);
384  if(res != tlm::END_RESP)
385  SCCERR(SCMOD) << "target did not respond with END_RESP to a BEGIN_RESP";
386  wait(clk_i.posedge_event());
387  if(protocol_cb[axi::fsm::EndRespE])
388  protocol_cb[axi::fsm::EndRespE](trans, true);
389 }
390 } // namespace pe
391 } // namespace axi
The ordered_semaphore primitive channel class.
TLM2.0 components modeling AHB.
Definition: axi_initiator.h:30
tlm::tlm_fw_transport_if< TYPES > axi_fw_transport_if
alias declaration for the forward interface
Definition: axi_tlm.h:916
a lock for the semaphore