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