[#69489] co-simulation: Allow multiple peripherals per renode module
diff --git a/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedCFU.cs b/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedCFU.cs index 79faba6..57f5bfd 100644 --- a/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedCFU.cs +++ b/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedCFU.cs
@@ -26,6 +26,10 @@ { public CoSimulatedCFU(Machine machine, long frequency = 0, ulong limitBuffer = LimitBuffer, int timeout = DefaultTimeout, string simulationFilePathLinux = null, string simulationFilePathWindows = null, string simulationFilePathMacOS = null) { + // Multiple CoSimulatedCFUs per CoSimulationConnection are currently not supported. + RenodeToCosimIndex = 0; + CosimToRenodeIndex = 0; + connection = new CoSimulationConnection(machine, "cosimulation_connection", frequency, simulationFilePathLinux, simulationFilePathWindows, simulationFilePathMacOS, null, null, null, @@ -265,6 +269,9 @@ } } + public int RenodeToCosimIndex { get; } + public int CosimToRenodeIndex { get; } + protected const ulong LimitBuffer = 100000; protected const int DefaultTimeout = 3000; private NativeBinder executeBinder;
diff --git a/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedCPU.cs b/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedCPU.cs index 6b76203..57feec1 100644 --- a/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedCPU.cs +++ b/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedCPU.cs
@@ -35,6 +35,10 @@ string simulationContextLinux = null, string simulationContextWindows = null, string simulationContextMacOS = null, string address = null) : base(0, cpuType, machine, endianness, bitness) { + // Multiple CoSimulatedCPUs per CoSimulationConnection are currently not supported. + RenodeToCosimIndex = 0; + CosimToRenodeIndex = 0; + cosimConnection = new CoSimulationConnection(machine, "cpu_cosim_cosimConnection", 0, simulationFilePathLinux, simulationFilePathWindows, simulationFilePathMacOS, simulationContextLinux, simulationContextWindows, simulationContextMacOS, @@ -83,7 +87,7 @@ this.NoisyLog("IRQ {0}, value {1}", number, value); lock(cosimConnectionLock) { - cosimConnection.Send(ActionType.Interrupt, (ulong)number, (ulong)(value ? 1 : 0)); + cosimConnection.Send(this, ActionType.Interrupt, (ulong)number, (ulong)(value ? 1 : 0)); } } @@ -92,7 +96,7 @@ lock(cosimConnectionLock) { setRegisterValue = false; - cosimConnection.Send(ActionType.RegisterSet, (ulong)register, (ulong) value); + cosimConnection.Send(this, ActionType.RegisterSet, (ulong)register, (ulong) value); while(!setRegisterValue) // This kind of while loops are for socket communication { cosimConnection.HandleMessage(); @@ -105,7 +109,7 @@ lock(cosimConnectionLock) { gotRegisterValue = false; - cosimConnection.Send(ActionType.RegisterGet, (ulong)register, 0); + cosimConnection.Send(this, ActionType.RegisterGet, (ulong)register, 0); while(!gotRegisterValue) { cosimConnection.HandleMessage(); @@ -127,7 +131,7 @@ while(instructionsExecutedThisRound < 1) { gotStep = false; - cosimConnection.Send(ActionType.Step, 0, 1); + cosimConnection.Send(this, ActionType.Step, 0, 1); while(!gotStep) { cosimConnection.HandleMessage(); @@ -137,7 +141,7 @@ else { ticksProcessed = false; - cosimConnection.Send(ActionType.TickClock, 0, numberOfInstructionsToExecute); + cosimConnection.Send(this, ActionType.TickClock, 0, numberOfInstructionsToExecute); while(!ticksProcessed) { cosimConnection.HandleMessage(); @@ -190,10 +194,10 @@ switch(executionMode) { case ExecutionMode.Continuous: - cosimConnection.Send(ActionType.SingleStepMode, 0, 0); + cosimConnection.Send(this, ActionType.SingleStepMode, 0, 0); break; case ExecutionMode.SingleStep: - cosimConnection.Send(ActionType.SingleStepMode, 0, 1); + cosimConnection.Send(this, ActionType.SingleStepMode, 0, 1); break; } @@ -291,6 +295,9 @@ } } + public int RenodeToCosimIndex { get; } + public int CosimToRenodeIndex { get; } + protected readonly object cosimConnectionLock = new object(); private readonly CoSimulationConnection cosimConnection;
diff --git a/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedPeripheral.cs b/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedPeripheral.cs index 8963921..718bf5c 100644 --- a/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedPeripheral.cs +++ b/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedPeripheral.cs
@@ -25,12 +25,14 @@ string simulationFilePathLinux = null, string simulationFilePathWindows = null, string simulationFilePathMacOS = null, string simulationContextLinux = null, string simulationContextWindows = null, string simulationContextMacOS = null, ulong limitBuffer = LimitBuffer, int timeout = DefaultTimeout, string address = null, bool createConnection = true, - ulong renodeToCosimSignalsOffset = 0, Range? cosimToRenodeSignalRange = null) + ulong renodeToCosimSignalsOffset = 0, Range? cosimToRenodeSignalRange = null, int renodeToCosimIndex = 0, int cosimToRenodeIndex = 0) { UseAbsoluteAddress = useAbsoluteAddress; this.maxWidth = maxWidth; this.renodeToCosimSignalsOffset = renodeToCosimSignalsOffset; this.cosimToRenodeSignalRange = cosimToRenodeSignalRange; + RenodeToCosimIndex = renodeToCosimIndex; + CosimToRenodeIndex = cosimToRenodeIndex; if(createConnection) { @@ -90,7 +92,7 @@ { return 0; } - return (byte)connection.Read(ActionType.ReadFromBusByte, offset); + return (byte)connection.Read(this, ActionType.ReadFromBusByte, offset); } public ushort ReadWord(long offset) @@ -100,7 +102,7 @@ { return 0; } - return (ushort)connection.Read(ActionType.ReadFromBusWord, offset); + return (ushort)connection.Read(this, ActionType.ReadFromBusWord, offset); } public uint ReadDoubleWord(long offset) @@ -110,7 +112,7 @@ { return 0; } - return (uint)connection.Read(ActionType.ReadFromBusDoubleWord, offset); + return (uint)connection.Read(this, ActionType.ReadFromBusDoubleWord, offset); } public ulong ReadQuadWord(long offset) @@ -120,7 +122,7 @@ { return 0; } - return connection.Read(ActionType.ReadFromBusQuadWord, offset); + return connection.Read(this, ActionType.ReadFromBusQuadWord, offset); } public void WriteByte(long offset, byte value) @@ -128,7 +130,7 @@ offset = UseAbsoluteAddress ? (long)absoluteAddress : offset; if(VerifyLength(8, offset, value)) { - connection.Write(ActionType.WriteToBusByte, offset, value); + connection.Write(this, ActionType.WriteToBusByte, offset, value); } } @@ -137,7 +139,7 @@ offset = UseAbsoluteAddress ? (long)absoluteAddress : offset; if(VerifyLength(16, offset, value)) { - connection.Write(ActionType.WriteToBusWord, offset, value); + connection.Write(this, ActionType.WriteToBusWord, offset, value); } } @@ -146,7 +148,7 @@ offset = UseAbsoluteAddress ? (long)absoluteAddress : offset; if(VerifyLength(32, offset, value)) { - connection.Write(ActionType.WriteToBusDoubleWord, offset, value); + connection.Write(this, ActionType.WriteToBusDoubleWord, offset, value); } } @@ -155,7 +157,7 @@ offset = UseAbsoluteAddress ? (long)absoluteAddress : offset; if(VerifyLength(64, offset, value)) { - connection.Write(ActionType.WriteToBusQuadWord, offset, value); + connection.Write(this, ActionType.WriteToBusQuadWord, offset, value); } } @@ -295,6 +297,9 @@ } } + public int RenodeToCosimIndex { get; } + public int CosimToRenodeIndex { get; } + protected CoSimulationConnection connection; protected const ulong LimitBuffer = 1000000; protected const int DefaultTimeout = 3000;
diff --git a/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedUART.cs b/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedUART.cs index 4e580d6..5442bc1 100644 --- a/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedUART.cs +++ b/src/Plugins/CoSimulationPlugin/CoSimulated/Peripherals/CoSimulatedUART.cs
@@ -27,14 +27,14 @@ simulationFilePathLinux, simulationFilePathWindows, simulationFilePathMacOS, simulationContextLinux, simulationContextWindows, simulationContextMacOS, limitBuffer, timeout, address, createConnection, renodeToCosimSignalsOffset, - cosimToRenodeSignalRange) + cosimToRenodeSignalRange, 0, 0) { IRQ = new GPIO(); } public void WriteChar(byte value) { - connection.Send((ActionType)UARTActionNumber.UARTRxd, 0, value); + connection.Send(this, (ActionType)UARTActionNumber.UARTRxd, 0, value); } public bool HandleReceivedMessage(ProtocolMessage message)
diff --git a/src/Plugins/CoSimulationPlugin/Connection/CoSimulationConnection.cs b/src/Plugins/CoSimulationPlugin/Connection/CoSimulationConnection.cs index 11dec20..4368951 100644 --- a/src/Plugins/CoSimulationPlugin/Connection/CoSimulationConnection.cs +++ b/src/Plugins/CoSimulationPlugin/Connection/CoSimulationConnection.cs
@@ -12,6 +12,7 @@ using Antmicro.Renode.Exceptions; using Antmicro.Renode.Logging; using Antmicro.Renode.Peripherals; +using Antmicro.Renode.Peripherals.Bus; using Antmicro.Renode.Peripherals.CPU; using Antmicro.Renode.Peripherals.CoSimulated; using Antmicro.Renode.Peripherals.Timers; @@ -72,16 +73,24 @@ RegisterInHostMachine(name); cosimConnection = SetupConnection(address, timeout, frequency, limitBuffer); + + cosimIdxToPeripheral = new Dictionary<int, ICoSimulationConnectible>(); } public void AttachTo(ICoSimulationConnectible peripheral) { + if(cosimIdxToPeripheral.ContainsKey(peripheral.CosimToRenodeIndex)) + { + throw new RecoverableException("Failed to add a peripheral to co-simulated connection. Make sure all connected peripherals have correctly assigned, unique cosimulation subordinate and manager indices in platform definition."); + } + cosimIdxToPeripheral.Add(peripheral.CosimToRenodeIndex, peripheral); peripheral.OnConnectionAttached(this); } public void DetachFrom(ICoSimulationConnectible peripheral) { peripheral.OnConnectionDetached(this); + cosimIdxToPeripheral.Remove(peripheral.CosimToRenodeIndex); } public void Dispose() @@ -205,17 +214,18 @@ cosimConnection.Connect(); } - public void Send(ActionType actionId, ulong offset, ulong value) + public void Send(ICoSimulationConnectible connectible, ActionType actionId, ulong offset, ulong value) { - if(!cosimConnection.TrySendMessage(new ProtocolMessage(actionId, offset, value))) + int renodeToCosimIndex = connectible != null ? connectible.RenodeToCosimIndex : ProtocolMessage.NoPeripheralIndex; + if(!cosimConnection.TrySendMessage(new ProtocolMessage(actionId, offset, value, renodeToCosimIndex))) { AbortAndLogError("Send error!"); } } - public void Respond(ActionType actionId, ulong offset, ulong value) + public void Respond(ActionType actionId, ulong offset, ulong value, int peripheralIdx) { - if(!cosimConnection.TryRespond(new ProtocolMessage(actionId, offset, value))) + if(!cosimConnection.TryRespond(new ProtocolMessage(actionId, offset, value, peripheralIdx))) { AbortAndLogError("Respond error!"); } @@ -231,12 +241,12 @@ { timer.Reset(); } - Send(ActionType.ResetPeripheral, 0, 0); + Send(null, ActionType.ResetPeripheral, 0, 0); } public void SendGPIO(int number, bool value) { - Write(ActionType.Interrupt, number, value ? 1ul : 0ul); + Write(null, ActionType.Interrupt, number, value ? 1ul : 0ul); } public string ConnectionParameters => (cosimConnection as SocketConnection)?.ConnectionParameters ?? ""; @@ -261,25 +271,25 @@ gpioEntries.RemoveAll(entry => entry.range.Equals(translationRange)); } - public void Write(ActionType type, long offset, ulong value) + public void Write(ICoSimulationConnectible connectible, ActionType type, long offset, ulong value) { if(!IsConnected) { this.Log(LogLevel.Warning, "Cannot write to peripheral. Set SimulationFilePath or connect to a simulator first!"); return; } - Send(type, (ulong)offset, value); + Send(connectible, type, (ulong)offset, value); ValidateResponse(Receive()); } - public ulong Read(ActionType type, long offset) + public ulong Read(ICoSimulationConnectible connectible, ActionType type, long offset) { if(!IsConnected) { this.Log(LogLevel.Warning, "Cannot read from peripheral. Set SimulationFilePath or connect to a simulator first!"); return 0; } - Send(type, (ulong)offset, 0); + Send(connectible, type, (ulong)offset, 0); var result = Receive(); ValidateResponse(result); @@ -321,7 +331,7 @@ timer = new LimitTimer(machine.ClockSource, frequency, null, LimitTimerName, limitBuffer, enabled: true, eventEnabled: true, autoUpdate: true); timer.LimitReached += () => { - if(!cosimConnection.TrySendMessage(new ProtocolMessage(ActionType.TickClock, 0, limitBuffer))) + if(!cosimConnection.TrySendMessage(new ProtocolMessage(ActionType.TickClock, 0, limitBuffer, ProtocolMessage.NoPeripheralIndex))) { AbortAndLogError("Send error!"); } @@ -357,6 +367,13 @@ private void HandleReceivedMessage(ProtocolMessage message) { + ICoSimulationConnectible peripheral = null; + if(message.PeripheralIndex != ProtocolMessage.NoPeripheralIndex && !cosimIdxToPeripheral.TryGetValue(message.PeripheralIndex, out peripheral)) + { + this.Log(LogLevel.Error, "Received co-simulation message {} to a peripheral with index {}, not registered in Renode. Make sure \"cosimToRenodeIndex\" property is provided in platform definition. Message will be ignored.", message.ActionId, message.PeripheralIndex); + return; + } + if(OnReceive != null) { foreach(OnReceiveDelegate or in OnReceive.GetInvocationList()) @@ -368,6 +385,13 @@ } } + IBusController systemBus = machine.SystemBus; + var busPeripheral = peripheral as IBusPeripheral; + if(busPeripheral != null) + { + systemBus = machine.GetSystemBus(busPeripheral); + } + switch(message.ActionId) { case ActionType.InvalidAction: @@ -378,39 +402,39 @@ break; case ActionType.PushByte: this.Log(LogLevel.Noisy, "Writing byte: 0x{0:X} to address: 0x{1:X}", message.Data, message.Address); - machine.SystemBus.WriteByte(message.Address, (byte)message.Data); - Respond(ActionType.PushConfirmation, 0, 0); + systemBus.WriteByte(message.Address, (byte)message.Data); + Respond(ActionType.PushConfirmation, 0, 0, message.PeripheralIndex); break; case ActionType.PushWord: this.Log(LogLevel.Noisy, "Writing word: 0x{0:X} to address: 0x{1:X}", message.Data, message.Address); - machine.SystemBus.WriteWord(message.Address, (ushort)message.Data); - Respond(ActionType.PushConfirmation, 0, 0); + systemBus.WriteWord(message.Address, (ushort)message.Data); + Respond(ActionType.PushConfirmation, 0, 0, message.PeripheralIndex); break; case ActionType.PushDoubleWord: this.Log(LogLevel.Noisy, "Writing double word: 0x{0:X} to address: 0x{1:X}", message.Data, message.Address); - machine.SystemBus.WriteDoubleWord(message.Address, (uint)message.Data); - Respond(ActionType.PushConfirmation, 0, 0); + systemBus.WriteDoubleWord(message.Address, (uint)message.Data); + Respond(ActionType.PushConfirmation, 0, 0, message.PeripheralIndex); break; case ActionType.PushQuadWord: this.Log(LogLevel.Noisy, "Writing quad word: 0x{0:X} to address: 0x{1:X}", message.Data, message.Address); - machine.SystemBus.WriteQuadWord(message.Address, message.Data); - Respond(ActionType.PushConfirmation, 0, 0); + systemBus.WriteQuadWord(message.Address, message.Data); + Respond(ActionType.PushConfirmation, 0, 0, message.PeripheralIndex); break; case ActionType.GetByte: this.Log(LogLevel.Noisy, "Requested byte from address: 0x{0:X}", message.Address); - Respond(ActionType.WriteToBus, 0, machine.SystemBus.ReadByte(message.Address)); + Respond(ActionType.WriteToBus, 0, systemBus.ReadByte(message.Address), message.PeripheralIndex); break; case ActionType.GetWord: this.Log(LogLevel.Noisy, "Requested word from address: 0x{0:X}", message.Address); - Respond(ActionType.WriteToBus, 0, machine.SystemBus.ReadWord(message.Address)); + Respond(ActionType.WriteToBus, 0, systemBus.ReadWord(message.Address), message.PeripheralIndex); break; case ActionType.GetDoubleWord: this.Log(LogLevel.Noisy, "Requested double word from address: 0x{0:X}", message.Address); - Respond(ActionType.WriteToBus, 0, machine.SystemBus.ReadDoubleWord(message.Address)); + Respond(ActionType.WriteToBus, 0, systemBus.ReadDoubleWord(message.Address), message.PeripheralIndex); break; case ActionType.GetQuadWord: this.Log(LogLevel.Noisy, "Requested quad word from address: 0x{0:X}", message.Address); - Respond(ActionType.WriteToBus, 0, machine.SystemBus.ReadQuadWord(message.Address)); + Respond(ActionType.WriteToBus, 0, systemBus.ReadQuadWord(message.Address), message.PeripheralIndex); break; case ActionType.TickClock: allTicksProcessedARE.Set(); @@ -476,6 +500,8 @@ private readonly ICoSimulationConnection cosimConnection; private const int DefaultTimeout = 3000; + + private readonly Dictionary<int, ICoSimulationConnectible> cosimIdxToPeripheral; private string simulationFilePath; private IMachine machine; private volatile bool disposeInitiated;
diff --git a/src/Plugins/CoSimulationPlugin/Connection/ICoSimulationConnectible.cs b/src/Plugins/CoSimulationPlugin/Connection/ICoSimulationConnectible.cs index fe59647..4084279 100644 --- a/src/Plugins/CoSimulationPlugin/Connection/ICoSimulationConnectible.cs +++ b/src/Plugins/CoSimulationPlugin/Connection/ICoSimulationConnectible.cs
@@ -13,5 +13,7 @@ { void OnConnectionAttached(CoSimulationConnection connection); void OnConnectionDetached(CoSimulationConnection connection); + int RenodeToCosimIndex { get; } + int CosimToRenodeIndex { get; } } }
diff --git a/src/Plugins/CoSimulationPlugin/Connection/Protocols/ProtocolMessage.cs b/src/Plugins/CoSimulationPlugin/Connection/Protocols/ProtocolMessage.cs index fb2d69f..317877a 100644 --- a/src/Plugins/CoSimulationPlugin/Connection/Protocols/ProtocolMessage.cs +++ b/src/Plugins/CoSimulationPlugin/Connection/Protocols/ProtocolMessage.cs
@@ -12,11 +12,12 @@ [StructLayout(LayoutKind.Sequential, Pack = 2)] public struct ProtocolMessage { - public ProtocolMessage(ActionType actionId, ulong address, ulong data) + public ProtocolMessage(ActionType actionId, ulong address, ulong data, int peripheralIndex) { this.ActionId = actionId; this.Address = address; this.Data = data; + this.PeripheralIndex = peripheralIndex; } public byte[] Serialize() @@ -61,5 +62,9 @@ public ActionType ActionId { get; set; } public ulong Address { get; set; } public ulong Data { get; set; } + public int PeripheralIndex { get; set; } + + // Peripheral index used for messages that are not associated with any peripherals. + public const int NoPeripheralIndex = -1; } }
diff --git a/src/Plugins/CoSimulationPlugin/Connection/SocketConnection.cs b/src/Plugins/CoSimulationPlugin/Connection/SocketConnection.cs index b793e5c..ee8bb25 100644 --- a/src/Plugins/CoSimulationPlugin/Connection/SocketConnection.cs +++ b/src/Plugins/CoSimulationPlugin/Connection/SocketConnection.cs
@@ -150,7 +150,7 @@ if(IsConnected) { parentElement.DebugLog("Sending 'Disconnect' message to close peripheral gracefully..."); - TrySendMessage(new ProtocolMessage(ActionType.Disconnect, 0, 0)); + TrySendMessage(new ProtocolMessage(ActionType.Disconnect, 0, 0, ProtocolMessage.NoPeripheralIndex)); mainSocketComunicator.CancelCommunication(); } @@ -305,9 +305,23 @@ private bool TryHandshake() { - return TrySendMessage(new ProtocolMessage(ActionType.Handshake, 0, 0)) - && TryReceiveMessage(out var result) - && result.ActionId == ActionType.Handshake; + if(!TrySendMessage(new ProtocolMessage(ActionType.Handshake, 0, 0, ProtocolMessage.NoPeripheralIndex))) + { + parentElement.Log(LogLevel.Error, "Failed to send handshake message to co-simulation."); + return false; + } + if(!TryReceiveMessage(out var result)) + { + parentElement.Log(LogLevel.Error, "Failed to receive handshake response from co-simulation."); + return false; + } + if(result.ActionId != ActionType.Handshake) + { + parentElement.Log(LogLevel.Error, "Invalid handshake response received from co-simulation."); + return false; + } + + return true; } private void HandleReceived(ProtocolMessage message)
diff --git a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/ahb/renode_ahb_manager.sv b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/ahb/renode_ahb_manager.sv index 0e1b2fb..9fd3ac0 100644 --- a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/ahb/renode_ahb_manager.sv +++ b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/ahb/renode_ahb_manager.sv
@@ -8,9 +8,9 @@ `timescale 1ns / 1ps -import renode_pkg::renode_runtime, renode_pkg::LogWarning; +import renode_pkg::renode_runtime, renode_pkg::bus_connection, renode_pkg::LogWarning; -module renode_ahb_manager ( +module renode_ahb_manager #(int RenodeToCosimIndex = 0) ( ref renode_runtime runtime, renode_ahb_if bus ); @@ -20,33 +20,33 @@ typedef logic [bus.DataWidth-1:0] data_t; wire clk = bus.hclk; - always @(runtime.controller.reset_assert_request) begin + always @(runtime.controllers[RenodeToCosimIndex].reset_assert_request) begin bus.hresetn = 0; bus.haddr = '0; bus.htrans = Idle; repeat (2) @(posedge clk); - runtime.controller.reset_assert_respond(); + runtime.controllers[RenodeToCosimIndex].reset_assert_respond(); end - always @(runtime.controller.reset_deassert_request) begin + always @(runtime.controllers[RenodeToCosimIndex].reset_deassert_request) begin bus.hresetn = 1; repeat (2) @(posedge clk); - runtime.controller.reset_deassert_respond(); + runtime.controllers[RenodeToCosimIndex].reset_deassert_respond(); end - always @(runtime.controller.read_transaction_request) read_transaction(); - always @(runtime.controller.write_transaction_request) write_transaction(); + always @(runtime.controllers[RenodeToCosimIndex].read_transaction_request) read_transaction(); + always @(runtime.controllers[RenodeToCosimIndex].write_transaction_request) write_transaction(); task static write_transaction(); renode_pkg::valid_bits_e valid_bits; data_t data; bit is_invalid; - valid_bits = runtime.controller.write_transaction_data_bits; - data = data_t'(runtime.controller.write_transaction_data & valid_bits); - configure_transfer(runtime.controller.write_transaction_address, valid_bits, Write, is_invalid); + valid_bits = runtime.controllers[RenodeToCosimIndex].write_transaction_data_bits; + data = data_t'(runtime.controllers[RenodeToCosimIndex].write_transaction_data & valid_bits); + configure_transfer(runtime.controllers[RenodeToCosimIndex].write_transaction_address, valid_bits, Write, is_invalid); if (is_invalid) begin - runtime.controller.write_respond(is_invalid); + runtime.controllers[RenodeToCosimIndex].write_respond(is_invalid); return; end @@ -55,7 +55,7 @@ bus.htrans <= Idle; do @(posedge clk); while (!bus.hready); - runtime.controller.write_respond(is_response_error(bus.hresp)); + runtime.controllers[RenodeToCosimIndex].write_respond(is_response_error(bus.hresp)); endtask task static read_transaction(); @@ -64,10 +64,10 @@ bit is_invalid; bit is_error; - valid_bits = runtime.controller.read_transaction_data_bits; - configure_transfer(runtime.controller.read_transaction_address, valid_bits, Read, is_invalid); + valid_bits = runtime.controllers[RenodeToCosimIndex].read_transaction_data_bits; + configure_transfer(runtime.controllers[RenodeToCosimIndex].read_transaction_address, valid_bits, Read, is_invalid); if (is_invalid) begin - runtime.controller.read_respond(renode_pkg::data_t'(0), is_invalid); + runtime.controllers[RenodeToCosimIndex].read_respond(renode_pkg::data_t'(0), is_invalid); return; end @@ -76,7 +76,7 @@ do @(posedge clk); while (!bus.hready); data = bus.hrdata; is_error = is_response_error(bus.hresp); - runtime.controller.read_respond(renode_pkg::data_t'(data) & valid_bits, is_error); + runtime.controllers[RenodeToCosimIndex].read_respond(renode_pkg::data_t'(data) & valid_bits, is_error); endtask task static configure_transfer(renode_pkg::address_t address, renode_pkg::valid_bits_e valid_bits, transfer_direction_e direction, output logic is_invalid);
diff --git a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/ahb/renode_ahb_subordinate.sv b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/ahb/renode_ahb_subordinate.sv index a572687..c183c6b 100644 --- a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/ahb/renode_ahb_subordinate.sv +++ b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/ahb/renode_ahb_subordinate.sv
@@ -10,7 +10,7 @@ import renode_pkg::renode_runtime, renode_pkg::LogWarning; -module renode_ahb_subordinate ( +module renode_ahb_subordinate #(int CosimToRenodeIndex = 0) ( ref renode_runtime runtime, renode_ahb_if bus ); @@ -20,18 +20,18 @@ typedef logic [bus.DataWidth-1:0] data_t; wire clk = bus.hclk; - always @(runtime.peripheral.reset_assert_request) begin + always @(runtime.peripherals[CosimToRenodeIndex].reset_assert_request) begin bus.hresetn = 0; bus.hresp = Okay; bus.hreadyout = 1; repeat (2) @(posedge clk); - runtime.peripheral.reset_assert_respond(); + runtime.peripherals[CosimToRenodeIndex].reset_assert_respond(); end - always @(runtime.peripheral.reset_deassert_request) begin + always @(runtime.peripherals[CosimToRenodeIndex].reset_deassert_request) begin bus.hresetn = 1; repeat (2) @(posedge clk); - runtime.peripheral.reset_deassert_respond(); + runtime.peripherals[CosimToRenodeIndex].reset_deassert_respond(); end always @(posedge clk) transaction(); @@ -46,7 +46,7 @@ wait_for_transfer(address, valid_bits, direction, is_invalid); - // The runtime.peripheral.read call may consume an unknown number of clock cycles. + // The runtime.peripherals[CosimToRenodeIndex].read call may consume an unknown number of clock cycles. // To to make the logic simpler both read and write transactions contain at least one cycle with a deasserted ready. // It also ensures that address and data phases don't overlap between transactions. bus.hreadyout <= 0; @@ -54,11 +54,11 @@ if (!is_invalid) begin if (direction == Read) begin - runtime.peripheral.read(address, valid_bits, data, is_error); + runtime.peripherals[CosimToRenodeIndex].read(address, valid_bits, data, is_error); bus.hrdata = data_t'(data & valid_bits); if (is_error) runtime.connection.log(LogWarning, $sformatf("Unable to read data from Renode at address 'h%h", address)); end else begin - runtime.peripheral.write(address, valid_bits, renode_pkg::data_t'(bus.hwdata) & valid_bits, is_error); + runtime.peripherals[CosimToRenodeIndex].write(address, valid_bits, renode_pkg::data_t'(bus.hwdata) & valid_bits, is_error); if (is_error) runtime.connection.log(LogWarning, $sformatf("Unable to write data to Renode at address 'h%h", address)); end end
diff --git a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/apb3/renode_apb3_completer.sv b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/apb3/renode_apb3_completer.sv index 82411a1..595cb68 100644 --- a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/apb3/renode_apb3_completer.sv +++ b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/apb3/renode_apb3_completer.sv
@@ -10,7 +10,8 @@ import renode_pkg::renode_runtime, renode_pkg::LogWarning; module renode_apb3_completer #( - parameter int unsigned OutputLatency = 0 + parameter int unsigned OutputLatency = 0, + int CosimToRenodeIndex = 0 ) ( ref renode_runtime runtime, renode_apb3_if bus @@ -45,18 +46,18 @@ assign bus.pslverr = pslverr; // Connection initiated reset - always @(runtime.peripheral.reset_assert_request) begin + always @(runtime.peripherals[CosimToRenodeIndex].reset_assert_request) begin rst_n = 0; // The reset takes 2 cycles to prevent a race condition without usage of a non-blocking assigment. repeat (2) @(posedge clk); - runtime.peripheral.reset_assert_respond(); + runtime.peripherals[CosimToRenodeIndex].reset_assert_respond(); end - always @(runtime.peripheral.reset_deassert_request) begin + always @(runtime.peripherals[CosimToRenodeIndex].reset_deassert_request) begin rst_n = 1; // There is one more wait for the clock edges to be sure that all modules aren't in a reset state. repeat (2) @(posedge clk); - runtime.peripheral.reset_deassert_respond(); + runtime.peripherals[CosimToRenodeIndex].reset_deassert_respond(); end renode_pkg::valid_bits_e valid_bits; @@ -106,7 +107,7 @@ // Workaround::Bug::Verilator::Task call inside of always block requires using fork...join fork begin - runtime.peripheral.write(renode_pkg::address_t'(paddr), valid_bits, renode_pkg::data_t'(pwdata), + runtime.peripherals[CosimToRenodeIndex].write(renode_pkg::address_t'(paddr), valid_bits, renode_pkg::data_t'(pwdata), is_error); if (is_error) begin runtime.connection.log(LogWarning, "Renode connection write transfer was unable to complete"); @@ -120,8 +121,8 @@ // Workaround::Bug::Verilator::Task call inside of always block requires using fork...join fork begin - // The runtime.peripheral.read call may cause elapse of a simulation time. - runtime.peripheral.read(renode_pkg::address_t'(paddr), valid_bits, prdata_int, is_error); + // The runtime.peripherals[CosimToRenodeIndex].read call may cause elapse of a simulation time. + runtime.peripherals[CosimToRenodeIndex].read(renode_pkg::address_t'(paddr), valid_bits, prdata_int, is_error); if (is_error) begin runtime.connection.log(LogWarning, "Renode connection read transfer was unable to complete"); end
diff --git a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/apb3/renode_apb3_requester.sv b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/apb3/renode_apb3_requester.sv index 80fd35d..4f2e317 100644 --- a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/apb3/renode_apb3_requester.sv +++ b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/apb3/renode_apb3_requester.sv
@@ -9,7 +9,7 @@ import renode_pkg::renode_runtime, renode_pkg::LogWarning; -module renode_apb3_requester ( +module renode_apb3_requester #(int RenodeToCosimIndex = 0) ( ref renode_runtime runtime, renode_apb3_if bus ); @@ -54,7 +54,7 @@ localparam int unsigned Back2BackNum = 1; - always @(runtime.controller.reset_assert_request) begin + always @(runtime.controllers[RenodeToCosimIndex].reset_assert_request) begin write_address = '0; read_address = '0; write_data = '0; @@ -63,14 +63,14 @@ rst_n = 0; // The reset takes 2 cycles to prevent a race condition without usage of a non-blocking assigment. repeat (2) @(posedge clk); - runtime.controller.reset_assert_respond(); + runtime.controllers[RenodeToCosimIndex].reset_assert_respond(); end - always @(runtime.controller.reset_deassert_request) begin + always @(runtime.controllers[RenodeToCosimIndex].reset_deassert_request) begin rst_n = 1; // There is one more wait for the clock edges to be sure that all modules aren't in a reset state. repeat (2) @(posedge clk); - runtime.controller.reset_deassert_respond(); + runtime.controllers[RenodeToCosimIndex].reset_deassert_respond(); end // Internal state @@ -85,13 +85,13 @@ // Waveform generation // - always @(runtime.controller.read_transaction_request) begin + always @(runtime.controllers[RenodeToCosimIndex].read_transaction_request) begin integer transaction_width; - if(!renode_pkg::is_access_aligned(runtime.controller.read_transaction_address, runtime.controller.read_transaction_data_bits)) begin + if(!renode_pkg::is_access_aligned(runtime.controllers[RenodeToCosimIndex].read_transaction_address, runtime.controllers[RenodeToCosimIndex].read_transaction_data_bits)) begin runtime.connection.log(LogWarning, "Unaligned access on APB bus results in unpredictable behavior"); end - transaction_width = renode_pkg::valid_bits_to_transaction_width(runtime.controller.read_transaction_data_bits); + transaction_width = renode_pkg::valid_bits_to_transaction_width(runtime.controllers[RenodeToCosimIndex].read_transaction_data_bits); if (bus.DataWidth > transaction_width) begin runtime.connection.log(LogWarning, $sformatf("Bus bus.bus.DataWidth is (%d) > transaction width (%d), MSB will be truncated.", bus.DataWidth, transaction_width)); @@ -100,19 +100,19 @@ $sformatf("Bus bus.bus.DataWidth is (%d) < transaction width (%d), MSB will be zero-extended.", bus.DataWidth, transaction_width)); end - read_address = address_t'(runtime.controller.read_transaction_address); + read_address = address_t'(runtime.controllers[RenodeToCosimIndex].read_transaction_address); write_mode = 1'b0; start_transaction = 1'b1; @(posedge clk) start_transaction <= 1'b0; end - always @(runtime.controller.write_transaction_request) begin + always @(runtime.controllers[RenodeToCosimIndex].write_transaction_request) begin integer transaction_width; - if(!renode_pkg::is_access_aligned(runtime.controller.write_transaction_address, runtime.controller.write_transaction_data_bits)) begin + if(!renode_pkg::is_access_aligned(runtime.controllers[RenodeToCosimIndex].write_transaction_address, runtime.controllers[RenodeToCosimIndex].write_transaction_data_bits)) begin runtime.connection.log(LogWarning, "Unaligned access on APB bus results in unpredictable behavior"); end - transaction_width = renode_pkg::valid_bits_to_transaction_width(runtime.controller.write_transaction_data_bits); + transaction_width = renode_pkg::valid_bits_to_transaction_width(runtime.controllers[RenodeToCosimIndex].write_transaction_data_bits); if (bus.DataWidth > transaction_width) begin runtime.connection.log(LogWarning, $sformatf("Bus bus.bus.DataWidth is (%d) > transaction width (%d), MSB will be truncated.", bus.DataWidth, transaction_width)); @@ -121,8 +121,8 @@ $sformatf("Bus bus.bus.DataWidth is (%d) < transaction width (%d), MSB will be zero-extended.", bus.DataWidth, transaction_width)); end - write_address = address_t'(runtime.controller.write_transaction_address); - write_data = data_t'(runtime.controller.write_transaction_data); + write_address = address_t'(runtime.controllers[RenodeToCosimIndex].write_transaction_address); + write_data = data_t'(runtime.controllers[RenodeToCosimIndex].write_transaction_data); write_mode = 1'b1; start_transaction = 1'b1; @(posedge clk) start_transaction <= 1'b0; @@ -174,9 +174,9 @@ S_ACCESS: begin if (pready) begin if (write_mode) begin - runtime.controller.write_respond(1'b0); // Notify Renode that write is done + runtime.controllers[RenodeToCosimIndex].write_respond(1'b0); // Notify Renode that write is done end else begin - runtime.controller.read_respond(renode_pkg::data_t'(prdata), 1'b0); + runtime.controllers[RenodeToCosimIndex].read_respond(renode_pkg::data_t'(prdata), 1'b0); end end end
diff --git a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/axi/renode_axi_manager.sv b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/axi/renode_axi_manager.sv index 5d70427..a523c36 100644 --- a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/axi/renode_axi_manager.sv +++ b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/axi/renode_axi_manager.sv
@@ -9,7 +9,7 @@ import renode_pkg::renode_runtime, renode_pkg::LogWarning; -module renode_axi_manager ( +module renode_axi_manager #(int RenodeToCosimIndex = 0) ( ref renode_runtime runtime, renode_axi_if bus ); @@ -22,25 +22,25 @@ wire clk = bus.aclk; - always @(runtime.controller.reset_assert_request) begin + always @(runtime.controllers[RenodeToCosimIndex].reset_assert_request) begin bus.arvalid = 0; bus.awvalid = 0; bus.wvalid = 0; bus.areset_n = 0; // The reset takes 2 cycles to prevent a race condition without usage of a non-blocking assigment. repeat (2) @(posedge clk); - runtime.controller.reset_assert_respond(); + runtime.controllers[RenodeToCosimIndex].reset_assert_respond(); end - always @(runtime.controller.reset_deassert_request) begin + always @(runtime.controllers[RenodeToCosimIndex].reset_deassert_request) begin bus.areset_n = 1; // There is one more wait for the clock edges to be sure that all modules aren't in a reset state. repeat (2) @(posedge clk); - runtime.controller.reset_deassert_respond(); + runtime.controllers[RenodeToCosimIndex].reset_deassert_respond(); end - always @(runtime.controller.read_transaction_request) read_transaction(); - always @(runtime.controller.write_transaction_request) write_transaction(); + always @(runtime.controllers[RenodeToCosimIndex].read_transaction_request) read_transaction(); + always @(runtime.controllers[RenodeToCosimIndex].write_transaction_request) write_transaction(); task static read_transaction(); bit is_error; @@ -49,18 +49,18 @@ burst_size_t burst_size; data_t data; - address = address_t'(runtime.controller.read_transaction_address); - valid_bits = runtime.controller.read_transaction_data_bits; + address = address_t'(runtime.controllers[RenodeToCosimIndex].read_transaction_address); + valid_bits = runtime.controllers[RenodeToCosimIndex].read_transaction_data_bits; if(!is_access_valid(address, valid_bits)) begin - runtime.controller.read_respond(0, 1); + runtime.controllers[RenodeToCosimIndex].read_respond(0, 1); end else begin burst_size = bus.valid_bits_to_burst_size(valid_bits); read(0, address, burst_size, data, is_error); data = data >> ((address % bus.StrobeWidth) * 8); - runtime.controller.read_respond(renode_pkg::data_t'(data) & valid_bits, is_error); + runtime.controllers[RenodeToCosimIndex].read_respond(renode_pkg::data_t'(data) & valid_bits, is_error); end endtask @@ -72,20 +72,20 @@ data_t data; strobe_t strobe; - address = address_t'(runtime.controller.write_transaction_address); - valid_bits = runtime.controller.write_transaction_data_bits; + address = address_t'(runtime.controllers[RenodeToCosimIndex].write_transaction_address); + valid_bits = runtime.controllers[RenodeToCosimIndex].write_transaction_data_bits; if(!is_access_valid(address, valid_bits)) begin - runtime.controller.write_respond(1); + runtime.controllers[RenodeToCosimIndex].write_respond(1); end else begin burst_size = bus.valid_bits_to_burst_size(valid_bits); - data = data_t'(runtime.controller.write_transaction_data & valid_bits); + data = data_t'(runtime.controllers[RenodeToCosimIndex].write_transaction_data & valid_bits); strobe = bus.burst_size_to_strobe(burst_size) << (address % bus.StrobeWidth); data = data << ((address % bus.StrobeWidth) * 8); write(0, address, burst_size, strobe, data, is_error); - runtime.controller.write_respond(is_error); + runtime.controllers[RenodeToCosimIndex].write_respond(is_error); end endtask
diff --git a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/axi/renode_axi_subordinate.sv b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/axi/renode_axi_subordinate.sv index b68cdb5..3b9578d 100644 --- a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/axi/renode_axi_subordinate.sv +++ b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/axi/renode_axi_subordinate.sv
@@ -9,7 +9,7 @@ import renode_pkg::renode_runtime, renode_pkg::LogWarning; -module renode_axi_subordinate ( +module renode_axi_subordinate #(int CosimToRenodeIndex = 0) ( ref renode_runtime runtime, renode_axi_if bus ); @@ -22,20 +22,20 @@ wire clk = bus.aclk; - always @(runtime.peripheral.reset_assert_request) begin + always @(runtime.peripherals[CosimToRenodeIndex].reset_assert_request) begin bus.rvalid = 0; bus.bvalid = 0; bus.areset_n = 0; // The reset takes 2 cycles to prevent a race condition without usage of a non-blocking assigment. repeat (2) @(posedge clk); - runtime.peripheral.reset_assert_respond(); + runtime.peripherals[CosimToRenodeIndex].reset_assert_respond(); end - always @(runtime.peripheral.reset_deassert_request) begin + always @(runtime.peripherals[CosimToRenodeIndex].reset_deassert_request) begin bus.areset_n = 1; // There is one more wait for the clock edges to be sure that all modules aren't in a reset state. repeat (2) @(posedge clk); - runtime.peripheral.reset_deassert_respond(); + runtime.peripherals[CosimToRenodeIndex].reset_deassert_respond(); end always @(clk) read_transaction(); @@ -63,7 +63,7 @@ end else begin // The conection.read call may cause simulation time to move forward - runtime.peripheral.read(renode_pkg::address_t'(address), valid_bits, data, is_error); + runtime.peripherals[CosimToRenodeIndex].read(renode_pkg::address_t'(address), valid_bits, data, is_error); if (is_error) begin runtime.connection.log(LogWarning, $sformatf("Unable to read data from Renode at address 'h%h, responding with 0.", address)); data = 0; @@ -111,7 +111,7 @@ if (bus.wlast != (address == address_last)) runtime.connection.log(LogWarning, "Unexpected state of the wlast signal."); // The conection.write call may cause simulation time to move forward - runtime.peripheral.write(renode_pkg::address_t'(address), valid_bits, renode_pkg::data_t'(data) & valid_bits, is_error); + runtime.peripherals[CosimToRenodeIndex].write(renode_pkg::address_t'(address), valid_bits, renode_pkg::data_t'(data) & valid_bits, is_error); if (is_error) runtime.connection.log(LogWarning, $sformatf("Unable to write data to Renode at address 'h%h", address)); end
diff --git a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/renode.sv b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/renode.sv index 7605c66..26fb41f 100644 --- a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/renode.sv +++ b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/renode.sv
@@ -7,12 +7,12 @@ `timescale 1ns / 1ps -import renode_pkg::renode_runtime; +import renode_pkg::renode_runtime, renode_pkg::bus_connection, renode_pkg::renode_connection, renode_pkg::no_peripheral_index; import renode_pkg::message_t, renode_pkg::address_t, renode_pkg::data_t, renode_pkg::valid_bits_e; module renode #( - int unsigned BusControllersCount = 0, - int unsigned BusPeripheralsCount = 0, + int unsigned RenodeToCosimCount = 0, + int unsigned CosimToRenodeCount = 0, int unsigned RenodeInputsCount = 1, int unsigned RenodeOutputsCount = 1 ) ( @@ -23,6 +23,14 @@ ); time renode_time = 0; + event reset_assert_all; + int reset_assert_done_count; + event reset_assert_done; + + event reset_deassert_all; + int reset_deassert_done_count; + event reset_deassert_done; + renode_inputs #( .InputsCount(RenodeInputsCount) ) gpio ( @@ -31,8 +39,59 @@ .inputs(renode_inputs) ); - always @(runtime.peripheral.read_transaction_request) read_transaction(); - always @(runtime.peripheral.write_transaction_request) write_transaction(); + initial begin + runtime.controllers = new[RenodeToCosimCount]; + foreach(runtime.controllers[i]) begin + runtime.controllers[i] = new(); + end + + runtime.peripherals = new[CosimToRenodeCount]; + foreach(runtime.peripherals[i]) begin + runtime.peripherals[i] = new(); + end + end + + if(CosimToRenodeCount > 0) begin + genvar i; + for(i = 0; i < CosimToRenodeCount; i += 1) begin + always @(runtime.peripherals[i].read_transaction_request) read_transaction(i); + always @(runtime.peripherals[i].write_transaction_request) write_transaction(i); + always @(reset_assert_all) runtime.peripherals[i].reset_assert(); + always @(runtime.peripherals[i].reset_assert_response) begin + reset_assert_done_count++; + if(reset_assert_done_count == (CosimToRenodeCount + RenodeToCosimCount)) begin + ->reset_assert_done; + end + end + always @(runtime.peripherals[i].reset_deassert_response) begin + reset_deassert_done_count++; + if(reset_deassert_done_count == (CosimToRenodeCount + RenodeToCosimCount)) begin + ->reset_deassert_done; + end + end + always @(reset_deassert_all) runtime.peripherals[i].reset_deassert(); + end + end + + if(RenodeToCosimCount > 0) begin + genvar i; + for(i = 0; i < RenodeToCosimCount; i += 1) begin + always @(reset_assert_all) runtime.controllers[i].reset_assert(); + always @(reset_deassert_all) runtime.controllers[i].reset_deassert(); + always @(runtime.controllers[i].reset_assert_response) begin + reset_assert_done_count++; + if(reset_assert_done_count == (CosimToRenodeCount + RenodeToCosimCount)) begin + ->reset_assert_done; + end + end + always @(runtime.controllers[i].reset_deassert_response) begin + reset_deassert_done_count++; + if(reset_deassert_done_count == (CosimToRenodeCount + RenodeToCosimCount)) begin + ->reset_deassert_done; + end + end + end + end task static receive_and_handle_message(); message_t message; @@ -54,14 +113,14 @@ renode_pkg::resetPeripheral: reset(); renode_pkg::tickClock: sync_time(time'(message.data)); renode_pkg::interrupt: handle_renode_output(message.address, message.data[0]); - renode_pkg::writeRequestQuadWord: write_to_bus(message.address, renode_pkg::QuadWord, message.data); - renode_pkg::writeRequestDoubleWord: write_to_bus(message.address, renode_pkg::DoubleWord, message.data); - renode_pkg::writeRequestWord: write_to_bus(message.address, renode_pkg::Word, message.data); - renode_pkg::writeRequestByte: write_to_bus(message.address, renode_pkg::Byte, message.data); - renode_pkg::readRequestQuadWord: read_from_bus(message.address, renode_pkg::QuadWord); - renode_pkg::readRequestDoubleWord: read_from_bus(message.address, renode_pkg::DoubleWord); - renode_pkg::readRequestWord: read_from_bus(message.address, renode_pkg::Word); - renode_pkg::readRequestByte: read_from_bus(message.address, renode_pkg::Byte); + renode_pkg::writeRequestQuadWord: write_to_bus(message.address, renode_pkg::QuadWord, message.data, message.peripheral_index); + renode_pkg::writeRequestDoubleWord: write_to_bus(message.address, renode_pkg::DoubleWord, message.data, message.peripheral_index); + renode_pkg::writeRequestWord: write_to_bus(message.address, renode_pkg::Word, message.data, message.peripheral_index); + renode_pkg::writeRequestByte: write_to_bus(message.address, renode_pkg::Byte, message.data, message.peripheral_index); + renode_pkg::readRequestQuadWord: read_from_bus(message.address, renode_pkg::QuadWord, message.peripheral_index); + renode_pkg::readRequestDoubleWord: read_from_bus(message.address, renode_pkg::DoubleWord, message.peripheral_index); + renode_pkg::readRequestWord: read_from_bus(message.address, renode_pkg::Word, message.peripheral_index); + renode_pkg::readRequestByte: read_from_bus(message.address, renode_pkg::Byte, message.peripheral_index); default: is_handled = 0; endcase @@ -70,41 +129,33 @@ endtask task static reset(); + // Nothing to reset, return immediately. + if(RenodeToCosimCount + CosimToRenodeCount == 0) return; + // The reset just locks the connection without using it to avoid an unexpected behaviour. // It also prevents from a message handling in the receive_and_handle_message until a reset deassertion. runtime.connection.exclusive_receive.get(); - // The delay was added to avoid a race condition. - // It may occure when an event is triggered before executing a wait for this event. - // A non-blocking trigger, which is an alternative solution, isn't supported by Verilator. + reset_assert_done_count = 0; #1 fork - begin - if (BusPeripheralsCount > 0) - runtime.peripheral.reset_assert(); - end - begin - if (BusControllersCount > 0) - runtime.controller.reset_assert(); - end - gpio.reset_assert(); + ->reset_assert_all; + gpio.reset_assert(); join + @(reset_assert_done); + // It's required to make values of all signals known (different than `x`) before a deassertion of resets. // The assignment to renode_outputs is an equivalent of a reset assertion. renode_outputs = 0; + reset_deassert_done_count = 0; fork - begin - if (BusPeripheralsCount > 0) - runtime.peripheral.reset_deassert(); - end - begin - if (BusControllersCount > 0) - runtime.controller.reset_deassert(); - end + ->reset_deassert_all; gpio.reset_deassert(); join + @(reset_deassert_done); + runtime.connection.exclusive_receive.put(); endtask @@ -112,87 +163,97 @@ renode_time = renode_time + time_to_elapse; while ($time < renode_time) @(clk); - runtime.connection.send_to_async_receiver(message_t'{renode_pkg::tickClock, 0, 0}); + runtime.connection.send_to_async_receiver(message_t'{renode_pkg::tickClock, 0, 0, renode_pkg::no_peripheral_index}); runtime.connection.log(renode_pkg::LogNoisy, $sformatf("Simulation time synced to %t", $realtime)); endtask - task automatic read_from_bus(address_t address, valid_bits_e data_bits); + task automatic read_from_bus(address_t address, valid_bits_e data_bits, int peripheral_index); data_t data = 0; bit is_error = 0; - runtime.controller.read(address, data_bits, data, is_error); + runtime.controllers[peripheral_index].read(address, data_bits, data, is_error); - if (is_error) runtime.connection.send(message_t'{renode_pkg::error, 0, 0}); - else runtime.connection.send(message_t'{renode_pkg::readRequest, address, data}); + if (is_error) runtime.connection.send(message_t'{renode_pkg::error, 0, 0, peripheral_index}); + else runtime.connection.send(message_t'{renode_pkg::readRequest, address, data, peripheral_index}); endtask - task automatic write_to_bus(address_t address, valid_bits_e data_bits, data_t data); + task automatic write_to_bus(address_t address, valid_bits_e data_bits, data_t data, int peripheral_index); bit is_error = 0; - runtime.controller.write(address, data_bits, data, is_error); + runtime.controllers[peripheral_index].write(address, data_bits, data, is_error); - if (is_error) runtime.connection.send(message_t'{renode_pkg::error, 0, 0}); - else runtime.connection.send(message_t'{renode_pkg::ok, 0, 0}); + if (is_error) runtime.connection.send(message_t'{renode_pkg::error, 0, 0, peripheral_index}); + else runtime.connection.send(message_t'{renode_pkg::ok, 0, 0, peripheral_index}); endtask - task static read_transaction(); + task automatic read_transaction(int peripheral_index); message_t message; - case (runtime.peripheral.read_transaction_data_bits) + case (runtime.peripherals[peripheral_index].read_transaction_data_bits) renode_pkg::Byte: message.action = renode_pkg::getByte; renode_pkg::Word: message.action = renode_pkg::getWord; renode_pkg::DoubleWord: message.action = renode_pkg::getDoubleWord; renode_pkg::QuadWord: message.action = renode_pkg::getQuadWord; default: begin - runtime.connection.fatal_error($sformatf("Renode doesn't support access with the 'b%b mask from a bus controller.", runtime.peripheral.read_transaction_data_bits)); - runtime.peripheral.read_respond(0, 1); + 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)); + runtime.peripherals[peripheral_index].read_respond(0, 1); return; end endcase - message.address = runtime.peripheral.read_transaction_address; + message.address = runtime.peripherals[peripheral_index].read_transaction_address; message.data = 0; runtime.connection.exclusive_receive.get(); + if(!runtime.connection.is_connected()) begin + runtime.connection.exclusive_receive.put(); + return; + end runtime.connection.send_to_async_receiver(message); runtime.connection.receive(message); while (message.action != renode_pkg::writeRequest) begin handle_message(message); + if(message.action == renode_pkg::disconnect) break; runtime.connection.receive(message); end runtime.connection.exclusive_receive.put(); - runtime.peripheral.read_respond(message.data, 0); + runtime.peripherals[peripheral_index].read_respond(message.data, 0); endtask - task static write_transaction(); + task automatic write_transaction(int peripheral_index); message_t message; - case (runtime.peripheral.write_transaction_data_bits) + case (runtime.peripherals[peripheral_index].write_transaction_data_bits) renode_pkg::Byte: message.action = renode_pkg::pushByte; renode_pkg::Word: message.action = renode_pkg::pushWord; renode_pkg::DoubleWord: message.action = renode_pkg::pushDoubleWord; renode_pkg::QuadWord: message.action = renode_pkg::pushQuadWord; default: begin - runtime.connection.fatal_error($sformatf("Renode doesn't support access with the 'b%b mask from a bus controller.", runtime.peripheral.read_transaction_data_bits)); - runtime.peripheral.write_respond(1); + 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)); + runtime.peripherals[peripheral_index].write_respond(1); return; end endcase - message.address = runtime.peripheral.write_transaction_address; - message.data = runtime.peripheral.write_transaction_data; + message.address = runtime.peripherals[peripheral_index].write_transaction_address; + message.data = runtime.peripherals[peripheral_index].write_transaction_data; runtime.connection.exclusive_receive.get(); + if(!runtime.connection.is_connected()) begin + runtime.connection.exclusive_receive.put(); + return; + end runtime.connection.send_to_async_receiver(message); runtime.connection.receive(message); while (message.action != renode_pkg::pushConfirmation) begin handle_message(message); + if(message.action == renode_pkg::disconnect) break; runtime.connection.receive(message); end runtime.connection.exclusive_receive.put(); - runtime.peripheral.write_respond(0); + runtime.peripherals[peripheral_index].write_respond(0); endtask // calculate number of bits needed to hold the output number @@ -202,12 +263,12 @@ task automatic handle_renode_output(address_t number, bit value); if (number >= 64'(RenodeOutputsCount)) begin runtime.connection.log(renode_pkg::LogWarning, $sformatf("Output %0d is out of range of [0;%0d]", number, RenodeOutputsCount - 1)); - runtime.connection.send(message_t'{renode_pkg::error, 0, 0}); + runtime.connection.send(message_t'{renode_pkg::error, 0, 0, renode_pkg::no_peripheral_index}); end @(posedge clk); renode_outputs[number[RenodeOutputsCountWidth-1:0]] <= value; - runtime.connection.send(message_t'{renode_pkg::ok, 0, 0}); + runtime.connection.send(message_t'{renode_pkg::ok, 0, 0, renode_pkg::no_peripheral_index}); endtask endmodule
diff --git a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/renode_inputs.sv b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/renode_inputs.sv index 7548138..9581602 100644 --- a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/renode_inputs.sv +++ b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/modules/renode_inputs.sv
@@ -7,7 +7,7 @@ `timescale 1ns / 1ps -import renode_pkg::renode_runtime; +import renode_pkg::renode_runtime, renode_pkg::no_peripheral_index; module renode_inputs #( int unsigned InputsCount = 1 @@ -36,7 +36,8 @@ runtime.connection.send_to_async_receiver(renode_pkg::message_t'{ renode_pkg::interrupt, renode_pkg::address_t'(addr), - renode_pkg::data_t'(inputs[addr]) + renode_pkg::data_t'(inputs[addr]), + renode_pkg::no_peripheral_index }); end end
diff --git a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/renode_pkg.sv b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/renode_pkg.sv index 5529c31..98c73d8 100644 --- a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/renode_pkg.sv +++ b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/hdl/renode_pkg.sv
@@ -17,10 +17,13 @@ `include "renode_action_enumerators.svh" } action_e; + const int no_peripheral_index = -1; + typedef struct { action_e action; address_t address; data_t data; + int peripheral_index; } message_t; typedef enum data_t { @@ -56,19 +59,22 @@ import "DPI-C" function bit renodeDPIReceive( output action_e action, output address_t address, - output data_t data + output data_t data, + output int peripheralIndex ); import "DPI-C" function bit renodeDPISend( action_e action, address_t address, - data_t data + data_t data, + int peripheralIndex ); import "DPI-C" function bit renodeDPISendToAsync( action_e action, address_t address, - data_t data + data_t data, + int peripheralIndex ); function static bit is_access_aligned(address_t address, valid_bits_e valid_bits); @@ -146,10 +152,10 @@ endfunction function bit try_receive(output message_t message); - bit is_received = renodeDPIReceive(message.action, message.address, message.data); + bit is_received = renodeDPIReceive(message.action, message.address, message.data, message.peripheral_index); if(is_received) begin `ifdef RENODE_DEBUG - $display("Renode at %t: Received action %0s, address = 'h%h, data = 'h%h", $realtime, message.action.name(), message.address, message.data); + $display("Renode at %t: Received action %0s, address = 'h%h, data = 'h%h, peripheral index: %d", $realtime, message.action.name(), message.address, message.data, message.peripheral_index); `endif end return is_received; @@ -157,16 +163,16 @@ function void send(message_t message); `ifdef RENODE_DEBUG - $display("Renode at %t: Sent action %0s, address = 'h%h, data = 'h%h", $realtime, message.action.name(), message.address, message.data); + $display("Renode at %t: Sent action %0s, address = 'h%h, data = 'h%h, peripheral index: %d", $realtime, message.action.name(), message.address, message.data, message.peripheral_index); `endif - if (!renodeDPISend(message.action, message.address, message.data)) fatal_error("Unexpected channel disconnection"); + if (!renodeDPISend(message.action, message.address, message.data, message.peripheral_index)) fatal_error("Unexpected channel disconnection"); endfunction function void send_to_async_receiver(message_t message); `ifdef RENODE_DEBUG - $display("Renode at %t: Sent async action %0s, address = 'h%h, data = 'h%h", $realtime, message.action.name(), message.address, message.data); + $display("Renode at %t: Sent async action %0s, address = 'h%h, data = 'h%h, peripheral index: %d", $realtime, message.action.name(), message.address, message.data, message.peripheral_index); `endif - if (!renodeDPISendToAsync(message.action, message.address, message.data)) fatal_error("Unexpected channel disconnection"); + if (!renodeDPISendToAsync(message.action, message.address, message.data, message.peripheral_index)) fatal_error("Unexpected channel disconnection"); endfunction local function void disconnect(); @@ -174,7 +180,7 @@ endfunction local function void handle_disconnect(); - send(message_t'{ok, 0, 0}); + send(message_t'{ok, 0, 0, renode_pkg::no_peripheral_index}); disconnect(); `ifdef RENODE_DEBUG $display("Renode at %t: disconnected", $realtime); @@ -262,8 +268,10 @@ const string AddressArgName = "RENODE_ADDRESS"; renode_connection connection = new(); - bus_connection controller = new(); - bus_connection peripheral = new(); + + // Initialized by the Renode module + bus_connection controllers[]; + bus_connection peripherals[]; function void connect_plus_args(); int receiver_port, sender_port;
diff --git a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/communication/socket_channel.cpp b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/communication/socket_channel.cpp index 64cfcd1..c287630 100644 --- a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/communication/socket_channel.cpp +++ b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/communication/socket_channel.cpp
@@ -35,14 +35,14 @@ { Protocol* received = receive(); if(received->actionId == handshake) { - sendMain(Protocol(handshake, 0, 0)); + sendMain(Protocol(handshake, 0, 0, noPeripheralIndex)); isConnected = true; } } void SocketCommunicationChannel::log(int logLevel, const char* data) { - sendSender(Protocol(logMessage, strlen(data), logLevel)); + sendSender(Protocol(logMessage, strlen(data), logLevel, noPeripheralIndex)); senderSocket->Send(data, strlen(data)); }
diff --git a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/renode.h b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/renode.h index 07fd0cb..c68eef7 100644 --- a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/renode.h +++ b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/renode.h
@@ -15,16 +15,18 @@ struct Protocol { Protocol() = default; - Protocol(int actionId, uint64_t addr, uint64_t value) + Protocol(int actionId, uint64_t addr, uint64_t value, int peripheralIndex = 0) { this->actionId = actionId; this->addr = addr; this->value = value; + this->peripheralIndex = peripheralIndex; } int actionId; uint64_t addr; uint64_t value; + int peripheralIndex; }; #pragma pack(pop) @@ -42,4 +44,6 @@ LOG_LEVEL_ERROR = 3 }; +const int noPeripheralIndex = -1; + #endif
diff --git a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/renode_dpi.cpp b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/renode_dpi.cpp index 0fdac9f..c5718a0 100644 --- a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/renode_dpi.cpp +++ b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/renode_dpi.cpp
@@ -10,7 +10,7 @@ static SocketCommunicationChannel *socketChannel; -bool renodeDPIReceive(uint32_t* actionId, uint64_t* address, uint64_t* value) +bool renodeDPIReceive(uint32_t* actionId, uint64_t* address, uint64_t* value, int32_t* peripheralIndex) { if(!socketChannel->getIsConnected()) { @@ -20,6 +20,8 @@ *actionId = message->actionId; *address = message->addr; *value = message->value; + *peripheralIndex = message->peripheralIndex; + delete message; return true; } @@ -43,23 +45,23 @@ return socketChannel != NULL && socketChannel->getIsConnected(); } -bool renodeDPISend(uint32_t actionId, uint64_t address, uint64_t value) +bool renodeDPISend(uint32_t actionId, uint64_t address, uint64_t value, int32_t peripheralIndex) { if(socketChannel == NULL || !socketChannel->getIsConnected()) { return false; } - socketChannel->sendMain(Protocol(actionId, address, value)); + socketChannel->sendMain(Protocol(actionId, address, value, peripheralIndex)); return true; } -bool renodeDPISendToAsync(uint32_t actionId, uint64_t address, uint64_t value) +bool renodeDPISendToAsync(uint32_t actionId, uint64_t address, uint64_t value, int32_t peripheralIndex) { if(socketChannel == NULL || !socketChannel->getIsConnected()) { return false; } - socketChannel->sendSender(Protocol(actionId, address, value)); + socketChannel->sendSender(Protocol(actionId, address, value, peripheralIndex)); return true; }
diff --git a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/renode_dpi.h b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/renode_dpi.h index 5b3a959..8bccf9f 100644 --- a/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/renode_dpi.h +++ b/src/Plugins/CoSimulationPlugin/IntegrationLibrary/src/renode_dpi.h
@@ -13,9 +13,9 @@ void renodeDPIConnect(int receiverPort, int senderPort, const char *address); void renodeDPIDisconnect(); bool renodeDPIIsConnected(); - bool renodeDPIReceive(uint32_t *actionId, uint64_t *address, uint64_t *value); - bool renodeDPISend(uint32_t actionId, uint64_t address, uint64_t value); - bool renodeDPISendToAsync(uint32_t actionId, uint64_t address, uint64_t value); + bool renodeDPIReceive(uint32_t *actionId, uint64_t *address, uint64_t *value, int32_t *peripheralIndex); + bool renodeDPISend(uint32_t actionId, uint64_t address, uint64_t value, int32_t peripheralIndex); + bool renodeDPISendToAsync(uint32_t actionId, uint64_t address, uint64_t value, int32_t peripheralIndex); bool renodeDPILog(int logLevel, const char *data); }