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()) {
392 std::shared_ptr<TargetInfoType> target =
it->second.target;
393 dmi.set_start_address(target->address);
394 dmi.set_end_address(target->address + target->size - 1);
404 it = m_regions.upper_bound(addr);
405 if (
it != m_regions.begin()) {
407 if (
it->second.end <= addr) {
413 it = m_regions.upper_bound(addr);
414 if (
it != m_regions.end()) {
431 hits = m_cache.get_hits();
432 misses = m_cache.get_misses();
438 void reset_cache_stats() { m_cache.reset_stats(); }
441 SCP_LOGGER_VECTOR(
D);
443 SCP_LOGGER((
DMI),
"dmi");
446#if defined(THREAD_SAFE) and THREAD_SAFE
452 std::set<int> initiators;
455 dmi_info(tlm::tlm_dmi&
_dmi) { dmi =
_dmi; }
458 std::map<uint64_t, dmi_info> m_dmi_info_map;
470 dmi_info* in_dmi_cache(tlm::tlm_dmi& dmi)
472 auto it = m_dmi_info_map.find(dmi.get_start_address());
473 if (
it != m_dmi_info_map.end()) {
474 if (
it->second.dmi.get_end_address() != dmi.get_end_address()) {
475 std::stringstream
ss;
476 ss <<
"Can't handle that: DMI overlap with differing end address (0x" << std::hex
477 <<
it->second.dmi.get_end_address() <<
" vs 0x" << dmi.get_end_address() <<
")";
480 return &(
it->second);
482 auto insit = m_dmi_info_map.emplace(dmi.get_start_address(), dmi_info(dmi));
483 return &(
insit.first->second);
496 void record_dmi(
int id, tlm::tlm_dmi& dmi)
498 auto it = m_dmi_info_map.find(dmi.get_start_address());
499 if (
it != m_dmi_info_map.end()) {
500 if (
it->second.dmi.get_end_address() != dmi.get_end_address()) {
501 SCP_WARN((
DMI)) <<
"A new DMI overlaps with an old one, invalidating the old one";
502 invalidate_direct_mem_ptr_ts(0, dmi.get_start_address(),
503 dmi.get_end_address());
507 dmi_info*
dinfo = in_dmi_cache(dmi);
508 dinfo->initiators.insert(
id);
520 void register_boundto(std::string s)
override
524 std::shared_ptr<target_info>
ti_ptr = std::make_shared<target_info>();
526 ti_ptr->index = bound_targets.size();
530 std::string
tmp = name();
532 for (
i = 0;
i <
tmp.length();
i++)
533 if (s[
i] !=
tmp[
i])
break;
534 ti_ptr->shortname = s.substr(
i);
535 bound_targets.push_back(
ti_ptr);
548 std::string txn_tostring(
const target_info* ti, tlm::tlm_generic_payload&
trans)
550 std::stringstream
info;
551 const char* cmd =
"UNKOWN";
552 switch (
trans.get_command()) {
553 case tlm::TLM_IGNORE_COMMAND:
556 case tlm::TLM_WRITE_COMMAND:
559 case tlm::TLM_READ_COMMAND:
565 <<
"0x" << std::hex <<
trans.get_address();
566 info <<
" len:" <<
trans.get_data_length();
567 unsigned char* ptr =
trans.get_data_ptr();
568 if ((
trans.get_command() == tlm::TLM_READ_COMMAND &&
trans.get_response_status() == tlm::TLM_OK_RESPONSE) ||
569 (
trans.get_command() == tlm::TLM_WRITE_COMMAND &&
570 trans.get_response_status() == tlm::TLM_INCOMPLETE_RESPONSE)) {
572 for (
int i =
trans.get_data_length();
i;
i--) {
573 info << std::setw(2) << std::setfill(
'0') << std::hex << (
unsigned int)(ptr[
i - 1]);
576 info <<
" " <<
trans.get_response_string() <<
" ";
577 for (
int i = 0;
i < tlm::max_num_extensions();
i++) {
578 if (
trans.get_extension(
i)) {
579 info <<
" extn:" <<
i;
595 std::vector<std::shared_ptr<target_info>> alias_targets;
599 std::vector<std::shared_ptr<target_info>> id_targets;
602 std::vector<PathIDExtension*> m_pathIDPool;
603#if defined(THREAD_SAFE) and THREAD_SAFE
617 void stamp_txn(
int id, tlm::tlm_generic_payload& txn)
620 txn.get_extension(
ext);
621 if (
ext ==
nullptr) {
622#if defined(THREAD_SAFE) and THREAD_SAFE
625 if (m_pathIDPool.size() == 0) {
628 ext = m_pathIDPool.back();
629 m_pathIDPool.pop_back();
631 txn.set_extension(
ext);
645 void unstamp_txn(
int id, tlm::tlm_generic_payload& txn)
648 txn.get_extension(
ext);
652 if (
ext->size() == 0) {
653#if defined(THREAD_SAFE) and THREAD_SAFE
656 txn.clear_extension(
ext);
657 m_pathIDPool.push_back(
ext);
673 void b_transport(
int id, tlm::tlm_generic_payload&
trans, sc_core::sc_time& delay)
675 sc_dt::uint64 addr =
trans.get_address();
678 SCP_WARN(())(
"Attempt to access unknown register at offset 0x{:x}", addr);
679 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
683 stamp_txn(
id,
trans);
685 SCP_TRACE((
D[ti->index]), ti->name) <<
"Start b_transport :" << txn_tostring(ti.get(),
trans);
687 if (
trans.get_response_status() >= tlm::TLM_INCOMPLETE_RESPONSE) {
688 if (ti->use_offset)
trans.set_address(addr - ti->address);
692 if (ti->use_offset)
trans.set_address(addr);
695 SCP_TRACE((
D[ti->index]), ti->name) <<
"Completed b_transport :" << txn_tostring(ti.get(),
trans);
697 unstamp_txn(
id,
trans);
711 unsigned int transport_dbg(
int id, tlm::tlm_generic_payload&
trans)
716 sc_dt::uint64 addr =
trans.get_address();
719 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
723 if (ti->use_offset)
trans.set_address(addr - ti->address);
724 SCP_TRACE((
D[ti->index]), ti->name) <<
"calling dbg_transport : " << scp::scp_txn_tostring(
trans);
726 if (ti->use_offset)
trans.set_address(addr);
742 bool get_direct_mem_ptr(
int id, tlm::tlm_generic_payload&
trans, tlm::tlm_dmi& dmi_data)
747 sc_dt::uint64 addr =
trans.get_address();
752 UnderlyingDMITlmExtension*
u_dmi;
757 (ti ?
"mapped" :
"nomap"));
758 u_dmi->add_dmi(
this,
dmi_data_hole, (ti ? gs::tlm_dmi_ex::dmi_mapped :
gs::tlm_dmi_ex::dmi_nomap));
764#if defined(THREAD_SAFE_REENTRANT) and THREAD_SAFE_REENTRANT
772 if (ti->use_offset)
trans.set_address(addr - ti->address);
773 SCP_TRACE((
D[ti->index]), ti->name) <<
"calling get_direct_mem_ptr : " << scp::scp_txn_tostring(
trans);
775 if (ti->use_offset)
trans.set_address(addr);
777 if (ti->use_offset) {
778 assert(dmi_data.get_start_address() < ti->size);
779 dmi_data.set_start_address(ti->address + dmi_data.get_start_address());
780 dmi_data.set_end_address(ti->address + dmi_data.get_end_address());
783 if (dmi_data.get_start_address() <
dmi_data_hole.get_start_address()) {
784 dmi_data.set_dmi_ptr(dmi_data.get_dmi_ptr() +
785 (
dmi_data_hole.get_start_address() - dmi_data.get_start_address()));
786 dmi_data.set_start_address(
dmi_data_hole.get_start_address());
788 if (dmi_data.get_end_address() >
dmi_data_hole.get_end_address()) {
791 record_dmi(
id, dmi_data);
794 (
"Providing DMI (status {:x}) {:x} - {:x}", status, dmi_data.get_start_address(), dmi_data.get_end_address());
795#if defined(THREAD_SAFE) and THREAD_SAFE
811 void invalidate_direct_mem_ptr(
int id, sc_dt::uint64 start, sc_dt::uint64 end)
813 if (id_targets[
id]->use_offset) {
814 start = id_targets[id]->address + start;
815 end = id_targets[id]->address + end;
817#if defined(THREAD_SAFE) and THREAD_SAFE
820 invalidate_direct_mem_ptr_ts(
id, start, end);
834 void invalidate_direct_mem_ptr_ts(
int id, sc_dt::uint64 start, sc_dt::uint64 end)
836 auto it = m_dmi_info_map.upper_bound(start);
838 if (
it != m_dmi_info_map.begin()) {
845 std::set<int> initiators;
847 while (
it != m_dmi_info_map.end()) {
848 tlm::tlm_dmi& r =
it->second.dmi;
850 if (r.get_start_address() > end) {
855 if (r.get_end_address() < start) {
861 SCP_TRACE((
DMI)) <<
"Queueing initiator " <<
t <<
" for invalidation, its bounds are [0x" << std::hex
862 <<
it->second.dmi.get_start_address() <<
" - 0x" <<
it->second.dmi.get_end_address()
864 initiators.insert(
t);
866 it = m_dmi_info_map.erase(
it);
868 for (
auto t : initiators) {
869 SCP_INFO((
DMI)) <<
"Invalidating initiator " <<
t <<
" [0x" << std::hex << start <<
" - 0x" << end <<
"]";
889 sc_dt::uint64 addr =
trans.get_address();
890 return m_address_map.find(addr,
trans.get_data_length());
900 if (!lazy_init) lazy_initialize();
905 std::atomic<bool> m_initialized{
false };
907#if defined(THREAD_SAFE) and THREAD_SAFE
910 std::list<std::string> get_matching_children(cci::cci_broker_handle
broker,
const std::string&
prefix,
911 const std::vector<cci_name_value_pair>&
list)
915 for (
const auto&
p :
list) {
916 if (
p.first.find(
prefix) == 0) {
940 void lazy_initialize()
override
943 if (m_initialized.load(std::memory_order_acquire)) {
947#if defined(THREAD_SAFE) and THREAD_SAFE
953 if (m_initialized.load(std::memory_order_relaxed)) {
960 return iv.first.find(
".aliases.") != std::string::npos;
964 for (
auto&
ti_ptr : bound_targets) {
965 std::string name =
ti_ptr->name;
970 m_broker.get_preset_cci_value(
ti_ptr->name +
".address").is_number()) {
972 (
"The configuration alias provided ({}) will be ignored as a valid address is also provided.",
src);
974 if (
src[0] ==
'&')
src = (
src.erase(0, 1)) +
".target_socket";
975 if (!
m_broker.has_preset_value(
src +
".address")) {
976 std::stringstream
ss;
977 ss <<
"The configuration alias provided (" <<
src <<
") can not be found.";
985 ti_ptr->address = gs::cci_get<uint64_t>(
m_broker, name +
".address");
987 ti_ptr->use_offset = gs::cci_get_d<bool>(
m_broker, name +
".relative_addresses",
true);
988 ti_ptr->chained = gs::cci_get_d<bool>(
m_broker, name +
".chained",
false);
989 ti_ptr->priority = gs::cci_get_d<uint32_t>(
m_broker, name +
".priority", 0);
992 <<
"Address map " <<
ti_ptr->name <<
" at address "
993 <<
"0x" << std::hex <<
ti_ptr->address <<
" size "
994 <<
"0x" << std::hex <<
ti_ptr->size << (
ti_ptr->use_offset ?
" (with relative address) " :
" ")
995 <<
"priority : " <<
ti_ptr->priority;
999 m_address_map.add(
ti_ptr);
1017 id_targets.push_back(
ti_ptr);
1021 m_initialized.store(
true, std::memory_order_release);
1025 cci::cci_param<bool> lazy_init;
1037 explicit router(
const sc_core::sc_module_name&
nm, cci::cci_broker_handle
broker = cci::cci_get_broker())
1038 : sc_core::sc_module(
nm)
1040 , target_socket(
"target_socket")
1043 , lazy_init(
"lazy_init",
false,
"Initialize the router lazily (eg. during simulation rather than BEOL)")
1050 initiator_socket.register_invalidate_direct_mem_ptr(
this,
1052 SCP_DEBUG((
DMI)) <<
"router Initializing DMI SCP reporting";
1079 unsigned int priority = 0)
1082 if (!m_broker.has_preset_value(s +
".address")) {
1083 m_broker.set_preset_cci_value(s +
".address", cci::cci_value(address));
1085 if (!m_broker.has_preset_value(s +
".size")) {
1086 m_broker.set_preset_cci_value(s +
".size", cci::cci_value(size));
1088 if (!m_broker.has_preset_value(s +
".relative_addresses")) {
1089 m_broker.set_preset_cci_value(s +
".relative_addresses", cci::cci_value(
masked));
1091 if (!m_broker.has_preset_value(s +
".priority")) {
1092 SCP_DEBUG(())(
"Setting prio to {}", priority);
1093 m_broker.set_preset_cci_value(s +
".priority", cci::cci_value(priority));
1095 initiator_socket.bind(
t);
1109 (
i.get_base_port())(target_socket.get_base_interface());
1110 (target_socket.get_base_port())(
i.get_base_interface());