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