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>
34 using namespace axi::fsm;
36 template <
typename CFG>
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>,
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"};
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);
110 sc_core::sc_clock* clk_if{
nullptr};
111 sc_core::sc_event clk_delayed, clk_self, ar_end_req_evt, wdata_end_req_evt;
112 std::array<fsm_handle*, 3> active_req_beat{
nullptr,
nullptr,
nullptr};
113 std::array<fsm_handle*, 3> active_req{
nullptr,
nullptr,
nullptr};
114 std::array<fsm_handle*, 3> active_resp_beat{
nullptr,
nullptr,
nullptr};
123 template <
typename CFG>
125 auto ret = tlm::TLM_ACCEPTED;
126 sc_core::sc_time delay = t < clk_if->period() ? sc_core::SC_ZERO_TIME : t;
127 SCCTRACE(SCMOD) <<
"nb_transport_bw " << phase <<
" of trans " << trans;
128 if(phase == axi::END_PARTIAL_REQ || phase == tlm::END_REQ) {
129 schedule(phase == tlm::END_REQ ? EndReqE : EndPartReqE, &trans, delay,
false);
130 }
else if(phase == axi::BEGIN_PARTIAL_RESP || phase == tlm::BEGIN_RESP) {
131 schedule(phase == tlm::BEGIN_RESP ? BegRespE : BegPartRespE, &trans, delay,
false);
133 SCCFATAL(SCMOD) <<
"Illegal phase received: " << phase;
137 template <
typename CFG>
143 auto byte_offset = beat_count * size;
144 auto offset = (fsm_hndl->
trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
145 typename CFG::data_t data{0};
146 if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) {
147 if(beat_count == 0) {
148 auto dptr = fsm_hndl->
trans->get_data_ptr();
149 for(
size_t i = offset; i < size; ++i, ++dptr) {
150 auto bit_offs = i * 8;
151 data(bit_offs + 7, bit_offs) = *dptr;
154 auto beat_start_idx = byte_offset - offset;
155 auto data_len = fsm_hndl->
trans->get_data_length();
156 auto dptr = fsm_hndl->
trans->get_data_ptr() + beat_start_idx;
157 for(
size_t i = 0; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr) {
158 auto bit_offs = i * 8;
159 data(bit_offs + 7, bit_offs) = *dptr;
163 auto dptr = fsm_hndl->
trans->get_data_ptr() + byte_offset;
164 for(
size_t i = 0; i < size; ++i, ++dptr) {
165 auto bit_offs = (offset + i) * 8;
166 data(bit_offs + 7, bit_offs) = *dptr;
173 fsm_hndl->
fsm->cb[RequestPhaseBeg] = [
this, fsm_hndl]() ->
void { fsm_hndl->
beat_count = 0; };
174 fsm_hndl->
fsm->cb[BegPartReqE] = [
this, fsm_hndl]() ->
void {
175 sc_assert(fsm_hndl->
trans->get_command() == tlm::TLM_WRITE_COMMAND);
176 tlm::tlm_phase phase = axi::BEGIN_PARTIAL_REQ;
177 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
178 auto ret = isckt->nb_transport_fw(*fsm_hndl->
trans, phase, t);
179 if(ret == tlm::TLM_UPDATED) {
180 schedule(EndPartReqE, fsm_hndl->
trans, t,
true);
183 fsm_hndl->
fsm->cb[EndPartReqE] = [
this, fsm_hndl]() ->
void {
184 wdata_end_req_evt.notify();
185 active_req_beat[tlm::TLM_WRITE_COMMAND] =
nullptr;
188 fsm_hndl->
fsm->cb[BegReqE] = [
this, fsm_hndl]() ->
void {
189 tlm::tlm_phase phase = tlm::BEGIN_REQ;
190 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
191 auto ret = isckt->nb_transport_fw(*fsm_hndl->
trans, phase, t);
192 if(ret == tlm::TLM_UPDATED) {
193 schedule(EndReqE, fsm_hndl->
trans, t,
true);
196 fsm_hndl->
fsm->cb[EndReqE] = [
this, fsm_hndl]() ->
void {
197 switch(fsm_hndl->
trans->get_command()) {
198 case tlm::TLM_READ_COMMAND:
199 ar_end_req_evt.notify();
200 active_req_beat[tlm::TLM_READ_COMMAND] =
nullptr;
202 case tlm::TLM_WRITE_COMMAND:
203 wdata_end_req_evt.notify();
204 active_req_beat[tlm::TLM_WRITE_COMMAND] =
nullptr;
211 fsm_hndl->
fsm->cb[BegPartRespE] = [
this, fsm_hndl]() ->
void {
212 assert(fsm_hndl->
trans->is_read());
213 active_resp_beat[tlm::TLM_READ_COMMAND] = fsm_hndl;
214 rresp_vl.notify({1, fsm_hndl});
216 fsm_hndl->
fsm->cb[EndPartRespE] = [
this, fsm_hndl]() ->
void {
218 assert(fsm_hndl->
trans->is_read());
219 tlm::tlm_phase phase = axi::END_PARTIAL_RESP;
220 sc_core::sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : sc_core::SC_ZERO_TIME);
221 auto ret = isckt->nb_transport_fw(*fsm_hndl->
trans, phase, t);
222 active_resp_beat[tlm::TLM_READ_COMMAND] =
nullptr;
225 fsm_hndl->
fsm->cb[BegRespE] = [
this, fsm_hndl]() ->
void {
226 SCCTRACE(SCMOD) <<
"processing event BegRespE for trans " << *fsm_hndl->
trans;
228 active_resp_beat[fsm_hndl->
trans->get_command()] = fsm_hndl;
229 switch(fsm_hndl->
trans->get_command()) {
230 case tlm::TLM_READ_COMMAND:
231 rresp_vl.notify({3, fsm_hndl});
233 case tlm::TLM_WRITE_COMMAND:
234 wresp_vl.notify({3, fsm_hndl});
240 fsm_hndl->
fsm->cb[EndRespE] = [
this, fsm_hndl]() ->
void {
242 tlm::tlm_phase phase = tlm::END_RESP;
243 sc_core::sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : sc_core::SC_ZERO_TIME);
244 auto ret = isckt->nb_transport_fw(*fsm_hndl->
trans, phase, t);
245 fsm_hndl->
finish.notify();
246 active_resp_beat[fsm_hndl->
trans->get_command()] =
nullptr;
251 this->ar_ready.write(
false);
252 wait(sc_core::SC_ZERO_TIME);
256 auto data_len = (1 << arsize) * (arlen + 1);
259 while(!this->ar_valid.read()) {
260 wait(this->ar_valid.posedge_event());
263 SCCTRACE(SCMOD) <<
"ARVALID detected for 0x" << std::hex << this->ar_addr.read();
265 arid = this->ar_id->read().to_uint();
266 arlen = this->ar_len->read().to_uint();
267 arsize = this->ar_size->read().to_uint();
269 data_len = (1 << arsize) * (arlen + 1);
271 gp->set_address(this->ar_addr.read());
272 gp->set_command(tlm::TLM_READ_COMMAND);
273 gp->set_streaming_width(data_len);
275 gp->get_extension(ext);
281 ext->
set_prot(this->ar_prot->read());
282 ext->
set_qos(CFG::IS_LITE ? 0U : this->ar_qos->read().to_uint());
283 ext->
set_region(CFG::IS_LITE ? 0U : this->ar_region->read().to_uint());
285 active_req_beat[tlm::TLM_READ_COMMAND] = find_or_create(gp);
286 react(axi::fsm::protocol_time_point_e::BegReqE, active_req_beat[tlm::TLM_READ_COMMAND]);
287 wait(ar_end_req_evt);
288 this->ar_ready.write(
true);
289 wait(clk_i.posedge_event());
290 this->ar_ready.write(
false);
295 this->r_valid.write(
false);
296 wait(sc_core::SC_ZERO_TIME);
300 std::tie(val, fsm_hndl) = rresp_vl.get();
301 SCCTRACE(SCMOD) <<
"got read response beat of trans " << *fsm_hndl->
trans;
303 this->r_data.write(get_read_data_for_beat(fsm_hndl));
305 this->r_valid.write(val & 0x1);
307 this->r_id->write(ext->
get_id());
308 this->r_last->write(val & 0x2);
311 wait(this->r_ready.posedge_event() | clk_delayed);
312 if(this->r_ready.read()) {
314 CFG::IS_LITE || (val & 0x2) ? axi::fsm::protocol_time_point_e::EndRespE : axi::fsm::protocol_time_point_e::EndPartRespE;
315 react(evt, active_resp_beat[tlm::TLM_READ_COMMAND]);
317 }
while(!this->r_ready.read());
318 SCCTRACE(SCMOD) <<
"finished read response beat of trans [" << fsm_hndl->
trans <<
"]";
319 wait(clk_i.posedge_event());
320 this->r_valid.write(
false);
322 this->r_last->write(
false);
327 this->aw_ready.write(
false);
328 wait(sc_core::SC_ZERO_TIME);
329 const auto awsize =
util::ilog2(CFG::BUSWIDTH / 8);
331 wait(this->aw_valid.posedge_event() | clk_delayed);
332 if(this->aw_valid.event() || (!active_req_beat[tlm::TLM_IGNORE_COMMAND] && this->aw_valid.read())) {
333 SCCTRACE(SCMOD) <<
"AWVALID detected for 0x" << std::hex << this->aw_addr.read();
335 aw_data awd = {CFG::IS_LITE ? 0U : this->aw_id->read().to_uint(),
336 this->aw_addr.read().to_uint64(),
337 this->aw_prot.read().to_uint(),
338 CFG::IS_LITE ? awsize : this->aw_size->read().to_uint(),
339 CFG::IS_LITE ? 0U : this->aw_cache->read().to_uint(),
340 CFG::IS_LITE ? 0U : this->aw_burst->read().to_uint(),
341 CFG::IS_LITE ? 0U : this->aw_qos->read().to_uint(),
342 CFG::IS_LITE ? 0U : this->aw_region->read().to_uint(),
343 CFG::IS_LITE ? 0U : this->aw_len->read().to_uint(),
344 CFG::IS_LITE ? false : this->aw_lock->read(),
347 aw_que.notify(std::move(awd));
348 this->aw_ready.write(
true);
349 wait(clk_i.posedge_event());
350 this->aw_ready.write(
false);
356 this->w_ready.write(
false);
357 wait(sc_core::SC_ZERO_TIME);
359 wait(this->w_valid.posedge_event() | clk_delayed);
360 this->w_ready.write(
false);
361 if(this->w_valid.event() || (!active_req_beat[tlm::TLM_WRITE_COMMAND] && this->w_valid.read())) {
362 if(!active_req[tlm::TLM_WRITE_COMMAND]) {
363 if(!aw_que.has_next())
364 wait(aw_que.event());
365 auto awd = aw_que.get();
366 auto data_len = (1 << awd.size) * (awd.len + 1);
368 gp->set_address(awd.addr);
369 gp->set_command(tlm::TLM_WRITE_COMMAND);
371 gp->get_extension(ext);
375 ext->
set_burst(axi::into<axi::burst_e>(awd.burst));
382 ext->
set_user(axi::common::id_type::CTRL, awd.user);
384 active_req_beat[tlm::TLM_WRITE_COMMAND] = find_or_create(gp);
385 active_req[tlm::TLM_WRITE_COMMAND] = active_req_beat[tlm::TLM_WRITE_COMMAND];
387 auto* fsm_hndl = active_req[tlm::TLM_WRITE_COMMAND];
388 SCCTRACE(SCMOD) <<
"WDATA detected for 0x" << std::hex << this->ar_addr.read();
389 auto& gp = fsm_hndl->
trans;
390 auto data = this->w_data.read();
391 auto strb = this->w_strb.read();
392 auto last = CFG::IS_LITE ? true : this->w_last->read();
395 auto byte_offset = beat_count * size;
396 auto offset = (fsm_hndl->
trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
397 if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) {
398 if(beat_count == 0) {
399 auto dptr = fsm_hndl->
trans->get_data_ptr();
400 auto beptr = fsm_hndl->
trans->get_byte_enable_ptr();
401 for(
size_t i = offset; i < size; ++i, ++dptr, ++beptr) {
402 auto bit_offs = i * 8;
403 *dptr = data(bit_offs + 7, bit_offs).to_uint();
404 *beptr = strb[i] ? 0xff : 0;
407 auto beat_start_idx = byte_offset - offset;
408 auto data_len = fsm_hndl->
trans->get_data_length();
409 auto dptr = fsm_hndl->
trans->get_data_ptr() + beat_start_idx;
410 auto beptr = fsm_hndl->
trans->get_byte_enable_ptr() + beat_start_idx;
411 for(
size_t i = 0; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr, ++beptr) {
412 auto bit_offs = i * 8;
413 *dptr = data(bit_offs + 7, bit_offs).to_uint();
414 *beptr = strb[i] ? 0xff : 0;
418 auto dptr = fsm_hndl->
trans->get_data_ptr() + byte_offset;
419 auto beptr = fsm_hndl->
trans->get_byte_enable_ptr() + byte_offset;
420 for(
size_t i = 0; i < size; ++i, ++dptr, ++beptr) {
421 auto bit_offs = (offset + i) * 8;
422 *dptr = data(bit_offs + 7, bit_offs).to_uint();
423 *beptr = strb[offset + i] ? 0xff : 0;
427 auto strobe = strb.to_uint();
429 auto act_data_len = CFG::IS_LITE ? util::bit_count(strobe) : (beat_count + 1) * size;
435 gp->set_data_length(act_data_len);
436 gp->set_byte_enable_length(act_data_len);
437 gp->set_streaming_width(act_data_len);
439 auto tp = CFG::IS_LITE || this->w_last->read() ? axi::fsm::protocol_time_point_e::BegReqE
440 : axi::fsm::protocol_time_point_e::BegPartReqE;
442 wait(wdata_end_req_evt);
443 this->w_ready.write(
true);
444 wait(clk_i.posedge_event());
445 this->w_ready.write(
false);
447 active_req[tlm::TLM_WRITE_COMMAND] =
nullptr;
453 this->b_valid.write(
false);
454 wait(sc_core::SC_ZERO_TIME);
458 std::tie(val, fsm_hndl) = wresp_vl.get();
459 SCCTRACE(SCMOD) <<
"got write response of trans " << *fsm_hndl->
trans;
462 this->b_valid.write(
true);
464 this->b_id->write(ext->
get_id());
465 SCCTRACE(SCMOD) <<
"got write response";
467 wait(this->b_ready.posedge_event() | clk_delayed);
468 if(this->b_ready.read()) {
469 react(axi::fsm::protocol_time_point_e::EndRespE, active_resp_beat[tlm::TLM_WRITE_COMMAND]);
471 }
while(!this->b_ready.read());
472 SCCTRACE(SCMOD) <<
"finished write response of trans [" << fsm_hndl->
trans <<
"]";
473 wait(clk_i.posedge_event());
474 this->b_valid.write(
false);
payload_type * allocate()
get a plain tlm_payload_type without extensions
static tlm_mm & get()
accessor function of the singleton
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)
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_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
resp_e get_resp() const
get the response status as POD