gem5 v24.0.0.0
Loading...
Searching...
No Matches
MultiSocketSimpleSwitchAT.h
Go to the documentation of this file.
1/*****************************************************************************
2
3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4 more contributor license agreements. See the NOTICE file distributed
5 with this work for additional information regarding copyright ownership.
6 Accellera licenses this file to you under the Apache License, Version 2.0
7 (the "License"); you may not use this file except in compliance with the
8 License. You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15 implied. See the License for the specific language governing
16 permissions and limitations under the License.
17
18 *****************************************************************************/
19
20#ifndef __SIMPLESWITCHAT_H__
21#define __SIMPLESWITCHAT_H__
22
23#include "tlm.h"
24
25#include "tlm_utils/multi_passthrough_initiator_socket.h"
26#include "tlm_utils/multi_passthrough_target_socket.h"
27#include "simpleAddressMap.h"
28#include "extensionPool.h"
29#include "tlm_utils/instance_specific_extensions.h"
30#include "tlm_utils/peq_with_cb_and_phase.h"
31
32
33/*
34This class is a simple crossbar switch through which an arbitrary number of initiators
35may communicate in parallel as long as they do not talk to the same target.
36
37If two requestors address the same target at the same point of time,
38the choice who will be allowed to communicate
39is done non-deterministically (based on the SystemC process exectution order).
40
41This could be avoided by changing the fwPEQ into a priority PEQ of some kind.
42
43The switch ensures that the end_req and end_resp rules are not violated when
44many initiator talk to the same target.
45*/
47{
48public:
54
55public:
56 target_socket_type target_socket; //the target multi socket
57
58private:
59 initiator_socket_type initiator_socket; //the initiator multi socket (private to enforce use of bindTarget function)
60 SimpleAddressMap m_addrMap; //a pretty simple address map
61 std::vector<std::deque<transaction_type*> > m_pendingReqs; //list of pending reqs per target
62 std::vector<std::deque<transaction_type*> > m_pendingResps; //list of pending resps per initiator
63 std::vector<sc_dt::uint64> m_masks; //address masks for each target
64 tlm_utils::instance_specific_extension_accessor accessMySpecificExtensions; //extension accessor to access private extensions
67
68
69 //an instance specific extension that tells us whether we are in a wrapped b_transport or not
71 public:
72 sc_core::sc_event event; //trigger this event when transaction is done
73 };
74
75 //an instance specific extension that holds information about source and sink of a txn
76 // as well as information if the req still has to be cleared and if the txn is already
77 // complete on the target side
79 public:
80 unsigned int fwID; //socket number of sink
81 unsigned int bwID; //socket number of source
82 bool clearReq; //is the txn still in req phase?
83 bool alreadyComplete; //has the txn already completed on the target side?
84 };
85
86 class internalPEQTypes{ //use the tpPEQ to delay connection infos
87 public:
90 };
92 unsigned int m_target_count; //number of connected targets (see bindTargetSocket for explanation)
93
94public:
109
111 ,sc_dt::uint64 low
112 ,sc_dt::uint64 high
113 ,sc_dt::uint64 mask = 0xffffffffffffffffULL){
114 initiator_socket(target); //bind sockets
115 //insert into address map and increase target count
116 // (we have to count the targets manually, because target_socket.size() is only reliable during simulation
117 // as it gets evaluated during end_of_elaboration)
118 m_addrMap.insert(low, high, m_target_count++);
119 m_masks.push_back(mask); //add the mask for this target
120 }
121
122 unsigned int decode(const sc_dt::uint64& address)
123 {
124 return m_addrMap.decode(address);
125 }
126
128 //initialize the lists of pending reqs and resps
131 }
132
133
134 void b_transport(int initiator_id, transaction_type& trans, sc_core::sc_time& t){
135 //first make sure that there is no BTag (just for debugging)
136 BTag* btag;
137 accessMySpecificExtensions(trans).get_extension(btag);
138 sc_assert(!btag);
139 BTag tag; //now add our BTag
140 bool added_mm=!trans.has_mm(); //in case there is no MM in we add it now
141 if (added_mm){
142 trans.set_mm(this);
143 trans.acquire(); //acquire the txn
144 }
145 accessMySpecificExtensions(trans).set_extension(&tag);
146 phase_type phase=tlm::BEGIN_REQ; //then simply use our nb implementation (respects all the rules)
147 initiatorNBTransport(initiator_id, trans, phase, t);
148 wait(tag.event); //and wait for the event to be triggered
149 if (added_mm){ //if we added MM
150 trans.release(); //we release our reference (this will not delete the txn but trigger the tag.event as soon as the ref count is zero)
151 if (trans.get_ref_count())
152 wait(tag.event); //wait for the ref count to get to zero
153 trans.set_mm(NULL); //remove the MM
154 }
155 //don't forget to remove the extension (instance specific extensions are not cleared off by MM)
156 accessMySpecificExtensions(trans).clear_extension(&tag);
157 }
158
160 BTag* btag;
161 accessMySpecificExtensions(*txn).get_extension(btag);
162 sc_assert(btag);
163 txn->reset(); //clean off all extension that were added down stream
164 btag->event.notify();
165 }
166
167 //do a fw transmission
169 phase_type& phase,
171 unsigned int tgtSocketNumber){
172 switch (initiator_socket[tgtSocketNumber]->nb_transport_fw(trans, phase, t)) {
174 case tlm::TLM_UPDATED:
175 // Transaction not yet finished
176 if (phase != tlm::BEGIN_REQ)
177 {
178 sc_assert(phase!=tlm::END_RESP);
179 m_bwPEQ.notify(trans,phase,t);
180 }
181 break;
183 // Transaction finished
184 ConnectionInfo* connInfo;
185 accessMySpecificExtensions(trans).get_extension(connInfo);
186 sc_assert(connInfo);
187 connInfo->alreadyComplete=true;
188 phase=tlm::BEGIN_RESP;
189 m_bwPEQ.notify(trans, phase, t);
190 break;
191 default:
192 sc_assert(0); exit(1);
193 };
194 }
195
196 //nb_transport_fw
198 transaction_type& trans,
199 phase_type& phase,
201 {
202 ConnectionInfo* connInfo;
203 accessMySpecificExtensions(trans).get_extension(connInfo);
204 m_fwPEQ.notify(trans,phase,t);
205 if (phase==tlm::BEGIN_REQ){
206 //add our private information to the txn
207 sc_assert(!connInfo);
208 connInfo=m_connInfoPool.construct();
209 connInfo->fwID=decode(trans.get_address());
210 connInfo->bwID=initiator_id;
211 connInfo->clearReq=true;
212 connInfo->alreadyComplete=false;
213 accessMySpecificExtensions(trans).set_extension(connInfo);
214 }
215 else
216 if (phase==tlm::END_RESP){
217 return tlm::TLM_COMPLETED;
218 }
219 else
220 {sc_assert(0); exit(1);}
221 return tlm::TLM_ACCEPTED;
222 }
223
225 transaction_type& trans,
226 phase_type& phase,
228 {
229 if (phase != tlm::END_REQ && phase != tlm::BEGIN_RESP) {
230 std::cout << "ERROR: '" << name()
231 << "': Illegal phase received from target." << std::endl;
232 sc_assert(false); exit(1);
233 }
234 //simply stuff it into the bw PEQ
235 m_bwPEQ.notify(trans,phase,t);
236 return tlm::TLM_ACCEPTED;
237 }
238
239 void bwPEQcb(transaction_type& trans, const phase_type& phase){
240 //first get our private info from the txn
241 ConnectionInfo* connInfo;
242 accessMySpecificExtensions(trans).get_extension(connInfo);
243 sc_assert(connInfo);
244 phase_type p=phase;
246 BTag* btag;
247 accessMySpecificExtensions(trans).get_extension(btag);
248 bool doCall=btag==NULL; //we only will do a bw call if we are not in a wrapped b_transport
249 if ((phase==tlm::END_REQ) | (connInfo->clearReq)){ //in case the target left out end_req clearReq reminds us to unlock the req port
250 sc_assert(m_pendingReqs[connInfo->fwID].size());
251 sc_assert(m_pendingReqs[connInfo->fwID].front()==&trans);
252 m_pendingReqs[connInfo->fwID].pop_front(); //allow another req to start at this target
253 if (m_pendingReqs[connInfo->fwID].size()){ //there was a pending req
255 initiatorNBTransport_core(*m_pendingReqs[connInfo->fwID].front(), ph, t,connInfo->fwID);
256 }
257 connInfo->clearReq=false;
258 }
259 //no else here, since we might clear the req AND begin a resp
260 if (phase==tlm::BEGIN_RESP){
261 m_pendingResps[connInfo->bwID].push_back(&trans);
262 doCall=m_pendingResps[connInfo->bwID].size()==1; //do a call in case the response socket was free
263 }
264
265 if (doCall){ //we have to do a call on the bw of fw path
266 if (btag){ //only possible if BEGIN_RESP and resp socket was free
268 m_fwPEQ.notify(trans, ph, t);
269 }
270 else
271 switch (target_socket[connInfo->bwID]->nb_transport_bw(trans, p, t)){
273 case tlm::TLM_UPDATED:
274 break;
275 case tlm::TLM_COMPLETED:{
276 //covers a piggy bagged END_RESP to START_RESP
278 m_fwPEQ.notify(trans, ph, t);
279 }
280 break;
281 default:
282 sc_assert(0); exit(1);
283
284 };
285 }
286 }
287
288 //the following two functions (fwPEQcb and clearPEQcb) could be one, if we were allowed
289 // to stick END_RESP into a PEQ
290 void fwPEQcb(transaction_type& trans, const phase_type& phase){
291 ConnectionInfo* connInfo;
292 accessMySpecificExtensions(trans).get_extension(connInfo);
293 sc_assert(connInfo);
294 phase_type ph=phase;
296 if (phase==tlm::BEGIN_REQ){
297 trans.set_address(trans.get_address()&m_masks[connInfo->fwID]); //mask address
298 m_pendingReqs[connInfo->fwID].push_back(&trans);
299 if (m_pendingReqs[connInfo->fwID].size()==1){ //the socket is free
300 initiatorNBTransport_core(trans, ph, t, connInfo->fwID);
301 }
302 }
303 else
304 {
305 //phase is always END_RESP
306 BTag* btag;
307 accessMySpecificExtensions(trans).get_extension(btag);
308 accessMySpecificExtensions(trans).clear_extension(connInfo); //remove our specific extension as it is not needed any more
309 if (!connInfo->alreadyComplete) {
310 sync_enum_type tmp=initiator_socket[connInfo->fwID]->nb_transport_fw(trans, ph, t);
312 }
313 sc_assert(m_pendingResps[connInfo->bwID].size());
314 m_pendingResps[connInfo->bwID].pop_front(); //remove current response
315 if (m_pendingResps[connInfo->bwID].size()){ //if there was one pending
316 ph=tlm::BEGIN_RESP; //schedule its transmission
317 m_bwPEQ.notify(*m_pendingResps[connInfo->bwID].front(),ph,t);
318 }
319 m_connInfoPool.free(connInfo); //release connInfo
320 if (btag) btag->event.notify(t); //release b_transport
321 }
322 }
323
325 std::cout<<"At "<<sc_core::sc_time_stamp()<<" status of "<<name()<<" is "<<std::endl
326 <<" Number of connected initiators: "<<target_socket.size()<<std::endl
327 <<" Number of connected targets: "<<initiator_socket.size()<<std::endl
328 <<" Pending requests:"<<std::endl;
329 for (unsigned int i=0; i<m_pendingReqs.size(); i++)
330 std::cout<<" "<<m_pendingReqs[i].size()<<" pending requests for target number "<<i<<std::endl;
331 std::cout<<" Pending responses:"<<std::endl;
332 for (unsigned int i=0; i<m_pendingResps.size(); i++)
333 std::cout<<" "<<m_pendingResps[i].size()<<" pending responses for initiator number "<<i<<std::endl;
334 std::cout<<" The address map is:"<<std::endl;
336
337 }
338};
339
340#endif
initiator_socket_type initiator_socket
MultiSocketSimpleSwitchAT(sc_core::sc_module_name name)
tlm_utils::multi_passthrough_target_socket< MultiSocketSimpleSwitchAT > target_socket_type
sync_enum_type targetNBTransport(int portId, transaction_type &trans, phase_type &phase, sc_core::sc_time &t)
tlm_utils::multi_passthrough_initiator_socket< MultiSocketSimpleSwitchAT > initiator_socket_type
std::vector< std::deque< transaction_type * > > m_pendingReqs
tlm_utils::peq_with_cb_and_phase< MultiSocketSimpleSwitchAT > m_fwPEQ
void initiatorNBTransport_core(transaction_type &trans, phase_type &phase, sc_core::sc_time &t, unsigned int tgtSocketNumber)
tlm::tlm_generic_payload transaction_type
void free(transaction_type *txn)
void bwPEQcb(transaction_type &trans, const phase_type &phase)
unsigned int decode(const sc_dt::uint64 &address)
sync_enum_type initiatorNBTransport(int initiator_id, transaction_type &trans, phase_type &phase, sc_core::sc_time &t)
ExtensionPool< ConnectionInfo > m_connInfoPool
void bindTargetSocket(initiator_socket_type::base_target_socket_type &target, sc_dt::uint64 low, sc_dt::uint64 high, sc_dt::uint64 mask=0xffffffffffffffffULL)
SC_HAS_PROCESS(MultiSocketSimpleSwitchAT)
std::vector< std::deque< transaction_type * > > m_pendingResps
void fwPEQcb(transaction_type &trans, const phase_type &phase)
tlm_utils::instance_specific_extension_accessor accessMySpecificExtensions
tlm_utils::peq_with_cb_and_phase< MultiSocketSimpleSwitchAT > m_bwPEQ
void b_transport(int initiator_id, transaction_type &trans, sc_core::sc_time &t)
std::vector< sc_dt::uint64 > m_masks
Simple address map implementation for the generic protocol.
void dumpMap()
Print map.
unsigned int decode(sc_dt::uint64 address_)
Decode slave address.
void insert(sc_dt::uint64 baseAddress_, sc_dt::uint64 highAddress_, unsigned int portNumber_)
Insert a slave into the address map.
const char * name() const
Definition sc_object.cc:44
STL vector class.
Definition stl.hh:37
void set_address(const sc_dt::uint64 address)
Definition gp.hh:185
sc_dt::uint64 get_address() const
Definition gp.hh:184
bool has_mm() const
Definition gp.hh:140
int get_ref_count() const
Definition gp.hh:137
void set_mm(tlm_mm_interface *mm)
Definition gp.hh:139
void register_nb_transport_bw(MODULE *mod, sync_enum_type(MODULE::*cb)(int, transaction_type &, phase_type &, sc_core::sc_time &))
An event queue that can contain any number of pending notifications.
void notify(tlm_payload_type &t, const tlm_phase_type &p, const sc_core::sc_time &when)
const sc_time SC_ZERO_TIME
Definition sc_time.cc:290
const sc_time & sc_time_stamp()
Definition sc_main.cc:127
uint64_t uint64
Definition sc_nbdefs.hh:172
@ BEGIN_RESP
Definition phase.hh:43
@ END_RESP
Definition phase.hh:44
@ BEGIN_REQ
Definition phase.hh:41
@ END_REQ
Definition phase.hh:42
tlm_sync_enum
Definition fw_bw_ifs.hh:31
@ TLM_COMPLETED
Definition fw_bw_ifs.hh:31
@ TLM_ACCEPTED
Definition fw_bw_ifs.hh:31
@ TLM_UPDATED
Definition fw_bw_ifs.hh:31
#define sc_assert(expr)

Generated on Tue Jun 18 2024 16:24:07 for gem5 by doxygen 1.11.0