scc 2025.09
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
29using namespace sc_core;
30using namespace tlm;
31namespace axi {
32namespace fsm {
33
34fsm_handle::fsm_handle():fsm{new AxiProtocolFsm()} {
35 fsm->initiate();
36}
37
38fsm_handle::~fsm_handle(){
39 fsm->terminate();
40 delete fsm;
41}
42
43base::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
128void 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
190tlm_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
235tlm_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}
payload_type * allocate()
get a plain tlm_payload_type without extensions
Definition tlm_mm.h:218
T * get() const noexcept
Return the stored pointer.
TLM2.0 components modeling AHB.
bool is_burst(const axi::axi_protocol_types::tlm_payload_type &trans)
Definition axi_tlm.h:1146
SystemC TLM.
Definition dmi_mgr.h:19
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 axi::fsm::fsm_handle * create_fsm_handle()=0
function to create a fsm_handle. Needs to be implemented by the derived class
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...
base(size_t transfer_width, bool coherent=false, axi::fsm::protocol_time_point_e wr_start=axi::fsm::RequestPhaseBeg)
the constructor
Definition base.cpp:43
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
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
static tlm_mm & get()
accessor function of the singleton
Definition tlm_mm.h:338