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