scc 2026.07
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/report.h>
22#include <scc/utilities.h>
23#include <sysc/utils/sc_vector.h>
24#include <tlm/scc/initiator_mixin.h>
25#include <tlm/scc/memory_map_collector.h>
26#include <tlm/scc/scv/tlm_rec_initiator_socket.h>
27#include <tlm/scc/scv/tlm_rec_target_socket.h>
28#include <tlm/scc/target_mixin.h>
29#include <tlm>
30#include <unordered_map>
31#include <util/range_lut.h>
32
33namespace scc {
42template <unsigned BUSWIDTH = LT, typename TARGET_SOCKET_TYPE = tlm::tlm_target_socket<BUSWIDTH>> struct router : sc_core::sc_module {
46 sc_core::sc_vector<target_sckt> target;
48 sc_core::sc_vector<intor_sckt> initiator;
58 router(const sc_core::sc_module_name& nm, size_t slave_cnt = 1, size_t master_cnt = 1, bool check_overlap_on_add_target = false);
59
60 ~router() = default;
72 template <typename TYPE> void bind_target(TYPE& socket, size_t idx, uint64_t base, uint64_t size, bool remap = true) {
73 set_target_range(idx, base, size, remap);
74 initiator[idx].bind(socket);
75 }
76
85 template <typename TYPE> void bind_target(TYPE& socket, size_t idx, std::string name) {
86 set_target_name(idx, name);
87 initiator[idx].bind(socket);
88 }
89
98 void set_initiator_base(size_t idx, uint64_t base) { ibases[idx] = base; }
108 void set_default_target(size_t idx) { default_idx = idx; }
116 void set_target_name(size_t idx, std::string name) { target_name_lut.insert(std::make_pair(name, idx)); }
126 void add_target_range(std::string name, uint64_t base, uint64_t size, bool remap = true);
136 void set_target_range(size_t idx, uint64_t base, uint64_t size, bool remap = true);
143 void set_warn_on_address_error(bool enable) { warn_on_address_error = enable; }
152 void b_transport(int i, tlm::tlm_generic_payload& trans, sc_core::sc_time& delay);
162 bool get_direct_mem_ptr(int i, tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data);
170 unsigned transport_dbg(int i, tlm::tlm_generic_payload& trans);
179 void invalidate_direct_mem_ptr(int id, ::sc_dt::uint64 start_range, ::sc_dt::uint64 end_range);
180
185 void end_of_elaboration() override;
186
187protected:
188 struct range_entry {
189 uint64_t base, size;
190 bool remap;
191 };
192 size_t default_idx = std::numeric_limits<size_t>::max();
193 std::vector<uint64_t> ibases;
194 std::vector<range_entry> tranges;
195 std::vector<sc_core::sc_mutex> mutexes;
196 util::range_lut<unsigned> addr_decoder;
197 std::unordered_map<std::string, size_t> target_name_lut;
198 bool check_overlap_on_add_target;
199 bool warn_on_address_error{false};
200};
201
202template <unsigned BUSWIDTH, typename TARGET_SOCKET_TYPE>
203router<BUSWIDTH, TARGET_SOCKET_TYPE>::router(const sc_core::sc_module_name& nm, size_t slave_cnt, size_t master_cnt,
204 bool check_overlap_on_add_target)
205: sc_module(nm)
206, target("target", master_cnt)
207, initiator("intor", slave_cnt)
208, ibases(master_cnt)
209, tranges(slave_cnt)
210, mutexes(slave_cnt)
211, addr_decoder(std::numeric_limits<unsigned>::max())
212, check_overlap_on_add_target(check_overlap_on_add_target) {
213 for(size_t i = 0; i < target.size(); ++i) {
214 target[i].register_b_transport(
215 [this, i](tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) -> void { this->b_transport(i, trans, delay); });
216 target[i].register_get_direct_mem_ptr([this, i](tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data) -> bool {
217 return this->get_direct_mem_ptr(i, trans, dmi_data);
218 });
219 target[i].register_transport_dbg([this, i](tlm::tlm_generic_payload& trans) -> unsigned { return this->transport_dbg(i, trans); });
220 ibases[i] = 0ULL;
221 }
222 for(size_t i = 0; i < initiator.size(); ++i) {
223 initiator[i].register_invalidate_direct_mem_ptr([this, i](::sc_dt::uint64 start_range, ::sc_dt::uint64 end_range) -> void {
224 this->invalidate_direct_mem_ptr(i, start_range, end_range);
225 });
226 tranges[i].base = 0ULL;
227 tranges[i].size = 0ULL;
228 tranges[i].remap = false;
229 }
230}
231
232template <unsigned BUSWIDTH, typename TARGET_SOCKET_TYPE>
233void router<BUSWIDTH, TARGET_SOCKET_TYPE>::set_target_range(size_t idx, uint64_t base, uint64_t size, bool remap) {
234 tranges[idx].base = base;
235 tranges[idx].size = size;
236 tranges[idx].remap = remap;
237 addr_decoder.addEntry(idx, base, size);
238 if(check_overlap_on_add_target)
239 addr_decoder.validate();
240}
241
242template <unsigned BUSWIDTH, typename TARGET_SOCKET_TYPE>
243void router<BUSWIDTH, TARGET_SOCKET_TYPE>::add_target_range(std::string name, uint64_t base, uint64_t size, bool remap) {
244 auto it = target_name_lut.find(name);
245#ifndef NDEBUG
246#if(SYSTEMC_VERSION >= 20171012)
247 if(it == target_name_lut.end()) {
248 std::stringstream ss;
249 ss << "No target index entry for '" << name << "' found ";
250 ::sc_core::sc_assertion_failed(ss.str().c_str(), __FILE__, __LINE__);
251 }
252#else
253 sc_assert(it != target_name_lut.end());
254#endif
255#endif
256 auto idx = it->second;
257 tranges[idx].base = base;
258 tranges[idx].size = size;
259 tranges[idx].remap = remap;
260 addr_decoder.addEntry(idx, base, size);
261 if(check_overlap_on_add_target)
262 addr_decoder.validate();
263}
264
265template <unsigned BUSWIDTH, typename TARGET_SOCKET_TYPE>
266void router<BUSWIDTH, TARGET_SOCKET_TYPE>::b_transport(int i, tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) {
267 ::sc_dt::uint64 address = trans.get_address();
268 if(ibases[i]) {
269 address += ibases[i];
270 trans.set_address(address);
271 }
272 size_t idx = addr_decoder.getEntry(address);
273 if(idx == addr_decoder.null_entry) {
274 if(default_idx == std::numeric_limits<size_t>::max()) {
275 if(warn_on_address_error) {
276 SCCWARN(SCMOD) << "target address=0x" << std::hex << address << " not found for "
277 << (trans.get_command() == tlm::TLM_READ_COMMAND ? "read" : "write") << " transaction.";
278 }
279 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
280 return;
281 }
282 idx = default_idx;
283 } else {
284 // Modify address within transaction
285 trans.set_address(address - (tranges[idx].remap ? tranges[idx].base : 0));
286 }
287 // Forward transaction to appropriate target
288 mutexes[idx].lock();
289 initiator[idx]->b_transport(trans, delay);
290 mutexes[idx].unlock();
291}
292template <unsigned BUSWIDTH, typename TARGET_SOCKET_TYPE>
293bool router<BUSWIDTH, TARGET_SOCKET_TYPE>::get_direct_mem_ptr(int i, tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data) {
294 ::sc_dt::uint64 address = trans.get_address();
295 if(ibases[i]) {
296 address += ibases[i];
297 trans.set_address(address);
298 }
299 size_t idx = addr_decoder.getEntry(address);
300 if(idx == addr_decoder.null_entry) {
301 if(default_idx == std::numeric_limits<size_t>::max()) {
302 if(warn_on_address_error) {
303 SCCWARN(SCMOD) << "target address=0x" << std::hex << address << " not found for "
304 << (trans.get_command() == tlm::TLM_READ_COMMAND ? "read" : "write") << " transaction.";
305 }
306 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
307 return false;
308 }
309 idx = default_idx;
310 }
311 // Modify address within transaction
312 auto offset = tranges[idx].remap ? tranges[idx].base : 0;
313 trans.set_address(address - offset);
314 bool status = initiator[idx]->get_direct_mem_ptr(trans, dmi_data);
315 // make sure end address does not exceed size
316 auto const remap_base = tranges[idx].remap ? 0 : tranges[idx].base;
317 auto const remap_size = tranges[idx].size;
318 auto const remap_end = remap_base + remap_size;
319 auto const remap_end_overflow = remap_end < remap_base;
320 if(remap_size && !remap_end_overflow && dmi_data.get_end_address() >= remap_end)
321 dmi_data.set_end_address(remap_end - 1);
322 // Calculate DMI address of target in system address space
323 dmi_data.set_start_address(dmi_data.get_start_address() - ibases[i] + offset);
324 dmi_data.set_end_address(dmi_data.get_end_address() - ibases[i] + offset);
325 return status;
326}
327template <unsigned BUSWIDTH, typename TARGET_SOCKET_TYPE>
328unsigned router<BUSWIDTH, TARGET_SOCKET_TYPE>::transport_dbg(int i, tlm::tlm_generic_payload& trans) {
329 if(trans.get_command() == tlm::TLM_IGNORE_COMMAND) {
330 if(auto ext = trans.get_extension<tlm::scc::memory_map_extension>()) {
331 ext->node.name = name();
332 auto start_addr = ext->node.start;
333 for(auto e : addr_decoder) {
334 auto addr = ext->offset + e.first;
335 auto entry = e.second;
336 switch(entry.type) {
337 case util::range_lut<unsigned>::BEGIN_RANGE:
338 start_addr = addr;
339 break;
340 case util::range_lut<unsigned>::SINGLE_BYTE_RANGE:
341 start_addr = addr;
342 case util::range_lut<unsigned>::END_RANGE: {
343 ext->node.elemets.emplace_back(start_addr, ext->offset + addr);
344 auto new_ext = tlm::scc::memory_map_extension(ext->node.elemets.back());
345 new_ext.offset = start_addr;
346 trans.set_extension(&new_ext);
347 initiator[entry.index]->transport_dbg(trans);
348 trans.set_extension(ext);
349 break;
350 }
351 }
352 }
353 return 0;
354 }
355 }
356 ::sc_dt::uint64 address = trans.get_address();
357 if(ibases[i]) {
358 address += ibases[i];
359 trans.set_address(address);
360 }
361 size_t idx = addr_decoder.getEntry(address);
362 if(idx == addr_decoder.null_entry) {
363 if(default_idx == std::numeric_limits<size_t>::max()) {
364 if(warn_on_address_error) {
365 SCCWARN(SCMOD) << "target address=0x" << std::hex << address << " not found for "
366 << (trans.get_command() == tlm::TLM_READ_COMMAND ? "read" : "write") << " transaction.";
367 }
368 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
369 return 0;
370 }
371 idx = default_idx;
372 } else {
373 // Modify address within transaction
374 trans.set_address(address - (tranges[idx].remap ? tranges[idx].base : 0));
375 }
376 // Forward debug transaction to appropriate target
377 return initiator[idx]->transport_dbg(trans);
378}
379template <unsigned BUSWIDTH, typename TARGET_SOCKET_TYPE>
380void router<BUSWIDTH, TARGET_SOCKET_TYPE>::invalidate_direct_mem_ptr(int id, ::sc_dt::uint64 start_range, ::sc_dt::uint64 end_range) {
381 // Reconstruct address range in system memory map
382 ::sc_dt::uint64 bw_start_range = start_range;
383 if(tranges[id].remap)
384 bw_start_range += tranges[id].base;
385 ::sc_dt::uint64 bw_end_range = end_range;
386 if(tranges[id].remap)
387 bw_end_range += tranges[id].base;
388 for(size_t i = 0; i < target.size(); ++i) {
389 target[i]->invalidate_direct_mem_ptr(bw_start_range - ibases[i], bw_end_range - ibases[i]);
390 }
391}
392template <unsigned BUSWIDTH, typename TARGET_SOCKET_TYPE> void router<BUSWIDTH, TARGET_SOCKET_TYPE>::end_of_elaboration() {
393 addr_decoder.validate();
394}
395
396} // namespace scc
397
398#endif /* SYSC_AVR_ROUTER_H_ */
initiator socket mixin
range based lookup table
Definition range_lut.h:37
SCC TLM utilities.
Definition router.h:188
router(const sc_core::sc_module_name &nm, size_t slave_cnt=1, size_t master_cnt=1, bool check_overlap_on_add_target=false)
constructs a router
Definition router.h:203
unsigned transport_dbg(int i, tlm::tlm_generic_payload &trans)
tagged debug transaction method
Definition router.h:328
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:85
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:72
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:243
void set_target_name(size_t idx, std::string name)
establish a mapping between socket name and socket index
Definition router.h:116
void set_warn_on_address_error(bool enable)
enable warning message on address not found error
Definition router.h:143
void set_default_target(size_t idx)
define the default target socket
Definition router.h:108
bool get_direct_mem_ptr(int i, tlm::tlm_generic_payload &trans, tlm::tlm_dmi &dmi_data)
tagged forward DMI method
Definition router.h:293
sc_core::sc_vector< target_sckt > target
the array of target sockets
Definition router.h:46
void invalidate_direct_mem_ptr(int id, ::sc_dt::uint64 start_range, ::sc_dt::uint64 end_range)
tagged backward DMI method
Definition router.h:380
void end_of_elaboration() override
tagged end of elaboration callback.
Definition router.h:392
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:233
void set_initiator_base(size_t idx, uint64_t base)
define a base address of a socket
Definition router.h:98
void b_transport(int i, tlm::tlm_generic_payload &trans, sc_core::sc_time &delay)
tagged blocking transport method
Definition router.h:266
sc_core::sc_vector< intor_sckt > initiator
the array of initiator sockets
Definition router.h:48