1 // 2 // Copyright (c) 2010-2024 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.Exceptions; 10 using Antmicro.Renode.Utilities; 11 12 namespace Antmicro.Renode.Core.Structure.Registers 13 { 14 public interface IRegisterField<T> 15 { 16 /// <summary> 17 /// Gets or sets the field's value. Access to this property does not invoke verification procedures in terms of FieldMode checking. 18 /// Also, it does not invoke callbacks. 19 /// </summary> 20 T Value { get; set; } 21 22 /// <summary> 23 /// Gets the field's width in bits. It should be used to verify if the value assigned to <cref="Value"> is valid, as exceeding 24 /// the field's limits causes an ArgumentException. 25 /// </summary> 26 int Width { get; } 27 28 Action<T, T> ReadCallback { get; set; } 29 Action<T, T> WriteCallback { get; set; } 30 Action<T, T> ChangeCallback { get; set; } 31 Func<T, T> ValueProviderCallback { get; set; } 32 } 33 34 public partial class PeripheralRegister 35 { 36 private sealed class ValueRegisterField : RegisterField<ulong>, IValueRegisterField 37 { ValueRegisterField(PeripheralRegister parent, int position, int width, FieldMode fieldMode, Action<ulong, ulong> readCallback, Action<ulong, ulong> writeCallback, Action<ulong, ulong> changeCallback, Func<ulong, ulong> valueProviderCallback, string name)38 public ValueRegisterField(PeripheralRegister parent, int position, int width, FieldMode fieldMode, Action<ulong, ulong> readCallback, 39 Action<ulong, ulong> writeCallback, Action<ulong, ulong> changeCallback, Func<ulong, ulong> valueProviderCallback, string name) 40 : base(parent, position, width, fieldMode, readCallback, writeCallback, changeCallback, valueProviderCallback, name) 41 { 42 } 43 FromBinary(ulong value)44 protected override ulong FromBinary(ulong value) 45 { 46 return value; 47 } 48 ToBinary(ulong value)49 protected override ulong ToBinary(ulong value) 50 { 51 return value; 52 } 53 } 54 55 private sealed class EnumRegisterField<TEnum> : RegisterField<TEnum>, IEnumRegisterField<TEnum> where TEnum : struct, IConvertible 56 { EnumRegisterField(PeripheralRegister parent, int position, int width, FieldMode fieldMode, Action<TEnum, TEnum> readCallback, Action<TEnum, TEnum> writeCallback, Action<TEnum, TEnum> changeCallback, Func<TEnum, TEnum> valueProviderCallback, string name)57 public EnumRegisterField(PeripheralRegister parent, int position, int width, FieldMode fieldMode, Action<TEnum, TEnum> readCallback, 58 Action<TEnum, TEnum> writeCallback, Action<TEnum, TEnum> changeCallback, Func<TEnum, TEnum> valueProviderCallback, string name) 59 : base(parent, position, width, fieldMode, readCallback, writeCallback, changeCallback, valueProviderCallback, name) 60 { 61 } 62 FromBinary(ulong value)63 protected override TEnum FromBinary(ulong value) 64 { 65 return EnumConverter<TEnum>.ToEnum(value); 66 } 67 ToBinary(TEnum value)68 protected override ulong ToBinary(TEnum value) 69 { 70 return EnumConverter<TEnum>.ToUInt64(value); 71 } 72 } 73 74 private sealed class FlagRegisterField : RegisterField<bool>, IFlagRegisterField 75 { FlagRegisterField(PeripheralRegister parent, int position, FieldMode fieldMode, Action<bool, bool> readCallback, Action<bool, bool> writeCallback, Action<bool, bool> changeCallback, Func<bool, bool> valueProviderCallback, string name)76 public FlagRegisterField(PeripheralRegister parent, int position, FieldMode fieldMode, Action<bool, bool> readCallback, 77 Action<bool, bool> writeCallback, Action<bool, bool> changeCallback, Func<bool, bool> valueProviderCallback, string name) 78 : base(parent, position, 1, fieldMode, readCallback, writeCallback, changeCallback, valueProviderCallback, name) 79 { 80 } 81 FromBinary(ulong value)82 protected override bool FromBinary(ulong value) 83 { 84 return value != 0; 85 } 86 ToBinary(bool value)87 protected override ulong ToBinary(bool value) 88 { 89 return value ? 1u : 0; 90 } 91 } 92 93 private abstract class RegisterField<T> : RegisterField, IRegisterField<T> 94 { 95 public T Value 96 { 97 get 98 { 99 return FromBinary(FilterValue(parent.UnderlyingValue)); 100 } 101 set 102 { 103 ulong binary = ToBinary(value); 104 if((binary >> width) > 0 && width < 64) 105 { 106 throw new ConstructionException("Value exceeds the size of the field."); 107 } 108 WriteFiltered(binary); 109 } 110 } 111 112 public int Width => width; 113 114 public Action<T, T> ReadCallback { get; set; } 115 public Action<T, T> WriteCallback { get; set; } 116 public Action<T, T> ChangeCallback { get; set; } 117 public Func<T, T> ValueProviderCallback { get; set; } 118 CallReadHandler(ulong oldValue, ulong newValue)119 public override void CallReadHandler(ulong oldValue, ulong newValue) 120 { 121 if(ReadCallback != null) 122 { 123 var oldValueFiltered = FilterValue(oldValue); 124 var newValueFiltered = FilterValue(newValue); 125 ReadCallback(FromBinary(oldValueFiltered), FromBinary(newValueFiltered)); 126 } 127 } 128 CallWriteHandler(ulong oldValue, ulong newValue)129 public override void CallWriteHandler(ulong oldValue, ulong newValue) 130 { 131 if(WriteCallback != null) 132 { 133 var oldValueFiltered = FilterValue(oldValue); 134 var newValueFiltered = FilterValue(newValue); 135 WriteCallback(FromBinary(oldValueFiltered), FromBinary(newValueFiltered)); 136 } 137 } 138 CallChangeHandler(ulong oldValue, ulong newValue)139 public override void CallChangeHandler(ulong oldValue, ulong newValue) 140 { 141 if(ChangeCallback != null) 142 { 143 var oldValueFiltered = FilterValue(oldValue); 144 var newValueFiltered = FilterValue(newValue); 145 ChangeCallback(FromBinary(oldValueFiltered), FromBinary(newValueFiltered)); 146 } 147 } 148 CallValueProviderHandler(ulong currentValue)149 public override ulong CallValueProviderHandler(ulong currentValue) 150 { 151 if(ValueProviderCallback != null) 152 { 153 var currentValueFiltered = FilterValue(currentValue); 154 return UnfilterValue(currentValue, ToBinary(ValueProviderCallback(FromBinary(currentValueFiltered)))); 155 } 156 return currentValue; 157 } 158 ToString()159 public override string ToString() 160 { 161 return $"[RegisterType<{typeof(T).Name}> Value={Value} Width={Width}]"; 162 } 163 RegisterField(PeripheralRegister parent, int position, int width, FieldMode fieldMode, Action<T, T> readCallback, Action<T, T> writeCallback, Action<T, T> changeCallback, Func<T, T> valueProviderCallback, string name)164 protected RegisterField(PeripheralRegister parent, int position, int width, FieldMode fieldMode, Action<T, T> readCallback, 165 Action<T, T> writeCallback, Action<T, T> changeCallback, Func<T, T> valueProviderCallback, string name) : base(parent, position, width, fieldMode, name) 166 { 167 if(!fieldMode.IsReadable() && valueProviderCallback != null) 168 { 169 throw new ConstructionException($"A write-only field cannot provide a value callback."); 170 } 171 172 ReadCallback = readCallback; 173 WriteCallback = writeCallback; 174 ChangeCallback = changeCallback; 175 ValueProviderCallback = valueProviderCallback; 176 } 177 FromBinary(ulong value)178 protected abstract T FromBinary(ulong value); 179 ToBinary(T value)180 protected abstract ulong ToBinary(T value); 181 } 182 183 private abstract class RegisterField 184 { CallReadHandler(ulong oldValue, ulong newValue)185 public abstract void CallReadHandler(ulong oldValue, ulong newValue); 186 CallWriteHandler(ulong oldValue, ulong newValue)187 public abstract void CallWriteHandler(ulong oldValue, ulong newValue); 188 CallChangeHandler(ulong oldValue, ulong newValue)189 public abstract void CallChangeHandler(ulong oldValue, ulong newValue); 190 CallValueProviderHandler(ulong currentValue)191 public abstract ulong CallValueProviderHandler(ulong currentValue); 192 193 public readonly int position; 194 public readonly int width; 195 public readonly string name; 196 public readonly FieldMode fieldMode; 197 RegisterField(PeripheralRegister parent, int position, int width, FieldMode fieldMode, string name)198 protected RegisterField(PeripheralRegister parent, int position, int width, FieldMode fieldMode, string name) 199 { 200 if(!fieldMode.IsValid()) 201 { 202 throw new ConstructionException("Invalid {0} flags for register field: {1}.".FormatWith(fieldMode.GetType().Name, fieldMode.ToString())); 203 } 204 this.parent = parent; 205 this.position = position; 206 this.fieldMode = fieldMode; 207 this.width = width; 208 this.name = name; 209 } 210 FilterValue(ulong value)211 protected ulong FilterValue(ulong value) 212 { 213 return BitHelper.GetValue(value, position, width); 214 } 215 UnfilterValue(ulong baseValue, ulong fieldValue)216 protected ulong UnfilterValue(ulong baseValue, ulong fieldValue) 217 { 218 BitHelper.UpdateWithShifted(ref baseValue, fieldValue, position, width); 219 return baseValue; 220 } 221 WriteFiltered(ulong value)222 protected void WriteFiltered(ulong value) 223 { 224 BitHelper.UpdateWithShifted(ref parent.UnderlyingValue, value, position, width); 225 } 226 227 protected readonly PeripheralRegister parent; 228 } 229 } 230 } 231