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 sc_dt::uint64
addr =
trans.get_address();
245 (ti ?
"mapped" :
"nomap"));
246 u_dmi->add_dmi(
this,
dmi_data_hole, (ti ? gs::tlm_dmi_ex::dmi_mapped : gs::tlm_dmi_ex::dmi_nomap));
253 if (!m_dmi_mutex.try_lock()) {
257 if (ti->use_offset)
trans.set_address(
addr - ti->address);
258 SCP_TRACE((
D[ti->index]), ti->name) <<
"calling get_direct_mem_ptr : " << scp::scp_txn_tostring(
trans);
259 bool status = initiator_socket[ti->index]->get_direct_mem_ptr(
trans, dmi_data);
260 if (ti->use_offset)
trans.set_address(
addr);
262 if (ti->use_offset) {
263 assert(dmi_data.get_start_address() < ti->size);
264 dmi_data.set_start_address(ti->address + dmi_data.get_start_address());
265 dmi_data.set_end_address(ti->address + dmi_data.get_end_address());
268 if (dmi_data.get_start_address() <
dmi_data_hole.get_start_address()) {
269 dmi_data.set_dmi_ptr(dmi_data.get_dmi_ptr() +
270 (
dmi_data_hole.get_start_address() - dmi_data.get_start_address()));
271 dmi_data.set_start_address(
dmi_data_hole.get_start_address());
273 if (dmi_data.get_end_address() >
dmi_data_hole.get_end_address()) {
276 record_dmi(
id, dmi_data);
279 (
"Providing DMI (status {:x}) {:x} - {:x}", status, dmi_data.get_start_address(), dmi_data.get_end_address());
280 m_dmi_mutex.unlock();
284 void invalidate_direct_mem_ptr(
int id, sc_dt::uint64 start, sc_dt::uint64 end)
286 if (id_targets[
id]->use_offset) {
287 start = id_targets[id]->address + start;
288 end = id_targets[id]->address + end;
290 std::lock_guard<std::mutex>
lock(m_dmi_mutex);
291 invalidate_direct_mem_ptr_ts(
id, start, end);
294 void invalidate_direct_mem_ptr_ts(
int id, sc_dt::uint64 start, sc_dt::uint64 end)
296 auto it = m_dmi_info_map.upper_bound(start);
298 if (
it != m_dmi_info_map.begin()) {
305 std::set<int> initiators;
307 while (
it != m_dmi_info_map.end()) {
308 tlm::tlm_dmi& r =
it->second.dmi;
310 if (r.get_start_address() > end) {
315 if (r.get_end_address() < start) {
320 for (
auto t :
it->second.initiators) {
321 SCP_TRACE((
DMI)) <<
"Queueing initiator " <<
t <<
" for invalidation, its bounds are [0x" << std::hex
322 <<
it->second.dmi.get_start_address() <<
" - 0x" <<
it->second.dmi.get_end_address()
324 initiators.insert(
t);
326 it = m_dmi_info_map.erase(
it);
328 for (
auto t : initiators) {
329 SCP_INFO((
DMI)) <<
"Invalidating initiator " <<
t <<
" [0x" << std::hex << start <<
" - 0x" << end <<
"]";
330 target_socket[
t]->invalidate_direct_mem_ptr(start, end);
338 sc_dt::uint64
addr =
trans.get_address();
339 sc_dt::uint64
len =
trans.get_data_length();
341 for (
auto ti : targets) {
342 if (
addr >= ti->address && (
addr - ti->address) < ti->size) {
351 uint64_t end = std::numeric_limits<uint64_t>::max();
353 for (
auto ti : targets) {
354 if (ti->address < end && ti->address >
addr) {
355 end = ti->address - 1;
357 if ((ti->address + ti->size) > start && (ti->address + ti->size) <=
addr) {
358 start = ti->address + ti->size;
360 if (
addr >= ti->address && (
addr - ti->address) < ti->size) {
361 if (ti->address > start) start = ti->address;
362 if ((ti->address + ti->size) < end) end = ti->address + ti->size;
363 SCP_DEBUG(())(
"Device found for address {:x} from {:x} to {:x}",
addr, start, end);
364 dmi.set_start_address(start);
365 dmi.set_end_address(end);
369 SCP_DEBUG(())(
"Hole for address {:x} from {:x} to {:x}",
addr, start, end);
370 dmi.set_start_address(start);
371 dmi.set_end_address(end);
376 virtual void before_end_of_elaboration()
378 if (!lazy_init) lazy_initialize();
382 bool initialized =
false;
383 void lazy_initialize()
385 if (initialized)
return;
388 for (
auto& ti : bound_targets) {
389 std::string name = ti.name;
391 if (gs::cci_get<std::string>(m_broker, ti.name +
".0",
src)) {
393 if (m_broker.has_preset_value(ti.name +
".address") &&
394 m_broker.get_preset_cci_value(ti.name +
".address").is_number()) {
396 (
"The configuration alias provided ({}) will be ignored as a valid address is also provided.",
src);
398 if (
src[0] ==
'&')
src = (
src.erase(0, 1)) +
".target_socket";
399 if (!m_broker.has_preset_value(
src +
".address")) {
401 (
"The configuration alias provided ({}) can not be found.",
src);
407 ti.address = gs::cci_get<uint64_t>(m_broker, name +
".address");
408 ti.size = gs::cci_get<uint64_t>(m_broker, name +
".size");
409 ti.use_offset = gs::cci_get_d<bool>(m_broker, name +
".relative_addresses",
true);
410 ti.chained = gs::cci_get_d<bool>(m_broker, name +
".chained",
false);
411 ti.priority = gs::cci_get_d<uint32_t>(m_broker, name +
".priority", 0);
414 <<
"Address map " << ti.name <<
" at address "
415 <<
"0x" << std::hex << ti.address <<
" size "
416 <<
"0x" << std::hex << ti.size << (ti.use_offset ?
" (with relative address) " :
"");
417 if (ti.chained)
SCP_DEBUG(())(
"{} is chained so debug will be suppressed", ti.name);
419 for (
auto tti : targets) {
420 if (tti->address >= ti.address && (ti.address - tti->address) < tti->size) {
421 SCP_WARN((
D[ti.index]), ti.name)(
"{} overlaps with {}", ti.name, tti->name);
425 targets.push_back(&ti);
428 std::string name = ti.name +
".aliases." +
n;
429 uint64_t address = gs::cci_get<uint64_t>(m_broker, name +
".address");
430 uint64_t size = gs::cci_get<uint64_t>(m_broker, name +
".size");
431 SCP_INFO((
D[ti.index]), ti.name)(
"Adding alias {} {:#x} (size: {})", name, address, size);
433 ati.address = address;
436 alias_targets.push_back(
ati);
438 id_targets.push_back(&ti);
440 for (
auto&
ati : alias_targets) {
441 targets.push_back(&
ati);
443 if (!targets.empty())
449 cci::cci_broker_handle m_broker;
452 cci::cci_param<bool> lazy_init;
454 explicit router(
const sc_core::sc_module_name&
nm, cci::cci_broker_handle
broker = cci::cci_get_broker())
455 : sc_core::sc_module(
nm)
456 , initiator_socket(
"initiator_socket", [&](std::string s) ->
void { register_boundto(s); })
457 , target_socket(
"target_socket")
459 , lazy_init(
"lazy_init",
false,
"Initialize the router lazily (eg. during simulation rather than BEOL)")
463 target_socket.register_b_transport(
this, &router::b_transport);
464 target_socket.register_transport_dbg(
this, &router::transport_dbg);
465 target_socket.register_get_direct_mem_ptr(
this, &router::get_direct_mem_ptr);
466 initiator_socket.register_invalidate_direct_mem_ptr(
this, &router::invalidate_direct_mem_ptr);
467 SCP_DEBUG((
DMI)) <<
"router Initializing DMI SCP reporting";
476 while (m_pathIDPool.size()) {
477 delete (m_pathIDPool.back());
478 m_pathIDPool.pop_back();
485 if (!m_broker.has_preset_value(s +
".address")) {
486 m_broker.set_preset_cci_value(s +
".address", cci::cci_value(address));
488 if (!m_broker.has_preset_value(s +
".size")) {
489 m_broker.set_preset_cci_value(s +
".size", cci::cci_value(size));
491 if (!m_broker.has_preset_value(s +
".relative_addresses")) {
492 m_broker.set_preset_cci_value(s +
".relative_addresses", cci::cci_value(
masked));
494 initiator_socket.bind(
t);
497 virtual void add_initiator(InitiatorSocket&
i)
500 (
i.get_base_port())(target_socket.get_base_interface());
501 (target_socket.get_base_port())(
i.get_base_interface());