scc 2025.09
SystemC components library
ace_target.h
1/*******************************************************************************
2 * Copyright 2021-2022 MINRES Technologies GmbH
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 _BUS_AXI_PIN_ACE_TARGET_H_
18#define _BUS_AXI_PIN_ACE_TARGET_H_
19
20#include <axi/axi_tlm.h>
21#include <axi/fsm/base.h>
22#include <axi/fsm/protocol_fsm.h>
23#include <axi/signal_if.h>
24#include <systemc>
25#include <tlm/scc/tlm_mm.h>
26#include <util/ities.h>
27
29namespace axi {
31namespace pin {
32
33using namespace axi::fsm;
34
35template <typename CFG>
36struct ace_target : public sc_core::sc_module,
37 public aw_ace<CFG, typename CFG::slave_types>,
38 public wdata_ace<CFG, typename CFG::slave_types>,
39 public b_ace<CFG, typename CFG::slave_types>,
40 public ar_ace<CFG, typename CFG::slave_types>,
41 public rresp_ace<CFG, typename CFG::slave_types>,
42
43 public ac_ace<CFG, typename CFG::slave_types>,
44 public cr_ace<CFG, typename CFG::slave_types>,
45 public cd_ace<CFG, typename CFG::slave_types>,
46
47 protected axi::fsm::base,
48 public axi::ace_bw_transport_if<axi::axi_protocol_types> {
49 SC_HAS_PROCESS(ace_target);
50
51 using payload_type = axi::axi_protocol_types::tlm_payload_type;
52 using phase_type = axi::axi_protocol_types::tlm_phase_type;
53
54 sc_core::sc_in<bool> clk_i{"clk_i"};
55
57
58 ace_target(sc_core::sc_module_name const& nm)
59 : sc_core::sc_module(nm)
60 // coherent= true
61 , base(CFG::BUSWIDTH, true) {
62 instance_name = name();
63 isckt.bind(*this);
64 SC_METHOD(clk_delay);
65 sensitive << clk_i.pos();
66 dont_initialize();
67 SC_THREAD(ar_t);
68 SC_THREAD(rresp_t);
69 SC_THREAD(aw_t);
70 SC_THREAD(wdata_t);
71 SC_THREAD(bresp_t);
72 SC_THREAD(ac_t);
73 SC_THREAD(cr_t);
74 SC_THREAD(cd_t);
75 }
76
77private:
78 tlm::tlm_sync_enum nb_transport_bw(payload_type& trans, phase_type& phase, sc_core::sc_time& t) override;
79 void b_snoop(payload_type& trans, sc_core::sc_time& t) override{};
80
81 void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, sc_dt::uint64 end_range) override;
82
83 void end_of_elaboration() override { clk_if = dynamic_cast<sc_core::sc_clock*>(clk_i.get_interface()); }
84
85 axi::fsm::fsm_handle* create_fsm_handle() override { return new fsm_handle(); }
86
87 void setup_callbacks(axi::fsm::fsm_handle*) override;
88
94 unsigned snoop_latency{1};
95
96 void clk_delay() {
97#ifdef DELTA_SYNC
98 if(sc_core::sc_delta_count_at_current_time() < 5) {
99 clk_self.notify(sc_core::SC_ZERO_TIME);
100 next_trigger(clk_self);
101 } else
102 clk_delayed.notify(sc_core::SC_ZERO_TIME /*clk_if ? clk_if->period() - 1_ps : 1_ps*/);
103#else
104 clk_delayed.notify(axi::CLK_DELAY);
105#endif
106 }
107 void ar_t();
108 void rresp_t();
109 void aw_t();
110 void wdata_t();
111 void bresp_t();
112 void ac_t();
113 void cr_t();
114 void cd_t();
115 static typename CFG::data_t get_read_data_for_beat(fsm::fsm_handle* fsm_hndl);
116 struct aw_data {
117 unsigned id;
118 uint64_t addr;
119 unsigned prot;
120 unsigned size;
121 unsigned cache;
122 unsigned burst;
123 unsigned qos;
124 unsigned region;
125 unsigned len;
126 unsigned domain;
127 unsigned snoop;
128 unsigned bar;
129 unsigned unique;
130 bool lock;
131 uint64_t user;
132 };
133
134 std::deque<axi::fsm::fsm_handle*> snp_resp_queue;
135
136 sc_core::sc_clock* clk_if{nullptr};
137 sc_core::sc_event clk_delayed, clk_self, ar_end_req_evt, wdata_end_req_evt, ac_evt, cd_end_req_evt, cr_end_req_evt;
138 std::array<fsm_handle*, 3> active_req_beat{nullptr, nullptr, nullptr};
139 std::array<fsm_handle*, 4> active_req{nullptr, nullptr, nullptr};
140 std::array<fsm_handle*, 3> active_resp_beat{nullptr, nullptr, nullptr};
141 scc::peq<aw_data> aw_que;
144 scc::peq<std::tuple<uint8_t, fsm_handle*>> cr_vl; // snoop response
145
146 unsigned int SNOOP = 3; // TBD??
147 void write_ac(tlm::tlm_generic_payload& trans);
148};
149
150} // namespace pin
151} // namespace axi
152
153template <typename CFG>
154inline tlm::tlm_sync_enum axi::pin::ace_target<CFG>::nb_transport_bw(payload_type& trans, phase_type& phase, sc_core::sc_time& t) {
155 auto ret = tlm::TLM_ACCEPTED;
156 SCCTRACE(SCMOD) << "nb_transport_bw with " << phase << " with delay= " << t << " of trans " << trans;
157 if(phase == END_PARTIAL_REQ || phase == tlm::END_REQ) { // read/write
158 schedule(phase == tlm::END_REQ ? EndReqE : EndPartReqE, &trans, t, false);
159 } else if(phase == axi::BEGIN_PARTIAL_RESP || phase == tlm::BEGIN_RESP) { // read/write response
160 schedule(phase == tlm::BEGIN_RESP ? BegRespE : BegPartRespE, &trans, t, false);
161 } else if(phase == tlm::BEGIN_REQ) { // snoop read
162 auto fsm_hndl = find_or_create(&trans, true);
163 fsm_hndl->is_snoop = true;
164 schedule(BegReqE, &trans, t);
165 } else if(phase == END_PARTIAL_RESP || phase == tlm::END_RESP) { // snoop read response
166 schedule(phase == tlm::END_RESP ? EndRespE : EndPartRespE, &trans, t);
167 }
168 return ret;
169}
170
171template <typename CFG>
172inline void axi::pin::ace_target<CFG>::invalidate_direct_mem_ptr(sc_dt::uint64 start_range, sc_dt::uint64 end_range) {}
173
174template <typename CFG> typename CFG::data_t axi::pin::ace_target<CFG>::get_read_data_for_beat(fsm_handle* fsm_hndl) {
175 auto beat_count = fsm_hndl->beat_count;
176 // SCCTRACE(SCMOD) << " " ;
177 auto size = axi::get_burst_size(*fsm_hndl->trans);
178 auto byte_offset = beat_count * size;
179 auto offset = (fsm_hndl->trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
180 typename CFG::data_t data{0};
181 if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) { // un-aligned multi-beat access
182 if(beat_count == 0) {
183 auto dptr = fsm_hndl->trans->get_data_ptr();
184 for(size_t i = offset; i < size; ++i, ++dptr) {
185 auto bit_offs = i * 8;
186 data(bit_offs + 7, bit_offs) = *dptr;
187 }
188 } else {
189 auto beat_start_idx = byte_offset - offset;
190 auto data_len = fsm_hndl->trans->get_data_length();
191 auto dptr = fsm_hndl->trans->get_data_ptr() + beat_start_idx;
192 for(size_t i = offset; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr) {
193 auto bit_offs = i * 8;
194 data(bit_offs + 7, bit_offs) = *dptr;
195 }
196 }
197 } else { // aligned or single beat access
198 auto dptr = fsm_hndl->trans->get_data_ptr() + byte_offset;
199 for(size_t i = 0; i < size; ++i, ++dptr) {
200 auto bit_offs = (offset + i) * 8;
201 data(bit_offs + 7, bit_offs) = *dptr;
202 }
203 }
204 return data;
205}
206
207template <typename CFG> inline void axi::pin::ace_target<CFG>::setup_callbacks(fsm_handle* fsm_hndl) {
208 fsm_hndl->fsm->cb[RequestPhaseBeg] = [this, fsm_hndl]() -> void { fsm_hndl->beat_count = 0; };
209 fsm_hndl->fsm->cb[BegPartReqE] = [this, fsm_hndl]() -> void {
210 sc_assert(fsm_hndl->trans->get_command() == tlm::TLM_WRITE_COMMAND);
211 tlm::tlm_phase phase = axi::BEGIN_PARTIAL_REQ;
212 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
213 auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
214 if(ret == tlm::TLM_UPDATED) {
215 schedule(EndPartReqE, fsm_hndl->trans, t, true);
216 }
217 };
218 fsm_hndl->fsm->cb[EndPartReqE] = [this, fsm_hndl]() -> void {
219 wdata_end_req_evt.notify();
220 active_req_beat[tlm::TLM_WRITE_COMMAND] = nullptr;
221 fsm_hndl->beat_count++;
222 };
223 fsm_hndl->fsm->cb[BegReqE] = [this, fsm_hndl]() -> void {
224 if(fsm_hndl->is_snoop) {
225 SCCTRACE(SCMOD) << "in BegReq of setup_cb, call write_ac() ";
226 active_req[SNOOP] = fsm_hndl;
227 write_ac(*fsm_hndl->trans);
228 ac_evt.notify(sc_core::SC_ZERO_TIME);
229
230 } else {
231 tlm::tlm_phase phase = tlm::BEGIN_REQ;
232 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
233 auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
234 if(ret == tlm::TLM_UPDATED) {
235 schedule(EndReqE, fsm_hndl->trans, t, true);
236 }
237 }
238 };
239
240 fsm_hndl->fsm->cb[EndReqE] = [this, fsm_hndl]() -> void {
241 if(fsm_hndl->is_snoop) {
242 SCCTRACE(SCMOD) << "snoop with EndReq evt";
243 auto latency = 0;
244 snp_resp_queue.push_back(fsm_hndl);
245 active_req[SNOOP] = nullptr;
246 tlm::tlm_phase phase = tlm::END_REQ;
247 // ?? here t(delay) should be zero or clock cycle??
248 // sc_core::sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : sc_core::SC_ZERO_TIME);
249 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
250 auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
251 auto exta = fsm_hndl->trans->get_extension<ace_extension>();
252 fsm_hndl->trans->set_response_status(tlm::TLM_OK_RESPONSE);
253 } else {
254 switch(fsm_hndl->trans->get_command()) {
255 case tlm::TLM_READ_COMMAND:
256 ar_end_req_evt.notify();
257 active_req_beat[tlm::TLM_READ_COMMAND] = nullptr;
258 break;
259 case tlm::TLM_WRITE_COMMAND:
260 wdata_end_req_evt.notify();
261 active_req_beat[tlm::TLM_WRITE_COMMAND] = nullptr;
262 fsm_hndl->beat_count++;
263 break;
264 default:
265 break;
266 }
267 }
268 };
269 fsm_hndl->fsm->cb[BegPartRespE] = [this, fsm_hndl]() -> void {
270 if(fsm_hndl->is_snoop) {
271 tlm::tlm_phase phase = axi::BEGIN_PARTIAL_RESP;
272 sc_core::sc_time t;
273 auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
274
275 } else {
276 assert(fsm_hndl->trans->is_read());
277 active_resp_beat[tlm::TLM_READ_COMMAND] = fsm_hndl;
278 rresp_vl.notify({1, fsm_hndl});
279 }
280 };
281 fsm_hndl->fsm->cb[EndPartRespE] = [this, fsm_hndl]() -> void {
282 if(fsm_hndl->is_snoop) {
283 fsm_hndl->beat_count++;
284 cd_end_req_evt.notify();
285
286 } else {
287 // scheduling the response
288 assert(fsm_hndl->trans->is_read());
289 tlm::tlm_phase phase = axi::END_PARTIAL_RESP;
290 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
291 auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
292 active_resp_beat[tlm::TLM_READ_COMMAND] = nullptr;
293 fsm_hndl->beat_count++;
294 }
295 };
296 fsm_hndl->fsm->cb[BegRespE] = [this, fsm_hndl]() -> void {
297 SCCTRACE(SCMOD) << "processing event BegRespE for trans " << *fsm_hndl->trans;
298 if(fsm_hndl->is_snoop) {
299 tlm::tlm_phase phase = tlm::BEGIN_RESP;
300 sc_core::sc_time t;
301 auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
302 } else {
303 auto size = axi::get_burst_size(*fsm_hndl->trans);
304 active_resp_beat[fsm_hndl->trans->get_command()] = fsm_hndl;
305 switch(fsm_hndl->trans->get_command()) {
306 case tlm::TLM_READ_COMMAND:
307 rresp_vl.notify({3, fsm_hndl});
308 break;
309 case tlm::TLM_WRITE_COMMAND:
310 wresp_vl.notify({3, fsm_hndl});
311 break;
312 default:
313 break;
314 }
315 }
316 };
317 fsm_hndl->fsm->cb[EndRespE] = [this, fsm_hndl]() -> void {
318 if(fsm_hndl->is_snoop) {
319 SCCTRACE(SCMOD) << " in EndRespE ";
320 cd_end_req_evt.notify();
321 cr_end_req_evt.notify(); // need to check these two event??
322 snp_resp_queue.pop_front();
323 fsm_hndl->finish.notify();
324
325 } else {
326 // scheduling the response
327 tlm::tlm_phase phase = tlm::END_RESP;
328 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
329 auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
330 SCCTRACE(SCMOD) << "EndResp of setup_cb with coherent = " << coherent;
331 if(coherent)
332 schedule(Ack, fsm_hndl->trans, t); // later can add ack_resp_delay to replace t
333 else {
334 fsm_hndl->finish.notify();
335 active_resp_beat[fsm_hndl->trans->get_command()] = nullptr;
336 }
337 }
338 };
339 fsm_hndl->fsm->cb[Ack] = [this, fsm_hndl]() -> void {
340 SCCTRACE(SCMOD) << " in Ack of setup_cb";
341 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
342 tlm::tlm_phase phase = axi::ACK;
343 auto ret = isckt->nb_transport_fw(*fsm_hndl->trans, phase, t);
344 fsm_hndl->finish.notify();
345 active_resp_beat[fsm_hndl->trans->get_command()] = nullptr;
346 };
347}
348
349template <typename CFG> inline void axi::pin::ace_target<CFG>::ar_t() {
350 this->ar_ready.write(false);
351 wait(sc_core::SC_ZERO_TIME);
352 auto arid = 0U;
353 auto arlen = 0U;
354 auto arsize = util::ilog2(CFG::BUSWIDTH / 8);
355
356 auto data_len = (1 << arsize) * (arlen + 1);
357 while(true) {
358 wait(clk_delayed);
359 while(!this->ar_valid.read()) {
360 wait(this->ar_valid.posedge_event());
361 wait(CLK_DELAY); // verilator might create spurious events
362 }
363 SCCTRACE(SCMOD) << "ARVALID detected for 0x" << std::hex << this->ar_addr.read();
364 if(!CFG::IS_LITE) {
365 arid = this->ar_id->read().to_uint();
366 arlen = this->ar_len->read().to_uint();
367 arsize = this->ar_size->read().to_uint();
368 }
369 data_len = (1 << arsize) * (arlen + 1);
371 gp->set_address(this->ar_addr.read());
372 gp->set_command(tlm::TLM_READ_COMMAND);
373 gp->set_streaming_width(data_len);
375 gp->get_extension(ext);
376 ext->set_id(arid);
377 ext->set_length(arlen);
378 ext->set_size(arsize);
379 if(this->ar_lock->read())
380 ext->set_exclusive(true);
381 ext->set_domain(axi::into<axi::domain_e>(this->ar_domain->read())); // ace extension
382 ext->set_snoop(axi::into<axi::snoop_e>(this->ar_snoop->read()));
383 ext->set_barrier(axi::into<axi::bar_e>(this->ar_bar->read()));
384 ext->set_burst(CFG::IS_LITE ? axi::burst_e::INCR : axi::into<axi::burst_e>(this->ar_burst->read()));
385 ext->set_cache(this->ar_cache->read());
386 ext->set_prot(this->ar_prot->read());
387 ext->set_qos(this->ar_qos->read());
388 ext->set_region(this->ar_region->read());
389
390 active_req_beat[tlm::TLM_READ_COMMAND] = find_or_create(gp);
391 react(axi::fsm::protocol_time_point_e::BegReqE, active_req_beat[tlm::TLM_READ_COMMAND]);
392 wait(ar_end_req_evt);
393 this->ar_ready.write(true);
394 wait(clk_i.posedge_event());
395 this->ar_ready.write(false);
396 }
397}
398
399template <typename CFG> inline void axi::pin::ace_target<CFG>::rresp_t() {
400 this->r_valid.write(false);
401 wait(sc_core::SC_ZERO_TIME);
402 fsm_handle* fsm_hndl;
403 uint8_t val;
404 while(true) {
405 // rresp_vl notified in BEGIN_PARTIAL_REQ ( val=1 ??)or in BEG_RESP(val=3??)
406 std::tie(val, fsm_hndl) = rresp_vl.get();
407 SCCTRACE(SCMOD) << __FUNCTION__ << " val = " << (uint16_t)val << " beat count = " << fsm_hndl->beat_count;
408 SCCTRACE(SCMOD) << __FUNCTION__ << " got read response beat of trans " << *fsm_hndl->trans;
409 auto ext = fsm_hndl->trans->get_extension<axi::ace_extension>();
410 this->r_data.write(get_read_data_for_beat(fsm_hndl));
411 this->r_resp.write(ext->get_cresp());
412 this->r_valid.write(val & 0x1);
413 if(!CFG::IS_LITE) {
414 this->r_id->write(ext->get_id());
415 this->r_last->write(val & 0x2);
416 }
417 do {
418 wait(this->r_ready.posedge_event() | clk_delayed);
419 if(this->r_ready.read()) {
420 auto evt =
421 CFG::IS_LITE || (val & 0x2) ? axi::fsm::protocol_time_point_e::EndRespE : axi::fsm::protocol_time_point_e::EndPartRespE;
422 react(evt, active_resp_beat[tlm::TLM_READ_COMMAND]);
423 }
424 } while(!this->r_ready.read());
425 SCCTRACE(SCMOD) << "finished read response beat of trans [" << fsm_hndl->trans << "]";
426 wait(clk_i.posedge_event());
427 this->r_valid.write(false);
428 if(!CFG::IS_LITE)
429 this->r_last->write(false);
430 }
431}
432
433template <typename CFG> inline void axi::pin::ace_target<CFG>::aw_t() {
434 this->aw_ready.write(false);
435 wait(sc_core::SC_ZERO_TIME);
436 const auto awsize = util::ilog2(CFG::BUSWIDTH / 8);
437 while(true) {
438 wait(clk_delayed);
439 while(!this->aw_valid.read()) {
440 wait(this->aw_valid.posedge_event());
441 wait(CLK_DELAY); // verilator might create spurious events
442 }
443 SCCTRACE(SCMOD) << "AWVALID detected for 0x" << std::hex << this->aw_addr.read();
444 // clang-format off
445 aw_data awd = {CFG::IS_LITE ? 0U : this->aw_id->read().to_uint(),
446 this->aw_addr.read().to_uint64(),
447 this->aw_prot.read().to_uint(),
448 CFG::IS_LITE ? awsize : this->aw_size->read().to_uint(),
449 CFG::IS_LITE ? 0U : this->aw_cache->read().to_uint(),
450 CFG::IS_LITE ? 0U : this->aw_burst->read().to_uint(),
451 CFG::IS_LITE ? 0U : this->aw_qos->read().to_uint(),
452 CFG::IS_LITE ? 0U : this->aw_region->read().to_uint(),
453 CFG::IS_LITE ? 0U : this->aw_len->read().to_uint(),
454 CFG::IS_LITE ? 0U : this->aw_domain->read().to_uint(),
455 CFG::IS_LITE ? 0U : this->aw_snoop->read().to_uint(),
456 CFG::IS_LITE ? 0U : this->aw_bar->read().to_uint(),
457 CFG::IS_LITE ? 0U : this->aw_unique->read(),
458 CFG::IS_LITE ? false : this->aw_lock->read(),
459 0};
460 // clang-format on
461 aw_que.notify(awd);
462 this->aw_ready.write(true);
463 wait(clk_i.posedge_event());
464 this->aw_ready.write(false);
465 }
466}
467
468template <typename CFG> inline void axi::pin::ace_target<CFG>::wdata_t() {
469 this->w_ready.write(false);
470 wait(sc_core::SC_ZERO_TIME);
471 while(true) {
472 wait(this->w_valid.posedge_event() | clk_delayed);
473 this->w_ready.write(false);
474 if(this->w_valid.event() || (!active_req_beat[tlm::TLM_WRITE_COMMAND] && this->w_valid.read())) {
475 if(!active_req[tlm::TLM_WRITE_COMMAND]) {
476 if(!aw_que.has_next())
477 wait(aw_que.event());
478 auto awd = aw_que.get();
479 auto data_len = (1 << awd.size) * (awd.len + 1);
480 auto gp = tlm::scc::tlm_mm<>::get().allocate<axi::ace_extension>(data_len, true);
481 gp->set_address(awd.addr);
482 gp->set_command(tlm::TLM_WRITE_COMMAND);
484 gp->get_extension(ext);
485 ext->set_id(awd.id);
486 ext->set_length(awd.len);
487 ext->set_size(awd.size);
488 ext->set_burst(axi::into<axi::burst_e>(awd.burst));
489 ext->set_prot(awd.prot);
490 ext->set_qos(awd.qos);
491 ext->set_cache(awd.cache);
492 ext->set_region(awd.region);
493 ext->set_snoop(axi::into<axi::snoop_e>(awd.snoop));
494 ext->set_barrier(axi::into<axi::bar_e>(awd.bar));
495 ext->set_unique(awd.unique);
496 ext->set_exclusive(awd.lock);
497 if(CFG::USERWIDTH)
498 ext->set_user(axi::common::id_type::CTRL, awd.user);
499
500 active_req_beat[tlm::TLM_WRITE_COMMAND] = find_or_create(gp);
501 active_req[tlm::TLM_WRITE_COMMAND] = active_req_beat[tlm::TLM_WRITE_COMMAND];
502 }
503 auto* fsm_hndl = active_req[tlm::TLM_WRITE_COMMAND];
504 SCCTRACE(SCMOD) << "WDATA detected for 0x" << std::hex << this->ar_addr.read();
505 auto& gp = fsm_hndl->trans;
506 auto data = this->w_data.read();
507 auto strb = this->w_strb.read();
508 auto last = CFG::IS_LITE ? true : this->w_last->read();
509 auto beat_count = fsm_hndl->beat_count;
510 auto size = axi::get_burst_size(*fsm_hndl->trans);
511 auto byte_offset = beat_count * size;
512 auto offset = (fsm_hndl->trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
513 if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) { // un-aligned multi-beat access
514 if(beat_count == 0) {
515 auto dptr = fsm_hndl->trans->get_data_ptr();
516 auto beptr = fsm_hndl->trans->get_byte_enable_ptr();
517 for(size_t i = offset; i < size; ++i, ++dptr, ++beptr) {
518 auto bit_offs = i * 8;
519 *dptr = data(bit_offs + 7, bit_offs).to_uint();
520 *beptr = strb[i] ? 0xff : 0;
521 }
522 } else {
523 auto beat_start_idx = byte_offset - offset;
524 auto data_len = fsm_hndl->trans->get_data_length();
525 auto dptr = fsm_hndl->trans->get_data_ptr() + beat_start_idx;
526 auto beptr = fsm_hndl->trans->get_byte_enable_ptr() + beat_start_idx;
527 for(size_t i = 0; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr, ++beptr) {
528 auto bit_offs = i * 8;
529 *dptr = data(bit_offs + 7, bit_offs).to_uint();
530 *beptr = strb[i] ? 0xff : 0;
531 }
532 }
533 } else { // aligned or single beat access
534 auto dptr = fsm_hndl->trans->get_data_ptr() + byte_offset;
535 auto beptr = fsm_hndl->trans->get_byte_enable_ptr() + byte_offset;
536 for(size_t i = 0; i < size; ++i, ++dptr, ++beptr) {
537 auto bit_offs = (offset + i) * 8;
538 *dptr = data(bit_offs + 7, bit_offs).to_uint();
539 *beptr = strb[offset + i] ? 0xff : 0;
540 }
541 }
542 // TODO: assuming consecutive write (not scattered)
543 auto strobe = strb.to_uint();
544 if(last) {
545 auto act_data_len = CFG::IS_LITE ? util::bit_count(strobe) : (beat_count + 1) * size;
546 // if(CFG::IS_LITE && act_data_len<CFG::BUSWIDTH/8) {
547 // std::fill(gp->get_byte_enable_ptr(), gp->get_byte_enable_ptr() + act_data_len, 0xff);
548 // std::fill(gp->get_byte_enable_ptr() + act_data_len, gp->get_byte_enable_ptr() +
549 // gp->get_byte_enable_length(), 0x0);
550 // }
551 gp->set_data_length(act_data_len);
552 gp->set_byte_enable_length(act_data_len);
553 gp->set_streaming_width(act_data_len);
554 }
555 auto tp = CFG::IS_LITE || this->w_last->read() ? axi::fsm::protocol_time_point_e::BegReqE
556 : axi::fsm::protocol_time_point_e::BegPartReqE;
557 react(tp, fsm_hndl);
558 // notifed in EndPartReqE/EndReq
559 wait(wdata_end_req_evt);
560 this->w_ready.write(true);
561 wait(clk_i.posedge_event());
562 this->w_ready.write(false);
563 if(last)
564 active_req[tlm::TLM_WRITE_COMMAND] = nullptr;
565 }
566 }
567}
568
569template <typename CFG> inline void axi::pin::ace_target<CFG>::bresp_t() {
570 this->b_valid.write(false);
571 wait(sc_core::SC_ZERO_TIME);
572 fsm_handle* fsm_hndl;
573 uint8_t val;
574 while(true) {
575 std::tie(val, fsm_hndl) = wresp_vl.get();
576 SCCTRACE(SCMOD) << "got write response of trans " << *fsm_hndl->trans;
577 auto ext = fsm_hndl->trans->get_extension<axi::ace_extension>();
578 this->b_resp.write(axi::to_int(ext->get_resp()));
579 this->b_valid.write(true);
580 if(!CFG::IS_LITE)
581 this->b_id->write(ext->get_id());
582 SCCTRACE(SCMOD) << "got write response";
583 do {
584 wait(this->b_ready.posedge_event() | clk_delayed);
585 if(this->b_ready.read()) {
586 react(axi::fsm::protocol_time_point_e::EndRespE, active_resp_beat[tlm::TLM_WRITE_COMMAND]);
587 }
588 } while(!this->b_ready.read());
589 SCCTRACE(SCMOD) << "finished write response of trans [" << fsm_hndl->trans << "]";
590 wait(clk_i.posedge_event());
591 this->b_valid.write(false);
592 }
593}
594
595// write snoop address
596template <typename CFG> inline void axi::pin::ace_target<CFG>::write_ac(tlm::tlm_generic_payload& trans) {
597 sc_dt::sc_uint<CFG::ADDRWIDTH> addr = trans.get_address();
598 this->ac_addr.write(addr);
599 auto ext = trans.get_extension<ace_extension>();
600 sc_assert(ext && "No ACE extension found for snoop access");
601 this->ac_prot.write(ext->get_prot());
602 this->ac_snoop->write(sc_dt::sc_uint<4>((uint8_t)ext->get_snoop()));
603}
604
605template <typename CFG> inline void axi::pin::ace_target<CFG>::ac_t() {
606 this->ac_valid.write(false);
607 wait(sc_core::SC_ZERO_TIME);
608 while(true) {
609 wait(ac_evt);
610 this->ac_valid.write(true);
611 do {
612 wait(this->ac_ready.posedge_event() | clk_delayed);
613 if(this->ac_ready.read()) {
614 SCCTRACE(SCMOD) << "in ac_t() detect ac_ready high , schedule EndReq";
615 react(axi::fsm::protocol_time_point_e::EndReqE, active_req[SNOOP]);
616 }
617 } while(!this->ac_ready.read());
618 wait(clk_i.posedge_event());
619 this->ac_valid.write(false);
620 }
621}
622
623template <typename CFG> inline void axi::pin::ace_target<CFG>::cd_t() {
624 this->cd_ready.write(false);
625 wait(sc_core::SC_ZERO_TIME);
626 while(true) {
627 wait(this->cd_valid.posedge_event() | clk_delayed);
628 if(this->cd_valid.read()) {
629 SCCTRACE(SCMOD) << "in cd_t(), received cd_valid high ";
630 wait(sc_core::SC_ZERO_TIME);
631 auto data = this->cd_data.read();
632 if(snp_resp_queue.empty())
633 sc_assert(" snp_resp_queue empty");
634 auto* fsm_hndl = snp_resp_queue.front();
635 auto beat_count = fsm_hndl->beat_count;
636 SCCTRACE(SCMOD) << "in cd_t(), received beau_count = " << fsm_hndl->beat_count;
637 auto size = axi::get_burst_size(*fsm_hndl->trans);
638 auto byte_offset = beat_count * size;
639 auto offset = (fsm_hndl->trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
640 if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) { // un-aligned multi-beat access
641 if(beat_count == 0) {
642 auto dptr = fsm_hndl->trans->get_data_ptr();
643 for(size_t i = offset; i < size; ++i, ++dptr) {
644 auto bit_offs = i * 8;
645 *dptr = data(bit_offs + 7, bit_offs).to_uint();
646 }
647 } else {
648 auto beat_start_idx = beat_count * size - offset;
649 auto data_len = fsm_hndl->trans->get_data_length();
650 auto dptr = fsm_hndl->trans->get_data_ptr() + beat_start_idx;
651 for(size_t i = offset; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr) {
652 auto bit_offs = i * 8;
653 *dptr = data(bit_offs + 7, bit_offs).to_uint();
654 }
655 }
656 } else { // aligned or single beat access
657 auto dptr = fsm_hndl->trans->get_data_ptr() + beat_count * size;
658 for(size_t i = 0; i < size; ++i, ++dptr) {
659 auto bit_offs = (offset + i) * 8;
660 *dptr = data(bit_offs + 7, bit_offs).to_uint();
661 }
662 }
663 /*
664 axi::ace_extension* e;
665 fsm_hndl->trans->get_extension(e);
666 e->set_resp(axi::into<axi::resp_e>(resp));
667 e->add_to_response_array(*e);
668 */
669 auto tp = CFG::IS_LITE || this->cd_last->read() ? axi::fsm::protocol_time_point_e::BegRespE
670 : axi::fsm::protocol_time_point_e::BegPartRespE;
671 if(!this->cd_last->read()) // only react BegPartRespE
672 react(tp, fsm_hndl);
673 // cd_end_req_evt notified in EndPartRespE or EndResp
674 wait(cd_end_req_evt);
675 this->cd_ready.write(true);
676 wait(clk_i.posedge_event());
677 this->cd_ready.write(false);
678 }
679 }
680}
681
682template <typename CFG> inline void axi::pin::ace_target<CFG>::cr_t() {
683 this->cr_ready.write(false);
684 wait(sc_core::SC_ZERO_TIME);
685 while(true) {
686 wait(this->cr_valid.posedge_event() | clk_delayed);
687 if(this->cr_valid.read()) {
688 SCCTRACE(SCMOD) << "in cr_t() received cr_valid high ";
689 wait(sc_core::SC_ZERO_TIME);
690
691 auto* fsm_hndl = snp_resp_queue.front();
692 auto crresp = this->cr_resp.read();
694 fsm_hndl->trans->get_extension(e);
695 e->set_cresp(crresp);
696
697 SCCTRACE(SCMOD) << " in cr_t() react() with BegRespE ";
698 // hongyu TBD?? schedule BegResp??
699 react(axi::fsm::protocol_time_point_e::BegRespE, fsm_hndl);
700 wait(cr_end_req_evt); // notify in EndResp
701 this->cr_ready.write(true);
702 wait(clk_i.posedge_event());
703 this->cr_ready.write(false);
704 }
705 }
706}
707
708#endif /* _BUS_AXI_PIN_ACE_TARGET_H_ */
payload_type * allocate()
get a plain tlm_payload_type without extensions
Definition tlm_mm.h:218
pin level adapters
TLM2.0 components modeling AHB.
E into(typename std::underlying_type< E >::type t)
constexpr ULT to_int(E t)
Definition axi_tlm.h:47
wdata_axi< CFG, TYPES > wdata_ace
alias declaration for rresp_ch_ace, wdata_ch_ace, b_ch_ace???
Definition signal_if.h:713
unsigned get_burst_size(const request &r)
Definition axi_tlm.h:1202
CONSTEXPR unsigned ilog2(uint32_t val)
Definition ities.h:235
void set_cresp(uint8_t)
set the coherent response status
Definition axi_tlm.h:1603
uint8_t get_cresp() const
get the coherent response status
Definition axi_tlm.h:1605
void set_barrier(bar_e)
set the AxBAR value
Definition axi_tlm.h:1521
void set_domain(domain_e)
set the AxDOMAIN value
Definition axi_tlm.h:1513
void set_unique(bool)
set the AxUNIQUE value
Definition axi_tlm.h:1525
snoop_e get_snoop() const
get the AxSNOOP value return the snoop value
Definition axi_tlm.h:1519
void set_snoop(snoop_e)
set the AxSNOOP value
Definition axi_tlm.h:1517
void set_exclusive(bool=true)
get the exclusive bit of AxLOCK (AxLOCK[0])
Definition axi_tlm.h:1369
void set_id(unsigned int value)
Definition axi_tlm.h:1297
void set_user(id_type chnl, unsigned int value)
Definition axi_tlm.h:1301
unsigned int get_id() const
Definition axi_tlm.h:1299
base class of all AXITLM based adapters and interfaces.
Definition base.h:43
virtual axi::fsm::fsm_handle * create_fsm_handle()=0
function to create a fsm_handle. Needs to be implemented by the derived class
base(size_t transfer_width, bool coherent=false, axi::fsm::protocol_time_point_e wr_start=axi::fsm::RequestPhaseBeg)
the constructor
Definition base.cpp:43
tlm::scc::tlm_gp_shared_ptr trans
pointer to the associated AXITLM payload
Definition types.h:62
sc_core::sc_event finish
event indicating the end of the transaction
Definition types.h:68
size_t beat_count
beat count of this transaction
Definition types.h:64
AxiProtocolFsm *const fsm
pointer to the FSM
Definition types.h:60
bool is_snoop
indicator if this is a snoop access
Definition types.h:66
void set_length(uint8_t)
set the AxLEN value of the transaction, the value denotes the burst length - 1
Definition axi_tlm.h:1452
void set_qos(uint8_t)
set the AxQOS (quality of service) value
Definition axi_tlm.h:1498
void set_cache(uint8_t)
set the AxCACHE value as POD, only value from 0..15 are allowed
Definition axi_tlm.h:1506
void set_region(uint8_t)
set the AxREGION value
Definition axi_tlm.h:1502
void set_burst(burst_e)
set the AxBURST value,
Definition axi_tlm.h:1463
void set_size(uint8_t)
get the AxSIZE value of the transaction, the length is 2^size. It needs to be less than 10 (512 bit w...
Definition axi_tlm.h:1456
uint8_t get_prot() const
set the AxPROT value as POD, only values from 0...7 are allowed
Definition axi_tlm.h:1472
void set_prot(uint8_t)
set the AxPROT value as POD, only values from 0...7 are allowed
Definition axi_tlm.h:1467
resp_e get_resp() const
get the response status as POD
Definition axi_tlm.h:1574
priority event queue
Definition peq.h:41
static tlm_mm & get()
accessor function of the singleton
Definition tlm_mm.h:338