116 using TargetSocket = tlm::tlm_base_target_socket_b<BUSWIDTH, tlm::tlm_fw_transport_if<>,
117 tlm::tlm_bw_transport_if<>>;
119 using InitiatorSocket = tlm::tlm_base_initiator_socket_b<BUSWIDTH, tlm::tlm_fw_transport_if<>,
120 tlm::tlm_bw_transport_if<>>;
124 using initiator_socket_type =
typename gs::router<
148 template <
typename TargetInfoType>
161 std::shared_ptr<TargetInfoType> target;
163 Region(
uint64_t s,
uint64_t e, std::shared_ptr<TargetInfoType>
t): start(s), end(
e), target(
t) {}
167 std::map<uint64_t, Region> m_regions;
204 m_regions.erase(
key);
210 std::shared_ptr<TargetInfoType> target;
214 : start(s), end(
e), target(
t), priority(
t->priority)
246 std::shared_ptr<TargetInfoType>
best_target =
nullptr;
288 std::stringstream
ss;
289 ss <<
"Region '" <<
interval.target->name <<
"' (0x" << std::hex <<
interval.start <<
"-0x"
291 <<
") is completely shadowed by higher priority regions and will never be accessed";
299 addressMap() =
default;
315 void add(std::shared_ptr<TargetInfoType>
t_info)
320 split_and_resolve(start, end,
t_info);
349 auto it = m_regions.upper_bound(address);
350 if (
it != m_regions.begin()) {
356 m_cache.put(address,
it->second.target, size);
357 return it->second.target;
362 m_cache.put(address,
nullptr, size);
382 std::shared_ptr<TargetInfoType> find_region(
uint64_t addr, tlm::tlm_dmi& dmi)
385 auto it = m_regions.upper_bound(addr);
386 if (
it != m_regions.begin()) {
393 std::shared_ptr<TargetInfoType> target =
it->second.target;
394 dmi.set_start_address(
it->second.start);
395 dmi.set_end_address(
it->second.end - 1);
405 it = m_regions.upper_bound(addr);
406 if (
it != m_regions.begin()) {
408 if (
it->second.end <= addr) {
414 it = m_regions.upper_bound(addr);
415 if (
it != m_regions.end()) {
432 hits = m_cache.get_hits();
433 misses = m_cache.get_misses();
439 void reset_cache_stats() { m_cache.reset_stats(); }
442 SCP_LOGGER_VECTOR(
D);
444 SCP_LOGGER((
DMI),
"dmi");
447#if defined(THREAD_SAFE) and THREAD_SAFE
453 std::set<int> initiators;
456 dmi_info(tlm::tlm_dmi&
_dmi) { dmi =
_dmi; }
459 std::map<uint64_t, dmi_info> m_dmi_info_map;
471 dmi_info* in_dmi_cache(tlm::tlm_dmi& dmi)
473 auto it = m_dmi_info_map.find(dmi.get_start_address());
474 if (
it != m_dmi_info_map.end()) {
475 if (
it->second.dmi.get_end_address() != dmi.get_end_address()) {
479 std::stringstream
ss;
480 ss <<
"Can't handle that: DMI overlap with differing end address (0x" << std::hex
481 <<
it->second.dmi.get_end_address() <<
" vs 0x" << dmi.get_end_address() <<
")";
484 return &(
it->second);
486 auto insit = m_dmi_info_map.emplace(dmi.get_start_address(), dmi_info(dmi));
487 return &(
insit.first->second);
500 void record_dmi(
int id, tlm::tlm_dmi& dmi)
502 auto it = m_dmi_info_map.find(dmi.get_start_address());
503 if (
it != m_dmi_info_map.end()) {
504 if (
it->second.dmi.get_end_address() != dmi.get_end_address()) {
505 SCP_WARN((
DMI)) <<
"A new DMI overlaps with an old one, invalidating the old one";
506 invalidate_direct_mem_ptr_ts(0, dmi.get_start_address(),
507 dmi.get_end_address());
511 dmi_info*
dinfo = in_dmi_cache(dmi);
512 dinfo->initiators.insert(
id);
524 void register_boundto(std::string s)
override
528 std::shared_ptr<target_info>
ti_ptr = std::make_shared<target_info>();
530 ti_ptr->index = bound_targets.size();
534 std::string
tmp = name();
536 for (
i = 0;
i <
tmp.length();
i++)
537 if (s[
i] !=
tmp[
i])
break;
538 ti_ptr->shortname = s.substr(
i);
539 bound_targets.push_back(
ti_ptr);
552 std::string txn_tostring(
const target_info* ti, tlm::tlm_generic_payload&
trans)
554 std::stringstream
info;
555 const char* cmd =
"UNKOWN";
556 switch (
trans.get_command()) {
557 case tlm::TLM_IGNORE_COMMAND:
560 case tlm::TLM_WRITE_COMMAND:
563 case tlm::TLM_READ_COMMAND:
569 <<
"0x" << std::hex <<
trans.get_address();
570 info <<
" len:" <<
trans.get_data_length();
571 unsigned char* ptr =
trans.get_data_ptr();
572 if ((
trans.get_command() == tlm::TLM_READ_COMMAND &&
trans.get_response_status() == tlm::TLM_OK_RESPONSE) ||
573 (
trans.get_command() == tlm::TLM_WRITE_COMMAND &&
574 trans.get_response_status() == tlm::TLM_INCOMPLETE_RESPONSE)) {
576 for (
int i =
trans.get_data_length();
i;
i--) {
577 info << std::setw(2) << std::setfill(
'0') << std::hex << (
unsigned int)(ptr[
i - 1]);
580 info <<
" " <<
trans.get_response_string() <<
" ";
581 for (
int i = 0;
i < tlm::max_num_extensions();
i++) {
582 if (
trans.get_extension(
i)) {
583 info <<
" extn:" <<
i;
599 std::vector<std::shared_ptr<target_info>> alias_targets;
603 std::vector<std::shared_ptr<target_info>> id_targets;
606 std::vector<PathIDExtension*> m_pathIDPool;
607#if defined(THREAD_SAFE) and THREAD_SAFE
621 void stamp_txn(
int id, tlm::tlm_generic_payload& txn)
624 txn.get_extension(
ext);
625 if (
ext ==
nullptr) {
626#if defined(THREAD_SAFE) and THREAD_SAFE
629 if (m_pathIDPool.size() == 0) {
632 ext = m_pathIDPool.back();
633 m_pathIDPool.pop_back();
635 txn.set_extension(
ext);
649 void unstamp_txn(
int id, tlm::tlm_generic_payload& txn)
652 txn.get_extension(
ext);
656 if (
ext->size() == 0) {
657#if defined(THREAD_SAFE) and THREAD_SAFE
660 txn.clear_extension(
ext);
661 m_pathIDPool.push_back(
ext);
677 void b_transport(
int id, tlm::tlm_generic_payload&
trans, sc_core::sc_time& delay)
679 sc_dt::uint64 addr =
trans.get_address();
682 SCP_WARN(())(
"Attempt to access unknown register at offset 0x{:x}", addr);
683 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
687 stamp_txn(
id,
trans);
689 SCP_TRACE((
D[ti->index]), ti->name) <<
"Start b_transport :" << txn_tostring(ti.get(),
trans);
691 if (
trans.get_response_status() >= tlm::TLM_INCOMPLETE_RESPONSE) {
692 if (ti->use_offset)
trans.set_address(addr - ti->address);
696 if (ti->use_offset)
trans.set_address(addr);
699 SCP_TRACE((
D[ti->index]), ti->name) <<
"Completed b_transport :" << txn_tostring(ti.get(),
trans);
701 unstamp_txn(
id,
trans);
715 unsigned int transport_dbg(
int id, tlm::tlm_generic_payload&
trans)
720 sc_dt::uint64 addr =
trans.get_address();
723 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
727 if (ti->use_offset)
trans.set_address(addr - ti->address);
728 SCP_TRACE((
D[ti->index]), ti->name) <<
"calling dbg_transport : " << scp::scp_txn_tostring(
trans);
730 if (ti->use_offset)
trans.set_address(addr);
746 bool get_direct_mem_ptr(
int id, tlm::tlm_generic_payload&
trans, tlm::tlm_dmi& dmi_data)
751 sc_dt::uint64 addr =
trans.get_address();
756 UnderlyingDMITlmExtension*
u_dmi;
761 (ti ?
"mapped" :
"nomap"));
762 u_dmi->add_dmi(
this,
dmi_data_hole, (ti ? gs::tlm_dmi_ex::dmi_mapped :
gs::tlm_dmi_ex::dmi_nomap));
768#if defined(THREAD_SAFE_REENTRANT) and THREAD_SAFE_REENTRANT
776 if (ti->use_offset)
trans.set_address(addr - ti->address);
777 SCP_TRACE((
D[ti->index]), ti->name) <<
"calling get_direct_mem_ptr : " << scp::scp_txn_tostring(
trans);
779 if (ti->use_offset)
trans.set_address(addr);
781 if (ti->use_offset) {
782 assert(dmi_data.get_start_address() < ti->size);
783 dmi_data.set_start_address(ti->address + dmi_data.get_start_address());
784 dmi_data.set_end_address(ti->address + dmi_data.get_end_address());
787 if (dmi_data.get_start_address() <
dmi_data_hole.get_start_address()) {
788 dmi_data.set_dmi_ptr(dmi_data.get_dmi_ptr() +
789 (
dmi_data_hole.get_start_address() - dmi_data.get_start_address()));
790 dmi_data.set_start_address(
dmi_data_hole.get_start_address());
792 if (dmi_data.get_end_address() >
dmi_data_hole.get_end_address()) {
795 record_dmi(
id, dmi_data);
798 (
"Providing DMI (status {:x}) {:x} - {:x}", status, dmi_data.get_start_address(), dmi_data.get_end_address());
799#if defined(THREAD_SAFE) and THREAD_SAFE
815 void invalidate_direct_mem_ptr(
int id, sc_dt::uint64 start, sc_dt::uint64 end)
817 if (id_targets[
id]->use_offset) {
818 start = id_targets[id]->address + start;
819 end = id_targets[id]->address + end;
821#if defined(THREAD_SAFE) and THREAD_SAFE
824 invalidate_direct_mem_ptr_ts(
id, start, end);
838 void invalidate_direct_mem_ptr_ts(
int id, sc_dt::uint64 start, sc_dt::uint64 end)
840 auto it = m_dmi_info_map.upper_bound(start);
842 if (
it != m_dmi_info_map.begin()) {
849 std::set<int> initiators;
851 while (
it != m_dmi_info_map.end()) {
852 tlm::tlm_dmi& r =
it->second.dmi;
854 if (r.get_start_address() > end) {
859 if (r.get_end_address() < start) {
865 SCP_TRACE((
DMI)) <<
"Queueing initiator " <<
t <<
" for invalidation, its bounds are [0x" << std::hex
866 <<
it->second.dmi.get_start_address() <<
" - 0x" <<
it->second.dmi.get_end_address()
868 initiators.insert(
t);
870 it = m_dmi_info_map.erase(
it);
872 for (
auto t : initiators) {
873 SCP_INFO((
DMI)) <<
"Invalidating initiator " <<
t <<
" [0x" << std::hex << start <<
" - 0x" << end <<
"]";
893 sc_dt::uint64 addr =
trans.get_address();
894 return m_address_map.find(addr,
trans.get_data_length());
904 if (!lazy_init) lazy_initialize();
909 std::atomic<bool> m_initialized{
false };
911#if defined(THREAD_SAFE) and THREAD_SAFE
914 std::list<std::string> get_matching_children(cci::cci_broker_handle
broker,
const std::string&
prefix,
915 const std::vector<cci_name_value_pair>&
list)
919 for (
const auto&
p :
list) {
920 if (
p.first.find(
prefix) == 0) {
944 void lazy_initialize()
override
947 if (m_initialized.load(std::memory_order_acquire)) {
951#if defined(THREAD_SAFE) and THREAD_SAFE
957 if (m_initialized.load(std::memory_order_relaxed)) {
964 return iv.first.find(
".aliases.") != std::string::npos;
968 for (
auto&
ti_ptr : bound_targets) {
969 std::string name =
ti_ptr->name;
974 m_broker.get_preset_cci_value(
ti_ptr->name +
".address").is_number()) {
976 (
"The configuration alias provided ({}) will be ignored as a valid address is also provided.",
src);
978 if (
src[0] ==
'&')
src = (
src.erase(0, 1)) +
".target_socket";
979 if (!
m_broker.has_preset_value(
src +
".address")) {
980 std::stringstream
ss;
981 ss <<
"The configuration alias provided (" <<
src <<
") can not be found.";
989 ti_ptr->address = gs::cci_get<uint64_t>(
m_broker, name +
".address");
991 ti_ptr->use_offset = gs::cci_get_d<bool>(
m_broker, name +
".relative_addresses",
true);
992 ti_ptr->chained = gs::cci_get_d<bool>(
m_broker, name +
".chained",
false);
993 ti_ptr->priority = gs::cci_get_d<uint32_t>(
m_broker, name +
".priority", 0);
996 <<
"Address map " <<
ti_ptr->name <<
" at address "
997 <<
"0x" << std::hex <<
ti_ptr->address <<
" size "
998 <<
"0x" << std::hex <<
ti_ptr->size << (
ti_ptr->use_offset ?
" (with relative address) " :
" ")
999 <<
"priority : " <<
ti_ptr->priority;
1003 m_address_map.add(
ti_ptr);
1021 id_targets.push_back(
ti_ptr);
1025 m_initialized.store(
true, std::memory_order_release);
1029 cci::cci_param<bool> lazy_init;
1041 explicit router(
const sc_core::sc_module_name&
nm, cci::cci_broker_handle
broker = cci::cci_get_broker())
1042 : sc_core::sc_module(
nm)
1044 , target_socket(
"target_socket")
1047 , lazy_init(
"lazy_init",
false,
"Initialize the router lazily (eg. during simulation rather than BEOL)")
1054 initiator_socket.register_invalidate_direct_mem_ptr(
this,
1056 SCP_DEBUG((
DMI)) <<
"router Initializing DMI SCP reporting";
1083 unsigned int priority = 0)
1086 if (!m_broker.has_preset_value(s +
".address")) {
1087 m_broker.set_preset_cci_value(s +
".address", cci::cci_value(address));
1089 if (!m_broker.has_preset_value(s +
".size")) {
1090 m_broker.set_preset_cci_value(s +
".size", cci::cci_value(size));
1092 if (!m_broker.has_preset_value(s +
".relative_addresses")) {
1093 m_broker.set_preset_cci_value(s +
".relative_addresses", cci::cci_value(
masked));
1095 if (!m_broker.has_preset_value(s +
".priority")) {
1096 SCP_DEBUG(())(
"Setting prio to {}", priority);
1097 m_broker.set_preset_cci_value(s +
".priority", cci::cci_value(priority));
1099 initiator_socket.bind(
t);
1113 (
i.get_base_port())(target_socket.get_base_interface());
1114 (target_socket.get_base_port())(
i.get_base_interface());