From 75c58310adef7d82bdd1ab5a01c8ecddf267c4e0 Mon Sep 17 00:00:00 2001 From: Nav Date: Wed, 5 Jun 2024 19:28:49 +0100 Subject: [PATCH] Validating resolved target peripherals in TDF validation --- .../TargetDescriptionFiles/AddressSpace.php | 20 ++++++ .../Services/ValidationService.php | 66 +++++++++++++++++++ .../TargetDescriptionFile.php | 6 +- build/scripts/Targets/TargetRegisterGroup.php | 12 +++- 4 files changed, 101 insertions(+), 3 deletions(-) diff --git a/build/scripts/Targets/TargetDescriptionFiles/AddressSpace.php b/build/scripts/Targets/TargetDescriptionFiles/AddressSpace.php index 597ccdf1..b5f63d26 100644 --- a/build/scripts/Targets/TargetDescriptionFiles/AddressSpace.php +++ b/build/scripts/Targets/TargetDescriptionFiles/AddressSpace.php @@ -61,4 +61,24 @@ class AddressSpace ) ); } + + /** + * Returns all memory segments that intercept with the given address range. + * + * @param int $startAddress + * @param int $endAddress + * + * @return MemorySegment[] + */ + public function findIntersectingMemorySegments(int $startAddress, int $endAddress): array + { + return array_filter( + $this->memorySegments, + function (MemorySegment $segment) use ($startAddress, $endAddress) : bool { + $segmentEndAddress = $segment->startAddress + $segment->size - 1; + return ($startAddress <= $segment->startAddress && $endAddress >= $segment->startAddress) + || ($startAddress >= $segment->startAddress && $startAddress <= $segmentEndAddress); + } + ); + } } diff --git a/build/scripts/Targets/TargetDescriptionFiles/Services/ValidationService.php b/build/scripts/Targets/TargetDescriptionFiles/Services/ValidationService.php index c4b90de1..c6a9b765 100644 --- a/build/scripts/Targets/TargetDescriptionFiles/Services/ValidationService.php +++ b/build/scripts/Targets/TargetDescriptionFiles/Services/ValidationService.php @@ -19,6 +19,8 @@ use Targets\TargetDescriptionFiles\Signal; use Targets\TargetDescriptionFiles\Pinout; use Targets\TargetDescriptionFiles\PinoutType; use Targets\TargetDescriptionFiles\Variant; +use Targets\TargetPeripheral; +use Targets\TargetRegisterGroup; require_once __DIR__ . '/../TargetDescriptionFile.php'; @@ -150,6 +152,15 @@ class ValidationService $processedVariantNames[] = $variant->name; } + // Validate resolved peripherals + foreach ($tdf->peripherals as $peripheral) { + if (($targetPeripheral = $tdf->getTargetPeripheral($peripheral->key)) === null) { + continue; + } + + $failures = array_merge($failures, $this->validateTargetPeripheral($targetPeripheral, $tdf)); + } + return $failures; } @@ -915,4 +926,59 @@ class ValidationService $failures ); } + + protected function validateTargetPeripheral(TargetPeripheral $targetPeripheral, TargetDescriptionFile $tdf): array + { + $failures = []; + + foreach ($targetPeripheral->registerGroups as $registerGroup) { + $failures = array_merge($failures, $this->validateTargetRegisterGroup($registerGroup, $tdf));; + } + + return array_map( + fn (string $failure): string => 'Resolved target peripheral "' . $targetPeripheral->name + . '" validation failure: ' . $failure, + $failures + ); + } + + protected function validateTargetRegisterGroup( + TargetRegisterGroup $registerGroup, + TargetDescriptionFile $tdf + ): array { + $failures = []; + + if ( + !empty($registerGroup->addressSpaceKey) + && ($addressSpace = $tdf->getAddressSpace($registerGroup->addressSpaceKey)) instanceof AddressSpace + ) { + foreach ($registerGroup->registers as $register) { + $intersectingSegments = $addressSpace->findIntersectingMemorySegments( + $register->address, + ($register->address + $register->size - 1) + ); + + if (empty($intersectingSegments)) { + $failures[] = 'Register "' . $register->key . '" is not contained within any memory segment'; + continue; + } + + if (count($intersectingSegments) > 1) { + $segmentKeys = array_map( + fn (MemorySegment $segment): string => '"' . $segment->key . '"', + $intersectingSegments + ); + $failures[] = 'Register "' . $register->key . '" spans multiple memory segments (' + . implode(',', $segmentKeys) . ')'; + continue; + } + } + } + + return array_map( + fn (string $failure): string => 'Target register group "' . $registerGroup->name + . '" validation failure: ' . $failure, + $failures + ); + } } diff --git a/build/scripts/Targets/TargetDescriptionFiles/TargetDescriptionFile.php b/build/scripts/Targets/TargetDescriptionFiles/TargetDescriptionFile.php index 4665a64a..55863e54 100644 --- a/build/scripts/Targets/TargetDescriptionFiles/TargetDescriptionFile.php +++ b/build/scripts/Targets/TargetDescriptionFiles/TargetDescriptionFile.php @@ -273,6 +273,7 @@ class TargetDescriptionFile $output->registerGroups[] = $this->targetRegisterGroupFromRegisterGroup( $registerGroupInstance->key, $registerGroupInstance->name, + $registerGroupInstance->addressSpaceKey, $registerGroup, $registerGroupInstance->offset ?? 0, $peripheral->moduleKey @@ -286,17 +287,19 @@ class TargetDescriptionFile private function targetRegisterGroupFromRegisterGroup( string $key, string $name, + string $addressSpaceKey, RegisterGroup $registerGroup, int $addressOffset, string $moduleKey ): TargetRegisterGroup { $addressOffset += $registerGroup->offset ?? 0; - $output = new TargetRegisterGroup($key, $name, $addressOffset, [], []); + $output = new TargetRegisterGroup($key, $name, $addressSpaceKey, $addressOffset, [], []); foreach ($registerGroup->subgroups as $subgroup) { $output->subgroups[] = $this->targetRegisterGroupFromRegisterGroup( $subgroup->key, $subgroup->name, + $addressSpaceKey, $subgroup, $addressOffset, $moduleKey @@ -310,6 +313,7 @@ class TargetDescriptionFile $output->subgroups[] = $this->targetRegisterGroupFromRegisterGroup( $subgroupReference->key, $subgroupReference->name, + $addressSpaceKey, $subgroup, $addressOffset, $moduleKey diff --git a/build/scripts/Targets/TargetRegisterGroup.php b/build/scripts/Targets/TargetRegisterGroup.php index 0c7fbbd3..d8e749c0 100644 --- a/build/scripts/Targets/TargetRegisterGroup.php +++ b/build/scripts/Targets/TargetRegisterGroup.php @@ -20,6 +20,7 @@ class TargetRegisterGroup { public ?string $key = null; public ?string $name = null; + public ?string $addressSpaceKey = null; public ?int $baseAddress = null; /** @var TargetRegisterGroup[] */ @@ -28,10 +29,17 @@ class TargetRegisterGroup /** @var TargetRegister[] */ public array $registers = []; - public function __construct(?string $key, ?string $name, ?int $baseAddress, array $subgroups, array $registers) - { + public function __construct( + ?string $key, + ?string $name, + ?string $addressSpaceKey, + ?int $baseAddress, + array $subgroups, + array $registers + ) { $this->key = $key; $this->name = $name; + $this->addressSpaceKey = $addressSpaceKey; $this->baseAddress = $baseAddress; $this->subgroups = $subgroups; $this->registers = $registers;