1 //
2 // Copyright (c) 2010-2025 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.Reflection;
11 using System.Text.RegularExpressions;
12 using System.Linq;
13 using Antmicro.Renode.Core;
14 using Antmicro.Renode.Peripherals.Bus;
15 using Antmicro.Renode.Logging;
16 using Antmicro.Renode.Peripherals;
17 using System.IO;
18 using Dynamitey;
19 using System.Text;
20 using System.Runtime.InteropServices;
21 using System.Drawing;
22 using Antmicro.Renode.Network;
23 using System.Diagnostics;
24 using Antmicro.Renode.Core.Structure.Registers;
25 using System.Threading;
26 using Antmicro.Renode.Peripherals.CPU;
27 using Antmicro.Renode.Logging.Profiling;
28 
29 namespace Antmicro.Renode.Utilities
30 {
31     public static class Misc
32     {
33         //TODO: isn't it obsolete?
34         //TODO: what if memory_size should be long?
CreateAtags(string bootargs, uint memorySize)35         public static List<UInt32> CreateAtags(string bootargs, uint memorySize)
36         {
37             var atags = new List<UInt32>
38                             {
39                                 5u,
40                                 0x54410001u,
41                                 1u,
42                                 0x1000u,
43                                 0u,
44                                 4u,
45                                 0x54410002u,
46                                 memorySize,
47                                 0u,
48                                 (uint)((bootargs.Length >> 2) + 3),
49                                 0x54410009u
50                             };
51 
52             //TODO: should be padded
53             var ascii = new ASCIIEncoding();
54             var bootargsByte = new List<byte>();
55             bootargsByte.AddRange(ascii.GetBytes(bootargs));
56             int i;
57             if((bootargs.Length % 4) != 0)
58             {
59                 for(i = 0; i < (4 - (bootargs.Length%4)); i++)
60                 {
61                     bootargsByte.Add(0); // pad with zeros
62                 }
63             }
64             for(i = 0; i < bootargsByte.Count; i += 4)
65             {
66                 atags.Add(BitConverter.ToUInt32(bootargsByte.ToArray(), i));
67             }
68             atags.Add(0u);
69 
70             atags.Add(0u); // ATAG_NONE
71             return atags;
72         }
73 
Is(this Type type)74         public static bool Is<T>(this Type type)
75         {
76             return type == typeof(T);
77         }
78 
IsPeripheral(object o)79         public static bool IsPeripheral(object o)
80         {
81             return o is IPeripheral;
82         }
83 
IsPythonObject(object o)84         public static bool IsPythonObject(object o)
85         {
86             return o.GetType().GetFields().Any(x => x.Name == ".class");
87         }
88 
IsPythonType(Type t)89         public static bool IsPythonType(Type t)
90         {
91             return t.GetFields().Any(x => x.Name == ".class");
92         }
93 
GetPythonName(object o)94         public static string GetPythonName(object o)
95         {
96             var cls = Dynamic.InvokeGet(o, ".class");
97             return cls.__name__;
98         }
99 
GetAllMethods(this Type t, bool recursive = true)100         public static IEnumerable<MethodInfo> GetAllMethods(this Type t, bool recursive = true)
101         {
102             if(t == null)
103             {
104                 return Enumerable.Empty<MethodInfo>();
105             }
106             if(recursive)
107             {
108                 return t.GetMethods(DefaultBindingFlags).Union(GetAllMethods(t.BaseType));
109             }
110             return t.GetMethods(DefaultBindingFlags);
111         }
112 
113         public static IEnumerable<MethodWithAttribute<T>> GetMethodsWithAttribute<T>(this Type type, bool inheritAttribute = true) where T : Attribute
114         {
115             return type.GetAllMethods()
116                 .Select(method => new MethodWithAttribute<T>(method, (T)method.GetCustomAttribute(typeof(T), inheritAttribute)))
117                 .Where(m => m.Attribute != null);
118         }
119 
GetAllFields(this Type t, bool recursive = true)120         public static IEnumerable<FieldInfo> GetAllFields(this Type t, bool recursive = true)
121         {
122             if(t == null)
123             {
124                 return Enumerable.Empty<FieldInfo>();
125             }
126             if(recursive)
127             {
128                 return t.GetFields(DefaultBindingFlags).Union(GetAllFields(t.BaseType));
129             }
130             return t.GetFields(DefaultBindingFlags);
131         }
132 
GetAllNestedTypes(this Type t, bool recursive = true)133         public static IEnumerable<Type> GetAllNestedTypes(this Type t, bool recursive = true)
134         {
135             if(t == null)
136             {
137                 return Enumerable.Empty<Type>();
138             }
139             if(recursive)
140             {
141                 return t.GetNestedTypes(DefaultBindingFlags).Union(t.BaseType.GetAllNestedTypes());
142             }
143             return t.GetNestedTypes(DefaultBindingFlags);
144         }
145 
ReadBytes(this Stream stream, int count, bool throwIfEndOfStream = false)146         public static byte[] ReadBytes(this Stream stream, int count, bool throwIfEndOfStream = false)
147         {
148             var buffer = new byte[count];
149             var read = 0;
150             while(read < count)
151             {
152                 var readInThisIteration = stream.Read(
153                     buffer,
154                     read,
155                     count - read
156                 );
157                 if(readInThisIteration == 0)
158                 {
159                     throw new EndOfStreamException(string.Format(
160                         "End of stream encountered, only {0} bytes could be read.",
161                         read
162                     )
163                     );
164                 }
165                 read += readInThisIteration;
166             }
167 
168             if(throwIfEndOfStream && read < count)
169             {
170                 throw new EndOfStreamException(
171                     $"End of stream encountered. {count}B were requested but only {read}B could be read"
172                 );
173             }
174             return buffer;
175         }
176 
KB(this int value)177         public static int KB(this int value)
178         {
179             return 1024 * value;
180         }
181 
MB(this int value)182         public static int MB(this int value)
183         {
184             return 1024 * value.KB();
185         }
186 
GB(this int value)187         public static ulong GB(this int value)
188         {
189             return 1024 * (ulong)value.MB();
190         }
191 
TB(this int value)192         public static ulong TB(this int value)
193         {
194             return 1024 * value.GB();
195         }
196 
197         /// <summary>
198         /// Computes which power of two is given number. You can only use this function if you know
199         /// that this number IS a power of two.
200         /// </summary>
Logarithm2(int value)201         public static int Logarithm2(int value)
202         {
203             return MultiplyDeBruijnBitPosition2[(int)((uint)(value * 0x077CB531u) >> 27)];
204         }
205 
206         public static byte[] AsRawBytes<T>(this T structure) where T : struct
207         {
208             var size = Marshal.SizeOf(typeof(T));
209             var result = new byte[size];
210             var bufferPointer = Marshal.AllocHGlobal(size);
Marshal.StructureToPtrAntmicro.Renode.Utilities.Misc.__anon1211             Marshal.StructureToPtr(structure, bufferPointer, false);
Marshal.CopyAntmicro.Renode.Utilities.Misc.__anon1212             Marshal.Copy(bufferPointer, result, 0, size);
Marshal.FreeHGlobalAntmicro.Renode.Utilities.Misc.__anon1213             Marshal.FreeHGlobal(bufferPointer);
214             return result;
215         }
216 
NormalizeBinary(double what)217         public static String NormalizeBinary(double what)
218         {
219             var prefix = (what < 0) ? "-" : "";
220             if(what == 0)
221             {
222                 return "0";
223             }
224             if(what < 0)
225             {
226                 what = -what;
227             }
228             var power = (int)Math.Log(what, 2);
229             var index = power / 10;
230             if(index >= BytePrefixes.Length)
231             {
232                 index = BytePrefixes.Length - 1;
233             }
234             what /= Math.Pow(2, 10 * index);
235             return string.Format(
236                 "{0}{1:0.##}{2}",
237                 prefix,
238                 what,
239                 BytePrefixes[index]
240             );
241         }
242 
ByteArrayWrite(long offset, uint value, byte[] array)243         public static void ByteArrayWrite(long offset, uint value, byte[] array)
244         {
245             var index = (int)(offset);
246             var bytes = BitConverter.GetBytes(value);
247             for(var i = 0; i < 4; i++)
248             {
249                 array[index + i] = bytes[i];
250             }
251         }
252 
ByteArrayRead(long offset, byte[] array)253         public static uint ByteArrayRead(long offset, byte[] array)
254         {
255             var index = (int)(offset);
256             var bytes = new byte[4];
257             for(var i = 0; i < 4; i++)
258             {
259                 bytes[i] = array[index + i];
260             }
261             return BitConverter.ToUInt32(bytes, 0);
262         }
263 
NormalizeDecimal(double what)264         public static String NormalizeDecimal(double what)
265         {
266             var prefix = (what < 0) ? "-" : "";
267             if(what == 0)
268             {
269                 return "0";
270             }
271             if(what < 0)
272             {
273                 what = -what;
274             }
275             var digits = Convert.ToInt32(Math.Floor(Math.Log10(what)));
276             var power = (long)(3 * Math.Round((digits / 3.0)));
277             var index = power / 3 + ZeroPrefixPosition;
278             if(index < 0)
279             {
280                 index = 0;
281                 power = 3 * (1 + ZeroPrefixPosition - SIPrefixes.Length);
282             } else if(index >= SIPrefixes.Length)
283             {
284                 index = SIPrefixes.Length - 1;
285                 power = 3 * (SIPrefixes.Length - ZeroPrefixPosition - 1);
286             }
287             what /= Math.Pow(10, power);
288             var unit = SIPrefixes[index];
289             what = Math.Round(what, 2);
290             return prefix + what + unit;
291         }
292 
GetShortName(object o)293         public static string GetShortName(object o)
294         {
295             if(Misc.IsPythonObject(o))
296             {
297                 return Misc.GetPythonName(o);
298             }
299             var type = o.GetType();
300             return type.Name;
301         }
302 
IsPowerOfTwo(ulong value)303         public static bool IsPowerOfTwo(ulong value)
304         {
305             return (value != 0) && (value & (value - 1)) == 0;
306         }
307 
NextPowerOfTwo(int value)308         public static int NextPowerOfTwo(int value)
309         {
310             value--;
311             value |= value >> 1;
312             value |= value >> 2;
313             value |= value >> 4;
314             value |= value >> 8;
315             value |= value >> 16;
316             value++;
317             return value;
318         }
319 
Times(this int times, Action<int> action)320         public static void Times(this int times, Action<int> action)
321         {
322             for(var i = 0; i < times; i++)
323             {
324                 action(i);
325             }
326         }
327 
Times(this int times, Action action)328         public static void Times(this int times, Action action)
329         {
330             for(var i = 0; i < times; i++)
331             {
332                 action();
333             }
334         }
335 
AppendIf(this String value, bool condition, string what)336         public static StringBuilder AppendIf(this String value, bool condition, string what)
337         {
338             var builder = new StringBuilder(value);
339             return AppendIf(builder, condition, what);
340         }
341 
AppendIf(this StringBuilder value, bool condition, string what)342         public static StringBuilder AppendIf(this StringBuilder value, bool condition, string what)
343         {
344             if(condition)
345             {
346                 value.Append(what);
347             }
348             return value;
349         }
350 
Indent(this String value, int count)351         public static String Indent(this String value, int count)
352         {
353             return "".PadLeft(count) + value;
354         }
355 
Indent(this String value, int count, char fill)356         public static String Indent(this String value, int count, char fill)
357         {
358             return "".PadLeft(count, fill) + value;
359         }
360 
Outdent(this String value, int count)361         public static String Outdent(this String value, int count)
362         {
363             return value + "".PadLeft(count);
364         }
365 
StartsWith(this String source, char value)366         public static Boolean StartsWith(this String source, char value)
367         {
368             if (source.Length > 0)
369             {
370                 return source[0] == value;
371             }
372             return false;
373         }
374 
EndsWith(this String source, char value)375         public static Boolean EndsWith(this String source, char value)
376         {
377             if (source.Length > 0)
378             {
379                 return source[source.Length - 1] == value;
380             }
381             return false;
382         }
383 
Trim(this String value, String toCut)384         public static String Trim(this String value, String toCut)
385         {
386             if (!value.StartsWith(toCut))
387             {
388                 return value;
389             }
390             return value.Substring(toCut.Length);
391         }
392 
IndexOf(this IEnumerable<TSource> source, Func<TSource, bool> predicate)393         public static int IndexOf<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
394         {
395             var i = 0;
396             foreach (var element in source)
397             {
398                 if (predicate(element))
399                     return i;
400 
401                 i++;
402             }
403             return -1;
404         }
405 
LastIndexOf(this IEnumerable<TSource> source, Func<TSource, bool> predicate)406         public static int LastIndexOf<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
407         {
408             var revSource = source.Reverse();
409             var i = revSource.Count() - 1;
410             foreach (var element in revSource)
411             {
412                 if (predicate(element))
413                     return i;
414 
415                 i--;
416             }
417             return -1;
418         }
419 
420 #if !NET
421         public static TSource MinBy<TSource, T>(this IEnumerable<TSource> source, Func<TSource, T> map) where T: IComparable<T>
422         {
423             return source.Aggregate((a, b) => map(a).CompareTo(map(b)) < 0 ? a : b);
424         }
425 #endif
426 
Stringify(this IEnumerable<TSource> source, string separator = R, int limitPerLine = 0)427         public static string Stringify<TSource>(this IEnumerable<TSource> source, string separator = " ", int limitPerLine = 0)
428         {
429             return Stringify(source.Select(x => x == null ? String.Empty : x.ToString()), separator, limitPerLine);
430         }
431 
Stringify(this IEnumerable<string> source, string separator = R, int limitPerLine = 0)432         public static string Stringify(this IEnumerable<string> source, string separator = " ", int limitPerLine = 0)
433         {
434             int idx = 0;
435             if(source.Any())
436             {
437                 return source.Aggregate((x, y) => x + separator + (limitPerLine != 0 && (++idx % limitPerLine == 0) ? "\n" : string.Empty) + y);
438             }
439             return String.Empty;
440         }
441 
HexStringToByteArray(string hexString, bool reverse = false, bool ignoreWhitespace = false)442         public static byte[] HexStringToByteArray(string hexString, bool reverse = false, bool ignoreWhitespace = false)
443         {
444             if(ignoreWhitespace)
445             {
446                 hexString = Regex.Replace(hexString, @"\s+", "");
447             }
448 
449             if(hexString.Length % 2 != 0)
450             {
451                 throw new FormatException($"The length of hex string ({hexString.Length}) is not a multiple of 2.");
452             }
453 
454             byte[] bytes = new byte[hexString.Length / 2];
455             for(int i = 0; i < bytes.Length; i++)
456             {
457                 int byteIndex = reverse ? bytes.Length - 1 - i : i;
458                 bytes[byteIndex] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
459             }
460             return bytes;
461         }
462 
463         // Can't use the `sizeof` in the generic code unless it is restricted to unmanaged types, and that's possible only in C#7.0 and newer.
464         // Hence the `elementSize` argument - otherwise it would be replaced with a `sizeof(T)`
TryParseHexString(string hexString, out T[] outArray, int elementSize, bool endiannessSwap=false)465         public static bool TryParseHexString<T>(string hexString, out T[] outArray, int elementSize, bool endiannessSwap=false)
466         {
467             var byteArray = HexStringToByteArray(hexString);
468             var byteLength = byteArray.Length;
469             if(byteLength % elementSize != 0)
470             {
471                 outArray = new T[0];
472                 return false;
473             }
474             outArray = new T[byteLength / elementSize];
475             if(endiannessSwap)
476             {
477                 EndiannessSwapInPlace(byteArray, elementSize);
478             }
479             Buffer.BlockCopy(byteArray, 0, outArray, 0, byteLength);
480             return true;
481         }
482 
ToHexString(this byte[] data)483         public static string ToHexString(this byte[] data)
484         {
485             var lookup = hexStringLookup.Value;
486             var builder = new StringBuilder(data.Length * 2);
487             for(var i = 0; i < data.Length; ++i)
488             {
489                 builder.Append(lookup[data[i]]);
490             }
491             return builder.ToString();
492         }
493 
ToHex(this byte value)494         public static string ToHex(this byte value)
495         {
496             return hexStringLookup.Value[value];
497         }
498 
ConcatRangeFromTo(this IEnumerable<int> enumerable, int start, int stopIncluded)499         public static IEnumerable<int> ConcatRangeFromTo(this IEnumerable<int> enumerable, int start, int stopIncluded)
500         {
501             return enumerable.Concat(Enumerable.Range(start, stopIncluded - start + 1));
502         }
503 
504         // MoreLINQ - Extensions to LINQ to Objects
505         // Copyright (c) 2008 Jonathan Skeet. All rights reserved.
DistinctBy(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer = null)506         public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
507             IEqualityComparer<TKey> comparer = null)
508         {
509             if(source == null)
510             {
511                 throw new ArgumentNullException("source");
512             }
513             if(keySelector == null)
514             {
515                 throw new ArgumentNullException("keySelector");
516             }
517             var knownKeys = new HashSet<TKey>(comparer);
518             foreach (var element in source)
519             {
520                 if (knownKeys.Add(keySelector(element)))
521                 {
522                     yield return element;
523                 }
524             }
525         }
526 
527         /// <summary>Adds elements to the end of an IEnumerable.</summary>
528         /// <typeparam name="T">Type of enumerable to return.</typeparam>
529         /// <returns>IEnumerable containing all the input elements, followed by the
530         /// specified additional elements.</returns>
Append(this IEnumerable<T> source, params T[] element)531         public static IEnumerable<T> Append<T>(this IEnumerable<T> source, params T[] element)
532         {
533             if(source == null)
534             {
535                 throw new ArgumentNullException("source");
536             }
537             return ConcatIterator(element, source, false);
538         }
539 
540         /// <summary>Adds elements to the start of an IEnumerable.</summary>
541         /// <typeparam name="T">Type of enumerable to return.</typeparam>
542         /// <returns>IEnumerable containing the specified additional elements, followed by
543         /// all the input elements.</returns>
Prepend(this IEnumerable<T> tail, params T[] head)544         public static IEnumerable<T> Prepend<T>(this IEnumerable<T> tail, params T[] head)
545         {
546             if(tail == null)
547             {
548                 throw new ArgumentNullException("tail");
549             }
550             return ConcatIterator(head, tail, true);
551         }
552 
ConcatIterator(T[] extraElements, IEnumerable<T> source, bool insertAtStart)553         private static IEnumerable<T> ConcatIterator<T>(T[] extraElements,
554             IEnumerable<T> source, bool insertAtStart)
555         {
556             if(insertAtStart)
557             {
558                 foreach(var e in extraElements)
559                 {
560                     yield return e;
561                 }
562             }
563             foreach(var e in source)
564             {
565                 yield return e;
566             }
567             if(!insertAtStart)
568             {
569                 foreach(var e in extraElements)
570                 {
571                     yield return e;
572                 }
573             }
574         }
575 
GetOrDefault(this IReadOnlyDictionary<TKey, TValue> @this, TKey key)576         public static TValue GetOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> @this, TKey key)
577         {
578             return @this.GetOrDefault(key, default(TValue));
579         }
580 
GetOrDefault(this IReadOnlyDictionary<TKey, TValue> @this, TKey key, TValue defaultValue)581         public static TValue GetOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> @this, TKey key, TValue defaultValue)
582         {
583             if(@this.TryGetValue(key, out var value))
584             {
585                 return value;
586             }
587             return defaultValue;
588         }
589 
HiByte(this UInt16 value)590         public static byte HiByte(this UInt16 value)
591         {
592             return (byte)((value >> 8) & 0xFF);
593         }
594 
LoByte(this UInt16 value)595         public static byte LoByte(this UInt16 value)
596         {
597             return (byte)(value & 0xFF);
598         }
599 
BinaryToGray(ulong binaryEncoding)600         public static ulong BinaryToGray(ulong binaryEncoding)
601         {
602             return binaryEncoding ^ (binaryEncoding >> 1);
603         }
604 
GrayToBinary(ulong grayEncoding)605         public static ulong GrayToBinary(ulong grayEncoding)
606         {
607             ulong binaryEncoding = grayEncoding;
608             while(grayEncoding > 0)
609             {
610                 grayEncoding >>= 1;
611                 binaryEncoding ^= grayEncoding;
612             }
613             return binaryEncoding;
614         }
615 
TryFromResourceToTemporaryFile(this Assembly assembly, string resourceName, out string outputFileFullPath, string nonstandardOutputFilename = null)616         public static bool TryFromResourceToTemporaryFile(this Assembly assembly, string resourceName, out string outputFileFullPath, string nonstandardOutputFilename = null)
617         {
618             // `GetManifestResourceStream` is not supported by dynamic assemblies
619             Stream libraryStream = assembly.IsDynamic
620                 ? null
621                 : assembly.GetManifestResourceStream(resourceName);
622 
623             if(libraryStream == null)
624             {
625                 if(File.Exists(resourceName))
626                 {
627                     libraryStream = new FileStream(resourceName, FileMode.Open, FileAccess.Read, FileShare.None);
628                 }
629                 if(libraryStream == null)
630                 {
631                     outputFileFullPath = null;
632                     return false;
633                 }
634             }
635 
636             string libraryFile;
637             if(nonstandardOutputFilename != null)
638             {
639                 // Overwrite file if already exists since nonstandard filenames are not unique due to not being prefixed with GUIDs
640                 // This can cause issues when running docker containers which can have reproducable PIDs even after restart and persistent /tmp
641                 if(!TemporaryFilesManager.Instance.TryCreateFile(nonstandardOutputFilename, out libraryFile, true))
642                 {
643                     Logging.Logger.Log(Logging.LogLevel.Error, "Could not unpack resource {0} to {1}. This likely signifies an internal error.", resourceName, nonstandardOutputFilename);
644                     outputFileFullPath = null;
645                     return false;
646                 }
647             }
648             else
649             {
650                 libraryFile = TemporaryFilesManager.Instance.GetTemporaryFile(resourceName);
651 
652                 if(String.IsNullOrEmpty(libraryFile))
653                 {
654                     outputFileFullPath = null;
655                     return false;
656                 }
657             }
658             outputFileFullPath = CopyToFile(libraryStream, libraryFile);
659             return true;
660         }
661 
FromResourceToTemporaryFile(this Assembly assembly, string resourceName)662         public static string FromResourceToTemporaryFile(this Assembly assembly, string resourceName)
663         {
664             if(!TryFromResourceToTemporaryFile(assembly, resourceName, out var result))
665             {
666                 throw new ArgumentException(string.Format("Cannot find library {0}", resourceName));
667             }
668             return result;
669         }
670 
Copy(this Stream from, Stream to)671         public static void Copy(this Stream from, Stream to)
672         {
673             var buffer = new byte[4096];
674             int read;
675             do
676             {
677                 read = from.Read(buffer, 0, buffer.Length);
678                 if(read <= 0) // to workaround ionic zip's bug
679                 {
680                     break;
681                 }
682                 to.Write(buffer, 0, read);
683             }
684             while(true);
685         }
686 
GetPixelFromPngImage(string fileName, int x, int y, out byte r, out byte g, out byte b)687         public static void GetPixelFromPngImage(string fileName, int x, int y, out byte r, out byte g, out byte b)
688         {
689             Bitmap bitmap;
690             if(fileName == LastBitmapName)
691             {
692                 bitmap = LastBitmap;
693             }
694             else
695             {
696                 bitmap = new Bitmap(fileName);
697                 LastBitmap = bitmap;
698                 LastBitmapName = fileName;
699             }
700             var color = bitmap.GetPixel(x, y);
701             r = color.R;
702             g = color.G;
703             b = color.B;
704         }
705 
706         private static string cachedRootDirectory;
707 
GetRootDirectory()708         public static string GetRootDirectory()
709         {
710             if(cachedRootDirectory != null)
711             {
712                 return cachedRootDirectory;
713             }
714 
715             if(TryGetRootDirectory(out var result))
716             {
717                 return result;
718             }
719 
720             // fall-back to the current working directory
721             var cwd = Directory.GetCurrentDirectory();
722             Logger.Log(LogLevel.Warning, "Could not find '.renode-root' - falling back to current working directory ({0}) - might cause problems.", cwd);
723             cachedRootDirectory = cwd;
724 
725             return cwd;
726         }
727 
TryGetRootDirectory(out string directory)728         public static bool TryGetRootDirectory(out string directory)
729         {
730             if(TryGetRootDirectory(AppDomain.CurrentDomain.BaseDirectory, out directory))
731             {
732                 // Firstly, try to resolve root directory starting from
733                 // directory containing current assembly. This should
734                 // work when Renode was run after being manually compiled from the source code.
735                 return true;
736             }
737 
738             // If we couldn't find root directory in previous step, try again
739             // starting from directory of main process' executable. This is fallback for
740             // when Renode was executed from self-contained binary.
741             var currentProcess = Process.GetCurrentProcess();
742             var currentModulePath = Path.GetFullPath(currentProcess.MainModule.FileName);
743             var rootDirectory = Path.GetDirectoryName(currentModulePath);
744             return TryGetRootDirectory(rootDirectory, out directory);
745         }
746 
TryGetRootDirectory(string baseDirectory, out string directory)747         public static bool TryGetRootDirectory(string baseDirectory, out string directory)
748         {
749             if(cachedRootDirectory != null)
750             {
751                 directory = cachedRootDirectory;
752                 return true;
753             }
754 
755             directory = null;
756             if(baseDirectory.Length == 0)
757             {
758                 return false;
759             }
760 
761             var currentDirectory = new DirectoryInfo(baseDirectory);
762             while(currentDirectory != null)
763             {
764                 var indicatorFiles = Directory.GetFiles(currentDirectory.FullName, ".renode-root");
765                 if(indicatorFiles.Length == 1)
766                 {
767                     var content = File.ReadAllLines(Path.Combine(currentDirectory.FullName, indicatorFiles[0]));
768                     if(content.Length == 1 && content[0] == "5344ec2a-1539-4017-9ae5-a27c279bd454")
769                     {
770                         directory = currentDirectory.FullName;
771                         cachedRootDirectory = directory;
772                         return true;
773                     }
774                 }
775                 currentDirectory = currentDirectory.Parent;
776             }
777             return false;
778         }
779 
Multiply(this TimeSpan multiplicand, int multiplier)780         public static TimeSpan Multiply(this TimeSpan multiplicand, int multiplier)
781         {
782             return TimeSpan.FromTicks(multiplicand.Ticks * multiplier);
783         }
784 
Multiply(this TimeSpan multiplicand, double multiplier)785         public static TimeSpan Multiply(this TimeSpan multiplicand, double multiplier)
786         {
787             return TimeSpan.FromTicks((long)(multiplicand.Ticks * multiplier));
788         }
789 
FormatWith(this String @this, params object[] args)790         public static String FormatWith(this String @this, params object[] args)
791         {
792             if(@this == null)
793             {
794                 throw new ArgumentNullException("this");
795             }
796             if(args == null)
797             {
798                 throw new ArgumentNullException("args");
799             }
800             return String.Format(@this, args);
801 
802         }
803 
CopyToFile(Stream libraryStream, string libraryFile)804         private static string CopyToFile(Stream libraryStream, string libraryFile)
805         {
806             try
807             {
808                 using(var destination = new FileStream(libraryFile, FileMode.Open, FileAccess.Write, FileShare.None))
809                 {
810                     libraryStream.Copy(destination);
811                     Logger.Noisy(String.Format("Library copied to {0}.", libraryFile));
812                 }
813                 return libraryFile;
814             }
815             catch(IOException e)
816             {
817                 throw new InvalidOperationException(String.Format("Error while copying file: {0}.", e.Message));
818             }
819             finally
820             {
821                 if(libraryStream != null)
822                 {
823                     libraryStream.Close();
824                 }
825             }
826         }
827 
ComputeHeaderIpChecksum(byte[] header, int start, int length)828         private static ushort ComputeHeaderIpChecksum(byte[] header, int start, int length)
829         {
830             ushort word16;
831             var sum = 0L;
832             for (var i = start; i < (length + start); i+=2)
833             {
834                 if(i - start == 10)
835                 {
836                     //These are IP Checksum fields.
837                     continue;
838                 }
839                 word16 = (ushort)(((header[i] << 8 ) & 0xFF00)
840                     + (header[i + 1] & 0xFF));
841                 sum += (long)word16;
842             }
843 
844             while ((sum >> 16) != 0)
845             {
846                 sum = (sum & 0xFFFF) + (sum >> 16);
847             }
848             sum = ~sum;
849             return (ushort)sum;
850         }
851 
852         // Calculates the TCP checksum using the IP Header and TCP Header.
853         // Ensure the TCPHeader contains an even number of bytes before passing to this method.
854         // If an odd number, pad with a 0 byte just for checksumming purposes.
GetPacketChecksum(byte[] packet, int startOfIp, int startOfPayload, bool withPseudoHeader)855         static ushort GetPacketChecksum(byte[] packet, int startOfIp, int startOfPayload, bool withPseudoHeader)
856         {
857             var sum = 0u;
858             // Protocol Header
859             for (var x = startOfPayload; x < packet.Length - 1; x += 2)
860             {
861                 sum += Ntoh(BitConverter.ToUInt16(packet, x));
862             }
863             if((packet.Length - startOfPayload) % 2 != 0)
864             {
865                 //odd length
866                 sum += (ushort)((packet[packet.Length - 1] << 8) | 0x00);
867             }
868             if(withPseudoHeader)
869             {
870                 // Pseudo header - Source Address
871                 sum += Ntoh(BitConverter.ToUInt16(packet, startOfIp + 12));
872                 sum += Ntoh(BitConverter.ToUInt16(packet, startOfIp + 14));
873                 // Pseudo header - Dest Address
874                 sum += Ntoh(BitConverter.ToUInt16(packet, startOfIp + 16));
875                 sum += Ntoh(BitConverter.ToUInt16(packet, startOfIp + 18));
876                 // Pseudo header - Protocol
877                 sum += Ntoh(BitConverter.ToUInt16(new byte[] { 0, packet[startOfIp + 9] }, 0));
878                 // Pseudo header - TCP Header length
879                 sum += (ushort)(packet.Length - startOfPayload);
880             }
881             // 16 bit 1's compliment
882             while((sum >> 16) != 0)
883             {
884                 sum = ((sum & 0xFFFF) + (sum >> 16));
885             }
886             return (ushort)~sum;
887         }
888 
Ntoh(UInt16 input)889         private static ushort Ntoh(UInt16 input)
890         {
891             int x = System.Net.IPAddress.NetworkToHostOrder(input);
892             return (ushort) (x >> 16);
893         }
894 
895         public enum TransportLayerProtocol
896         {
897             ICMP = 0x1,
898             TCP = 0x6,
899             UDP = 0x11
900         }
901         public enum PacketType
902         {
903             IP = 0x800,
904             ARP = 0x806,
905         }
906 
907         //TODO: Support for ipv6
FillPacketWithChecksums(IPeripheral source, byte[] packet, params TransportLayerProtocol[] interpretedProtocols)908         public static void FillPacketWithChecksums(IPeripheral source, byte[] packet, params TransportLayerProtocol[] interpretedProtocols)
909         {
910             if (packet.Length < MACLength) {
911                 source.Log(LogLevel.Error, String.Format("Expected packet of at least {0} bytes, got {1}.", MACLength, packet.Length));
912                 return;
913             }
914             var packet_type = (PacketType) ((packet[12] << 8) | packet[13]);
915             if (packet_type == PacketType.ARP) {
916                 // ARP
917                 return;
918             } else if (packet_type != PacketType.IP) {
919                 source.Log(LogLevel.Error, String.Format("Unknown packet type: 0x{0:X}. Supported are: 0x800 (IP) and 0x806 (ARP).", (ushort)packet_type));
920                 return;
921             }
922             if (packet.Length < (MACLength+12)) {
923                 source.Log(LogLevel.Error, "IP Packet is too short!");
924                 return;
925             }
926             // IPvX
927             if ((packet[MACLength] >> 4) != 0x04) {
928                 source.Log(LogLevel.Error, String.Format("Only IPv4 packets are supported. Got IPv{0}", (packet[MACLength] >> 4)));
929                 return;
930             }
931             // IPv4
932             var ipLength = (packet[MACLength] & 0x0F) * 4;
933             if(ipLength != 0)
934             {
935                 var ipChecksum = ComputeHeaderIpChecksum(packet, MACLength, ipLength);
936                 packet[MACLength + 10] = (byte)(ipChecksum >> 8);
937                 packet[MACLength + 11] = (byte)(ipChecksum & 0xFF);
938             } else {
939                 source.Log(LogLevel.Error, "Something is wrong - IP packet of len 0");
940             }
941             if(interpretedProtocols != null && interpretedProtocols.Contains((TransportLayerProtocol)packet[MACLength + 9]))
942             {
943                 var payloadStart = MACLength + ipLength;
944                 var protocol = (TransportLayerProtocol)packet[MACLength + 9];
945                 var checksum = GetPacketChecksum(packet, MACLength, payloadStart, protocol != TransportLayerProtocol.ICMP);
946                 switch(protocol)
947                 {
948                 case TransportLayerProtocol.ICMP:
949                     packet[payloadStart + 2] = (byte)((checksum >> 8) & 0xFF);
950                     packet[payloadStart + 3] = (byte)((checksum ) & 0xFF);
951                     break;
952                 case TransportLayerProtocol.TCP:
953                     packet[payloadStart + 16] = (byte)((checksum >> 8) & 0xFF);
954                     packet[payloadStart + 17] = (byte)((checksum ) & 0xFF);
955                     break;
956                 case TransportLayerProtocol.UDP:
957                     packet[payloadStart + 6] = (byte)((checksum >> 8) & 0xFF);
958                     packet[payloadStart + 7] = (byte)((checksum ) & 0xFF);
959                     break;
960                 default:
961                     throw new NotImplementedException();
962                 }
963             }
964         }
965 
DumpPacket(EthernetFrame packet, bool isSend, IMachine machine)966         public static string DumpPacket(EthernetFrame packet, bool isSend, IMachine machine)
967         {
968             var builder = new StringBuilder();
969             string machName;
970             if(!EmulationManager.Instance.CurrentEmulation.TryGetMachineName(machine, out machName))
971             {
972                 //probably the emulation is closing now, just return.
973                 return string.Empty;
974             }
975             if(isSend)
976             {
977                 builder.AppendLine(String.Format("Sending packet from {0}, length: {1}", machName, packet.Bytes.Length));
978             }
979             else
980             {
981                 builder.AppendLine(String.Format("Receiving packet on {0}, length: {1}", machName, packet.Bytes.Length));
982             }
983             builder.Append(packet.ToString());
984             return builder.ToString();
985         }
986 
Swap(ref T a, ref T b)987         public static void Swap<T>(ref T a, ref T b)
988         {
989             T temporary = a;
990             a = b;
991             b = temporary;
992         }
993 
SwapBytesUShort(ushort val)994         public static ushort SwapBytesUShort(ushort val)
995         {
996             return (ushort)((val << 8) | (val >> 8));
997         }
998 
SwapBytesUInt(uint value)999         public static uint SwapBytesUInt(uint value)
1000         {
1001             return (value & 0xFF000000) >> 24
1002                  | (value & 0x00FF0000) >> 8
1003                  | (value & 0x0000FF00) << 8
1004                  | (value & 0x000000FF) << 24;
1005         }
1006 
SwapBytesULong(ulong value)1007         public static ulong SwapBytesULong(ulong value)
1008         {
1009             return (value & 0xFF00000000000000) >> 56
1010                  | (value & 0x00FF000000000000) >> 40
1011                  | (value & 0x0000FF0000000000) >> 24
1012                  | (value & 0x000000FF00000000) >> 8
1013                  | (value & 0x00000000FF000000) << 8
1014                  | (value & 0x0000000000FF0000) << 24
1015                  | (value & 0x000000000000FF00) << 40
1016                  | (value & 0x00000000000000FF) << 56;
1017         }
1018 
SwapBytes(T value)1019         public static T SwapBytes<T>(T value)
1020         {
1021             var type = typeof(T);
1022             if(type == typeof(uint))
1023             {
1024                 return (T)(object)SwapBytesUInt((uint)(object)value);
1025             }
1026             else if(type == typeof(ushort))
1027             {
1028                 return (T)(object)SwapBytesUShort((ushort)(object)value);
1029             }
1030             else if(type == typeof(byte))
1031             {
1032                 return value;
1033             }
1034             else
1035             {
1036                 throw new ArgumentException($"Unhandled type {type}");
1037             }
1038         }
1039 
SwapElements(T[] arr, int id1, int id2)1040         public static void SwapElements<T>(T[] arr, int id1, int id2)
1041         {
1042             var tmp = arr[id1];
1043             arr[id1] = arr[id2];
1044             arr[id2] = tmp;
1045         }
1046 
EndiannessSwapInPlace(byte[] input, int width, int offset = 0, int? length = null)1047         public static bool EndiannessSwapInPlace(byte[] input, int width, int offset = 0, int? length = null)
1048         {
1049             if(offset > input.Length)
1050             {
1051                 return false;
1052             }
1053 
1054             var bytesFromOffset = input.Length - offset;
1055             var len = length ?? bytesFromOffset;
1056             if(len > bytesFromOffset || len % width != 0)
1057             {
1058                 return false;
1059             }
1060 
1061             for(var i = offset; i < offset + len; i += width)
1062             {
1063                 for(var j = 0; j < width / 2; j++)
1064                 {
1065                     SwapElements(input, i + j, i + width - j - 1);
1066                 }
1067             }
1068 
1069             return true;
1070         }
1071 
EndiannessSwap(uint value)1072         public static uint EndiannessSwap(uint value)
1073         {
1074             var temp = new byte[sizeof(uint)];
1075             Misc.ByteArrayWrite(0, value, temp);
1076             Misc.EndiannessSwapInPlace(temp, sizeof(uint));
1077             return Misc.ByteArrayRead(0, temp);
1078         }
1079 
CalculateUnitSuffix(double value, out double newValue, out string unit)1080         public static bool CalculateUnitSuffix(double value, out double newValue, out string unit)
1081         {
1082             var units = new [] { "B", "KB", "MB", "GB", "TB" };
1083 
1084             var v = value;
1085             var i = 0;
1086             while(i < units.Length - 1 && Math.Round(v / 1024) >= 1)
1087             {
1088                 v /= 1024;
1089                 i++;
1090             }
1091 
1092             newValue = v;
1093             unit = units[i];
1094 
1095             return true;
1096         }
1097 
ToOrdinal(this int num)1098         public static string ToOrdinal(this int num)
1099         {
1100             if(num <= 0)
1101             {
1102                 return num.ToString();
1103             }
1104             switch(num % 100)
1105             {
1106             case 11:
1107             case 12:
1108             case 13:
1109                 return num + "th";
1110             }
1111 
1112             switch(num % 10)
1113             {
1114             case 1:
1115                 return num + "st";
1116             case 2:
1117                 return num + "nd";
1118             case 3:
1119                 return num + "rd";
1120             default:
1121                 return num + "th";
1122             }
1123         }
1124 
1125         private const int MACLength = 14;
1126 
1127         private static string LastBitmapName = "";
1128         private static Bitmap LastBitmap;
1129 
1130         private const BindingFlags DefaultBindingFlags = BindingFlags.Public | BindingFlags.NonPublic |
1131                 BindingFlags.Instance | BindingFlags.DeclaredOnly;
1132 
1133         private static readonly string[] SIPrefixes = {
1134                 "p",
1135                 "n",
1136                 "µ",
1137                 "m",
1138                 "",
1139                 "k",
1140                 "M",
1141                 "G",
1142                 "T"
1143             };
1144         private static readonly string[] BytePrefixes = {
1145                 "",
1146                 "Ki",
1147                 "Mi",
1148                 "Gi",
1149                 "Ti"
1150             };
1151         private const int ZeroPrefixPosition = 4;
1152         private static readonly int[] MultiplyDeBruijnBitPosition2 =
1153          {
1154            0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
1155            31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
1156          };
1157 
1158         /// <summary>
1159         /// Checks if the current user is a root.
1160         /// </summary>
1161         /// <value><c>true</c> if is root; otherwise, <c>false</c>.</value>
1162         public static bool IsRoot
1163         {
1164             get { return Environment.UserName == "root"; }
1165         }
1166 
1167         public static bool IsOnOsX
1168         {
1169             get
1170             {
1171                 if(Environment.OSVersion.Platform == PlatformID.MacOSX)
1172                 {
1173                     return true;
1174                 }
1175                 return Directory.Exists("/Library") && Directory.Exists("/Applications");
1176             }
1177         }
1178 
IsCommandAvaialble(string command)1179         public static bool IsCommandAvaialble(string command)
1180         {
1181             var verifyProc = new Process();
1182             verifyProc.StartInfo.UseShellExecute = false;
1183             verifyProc.StartInfo.RedirectStandardError = true;
1184             verifyProc.StartInfo.RedirectStandardInput = true;
1185             verifyProc.StartInfo.RedirectStandardOutput = true;
1186             verifyProc.EnableRaisingEvents = false;
1187             verifyProc.StartInfo.FileName = "which";
1188             verifyProc.StartInfo.Arguments = command;
1189 
1190             verifyProc.Start();
1191 
1192             verifyProc.WaitForExit();
1193             return verifyProc.ExitCode == 0;
1194         }
1195 
PrettyPrintFlagsEnum(Enum enumeration)1196         public static string PrettyPrintFlagsEnum(Enum enumeration)
1197         {
1198             var values = new List<string>();
1199             foreach(Enum value in Enum.GetValues(enumeration.GetType()))
1200             {
1201                 if((Convert.ToUInt64(enumeration) & Convert.ToUInt64(value)) != 0)
1202                 {
1203                     values.Add(value.ToString());
1204                 }
1205             }
1206             return values.Count == 0 ? "-" : values.Aggregate((x, y) => x + ", " + y);
1207         }
1208 
TryGetMatchingSignature(IEnumerable<Type> signatures, MethodInfo mi, out Type matchingSignature)1209         public static bool TryGetMatchingSignature(IEnumerable<Type> signatures, MethodInfo mi, out Type matchingSignature)
1210         {
1211             matchingSignature = signatures.FirstOrDefault(x => HasMatchingSignature(x, mi));
1212             return matchingSignature != null;
1213         }
1214 
HasMatchingSignature(Type delegateType, MethodInfo mi)1215         public static bool HasMatchingSignature(Type delegateType, MethodInfo mi)
1216         {
1217             var delegateMethodInfo = delegateType.GetMethod("Invoke");
1218 
1219             return mi.ReturnType == delegateMethodInfo.ReturnType &&
1220                 mi.GetParameters().Select(x => x.ParameterType).SequenceEqual(delegateMethodInfo.GetParameters().Select(x => x.ParameterType));
1221         }
1222 
1223         public static T Clamp<T>(this T @this, T min, T max) where T : IComparable
1224         {
1225             if(@this.CompareTo(min) < 0)
1226             {
1227                 return min;
1228             }
1229             else if(@this.CompareTo(max) > 0)
1230             {
1231                 return max;
1232             }
1233             return @this;
1234         }
1235 
Split(this string value, int size)1236         public static string[] Split(this string value, int size)
1237         {
1238             var ind = 0;
1239             return value.GroupBy(x => ind++ / size).Select(x => string.Join("", x)).ToArray();
1240         }
1241 
Split(this IEnumerable<T> values, int size)1242         public static IEnumerable<T[]> Split<T>(this IEnumerable<T> values, int size)
1243         {
1244             var i = 0;
1245             return values.GroupBy(_ => i++ / size).Select(chunk => chunk.ToArray());
1246         }
1247 
SetBit(this IValueRegisterField field, byte index, bool value)1248         public static void SetBit(this IValueRegisterField field, byte index, bool value)
1249         {
1250             var val =  field.Value;
1251             BitHelper.SetBit(ref val, index, value);
1252             field.Value = val;
1253         }
1254 
InMicroseconds(this TimeSpan ts)1255         public static ulong InMicroseconds(this TimeSpan ts)
1256         {
1257             return (ulong)(ts.Ticks / 10);
1258         }
1259 
WaitWhile(this object @this, Func<bool> condition, string reason)1260         public static void WaitWhile(this object @this, Func<bool> condition, string reason)
1261         {
1262             @this.Trace($"Waiting for '{reason}'...");
1263             while(condition())
1264             {
1265                 Monitor.Wait(@this);
1266             }
1267             @this.Trace($"Waiting for '{reason}' finished.");
1268         }
1269 
FlipFlag(ref TEnum value, TEnum flag, bool state)1270         public static void FlipFlag<TEnum>(ref TEnum value, TEnum flag, bool state)
1271         {
1272             if(!typeof(TEnum).IsEnum)
1273             {
1274                 throw new ArgumentException("TEnum must be an enumerated type.");
1275             }
1276             var intValue = (long)(object)value;
1277             var intFlag = (long)(object)flag;
1278             if(state)
1279             {
1280                 intValue |= intFlag;
1281             }
1282             else
1283             {
1284                 intValue &= ~intFlag;
1285             }
1286             value = (TEnum)(object)intValue;
1287         }
1288 
PrettyPrintCollection(IEnumerable<T> collection, Func<T, string> formatter = null)1289         public static string PrettyPrintCollection<T>(IEnumerable<T> collection, Func<T, string> formatter = null)
1290         {
1291             return collection == null || !collection.Any()
1292                 ? "[]"
1293                 : $"[{(string.Join(", ", collection.Select(x => formatter == null ? x.ToString() : formatter(x))))}]";
1294         }
1295 
PrettyPrintCollectionHex(IEnumerable<T> collection)1296         public static string PrettyPrintCollectionHex<T>(IEnumerable<T> collection)
1297         {
1298             return PrettyPrintCollection(collection, x => "0x{0:X}".FormatWith(x));
1299         }
1300 
ToLazyHexString(this IEnumerable<T> collection)1301         public static LazyHexString<T> ToLazyHexString<T>(this IEnumerable<T> collection)
1302         {
1303             return new LazyHexString<T>(collection);
1304         }
1305 
ToUInt32Smart(this byte[] @this)1306         public static UInt32 ToUInt32Smart(this byte[] @this)
1307         {
1308             if(@this.Length > 4)
1309             {
1310                 throw new ArgumentException($"Bytes array is tool long. Expected at most 4 bytes, but got {@this.Length}");
1311             }
1312             var result = 0u;
1313             for(var i = 0; i < @this.Length; i++)
1314             {
1315                 result |= ((uint)@this[i] << (8 * i));
1316             }
1317             return result;
1318         }
1319 
With(this DateTime @this, int? year = null, int? month = null, int? day = null, int? hour = null, int? minute = null, int? second = null, double? millisecond = null)1320         public static DateTime With(this DateTime @this, int? year = null, int? month = null, int? day = null, int? hour = null, int? minute = null, int? second = null, double? millisecond = null)
1321         {
1322             var dateTime = new DateTime(
1323                 year ?? @this.Year,
1324                 month ?? @this.Month,
1325                 day ?? @this.Day,
1326                 hour ?? @this.Hour,
1327                 minute ?? @this.Minute,
1328                 second ?? @this.Second);
1329 
1330             if(millisecond != null)
1331             {
1332                 dateTime = dateTime.AddMilliseconds(millisecond.Value);
1333             }
1334 
1335             return dateTime;
1336         }
1337 
EnqueueRange(this Queue<T> @this, IEnumerable<T> data, int? limit = null)1338         public static int EnqueueRange<T>(this Queue<T> @this, IEnumerable<T> data, int? limit = null)
1339         {
1340             var counter = 0;
1341             foreach(var e in data.Take(limit ?? int.MaxValue))
1342             {
1343                 @this.Enqueue(e);
1344                 counter++;
1345             }
1346             return counter;
1347         }
1348 
DequeueRange(this Queue<T> @this, int limit)1349         public static T[] DequeueRange<T>(this Queue<T> @this, int limit)
1350         {
1351             var result = new T[Math.Min(@this.Count, limit)];
1352             for(var i = 0; i < result.Length; i++)
1353             {
1354                 result[i] = @this.Dequeue();
1355             }
1356             return result;
1357         }
1358 
DequeueAll(this Queue<T> @this)1359         public static T[] DequeueAll<T>(this Queue<T> @this)
1360         {
1361             return DequeueRange(@this, @this.Count);
1362         }
1363 
TryDequeue(this Queue<T> @this, out T result)1364         public static bool TryDequeue<T>(this Queue<T> @this, out T result)
1365         {
1366             if(@this.Count == 0)
1367             {
1368                 result = default(T);
1369                 return false;
1370             }
1371             result = @this.Dequeue();
1372             return true;
1373         }
1374 
PopRange(this Stack<T> @this, int limit)1375         public static IEnumerable<T> PopRange<T>(this Stack<T> @this, int limit)
1376         {
1377             while(@this.Count > 0 && limit > 0)
1378             {
1379                 limit--;
1380                 yield return @this.Pop();
1381             }
1382         }
1383 
PopAll(this Stack<T> @this)1384         public static IEnumerable<T> PopAll<T>(this Stack<T> @this)
1385         {
1386             return PopRange(@this, @this.Count);
1387         }
1388 
TryCreateFrameOrLogWarning(IEmulationElement source, byte[] data, out EthernetFrame frame, bool addCrc)1389         public static bool TryCreateFrameOrLogWarning(IEmulationElement source, byte[] data, out EthernetFrame frame, bool addCrc)
1390         {
1391             if(EthernetFrame.TryCreateEthernetFrame(data, addCrc, out frame))
1392             {
1393                 return true;
1394             }
1395             source.Log(LogLevel.Warning, "Insufficient data to create an ethernet frame, expected {0} bytes but got {1} bytes.",
1396                     EthernetFrame.MinFrameSizeWithoutCRC + (addCrc ? 0 : EthernetFrame.CRCLength), data.Length);
1397             return false;
1398         }
1399 
StripNonSafeCharacters(this string input)1400         public static string StripNonSafeCharacters(this string input)
1401         {
1402             return Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(input).Where(x => (x >= 32 && x <= 126) || (x == '\n')).ToArray());
1403         }
1404 
SurroundWith(this string str, string surrounding)1405         public static string SurroundWith(this string str, string surrounding)
1406         {
1407             return $"{surrounding}{str}{surrounding}";
1408         }
1409 
1410         // allocate file of a given name
1411         // if it already exists - rename it using pattern path.III (III being an integer)
1412         // returns information if there was a rename and III of the last renamed file
AllocateFile(string path, out int counter)1413         public static bool AllocateFile(string path, out int counter)
1414         {
1415             counter = 0;
1416             var renamed = false;
1417             var dstName = $"{path}.{counter}";
1418 
1419             while(!TryCreateEmptyFile(path))
1420             {
1421                 while(File.Exists(dstName))
1422                 {
1423                     counter++;
1424                     dstName = $"{path}.{counter}";
1425                 }
1426                 File.Move(path, dstName);
1427                 renamed = true;
1428             }
1429             return renamed;
1430         }
1431 
1432         // Allows to have static initialization of a two-element tuple list.
1433         // To enable other arities of tuples, add more overloads.
Add(this IList<Tuple<T1, T2>> list, T1 item1, T2 item2)1434         public static void Add<T1, T2>(this IList<Tuple<T1, T2>> list,
1435             T1 item1, T2 item2)
1436         {
1437             list.Add(Tuple.Create(item1, item2));
1438         }
1439 
TryCreateEmptyFile(string p)1440         private static bool TryCreateEmptyFile(string p)
1441         {
1442             try
1443             {
1444                 File.Open(p, FileMode.CreateNew).Dispose();
1445                 return true;
1446             }
1447             catch(IOException)
1448             {
1449                 // this is expected - the file already exists
1450                 return false;
1451             }
1452         }
1453 
TryParseBitPattern(string pattern, out ulong value, out ulong mask)1454         public static bool TryParseBitPattern(string pattern, out ulong value, out ulong mask)
1455         {
1456             value = 0uL;
1457             mask = 0uL;
1458 
1459             if(pattern.Length > 64)
1460             {
1461                 return false;
1462             }
1463 
1464             var currentBit = pattern.Length - 1;
1465 
1466             foreach(var p in pattern)
1467             {
1468                 switch(p)
1469                 {
1470                     case '0':
1471                         mask |= (1uL << currentBit);
1472                         break;
1473 
1474                     case '1':
1475                         mask |= (1uL << currentBit);
1476                         value |= (1uL << currentBit);
1477                         break;
1478 
1479                     default:
1480                         // all characters other than '0' or '1' are treated as 'any-value'
1481                         break;
1482                 }
1483 
1484                 currentBit--;
1485             }
1486 
1487             return true;
1488         }
1489 
SetBytesFromValue(this byte[] array, uint value, int startIndex)1490         public static void SetBytesFromValue(this byte[] array, uint value, int startIndex)
1491         {
1492             foreach(var b in BitConverter.GetBytes(value))
1493             {
1494                 array[startIndex++] = b;
1495             }
1496         }
1497 
1498         public static bool TryFindPreceedingEnumItem<T>(uint value, out T bestCandidate, out int offset) where T: IConvertible
1499         {
1500             var allValues = Enum.GetValues(typeof(T));
1501             var maxIndex = allValues.Length - 1;
1502 
1503             bestCandidate = default(T);
1504             offset = 0;
1505 
1506             if((int)allValues.GetValue(0) > value)
1507             {
1508                 // there are no values preceeding given value
1509                 return false;
1510             }
1511 
1512             int currentValue = 0;
1513             int lowBorder = 0;
1514             int highBorder = maxIndex;
1515 
1516             // binary search
1517             while(highBorder != lowBorder)
1518             {
1519                 var currentIndex = lowBorder + ((highBorder - lowBorder) / 2);
1520                 currentValue = (int)allValues.GetValue(currentIndex);
1521 
1522                 if(currentValue == value)
1523                 {
1524                     break;
1525                 }
1526                 else if(currentValue < value)
1527                 {
1528                     lowBorder = currentIndex + 1;
1529                 }
1530                 else
1531                 {
1532                     highBorder = currentIndex;
1533                 }
1534             }
1535             bestCandidate = (T)Enum.ToObject(typeof(T), currentValue);
1536             offset = (int)(value - currentValue);
1537             return true;
1538         }
1539 
FillByteArrayWithArray(byte[] destinationArray, byte[] sourceArray)1540         public static void FillByteArrayWithArray(byte[] destinationArray, byte[] sourceArray)
1541         {
1542             var srcLength = sourceArray.Length;
1543             var dstLength = destinationArray.Length;
1544             if(srcLength >= dstLength)
1545             {
1546                 Buffer.BlockCopy(sourceArray, 0, destinationArray, 0, dstLength);
1547             }
1548             else
1549             {
1550                 var currentIndex = 0;
1551                 while((currentIndex + srcLength) < dstLength)
1552                 {
1553                     Buffer.BlockCopy(sourceArray, 0, destinationArray, currentIndex, srcLength);
1554                     currentIndex += srcLength;
1555                 }
1556                 var remindingElements = dstLength % srcLength;
1557                 Buffer.BlockCopy(sourceArray, 0, destinationArray, currentIndex, remindingElements);
1558             }
1559         }
1560 
CopyAndResize(this T[] source, int length)1561         public static T[] CopyAndResize<T>(this T[] source, int length)
1562         {
1563             if(source.Length == length)
1564             {
1565                 return source.ToArray();
1566             }
1567             var data = new T[length];
1568             Array.Copy(source, data, Math.Min(source.Length, length));
1569             return data;
1570         }
1571 
CountTrailingZeroes(uint value)1572         public static int CountTrailingZeroes(uint value)
1573         {
1574             int count = 0;
1575             while((value & 0x1) == 0)
1576             {
1577                 count += 1;
1578                 value >>= 1;
1579                 if(count == sizeof(uint) * 8)
1580                 {
1581                     break;
1582                 }
1583             }
1584             return count;
1585         }
1586 
1587         // Remaps a number from [inMin; inMax] to [outMin; outMax].
1588         // Supports "reversing the direction", like remapping [0; 10] to [1; -1].
1589         // If the input is null or outside the input range, returns null.
1590         public static decimal? RemapNumber(decimal? value, decimal inMin, decimal inMax, decimal outMin, decimal outMax)
1591         {
1592             if(value == null || value < inMin || value > inMax)
1593             {
1594                 return null;
1595             }
1596 
1597             var inRangeLen = inMax - inMin;
1598             var outRangeLen = outMax - outMin;
1599             return (value - inMin) * outRangeLen / inRangeLen + outMin;
1600         }
1601 
AsBytes(uint[] data)1602         public static byte[] AsBytes(uint[] data)
1603         {
1604             var outLength = data.Length * sizeof(uint);
1605             var dataAsBytes = new byte[outLength];
1606             Buffer.BlockCopy(data, 0, dataAsBytes, 0, outLength);
1607             return dataAsBytes;
1608         }
1609 
1610         public static T ReadStruct<T>(this Stream @this) where T : struct
1611         {
1612             var structSize = Marshal.SizeOf(typeof(T));
1613             return @this.ReadBytes(structSize).ToStruct<T>();
1614         }
1615 
1616         public static T ToStruct<T>(this byte[] @this) where T : struct
1617         {
1618             var size = @this.Length;
1619             var bufferPointer = Marshal.AllocHGlobal(size);
1620             Marshal.Copy(@this, 0, bufferPointer, size);
1621             var result = (T)Marshal.PtrToStructure(bufferPointer, typeof(T));
Marshal.FreeHGlobalAntmicro.Renode.Utilities.Misc.__anon31622             Marshal.FreeHGlobal(bufferPointer);
1623             return result;
1624         }
1625 
TryGetNext(this IEnumerator<T> @this, out T element)1626         public static bool TryGetNext<T>(this IEnumerator<T> @this, out T element)
1627         {
1628             element = default(T);
1629             if(@this.MoveNext())
1630             {
1631                 element = @this.Current;
1632                 return true;
1633             }
1634             return false;
1635         }
1636 
1637         public static byte ReadWithOffset<T>(this T @this, long register, int offset, bool msbFirst = false) where T : IRegisterCollection
1638         {
1639             int innerOffset;
1640             uint outputValue;
1641             if(@this is ByteRegisterCollection)
1642             {
1643                 ByteRegisterCollection byteRegisterCollection = @this as ByteRegisterCollection;
1644                 innerOffset = 0;
1645                 outputValue = (uint)byteRegisterCollection.Read(register);
1646             }
1647             else if(@this is WordRegisterCollection)
1648             {
1649                 WordRegisterCollection wordRegisterCollection = @this as WordRegisterCollection;
1650                 innerOffset = offset % 2;
1651                 if(msbFirst)
1652                 {
1653                     innerOffset = 1 - innerOffset;
1654                 }
1655                 outputValue = (uint)wordRegisterCollection.Read(register + offset / 2);
1656             }
1657             else if(@this is DoubleWordRegisterCollection)
1658             {
1659                 DoubleWordRegisterCollection doubleWordRegisterCollection = @this as DoubleWordRegisterCollection;
1660                 innerOffset = offset % 4;
1661                 if(msbFirst)
1662                 {
1663                     innerOffset = 3 - innerOffset;
1664                 }
1665                 outputValue = (uint)doubleWordRegisterCollection.Read(register + offset / 4);
1666             }
1667             else
1668             {
1669                 throw new Exception("unreachable code");
1670             }
1671             var mask = 0xFFUL << (innerOffset * 8);
1672             return (byte)((outputValue & mask) >> (innerOffset * 8));
1673         }
1674 
1675         public static void WriteWithOffset<T>(this T @this, long register, int offset, byte value, bool msbFirst = false) where T : IRegisterCollection
1676         {
1677             int innerOffset;
1678             uint previousValue;
1679             Action<uint> writeFunction;
1680             if(@this is ByteRegisterCollection)
1681             {
1682                 ByteRegisterCollection byteRegisterCollection = @this as ByteRegisterCollection;
1683                 innerOffset = 0;
1684                 previousValue = (uint)byteRegisterCollection.Read(register);
1685                 writeFunction = (data) => byteRegisterCollection.Write(register, (byte)data);
1686             }
1687             else if(@this is WordRegisterCollection)
1688             {
1689                 WordRegisterCollection wordRegisterCollection = @this as WordRegisterCollection;
1690                 innerOffset = offset % 2;
1691                 if(msbFirst)
1692                 {
1693                     innerOffset = 1 - innerOffset;
1694                 }
1695                 previousValue = (uint)wordRegisterCollection.Read(register + offset / 2);
1696                 writeFunction = (data) => wordRegisterCollection.Write(register + offset / 2, (ushort)data);
1697             }
1698             else if(@this is DoubleWordRegisterCollection)
1699             {
1700                 DoubleWordRegisterCollection doubleWordRegisterCollection = @this as DoubleWordRegisterCollection;
1701                 innerOffset = offset % 4;
1702                 if(msbFirst)
1703                 {
1704                     innerOffset = 3 - innerOffset;
1705                 }
1706                 previousValue = (uint)doubleWordRegisterCollection.Read(register + offset / 4);
1707                 writeFunction = (data) => doubleWordRegisterCollection.Write(register + offset / 4, (uint)data);
1708             }
1709             else
1710             {
1711                 throw new Exception("unreachable code");
1712             }
1713             var mask = 0xFFU << (innerOffset * 8);
1714             var newValue = (previousValue & ~mask) | ((uint)value << (innerOffset * 8));
1715             writeFunction((uint)newValue);
1716         }
1717 
Iterate(Func<T> function)1718         public static IEnumerable<T> Iterate<T>(Func<T> function)
1719         {
1720             while(true)
1721             {
1722                 yield return function();
1723             }
1724         }
1725 
1726 #if !NET
1727         // Enumerable.TakeLast is in the standard library on .NET Core but isn't available on .NET Framework
TakeLast(this IEnumerable<T> @this, int count)1728         public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> @this, int count)
1729         {
1730             // This will enumerate the collection twice - it might be not optimal for performance sensitive operations
1731             return @this.Skip(Math.Max(0, @this.Count() - count));
1732         }
1733 
Chunk(this IEnumerable<T> @this, int size)1734         public static IEnumerable<T[]> Chunk<T>(this IEnumerable<T> @this, int size)
1735         {
1736             var buffer = new Queue<T>();
1737             foreach(var item in @this)
1738             {
1739                 buffer.Enqueue(item);
1740                 if(buffer.Count == size)
1741                 {
1742                     yield return buffer.ToArray();
1743                     buffer.Clear();
1744                 }
1745             }
1746 
1747             if(buffer.Count > 0)
1748             {
1749                 yield return buffer.ToArray();
1750             }
1751         }
1752 
Fill(this T[] array, T value, int startIndex = 0, int? count = null)1753         public static void Fill<T>(this T[] array, T value, int startIndex = 0, int? count = null)
1754         {
1755             if(startIndex >= array.Length || startIndex < 0)
1756             {
1757                 throw new ArgumentException("has to be a legal index", nameof(startIndex));
1758             }
1759             count = count ?? array.Length - startIndex;
1760             if(startIndex + count.Value > array.Length)
1761             {
1762                 throw new ArgumentException("value out of bounds", nameof(count));
1763             }
1764             for(var i = 0; i < count.Value; ++i)
1765             {
1766                 array[startIndex + i] = value;
1767             }
1768         }
1769 #else
Fill(this T[] array, T value, int startIndex = 0, int? count = null)1770         public static void Fill<T>(this T[] array, T value, int startIndex = 0, int? count = null)
1771         {
1772             Array.Fill(array, value, startIndex, count ?? array.Length - startIndex);
1773         }
1774 #endif
1775 
CastToULong(dynamic number)1776         public static ulong CastToULong(dynamic number)
1777         {
1778             if(new Type[] { typeof(byte), typeof(ushort), typeof(uint), typeof(ulong)}.Any((t) => number.GetType() == t))
1779             {
1780                 return (ulong)number;
1781             }
1782             throw new ArgumentException($"Can't cast {number.GetType()} to ulong", "number");
1783         }
1784 
Prefix(IEnumerable<T> enumerable, Func<T, T, T> function)1785         public static IEnumerable<T> Prefix<T>(IEnumerable<T> enumerable, Func<T, T, T> function)
1786         {
1787             var enumerator = enumerable.GetEnumerator();
1788             // Using `out var` here causes a compiler crash in Mono 6.8.0.105+dfsg-3.3 from Debian
1789             if(!enumerator.TryGetNext(out T prefix))
1790             {
1791                 yield break;
1792             }
1793             while(enumerator.MoveNext())
1794             {
1795                 yield return prefix;
1796                 prefix = function(prefix, enumerator.Current);
1797             }
1798             yield return prefix;
1799         }
1800 
AddIf(this ICollection<T> collection, bool condition, T item)1801         public static void AddIf<T>(this ICollection<T> collection, bool condition, T item)
1802         {
1803             if(condition)
1804             {
1805                 collection.Add(item);
1806             }
1807         }
1808 
IsStructType(Type type)1809         public static bool IsStructType(Type type)
1810         {
1811             // According to docs, IsValueType return true for structs, enums and primitive types
1812             return type.IsValueType && !type.IsPrimitive && !type.IsEnum;
1813         }
1814 
MemoryOperationToMpuAccess(MemoryOperation operation)1815         public static MpuAccess MemoryOperationToMpuAccess(MemoryOperation operation)
1816         {
1817             switch(operation)
1818             {
1819                 case MemoryOperation.InsnFetch:
1820                     return MpuAccess.InstructionFetch;
1821                 case MemoryOperation.MemoryIOWrite:
1822                 case MemoryOperation.MemoryWrite:
1823                     return MpuAccess.Write;
1824                 case MemoryOperation.MemoryIORead:
1825                 case MemoryOperation.MemoryRead:
1826                     return MpuAccess.Read;
1827                 default:
1828                     throw new ArgumentException("Invalid conversion from MemoryOperation to MpuAccess");
1829             }
1830         }
1831 
GCD(ulong a, ulong b)1832         public static ulong GCD(ulong a, ulong b)
1833         {
1834             while(a != 0 && b != 0)
1835             {
1836                 if(a > b)
1837                 {
1838                     a %= b;
1839                 }
1840                 else
1841                 {
1842                     b %= a;
1843                 }
1844             }
1845             return a | b;
1846         }
1847 
LCM(ulong a, ulong b)1848         public static ulong LCM(ulong a, ulong b)
1849         {
1850             return a / GCD(a, b) * b;
1851         }
1852 
ReturnThenAssign(ref T variable, T value)1853         public static T ReturnThenAssign<T>(ref T variable, T value)
1854         {
1855             var temp = variable;
1856             variable = value;
1857             return temp;
1858         }
1859 
ReturnThenSet(ref bool variable, bool value = true)1860         public static bool ReturnThenSet(ref bool variable, bool value = true) => ReturnThenAssign(ref variable, value);
1861 
1862         public static bool ReturnThenClear(ref bool variable) => ReturnThenAssign(ref variable, false);
1863 
1864         public static DateTime UnixEpoch = new DateTime(1970, 1, 1);
1865 
1866         private static readonly Lazy<string[]> hexStringLookup = new Lazy<string[]>(() =>
1867         {
1868             var lookup = new string[0x100];
1869             for(var i = 0; i < lookup.Length; ++i)
1870             {
1871                 lookup[i] = $"{i:X02}";
1872             }
1873             return lookup;
1874         }, isThreadSafe: true);
1875     }
1876 
1877     public class MethodWithAttribute<T> where T : Attribute
1878     {
MethodWithAttribute(MethodInfo method, T attribute)1879         public MethodWithAttribute(MethodInfo method, T attribute)
1880         {
1881             Method = method;
1882             Attribute = attribute;
1883         }
1884 
1885         public MethodInfo Method { get; }
1886         public T Attribute { get; }
1887     }
1888 
1889     public class LazyHexString<T>
1890     {
LazyHexString(IEnumerable<T> collection)1891         public LazyHexString(IEnumerable<T> collection)
1892         {
1893             this.collection = collection;
1894         }
1895 
ToString()1896         public override string ToString()
1897         {
1898             return Misc.PrettyPrintCollectionHex(collection);
1899         }
1900 
1901         private readonly IEnumerable<T> collection;
1902     }
1903 }
1904 
1905