1 // 2 // Copyright (c) 2010-2018 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using NUnit.Framework; 9 using Antmicro.Renode.Utilities; 10 using System.IO; 11 using Antmicro.Renode.Peripherals.Bus; 12 using Machine = Antmicro.Renode.Core.Machine; 13 using Antmicro.Renode.Exceptions; 14 15 namespace Antmicro.Renode.UnitTests 16 { 17 [TestFixture] 18 public class SVDParserTests 19 { 20 [OneTimeSetUp] Init()21 public void Init() 22 { 23 currentMachine = new Machine(); 24 } 25 26 #region Format tests 27 28 [Test] ShouldThrowOnNonexistingFile()29 public void ShouldThrowOnNonexistingFile() 30 { 31 Assert.Throws<RecoverableException>(() => 32 { 33 currentMachine = new Machine(); 34 device = new SVDParser(Path.Combine("invalid", "path.svd"), currentMachine.SystemBus); 35 }); 36 } 37 38 [Test] ShouldThrowOnEmptyFile()39 public void ShouldThrowOnEmptyFile() 40 { 41 Assert.Throws<RecoverableException>(() => 42 { 43 SetUpDeviceWithString(""); 44 }); 45 } 46 47 [Test] ShouldThrowOnInvalidXml()48 public void ShouldThrowOnInvalidXml() 49 { 50 Assert.Throws<RecoverableException>(() => 51 { 52 SetUpDeviceWithString("Lorem ipsum..."); 53 }); 54 } 55 56 [Test] ShouldThrowOnInvalidSvd()57 public void ShouldThrowOnInvalidSvd() 58 { 59 Assert.Throws<RecoverableException>(() => 60 { 61 SetUpDeviceWithString(@"<?xml version=""1.0"" encoding=""utf-8"" standalone=""no""?> 62 <invalidTag> 63 </invalidTag> 64 "); 65 }); 66 } 67 68 [Test] ShouldThrowOnDeviceWithNoMandatoryFields()69 public void ShouldThrowOnDeviceWithNoMandatoryFields() 70 { 71 Assert.Throws<RecoverableException>(() => 72 { 73 SetUpDeviceWithString(@"<?xml version=""1.0"" encoding=""utf-8"" standalone=""no""?> 74 <device> 75 </device> 76 "); 77 }); 78 } 79 80 [Test] ShouldThrowOnDeviceWithNoPeripheralsTag()81 public void ShouldThrowOnDeviceWithNoPeripheralsTag() 82 { 83 Assert.Throws<RecoverableException>(() => 84 { 85 SetUpDeviceWithInfix(""); 86 }); 87 } 88 89 [Test] ShouldThrowOnDeviceWithNotEveryMandatoryField()90 public void ShouldThrowOnDeviceWithNotEveryMandatoryField() 91 { 92 // Both tags <description> and <name> are mandatory. 93 string[] mandatories = { "descripion", "name" }; 94 foreach(var item in mandatories) 95 { 96 Assert.Throws<RecoverableException>(() => 97 { 98 SetUpDeviceWithString($@"<?xml version=""1.0"" encoding=""utf-8"" standalone=""no""?> 99 <device> 100 <{item}>value</{item}> 101 </device>" 102 ); 103 }); 104 } 105 } 106 107 [Test] ShouldThrowOnCpuWithoutEndianness()108 public void ShouldThrowOnCpuWithoutEndianness() 109 { 110 // If cpu is defined the tag <endian> is mandatory. 111 Assert.Throws<RecoverableException>(() => 112 { 113 SetUpDeviceWithString($@"<?xml version=""1.0"" encoding=""utf-8"" standalone=""no""?> 114 <device> 115 <description>Test description</description> 116 <name>Test name</name> 117 <cpu> 118 </cpu> 119 </device>" 120 ); 121 }); 122 } 123 124 [Test] ShouldThrowOnPeripheralWithNotEveryMandatoryField([Values(R, R)] string tag)125 public void ShouldThrowOnPeripheralWithNotEveryMandatoryField([Values("name", "baseAddress")] string tag) 126 { 127 // Both tags <name> and <baseAddress> are mandatory. 128 // 0x1000 is used as a field value so we do not have to care about field types in this test. 129 Assert.Throws<RecoverableException>(() => 130 { 131 SetUpDeviceWithInfix($@" 132 <peripherals> 133 <peripheral> 134 <{tag}>0x1000</{tag}> 135 </peripheral> 136 </peripherals> 137 "); 138 }); 139 } 140 141 [Test] ShouldThrowOnClusterWithoutMandatoryFields()142 public void ShouldThrowOnClusterWithoutMandatoryFields() 143 { 144 // Tag <addressOffset> is mandatory. 145 Assert.Throws<RecoverableException>(() => 146 { 147 SetUpDeviceWithInfix(@" 148 <peripherals> 149 <peripheral> 150 <name>Peripheral1</name> 151 <baseAddress>0x1000</baseAddress> 152 <registers> 153 <cluster> 154 <!--addressOffset and name missing--> 155 <register> 156 <name>REG1</name> 157 <addressOffset>0x0</addressOffset> 158 <resetValue>0</resetValue> 159 </register> 160 </cluster> 161 </registers> 162 </peripheral> 163 </peripherals> 164 "); 165 }); 166 } 167 168 [Test] ShouldThrowOnRegisterWithNotEveryMandatoryField([Values(R, R)] string tag)169 public void ShouldThrowOnRegisterWithNotEveryMandatoryField([Values("name", "addressOffset")] string tag) 170 { 171 // Both tags <name> and <addressOffset> are mandatory. 172 // 0x1000 is used as a field value so we do not have to care about field types in this test. 173 Assert.Throws<RecoverableException>(() => 174 { 175 SetUpDeviceWithInfix($@" 176 <peripherals> 177 <peripheral> 178 <name>Peripheral1</name> 179 <baseAddress>0x1000</baseAddress> 180 <registers> 181 <cluster> 182 <addressOffset>0</addressOffset> 183 <register> 184 <{tag}>0x1000</{tag}> 185 </register> 186 </cluster> 187 </registers> 188 </peripheral> 189 </peripherals> 190 "); 191 }); 192 } 193 194 [Test] ShouldThrowOnDeviceWithInvalidSize()195 public void ShouldThrowOnDeviceWithInvalidSize() 196 { 197 Assert.Throws<RecoverableException>(() => 198 { 199 SetUpDeviceWithString(@"<?xml version=""1.0"" encoding=""utf-8"" standalone=""no""?> 200 <device> 201 <description>Test description</description> 202 <name>Test name</name> 203 <size>invalidValue</size> 204 </device>" 205 ); 206 }); 207 } 208 209 [Test] ShouldThrowOnDeviceWithInvalidResetValue()210 public void ShouldThrowOnDeviceWithInvalidResetValue() 211 { 212 Assert.Throws<RecoverableException>(() => 213 { 214 SetUpDeviceWithString(@"<?xml version=""1.0"" encoding=""utf-8"" standalone=""no""?> 215 <device> 216 <description>Test description</description> 217 <name>Test name</name> 218 <resetValue>invalidValue</resetValue> 219 <peripherals> 220 </peripherals> 221 </device>" 222 ); 223 }); 224 } 225 226 [Test] ShouldThrowOnDeviceWithInvalidAccess()227 public void ShouldThrowOnDeviceWithInvalidAccess() 228 { 229 Assert.Throws<RecoverableException>(() => 230 { 231 SetUpDeviceWithString(@"<?xml version=""1.0"" encoding=""utf-8"" standalone=""no""?> 232 <device> 233 <description>Test description</description> 234 <name>Test name</name> 235 <access>invalidValue</access> 236 </device>" 237 ); 238 }); 239 } 240 241 [Test] ShouldThrowOnCpuWithInvalidEndianness()242 public void ShouldThrowOnCpuWithInvalidEndianness() 243 { 244 Assert.Throws<RecoverableException>(() => 245 { 246 SetUpDeviceWithString($@"<?xml version=""1.0"" encoding=""utf-8"" standalone=""no""?> 247 <device> 248 <description>Test description</description> 249 <name>Test name</name> 250 <cpu> 251 <endian>invalidValue</endian> 252 </cpu> 253 <peripherals> 254 </peripherals> 255 </device>" 256 ); 257 }); 258 } 259 260 [Test] ShouldThrowOnRegisterWithoutDeterminedSizeAndResetValue()261 public void ShouldThrowOnRegisterWithoutDeterminedSizeAndResetValue() 262 { 263 Assert.Throws<RecoverableException>(() => 264 { 265 SetUpDeviceWithString($@"<?xml version=""1.0"" encoding=""utf-8"" standalone=""no""?> 266 <device> 267 <description>Test description</description> 268 <name>Test name</name> 269 <access>read-write</access> 270 <peripherals> 271 <peripheral> 272 <name>name</name> 273 <baseAddress>0</baseAddress> 274 <registers> 275 <register> 276 <name>REG1</name> 277 <addressOffset>0</addressOffset> 278 </register> 279 </registers> 280 </peripheral> 281 </peripherals> 282 </device>" 283 ); 284 }); 285 } 286 287 #endregion Format tests 288 289 #region Read tests 290 291 [Test] ShouldReadValueFromRegister()292 public void ShouldReadValueFromRegister() 293 { 294 var variableValue = 0xDEADBEEF; 295 SetUpDeviceWithInfix($@" 296 <peripherals> 297 <peripheral> 298 <name>Peripheral1</name> 299 <baseAddress>0x1000</baseAddress> 300 <registers> 301 <register> 302 <name>REG1</name> 303 <addressOffset>0x0</addressOffset> 304 <resetValue>{variableValue}</resetValue> 305 </register> 306 </registers> 307 </peripheral> 308 </peripherals> 309 "); 310 Assert.IsTrue(device.TryReadAccess(0x1000, out var result, SysbusAccessWidth.DoubleWord)); 311 Assert.AreEqual(result, variableValue); 312 } 313 314 [Test] ShouldReadValueFromRegisterInBigEndian()315 public void ShouldReadValueFromRegisterInBigEndian() 316 { 317 var variableValue = 0xDEADBEEF; 318 byte[] bytes = BitConverter.GetBytes(variableValue); 319 SetUpDeviceWithInfix($@" 320 <peripherals> 321 <peripheral> 322 <name>Peripheral1</name> 323 <baseAddress>0x1000</baseAddress> 324 <registers> 325 <register> 326 <name>REG1</name> 327 <addressOffset>0x0</addressOffset> 328 <resetValue>{variableValue}</resetValue> 329 </register> 330 </registers> 331 </peripheral> 332 </peripherals> 333 ", 334 false 335 ); 336 337 byte[] newBytes = { bytes[3], bytes[2], bytes[1], bytes[0] }; 338 var expectedValue = BitConverter.ToUInt32(newBytes, 0); 339 Assert.IsTrue(device.TryReadAccess(0x1000, out var result, SysbusAccessWidth.DoubleWord)); 340 Assert.AreEqual(result, expectedValue); 341 } 342 343 [Test] ShouldHandleDifferentAccessPermissions([Values(R, R, R, R, R)] string access)344 public void ShouldHandleDifferentAccessPermissions([Values("write-only", "read-only", "read-write", "read-writeOnce", "writeOnce")] string access) 345 { 346 SetUpDeviceWithInfix($@" 347 <peripherals> 348 <peripheral> 349 <name>Peripheral1</name> 350 <baseAddress>0x1000</baseAddress> 351 <registers> 352 <register> 353 <name>REG1</name> 354 <addressOffset>0x0</addressOffset> 355 <resetValue>0x01234567</resetValue> 356 <access>{access}</access> 357 </register> 358 </registers> 359 </peripheral> 360 </peripherals> 361 "); 362 var returnValue = device.TryReadAccess(0x1000, out var result, SysbusAccessWidth.DoubleWord); 363 if(access == "write-only" || access == "writeOnce") 364 { 365 Assert.AreEqual(result, 0); 366 Assert.IsTrue(returnValue); 367 } 368 else 369 { 370 Assert.AreEqual(result, 0x01234567); 371 Assert.IsTrue(returnValue); 372 } 373 } 374 375 [Test] ShouldReadFromRegistersOfDifferentSizes()376 public void ShouldReadFromRegistersOfDifferentSizes() 377 { 378 var variableValue = 0xDEADBEEF; 379 var maxSize = 32; 380 for(var i = 1; i < maxSize; i++) 381 { 382 SetUpDeviceWithInfix($@" 383 <peripherals> 384 <peripheral> 385 <name>Peripheral1</name> 386 <baseAddress>0x1000</baseAddress> 387 <registers> 388 <register> 389 <name>REG1</name> 390 <addressOffset>0x0</addressOffset> 391 <size>{i}</size> 392 <resetValue>{variableValue}</resetValue> 393 <access>read-write</access> 394 </register> 395 </registers> 396 </peripheral> 397 </peripherals> 398 "); 399 var mask = (uint)((1ul << i) - 1); 400 var expectedValue = variableValue & mask; 401 Assert.IsTrue(device.TryReadAccess(0x1000, out var result, SysbusAccessWidth.DoubleWord)); 402 Assert.AreEqual(result, expectedValue); 403 } 404 } 405 406 [Test] ShouldReadFromUnalignedOffsetInOnePeripheral()407 public void ShouldReadFromUnalignedOffsetInOnePeripheral() 408 { 409 byte[] bytes = { 11, 22, 33, 44, 55, 66, 77, 88 }; 410 SetUpDeviceWithInfix($@" 411 <peripherals> 412 <peripheral> 413 <access>read-write</access> 414 <name>Peripheral1</name> 415 <baseAddress>0x1000</baseAddress> 416 <registers> 417 <register> 418 <name>REG1</name> 419 <addressOffset>0x0</addressOffset> 420 <resetValue>{BitConverter.ToUInt32(bytes, 0)}</resetValue> 421 <size>32</size> 422 </register> 423 <register> 424 <name>REG2</name> 425 <addressOffset>0x4</addressOffset> 426 <resetValue>{bytes[4]}</resetValue> 427 <size>8</size> 428 </register> 429 <register> 430 <name>REG3</name> 431 <addressOffset>0x5</addressOffset> 432 <resetValue>{bytes[5]}</resetValue> 433 <size>8</size> 434 </register> 435 <register> 436 <name>REG4</name> 437 <addressOffset>0x6</addressOffset> 438 <resetValue>{BitConverter.ToInt16(bytes, 6)}</resetValue> 439 <size>16</size> 440 </register> 441 </registers> 442 </peripheral> 443 </peripherals> 444 "); 445 446 for(var i = -3; i < 8; i++) 447 { 448 var readingAddress = (ulong)(0x1000 + i); 449 var expectedBytes = new byte[4]; 450 for(var j = 0u; j < 4; j++) 451 { 452 if(readingAddress + j >= 0x1000 && readingAddress + j < 0x1008) 453 { 454 expectedBytes[j] = bytes[readingAddress + j - 0x1000]; 455 } 456 else 457 { 458 expectedBytes[j] = 0; 459 } 460 } 461 var expectedValue = BitConverter.ToUInt32(expectedBytes, 0); 462 Assert.IsTrue(device.TryReadAccess(readingAddress, out var result, SysbusAccessWidth.DoubleWord)); 463 Assert.AreEqual(result, expectedValue); 464 } 465 } 466 467 [Test] ShouldReadFromUnalignedOffsetInManyPeripherals()468 public void ShouldReadFromUnalignedOffsetInManyPeripherals() 469 { 470 byte[] bytes = { 11, 22, 33, 44, 55, 66, 77, 88 }; 471 SetUpDeviceWithInfix($@" 472 <peripherals> 473 474 <peripheral> 475 <access>read-write</access> 476 <name>Peripheral1</name> 477 <baseAddress>0x1000</baseAddress> 478 <registers> 479 <register> 480 <name>REG1</name> 481 <addressOffset>0x0</addressOffset> 482 <resetValue>{BitConverter.ToUInt32(bytes, 0)}</resetValue> 483 <size>32</size> 484 </register> 485 </registers> 486 </peripheral> 487 488 <peripheral> 489 <access>read-write</access> 490 <name>Peripheral2</name> 491 <baseAddress>0x1004</baseAddress> 492 <registers> 493 <register> 494 <name>REG2</name> 495 <addressOffset>0</addressOffset> 496 <resetValue>{bytes[4]}</resetValue> 497 <size>8</size> 498 </register> 499 <register> 500 <name>REG3</name> 501 <addressOffset>1</addressOffset> 502 <resetValue>{bytes[5]}</resetValue> 503 <size>8</size> 504 </register> 505 </registers> 506 </peripheral> 507 508 <peripheral> 509 <access>read-write</access> 510 <name>Peripheral3</name> 511 <baseAddress>0x1006</baseAddress> 512 <registers> 513 <register> 514 <name>REG4</name> 515 <addressOffset>0</addressOffset> 516 <resetValue>{BitConverter.ToInt16(bytes, 6)}</resetValue> 517 <size>16</size> 518 </register> 519 </registers> 520 </peripheral> 521 </peripherals> 522 "); 523 524 for(var i = -3; i < 8; i++) 525 { 526 var readingAddress = (ulong)(0x1000 + i); 527 var expectedBytes = new byte[4]; 528 for(var j = 0u; j < 4; j++) 529 { 530 if(readingAddress + j >= 0x1000 && readingAddress + j < 0x1008) 531 { 532 expectedBytes[j] = bytes[readingAddress + j - 0x1000]; 533 } 534 else 535 { 536 expectedBytes[j] = 0; 537 } 538 } 539 var expectedValue = BitConverter.ToUInt32(expectedBytes, 0); 540 541 Assert.IsTrue(device.TryReadAccess(readingAddress, out var result, SysbusAccessWidth.DoubleWord)); 542 Assert.AreEqual(result, expectedValue); 543 } 544 } 545 546 [Test] ShouldReadFromUnalignedOffsetInOnePeripheralInBigEndian()547 public void ShouldReadFromUnalignedOffsetInOnePeripheralInBigEndian() 548 { 549 byte[] bytes = { 11, 22, 33, 44, 55, 66, 77, 88 }; 550 SetUpDeviceWithInfix($@" 551 <peripherals> 552 <peripheral> 553 <access>read-write</access> 554 <name>Peripheral1</name> 555 <baseAddress>0x1000</baseAddress> 556 <registers> 557 <register> 558 <name>REG1</name> 559 <addressOffset>0x0</addressOffset> 560 <resetValue>{BitConverter.ToUInt32(bytes, 0)}</resetValue> 561 <size>32</size> 562 </register> 563 <register> 564 <name>REG2</name> 565 <addressOffset>0x4</addressOffset> 566 <resetValue>{bytes[4]}</resetValue> 567 <size>8</size> 568 </register> 569 <register> 570 <name>REG3</name> 571 <addressOffset>0x5</addressOffset> 572 <resetValue>{bytes[5]}</resetValue> 573 <size>8</size> 574 </register> 575 <register> 576 <name>REG4</name> 577 <addressOffset>0x6</addressOffset> 578 <resetValue>{BitConverter.ToInt16(bytes, 6)}</resetValue> 579 <size>16</size> 580 </register> 581 </registers> 582 </peripheral> 583 </peripherals> 584 ", 585 false 586 ); 587 var readingAddress = (ulong)(0x1000 - 3); 588 for(var i = -3; i < 8; i++) 589 { 590 var expectedBytes = new byte[4]; 591 for(var j = 0u; j < 4; j++) 592 { 593 var tmpAddres = readingAddress + j; 594 if(tmpAddres >= 0x1000 && tmpAddres < 0x1008) 595 { 596 if(tmpAddres <= 0x1003) 597 { 598 var offset = tmpAddres - 0x1000; 599 var bigEndianAddress = 0x1003 - offset; 600 expectedBytes[j] = bytes[bigEndianAddress - 0x1000]; 601 } 602 else if(tmpAddres == 0x1004) 603 { 604 expectedBytes[j] = bytes[tmpAddres - 0x1000]; 605 } 606 else if(tmpAddres == 0x1005) 607 { 608 expectedBytes[j] = bytes[tmpAddres - 0x1000]; 609 } 610 else 611 { 612 var offset = tmpAddres - 0x1006; 613 var bigEndianAddress = 0x1007 - offset; 614 expectedBytes[j] = bytes[bigEndianAddress - 0x1000]; 615 } 616 } 617 else 618 { 619 expectedBytes[j] = 0; 620 } 621 } 622 var expectedValue = BitConverter.ToUInt32(expectedBytes, 0); 623 Assert.IsTrue(device.TryReadAccess(readingAddress, out var result, SysbusAccessWidth.DoubleWord)); 624 Assert.AreEqual(result, expectedValue); 625 readingAddress++; 626 } 627 } 628 629 [Test] ShouldReadFromUnalignedOffsetInOnePeripheralWithWriteOnlyRegister()630 public void ShouldReadFromUnalignedOffsetInOnePeripheralWithWriteOnlyRegister() 631 { 632 byte[] bytes = { 11, 22, 33, 44, 55, 66, 77, 88 }; 633 SetUpDeviceWithInfix($@" 634 <peripherals> 635 <peripheral> 636 <access>read-write</access> 637 <name>Peripheral1</name> 638 <baseAddress>0x1000</baseAddress> 639 <registers> 640 <register> 641 <name>REG1</name> 642 <addressOffset>0x0</addressOffset> 643 <resetValue>{BitConverter.ToUInt32(bytes, 0)}</resetValue> 644 <size>32</size> 645 </register> 646 <register> 647 <name>REG2</name> 648 <addressOffset>0x4</addressOffset> 649 <resetValue>{bytes[4]}</resetValue> 650 <access>write-only</access> 651 <size>8</size> 652 </register> 653 <register> 654 <name>REG3</name> 655 <addressOffset>0x5</addressOffset> 656 <resetValue>{bytes[5]}</resetValue> 657 <access>write-only</access> 658 <size>8</size> 659 </register> 660 <register> 661 <name>REG4</name> 662 <addressOffset>0x6</addressOffset> 663 <resetValue>{BitConverter.ToInt16(bytes, 6)}</resetValue> 664 <size>16</size> 665 </register> 666 </registers> 667 </peripheral> 668 </peripherals> 669 ", 670 false 671 ); 672 var readingAddress = (ulong)(0x1000 - 3); 673 for(var i = -3; i < 8; i++) 674 { 675 var expectedBytes = new byte[4]; 676 for(var j = 0u; j < 4; j++) 677 { 678 var tmpAddres = readingAddress + j; 679 if(tmpAddres >= 0x1000 && tmpAddres < 0x1008) 680 { 681 if(tmpAddres == 0x1004 || tmpAddres == 0x1005) 682 { 683 expectedBytes[j] = 0; 684 } 685 else if(tmpAddres <= 0x1003) 686 { 687 var offset = tmpAddres - 0x1000; 688 var bigEndianAddress = 0x1003 - offset; 689 expectedBytes[j] = bytes[bigEndianAddress - 0x1000]; 690 } 691 else if(tmpAddres == 0x1004) 692 { 693 expectedBytes[j] = bytes[tmpAddres - 0x1000]; 694 } 695 else if(tmpAddres == 0x1005) 696 { 697 expectedBytes[j] = bytes[tmpAddres - 0x1000]; 698 } 699 else 700 { 701 var offset = tmpAddres - 0x1006; 702 var bigEndianAddress = 0x1007 - offset; 703 expectedBytes[j] = bytes[bigEndianAddress - 0x1000]; 704 } 705 } 706 else 707 { 708 expectedBytes[j] = 0; 709 } 710 } 711 var expectedValue = BitConverter.ToUInt32(expectedBytes, 0); 712 Assert.IsTrue(device.TryReadAccess(readingAddress, out var result, SysbusAccessWidth.DoubleWord)); 713 Assert.AreEqual(result, expectedValue); 714 readingAddress++; 715 } 716 } 717 718 #endregion Read tests 719 720 #region Inheritance tests 721 722 [Test] ShouldConcatenateAddressOffsets()723 public void ShouldConcatenateAddressOffsets() 724 { 725 var baseAddress = 0x10000; 726 int[] addressOffset = { 0x1000, 0x100, 0x10 }; 727 var finalAddressOffset = 0x11110u; 728 729 SetUpDeviceWithInfix($@" 730 <peripherals> 731 <peripheral> 732 <name>Peripheral1</name> 733 <baseAddress>{baseAddress}</baseAddress> 734 <access>read-write</access> 735 <registers> 736 <cluster> 737 <name>C0</name> 738 <addressOffset>{addressOffset[0]}</addressOffset> 739 <cluster> 740 <name>C1</name> 741 <addressOffset>{addressOffset[1]}</addressOffset> 742 <register> 743 <name>REG1</name> 744 <addressOffset>{addressOffset[2]}</addressOffset> 745 <resetValue>0x1000</resetValue> 746 </register> 747 </cluster> 748 </cluster> 749 </registers> 750 </peripheral> 751 </peripherals> 752 "); 753 Assert.IsTrue(device.TryReadAccess(finalAddressOffset, out var result, SysbusAccessWidth.DoubleWord)); 754 Assert.AreEqual(result, 0x1000); 755 } 756 757 [Test] ShouldInheritSettingsFromParentPeripheral()758 public void ShouldInheritSettingsFromParentPeripheral() 759 { 760 SetUpDeviceWithInfix(@" 761 <peripherals> 762 <peripheral> 763 <name>Peripheral1</name> 764 <baseAddress>0x1000</baseAddress> 765 <size>11</size> 766 <resetValue>0xA5445E63</resetValue> 767 <access>read-writeOnce</access> 768 <registers> 769 <register> 770 <name>REG1</name> 771 <addressOffset>0x0</addressOffset> 772 </register> 773 <register> 774 <name>REG2</name> 775 <addressOffset>0x10</addressOffset> 776 <size>27</size> 777 </register> 778 <register> 779 <name>REG3</name> 780 <addressOffset>0x20</addressOffset> 781 <resetValue>0x12345678</resetValue> 782 <size>27</size> 783 </register> 784 </registers> 785 </peripheral> 786 </peripherals> 787 "); 788 Assert.IsTrue(device.TryReadAccess(0x1000, out var result, SysbusAccessWidth.DoubleWord)); 789 Assert.AreEqual(result, 0x00000663); 790 Assert.IsTrue(device.TryReadAccess(0x1010, out result, SysbusAccessWidth.DoubleWord)); 791 Assert.AreEqual(result, 0x05445E63); 792 Assert.IsTrue(device.TryReadAccess(0x1020, out result, SysbusAccessWidth.DoubleWord)); 793 Assert.AreEqual(result, 0x02345678); 794 } 795 796 [Test] ShouldInheritSettingsFromParentCluster()797 public void ShouldInheritSettingsFromParentCluster() 798 { 799 SetUpDeviceWithInfix(@" 800 <peripherals> 801 <peripheral> 802 <name>Peripheral1</name> 803 <baseAddress>0x1000</baseAddress> 804 <size>32</size> 805 <resetValue>0xFFFFFFFF</resetValue> 806 <access>read-writeOnce</access> 807 <registers> 808 <cluster> 809 <name>Cluster1</name> 810 <addressOffset>0x100</addressOffset> 811 <resetValue>0xA5445E63</resetValue> 812 <size>11</size> 813 <register> 814 <name>REG1</name> 815 <addressOffset>0x0</addressOffset> 816 </register> 817 <register> 818 <name>REG2</name> 819 <addressOffset>0x10</addressOffset> 820 <size>27</size> 821 </register> 822 <register> 823 <name>REG3</name> 824 <addressOffset>0x20</addressOffset> 825 <resetValue>0x12345678</resetValue> 826 <size>27</size> 827 </register> 828 </cluster> 829 </registers> 830 </peripheral> 831 </peripherals> 832 "); 833 Assert.IsTrue(device.TryReadAccess(0x1100, out var result, SysbusAccessWidth.DoubleWord)); 834 Assert.AreEqual(result, 0x00000663); 835 Assert.IsTrue(device.TryReadAccess(0x1110, out result, SysbusAccessWidth.DoubleWord)); 836 Assert.AreEqual(result, 0x05445E63); 837 Assert.IsTrue(device.TryReadAccess(0x1120, out result, SysbusAccessWidth.DoubleWord)); 838 Assert.AreEqual(result, 0x02345678); 839 } 840 841 [Test] ShouldInheritSettingsFromParentClusterAndPeripheral()842 public void ShouldInheritSettingsFromParentClusterAndPeripheral() 843 { 844 SetUpDeviceWithInfix(@" 845 <peripherals> 846 <peripheral> 847 <name>Peripheral1</name> 848 <baseAddress>0x1000</baseAddress> 849 <size>11</size> 850 <resetValue>0xFFFFFFFF</resetValue> 851 <access>read-writeOnce</access> 852 <registers> 853 <register> 854 <name>REG1</name> 855 <addressOffset>0x0</addressOffset> 856 </register> 857 <cluster> 858 <name>Cluster1</name> 859 <addressOffset>0x100</addressOffset> 860 <resetValue>0xA5445E63</resetValue> 861 <size>27</size> 862 <register> 863 <name>REG2</name> 864 <addressOffset>0x10</addressOffset> 865 </register> 866 <register> 867 <name>REG3</name> 868 <addressOffset>0x20</addressOffset> 869 <resetValue>0x12345678</resetValue> 870 </register> 871 </cluster> 872 </registers> 873 </peripheral> 874 </peripherals> 875 "); 876 Assert.IsTrue(device.TryReadAccess(0x1000, out var result, SysbusAccessWidth.DoubleWord)); 877 Assert.AreEqual(result, 0x000007FF); 878 Assert.IsTrue(device.TryReadAccess(0x1110, out result, SysbusAccessWidth.DoubleWord)); 879 Assert.AreEqual(result, 0x05445E63); 880 Assert.IsTrue(device.TryReadAccess(0x1120, out result, SysbusAccessWidth.DoubleWord)); 881 Assert.AreEqual(result, 0x02345678); 882 } 883 884 #endregion Inheritance tests 885 886 #region Deriving tests 887 888 [Test] ShouldThrowOnDerivingFromNonexistingRegister()889 public void ShouldThrowOnDerivingFromNonexistingRegister() 890 { 891 Assert.Throws<RecoverableException>(() => 892 { 893 SetUpDeviceWithInfix(@" 894 <peripherals> 895 <peripheral> 896 <name>Peripheral1</name> 897 <baseAddress>0x1000</baseAddress> 898 <access>read-write</access> 899 <registers> 900 <register> 901 <name>REG1</name> 902 <addressOffset>0x0</addressOffset> 903 <size>32</size> 904 <resetValue>0xF2468ACE</resetValue> 905 </register> 906 <register derivedFrom=""invalidObject""> 907 <name>REG2</name> 908 <addressOffset>0x10</addressOffset> 909 </register> 910 </registers> 911 </peripheral> 912 </peripherals> 913 "); 914 device.TryReadAccess(0x1010, out var result, SysbusAccessWidth.DoubleWord); 915 }); 916 } 917 918 [Test] ShouldDeriveFromRegisterInTheSameScope()919 public void ShouldDeriveFromRegisterInTheSameScope() 920 { 921 SetUpDeviceWithInfix(@" 922 <peripherals> 923 <peripheral> 924 <name>Peripheral1</name> 925 <baseAddress>0x1000</baseAddress> 926 <access>read-write</access> 927 <registers> 928 <register> 929 <name>REG1</name> 930 <addressOffset>0x0</addressOffset> 931 <size>32</size> 932 <resetValue>0xF2468ACE</resetValue> 933 </register> 934 <register derivedFrom=""REG1""> 935 <name>REG2</name> 936 <addressOffset>0x10</addressOffset> 937 </register> 938 </registers> 939 </peripheral> 940 </peripherals> 941 "); 942 Assert.IsTrue(device.TryReadAccess(0x1010, out var result, SysbusAccessWidth.DoubleWord)); 943 Assert.AreEqual(result, 0xF2468ACE); 944 } 945 946 [Test] ShouldDeriveFromRegisterInDifferentCluster()947 public void ShouldDeriveFromRegisterInDifferentCluster() 948 { 949 SetUpDeviceWithInfix(@" 950 <peripherals> 951 <peripheral> 952 <name>Peripheral1</name> 953 <baseAddress>0x1000</baseAddress> 954 <access>read-write</access> 955 <registers> 956 <cluster> 957 <name>C0</name> 958 <addressOffset>0x0</addressOffset> 959 <register> 960 <name>REG1</name> 961 <addressOffset>0x0</addressOffset> 962 <size>32</size> 963 <resetValue>0xF2468ACE</resetValue> 964 </register> 965 </cluster> 966 <register derivedFrom=""Peripheral1.C0.REG1""> 967 <name>REG2</name> 968 <addressOffset>0x10</addressOffset> 969 </register> 970 </registers> 971 </peripheral> 972 </peripherals> 973 "); 974 Assert.IsTrue(device.TryReadAccess(0x1010, out var result, SysbusAccessWidth.DoubleWord)); 975 Assert.AreEqual(result, 0xF2468ACE); 976 } 977 978 [Test] ShouldDeriveFromRegisterInDifferentPeripheral()979 public void ShouldDeriveFromRegisterInDifferentPeripheral() 980 { 981 SetUpDeviceWithInfix(@" 982 <peripherals> 983 <peripheral> 984 <name>Peripheral1</name> 985 <baseAddress>0x1000</baseAddress> 986 <access>read-write</access> 987 <registers> 988 <cluster> 989 <name>C0</name> 990 <size>32</size> 991 <addressOffset>0x0</addressOffset> 992 <register> 993 <name>REG1</name> 994 <addressOffset>0x0</addressOffset> 995 <resetValue>0xF2468ACE</resetValue> 996 </register> 997 </cluster> 998 </registers> 999 </peripheral> 1000 <peripheral> 1001 <name>Peripheral2</name> 1002 <baseAddress>0x2000</baseAddress> 1003 <access>read-write</access> 1004 <registers> 1005 <register derivedFrom=""Peripheral1.C0.REG1""> 1006 <name>REG2</name> 1007 <addressOffset>0x10</addressOffset> 1008 </register> 1009 </registers> 1010 </peripheral> 1011 </peripherals> 1012 "); 1013 Assert.IsTrue(device.TryReadAccess(0x2010, out var result, SysbusAccessWidth.DoubleWord)); 1014 Assert.AreEqual(result, 0xF2468ACE); 1015 } 1016 1017 #endregion Deriving tests 1018 SetUpDeviceWithInfix(string infix, bool littleEndian = true)1019 private void SetUpDeviceWithInfix(string infix, bool littleEndian = true) 1020 { 1021 var fileName = TemporaryFilesManager.Instance.GetTemporaryFile(); 1022 File.WriteAllText(fileName, (littleEndian ? Prefix : BigEndianPrefix) + infix + Postfix); 1023 device = new SVDParser(fileName, currentMachine.SystemBus); 1024 } 1025 SetUpDeviceWithString(string content)1026 private void SetUpDeviceWithString(string content) 1027 { 1028 var fileName = TemporaryFilesManager.Instance.GetTemporaryFile(); 1029 File.WriteAllText(fileName, content); 1030 device = new SVDParser(fileName, currentMachine.SystemBus); 1031 } 1032 1033 private Machine currentMachine; 1034 private SVDParser device; 1035 1036 private const string Prefix = @"<?xml version=""1.0"" encoding=""utf-8"" standalone=""no""?> 1037 <device> 1038 <description>Test description</description> 1039 <name>Test name</name> 1040 <size>32</size> 1041 <access>read-write</access> 1042 <resetValue>0xA5A5A5A5</resetValue> 1043 "; 1044 1045 private const string BigEndianPrefix = @"<?xml version=""1.0"" encoding=""utf-8"" standalone=""no""?> 1046 <device> 1047 <description>Test description</description> 1048 <name>Test name</name> 1049 <size>32</size> 1050 <access>read-write</access> 1051 <resetValue>0xA5A5A5A5</resetValue> 1052 <cpu> 1053 <endian>big</endian> 1054 </cpu> 1055 "; 1056 1057 private const string Postfix = @" 1058 </device> 1059 "; 1060 } 1061 } 1062