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