1// 2// Copyright (c) 2010-2024 Antmicro 3// 4// This file is licensed under the MIT License. 5// Full license text is available in 'licenses/MIT.txt'. 6// 7 8`timescale 1ns / 1ps 9 10import renode_pkg::renode_runtime, renode_pkg::bus_connection, renode_pkg::renode_connection, renode_pkg::no_peripheral_index; 11import renode_pkg::message_t, renode_pkg::address_t, renode_pkg::data_t, renode_pkg::valid_bits_e; 12 13module renode #( 14 int unsigned RenodeToCosimCount = 0, 15 int unsigned CosimToRenodeCount = 0, 16 int unsigned RenodeInputsCount = 1, 17 int unsigned RenodeOutputsCount = 1 18) ( 19 ref renode_runtime runtime, 20 input logic clk, 21 input logic [RenodeInputsCount-1:0] renode_inputs, 22 output logic [RenodeOutputsCount-1:0] renode_outputs 23); 24 time renode_time = 0; 25 26 event reset_assert_all; 27 int reset_assert_done_count; 28 event reset_assert_done; 29 30 event reset_deassert_all; 31 int reset_deassert_done_count; 32 event reset_deassert_done; 33 34 renode_inputs #( 35 .InputsCount(RenodeInputsCount) 36 ) gpio ( 37 .runtime(runtime), 38 .clk(clk), 39 .inputs(renode_inputs) 40 ); 41 42 initial begin 43 runtime.controllers = new[RenodeToCosimCount]; 44 foreach(runtime.controllers[i]) begin 45 runtime.controllers[i] = new(); 46 end 47 48 runtime.peripherals = new[CosimToRenodeCount]; 49 foreach(runtime.peripherals[i]) begin 50 runtime.peripherals[i] = new(); 51 end 52 end 53 54 if(CosimToRenodeCount > 0) begin 55 genvar i; 56 for(i = 0; i < CosimToRenodeCount; i += 1) begin 57 always @(runtime.peripherals[i].read_transaction_request) read_transaction(i); 58 always @(runtime.peripherals[i].write_transaction_request) write_transaction(i); 59 always @(reset_assert_all) runtime.peripherals[i].reset_assert(); 60 always @(runtime.peripherals[i].reset_assert_response) begin 61 reset_assert_done_count++; 62 if(reset_assert_done_count == (CosimToRenodeCount + RenodeToCosimCount)) begin 63 ->reset_assert_done; 64 end 65 end 66 always @(runtime.peripherals[i].reset_deassert_response) begin 67 reset_deassert_done_count++; 68 if(reset_deassert_done_count == (CosimToRenodeCount + RenodeToCosimCount)) begin 69 ->reset_deassert_done; 70 end 71 end 72 always @(reset_deassert_all) runtime.peripherals[i].reset_deassert(); 73 end 74 end 75 76 if(RenodeToCosimCount > 0) begin 77 genvar i; 78 for(i = 0; i < RenodeToCosimCount; i += 1) begin 79 always @(reset_assert_all) runtime.controllers[i].reset_assert(); 80 always @(reset_deassert_all) runtime.controllers[i].reset_deassert(); 81 always @(runtime.controllers[i].reset_assert_response) begin 82 reset_assert_done_count++; 83 if(reset_assert_done_count == (CosimToRenodeCount + RenodeToCosimCount)) begin 84 ->reset_assert_done; 85 end 86 end 87 always @(runtime.controllers[i].reset_deassert_response) begin 88 reset_deassert_done_count++; 89 if(reset_deassert_done_count == (CosimToRenodeCount + RenodeToCosimCount)) begin 90 ->reset_deassert_done; 91 end 92 end 93 end 94 end 95 96 task static receive_and_handle_message(); 97 message_t message; 98 bit did_receive; 99 100 // This task doesn't block elapse of a simulation time, when messages are being received and handled in an other place. 101 if (runtime.connection.exclusive_receive.try_get() != 0) begin 102 did_receive = runtime.connection.try_receive(message); 103 runtime.connection.exclusive_receive.put(); 104 if (did_receive) handle_message(message); 105 end 106 endtask 107 108 task static handle_message(message_t message); 109 bit is_handled; 110 111 is_handled = 1; 112 case (message.action) 113 renode_pkg::resetPeripheral: reset(); 114 renode_pkg::tickClock: sync_time(time'(message.data)); 115 renode_pkg::interrupt: handle_renode_output(message.address, message.data[0]); 116 renode_pkg::writeRequestQuadWord: write_to_bus(message.address, renode_pkg::QuadWord, message.data, message.peripheral_index); 117 renode_pkg::writeRequestDoubleWord: write_to_bus(message.address, renode_pkg::DoubleWord, message.data, message.peripheral_index); 118 renode_pkg::writeRequestWord: write_to_bus(message.address, renode_pkg::Word, message.data, message.peripheral_index); 119 renode_pkg::writeRequestByte: write_to_bus(message.address, renode_pkg::Byte, message.data, message.peripheral_index); 120 renode_pkg::readRequestQuadWord: read_from_bus(message.address, renode_pkg::QuadWord, message.peripheral_index); 121 renode_pkg::readRequestDoubleWord: read_from_bus(message.address, renode_pkg::DoubleWord, message.peripheral_index); 122 renode_pkg::readRequestWord: read_from_bus(message.address, renode_pkg::Word, message.peripheral_index); 123 renode_pkg::readRequestByte: read_from_bus(message.address, renode_pkg::Byte, message.peripheral_index); 124 default: is_handled = 0; 125 endcase 126 127 if (!is_handled) runtime.connection.handle_message(message, is_handled); 128 if (!is_handled) runtime.connection.log(renode_pkg::LogWarning, $sformatf("Trying to handle the unsupported action (%0s)", message.action.name())); 129 endtask 130 131 task static reset(); 132 // Nothing to reset, return immediately. 133 if(RenodeToCosimCount + CosimToRenodeCount == 0) return; 134 135 // The reset just locks the connection without using it to avoid an unexpected behaviour. 136 // It also prevents from a message handling in the receive_and_handle_message until a reset deassertion. 137 runtime.connection.exclusive_receive.get(); 138 139 reset_assert_done_count = 0; 140 #1 fork 141 ->reset_assert_all; 142 gpio.reset_assert(); 143 join 144 145 @(reset_assert_done); 146 147 // It's required to make values of all signals known (different than `x`) before a deassertion of resets. 148 // The assignment to renode_outputs is an equivalent of a reset assertion. 149 renode_outputs = 0; 150 151 reset_deassert_done_count = 0; 152 fork 153 ->reset_deassert_all; 154 gpio.reset_deassert(); 155 join 156 157 @(reset_deassert_done); 158 159 runtime.connection.exclusive_receive.put(); 160 endtask 161 162 task static sync_time(time time_to_elapse); 163 renode_time = renode_time + time_to_elapse; 164 while ($time < renode_time) @(clk); 165 166 runtime.connection.send_to_async_receiver(message_t'{renode_pkg::tickClock, 0, 0, renode_pkg::no_peripheral_index}); 167 runtime.connection.log(renode_pkg::LogNoisy, $sformatf("Simulation time synced to %t", $realtime)); 168 endtask 169 170 task automatic read_from_bus(address_t address, valid_bits_e data_bits, int peripheral_index); 171 data_t data = 0; 172 bit is_error = 0; 173 runtime.controllers[peripheral_index].read(address, data_bits, data, is_error); 174 175 if (is_error) runtime.connection.send(message_t'{renode_pkg::error, 0, 0, peripheral_index}); 176 else runtime.connection.send(message_t'{renode_pkg::readRequest, address, data, peripheral_index}); 177 endtask 178 179 task automatic write_to_bus(address_t address, valid_bits_e data_bits, data_t data, int peripheral_index); 180 bit is_error = 0; 181 runtime.controllers[peripheral_index].write(address, data_bits, data, is_error); 182 183 if (is_error) runtime.connection.send(message_t'{renode_pkg::error, 0, 0, peripheral_index}); 184 else runtime.connection.send(message_t'{renode_pkg::ok, 0, 0, peripheral_index}); 185 endtask 186 187 task automatic read_transaction(int peripheral_index); 188 message_t message; 189 190 case (runtime.peripherals[peripheral_index].read_transaction_data_bits) 191 renode_pkg::Byte: message.action = renode_pkg::getByte; 192 renode_pkg::Word: message.action = renode_pkg::getWord; 193 renode_pkg::DoubleWord: message.action = renode_pkg::getDoubleWord; 194 renode_pkg::QuadWord: message.action = renode_pkg::getQuadWord; 195 default: begin 196 runtime.connection.fatal_error($sformatf("Renode doesn't support access with the 'b%b mask from a bus controller.", runtime.peripherals[peripheral_index].read_transaction_data_bits)); 197 runtime.peripherals[peripheral_index].read_respond(0, 1); 198 return; 199 end 200 endcase 201 message.address = runtime.peripherals[peripheral_index].read_transaction_address; 202 message.data = 0; 203 204 runtime.connection.exclusive_receive.get(); 205 if(!runtime.connection.is_connected()) begin 206 runtime.connection.exclusive_receive.put(); 207 return; 208 end 209 210 runtime.connection.send_to_async_receiver(message); 211 212 runtime.connection.receive(message); 213 while (message.action != renode_pkg::writeRequest) begin 214 handle_message(message); 215 if(message.action == renode_pkg::disconnect) break; 216 runtime.connection.receive(message); 217 end 218 219 runtime.connection.exclusive_receive.put(); 220 runtime.peripherals[peripheral_index].read_respond(message.data, 0); 221 endtask 222 223 task automatic write_transaction(int peripheral_index); 224 message_t message; 225 226 case (runtime.peripherals[peripheral_index].write_transaction_data_bits) 227 renode_pkg::Byte: message.action = renode_pkg::pushByte; 228 renode_pkg::Word: message.action = renode_pkg::pushWord; 229 renode_pkg::DoubleWord: message.action = renode_pkg::pushDoubleWord; 230 renode_pkg::QuadWord: message.action = renode_pkg::pushQuadWord; 231 default: begin 232 runtime.connection.fatal_error($sformatf("Renode doesn't support access with the 'b%b mask from a bus controller.", runtime.peripherals[peripheral_index].read_transaction_data_bits)); 233 runtime.peripherals[peripheral_index].write_respond(1); 234 return; 235 end 236 endcase 237 message.address = runtime.peripherals[peripheral_index].write_transaction_address; 238 message.data = runtime.peripherals[peripheral_index].write_transaction_data; 239 240 runtime.connection.exclusive_receive.get(); 241 if(!runtime.connection.is_connected()) begin 242 runtime.connection.exclusive_receive.put(); 243 return; 244 end 245 246 runtime.connection.send_to_async_receiver(message); 247 runtime.connection.receive(message); 248 while (message.action != renode_pkg::pushConfirmation) begin 249 handle_message(message); 250 if(message.action == renode_pkg::disconnect) break; 251 runtime.connection.receive(message); 252 end 253 254 runtime.connection.exclusive_receive.put(); 255 256 runtime.peripherals[peripheral_index].write_respond(0); 257 endtask 258 259 // calculate number of bits needed to hold the output number 260 `define max(a,b) (a > b) ? a : b 261 localparam RenodeOutputsCountWidth = `max($clog2(RenodeOutputsCount), 1); 262 263 task automatic handle_renode_output(address_t number, bit value); 264 if (number >= 64'(RenodeOutputsCount)) begin 265 runtime.connection.log(renode_pkg::LogWarning, $sformatf("Output %0d is out of range of [0;%0d]", number, RenodeOutputsCount - 1)); 266 runtime.connection.send(message_t'{renode_pkg::error, 0, 0, renode_pkg::no_peripheral_index}); 267 end 268 269 @(posedge clk); 270 renode_outputs[number[RenodeOutputsCountWidth-1:0]] <= value; 271 272 runtime.connection.send(message_t'{renode_pkg::ok, 0, 0, renode_pkg::no_peripheral_index}); 273 endtask 274endmodule 275