quic/qbox
Loading...
Searching...
No Matches
reg_router.h
1/*
2 * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef _GREENSOCS_BASE_COMPONENTS_REG_ROUTER_H
8#define _GREENSOCS_BASE_COMPONENTS_REG_ROUTER_H
9
10#include <cinttypes>
11#include <iomanip>
12#include <cci_configuration>
13#include <systemc>
14#include <tlm>
15#include <scp/report.h>
16#include <scp/helpers.h>
17#include <tlm_utils/multi_passthrough_initiator_socket.h>
18#include <tlm_utils/multi_passthrough_target_socket.h>
19#include <cciutils.h>
20#include <module_factory_registery.h>
21#include <module_factory_container.h>
22#include <tlm_sockets_buswidth.h>
23#include <router_if.h>
24#include <vector>
25#include <memory>
26#include <map>
27#include <functional>
28
29#define ENABLE_MODULE_NAME_DBG_INFO 1
30namespace gs {
31
32template <unsigned int BUSWIDTH = DEFAULT_TLM_BUSWIDTH>
33class reg_router : public sc_core::sc_module, public gs::router_if<BUSWIDTH>
34{
35 SCP_LOGGER(());
36 SCP_LOGGER((DMI), "dmi");
37
41 using gs::router_if<BUSWIDTH>::bound_targets;
42
43 void register_boundto(std::string s)
44 {
46 target_info ti = { 0 };
47 ti.name = s;
48 ti.index = bound_targets.size();
49 SCP_DEBUG(()) << "Connecting : " << ti.name;
50 auto tmp = name();
51 int i;
52 for (i = 0; i < s.length(); i++)
53 if (s[i] != tmp[i]) break;
54 ti.shortname = s.substr(i);
55 bound_targets.push_back(ti);
56 }
57
58public:
59 void b_transport(int id, tlm::tlm_generic_payload& trans, sc_core::sc_time& delay)
60 {
61 sc_dt::uint64 addr = trans.get_address();
62
63 auto ti = decode_address(trans);
64
65 if (!ti) {
66 SCP_WARN(())("Attempt to access unknown location in register memory at offset 0x{:x}", addr);
67 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
68 return;
69 }
70
71#ifdef ENABLE_MODULE_NAME_DBG_INFO
73 bool mod_found = false;
74 const char* mod_name = get_module_name(trans, mod_addr, mod_found);
75 if (mod_name)
76 SCP_DEBUG(()) << "b_transport: " << txn_command_str(trans) << " to Register at address: 0x" << std::hex
77 << trans.get_address() << " which belongs to Module: [" << mod_name << "]";
78 if (m_pre_b_transport_callback) m_pre_b_transport_callback(mod_found, mod_addr);
79#endif
80
81 bool found_cb = do_callbacks(trans, delay);
82 if (trans.get_response_status() >= tlm::TLM_INCOMPLETE_RESPONSE) {
83 SCP_TRACEALL(()) << "call b_transport: " << txn_to_str(trans, false, found_cb);
84 if (ti->use_offset) trans.set_address(addr - ti->address);
85 initiator_socket[ti->index]->b_transport(trans, delay);
86 if (ti->use_offset) trans.set_address(addr);
87 SCP_TRACEALL(()) << "b_transport returned: " << txn_to_str(trans, false, found_cb);
88 }
89 if (trans.get_response_status() >= tlm::TLM_OK_RESPONSE) {
90 do_callbacks(trans, delay);
91 }
92 if (cb_targets.size() > 0) {
93 trans.set_dmi_allowed(false);
94 }
95 }
96
97 unsigned int transport_dbg(int id, tlm::tlm_generic_payload& trans)
98 {
99 sc_dt::uint64 addr = trans.get_address();
100 // transport_dbg transactions should only be handled by register memory
101 auto ti = decode_address(trans);
102
103 if (!ti) {
104 SCP_WARN(())("transport_dbg: Attempt to access unknown location in register memory at offset 0x{:x}", addr);
105 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
106 return 0;
107 }
108
109#ifdef ENABLE_MODULE_NAME_DBG_INFO
110 uint64_t mod_addr = 0;
111 bool mod_found = false;
112 const char* mod_name = get_module_name(trans, mod_addr, mod_found);
113 if (mod_name)
114 SCP_DEBUG(()) << "transport_dbg: " << txn_command_str(trans) << " to Register at address: 0x" << std::hex
115 << trans.get_address() << " which belongs to Module: [" << mod_name << "]";
116 if (m_pre_b_transport_callback) m_pre_b_transport_callback(mod_found, mod_addr);
117#endif
118
119 if (ti->use_offset) trans.set_address(addr - ti->address);
120 SCP_TRACEALL(()) << "[REG-MEM] call transport_dbg [txn]: " << scp::scp_txn_tostring(trans);
121 unsigned int ret = initiator_socket[ti->index]->transport_dbg(trans);
122 if (ti->use_offset) trans.set_address(addr);
123 return ret;
124 }
125
126 bool get_direct_mem_ptr(int id, tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data)
127 {
128 SCP_TRACE(()) << "[REG-MEM] call get_direct_mem_ptr (not allowed) [txn]: " << scp::scp_txn_tostring(trans);
129 return false;
130 }
131
132 std::string txn_to_str(tlm::tlm_generic_payload& trans, bool is_callback = false, bool found_callback = false)
133 {
134 std::stringstream ss;
135 std::string cmd = txn_command_str(trans);
136 if (is_callback && found_callback) {
137 if (cmd != "IGNORE" && cmd != "UNKNOWN") {
138 if ((trans.get_response_status() == tlm::TLM_INCOMPLETE_RESPONSE))
139 ss << "[PRE-" << cmd << "] Register callbacks [txn]: ";
140 else if ((trans.get_response_status() == tlm::TLM_OK_RESPONSE))
141 ss << "[POST-" << cmd << "] Register callbacks [txn]: ";
142 }
143 } else if (found_callback) {
144 ss << "[REG-MEM] (" << cmd << " TO REG-MEM BEFORE " << cmd << " CB) [txn]: ";
145 } else {
146 ss << "[REG-MEM] (NO CB FOUND) [txn]: ";
147 }
148
149 ss << scp::scp_txn_tostring(trans);
150 return ss.str();
151 }
152
153 std::string txn_command_str(const tlm::tlm_generic_payload& trans)
154 {
155 std::string cmd;
156 switch (trans.get_command()) {
157 case tlm::TLM_READ_COMMAND:
158 cmd = "READ";
159 break;
160 case tlm::TLM_WRITE_COMMAND:
161 cmd = "WRITE";
162 break;
163 case tlm::TLM_IGNORE_COMMAND:
164 cmd = "IGNORE";
165 break;
166 default:
167 cmd = "UNKNOWN";
168 break;
169 }
170 return cmd;
171 }
172
173#ifdef ENABLE_MODULE_NAME_DBG_INFO
174 const char* get_module_name(const tlm::tlm_generic_payload& trans, uint64_t& mod_addr, bool& mod_found)
175 {
176 if (mod_addr_name_map.empty()) {
177 return nullptr;
178 }
179 uint64_t addr = trans.get_address();
180 auto search = mod_addr_name_map.equal_range(addr);
181 if (search.first != mod_addr_name_map.end() && search.first->first == addr) {
182 if ((addr - search.first->first) < search.first->second.first) {
183 mod_addr = search.first->first;
184 mod_found = true;
185 return search.first->second.second;
186 }
187 } else if (search.second != mod_addr_name_map.begin()) {
188 auto expected_node = std::prev(search.second);
189 if ((addr - expected_node->first) < expected_node->second.first) {
190 mod_addr = expected_node->first;
191 mod_found = true;
192 return expected_node->second.second;
193 } else {
194 mod_found = false;
195 }
196 } else {
197 mod_found = false;
198 }
199 return nullptr;
200 }
201#endif
202
203 bool do_callbacks(tlm::tlm_generic_payload& trans, sc_core::sc_time& delay)
204 {
205 if (cb_targets.empty()) {
206 return false;
207 }
208
209 sc_dt::uint64 addr = trans.get_address();
210 sc_dt::uint64 len = trans.get_data_length();
211 target_info* ti;
212
213 auto search = cb_targets.equal_range(addr);
214 if (search.first != cb_targets.end() && search.first->first == addr) {
215 if ((addr - search.first->first) < search.first->second->size) {
216 ti = search.first->second;
217 }
218 } else if (search.second != cb_targets.begin()) {
219 auto expected_node = std::prev(search.second);
220 if ((addr - expected_node->first) < expected_node->second->size) {
221 ti = expected_node->second;
222 } else {
223 return false;
224 }
225 } else {
226 return false;
227 }
228 SCP_TRACEALL(()) << "call b_transport: " << txn_to_str(trans, true, true);
229 if (ti->use_offset) trans.set_address(addr - ti->address);
230 initiator_socket[ti->index]->b_transport(trans, delay);
231 if (ti->use_offset) trans.set_address(addr);
232 SCP_TRACEALL(()) << "b_transport returned : " << txn_to_str(trans, true, true);
233 if (trans.get_response_status() <= tlm::TLM_GENERIC_ERROR_RESPONSE) {
234 SCP_WARN(()) << "Accesing register callback at addr: " << std::hex << addr
235 << " returned with: " << trans.get_response_string();
236 }
237 return true;
238 }
239
240 target_info* decode_address(tlm::tlm_generic_payload& trans)
241 {
242 lazy_initialize();
243
244 sc_dt::uint64 addr = trans.get_address();
245 sc_dt::uint64 len = trans.get_data_length();
246
247 for (auto ti : mem_targets) {
248 if (addr >= ti->address && (addr - ti->address) < ti->size) {
249 return ti;
250 }
251 }
252 return nullptr;
253 }
254
255protected:
256 virtual void before_end_of_elaboration()
257 {
258 if (!lazy_init) lazy_initialize();
259 }
260
261protected:
262 void lazy_initialize()
263 {
264 if (initialized) return;
265 initialized = true;
266
267 for (auto& ti : bound_targets) {
268 std::string name = ti.name;
269 std::string src;
270
271 ti.address = gs::cci_get<uint64_t>(m_broker, name + ".address");
272 ti.size = gs::cci_get<uint64_t>(m_broker, name + ".size");
273 ti.use_offset = gs::cci_get_d<bool>(m_broker, name + ".relative_addresses", true);
274 ti.is_callback = gs::cci_get_d<bool>(m_broker, name + ".is_callback", false);
275
276 SCP_INFO(()) << "Address map " << ti.name + " at"
277 << " address "
278 << "0x" << std::hex << ti.address << " size "
279 << "0x" << std::hex << ti.size << (ti.use_offset ? " (with relative address) " : "")
280 << (ti.is_callback ? " (callback) " : "");
281
282 if (ti.is_callback) {
283 auto insertion_pair = cb_targets.insert(std::make_pair(ti.address, &ti));
284 if (!insertion_pair.second)
285 SCP_FATAL(()) << "a CB register with the same adress: 0x" << std::hex << ti.address
286 << " was already bound!";
287 } else {
288 if (!mem_targets.empty()) {
289 for (const auto& mem : mem_targets) {
290 if (((ti.address >= mem->address) && ((ti.address - mem->address) < mem->size)) ||
291 ((ti.address < mem->address) && ((ti.address + ti.size) > mem->address))) {
292 SCP_WARN(()) << ti.name << " overlaps with " << mem->name;
293 }
294 }
295 }
296 mem_targets.push_back(&ti);
297 }
298 }
299 }
300
301public:
302 explicit reg_router(
303 const sc_core::sc_module_name& nm,
304 const std::map<uint64_t, std::pair<uint64_t, const char*>>& p_mod_addr_name_map =
305 std::map<uint64_t, std::pair<uint64_t, const char*>>(),
306 const std::function<void(bool, uint64_t)>& pre_b_transport_callback = std::function<void(bool, uint64_t)>(),
307 cci::cci_broker_handle broker = cci::cci_get_broker())
308 : sc_core::sc_module(nm)
309 , initiator_socket("initiator_socket", [&](std::string s) -> void { register_boundto(s); })
310 , target_socket("target_socket")
311 , m_broker(broker)
312 , lazy_init("lazy_init", false, "Initialize the reg_router lazily (eg. during simulation rather than BEOL)")
313 , mod_addr_name_map(p_mod_addr_name_map)
314 , m_pre_b_transport_callback(pre_b_transport_callback)
315 {
316 SCP_DEBUG(()) << "reg_router constructed";
317
318 target_socket.register_b_transport(this, &reg_router::b_transport);
319 target_socket.register_transport_dbg(this, &reg_router::transport_dbg);
320 target_socket.register_get_direct_mem_ptr(this, &reg_router::get_direct_mem_ptr);
321 // memory model doesn't implement invalidate_direct_mem_ptr so no need to register it
322 SCP_DEBUG((DMI)) << "reg_router Initializing DMI SCP reporting";
323 }
324
325 reg_router() = delete;
326
327 reg_router(const reg_router&) = delete;
328
329 ~reg_router() = default;
330
331public:
332 // make the sockets public for binding
333 initiator_socket_type initiator_socket;
334 tlm_utils::multi_passthrough_target_socket<reg_router<BUSWIDTH>, BUSWIDTH> target_socket;
335 cci::cci_broker_handle m_broker;
336 cci::cci_param<bool> lazy_init;
337
338private:
339 std::vector<target_info*> mem_targets;
340 std::map<sc_dt::uint64, target_info*> cb_targets;
341 std::map<uint64_t, std::pair<uint64_t, const char*>> mod_addr_name_map;
342 std::function<void(bool, uint64_t)> m_pre_b_transport_callback;
343 bool initialized = false;
344};
345} // namespace gs
346
347extern "C" void module_register();
348#endif
Definition target.h:160
Definition reg_router.h:34
Definition router_if.h:23
Tool which reads a Lua configuration file and sets parameters.
Definition biflow.cc:10
Definition router_if.h:48