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.Peripherals; 10 using System.Collections.Generic; 11 using Antmicro.Renode.Utilities; 12 using System.Linq; 13 using Antmicro.Renode.Logging; 14 15 namespace Antmicro.Renode.Core.Structure.Registers 16 { 17 /// <summary> 18 /// 64 bit <see cref="PeripheralRegister"/>. 19 /// </summary> 20 public sealed class QuadWordRegister : PeripheralRegister, IPeripheralRegister<ulong> 21 { 22 /// <summary> 23 /// Creates a register with one field, serving a purpose of read and write register. 24 /// </summary> 25 /// <returns>A new register.</returns> 26 /// <param name="resetValue">Reset value.</param> 27 /// <param name="name">Ignored parameter, for convenience. Treat it as a comment.</param> CreateRWRegister(ulong resetValue = 0, string name = null, bool softResettable = true)28 public static QuadWordRegister CreateRWRegister(ulong resetValue = 0, string name = null, bool softResettable = true) 29 { 30 //null because parent is used for logging purposes only - this will never happen in this case. 31 var register = new QuadWordRegister(null, resetValue, softResettable); 32 register.DefineValueField(0, register.RegisterWidth); 33 return register; 34 } 35 QuadWordRegister(IPeripheral parent, ulong resetValue = 0, bool softResettable = true)36 public QuadWordRegister(IPeripheral parent, ulong resetValue = 0, bool softResettable = true) : base(parent, resetValue, softResettable, QuadWordWidth) 37 { 38 } 39 40 /// <summary> 41 /// Retrieves the current value of readable fields. All FieldMode values are interpreted and callbacks are executed where applicable. 42 /// </summary> Read()43 public ulong Read() 44 { 45 return ReadInner(); 46 } 47 48 /// <summary> 49 /// Writes the given value to writeable fields. All FieldMode values are interpreted and callbacks are executed where applicable. 50 /// </summary> Write(long offset, ulong value)51 public void Write(long offset, ulong value) 52 { 53 WriteInner(offset, value); 54 } 55 56 /// <summary> 57 /// Defines the read callback that is called once on each read, regardles of the number of defined register fields. 58 /// Note that it will also be called for unreadable registers. 59 /// </summary> 60 /// <param name="readCallback">Method to be called whenever this register is read. The first parameter is the value of this register before read, 61 /// the second parameter is the value after read.</param> DefineReadCallback(Action<ulong, ulong> readCallback)62 public void DefineReadCallback(Action<ulong, ulong> readCallback) 63 { 64 readCallbacks.Add(readCallback); 65 } 66 67 /// <summary> 68 /// Defines the write callback that is called once on each write, regardles of the number of defined register fields. 69 /// Note that it will also be called for unwrittable registers. 70 /// </summary> 71 /// <param name="writeCallback">Method to be called whenever this register is written to. The first parameter is the value of this register before write, 72 /// the second parameter is the value written (without any modification).</param> DefineWriteCallback(Action<ulong, ulong> writeCallback)73 public void DefineWriteCallback(Action<ulong, ulong> writeCallback) 74 { 75 writeCallbacks.Add(writeCallback); 76 } 77 78 /// <summary> 79 /// Defines the change callback that is called once on each change, regardles of the number of defined register fields. 80 /// Note that it will also be called for unwrittable registers. 81 /// </summary> 82 /// <param name="changeCallback">Method to be called whenever this register's value is changed, either due to read or write. The first parameter is the value of this register before change, 83 /// the second parameter is the value after change.</param> DefineChangeCallback(Action<ulong, ulong> changeCallback)84 public void DefineChangeCallback(Action<ulong, ulong> changeCallback) 85 { 86 changeCallbacks.Add(changeCallback); 87 } 88 89 /// <summary> 90 /// Gets or sets the underlying value without any modification or reaction. 91 /// </summary> 92 public ulong Value 93 { 94 get 95 { 96 return UnderlyingValue; 97 } 98 set 99 { 100 UnderlyingValue = value; 101 } 102 } 103 104 public const int QuadWordWidth = 64; 105 CallChangeHandlers(ulong oldValue, ulong newValue)106 protected override void CallChangeHandlers(ulong oldValue, ulong newValue) 107 { 108 CallHandlers(changeCallbacks, oldValue, newValue); 109 } 110 CallReadHandlers(ulong oldValue, ulong newValue)111 protected override void CallReadHandlers(ulong oldValue, ulong newValue) 112 { 113 CallHandlers(readCallbacks, oldValue, newValue); 114 } 115 CallWriteHandlers(ulong oldValue, ulong newValue)116 protected override void CallWriteHandlers(ulong oldValue, ulong newValue) 117 { 118 CallHandlers(writeCallbacks, oldValue, newValue); 119 } 120 121 private List<Action<ulong, ulong>> readCallbacks = new List<Action<ulong, ulong>>(); 122 private List<Action<ulong, ulong>> writeCallbacks = new List<Action<ulong, ulong>>(); 123 private List<Action<ulong, ulong>> changeCallbacks = new List<Action<ulong, ulong>>(); 124 } 125 126 /// <summary> 127 /// 32 bit <see cref="PeripheralRegister"/>. 128 /// </summary> 129 public sealed class DoubleWordRegister : PeripheralRegister, IPeripheralRegister<uint> 130 { 131 /// <summary> 132 /// Creates a register with one field, serving a purpose of read and write register. 133 /// </summary> 134 /// <returns>A new register.</returns> 135 /// <param name="resetValue">Reset value.</param> 136 /// <param name="name">Ignored parameter, for convenience. Treat it as a comment.</param> CreateRWRegister(uint resetValue = 0, string name = null, bool softResettable = true)137 public static DoubleWordRegister CreateRWRegister(uint resetValue = 0, string name = null, bool softResettable = true) 138 { 139 //null because parent is used for logging purposes only - this will never happen in this case. 140 var register = new DoubleWordRegister(null, resetValue, softResettable); 141 register.DefineValueField(0, register.RegisterWidth); 142 return register; 143 } 144 DoubleWordRegister(IPeripheral parent, ulong resetValue = 0, bool softResettable = true)145 public DoubleWordRegister(IPeripheral parent, ulong resetValue = 0, bool softResettable = true) : base(parent, resetValue, softResettable, DoubleWordWidth) 146 { 147 } 148 149 /// <summary> 150 /// Retrieves the current value of readable fields. All FieldMode values are interpreted and callbacks are executed where applicable. 151 /// </summary> Read()152 public uint Read() 153 { 154 return (uint)ReadInner(); 155 } 156 157 /// <summary> 158 /// Writes the given value to writeable fields. All FieldMode values are interpreted and callbacks are executed where applicable. 159 /// </summary> Write(long offset, uint value)160 public void Write(long offset, uint value) 161 { 162 WriteInner(offset, value); 163 } 164 165 /// <summary> 166 /// Defines the read callback that is called once on each read, regardles of the number of defined register fields. 167 /// Note that it will also be called for unreadable registers. 168 /// </summary> 169 /// <param name="readCallback">Method to be called whenever this register is read. The first parameter is the value of this register before read, 170 /// the second parameter is the value after read.</param> DefineReadCallback(Action<uint, uint> readCallback)171 public void DefineReadCallback(Action<uint, uint> readCallback) 172 { 173 readCallbacks.Add(readCallback); 174 } 175 176 /// <summary> 177 /// Defines the write callback that is called once on each write, regardles of the number of defined register fields. 178 /// Note that it will also be called for unwrittable registers. 179 /// </summary> 180 /// <param name="writeCallback">Method to be called whenever this register is written to. The first parameter is the value of this register before write, 181 /// the second parameter is the value written (without any modification).</param> DefineWriteCallback(Action<uint, uint> writeCallback)182 public void DefineWriteCallback(Action<uint, uint> writeCallback) 183 { 184 writeCallbacks.Add(writeCallback); 185 } 186 187 /// <summary> 188 /// Defines the change callback that is called once on each change, regardles of the number of defined register fields. 189 /// Note that it will also be called for unwrittable registers. 190 /// </summary> 191 /// <param name="changeCallback">Method to be called whenever this register's value is changed, either due to read or write. The first parameter is the value of this register before change, 192 /// the second parameter is the value after change.</param> DefineChangeCallback(Action<uint, uint> changeCallback)193 public void DefineChangeCallback(Action<uint, uint> changeCallback) 194 { 195 changeCallbacks.Add(changeCallback); 196 } 197 198 /// <summary> 199 /// Gets or sets the underlying value without any modification or reaction. 200 /// </summary> 201 public uint Value 202 { 203 get 204 { 205 return (uint)UnderlyingValue; 206 } 207 set 208 { 209 UnderlyingValue = value; 210 } 211 } 212 213 public const int DoubleWordWidth = 32; 214 CallChangeHandlers(ulong oldValue, ulong newValue)215 protected override void CallChangeHandlers(ulong oldValue, ulong newValue) 216 { 217 CallHandlers(changeCallbacks, (uint)oldValue, (uint)newValue); 218 } 219 CallReadHandlers(ulong oldValue, ulong newValue)220 protected override void CallReadHandlers(ulong oldValue, ulong newValue) 221 { 222 CallHandlers(readCallbacks, (uint)oldValue, (uint)newValue); 223 } 224 CallWriteHandlers(ulong oldValue, ulong newValue)225 protected override void CallWriteHandlers(ulong oldValue, ulong newValue) 226 { 227 CallHandlers(writeCallbacks, (uint)oldValue, (uint)newValue); 228 } 229 230 private List<Action<uint, uint>> readCallbacks = new List<Action<uint, uint>>(); 231 private List<Action<uint, uint>> writeCallbacks = new List<Action<uint, uint>>(); 232 private List<Action<uint, uint>> changeCallbacks = new List<Action<uint, uint>>(); 233 } 234 235 /// <summary> 236 /// 16 bit <see cref="PeripheralRegister"/>. 237 /// </summary> 238 public sealed class WordRegister : PeripheralRegister, IPeripheralRegister<ushort> 239 { 240 /// <summary> 241 /// Creates a register with one field, serving a purpose of read and write register. 242 /// </summary> 243 /// <returns>A new register.</returns> 244 /// <param name="resetValue">Reset value.</param> 245 /// <param name="name">Ignored parameter, for convenience. Treat it as a comment.</param> CreateRWRegister(uint resetValue = 0, string name = null, bool softResettable = true)246 public static WordRegister CreateRWRegister(uint resetValue = 0, string name = null, bool softResettable = true) 247 { 248 //null because parent is used for logging purposes only - this will never happen in this case. 249 var register = new WordRegister(null, resetValue, softResettable); 250 register.DefineValueField(0, register.RegisterWidth); 251 return register; 252 } 253 WordRegister(IPeripheral parent, ulong resetValue = 0, bool softResettable = true)254 public WordRegister(IPeripheral parent, ulong resetValue = 0, bool softResettable = true) : base(parent, resetValue, softResettable, WordWidth) 255 { 256 } 257 258 /// <summary> 259 /// Retrieves the current value of readable fields. All FieldMode values are interpreted and callbacks are executed where applicable. 260 /// </summary> Read()261 public ushort Read() 262 { 263 return (ushort)ReadInner(); 264 } 265 266 /// <summary> 267 /// Writes the given value to writeable fields. All FieldMode values are interpreted and callbacks are executed where applicable. 268 /// </summary> Write(long offset, ushort value)269 public void Write(long offset, ushort value) 270 { 271 WriteInner(offset, value); 272 } 273 274 /// <summary> 275 /// Defines the read callback that is called once on each read, regardles of the number of defined register fields. 276 /// Note that it will also be called for unreadable registers. 277 /// </summary> 278 /// <param name="readCallback">Method to be called whenever this register is read. The first parameter is the value of this register before read, 279 /// the second parameter is the value after read.</param> DefineReadCallback(Action<ushort, ushort> readCallback)280 public void DefineReadCallback(Action<ushort, ushort> readCallback) 281 { 282 readCallbacks.Add(readCallback); 283 } 284 285 /// <summary> 286 /// Defines the write callback that is called once on each write, regardles of the number of defined register fields. 287 /// Note that it will also be called for unwrittable registers. 288 /// </summary> 289 /// <param name="writeCallback">Method to be called whenever this register is written to. The first parameter is the value of this register before write, 290 /// the second parameter is the value written (without any modification).</param> DefineWriteCallback(Action<ushort, ushort> writeCallback)291 public void DefineWriteCallback(Action<ushort, ushort> writeCallback) 292 { 293 writeCallbacks.Add(writeCallback); 294 } 295 296 /// <summary> 297 /// Defines the change callback that is called once on each change, regardles of the number of defined register fields. 298 /// Note that it will also be called for unwrittable registers. 299 /// </summary> 300 /// <param name="changeCallback">Method to be called whenever this register's value is changed, either due to read or write. The first parameter is the value of this register before change, 301 /// the second parameter is the value after change.</param> DefineChangeCallback(Action<ushort, ushort> changeCallback)302 public void DefineChangeCallback(Action<ushort, ushort> changeCallback) 303 { 304 changeCallbacks.Add(changeCallback); 305 } 306 307 /// <summary> 308 /// Gets or sets the underlying value without any modification or reaction. 309 /// </summary> 310 public ushort Value 311 { 312 get 313 { 314 return (ushort)UnderlyingValue; 315 } 316 set 317 { 318 UnderlyingValue = value; 319 } 320 } 321 322 public const int WordWidth = 16; 323 CallChangeHandlers(ulong oldValue, ulong newValue)324 protected override void CallChangeHandlers(ulong oldValue, ulong newValue) 325 { 326 CallHandlers(changeCallbacks, (ushort)oldValue, (ushort)newValue); 327 } 328 CallReadHandlers(ulong oldValue, ulong newValue)329 protected override void CallReadHandlers(ulong oldValue, ulong newValue) 330 { 331 CallHandlers(readCallbacks, (ushort)oldValue, (ushort)newValue); 332 } 333 CallWriteHandlers(ulong oldValue, ulong newValue)334 protected override void CallWriteHandlers(ulong oldValue, ulong newValue) 335 { 336 CallHandlers(writeCallbacks, (ushort)oldValue, (ushort)newValue); 337 } 338 339 private List<Action<ushort, ushort>> readCallbacks = new List<Action<ushort, ushort>>(); 340 private List<Action<ushort, ushort>> writeCallbacks = new List<Action<ushort, ushort>>(); 341 private List<Action<ushort, ushort>> changeCallbacks = new List<Action<ushort, ushort>>(); 342 } 343 344 /// <summary> 345 /// 8 bit <see cref="PeripheralRegister"/>. 346 /// </summary> 347 public sealed class ByteRegister : PeripheralRegister, IPeripheralRegister<byte> 348 { 349 /// <summary> 350 /// Creates a register with one field, serving a purpose of read and write register. 351 /// </summary> 352 /// <returns>A new register.</returns> 353 /// <param name="resetValue">Reset value.</param> 354 /// <param name="name">Ignored parameter, for convenience. Treat it as a comment.</param> CreateRWRegister(uint resetValue = 0, string name = null, bool softResettable = true)355 public static ByteRegister CreateRWRegister(uint resetValue = 0, string name = null, bool softResettable = true) 356 { 357 //null because parent is used for logging purposes only - this will never happen in this case. 358 var register = new ByteRegister(null, resetValue, softResettable); 359 register.DefineValueField(0, register.RegisterWidth); 360 return register; 361 } 362 ByteRegister(IPeripheral parent, ulong resetValue = 0, bool softResettable = true)363 public ByteRegister(IPeripheral parent, ulong resetValue = 0, bool softResettable = true) : base(parent, resetValue, softResettable, ByteWidth) 364 { 365 } 366 367 /// <summary> 368 /// Retrieves the current value of readable fields. All FieldMode values are interpreted and callbacks are executed where applicable. 369 /// </summary> Read()370 public byte Read() 371 { 372 return (byte)ReadInner(); 373 } 374 375 /// <summary> 376 /// Writes the given value to writeable fields. All FieldMode values are interpreted and callbacks are executed where applicable. 377 /// </summary> Write(long offset, byte value)378 public void Write(long offset, byte value) 379 { 380 WriteInner(offset, value); 381 } 382 383 /// <summary> 384 /// Defines the read callback that is called once on each read, regardles of the number of defined register fields. 385 /// Note that it will also be called for unreadable registers. 386 /// </summary> 387 /// <param name="readCallback">Method to be called whenever this register is read. The first parameter is the value of this register before read, 388 /// the second parameter is the value after read.</param> DefineReadCallback(Action<byte, byte> readCallback)389 public void DefineReadCallback(Action<byte, byte> readCallback) 390 { 391 readCallbacks.Add(readCallback); 392 } 393 394 /// <summary> 395 /// Defines the write callback that is called once on each write, regardles of the number of defined register fields. 396 /// Note that it will also be called for unwrittable registers. 397 /// </summary> 398 /// <param name="writeCallback">Method to be called whenever this register is written to. The first parameter is the value of this register before write, 399 /// the second parameter is the value written (without any modification).</param> DefineWriteCallback(Action<byte, byte> writeCallback)400 public void DefineWriteCallback(Action<byte, byte> writeCallback) 401 { 402 writeCallbacks.Add(writeCallback); 403 } 404 405 /// <summary> 406 /// Defines the change callback that is called once on each change, regardles of the number of defined register fields. 407 /// Note that it will also be called for unwrittable registers. 408 /// </summary> 409 /// <param name="changeCallback">Method to be called whenever this register's value is changed, either due to read or write. The first parameter is the value of this register before change, 410 /// the second parameter is the value after change.</param> DefineChangeCallback(Action<byte, byte> changeCallback)411 public void DefineChangeCallback(Action<byte, byte> changeCallback) 412 { 413 changeCallbacks.Add(changeCallback); 414 } 415 416 /// <summary> 417 /// Gets or sets the underlying value without any modification or reaction. 418 /// </summary> 419 public byte Value 420 { 421 get 422 { 423 return (byte)UnderlyingValue; 424 } 425 set 426 { 427 UnderlyingValue = value; 428 } 429 } 430 431 public const int ByteWidth = 8; 432 CallChangeHandlers(ulong oldValue, ulong newValue)433 protected override void CallChangeHandlers(ulong oldValue, ulong newValue) 434 { 435 CallHandlers(changeCallbacks, (byte)oldValue, (byte)newValue); 436 } 437 CallReadHandlers(ulong oldValue, ulong newValue)438 protected override void CallReadHandlers(ulong oldValue, ulong newValue) 439 { 440 CallHandlers(readCallbacks, (byte)oldValue, (byte)newValue); 441 } 442 CallWriteHandlers(ulong oldValue, ulong newValue)443 protected override void CallWriteHandlers(ulong oldValue, ulong newValue) 444 { 445 CallHandlers(writeCallbacks, (byte)oldValue, (byte)newValue); 446 } 447 448 private List<Action<byte, byte>> readCallbacks = new List<Action<byte, byte>>(); 449 private List<Action<byte, byte>> writeCallbacks = new List<Action<byte, byte>>(); 450 private List<Action<byte, byte>> changeCallbacks = new List<Action<byte, byte>>(); 451 452 } 453 454 public interface IPeripheralRegister<T> 455 { Read()456 T Read(); Write(long offset, T value)457 void Write(long offset, T value); Reset()458 void Reset(); 459 } 460 461 /// <summary> 462 /// Represents a register of a given width, containing defined fields. 463 /// Fields may not exceed this register's width, nor may they overlap each other. 464 /// Fields that are not handled (e.g. left for future implementation or unimportant) have to be tagged. 465 /// Otherwise, they will not be logged. 466 /// </summary> 467 public abstract partial class PeripheralRegister 468 { 469 /// <summary> 470 /// Restores this register's value to its reset value, defined on per-field basis. 471 /// </summary> Reset()472 public void Reset() 473 { 474 BitHelper.UpdateWithMasked(ref UnderlyingValue, resetValue, resettableMask); 475 } 476 477 /// <summary> 478 /// Wrapper for <see cref="Tag"/> method, tagging bits as "RESERVED". 479 /// </summary> 480 /// <param name="position">Offset in the register.</param> 481 /// <param name="width">Width of field.</param> 482 /// <param name="allowedValue">Value allowed to be written.<\param> Reserved(int position, int width, ulong? allowedValue = null)483 public void Reserved(int position, int width, ulong? allowedValue = null) 484 { 485 Tag("RESERVED", position, width, allowedValue); 486 } 487 488 /// <summary> 489 /// Mark an unhandled field, so it is logged with its name. 490 /// </summary> 491 /// <param name="name">Name of the unhandled field.</param> 492 /// <param name="position">Offset in the register.</param> 493 /// <param name="width">Width of field.</param> 494 /// <param name="allowedValue">Value allowed to be written.<\param> Tag(string name, int position, int width, ulong? allowedValue = null)495 public void Tag(string name, int position, int width, ulong? allowedValue = null) 496 { 497 ThrowIfRangeIllegal(position, width, name); 498 499 if(allowedValue != null) 500 { 501 ThrowIfAllowedValueDoesNotFitInWidth(width, allowedValue.Value, name); 502 } 503 504 tags.Add(new Tag 505 { 506 Name = name, 507 Position = position, 508 Width = width, 509 AllowedValue = allowedValue 510 }); 511 } 512 513 /// <summary> 514 /// Defines the flag field. Its width is always 1 and is interpreted as boolean value. 515 /// </summary> 516 /// <param name="position">Offset in the register.</param> 517 /// <param name="mode">Access modifiers of this field.</param> 518 /// <param name="readCallback">Method to be called whenever the containing register is read. The first parameter is the value of this field before read, 519 /// the second parameter is the value after read. Note that it will also be called for unreadable fields.</param> 520 /// <param name="writeCallback">Method to be called whenever the containing register is written to. The first parameter is the value of this field before write, 521 /// the second parameter is the value written (without any modification). Note that it will also be called for unwrittable fields.</param> 522 /// <param name="changeCallback">Method to be called whenever this field's value is changed, either due to read or write. The first parameter is the value of this field before change, 523 /// the second parameter is the value after change. Note that it will also be called for unwrittable fields.</param> 524 /// <param name="valueProviderCallback">Method to be called whenever this field is read. The value passed is the current field's value, that will be overwritten by 525 /// the value returned from it. This returned value is eventually passed as the first parameter of <paramref name="readCallback"/>.</param> 526 /// <param name="softResettable">Indicates whether the field should be cleared by soft reset.</param> 527 /// <param name="name">Ignored parameter, for convenience. Treat it as a comment.</param> DefineFlagField(int position, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<bool, bool> readCallback = null, Action<bool, bool> writeCallback = null, Action<bool, bool> changeCallback = null, Func<bool, bool> valueProviderCallback = null, bool softResettable = true, string name = null)528 public IFlagRegisterField DefineFlagField(int position, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<bool, bool> readCallback = null, 529 Action<bool, bool> writeCallback = null, Action<bool, bool> changeCallback = null, Func<bool, bool> valueProviderCallback = null, bool softResettable = true, 530 string name = null) 531 { 532 ThrowIfRangeIllegal(position, 1, name); 533 var field = new FlagRegisterField(this, position, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, name); 534 registerFields.Add(field); 535 if(!softResettable) 536 { 537 MarkNonResettable(position, 1); 538 } 539 RecalculateFieldMask(); 540 return field; 541 } 542 543 /// <summary> 544 /// Defines the value field. Its value is interpreted as a regular number. 545 /// </summary> 546 /// <param name="position">Offset in the register.</param> 547 /// <param name="width">Maximum width of the value, in terms of binary representation.</param> 548 /// <param name="mode">Access modifiers of this field.</param> 549 /// <param name="readCallback">Method to be called whenever the containing register is read. The first parameter is the value of this field before read, 550 /// the second parameter is the value after read. Note that it will also be called for unreadable fields.</param> 551 /// <param name="writeCallback">Method to be called whenever the containing register is written to. The first parameter is the value of this field before write, 552 /// the second parameter is the value written (without any modification). Note that it will also be called for unwrittable fields.</param> 553 /// <param name="changeCallback">Method to be called whenever this field's value is changed, either due to read or write. The first parameter is the value of this field before change, 554 /// the second parameter is the value after change. Note that it will also be called for unwrittable fields.</param> 555 /// <param name="valueProviderCallback">Method to be called whenever this field is read. The value passed is the current field's value, that will be overwritten by 556 /// the value returned from it. This returned value is eventually passed as the first parameter of <paramref name="readCallback"/>.</param> 557 /// <param name="softResettable">Indicates whether the field should be cleared by soft reset.</param> 558 /// <param name="name">Ignored parameter, for convenience. Treat it as a comment.</param> DefineValueField(int position, int width, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<ulong, ulong> readCallback = null, Action<ulong, ulong> writeCallback = null, Action<ulong, ulong> changeCallback = null, Func<ulong, ulong> valueProviderCallback = null, bool softResettable = true, string name = null)559 public IValueRegisterField DefineValueField(int position, int width, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<ulong, ulong> readCallback = null, 560 Action<ulong, ulong> writeCallback = null, Action<ulong, ulong> changeCallback = null, Func<ulong, ulong> valueProviderCallback = null, bool softResettable = true, 561 string name = null) 562 { 563 ThrowIfRangeIllegal(position, width, name); 564 ThrowIfZeroWidth(position, width, name); 565 var field = new ValueRegisterField(this, position, width, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, name); 566 registerFields.Add(field); 567 if(!softResettable) 568 { 569 MarkNonResettable(position, width); 570 } 571 RecalculateFieldMask(); 572 return field; 573 } 574 575 /// <summary> 576 /// Defines the enum field. Its value is interpreted as an enumeration 577 /// </summary> 578 /// <param name="position">Offset in the register.</param> 579 /// <param name="width">Maximum width of the value, in terms of binary representation.</param> 580 /// <param name="mode">Access modifiers of this field.</param> 581 /// <param name="readCallback">Method to be called whenever the containing register is read. The first parameter is the value of this field before read, 582 /// the second parameter is the value after read. Note that it will also be called for unreadable fields.</param> 583 /// <param name="writeCallback">Method to be called whenever the containing register is written to. The first parameter is the value of this field before write, 584 /// the second parameter is the value written (without any modification). Note that it will also be called for unwrittable fields.</param> 585 /// <param name="changeCallback">Method to be called whenever this field's value is changed, either due to read or write. The first parameter is the value of this field before change, 586 /// the second parameter is the value after change. Note that it will also be called for unwrittable fields.</param> 587 /// <param name="valueProviderCallback">Method to be called whenever this field is read. The value passed is the current field's value, that will be overwritten by 588 /// the value returned from it. This returned value is eventually passed as the first parameter of <paramref name="readCallback"/>.</param> 589 /// <param name="softResettable">Indicates whether the field should be cleared by soft reset.</param> 590 /// <param name="name">Ignored parameter, for convenience. Treat it as a comment.</param> 591 public IEnumRegisterField<TEnum> DefineEnumField<TEnum>(int position, int width, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<TEnum, TEnum> readCallback = null, 592 Action<TEnum, TEnum> writeCallback = null, Action<TEnum, TEnum> changeCallback = null, Func<TEnum, TEnum> valueProviderCallback = null, bool softResettable = true, 593 string name = null) 594 where TEnum : struct, IConvertible 595 { ThrowIfRangeIllegalAntmicro.Renode.Core.Structure.Registers.PeripheralRegister.IConvertible596 ThrowIfRangeIllegal(position, width, name); ThrowIfZeroWidthAntmicro.Renode.Core.Structure.Registers.PeripheralRegister.IConvertible597 ThrowIfZeroWidth(position, width, name); 598 var field = new EnumRegisterField<TEnum>(this, position, width, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, name); registerFields.AddAntmicro.Renode.Core.Structure.Registers.PeripheralRegister.IConvertible599 registerFields.Add(field); 600 if(!softResettable) 601 { 602 MarkNonResettable(position, width); 603 } RecalculateFieldMaskAntmicro.Renode.Core.Structure.Registers.PeripheralRegister.IConvertible604 RecalculateFieldMask(); 605 return field; 606 } 607 608 public int RegisterWidth { get; } 609 PeripheralRegister(IPeripheral parent, ulong resetValue, bool softResettable, int width)610 protected PeripheralRegister(IPeripheral parent, ulong resetValue, bool softResettable, int width) 611 { 612 this.parent = parent; 613 RegisterWidth = width; 614 this.resetValue = resetValue; 615 // We want to reset the register before setting the resettableMask. If we don't do that then 616 // the register will not be initialized to the resetValue, instead it will hold the default value of 0 617 Reset(); 618 if(!softResettable) 619 { 620 resettableMask = 0; 621 } 622 } 623 ReadInner()624 protected ulong ReadInner() 625 { 626 foreach(var registerField in registerFields) 627 { 628 UnderlyingValue = registerField.CallValueProviderHandler(UnderlyingValue); 629 } 630 var baseValue = UnderlyingValue; 631 var valueToRead = UnderlyingValue; 632 var changedFields = new List<RegisterField>(); 633 foreach(var registerField in registerFields) 634 { 635 if(!registerField.fieldMode.IsReadable()) 636 { 637 BitHelper.ClearBits(ref valueToRead, registerField.position, registerField.width); 638 } 639 640 if(registerField.fieldMode.IsFlagSet(FieldMode.ReadToClear) 641 && BitHelper.AreAnyBitsSet(UnderlyingValue, registerField.position, registerField.width)) 642 { 643 BitHelper.ClearBits(ref UnderlyingValue, registerField.position, registerField.width); 644 changedFields.Add(registerField); 645 } 646 if(registerField.fieldMode.IsFlagSet(FieldMode.ReadToSet) 647 && !BitHelper.AreAllBitsSet(UnderlyingValue, registerField.position, registerField.width)) 648 { 649 BitHelper.SetBits(ref UnderlyingValue, registerField.position, registerField.width); 650 changedFields.Add(registerField); 651 } 652 } 653 foreach(var registerField in registerFields) 654 { 655 registerField.CallReadHandler(baseValue, UnderlyingValue); 656 } 657 foreach(var changedRegister in changedFields.Distinct()) 658 { 659 changedRegister.CallChangeHandler(baseValue, UnderlyingValue); 660 } 661 662 CallReadHandlers(baseValue, UnderlyingValue); 663 if(changedFields.Any()) 664 { 665 CallChangeHandlers(baseValue, UnderlyingValue); 666 } 667 668 return valueToRead; 669 } 670 WriteInner(long offset, ulong value)671 protected void WriteInner(long offset, ulong value) 672 { 673 var baseValue = UnderlyingValue; 674 var difference = UnderlyingValue ^ value; 675 var changedRegisters = new List<RegisterField>(); 676 foreach(var registerField in registerFields) 677 { 678 //switch is OK, because write modes are exclusive. 679 switch(registerField.fieldMode.WriteBits()) 680 { 681 case FieldMode.Write: 682 if(BitHelper.AreAnyBitsSet(difference, registerField.position, registerField.width)) 683 { 684 BitHelper.UpdateWith(ref UnderlyingValue, value, registerField.position, registerField.width); 685 changedRegisters.Add(registerField); 686 } 687 break; 688 case FieldMode.Set: 689 var setRegisters = value & (~UnderlyingValue); 690 if(BitHelper.AreAnyBitsSet(setRegisters, registerField.position, registerField.width)) 691 { 692 BitHelper.OrWith(ref UnderlyingValue, setRegisters, registerField.position, registerField.width); 693 changedRegisters.Add(registerField); 694 } 695 break; 696 case FieldMode.Toggle: 697 if(BitHelper.AreAnyBitsSet(value, registerField.position, registerField.width)) 698 { 699 BitHelper.XorWith(ref UnderlyingValue, value, registerField.position, registerField.width); 700 changedRegisters.Add(registerField); 701 } 702 break; 703 case FieldMode.WriteOneToClear: 704 if(BitHelper.AreAnyBitsSet((~difference & value), registerField.position, registerField.width)) 705 { 706 BitHelper.AndWithNot(ref UnderlyingValue, value, registerField.position, registerField.width); 707 changedRegisters.Add(registerField); 708 } 709 break; 710 case FieldMode.WriteZeroToClear: 711 if(BitHelper.AreAnyBitsSet((difference & UnderlyingValue), registerField.position, registerField.width)) 712 { 713 BitHelper.AndWithNot(ref UnderlyingValue, ~value, registerField.position, registerField.width); 714 changedRegisters.Add(registerField); 715 } 716 break; 717 case FieldMode.WriteZeroToSet: 718 var negSetRegisters = ~value & (~UnderlyingValue); 719 if(BitHelper.AreAnyBitsSet(negSetRegisters, registerField.position, registerField.width)) 720 { 721 BitHelper.OrWith(ref UnderlyingValue, negSetRegisters, registerField.position, registerField.width); 722 changedRegisters.Add(registerField); 723 } 724 break; 725 case FieldMode.WriteZeroToToggle: 726 if(BitHelper.AreAnyBitsSet(~value, registerField.position, registerField.width)) 727 { 728 BitHelper.XorWith(ref UnderlyingValue, ~value, registerField.position, registerField.width); 729 changedRegisters.Add(registerField); 730 } 731 break; 732 case FieldMode.WriteToClear: 733 if(BitHelper.AreAnyBitsSet(UnderlyingValue, registerField.position, registerField.width)) 734 { 735 BitHelper.ClearBits(ref UnderlyingValue, registerField.position, registerField.width); 736 changedRegisters.Add(registerField); 737 } 738 break; 739 } 740 } 741 foreach(var registerField in registerFields) 742 { 743 registerField.CallWriteHandler(baseValue, value); 744 } 745 foreach(var changedRegister in changedRegisters.Distinct()) 746 { 747 changedRegister.CallChangeHandler(baseValue, UnderlyingValue); 748 } 749 750 CallWriteHandlers(baseValue, value); 751 if(changedRegisters.Any()) 752 { 753 CallChangeHandlers(baseValue, UnderlyingValue); 754 } 755 756 var unhandledWrites = difference & ~definedFieldsMask; 757 if(unhandledWrites != 0) 758 { 759 parent.Log(LogLevel.Warning, TagLogger(offset, unhandledWrites, value)); 760 } 761 762 if(InvalidTagValues(offset, value, out var invalidValueLog)) 763 { 764 parent.Log(LogLevel.Error, invalidValueLog); 765 } 766 } 767 CallHandlers(List<Action<T, T>> handlers, T oldValue, T newValue)768 protected void CallHandlers<T>(List<Action<T, T>> handlers, T oldValue, T newValue) 769 { 770 foreach(var handler in handlers) 771 { 772 handler(oldValue, newValue); 773 } 774 } 775 CallWriteHandlers(ulong oldValue, ulong newValue)776 protected abstract void CallWriteHandlers(ulong oldValue, ulong newValue); CallReadHandlers(ulong oldValue, ulong newValue)777 protected abstract void CallReadHandlers(ulong oldValue, ulong newValue); CallChangeHandlers(ulong oldValue, ulong newValue)778 protected abstract void CallChangeHandlers(ulong oldValue, ulong newValue); 779 780 781 protected ulong UnderlyingValue; 782 783 /// <summary> 784 /// Returns information about tag writes. Extracted as a method to allow future lazy evaluation. 785 /// </summary> 786 /// <param name="offset">The offset of the affected register.</param> 787 /// <param name="unhandledMask">Unhandled bits mask.</param> 788 /// <param name="originalValue">The whole value written to the register.</param> TagLogger(long offset, ulong unhandledMask, ulong originalValue)789 private string TagLogger(long offset, ulong unhandledMask, ulong originalValue) 790 { 791 var tagsAffected = tags.Where(x => BitHelper.AreAnyBitsSet(unhandledMask, x.Position, x.Width)) 792 .Select(x => new { x.Name, Value = BitHelper.GetValue(originalValue, x.Position, x.Width) }); 793 return "Unhandled write to offset 0x{2:X}. Unhandled bits: [{1}] when writing value 0x{3:X}.{0}" 794 .FormatWith(tagsAffected.Any() ? " Tags: {0}.".FormatWith( 795 tagsAffected.Select(x => "{0} (0x{1:X})".FormatWith(x.Name, x.Value)).Stringify(", ")) : String.Empty, 796 BitHelper.GetSetBitsPretty(unhandledMask), 797 offset, 798 originalValue); 799 } 800 InvalidTagValues(long offset, ulong originalValue, out string log)801 private bool InvalidTagValues(long offset, ulong originalValue, out string log) 802 { 803 ulong allowedValuesMask = 0; 804 ulong allowedValues = 0; 805 806 foreach(var tag in tags.Where(x => x.AllowedValue != null)) 807 { 808 allowedValuesMask |= BitHelper.CalculateQuadWordMask(tag.Width, tag.Position); 809 allowedValues |= tag.AllowedValue.Value << tag.Position; 810 } 811 812 var invalidBits = (allowedValues ^ originalValue) & allowedValuesMask; 813 if(invalidBits == 0) 814 { 815 log = ""; 816 return false; 817 } 818 819 var writtenValue = "0b" + Convert.ToString((long)originalValue, 2).PadLeft(RegisterWidth, '0'); 820 var desiredValues = "0b"; 821 822 for(int i = RegisterWidth - 1; i >= 0; i--) 823 { 824 if(((allowedValuesMask >> i) & 1u) == 1) 825 { 826 desiredValues += ((allowedValues >> i) & 1) == 0 ? "0" : "1"; 827 } 828 else 829 { 830 desiredValues += "x"; 831 } 832 } 833 log = $"Invalid value written to offset 0x{offset:X} reserved bits. Allowed values = {desiredValues}, Value written = {writtenValue}"; 834 return true; 835 } 836 837 ThrowIfRangeIllegal(int position, int width, string name)838 private void ThrowIfRangeIllegal(int position, int width, string name) 839 { 840 if(width < 0) 841 { 842 throw new ArgumentException("Field {0} has to have a size larger than or equal to 0.".FormatWith(name ?? "at {0} of {1} bits".FormatWith(position, width))); 843 } 844 if(position + width > RegisterWidth) 845 { 846 throw new ArgumentException("Field {0} does not fit in the register size.".FormatWith(name ?? "at {0} of {1} bits".FormatWith(position, width))); 847 } 848 foreach(var field in registerFields.Select(x => new { x.position, x.width }).Concat(tags.Select(x => new { position = x.Position, width = x.Width }))) 849 { 850 var minEnd = Math.Min(position + width, field.position + field.width); 851 var maxStart = Math.Max(position, field.position); 852 if(minEnd > maxStart) 853 { 854 throw new ArgumentException("Field {0} intersects with another range.".FormatWith(name ?? "at {0} of {1} bits".FormatWith(position, width))); 855 } 856 } 857 } 858 ThrowIfZeroWidth(int position, int width, string name)859 private void ThrowIfZeroWidth(int position, int width, string name) 860 { 861 if(width == 0) 862 { 863 throw new ArgumentException("Field {0} has to have a size not equal to 0.".FormatWith(name ?? "at {0} of {1} bits".FormatWith(position, width))); 864 } 865 } 866 ThrowIfAllowedValueDoesNotFitInWidth(int width, ulong allowedValue, string name)867 private void ThrowIfAllowedValueDoesNotFitInWidth(int width, ulong allowedValue, string name) 868 { 869 if((allowedValue >> width) != 0) 870 { 871 throw new ArgumentException($"Fields {name} allowedValue does not fit in its width"); 872 } 873 } 874 RecalculateFieldMask()875 private void RecalculateFieldMask() 876 { 877 var mask = 0UL; 878 foreach(var field in registerFields) 879 { 880 mask |= BitHelper.CalculateQuadWordMask(field.width, field.position); 881 } 882 definedFieldsMask = mask; 883 } 884 MarkNonResettable(int position, int width)885 private void MarkNonResettable(int position, int width) 886 { 887 BitHelper.ClearBits(ref resettableMask, position, width); 888 } 889 890 private List<RegisterField> registerFields = new List<RegisterField>(); 891 892 private List<Tag> tags = new List<Tag>(); 893 894 private IPeripheral parent; 895 896 private ulong definedFieldsMask; 897 898 private ulong resettableMask = ulong.MaxValue; 899 private readonly ulong resetValue; 900 } 901 } 902