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