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 Antmicro.Renode.Peripherals.Bus; 10 using Antmicro.Renode.Peripherals; 11 using Antmicro.Renode.Utilities; 12 using Antmicro.Renode.Logging; 13 using System.Collections.Generic; 14 using Antmicro.Renode.Peripherals.CPU; 15 using Antmicro.Renode.Exceptions; 16 using Endianess = ELFSharp.ELF.Endianess; 17 18 namespace Antmicro.Renode.Peripherals.Memory 19 { 20 public class ArrayMemory : IMemory, ICanLoadFiles, IEndiannessAware 21 { ArrayMemory(byte[] source)22 public ArrayMemory(byte[] source) 23 { 24 array = source; 25 } 26 ArrayMemory(ulong size, byte initialValue = 0x00)27 public ArrayMemory(ulong size, byte initialValue = 0x00) 28 { 29 if(size > MaxSize) 30 { 31 throw new ConstructionException($"Memory size cannot be larger than 0x{MaxSize:X}, requested: 0x{size:X}"); 32 } 33 array = new byte[size]; 34 if(initialValue != 0x00) 35 { 36 Fill(initialValue); 37 } 38 } 39 ReadQuadWord(long offset)40 public virtual ulong ReadQuadWord(long offset) 41 { 42 if(!IsCorrectOffset(offset, sizeof(ulong))) 43 { 44 return 0; 45 } 46 var intOffset = (int)offset; 47 var result = BitConverter.ToUInt64(array, intOffset); 48 return result; 49 } 50 WriteQuadWord(long offset, ulong value)51 public virtual void WriteQuadWord(long offset, ulong value) 52 { 53 if(!IsCorrectOffset(offset, sizeof(ulong))) 54 { 55 return; 56 } 57 var bytes = BitConverter.GetBytes(value); 58 bytes.CopyTo(array, offset); 59 } 60 ReadDoubleWord(long offset)61 public uint ReadDoubleWord(long offset) 62 { 63 if(!IsCorrectOffset(offset, sizeof(uint))) 64 { 65 return 0; 66 } 67 var intOffset = (int)offset; 68 var result = BitConverter.ToUInt32(array, intOffset); 69 return result; 70 } 71 WriteDoubleWord(long offset, uint value)72 public virtual void WriteDoubleWord(long offset, uint value) 73 { 74 if(!IsCorrectOffset(offset, sizeof(uint))) 75 { 76 return; 77 } 78 var bytes = BitConverter.GetBytes(value); 79 bytes.CopyTo(array, offset); 80 } 81 Reset()82 public void Reset() 83 { 84 // nothing happens 85 } 86 ReadWord(long offset)87 public ushort ReadWord(long offset) 88 { 89 if(!IsCorrectOffset(offset, sizeof(ushort))) 90 { 91 return 0; 92 } 93 var intOffset = (int)offset; 94 var result = BitConverter.ToUInt16(array, intOffset); 95 return result; 96 } 97 WriteWord(long offset, ushort value)98 public virtual void WriteWord(long offset, ushort value) 99 { 100 if(!IsCorrectOffset(offset, sizeof(ushort))) 101 { 102 return; 103 } 104 var bytes = BitConverter.GetBytes(value); 105 bytes.CopyTo(array, offset); 106 } 107 ReadByte(long offset)108 public byte ReadByte(long offset) 109 { 110 if(!IsCorrectOffset(offset, sizeof(byte))) 111 { 112 return 0; 113 } 114 var intOffset = (int)offset; 115 var result = array[intOffset]; 116 return result; 117 } 118 WriteByte(long offset, byte value)119 public virtual void WriteByte(long offset, byte value) 120 { 121 if(!IsCorrectOffset(offset, sizeof(byte))) 122 { 123 return; 124 } 125 var intOffset = (int)offset; 126 array[intOffset] = value; 127 } 128 ReadBytes(long offset, int count, IPeripheral context = null)129 public byte[] ReadBytes(long offset, int count, IPeripheral context = null) 130 { 131 if(!IsCorrectOffset(offset, count)) 132 { 133 return new byte[count]; 134 } 135 var result = new byte[count]; 136 Array.Copy(array, offset, result, 0, count); 137 return result; 138 } 139 WriteBytes(long offset, byte[] bytes, int startingIndex, int count, IPeripheral context = null)140 public void WriteBytes(long offset, byte[] bytes, int startingIndex, int count, IPeripheral context = null) 141 { 142 if(!IsCorrectOffset(offset, count)) 143 { 144 return; 145 } 146 Array.Copy(bytes, startingIndex, array, offset, count); 147 } 148 LoadFileChunks(string path, IEnumerable<FileChunk> chunks, ICPU cpu)149 public void LoadFileChunks(string path, IEnumerable<FileChunk> chunks, ICPU cpu) 150 { 151 this.LoadFileChunks(chunks, cpu); 152 } 153 Fill(byte value)154 public void Fill(byte value) 155 { 156 array.Fill(value); 157 } 158 FillRegion(byte value, int startIndex, int count)159 public void FillRegion(byte value, int startIndex, int count) 160 { 161 array.Fill(value, startIndex, count); 162 } 163 164 public long Size 165 { 166 get 167 { 168 return array.Length; 169 } 170 } 171 172 // ArrayMemory matches the host endianness because host-endian BitConverter operations are used for 173 // accesses wider than a byte. 174 public Endianess Endianness => BitConverter.IsLittleEndian ? Endianess.LittleEndian : Endianess.BigEndian; 175 176 protected readonly byte[] array; 177 IsCorrectOffset(long offset, int size)178 private bool IsCorrectOffset(long offset, int size) 179 { 180 var result = offset >= 0 && offset <= array.Length - size; 181 if(!result) 182 { 183 this.Log(LogLevel.Error, "Tried to read {0} byte(s) at offset 0x{1:X} outside the range of the peripheral 0x0 - 0x{2:X}", size, offset, array.Length - 1); 184 } 185 return result; 186 } 187 188 // Objects bigger than 2GB are supported in .NET Framework with `gcAllowVeryLargeObjects` 189 // enabled and in .NET by default but there can be no more elements than that in a single 190 // dimension of an array. We could, e.g., double it by using more dimensions but generally 191 // ArrayMemory is mostly intended to be used for memory smaller than page size, which is 192 // required by MappedMemory, so this is much more than should be needed for ArrayMemory. 193 private const ulong MaxSize = 0x7FFFFFC7; 194 } 195 } 196