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 using Antmicro.Renode.Core; 8 using Antmicro.Renode.Exceptions; 9 using Antmicro.Renode.Logging; 10 using Antmicro.Renode.Peripherals.Bus; 11 using Antmicro.Renode.Peripherals.CPU; 12 using Antmicro.Renode.Peripherals.Timers; 13 using Antmicro.Renode.Time; 14 using Antmicro.Renode.Utilities; 15 using System; 16 using System.Collections.Generic; 17 using System.Collections.ObjectModel; 18 using System.Diagnostics; 19 using System.Linq; 20 using System.Net; 21 using System.Net.Sockets; 22 using System.Runtime.InteropServices; 23 using System.Text; 24 using System.Threading; 25 #if !PLATFORM_WINDOWS 26 using Mono.Unix.Native; 27 #endif 28 29 namespace Antmicro.Renode.Peripherals.SystemC 30 { 31 public enum RenodeAction : byte 32 { 33 Init = 0, 34 Read = 1, 35 Write = 2, 36 Timesync = 3, 37 GPIOWrite = 4, 38 Reset = 5, 39 DMIReq = 6, 40 InvalidateTBs = 7, 41 ReadRegister = 8, 42 WriteRegister = 9, 43 } 44 45 [StructLayout(LayoutKind.Sequential, Pack = 1)] 46 public struct RenodeMessage 47 { RenodeMessageAntmicro.Renode.Peripherals.SystemC.RenodeMessage48 public RenodeMessage(RenodeAction actionId, byte dataLength, byte connectionIndex, ulong address, ulong payload) 49 { 50 ActionId = actionId; 51 DataLength = dataLength; 52 ConnectionIndex = connectionIndex; 53 Address = address; 54 Payload = payload; 55 } 56 SerializeAntmicro.Renode.Peripherals.SystemC.RenodeMessage57 public byte[] Serialize() 58 { 59 var size = Marshal.SizeOf(this); 60 var result = new byte[size]; 61 var handler = default(GCHandle); 62 63 try 64 { 65 handler = GCHandle.Alloc(result, GCHandleType.Pinned); 66 Marshal.StructureToPtr(this, handler.AddrOfPinnedObject(), false); 67 } 68 finally 69 { 70 if(handler.IsAllocated) 71 { 72 handler.Free(); 73 } 74 } 75 76 return result; 77 } 78 DeserializeAntmicro.Renode.Peripherals.SystemC.RenodeMessage79 public void Deserialize(byte[] message) 80 { 81 var handler = default(GCHandle); 82 try 83 { 84 handler = GCHandle.Alloc(message, GCHandleType.Pinned); 85 this = (RenodeMessage)Marshal.PtrToStructure(handler.AddrOfPinnedObject(), typeof(RenodeMessage)); 86 } 87 finally 88 { 89 if(handler.IsAllocated) 90 { 91 handler.Free(); 92 } 93 } 94 } 95 ToStringAntmicro.Renode.Peripherals.SystemC.RenodeMessage96 public override string ToString() 97 { 98 return $"RenodeMessage [{ActionId}@{ConnectionIndex}:{Address}] {Payload}"; 99 } 100 IsSystemBusConnectionAntmicro.Renode.Peripherals.SystemC.RenodeMessage101 public bool IsSystemBusConnection() => ConnectionIndex == MainSystemBusConnectionIndex; IsDirectConnectionAntmicro.Renode.Peripherals.SystemC.RenodeMessage102 public bool IsDirectConnection() => !IsSystemBusConnection(); 103 GetDirectConnectionIndexAntmicro.Renode.Peripherals.SystemC.RenodeMessage104 public byte GetDirectConnectionIndex() 105 { 106 if(!IsDirectConnection()) 107 { 108 Logger.Log(LogLevel.Error, "Message for main system bus connection does not have a direct connection index."); 109 return 0xff; 110 } 111 return (byte)(ConnectionIndex - 1); 112 } 113 114 public const int DMIAllowed = 1; 115 public const int DMINotAllowed = 0; 116 117 private const byte MainSystemBusConnectionIndex = 0; 118 119 public readonly RenodeAction ActionId; 120 public readonly byte DataLength; 121 public readonly byte ConnectionIndex; 122 public readonly ulong Address; 123 public readonly ulong Payload; 124 } 125 126 [StructLayout(LayoutKind.Sequential, Pack = 1)] 127 public struct DMIMessage 128 { DMIMessageAntmicro.Renode.Peripherals.SystemC.DMIMessage129 public DMIMessage(RenodeAction actionId, byte allowed, ulong startAddress, ulong endAddress, ulong mmfOffset, string mmfPath) 130 { 131 ActionId = actionId; 132 Allowed = allowed; 133 StartAddress = startAddress; 134 EndAddress = endAddress; 135 MMFOffset = mmfOffset; 136 MMFPath = new byte[256]; 137 byte[] mmfPathBytes = Encoding.ASCII.GetBytes(mmfPath); 138 if(mmfPathBytes.Length > 256) 139 { 140 Logger.Log(LogLevel.Error, "MMF path name is too long"); 141 } 142 else 143 { 144 Array.Copy(mmfPathBytes, MMFPath, Math.Min(mmfPathBytes.Length, MMFPath.Length)); 145 } 146 } 147 SerializeAntmicro.Renode.Peripherals.SystemC.DMIMessage148 public byte[] Serialize() 149 { 150 var size = Marshal.SizeOf(this); 151 var result = new byte[size]; 152 var handler = default(GCHandle); 153 154 try 155 { 156 handler = GCHandle.Alloc(result, GCHandleType.Pinned); 157 Marshal.StructureToPtr(this, handler.AddrOfPinnedObject(), false); 158 } 159 finally 160 { 161 if(handler.IsAllocated) 162 { 163 handler.Free(); 164 } 165 } 166 167 return result; 168 } 169 DeserializeAntmicro.Renode.Peripherals.SystemC.DMIMessage170 public void Deserialize(byte[] message) 171 { 172 var handler = default(GCHandle); 173 try 174 { 175 handler = GCHandle.Alloc(message, GCHandleType.Pinned); 176 this = (DMIMessage)Marshal.PtrToStructure(handler.AddrOfPinnedObject(), typeof(DMIMessage)); 177 } 178 finally 179 { 180 if(handler.IsAllocated) 181 { 182 handler.Free(); 183 } 184 } 185 } 186 ToStringAntmicro.Renode.Peripherals.SystemC.DMIMessage187 public override string ToString() 188 { 189 return $"DMIMessage [{ActionId}@{StartAddress}:{EndAddress}]"; 190 } 191 192 public readonly RenodeAction ActionId; 193 public readonly byte Allowed; 194 public readonly ulong StartAddress; 195 public readonly ulong EndAddress; 196 public readonly ulong MMFOffset; 197 198 // TODO: 256 should be a named constant 199 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] 200 public byte[] MMFPath; 201 } 202 203 public interface IDirectAccessPeripheral : IPeripheral 204 { ReadDirect(byte dataLength, long offset, byte connectionIndex)205 ulong ReadDirect(byte dataLength, long offset, byte connectionIndex); WriteDirect(byte dataLength, long offset, ulong value, byte connectionIndex)206 void WriteDirect(byte dataLength, long offset, ulong value, byte connectionIndex); 207 }; 208 209 public class SystemCPeripheral : IQuadWordPeripheral, IDoubleWordPeripheral, IWordPeripheral, IBytePeripheral, INumberedGPIOOutput, IGPIOReceiver, IDirectAccessPeripheral, IDisposable 210 { SystemCPeripheral( IMachine machine, string address, int port = 0, int timeSyncPeriodUS = 1000, bool disableTimeoutCheck = false )211 public SystemCPeripheral( 212 IMachine machine, 213 string address, 214 int port = 0, 215 int timeSyncPeriodUS = 1000, 216 bool disableTimeoutCheck = false 217 ) 218 { 219 this.address = address; 220 this.requestedPort = port; 221 this.machine = machine; 222 this.timeSyncPeriodUS = timeSyncPeriodUS; 223 this.disableTimeoutCheck = disableTimeoutCheck; 224 sysbus = machine.GetSystemBus(this); 225 226 directAccessPeripherals = new Dictionary<int, IDirectAccessPeripheral>(); 227 228 messageLock = new object(); 229 230 backwardThread = new Thread(BackwardConnectionLoop) 231 { 232 IsBackground = true, 233 Name = "SystemC.BackwardThread" 234 }; 235 236 var innerConnections = new Dictionary<int, IGPIO>(); 237 for(int i = 0; i < NumberOfGPIOPins; i++) 238 { 239 innerConnections[i] = new GPIO(); 240 } 241 Connections = new ReadOnlyDictionary<int, IGPIO>(innerConnections); 242 } 243 AddDirectConnection(byte connectionIndex, IDirectAccessPeripheral target)244 public void AddDirectConnection(byte connectionIndex, IDirectAccessPeripheral target) 245 { 246 if(directAccessPeripherals.ContainsKey(connectionIndex)) 247 { 248 this.Log(LogLevel.Error, "Failed to add Direct Connection #{0} - connection with this index is already present", connectionIndex); 249 return; 250 } 251 252 directAccessPeripherals.Add(connectionIndex, target); 253 } 254 255 public string SystemCExecutablePath 256 { 257 get => systemcExecutablePath; 258 set 259 { 260 try 261 { 262 systemcExecutablePath = value; 263 var listenerSocket = CreateListenerSocket(requestedPort); 264 var assignedPort = ((IPEndPoint)listenerSocket.LocalEndPoint).Port; 265 this.Log(LogLevel.Info, "SystemCPeripheral waiting for forward SystemC connection on {0}:{1}", address, assignedPort); 266 var connectionParams = $"{address} {assignedPort}"; 267 StartSystemCProcess(systemcExecutablePath, connectionParams); 268 SetupConnection(listenerSocket); 269 SetupTimesync(); 270 } 271 catch(Exception e) 272 { 273 throw new RecoverableException($"Failed to start SystemC process: {e.Message}"); 274 } 275 } 276 } 277 ReadQuadWord(long offset)278 public ulong ReadQuadWord(long offset) 279 { 280 return Read(8, offset); 281 } 282 WriteQuadWord(long offset, ulong value)283 public void WriteQuadWord(long offset, ulong value) 284 { 285 Write(8, offset, value); 286 } 287 ReadDoubleWord(long offset)288 public uint ReadDoubleWord(long offset) 289 { 290 return (uint)Read(4, offset); 291 } 292 WriteDoubleWord(long offset, uint value)293 public void WriteDoubleWord(long offset, uint value) 294 { 295 Write(4, offset, value); 296 } 297 ReadWord(long offset)298 public ushort ReadWord(long offset) 299 { 300 return (ushort)Read(2, offset); 301 } 302 WriteWord(long offset, ushort value)303 public void WriteWord(long offset, ushort value) 304 { 305 Write(2, offset, value); 306 } 307 ReadByte(long offset)308 public byte ReadByte(long offset) 309 { 310 return (byte)Read(1, offset); 311 } 312 WriteByte(long offset, byte value)313 public void WriteByte(long offset, byte value) 314 { 315 Write(1, offset, value); 316 } 317 ReadDirect(byte dataLength, long offset, byte connectionIndex)318 public ulong ReadDirect(byte dataLength, long offset, byte connectionIndex) 319 { 320 return Read(dataLength, offset, connectionIndex); 321 } 322 WriteDirect(byte dataLength, long offset, ulong value, byte connectionIndex)323 public void WriteDirect(byte dataLength, long offset, ulong value, byte connectionIndex) 324 { 325 Write(dataLength, offset, value, connectionIndex); 326 } 327 OnGPIO(int number, bool value)328 public void OnGPIO(int number, bool value) 329 { 330 // When GPIO connections are initialized, OnGPIO is called with 331 // false value. The socket is not yet initialized in that case. We 332 // can safely return, no special initialization is required. 333 if(forwardSocket == null) 334 { 335 return; 336 } 337 338 BitHelper.SetBit(ref outGPIOState, (byte)number, value); 339 var request = new RenodeMessage(RenodeAction.GPIOWrite, 0, 0, 0, outGPIOState); 340 SendRequest(request, out var response); 341 } 342 Reset()343 public void Reset() 344 { 345 outGPIOState = 0; 346 var request = new RenodeMessage(RenodeAction.Reset, 0, 0, 0, 0); 347 SendRequest(request, out var response); 348 } 349 Dispose()350 public void Dispose() 351 { 352 if(systemcProcess != null && !systemcProcess.HasExited) 353 { 354 // Init message sent after connection has been established signifies Renode terminated and SystemC process 355 // should exit. 356 var request = new RenodeMessage(RenodeAction.Init, 0, 0, 0, 0); 357 SendRequest(request, out var response); 358 359 if(!systemcProcess.WaitForExit(500)) { 360 this.Log(LogLevel.Info, "SystemC process failed to exit gracefully - killing it."); 361 systemcProcess.Kill(); 362 } 363 } 364 365 forwardSocket?.Close(); 366 backwardSocket?.Close(); 367 } 368 369 public IReadOnlyDictionary<int, IGPIO> Connections { get; } 370 Read(byte dataLength, long offset, byte connectionIndex = 0)371 private ulong Read(byte dataLength, long offset, byte connectionIndex = 0) 372 { 373 return ReadInternal(RenodeAction.Read, dataLength, offset, connectionIndex); 374 } 375 ReadRegister(byte dataLength, long offset, byte connectionIndex = 0)376 public ulong ReadRegister(byte dataLength, long offset, byte connectionIndex = 0) 377 { 378 return ReadInternal(RenodeAction.ReadRegister, dataLength, offset, connectionIndex); 379 } 380 ReadInternal(RenodeAction action, byte dataLength, long offset, byte connectionIndex)381 private ulong ReadInternal(RenodeAction action, byte dataLength, long offset, byte connectionIndex) 382 { 383 var request = new RenodeMessage(action, dataLength, connectionIndex, (ulong)offset, 0); 384 if(!SendRequest(request, out var response)) 385 { 386 this.Log(LogLevel.Error, "Request to SystemCPeripheral failed, Read will return 0."); 387 return 0; 388 } 389 390 TryToSkipTransactionTime(response.Address); 391 392 return response.Payload; 393 } 394 Write(byte dataLength, long offset, ulong value, byte connectionIndex = 0)395 private void Write(byte dataLength, long offset, ulong value, byte connectionIndex = 0) 396 { 397 WriteInternal(RenodeAction.Write, dataLength, offset, value, connectionIndex); 398 } 399 WriteRegister(byte dataLength, long offset, ulong value, byte connectionIndex = 0)400 public void WriteRegister(byte dataLength, long offset, ulong value, byte connectionIndex = 0) 401 { 402 WriteInternal(RenodeAction.WriteRegister, dataLength, offset, value, connectionIndex); 403 } 404 WriteInternal(RenodeAction action, byte dataLength, long offset, ulong value, byte connectionIndex)405 private void WriteInternal(RenodeAction action, byte dataLength, long offset, ulong value, byte connectionIndex) 406 { 407 var request = new RenodeMessage(action, dataLength, connectionIndex, (ulong)offset, value); 408 if(!SendRequest(request, out var response)) 409 { 410 this.Log(LogLevel.Error, "Request to SystemCPeripheral failed, Write will have no effect."); 411 return; 412 } 413 414 TryToSkipTransactionTime(response.Address); 415 } 416 GetCurrentVirtualTimeUS()417 private ulong GetCurrentVirtualTimeUS() 418 { 419 // Truncate, as the SystemC integration uses microsecond resolution 420 return (ulong)machine.LocalTimeSource.ElapsedVirtualTime.TotalMicroseconds; 421 } 422 StartSystemCProcess(string systemcExecutablePath, string connectionParams)423 private void StartSystemCProcess(string systemcExecutablePath, string connectionParams) 424 { 425 try 426 { 427 #if !PLATFORM_WINDOWS 428 Mono.Unix.Native.Syscall.chmod(systemcExecutablePath, FilePermissions.S_IRWXU); 429 #endif 430 systemcProcess = new Process 431 { 432 StartInfo = new ProcessStartInfo(systemcExecutablePath) 433 { 434 UseShellExecute = false, 435 Arguments = connectionParams 436 } 437 }; 438 439 systemcProcess.Start(); 440 } 441 catch(Exception e) 442 { 443 throw new RecoverableException(e.Message); 444 } 445 } 446 CreateListenerSocket(int requestedPort)447 private Socket CreateListenerSocket(int requestedPort) 448 { 449 var listenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 450 listenerSocket.Bind(new IPEndPoint(IPAddress.Parse(address), requestedPort)); 451 listenerSocket.Listen(2); 452 return listenerSocket; 453 } 454 SetupConnection(Socket listenerSocket)455 private void SetupConnection(Socket listenerSocket) 456 { 457 458 forwardSocket = listenerSocket.Accept(); 459 forwardSocket.SendTimeout = 1000; 460 // No ReceiveTimeout for forwardSocket if the disableTimeoutCheck constructor argument is set - so if a debugger halts the SystemC process, Renode will wait for the process to restart 461 if(!disableTimeoutCheck) 462 { 463 forwardSocket.ReceiveTimeout = 1000; 464 } 465 466 backwardSocket = listenerSocket.Accept(); 467 backwardSocket.SendTimeout = 1000; 468 // No ReceiveTimeout for backwardSocket - it runs on a dedicated thread and by design blocks on Receive until a message arrives from SystemC process. 469 470 listenerSocket.Close(); 471 472 SendRequest(new RenodeMessage(RenodeAction.Init, 0, 0, 0, (ulong)timeSyncPeriodUS), out var response); 473 474 backwardThread.Start(); 475 } 476 SetupTimesync()477 private void SetupTimesync() 478 { 479 // Timer unit is microseconds 480 var timerName = "RenodeSystemCTimesyncTimer"; 481 var timesyncFrequency = 1000000; 482 var timesyncLimit = (ulong)timeSyncPeriodUS; 483 484 var timesyncTimer = new LimitTimer(machine.ClockSource, timesyncFrequency, this, timerName, limit: timesyncLimit, enabled: true, eventEnabled: true, autoUpdate: true); 485 486 Action<TimeInterval, TimeInterval> adjustTimesyncToQuantum = ((_, newQuantum) => { 487 if(TimeInterval.FromMicroseconds(timesyncTimer.Limit) < newQuantum) 488 { 489 var newLimit = (ulong)newQuantum.TotalMicroseconds; 490 this.Log(LogLevel.Warning, $"Requested time synchronization period of {timesyncTimer.Limit}us is smaller than local time source quantum - synchronization time will be changed to {newLimit}us to match it."); 491 timesyncTimer.Limit = newLimit; 492 } 493 }); 494 var currentQuantum = machine.LocalTimeSource.Quantum; 495 adjustTimesyncToQuantum(currentQuantum, currentQuantum); 496 machine.LocalTimeSource.QuantumChanged += adjustTimesyncToQuantum; 497 498 timesyncTimer.LimitReached += () => 499 { 500 machine.LocalTimeSource.ExecuteInNearestSyncedState(_ => 501 { 502 var request = new RenodeMessage(RenodeAction.Timesync, 0, 0, 0, GetCurrentVirtualTimeUS()); 503 SendRequest(request, out var response); 504 }); 505 }; 506 } 507 SendRequest(RenodeMessage request, out RenodeMessage responseMessage)508 private bool SendRequest(RenodeMessage request, out RenodeMessage responseMessage) 509 { 510 lock (messageLock) 511 { 512 var messageSize = Marshal.SizeOf(typeof(RenodeMessage)); 513 var recvBytes = new byte[messageSize]; 514 if(forwardSocket != null) 515 { 516 forwardSocket.Send(request.Serialize(), SocketFlags.None); 517 forwardSocket.Receive(recvBytes, 0, messageSize, SocketFlags.None); 518 519 responseMessage = new RenodeMessage(); 520 responseMessage.Deserialize(recvBytes); 521 522 return true; 523 } 524 else 525 { 526 this.Log(LogLevel.Error, "Unable to communicate with SystemC peripheral. Try setting SystemCExecutablePath first."); 527 responseMessage = new RenodeMessage(); 528 return false; 529 } 530 } 531 } 532 BackwardConnectionLoop()533 private void BackwardConnectionLoop() 534 { 535 while(true) 536 { 537 var messageSize = Marshal.SizeOf(typeof(RenodeMessage)); 538 var recvBytes = new byte[messageSize]; 539 540 var nbytes = backwardSocket.Receive(recvBytes, 0, messageSize, SocketFlags.None); 541 if(nbytes == 0) { 542 this.Log(LogLevel.Info, "Backward connection to SystemC process closed."); 543 return; 544 } 545 546 var message = new RenodeMessage(); 547 message.Deserialize(recvBytes); 548 549 ulong payload = 0; 550 switch(message.ActionId) 551 { 552 case RenodeAction.GPIOWrite: 553 // We have to respond before GPIO state is changed, because SystemC is blocked until 554 // it receives the response. Setting the GPIO may require it to respond, e. g. when it 555 // is interracted with from an interrupt handler. 556 backwardSocket.Send(message.Serialize(), SocketFlags.None); 557 for(int pin = 0; pin < NumberOfGPIOPins; pin++) 558 { 559 bool irqval = (message.Payload & (1UL << pin)) != 0; 560 Connections[pin].Set(irqval); 561 } 562 break; 563 case RenodeAction.Write: 564 bool writeToSharedMem = false; 565 if(message.IsSystemBusConnection()) 566 { 567 var targetMem = sysbus.FindMemory(message.Address); 568 if(targetMem != null) 569 { 570 writeToSharedMem = targetMem.Peripheral.UsingSharedMemory; 571 } 572 sysbus.TryGetCurrentCPU(out var icpu); 573 switch(message.DataLength) 574 { 575 case 1: 576 sysbus.WriteByte(message.Address, (byte)message.Payload, context: icpu); 577 break; 578 case 2: 579 sysbus.WriteWord(message.Address, (ushort)message.Payload, context: icpu); 580 break; 581 case 4: 582 sysbus.WriteDoubleWord(message.Address, (uint)message.Payload, context: icpu); 583 break; 584 case 8: 585 sysbus.WriteQuadWord(message.Address, message.Payload, context: icpu); 586 break; 587 default: 588 this.Log(LogLevel.Error, "SystemC integration error - invalid data length {0} sent through backward connection from the SystemC process.", message.DataLength); 589 break; 590 } 591 } 592 else 593 { 594 directAccessPeripherals[message.GetDirectConnectionIndex()].WriteDirect( 595 message.DataLength, (long)message.Address, message.Payload, message.ConnectionIndex); 596 } 597 var writeResponseMessage = new RenodeMessage(message.ActionId, message.DataLength, 598 writeToSharedMem ? (byte)RenodeMessage.DMIAllowed : (byte)RenodeMessage.DMINotAllowed, message.Address, message.Payload); 599 backwardSocket.Send(writeResponseMessage.Serialize(), SocketFlags.None); 600 break; 601 case RenodeAction.Read: 602 bool readFromSharedMem = false; 603 if(message.IsSystemBusConnection()) 604 { 605 var targetMem = sysbus.FindMemory(message.Address); 606 if(targetMem != null) 607 { 608 readFromSharedMem = targetMem.Peripheral.UsingSharedMemory; 609 } 610 sysbus.TryGetCurrentCPU(out var icpu); 611 switch(message.DataLength) 612 { 613 case 1: 614 payload = (ulong)sysbus.ReadByte(message.Address, context: icpu); 615 break; 616 case 2: 617 payload = (ulong)sysbus.ReadWord(message.Address, context: icpu); 618 break; 619 case 4: 620 payload = (ulong)sysbus.ReadDoubleWord(message.Address, context: icpu); 621 break; 622 case 8: 623 payload = (ulong)sysbus.ReadQuadWord(message.Address, context: icpu); 624 break; 625 default: 626 this.Log(LogLevel.Error, "SystemC integration error - invalid data length {0} sent through backward connection from the SystemC process.", message.DataLength); 627 break; 628 } 629 } 630 else 631 { 632 payload = directAccessPeripherals[message.GetDirectConnectionIndex()].ReadDirect(message.DataLength, (long)message.Address, message.ConnectionIndex); 633 } 634 var readResponseMessage = new RenodeMessage(message.ActionId, message.DataLength, 635 readFromSharedMem ? (byte)RenodeMessage.DMIAllowed : (byte)RenodeMessage.DMINotAllowed, message.Address, payload); 636 637 backwardSocket.Send(readResponseMessage.Serialize(), SocketFlags.None); 638 break; 639 case RenodeAction.DMIReq: 640 bool allowDMI = false; 641 var targetMemory = sysbus.FindMemory(message.Address); 642 if(targetMemory != null) 643 { 644 allowDMI = targetMemory.Peripheral.UsingSharedMemory; 645 } 646 long memBase = (long)(targetMemory.RegistrationPoint.Range.StartAddress + targetMemory.RegistrationPoint.Offset); 647 long memOffset = (long)message.Address - memBase; 648 ulong segmentStart = (ulong)memBase + (ulong)(memOffset - (memOffset % targetMemory.Peripheral.SegmentSize)); 649 int segmentNo = 0; 650 if(allowDMI) 651 { 652 segmentNo = (int)(memOffset / targetMemory.Peripheral.SegmentSize); 653 allowDMI = segmentNo >= 0 && segmentNo < targetMemory.Peripheral.SegmentCount; 654 } 655 if(allowDMI) 656 { 657 // DMI allowed 658 var responseDMIMessage = new DMIMessage( 659 message.ActionId, 660 RenodeMessage.DMIAllowed, 661 segmentStart, 662 segmentStart + (ulong)targetMemory.Peripheral.SegmentSize - 1UL, // segment end 663 targetMemory.Peripheral.GetSegmentAlignmentOffset(segmentNo), // offset into the MMF corresponding to the segment start address 664 targetMemory.Peripheral.GetSegmentPath(segmentNo) // MMF path 665 ); 666 backwardSocket.Send(responseDMIMessage.Serialize(), SocketFlags.None); 667 } 668 else 669 { 670 // DMI rejected 671 var responseDMIMessage = new DMIMessage( 672 message.ActionId, 673 RenodeMessage.DMINotAllowed, 674 0UL, 675 0UL, 676 0UL, 677 "" 678 ); 679 backwardSocket.Send(responseDMIMessage.Serialize(), SocketFlags.None); 680 } 681 break; 682 case RenodeAction.InvalidateTBs: 683 TryToInvalidateTBs(message.Address, message.Payload); 684 backwardSocket.Send(message.Serialize(), SocketFlags.None); 685 break; 686 default: 687 this.Log(LogLevel.Error, "SystemC integration error - invalid message type {0} sent through backward connection from the SystemC process.", message.ActionId); 688 break; 689 } 690 } 691 } 692 TryToInvalidateTBs(ulong startAddress, ulong endAddress)693 private void TryToInvalidateTBs(ulong startAddress, ulong endAddress) 694 { 695 foreach(var cpu in machine.SystemBus.GetCPUs().OfType<CPU.ICPU>()) 696 { 697 var translationCPU = cpu as TranslationCPU; 698 if(translationCPU != null) 699 { 700 translationCPU.InvalidateTranslationBlocks(new IntPtr((int)startAddress), new IntPtr((int)endAddress)); 701 } 702 } 703 } 704 TryToSkipTransactionTime(ulong timeUS)705 private void TryToSkipTransactionTime(ulong timeUS) 706 { 707 if(machine.SystemBus.TryGetCurrentCPU(out var icpu)) 708 { 709 var baseCPU = icpu as BaseCPU; 710 if(baseCPU != null) 711 { 712 baseCPU.SkipTime(TimeInterval.FromMicroseconds(timeUS)); 713 } 714 else 715 { 716 this.Log(LogLevel.Error, "Failed to get CPU, all SystemC transactions processed as if they have no duration. This can desynchronize Renode and SystemC simulations."); 717 } 718 } 719 } 720 721 private readonly IBusController sysbus; 722 private readonly IMachine machine; 723 724 // NumberOfGPIOPins must be equal to renode_bridge.h:NUM_GPIO 725 private const int NumberOfGPIOPins = 64; 726 727 private readonly string address; 728 private readonly int requestedPort; 729 private readonly int timeSyncPeriodUS; 730 private readonly bool disableTimeoutCheck; 731 private readonly object messageLock; 732 733 private readonly Thread backwardThread; 734 735 private Dictionary<int, IDirectAccessPeripheral> directAccessPeripherals; 736 private string systemcExecutablePath; 737 private Process systemcProcess; 738 739 private ulong outGPIOState; 740 741 private Socket forwardSocket; 742 private Socket backwardSocket; 743 } 744 } 745