1 //
2 // Copyright (c) 2010-2024 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using System.Collections.Generic;
10 using System.Linq;
11 using Antmicro.Renode.Core;
12 using Antmicro.Renode.Core.Structure;
13 using Antmicro.Renode.Peripherals.Bus;
14 using Antmicro.Renode.UserInterface;
15 
16 using Endianess = ELFSharp.ELF.Endianess;
17 
18 namespace Antmicro.Renode.Peripherals
19 {
20     [Icon("box")]
21     public interface IPeripheral : IEmulationElement, IAnalyzable
22     {
Reset()23         void Reset();
24     }
25 
26     public static class IPeripheralExtensions
27     {
HasGPIO(this IPeripheral peripheral)28         public static bool HasGPIO(this IPeripheral peripheral)
29         {
30             return peripheral is INumberedGPIOOutput || peripheral.GetType().GetProperties().Any(x => x.PropertyType == typeof(GPIO));
31         }
32 
33         /// <summary>
34         /// This method returns connected GPIO endpoints of a given peripheral.
35         /// </summary>
36         /// <returns>Collection of tuples: local GPIO name maped on endpoint to which it is connected. In case of INumberedGPIOOutput name is local number</returns>
37         /// <param name="peripheral">Peripheral.</param>
GetGPIOs(this IPeripheral peripheral)38         public static IEnumerable<Tuple<string, IGPIO>> GetGPIOs(this IPeripheral peripheral)
39         {
40             IEnumerable<Tuple<string, IGPIO>> result = null;
41             var numberGPIOOuput = peripheral as INumberedGPIOOutput;
42             if(numberGPIOOuput != null)
43             {
44                 result = numberGPIOOuput.Connections.Select(x => Tuple.Create(x.Key.ToString(), x.Value));
45             }
46 
47             var local = peripheral.GetType().GetProperties().Where(x => x.PropertyType == typeof(GPIO)).Select(x => Tuple.Create(x.Name, (IGPIO)((GPIO)x.GetValue(peripheral))));
48             return result == null ? local : result.Union(local);
49         }
50 
TryGetMachine(this IPeripheral @this, out IMachine machine)51         public static bool TryGetMachine(this IPeripheral @this, out IMachine machine)
52         {
53             if(EmulationManager.Instance.CurrentEmulation.TryGetMachineForPeripheral(@this, out machine))
54             {
55                 return true;
56             }
57 
58             // let's try a fallback:
59             // check if the provided object is not a container of peripherals -
60             // in such case if and only if all peripherals belong to the same machine we can return it
61             var simpleContainer = @this as ISimpleContainer;
62             if(simpleContainer != null)
63             {
64                 try
65                 {
66                     var allMachines = simpleContainer.ChildCollection.Select(x => x.Value.GetMachine()).Distinct().ToArray();
67                     if(allMachines.Length == 1)
68                     {
69                         machine = allMachines[0];
70                         return true;
71                     }
72                 }
73                 catch(Exception)
74                 {
75                     // the try/catch here is to obtain a more readable stack trace;
76                     // do nothing, we'll throw in a second anyway
77                 }
78             }
79             return false;
80         }
81 
GetMachine(this IPeripheral @this)82         public static IMachine GetMachine(this IPeripheral @this)
83         {
84             if(@this.TryGetMachine(out var machine))
85             {
86                 return machine;
87             }
88             throw new ArgumentException($"Couldn't find machine for a given peripheral of type {@this.GetType().FullName}.");
89         }
90 
GetEndianness(this IPeripheral @this, Endianess? defaultEndianness = null)91         public static Endianess GetEndianness(this IPeripheral @this, Endianess? defaultEndianness = null)
92         {
93             if(@this is IEndiannessAware endiannessAwarePeripheral)
94             {
95                 return endiannessAwarePeripheral.Endianness;
96             }
97             if(defaultEndianness != null)
98             {
99                 return defaultEndianness.Value;
100             }
101             if(@this is IBusPeripheral busPeripheral)
102             {
103                 return @this.GetMachine().GetSystemBus(busPeripheral).Endianess;
104             }
105             return @this.GetMachine().SystemBus.Endianess;
106         }
107 
IsHostEndian(this IPeripheral @this)108         public static bool IsHostEndian(this IPeripheral @this)
109         {
110             return (@this.GetEndianness() == Endianess.LittleEndian) == BitConverter.IsLittleEndian;
111         }
112 
GetName(this IPeripheral @this)113         public static string GetName(this IPeripheral @this)
114         {
115             var machine = @this.GetMachine();
116             var machineName = EmulationManager.Instance.CurrentEmulation[machine];
117             return $"{machineName}.{machine.GetLocalName(@this)}";
118         }
119     }
120 }
121