17#include <axi/checker/ace_protocol.h>
18#include <scc/report.h>
22ace_protocol::~ace_protocol() =
default;
24void ace_protocol::fw_pre(
const ace_protocol::payload_type& trans,
const ace_protocol::phase_type& phase) {
25 auto cmd = trans.get_command();
26 if(cmd == tlm::TLM_IGNORE_COMMAND)
27 SCCERR(name) <<
"Illegal command: tlm::TLM_IGNORE_COMMAND on forward path";
28 if(check_phase_change(trans, phase))
30 SCCERR(name) <<
"Illegal phase transition: " << phase.get_name() <<
" on forward path";
32 SCCERR(name) <<
"Illegal phase transition: " << phase <<
" on return in forward path";
36void ace_protocol::fw_post(
const ace_protocol::payload_type& trans,
const ace_protocol::phase_type& phase, tlm::tlm_sync_enum rstat) {
37 if(rstat == tlm::TLM_ACCEPTED)
39 auto cmd = trans.get_command();
40 if(req_beat[cmd] == tlm::BEGIN_REQ && (phase == tlm::BEGIN_RESP || phase == axi::BEGIN_PARTIAL_RESP))
41 req_beat[cmd] = tlm::UNINITIALIZED_PHASE;
42 if(check_phase_change(trans, phase))
44 SCCERR(name) <<
"Illegal phase transition: " << phase.get_name() <<
" on return in forward path";
46 SCCERR(name) <<
"Illegal phase transition: " << phase <<
" on return in forward path";
50void ace_protocol::bw_pre(
const ace_protocol::payload_type& trans,
const ace_protocol::phase_type& phase) {
51 auto cmd = trans.get_command();
52 if(cmd == tlm::TLM_IGNORE_COMMAND)
53 SCCERR(name) <<
"Illegal command: tlm::TLM_IGNORE_COMMAND on forward path";
54 if(check_phase_change(trans, phase))
56 SCCERR(name) <<
"Illegal phase transition: " << phase.get_name() <<
" on backward path";
58 SCCERR(name) <<
"Illegal phase transition: " << phase <<
" on backward path";
62void ace_protocol::bw_post(
const ace_protocol::payload_type& trans,
const ace_protocol::phase_type& phase, tlm::tlm_sync_enum rstat) {
63 if(rstat == tlm::TLM_ACCEPTED)
65 if(check_phase_change(trans, phase))
67 SCCERR(name) <<
"Illegal phase transition: " << phase.get_name() <<
" on return in backward path";
69 SCCERR(name) <<
"Illegal phase transition: " << phase <<
" on forward path";
73bool ace_protocol::check_phase_change(payload_type
const& trans,
const ace_protocol::phase_type& phase) {
75 auto cur_req = req_beat[trans.get_command()];
76 auto cur_resp = resp_beat[trans.get_command()];
78 if(phase == tlm::BEGIN_REQ || phase == axi::BEGIN_PARTIAL_REQ) {
79 error |= cur_req != tlm::UNINITIALIZED_PHASE;
81 }
else if(phase == axi::END_PARTIAL_REQ) {
82 error |= cur_req != axi::BEGIN_PARTIAL_REQ;
83 cur_req = tlm::UNINITIALIZED_PHASE;
84 }
else if(phase == tlm::END_REQ) {
85 error |= cur_req != tlm::BEGIN_REQ;
86 cur_req = tlm::UNINITIALIZED_PHASE;
87 }
else if(phase == tlm::BEGIN_RESP || phase == axi::BEGIN_PARTIAL_RESP) {
88 error |= cur_resp != tlm::UNINITIALIZED_PHASE;
90 }
else if(phase == tlm::END_RESP) {
91 error |= cur_resp != tlm::BEGIN_RESP;
92 cur_resp = tlm::UNINITIALIZED_PHASE;
93 }
else if(phase == axi::END_PARTIAL_RESP) {
94 error |= cur_resp != axi::BEGIN_PARTIAL_RESP;
95 cur_resp = tlm::UNINITIALIZED_PHASE;
99 if(req_beat[trans.get_command()] != cur_req) {
100 req_beat[trans.get_command()] = cur_req;
101 request_update(trans);
103 if(resp_beat[trans.get_command()] != cur_resp) {
104 resp_beat[trans.get_command()] = cur_resp;
105 response_update(trans);
110void ace_protocol::request_update(
const payload_type& trans) {
111 auto axi_id = axi::get_axi_id(trans);
114 if(trans.is_write()) {
115 if(req_beat[tlm::TLM_WRITE_COMMAND] == tlm::UNINITIALIZED_PHASE) {
116 req_id[tlm::TLM_WRITE_COMMAND] = umax;
118 if(req_id[tlm::TLM_WRITE_COMMAND] == umax) {
119 req_id[tlm::TLM_WRITE_COMMAND] = axi_id;
121 }
else if(req_id[tlm::TLM_WRITE_COMMAND] != axi_id) {
122 SCCERR(name) <<
"Illegal ordering: a transaction with AWID:0x" << std::hex << axi_id
123 <<
" starts while a transaction with AWID:0x" << req_id[tlm::TLM_WRITE_COMMAND] <<
" is active";
125 if(req_beat[tlm::TLM_WRITE_COMMAND] == tlm::BEGIN_REQ) {
126 if(wr_req_beat_count != axi_burst_len) {
127 SCCERR(name) <<
"Illegal AXI settings: number of transferred beats (" << wr_req_beat_count
130 auto mask = bw - 1ULL;
131 auto offset = trans.get_address() & mask;
133 if(trans.get_data_length() > (1 << axi_burst_size) * axi_burst_len) {
134 SCCERR(name) <<
"Illegal AXI settings: transaction data length (" << trans.get_data_length()
135 <<
") does not correspond to AxSIZE/AxLEN setting (" << axi_burst_size <<
"/" << axi_burst_len - 1
136 <<
") for " << trans;
139 if((trans.get_data_length() + offset) >= (1 << axi_burst_size) * axi_burst_len) {
140 SCCERR(name) <<
"Illegal AXI settings: transaction data length (" << trans.get_data_length()
141 <<
") does not correspond to AxSIZE/AxLEN setting (" << axi_burst_size <<
"/" << axi_burst_len - 1
142 <<
") for " << trans;
145 wr_req_beat_count = 0;
146 open_tx_by_id[tlm::TLM_WRITE_COMMAND][axi_id].push_back(
reinterpret_cast<uintptr_t
>(&trans));
148 check_properties(trans);
150 }
else if(trans.is_read()) {
151 if(req_beat[tlm::TLM_READ_COMMAND] == tlm::UNINITIALIZED_PHASE) {
152 req_id[tlm::TLM_READ_COMMAND] = umax;
153 }
else if(req_beat[tlm::TLM_READ_COMMAND] == tlm::BEGIN_REQ) {
154 if(req_id[tlm::TLM_READ_COMMAND] == umax) {
155 req_id[tlm::TLM_READ_COMMAND] = axi_id;
156 open_tx_by_id[tlm::TLM_READ_COMMAND][axi_id].push_back(
reinterpret_cast<uintptr_t
>(&trans));
157 }
else if(req_id[tlm::TLM_READ_COMMAND] != axi_id) {
158 SCCERR(name) <<
"Illegal phase: a read transaction uses a phase with id " << req_beat[tlm::TLM_READ_COMMAND];
160 check_properties(trans);
162 SCCERR(name) <<
"Illegal phase: a read transaction uses a phase with id " << req_beat[tlm::TLM_READ_COMMAND];
167void ace_protocol::response_update(
const payload_type& trans) {
168 auto axi_id = axi::get_axi_id(trans);
171 if(trans.is_write()) {
172 if(resp_beat[tlm::TLM_WRITE_COMMAND] == tlm::UNINITIALIZED_PHASE) {
173 resp_id[tlm::TLM_WRITE_COMMAND] = umax;
174 }
else if(resp_beat[tlm::TLM_WRITE_COMMAND] == tlm::BEGIN_RESP) {
175 if(resp_id[tlm::TLM_WRITE_COMMAND] == umax) {
176 resp_id[tlm::TLM_WRITE_COMMAND] = axi_id;
177 if(open_tx_by_id[tlm::TLM_WRITE_COMMAND][axi_id].front() !=
reinterpret_cast<uintptr_t
>(&trans)) {
178 SCCERR(name) <<
"Write response ordering violation: a response with AWID:0x" << std::hex << axi_id
179 <<
" starts before the previous response with the same id finished";
181 }
else if(resp_id[tlm::TLM_WRITE_COMMAND] != axi_id) {
182 SCCERR(name) <<
"Illegal phase: a read transaction uses a phase with id " << resp_beat[tlm::TLM_WRITE_COMMAND];
184 open_tx_by_id[tlm::TLM_WRITE_COMMAND][axi_id].pop_front();
186 SCCERR(name) <<
"Illegal phase: a read transaction uses a phase with id " << resp_beat[tlm::TLM_WRITE_COMMAND];
188 }
else if(trans.is_read()) {
189 if(resp_beat[tlm::TLM_READ_COMMAND] == tlm::UNINITIALIZED_PHASE) {
190 resp_id[tlm::TLM_READ_COMMAND] = umax;
192 if(resp_id[tlm::TLM_READ_COMMAND] == umax) {
193 resp_id[tlm::TLM_READ_COMMAND] = axi_id;
194 if(open_tx_by_id[tlm::TLM_READ_COMMAND][axi_id].front() !=
reinterpret_cast<uintptr_t
>(&trans)) {
195 SCCERR(name) <<
"Read response ordering violation: a response with ARID:0x" << std::hex << axi_id
196 <<
" starts before the previous response with the same id finished";
198 rd_resp_beat_count[axi_id]++;
199 }
else if(resp_id[tlm::TLM_READ_COMMAND] != axi_id) {
200 SCCERR(name) <<
"Illegal phase: a read transaction uses a phase with id " << resp_beat[tlm::TLM_READ_COMMAND];
202 if(resp_beat[tlm::TLM_READ_COMMAND] == tlm::BEGIN_RESP) {
203 if(rd_resp_beat_count[axi_id] != axi_burst_len) {
204 SCCERR(name) <<
"Illegal AXI settings: number of transferred beats (" << wr_req_beat_count
207 auto mask = bw - 1ULL;
208 auto offset = trans.get_address() & mask;
210 if(trans.get_data_length() > (1 << axi_burst_size) * axi_burst_len) {
211 SCCERR(name) <<
"Illegal AXI settings: transaction data length (" << trans.get_data_length()
212 <<
") does not correspond to AxSIZE/AxLEN setting (" << axi_burst_size <<
"/" << axi_burst_len - 1
213 <<
") for " << trans;
216 if((trans.get_data_length() + offset) >= (1 << axi_burst_size) * axi_burst_len) {
217 SCCERR(name) <<
"Illegal AXI settings: transaction data length (" << trans.get_data_length()
218 <<
") does not correspond to AxSIZE/AxLEN setting (" << axi_burst_size <<
"/" << axi_burst_len - 1
219 <<
") for " << trans;
222 open_tx_by_id[tlm::TLM_READ_COMMAND][axi_id].pop_front();
223 rd_resp_beat_count[axi_id] = 0;
233void ace_protocol::check_properties(
const payload_type& trans) {
234 if(
auto* ace_ext = trans.get_extension<axi::ace_extension>()) {
235 if(ace_ext->get_cache() & 0xc0) {
236 if(!ace_ext->get_cache())
237 SCCERR(name) <<
"Illegal ACEL settings: active allocate bit(s) requires modifiable bit set";
239 auto snoop = ace_ext->get_snoop();
240 auto domain = ace_ext->get_domain();
241 auto bar = ace_ext->get_barrier();
242 switch(comb(bar, domain, snoop)) {
244 case comb(bar_e::RESPECT_BARRIER, domain_e::NON_SHAREABLE, snoop_e::READ_NO_SNOOP):
303 SCCERR(name) <<
"Illegal ACE settings: According to D3.1.1 Read and write Shareable transaction types of ARM IHI 0022H the "
304 "following setting is illegal:\n"
310 case snoop_e::READ_CLEAN:
311 case snoop_e::READ_NOT_SHARED_DIRTY:
312 case snoop_e::READ_SHARED:
313 case snoop_e::READ_UNIQUE:
314 case snoop_e::CLEAN_UNIQUE:
315 case snoop_e::MAKE_UNIQUE:
316 case snoop_e::WRITE_LINE_UNIQUE:
318 if(ace_ext->get_domain() == domain_e::NON_SHAREABLE) {
319 SCCERR(name) <<
"Illegal ACE settings: According to D3.1.6 Transaction constraints of ARM IHI 0022H the following setting "
321 <<
"AxDOMAIN:" <<
to_char(ace_ext->get_domain());
324 case snoop_e::CLEAN_SHARED:
325 case snoop_e::CLEAN_INVALID:
326 case snoop_e::MAKE_INVALID:
327 case snoop_e::WRITE_EVICT:
328 if(ace_ext->get_domain() == domain_e::SYSTEM) {
329 SCCERR(name) <<
"Illegal ACE settings: According to D3.1.6 Transaction constraints of ARM IHI 0022H the following setting "
331 <<
"AxDOMAIN:" <<
to_char(ace_ext->get_domain());
333 if(ace_ext->get_length() && (1u << ace_ext->get_size()) != bw) {
334 SCCERR(name) <<
"Illegal ACE settings: According to D3.1.6 Transaction constraints of ARM IHI 0022H the following setting "
336 <<
"AxLEN:" <<
static_cast<unsigned>(ace_ext->get_length())
337 <<
", AxSIZE:" <<
static_cast<unsigned>(ace_ext->get_size()) <<
" with bus with:" << bw;
340 switch(ace_ext->get_burst()) {
342 width = (1 + ace_ext->get_length()) * (1u << ace_ext->get_size());
345 if(trans.get_address() & (width - 1)) {
346 SCCERR(name) <<
"Illegal ACE settings: According to D3.1.6 Transaction constraints of ARM IHI 0022H the following "
347 "setting is illegal:\n"
348 <<
"AxBURST:" <<
to_char(ace_ext->get_burst()) <<
", ADDR:0x" << std::hex << trans.get_address();
352 SCCERR(name) <<
"Illegal ACE settings: According to D3.1.6 Transaction constraints of ARM IHI 0022H the following setting "
354 <<
"AxBURST:" <<
to_char(ace_ext->get_burst());
357 SCCERR(name) <<
"Illegal ACE settings: According to D3.1.6 Transaction constraints of ARM IHI 0022H the following setting "
359 <<
"AxBAR:" <<
to_char(ace_ext->get_barrier());
361 if(!ace_ext->is_modifiable()) {
362 SCCERR(name) <<
"Illegal ACE settings: According to D3.1.6 Transaction constraints of ARM IHI 0022H the following setting "
364 <<
"AxCACHE:" <<
static_cast<unsigned>(ace_ext->get_cache());
TLM2.0 components modeling AHB.
const char * to_char(E t)
unsigned get_burst_length(const request &r)
@ MEMORY_BARRIER
Normal access, respecting barriers.
@ IGNORE_BARRIER
Memory barrier.
constexpr ULT to_int(E t)
unsigned get_burst_size(const request &r)