quic/qbox
Loading...
Searching...
No Matches
remote.h
1/*
2 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef _GREENSOCS_BASE_COMPONENTS_REMOTE_H
8#define _GREENSOCS_BASE_COMPONENTS_REMOTE_H
9
10#include <cci_configuration>
11#include <systemc>
12#include <tlm>
13#include <scp/report.h>
14
15#include <tlm_utils/simple_initiator_socket.h>
16#include <tlm_utils/simple_target_socket.h>
17#include <tlm_utils/multi_passthrough_initiator_socket.h>
18#include <tlm_utils/multi_passthrough_target_socket.h>
19
20#include <libgsutils.h>
21#include <uutils.h>
22#include <libgssync.h>
23#include <cciutils.h>
24#include <ports/initiator-signal-socket.h>
25#include <ports/target-signal-socket.h>
26#include <tlm-extensions/shmem_extension.h>
27#include <module_factory_registery.h>
28#include <module_factory_container.h>
29#include <iomanip>
30#include <unistd.h>
31#include <condition_variable>
32#include <mutex>
33#include <thread>
34#include <algorithm>
35#include <list>
36#include <limits>
37#include <vector>
38#include <atomic>
39#include <future>
40#include <queue>
41#include <utility>
42#include <type_traits>
43#include <chrono>
44#include <memory_services.h>
45
46#include <rpc/client.h>
47#include <rpc/rpc_error.h>
48#include <rpc/server.h>
49#include <rpc/this_handler.h>
50#include <rpc/this_session.h>
51#include <async_event.h>
52#include <transaction_forwarder_if.h>
53#include <tlm_sockets_buswidth.h>
54
55#define GS_Process_Server_Port "GS_Process_Server_Port"
56#define GS_Process_Server_Port_Len 22
57#define DECIMAL_PORT_NUM_STR_LEN 20
58#define DECIMAL_PID_T_STR_LEN 20
59#define RPC_TIMEOUT 500
60
61namespace gs {
62
63#ifdef _WIN32
65{
66private:
69 HANDLE m_process_dup = NULL; // Duplicated handle
70 std::thread m_exit_waiter_thread;
71 std::atomic_bool m_exit_waiter_active{ false };
72
73public:
76 {
78 if (m_exit_waiter_thread.joinable()) {
80 }
84 }
85 if (m_process_dup) {
88 }
89 }
90
91 // Create a process from executable path and arguments, and store its handle
92 bool create_partner_process(const std::string& exe_path, const std::list<std::string>& arguments)
93 {
96 ZeroMemory(&si, sizeof(si));
97 si.cb = sizeof(si);
98 ZeroMemory(&pi, sizeof(pi));
99
100 std::string serialized_arguments;
101 for (const auto& arg : arguments) {
102 serialized_arguments.append(arg).append(1, ' ');
103 }
104 // Trim trailing whitespace
105 serialized_arguments.pop_back();
106
107 // Create a duplicated handle of the current process.
108 // This handle can be used by child processes to detect the termination of the current process.
111 // If duplication fails, still close thread handle and return false
114 return false;
115 }
116
117 // Creates partner process and inherits duplicated handle
119 &si, &pi);
120 if (!result) {
121 SCP_FATAL("Remote process")("");
122 }
123 m_partner_process = pi.hProcess;
124
125 // Close thread handle, we only need process handle
126 CloseHandle(pi.hThread);
127 return true;
128 }
129
130 // Get the duplicated process handle
131 HANDLE get_process_dup() const { return m_process_dup; }
132
133 // Set the partner process handle directly
134 // This setter is called from the child process
136
137 // Get the partner process handle
139
140 // Wait for partner process termination in a separate thread and execute callback
141 void on_partner_exit(std::function<void()> callback)
142 {
143 if (!m_partner_process) return;
145 m_exit_waiter_thread = std::thread([this, callback]() {
147 if (!m_exit_waiter_active) return;
148 if (res == WAIT_OBJECT_0) {
149 callback();
150 }
151 });
152 }
153};
154#endif // _WIN32
155
156// #define DMICACHE switchthis on - then you need a mutex
157/* rpc pass through should pass through ONE forward connection ? */
158
159template <unsigned int BUSWIDTH = DEFAULT_TLM_BUSWIDTH>
160class PassRPC : public sc_core::sc_module, public transaction_forwarder_if<PASS>
161{
162 SCP_LOGGER();
163 using MOD = PassRPC<BUSWIDTH>;
164
165 static std::string txn_str(tlm::tlm_generic_payload& trans)
166 {
167 std::stringstream info;
168
169 const char* cmd = "unknown";
170 switch (trans.get_command()) {
171 case tlm::TLM_IGNORE_COMMAND:
172 cmd = "ignore";
173 break;
174 case tlm::TLM_WRITE_COMMAND:
175 cmd = "write";
176 break;
177 case tlm::TLM_READ_COMMAND:
178 cmd = "read";
179 break;
180 }
181
182 info << " " << cmd << " to address "
183 << "0x" << std::hex << trans.get_address();
184
185 info << " len:" << trans.get_data_length();
186 unsigned char* ptr = trans.get_data_ptr();
187 info << " returned with data 0x";
188 for (int i = trans.get_data_length(); i; i--) {
189 info << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)(ptr[i - 1]);
190 }
191 info << " status:" << trans.get_response_status() << " ";
192 if (trans.is_dmi_allowed()) info << " DMI OK ";
193 for (int i = 0; i < tlm::max_num_extensions(); i++) {
194 if (trans.get_extension(i)) {
195 info << " extn " << i;
196 }
197 }
198 return info.str();
199 }
200
201 using str_pairs = std::vector<std::pair<std::string, std::string>>;
202#ifdef DMICACHE
203 /* Handle local DMI cache */
204
205 std::map<uint64_t, tlm::tlm_dmi> m_dmi_cache;
206 tlm::tlm_dmi* in_cache(uint64_t address)
207 {
208 if (m_dmi_cache.size() > 0) {
209 auto it = m_dmi_cache.upper_bound(address);
210 if (it != m_dmi_cache.begin()) {
211 it = std::prev(it);
212 if ((address >= it->second.get_start_address()) && (address <= it->second.get_end_address())) {
213 return &(it->second);
214 }
215 }
216 }
217 return nullptr;
218 }
219 void cache_clean(uint64_t start, uint64_t end)
220 {
221 auto it = m_dmi_cache.upper_bound(start);
222
223 if (it != m_dmi_cache.begin()) {
224 /*
225 * Start with the preceding region, as it may already cross the
226 * range we must invalidate.
227 */
228 it--;
229 }
230
231 while (it != m_dmi_cache.end()) {
232 tlm::tlm_dmi& r = it->second;
233
234 if (r.get_start_address() > end) {
235 /* We've got out of the invalidation range */
236 break;
237 }
238
239 if (r.get_end_address() < start) {
240 /* We are not in yet */
241 it++;
242 continue;
243 }
244 it = m_dmi_cache.erase(it);
245 }
246 }
247#endif
248 /* RPC structure for TLM_DMI */
249 struct tlm_dmi_rpc {
250 std::string m_shmem_fn;
251 size_t m_shmem_size;
252 uint64_t m_shmem_offset;
253
254 uint64_t m_dmi_start_address;
255 uint64_t m_dmi_end_address;
256 int m_dmi_access; /*tlm::tlm_dmi::dmi_access_e */
257 double m_dmi_read_latency;
258 double m_dmi_write_latency;
259
260 MSGPACK_DEFINE_ARRAY(m_shmem_fn, m_shmem_size, m_shmem_offset, m_dmi_start_address, m_dmi_end_address,
261 m_dmi_access, m_dmi_read_latency, m_dmi_write_latency);
262
263 void from_tlm(tlm::tlm_dmi& other, ShmemIDExtension* shm)
264 {
265 m_shmem_fn = shm->m_memid;
266 m_shmem_size = shm->m_size;
267 m_shmem_offset = (uint64_t)(other.get_dmi_ptr()) - shm->m_mapped_addr;
268 m_dmi_start_address = other.get_start_address();
269 m_dmi_end_address = other.get_end_address();
270 m_dmi_access = other.get_granted_access();
271 m_dmi_read_latency = other.get_read_latency().to_seconds();
272 m_dmi_write_latency = other.get_write_latency().to_seconds();
273 }
274
275 void to_tlm(tlm::tlm_dmi& other)
276 {
277 if (m_shmem_size == 0) return;
278 other.set_dmi_ptr(m_shmem_offset + MemoryServices::get().map_mem_join(m_shmem_fn, m_shmem_size));
279 other.set_start_address(m_dmi_start_address);
280 other.set_end_address(m_dmi_end_address);
281 other.set_granted_access((tlm::tlm_dmi::dmi_access_e)m_dmi_access);
282 other.set_read_latency(sc_core::sc_time(m_dmi_read_latency, sc_core::SC_SEC));
283 other.set_write_latency(sc_core::sc_time(m_dmi_write_latency, sc_core::SC_SEC));
284 }
285 };
286
287 struct tlm_generic_payload_rpc {
288 sc_dt::uint64 m_address;
289 int m_command;
290 unsigned int m_length;
291 int m_response_status;
292 bool m_dmi;
293 unsigned int m_byte_enable_length;
294 unsigned int m_streaming_width;
295 int m_gp_option;
296
297 double m_sc_time;
298 double m_quantum_time;
299
300 std::vector<unsigned char> m_data;
301 std::vector<unsigned char> m_byte_enable;
302 // extensions will not be carried
303 MSGPACK_DEFINE_ARRAY(m_address, m_command, m_length, m_response_status, m_dmi, m_byte_enable_length,
304 m_streaming_width, m_gp_option, m_sc_time, m_quantum_time, m_data, m_byte_enable);
305
306 void from_tlm(tlm::tlm_generic_payload& other)
307 {
308 m_command = other.get_command();
309 m_address = other.get_address();
310 m_length = other.get_data_length();
311 m_response_status = other.get_response_status();
312 m_byte_enable_length = other.get_byte_enable_length();
313 m_streaming_width = other.get_streaming_width();
314 m_gp_option = other.get_gp_option();
315 m_dmi = other.is_dmi_allowed();
316 unsigned char* data_ptr = other.get_data_ptr();
317 if (m_length && data_ptr) {
318 m_data.resize(m_length);
319 std::copy(data_ptr, data_ptr + m_length, m_data.begin());
320 } else {
321 m_length = 0;
322 m_data.clear();
323 }
324 unsigned char* byte_enable_ptr = other.get_byte_enable_ptr();
325 if (m_byte_enable_length && byte_enable_ptr) {
326 m_byte_enable.resize(m_byte_enable_length);
327 std::copy(byte_enable_ptr, byte_enable_ptr + m_byte_enable_length, m_byte_enable.begin());
328 } else {
329 m_byte_enable_length = 0;
330 m_byte_enable.clear();
331 }
332 }
333 void deep_copy_to_tlm(tlm::tlm_generic_payload& other)
334 {
335 other.set_command((tlm::tlm_command)(m_command));
336 other.set_address(m_address);
337 other.set_data_length(m_length);
338 other.set_response_status((tlm::tlm_response_status)(m_response_status));
339 other.set_byte_enable_length(m_byte_enable_length);
340 other.set_streaming_width(m_streaming_width);
341 other.set_gp_option((tlm::tlm_gp_option)(m_gp_option));
342 other.set_dmi_allowed(m_dmi);
343 if (!m_length) {
344 other.set_data_ptr(nullptr);
345 } else {
346 other.set_data_ptr(reinterpret_cast<unsigned char*>(m_data.data()));
347 }
348 if (!m_byte_enable_length) {
349 other.set_byte_enable_ptr(nullptr);
350 } else {
351 other.set_byte_enable_ptr(reinterpret_cast<unsigned char*>(m_byte_enable.data()));
352 }
353 }
354
355 void update_to_tlm(tlm::tlm_generic_payload& other)
356 {
357 tlm::tlm_generic_payload tmp; // make use of TLM's built in update
358 if (!m_length) {
359 tmp.set_data_ptr(nullptr);
360 } else {
361 tmp.set_data_ptr(reinterpret_cast<unsigned char*>(m_data.data()));
362 }
363
364 if (!m_byte_enable_length) {
365 other.set_byte_enable_ptr(nullptr);
366 } else {
367 tmp.set_byte_enable_ptr(reinterpret_cast<unsigned char*>(m_byte_enable.data()));
368 }
369 tmp.set_data_length(m_length);
370 tmp.set_byte_enable_length(m_byte_enable_length);
371 tmp.set_response_status((tlm::tlm_response_status)m_response_status);
372 tmp.set_dmi_allowed(m_dmi);
373 other.update_original_from(tmp, m_byte_enable_length > 0);
374 }
375 };
376
377 cci::cci_broker_handle m_broker;
378 str_pairs m_cci_db;
379 std::mutex m_cci_db_mut;
380
381 class initiator_socket_spying
382 : public tlm_utils::simple_initiator_socket_b<MOD, BUSWIDTH, tlm::tlm_base_protocol_types,
383 sc_core::SC_ZERO_OR_MORE_BOUND>
384 {
385 using socket_type = tlm_utils::simple_initiator_socket_b<MOD, BUSWIDTH, tlm::tlm_base_protocol_types,
386 sc_core::SC_ZERO_OR_MORE_BOUND>;
387 using typename socket_type::base_target_socket_type; // tlm_utils::simple_initiator_socket<MOD,
388 // BUSWIDTH>::base_target_socket_type;
389
390 const std::function<void(std::string)> register_cb;
391
392 public:
393 initiator_socket_spying(const char* name, const std::function<void(std::string)>& f)
394 : socket_type::simple_initiator_socket_b(name), register_cb(f)
395 {
396 }
397
398 void bind(base_target_socket_type& socket)
399 {
400 socket_type::bind(socket);
401 register_cb(socket.get_base_export().name());
402 }
403
404 // hierarchial binding
405 void bind(tlm::tlm_initiator_socket<BUSWIDTH>& socket)
406 {
407 socket_type::bind(socket);
408 register_cb(socket.get_base_port().name());
409 }
410 };
411
412 /* NB use the EXPORT name, so as not to be hassled by the _port_0*/
413 std::string nameFromSocket(std::string s) { return s; }
414
415 void remote_register_boundto(std::string s) { SCP_DEBUG(()) << "Binding: " << s; }
416
417public:
418 // NB there is a 'feature' in multi passthrough sockets, the 'name' is always returned as the
419 // name of the socket itself, in our case "target_socket_0". This means that address lookup will
420 // only work for the FIRST such socket, all others will require a 'pass' or should be driven
421 // from models that dont use the CCI address map info.
422 // We can fix this using a template and vector of sockets....
423 using tlm_target_socket = tlm_utils::simple_target_socket_tagged_b<MOD, BUSWIDTH, tlm::tlm_base_protocol_types,
424 sc_core::SC_ZERO_OR_MORE_BOUND>;
425
426 sc_core::sc_vector<tlm_target_socket> target_sockets;
427 sc_core::sc_vector<initiator_socket_spying> initiator_sockets;
428
429 sc_core::sc_vector<InitiatorSignalSocket<bool>> initiator_signal_sockets;
430 sc_core::sc_vector<TargetSignalSocket<bool>> target_signal_sockets;
431
432 cci::cci_param<uint32_t> p_client_port;
433 cci::cci_param<uint32_t> p_server_port;
434 cci::cci_param<std::string> p_exec_path;
435 bool m_is_local;
436 cci::cci_param<std::string> p_sync_policy;
437 cci::cci_param<uint32_t> p_tlm_initiator_ports_num;
438 cci::cci_param<uint32_t> p_tlm_target_ports_num;
439 cci::cci_param<uint32_t> p_initiator_signals_num;
440 cci::cci_param<uint32_t> p_target_signals_num;
441
442private:
443 rpc::client* client = nullptr;
444 rpc::server* server = nullptr;
445 int m_child_pid = 0;
446 std::condition_variable is_client_connected;
447 std::condition_variable is_sc_status_set;
448 std::mutex client_conncted_mut;
449 std::mutex sc_status_mut;
450 std::mutex stop_mutex;
451 std::atomic_bool cancel_waiting;
452 std::thread::id sc_tid;
453 std::queue<std::pair<int, bool>> sig_queue;
454 std::mutex sig_queue_mut;
455 sc_core::sc_status m_remote_status = static_cast<sc_core::sc_status>(0);
456
457 int targets_bound = 0;
458
459 // std::shared_ptr<gs::tlm_quantumkeeper_extended> m_qk;
460 gs::runonsysc m_sc;
462
463#ifdef _WIN32
465#else // _WIN32
466 ProcAliveHandler pahandler;
467#endif
468 class trans_waiter
469 {
470 private:
471 std::string m_name;
472 std::queue<std::function<void()>> notifiers;
473 std::thread notifier_thread;
474 std::atomic_bool is_stopped;
475 std::atomic_bool is_started;
476
477 public:
478 std::vector<gs::async_event> data_ready_events;
479 std::vector<sc_core::sc_event> port_available_events;
480 std::vector<bool> is_port_busy;
481 std::condition_variable is_rpc_execed;
482 std::mutex start_stop_mutex;
483 std::mutex rpc_execed_mut;
490 private:
491 void notifier_task()
492 {
493 while (!is_stopped) {
494 std::unique_lock<std::mutex> ul(rpc_execed_mut);
495 is_rpc_execed.wait_for(ul, std::chrono::milliseconds(RPC_TIMEOUT),
496 [this]() { return (!notifiers.empty() || is_stopped); });
497 while (!notifiers.empty()) {
498 notifiers.front()();
499 notifiers.pop();
500 }
501 ul.unlock();
502 }
503 }
504
505 public:
506 trans_waiter(std::string p_name, uint32_t ev_num)
507 : m_name(p_name)
508 , data_ready_events(ev_num)
509 , port_available_events(ev_num)
510 , is_port_busy(ev_num, false)
511 , is_stopped(false)
512 , is_started(false)
513 {
514 }
515 void start()
516 {
517 {
518 std::lock_guard<std::mutex> start_lg(start_stop_mutex);
519 if (is_started) return;
520 is_started = true;
521 }
522
523 notifier_thread = std::thread(&trans_waiter::notifier_task, this);
524 }
525
526 void stop()
527 {
528 {
529 std::lock_guard<std::mutex> stop_lg(start_stop_mutex);
530 if (is_stopped || !is_started) return;
531 is_stopped = true;
532 }
533 {
534 std::lock_guard<std::mutex> lg(rpc_execed_mut);
535 is_rpc_execed.notify_one();
536 }
537
538 if (notifier_thread.joinable()) notifier_thread.join();
539 }
540
541 ~trans_waiter() { stop(); }
542
543 void enqueue_notifier(std::function<void()> notifier) { notifiers.push(notifier); }
544 };
545
546 std::unique_ptr<trans_waiter> btspt_waiter;
547
548 template <typename... Args>
549 std::future<RPCLIB_MSGPACK::object_handle> do_rpc_async_call(std::string const& func_name, Args... args)
550 {
551 if (!client) {
552 stop_and_exit();
553 }
554 std::future<RPCLIB_MSGPACK::object_handle> ret;
555 try {
556 ret = client->async_call(func_name, std::forward<Args>(args)...);
557 } catch (const std::future_error& e) {
558 SCP_DEBUG(()) << name() << " PassRPC::do_rpc_async_call() Connection with remote is closed: " << e.what();
559 stop_and_exit();
560 } catch (...) {
561 SCP_DEBUG(()) << name() << " PassRPC::do_rpc_async_call() Unknown error!";
562 stop_and_exit();
563 }
564 return ret;
565 }
566
567 template <typename T>
568 T do_rpc_async_get(std::future<RPCLIB_MSGPACK::object_handle> fut)
569 {
570 T ret;
571 try {
572 ret = do_rpc_as<T>(fut.get());
573 } catch (const std::future_error& e) {
574 SCP_DEBUG(()) << name() << " PassRPC::do_rpc_async_get() RPC future is corrupted: " << e.what();
575 stop_and_exit();
576 } catch (...) {
577 SCP_DEBUG(()) << name() << " PassRPC::do_rpc_async_get() Unknown error!";
578 stop_and_exit();
579 }
580 return ret;
581 }
582
583 template <typename T>
584 T do_rpc_as(RPCLIB_MSGPACK::object_handle handle)
585 {
586 T ret;
587 try {
588 ret = handle.template as<T>();
589 } catch (...) {
590 SCP_DEBUG(()) << name() << " PassRPC::do_rpc_as() RPC remote value is corrupted!";
591 stop_and_exit();
592 }
593 return ret;
594 }
595
596 template <typename... Args>
597 RPCLIB_MSGPACK::object_handle do_rpc_call(std::string const& func_name, Args... args)
598 {
599 if (!client) {
600 stop_and_exit();
601 }
602 RPCLIB_MSGPACK::object_handle ret;
603 try {
604 ret = client->call(func_name, std::forward<Args>(args)...);
605 }
606
607 catch (const std::future_error& e) {
608 SCP_DEBUG(()) << name() << " PassRPC::do_rpc_call() Connection with remote is closed: " << e.what();
609 stop_and_exit();
610 } catch (...) {
611 SCP_DEBUG(()) << name() << " PassRPC::do_rpc_call() Unknown error!";
612 stop_and_exit();
613 }
614
615 return ret;
616 }
617
618 bool is_local_mode() { return (m_container && m_is_local); }
619
620 void fw_b_transport(int id, tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) override
621 {
622 SCP_DEBUG(()) << "calling b_transport on initiator_socket_" << id << " " << scp::scp_txn_tostring(trans);
623 initiator_sockets[id]->b_transport(trans, delay);
624 SCP_DEBUG(()) << "return from b_transport on initiator_socket_" << id << " " << scp::scp_txn_tostring(trans);
625 }
626
627 unsigned int fw_transport_dbg(int id, tlm::tlm_generic_payload& trans) override
628 {
629 SCP_DEBUG(()) << "calling transport_dbg on initiator_socket_" << id << " " << scp::scp_txn_tostring(trans);
630 unsigned int ret = initiator_sockets[id]->transport_dbg(trans);
631 SCP_DEBUG(()) << "return from transport_dbg on initiator_socket_" << id << " " << scp::scp_txn_tostring(trans);
632 return ret;
633 }
634
635 bool fw_get_direct_mem_ptr(int id, tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data) override
636 {
637 SCP_DEBUG(()) << "calling get_direct_mem_ptr on initiator_socket_" << id << " " << scp::scp_txn_tostring(trans);
638 bool ret = initiator_sockets[id]->get_direct_mem_ptr(trans, dmi_data);
639 SCP_DEBUG(()) << "return from get_direct_mem_ptr on initiator_socket_" << id << " "
640 << " RET: " << std::boolalpha << ret << " " << scp::scp_txn_tostring(trans)
641 << " IS_READ_ALLOWED: " << std::boolalpha << dmi_data.is_read_allowed() << " "
642 << " IS_WRITE_ALLOWED: " << std::boolalpha << dmi_data.is_write_allowed();
643 return ret;
644 }
645
646 void fw_invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end) override
647 {
648 SCP_DEBUG(()) << " " << name() << " invalidate_direct_mem_ptr "
649 << " start address 0x" << std::hex << start << " end address 0x" << std::hex << end;
650 for (int i = 0; i < target_sockets.size(); i++) {
651 target_sockets[i]->invalidate_direct_mem_ptr(start, end);
652 }
653 }
654
655 void fw_handle_signal(int id, bool value) override
656 {
657 SCP_DEBUG(()) << "calling handle_signal on initiator_signal_socket_" << id << " value: " << std::boolalpha
658 << value;
659 initiator_signal_sockets[id]->write(value);
660 }
661
662 /* b_transport interface */
663 void b_transport(int id, tlm::tlm_generic_payload& trans, sc_core::sc_time& delay)
664 {
665 if (is_local_mode()) {
666 m_container->fw_b_transport(id, trans, delay);
667 return;
668 }
669
670 while (btspt_waiter->is_port_busy[id]) {
671 sc_core::wait(btspt_waiter->port_available_events[id]);
672 }
673 btspt_waiter->is_port_busy[id] = true;
674
675 tlm_generic_payload_rpc t;
676 tlm_generic_payload_rpc r;
677 double time = sc_core::sc_time_stamp().to_seconds();
678
679 uint64_t addr = trans.get_address();
680 // If we have a locally cached DMI, use it!
681#ifdef DMICACHE
682 auto c = in_cache(addr);
683 if (c) {
684 uint64_t len = trans.get_data_length();
685 if (addr >= c->get_start_address() && addr + len <= c->get_end_address()) {
686 switch (trans.get_command()) {
687 case tlm::TLM_IGNORE_COMMAND:
688 break;
689 case tlm::TLM_WRITE_COMMAND:
690 memcpy(c->get_dmi_ptr() + (addr - c->get_start_address()), trans.get_data_ptr(), len);
691 break;
692 case tlm::TLM_READ_COMMAND:
693 memcpy(trans.get_data_ptr(), c->get_dmi_ptr() + (addr - c->get_start_address()), len);
694 break;
695 }
696 trans.set_dmi_allowed(true);
697 trans.set_response_status(tlm::TLM_OK_RESPONSE);
698 return;
699 }
700 }
701#endif
702 t.from_tlm(trans);
703 t.m_quantum_time = delay.to_seconds();
704 t.m_sc_time = sc_core::sc_time_stamp().to_seconds();
711 if (std::this_thread::get_id() == sc_tid && sc_core::sc_get_status() >= sc_core::sc_status::SC_RUNNING &&
712 sc_core::sc_get_curr_process_kind() != sc_core::sc_curr_proc_kind::SC_NO_PROC_) {
713 SCP_DEBUG(()) << name() << " B_TSPT handle reentrancy, sc_get_curr_simcontext " << sc_get_curr_simcontext()
714 << " SC current process kind = " << sc_core::sc_get_curr_process_kind();
715 btspt_waiter->start();
716
717 std::unique_lock<std::mutex> ul(btspt_waiter->rpc_execed_mut);
718 btspt_waiter->enqueue_notifier([&]() {
719 r = do_rpc_as<tlm_generic_payload_rpc>(do_rpc_call("b_tspt", id, t));
720 btspt_waiter->data_ready_events[id].async_notify();
721 });
722 btspt_waiter->is_rpc_execed.notify_one();
723 ul.unlock();
724 SCP_DEBUG(()) << name() << " B_TSPT wait for event, sc_get_curr_simcontext " << sc_get_curr_simcontext()
725 << " SC current process kind = " << sc_core::sc_get_curr_process_kind();
726 if (sc_core::sc_get_curr_process_kind() != sc_core::sc_curr_proc_kind::SC_METHOD_PROC_) {
727 sc_core::wait(btspt_waiter->data_ready_events[id]); // systemc wait
728 } else {
729 SCP_FATAL(()) << name() << " b_transport was called from the context of SC_METHOD!";
730 }
731 } else {
732 r = do_rpc_as<tlm_generic_payload_rpc>(do_rpc_call("b_tspt", id, t));
733 }
734
735 r.update_to_tlm(trans);
736 delay = sc_core::sc_time(r.m_quantum_time, sc_core::SC_SEC);
737 sc_core::sc_time other_time = sc_core::sc_time(r.m_sc_time, sc_core::SC_SEC);
738 btspt_waiter->is_port_busy[id] = false;
739 btspt_waiter->port_available_events[id].notify(sc_core::SC_ZERO_TIME);
740 }
741 tlm_generic_payload_rpc b_transport_rpc(int id, tlm_generic_payload_rpc t)
742 {
743 tlm::tlm_generic_payload trans;
744 t.deep_copy_to_tlm(trans);
745 sc_core::sc_time delay = sc_core::sc_time(t.m_quantum_time, sc_core::SC_SEC);
746 sc_core::sc_time other_time = sc_core::sc_time(t.m_sc_time, sc_core::SC_SEC);
747
748 m_sc.run_on_sysc([&] { initiator_sockets[id]->b_transport(trans, delay); });
749 t.from_tlm(trans);
750 t.m_quantum_time = delay.to_seconds();
751 return t;
752 }
753
754 /* Debug transport interface */
755 unsigned int transport_dbg(int id, tlm::tlm_generic_payload& trans)
756 {
757 if (is_local_mode()) {
758 return m_container->fw_transport_dbg(id, trans);
759 }
760 SCP_DEBUG(()) << name() << " ->remote debug tlm " << txn_str(trans);
761 tlm_generic_payload_rpc t;
762 tlm_generic_payload_rpc r;
763
764 t.from_tlm(trans);
765 r = do_rpc_as<tlm_generic_payload_rpc>(do_rpc_call("dbg_tspt", id, t));
766 r.update_to_tlm(trans);
767 SCP_DEBUG(()) << name() << " <-remote debug tlm done " << txn_str(trans);
768 // this is not entirely accurate, but see below
769 return trans.get_response_status() == tlm::TLM_OK_RESPONSE ? trans.get_data_length() : 0;
770 }
771 tlm_generic_payload_rpc transport_dbg_rpc(int id, tlm_generic_payload_rpc t)
772 {
773 tlm::tlm_generic_payload trans;
774 t.deep_copy_to_tlm(trans);
775 int ret_len;
776 SCP_DEBUG(()) << name() << " remote-> debug tlm " << txn_str(trans);
777 ret_len = initiator_sockets[id]->transport_dbg(trans);
778 t.from_tlm(trans);
779 SCP_DEBUG(()) << name() << " remote<- debug tlm done " << txn_str(trans);
780
781 if (!(trans.get_data_length() == ret_len || trans.get_response_status() != tlm::TLM_OK_RESPONSE)) {
782 assert(false);
783 SCP_WARN(()) << "debug transaction not able to access required length of data.";
784 }
785 return t;
786 }
787
788 bool get_direct_mem_ptr(int id, tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data)
789 {
790 if (is_local_mode()) {
791 return m_container->fw_get_direct_mem_ptr(id, trans, dmi_data);
792 }
793 tlm::tlm_dmi* c;
794 SCP_DEBUG(()) << " " << name() << " get_direct_mem_ptr to address "
795 << "0x" << std::hex << trans.get_address();
796
797#ifdef DMICACHE
798 c = in_cache(trans.get_address());
799 if (c) {
800 dmi_data = *c;
801 return !(dmi_data.is_none_allowed());
802 }
803#endif
804 tlm_generic_payload_rpc t;
805 tlm_dmi_rpc r;
806 t.from_tlm(trans);
807 r = do_rpc_as<tlm_dmi_rpc>(do_rpc_call("dmi_req", id, t));
808
809 if (r.m_shmem_size == 0) {
810 SCP_DEBUG(()) << name() << "DMI OK, but no shared memory available?" << trans.get_address();
811 return false;
812 }
813 r.to_tlm(dmi_data);
814#ifdef DMICACHE
815 assert(m_dmi_cache.count(dmi_data.get_start_address()) == 0);
816 m_dmi_cache[dmi_data.get_start_address()] = dmi_data;
817#endif
818 return !(dmi_data.is_none_allowed());
819 }
820
821 tlm_dmi_rpc get_direct_mem_ptr_rpc(int id, tlm_generic_payload_rpc t)
822 {
823 tlm::tlm_generic_payload trans;
824 t.deep_copy_to_tlm(trans);
825
826 SCP_DEBUG(()) << " " << name() << " get_direct_mem_ptr " << txn_str(trans);
827
828 tlm::tlm_dmi dmi_data;
829 tlm_dmi_rpc ret;
830 ret.m_shmem_size = 0;
831 if (initiator_sockets[id]->get_direct_mem_ptr(trans, dmi_data)) {
832 ShmemIDExtension* ext = trans.get_extension<ShmemIDExtension>();
833 if (!ext) return ret;
834 ret.from_tlm(dmi_data, ext);
835 }
836 return ret;
837 }
838
839 /* Invalidate DMI Interface */
840 void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end)
841 {
842 if (is_local_mode()) {
843 m_container->fw_invalidate_direct_mem_ptr(start, end);
844 }
845 SCP_DEBUG(()) << " " << name() << " invalidate_direct_mem_ptr "
846 << " start address 0x" << std::hex << start << " end address 0x" << std::hex << end;
847 do_rpc_async_call("dmi_inv", start, end);
848 }
849 void invalidate_direct_mem_ptr_rpc(sc_dt::uint64 start, sc_dt::uint64 end)
850 {
851 SCP_DEBUG(()) << " " << name() << " invalidate_direct_mem_ptr "
852 << " start address 0x" << std::hex << start << " end address 0x" << std::hex << end;
853#ifdef DMICACHE
854 cache_clean(start, end);
855#endif
856 for (int i = 0; i < target_sockets.size(); i++) {
857 target_sockets[i]->invalidate_direct_mem_ptr(start, end);
858 }
859 }
860
864 bool is_self_param(const std::string& parent, const std::string& parname, const std::string& value)
865 {
866 std::vector<std::string> match_words = {
867 "args", "moduletype", "initiator_socket", "target_socket", "initiator_signal_socket", "target_signal_socket"
868 };
869 return (std::find_if(match_words.begin(), match_words.end(), [parent, parname, value](std::string entry) {
870 std::string search_str = parent + "." + entry;
871 if (entry == "moduletype" && value == "\"RemotePass\"") search_str = entry;
872 return parname.find(search_str) != std::string::npos;
873 }) != match_words.end());
874 }
875
876 str_pairs get_cci_db()
877 {
878 std::string parent = std::string(name());
879 str_pairs ret;
880 for (auto p : m_broker.get_unconsumed_preset_values()) {
881 std::string name = p.first;
882 std::string k = p.first;
883 if (k.find(parent) == 0) {
884 if (is_self_param(parent, k, p.second.to_json())) continue;
885 k = k.substr(parent.length() + 1);
886 ret.push_back(std::make_pair("$" + k, p.second.to_json()));
887 // mark parameters in the remote as 'used'
888 m_broker.ignore_unconsumed_preset_values(
889 [name](const std::pair<std::string, cci::cci_value>& iv) -> bool { return iv.first == name; });
890 } else if (k.find('.') == std::string::npos) {
891 ret.push_back(std::make_pair(k, p.second.to_json()));
892 }
893 }
894 return ret;
895 }
896
897 void set_cci_db(str_pairs db)
898 {
899 std::string modname = std::string(name());
900 std::string parent = std::string(modname).substr(0, modname.find_last_of("."));
901
902 for (auto p : db) {
903 std::string parname;
904 if (p.first[0] == '$') {
905 parname = parent + "." + p.first.substr(1);
906 } else if (p.first[0] == '@') {
907 parname = modname + "." + p.first.substr(1);
908 } else {
909 parname = p.first;
910 }
911 auto handle = m_broker.get_param_handle(parname);
912 if (handle.is_valid())
913 handle.set_cci_value(cci::cci_value::from_json(p.second));
914 else
915 m_broker.set_preset_cci_value(parname, cci::cci_value::from_json(p.second));
916
917 SCP_DEBUG(()) << "Setting " << parname << " to " << p.second;
918 }
919 }
920
921public:
922 PassRPC(const sc_core::sc_module_name& nm, bool is_local = false)
923 : sc_core::sc_module(nm)
924 , m_broker(cci::cci_get_broker())
925 , initiator_sockets("initiator_socket")
926 , target_sockets("target_socket")
927 , initiator_signal_sockets("initiator_signal_socket")
928 , target_signal_sockets("target_signal_socket")
929 , p_client_port("client_port", 0,
930 "The port that should be used to connect this client to the "
931 "remote server")
932 , p_server_port("server_port", 0, "The port that should be used to server on")
933 , p_exec_path("exec_path", "",
934 "The path to the executable that should be started by "
935 "the bridge")
936 , m_is_local(is_local)
937 , p_sync_policy("sync_policy", "multithread-unconstrained", "Sync policy for the remote")
938 , p_tlm_initiator_ports_num("tlm_initiator_ports_num", 0, "number of tlm initiator ports")
939 , p_tlm_target_ports_num("tlm_target_ports_num", 0, "number of tlm target ports")
940 , p_initiator_signals_num("initiator_signals_num", 0, "number of initiator signals")
941 , p_target_signals_num("target_signals_num", 0, "number of target signals")
942 , cancel_waiting(false)
943 {
944 SigHandler::get().add_sigint_handler(Handler_CB::PASS);
945 SigHandler::get().register_on_exit_cb(std::string(name()) + ".gs::PassRPC::stop", [this]() { stop(); });
946
947 sc_tid = std::this_thread::get_id();
948
949 SCP_DEBUG(()) << "PassRPC constructor";
950 m_container = dynamic_cast<gs::ModuleFactory::ContainerBase*>(get_parent_object());
951 if (is_local_mode()) {
952 SCP_DEBUG(()) << "Working in LOCAL mode!";
953 } else {
954 SCP_DEBUG(()) << get_current_process_id() << " IS THE RPC PID, " << std::this_thread::get_id()
955 << " is the thread ID";
956
957 // always serve on a new port
958 server = new rpc::server(p_server_port);
959 server->suppress_exceptions(true);
960 p_server_port = server->port();
961 assert(p_server_port > 0);
962
963 /* Get parent server port if current process is child */
964 if (!in_server() && p_client_port.get_value() == 0) {
965 p_client_port = get_rpc_server_port();
966 }
967
968 // other end contacted us, connect to their port
969 // and return back the cci database
970 server->bind("reg", [&](int port) {
971 SCP_DEBUG(()) << "reg " << name() << ", pid: " << get_current_process_id() << ", port: " << port;
972 assert(p_client_port == 0 && client == nullptr);
973 p_client_port = port;
974 if (!client) client = new rpc::client("127.0.0.1", p_client_port);
975 std::unique_lock<std::mutex> ul(client_conncted_mut);
976 is_client_connected.notify_one();
977 ul.unlock();
978 // we are not interested in the return future from async_call
979#ifdef _WIN32
980 // Send to partner process a duplicated copy of the current process handler.
981 do_rpc_async_call("partner_handle",
982 reinterpret_cast<uintptr_t>(m_partner_process_manager.get_process_dup()));
983#else
984 do_rpc_async_call("sock_pair", pahandler.get_sockpair_fd0(), pahandler.get_sockpair_fd1());
985#endif // _WIN32
986 return get_cci_db();
987 });
988
989 // would it be better to have a 'remote cci broker' that connected back,
990 server->bind("cci_db", [&](str_pairs db) {
991 if (sc_core::sc_get_status() > sc_core::sc_status::SC_BEFORE_END_OF_ELABORATION) {
992 std::cerr << "Attempt to do cci_db() RPC after "
993 "sc_core::sc_status::SC_BEFORE_END_OF_ELABORATION"
994 << std::endl;
995 exit(1);
996 }
997 std::lock_guard<std::mutex> lg(m_cci_db_mut);
998 m_cci_db.insert(m_cci_db.end(), db.begin(), db.end());
999 return;
1000 });
1001
1002 server->bind("status", [&](int s) {
1003 SCP_DEBUG(()) << "SIMULATION STATE " << name() << " to status " << s;
1004 assert(s > m_remote_status);
1005 m_remote_status = static_cast<sc_core::sc_status>(s);
1006 std::lock_guard<std::mutex> lg(sc_status_mut);
1007 is_sc_status_set.notify_one();
1008 return;
1009 });
1010
1011 server->bind("b_tspt", [&](int id, tlm_generic_payload_rpc txn) {
1012 try {
1013 return PassRPC::b_transport_rpc(id, txn);
1014 } catch (std::runtime_error const& e) {
1015 std::cerr << "Main Error: '" << e.what() << "'\n";
1016 exit(1);
1017 } catch (const std::exception& exc) {
1018 std::cerr << "main Error: '" << exc.what() << "'\n";
1019 exit(1);
1020 } catch (...) {
1021 std::cerr << "Unknown error (main.cc)!\n";
1022 exit(1);
1023 }
1024 });
1025
1026 server->bind("dbg_tspt", [&](int id, tlm_generic_payload_rpc txn) {
1027 SCP_DEBUG(()) << "Got DBG Tspt";
1028 return PassRPC::transport_dbg_rpc(id, txn);
1029 });
1030
1031 server->bind("dmi_inv", [&](uint64_t start, uint64_t end) {
1032 return PassRPC::invalidate_direct_mem_ptr_rpc(start, end);
1033 });
1034
1035 server->bind("dmi_req",
1036 [&](int id, tlm_generic_payload_rpc txn) { return PassRPC::get_direct_mem_ptr_rpc(id, txn); });
1037
1038 server->bind("exit", [&](int i) {
1039 SCP_DEBUG(()) << "exit " << name();
1040 m_sc.run_on_sysc([&] {
1041 rpc::this_session().post_exit();
1042 delete client;
1043 client = nullptr;
1044 sc_core::sc_stop();
1045 });
1046 // m_qk->stop();
1047 return;
1048 });
1049
1050 server->bind("signal", [&](int i, bool v) {
1051 if (sc_core::sc_get_status() < sc_core::sc_status::SC_START_OF_SIMULATION) {
1052 std::lock_guard<std::mutex> lg(sig_queue_mut);
1053 sig_queue.push(std::make_pair(i, v));
1054 return;
1055 }
1056 m_sc.run_on_sysc([&] { initiator_signal_sockets[i]->write(v); },
1057 (sc_core::sc_get_status() < sc_core::sc_status::SC_RUNNING ? false : true));
1058 return;
1059 });
1060
1061#ifdef _WIN32
1062 server->bind("partner_handle", [&](uintptr_t partner_handle_value) {
1063 HANDLE partner_handle = reinterpret_cast<HANDLE>(partner_handle_value);
1064 m_partner_process_manager.set_partner_process(partner_handle);
1065 m_partner_process_manager.on_partner_exit([&]() {
1066 std::cerr << "remote process (" << get_current_process_id() << ") detected parent ("
1067 << GetProcessId(partner_handle) << ") exit!" << std::endl;
1068 });
1069 return;
1070 });
1071#else
1072 server->bind("sock_pair", [&](int sock_fd0, int sock_fd1) {
1073 pahandler.recv_sockpair_fds_from_remote(sock_fd0, sock_fd1);
1074 pahandler.check_parent_conn_nth([&]() {
1075 std::cerr << "remote process (" << getpid() << ") detected parent (" << pahandler.get_ppid()
1076 << ") exit!" << std::endl;
1077 });
1078 return;
1079 });
1080#endif //_WIN32
1081
1082 server->async_run(1);
1083
1084 if (p_client_port) {
1085 SCP_INFO(()) << "Connecting client on port " << p_client_port;
1086 if (!client) client = new rpc::client("127.0.0.1", p_client_port);
1087 set_cci_db(do_rpc_as<str_pairs>(do_rpc_call("reg", (int)p_server_port)));
1088 }
1089 }
1090
1091 btspt_waiter = std::make_unique<trans_waiter>("btspt_waiter", p_tlm_target_ports_num.get_value());
1092
1093 initiator_sockets.init(p_tlm_initiator_ports_num.get_value(), [this](const char* n, int i) {
1094 return new initiator_socket_spying(n, [&](std::string s) -> void { remote_register_boundto(s); });
1095 });
1096 target_sockets.init(p_tlm_target_ports_num.get_value(),
1097 [this](const char* n, int i) { return new tlm_target_socket(n); });
1098 initiator_signal_sockets.init(p_initiator_signals_num.get_value(),
1099 [this](const char* n, int i) { return new InitiatorSignalSocket<bool>(n); });
1100 target_signal_sockets.init(p_target_signals_num.get_value(),
1101 [this](const char* n, int i) { return new TargetSignalSocket<bool>(n); });
1102
1103 for (int i = 0; i < p_tlm_target_ports_num.get_value(); i++) {
1104 target_sockets[i].register_b_transport(this, &PassRPC::b_transport, i);
1105 target_sockets[i].register_transport_dbg(this, &PassRPC::transport_dbg, i);
1106 target_sockets[i].register_get_direct_mem_ptr(this, &PassRPC::get_direct_mem_ptr, i);
1107 }
1108
1109 for (int i = 0; i < p_tlm_initiator_ports_num.get_value(); i++) {
1110 initiator_sockets[i].register_invalidate_direct_mem_ptr(this, &PassRPC::invalidate_direct_mem_ptr);
1111 }
1112
1113 for (int i = 0; i < p_target_signals_num.get_value(); i++) {
1114 target_signal_sockets[i].register_value_changed_cb([&, i](bool value) {
1115 if (is_local_mode()) {
1116 m_container->fw_handle_signal(i, value);
1117 return;
1118 }
1119 do_rpc_async_call("signal", i, value);
1120 });
1121 }
1122
1123 if (!is_local_mode()) {
1124 if (in_server()) {
1125 std::list<std::string> remote_process_args;
1126
1127 build_remote_cmdline(remote_process_args);
1128 launch_remote_process(remote_process_args);
1129 }
1130
1131 // Make sure by now the client is connected so we can send/recieve.
1132 std::unique_lock<std::mutex> ul(client_conncted_mut);
1133 is_client_connected.wait(ul, [&]() { return (p_client_port > 0 || cancel_waiting); });
1134 ul.unlock();
1135 send_status();
1136 }
1137 } // namespace gs
1138 PassRPC(const sc_core::sc_module_name& nm, int port): PassRPC(nm, "", port) {}; // convenience constructor
1139
1140#ifdef _WIN32
1141 void launch_remote_process(const std::list<std::string>& remote_process_args)
1142 {
1143 m_partner_process_manager.create_partner_process(p_exec_path.get_value(), remote_process_args);
1144 }
1145
1146 int get_current_process_id() { return static_cast<int>(GetCurrentProcessId()); }
1147
1148#else
1149 void launch_remote_process(const std::list<std::string>& remote_process_args)
1150 {
1151 // Convert remote_process_args (list<string>) to a NULL-terminated argv-style array
1152 std::vector<const char*> remote_argv_vec;
1153 remote_argv_vec.reserve(remote_process_args.size() + 1);
1154 for (const auto& arg : remote_process_args) {
1155 remote_argv_vec.push_back(arg.c_str());
1156 }
1157 remote_argv_vec.push_back(nullptr); // exec* expects a terminating null
1158
1159 const char* const* remote_argv = remote_argv_vec.data();
1160
1161 m_child_pid = fork();
1162
1163 if (m_child_pid > 0) {
1164 pahandler.setup_parent_conn_checker();
1165 SigHandler::get().set_nosig_chld_stop();
1166 SigHandler::get().add_sigchld_handler(Handler_CB::EXIT);
1167 } else if (m_child_pid == 0) {
1168 execv(p_exec_path.get_value().c_str(), const_cast<char**>(&remote_argv_vec[0]));
1169
1170 SCP_FATAL(()) << "Unable to exec the remote child process, '" << p_exec_path.get_value()
1171 << "', error: " << std::strerror(errno);
1172 } else {
1173 SCP_FATAL(()) << "failed to fork remote process, error: " << std::strerror(errno);
1174 }
1175 }
1176
1177 int get_current_process_id() { return getpid(); }
1178#endif // _WIN32
1179
1180 bool in_server() { return !p_exec_path.get_value().empty(); }
1181
1182 void build_remote_cmdline(std::list<std::string>& remote_cmdline)
1183 {
1184 // Add executable path as first parameter
1185 remote_cmdline.push_back(p_exec_path.get_value());
1186
1187 // Add server port as --param argument for ArgParser
1188 remote_cmdline.push_back("--param");
1189 remote_cmdline.push_back("rpc_server_port=" + std::to_string(p_server_port.get_value()));
1190
1191 // Get unconsumed preset parameters from the cci broker
1192 auto argv_cci_children = gs::sc_cci_children((std::string(name()) + ".remote_argv").c_str());
1193
1194 // Add unconsumed preset parameters to the remote command line
1196 }
1197
1198 void send_status()
1199 {
1200 SCP_DEBUG(()) << "SIMULATION STATE send " << name() << " to status " << sc_core::sc_get_status();
1201 do_rpc_call("status", static_cast<int>(sc_core::sc_get_status()));
1202 std::unique_lock<std::mutex> ul(sc_status_mut);
1203 is_sc_status_set.wait(ul, [&]() { return (m_remote_status >= sc_core::sc_get_status() || cancel_waiting); });
1204 ul.unlock();
1205 SCP_DEBUG(()) << "SIMULATION STATE synced " << name() << " to status " << sc_core::sc_get_status();
1206 }
1207
1208 void handle_before_sim_start_signals()
1209 {
1210 std::lock_guard<std::mutex> lg(sig_queue_mut);
1211 while (!sig_queue.empty()) {
1212 std::pair<int, bool> sig = sig_queue.front();
1213 sig_queue.pop();
1214 m_sc.run_on_sysc([&] { initiator_signal_sockets[sig.first]->write(sig.second); }, false);
1215 }
1216 }
1217
1218 uint32_t get_rpc_server_port()
1219 {
1220 auto handle = m_broker.get_param_handle("rpc_server_port");
1221 uint32_t rpc_server_port = std::numeric_limits<uint32_t>::max();
1222 assert(handle.is_valid());
1223 try {
1224 rpc_server_port = handle.get_cci_value().get_uint();
1225 } catch (const std::exception& e) {
1226 std::cerr << e.what() << '\n';
1227 }
1228
1229 if (rpc_server_port > 65535) {
1230 SCP_FATAL(())("rpc_server_port parameter value {} is out of range (0-65535)", rpc_server_port);
1231 }
1232
1233 return rpc_server_port;
1234 }
1235
1236 void stop()
1237 {
1238 {
1239 std::lock_guard<std::mutex> lg(stop_mutex);
1240 if (cancel_waiting || is_local_mode()) return;
1241 cancel_waiting = true;
1242 }
1243 {
1244 std::lock_guard<std::mutex> cc_lg(client_conncted_mut);
1245 is_client_connected.notify_one();
1246 }
1247 {
1248 std::lock_guard<std::mutex> scs_lg(sc_status_mut);
1249 is_sc_status_set.notify_one();
1250 }
1251 btspt_waiter->stop();
1252 if (server) {
1253 server->close_sessions();
1254 server->stop();
1255 delete server;
1256 server = nullptr;
1257 }
1258 if (client) {
1259 do_rpc_async_call("exit", 0);
1260 delete client;
1261 client = nullptr;
1262 }
1263 }
1264
1265 void stop_and_exit()
1266 {
1267 stop();
1269 }
1270
1271 void before_end_of_elaboration() override
1272 {
1273 if (is_local_mode()) return;
1274 send_status();
1275 std::lock_guard<std::mutex> lg(m_cci_db_mut);
1276 set_cci_db(m_cci_db);
1277 }
1278
1279 void end_of_elaboration() override
1280 {
1281 if (is_local_mode()) return;
1282 send_status();
1283 }
1284
1285 void start_of_simulation() override
1286 {
1287 if (is_local_mode()) return;
1288 send_status();
1289 handle_before_sim_start_signals();
1290 }
1291
1292 PassRPC() = delete;
1293 PassRPC(const PassRPC&) = delete;
1294 ~PassRPC()
1295 {
1296 SigHandler::get().deregister_on_exit_cb(std::string(name()) + ".gs::PassRPC::stop");
1297 if (is_local_mode()) return;
1298 SCP_DEBUG(()) << "EXIT " << name();
1299 stop();
1300#ifdef DMICACHE
1301 m_dmi_cache.clear();
1302#endif
1303 }
1304
1305 void end_of_simulation() override
1306 {
1307 if (is_local_mode()) return;
1308 stop();
1309 }
1310}; // namespace gs
1311template <unsigned int BUSWIDTH = DEFAULT_TLM_BUSWIDTH>
1312class LocalPass : public PassRPC<>
1313{
1314public:
1315 SCP_LOGGER(());
1316 LocalPass(const sc_core::sc_module_name& n): PassRPC(n, true) { SCP_DEBUG(()) << "LocalPass constructor"; }
1317
1318 virtual ~LocalPass() = default;
1319};
1320
1321template <unsigned int BUSWIDTH = DEFAULT_TLM_BUSWIDTH>
1322class RemotePass : public PassRPC<>
1323{
1324public:
1325 SCP_LOGGER(());
1326 RemotePass(const sc_core::sc_module_name& n): PassRPC(n, false) { SCP_DEBUG(()) << "RemotePass constructor"; }
1327
1328 virtual ~RemotePass() = default;
1329};
1330
1331} // namespace gs
1332// need to be register without the dynamic library feature because of the order of execution of the code.
1335GSC_MODULE_REGISTER(LocalPass);
1336GSC_MODULE_REGISTER(RemotePass);
1337
1338#endif
Definition target.h:160
Definition remote.h:1313
Definition module_factory_container.h:49
Definition remote.h:161
Definition uutils.h:169
void check_parent_conn_nth(std::function< void()> on_parent_exit)
Definition uutils.cc:486
Definition remote.h:1323
Definition shmem_extension.h:24
Definition runonsysc.h:23
bool run_on_sysc(std::function< void()> job_entry, bool wait=true)
Run a job on the SystemC kernel thread.
Definition runonsysc.h:211
Definition transaction_forwarder_if.h:23
Tool which reads a Lua configuration file and sets parameters.
Definition biflow.cc:10
std::list< std::string > sc_cci_children(sc_core::sc_module_name name)
return a list of 'unconsumed' children from the given module name, can be used inside or outside the ...
Definition cciutils.cc:63