scc  2022.4.0
SystemC components library
router.h
1 /*******************************************************************************
2  * Copyright 2016, 2018 MINRES Technologies GmbH
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.
15  *******************************************************************************/
16 
17 #ifndef _SYSC_ROUTER_H_
18 #define _SYSC_ROUTER_H_
19 
20 #include <limits>
21 #include <scc/utilities.h>
22 #include <sysc/utils/sc_vector.h>
23 #include <tlm.h>
24 #include <tlm/scc/initiator_mixin.h>
25 #include <tlm/scc/scv/tlm_rec_initiator_socket.h>
26 #include <tlm/scc/scv/tlm_rec_target_socket.h>
27 #include <tlm/scc/target_mixin.h>
28 #include <unordered_map>
29 #include <util/range_lut.h>
30 
31 namespace scc {
40 template <unsigned BUSWIDTH = LT> class router : sc_core::sc_module {
41 public:
45  sc_core::sc_vector<target_sckt> target;
47  sc_core::sc_vector<intor_sckt> initiator;
56  router(const sc_core::sc_module_name& nm, unsigned slave_cnt = 1, unsigned master_cnt = 1);
57 
58  ~router() = default;
70  template <typename TYPE> void bind_target(TYPE& socket, size_t idx, uint64_t base, uint64_t size, bool remap = true) {
71  set_target_range(idx, base, size, remap);
72  initiator[idx].bind(socket);
73  }
83  template <typename TYPE> void bind_target(TYPE& socket, size_t idx, std::string name) {
84  set_target_name(idx, name);
85  initiator[idx].bind(socket);
86  }
96  void set_initiator_base(size_t idx, uint64_t base) { ibases[idx] = base; }
106  void set_default_target(size_t idx) { default_idx = idx; }
114  void set_target_name(size_t idx, std::string name) { target_name_lut.insert(std::make_pair(name, idx)); }
124  void add_target_range(std::string name, uint64_t base, uint64_t size, bool remap = true);
134  void set_target_range(size_t idx, uint64_t base, uint64_t size, bool remap = true);
143  void b_transport(int i, tlm::tlm_generic_payload& trans, sc_core::sc_time& delay);
153  bool get_direct_mem_ptr(int i, tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data);
161  unsigned transport_dbg(int i, tlm::tlm_generic_payload& trans);
170  void invalidate_direct_mem_ptr(int id, ::sc_dt::uint64 start_range, ::sc_dt::uint64 end_range);
171 
172 protected:
173  struct range_entry {
174  uint64_t base, size;
175  bool remap;
176  };
177  size_t default_idx = std::numeric_limits<size_t>::max();
178  std::vector<uint64_t> ibases;
179  std::vector<range_entry> tranges;
180  std::vector<sc_core::sc_mutex> mutexes;
181  util::range_lut<unsigned> addr_decoder;
182  std::unordered_map<std::string, size_t> target_name_lut;
183 };
184 
185 template <unsigned BUSWIDTH>
186 router<BUSWIDTH>::router(const sc_core::sc_module_name& nm, unsigned slave_cnt, unsigned master_cnt)
187 : sc_module(nm)
188 , target("target", master_cnt)
189 , initiator("intor", slave_cnt)
190 , ibases(master_cnt)
191 , tranges(slave_cnt)
192 , mutexes(slave_cnt)
193 , addr_decoder(std::numeric_limits<unsigned>::max()) {
194  for(size_t i = 0; i < target.size(); ++i) {
195  target[i].register_b_transport(
196  [=](tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) -> void { this->b_transport(i, trans, delay); });
197  target[i].register_get_direct_mem_ptr(
198  [=](tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data) -> bool { return this->get_direct_mem_ptr(i, trans, dmi_data); });
199  target[i].register_transport_dbg([=](tlm::tlm_generic_payload& trans) -> unsigned { return this->transport_dbg(i, trans); });
200  ibases[i] = 0ULL;
201  }
202  for(size_t i = 0; i < initiator.size(); ++i) {
203  initiator[i].register_invalidate_direct_mem_ptr([=](::sc_dt::uint64 start_range, ::sc_dt::uint64 end_range) -> void {
204  this->invalidate_direct_mem_ptr(i, start_range, end_range);
205  });
206  tranges[i].base = 0ULL;
207  tranges[i].size = 0ULL;
208  tranges[i].remap = false;
209  }
210 }
211 
212 template <unsigned BUSWIDTH> void router<BUSWIDTH>::set_target_range(size_t idx, uint64_t base, uint64_t size, bool remap) {
213  tranges[idx].base = base;
214  tranges[idx].size = size;
215  tranges[idx].remap = remap;
216  addr_decoder.addEntry(idx, base, size);
217 }
218 
219 template <unsigned BUSWIDTH> void router<BUSWIDTH>::add_target_range(std::string name, uint64_t base, uint64_t size, bool remap) {
220  auto it = target_name_lut.find(name);
221 #ifndef NDEBUG
222 #if(SYSTEMC_VERSION >= 20171012)
223  if(it == target_name_lut.end()) {
224  std::stringstream ss;
225  ss << "No target index entry for '" << name << "' found ";
226  ::sc_core::sc_assertion_failed(ss.str().c_str(), __FILE__, __LINE__);
227  }
228 #else
229  sc_assert(it != target_name_lut.end());
230 #endif
231 #endif
232  auto idx = it->second;
233  tranges[idx].base = base;
234  tranges[idx].size = size;
235  tranges[idx].remap = remap;
236  addr_decoder.addEntry(idx, base, size);
237 }
238 
239 template <unsigned BUSWIDTH> void router<BUSWIDTH>::b_transport(int i, tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) {
240  ::sc_dt::uint64 address = trans.get_address();
241  if(ibases[i]) {
242  address += ibases[i];
243  trans.set_address(address);
244  }
245  size_t idx = addr_decoder.getEntry(address);
246  if(idx == addr_decoder.null_entry) {
247  if(default_idx == std::numeric_limits<size_t>::max()) {
248  trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
249  return;
250  }
251  idx = default_idx;
252  } else {
253  // Modify address within transaction
254  trans.set_address(address - (tranges[idx].remap ? tranges[idx].base : 0));
255  }
256  // Forward transaction to appropriate target
257  mutexes[idx].lock();
258  initiator[idx]->b_transport(trans, delay);
259  mutexes[idx].unlock();
260 }
261 template <unsigned BUSWIDTH> bool router<BUSWIDTH>::get_direct_mem_ptr(int i, tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data) {
262  ::sc_dt::uint64 address = trans.get_address();
263  if(ibases[i]) {
264  address += ibases[i];
265  trans.set_address(address);
266  }
267  size_t idx = addr_decoder.getEntry(address);
268  if(idx == addr_decoder.null_entry) {
269  if(default_idx == std::numeric_limits<size_t>::max()) {
270  trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
271  return false;
272  }
273  idx = default_idx;
274  } else {
275  // Modify address within transaction
276  trans.set_address(address - (tranges[idx].remap ? tranges[idx].base : 0));
277  }
278  bool status = initiator[idx]->get_direct_mem_ptr(trans, dmi_data);
279  // Calculate DMI address of target in system address space
280  auto offset = tranges[idx].remap ? tranges[idx].base : 0;
281  dmi_data.set_start_address(dmi_data.get_start_address() - ibases[i] + offset);
282  dmi_data.set_end_address(dmi_data.get_end_address() - ibases[i] + offset);
283  return status;
284 }
285 template <unsigned BUSWIDTH> unsigned router<BUSWIDTH>::transport_dbg(int i, tlm::tlm_generic_payload& trans) {
286  ::sc_dt::uint64 address = trans.get_address();
287  if(ibases[i]) {
288  address += ibases[i];
289  trans.set_address(address);
290  }
291  size_t idx = addr_decoder.getEntry(address);
292  if(idx == addr_decoder.null_entry) {
293  if(default_idx == std::numeric_limits<size_t>::max()) {
294  trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
295  return 0;
296  }
297  idx = default_idx;
298  } else {
299  // Modify address within transaction
300  trans.set_address(address - (tranges[idx].remap ? tranges[idx].base : 0));
301  }
302  // Forward debug transaction to appropriate target
303  return initiator[idx]->transport_dbg(trans);
304 }
305 template <unsigned BUSWIDTH>
306 void router<BUSWIDTH>::invalidate_direct_mem_ptr(int id, ::sc_dt::uint64 start_range, ::sc_dt::uint64 end_range) {
307  // Reconstruct address range in system memory map
308  ::sc_dt::uint64 bw_start_range = start_range;
309  if(tranges[id].remap)
310  bw_start_range += tranges[id].base;
311  ::sc_dt::uint64 bw_end_range = end_range;
312  if(tranges[id].remap)
313  bw_end_range += tranges[id].base;
314  for(size_t i = 0; i < target.size(); ++i) {
315  target[i]->invalidate_direct_mem_ptr(bw_start_range - ibases[i], bw_end_range - ibases[i]);
316  }
317 }
318 
319 } // namespace scc
320 
321 #endif /* SYSC_AVR_ROUTER_H_ */
initiator ID recording TLM extension
a TLM2.0 router for loosly-timed (LT) models
Definition: router.h:40
void set_target_name(size_t idx, std::string name)
establish a mapping between socket name and socket index
Definition: router.h:114
void set_default_target(size_t idx)
define the default target socket
Definition: router.h:106
bool get_direct_mem_ptr(int i, tlm::tlm_generic_payload &trans, tlm::tlm_dmi &dmi_data)
tagged forward DMI method
Definition: router.h:261
router(const sc_core::sc_module_name &nm, unsigned slave_cnt=1, unsigned master_cnt=1)
constructs a router
Definition: router.h:186
unsigned transport_dbg(int i, tlm::tlm_generic_payload &trans)
tagged debug transaction method
Definition: router.h:285
sc_core::sc_vector< target_sckt > target
the array of target sockets
Definition: router.h:45
void set_initiator_base(size_t idx, uint64_t base)
define a base address of a socket
Definition: router.h:96
void set_target_range(size_t idx, uint64_t base, uint64_t size, bool remap=true)
establish a mapping between a socket and a target address range
Definition: router.h:212
void bind_target(TYPE &socket, size_t idx, uint64_t base, uint64_t size, bool remap=true)
bind the initiator socket of the router to some target giving a base and size
Definition: router.h:70
void add_target_range(std::string name, uint64_t base, uint64_t size, bool remap=true)
establish a mapping between a named socket and a target address range
Definition: router.h:219
sc_core::sc_vector< intor_sckt > initiator
the array of initiator sockets
Definition: router.h:47
void bind_target(TYPE &socket, size_t idx, std::string name)
bind the initiator socket of the router to some target and name it
Definition: router.h:83
void b_transport(int i, tlm::tlm_generic_payload &trans, sc_core::sc_time &delay)
tagged blocking transport method
Definition: router.h:239
void invalidate_direct_mem_ptr(int id, ::sc_dt::uint64 start_range, ::sc_dt::uint64 end_range)
tagged backward DMI method
Definition: router.h:306
initiator socket mixin
SCC SystemC utilities.
Definition: router.h:173