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