scc  2024.06
SystemC components library
axi_protocol.cpp
1 /*
2  * Copyright 2020-2022 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/checker/axi_protocol.h>
18 #include <scc/report.h>
19 namespace axi {
20 namespace checker {
21 
22 void axi_protocol::fw_pre(const axi_protocol::payload_type &trans, const axi_protocol::phase_type &phase) {
23  auto cmd = trans.get_command();
24  if (cmd == tlm::TLM_IGNORE_COMMAND)
25  SCCERR(name) << "Illegal command: tlm::TLM_IGNORE_COMMAND on forward path";
26  if (check_phase_change(trans, phase))
27 #ifndef NCSC
28  SCCERR(name) << "Illegal phase transition: " << phase.get_name() << " on forward path";
29 #else
30  SCCERR(name) << "Illegal phase transition: " << phase << " on forward path";
31 #endif
32 }
33 
34 void axi_protocol::fw_post(const axi_protocol::payload_type &trans, const axi_protocol::phase_type &phase, tlm::tlm_sync_enum rstat) {
35  if(rstat == tlm::TLM_ACCEPTED) return;
36  auto cmd = trans.get_command();
37  if(req_beat[cmd]==tlm::BEGIN_REQ && (phase == tlm::BEGIN_RESP || phase == axi::BEGIN_PARTIAL_RESP))
38  req_beat[cmd]= tlm::UNINITIALIZED_PHASE;
39  if (check_phase_change(trans, phase))
40 #ifndef NCSC
41  SCCERR(name) << "Illegal phase transition: " << phase.get_name() << " on return in forward path";
42 #else
43  SCCERR(name) << "Illegal phase transition: " << phase << " on return in forward path";
44 #endif
45 }
46 
47 void axi_protocol::bw_pre(const axi_protocol::payload_type &trans, const axi_protocol::phase_type &phase) {
48  auto cmd = trans.get_command();
49  if (cmd == tlm::TLM_IGNORE_COMMAND)
50  SCCERR(name) << "Illegal command: tlm::TLM_IGNORE_COMMAND on forward path";
51  if (check_phase_change(trans, phase))
52 #ifndef NCSC
53  SCCERR(name) << "Illegal phase transition: " << phase.get_name() << " on backward path";
54 #else
55  SCCERR(name) << "Illegal phase transition: " << phase << " on backward path";
56 #endif
57 }
58 
59 void axi_protocol::bw_post(const axi_protocol::payload_type &trans, const axi_protocol::phase_type &phase, tlm::tlm_sync_enum rstat) {
60  if(rstat == tlm::TLM_ACCEPTED) return;
61  if (check_phase_change(trans, phase))
62 #ifndef NCSC
63  SCCERR(name) << "Illegal phase transition: " << phase.get_name() << " on return in backward path";
64 #else
65  SCCERR(name) << "Illegal phase transition: " << phase << " on return in backward path";
66 #endif
67 }
68 
69 bool axi_protocol::check_phase_change(payload_type const& trans, const axi_protocol::phase_type &phase) {
70  // phase tests
71  auto cur_req = req_beat[trans.get_command()];
72  auto cur_resp = resp_beat[trans.get_command()];
73  bool error{false};
74  if (phase == tlm::BEGIN_REQ || phase == axi::BEGIN_PARTIAL_REQ) {
75  error |= cur_req != tlm::UNINITIALIZED_PHASE;
76  cur_req = phase;
77  } else if(phase==axi::END_PARTIAL_REQ) {
78  error |= cur_req != axi::BEGIN_PARTIAL_REQ;
79  cur_req = tlm::UNINITIALIZED_PHASE;
80  } else if(phase==tlm::END_REQ) {
81  error |= cur_req != tlm::BEGIN_REQ;
82  cur_req = tlm::UNINITIALIZED_PHASE;
83  } else if(phase == tlm::BEGIN_RESP || phase == axi::BEGIN_PARTIAL_RESP) {
84  error |= cur_resp!=tlm::UNINITIALIZED_PHASE;
85  cur_resp = phase;
86  } else if (phase == tlm::END_RESP) {
87  error |= cur_resp != tlm::BEGIN_RESP;
88  cur_resp = tlm::UNINITIALIZED_PHASE;
89  } else if (phase == axi::END_PARTIAL_RESP) {
90  error |= cur_resp != axi::BEGIN_PARTIAL_RESP;
91  cur_resp = tlm::UNINITIALIZED_PHASE;
92  } else {
93  error |= true;
94  }
95  if(req_beat[trans.get_command()] != cur_req){
96  req_beat[trans.get_command()] = cur_req;
97  request_update(trans);
98  }
99  if(resp_beat[trans.get_command()] != cur_resp){
100  resp_beat[trans.get_command()] = cur_resp;
101  response_update(trans);
102  }
103  return error;
104 }
105 
106 void axi_protocol::request_update(const payload_type &trans) {
107  auto axi_id = axi::get_axi_id(trans);
108  auto axi_burst_len = axi::get_burst_length(trans);
109  if(trans.is_write()){
110  if(req_beat[tlm::TLM_WRITE_COMMAND]==tlm::UNINITIALIZED_PHASE) {
111  req_id[tlm::TLM_WRITE_COMMAND] = umax;
112  } else {
113  if(req_id[tlm::TLM_WRITE_COMMAND] == umax) {
114  req_id[tlm::TLM_WRITE_COMMAND] = axi_id;
115  wr_req_beat_count++;
116  } else if(req_id[tlm::TLM_WRITE_COMMAND] != axi_id){
117  SCCERR(name) << "Illegal ordering: a transaction with AWID:0x"<<std::hex<<axi_id<<" starts while a transaction with AWID:0x"<<req_id[tlm::TLM_WRITE_COMMAND]<<" is active";
118  }
119  if(req_beat[tlm::TLM_WRITE_COMMAND]==tlm::BEGIN_REQ) {
120  if(wr_req_beat_count != axi_burst_len){
121  SCCERR(name) << "Illegal AXI settings: number of transferred beats ("<<wr_req_beat_count<<") does not comply with AWLEN:0x"<<std::hex<<axi::get_burst_length(trans)-1;
122  }
123  wr_req_beat_count=0;
124  open_tx_by_id[tlm::TLM_WRITE_COMMAND][axi_id].push_back(reinterpret_cast<uintptr_t>(&trans));
125  check_properties(trans);
126  }
127  }
128  } else if(trans.is_read()) {
129  if(req_beat[tlm::TLM_READ_COMMAND]==tlm::UNINITIALIZED_PHASE) {
130  req_id[tlm::TLM_READ_COMMAND] = umax;
131  } else if(req_beat[tlm::TLM_READ_COMMAND]==tlm::BEGIN_REQ) {
132  if(req_id[tlm::TLM_READ_COMMAND] == umax) {
133  req_id[tlm::TLM_READ_COMMAND] = axi_id;
134  open_tx_by_id[tlm::TLM_READ_COMMAND][axi_id].push_back(reinterpret_cast<uintptr_t>(&trans));
135  } else if(req_id[tlm::TLM_READ_COMMAND] != axi_id){
136  SCCERR(name) << "Illegal phase: a read transaction uses a phase with id "<<req_beat[tlm::TLM_READ_COMMAND];
137  }
138  check_properties(trans);
139  } else {
140  SCCERR(name) << "Illegal phase: a read transaction uses a phase with id "<<req_beat[tlm::TLM_READ_COMMAND];
141  }
142  }
143 }
144 
145 void axi_protocol::response_update(const payload_type &trans) {
146  auto axi_id = axi::get_axi_id(trans);
147  auto axi_burst_len = axi::get_burst_length(trans);
148  if(trans.is_write()){
149  if(resp_beat[tlm::TLM_WRITE_COMMAND]==tlm::UNINITIALIZED_PHASE) {
150  resp_id[tlm::TLM_WRITE_COMMAND] = umax;
151  } else if(resp_beat[tlm::TLM_WRITE_COMMAND]==tlm::BEGIN_RESP) {
152  if(resp_id[tlm::TLM_WRITE_COMMAND] == umax) {
153  resp_id[tlm::TLM_WRITE_COMMAND] = axi_id;
154  if(open_tx_by_id[tlm::TLM_WRITE_COMMAND][axi_id].front()!=reinterpret_cast<uintptr_t>(&trans)) {
155  SCCERR(name) << "Write response ordering violation: a response with AWID:0x"<<std::hex<<axi_id<<" starts before the previous response with the same id finished";
156  }
157  } else if(resp_id[tlm::TLM_WRITE_COMMAND] != axi_id){
158  SCCERR(name) << "Illegal phase: a read transaction uses a phase with id "<<resp_beat[tlm::TLM_WRITE_COMMAND];
159  }
160  open_tx_by_id[tlm::TLM_WRITE_COMMAND][axi_id].pop_front();
161  } else {
162  SCCERR(name) << "Illegal phase: a read transaction uses a phase with id "<<resp_beat[tlm::TLM_WRITE_COMMAND];
163  }
164  } else if(trans.is_read()) {
165  if(resp_beat[tlm::TLM_READ_COMMAND]==tlm::UNINITIALIZED_PHASE) {
166  resp_id[tlm::TLM_READ_COMMAND] = umax;
167  } else {
168  if(resp_id[tlm::TLM_READ_COMMAND] == umax) {
169  resp_id[tlm::TLM_READ_COMMAND] = axi_id;
170  if(open_tx_by_id[tlm::TLM_READ_COMMAND][axi_id].front()!=reinterpret_cast<uintptr_t>(&trans)) {
171  SCCERR(name) << "Read response ordering violation: a response with ARID:0x"<<std::hex<<axi_id<<" starts before the previous response with the same id finished";
172  }
173  rd_resp_beat_count[axi_id]++;
174  } else if(resp_id[tlm::TLM_READ_COMMAND] != axi_id){
175  SCCERR(name) << "Illegal phase: a read transaction uses a phase with id "<<resp_beat[tlm::TLM_READ_COMMAND];
176  }
177  if(resp_beat[tlm::TLM_READ_COMMAND]==tlm::BEGIN_RESP) {
178  if(rd_resp_beat_count[axi_id] != axi_burst_len){
179  SCCERR(name) << "Illegal AXI settings: number of transferred beats ("<<wr_req_beat_count<<") does not comply with AWLEN:0x"<<std::hex<<axi::get_burst_length(trans)-1;
180  }
181  open_tx_by_id[tlm::TLM_READ_COMMAND][axi_id].pop_front();
182  rd_resp_beat_count[axi_id]=0;
183  }
184  }
185  }
186 }
187 
188 void axi_protocol::check_datawith_settings(payload_type const&trans){
189  auto axi_burst_len = axi::get_burst_length(trans);
190  auto axi_burst_size = axi::get_burst_size(trans);
191  auto mask = bw-1ULL;
192  auto offset = trans.get_address() & mask;
193  if(!offset){
194  if(trans.get_data_length() != (axi_burst_size * axi_burst_len)) {
195  SCCERR(name) << "Illegal AXI settings: transaction data length (" << trans.get_data_length() << ") does not correspond to AxSIZE/AxLEN setting ("
196  << axi_burst_size << "/" << axi_burst_len-1 << ") and buswidth "<<bw<< " for " << trans;
197  }
198  } else {
199  if((trans.get_data_length() + offset) > (axi_burst_size * axi_burst_len)) {
200  SCCERR(name) << "Illegal AXI settings: transaction data length (" << trans.get_data_length() << ") does not correspond to AxSIZE/AxLEN setting ("
201  << axi_burst_size << "/" << axi_burst_len-1 << ") and buswidth "<<bw<< " for " << trans;
202  }
203  }
204 
205 }
206 constexpr unsigned comb(axi::bar_e bar, axi::domain_e domain, axi::snoop_e snoop){
207  return to_int(bar)<<10|to_int(domain)<<8|to_int(snoop);
208 };
209 
210 void axi_protocol::check_properties(const payload_type &trans) {
211  check_datawith_settings(trans);
212  if(auto* axi4_ext = trans.get_extension<axi::axi4_extension>()){
213  if(axi4_ext->get_cache()&0xc0) {
214  if(!axi4_ext->get_cache())
215  SCCERR(name)<<"Illegal AXI settings: active allocate bit(s) requires modifiable bit set";
216  }
217  if(axi4_ext->get_qos()>15)
218  SCCERR(name)<<"Illegal AXI4 settings: maximum value of QoS is 15, illegal value is "<<axi4_ext->get_qos();
219  } else if(auto* ace_ext = trans.get_extension<axi::ace_extension>()){
220  if(ace_ext->get_cache()&0xc0) {
221  if(!ace_ext->get_cache())
222  SCCERR(name)<<"Illegal ACEL settings: active allocate bit(s) requires modifiable bit set";
223  auto snoop = ace_ext->get_snoop();
224  auto domain = ace_ext->get_domain();
225  auto bar = ace_ext->get_barrier();
226  switch(comb(bar, domain, snoop)){
227  case comb(bar_e::RESPECT_BARRIER, domain_e::NON_SHAREABLE, snoop_e::READ_NO_SNOOP):
228  case comb(bar_e::RESPECT_BARRIER, domain_e::SYSTEM, snoop_e::READ_NO_SNOOP):
229  case comb(bar_e::RESPECT_BARRIER, domain_e::INNER_SHAREABLE, snoop_e::READ_ONCE):
230  case comb(bar_e::RESPECT_BARRIER, domain_e::OUTER_SHAREABLE, snoop_e::READ_ONCE):
231  case comb(bar_e::RESPECT_BARRIER, domain_e::NON_SHAREABLE, snoop_e::CLEAN_SHARED):
232  case comb(bar_e::RESPECT_BARRIER, domain_e::INNER_SHAREABLE, snoop_e::CLEAN_SHARED):
233  case comb(bar_e::RESPECT_BARRIER, domain_e::OUTER_SHAREABLE, snoop_e::CLEAN_SHARED):
234  case comb(bar_e::RESPECT_BARRIER, domain_e::NON_SHAREABLE, snoop_e::CLEAN_INVALID):
235  case comb(bar_e::RESPECT_BARRIER, domain_e::INNER_SHAREABLE, snoop_e::CLEAN_INVALID):
236  case comb(bar_e::RESPECT_BARRIER, domain_e::OUTER_SHAREABLE, snoop_e::CLEAN_INVALID):
237  case comb(bar_e::RESPECT_BARRIER, domain_e::NON_SHAREABLE, snoop_e::MAKE_INVALID):
238  case comb(bar_e::RESPECT_BARRIER, domain_e::INNER_SHAREABLE, snoop_e::MAKE_INVALID):
239  case comb(bar_e::RESPECT_BARRIER, domain_e::OUTER_SHAREABLE, snoop_e::MAKE_INVALID):
240  case comb(bar_e::MEMORY_BARRIER, domain_e::NON_SHAREABLE, snoop_e::READ_NO_SNOOP):
241  case comb(bar_e::MEMORY_BARRIER, domain_e::INNER_SHAREABLE, snoop_e::READ_ONCE):
242  case comb(bar_e::MEMORY_BARRIER, domain_e::OUTER_SHAREABLE, snoop_e::READ_ONCE):
243  case comb(bar_e::MEMORY_BARRIER, domain_e::SYSTEM, snoop_e::READ_NO_SNOOP):
244 
245  case comb(bar_e::RESPECT_BARRIER, domain_e::NON_SHAREABLE, snoop_e::WRITE_NO_SNOOP):
246  case comb(bar_e::RESPECT_BARRIER, domain_e::SYSTEM, snoop_e::WRITE_NO_SNOOP):
247  case comb(bar_e::RESPECT_BARRIER, domain_e::INNER_SHAREABLE, snoop_e::WRITE_UNIQUE):
248  case comb(bar_e::RESPECT_BARRIER, domain_e::OUTER_SHAREABLE, snoop_e::WRITE_UNIQUE):
249  case comb(bar_e::RESPECT_BARRIER, domain_e::INNER_SHAREABLE, snoop_e::WRITE_LINE_UNIQUE):
250  case comb(bar_e::RESPECT_BARRIER, domain_e::OUTER_SHAREABLE, snoop_e::WRITE_LINE_UNIQUE):
251  case comb(bar_e::MEMORY_BARRIER, domain_e::NON_SHAREABLE, snoop_e::WRITE_NO_SNOOP):
252  case comb(bar_e::MEMORY_BARRIER, domain_e::INNER_SHAREABLE, snoop_e::WRITE_UNIQUE):
253  case comb(bar_e::MEMORY_BARRIER, domain_e::OUTER_SHAREABLE, snoop_e::WRITE_UNIQUE):
254  case comb(bar_e::MEMORY_BARRIER, domain_e::SYSTEM, snoop_e::WRITE_NO_SNOOP):
255  break;
256  default:
257  SCCERR(name)<<"Illegal ACEL settings: According to D11.2 ACE-Lite signal requirements of ARM IHI 0022H the following setting is illegal:\n"
258  << "AxBAR:"<<to_char(bar)<<", AxDOMAIN:"<<to_char(domain)<<", AxSNOOP:"<<to_char(snoop);
259  }
260  }
261  } else if(auto* axi3_ext = trans.get_extension<axi::axi4_extension>()){
262  if(axi3_ext->get_cache()&0xc0) {
263  if(!axi3_ext->get_cache())
264  SCCERR(name)<<"Illegal AXI settings: active allocate bit(s) requires modifiable bit set";
265  }
266  }
267 }
268 
269 } /* namespace checker */
270 } /* namespace axi */
TLM2.0 components modeling AHB.
Definition: axi_initiator.h:30
unsigned get_burst_length(const request &r)
Definition: axi_tlm.h:1167
domain_e
Definition: axi_tlm.h:85
bar_e
Definition: axi_tlm.h:89
@ MEMORY_BARRIER
Normal access, respecting barriers.
const char * to_char(E t)
snoop_e
Definition: axi_tlm.h:99
constexpr ULT to_int(E t)
Definition: axi_tlm.h:47
unsigned get_burst_size(const request &r)
Definition: axi_tlm.h:1202