1 //
2 // Copyright (c) 2010-2025 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 #include "renode_bridge.h"
8 
9 #include <cstdint>
10 #include <cstdio>
11 #include <cstdlib>
12 #include <chrono>
13 #include <thread>
14 #ifdef __linux__
15 #include <fcntl.h>
16 #include <unistd.h>
17 #include <sys/mman.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #endif
21 
22 #include "socket-cpp/Socket/TCPClient.h"
23 
24 // ================================================================================
25 //  > Communication protocol
26 // ================================================================================
27 
28 // Forward socket: Request from Renode, Response from SystemC
29 // Backward socket: Request from SystemC, Response From Renode
30 
31 enum renode_action : uint8_t {
32   INIT = 0,
33   // Socket: forward only
34   // Init message received for the second time signifies Renode terminated and
35   // the process should exit. Request:
36   //     data_length: ignored
37   //     address: ignored
38   //     connection_index: ignored
39   //     payload: time synchronization granularity in us
40   //       TIMESYNC messages will be sent with this period. This does NOT
41   //       guarantee that the processes will never desynchronize by more than
42   //       this amount.
43   // Response:
44   //      Identical to the request message.
45   READ = 1,
46   // Socket: forward, backward
47   // Request:
48   //     data_length: number of bytes to read [1, 8]
49   //     address: address to read from, in target's address space
50   //     payload: ignored
51   //     connection_index: 0 for SystemBus, [1, NUM_DIRECT_CONNECTIONS]
52   //     for direct connection
53   // Response:
54   //     address: duration of transaction in us
55   //     payload: read value
56   //     connection_index: 0=DMI unsupported, 1=DMI supported
57   //     Otherwise identical to the request message.
58   WRITE = 2,
59   // Socket: forward, backward
60   // Request:
61   //     data_length: number of bytes to write [1, 8].
62   //     address: address to write to, in target's address space
63   //     payload: value to write
64   //     connection_index: 0 for SystemBus, [1, NUM_DIRECT_CONNECTIONS] for
65   //       direct connection
66   // Response:
67   //     address: duration of transaction in us
68   //     connection_index: 0=DMI unsupported, 1=DMI supported
69   //     Otherwise identical to the request message.
70   TIMESYNC = 3,
71   // Socket: forward only
72   // Request:
73   //     data_length: ignored
74   //     address: ignored
75   //     connection_index: ignored
76   // Response:
77   //     payload: current target virtual time in microseconds
78   //     Otherwise identical to the request message.
79   GPIOWRITE = 4,
80   // Socket: forward, backward
81   // Request:
82   //     data_length: ignored
83   //     address: ignored
84   //     connection_index: ignored
85   //     payload: state of GPIO bitfield
86   // Response:
87   //     Identical to the request message.
88   RESET = 5,
89   // Socket: forward
90   // Request:
91   //     data_length: ignored
92   //     address: ignored
93   //     connection_index: ignored
94   //     payload: ignored
95   // Response:
96   //     Identical to the request message.
97   DMIREQ = 6,
98   // Socket: backward
99   // Request:
100   //     data_length: ignored
101   //     address: address in target's address space
102   //     payload: ignored
103   //     to write connection_index: 0 for SystemBus
104   // Response is a dmi_message.
105   TBSINVALID = 7,
106   // Socket: backward
107   // Request:
108   //     data_length: ignored
109   //     connection_index: ignored
110   //     address: start_address
111   //     payload: end_address
112   // Response:
113   //     Identical to the request message.
114   READ_REGISTER = 8,
115   // Socket: forward only
116   // Request:
117   //     data_length: number of bytes to read [1, 8]
118   //     address: register to read from, in target's register space
119   //     payload: value to write
120   //     connection_index: 0 for SystemBus, [1, NUM_DIRECT_CONNECTIONS]
121   //       for direct connection
122   // Response:
123   //     address: duration of transaction in us
124   //     payload: read value
125   //     Otherwise identical to the request message.
126   WRITE_REGISTER = 9,
127   // Socket: forward only
128   // Request:
129   //     data_length: number of bytes to write [1, 8].
130   //     address: register to write to, in target's register space
131   //     payload: value to write
132   //     connection_index: 0 for SystemBus, [1, NUM_DIRECT_CONNECTIONS] for
133   //       direct connection
134   // Response:
135   //     address: duration of transaction in us
136   //     Otherwise identical to the request message.
137 };
138 
139 #pragma pack(push, 1)
140 struct renode_message {
141   renode_action action;
142   uint8_t data_length;
143   uint8_t connection_index;
144   uint64_t address;
145   uint64_t payload;
146 };
147 
148 struct dmi_message {
149   renode_action action;
150   uint8_t allowed;
151   uint64_t start_address;
152   uint64_t end_address;
153   uint64_t mmf_offset;
154   char mmf_path[256];
155 };
156 #pragma pack(pop)
157 
158 // ================================================================================
159 //  > Debug printing
160 // ================================================================================
161 
print_renode_message(renode_message * message)162 static void print_renode_message(renode_message *message) {
163   if (message->action == TIMESYNC)
164     return;
165   uint64_t thread_id = 0;
166   { // Get a cross-platform thread identifier
167     std::hash<std::thread::id> hasher;
168     thread_id = hasher(std::this_thread::get_id());
169   }
170   printf("[0x%08lX][RENODE MESSAGE] Action: ", thread_id);
171   switch (message->action) {
172   case INIT:
173     printf("INIT");
174     break;
175   case READ:
176     printf("READ");
177     break;
178   case WRITE:
179     printf("WRITE");
180     break;
181   case TIMESYNC:
182     printf("TIMESYNC");
183     break;
184   case GPIOWRITE:
185     printf("GPIOWRITE");
186     break;
187   case RESET:
188     printf("RESET");
189     break;
190   default:
191     printf("INVALID");
192   }
193   printf(" | Address: 0x%08lX", message->address);
194   printf(" | Payload: 0x%08lX", message->payload);
195   printf(" | ConnIdx: %u\n", message->connection_index);
196 }
197 
print_transaction_status(tlm::tlm_generic_payload * payload)198 static void print_transaction_status(tlm::tlm_generic_payload *payload) {
199   tlm::tlm_response_status status = payload->get_response_status();
200   std::string response_string = payload->get_response_string();
201   printf("Renode transport status: %s\n", response_string.c_str());
202 }
203 
204 // ================================================================================
205 //  > Renode Bridge SystemC module
206 // ================================================================================
207 
initialize_payload(tlm::tlm_generic_payload * payload,const renode_message * message,uint8_t * data)208 static void initialize_payload(tlm::tlm_generic_payload *payload,
209                                const renode_message *message, uint8_t *data) {
210   tlm::tlm_command command = tlm::TLM_IGNORE_COMMAND;
211   switch (message->action) {
212   case WRITE:
213   case WRITE_REGISTER:
214     command = tlm::TLM_WRITE_COMMAND;
215     break;
216   case READ:
217   case READ_REGISTER:
218     command = tlm::TLM_READ_COMMAND;
219     break;
220   default:
221     assert(!"Only WRITE and READ messages should initialize TLM payload");
222   }
223 
224   payload->set_command(command);
225   // Right now the address visible to SystemC is directly the offset
226   // from Renode; i. e. if we write to address 0x9000100 and the peripheral
227   // address is 0x9000000, then address in SystemC will be 0x100.
228   payload->set_address(message->address);
229   payload->set_data_ptr(data);
230   payload->set_data_length(message->data_length);
231   payload->set_byte_enable_ptr(nullptr);
232   payload->set_byte_enable_length(0);
233   payload->set_streaming_width(message->data_length);
234   payload->set_dmi_allowed(false);
235   payload->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
236 }
237 
initialize_connection(CTCPClient * connection,renode_message * message,int64_t * out_max_desync_us)238 static bool initialize_connection(CTCPClient *connection,
239                                   renode_message *message,
240                                   int64_t *out_max_desync_us) {
241   // Receive INIT message from Renode and use it to setup connection, e. g.
242   // time synchronization period.
243   // This is done during SystemC elaboration, once per lifetime of the module.
244   int nread = connection->Receive((char *)message, sizeof(renode_message));
245   if (nread <= 0) {
246     return false;
247   }
248 
249 #ifdef VERBOSE
250   print_renode_message(message);
251 #endif
252 
253   if (message->action != renode_action::INIT) {
254     fprintf(stderr, "Renode bridge connection error: missing INIT action.\n");
255     return false;
256   }
257   *out_max_desync_us = static_cast<int64_t>(message->payload);
258 
259   // Acknowledge initialization is done.
260   connection->Send((char *)message, sizeof(renode_message));
261 #ifdef VERBOSE
262   printf("Connection to Renode initialized with timesync period %lu us.\n",
263          *out_max_desync_us);
264 #endif
265   return true;
266 }
267 
sc_time_to_us(sc_core::sc_time time)268 static uint64_t sc_time_to_us(sc_core::sc_time time) {
269   // Converts sc_time to microseconds count.
270   return static_cast<int64_t>(time.to_seconds() * 1000000.0);
271 }
272 
273 static uint64_t
perform_transaction(renode_bridge::renode_bus_initiator_socket & socket,tlm::tlm_generic_payload * payload)274 perform_transaction(renode_bridge::renode_bus_initiator_socket &socket,
275                     tlm::tlm_generic_payload *payload) {
276   sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
277   socket->b_transport(*payload, delay);
278 #ifdef VERBOSE
279   print_transaction_status(payload);
280 #endif
281   return sc_time_to_us(delay);
282 }
283 
terminate_simulation(int exitstatus)284 static void terminate_simulation(int exitstatus) {
285   sc_core::sc_stop();
286   exit(exitstatus);
287 }
288 
connect_with_retry(CTCPClient * socket,const char * address,const char * port)289 static void connect_with_retry(CTCPClient* socket, const char* address, const char* port) {
290   constexpr uint32_t max_retry_s = 10;
291   constexpr uint32_t retry_interval_s = 2;
292 
293   uint32_t retry_s = 0;
294   while (!socket->Connect(address, port)) {
295     fprintf(stderr, "Failed to connect to Renode, retrying in %us...\n", retry_interval_s);
296     std::this_thread::sleep_for(std::chrono::seconds(retry_interval_s));
297     retry_s += retry_interval_s;
298     if(retry_s >= max_retry_s) {
299         fprintf(stderr, "Maximum timeout reached. Failed to initialize Renode connection. Aborting.\n");
300         terminate_simulation(1);
301     }
302   }
303 }
304 
305 SC_HAS_PROCESS(renode_bridge);
renode_bridge(sc_core::sc_module_name name,const char * address,const char * port)306 renode_bridge::renode_bridge(sc_core::sc_module_name name, const char *address,
307                              const char *port)
308     : sc_module(name),
309       initiator_socket("initiator_socket"),
310       register_initiator_socket("register_initiator_socket"),
311       fw_connection_initialized(false) {
312   SC_THREAD(forward_loop);
313   SC_THREAD(on_port_gpio);
314   for (int i = 0; i < NUM_GPIO; ++i) {
315     sensitive << gpio_ports_in[i];
316   }
317 
318   bus_target_fw_handler.initialize(this, 0);
319   cpu_target_fw_handler.initialize(this, 0);
320 
321   target_socket.bind(bus_target_fw_handler.socket);
322   for (int i = 0; i < NUM_DIRECT_CONNECTIONS; ++i) {
323     dc_initiators[i].initialize(this);
324     dc_targets[i].initialize(this, i + 1);
325     direct_connection_targets[i].bind(dc_targets[i]);
326     direct_connection_initiators[i].bind(dc_initiators[i]);
327   }
328 
329   bus_initiator_bw_handler.initialize(this);
330   cpu_initiator_bw_handler.initialize(this);
331   initiator_socket.bind(bus_initiator_bw_handler);
332   register_initiator_socket.bind(cpu_initiator_bw_handler);
333 
334   payload.reset(new tlm::tlm_generic_payload());
335 
336   forward_connection.reset(new CTCPClient(NULL, ASocket::NO_FLAGS));
337   connect_with_retry(forward_connection.get(), address, port);
338 
339   backward_connection.reset(new CTCPClient(NULL, ASocket::NO_FLAGS));
340   connect_with_retry(backward_connection.get(), address, port);
341 }
342 
~renode_bridge()343 renode_bridge::~renode_bridge() {
344   forward_connection->Disconnect();
345   backward_connection->Disconnect();
346 }
347 
forward_loop()348 void renode_bridge::forward_loop() {
349   // Processing of requests initiated by Renode.
350   uint8_t data[8] = {};
351 
352   renode_message message;
353 
354   int64_t max_desync_us;
355   if (!initialize_connection(forward_connection.get(), &message,
356                              &max_desync_us)) {
357     fprintf(stderr, "Failed to initialize Renode connection. Aborting.\n");
358     terminate_simulation(1);
359     return;
360   }
361   fw_connection_initialized = true;
362 
363   while (true) {
364     memset(data, 0, sizeof(data));
365 
366     int nread =
367         forward_connection->Receive((char *)&message, sizeof(renode_message));
368     if (nread <= 0) {
369 #ifdef VERBOSE
370       printf("Connection to Renode closed.\n");
371 #endif
372       break;
373     }
374 
375 #ifdef VERBOSE
376     print_renode_message(&message);
377 #endif
378 
379     // Choose the appropriate initiator socket to initiate the transaction with.
380     renode_bus_initiator_socket *initiator_socket = nullptr;
381     if (message.connection_index > NUM_DIRECT_CONNECTIONS) {
382       fprintf(stderr,
383               "Invalid connection_index %u, exceeds available number of direct "
384               "connections (%u)\n",
385               message.connection_index, NUM_DIRECT_CONNECTIONS);
386       return;
387     }
388 
389     if (message.connection_index == 0) {
390       initiator_socket = &this->initiator_socket;
391     } else {
392       initiator_socket =
393           &this->direct_connection_initiators[message.connection_index - 1];
394     }
395 
396     switch (message.action) {
397     case renode_action::WRITE: {
398       handle_write(*initiator_socket, message, data);
399     } break;
400     case renode_action::READ: {
401       handle_read(*initiator_socket, message, data);
402     } break;
403      case renode_action::WRITE_REGISTER: {
404       handle_write(register_initiator_socket, message, data);
405     } break;
406      case renode_action::READ_REGISTER: {
407       handle_read(register_initiator_socket, message, data);
408     } break;
409     case renode_action::TIMESYNC: {
410       // Renode drives the simulation time. This module never leaves the delta
411       // cycle loop until a TIMESYNC with future time is received. It then waits
412       // for the time difference between current virtual time and time from
413       // TIMESYNC, allowing the SystemC simulation to progress in time. This is
414       // effectively a synchronization barrier.
415       int64_t systemc_time_us = sc_time_to_us(sc_core::sc_time_stamp());
416       int64_t renode_time_us = (int64_t)message.payload;
417 
418       int64_t dt = renode_time_us - systemc_time_us;
419       message.payload = systemc_time_us;
420       if (dt > max_desync_us) {
421         wait(dt, sc_core::SC_US);
422       }
423       message.payload = sc_time_to_us(sc_core::sc_time_stamp());
424       forward_connection->Send((char *)&message, sizeof(renode_message));
425     } break;
426     case renode_action::GPIOWRITE: {
427       for (int i = 0; i < NUM_GPIO; ++i) {
428         sc_core::sc_interface *interface = gpio_ports_out[i].get_interface();
429         if (interface != nullptr) {
430           gpio_ports_out[i]->write((message.payload & (1 << i)) != 0);
431         }
432       }
433       forward_connection->Send((char *)&message, sizeof(renode_message));
434     } break;
435     case renode_action::INIT: {
436       terminate_simulation(0);
437     } break;
438     case renode_action::RESET: {
439       sc_core::sc_interface *interface = reset.get_interface();
440       if (interface != nullptr) {
441         reset->write(true);
442       }
443       forward_connection->Send((char *)&message, sizeof(renode_message));
444     } break;
445     default:
446       fprintf(stderr, "Malformed message received from Renode - terminating simulation.\n");
447       terminate_simulation(1);
448     }
449   }
450 }
451 
invalidate_translation_blocks(uint64_t start_address,uint64_t end_address)452 void renode_bridge::invalidate_translation_blocks(uint64_t start_address, uint64_t end_address) {
453     renode_message message = {};
454     message.action = renode_action::TBSINVALID;
455     message.address = start_address;
456     message.payload = end_address;
457 
458     backward_connection->Send((char *)&message, sizeof(renode_message));
459     // Response is ignored.
460     backward_connection->Receive((char *)&message, sizeof(renode_message));
461 }
462 
handle_read(renode_bus_initiator_socket & socket,renode_message & message,uint8_t data[8])463 void renode_bridge::handle_read(renode_bus_initiator_socket &socket, renode_message &message, uint8_t data[8]) {
464   initialize_payload(payload.get(), &message, data);
465 
466   uint64_t delay = perform_transaction(socket, payload.get());
467 
468   // NOTE: address field is re-used here to pass timing information.
469   message.address = delay;
470   message.payload = *((uint64_t *)data);
471   forward_connection->Send((char *)&message, sizeof(renode_message));
472   wait(sc_core::SC_ZERO_TIME);
473 }
474 
handle_write(renode_bus_initiator_socket & socket,renode_message & message,uint8_t data[8])475 void renode_bridge::handle_write(renode_bus_initiator_socket &socket, renode_message &message, uint8_t data[8]) {
476   initialize_payload(payload.get(), &message, data);
477 
478   *((uint64_t *)data) = message.payload;
479 
480   uint64_t delay = perform_transaction(socket, payload.get());
481 
482   // NOTE: address field is re-used here to pass timing information.
483   message.address = delay;
484   forward_connection->Send((char *)&message, sizeof(renode_message));
485 
486   wait(sc_core::SC_ZERO_TIME);
487 }
488 
on_port_gpio()489 void renode_bridge::on_port_gpio() {
490   while (true) {
491     // Wait for a change in any of the GPIO ports.
492     wait();
493 
494     uint64_t gpio_state = 0;
495     for (int i = 0; i < NUM_GPIO; ++i) {
496       sc_core::sc_interface *interface = gpio_ports_in[i].get_interface();
497       if (interface != nullptr) {
498         if (gpio_ports_in[i]->read()) {
499           gpio_state |= (1ull << i);
500         } else {
501           gpio_state &= ~(1ull << i);
502         }
503       }
504     }
505 
506     renode_message message = {};
507     message.action = renode_action::GPIOWRITE;
508     message.payload = gpio_state;
509 
510     backward_connection->Send((char *)&message, sizeof(renode_message));
511     // Response is ignored.
512     backward_connection->Receive((char *)&message, sizeof(renode_message));
513   }
514 }
515 
service_backward_request(tlm::tlm_generic_payload & payload,uint8_t connection_idx,sc_core::sc_time & delay)516 void renode_bridge::service_backward_request(tlm::tlm_generic_payload &payload,
517                                              uint8_t connection_idx,
518                                              sc_core::sc_time &delay) {
519   unsigned int bytes_done = 0;
520   unsigned int bytes_remaining = payload.get_data_length();
521   renode_message message = {};
522   if (payload.is_read()) {
523     message.action = renode_action::READ;
524   } else if (payload.is_write()) {
525     message.action = renode_action::WRITE;
526   } else {
527     return;
528   }
529 
530   while (bytes_remaining) {
531     message.address = payload.get_address() + bytes_done;
532     message.connection_index = connection_idx;
533     message.data_length = bytes_remaining > 8 ? 8 : bytes_remaining;
534     bytes_remaining -= message.data_length;
535     if (payload.is_write()) {
536       memcpy(&message.payload, payload.get_data_ptr() + bytes_done, message.data_length);
537     }
538 
539     backward_connection->Send((char *)&message, sizeof(renode_message));
540     backward_connection->Receive((char *)&message, sizeof(renode_message));
541 
542     if (payload.is_read()) {
543       memcpy(payload.get_data_ptr() + bytes_done, &message.payload, message.data_length);
544     }
545 
546     bytes_done += 8;
547   }
548 
549   if (connection_idx == 0 && message.connection_index == 1) {
550     payload.set_dmi_allowed(true);
551   }
552 
553   payload.set_response_status(tlm::TLM_OK_RESPONSE);
554 }
555 
556 // ================================================================================
557 //   target_fw_handler
558 // ================================================================================
559 
initialize(renode_bridge * renode_bridge,uint8_t conn_idx)560 void renode_bridge::target_fw_handler::initialize(
561     renode_bridge *renode_bridge, uint8_t conn_idx) {
562   bridge = renode_bridge;
563   connection_idx = conn_idx;
564   socket.bind(*this);
565 }
566 
b_transport(tlm::tlm_generic_payload & payload,sc_core::sc_time & delay)567 void renode_bridge::target_fw_handler::b_transport(
568     tlm::tlm_generic_payload &payload, sc_core::sc_time &delay) {
569   bridge->service_backward_request(payload, connection_idx, delay);
570 }
571 
572 tlm::tlm_sync_enum
nb_transport_fw(tlm::tlm_generic_payload & trans,tlm::tlm_phase & phase,sc_core::sc_time & t)573 renode_bridge::target_fw_handler::nb_transport_fw(
574     tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase,
575     sc_core::sc_time &t) {
576   bridge->service_backward_request(trans, connection_idx, t);
577   return tlm::TLM_COMPLETED;
578 }
579 
580 tlm::tlm_sync_enum
nb_transport_bw(tlm::tlm_generic_payload &,tlm::tlm_phase &,sc_core::sc_time &)581 renode_bridge::target_fw_handler::nb_transport_bw(
582     tlm::tlm_generic_payload &, tlm::tlm_phase &, sc_core::sc_time &) {
583   fprintf(stderr, "[ERROR] nb_transport_bw not implemented for "
584                   "target_fw_handler.\n");
585   return tlm::TLM_COMPLETED;
586 }
587 
invalidate_direct_mem_ptr(sc_dt::uint64,sc_dt::uint64)588 void renode_bridge::target_fw_handler::invalidate_direct_mem_ptr(
589   sc_dt::uint64, sc_dt::uint64) {
590   fprintf(stderr, "[ERROR] invalidate_direct_mem_ptr not implemented for "
591                     "target_fw_handler.\n");
592 }
593 
get_direct_mem_ptr(tlm::tlm_generic_payload & trans,tlm::tlm_dmi & dmi_data)594 bool renode_bridge::target_fw_handler::get_direct_mem_ptr(
595     tlm::tlm_generic_payload &trans, tlm::tlm_dmi &dmi_data) {
596   if (connection_idx != 0) {
597     fprintf(stderr, "[ERROR] get_direct_mem_ptr not implemented for "
598                     "target_fw_handler.\n");
599     return false;
600   } else {
601     return bridge->service_backward_request_dmi(trans, dmi_data);
602   }
603 }
604 
service_backward_request_dmi(tlm::tlm_generic_payload & payload,tlm::tlm_dmi & dmi_data)605 bool renode_bridge::service_backward_request_dmi(tlm::tlm_generic_payload &payload, tlm::tlm_dmi &dmi_data) {
606 
607 #ifdef __linux__
608   renode_message message = {};
609   message.address = payload.get_address();
610   message.data_length = payload.get_data_length();
611   message.connection_index = 0;
612   message.action = renode_action::DMIREQ;
613 
614   dmi_message response;
615 
616   backward_connection->Send((char *)&message, sizeof(renode_message));
617 
618   backward_connection->Receive((char *)&response, sizeof(dmi_message));
619 
620   bool dmi_allowed = response.allowed;
621 
622   if (dmi_allowed && response.mmf_offset % sysconf(_SC_PAGESIZE)) {
623       fprintf(stderr, "[ERROR] invalid offset for MMF %s\n", response.mmf_path);
624       dmi_allowed = false;
625   }
626 
627   if (dmi_allowed) {
628     dmi_data.allow_read_write();
629     dmi_data.set_start_address(response.start_address);
630     dmi_data.set_end_address(response.end_address);
631     int mmf_fd = open(response.mmf_path, O_RDWR);
632     if (mmf_fd != -1) {
633       unsigned char* mmf_base = static_cast<unsigned char*>(mmap(
634         nullptr,
635         static_cast<size_t>(dmi_data.get_end_address() - dmi_data.get_start_address() + 1),
636         PROT_WRITE|PROT_READ,
637         MAP_SHARED,
638         mmf_fd,
639         response.mmf_offset
640       ));
641       if (mmf_base != MAP_FAILED) {
642         dmi_data.set_dmi_ptr(mmf_base);
643         return true;
644       }
645     }
646   }
647 #else
648   // at present DMI support has been implemented for linux only.
649   // print a one-time warning for DMI request on another operating system
650   static bool dmi_disabled_warned = false;
651   if (!dmi_disabled_warned) {
652     fprintf(stderr, "[WARNING] DMI support is unimplemented on this operating system\n");
653   }
654   dmi_disabled_warned = true;
655 #endif
656 
657   return false;
658 }
659 
transport_dbg(tlm::tlm_generic_payload & trans)660 unsigned int renode_bridge::target_fw_handler::transport_dbg(
661     tlm::tlm_generic_payload &trans) {
662 
663   // The SystemC simulation can begin before the connection with Renode is
664   // initialized. Reject any transactions during this interval.
665   if (!bridge->is_initialized()) return 0;
666 
667   sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
668   bridge->service_backward_request(trans, connection_idx, delay);
669   return trans.is_response_ok() ? trans.get_data_length() : 0;
670 }
671 
672 // ================================================================================
673 //  initiator_bw_handler
674 // ================================================================================
675 
initialize(renode_bridge * renode_bridge)676 void renode_bridge::initiator_bw_handler::initialize(
677     renode_bridge *renode_bridge) {
678   bridge = renode_bridge;
679 }
680 
nb_transport_bw(tlm::tlm_generic_payload & trans,tlm::tlm_phase & phase,sc_core::sc_time & t)681 tlm::tlm_sync_enum renode_bridge::initiator_bw_handler::nb_transport_bw(
682     tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase,
683     sc_core::sc_time &t) {
684   fprintf(stderr, "[ERROR] nb_transport_bw not implemented for "
685                   "initiator_bw_handler- this should never be called, "
686                   "as Renode integration only uses b_transfer.\n");
687   return tlm::TLM_COMPLETED;
688 }
689 
invalidate_direct_mem_ptr(sc_dt::uint64 start_range,sc_dt::uint64 end_range)690 void renode_bridge::initiator_bw_handler::invalidate_direct_mem_ptr(
691     sc_dt::uint64 start_range, sc_dt::uint64 end_range) {
692   fprintf(stderr, "[ERROR] invalidate_direct_mem_ptr not implemented for "
693                   "initiator_bw_handler - this should never be called, "
694                   "as Renode integration only uses b_transfer.\n");
695 }
696 
697 // ================================================================================
698