1 // 2 // Copyright (c) 2010-2024 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 System.Xml.Linq; 9 using System.Linq; 10 using Antmicro.Renode.Logging; 11 using System.Collections.Generic; 12 using Antmicro.Renode.Exceptions; 13 using System.Xml; 14 using System.IO; 15 using Antmicro.Renode.Utilities; 16 using System.IO.Compression; 17 18 namespace Antmicro.Renode.Peripherals.Bus 19 { 20 public sealed class SVDParser 21 { SVDParser(string path, IBusController parent)22 public SVDParser(string path, IBusController parent) 23 { 24 currentSystemBus = parent; 25 XDocument document; 26 Stream possibleGzip; 27 try 28 { 29 using(possibleGzip = File.OpenRead(path)) 30 { 31 if(possibleGzip.ReadByte() == 0x1F && possibleGzip.ReadByte() == 0x8B) // gzip header 32 { 33 parent.Log(LogLevel.Info, "Detected gzipped file, ungzipping."); 34 possibleGzip.Close(); 35 possibleGzip = new GZipStream(File.OpenRead(path), CompressionMode.Decompress); 36 path = TemporaryFilesManager.Instance.GetTemporaryFile(); 37 using(var extractedFile = File.OpenWrite(path)) 38 { 39 possibleGzip.CopyTo(extractedFile); 40 } 41 parent.Log(LogLevel.Info, "Successfully ungzipped."); 42 } 43 } 44 using(var stream = File.OpenRead(path)) 45 { 46 document = XDocument.Load(stream); 47 } 48 } 49 catch(Exception ex) 50 { 51 if(ex is FileNotFoundException || ex is DirectoryNotFoundException || ex is PathTooLongException) 52 { 53 throw new RecoverableException($"File '{path}' does not exist."); 54 } 55 else if(ex is UnauthorizedAccessException) 56 { 57 throw new RecoverableException($"File '{path}' cannot be loaded due to insufficient permissions."); 58 } 59 else if(ex is IOException) 60 { 61 throw new RecoverableException($"An I/O error occurred while opening the file '{path}'."); 62 } 63 else if(ex is XmlException) 64 { 65 throw new RecoverableException($"Given SVD file could not be loaded due to an exception: {ex.Message}."); 66 } 67 throw; 68 } 69 var deviceNode = document.Elements().FirstOrDefault(x => x.Name == "device"); 70 if(deviceNode == null) 71 { 72 throw new RecoverableException($"There is no <device> element in the file '{path}'."); 73 } 74 var device = new SVDDevice(deviceNode, this); 75 76 registerDictionary = new Dictionary<ulong, SVDRegister>(); 77 foreach(var register in device.Peripherals.SelectMany(x => x.Registers)) 78 { 79 AppendRegisterToDictionary(register); 80 } 81 parent.Log(LogLevel.Info, "Loaded SVD: {0}. Name: {1}. Description: {2}.", path, device.Name, device.Description); 82 } 83 TryReadAccess(ulong offset, out ulong value, SysbusAccessWidth width)84 public bool TryReadAccess(ulong offset, out ulong value, SysbusAccessWidth width) 85 { 86 var bytesToRead = CheckAndGetWidth(width); 87 var weHaveIt = false; 88 value = 0; 89 90 if(HitInTheRegisterDictionary(out var tmpRegister, offset, bytesToRead)) 91 { 92 weHaveIt = true; 93 if(tmpRegister.HasReadAccess) 94 { 95 value = tmpRegister.ResetValue; 96 LogReadSuccess(value, tmpRegister.Peripheral.Name, tmpRegister.Name, offset, width); 97 } 98 else 99 { 100 LogReadFail(tmpRegister.Peripheral.Name, tmpRegister.Name, offset, width); 101 } 102 } 103 else 104 { 105 value = AssembleValueFromRegisters(offset, width, ref weHaveIt); 106 } 107 return weHaveIt; 108 } 109 TryWriteAccess(ulong offset, ulong value, SysbusAccessWidth width)110 public bool TryWriteAccess(ulong offset, ulong value, SysbusAccessWidth width) 111 { 112 int bytesToWrite = CheckAndGetWidth(width); 113 var weHaveIt = false; 114 if(HitInTheRegisterDictionary(out var tmpRegister, offset, bytesToWrite)) 115 { 116 weHaveIt = true; 117 if(tmpRegister.HasWriteAccess || tmpRegister.HasWriteOnceAccess) 118 { 119 LogWriteSuccess(value, tmpRegister.Peripheral.Name, tmpRegister.Name, offset, width, tmpRegister.HasWriteOnceAccess); 120 } 121 else 122 { 123 LogWriteFail(value, tmpRegister.Peripheral.Name, tmpRegister.Name, offset, width); 124 } 125 } 126 else 127 { 128 LogWriteRequests(value, offset, width, ref weHaveIt); 129 } 130 return weHaveIt; 131 } 132 HitInTheRegisterDictionary(out SVDRegister tmpRegister, ulong offset, int countOfBytes)133 private bool HitInTheRegisterDictionary(out SVDRegister tmpRegister, ulong offset, int countOfBytes) 134 { 135 return registerDictionary.TryGetValue(offset, out tmpRegister) && tmpRegister.Address == offset && tmpRegister.SizeInBytes == countOfBytes; 136 } 137 LogWriteRequests(ulong value, ulong offset, SysbusAccessWidth width, ref bool weHaveIt)138 private void LogWriteRequests(ulong value, ulong offset, SysbusAccessWidth width, ref bool weHaveIt) 139 { 140 var sizeInBytes = (int)width; 141 for(var i = 0; i < sizeInBytes; i++) 142 { 143 var tmpOffset = offset + (ulong)i; 144 if(registerDictionary.TryGetValue(tmpOffset, out var register)) 145 { 146 var howManyTimes = HowManyRequestsToTheRegister(register, sizeInBytes, offset, tmpOffset); 147 var mask = ((1ul << (8 * howManyTimes)) - 1) << (8 * i); 148 var tmpValue = (value & mask) >> (8 * i); 149 if(register.HasWriteAccess || register.HasWriteOnceAccess) 150 { 151 weHaveIt = true; 152 LogWriteSuccess(tmpValue, register.Peripheral.Name, register.Name, tmpOffset, width, register.Access == PermittedAccess.WriteOnce, offset, value); 153 } 154 else 155 { 156 LogWriteFail(tmpValue, register.Peripheral.Name, register.Name, tmpOffset, width, offset, value); 157 } 158 i += howManyTimes - 1; 159 } 160 } 161 } 162 AssembleValueFromRegisters(ulong offset, SysbusAccessWidth width, ref bool weHaveIt)163 private ulong AssembleValueFromRegisters(ulong offset, SysbusAccessWidth width, ref bool weHaveIt) 164 { 165 var sizeInBytes = (int)width; 166 var result = 0ul; 167 for(var i = 0; i < sizeInBytes; i++) 168 { 169 var tmpOffset = offset + (ulong)i; 170 if(registerDictionary.TryGetValue(tmpOffset, out var register)) 171 { 172 var howManyTimes = HowManyRequestsToTheRegister(register, sizeInBytes, offset, tmpOffset); 173 var mask = ((1ul << (8 * howManyTimes)) - 1) << (8 * (int)(tmpOffset - register.Address)); 174 var tmpValue = (register.ResetValue & mask) >> (8 * (int)(tmpOffset - register.Address)); 175 if(register.HasReadAccess) 176 { 177 weHaveIt = true; 178 LogReadSuccess(tmpValue, register.Peripheral.Name, register.Name, tmpOffset, width, offset); 179 result += tmpValue << (8 * i); 180 } 181 else 182 { 183 LogReadFail(register.Peripheral.Name, register.Name, tmpOffset, width, offset); 184 } 185 i += howManyTimes - 1; 186 } 187 } 188 return result; 189 } 190 HowManyRequestsToTheRegister(SVDRegister register, int sizeInBytes, ulong offset, ulong tmpOffset)191 private int HowManyRequestsToTheRegister(SVDRegister register, int sizeInBytes, ulong offset, ulong tmpOffset) 192 { 193 var registerLastAddress = register.Address + register.SizeInBytes - 1; 194 var lastReadingAddress = offset + checked((ulong)sizeInBytes) - 1; 195 var diff = (int)(registerLastAddress - lastReadingAddress); 196 int howManyTimes = (int)(registerLastAddress - tmpOffset + 1) - (diff > 0 ? diff : 0); 197 return howManyTimes; 198 } 199 AppendRegisterToDictionary(SVDRegister register)200 private void AppendRegisterToDictionary(SVDRegister register) 201 { 202 var bytes = register.SizeInBytes; 203 for(var i = 0u; i < bytes; i++) 204 { 205 var address = register.Address + i; 206 if(!registerDictionary.ContainsKey(address)) 207 { 208 registerDictionary.Add(address, register); 209 } 210 else 211 { 212 // There is a posibility to set the same address for various registers. 213 // e.g. first register with a read-only permission access but second with a write-only. 214 registerDictionary[address].MergeWithRegister(register); 215 } 216 } 217 } 218 LogReadSuccess(ulong value, string peripheralName, string name, ulong offset, SysbusAccessWidth width, ulong? originalOffset = null)219 private void LogReadSuccess(ulong value, string peripheralName, string name, ulong offset, SysbusAccessWidth width, ulong? originalOffset = null) 220 { 221 var formatString = "Read{5} from an unimplemented register {1}:{2} (0x{3:X}){4}, returning a value from SVD: 0x{0:X}"; 222 formatString = currentSystemBus.DecorateWithCPUNameAndPC(formatString); 223 224 var originalReadIndication = String.Empty; 225 if(originalOffset.HasValue) 226 { 227 originalReadIndication = $" (caused by reading offset 0x{originalOffset:X})"; 228 } 229 currentSystemBus.Log( 230 LogLevel.Warning, 231 formatString, 232 value, 233 peripheralName, 234 name, 235 offset, 236 originalReadIndication, 237 width 238 ); 239 } 240 LogWriteSuccess(ulong value, string peripheralName, string name, ulong offset, SysbusAccessWidth width, bool writeOnce = false, ulong? originalOffset = null, ulong? originalValue = null)241 private void LogWriteSuccess(ulong value, string peripheralName, string name, ulong offset, SysbusAccessWidth width, bool writeOnce = false, ulong? originalOffset = null, ulong? originalValue = null) 242 { 243 var formatString = "Write{6} of value 0x{0:X} to an unimplemented{5} register {1}:{2} (0x{3:X}){4} generated from SVD"; 244 formatString = currentSystemBus.DecorateWithCPUNameAndPC(formatString); 245 246 var originalWriteIndication = String.Empty; 247 var writeOnceIndication = String.Empty; 248 if(originalValue.HasValue) 249 { 250 originalWriteIndication = $" (caused by writing offset 0x{originalOffset:X} value 0x{originalValue:X})"; 251 } 252 if(writeOnce) 253 { 254 writeOnceIndication = " write-once"; 255 } 256 currentSystemBus.Log( 257 LogLevel.Warning, 258 formatString, 259 value, 260 peripheralName, 261 name, 262 offset, 263 originalWriteIndication, 264 writeOnceIndication, 265 width 266 ); 267 } 268 LogReadFail(string peripheralName, string name, ulong offset, SysbusAccessWidth width, ulong? originalOffset = null)269 private void LogReadFail(string peripheralName, string name, ulong offset, SysbusAccessWidth width, ulong? originalOffset = null) 270 { 271 var formatString = "Invalid Read{4} from an unimplemented write-only register {0}:{1} (0x{2:X}){3}, returning a value from SVD: 0x0"; 272 formatString = currentSystemBus.DecorateWithCPUNameAndPC(formatString); 273 274 var originalReadIndication = String.Empty; 275 if(originalOffset.HasValue) 276 { 277 originalReadIndication = $" (caused by reading offset 0x{originalOffset:X})"; 278 } 279 currentSystemBus.Log( 280 LogLevel.Warning, 281 formatString, 282 peripheralName, 283 name, 284 offset, 285 originalReadIndication, 286 width 287 ); 288 } 289 LogWriteFail(ulong value, string peripheralName, string name, ulong offset, SysbusAccessWidth width, ulong? originalOffset = null, ulong? originalValue = null)290 private void LogWriteFail(ulong value, string peripheralName, string name, ulong offset, SysbusAccessWidth width, ulong? originalOffset = null, ulong? originalValue = null) 291 { 292 var formatString = "Invalid Write{5} of value 0x{0:X} to an unimplemented read-only register {1}:{2} (0x{3:X}){4} generated from SVD"; 293 formatString = currentSystemBus.DecorateWithCPUNameAndPC(formatString); 294 295 var originalWriteIndication = String.Empty; 296 if(originalValue.HasValue) 297 { 298 originalWriteIndication = $" (caused by writing offset 0x{originalOffset:X} value 0x{originalValue:X})"; 299 } 300 currentSystemBus.Log( 301 LogLevel.Warning, 302 formatString, 303 value, 304 peripheralName, 305 name, 306 offset, 307 originalWriteIndication, 308 width 309 ); 310 } 311 CheckAndGetWidth(SysbusAccessWidth type)312 private static int CheckAndGetWidth(SysbusAccessWidth type) 313 { 314 switch(type) 315 { 316 case SysbusAccessWidth.Byte: 317 case SysbusAccessWidth.Word: 318 case SysbusAccessWidth.DoubleWord: 319 case SysbusAccessWidth.QuadWord: 320 return (int)type; 321 default: 322 throw new ArgumentException($"'{type}' is unsupported width of data."); 323 } 324 } 325 CalculateOffset(ulong? baseAddress, ulong? addressOffset)326 private static ulong? CalculateOffset(ulong? baseAddress, ulong? addressOffset) 327 { 328 if(baseAddress == null) 329 { 330 return null; 331 } 332 else 333 { 334 if(addressOffset == null) 335 { 336 return baseAddress; 337 } 338 else 339 { 340 return baseAddress + addressOffset; 341 } 342 } 343 } 344 GetMandatoryField(XElement node, string fieldName)345 private static string GetMandatoryField(XElement node, string fieldName) 346 { 347 var fieldElement = node.Element(fieldName); 348 if(fieldElement != null) 349 { 350 return fieldElement.Value; 351 } 352 else 353 { 354 var path = GetPath(node); 355 throw new RecoverableException($"Field '{fieldName}' in '{path}' is required."); 356 } 357 } 358 GetOptionalFieldOrNull(XElement node, string fieldName)359 private static string GetOptionalFieldOrNull(XElement node, string fieldName) 360 { 361 var fieldElement = node.Element(fieldName); 362 if(fieldElement != null) 363 { 364 return fieldElement.Value; 365 } 366 else 367 { 368 return null; 369 } 370 } 371 GetPath(XElement node)372 private static string GetPath(XElement node) 373 { 374 var rootElementName = "device"; 375 var path = node.Element("name") != null ? node.Element("name").Value : $"<{node.Name.LocalName}>"; 376 var tmpElement = node.Parent; 377 if(tmpElement != null) 378 { 379 while(tmpElement.Name != rootElementName) 380 { 381 var tmpNameElement = tmpElement.Element("name"); 382 if(tmpNameElement != null) 383 { 384 path = $"{tmpNameElement.Value}.{path}"; 385 } 386 tmpElement = tmpElement.Parent; 387 } 388 } 389 return path; 390 } 391 SmartParseHexOrDecimal(string whatToParse, XElement node)392 private static ulong? SmartParseHexOrDecimal(string whatToParse, XElement node) 393 { 394 if(whatToParse == null) 395 { 396 return null; 397 } 398 else 399 { 400 SmartParser.Instance.TryParse(whatToParse, typeof(ulong), out var result); 401 if(result != null) 402 { 403 return (ulong)result; 404 } 405 else 406 { 407 throw new RecoverableException($"Cannot parse '{whatToParse}' to a number in '{GetPath(node)}'."); 408 } 409 } 410 } 411 412 private IBusController currentSystemBus; 413 private Dictionary<ulong, SVDRegister> registerDictionary; 414 415 private class SVDDevice 416 { SVDDevice(XElement deviceNode, SVDParser parent)417 public SVDDevice(XElement deviceNode, SVDParser parent) 418 { 419 this.deviceNode = deviceNode; 420 Parent = parent; 421 Description = GetMandatoryField(deviceNode, "description"); 422 Name = GetMandatoryField(deviceNode, "name"); 423 Peripherals = new List<SVDPeripheral>(); 424 425 var cpuElement = deviceNode.Element("cpu"); 426 if(cpuElement == null) 427 { 428 Endianess = Endianess.LittleEndian; 429 } 430 else 431 { 432 var endianessString = GetMandatoryField(cpuElement, "endian"); 433 Endianess = GetEndianess(endianessString); 434 } 435 436 var defaultRegisterSettings = GetLocalRegisterSettings(deviceNode); 437 ScanPeripherals(defaultRegisterSettings); 438 } 439 440 public String Name { get; private set; } 441 public String Description { get; private set; } 442 public Endianess Endianess { get; private set; } 443 public List<SVDPeripheral> Peripherals { get; private set; } 444 public SVDParser Parent { get; private set; } 445 ScanPeripherals(RegisterSettings defaultRegisterSettings)446 private void ScanPeripherals(RegisterSettings defaultRegisterSettings) 447 { 448 if(deviceNode.Element("peripherals") == null) 449 { 450 throw new RecoverableException("There is no <peripherals> section."); 451 } 452 var peripheralElements = deviceNode.Element("peripherals").Elements("peripheral"); 453 if(!peripheralElements.Any()) 454 { 455 Parent.currentSystemBus.Log(LogLevel.Warning, "There are no <peripheral> sections in <peripherals>."); 456 } 457 foreach(var peripheralElement in peripheralElements) 458 { 459 var derivingAttribute = peripheralElement.Attribute("derivedFrom"); 460 if(derivingAttribute == null) 461 { 462 ScanPeripheral(peripheralElement, defaultRegisterSettings); 463 } 464 else 465 { 466 var derivedElement = GetDerivedElementFromTheScope( 467 peripheralElement, 468 peripheralElements, 469 NestingType.Peripheral, 470 derivingAttribute.Value 471 ); 472 if(!peripheralElement.Elements("registers").Any()) 473 { 474 peripheralElement.Add(derivedElement.Element("registers")); 475 } 476 var newDefaultRegisterSettings = GetRegisterSettings(derivedElement, defaultRegisterSettings); 477 ScanPeripheral(peripheralElement, newDefaultRegisterSettings); 478 } 479 } 480 } 481 ScanPeripheral(XElement node, RegisterSettings defaultRegisterSettings)482 private void ScanPeripheral(XElement node, RegisterSettings defaultRegisterSettings) 483 { 484 var name = GetMandatoryField(node, "name"); 485 var newRegisterSettings = GetRegisterSettings(node, defaultRegisterSettings); 486 var peripheral = new SVDPeripheral(name, this); 487 Peripherals.Add(peripheral); 488 489 var registersElement = node.Element("registers"); 490 if(registersElement != null) 491 { 492 ScanRegistersAndClusters(registersElement, newRegisterSettings, peripheral); 493 } 494 } 495 ScanRegistersAndClusters(XElement node, RegisterSettings defaultRegisterSettings, SVDPeripheral peripheral)496 private void ScanRegistersAndClusters(XElement node, RegisterSettings defaultRegisterSettings, SVDPeripheral peripheral) 497 { 498 ScanClusters(node, defaultRegisterSettings, peripheral); 499 ScanRegisters(node, defaultRegisterSettings, peripheral); 500 } 501 GetDerivedElementFromTheScope(XElement element, IEnumerable<XElement> collection, NestingType type, string derivedName)502 private XElement GetDerivedElementFromTheScope(XElement element, IEnumerable<XElement> collection, NestingType type, string derivedName) 503 { 504 var result = collection.FirstOrDefault(x => x.Name == type.ToString().ToLower() && ElementNameEquals(x, derivedName)); 505 if(result == null) 506 { 507 var name = GetMandatoryField(element, "name"); 508 throw new RecoverableException($"The SVD {type} '{name}' derives from '{derivedName}', but '{derivedName}' cannot be found."); 509 } 510 return result; 511 } 512 ScanClusters(XElement node, RegisterSettings defaultRegisterSettings, SVDPeripheral peripheral)513 private void ScanClusters(XElement node, RegisterSettings defaultRegisterSettings, SVDPeripheral peripheral) 514 { 515 var clusterItems = node.Elements("cluster"); 516 foreach(var cluster in clusterItems) 517 { 518 var derivedAttribute = cluster.Attribute("derivedFrom"); 519 if(derivedAttribute == null) 520 { 521 ScanCluster(cluster, defaultRegisterSettings, peripheral); 522 } 523 else 524 { 525 var derivedClusterName = derivedAttribute.Value; 526 var derivedCluster = FindDerivedElement(NestingType.Cluster, cluster, derivedAttribute.Value, defaultRegisterSettings, out var outRegisterSettings); 527 528 if(!cluster.Elements("register").Any()) 529 { 530 cluster.Add(derivedCluster.Elements("register")); 531 } 532 if(!cluster.Elements("cluster").Any()) 533 { 534 cluster.Add(derivedCluster.Elements("cluster")); 535 } 536 537 ScanCluster(cluster, outRegisterSettings, peripheral); 538 } 539 } 540 } 541 ScanRegisters(XElement node, RegisterSettings defaultRegisterSettings, SVDPeripheral peripheral)542 private void ScanRegisters(XElement node, RegisterSettings defaultRegisterSettings, SVDPeripheral peripheral) 543 { 544 var registerItems = node.Elements("register"); 545 foreach(var register in registerItems) 546 { 547 var derivedAttribute = register.Attribute("derivedFrom"); 548 if(derivedAttribute == null) 549 { 550 ScanRegister(register, defaultRegisterSettings, peripheral); 551 } 552 else 553 { 554 var derivedRegisterName = derivedAttribute.Value; 555 var derivedRegister = FindDerivedElement(NestingType.Register, register, derivedAttribute.Value, defaultRegisterSettings, out var outRegisterSettings); 556 557 ScanRegister(register, outRegisterSettings, peripheral); 558 } 559 } 560 } 561 FindDerivedElement(NestingType nestingType, XElement element, String derivedElementName, RegisterSettings defaultRegisterSettings, out RegisterSettings outRegisterSettings)562 private XElement FindDerivedElement(NestingType nestingType, XElement element, String derivedElementName, RegisterSettings defaultRegisterSettings, out RegisterSettings outRegisterSettings) 563 { 564 string[] derivedSplitNode = derivedElementName.Split('.'); 565 outRegisterSettings = defaultRegisterSettings; 566 567 XElement derivedElement; 568 if(derivedSplitNode.Length == 1) 569 { 570 derivedElement = GetDerivedElementFromTheScope( 571 element, 572 element.Parent.Elements(), 573 nestingType, 574 derivedElementName 575 ); 576 } 577 else 578 { 579 var derivedPeripheral = GetDerivedElementFromTheScope( 580 element, 581 deviceNode.Element("peripherals").Elements(), 582 NestingType.Peripheral, 583 derivedSplitNode[0] 584 ); 585 586 outRegisterSettings = GetRegisterSettings(derivedPeripheral, defaultRegisterSettings); 587 derivedElement = derivedPeripheral.Element("registers"); 588 589 // if we are deriving from the cluster we should go through all cluster in the cluster chain, 590 // but if we are deriving from register we should go through all cluster chain but last one. 591 var limit = derivedSplitNode.Length - (nestingType == NestingType.Register ? 1 : 0); 592 for(var i = 1; i < limit; i++) 593 { 594 derivedElement = GetDerivedElementFromTheScope( 595 derivedElement, 596 derivedElement.Elements("cluster"), 597 NestingType.Cluster, 598 derivedSplitNode[i] 599 ); 600 var address = CalculateOffset( 601 outRegisterSettings.Address, 602 GetAddressOffset(derivedElement) 603 ); 604 outRegisterSettings = GetRegisterSettings(derivedElement, outRegisterSettings, address); 605 } 606 // If we are deriving from the register, we must find this register in the last cluster in the chain. 607 if(nestingType == NestingType.Register) 608 { 609 derivedElement = derivedElement.Elements("register").First(x => x.Element("name").Value == derivedSplitNode[derivedSplitNode.Length - 1]); 610 } 611 } 612 outRegisterSettings = GetRegisterSettings(derivedElement, outRegisterSettings, defaultRegisterSettings.Address); 613 return derivedElement; 614 } 615 ScanCluster(XElement node, RegisterSettings defaultRegisterSettings, SVDPeripheral peripheral)616 private void ScanCluster(XElement node, RegisterSettings defaultRegisterSettings, SVDPeripheral peripheral) 617 { 618 GetMandatoryField(node, "name"); 619 var address = CalculateOffset( 620 defaultRegisterSettings.Address, 621 GetAddressOffset(node) 622 ); 623 var newRegisterSettings = GetRegisterSettings(node, defaultRegisterSettings, address); 624 ScanRegistersAndClusters(node, newRegisterSettings, peripheral); 625 } 626 ScanRegister(XElement node, RegisterSettings defaultRegisterSettings, SVDPeripheral peripheral)627 private void ScanRegister(XElement node, RegisterSettings defaultRegisterSettings, SVDPeripheral peripheral) 628 { 629 var address = CalculateOffset( 630 defaultRegisterSettings.Address, 631 GetAddressOffset(node) 632 ); 633 var newRegisterSettings = GetRegisterSettings(node, defaultRegisterSettings, address); 634 var name = GetMandatoryField(node, "name"); 635 var newRegister = new SVDRegister(node, name, newRegisterSettings, peripheral); 636 peripheral.Registers.Add(newRegister); 637 } 638 GetLocalRegisterSettings(XElement node)639 private static RegisterSettings GetLocalRegisterSettings(XElement node) 640 { 641 var sizeString = GetOptionalFieldOrNull(node, "size"); 642 var resetValueString = GetOptionalFieldOrNull(node, "resetValue"); 643 var accessString = GetOptionalFieldOrNull(node, "access"); 644 ulong? address = null; 645 var nodeName = node.Name.LocalName; 646 if(nodeName == NestingType.Peripheral.ToString().ToLower()) 647 { 648 address = GetBaseAddress(node); 649 } 650 else if(nodeName == NestingType.Cluster.ToString().ToLower() || nodeName == NestingType.Register.ToString().ToLower()) 651 { 652 address = GetAddressOffset(node); 653 } 654 655 return new RegisterSettings( 656 (int?)SmartParseHexOrDecimal(sizeString, node), 657 (ulong?)SmartParseHexOrDecimal(resetValueString, node), 658 address, 659 GetPermittedAccess(accessString) 660 ); 661 } 662 GetRegisterSettings(XElement node, RegisterSettings defaultRegisterSettings, ulong? definiteAddress = null)663 private static RegisterSettings GetRegisterSettings(XElement node, RegisterSettings defaultRegisterSettings, ulong? definiteAddress = null) 664 { 665 var localRegisterSettings = GetLocalRegisterSettings(node); 666 return new RegisterSettings( 667 defaultRegisterSettings, 668 localRegisterSettings.Size, 669 localRegisterSettings.ResetValue, 670 definiteAddress ?? localRegisterSettings.Address, 671 localRegisterSettings.Access 672 ); 673 } 674 GetBaseAddress(XElement node)675 private static ulong? GetBaseAddress(XElement node) 676 { 677 var addressOffsetString = GetMandatoryField(node, "baseAddress"); 678 return SmartParseHexOrDecimal(addressOffsetString, node); 679 } 680 GetAddressOffset(XElement node)681 private static ulong? GetAddressOffset(XElement node) 682 { 683 var addressOffsetString = GetMandatoryField(node, "addressOffset"); 684 return SmartParseHexOrDecimal(addressOffsetString, node); 685 } 686 GetPermittedAccess(string accessString)687 private static PermittedAccess? GetPermittedAccess(string accessString) 688 { 689 switch(accessString?.ToLower()) 690 { 691 case null: 692 return null; 693 case "read-only": 694 return PermittedAccess.Read; 695 case "write-only": 696 return PermittedAccess.Write; 697 case "read-write": 698 return PermittedAccess.Read | PermittedAccess.Write; 699 case "writeonce": 700 return PermittedAccess.WriteOnce; 701 case "read-writeonce": 702 return PermittedAccess.Read | PermittedAccess.WriteOnce; 703 default: 704 throw new RecoverableException(string.Format("Found element with unexpected access type: {0}.", accessString)); 705 } 706 } 707 GetEndianess(string endianessString)708 private static Endianess GetEndianess(string endianessString) 709 { 710 switch(endianessString) 711 { 712 case "little": 713 return Endianess.LittleEndian; 714 case "big": 715 return Endianess.BigEndian; 716 case "selectable": 717 return Endianess.Selectable; 718 case "other": 719 return Endianess.Other; 720 default: 721 throw new RecoverableException(string.Format("Found element with unexpected endianess type: {0}.", endianessString)); 722 } 723 } 724 ElementNameEquals(XElement node, string name)725 private static bool ElementNameEquals(XElement node, string name) 726 { 727 var nameElement = node.Elements("name").FirstOrDefault(); 728 if(nameElement != null && nameElement.Value == name) 729 { 730 return true; 731 } 732 return false; 733 } 734 735 private XElement deviceNode; 736 } 737 738 private class SVDPeripheral 739 { SVDPeripheral(string name, SVDDevice includedDevice)740 public SVDPeripheral(string name, SVDDevice includedDevice) 741 { 742 Name = name; 743 Registers = new List<SVDRegister>(); 744 ParentDevice = includedDevice; 745 } 746 747 public string Name { get; private set; } 748 public List<SVDRegister> Registers { get; private set; } 749 public SVDDevice ParentDevice { get; private set; } 750 } 751 752 private class SVDRegister 753 { SVDRegister(XElement node, string name, RegisterSettings settings, SVDPeripheral peripheral)754 public SVDRegister(XElement node, string name, RegisterSettings settings, SVDPeripheral peripheral) 755 { 756 Name = name; 757 path = GetPath(node); 758 Peripheral = peripheral; 759 Size = settings.Size ?? throw new RecoverableException($"Size not provided for register '{path}'."); 760 // Register's size can be not dividable by 8 761 SizeInBytes = (uint)Math.Ceiling(Size / 8.0); 762 // Reset value assumed to be 0 if not provided. Maximum size of the register cropped to 64 bits. 763 ResetValue = (settings.ResetValue & 0xFFFFFFFFFFFFFFFFul) ?? 0u; 764 if(Size > 64) 765 { 766 ResetValue = 0u; 767 Peripheral.ParentDevice.Parent.currentSystemBus.Log( 768 LogLevel.Warning, 769 "Register {0} size set to {1} bits. Registers larger than 64 bits are not supported. Reset value for this register is set to {2}.", 770 Name, 771 Size, 772 ResetValue 773 ); 774 } 775 Address = settings.Address ?? throw new RecoverableException($"Address not provided for register '{path}'."); 776 Access = settings.Access ?? PermittedAccess.Read | PermittedAccess.Write; 777 } 778 779 public bool HasReadAccess => (Access & PermittedAccess.Read) != 0; 780 public bool HasWriteAccess => (Access & PermittedAccess.Write) != 0; 781 public bool HasWriteOnceAccess => (Access & PermittedAccess.WriteOnce) != 0; 782 783 public string Name { get; private set; } 784 public int Size { get; private set; } 785 public ulong Address { get; private set; } 786 public uint SizeInBytes { get; private set; } 787 public PermittedAccess Access { get; private set; } 788 public SVDPeripheral Peripheral { get; private set; } 789 790 public ulong ResetValue 791 { 792 get 793 { 794 return resetValueWithCorrectEndianess; 795 } 796 private set 797 { 798 var resetValueInLittleEndian = value; 799 // In SVD file it is possible to try set larger value than registers capacity is. 800 var max = (ulong)(1L << Size) - 1; 801 if(resetValueInLittleEndian > max) 802 { 803 var normalizeResetValue = resetValueInLittleEndian & max; 804 Peripheral.ParentDevice.Parent.currentSystemBus.Log( 805 LogLevel.Warning, 806 "The reset value 0x{0:X} does not fit to {1}-bit register '{2}'. Reset value set to 0x{3:X}.", 807 resetValueInLittleEndian, 808 Size, 809 path, 810 normalizeResetValue 811 ); 812 resetValueInLittleEndian = normalizeResetValue; 813 } 814 815 if(Peripheral.ParentDevice.Endianess == Endianess.BigEndian) 816 { 817 var resetValueInBigEndian = 0ul; 818 for(var i = 0; i < SizeInBytes; i++) 819 { 820 var tmp = ((resetValueInLittleEndian >> 8 * i) & 0xFF); 821 resetValueInBigEndian += tmp << (int)(8 * (SizeInBytes - 1 - i)); 822 } 823 resetValueWithCorrectEndianess = resetValueInBigEndian; 824 } 825 else 826 { 827 resetValueWithCorrectEndianess = resetValueInLittleEndian; 828 } 829 } 830 } 831 MergeWithRegister(SVDRegister register)832 public void MergeWithRegister(SVDRegister register) 833 { 834 Name = Name + "|" + register.Name; 835 Access |= register.Access; 836 if(!HasReadAccess && register.HasReadAccess) 837 { 838 ResetValue = register.ResetValue; 839 } 840 } 841 842 private ulong resetValueWithCorrectEndianess; 843 private string path; 844 } 845 846 private struct RegisterSettings 847 { RegisterSettingsAntmicro.Renode.Peripherals.Bus.SVDParser.RegisterSettings848 public RegisterSettings(int? size, ulong? resetValue, ulong? address, PermittedAccess? access) 849 { 850 Size = size; 851 ResetValue = resetValue; 852 Address = address; 853 Access = access; 854 } 855 RegisterSettingsAntmicro.Renode.Peripherals.Bus.SVDParser.RegisterSettings856 public RegisterSettings(RegisterSettings parentRegisterSettings, int? size = null, ulong? resetValue = null, ulong? address = null, PermittedAccess? access = null) 857 { 858 Size = size ?? parentRegisterSettings.Size; 859 ResetValue = resetValue ?? parentRegisterSettings.ResetValue; 860 Address = address ?? parentRegisterSettings.Address; 861 Access = access ?? parentRegisterSettings.Access; 862 } 863 864 public int? Size { get; private set; } 865 public ulong? ResetValue { get; private set; } 866 public ulong? Address { get; private set; } 867 public PermittedAccess? Access { get; private set; } 868 } 869 870 [Flags] 871 private enum PermittedAccess 872 { 873 Read = 1, 874 Write = 2, 875 WriteOnce = 4 876 } 877 878 private enum NestingType 879 { 880 Peripheral, 881 Cluster, 882 Register 883 } 884 885 private enum Endianess 886 { 887 LittleEndian, 888 BigEndian, 889 Selectable, 890 Other 891 } 892 893 private enum OperationDirection 894 { 895 Read, 896 Write 897 } 898 } 899 } 900