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 NUnit.Framework; 10 using Antmicro.Renode.Core.Structure.Registers; 11 using System.Collections.Generic; 12 using Antmicro.Renode.Exceptions; 13 using Antmicro.Renode.Utilities; 14 15 namespace Antmicro.Renode.UnitTests 16 { 17 [TestFixture] 18 public class RegistersTests 19 { 20 [Test] ShouldNotAcceptOutOfBoundsValues()21 public void ShouldNotAcceptOutOfBoundsValues() 22 { 23 Assert.Catch<ConstructionException>(() => enumRWField.Value = (TwoBitEnum)(1 << 2)); 24 Assert.Catch<ConstructionException>(() => valueRWField.Value = (1 << 4)); 25 } 26 27 [Test] ShouldNotAcceptNegativeFields()28 public void ShouldNotAcceptNegativeFields() 29 { 30 var localRegister = new DoubleWordRegister(null); 31 Assert.Catch<ArgumentException>(() => localRegister.DefineEnumField<TwoBitEnum>(0, -1)); 32 Assert.Catch<ArgumentException>(() => localRegister.DefineValueField(0, -1)); 33 } 34 35 [Test] ShouldNotExceedRegisterSize()36 public void ShouldNotExceedRegisterSize() 37 { 38 var registersAndPositions = new Dictionary<PeripheralRegister, int> 39 { 40 { new QuadWordRegister(null), 63 }, 41 { new DoubleWordRegister(null), 31 }, 42 { new WordRegister(null), 15 }, 43 { new ByteRegister(null), 7 } 44 }; 45 foreach(var registerAndPosition in registersAndPositions) 46 { 47 var localRegister = registerAndPosition.Key; 48 Assert.Catch<ArgumentException>(() => localRegister.DefineEnumField<TwoBitEnum>(registerAndPosition.Value, 2)); 49 } 50 } 51 52 [Test] ShouldNotAllowIntersectingFields()53 public void ShouldNotAllowIntersectingFields() 54 { 55 var localRegister = new QuadWordRegister(null); 56 localRegister.DefineValueField(1, 5); 57 Assert.Catch<ArgumentException>(() => localRegister.DefineValueField(0, 2)); 58 } 59 60 [Test] ShouldWriteFieldsWithMaxLength()61 public void ShouldWriteFieldsWithMaxLength() 62 { 63 var localRegister = new DoubleWordRegister(null); 64 localRegister.DefineValueField(0, 32); 65 localRegister.Write(0, uint.MaxValue); 66 Assert.AreEqual(uint.MaxValue, localRegister.Read()); 67 } 68 69 [Test] ShouldReadBoolField()70 public void ShouldReadBoolField() 71 { 72 register.Write(0, 1 << 2); 73 Assert.AreEqual(true, flagRWField.Value); 74 } 75 76 [Test] ShouldReadEnumField()77 public void ShouldReadEnumField() 78 { 79 register.Write(0, 3); 80 Assert.AreEqual(TwoBitEnum.D, enumRWField.Value); 81 } 82 83 [Test] ShouldRead64BitWideEnum()84 public void ShouldRead64BitWideEnum() 85 { 86 var localRegister = new QuadWordRegister(null); 87 var localEnumField = localRegister.DefineEnumField<SixtyFourBitEnum>(0, 64); 88 89 localRegister.Write(0, ulong.MaxValue); 90 Assert.AreEqual(SixtyFourBitEnum.B, localEnumField.Value); 91 } 92 93 [Test] ShouldReadValueField()94 public void ShouldReadValueField() 95 { 96 register.Write(0, 88); //1011000 97 Assert.AreEqual(11, valueRWField.Value); //1011 98 } 99 100 [Test] ShouldWriteBoolField()101 public void ShouldWriteBoolField() 102 { 103 flagRWField.Value = true; 104 Assert.AreEqual(1 << 2 | RegisterResetValue, register.Read()); 105 } 106 107 [Test] ShouldWriteEnumField()108 public void ShouldWriteEnumField() 109 { 110 enumRWField.Value = TwoBitEnum.D; 111 Assert.AreEqual((uint)TwoBitEnum.D | RegisterResetValue, register.Read()); 112 } 113 114 [Test] ShouldWrite64BitWideEnum()115 public void ShouldWrite64BitWideEnum() 116 { 117 var localRegister = new QuadWordRegister(null); 118 var localEnumField = localRegister.DefineEnumField<SixtyFourBitEnum>(0, 64); 119 120 localEnumField.Value = SixtyFourBitEnum.A; 121 Assert.AreEqual((ulong)SixtyFourBitEnum.A, localRegister.Read()); 122 } 123 124 [Test] ShouldWriteValueField()125 public void ShouldWriteValueField() 126 { 127 valueRWField.Value = 11; 128 Assert.AreEqual(88 | RegisterResetValue, register.Read()); 129 } 130 131 [Test] ShouldResetComplexRegister()132 public void ShouldResetComplexRegister() 133 { 134 register.Reset(); 135 Assert.AreEqual(0x3780, register.Read()); 136 } 137 138 [Test] ShouldNotWriteUnwritableField()139 public void ShouldNotWriteUnwritableField() 140 { 141 register.Write(0, 1 << 21); 142 Assert.AreEqual(false, flagRField.Value); 143 } 144 145 [Test] ShouldNotReadUnreadableField()146 public void ShouldNotReadUnreadableField() 147 { 148 flagWField.Value = true; 149 Assert.AreEqual(RegisterResetValue, register.Read()); 150 } 151 152 [Test] ShouldWriteZeroToClear()153 public void ShouldWriteZeroToClear() 154 { 155 flagW0CField.Value = true; 156 Assert.AreEqual(1 << 18 | RegisterResetValue, register.Read()); 157 register.Write(0, 0); 158 Assert.AreEqual(false, flagW0CField.Value); 159 Assert.AreEqual(0, register.Read() & readMask); 160 } 161 162 [Test] ShouldWriteOneToClear()163 public void ShouldWriteOneToClear() 164 { 165 flagW1CField.Value = true; 166 Assert.AreEqual(1 << 17 | RegisterResetValue, register.Read() & readMask); 167 register.Write(0, 1 << 17); 168 Assert.AreEqual(false, flagW0CField.Value); 169 Assert.AreEqual(0, register.Read() & readMask); 170 } 171 172 [Test] ShouldWriteToClear()173 public void ShouldWriteToClear() 174 { 175 flagWTCField.Value = true; 176 Assert.AreEqual(1u << 31 | RegisterResetValue, register.Read()); 177 register.Write(0, 1u << 31); 178 Assert.IsFalse(flagWTCField.Value); 179 180 flagWTCField.Value = true; 181 register.Write(0, 0); 182 Assert.IsFalse(flagWTCField.Value); 183 } 184 185 [Test] ShouldReadToClear()186 public void ShouldReadToClear() 187 { 188 flagWRTCField.Value = true; 189 Assert.AreEqual(1 << 19 | RegisterResetValue, register.Read()); 190 Assert.AreEqual(false, flagWRTCField.Value); 191 } 192 193 [Test] ShouldWriteZeroToSet()194 public void ShouldWriteZeroToSet() 195 { 196 flagWZTSField.Value = false; 197 198 register.Write(0, 1 << 0x1c); 199 Assert.IsFalse(flagWZTSField.Value); 200 201 register.Write(0, 0); 202 Assert.IsTrue(flagWZTSField.Value); 203 204 register.Write(0, 0); 205 Assert.IsTrue(flagWZTSField.Value); 206 207 register.Write(0, 1 << 0x1c); 208 Assert.IsTrue(flagWZTSField.Value); 209 } 210 211 [Test] ShouldWriteZeroToToggle()212 public void ShouldWriteZeroToToggle() 213 { 214 flagWZTTField.Value = false; 215 216 register.Write(0, 1 << 0x1d); 217 Assert.IsFalse(flagWZTTField.Value); 218 219 register.Write(0, 0); 220 Assert.IsTrue(flagWZTTField.Value); 221 222 register.Write(0, 1 << 0x1d); 223 Assert.IsTrue(flagWZTTField.Value); 224 225 register.Write(0, 0); 226 Assert.IsFalse(flagWZTTField.Value); 227 } 228 229 [Test] ShouldReadToSet()230 public void ShouldReadToSet() 231 { 232 flagRTSField.Value = false; 233 Assert.AreEqual(~(1UL << 0x1e) & RegisterResetValue, register.Read()); 234 Assert.IsTrue(flagRTSField.Value); 235 } 236 237 [Test] ShouldCallReadHandler()238 public void ShouldCallReadHandler() 239 { 240 //for the sake of sanity 241 Assert.AreEqual(0, enumCallbacks); 242 Assert.AreEqual(0, boolCallbacks); 243 Assert.AreEqual(0, numberCallbacks); 244 register.Read(); 245 Assert.AreEqual(1, enumCallbacks); 246 Assert.AreEqual(1, boolCallbacks); 247 Assert.AreEqual(1, numberCallbacks); 248 249 Assert.IsTrue(oldBoolValue == newBoolValue); 250 Assert.IsTrue(oldEnumValue == newEnumValue); 251 Assert.IsTrue(oldNumberValue == newNumberValue); 252 } 253 254 [Test] ShouldRetrieveValueFromHandler()255 public void ShouldRetrieveValueFromHandler() 256 { 257 enableValueProviders = true; 258 register.Write(0, 3 << 0x16 | 1 << 0x19); 259 Assert.AreEqual(4 << 0x16 | 1 << 0x1A, register.Read()); 260 } 261 262 [Test] ShouldCallWriteAndChangeHandler()263 public void ShouldCallWriteAndChangeHandler() 264 { 265 Assert.AreEqual(0, enumCallbacks); 266 Assert.AreEqual(0, boolCallbacks); 267 Assert.AreEqual(0, numberCallbacks); 268 register.Write(0, 0x2A80); 269 //Two calls for changed registers, 1 call for unchanged register 270 Assert.AreEqual(2, enumCallbacks); 271 Assert.AreEqual(1, boolCallbacks); 272 Assert.AreEqual(2, numberCallbacks); 273 274 Assert.IsTrue(oldBoolValue == newBoolValue); 275 Assert.IsTrue(oldEnumValue == TwoBitEnum.D && newEnumValue == TwoBitEnum.B); 276 Assert.IsTrue(oldNumberValue == 13); 277 Assert.IsTrue(newNumberValue == 10); 278 } 279 280 [Test] ShouldCallGlobalReadHandler()281 public void ShouldCallGlobalReadHandler() 282 { 283 flagRTSField.Value = true; // prevent change callback from being fired 284 Assert.AreEqual(0, globalCallbacks); 285 register.Read(); 286 Assert.AreEqual(1, globalCallbacks); 287 Assert.AreEqual(RegisterResetValue & readMask, oldGlobalValue & readMask); 288 Assert.AreEqual(RegisterResetValue & readMask, newGlobalValue & readMask); 289 } 290 291 [Test] ShouldCallGlobalWriteAndChangeHandler()292 public void ShouldCallGlobalWriteAndChangeHandler() 293 { 294 register.Reset(); 295 Assert.AreEqual(0, globalCallbacks); 296 register.Write(0, 0x2A80 & writeMask); 297 //1 for write, 1 for change 298 Assert.AreEqual(2, globalCallbacks); 299 300 Assert.AreEqual(RegisterResetValue, oldGlobalValue); 301 Assert.AreEqual(0x2A80 & writeMask, newGlobalValue & writeMask); 302 } 303 304 [Test] ShouldWorkWithUndefinedEnumValue()305 public void ShouldWorkWithUndefinedEnumValue() 306 { 307 register.Write(0, 2); 308 Assert.AreEqual((TwoBitEnum)2, enumRWField.Value); 309 } 310 311 [Test] ShouldToggleField()312 public void ShouldToggleField() 313 { 314 register.Write(0, 1 << 15); 315 Assert.AreEqual(true, flagTRField.Value); 316 register.Write(0, 1 << 15); 317 Assert.AreEqual(false, flagTRField.Value); 318 register.Write(0, 1 << 15); 319 Assert.AreEqual(true, flagTRField.Value); 320 } 321 322 [Test] ShouldSetField()323 public void ShouldSetField() 324 { 325 register.Write(0, 1 << 16); 326 Assert.AreEqual(true, flagSRField.Value); 327 register.Write(0, 0); 328 Assert.AreEqual(true, flagSRField.Value); 329 } 330 331 [Test] ShouldHandle64BitWideRegistersProperly()332 public void ShouldHandle64BitWideRegistersProperly() 333 { 334 ulong test = 0; 335 new QuadWordRegister(null, 0).WithValueField(0, 64, writeCallback: (oldValue, newValue) => test = newValue).Write(0x0, 0xDEADBEEF01234567UL); 336 Assert.AreEqual(0xDEADBEEF01234567UL, test); 337 } 338 339 [Test] ShouldHandle32BitWideRegistersProperly()340 public void ShouldHandle32BitWideRegistersProperly() 341 { 342 uint test = 0; 343 new DoubleWordRegister(null, 0).WithValueField(0, 32, writeCallback: (oldValue, newValue) => test = (uint)newValue).Write(0x0, 0xDEADBEEF); 344 Assert.AreEqual(0xDEADBEEF, test); 345 } 346 347 [SetUp] SetUp()348 public void SetUp() 349 { 350 register = new QuadWordRegister(null, RegisterResetValue); 351 enumRWField = register.DefineEnumField<TwoBitEnum>(0, 2); 352 flagRWField = register.DefineFlagField(2); 353 valueRWField = register.DefineValueField(3, 4); 354 register.DefineEnumField<TwoBitEnum>(7, 2, readCallback: EnumCallback, writeCallback: EnumCallback, changeCallback: EnumCallback); 355 register.DefineFlagField(9, readCallback: BoolCallback, writeCallback: BoolCallback, changeCallback: BoolCallback); 356 register.DefineValueField(10, 4, readCallback: NumberCallback, writeCallback: NumberCallback, changeCallback: NumberCallback); 357 flagTRField = register.DefineFlagField(15, FieldMode.Read | FieldMode.Toggle); 358 flagSRField = register.DefineFlagField(16, FieldMode.Read | FieldMode.Set); 359 flagW1CField = register.DefineFlagField(17, FieldMode.Read | FieldMode.WriteOneToClear); 360 flagW0CField = register.DefineFlagField(18, FieldMode.Read | FieldMode.WriteZeroToClear); 361 flagWRTCField = register.DefineFlagField(19, FieldMode.ReadToClear | FieldMode.Write); 362 flagWField = register.DefineFlagField(20, FieldMode.Write); 363 flagRField = register.DefineFlagField(21, FieldMode.Read); 364 register.DefineValueField(22, 3, valueProviderCallback: ModifyingValueCallback); 365 register.DefineFlagField(25, valueProviderCallback: ModifyingFlagCallback); 366 register.DefineEnumField<TwoBitEnum>(26, 2, valueProviderCallback: ModifyingEnumCallback); 367 flagWZTSField = register.DefineFlagField(28, FieldMode.WriteZeroToSet); 368 flagWZTTField = register.DefineFlagField(29, FieldMode.WriteZeroToToggle); 369 flagRTSField = register.DefineFlagField(30, FieldMode.ReadToSet); 370 flagWTCField = register.DefineFlagField(31, FieldMode.Read | FieldMode.WriteToClear); 371 372 register.WithReadCallback(GlobalCallback).WithWriteCallback(GlobalCallback).WithChangeCallback(GlobalCallback); 373 374 enableValueProviders = false; 375 376 enumCallbacks = 0; 377 boolCallbacks = 0; 378 numberCallbacks = 0; 379 globalCallbacks = 0; 380 oldBoolValue = false; 381 newBoolValue = false; 382 oldEnumValue = TwoBitEnum.A; 383 newEnumValue = TwoBitEnum.A; 384 oldNumberValue = 0; 385 newNumberValue = 0; 386 oldGlobalValue = 0; 387 newGlobalValue = 0; 388 } 389 GlobalCallback(ulong oldValue, ulong newValue)390 private void GlobalCallback(ulong oldValue, ulong newValue) 391 { 392 globalCallbacks++; 393 oldGlobalValue = oldValue; 394 newGlobalValue = newValue; 395 } 396 EnumCallback(TwoBitEnum oldValue, TwoBitEnum newValue)397 private void EnumCallback(TwoBitEnum oldValue, TwoBitEnum newValue) 398 { 399 enumCallbacks++; 400 oldEnumValue = oldValue; 401 newEnumValue = newValue; 402 } 403 BoolCallback(bool oldValue, bool newValue)404 private void BoolCallback(bool oldValue, bool newValue) 405 { 406 boolCallbacks++; 407 oldBoolValue = oldValue; 408 newBoolValue = newValue; 409 } 410 NumberCallback(ulong oldValue, ulong newValue)411 private void NumberCallback(ulong oldValue, ulong newValue) 412 { 413 numberCallbacks++; 414 oldNumberValue = oldValue; 415 newNumberValue = newValue; 416 } 417 ModifyingValueCallback(ulong currentValue)418 private ulong ModifyingValueCallback(ulong currentValue) 419 { 420 if(enableValueProviders) 421 { 422 return currentValue + 1; 423 } 424 return currentValue; 425 } 426 ModifyingFlagCallback(bool currentValue)427 private bool ModifyingFlagCallback(bool currentValue) 428 { 429 if(enableValueProviders) 430 { 431 return !currentValue; 432 } 433 return currentValue; 434 } 435 ModifyingEnumCallback(TwoBitEnum currentValue)436 private TwoBitEnum ModifyingEnumCallback(TwoBitEnum currentValue) 437 { 438 if(enableValueProviders) 439 { 440 return currentValue + 1; 441 } 442 return currentValue; 443 } 444 445 /*Offset | Field 446 -------------------- 447 0 | Enum rw 448 1 | 449 -------------------- 450 2 | Bool rw 451 -------------------- 452 3 | Value rw 453 4 | 454 5 | 455 6 | 456 -------------------- 457 7 | Enum rw w/callbacks, reset value 3 458 8 | 459 -------------------- 460 9 | Bool rw w/callbacks, reset value 1 461 -------------------- 462 A | Value rw w/callbacks, reset value 13 463 B | 464 C | 465 D | 466 -------------------- 467 F | Bool tr 468 -------------------- 469 10 | Bool sr 470 -------------------- 471 11 | Bool w1c 472 -------------------- 473 12 | Bool w0c 474 -------------------- 475 13 | Bool wrtc 476 -------------------- 477 14 | Bool w 478 -------------------- 479 15 | Bool r 480 -------------------- 481 16 | Value rw w/changing r callback 482 17 | 483 18 | 484 -------------------- 485 19 | Bool rw w/changing r callback 486 -------------------- 487 1A | Enum rw w/changing r callback 488 1B | 489 -------------------- 490 1C | Bool wzts 491 -------------------- 492 1D | Bool wztt 493 -------------------- 494 1E | Bool rts 495 -------------------- 496 1F | Bool wtc 497 */ 498 private QuadWordRegister register; 499 500 private int enumCallbacks; 501 private int boolCallbacks; 502 private int numberCallbacks; 503 504 private int globalCallbacks; 505 506 private TwoBitEnum oldEnumValue; 507 private TwoBitEnum newEnumValue; 508 private bool oldBoolValue; 509 private bool newBoolValue; 510 private ulong oldNumberValue; 511 private ulong newNumberValue; 512 private ulong oldGlobalValue; 513 private ulong newGlobalValue; 514 515 private bool enableValueProviders; 516 517 private IEnumRegisterField<TwoBitEnum> enumRWField; 518 private IFlagRegisterField flagRWField; 519 private IValueRegisterField valueRWField; 520 private IFlagRegisterField flagTRField; 521 private IFlagRegisterField flagSRField; 522 private IFlagRegisterField flagW1CField; 523 private IFlagRegisterField flagW0CField; 524 private IFlagRegisterField flagWRTCField; 525 private IFlagRegisterField flagWField; 526 private IFlagRegisterField flagRField; 527 private IFlagRegisterField flagWZTSField; 528 private IFlagRegisterField flagWZTTField; 529 private IFlagRegisterField flagRTSField; 530 private IFlagRegisterField flagWTCField; 531 532 // Bits that store written value 533 private ulong writeMask = 0b0000_1111_1101_1000__0111_1111_1111_1111; 534 // Bits that provide stored value 535 private ulong readMask = 0b0000_1111_1110_0111__1111_1111_1111_1111; 536 private const ulong RegisterResetValue = 0x3780u; 537 538 private enum TwoBitEnum 539 { 540 A = 0, 541 B = 1, 542 D = 3 543 } 544 545 private enum SixtyFourBitEnum : ulong 546 { 547 A = 0x0123456789123456, 548 B = 0xFFFFFFFFFFFFFFFF 549 } 550 } 551 } 552