scc 2026.07
SystemC components library
axi_tlm.cpp
1/*
2 * Copyright 2020 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#include "axi_tlm.h"
18#include <tlm/scc/scv/tlm_extension_recording_registry.h>
19
20namespace axi {
21
22namespace {
23std::array<std::string, 3> cmd_str{"R", "W", "I"};
24}
25
26template <> const char* to_char<snoop_e>(snoop_e v) {
27 switch(v) {
28 case snoop_e::READ_NO_SNOOP:
29 return "READ_NO_SNOOP"; //= 0x10
30 case snoop_e::READ_ONCE:
31 return "READ_ONCE"; //= 0
32 case snoop_e::READ_SHARED:
33 return "READ_SHARED"; // = 1,
34 case snoop_e::READ_CLEAN:
35 return "READ_CLEAN"; // = 2,
36 case snoop_e::READ_NOT_SHARED_DIRTY:
37 return "READ_NOT_SHARED_DIRTY"; // = 0x3,
38 case snoop_e::READ_UNIQUE:
39 return "READ_UNIQUE"; // = 0x7,
40 case snoop_e::CLEAN_SHARED:
41 return "CLEAN_SHARED"; // = 0x8,
42 case snoop_e::CLEAN_INVALID:
43 return "CLEAN_INVALID"; // = 0x9,
44 case snoop_e::CLEAN_SHARED_PERSIST:
45 return "CLEAN_SHARED_PERSIST"; // = 0xa,
46 case snoop_e::CLEAN_UNIQUE:
47 return "CLEAN_UNIQUE"; // = 0xb,
48 case snoop_e::MAKE_UNIQUE:
49 return "MAKE_UNIQUE"; // = 0xc,
50 case snoop_e::MAKE_INVALID:
51 return "MAKE_INVALID"; // = 0xd,
52 case snoop_e::DVM_COMPLETE:
53 return "DVM_COMPLETE"; // = 0xe,
54 case snoop_e::DVM_MESSAGE:
55 return "DVM_MESSAGE"; // = 0xf
56 case snoop_e::BARRIER:
57 return "BARRIER"; // = 0x40,
58 case snoop_e::WRITE_NO_SNOOP:
59 return "WRITE_NO_SNOOP"; //= 0x30
60 case snoop_e::WRITE_UNIQUE:
61 return "WRITE_UNIQUE"; //= 0x20
62 case snoop_e::WRITE_LINE_UNIQUE:
63 return "WRITE_LINE_UNIQUE"; // = 0x21,
64 case snoop_e::WRITE_CLEAN:
65 return "WRITE_CLEAN"; // = 0x22,
66 case snoop_e::WRITE_BACK:
67 return "WRITE_BACK"; // = 0x23,
68 case snoop_e::EVICT:
69 return "EVICT"; // = 0x24,
70 case snoop_e::WRITE_EVICT:
71 return "WRITE_EVICT"; // = 0x25,
72 case snoop_e::CMO_ON_WRITE:
73 return "CMO_ON_WRITE"; // = 0x26,
74 case snoop_e::WRITE_UNIQUE_PTL_STASH:
75 return "WRITE_UNIQUE_PTL_STASH"; // = 0x28,
76 case snoop_e::WRITE_UNIQUE_FULL_STASH:
77 return "WRITE_UNIQUE_FULL_STASH"; // = 0x29,
78 case snoop_e::STASH_ONCE_SHARED:
79 return "STASH_ONCE_SHARED"; // = 0x2c,
80 case snoop_e::STASH_ONCE_UNIQUE:
81 return "STASH_ONCE_UNIQUE"; // = 0x2d,
82 case snoop_e::STASH_TRANSLATION:
83 return "STASH_TRANSLATION"; // = 0x2e,
84 default:
85 return "reserved";
86 };
87}
88
89template <> const char* to_char<burst_e>(burst_e v) {
90 switch(v) {
91 case burst_e::FIXED:
92 return "FIXED";
93 case burst_e::INCR:
94 return "INCR";
95 case burst_e::WRAP:
96 return "WRAP";
97 default:
98 return "UNKNOWN";
99 }
100}
101
102template <> const char* to_char<lock_e>(lock_e v) {
103 switch(v) {
104 case lock_e::NORMAL:
105 return "NORMAL";
106 case lock_e::EXLUSIVE:
107 return "EXLUSIVE";
108 case lock_e::LOCKED:
109 return "LOCKED";
110 default:
111 return "UNKNOWN";
112 }
113}
114
115template <> const char* to_char<domain_e>(domain_e v) {
116 switch(v) {
117 case domain_e::NON_SHAREABLE:
118 return "NON_SHAREABLE";
119 case domain_e::INNER_SHAREABLE:
120 return "INNER_SHAREABLE";
121 case domain_e::OUTER_SHAREABLE:
122 return "OUTER_SHAREABLE";
123 case domain_e::SYSTEM:
124 return "SYSTEM";
125 default:
126 return "UNKNOWN";
127 }
128}
129
130template <> const char* to_char<bar_e>(bar_e v) {
131 switch(v) {
132 case bar_e::RESPECT_BARRIER:
133 return "RESPECT_BARRIER";
135 return "MEMORY_BARRIER";
137 return "IGNORE_BARRIER";
139 return "SYNCHRONISATION_BARRIER";
140 default:
141 return "UNKNOWN";
142 }
143}
144
145template <> const char* to_char<resp_e>(resp_e v) {
146 switch(v) {
147 case resp_e::OKAY:
148 return "OKAY";
149 case resp_e::EXOKAY:
150 return "EXOKAY";
151 case resp_e::SLVERR:
152 return "SLVERR";
153 case resp_e::DECERR:
154 return "DECERR";
155 default:
156 return "OTHER";
157 }
158}
159
160std::ostream& operator<<(std::ostream& os, const tlm::tlm_generic_payload& t) {
161 char const* ch = t.get_command() == tlm::TLM_READ_COMMAND ? "AR" : (t.get_command() == tlm::TLM_WRITE_COMMAND ? "AW" : "");
162 os << "CMD:" << cmd_str[t.get_command()] << ", " << ch << "ADDR:0x" << std::hex << t.get_address() << ", TXLEN:0x"
163 << t.get_data_length();
164 if(auto e = t.get_extension<axi::ace_extension>()) {
165 os << ", " << ch << "ID:" << e->get_id() << ", " << ch << "LEN:0x" << std::hex << static_cast<unsigned>(e->get_length()) << ", "
166 << ch << "SIZE:0x" << static_cast<unsigned>(e->get_size()) << std::dec << ", " << ch << "BURST:" << to_char(e->get_burst())
167 << ", " << ch << "PROT:" << static_cast<unsigned>(e->get_prot()) << ", " << ch
168 << "CACHE:" << static_cast<unsigned>(e->get_cache()) << ", " << ch << "QOS:" << static_cast<unsigned>(e->get_qos()) << ", " << ch
169 << "REGION:" << static_cast<unsigned>(e->get_region()) << ", " << ch << "SNOOP:0x" << std::hex
170 << (static_cast<unsigned>(e->get_snoop()) & 0xf) << std::dec << ", " << ch << "DOMAIN:" << to_char(e->get_domain()) << ", " << ch
171 << "BAR:" << to_char(e->get_barrier()) << ", " << ch << "UNIQUE:" << e->get_unique();
172 } else if(auto e = t.get_extension<axi::axi4_extension>()) {
173 os << ", " << ch << "ID:" << e->get_id() << ", " << ch << "LEN:0x" << std::hex << static_cast<unsigned>(e->get_length()) << ", "
174 << ch << "SIZE:0x" << static_cast<unsigned>(e->get_size()) << std::dec << ", " << ch << "BURST:" << to_char(e->get_burst())
175 << ", " << ch << "PROT:" << static_cast<unsigned>(e->get_prot()) << ", " << ch
176 << "CACHE:" << static_cast<unsigned>(e->get_cache()) << ", " << ch << "QOS:" << static_cast<unsigned>(e->get_qos()) << ", " << ch
177 << "REGION:" << static_cast<unsigned>(e->get_region());
178 } else if(auto e = t.get_extension<axi::axi3_extension>()) {
179 os << ", " << ch << "ID:" << e->get_id() << ", " << ch << "LEN:0x" << std::hex << static_cast<unsigned>(e->get_length()) << ", "
180 << ch << "SIZE:0x" << static_cast<unsigned>(e->get_size()) << std::dec << ", " << ch << "BURST:" << to_char(e->get_burst())
181 << ", " << ch << "PROT:" << static_cast<unsigned>(e->get_prot()) << ", " << ch
182 << "CACHE:" << static_cast<unsigned>(e->get_cache()) << ", " << ch << "QOS:" << static_cast<unsigned>(e->get_qos()) << ", " << ch
183 << "REGION:" << static_cast<unsigned>(e->get_region());
184 }
185 os << " [ptr:" << &t << "]";
186 return os;
187}
188
189namespace {
190const std::array<std::array<bool, 4>, 16> rd_valid{{
191 {true, true, true, true}, // ReadNoSnoop/ReadOnce
192 {false, true, true, false}, // ReadShared
193 {false, true, true, false}, // ReadClean
194 {false, true, true, false}, // ReadNotSharedDirty
195 {false, true, true, false}, // ReadOnceCleanInvalid (ACE5)
196 {false, true, true, false}, // ReadOnceMakeInvalid (ACE5)
197 {false, false, false, false}, //
198 {false, true, true, false}, // ReadUnique
199 {true, true, true, false}, // CleanShared
200 {true, true, true, false}, // CleanInvalid
201 {false, true, true, false}, // CleanSharedPersist (ACE5)
202 {false, true, true, false}, // CleanUnique
203 {false, true, true, false}, // MakeUnique
204 {true, true, true, false}, // MakeInvalid
205 {false, true, true, false}, // DVM Complete
206 {false, true, true, false} // DVM Message
207}};
208const std::array<std::array<bool, 4>, 16> wr_valid{{
209 {true, true, true, true}, // WriteNoSnoop/WriteUnique
210 {false, true, true, false}, // WriteLineUnique
211 {true, true, true, false}, // WriteClean
212 {true, true, true, false}, // WriteBack
213 {false, true, true, false}, // Evict
214 {true, true, true, false}, // WriteEvict
215 {false, false, false, false}, // CmoOnWrite (ACE5L)
216 {false, false, false, false}, //
217 {true, true, true, false}, // WriteUniquePtlStash (ACE5L)
218 {true, true, true, false}, // CleanInvalid
219 {false, true, true, false}, // WriteUniqueFullStash (ACE5L)
220 {false, false, false, false}, //
221 {true, true, true, false}, // StashOnceShared (ACE5L)
222 {false, true, true, false}, // StashOnceUnique (ACE5L)
223 {false, true, true, false}, // StashTranslation (ACE5L)
224 {false, false, false, false} //
225}};
226} // namespace
227template <> char const* is_valid_msg<axi::ace_extension>(axi::ace_extension* ext) {
228 auto snoop = to_int(ext->get_snoop());
229 auto cache = ext->get_cache();
230 auto domain = ext->get_domain();
231 if(snoop < 32) { // a read access
232 if(!rd_valid[snoop & 0xf][to_int(domain)])
233 return "illegal read snoop value";
234 } else {
235 if(!wr_valid[snoop & 0xf][to_int(ext->get_domain())])
236 return "illegal write snoop value";
237 }
238 if(cache < 2 && domain != axi::domain_e::SYSTEM)
239 return "non-cacheable transactions require AXDOMAIN setting of SYSTEM(0x3) based on specification";
240 if(cache > 3 && domain == axi::domain_e::SYSTEM)
241 return "cacheable transaction must not set AXDOMAIN to SYSTEM(0x3) based on specification";
242 if((cache & 2) == 0 && domain != domain_e::NON_SHAREABLE && domain != domain_e::SYSTEM) {
243 if(domain != domain_e::INNER_SHAREABLE)
244 return "illegal AXDOMAIN=INNER_SHAREABLE(0x1) for no non-cacheable access";
245 return "illegal AXDOMAIN=OUTER_SHAREABLE(0x2) for no non-cacheable access";
246 }
247 // check table ED3-7 and D3-8 of IHI0022H
248 switch(ext->get_snoop()) {
249 case snoop_e::READ_NO_SNOOP:
250 if(domain != domain_e::NON_SHAREABLE && domain != domain_e::SYSTEM)
251 return "illegal AXDOMAIN for no non-coherent READ_NO_SNOOP access";
252 break;
253 case snoop_e::WRITE_NO_SNOOP: // non coherent access to coherent domain
254 if(domain != domain_e::NON_SHAREABLE && domain != domain_e::SYSTEM)
255 return "illegal AXDOMAIN for no non-coherent WRITE_NO_SNOOP access";
256 break;
257 case snoop_e::READ_ONCE:
258 case snoop_e::READ_SHARED:
259 case snoop_e::READ_CLEAN:
260 case snoop_e::READ_NOT_SHARED_DIRTY:
261 case snoop_e::READ_UNIQUE:
262 case snoop_e::MAKE_UNIQUE:
263 case snoop_e::DVM_COMPLETE:
264 case snoop_e::DVM_MESSAGE:
265 case snoop_e::WRITE_UNIQUE:
266 case snoop_e::WRITE_LINE_UNIQUE:
267 case snoop_e::EVICT:
268 if(domain != domain_e::INNER_SHAREABLE && domain != domain_e::OUTER_SHAREABLE) {
269 if(domain != domain_e::NON_SHAREABLE)
270 return "illegal AXDOMAIN=NON_SHAREABLE(0x0) for coherent access";
271 return "illegal AXDOMAIN=SYSTEM(0x3) for coherent access";
272 }
273 break;
274 case snoop_e::CLEAN_SHARED:
275 case snoop_e::CLEAN_INVALID:
276 case snoop_e::MAKE_INVALID:
277 case snoop_e::WRITE_CLEAN:
278 case snoop_e::WRITE_BACK:
279 case snoop_e::WRITE_EVICT:
280 if(domain == domain_e::SYSTEM) {
281 return "illegal AXDOMAIN=SYSTEM(0x3) for coherent access";
282 }
283 break;
284 default:
285 break;
286 }
287 if((ext->get_barrier() == bar_e::MEMORY_BARRIER || ext->get_barrier() == bar_e::SYNCHRONISATION_BARRIER) && (snoop & 0xf) != 0)
288 return "illegal barrier/snoop value combination";
289 switch(cache) {
290 case 4:
291 case 5:
292 case 8:
293 case 9:
294 case 12:
295 case 13:
296 return "reserved AxCACHE value";
297 default:
298 break;
299 }
300 return nullptr;
301}
302
303template <> char const* is_valid_msg<axi::axi4_extension>(axi::axi4_extension* ext) {
304 switch(ext->get_cache()) {
305 case 4:
306 case 5:
307 case 8:
308 case 9:
309 case 12:
310 case 13:
311 return "reserved AxCACHE value";
312 }
313 return nullptr;
314}
315
316template <> char const* is_valid_msg<axi::axi3_extension>(axi::axi3_extension* ext) {
317 switch(ext->get_cache()) {
318 case 4:
319 case 5:
320 case 8:
321 case 9:
322 case 12:
323 case 13:
324 return "illegal AxCACHE value";
325 }
326 return nullptr;
327}
328} // namespace axi
TLM2.0 components modeling AHB.
const char * to_char(E t)
domain_e
Definition axi_tlm.h:84
bar_e
Definition axi_tlm.h:88
@ MEMORY_BARRIER
Normal access, respecting barriers.
Definition axi_tlm.h:90
@ SYNCHRONISATION_BARRIER
Normal access, ignoring barriers.
Definition axi_tlm.h:92
@ IGNORE_BARRIER
Memory barrier.
Definition axi_tlm.h:91
burst_e
Definition axi_tlm.h:72
snoop_e
Definition axi_tlm.h:98
constexpr ULT to_int(E t)
Definition axi_tlm.h:46
lock_e
Definition axi_tlm.h:80
resp_e
Definition axi_tlm.h:155
bar_e get_barrier() const
get the AxBAR value return the barrier value
Definition axi_tlm.h:1509
snoop_e get_snoop() const
get the AxSNOOP value return the snoop value
Definition axi_tlm.h:1505
domain_e get_domain() const
get the AxDOMAIN value return the domain value
Definition axi_tlm.h:1501
uint8_t get_cache() const
get the AxCACHE value as POD
Definition axi_tlm.h:1497