1 //
2 // Copyright (c) 2010-2021 Antmicro
3 //
4 //  This file is licensed under the MIT License.
5 //  Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Linq;
9 using ELFSharp.ELF;
10 using Microsoft.Scripting.Utils;
11 
12 namespace Antmicro.Renode.Peripherals.CPU
13 {
14     public struct RegisterValue
15     {
16         public ulong RawValue { get; private set; }
17         public byte[] ByteArrayValue { get; private set; }
18         public uint Bits { get; private set; }
19 
20         // this is not the perfect solution,
21         // as it displays the value always in hex
22         // which may be inconsistent with monitor
23         // output mode
ToStringAntmicro.Renode.Peripherals.CPU.RegisterValue24         public override string ToString()
25         {
26             return $"0x{RawValue.ToString("x")}";
27         }
28 
GetBytesAntmicro.Renode.Peripherals.CPU.RegisterValue29         public byte[] GetBytes(Endianess endianness)
30         {
31             bool needsByteSwap = (endianness == Endianess.LittleEndian) != BitConverter.IsLittleEndian;
32             byte[] bytes;
33 
34             if(ByteArrayValue != null)
35             {
36                 return ByteArrayValue;
37             }
38 
39             switch (Bits)
40             {
41                 case 8:
42                     bytes = new[] { (byte)RawValue };
43                     break;
44                 case 16:
45                     bytes = BitConverter.GetBytes((ushort)RawValue);
46                     break;
47                 case 32:
48                     bytes = BitConverter.GetBytes((uint)RawValue);
49                     break;
50                 case 64:
51                     bytes = BitConverter.GetBytes(RawValue);
52                     break;
53                 default:
54                     throw new ArgumentException($"Unexpected bits count: {Bits}");
55             }
56 
57             return needsByteSwap ? bytes.Reverse().ToArray() : bytes;
58         }
59 
60         // this is to support using 64bit integer values for RegisterValue in monitor
operator RegisterValueAntmicro.Renode.Peripherals.CPU.RegisterValue61         public static implicit operator RegisterValue(long v)
62         {
63             return new RegisterValue { RawValue = (ulong)v, ByteArrayValue = null, Bits = 64 };
64         }
65 
operator RegisterValueAntmicro.Renode.Peripherals.CPU.RegisterValue66         public static implicit operator RegisterValue(ulong v)
67         {
68             return new RegisterValue { RawValue = v, ByteArrayValue = null, Bits = 64 };
69         }
70 
operator RegisterValueAntmicro.Renode.Peripherals.CPU.RegisterValue71         public static implicit operator RegisterValue(uint v)
72         {
73             return new RegisterValue { RawValue = v, ByteArrayValue = null, Bits = 32 };
74         }
75 
operator RegisterValueAntmicro.Renode.Peripherals.CPU.RegisterValue76         public static implicit operator RegisterValue(ushort v)
77         {
78             return new RegisterValue { RawValue = v, ByteArrayValue = null, Bits = 16 };
79         }
80 
operator RegisterValueAntmicro.Renode.Peripherals.CPU.RegisterValue81         public static implicit operator RegisterValue(byte v)
82         {
83             return new RegisterValue { RawValue = v, ByteArrayValue = null, Bits = 8 };
84         }
85 
operator RegisterValueAntmicro.Renode.Peripherals.CPU.RegisterValue86         public static implicit operator RegisterValue(byte[] v)
87         {
88             return new RegisterValue { RawValue = default(ulong), ByteArrayValue = v, Bits = (uint)v.Length * 8 };
89         }
90 
operator ulongAntmicro.Renode.Peripherals.CPU.RegisterValue91         public static implicit operator ulong(RegisterValue v)
92         {
93             if(v.ByteArrayValue != null)
94             {
95                 if(v.TryGetBytesForInt(8, out var bytes))
96                 {
97                     return BitConverter.ToUInt64(bytes, 0);
98                 }
99                 throw new InvalidCastException("Value is too big to be expressed as UInt64");
100             }
101 
102             return v.RawValue;
103         }
104 
operator uintAntmicro.Renode.Peripherals.CPU.RegisterValue105         public static implicit operator uint(RegisterValue v)
106         {
107             if(v.ByteArrayValue != null)
108             {
109                 if(v.TryGetBytesForInt(4, out var bytes))
110                 {
111                     return BitConverter.ToUInt32(bytes, 0);
112                 }
113                 throw new InvalidCastException("Value is too big to be expressed as UInt32");
114             }
115 
116             if(v.Bits > 32 && v.RawValue > UInt32.MaxValue)
117             {
118                 throw new InvalidCastException("Value is too big to be expressed as UInt32");
119             }
120 
121             return (UInt32)v.RawValue;
122         }
123 
operator ushortAntmicro.Renode.Peripherals.CPU.RegisterValue124         public static implicit operator ushort(RegisterValue v)
125         {
126             if(v.ByteArrayValue != null)
127             {
128                 if(v.TryGetBytesForInt(2, out var bytes))
129                 {
130                     return BitConverter.ToUInt16(bytes, 0);
131                 }
132                 throw new InvalidCastException("Value is too big to be expressed as UInt16");
133             }
134 
135             if(v.Bits > 16 && v.RawValue > UInt16.MaxValue)
136             {
137                 throw new InvalidCastException("Value is too big to be expressed as UInt16");
138             }
139 
140             return (UInt16)v.RawValue;
141         }
142 
operator byteAntmicro.Renode.Peripherals.CPU.RegisterValue143         public static implicit operator byte(RegisterValue v)
144         {
145             if(v.ByteArrayValue != null)
146             {
147                 if(v.TryGetBytesForInt(1, out var bytes))
148                 {
149                     return bytes[0];
150                 }
151                 throw new InvalidCastException("Value is too big to be expressed as Byte");
152             }
153 
154             if(v.Bits > 8 && v.RawValue > Byte.MaxValue)
155             {
156                 throw new InvalidCastException("Value is too big to be expressed as Byte");
157             }
158 
159             return (Byte)v.RawValue;
160         }
161 
CreateAntmicro.Renode.Peripherals.CPU.RegisterValue162         public static RegisterValue Create(ulong rawValue, uint bits)
163         {
164             return new RegisterValue { RawValue = rawValue, ByteArrayValue = null, Bits = bits };
165         }
166 
TryGetBytesForIntAntmicro.Renode.Peripherals.CPU.RegisterValue167         private bool TryGetBytesForInt(int size, out byte[] bytes)
168         {
169             if(ByteArrayValue == null || ByteArrayValue.Skip(size).Any(b => b != 0))
170             {
171                 bytes = default(byte[]);
172                 return false;
173             }
174 
175             bytes = ByteArrayValue.Take(size).ToArray();
176             return true;
177         }
178     }
179 }
180