46    SCP_LOGGER((
DMI), 
"dmi");
 
   48    using TargetSocket = tlm::tlm_base_target_socket_b<BUSWIDTH, tlm::tlm_fw_transport_if<>,
 
   49                                                       tlm::tlm_bw_transport_if<>>;
 
   50    using InitiatorSocket = tlm::tlm_base_initiator_socket_b<BUSWIDTH, tlm::tlm_fw_transport_if<>,
 
   51                                                             tlm::tlm_bw_transport_if<>>;
 
   58    std::mutex m_dmi_mutex;
 
   60        std::set<int> initiators;
 
   62        dmi_info(tlm::tlm_dmi& 
_dmi) { dmi = 
_dmi; }
 
   64    std::map<uint64_t, dmi_info> m_dmi_info_map;
 
   65    dmi_info* in_dmi_cache(tlm::tlm_dmi& dmi)
 
   67        auto it = m_dmi_info_map.find(dmi.get_start_address());
 
   68        if (
it != m_dmi_info_map.end()) {
 
   69            if (
it->second.dmi.get_end_address() != dmi.get_end_address()) {
 
   74        auto insit = m_dmi_info_map.insert({ dmi.get_start_address(), dmi_info(dmi) });
 
   75        return &(
insit.first->second);
 
   77    void record_dmi(
int id, tlm::tlm_dmi& dmi)
 
   79        auto it = m_dmi_info_map.find(dmi.get_start_address());
 
   80        if (
it != m_dmi_info_map.end()) {
 
   81            if (
it->second.dmi.get_end_address() != dmi.get_end_address()) {
 
   82                SCP_WARN((
DMI)) << 
"A new DMI overlaps with an old one, invalidating the old one";
 
   83                invalidate_direct_mem_ptr_ts(0, dmi.get_start_address(),
 
   84                                             dmi.get_end_address()); 
 
   88        dmi_info* 
dinfo = in_dmi_cache(dmi);
 
   89        dinfo->initiators.insert(
id);
 
   92    void register_boundto(std::string s)
 
   97        ti.index = bound_targets.size();
 
   99        SCP_DEBUG((
D[ti.index])) << 
"Connecting : " << ti.name;
 
  103        for (
i = 0; 
i < s.length(); 
i++)
 
  104            if (s[
i] != 
tmp[
i]) 
break;
 
  105        ti.shortname = s.substr(
i);
 
  107        bound_targets.push_back(ti);
 
  109    std::map<uint64_t, std::string> name_map;
 
  112        std::stringstream 
info;
 
  113        const char* cmd = 
"UNKOWN";
 
  114        switch (
trans.get_command()) {
 
  115        case tlm::TLM_IGNORE_COMMAND:
 
  118        case tlm::TLM_WRITE_COMMAND:
 
  121        case tlm::TLM_READ_COMMAND:
 
  127             << 
"0x" << std::hex << 
trans.get_address();
 
  128        info << 
" len:" << 
trans.get_data_length();
 
  129        unsigned char* 
ptr = 
trans.get_data_ptr();
 
  130        if ((
trans.get_command() == tlm::TLM_READ_COMMAND && 
trans.get_response_status() == tlm::TLM_OK_RESPONSE) ||
 
  131            (
trans.get_command() == tlm::TLM_WRITE_COMMAND &&
 
  132             trans.get_response_status() == tlm::TLM_INCOMPLETE_RESPONSE)) {
 
  134            for (
int i = 
trans.get_data_length(); 
i; 
i--) {
 
  135                info << std::setw(2) << std::setfill(
'0') << std::hex << (
unsigned int)(
ptr[
i - 1]);
 
  138        info << 
" " << 
trans.get_response_string() << 
" ";
 
  139        for (
int i = 0; 
i < tlm::max_num_extensions(); 
i++) {
 
  140            if (
trans.get_extension(
i)) {
 
  141                info << 
" extn:" << 
i;
 
  149    initiator_socket_type initiator_socket;
 
  150    tlm_utils::multi_passthrough_target_socket<router<BUSWIDTH>, 
BUSWIDTH> target_socket;
 
  153    std::vector<target_info> alias_targets;
 
  154    std::vector<target_info*> targets;
 
  155    std::vector<target_info*> id_targets;
 
  157    std::vector<PathIDExtension*> m_pathIDPool; 
 
  158#if THREAD_SAFE == true 
  161    void stamp_txn(
int id, tlm::tlm_generic_payload& 
txn)
 
  165        if (
ext == 
nullptr) {
 
  166#if THREAD_SAFE == true 
  169            if (m_pathIDPool.size() == 0) {
 
  172                ext = m_pathIDPool.back();
 
  173                m_pathIDPool.pop_back();
 
  179    void unstamp_txn(
int id, tlm::tlm_generic_payload& 
txn)
 
  186        if (
ext->size() == 0) {
 
  187#if THREAD_SAFE == true 
  191            m_pathIDPool.push_back(
ext);
 
  195    void b_transport(
int id, tlm::tlm_generic_payload& 
trans, sc_core::sc_time& delay)
 
  198        sc_dt::uint64 
addr = 
trans.get_address();
 
  199        auto ti = decode_address(
trans);
 
  201            SCP_WARN(())(
"Attempt to access unknown register at offset 0x{:x}", 
addr);
 
  202            trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
 
  206        stamp_txn(
id, 
trans);
 
  207        if (!ti->chained) 
SCP_TRACE((
D[ti->index]), ti->name) << 
"calling b_transport : " << txn_tostring(ti, 
trans);
 
  208        if (
trans.get_response_status() >= tlm::TLM_INCOMPLETE_RESPONSE) {
 
  209            if (ti->use_offset) 
trans.set_address(
addr - ti->address);
 
  210            initiator_socket[ti->index]->b_transport(
trans, delay);
 
  211            if (ti->use_offset) 
trans.set_address(
addr);
 
  213        if (!ti->chained) 
SCP_TRACE((
D[ti->index]), ti->name) << 
"b_transport returned : " << txn_tostring(ti, 
trans);
 
  214        unstamp_txn(
id, 
trans);
 
  217    unsigned int transport_dbg(
int id, tlm::tlm_generic_payload& 
trans)
 
  219        sc_dt::uint64 
addr = 
trans.get_address();
 
  220        auto ti = decode_address(
trans);
 
  222            trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
 
  226        if (ti->use_offset) 
trans.set_address(
addr - ti->address);
 
  227        SCP_TRACE((
D[ti->index]), ti->name) << 
"calling dbg_transport : " << scp::scp_txn_tostring(
trans);
 
  228        unsigned int ret = initiator_socket[ti->index]->transport_dbg(
trans);
 
  229        if (ti->use_offset) 
trans.set_address(
addr);
 
  233    bool get_direct_mem_ptr(
int id, tlm::tlm_generic_payload& 
trans, tlm::tlm_dmi& dmi_data)
 
  235        std::lock_guard<std::mutex> 
lock(m_dmi_mutex);
 
  236        sc_dt::uint64 
addr = 
trans.get_address();
 
  246             (ti ? 
"mapped" : 
"nomap"));
 
  247            u_dmi->add_dmi(
this, 
dmi_data_hole, (ti ? gs::tlm_dmi_ex::dmi_mapped : gs::tlm_dmi_ex::dmi_nomap));
 
  254        if (ti->use_offset) 
trans.set_address(
addr - ti->address);
 
  255        SCP_TRACE((
D[ti->index]), ti->name) << 
"calling get_direct_mem_ptr : " << scp::scp_txn_tostring(
trans);
 
  256        bool status = initiator_socket[ti->index]->get_direct_mem_ptr(
trans, dmi_data);
 
  257        if (ti->use_offset) 
trans.set_address(
addr);
 
  259            if (ti->use_offset) {
 
  260                assert(dmi_data.get_start_address() < ti->size);
 
  261                dmi_data.set_start_address(ti->address + dmi_data.get_start_address());
 
  262                dmi_data.set_end_address(ti->address + dmi_data.get_end_address());
 
  265            if (dmi_data.get_start_address() < 
dmi_data_hole.get_start_address()) {
 
  266                dmi_data.set_dmi_ptr(dmi_data.get_dmi_ptr() +
 
  267                                     (
dmi_data_hole.get_start_address() - dmi_data.get_start_address()));
 
  268                dmi_data.set_start_address(
dmi_data_hole.get_start_address());
 
  270            if (dmi_data.get_end_address() > 
dmi_data_hole.get_end_address()) {
 
  273            record_dmi(
id, dmi_data);
 
  276        (
"Providing DMI (status {:x}) {:x} - {:x}", status, dmi_data.get_start_address(), dmi_data.get_end_address());
 
  280    void invalidate_direct_mem_ptr(
int id, sc_dt::uint64 start, sc_dt::uint64 end)
 
  282        if (id_targets[
id]->use_offset) {
 
  283            start = id_targets[id]->address + start;
 
  284            end = id_targets[id]->address + end;
 
  286        std::lock_guard<std::mutex> 
lock(m_dmi_mutex);
 
  287        invalidate_direct_mem_ptr_ts(
id, start, end);
 
  290    void invalidate_direct_mem_ptr_ts(
int id, sc_dt::uint64 start, sc_dt::uint64 end)
 
  292        auto it = m_dmi_info_map.upper_bound(start);
 
  294        if (
it != m_dmi_info_map.begin()) {
 
  301        std::set<int> initiators;
 
  303        while (
it != m_dmi_info_map.end()) {
 
  304            tlm::tlm_dmi& r = 
it->second.dmi;
 
  306            if (r.get_start_address() > end) {
 
  311            if (r.get_end_address() < start) {
 
  316            for (
auto t : 
it->second.initiators) {
 
  317                SCP_TRACE((
DMI)) << 
"Queueing initiator " << 
t << 
" for invalidation, its bounds are [0x" << std::hex
 
  318                                 << 
it->second.dmi.get_start_address() << 
" - 0x" << 
it->second.dmi.get_end_address()
 
  320                initiators.insert(
t);
 
  322            it = m_dmi_info_map.erase(
it);
 
  324        for (
auto t : initiators) {
 
  325            SCP_INFO((
DMI)) << 
"Invalidating initiator " << 
t << 
" [0x" << std::hex << start << 
" - 0x" << end << 
"]";
 
  326            target_socket[
t]->invalidate_direct_mem_ptr(start, end);
 
  334        sc_dt::uint64 
addr = 
trans.get_address();
 
  335        sc_dt::uint64 
len = 
trans.get_data_length();
 
  337        for (
auto ti : targets) {
 
  338            if (
addr >= ti->address && (
addr - ti->address) < ti->size) {
 
  347        uint64_t end = std::numeric_limits<uint64_t>::max();
 
  349        for (
auto ti : targets) {
 
  350            if (ti->address < end && ti->address > 
addr) {
 
  351                end = ti->address - 1;
 
  353            if ((ti->address + ti->size) > start && (ti->address + ti->size) <= 
addr) {
 
  354                start = ti->address + ti->size;
 
  356            if (
addr >= ti->address && (
addr - ti->address) < ti->size) {
 
  357                if (ti->address > start) start = ti->address;
 
  358                if ((ti->address + ti->size) < end) end = ti->address + ti->size;
 
  359                SCP_DEBUG(())(
"Device found for address {:x} from {:x} to {:x}", 
addr, start, end);
 
  360                dmi.set_start_address(start);
 
  361                dmi.set_end_address(end);
 
  365        SCP_DEBUG(())(
"Hole for address {:x} from {:x} to {:x}", 
addr, start, end);
 
  366        dmi.set_start_address(start);
 
  367        dmi.set_end_address(end);
 
  372    virtual void before_end_of_elaboration()
 
  374        if (!lazy_init) lazy_initialize();
 
  378    bool initialized = 
false;
 
  379    void lazy_initialize()
 
  381        if (initialized) 
return;
 
  384        for (
auto& ti : bound_targets) {
 
  385            std::string name = ti.name;
 
  387            if (gs::cci_get<std::string>(m_broker, ti.name + 
".0", 
src)) {
 
  389                if (m_broker.has_preset_value(ti.name + 
".address") &&
 
  390                    m_broker.get_preset_cci_value(ti.name + 
".address").is_number()) {
 
  392                    (
"The configuration alias provided ({}) will be ignored as a valid address is also provided.", 
src);
 
  394                    if (
src[0] == 
'&') 
src = (
src.erase(0, 1)) + 
".target_socket";
 
  395                    if (!m_broker.has_preset_value(
src + 
".address")) {
 
  397                        (
"The configuration alias provided ({}) can not be found.", 
src);
 
  403            ti.address = gs::cci_get<uint64_t>(m_broker, name + 
".address");
 
  404            ti.size = gs::cci_get<uint64_t>(m_broker, name + 
".size");
 
  405            ti.use_offset = gs::cci_get_d<bool>(m_broker, name + 
".relative_addresses", 
true);
 
  406            ti.chained = gs::cci_get_d<bool>(m_broker, name + 
".chained", 
false);
 
  407            ti.priority = gs::cci_get_d<uint32_t>(m_broker, name + 
".priority", 0);
 
  410                << 
"Address map " << ti.name << 
" at address " 
  411                << 
"0x" << std::hex << ti.address << 
" size " 
  412                << 
"0x" << std::hex << ti.size << (ti.use_offset ? 
" (with relative address) " : 
"");
 
  413            if (ti.chained) 
SCP_DEBUG(())(
"{} is chained so debug will be suppressed", ti.name);
 
  415            for (
auto tti : targets) {
 
  416                if (tti->address >= ti.address && (ti.address - tti->address) < tti->size) {
 
  417                    SCP_WARN((
D[ti.index]), ti.name)(
"{} overlaps with {}", ti.name, tti->name);
 
  421            targets.push_back(&ti);
 
  424                std::string name = ti.name + 
".aliases." + 
n;
 
  425                uint64_t address = gs::cci_get<uint64_t>(m_broker, name + 
".address");
 
  426                uint64_t size = gs::cci_get<uint64_t>(m_broker, name + 
".size");
 
  427                SCP_INFO((
D[ti.index]), ti.name)(
"Adding alias {} {:#x} (size: {})", name, address, size);
 
  429                ati.address = address;
 
  432                alias_targets.push_back(
ati);
 
  434            id_targets.push_back(&ti);
 
  436        for (
auto& 
ati : alias_targets) {
 
  437            targets.push_back(&
ati);
 
  439        if (!targets.empty())
 
  445    cci::cci_broker_handle m_broker;
 
  448    cci::cci_param<bool> lazy_init;
 
  450    explicit router(
const sc_core::sc_module_name& 
nm, cci::cci_broker_handle 
broker = cci::cci_get_broker())
 
  451        : sc_core::sc_module(
nm)
 
  452        , initiator_socket(
"initiator_socket", [&](std::string s) -> 
void { register_boundto(s); })
 
  453        , target_socket(
"target_socket")
 
  455        , lazy_init(
"lazy_init", 
false, 
"Initialize the router lazily (eg. during simulation rather than BEOL)")
 
  459        target_socket.register_b_transport(
this, &router::b_transport);
 
  460        target_socket.register_transport_dbg(
this, &router::transport_dbg);
 
  461        target_socket.register_get_direct_mem_ptr(
this, &router::get_direct_mem_ptr);
 
  462        initiator_socket.register_invalidate_direct_mem_ptr(
this, &router::invalidate_direct_mem_ptr);
 
  463        SCP_DEBUG((
DMI)) << 
"router Initializing DMI SCP reporting";
 
  472        while (m_pathIDPool.size()) {
 
  473            delete (m_pathIDPool.back());
 
  474            m_pathIDPool.pop_back();
 
  481        if (!m_broker.has_preset_value(s + 
".address")) {
 
  482            m_broker.set_preset_cci_value(s + 
".address", cci::cci_value(address));
 
  484        if (!m_broker.has_preset_value(s + 
".size")) {
 
  485            m_broker.set_preset_cci_value(s + 
".size", cci::cci_value(size));
 
  487        if (!m_broker.has_preset_value(s + 
".relative_addresses")) {
 
  488            m_broker.set_preset_cci_value(s + 
".relative_addresses", cci::cci_value(
masked));
 
  490        initiator_socket.bind(
t);
 
  493    virtual void add_initiator(InitiatorSocket& 
i)
 
  496        (
i.get_base_port())(target_socket.get_base_interface());
 
  497        (target_socket.get_base_port())(
i.get_base_interface());