scc  2024.06
SystemC components library
chi_rn_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 
17 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
18 #define SC_INCLUDE_DYNAMIC_PROCESSES
19 #endif
20 #include <atp/timing_params.h>
21 #include <axi/axi_tlm.h>
22 #include <cache/cache_info.h>
23 #include <chi/pe/chi_rn_initiator.h>
24 #include <scc/report.h>
25 #include <util/strprintf.h>
26 #include <tlm/scc/tlm_mm.h>
27 #include <tlm/scc/tlm_gp_shared.h>
28 
29 using namespace sc_core;
30 using namespace chi;
31 using namespace chi::pe;
33 
34 namespace {
35 uint8_t log2n(uint8_t siz) { return ((siz > 1) ? 1 + log2n(siz >> 1) : 0); }
36 inline uintptr_t to_id(tlm::tlm_generic_payload& t) { return reinterpret_cast<uintptr_t>(&t); }
37 inline uintptr_t to_id(tlm::tlm_generic_payload* t) { return reinterpret_cast<uintptr_t>(t); }
38 void convert_axi4ace_to_chi(tlm::tlm_generic_payload& gp, char const* name, bool legacy_mapping = false) {
39  if(gp.get_data_length() > 64) {
40  SCCWARN(__FUNCTION__) << "Data length of " << gp.get_data_length()
41  << " is not supported by CHI, shortening payload";
42  gp.set_data_length(64);
43  }
44  auto ace_ext = gp.set_extension<axi::ace_extension>(nullptr);
45  auto axi4_ext = gp.set_extension<axi::axi4_extension>(nullptr);
46 
47  // Check that either the AXI4 or ACE extension is set
48  sc_assert(ace_ext != nullptr || axi4_ext != nullptr);
49 
50  bool is_ace = (ace_ext != nullptr);
51 
52  auto* chi_req_ext = new chi::chi_ctrl_extension;
53 
54  //---------- Map the fields in AXI4/ACE extension to CHI request extension
55  // 1. Set SRC ID and TGT ID based on Address of transaction?? XXX: Currently hardcoded
56 
57  // Map AXI4/ACE ID to CHI TXN ID
58  chi_req_ext->set_txn_id(is_ace ? ace_ext->get_id() : axi4_ext->get_id());
59  chi_req_ext->set_qos(is_ace ? ace_ext->get_qos() : axi4_ext->get_qos());
60  SCCTRACE(name) << "chi_ctrl_extension set TxnID=0x" << std::hex << chi_req_ext->get_txn_id();
61 
62  // XXX: Can gp.get_data_length() be mapped to CHI req 'size' field?
63  sc_assert(((gp.get_data_length() & (gp.get_data_length() - 1)) == 0) &&
64  "CHI data size is not a power of 2: Byte transfer: 0->1, 1->2, 2->4, 3->8, .. 6->64, 7->reserved");
65  uint8_t chi_size = log2n(gp.get_data_length());
66  SCCDEBUG(name) << "convert_axi4ace_to_chi: data length = " << gp.get_data_length()
67  << "; Converted data length to chi_size = " << static_cast<unsigned>(chi_size);
68 
69  chi_req_ext->req.set_size(chi_size);
70 
71  uint8_t mem_attr = 0; // CHI request field MemAttr
72 
73  // Set opcode based on snoop, bar and domain
74  if(!is_ace) {
75  // Non coherent
76  sc_assert(gp.is_read() || gp.is_write()); // Read/Write, no cache maintenance
77  chi_req_ext->req.set_opcode(gp.is_read() ? chi::req_optype_e::ReadNoSnp : chi::req_optype_e::WriteNoSnpFull);
78  } else {
79 
80  auto axi_gp_cmd = gp.get_command();
81  auto axi_snp = ace_ext->get_snoop();
82  auto axi_domain = ace_ext->get_domain();
83  auto axi_bar = ace_ext->get_barrier();
84  auto axi_atomic = ace_ext->get_atop();
85  // AN-573. If something is cacheable, then set, if something is not cacheable, then don't set snpattr.
86  auto cacheable = ace_ext->is_modifiable();
87  SCCDEBUG(name) << "AXI/ACE: snoop = " << axi::to_char(axi_snp) << ", barrier = " << axi::to_char(axi_bar)
88  << ", domain = " << axi::to_char(axi_domain);
89  if(axi_bar == axi::bar_e::MEMORY_BARRIER) {
90  sc_assert(axi_snp == axi::snoop_e::BARRIER);
91  SCCERR(name) << "Barrier transaction has no mapping in CHI";
92  }
93  chi::req_optype_e opcode{chi::req_optype_e::ReqLCrdReturn};
94 
95  if(axi_atomic) {
96  SCCDEBUG(name) << "AWATOP value: " << std::hex << static_cast<unsigned>(axi_atomic);
97  auto atomic_opcode = (axi_atomic >> 4) & 3;
98  auto atomic_subcode = axi_atomic & 7;
99 
100  if(atomic_opcode == 1) {
101  const std::array<chi::req_optype_e, 8> atomic_store_opcodes = {
102  chi::req_optype_e::AtomicStoreAdd, chi::req_optype_e::AtomicStoreClr,
103  chi::req_optype_e::AtomicStoreEor, chi::req_optype_e::AtomicStoreSet,
104  chi::req_optype_e::AtomicStoreSmax, chi::req_optype_e::AtomicStoreSmin,
105  chi::req_optype_e::AtomicStoreUmax, chi::req_optype_e::AtomicStoreUmin};
106  opcode = atomic_store_opcodes[atomic_subcode];
107  } else if(atomic_opcode == 2) {
108  const std::array<chi::req_optype_e, 8> atomic_load_opcodes = {
109  chi::req_optype_e::AtomicLoadAdd, chi::req_optype_e::AtomicLoadClr,
110  chi::req_optype_e::AtomicLoadEor, chi::req_optype_e::AtomicLoadSet,
111  chi::req_optype_e::AtomicLoadSmax, chi::req_optype_e::AtomicLoadSmin,
112  chi::req_optype_e::AtomicLoadUmax, chi::req_optype_e::AtomicLoadUmin};
113  opcode = atomic_load_opcodes[atomic_subcode];
114  } else if(axi_atomic == 0x30)
115  opcode = chi::req_optype_e::AtomicSwap;
116  else if(axi_atomic == 0x31)
117  opcode = chi::req_optype_e::AtomicCompare;
118  else
119  SCCERR(name) << "Can't handle AXI AWATOP value: " << axi_atomic;
120 
121  chi_req_ext->req.set_opcode(opcode);
122  chi_req_ext->req.set_snp_attr(axi_snp != axi::snoop_e::READ_NO_SNOOP);
123  chi_req_ext->req.set_snoop_me(axi_snp != axi::snoop_e::READ_NO_SNOOP);
124  } else if(gp.is_read()) {
125  switch(axi_snp) {
126  case axi::snoop_e::READ_NO_SNOOP:
127  sc_assert(axi_domain == axi::domain_e::NON_SHAREABLE || axi_domain == axi::domain_e::SYSTEM);
128  opcode = chi::req_optype_e::ReadNoSnp;
129  break;
130  case axi::snoop_e::READ_ONCE:
131  sc_assert(axi_domain == axi::domain_e::INNER_SHAREABLE || axi_domain == axi::domain_e::OUTER_SHAREABLE);
132  opcode = chi::req_optype_e::ReadOnce;
133  chi_req_ext->req.set_snp_attr(cacheable);
134  break;
135  case axi::snoop_e::READ_SHARED:
136  opcode = chi::req_optype_e::ReadShared;
137  break;
138  case axi::snoop_e::READ_CLEAN:
139  opcode = chi::req_optype_e::ReadClean;
140  break;
141  case axi::snoop_e::READ_NOT_SHARED_DIRTY:
142  opcode = chi::req_optype_e::ReadNotSharedDirty;
143  break;
144  case axi::snoop_e::READ_UNIQUE:
145  opcode = chi::req_optype_e::ReadUnique;
146  break;
147  case axi::snoop_e::CLEAN_SHARED:
148  opcode = chi::req_optype_e::CleanShared;
149  gp.set_data_length(0);
150  break;
151  case axi::snoop_e::CLEAN_INVALID:
152  opcode = chi::req_optype_e::CleanInvalid;
153  gp.set_data_length(0);
154  break;
155  case axi::snoop_e::CLEAN_SHARED_PERSIST:
156  opcode = chi::req_optype_e::CleanSharedPersist;
157  gp.set_data_length(0);
158  break;
159  case axi::snoop_e::CLEAN_UNIQUE:
160  opcode = chi::req_optype_e::CleanUnique;
161  gp.set_data_length(0);
162  break;
163  case axi::snoop_e::MAKE_UNIQUE:
164  opcode = chi::req_optype_e::MakeUnique;
165  gp.set_data_length(0);
166  break;
167  case axi::snoop_e::MAKE_INVALID:
168  opcode = chi::req_optype_e::MakeInvalid;
169  gp.set_data_length(0);
170  break;
171  default:
172  SCCWARN(name) << "unexpected read type";
173  break;
174  }
175  chi_req_ext->req.set_opcode(opcode);
176 
177  if(axi_snp != axi::snoop_e::READ_NO_SNOOP) {
178  chi_req_ext->req.set_snp_attr(cacheable);
179  }
180  if(opcode == chi::req_optype_e::StashOnceUnique || opcode == chi::req_optype_e::StashOnceShared) {
181  gp.set_data_length(0);
182  gp.set_command(tlm::TLM_IGNORE_COMMAND);
183  if(ace_ext->is_stash_nid_en()) {
184  chi_req_ext->req.set_stash_n_id(ace_ext->get_stash_nid());
185  chi_req_ext->req.set_stash_n_id_valid(true);
186  }
187  if(ace_ext->is_stash_lpid_en()) {
188  chi_req_ext->req.set_stash_lp_id(ace_ext->get_stash_lpid());
189  chi_req_ext->req.set_stash_lp_id_valid(true);
190  }
191  }
192  } else if(gp.is_write()) {
193  switch(axi_snp) {
194  case axi::snoop_e::WRITE_NO_SNOOP:
195  sc_assert(axi_domain == axi::domain_e::NON_SHAREABLE || axi_domain == axi::domain_e::SYSTEM);
196  opcode = gp.get_data_length() == 64 ? chi::req_optype_e::WriteNoSnpFull : chi::req_optype_e::WriteNoSnpPtl;
197  break;
198  case axi::snoop_e::WRITE_UNIQUE:
199  sc_assert(axi_domain == axi::domain_e::INNER_SHAREABLE || axi_domain == axi::domain_e::OUTER_SHAREABLE);
200  opcode = gp.get_data_length() == 64 ? chi::req_optype_e::WriteUniqueFull:chi::req_optype_e::WriteUniquePtl;
201  chi_req_ext->req.set_snp_attr(cacheable);
202  break;
203  case axi::snoop_e::WRITE_LINE_UNIQUE:
204  opcode = chi::req_optype_e::WriteUniqueFull;
205  break;
206  case axi::snoop_e::WRITE_CLEAN: {
207  bool ptl = false;
208  for(auto i = 0; i < gp.get_byte_enable_length(); ++i) {
209  if(gp.get_byte_enable_ptr()[i] == 0) {
210  ptl = true;
211  break;
212  }
213  }
214  if(ptl)
215  opcode = chi::req_optype_e::WriteCleanPtl;
216  else
217  opcode = chi::req_optype_e::WriteCleanFull;
218  break;
219  }
220  case axi::snoop_e::WRITE_BACK:
221  opcode = gp.get_data_length() == 64 ? chi::req_optype_e::WriteBackFull : chi::req_optype_e::WriteBackPtl;
222  break;
223  case axi::snoop_e::EVICT:
224  opcode = chi::req_optype_e::Evict;
225  break;
226  case axi::snoop_e::WRITE_EVICT:
227  opcode = chi::req_optype_e::WriteEvictFull;
228  break;
229  case axi::snoop_e::WRITE_UNIQUE_PTL_STASH:
230  opcode = chi::req_optype_e::WriteUniquePtlStash;
231  break;
232  case axi::snoop_e::WRITE_UNIQUE_FULL_STASH:
233  opcode = chi::req_optype_e::WriteUniqueFullStash;
234  break;
235  case axi::snoop_e::STASH_ONCE_UNIQUE:
236  opcode = chi::req_optype_e::StashOnceUnique;
237  gp.set_data_length(0);
238  chi_req_ext->req.set_size(6); // full cache line
239  break;
240  case axi::snoop_e::STASH_ONCE_SHARED:
241  opcode = chi::req_optype_e::StashOnceShared;
242  gp.set_data_length(0);
243  chi_req_ext->req.set_size(6); // full cache line
244  break;
245  default:
246  SCCWARN(name) << "unexpected snoop type " << axi::to_char(axi_snp) << " during write";
247  break;
248  }
249  chi_req_ext->req.set_opcode(opcode);
250 
251  if(axi_snp != axi::snoop_e::WRITE_NO_SNOOP) {
252  chi_req_ext->req.set_snp_attr(cacheable);
253  }
254  if(opcode == chi::req_optype_e::WriteUniquePtlStash || opcode == chi::req_optype_e::WriteUniqueFullStash ||
255  opcode == chi::req_optype_e::StashOnceUnique || opcode == chi::req_optype_e::StashOnceShared) {
256  if(ace_ext->is_stash_nid_en()) {
257  chi_req_ext->req.set_stash_n_id(ace_ext->get_stash_nid());
258  chi_req_ext->req.set_stash_n_id_valid(true);
259  }
260  if(ace_ext->is_stash_lpid_en()) {
261  chi_req_ext->req.set_stash_lp_id(ace_ext->get_stash_lpid());
262  chi_req_ext->req.set_stash_lp_id_valid(true);
263  }
264  }
265  } else {
266  // Must be Cache maintenance. XXX: To do
267  SCCERR(name) << "Not yet implemented !!! ";
268  }
269 
270  if(legacy_mapping) {
288  //
289  // Cache Read Write
290  // 0000 0010 Read/Write
291  // 0001 0011 Read/Write
292  // 0010 0000 Read/Write
293  // 0011 0001 Read/Write
294  // 0110 1101 0101 Read Write
295  // 0111 1101 0101 Read Write
296  // 1010 0101 1101 Read Write
297  // 1011 0101 1101 Read Write
298  // 1110 1101 Read/Write
299  // 1111 1101 Read/Write
300 
301  switch(ace_ext->get_cache()) {
302  case 0b0000:
303  mem_attr = 0b0010;
304  break;
305  case 0b0001:
306  mem_attr = 0b0011;
307  break;
308  case 0b0010:
309  mem_attr = 0b0000;
310  break;
311  case 0b0011:
312  mem_attr = 0b0001;
313  break;
314  case 0b0110:
315  case 0b0111:
316  mem_attr = gp.is_read() ? 0b1101 : 0b0101;
317  break;
318  case 0b1010:
319  case 0b1011:
320  mem_attr = gp.is_read() ? 0b0101 : 0b1101;
321  break;
322  case 0b1110:
323  case 0b1111:
324  mem_attr = 0b1101;
325  break;
326  default:
327  SCCERR(name) << "Unexpected AxCACHE type";
328  break;
329  }
330  } else {
331  auto allocate = (ace_ext->is_allocate());
332  auto cachable = ace_ext->is_cacheable();
333  auto ewa = ace_ext->is_bufferable();
334  auto device = ace_ext->get_cache() < 2;
335  mem_attr = (allocate ? 8 : 0) + (cachable ? 4 : 0) + (device ? 2 : 0) + (ewa ? 1 : 0);
336  // ReadNoSnp., ReadNoSnpSep., ReadOnce*., WriteNoSnp., WriteNoSnp, CMO., WriteNoSnpZero., WriteUnique.,
337  // WriteUnique, CMO., WriteUniqueZero., Atomic.
338  if(!device)
339  switch(opcode) {
340  case chi::req_optype_e::ReadNoSnp:
341  case chi::req_optype_e::ReadNoSnpSep:
342  case chi::req_optype_e::ReadOnce:
343  case chi::req_optype_e::ReadOnceCleanInvalid:
344  case chi::req_optype_e::ReadOnceMakeInvalid:
345  case chi::req_optype_e::WriteNoSnpPtl:
346  case chi::req_optype_e::WriteNoSnpFull:
347  case chi::req_optype_e::WriteUniquePtl:
348  case chi::req_optype_e::WriteUniqueFull:
349  case chi::req_optype_e::AtomicStoreAdd:
350  case chi::req_optype_e::AtomicStoreClr:
351  case chi::req_optype_e::AtomicStoreEor:
352  case chi::req_optype_e::AtomicStoreSet:
353  case chi::req_optype_e::AtomicStoreSmax:
354  case chi::req_optype_e::AtomicStoreSmin:
355  case chi::req_optype_e::AtomicStoreUmax:
356  case chi::req_optype_e::AtomicStoreUmin:
357  case chi::req_optype_e::AtomicLoadAdd:
358  case chi::req_optype_e::AtomicLoadClr:
359  case chi::req_optype_e::AtomicLoadEor:
360  case chi::req_optype_e::AtomicLoadSet:
361  case chi::req_optype_e::AtomicLoadSmax:
362  case chi::req_optype_e::AtomicLoadSmin:
363  case chi::req_optype_e::AtomicLoadUmax:
364  case chi::req_optype_e::AtomicLoadUmin:
365  case chi::req_optype_e::AtomicSwap:
366  case chi::req_optype_e::AtomicCompare:
367  chi_req_ext->req.set_order(0b00);
368  break;
369  default:
370  break;
371  }
372  }
373  }
374  chi_req_ext->req.set_mem_attr(mem_attr);
375 
376  if(auto msg = chi::is_valid_msg(chi_req_ext))
377  SCCFATAL(__FUNCTION__) << "Conversion created an invalid chi request, pls. check the AXI/ACE settings: "<<msg;
378 
379  if(gp.has_mm())
380  gp.set_auto_extension(chi_req_ext);
381  else {
382  gp.set_extension(chi_req_ext);
383  }
384  delete ace_ext;
385  ace_ext = nullptr;
386  delete axi4_ext;
387  axi4_ext = nullptr;
388  gp.set_extension(ace_ext);
389  gp.set_extension(axi4_ext);
390 }
391 
392 void setExpCompAck(chi::chi_ctrl_extension* const req_e) {
393  switch(req_e->req.get_opcode()) {
394  // Ref : Sec 2.8.3 pg 97
395  case chi::req_optype_e::ReadNoSnpSep: // Ref: Pg 143
396  // Ref : Table 2.7 pg 55
397  case chi::req_optype_e::Evict:
398  case chi::req_optype_e::StashOnceUnique:
399  case chi::req_optype_e::StashOnceShared:
400  case chi::req_optype_e::CleanShared:
401  case chi::req_optype_e::CleanSharedPersist:
402  case chi::req_optype_e::CleanSharedPersistSep:
403  case chi::req_optype_e::CleanInvalid:
404  case chi::req_optype_e::MakeInvalid:
405  // write case
406  case chi::req_optype_e::WriteNoSnpZero:
407  case chi::req_optype_e::WriteNoSnpFull:
408  case chi::req_optype_e::WriteNoSnpPtl:
409  case chi::req_optype_e::WriteUniqueZero:
410  case chi::req_optype_e::WriteUniquePtl:
411  case chi::req_optype_e::WriteUniqueFull:
412  case chi::req_optype_e::WriteUniqueFullStash:
413  case chi::req_optype_e::WriteBackFull:
414  case chi::req_optype_e::WriteBackPtl:
415  case chi::req_optype_e::WriteCleanFull:
416  case chi::req_optype_e::WriteCleanPtl:
417  // Atomics
418  case chi::req_optype_e::AtomicStoreAdd:
419  case chi::req_optype_e::AtomicStoreClr:
420  case chi::req_optype_e::AtomicStoreEor:
421  case chi::req_optype_e::AtomicStoreSet:
422  case chi::req_optype_e::AtomicStoreSmax:
423  case chi::req_optype_e::AtomicStoreSmin:
424  case chi::req_optype_e::AtomicStoreUmax:
425  case chi::req_optype_e::AtomicStoreUmin:
426  case chi::req_optype_e::AtomicLoadAdd:
427  case chi::req_optype_e::AtomicLoadClr:
428  case chi::req_optype_e::AtomicLoadEor:
429  case chi::req_optype_e::AtomicLoadSet:
430  case chi::req_optype_e::AtomicLoadSmax:
431  case chi::req_optype_e::AtomicLoadSmin:
432  case chi::req_optype_e::AtomicLoadUmax:
433  case chi::req_optype_e::AtomicLoadUmin:
434  case chi::req_optype_e::AtomicCompare:
435  case chi::req_optype_e::AtomicSwap:
436 
437  // case chi::req_optype_e::ReadNoSnp: //XXX: Temporary for testing
438  // case chi::req_optype_e::ReadOnce: //XXX: Temporary for testing
439  req_e->req.set_exp_comp_ack(false);
440  break;
441 
442  // Ref : pg 55
443  case chi::req_optype_e::ReadNoSnp:
444  case chi::req_optype_e::ReadOnce:
445  case chi::req_optype_e::CleanUnique:
446  case chi::req_optype_e::MakeUnique:
447  req_e->req.set_exp_comp_ack(true);
448  break;
449  default: // XXX: Should default ExpCompAck be true or false?
450  req_e->req.set_exp_comp_ack(true);
451  break;
452  }
453 
454  // XXX: For Ordered Read, set ExpCompAck. Check once again, not clear
455  if((req_e->req.get_opcode() == chi::req_optype_e::ReadNoSnp ||
456  req_e->req.get_opcode() == chi::req_optype_e::ReadOnce) &&
457  (req_e->req.get_order() == 0b10 || req_e->req.get_order() == 0b11)) {
458  req_e->req.set_exp_comp_ack(true);
459  }
460 
461  // Ref pg 101: Ordered write => set ExpCompAck (XXX: Check if its true for all Writes)
462  if((req_e->req.get_opcode() >= chi::req_optype_e::WriteEvictFull &&
463  req_e->req.get_opcode() <= chi::req_optype_e::WriteUniquePtlStash) &&
464  (req_e->req.get_order() == 0b10 || req_e->req.get_order() == 0b11)) {
465  req_e->req.set_exp_comp_ack(true);
466  }
467 }
468 
469 bool make_rsp_from_req(tlm::tlm_generic_payload& gp, chi::rsp_optype_e rsp_opcode) {
470  if(auto* ctrl_e = gp.get_extension<chi::chi_ctrl_extension>()) {
471  if(rsp_opcode == chi::rsp_optype_e::CompAck) {
472  if(is_dataless(ctrl_e) || gp.is_write()) {
473  ctrl_e->resp.set_tgt_id(ctrl_e->req.get_tgt_id());
474  ctrl_e->resp.set_trace_tag(ctrl_e->req.is_trace_tag()); // XXX ??
475  if(ctrl_e->req.get_opcode() == chi::req_optype_e::MakeReadUnique) {
476  ctrl_e->set_txn_id(ctrl_e->resp.get_db_id());
477  }
478  } else {
479  auto dat_e = gp.get_extension<chi::chi_data_extension>();
480  ctrl_e->req.set_tgt_id(dat_e->dat.get_home_n_id());
481  ctrl_e->set_src_id(dat_e->get_src_id());
482  ctrl_e->set_qos(dat_e->get_qos());
483  ctrl_e->set_txn_id(dat_e->dat.get_db_id());
484  ctrl_e->resp.set_tgt_id(dat_e->dat.get_tgt_id());
485  ctrl_e->resp.set_trace_tag(dat_e->dat.is_trace_tag()); // XXX ??
486  }
487  ctrl_e->resp.set_opcode(rsp_opcode);
488  return true;
489  } else
490  ctrl_e->resp.set_opcode(rsp_opcode);
491  } else if(auto* snp_e = gp.get_extension<chi::chi_snp_extension>()) {
492  snp_e->resp.set_opcode(rsp_opcode);
493  if(rsp_opcode == chi::rsp_optype_e::CompAck) {
494  if(auto dat_e = gp.get_extension<chi::chi_data_extension>()) {
495  snp_e->set_src_id(dat_e->get_src_id());
496  snp_e->set_qos(dat_e->get_qos());
497  snp_e->set_txn_id(dat_e->dat.get_db_id());
498  snp_e->resp.set_tgt_id(dat_e->dat.get_tgt_id());
499  snp_e->resp.set_trace_tag(dat_e->dat.is_trace_tag()); // XXX ?
500  }
501  return true;
502  }
503  }
504  return false;
505 }
506 
507 } // anonymous namespace
508 
509 SC_HAS_PROCESS(chi_rn_initiator_b);
510 
511 chi::pe::chi_rn_initiator_b::chi_rn_initiator_b(sc_core::sc_module_name nm,
512  sc_core::sc_port_b<chi::chi_fw_transport_if<chi_protocol_types>>& port,
513  size_t transfer_width)
514 : sc_module(nm)
515 , socket_fw(port)
516 , transfer_width_in_bytes(transfer_width / 8) {
517  fw_i.bind(*this);
518 
519  SC_METHOD(clk_counter);
520  sensitive << clk_i.pos();
521  SC_THREAD(snoop_dispatch);
522 }
523 
524 chi::pe::chi_rn_initiator_b::~chi_rn_initiator_b() {
525  if(tx_state_by_trans.size()) {
526  for(auto& e : tx_state_by_trans)
527  SCCDEBUG(SCMOD) << "unfinished transaction with ptr: "<< e.first << " with access address = 0x" << std::hex << ((tlm::tlm_generic_payload*)e.first)->get_address() ;
528  SCCWARN(SCMOD) << "is still waiting for unfinished transactions with number = " << tx_state_by_trans.size() ;
529 
530  }
531  for(auto& e : tx_state_by_trans)
532  delete e.second;
533  for(auto p: tx_state_pool)
534  delete p;
535 }
536 
537 void chi::pe::chi_rn_initiator_b::clk_counter() {
538  if(m_clock_counter>1 &&
539  snp_credit_sent.get()<15 &&
540  snp_counter.get()<snp_req_credit_limit.get_value()) {
541  auto credit2send = std::min<unsigned>(15-snp_credit_sent.get(), snp_req_credit_limit.get_value()-snp_counter.get());
542  grant_credit(credit2send);
543  snp_credit_sent+=credit2send;
544  }
545  m_clock_counter++;
546 }
547 
548 
549 void chi::pe::chi_rn_initiator_b::b_snoop(payload_type& trans, sc_core::sc_time& t) {
550  if(bw_o.get_interface()) {
551  auto latency = bw_o->transport(trans);
552  if(latency < std::numeric_limits<unsigned>::max())
553  t += latency * (clk_if ? clk_if->period() : clk_period);
554  }
555 }
556 
557 void chi::pe::chi_rn_initiator_b::snoop_resp(payload_type& trans, bool sync) {
558  auto req_ext = trans.get_extension<chi_snp_extension>();
559  sc_assert(req_ext != nullptr);
560  auto it = tx_state_by_trans.find(to_id(trans));
561  sc_assert(it != tx_state_by_trans.end());
562  auto* txs = it->second;
563  handle_snoop_response(trans, txs);
564  tx_state_pool.push_back(it->second);
565  tx_state_pool.back()->peq.clear();
566  tx_state_by_trans.erase(to_id(trans));
567  if(trans.has_mm())
568  trans.release();
569 }
570 
571 tlm::tlm_sync_enum chi::pe::chi_rn_initiator_b::nb_transport_bw(payload_type& trans, phase_type& phase,
572  sc_core::sc_time& t) {
573  if(auto snp_ext = trans.get_extension<chi_snp_extension>()) {
574  if(phase == tlm::BEGIN_REQ) {
575  if(trans.has_mm())
576  trans.acquire();
577  snp_credit_sent--;
578  snp_peq.notify(trans, t);
579  if(snp_counter<snp_req_credit_limit.get_value()) {
580  snp_counter++;
581  snp_credit_sent++;
582  trans.set_auto_extension(new chi_credit_extension(credit_type_e::REQ));
583  }
584  } else {
585  auto it = tx_state_by_trans.find(to_id(trans));
586  sc_assert(it != tx_state_by_trans.end());
587  it->second->peq.notify(std::make_tuple(&trans, phase), t);
588  }
589  } else {
590  if(phase == tlm::BEGIN_REQ) {
591  if(auto credit_ext = trans.get_extension<chi_credit_extension>()) {
592  if(credit_ext->type == credit_type_e::REQ) {
593  SCCTRACEALL(SCMOD) << "Received " << credit_ext->count << " req "
594  << (credit_ext->count == 1 ? "credit" : "credits");
595  for(auto i = 0U; i < credit_ext->count; ++i)
596  req_credits.post();
597  }
598  phase = tlm::END_RESP;
599  trans.set_response_status(tlm::TLM_OK_RESPONSE);
600  if(clk_if)
601  t += clk_if->period() - 1_ps;
602  return tlm::TLM_COMPLETED;
603  } else {
604  SCCFATAL(SCMOD) << "Illegal transaction received from HN";
605  }
606  } else {
607  auto it = tx_state_by_trans.find(to_id(trans));
608  sc_assert(it != tx_state_by_trans.end());
609  it->second->peq.notify(std::make_tuple(&trans, phase), t);
610  }
611  }
612  return tlm::TLM_ACCEPTED;
613 }
614 
615 void chi::pe::chi_rn_initiator_b::invalidate_direct_mem_ptr(sc_dt::uint64 start_range, sc_dt::uint64 end_range) {}
616 
617 void chi::pe::chi_rn_initiator_b::update_data_extension(chi::chi_data_extension* data_ext, payload_type& trans) {
618  auto req_e = trans.get_extension<chi::chi_ctrl_extension>();
619  sc_assert(req_e != nullptr);
620  switch(req_e->req.get_opcode()) {
621  case chi::req_optype_e::WriteNoSnpPtl:
622  case chi::req_optype_e::WriteNoSnpFull:
623  case chi::req_optype_e::WriteUniquePtl:
624  case chi::req_optype_e::WriteUniqueFull:
625  case chi::req_optype_e::WriteUniquePtlStash:
626  case chi::req_optype_e::WriteUniqueFullStash:
627  // CHE-E
628  case chi::req_optype_e::WriteNoSnpFullCleanSh:
629  case chi::req_optype_e::WriteNoSnpFullCleanInv:
630  case chi::req_optype_e::WriteNoSnpFullCleanShPerSep:
631  case chi::req_optype_e::WriteUniqueFullCleanSh:
632  case chi::req_optype_e::WriteUniqueFullCleanShPerSep:
633  case chi::req_optype_e::WriteBackFullCleanShPerSep:
634  case chi::req_optype_e::WriteNoSnpPtlCleanSh:
635  case chi::req_optype_e::WriteNoSnpPtlCleanInv:
636  case chi::req_optype_e::WriteNoSnpPtlCleanShPerSep:
637  case chi::req_optype_e::WriteUniquePtlCleanSh:
638  case chi::req_optype_e::WriteUniquePtlCleanShPerSep:
639  data_ext->dat.set_opcode(chi::dat_optype_e::NonCopyBackWrData);
640  break;
641 
642  case chi::req_optype_e::WriteBackFull:
643  case chi::req_optype_e::WriteBackPtl:
644  case chi::req_optype_e::WriteCleanFull:
645  case chi::req_optype_e::WriteCleanPtl:
646  // CHI-E
647  case chi::req_optype_e::WriteBackFullCleanSh:
648  case chi::req_optype_e::WriteBackFullCleanInv:
649  case chi::req_optype_e::WriteCleanFullCleanSh:
650  case chi::req_optype_e::WriteCleanFullCleanShPerSep:
651  case chi::req_optype_e::WriteEvictFull:
652  data_ext->dat.set_opcode(chi::dat_optype_e::CopyBackWrData);
653  break;
654 
655  case chi::req_optype_e::AtomicStoreAdd:
656  case chi::req_optype_e::AtomicStoreClr:
657  case chi::req_optype_e::AtomicStoreEor:
658  case chi::req_optype_e::AtomicStoreSet:
659  case chi::req_optype_e::AtomicStoreSmax:
660  case chi::req_optype_e::AtomicStoreSmin:
661  case chi::req_optype_e::AtomicStoreUmax:
662  case chi::req_optype_e::AtomicStoreUmin:
663  data_ext->dat.set_opcode(chi::dat_optype_e::NonCopyBackWrData);
664  break;
665  case chi::req_optype_e::AtomicLoadAdd:
666  case chi::req_optype_e::AtomicLoadClr:
667  case chi::req_optype_e::AtomicLoadEor:
668  case chi::req_optype_e::AtomicLoadSet:
669  case chi::req_optype_e::AtomicLoadSmax:
670  case chi::req_optype_e::AtomicLoadSmin:
671  case chi::req_optype_e::AtomicLoadUmax:
672  case chi::req_optype_e::AtomicLoadUmin:
673  case chi::req_optype_e::AtomicSwap:
674  case chi::req_optype_e::AtomicCompare:
675  data_ext->dat.set_opcode(chi::dat_optype_e::NonCopyBackWrData);
676  break;
677  default:
678  SCCWARN(SCMOD) << " Unable to match req_opcode with data_opcode in write transaction ";
679  }
680  if(data_ext->dat.get_opcode() == chi::dat_optype_e::NonCopyBackWrData) {
681  data_ext->dat.set_resp(chi::dat_resptype_e::NonCopyBackWrData);
682  } else if(data_ext->dat.get_opcode() == chi::dat_optype_e::NCBWrDataCompAck) {
683  data_ext->dat.set_resp(chi::dat_resptype_e::NCBWrDataCompAck);
684  } else if(data_ext->dat.get_opcode() == chi::dat_optype_e::CopyBackWrData) {
685  auto cache_ext = trans.get_extension<::cache::cache_info>();
686  sc_assert(cache_ext != nullptr);
687  auto cache_state = cache_ext->get_state();
688  if(cache_state == ::cache::state::IX) {
689  data_ext->dat.set_resp(chi::dat_resptype_e::CopyBackWrData_I);
690  } else if(cache_state == ::cache::state::UC) {
691  data_ext->dat.set_resp(chi::dat_resptype_e::CopyBackWrData_UC);
692  } else if(cache_state == ::cache::state::SC) {
693  data_ext->dat.set_resp(chi::dat_resptype_e::CopyBackWrData_SC);
694  } else if(cache_state == ::cache::state::UD) {
695  data_ext->dat.set_resp(chi::dat_resptype_e::CopyBackWrData_UD_PD);
696  } else if(cache_state == ::cache::state::SD) {
697  data_ext->dat.set_resp(chi::dat_resptype_e::CopyBackWrData_SD_PD);
698  } else
699  SCCWARN(SCMOD) << " Unable to match cache state with resptype ";
700  } else {
701  SCCWARN(SCMOD) << "Unable to match resptype with WriteData Responses";
702  }
703 
704  auto db_id = req_e->resp.get_db_id();
705  data_ext->set_txn_id(db_id);
706  data_ext->set_src_id(req_e->resp.get_tgt_id());
707  data_ext->dat.set_tgt_id(req_e->get_src_id());
708 }
709 
710 void chi::pe::chi_rn_initiator_b::create_data_ext(payload_type& trans) {
711  auto data_ext = new chi::chi_data_extension;
712  update_data_extension(data_ext, trans);
713  trans.set_auto_extension<chi::chi_data_extension>(data_ext);
714 }
715 
716 void chi::pe::chi_rn_initiator_b::send_packet(tlm::tlm_phase phase, payload_type& trans,
718  if(protocol_cb[WDAT])
719  protocol_cb[WDAT](WDAT, trans);
720  sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
721  tlm::tlm_sync_enum ret = socket_fw->nb_transport_fw(trans, phase, delay);
722  if(ret == tlm::TLM_UPDATED) {
723  if(phase == chi::END_PARTIAL_DATA || phase == chi::END_DATA) {
724  if(delay.value())
725  wait(delay);
726  }
727  } else {
728  auto entry = txs->peq.get();
729  sc_assert(std::get<0>(entry) == &trans &&
730  (std::get<1>(entry) == chi::END_PARTIAL_DATA || std::get<1>(entry) == chi::END_DATA));
731  }
732  auto timing_e = trans.get_extension<atp::timing_params>();
733  auto delay_in_cycles = (timing_e && timing_e->wbv) ? timing_e->wbv : 1;
734  while(delay_in_cycles) {
735  delay_in_cycles--;
736  wait(clk_i.posedge_event());
737  }
738 }
739 
740 void chi::pe::chi_rn_initiator_b::send_wdata(payload_type& trans, chi::pe::chi_rn_initiator_b::tx_state* txs) {
741  sc_core::sc_time delay;
742  tlm::tlm_phase phase;
743  auto data_ext = trans.get_extension<chi::chi_data_extension>();
744  if(data_ext == nullptr) {
745  create_data_ext(trans);
746  data_ext = trans.get_extension<chi::chi_data_extension>();
747  }
748 
749  auto beat_cnt = calculate_beats(trans);
750  SCCDEBUG(SCMOD) << "Starting transaction on channel WDAT : (opcode, cmd, addr, len) = ("
751  << to_char(data_ext->dat.get_opcode()) << ", " << trans.get_command() << ", " << std::hex
752  << trans.get_address() << ", " << trans.get_data_length() << ")";
753  if(!data_interleaving.get_value()) {
754  auto e = trans.get_extension<atp::timing_params>();
755  if(e) {
756  sem_lock l(prio_wdat_chnl);
757  auto clock_count = sc_core::sc_time_stamp().value() / clk_if->period().value();
758  while(clock_count < e->start_soonest) {
759  wait(clk_i.negedge_event());
760  clock_count = sc_core::sc_time_stamp().value() / clk_if->period().value();
761  }
762  wdat_chnl.wait(1);
763  auto time_offset = sc_core::sc_time_stamp() % clk_if->period();
764  } else
765  wdat_chnl.wait();
766  for(auto i = 0U; i < beat_cnt; ++i) {
767  if(i < beat_cnt - 1)
768  phase = chi::BEGIN_PARTIAL_DATA;
769  else
770  phase = chi::BEGIN_DATA;
771 
772  // transfer_width_in_bytes is bus_width in bytes, data_ID reference from table 13_42
773  data_ext->dat.set_data_id(i<<(transfer_width_in_bytes*8/128 -1));
774  SCCTRACE(SCMOD) << "WDAT flit with txnid " << data_ext->cmn.get_txn_id() << " data_id = " << (unsigned int)(data_ext->dat.get_data_id())<< " sent. Beat count: " << i
775  << ", addr: 0x" << std::hex << trans.get_address() << ", last=" << (i == (beat_cnt - 1));
776  send_packet(phase, trans, txs);
777  }
778  wdat_chnl.post();
779  } else { // data packet interleaving allowed
780  for(auto i = 0U; i < beat_cnt; ++i) {
781  {
782  sem_lock lck(wdat_chnl);
783  if(i < beat_cnt - 1)
784  phase = chi::BEGIN_PARTIAL_DATA;
785  else
786  phase = chi::BEGIN_DATA;
787 
788  data_ext->dat.set_data_id(i<<(transfer_width_in_bytes*8/128 -1));
789  SCCTRACE(SCMOD) << "WDAT flit with txnid " << data_ext->cmn.get_txn_id() << " data_id = " << (unsigned int)(data_ext->dat.get_data_id())<< " sent. Beat count: " << i
790  << ", addr: 0x" << std::hex << trans.get_address()
791  << ", last=" << (i == (beat_cnt - 1));
792  send_packet(phase, trans, txs);
793  }
794  wait(SC_ZERO_TIME); // yield execution to allow others to lock
795  }
796  }
797 }
798 
799 void chi::pe::chi_rn_initiator_b::send_comp_ack(payload_type& trans, tx_state*& txs) {
800  if(make_rsp_from_req(trans, chi::rsp_optype_e::CompAck)) {
801  sem_lock lck(sresp_chnl);
802  SCCDEBUG(SCMOD) << "Send the CompAck response on SRSP channel, addr: 0x" << std::hex << trans.get_address();
803  if(protocol_cb[SRSP])
804  protocol_cb[SRSP](SRSP, trans);
805  tlm::tlm_phase phase = chi::ACK;
806  auto delay = SC_ZERO_TIME;
807  auto ret = socket_fw->nb_transport_fw(trans, phase, delay);
808  if(ret == tlm::TLM_UPDATED && phase == chi::ACK) {
809  if(delay.value())
810  wait(delay);
811  } else {
812  auto entry = txs->peq.get();
813  sc_assert(std::get<0>(entry) == &trans && std::get<1>(entry) == tlm::END_RESP);
814  }
815  wait(clk_i.posedge_event()); // sync to clock before releasing resource
816  }
817 }
818 
819 bool expectCompCMO(chi::chi_ctrl_extension* ext){
820  switch(ext->req.get_opcode()){
821  case req_optype_e::WriteBackFullCleanSh:
822  case req_optype_e::WriteBackFullCleanInv:
823  case req_optype_e::WriteBackFullCleanShPerSep:
824  case req_optype_e::WriteCleanFullCleanSh:
825  case req_optype_e::WriteCleanFullCleanShPerSep:
826  case req_optype_e::WriteNoSnpFullCleanSh:
827  case req_optype_e::WriteNoSnpFullCleanInv:
828  case req_optype_e::WriteNoSnpFullCleanShPerSep:
829  case req_optype_e::WriteUniquePtlCleanSh:
830  case req_optype_e::WriteUniqueFullCleanSh:
831  case req_optype_e::WriteUniquePtlCleanShPerSep:
832  case req_optype_e::WriteUniqueFullCleanShPerSep:
833  return true;
834  default:
835  return false;
836  }
837 }
838 
839 bool expectPersist(chi::chi_ctrl_extension* ext){
840  switch(ext->req.get_opcode()){
841  case req_optype_e::WriteBackFullCleanShPerSep:
842  case req_optype_e::WriteCleanFullCleanShPerSep:
843  case req_optype_e::WriteNoSnpFullCleanShPerSep:
844  case req_optype_e::WriteUniquePtlCleanShPerSep:
845  case req_optype_e::WriteUniqueFullCleanShPerSep:
846  case req_optype_e::CleanSharedPersistSep:
847  return true;
848  default:
849  return false;
850  }
851 }
852 
853 enum { WAIT_CTRL=0x1, WAIT_DATA=0x2, WAIT_COMPCMO=4, WAIT_PERSIST=8};
854 void chi::pe::chi_rn_initiator_b::exec_read_write_protocol(const unsigned int txn_id, payload_type& trans,
856  // TODO: in write case CAIU does not send BEGIN_RESP;
857  sc_core::sc_time delay;
858  auto ctrl_ext = trans.get_extension<chi::chi_ctrl_extension>();
859  unsigned not_finish = WAIT_CTRL;
860  not_finish |= is_dataless(ctrl_ext)?0:WAIT_DATA;
861  not_finish |= expectCompCMO(ctrl_ext)?WAIT_COMPCMO:0;
862  not_finish |= expectPersist(ctrl_ext)?WAIT_PERSIST:0;
863  auto exp_beat_cnt = calculate_beats(trans);
864  auto beat_cnt = 0U;
865  while(not_finish) {
866  // waiting for response
867  auto entry = txs->peq.get();
868  sc_assert(std::get<0>(entry) == &trans);
869  auto phase = std::get<1>(entry);
870  if(phase == tlm::BEGIN_RESP) {
871  if(chi::is_dataless(ctrl_ext)){
872  switch(ctrl_ext->resp.get_opcode()) {
873  case chi::rsp_optype_e::Comp: // Response to dataless Make(Read)Unique request
874  if(ctrl_ext->req.get_opcode() == chi::req_optype_e::MakeReadUnique)
875  not_finish &= ~WAIT_CTRL;
876  else
877  switch(ctrl_ext->resp.get_resp()) {
878  case chi::rsp_resptype_e::Comp_I:
879  case chi::rsp_resptype_e::Comp_UC:
880  case chi::rsp_resptype_e::Comp_SC:
881  not_finish &= ~WAIT_CTRL;
882  break;
883  default:
884  break;
885  }
886  break;
887  case chi::rsp_optype_e::CompDBIDResp: // in case of WriteNoSnpZero, which is dataless
888  case chi::rsp_optype_e::CompPersist:
889  case chi::rsp_optype_e::CompCMO:
890  case chi::rsp_optype_e::CompStashDone:
891  not_finish &= ~WAIT_CTRL;
892  break;
893  case chi::rsp_optype_e::Persist:
894  not_finish &= ~WAIT_PERSIST;
895  break;
896  default:
897  break;
898  }
899  not_finish &= ~WAIT_DATA;
900  send_cresp_response(trans);
901  } else if(trans.is_write()) {
902  switch(ctrl_ext->resp.get_opcode()) {
903  case chi::rsp_optype_e::CompCMO:
904  not_finish &= ~WAIT_COMPCMO;
905  send_cresp_response(trans);
906  break;
907  case chi::rsp_optype_e::Persist:
908  not_finish &= ~WAIT_PERSIST;
909  send_cresp_response(trans);
910  break;
911  case chi::rsp_optype_e::CompDBIDResp:
912  not_finish &= ~WAIT_CTRL;
913  /* no break */
914  case chi::rsp_optype_e::DBIDResp:
915  case chi::rsp_optype_e::DBIDRespOrd:
916  send_cresp_response(trans);
917  send_wdata(trans, txs);
918  not_finish &= ~WAIT_DATA;
919  break;
920  case chi::rsp_optype_e::Comp:
921  not_finish &= ~WAIT_CTRL;
922  send_cresp_response(trans);
923  break;
924  default:
925  SCCFATAL(SCMOD) << "Illegal opcode received: " << to_char(ctrl_ext->resp.get_opcode());
926  }
927  } else if(trans.is_read()) {
928  not_finish &= ~WAIT_CTRL;
929  send_cresp_response(trans);
930  }
931  } else if(trans.is_read() && (phase == chi::BEGIN_PARTIAL_DATA || phase == chi::BEGIN_DATA)) {
932  SCCTRACE(SCMOD) << "RDAT flit received. Beat count: " << beat_cnt << ", addr: 0x" << std::hex
933  << trans.get_address();
934  if(protocol_cb[RDAT])
935  protocol_cb[RDAT](RDAT, trans);
936  phase = phase == chi::BEGIN_PARTIAL_DATA?(tlm::tlm_phase) chi::END_PARTIAL_DATA:(tlm::tlm_phase)END_DATA;
937  delay = clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : SC_ZERO_TIME;
938  socket_fw->nb_transport_fw(trans, phase, delay);
939  beat_cnt++;
940  if(phase == chi::END_DATA) {
941  not_finish &= ~(WAIT_CTRL | WAIT_DATA); // clear data bit
942  if(beat_cnt != exp_beat_cnt)
943  SCCERR(SCMOD) << "Wrong beat count, expected " << exp_beat_cnt << ", got " << beat_cnt;
944  }
945  } else {
946  SCCFATAL(SCMOD) << "Illegal protocol state (maybe just not implemented?)";
947  }
948  }
949 }
950 
951 void chi::pe::chi_rn_initiator_b::send_cresp_response(payload_type& trans) {
952  auto resp_ext = trans.get_extension<chi::chi_ctrl_extension>();
953  sc_assert(resp_ext != nullptr);
954  if(is_request_order(resp_ext))
955  req_order.post();
956  auto id = (unsigned)(resp_ext->get_txn_id());
957  SCCDEBUG(SCMOD) << "got cresp: src_id=" << (unsigned)resp_ext->get_src_id()
958  << ", tgt_id=" << (unsigned)resp_ext->resp.get_tgt_id()
959  << ", txnid=0x" << std::hex << id << ", " << to_char(resp_ext->resp.get_opcode())
960  << ", resp=" << to_char(resp_ext->resp.get_resp())
961  << ", db_id=" << (unsigned)resp_ext->resp.get_db_id() << ", addr=0x" << std::hex
962  << trans.get_address() << ")";
963  if(protocol_cb[CRSP])
964  protocol_cb[CRSP](CRSP, trans);
965  tlm::tlm_phase phase = tlm::END_RESP;
966  sc_core::sc_time delay = clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : SC_ZERO_TIME;
967  socket_fw->nb_transport_fw(trans, phase, delay);
968  wait(clk_i.posedge_event());
969 }
970 
971 void chi::pe::chi_rn_initiator_b::exec_atomic_protocol(const unsigned int txn_id, payload_type& trans,
973  sc_core::sc_time delay;
974  // waiting for response
975  auto entry = txs->peq.get();
976  sc_assert(std::get<0>(entry) == &trans);
977  auto phase = std::get<1>(entry);
978  if(phase == tlm::BEGIN_RESP) {
979  send_cresp_response(trans);
980  auto resp_ext = trans.get_extension<chi::chi_ctrl_extension>();
981  if(resp_ext->resp.get_opcode() == chi::rsp_optype_e::DBIDResp) {
982  SCCERR(SCMOD) << "CRESP illegal response opcode: " << to_char(resp_ext->resp.get_opcode());
983  }
984  } else {
985  SCCERR(SCMOD) << "Illegal protocol state (maybe just not implemented?) " << phase;
986  }
987 
988  auto not_finish = 0b11U; // bit0: sending data ongoing, bit1: receiving data ongoing
989  auto exp_beat_cnt = calculate_beats(trans);
990  auto input_beat_cnt = 0U;
991  auto output_beat_cnt = 0U;
992 
993  sem_lock lck(wdat_chnl);
994  while(not_finish) {
997  if(output_beat_cnt < exp_beat_cnt) {
998  ;
999  if(auto data_ext = trans.get_extension<chi::chi_data_extension>()) {
1000  update_data_extension(data_ext, trans);
1001  } else {
1002  create_data_ext(trans);
1003  }
1004  output_beat_cnt++;
1005  SCCDEBUG(SCMOD) << "Atomic send data (txn_id,opcode,cmd,addr,len) = (" << txn_id << ","
1006  << to_char(trans.get_extension<chi::chi_data_extension>()->dat.get_opcode()) << ", "
1007  << trans.get_command() << ",0x" << std::hex << trans.get_address() << ","
1008  << trans.get_data_length() << "), beat=" << output_beat_cnt << "/" << exp_beat_cnt;
1009  if(output_beat_cnt < exp_beat_cnt)
1010  phase = chi::BEGIN_PARTIAL_DATA;
1011  else
1012  phase = chi::BEGIN_DATA;
1013  send_packet(phase, trans, txs);
1014  if(output_beat_cnt == exp_beat_cnt) {
1015  wait(clk_i.posedge_event()); // sync to clock before releasing resource
1016  not_finish &= 0x2; // clear bit0
1017  }
1018  }
1020  if(input_beat_cnt < exp_beat_cnt && txs->peq.has_next()) {
1021 
1022  // waiting for response
1023  auto entry = txs->peq.get();
1024  sc_assert(std::get<0>(entry) == &trans);
1025  phase = std::get<1>(entry);
1026 
1027  if(phase == chi::BEGIN_PARTIAL_DATA || phase == chi::BEGIN_DATA) {
1028  auto data_ext = trans.get_extension<chi::chi_data_extension>();
1029  sc_assert(data_ext);
1030  input_beat_cnt++;
1031  SCCDEBUG(SCMOD) << "Atomic received data (txn_id,opcode,cmd,addr,len)=(" << txn_id << ","
1032  << to_char(data_ext->dat.get_opcode()) << "," << trans.get_command() << ",0x"
1033  << std::hex << trans.get_address() << "," << trans.get_data_length()
1034  << "), beat=" << input_beat_cnt << "/" << exp_beat_cnt;
1035  if(protocol_cb[RDAT])
1036  protocol_cb[RDAT](RDAT, trans);
1037  phase = phase == chi::BEGIN_PARTIAL_DATA?(tlm::tlm_phase) chi::END_PARTIAL_DATA:(tlm::tlm_phase)END_DATA;
1038  delay = clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : SC_ZERO_TIME;
1039  socket_fw->nb_transport_fw(trans, phase, delay);
1040  if(phase == chi::END_DATA) {
1041  not_finish &= 0x1; // clear bit1
1042  if(input_beat_cnt != exp_beat_cnt)
1043  SCCERR(SCMOD) << "Wrong beat count, expected " << exp_beat_cnt << ", got " << input_beat_cnt;
1044  }
1045  } else {
1046  SCCERR(SCMOD) << "Illegal protocol state: " << phase;
1047  }
1048  } else if(output_beat_cnt == exp_beat_cnt)
1049  wait(txs->peq.event());
1050  }
1051 }
1052 
1053 void chi::pe::chi_rn_initiator_b::transport(payload_type& trans, bool blocking) {
1054  SCCTRACE(SCMOD) << "got transport req";
1055  if(blocking) {
1056  sc_time t;
1057  socket_fw->b_transport(trans, t);
1058  } else {
1059  auto req_ext = trans.get_extension<chi_ctrl_extension>();
1060  if(!req_ext) {
1061  convert_axi4ace_to_chi(trans, name(), use_legacy_mapping.get_value());
1062  req_ext = trans.get_extension<chi_ctrl_extension>();
1063  sc_assert(req_ext != nullptr);
1064  }
1065  req_ext->set_src_id(src_id.get_value());
1066  req_ext->req.set_tgt_id(tgt_id.get_value());
1067  req_ext->req.set_max_flit(calculate_beats(trans) - 1);
1068  tx_waiting++;
1069  auto it = tx_state_by_trans.find(to_id(trans));
1070  if(it == tx_state_by_trans.end()) {
1071  if(!tx_state_pool.size())
1072  tx_state_pool.push_back(new tx_state(util::strprintf("peq_%d", ++peq_cnt)));
1073  bool success;
1074  std::tie(it, success) = tx_state_by_trans.insert({to_id(trans), tx_state_pool.back()});
1075  tx_state_pool.pop_back();
1076  }
1077  auto& txs = it->second;
1078  auto const txn_id = req_ext->get_txn_id();
1079  if(chi::is_request_order(req_ext)) {
1080  req_order.wait();
1081  }
1082  if(strict_income_order.get_value()) strict_order_sem.wait();
1083  sem_lock txnlck(active_tx_by_id[txn_id]); // wait until running tx with same id is over
1084  tx_waiting4crd++;
1085  tx_waiting--;
1086  if(strict_income_order.get_value()) strict_order_sem.post();
1087  setExpCompAck(req_ext);
1089  auto timing_e = trans.get_extension<atp::timing_params>();
1090  if(timing_e != nullptr) { // TPU as it has been defined in TPU
1091  auto delay_in_cycles = trans.is_read() ? timing_e->artv : timing_e->awtv;
1092  auto current_count = get_clk_cnt();
1093  if(current_count - m_prev_clk_cnt < delay_in_cycles) {
1094  unsigned delta_cycles = delay_in_cycles - (current_count - m_prev_clk_cnt);
1095  while(delta_cycles) {
1096  delta_cycles--;
1097  wait(clk_i.posedge_event());
1098  }
1099  }
1100  } // no timing info in case of STL
1101  {
1102  sem_lock lck(req_chnl);
1103  // Check if Link-credits are available for sending this transaction and wait if not
1104  req_credits.wait();
1105  tx_outstanding++;
1106  tx_waiting4crd--;
1107  SCCTRACE(SCMOD) << "starting transaction with txn_id=" << txn_id;
1108  m_prev_clk_cnt = get_clk_cnt();
1109  SCCTRACE(SCMOD) << "Send REQ, addr: 0x" << std::hex << trans.get_address() << ", TxnID: 0x" << std::hex
1110  << txn_id;
1111  if(protocol_cb[REQ])
1112  protocol_cb[REQ](REQ, trans);
1113  tlm::tlm_phase phase = tlm::BEGIN_REQ;
1114  sc_core::sc_time delay;
1115  tlm::tlm_sync_enum ret = socket_fw->nb_transport_fw(trans, phase, delay);
1116  if(ret == tlm::TLM_UPDATED) {
1117  sc_assert(phase == tlm::END_REQ);
1118  wait(delay);
1119  } else {
1120  auto entry = txs->peq.get();
1121  sc_assert(std::get<0>(entry) == &trans && std::get<1>(entry) == tlm::END_REQ);
1122  }
1123  auto credit_ext = trans.get_extension<chi_credit_extension>();
1124  wait(clk_i.posedge_event()); // sync to clock before releasing resource
1125  if(credit_ext) {
1126  if(credit_ext->type == credit_type_e::REQ) {
1127  SCCTRACEALL(SCMOD) << "Received " << credit_ext->count << " req "
1128  << (credit_ext->count == 1 ? "credit" : "credits");
1129  for(auto i = 0U; i < credit_ext->count; ++i)
1130  req_credits.post();
1131  trans.set_auto_extension<chi_credit_extension>(nullptr);
1132  }
1133  }
1134  }
1135 
1136  if((req_optype_e::AtomicLoadAdd <= req_ext->req.get_opcode()) &&
1137  (req_ext->req.get_opcode() <= req_optype_e::AtomicCompare))
1138  exec_atomic_protocol(txn_id, trans, txs);
1139  else {
1140  exec_read_write_protocol(txn_id, trans, txs);
1141  bool is_atomic = req_ext->req.get_opcode() >= req_optype_e::AtomicStoreAdd &&
1142  req_ext->req.get_opcode() <= req_optype_e::AtomicCompare;
1143  bool compack_allowed = true;
1144  switch(req_ext->req.get_opcode()) {
1145  case req_optype_e::WriteUniqueFullStash:
1146  case req_optype_e::WriteUniquePtlStash:
1147  case req_optype_e::StashOnceShared:
1148  case req_optype_e::StashOnceUnique:
1149  case req_optype_e::WriteBackPtl:
1150  case req_optype_e::WriteBackFull:
1151  case req_optype_e::WriteCleanFull:
1152  case req_optype_e::WriteCleanPtl:
1153  case req_optype_e::CleanSharedPersistSep:
1154  case req_optype_e::WriteEvictFull:
1155  case req_optype_e::WriteUniqueZero:
1156  case req_optype_e::WriteNoSnpZero:
1157  case req_optype_e::StashOnceSepShared:
1158  case req_optype_e::StashOnceSepUnique:
1159  case req_optype_e::WriteBackFullCleanSh:
1160  case req_optype_e::WriteBackFullCleanInv:
1161  case req_optype_e::WriteBackFullCleanShPerSep:
1162  case req_optype_e::WriteCleanFullCleanSh :
1163  case req_optype_e::WriteCleanFullCleanShPerSep:
1164  compack_allowed = false;
1165  break;
1166  default:
1167  break;
1168  }
1169  if(!is_atomic && compack_allowed && req_ext->req.is_exp_comp_ack())
1170  send_comp_ack(trans, txs);
1171  }
1172 
1173  trans.set_response_status(tlm::TLM_OK_RESPONSE);
1174  wait(clk_i.posedge_event()); // sync to clock
1175  tx_state_pool.push_back(it->second);
1176  tx_state_pool.back()->peq.clear();
1177  tx_state_by_trans.erase(it);
1178  SCCTRACE(SCMOD) << "finished non-blocking protocol";
1179  any_tx_finished.notify(SC_ZERO_TIME);
1180  tx_outstanding--;
1181  }
1182 }
1183 
1184 void chi::pe::chi_rn_initiator_b::handle_snoop_response(payload_type& trans,
1186  auto ext = trans.get_extension<chi_data_extension>();
1187  tlm::tlm_phase phase;
1188  sc_time delay;
1189  if(ext) {
1190  ext->set_src_id(src_id.get_value());
1191  send_wdata(trans, txs);
1192  snp_counter--;
1193  return;
1194  }
1195  // dataless response or stash
1196  auto snp_ext = trans.get_extension<chi_snp_extension>();
1197  sc_assert(snp_ext != nullptr);
1198 
1199  snp_ext->set_src_id(src_id.get_value());
1200  snp_ext->resp.set_tgt_id(snp_ext->get_src_id());
1201  snp_ext->resp.set_db_id(snp_ext->get_txn_id());
1202 
1203  phase = tlm::BEGIN_RESP; // SRSP channel
1204  delay = SC_ZERO_TIME;
1205  auto not_finish =
1206  snp_ext->resp.get_data_pull() ? 0b11U : 0b10U; // bit0: data is ongoing, bit1: ctrl resp. is ongoing
1207  {
1208  auto e = trans.get_extension<atp::timing_params>();
1209  if(e) {
1210  sem_lock l(prio_sresp_chnl);
1211  while(get_clk_cnt() < e->start_soonest) {
1212  wait(clk_i.negedge_event());
1213  }
1214  sresp_chnl.wait(1);
1215  wait(clk_i.posedge_event());
1216  } else
1217  sresp_chnl.wait();
1218  if(protocol_cb[SRSP])
1219  protocol_cb[SRSP](SRSP, trans);
1220  auto ret = socket_fw->nb_transport_fw(trans, phase, delay);
1221  if(ret == tlm::TLM_UPDATED) {
1222  sc_assert(phase == tlm::END_RESP); // SRSP channel
1223  wait(delay);
1224  not_finish &= 0x1; // clear bit1
1225  }
1226  wait(clk_i.posedge_event()); // sync to clock before releasing resource
1227  sresp_chnl.post();
1228  }
1229  if(snp_ext->resp.get_data_pull() && trans.get_data_length() < 64) {
1230  delete[] trans.get_data_ptr();
1231  trans.set_data_ptr(new uint8_t[64]);
1232  trans.set_data_length(64);
1233  }
1234  auto exp_beat_cnt = calculate_beats(trans);
1235  auto beat_cnt = 0U;
1236  while(not_finish) {
1237  // waiting for response
1238  auto entry = txs->peq.get();
1239  sc_assert(std::get<0>(entry) == &trans);
1240  auto phase = std::get<1>(entry);
1241  if(phase == tlm::END_RESP) {
1242  not_finish &= 0x1; // clear bit1
1243  } else if(snp_ext->resp.get_data_pull() && (phase == chi::BEGIN_PARTIAL_DATA || phase == chi::BEGIN_DATA)) {
1244  SCCTRACE(SCMOD) << "RDAT packet received with phase " << phase << ". Beat count: " << beat_cnt
1245  << ", addr: 0x" << std::hex << trans.get_address();
1246  not_finish &= 0x1; // clear bit1
1247  if(protocol_cb[WDAT])
1248  protocol_cb[WDAT](WDAT, trans);
1249  phase = phase == chi::BEGIN_PARTIAL_DATA?(tlm::tlm_phase) chi::END_PARTIAL_DATA:(tlm::tlm_phase)END_DATA;
1250  delay = clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : SC_ZERO_TIME;
1251  socket_fw->nb_transport_fw(trans, phase, delay);
1252  beat_cnt++;
1253  if(phase == chi::END_DATA) {
1254  not_finish &= 0x2; // clear bit0
1255  if(beat_cnt != exp_beat_cnt)
1256  SCCERR(SCMOD) << "Wrong beat count, expected " << exp_beat_cnt << ", got " << beat_cnt;
1257  if(bw_o.get_interface())
1258  bw_o->transport(trans); //FIXME: explain why this needs to be called- Maybe stash?
1259  }
1260 
1261  } else {
1262  SCCFATAL(SCMOD) << "Illegal protocol state (maybe just not implemented?)";
1263  }
1264  }
1265  snp_counter--;
1266  wait(clk_i.posedge_event()); // sync to clock before releasing resource
1267  if(snp_ext->resp.get_data_pull())
1268  send_comp_ack(trans, txs);
1269 }
1270 
1271 // This process handles the SNOOP request received from ICN/HN and dispatches them to the snoop_handler threads
1272 void chi::pe::chi_rn_initiator_b::snoop_dispatch() {
1273  sc_core::sc_spawn_options opts;
1274  opts.set_stack_size(0x10000);
1275  payload_type* trans{nullptr};
1276  while(true) {
1277  while(!(trans = snp_peq.get_next_transaction())) {
1278  wait(snp_peq.get_event());
1279  }
1280  if(thread_avail == 0 && thread_active < 32) {
1281  sc_core::sc_spawn(
1282  [this]() {
1283  payload_type* trans{nullptr};
1284  thread_avail++;
1285  thread_active++;
1286  while(true) {
1287  while(!(trans = snp_dispatch_que.get_next_transaction()))
1288  wait(snp_dispatch_que.get_event());
1289  sc_assert(thread_avail > 0);
1290  thread_avail--;
1291  this->snoop_handler(trans);
1292  thread_avail++;
1293  }
1294  },
1295  nullptr, &opts);
1296  }
1297  snp_dispatch_que.notify(*trans);
1298  }
1299 }
1300 
1301 void chi::pe::chi_rn_initiator_b::snoop_handler(payload_type* trans) {
1302  auto req_ext = trans->get_extension<chi_snp_extension>();
1303  sc_assert(req_ext != nullptr);
1304  auto const txn_id = req_ext->get_txn_id();
1305 
1306  SCCDEBUG(SCMOD) << "Received SNOOP request: (src_id, txn_id, opcode, command, address) = " << req_ext->get_src_id()
1307  << ", " << txn_id << ", " << to_char(req_ext->req.get_opcode()) << ", "
1308  << (trans->is_read() ? "READ" : "WRITE") << ", " << std::hex << trans->get_address() << ")";
1309 
1310  auto it = tx_state_by_trans.find(to_id(trans));
1311  if(it == tx_state_by_trans.end()) {
1312  if(!tx_state_pool.size())
1313  tx_state_pool.push_back(new tx_state(util::strprintf("peq_%d", ++peq_cnt)));
1314  bool success;
1315  std::tie(it, success) = tx_state_by_trans.insert({to_id(trans), tx_state_pool.back()});
1316  tx_state_pool.pop_back();
1317  }
1318  auto* txs = it->second;
1319 
1320  if(protocol_cb[SNP])
1321  protocol_cb[SNP](SNP, *trans);
1322  sc_time delay = clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : SC_ZERO_TIME;
1323  tlm::tlm_phase phase = tlm::END_REQ;
1324  socket_fw->nb_transport_fw(*trans, phase, delay);
1325  auto cycles = 0U;
1326  if(bw_o.get_interface())
1327  cycles = bw_o->transport(*trans);
1328  if(cycles < std::numeric_limits<unsigned>::max()) {
1329  // we handle the snoop access ourselfs
1330  // for(size_t i = 0; i < cycles + 1; ++i)
1331  // wait(clk_i.posedge_event());
1332  auto clock_count = sc_core::sc_time_stamp().value() / clk_if->period().value();
1333  auto e = new atp::timing_params(clock_count + cycles - 2);
1334  trans->set_auto_extension(e);
1335 
1336  handle_snoop_response(*trans, txs);
1337  tx_state_pool.push_back(it->second);
1338  tx_state_pool.back()->peq.clear();
1339  tx_state_by_trans.erase(to_id(trans));
1340  if(trans->has_mm())
1341  trans->release();
1342  }
1343 }
1344 
1345 void chi::pe::chi_rn_initiator_b::grant_credit(unsigned amount){
1346  tlm::tlm_phase ph = tlm::BEGIN_REQ;
1347  auto t = sc_core::SC_ZERO_TIME;
1349  auto ext = gp->template get_extension<chi_credit_extension>();
1350  ext->type = credit_type_e::REQ;
1351  ext->count = amount;
1352  socket_fw->nb_transport_fw(*gp, ph, t);
1353 }
void transport(payload_type &trans, bool blocking) override
The forward transport function. It behaves blocking and is re-entrant.
void snoop_resp(payload_type &trans, bool sync=false) override
triggers a non-blocking snoop response if the snoop callback does not do so.
payload_type * allocate()
get a plain tlm_payload_type without extensions
Definition: tlm_mm.h:185
@ MEMORY_BARRIER
Normal access, respecting barriers.
const char * to_char(E t)
TLM2.0 components modeling CHI.
Definition: chi_tlm.cpp:21
tlm::tlm_fw_transport_if< TYPES > chi_fw_transport_if
alias declaration for the forward interface
Definition: chi_tlm.h:912
const char * to_char(E t)
std::string strprintf(const std::string format,...)
allocate and print to a string buffer
Definition: strprintf.h:35
unsigned int get_id() const
Definition: axi_tlm.h:1299
uint8_t get_qos() const
get the AxQOS (quality of service) value
Definition: axi_tlm.h:1500
unsigned int get_txn_id() const
Definition: chi_tlm.h:1154
a lock for the semaphore
TYPE get()
blocking get
Definition: peq.h:128
sc_core::sc_event & event()
get the available event
Definition: peq.h:140
static tlm_mm & get()
accessor function of the singleton
Definition: tlm_mm.h:293