17 #ifndef _BUS_AXI_PIN_AXI4_INITIATOR_H_
18 #define _BUS_AXI_PIN_AXI4_INITIATOR_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>
25 #include <tlm_utils/peq_with_cb_and_phase.h>
32 using namespace axi::fsm;
34 template <
typename CFG>
36 public aw_axi<CFG, typename CFG::master_types>,
37 public wdata_axi<CFG, typename CFG::master_types>,
38 public b_axi<CFG, typename CFG::master_types>,
39 public ar_axi<CFG, typename CFG::master_types>,
40 public rresp_axi<CFG, typename CFG::master_types>,
45 using payload_type = axi::axi_protocol_types::tlm_payload_type;
46 using phase_type = axi::axi_protocol_types::tlm_phase_type;
48 sc_core::sc_in<bool> clk_i{
"clk_i"};
53 : sc_core::sc_module(nm)
54 ,
base(CFG::BUSWIDTH) {
55 instance_name = name();
58 sensitive << clk_i.pos();
67 void b_transport(payload_type& trans, sc_core::sc_time& t)
override {
68 trans.set_dmi_allowed(
false);
69 trans.set_response_status(tlm::TLM_OK_RESPONSE);
72 tlm::tlm_sync_enum nb_transport_fw(payload_type& trans, phase_type& phase, sc_core::sc_time& t)
override {
74 sc_core::sc_time delay;
75 fw_peq.notify(trans, phase, delay);
76 return tlm::TLM_ACCEPTED;
79 bool get_direct_mem_ptr(payload_type& trans, tlm::tlm_dmi& dmi_data)
override {
80 trans.set_dmi_allowed(
false);
84 unsigned int transport_dbg(payload_type& trans)
override {
return 0; }
86 void end_of_elaboration()
override { clk_if =
dynamic_cast<sc_core::sc_clock*
>(clk_i.get_interface()); }
92 void clk_delay() { clk_delayed.notify(axi::CLK_DELAY); }
99 std::array<unsigned, 3> outstanding_cnt{0, 0, 0};
100 std::array<fsm_handle*, 3> active_req{
nullptr,
nullptr,
nullptr};
101 std::array<fsm_handle*, 3> active_resp{
nullptr,
nullptr,
nullptr};
102 sc_core::sc_clock* clk_if{
nullptr};
103 sc_core::sc_event clk_delayed, clk_self, r_end_resp_evt, aw_evt, ar_evt;
104 void nb_fw(payload_type& trans,
const phase_type& phase) {
105 auto delay = sc_core::SC_ZERO_TIME;
108 tlm_utils::peq_with_cb_and_phase<axi4_initiator> fw_peq{
this, &axi4_initiator::nb_fw};
109 std::unordered_map<unsigned, std::deque<fsm_handle*>> rd_resp_by_id, wr_resp_by_id;
110 sc_core::sc_buffer<uint8_t> wdata_vl;
111 void write_ar(tlm::tlm_generic_payload& trans);
112 void write_aw(tlm::tlm_generic_payload& trans);
113 void write_wdata(tlm::tlm_generic_payload& trans,
unsigned beat,
bool last =
false);
120 sc_dt::sc_uint<CFG::ADDRWIDTH> addr = trans.get_address();
121 this->ar_addr.write(addr);
123 this->ar_prot.write(ext->get_prot());
125 auto id = ext->get_id();
126 if(
id >= (1 << CFG::IDWIDTH))
127 SCCERR(SCMOD) <<
"ARID value larger that signal arid with width=" << CFG::IDWIDTH <<
" can carry";
128 this->ar_id->write(sc_dt::sc_uint<CFG::IDWIDTH>(
id));
129 this->ar_len->write(sc_dt::sc_uint<8>(ext->get_length()));
130 this->ar_size->write(sc_dt::sc_uint<3>(ext->get_size()));
131 this->ar_burst->write(sc_dt::sc_uint<2>(
axi::to_int(ext->get_burst())));
132 if(ext->is_exclusive())
133 this->ar_lock->write(
true);
134 this->ar_cache->write(sc_dt::sc_uint<4>(ext->get_cache()));
135 this->ar_qos->write(ext->get_qos());
136 if(this->ar_user.get_interface())
137 this->ar_user->write(ext->get_user(axi::common::id_type::CTRL));
143 sc_dt::sc_uint<CFG::ADDRWIDTH> addr = trans.get_address();
144 this->aw_addr.write(addr);
146 this->aw_prot.write(ext->get_prot());
148 auto id = ext->get_id();
149 if(
id >= (1 << CFG::IDWIDTH))
150 SCCERR(SCMOD) <<
"AWID value larger than signal awid with width=" << CFG::IDWIDTH <<
" can carry";
151 this->aw_id->write(sc_dt::sc_uint<CFG::IDWIDTH>(
id));
152 this->aw_len->write(sc_dt::sc_uint<8>(ext->get_length()));
153 this->aw_size->write(sc_dt::sc_uint<3>(ext->get_size()));
154 this->aw_burst->write(sc_dt::sc_uint<2>(
axi::to_int(ext->get_burst())));
155 this->aw_cache->write(sc_dt::sc_uint<4>(ext->get_cache()));
156 this->aw_qos->write(ext->get_qos());
157 if(ext->is_exclusive())
158 this->aw_lock->write(
true);
159 if(this->aw_user.get_interface())
160 this->aw_user->write(ext->get_user(axi::common::id_type::CTRL));
167 typename CFG::data_t data{0};
168 sc_dt::sc_uint<CFG::BUSWIDTH / 8> strb{0};
171 auto byte_offset = beat * size;
172 auto offset = (trans.get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
173 auto beptr = trans.get_byte_enable_length() ? trans.get_byte_enable_ptr() + byte_offset :
nullptr;
174 if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) {
176 auto dptr = trans.get_data_ptr();
177 for(
size_t i = offset; i < size; ++i, ++dptr) {
178 auto bit_offs = i * 8;
179 data(bit_offs + 7, bit_offs) = *dptr;
181 strb[i] = *beptr == 0xff;
187 auto beat_start_idx = byte_offset - offset;
188 auto data_len = trans.get_data_length();
189 auto dptr = trans.get_data_ptr() + beat_start_idx;
190 for(
size_t i = 0; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr) {
191 auto bit_offs = i * 8;
192 data(bit_offs + 7, bit_offs) = *dptr;
194 strb[i] = *beptr == 0xff;
201 auto dptr = trans.get_data_ptr() + byte_offset;
202 for(
size_t i = 0; i < size; ++i, ++dptr) {
203 auto bit_offs = (offset + i) * 8;
204 data(bit_offs + 7, bit_offs) = *dptr;
206 strb[offset + i] = *beptr == 0xff;
209 strb[offset + i] =
true;
212 this->w_data.write(data);
213 this->w_strb.write(strb);
215 this->w_id->write(ext->get_id());
216 if(this->w_user.get_interface())
217 this->w_user->write(ext->get_user(axi::common::id_type::DATA));
222 fsm_hndl->
fsm->cb[RequestPhaseBeg] = [
this, fsm_hndl]() ->
void {
224 outstanding_cnt[fsm_hndl->
trans->get_command()]++;
226 auto offset = fsm_hndl->
trans->get_address() % (CFG::BUSWIDTH / 8);
227 if(offset + fsm_hndl->
trans->get_data_length() > CFG::BUSWIDTH / 8) {
228 SCCFATAL(SCMOD) <<
" transaction " << *fsm_hndl->
trans <<
" is not AXI4Lite compliant";
232 fsm_hndl->
fsm->cb[BegPartReqE] = [
this, fsm_hndl]() ->
void {
233 sc_assert(fsm_hndl->
trans->is_write());
235 write_aw(*fsm_hndl->
trans);
236 aw_evt.notify(sc_core::SC_ZERO_TIME);
239 active_req[tlm::TLM_WRITE_COMMAND] = fsm_hndl;
242 fsm_hndl->
fsm->cb[EndPartReqE] = [
this, fsm_hndl]() ->
void {
243 active_req[tlm::TLM_WRITE_COMMAND] =
nullptr;
244 tlm::tlm_phase phase = axi::END_PARTIAL_REQ;
245 sc_core::sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : sc_core::SC_ZERO_TIME);
246 auto ret = tsckt->nb_transport_bw(*fsm_hndl->
trans, phase, t);
249 fsm_hndl->
fsm->cb[BegReqE] = [
this, fsm_hndl]() ->
void {
250 switch(fsm_hndl->
trans->get_command()) {
251 case tlm::TLM_READ_COMMAND:
252 active_req[tlm::TLM_READ_COMMAND] = fsm_hndl;
253 write_ar(*fsm_hndl->
trans);
254 ar_evt.notify(sc_core::SC_ZERO_TIME);
256 case tlm::TLM_WRITE_COMMAND:
257 active_req[tlm::TLM_WRITE_COMMAND] = fsm_hndl;
259 write_aw(*fsm_hndl->
trans);
260 aw_evt.notify(sc_core::SC_ZERO_TIME);
266 fsm_hndl->
fsm->cb[EndReqE] = [
this, fsm_hndl]() ->
void {
267 auto id = axi::get_axi_id(*fsm_hndl->
trans);
268 switch(fsm_hndl->
trans->get_command()) {
269 case tlm::TLM_READ_COMMAND:
270 rd_resp_by_id[id].push_back(fsm_hndl);
271 active_req[tlm::TLM_READ_COMMAND] =
nullptr;
273 case tlm::TLM_WRITE_COMMAND:
274 wr_resp_by_id[id].push_back(fsm_hndl);
275 active_req[tlm::TLM_WRITE_COMMAND] =
nullptr;
278 tlm::tlm_phase phase = tlm::END_REQ;
279 sc_core::sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : sc_core::SC_ZERO_TIME);
280 auto ret = tsckt->nb_transport_bw(*fsm_hndl->
trans, phase, t);
281 fsm_hndl->
trans->set_response_status(tlm::TLM_OK_RESPONSE);
283 fsm_hndl->
fsm->cb[BegPartRespE] = [
this, fsm_hndl]() ->
void {
285 assert(fsm_hndl->
trans->is_read());
286 tlm::tlm_phase phase = axi::BEGIN_PARTIAL_RESP;
287 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
288 auto ret = tsckt->nb_transport_bw(*fsm_hndl->
trans, phase, t);
290 fsm_hndl->
fsm->cb[EndPartRespE] = [
this, fsm_hndl]() ->
void {
292 r_end_resp_evt.notify();
294 fsm_hndl->
fsm->cb[BegRespE] = [
this, fsm_hndl]() ->
void {
296 tlm::tlm_phase phase = tlm::BEGIN_RESP;
297 sc_core::sc_time t(sc_core::SC_ZERO_TIME);
298 auto ret = tsckt->nb_transport_bw(*fsm_hndl->
trans, phase, t);
300 fsm_hndl->
fsm->cb[EndRespE] = [
this, fsm_hndl]() ->
void {
301 r_end_resp_evt.notify();
302 if(fsm_hndl->
trans->is_read())
303 rd_resp_by_id[axi::get_axi_id(*fsm_hndl->
trans)].pop_front();
304 if(fsm_hndl->
trans->is_write())
305 wr_resp_by_id[axi::get_axi_id(*fsm_hndl->
trans)].pop_front();
310 this->ar_valid.write(
false);
311 wait(sc_core::SC_ZERO_TIME);
314 this->ar_valid.write(
true);
316 wait(this->ar_ready.posedge_event() | clk_delayed);
317 if(this->ar_ready.read())
318 react(axi::fsm::protocol_time_point_e::EndReqE, active_req[tlm::TLM_READ_COMMAND]);
319 }
while(!this->ar_ready.read());
320 wait(clk_i.posedge_event());
321 this->ar_valid.write(
false);
326 this->r_ready.write(
false);
327 wait(sc_core::SC_ZERO_TIME);
329 if(!this->r_valid.read())
330 wait(this->r_valid.posedge_event());
333 if(this->r_valid.event() || (!active_resp[tlm::TLM_READ_COMMAND] && this->r_valid.read())) {
334 wait(sc_core::SC_ZERO_TIME);
335 auto id = CFG::IS_LITE ? 0U : this->r_id->read().to_uint();
336 auto data = this->r_data.read();
337 auto resp = this->r_resp.read();
338 auto& q = rd_resp_by_id[id];
339 sc_assert(q.size() &&
"No transaction found for received id");
340 auto* fsm_hndl = q.front();
343 auto byte_offset = beat_count * size;
344 auto offset = (fsm_hndl->
trans->get_address() + byte_offset) & (CFG::BUSWIDTH / 8 - 1);
345 if(offset && (size + offset) > (CFG::BUSWIDTH / 8)) {
346 if(beat_count == 0) {
347 auto dptr = fsm_hndl->
trans->get_data_ptr();
348 for(
size_t i = offset; i < size; ++i, ++dptr) {
349 auto bit_offs = i * 8;
350 *dptr = data(bit_offs + 7, bit_offs).to_uint();
353 auto beat_start_idx = beat_count * size - offset;
354 auto data_len = fsm_hndl->
trans->get_data_length();
355 auto dptr = fsm_hndl->
trans->get_data_ptr() + beat_start_idx;
356 for(
size_t i = offset; i < size && (beat_start_idx + i) < data_len; ++i, ++dptr) {
357 auto bit_offs = i * 8;
358 *dptr = data(bit_offs + 7, bit_offs).to_uint();
362 auto dptr = fsm_hndl->
trans->get_data_ptr() + beat_count * size;
363 for(
size_t i = 0; i < size; ++i, ++dptr) {
364 auto bit_offs = (offset + i) * 8;
365 *dptr = data(bit_offs + 7, bit_offs).to_uint();
369 fsm_hndl->
trans->get_extension(e);
370 e->
set_resp(axi::into<axi::resp_e>(resp));
372 auto tp = CFG::IS_LITE || this->r_last->read() ? axi::fsm::protocol_time_point_e::BegRespE
373 : axi::fsm::protocol_time_point_e::BegPartRespE;
375 wait(r_end_resp_evt);
376 this->r_ready.write(
true);
377 wait(clk_i.posedge_event());
378 this->r_ready.write(
false);
384 this->aw_valid.write(
false);
385 wait(sc_core::SC_ZERO_TIME);
388 this->aw_valid.write(
true);
390 wait(this->aw_ready.posedge_event() | clk_delayed);
391 }
while(!this->aw_ready.read());
392 wait(clk_i.posedge_event());
393 this->aw_valid.write(
false);
398 this->w_valid.write(
false);
399 wait(sc_core::SC_ZERO_TIME);
402 this->w_last->write(
false);
403 wait(wdata_vl.default_event());
404 auto val = wdata_vl.read();
405 this->w_valid.write(val & 0x1);
407 this->w_last->write(val & 0x2);
409 wait(this->w_ready.posedge_event() | clk_delayed);
410 if(this->w_ready.read()) {
412 CFG::IS_LITE || (val & 0x2) ? axi::fsm::protocol_time_point_e::EndReqE : axi::fsm::protocol_time_point_e::EndPartReqE;
413 react(evt, active_req[tlm::TLM_WRITE_COMMAND]);
415 }
while(!this->w_ready.read());
416 wait(clk_i.posedge_event());
417 this->w_valid.write(
false);
422 this->b_ready.write(
false);
423 wait(sc_core::SC_ZERO_TIME);
425 wait(this->b_valid.posedge_event() | clk_delayed);
426 if(this->b_valid.event() || (!active_resp[tlm::TLM_WRITE_COMMAND] && this->b_valid.read())) {
427 auto id = !CFG::IS_LITE ? this->b_id->read().to_uint() : 0U;
428 auto resp = this->b_resp.read();
429 auto& q = wr_resp_by_id[id];
431 auto* fsm_hndl = q.front();
433 fsm_hndl->
trans->get_extension(e);
434 e->
set_resp(axi::into<axi::resp_e>(resp));
435 react(axi::fsm::protocol_time_point_e::BegRespE, fsm_hndl);
436 wait(r_end_resp_evt);
437 this->b_ready.write(
true);
438 wait(clk_i.posedge_event());
439 this->b_ready.write(
false);
TLM2.0 components modeling AHB.
tlm::tlm_fw_transport_if< TYPES > axi_fw_transport_if
alias declaration for the forward interface
constexpr ULT to_int(E t)
unsigned get_burst_size(const request &r)
void add_to_response_array(response &)
add a read response to the response array
base class of all AXITLM based adapters and interfaces.
tlm::tlm_sync_enum nb_fw(payload_type &trans, phase_type const &phase, sc_core::sc_time &t)
triggers the FSM based on TLM phases in the forward path. Should be called from np_transport_fw of th...
tlm::scc::tlm_gp_shared_ptr trans
pointer to the associated AXITLM payload
size_t beat_count
beat count of this transaction
AxiProtocolFsm *const fsm
pointer to the FSM
uint8_t get_size() const
set the AxSIZE value of the transaction
void set_resp(resp_e)
set the response status as POD