1 //
2 // Copyright (c) 2021 Antmicro
3 //
4 //  This file is licensed under the MIT License.
5 //  Full license text is available in 'licenses/MIT.txt'.
6 using System;
7 using System.Linq;
8 using Antmicro.Renode.Core;
9 using Antmicro.Renode.Debugging;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Utilities;
12 using Antmicro.Renode.Peripherals;
13 
14 namespace Antmicro.Renode.Peripherals.Utilities
15 {
16     public class ByteArrayWithAccessTracking
17     {
ByteArrayWithAccessTracking(IPeripheral parent, uint partsCount, uint accessByteWidth, string name)18         public ByteArrayWithAccessTracking(IPeripheral parent, uint partsCount, uint accessByteWidth, string name)
19         {
20             if(accessByteWidth != 4)
21             {
22                 throw new ArgumentException("Access widths other than 4 are not supported yet");
23             }
24             this.parent = parent;
25             this.name = name;
26             this.accessByteWidth = accessByteWidth;
27             this.partsCount = partsCount;
28             array = new byte[partsCount * accessByteWidth];
29             partAccessed = new StateTracker[partsCount];
30 
31             Reset();
32         }
33 
Reset()34         public void Reset()
35         {
36             ClearAccessTracking();
37             Array.Clear(array, 0, array.Length);
38         }
39 
SetPart(uint part, uint value)40         public void SetPart(uint part, uint value)
41         {
42             if(part >= partsCount)
43             {
44                 throw new ArgumentOutOfRangeException();
45             }
46 
47             if(AllDataWritten)
48             {
49                 // New cycle begins; old data is invalid now
50                 ClearAccessTracking();
51             }
52 
53             var offset = part * accessByteWidth;
54             var tempArray = BitConverter.GetBytes(value);
55 
56             for(var i = 0; i < accessByteWidth; i++)
57             {
58                 array[i + offset] = tempArray[i];
59             }
60 
61             partAccessed[part] = StateTracker.Written;
62         }
63 
GetPartAsDoubleWord(uint part)64         public uint GetPartAsDoubleWord(uint part)
65         {
66             if(part >= partsCount)
67             {
68                 throw new ArgumentOutOfRangeException();
69             }
70 
71             var value = BitHelper.ToUInt32(array, (int)(part * accessByteWidth), (int)accessByteWidth, true);
72             partAccessed[part] = StateTracker.Read;
73             return value;
74         }
75 
SetArrayTo(byte[] data, bool trackAccess = true)76         public void SetArrayTo(byte[] data, bool trackAccess = true)
77         {
78             if(data.Length != array.Length)
79             {
80                 throw new ArgumentException("Tried to write array with an incorrect data length");
81             }
82             array = data;
83 
84             if(trackAccess)
85             {
86                 SetAllAccessTrackingTo(StateTracker.Written);
87             }
88         }
89 
RetriveData(bool trackAccess = true)90         public byte[] RetriveData(bool trackAccess = true)
91         {
92             if(!AllDataWritten)
93             {
94                 parent.Log(LogLevel.Warning, "Trying to retrive registers '{0}' data before all of them have been written. Returning empty array", name);
95                 return new byte[0];
96             }
97 
98             if(trackAccess)
99             {
100                 SetAllAccessTrackingTo(StateTracker.Read);
101             }
102 
103             return array;
104         }
105 
106         public bool AllDataWritten => partAccessed.All(a => a == StateTracker.Written);
107 
108         public bool AllDataRead => partAccessed.All(a => a == StateTracker.Read);
109 
ClearAccessTracking()110         private void ClearAccessTracking()
111         {
112             Array.Clear(partAccessed, 0, partAccessed.Length);
113         }
114 
SetAllAccessTrackingTo(StateTracker state)115         private void SetAllAccessTrackingTo(StateTracker state)
116         {
117             for(var index = 0; index < partAccessed.Length; index++)
118             {
119                 partAccessed[index] = state;
120             }
121         }
122 
123         private byte[] array;
124         private readonly string name;
125         private readonly uint accessByteWidth;
126         private readonly uint partsCount;
127 
128         private readonly IPeripheral parent;
129         private readonly StateTracker[] partAccessed;
130 
131         private enum StateTracker
132         {
133             Untouched = 0,
134             Written = 1,
135             Read = 2,
136         }
137     }
138 }
139