17 #ifndef _BUS_AXI_PIN_ACE_LITE_TARGET_H_
18 #define _BUS_AXI_PIN_ACE_LITE_TARGET_H_
20 #include <axi/axi_tlm.h>
21 #include <axi/fsm/base.h>
22 #include <axi/fsm/protocol_fsm.h>
23 #include <interfaces/axi/signal_if.h>
25 #include <tlm/scc/tlm_mm.h>
26 #include <util/ities.h>
33 using namespace axi::fsm;
35 template <
typename CFG>
39 public b_ace_lite<CFG, typename CFG::slave_types>,
46 using payload_type = axi::axi_protocol_types::tlm_payload_type;
47 using phase_type = axi::axi_protocol_types::tlm_phase_type;
49 sc_core::sc_in<bool> clk_i{
"clk_i"};
54 : sc_core::sc_module(nm)
56 ,
base(CFG::BUSWIDTH,
false) {
57 instance_name = name();
60 sensitive << clk_i.pos();
70 tlm::tlm_sync_enum nb_transport_bw(payload_type& trans, phase_type& phase, sc_core::sc_time& t)
override;
72 void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, sc_dt::uint64 end_range)
override;
74 void end_of_elaboration()
override { clk_if =
dynamic_cast<sc_core::sc_clock*
>(clk_i.get_interface()); }
82 if(sc_core::sc_delta_count_at_current_time() < 5) {
83 clk_self.notify(sc_core::SC_ZERO_TIME);
84 next_trigger(clk_self);
86 clk_delayed.notify(sc_core::SC_ZERO_TIME );
88 clk_delayed.notify(axi::CLK_DELAY);
96 static typename CFG::data_t get_read_data_for_beat(
fsm::fsm_handle* fsm_hndl);
117 std::deque<axi::fsm::fsm_handle*> snp_resp_queue;
119 sc_core::sc_clock* clk_if{
nullptr};
120 sc_core::sc_event clk_delayed, clk_self, ar_end_req_evt, wdata_end_req_evt;
121 std::array<fsm_handle*, 3> active_req_beat{
nullptr,
nullptr,
nullptr};
122 std::array<fsm_handle*, 3> active_req{
nullptr,
nullptr,
nullptr};
123 std::array<fsm_handle*, 3> active_resp_beat{
nullptr,
nullptr,
nullptr};
131 template <
typename CFG>
133 auto ret = tlm::TLM_ACCEPTED;
134 SCCTRACE(SCMOD) <<
"nb_transport_bw with " << phase <<
" with delay= " << t <<
" of trans " << trans;
135 if(phase == END_PARTIAL_REQ || phase == tlm::END_REQ) {
136 schedule(phase == tlm::END_REQ ? EndReqE : EndPartReqE, &trans, t,
false);
137 }
else if(phase == axi::BEGIN_PARTIAL_RESP || phase == tlm::BEGIN_RESP) {
138 schedule(phase == tlm::BEGIN_RESP ? BegRespE : BegPartRespE, &trans, t,
false);
140 SCCFATAL(SCMOD) <<
"Illegal phase received: " << phase;
144 template <
typename CFG>
150 auto byte_offset = beat_count * size;
151 auto offset = (fsm_hndl->
trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
152 typename CFG::data_t data{0};
153 if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) {
154 if(beat_count == 0) {
155 auto dptr = fsm_hndl->
trans->get_data_ptr();
156 for(
size_t i = offset; i < size; ++i, ++dptr) {
157 auto bit_offs = i * 8;
158 data(bit_offs + 7, bit_offs) = *dptr;
161 auto beat_start_idx = byte_offset - offset;
162 auto data_len = fsm_hndl->
trans->get_data_length();
163 auto dptr = fsm_hndl->
trans->get_data_ptr() + beat_start_idx;
164 for(
size_t i = 0; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr) {
165 auto bit_offs = i * 8;
166 data(bit_offs + 7, bit_offs) = *dptr;
170 auto dptr = fsm_hndl->
trans->get_data_ptr() + byte_offset;
171 for(
size_t i = 0; i < size; ++i, ++dptr) {
172 auto bit_offs = (offset + i) * 8;
173 data(bit_offs + 7, bit_offs) = *dptr;
180 fsm_hndl->
fsm->cb[RequestPhaseBeg] = [
this, fsm_hndl]() ->
void { fsm_hndl->
beat_count = 0; };
181 fsm_hndl->
fsm->cb[BegPartReqE] = [
this, fsm_hndl]() ->
void {
182 sc_assert(fsm_hndl->
trans->get_command() == tlm::TLM_WRITE_COMMAND);
183 tlm::tlm_phase phase = axi::BEGIN_PARTIAL_REQ;
184 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
185 auto ret = isckt->nb_transport_fw(*fsm_hndl->
trans, phase, t);
186 if(ret == tlm::TLM_UPDATED) {
187 schedule(EndPartReqE, fsm_hndl->
trans, t,
true);
190 fsm_hndl->
fsm->cb[EndPartReqE] = [
this, fsm_hndl]() ->
void {
191 wdata_end_req_evt.notify();
192 active_req_beat[tlm::TLM_WRITE_COMMAND] =
nullptr;
195 fsm_hndl->
fsm->cb[BegReqE] = [
this, fsm_hndl]() ->
void {
196 tlm::tlm_phase phase = tlm::BEGIN_REQ;
197 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
198 auto ret = isckt->nb_transport_fw(*fsm_hndl->
trans, phase, t);
199 if(ret == tlm::TLM_UPDATED) {
200 schedule(EndReqE, fsm_hndl->
trans, t,
true);
203 fsm_hndl->
fsm->cb[EndReqE] = [
this, fsm_hndl]() ->
void {
204 switch(fsm_hndl->
trans->get_command()) {
205 case tlm::TLM_READ_COMMAND:
206 ar_end_req_evt.notify();
207 active_req_beat[tlm::TLM_READ_COMMAND] =
nullptr;
209 case tlm::TLM_WRITE_COMMAND:
210 wdata_end_req_evt.notify();
211 active_req_beat[tlm::TLM_WRITE_COMMAND] =
nullptr;
218 fsm_hndl->
fsm->cb[BegPartRespE] = [
this, fsm_hndl]() ->
void {
219 assert(fsm_hndl->
trans->is_read());
220 active_resp_beat[tlm::TLM_READ_COMMAND] = fsm_hndl;
221 rresp_vl.notify({1, fsm_hndl});
223 fsm_hndl->
fsm->cb[EndPartRespE] = [
this, fsm_hndl]() ->
void {
225 assert(fsm_hndl->
trans->is_read());
226 tlm::tlm_phase phase = axi::END_PARTIAL_RESP;
227 sc_core::sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : sc_core::SC_ZERO_TIME);
228 auto ret = isckt->nb_transport_fw(*fsm_hndl->
trans, phase, t);
229 active_resp_beat[tlm::TLM_READ_COMMAND] =
nullptr;
232 fsm_hndl->
fsm->cb[BegRespE] = [
this, fsm_hndl]() ->
void {
233 SCCTRACE(SCMOD) <<
"processing event BegRespE for trans " << *fsm_hndl->
trans;
235 active_resp_beat[fsm_hndl->
trans->get_command()] = fsm_hndl;
236 switch(fsm_hndl->
trans->get_command()) {
237 case tlm::TLM_READ_COMMAND:
238 rresp_vl.notify({3, fsm_hndl});
240 case tlm::TLM_WRITE_COMMAND:
241 wresp_vl.notify({3, fsm_hndl});
247 fsm_hndl->
fsm->cb[EndRespE] = [
this, fsm_hndl]() ->
void {
249 tlm::tlm_phase phase = tlm::END_RESP;
250 sc_core::sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : sc_core::SC_ZERO_TIME);
251 auto ret = isckt->nb_transport_fw(*fsm_hndl->
trans, phase, t);
252 SCCTRACE(SCMOD) <<
"EndResp of setup_cb with coherent = " << coherent;
253 fsm_hndl->
finish.notify();
254 active_resp_beat[fsm_hndl->
trans->get_command()] =
nullptr;
259 this->ar_ready.write(
false);
260 wait(sc_core::SC_ZERO_TIME);
264 auto data_len = (1 << arsize) * (arlen + 1);
267 while(!this->ar_valid.read()) {
268 wait(this->ar_valid.posedge_event());
271 SCCTRACE(SCMOD) <<
"ARVALID detected for 0x" << std::hex << this->ar_addr.read();
272 arid = this->ar_id->read().to_uint();
273 arlen = this->ar_len->read().to_uint();
274 arsize = this->ar_size->read().to_uint();
275 data_len = (1 << arsize) * (arlen + 1);
277 gp->set_address(this->ar_addr.read());
278 gp->set_command(tlm::TLM_READ_COMMAND);
279 gp->set_streaming_width(data_len);
281 gp->get_extension(ext);
284 if(this->ar_lock->read())
287 ext->
set_burst(axi::into<axi::burst_e>(this->ar_burst->read()));
289 ext->
set_prot(this->ar_prot->read());
290 ext->
set_qos(this->ar_qos->read());
292 ext->
set_domain(axi::into<axi::domain_e>(this->ar_domain->read()));
293 ext->
set_snoop(axi::into<axi::snoop_e>(this->ar_snoop->read()));
294 ext->
set_barrier(axi::into<axi::bar_e>(this->ar_bar->read()));
296 active_req_beat[tlm::TLM_READ_COMMAND] = find_or_create(gp);
297 react(axi::fsm::protocol_time_point_e::BegReqE, active_req_beat[tlm::TLM_READ_COMMAND]);
298 wait(ar_end_req_evt);
299 this->ar_ready.write(
true);
300 wait(clk_i.posedge_event());
301 this->ar_ready.write(
false);
306 this->r_valid.write(
false);
307 wait(sc_core::SC_ZERO_TIME);
312 std::tie(val, fsm_hndl) = rresp_vl.get();
313 SCCTRACE(SCMOD) << __FUNCTION__ <<
" val = " << (uint16_t)val <<
" beat count = " << fsm_hndl->
beat_count;
314 SCCTRACE(SCMOD) << __FUNCTION__ <<
" got read response beat of trans " << *fsm_hndl->
trans;
316 this->r_data.write(get_read_data_for_beat(fsm_hndl));
318 this->r_valid.write(val & 0x1);
319 this->r_id->write(ext->
get_id());
320 this->r_last->write(val & 0x2);
322 wait(this->r_ready.posedge_event() | clk_delayed);
323 if(this->r_ready.read()) {
324 auto evt = (val & 0x2) ? axi::fsm::protocol_time_point_e::EndRespE : axi::fsm::protocol_time_point_e::EndPartRespE;
325 react(evt, active_resp_beat[tlm::TLM_READ_COMMAND]);
327 }
while(!this->r_ready.read());
328 SCCTRACE(SCMOD) <<
"finished read response beat of trans [" << fsm_hndl->
trans <<
"]";
329 wait(clk_i.posedge_event());
330 this->r_valid.write(
false);
331 this->r_last->write(
false);
336 this->aw_ready.write(
false);
337 wait(sc_core::SC_ZERO_TIME);
338 const auto awsize =
util::ilog2(CFG::BUSWIDTH / 8);
341 while(!this->aw_valid.read()) {
342 wait(this->aw_valid.posedge_event());
345 SCCTRACE(SCMOD) <<
"AWVALID detected for 0x" << std::hex << this->aw_addr.read();
347 aw_data awd = { this->aw_id->read().to_uint(),
348 this->aw_addr.read().to_uint64(),
349 this->aw_prot.read().to_uint(),
350 this->aw_size->read().to_uint(),
351 this->aw_cache->read().to_uint(),
352 this->aw_burst->read().to_uint(),
353 this->aw_qos->read().to_uint(),
354 this->aw_region->read().to_uint(),
355 this->aw_len->read().to_uint(),
356 this->aw_domain->read().to_uint(),
357 this->aw_snoop->read().to_uint(),
358 this->aw_bar->read().to_uint(),
359 this->aw_unique->read(),
360 this->aw_stashniden->read() ? 0U : this->aw_stashnid->read().to_uint(),
361 this->aw_stashlpiden->read()? 0U : this->aw_stashlpid->read().to_uint(),
362 this->aw_lock->read() ? true :
false,
366 this->aw_ready.write(
true);
367 wait(clk_i.posedge_event());
368 this->aw_ready.write(
false);
373 this->w_ready.write(
false);
374 wait(sc_core::SC_ZERO_TIME);
376 wait(this->w_valid.read() ? clk_delayed : this->w_valid.posedge_event());
377 if(this->w_valid.read()) {
378 if(!active_req[tlm::TLM_WRITE_COMMAND]) {
379 if(!aw_que.has_next())
380 wait(aw_que.event());
381 auto awd = aw_que.get();
382 auto data_len = (1 << awd.size) * (awd.len + 1);
384 gp->set_address(awd.addr);
385 gp->set_command(tlm::TLM_WRITE_COMMAND);
387 gp->get_extension(ext);
391 ext->
set_burst(axi::into<axi::burst_e>(awd.burst));
396 ext->
set_snoop(axi::into<axi::snoop_e>(awd.snoop));
403 ext->
set_user(axi::common::id_type::CTRL, awd.user);
404 active_req_beat[tlm::TLM_WRITE_COMMAND] = find_or_create(gp);
405 active_req[tlm::TLM_WRITE_COMMAND] = active_req_beat[tlm::TLM_WRITE_COMMAND];
406 active_req_beat[tlm::TLM_WRITE_COMMAND]->aux.i32.i0 = 0;
408 auto* fsm_hndl = active_req[tlm::TLM_WRITE_COMMAND];
409 SCCTRACE(SCMOD) <<
"WDATA detected for 0x" << std::hex << this->ar_addr.read();
410 auto& gp = fsm_hndl->
trans;
411 auto data = this->w_data.read();
412 auto strb = this->w_strb.read();
413 auto last = this->w_last->read();
416 auto byte_offset = beat_count * size;
417 auto offset = (fsm_hndl->
trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
418 if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) {
419 if(beat_count == 0) {
420 auto dptr = fsm_hndl->
trans->get_data_ptr();
421 auto beptr = fsm_hndl->
trans->get_byte_enable_ptr();
422 for(
size_t i = offset; i < size; ++i, ++dptr, ++beptr) {
423 auto bit_offs = i * 8;
424 *dptr = data(bit_offs + 7, bit_offs).to_uint();
425 *beptr = strb[i] ? 0xff : 0;
426 fsm_hndl->aux.i32.i0 += strb[i] ? 1 : 0;
429 auto beat_start_idx = byte_offset - offset;
430 auto data_len = fsm_hndl->
trans->get_data_length();
431 auto dptr = fsm_hndl->
trans->get_data_ptr() + beat_start_idx;
432 auto beptr = fsm_hndl->
trans->get_byte_enable_ptr() + beat_start_idx;
433 for(
size_t i = 0; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr, ++beptr) {
434 auto bit_offs = i * 8;
435 *dptr = data(bit_offs + 7, bit_offs).to_uint();
436 *beptr = strb[i] ? 0xff : 0;
437 fsm_hndl->aux.i32.i0 += strb[i] ? 1 : 0;
441 auto dptr = fsm_hndl->
trans->get_data_ptr() + byte_offset;
442 auto beptr = fsm_hndl->
trans->get_byte_enable_ptr() + byte_offset;
443 for(
size_t i = 0; i < size; ++i, ++dptr, ++beptr) {
444 auto bit_offs = (offset + i) * 8;
445 *dptr = data(bit_offs + 7, bit_offs).to_uint();
446 *beptr = strb[offset + i] ? 0xff : 0;
447 fsm_hndl->aux.i32.i0 += strb[offset + i] ? 1 : 0;
451 auto strobe = strb.to_uint();
453 auto act_data_len = fsm_hndl->aux.i32.i0;
454 gp->set_data_length(act_data_len);
455 gp->set_byte_enable_length(act_data_len);
456 gp->set_streaming_width(act_data_len);
458 auto tp = this->w_last->read() ? axi::fsm::protocol_time_point_e::BegReqE : axi::fsm::protocol_time_point_e::BegPartReqE;
461 wait(wdata_end_req_evt);
462 this->w_ready.write(
true);
463 wait(clk_i.posedge_event());
464 this->w_ready.write(
false);
466 active_req[tlm::TLM_WRITE_COMMAND] =
nullptr;
472 this->b_valid.write(
false);
473 wait(sc_core::SC_ZERO_TIME);
477 std::tie(val, fsm_hndl) = wresp_vl.get();
478 SCCTRACE(SCMOD) <<
"got write response of trans " << *fsm_hndl->
trans;
481 this->b_valid.write(
true);
482 this->b_id->write(ext->
get_id());
483 SCCTRACE(SCMOD) <<
"got write response";
485 wait(this->b_ready.posedge_event() | clk_delayed);
486 if(this->b_ready.read()) {
487 react(axi::fsm::protocol_time_point_e::EndRespE, active_resp_beat[tlm::TLM_WRITE_COMMAND]);
489 }
while(!this->b_ready.read());
490 SCCTRACE(SCMOD) <<
"finished write response of trans [" << fsm_hndl->
trans <<
"]";
491 wait(clk_i.posedge_event());
492 this->b_valid.write(
false);
payload_type * allocate()
get a plain tlm_payload_type without extensions
TLM2.0 components modeling AHB.
tlm::tlm_bw_transport_if< TYPES > axi_bw_transport_if
alias declaration for the backward interface:
constexpr ULT to_int(E t)
unsigned get_burst_size(const request &r)
CONSTEXPR unsigned ilog2(uint32_t val)
uint8_t get_cresp() const
get the coherent response status
void set_barrier(bar_e)
set the AxBAR value
void set_domain(domain_e)
set the AxDOMAIN value
void set_snoop(snoop_e)
set the AxSNOOP value
void set_exclusive(bool=true)
get the exclusive bit of AxLOCK (AxLOCK[0])
void set_id(unsigned int value)
void set_user(id_type chnl, unsigned int value)
unsigned int get_id() const
base class of all AXITLM based adapters and interfaces.
tlm::scc::tlm_gp_shared_ptr trans
pointer to the associated AXITLM payload
sc_core::sc_event finish
event indicating the end of the transaction
size_t beat_count
beat count of this transaction
AxiProtocolFsm *const fsm
pointer to the FSM
void set_length(uint8_t)
set the AxLEN value of the transaction, the value denotes the burst length - 1
void set_qos(uint8_t)
set the AxQOS (quality of service) value
void set_cache(uint8_t)
set the AxCACHE value as POD, only value from 0..15 are allowed
void set_region(uint8_t)
set the AxREGION value
void set_stash_lpid(uint8_t)
set the raw AWSTASHLPID value
void set_burst(burst_e)
set the AxBURST value,
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...
void set_prot(uint8_t)
set the AxPROT value as POD, only values from 0...7 are allowed
void set_stash_nid(uint8_t)
set the raw AWSTASHNID value
resp_e get_resp() const
get the response status as POD
static tlm_mm & get()
accessor function of the singleton