scc  2022.4.0
SystemC components library
base.cpp
1 /*
2  * Copyright 2020 - 2022 Arteris IP
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.axi_util.cpp
15  */
16 
17 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES
18 #define SC_INCLUDE_DYNAMIC_PROCESSES
19 #endif
20 
21 #include "base.h"
22 #include "protocol_fsm.h"
23 #include <scc/report.h>
24 #include <systemc>
25 #include <tlm/scc/tlm_id.h>
26 #include <tlm/scc/tlm_mm.h>
27 #include <scc/utilities.h>
28 
29 using namespace sc_core;
30 using namespace tlm;
31 namespace axi {
32 namespace fsm {
33 
34 fsm_handle::fsm_handle():fsm{new AxiProtocolFsm()} {
35  fsm->initiate();
36 }
37 
38 fsm_handle::~fsm_handle(){
39  fsm->terminate();
40  delete fsm;
41 }
42 
43 base::base(size_t transfer_width, bool coherent, protocol_time_point_e wr_start)
44 : transfer_width_in_bytes(transfer_width / 8)
45 , wr_start(wr_start)
46 , coherent(coherent) {
47  assert(wr_start == RequestPhaseBeg || wr_start == WValidE);
48  idle_fsm.clear();
49  active_fsm.clear();
50  sc_core::sc_spawn_options opts;
51  opts.dont_initialize();
52  opts.spawn_method();
53  opts.set_sensitivity(&fsm_event_queue.event());
54  sc_core::sc_spawn(sc_bind(&base::process_fsm_event, this), sc_core::sc_gen_unique_name("fsm_event_method"), &opts);
55  fsm_clk_queue.set_avail_cb([this]() {
56  if(fsm_clk_queue_hndl.valid())
57  fsm_clk_queue_hndl.enable();
58  });
59  fsm_clk_queue.set_empty_cb([this]() {
60  if(fsm_clk_queue_hndl.valid())
61  fsm_clk_queue_hndl.disable();
62  });
63 }
64 
66  auto it = active_fsm.find(gp);
67  if(!gp || it == active_fsm.end()) {
68  if(gp) {
69  SCCTRACE(instance_name) << "creating fsm for trans " << *gp;
70  } else {
71  SCCTRACE(instance_name) << "creating fsm for new transaction";
72  }
73  if(idle_fsm.empty()) {
74  auto fsm_hndl = create_fsm_handle();
75  setup_callbacks(fsm_hndl);
76  idle_fsm.push_back(fsm_hndl);
77  allocated_fsm.emplace_back(fsm_hndl);
78  }
79  auto fsm_hndl = idle_fsm.front();
80  idle_fsm.pop_front();
81  fsm_hndl->reset();
82  if(gp != nullptr) {
83  fsm_hndl->trans = gp;
84  } else {
85  fsm_hndl->trans = ace ? tlm::scc::tlm_mm<>::get().allocate<ace_extension>()
87  }
88  active_fsm.insert(std::make_pair(fsm_hndl->trans.get(), fsm_hndl));
89  fsm_hndl->start = sc_time_stamp();
90  return fsm_hndl;
91  } else {
92  it->second->start = sc_time_stamp();
93  return it->second;
94  }
95 }
96 
98  while(auto e = fsm_event_queue.get_next()) {
99  auto entry = e.get();
100  if(std::get<2>(entry))
101  schedule(std::get<0>(entry), std::get<1>(entry), 0);
102  else
103  react(std::get<0>(entry), std::get<1>(entry));
104  }
105 }
106 
108  if(!fsm_clk_queue_hndl.valid())
109  fsm_clk_queue_hndl = sc_process_handle(sc_get_current_process_handle());
110  if(fsm_clk_queue.avail())
111  while(fsm_clk_queue.avail()) {
112  auto entry = fsm_clk_queue.front();
113  if(std::get<2>(entry) == 0) {
114  SCCTRACE(instance_name) << "processing event " << evt2str(std::get<0>(entry)) << " of trans "
115  << *std::get<1>(entry);
116  react(std::get<0>(entry), std::get<1>(entry));
117  } else {
118  std::get<2>(entry) -= 1;
119  fsm_clk_queue.push_back(entry);
120  }
121  fsm_clk_queue.pop_front();
122  }
123  else
124  // fall asleep if there is nothing to process
125  fsm_clk_queue_hndl.disable();
126 }
127 
128 void base::react(protocol_time_point_e event, axi::fsm::fsm_handle* fsm_hndl) {
129  SCCTRACE(instance_name)<< "in react() base has coherent =" << coherent << " with event " << evt2str(event);
130  fsm_hndl->state=event;
131  switch(event) {
132  case WValidE:
133  fsm_hndl->fsm->process_event(WReq());
134  return;
135  case WReadyE:
136  case RequestPhaseBeg:
137  if(is_burst(*fsm_hndl->trans) && fsm_hndl->trans->is_write() &&
138  !is_dataless(fsm_hndl->trans->get_extension<axi::ace_extension>()))
139  fsm_hndl->fsm->process_event(BegPartReq());
140  else
141  fsm_hndl->fsm->process_event(BegReq());
142  return;
143  case BegPartReqE:
144  fsm_hndl->fsm->process_event(BegPartReq());
145  return;
146  case EndPartReqE:
147  fsm_hndl->fsm->process_event(EndPartReq());
148  return;
149  case BegReqE:
150  fsm_hndl->fsm->process_event(BegReq());
151  return;
152  case EndReqE:
153  fsm_hndl->fsm->process_event(EndReq());
154  return;
155  case BegPartRespE:
156  fsm_hndl->fsm->process_event(BegPartResp());
157  return;
158  case EndPartRespE:
159  fsm_hndl->fsm->process_event(EndPartResp());
160  return;
161  case BegRespE:
162  fsm_hndl->fsm->process_event(BegResp());
163  return;
164  case EndRespE:
165  SCCTRACE(instance_name)<< "in EndResp of base() with coherent =" << coherent;
166  if(!coherent || fsm_hndl->is_snoop) {
167  SCCTRACE(instance_name) << "freeing fsm for trans " << *fsm_hndl->trans;
168  fsm_hndl->fsm->process_event(EndResp());
169  active_fsm.erase(fsm_hndl->trans.get());
170  fsm_hndl->trans = nullptr;
171  idle_fsm.push_back(fsm_hndl);
172  finish_evt.notify();
173  } else {
174  fsm_hndl->fsm->process_event(EndRespNoAck());
175  }
176  return;
177  case Ack:
178  SCCTRACE(instance_name) << "freeing fsm for trans " << *fsm_hndl->trans;
179  fsm_hndl->fsm->process_event(AckRecv());
180  active_fsm.erase(fsm_hndl->trans.get());
181  fsm_hndl->trans = nullptr;
182  idle_fsm.push_back(fsm_hndl);
183  finish_evt.notify();
184  return;
185  default:
186  SCCFATAL(instance_name) << "No valid protocol time point";
187  }
188 }
189 
190 tlm_sync_enum base::nb_fw(payload_type& trans, phase_type const& phase, sc_time& t) {
191  SCCTRACE(instance_name) << "base::nb_fw " << phase << " with delay = " << t << " of trans " << trans;
192  if(phase == BEGIN_PARTIAL_REQ || phase == BEGIN_REQ) { // read/write
193  auto fsm_hndl = find_or_create(&trans);
194  if(!trans.is_read()) {
195  protocol_time_point_e evt = axi::fsm::RequestPhaseBeg;
196  if(fsm_hndl->beat_count == 0 && wr_start != RequestPhaseBeg)
197  evt = wr_start;
198  else
199  evt = phase == BEGIN_PARTIAL_REQ ? BegPartReqE : BegReqE;
200  if(t == SC_ZERO_TIME) {
201  react(evt, &trans);
202  } else {
203  schedule(evt, &trans, t);
204  }
205  } else {
206  if(t == SC_ZERO_TIME) {
207  react(BegReqE, &trans);
208  } else
209  schedule(BegReqE, &trans, t);
210  }
211  } else if(phase == END_PARTIAL_RESP || phase == END_RESP) {
212  if(t == SC_ZERO_TIME) {
213  react(phase == END_RESP ? EndRespE : EndPartRespE, &trans);
214  } else
215  schedule(phase == END_RESP ? EndRespE : EndPartRespE, &trans, t);
216  } else if(phase == END_REQ) { // snoop access resp
217  if(t == SC_ZERO_TIME) {
218  react(EndReqE, &trans);
219  } else
220  schedule(EndReqE, &trans, t);
221  } else if(phase == BEGIN_PARTIAL_RESP || phase == BEGIN_RESP) { // snoop access resp
222  if(t == SC_ZERO_TIME) {
223  react(phase == BEGIN_RESP ? BegRespE : BegPartRespE, &trans);
224  } else
225  schedule(phase == BEGIN_RESP ? BegRespE : BegPartRespE, &trans, t);
226  } else if(phase == axi::ACK) {
227  if(t == SC_ZERO_TIME) {
228  react(Ack, &trans);
229  } else
230  schedule(Ack, &trans, t);
231  }
232  return TLM_ACCEPTED;
233 }
234 
235 tlm_sync_enum base::nb_bw(payload_type& trans, phase_type const& phase, sc_time& t) {
236  SCCTRACE(instance_name) << "base::nb_bw " << phase << " of trans " << trans;
237  if(phase == END_PARTIAL_REQ || phase == END_REQ) { // read/write
238  if(t == SC_ZERO_TIME) {
239  react(phase == END_REQ ? EndReqE : EndPartReqE, &trans);
240  } else
241  schedule(phase == END_REQ ? EndReqE : EndPartReqE, &trans, t);
242  } else if(phase == BEGIN_PARTIAL_RESP || phase == BEGIN_RESP) { // read/write response
243  if(t == SC_ZERO_TIME) {
244  react(phase == BEGIN_RESP ? BegRespE : BegPartRespE, &trans);
245  } else
246  schedule(phase == BEGIN_RESP ? BegRespE : BegPartRespE, &trans, t);
247  } else if(phase == BEGIN_REQ) { // snoop read
248  auto fsm_hndl = find_or_create(&trans, true);
249  fsm_hndl->is_snoop = true;
250  if(t == SC_ZERO_TIME) {
251  react(BegReqE, &trans);
252  } else
253  schedule(BegReqE, &trans, t);
254  } else if(phase == END_PARTIAL_RESP || phase == END_RESP) { // snoop read response
255  if(t == SC_ZERO_TIME) {
256  react(phase == END_RESP ? EndRespE : EndPartRespE, &trans);
257  } else
258  schedule(phase == END_RESP ? EndRespE : EndPartRespE, &trans, t);
259  }
260  return TLM_ACCEPTED;
261 }
262 
263 }
264 }
tlm::tlm_generic_payload * get() const noexcept
Return the stored pointer.
Definition: tlm_gp_shared.h:91
a tlm memory manager
Definition: tlm_mm.h:161
payload_type * allocate()
get a plain tlm_payload_type without extensions
Definition: tlm_mm.h:228
static tlm_mm & get()
accessor function of the singleton
Definition: tlm_mm.h:222
TLM2.0 components modeling AHB.
Definition: axi_initiator.h:30
bool is_burst(const axi::axi_protocol_types::tlm_payload_type &trans)
Definition: axi_tlm.h:1101
SystemC TLM.
void react(axi::fsm::protocol_time_point_e event, tlm::scc::tlm_gp_shared_ptr &trans)
triggers the FSM with event and given transaction
Definition: base.h:134
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...
Definition: base.cpp:190
virtual void setup_callbacks(axi::fsm::fsm_handle *)=0
this function is called to add the callbacks to the fsm handle during creation. Needs to be implement...
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...
Definition: base.h:107
void process_fsm_clk_queue()
processes the fsm_clk_queue and triggers the FSM accordingly. Should be registered as rising-edge clo...
Definition: base.cpp:107
tlm::tlm_sync_enum nb_bw(payload_type &trans, phase_type const &phase, sc_core::sc_time &t)
triggers the FSM based on TLM phases in the backward path. Should be called from np_transport_bw of t...
Definition: base.cpp:235
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
Definition: base.cpp:65
void process_fsm_event()
processes the fsm_event_queue and triggers FSM aligned
Definition: base.cpp:97
axi::axi_protocol_types::tlm_payload_type payload_type
aliases used in the class
Definition: base.h:45
virtual axi::fsm::fsm_handle * create_fsm_handle()=0
function to create a fsm_handle. Needs to be implemented by the derived class
tlm::scc::tlm_gp_shared_ptr trans
pointer to the associated AXITLM payload
Definition: types.h:62
size_t beat_count
beat count of this transaction
Definition: types.h:64
AxiProtocolFsm *const fsm
pointer to the FSM
Definition: types.h:60
bool is_snoop
indicator if this is a snoop access
Definition: types.h:66
boost::optional< TYPE > get_next()
non-blocking get
Definition: peq.h:111
sc_core::sc_event & event()
get the available event
Definition: peq.h:140