scc 2025.09
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 =
162 t.get_command() == tlm::TLM_READ_COMMAND ? "AR" : (t.get_command() == tlm::TLM_WRITE_COMMAND ? "AW" : "");
163 os << "CMD:" << cmd_str[t.get_command()] << ", " << ch << "ADDR:0x" << std::hex << t.get_address() << ", TXLEN:0x"
164 << t.get_data_length();
165 if(auto e = t.get_extension<axi::ace_extension>()) {
166 os << ", " << ch << "ID:" << e->get_id() << ", " << ch << "LEN:0x" << std::hex
167 << static_cast<unsigned>(e->get_length()) << ", " << ch << "SIZE:0x" << static_cast<unsigned>(e->get_size())
168 << std::dec << ", " << ch << "BURST:" << to_char(e->get_burst()) << ", " << ch
169 << "PROT:" << static_cast<unsigned>(e->get_prot()) << ", " << ch
170 << "CACHE:" << static_cast<unsigned>(e->get_cache()) << ", " << ch
171 << "QOS:" << static_cast<unsigned>(e->get_qos()) << ", " << ch
172 << "REGION:" << static_cast<unsigned>(e->get_region()) << ", " << ch << "SNOOP:0x" << std::hex
173 << (static_cast<unsigned>(e->get_snoop()) & 0xf) << std::dec << ", " << ch
174 << "DOMAIN:" << to_char(e->get_domain()) << ", " << ch << "BAR:" << to_char(e->get_barrier()) << ", " << ch
175 << "UNIQUE:" << e->get_unique();
176 } else if(auto e = t.get_extension<axi::axi4_extension>()) {
177 os << ", " << ch << "ID:" << e->get_id() << ", " << ch << "LEN:0x" << std::hex
178 << static_cast<unsigned>(e->get_length()) << ", " << ch << "SIZE:0x" << static_cast<unsigned>(e->get_size())
179 << std::dec << ", " << ch << "BURST:" << to_char(e->get_burst()) << ", " << ch
180 << "PROT:" << static_cast<unsigned>(e->get_prot()) << ", " << ch
181 << "CACHE:" << static_cast<unsigned>(e->get_cache()) << ", " << ch
182 << "QOS:" << static_cast<unsigned>(e->get_qos()) << ", " << ch
183 << "REGION:" << static_cast<unsigned>(e->get_region());
184 } else if(auto e = t.get_extension<axi::axi3_extension>()) {
185 os << ", " << ch << "ID:" << e->get_id() << ", " << ch << "LEN:0x" << std::hex
186 << static_cast<unsigned>(e->get_length()) << ", " << ch << "SIZE:0x" << static_cast<unsigned>(e->get_size())
187 << std::dec << ", " << ch << "BURST:" << to_char(e->get_burst()) << ", " << ch
188 << "PROT:" << static_cast<unsigned>(e->get_prot()) << ", " << ch
189 << "CACHE:" << static_cast<unsigned>(e->get_cache()) << ", " << ch
190 << "QOS:" << static_cast<unsigned>(e->get_qos()) << ", " << ch
191 << "REGION:" << static_cast<unsigned>(e->get_region());
192 }
193 os << " [ptr:" << &t << "]";
194 return os;
195}
196
197namespace {
198const std::array<std::array<bool, 4>, 16> rd_valid{{
199 {true, true, true, true}, // ReadNoSnoop/ReadOnce
200 {false, true, true, false}, // ReadShared
201 {false, true, true, false}, // ReadClean
202 {false, true, true, false}, // ReadNotSharedDirty
203 {false, true, true, false}, // ReadOnceCleanInvalid (ACE5)
204 {false, true, true, false}, // ReadOnceMakeInvalid (ACE5)
205 {false, false, false, false}, //
206 {false, true, true, false}, // ReadUnique
207 {true, true, true, false}, // CleanShared
208 {true, true, true, false}, // CleanInvalid
209 {false, true, true, false}, // CleanSharedPersist (ACE5)
210 {false, true, true, false}, // CleanUnique
211 {false, true, true, false}, // MakeUnique
212 {true, true, true, false}, // MakeInvalid
213 {false, true, true, false}, // DVM Complete
214 {false, true, true, false} // DVM Message
215}};
216const std::array<std::array<bool, 4>, 16> wr_valid{{
217 {true, true, true, true}, // WriteNoSnoop/WriteUnique
218 {false, true, true, false}, // WriteLineUnique
219 {true, true, true, false}, // WriteClean
220 {true, true, true, false}, // WriteBack
221 {false, true, true, false}, // Evict
222 {true, true, true, false}, // WriteEvict
223 {false, false, false, false}, // CmoOnWrite (ACE5L)
224 {false, false, false, false}, //
225 {true, true, true, false}, // WriteUniquePtlStash (ACE5L)
226 {true, true, true, false}, // CleanInvalid
227 {false, true, true, false}, // WriteUniqueFullStash (ACE5L)
228 {false, false, false, false}, //
229 {true, true, true, false}, // StashOnceShared (ACE5L)
230 {false, true, true, false}, // StashOnceUnique (ACE5L)
231 {false, true, true, false}, // StashTranslation (ACE5L)
232 {false, false, false, false} //
233}};
234} // namespace
235template <> char const* is_valid_msg<axi::ace_extension>(axi::ace_extension* ext) {
236 auto snoop = to_int(ext->get_snoop());
237 auto cache = ext->get_cache();
238 auto domain = ext->get_domain();
239 if(snoop < 32) { // a read access
240 if(!rd_valid[snoop & 0xf][to_int(domain)])
241 return "illegal read snoop value";
242 } else {
243 if(!wr_valid[snoop & 0xf][to_int(ext->get_domain())])
244 return "illegal write snoop value";
245 }
246 if(cache<2 && domain != axi::domain_e::SYSTEM)
247 return "non-cacheable transactions require AXDOMAIN setting of SYSTEM(0x3) based on specification";
248 if(cache>3 && domain == axi::domain_e::SYSTEM)
249 return "cacheable transaction must not set AXDOMAIN to SYSTEM(0x3) based on specification";
250 if((cache & 2) == 0 && domain != domain_e::NON_SHAREABLE && domain != domain_e::SYSTEM) {
251 if( domain != domain_e::INNER_SHAREABLE)
252 return "illegal AXDOMAIN=INNER_SHAREABLE(0x1) for no non-cacheable access";
253 return "illegal AXDOMAIN=OUTER_SHAREABLE(0x2) for no non-cacheable access";
254 }
255 // check table ED3-7 and D3-8 of IHI0022H
256 switch(ext->get_snoop()) {
257 case snoop_e::READ_NO_SNOOP:
258 if(domain != domain_e::NON_SHAREABLE && domain != domain_e::SYSTEM)
259 return "illegal AXDOMAIN for no non-coherent READ_NO_SNOOP access";
260 break;
261 case snoop_e::WRITE_NO_SNOOP: // non coherent access to coherent domain
262 if(domain != domain_e::NON_SHAREABLE && domain != domain_e::SYSTEM)
263 return "illegal AXDOMAIN for no non-coherent WRITE_NO_SNOOP access";
264 break;
265 case snoop_e::READ_ONCE:
266 case snoop_e::READ_SHARED:
267 case snoop_e::READ_CLEAN:
268 case snoop_e::READ_NOT_SHARED_DIRTY:
269 case snoop_e::READ_UNIQUE:
270 case snoop_e::MAKE_UNIQUE:
271 case snoop_e::DVM_COMPLETE:
272 case snoop_e::DVM_MESSAGE:
273 case snoop_e::WRITE_UNIQUE:
274 case snoop_e::WRITE_LINE_UNIQUE:
275 case snoop_e::EVICT:
276 if(domain != domain_e::INNER_SHAREABLE && domain != domain_e::OUTER_SHAREABLE) {
277 if(domain != domain_e::NON_SHAREABLE)
278 return "illegal AXDOMAIN=NON_SHAREABLE(0x0) for coherent access";
279 return "illegal AXDOMAIN=SYSTEM(0x3) for coherent access";
280 }
281 break;
282 case snoop_e::CLEAN_SHARED:
283 case snoop_e::CLEAN_INVALID:
284 case snoop_e::MAKE_INVALID:
285 case snoop_e::WRITE_CLEAN:
286 case snoop_e::WRITE_BACK:
287 case snoop_e::WRITE_EVICT:
288 if(domain == domain_e::SYSTEM) {
289 return "illegal AXDOMAIN=SYSTEM(0x3) for coherent access";
290 }
291 break;
292 default:
293 break;
294 }
296 (snoop & 0xf) != 0)
297 return "illegal barrier/snoop value combination";
298 switch(cache) {
299 case 4:
300 case 5:
301 case 8:
302 case 9:
303 case 12:
304 case 13:
305 return "reserved AxCACHE value";
306 default:
307 break;
308 }
309 return nullptr;
310}
311
312template <> char const* is_valid_msg<axi::axi4_extension>(axi::axi4_extension* ext) {
313 switch(ext->get_cache()) {
314 case 4:
315 case 5:
316 case 8:
317 case 9:
318 case 12:
319 case 13:
320 return "reserved AxCACHE value";
321 }
322 return nullptr;
323}
324
325template <> char const* is_valid_msg<axi::axi3_extension>(axi::axi3_extension* ext) {
326 switch(ext->get_cache()) {
327 case 4:
328 case 5:
329 case 8:
330 case 9:
331 case 12:
332 case 13:
333 return "illegal AxCACHE value";
334 }
335 return nullptr;
336}
337} // namespace axi
TLM2.0 components modeling AHB.
const char * to_char(E t)
domain_e
Definition axi_tlm.h:85
bar_e
Definition axi_tlm.h:89
@ MEMORY_BARRIER
Normal access, respecting barriers.
Definition axi_tlm.h:91
@ SYNCHRONISATION_BARRIER
Normal access, ignoring barriers.
Definition axi_tlm.h:93
@ IGNORE_BARRIER
Memory barrier.
Definition axi_tlm.h:92
burst_e
Definition axi_tlm.h:73
snoop_e
Definition axi_tlm.h:99
constexpr ULT to_int(E t)
Definition axi_tlm.h:47
lock_e
Definition axi_tlm.h:81
resp_e
Definition axi_tlm.h:156
bar_e get_barrier() const
get the AxBAR value return the barrier value
Definition axi_tlm.h:1523
snoop_e get_snoop() const
get the AxSNOOP value return the snoop value
Definition axi_tlm.h:1519
domain_e get_domain() const
get the AxDOMAIN value return the domain value
Definition axi_tlm.h:1515
uint8_t get_cache() const
get the AxCACHE value as POD
Definition axi_tlm.h:1511