17 #include "simple_initiator.h"
18 #include <axi/fsm/protocol_fsm.h>
19 #include <axi/fsm/types.h>
20 #include <scc/report.h>
22 #include <tlm/scc/tlm_id.h>
24 using namespace sc_core;
27 using namespace axi::fsm;
35 simple_initiator_b::simple_initiator_b(
const sc_core::sc_module_name& nm,
37 size_t transfer_width,
bool ack_phase)
39 ,
base(transfer_width, ack_phase)
46 SC_METHOD(fsm_clk_method);
48 sensitive << clk_i.pos();
49 SC_METHOD(process_snoop_resp);
50 sensitive << clk_i.pos();
51 snp_resp_queue.set_avail_cb([
this]() {
52 if(snp_resp_queue_hndl.valid())
53 snp_resp_queue_hndl.enable();
55 snp_resp_queue.set_empty_cb([
this]() {
56 if(snp_resp_queue_hndl.valid())
57 snp_resp_queue_hndl.disable();
61 sensitive << cbpeq.
event();
64 void simple_initiator_b::end_of_elaboration() { clk_if =
dynamic_cast<sc_core::sc_clock*
>(clk_i.get_interface()); }
70 SCCTRACE(SCMOD) <<
"got transport req for trans " << trans;
73 socket_fw->b_transport(trans, t);
78 wait(clk_i.posedge_event());
81 wait(clk_i.posedge_event());
83 react(RequestPhaseBeg, fsm);
84 SCCTRACE(SCMOD) <<
"started non-blocking protocol";
85 sc_core::wait(fsm->
finish);
86 SCCTRACE(SCMOD) <<
"finished non-blocking protocol";
93 fsm_hndl->
fsm->cb[RequestPhaseBeg] = [
this, fsm_hndl]() ->
void {
95 auto& f = protocol_cb[RequestPhaseBeg];
99 fsm_hndl->
fsm->cb[BegPartReqE] = [
this, fsm_hndl]() ->
void {
101 tlm::tlm_phase phase = axi::BEGIN_PARTIAL_REQ;
102 auto ret = socket_fw->nb_transport_fw(*fsm_hndl->
trans, phase, t);
103 if(ret == tlm::TLM_UPDATED) {
104 schedule(EndPartReqE, fsm_hndl->
trans, t,
true);
106 if(protocol_cb[BegPartReqE])
107 cbpeq.notify(std::make_tuple(BegPartReqE, fsm_hndl->
trans, fsm_hndl->
is_snoop), sc_core::SC_ZERO_TIME);
109 fsm_hndl->
fsm->cb[EndPartReqE] = [
this, fsm_hndl]() ->
void {
112 if(::scc::get_value(wr_data_beat_delay) > 0)
113 schedule(BegPartReqE, fsm_hndl->
trans, ::scc::get_value(wr_data_beat_delay) - 1);
115 schedule(BegPartReqE, fsm_hndl->
trans, SC_ZERO_TIME);
116 else if(::scc::get_value(wr_data_beat_delay) > 0)
117 schedule(BegReqE, fsm_hndl->
trans, ::scc::get_value(wr_data_beat_delay) - 1);
119 schedule(BegReqE, fsm_hndl->
trans, 0);
120 if(protocol_cb[EndPartReqE])
121 cbpeq.notify(std::make_tuple(EndPartReqE, fsm_hndl->
trans, fsm_hndl->
is_snoop), sc_core::SC_ZERO_TIME);
123 fsm_hndl->
fsm->cb[BegReqE] = [
this, fsm_hndl]() ->
void {
125 schedule(EndReqE, fsm_hndl->
trans, SC_ZERO_TIME);
128 tlm::tlm_phase phase = tlm::BEGIN_REQ;
129 auto ret = socket_fw->nb_transport_fw(*fsm_hndl->
trans, phase, t);
130 if(ret == tlm::TLM_UPDATED) {
131 schedule(EndReqE, fsm_hndl->
trans, t,
true);
134 if(protocol_cb[BegReqE])
135 cbpeq.notify(std::make_tuple(BegReqE, fsm_hndl->
trans, fsm_hndl->
is_snoop), sc_core::SC_ZERO_TIME);
137 fsm_hndl->
fsm->cb[EndReqE] = [
this, fsm_hndl]() ->
void {
139 tlm::tlm_phase phase = tlm::END_REQ;
140 sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : SC_ZERO_TIME);
141 auto ret = socket_fw->nb_transport_fw(*fsm_hndl->
trans, phase, t);
143 sc_assert(ext &&
"No ACE extension found for snoop access");
145 fsm_hndl->
trans->set_response_status(tlm::TLM_OK_RESPONSE);
146 auto latency = snoop_latency;
147 if(bw_o.get_interface()) {
149 if(thread_avail == 0) {
150 sc_core::sc_spawn_options opts;
151 opts.set_stack_size(0x10000);
157 auto req = dispatch_queue.read();
158 sc_assert(thread_avail > 0);
160 auto latency = bw_o->transport(*req);
161 if(latency < std::numeric_limits<unsigned>::max()) {
164 auto evt = ext->is_snoop_data_transfer() && length > 1 ? BegPartRespE : BegRespE;
165 snp_resp_queue.push_back(std::make_tuple(evt, req.get(), latency));
171 dispatch_queue.write(fsm_hndl->
trans);
172 latency = std::numeric_limits<unsigned>::max();
173 }
else if(snoop_cb) {
174 latency = snoop_cb(*fsm_hndl->
trans);
176 ext->set_snoop_data_transfer(
false);
177 ext->set_snoop_error(
false);
178 ext->set_pass_dirty(
false);
179 ext->set_shared(
false);
180 ext->set_snoop_was_unique(
false);
182 if(latency < std::numeric_limits<unsigned>::max()) {
184 auto evt = ext->is_snoop_data_transfer() && length > 1 ? BegPartRespE : BegRespE;
185 snp_resp_queue.push_back(std::make_tuple(evt, fsm_hndl->
trans.
get(), latency));
189 if(fsm_hndl->
trans->is_write())
194 if(protocol_cb[EndReqE])
195 cbpeq.notify(std::make_tuple(EndReqE, fsm_hndl->
trans, fsm_hndl->
is_snoop), sc_core::SC_ZERO_TIME);
197 fsm_hndl->
fsm->cb[BegPartRespE] = [
this, fsm_hndl]() ->
void {
199 tlm::tlm_phase phase = axi::BEGIN_PARTIAL_RESP;
201 auto ret = socket_fw->nb_transport_fw(*fsm_hndl->
trans, phase, t);
203 if(::scc::get_value(rd_data_accept_delay))
204 schedule(EndPartRespE, fsm_hndl->
trans, ::scc::get_value(rd_data_accept_delay));
206 schedule(EndPartRespE, fsm_hndl->
trans, SC_ZERO_TIME);
208 if(protocol_cb[BegPartRespE])
209 cbpeq.notify(std::make_tuple(BegPartRespE, fsm_hndl->
trans, fsm_hndl->
is_snoop), sc_core::SC_ZERO_TIME);
211 fsm_hndl->
fsm->cb[EndPartRespE] = [
this, fsm_hndl]() ->
void {
215 schedule(fsm_hndl->
beat_count < (size-1) ? BegPartRespE : BegRespE, fsm_hndl->
trans, 0);
217 sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : SC_ZERO_TIME);
218 tlm::tlm_phase phase = axi::END_PARTIAL_RESP;
219 auto ret = socket_fw->nb_transport_fw(*fsm_hndl->
trans, phase, t);
222 if(protocol_cb[EndPartRespE])
223 cbpeq.notify(std::make_tuple(EndPartRespE, fsm_hndl->
trans, fsm_hndl->
is_snoop), sc_core::SC_ZERO_TIME);
225 fsm_hndl->
fsm->cb[BegRespE] = [
this, fsm_hndl]() ->
void {
227 tlm::tlm_phase phase = tlm::BEGIN_RESP;
229 auto ret = socket_fw->nb_transport_fw(*fsm_hndl->
trans, phase, t);
231 auto del = fsm_hndl->
trans->is_read() ? ::scc::get_value(rd_data_accept_delay)
232 : ::scc::get_value(wr_resp_accept_delay);
234 schedule(EndRespE, fsm_hndl->
trans, del);
236 schedule(EndRespE, fsm_hndl->
trans, SC_ZERO_TIME);
238 if(protocol_cb[BegRespE])
239 cbpeq.notify(std::make_tuple(BegRespE, fsm_hndl->
trans, fsm_hndl->
is_snoop), sc_core::SC_ZERO_TIME);
241 fsm_hndl->
fsm->cb[EndRespE] = [
this, fsm_hndl]() ->
void {
245 sc_time t(clk_if ? ::scc::time_to_next_posedge(clk_if) - 1_ps : SC_ZERO_TIME);
246 tlm::tlm_phase phase = tlm::END_RESP;
247 auto ret = socket_fw->nb_transport_fw(*fsm_hndl->
trans, phase, t);
249 schedule(Ack, fsm_hndl->
trans, ::scc::get_value(ack_resp_delay));
251 fsm_hndl->
finish.notify(sc_core::SC_ZERO_TIME);
253 if(protocol_cb[EndRespE])
254 cbpeq.notify(std::make_tuple(EndRespE, fsm_hndl->
trans, fsm_hndl->
is_snoop), sc_core::SC_ZERO_TIME);
256 fsm_hndl->
fsm->cb[Ack] = [
this, fsm_hndl]() ->
void {
258 tlm::tlm_phase phase = axi::ACK;
259 auto ret = socket_fw->nb_transport_fw(*fsm_hndl->
trans, phase, t);
260 fsm_hndl->
finish.notify(sc_core::SC_ZERO_TIME);
262 cbpeq.notify(std::make_tuple(Ack, fsm_hndl->
trans, fsm_hndl->
is_snoop), sc_core::SC_ZERO_TIME);
266 tlm_sync_enum simple_initiator_b::nb_transport_bw(payload_type& trans, phase_type& phase, sc_time& t) {
267 auto ret = TLM_ACCEPTED;
268 SCCTRACE(SCMOD) <<
"nb_transport_bw " << phase <<
" of trans " << trans;
269 if(phase == END_PARTIAL_REQ || phase == END_REQ) {
270 schedule(phase == END_REQ ? EndReqE : EndPartReqE, &trans, t,
false);
271 }
else if(phase == BEGIN_PARTIAL_RESP || phase == BEGIN_RESP) {
272 schedule(phase == BEGIN_RESP ? BegRespE : BegPartRespE, &trans, t,
false);
273 }
else if(phase == BEGIN_REQ) {
275 fsm_hndl->is_snoop =
true;
277 }
else if(phase == END_PARTIAL_RESP || phase == END_RESP) {
278 schedule(phase == END_RESP ? EndRespE : EndPartRespE, &trans, t);
283 void simple_initiator_b::b_snoop(payload_type& trans, sc_time& t) {
284 if(bw_o.get_interface()) {
285 auto latency = bw_o->transport(trans);
286 if(latency < std::numeric_limits<unsigned>::max())
287 t += latency * clk_period;
288 }
else if(snoop_cb) {
289 auto latency = snoop_cb(trans);
290 if(latency < std::numeric_limits<unsigned>::max())
291 t += latency * clk_period;
295 void simple_initiator_b::process_snoop_resp() {
296 if(!snp_resp_queue_hndl.valid())
297 snp_resp_queue_hndl = sc_process_handle(sc_get_current_process_handle());
298 if(snp_resp_queue.avail())
299 while(snp_resp_queue.avail()) {
300 auto entry = snp_resp_queue.front();
301 if(std::get<2>(entry) == 0) {
303 snp_resp_queue.push_back(entry);
306 auto gp = std::get<1>(entry);
307 SCCTRACE(instance_name)
308 <<
"processing event " << evt2str(std::get<0>(entry)) <<
" of trans " << *gp;
309 react(std::get<0>(entry), std::get<1>(entry));
312 std::get<2>(entry) -= 1;
313 snp_resp_queue.push_back(entry);
315 snp_resp_queue.pop_front();
319 snp_resp_queue_hndl.disable();
324 sc_assert(fsm_hndl !=
nullptr);
327 protocol_time_point_e e = ext->is_snoop_data_transfer() && size > 0 ? BegPartRespE : BegRespE;
329 snp_resp_queue.push_back(std::make_tuple(e, &trans, 0));
339 void simple_initiator_b::cbpeq_cb() {
341 auto e = cbpeq.
get();
342 protocol_cb[std::get<0>(e)](*std::get<1>(e), std::get<2>(e));
void setup_callbacks(axi::fsm::fsm_handle *) override
axi::fsm::fsm_handle * create_fsm_handle() override
void snoop_resp(payload_type &trans, bool sync=false) override
triggers a non-blocking snoop response if the snoop callback does not do so.
sc_core::sc_attribute< unsigned > rd_data_accept_delay
the latency between between BEGIN(_PARTIAL)_RESP and END(_PARTIAL)_RESP (RVALID to RREADY)
sc_core::sc_attribute< unsigned > wr_resp_accept_delay
the latency between between BEGIN_RESP and END_RESP (BVALID to BREADY)
sc_core::sc_attribute< unsigned > ack_resp_delay
the latency between between BEGIN_RESP and END_RESP (BVALID to BREADY)
sc_core::sc_attribute< unsigned > wr_data_beat_delay
the latency between between END(_PARTIAL)_REQ and BEGIN(_PARTIAL)_REQ (AWREADY to AWVALID and WREADY ...
void transport(payload_type &trans, bool blocking) override
The forward transport function. It behaves blocking and is re-entrant.
int get_value() const override
get the value of the semaphore
int wait() override
lock (take) the semaphore, block if not available
tlm::tlm_generic_payload * get() const noexcept
Return the stored pointer.
protocol engine implementations
TLM2.0 components modeling AHB.
unsigned get_burst_length(const request &r)
tlm::tlm_fw_transport_if< TYPES > axi_fw_transport_if
alias declaration for the forward interface
base class of all AXITLM based adapters and interfaces.
void react(axi::fsm::protocol_time_point_e event, tlm::scc::tlm_gp_shared_ptr &trans)
triggers the FSM with event and given transaction
void schedule(axi::fsm::protocol_time_point_e e, tlm::scc::tlm_gp_shared_ptr &gp, unsigned cycles)
processes the fsm_sched_queue and propagates events to fsm_clk_queue. Should be registered as falling...
axi::fsm::fsm_handle * find_or_create(payload_type *gp=nullptr, bool ace=false)
retrieve the FSM handle based on the transaction passed. If non exist one will be created
axi::axi_protocol_types::tlm_payload_type payload_type
aliases used in the class
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
bool is_snoop
indicator if this is a snoop access
uint8_t get_length() const
get the AxLEN value of the transaction, the value denotes the burst length - 1
bool has_next()
check if value is available at current time
sc_core::sc_event & event()
get the available event