17#ifndef _BUS_AXI_PIN_AXI4_TARGET_H_
18#define _BUS_AXI_PIN_AXI4_TARGET_H_
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 <scc/utilities.h>
26#include <tlm/scc/tlm_mm.h>
27#include <util/ities.h>
34using namespace axi::fsm;
36template <
typename CFG>
37struct axi4_target :
public sc_core::sc_module,
38 public aw_axi<CFG, typename CFG::slave_types>,
39 public wdata_axi<CFG, typename CFG::slave_types>,
40 public b_axi<CFG, typename CFG::slave_types>,
41 public ar_axi<CFG, typename CFG::slave_types>,
42 public rresp_axi<CFG, typename CFG::slave_types>,
45 SC_HAS_PROCESS(axi4_target);
47 using payload_type = axi::axi_protocol_types::tlm_payload_type;
48 using phase_type = axi::axi_protocol_types::tlm_phase_type;
50 sc_core::sc_in<bool> clk_i{
"clk_i"};
54 axi4_target(sc_core::sc_module_name
const& nm)
55 : sc_core::sc_module(nm)
56 ,
base(CFG::BUSWIDTH) {
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);
111 sc_core::sc_clock* clk_if{
nullptr};
112 sc_core::sc_event clk_delayed, clk_self, ar_end_req_evt, wdata_end_req_evt;
113 std::array<fsm_handle*, 3> active_req_beat{
nullptr,
nullptr,
nullptr};
114 std::array<fsm_handle*, 3> active_req{
nullptr,
nullptr,
nullptr};
115 std::array<fsm_handle*, 3> active_resp_beat{
nullptr,
nullptr,
nullptr};
126template <
typename CFG>
127inline tlm::tlm_sync_enum axi::pin::axi4_target<CFG>::nb_transport_bw(payload_type& trans, phase_type& phase, sc_core::sc_time& t) {
128 auto ret = tlm::TLM_ACCEPTED;
129 sc_core::sc_time delay = (clk_if && t < clk_if->period()) ? sc_core::SC_ZERO_TIME : t;
130 SCCTRACE(SCMOD) <<
"nb_transport_bw " << phase <<
" of trans " << trans;
131 if(phase == axi::END_PARTIAL_REQ || phase == tlm::END_REQ) {
132 schedule(phase == tlm::END_REQ ? EndReqE : EndPartReqE, &trans, delay,
false);
133 }
else if(phase == axi::BEGIN_PARTIAL_RESP || phase == tlm::BEGIN_RESP) {
134 schedule(phase == tlm::BEGIN_RESP ? BegRespE : BegPartRespE, &trans, delay,
false);
136 SCCFATAL(SCMOD) <<
"Illegal phase received: " << phase;
140template <
typename CFG>
141inline void axi::pin::axi4_target<CFG>::invalidate_direct_mem_ptr(sc_dt::uint64 start_range, sc_dt::uint64 end_range) {}
143template <
typename CFG>
typename CFG::data_t axi::pin::axi4_target<CFG>::get_read_data_for_beat(
fsm_handle* fsm_hndl) {
146 auto byte_offset = beat_count * size;
147 auto offset = (fsm_hndl->
trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
148 typename CFG::data_t data{0};
149 if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) {
150 if(beat_count == 0) {
151 auto dptr = fsm_hndl->
trans->get_data_ptr();
152 for(
size_t i = offset; i < size; ++i, ++dptr) {
153 auto bit_offs = i * 8;
154 data(bit_offs + 7, bit_offs) = *dptr;
157 auto beat_start_idx = byte_offset - offset;
158 auto data_len = fsm_hndl->
trans->get_data_length();
159 auto dptr = fsm_hndl->
trans->get_data_ptr() + beat_start_idx;
160 for(
size_t i = 0; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr) {
161 auto bit_offs = i * 8;
162 data(bit_offs + 7, bit_offs) = *dptr;
166 auto dptr = fsm_hndl->
trans->get_data_ptr() + byte_offset;
167 for(
size_t i = 0; i < size; ++i, ++dptr) {
168 auto bit_offs = (offset + i) * 8;
169 data(bit_offs + 7, bit_offs) = *dptr;
175template <
typename CFG>
inline void axi::pin::axi4_target<CFG>::setup_callbacks(
fsm_handle* fsm_hndl) {
176 fsm_hndl->
fsm->cb[RequestPhaseBeg] = [
this, fsm_hndl]() ->
void { fsm_hndl->
beat_count = 0; };
177 fsm_hndl->
fsm->cb[BegPartReqE] = [
this, fsm_hndl]() ->
void {
178 sc_assert(fsm_hndl->
trans->get_command() == tlm::TLM_WRITE_COMMAND);
179 tlm::tlm_phase phase = axi::BEGIN_PARTIAL_REQ;
180 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
181 auto ret = isckt->nb_transport_fw(*fsm_hndl->
trans, phase, t);
182 if(ret == tlm::TLM_UPDATED) {
183 schedule(EndPartReqE, fsm_hndl->
trans, t,
true);
186 fsm_hndl->
fsm->cb[EndPartReqE] = [
this, fsm_hndl]() ->
void {
187 wdata_end_req_evt.notify();
188 active_req_beat[tlm::TLM_WRITE_COMMAND] =
nullptr;
191 fsm_hndl->
fsm->cb[BegReqE] = [
this, fsm_hndl]() ->
void {
192 tlm::tlm_phase phase = tlm::BEGIN_REQ;
193 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
194 auto ret = isckt->nb_transport_fw(*fsm_hndl->
trans, phase, t);
195 if(ret == tlm::TLM_UPDATED) {
196 schedule(EndReqE, fsm_hndl->
trans, t,
true);
199 fsm_hndl->
fsm->cb[EndReqE] = [
this, fsm_hndl]() ->
void {
200 switch(fsm_hndl->
trans->get_command()) {
201 case tlm::TLM_READ_COMMAND:
202 ar_end_req_evt.notify();
203 active_req_beat[tlm::TLM_READ_COMMAND] =
nullptr;
205 case tlm::TLM_WRITE_COMMAND:
206 wdata_end_req_evt.notify();
207 active_req_beat[tlm::TLM_WRITE_COMMAND] =
nullptr;
214 fsm_hndl->
fsm->cb[BegPartRespE] = [
this, fsm_hndl]() ->
void {
215 assert(fsm_hndl->
trans->is_read());
216 active_resp_beat[tlm::TLM_READ_COMMAND] = fsm_hndl;
217 rresp_vl.notify({1, fsm_hndl});
219 fsm_hndl->
fsm->cb[EndPartRespE] = [
this, fsm_hndl]() ->
void {
221 assert(fsm_hndl->
trans->is_read());
222 tlm::tlm_phase phase = axi::END_PARTIAL_RESP;
223 sc_core::sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : sc_core::SC_ZERO_TIME);
224 auto ret = isckt->nb_transport_fw(*fsm_hndl->
trans, phase, t);
225 active_resp_beat[tlm::TLM_READ_COMMAND] =
nullptr;
228 fsm_hndl->
fsm->cb[BegRespE] = [
this, fsm_hndl]() ->
void {
229 SCCTRACE(SCMOD) <<
"processing event BegRespE for trans " << *fsm_hndl->
trans;
231 active_resp_beat[fsm_hndl->
trans->get_command()] = fsm_hndl;
232 switch(fsm_hndl->
trans->get_command()) {
233 case tlm::TLM_READ_COMMAND:
234 rresp_vl.notify({3, fsm_hndl});
236 case tlm::TLM_WRITE_COMMAND:
237 wresp_vl.notify({3, fsm_hndl});
243 fsm_hndl->
fsm->cb[EndRespE] = [
this, fsm_hndl]() ->
void {
245 tlm::tlm_phase phase = tlm::END_RESP;
246 sc_core::sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : sc_core::SC_ZERO_TIME);
247 auto ret = isckt->nb_transport_fw(*fsm_hndl->
trans, phase, t);
248 fsm_hndl->
finish.notify();
249 active_resp_beat[fsm_hndl->
trans->get_command()] =
nullptr;
253template <
typename CFG>
inline void axi::pin::axi4_target<CFG>::ar_t() {
254 this->ar_ready.write(
false);
255 wait(sc_core::SC_ZERO_TIME);
259 auto data_len = (1 << arsize) * (arlen + 1);
262 while(!this->ar_valid.read()) {
263 wait(this->ar_valid.posedge_event());
266 SCCTRACE(SCMOD) <<
"ARVALID detected for 0x" << std::hex << this->ar_addr.read();
268 arid = this->ar_id->read().to_uint();
269 arlen = this->ar_len->read().to_uint();
270 arsize = this->ar_size->read().to_uint();
272 data_len = (1 << arsize) * (arlen + 1);
274 gp->set_address(this->ar_addr.read());
275 gp->set_command(tlm::TLM_READ_COMMAND);
276 gp->set_streaming_width(data_len);
278 gp->get_extension(ext);
284 ext->
set_prot(this->ar_prot->read());
285 ext->
set_qos(CFG::IS_LITE ? 0U : this->ar_qos->read().to_uint());
286 ext->
set_region(CFG::IS_LITE ? 0U : this->ar_region->read().to_uint());
288 active_req_beat[tlm::TLM_READ_COMMAND] = find_or_create(gp);
289 react(axi::fsm::protocol_time_point_e::BegReqE, active_req_beat[tlm::TLM_READ_COMMAND]);
290 wait(ar_end_req_evt);
291 this->ar_ready.write(
true);
292 wait(clk_i.posedge_event());
293 this->ar_ready.write(
false);
297template <
typename CFG>
inline void axi::pin::axi4_target<CFG>::rresp_t() {
298 this->r_valid.write(
false);
299 wait(sc_core::SC_ZERO_TIME);
303 std::tie(val, fsm_hndl) = rresp_vl.get();
304 SCCTRACE(SCMOD) <<
"got read response beat of trans " << *fsm_hndl->
trans;
306 this->r_data.write(get_read_data_for_beat(fsm_hndl));
308 this->r_valid.write(val & 0x1);
310 this->r_id->write(ext->
get_id());
311 this->r_last->write(val & 0x2);
314 wait(this->r_ready.posedge_event() | clk_delayed);
315 if(this->r_ready.read()) {
317 CFG::IS_LITE || (val & 0x2) ? axi::fsm::protocol_time_point_e::EndRespE :
axi::fsm::protocol_time_point_e::EndPartRespE;
318 react(evt, active_resp_beat[tlm::TLM_READ_COMMAND]);
320 }
while(!this->r_ready.read());
321 SCCTRACE(SCMOD) <<
"finished read response beat of trans [" << fsm_hndl->
trans <<
"]";
322 wait(clk_i.posedge_event());
323 this->r_valid.write(
false);
325 this->r_last->write(
false);
329template <
typename CFG>
inline void axi::pin::axi4_target<CFG>::aw_t() {
330 this->aw_ready.write(
false);
331 wait(sc_core::SC_ZERO_TIME);
332 const auto awsize =
util::ilog2(CFG::BUSWIDTH / 8);
335 while(!this->aw_valid.read()) {
336 wait(this->aw_valid.posedge_event());
339 SCCTRACE(SCMOD) <<
"AWVALID detected for 0x" << std::hex << this->aw_addr.read();
341 aw_data awd = {CFG::IS_LITE ? 0U : this->aw_id->read().to_uint(),
342 this->aw_addr.read().to_uint64(),
343 this->aw_prot.read().to_uint(),
344 CFG::IS_LITE ? awsize : this->aw_size->read().to_uint(),
345 CFG::IS_LITE ? 0U : this->aw_cache->read().to_uint(),
346 CFG::IS_LITE ? 0U : this->aw_burst->read().to_uint(),
347 CFG::IS_LITE ? 0U : this->aw_qos->read().to_uint(),
348 CFG::IS_LITE ? 0U : this->aw_region->read().to_uint(),
349 CFG::IS_LITE ? 0U : this->aw_len->read().to_uint(),
350 CFG::IS_LITE ? false : this->aw_lock->read(),
352 CFG::IS_LITE ? 0U : this->aw_atop->read().to_uint()
355 aw_que.notify(std::move(awd));
356 this->aw_ready.write(
true);
357 wait(clk_i.posedge_event());
358 this->aw_ready.write(
false);
362template <
typename CFG>
inline void axi::pin::axi4_target<CFG>::wdata_t() {
363 this->w_ready.write(
false);
364 wait(sc_core::SC_ZERO_TIME);
366 wait(this->w_valid.read() ? clk_delayed : this->w_valid.posedge_event());
367 if(this->w_valid.read()) {
368 if(!active_req[tlm::TLM_WRITE_COMMAND]) {
369 if(!aw_que.has_next())
370 wait(aw_que.event());
371 auto awd = aw_que.get();
372 auto data_len = (1 << awd.size) * (awd.len + 1);
374 gp->set_address(awd.addr);
375 gp->set_command(tlm::TLM_WRITE_COMMAND);
377 gp->get_extension(ext);
389 ext->
set_user(axi::common::id_type::CTRL, awd.user);
391 active_req_beat[tlm::TLM_WRITE_COMMAND] = find_or_create(gp);
392 active_req[tlm::TLM_WRITE_COMMAND] = active_req_beat[tlm::TLM_WRITE_COMMAND];
393 active_req_beat[tlm::TLM_WRITE_COMMAND]->aux.i32.i0 = 0;
395 auto* fsm_hndl = active_req[tlm::TLM_WRITE_COMMAND];
396 SCCTRACE(SCMOD) <<
"WDATA detected for 0x" << std::hex << this->ar_addr.read();
397 auto& gp = fsm_hndl->
trans;
398 auto data = this->w_data.read();
399 auto strb = this->w_strb.read();
400 auto last = CFG::IS_LITE ? true : this->w_last->read();
403 auto byte_offset = beat_count * size;
404 auto offset = (fsm_hndl->
trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
405 if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) {
406 if(beat_count == 0) {
407 auto dptr = fsm_hndl->
trans->get_data_ptr();
408 auto beptr = fsm_hndl->
trans->get_byte_enable_ptr();
409 for(
size_t i = offset; i < size; ++i, ++dptr, ++beptr) {
410 auto bit_offs = i * 8;
411 *dptr = data(bit_offs + 7, bit_offs).to_uint();
412 *beptr = strb[i] ? 0xff : 0;
413 fsm_hndl->aux.i32.i0 += strb[i] ? 1 : 0;
416 auto beat_start_idx = byte_offset - offset;
417 auto data_len = fsm_hndl->
trans->get_data_length();
418 auto dptr = fsm_hndl->
trans->get_data_ptr() + beat_start_idx;
419 auto beptr = fsm_hndl->
trans->get_byte_enable_ptr() + beat_start_idx;
420 for(
size_t i = 0; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr, ++beptr) {
421 auto bit_offs = i * 8;
422 *dptr = data(bit_offs + 7, bit_offs).to_uint();
423 *beptr = strb[i] ? 0xff : 0;
424 fsm_hndl->aux.i32.i0 += strb[i] ? 1 : 0;
428 auto dptr = fsm_hndl->
trans->get_data_ptr() + byte_offset;
429 auto beptr = fsm_hndl->
trans->get_byte_enable_ptr() + byte_offset;
430 for(
size_t i = 0; i < size; ++i, ++dptr, ++beptr) {
431 auto bit_offs = (offset + i) * 8;
432 *dptr = data(bit_offs + 7, bit_offs).to_uint();
433 *beptr = strb[offset + i] ? 0xff : 0;
434 fsm_hndl->aux.i32.i0 += strb[offset + i] ? 1 : 0;
438 auto strobe = strb.to_uint();
442 auto act_data_len = CFG::IS_LITE ? util::bit_count(strobe) : offset == 0 ? (beat_count + 1) * size : fsm_hndl->aux.i32.i0;
443 gp->set_data_length(act_data_len);
444 gp->set_streaming_width(act_data_len);
445 if(fsm_hndl->aux.i32.i0 == act_data_len) {
446 gp->set_byte_enable_length(0);
448 gp->set_byte_enable_length(act_data_len);
451 auto tp = CFG::IS_LITE || this->w_last->read() ? axi::fsm::protocol_time_point_e::BegReqE
452 : axi::fsm::protocol_time_point_e::BegPartReqE;
454 wait(wdata_end_req_evt);
455 this->w_ready.write(
true);
456 wait(clk_i.posedge_event());
457 this->w_ready.write(
false);
459 active_req[tlm::TLM_WRITE_COMMAND] =
nullptr;
464template <
typename CFG>
inline void axi::pin::axi4_target<CFG>::bresp_t() {
465 this->b_valid.write(
false);
466 wait(sc_core::SC_ZERO_TIME);
470 std::tie(val, fsm_hndl) = wresp_vl.get();
471 SCCTRACE(SCMOD) <<
"got write response of trans " << *fsm_hndl->
trans;
474 this->b_valid.write(
true);
476 this->b_id->write(ext->
get_id());
477 SCCTRACE(SCMOD) <<
"got write response for b_id= " << this->b_id;
479 wait(this->b_ready.posedge_event() | clk_delayed);
480 if(this->b_ready.read()) {
481 react(axi::fsm::protocol_time_point_e::EndRespE, active_resp_beat[tlm::TLM_WRITE_COMMAND]);
483 }
while(!this->b_ready.read());
484 SCCTRACE(SCMOD) <<
"finished write response of trans [" << fsm_hndl->
trans <<
"]";
485 wait(clk_i.posedge_event());
486 this->b_valid.write(
false);
payload_type * allocate()
get a plain tlm_payload_type without extensions
TLM2.0 components modeling AHB.
E into(typename std::underlying_type< E >::type t)
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)
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.
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
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_burst(burst_e)
set the AxBURST value,
void set_atop(uint8_t)
set the raw AWATOP 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
resp_e get_resp() const
get the response status as POD
static tlm_mm & get()
accessor function of the singleton