17#ifndef _SYSC_ROUTER_H_
18#define _SYSC_ROUTER_H_
21#include <scc/report.h>
22#include <scc/utilities.h>
23#include <sysc/utils/sc_vector.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>
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;
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);
71 template <
typename TYPE>
void bind_target(TYPE& socket,
size_t idx, uint64_t base, uint64_t size,
bool remap =
true) {
84 template <
typename TYPE>
void bind_target(TYPE& socket,
size_t idx, std::string name) {
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);
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);
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;
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};
201template <
unsigned BUSWIDTH,
typename TARGET_SOCKET_TYPE>
203 bool check_overlap_on_add_target)
205,
target(
"target", master_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 {
218 target[i].register_transport_dbg([
this, i](tlm::tlm_generic_payload& trans) ->
unsigned {
return this->
transport_dbg(i, trans); });
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 {
225 tranges[i].base = 0ULL;
226 tranges[i].size = 0ULL;
227 tranges[i].remap =
false;
231template <
unsigned BUSWIDTH,
typename TARGET_SOCKET_TYPE>
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();
241template <
unsigned BUSWIDTH,
typename TARGET_SOCKET_TYPE>
243 auto it = target_name_lut.find(name);
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__);
252 sc_assert(it != target_name_lut.end());
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();
264template <
unsigned BUSWIDTH,
typename TARGET_SOCKET_TYPE>
266 ::sc_dt::uint64 address = trans.get_address();
268 address += ibases[i];
269 trans.set_address(address);
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.";
278 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
284 trans.set_address(address - (tranges[idx].remap ? tranges[idx].base : 0));
288 initiator[idx]->b_transport(trans, delay);
289 mutexes[idx].unlock();
291template <
unsigned BUSWIDTH,
typename TARGET_SOCKET_TYPE>
293 ::sc_dt::uint64 address = trans.get_address();
295 address += ibases[i];
296 trans.set_address(address);
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.";
305 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
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);
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);
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);
323template <
unsigned BUSWIDTH,
typename TARGET_SOCKET_TYPE>
325 ::sc_dt::uint64 address = trans.get_address();
327 address += ibases[i];
328 trans.set_address(address);
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.";
337 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
343 trans.set_address(address - (tranges[idx].remap ? tranges[idx].base : 0));
346 return initiator[idx]->transport_dbg(trans);
348template <
unsigned BUSWIDTH,
typename TARGET_SOCKET_TYPE>
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]);
362 addr_decoder.validate();
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
unsigned transport_dbg(int i, tlm::tlm_generic_payload &trans)
tagged debug transaction method
void bind_target(TYPE &socket, size_t idx, std::string name)
bind the initiator socket of the router to some target and name it
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
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
void set_target_name(size_t idx, std::string name)
establish a mapping between socket name and socket index
void set_warn_on_address_error(bool enable)
enable warning message on address not found error
void set_default_target(size_t idx)
define the default target socket
bool get_direct_mem_ptr(int i, tlm::tlm_generic_payload &trans, tlm::tlm_dmi &dmi_data)
tagged forward DMI method
sc_core::sc_vector< target_sckt > target
the array of target sockets
void invalidate_direct_mem_ptr(int id, ::sc_dt::uint64 start_range, ::sc_dt::uint64 end_range)
tagged backward DMI method
void end_of_elaboration() override
tagged end of elaboration callback.
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
void set_initiator_base(size_t idx, uint64_t base)
define a base address of a socket
void b_transport(int i, tlm::tlm_generic_payload &trans, sc_core::sc_time &delay)
tagged blocking transport method
sc_core::sc_vector< intor_sckt > initiator
the array of initiator sockets