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 #pragma once 8 9 #include <memory> 10 11 #include "tlm.h" 12 #include "tlm_utils/simple_initiator_socket.h" 13 #include "tlm_utils/simple_target_socket.h" 14 15 struct CTCPClient; 16 struct renode_message; 17 18 #ifndef RENODE_BUSWIDTH 19 #define RENODE_BUSWIDTH 32 20 #endif 21 22 #define NUM_GPIO 64 23 #define NUM_DIRECT_CONNECTIONS 4 24 25 // ================================================================================ 26 // renode_bridge 27 // 28 // SystemC module that serves as an interface with Renode. 29 // ================================================================================ 30 31 class renode_bridge : sc_core::sc_module { 32 public: 33 renode_bridge(sc_core::sc_module_name name, const char *address, 34 const char *port); 35 ~renode_bridge(); 36 37 // Returns true if connection with Renode has been established, false otherwise. is_initialized()38 bool is_initialized() { return fw_connection_initialized; } 39 40 public: 41 using renode_bus_target_socket = 42 tlm::tlm_target_socket<RENODE_BUSWIDTH, tlm::tlm_base_protocol_types, 1, 43 sc_core::SC_ZERO_OR_MORE_BOUND>; 44 using renode_bus_initiator_socket = 45 tlm::tlm_initiator_socket<RENODE_BUSWIDTH, tlm::tlm_base_protocol_types, 46 1, sc_core::SC_ZERO_OR_MORE_BOUND>; 47 using gpio_in_port = sc_core::sc_port<sc_core::sc_signal_in_if<bool>, 1, 48 sc_core::SC_ZERO_OR_MORE_BOUND>; 49 using gpio_out_port = sc_core::sc_port<sc_core::sc_signal_out_if<bool>, 1, 50 sc_core::SC_ZERO_OR_MORE_BOUND>; 51 using reset_port = sc_core::sc_port<sc_core::sc_signal_inout_if<bool>, 1, 52 sc_core::SC_ZERO_OR_MORE_BOUND>; 53 54 // Socket forwarding memory transactions performed in Renode to SystemC. 55 renode_bus_initiator_socket initiator_socket; 56 57 // Socket forwarding register transactions performed in Renode to SystemC. 58 renode_bus_initiator_socket register_initiator_socket; 59 60 // Socket forwarding transactions performed in SystemC to Renode. 61 renode_bus_target_socket target_socket; 62 63 // Direct connections allow for binding peripherals directly to each other in 64 // Renode (bypassing System Bus). 65 renode_bus_initiator_socket 66 direct_connection_initiators[NUM_DIRECT_CONNECTIONS]; 67 renode_bus_target_socket direct_connection_targets[NUM_DIRECT_CONNECTIONS]; 68 69 // Input GPIO ports - signal changes are driven by SystemC and propagated to 70 // Renode. 71 gpio_in_port gpio_ports_in[NUM_GPIO]; 72 73 // Output GPIO ports - signal changes are driven by Renode and propagated to 74 // SystemC. 75 gpio_out_port gpio_ports_out[NUM_GPIO]; 76 77 // Reset signal. 78 // Raised when the peripheral is reset. Expected to be lowered by SystemC 79 // once the reset process is complete. 80 reset_port reset; 81 82 // Informs Renode CPU that memory has been modified in the given range. This 83 // is necessary when using DMI (get_direct_mem_ptr) to modify memory 84 // containing CPU instructions. 85 void invalidate_translation_blocks(uint64_t start_address, uint64_t end_address); 86 87 private: 88 struct initiator_bw_handler: tlm::tlm_bw_transport_if<> { 89 initiator_bw_handler() = default; 90 void initialize(renode_bridge *); 91 92 virtual tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload &trans, 93 tlm::tlm_phase &phase, 94 sc_core::sc_time &t); 95 virtual void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, 96 sc_dt::uint64 end_range); 97 98 private: 99 renode_bridge *bridge; 100 }; 101 102 struct target_fw_handler: tlm::tlm_fw_transport_if<> { 103 target_fw_handler() = default; 104 105 renode_bus_target_socket socket; 106 107 void initialize(renode_bridge *, uint8_t connection_idx); 108 109 virtual void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, 110 sc_dt::uint64 end_range); 111 virtual tlm::tlm_sync_enum 112 nb_transport_bw(tlm::tlm_generic_payload &payload, tlm::tlm_phase &phase, 113 sc_core::sc_time &delta); 114 virtual tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &trans, 115 tlm::tlm_phase &phase, 116 sc_core::sc_time &t); 117 virtual void b_transport(tlm::tlm_generic_payload &trans, 118 sc_core::sc_time &delay); 119 virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload &trans, 120 tlm::tlm_dmi &dmi_data); 121 virtual unsigned int transport_dbg(tlm::tlm_generic_payload &trans); 122 123 private: 124 renode_bridge *bridge; 125 uint8_t connection_idx; 126 }; 127 128 void forward_loop(); 129 void handle_read(renode_bus_initiator_socket &socket, renode_message &message, uint8_t data[8]); 130 void handle_write(renode_bus_initiator_socket &socket, renode_message &message, uint8_t data[8]); 131 void on_port_gpio(); 132 133 void update_backward_gpio_state(uint64_t new_gpio_state); 134 void service_backward_request(tlm::tlm_generic_payload &payload, 135 uint8_t connection_idx, 136 sc_core::sc_time &delay); 137 bool service_backward_request_dmi(tlm::tlm_generic_payload &payload, 138 tlm::tlm_dmi &dmi_data); 139 int64_t get_systemc_time_us(); 140 141 // Connection from Renode -> SystemC. 142 std::unique_ptr<CTCPClient> forward_connection; 143 144 // Connection from SystemC -> Renode 145 std::unique_ptr<CTCPClient> backward_connection; 146 147 // Construction/destruction of tlm_generic_payload is an expensive operation, 148 // so a single tlm_generic_payload object is reused, as recommended by OSCI 149 // TLM-2.0 Language Reference Manual. It also requires that the object is 150 // allocated on the heap. 151 std::unique_ptr<tlm::tlm_generic_payload> payload; 152 153 initiator_bw_handler bus_initiator_bw_handler; 154 initiator_bw_handler cpu_initiator_bw_handler; 155 target_fw_handler bus_target_fw_handler; 156 target_fw_handler cpu_target_fw_handler; 157 158 initiator_bw_handler dc_initiators[NUM_DIRECT_CONNECTIONS]; 159 target_fw_handler dc_targets[NUM_DIRECT_CONNECTIONS]; 160 161 bool fw_connection_initialized; 162 }; 163 164 // ================================================================================ 165