Refactored TDF processing PHP code to confirm to new TDF format

This commit is contained in:
Nav
2024-02-09 23:30:47 +00:00
parent 09a5be91fd
commit c563443737
58 changed files with 1877 additions and 1762 deletions

View File

@@ -0,0 +1,513 @@
<?php
namespace Targets\TargetDescriptionFiles\Avr8;
use Targets\TargetDescriptionFiles\Services\StringService;
use Targets\TargetDescriptionFiles\TargetDescriptionFile;
use Targets\TargetDescriptionFiles\MemorySegment;
use Targets\TargetDescriptionFiles\MemorySegmentSection;
use Targets\TargetDescriptionFiles\PhysicalInterface;
use Targets\TargetPeripheral;
use Targets\TargetRegister;
use Targets\TargetRegisterGroup;
require_once __DIR__ . "/../TargetDescriptionFile.php";
require_once __DIR__ . "/../Services/StringService.php";
require_once __DIR__ . "/AvrFamily.php";
require_once __DIR__ . "/AvrPhysicalInterface.php";
require_once __DIR__ . "/Signature.php";
require_once __DIR__ . "/DebugWireParameters.php";
require_once __DIR__ . "/IspParameters.php";
require_once __DIR__ . "/JtagParameters.php";
require_once __DIR__ . "/PdiParameters.php";
require_once __DIR__ . "/UpdiParameters.php";
require_once __DIR__ . "/FuseBitsDescriptor.php";
class Avr8TargetDescriptionFile extends TargetDescriptionFile
{
private StringService $stringService;
public function __construct(?StringService $stringService = null)
{
$this->stringService = $stringService ?? new StringService();
}
public function getAdditionalDeviceAttributes(): array
{
return [
'avr-family' => $this->getAvrFamily()->value,
];
}
public function getSignature(): ?Signature
{
$byteZero = $this->getPropertyValue('signatures', 'signature0');
$byteOne = $this->getPropertyValue('signatures', 'signature1');
$byteTwo = $this->getPropertyValue('signatures', 'signature2');
if (!empty($byteZero) && !empty($byteOne) && !empty($byteTwo)) {
$signature = new Signature();
$signature->byteZero = $this->stringService->tryStringToInt($byteZero);
$signature->byteOne = $this->stringService->tryStringToInt($byteOne);
$signature->byteTwo = $this->stringService->tryStringToInt($byteTwo);
return $signature;
}
return null;
}
public function getAvrFamily(): ?AvrFamily
{
return AvrFamily::tryFrom($this->deviceAttributesByName['avr-family']);
}
public function getSupportedPhysicalInterfaces(): array
{
$physicalInterfacesByName = [
'isp' => AvrPhysicalInterface::ISP,
'debugwire' => AvrPhysicalInterface::DEBUG_WIRE,
'updi' => AvrPhysicalInterface::UPDI,
'pdi' => AvrPhysicalInterface::PDI,
'jtag' => AvrPhysicalInterface::JTAG,
];
return array_filter(array_map(
fn (PhysicalInterface $interface): ?AvrPhysicalInterface
=> $physicalInterfacesByName[strtolower($interface->name ?? '')] ?? null,
$this->physicalInterfaces
));
}
public function getSupportedDebugPhysicalInterfaces(): array
{
$physicalInterfacesByName = [
'debugwire' => AvrPhysicalInterface::DEBUG_WIRE,
'updi' => AvrPhysicalInterface::UPDI,
'pdi' => AvrPhysicalInterface::PDI,
'jtag' => AvrPhysicalInterface::JTAG,
];
return array_filter(array_map(
fn (PhysicalInterface $interface): ?AvrPhysicalInterface
=> $physicalInterfacesByName[strtolower($interface->name ?? '')] ?? null,
$this->physicalInterfaces
));
}
public function getDebugWireParameters(): DebugWireParameters
{
$output = new DebugWireParameters();
$programMemorySegment = $this->getProgramMemorySegment();
if ($programMemorySegment instanceof MemorySegment) {
$output->flashStartAddress = $programMemorySegment->startAddress;
$output->flashSize = $programMemorySegment->size;
$output->flashPageSize = $programMemorySegment->pageSize;
}
$ramMemorySegment = $this->getRamSegment();
if ($ramMemorySegment instanceof MemorySegment) {
$output->ramStartAddress = $ramMemorySegment->startAddress;
}
$output->bootSections = $this->getBootSections();
$eepromMemorySegment = $this->getEepromSegment();
if ($eepromMemorySegment instanceof MemorySegment) {
$output->eepromSize = $eepromMemorySegment->size;
$output->eepromPageSize = $eepromMemorySegment->pageSize;
}
$output->ocdRevision = $this->stringService->tryStringToInt($this->getPropertyValue('ocd', 'ocd_revision'));
$output->ocdDataRegister = $this->stringService->tryStringToInt($this->getPropertyValue('ocd', 'ocd_datareg'));
$eepromPeripheral = $this->getTargetPeripheral('eeprom');
if ($eepromPeripheral instanceof TargetPeripheral) {
$eepromAddressRegister = $eepromPeripheral->getRegister('eeprom', 'eear');
if ($eepromAddressRegister instanceof TargetRegister) {
$output->eepromAddressRegisterLow = $eepromAddressRegister->address;
$output->eepromAddressRegisterHigh = ($eepromAddressRegister->size == 2)
? $eepromAddressRegister->address + 1
: $eepromAddressRegister->address;
} else {
$eepromAddressRegisterLow = $eepromPeripheral->getRegister('eeprom', 'eearl');
$eepromAddressRegisterHigh = $eepromPeripheral->getRegister('eeprom', 'eearh');
if ($eepromAddressRegisterLow instanceof TargetRegister) {
$output->eepromAddressRegisterLow = $eepromAddressRegisterLow->address;
$output->eepromAddressRegisterHigh = $eepromAddressRegisterLow->address;
}
if ($eepromAddressRegisterHigh instanceof TargetRegister) {
$output->eepromAddressRegisterHigh = $eepromAddressRegisterHigh->address;
}
}
$eepromDataRegister = $eepromPeripheral->getRegister('eeprom', 'eedr');
if ($eepromDataRegister instanceof TargetRegister) {
$output->eepromDataRegisterAddress = $eepromDataRegister->address;
}
$eepromControlRegister = $eepromPeripheral->getRegister('eeprom', 'eecr');
if ($eepromControlRegister instanceof TargetRegister) {
$output->eepromControlRegisterAddress = $eepromControlRegister->address;
}
}
$cpuPeripheral = $this->getTargetPeripheral('cpu');
if ($cpuPeripheral instanceof TargetPeripheral) {
$spmcsRegister = $cpuPeripheral->getRegister('cpu', 'spmcsr')
?? $cpuPeripheral->getRegister('cpu', 'spmcr');
if ($spmcsRegister instanceof TargetRegister) {
$output->spmcRegisterStartAddress = $spmcsRegister->address;
}
$osccalRegister = $cpuPeripheral->getRegister('cpu', 'osccal')
?? $cpuPeripheral->getRegister('cpu', 'osccal0')
?? $cpuPeripheral->getRegister('cpu', 'osccal1')
?? $cpuPeripheral->getRegister('cpu', 'fosccal')
?? $cpuPeripheral->getRegister('cpu', 'sosccala');
if ($osccalRegister instanceof TargetRegister) {
$output->osccalAddress = $osccalRegister->address;
}
}
if ($output->spmcRegisterStartAddress === null) {
$bootLoaderPeripheral = $this->getTargetPeripheral('boot_load');
if ($bootLoaderPeripheral instanceof TargetPeripheral) {
$spmcsRegister = $bootLoaderPeripheral->getRegister('boot_load', 'spmcr')
?? $bootLoaderPeripheral->getRegister('boot_load', 'spmcsr');
if ($spmcsRegister instanceof TargetRegister) {
$output->spmcRegisterStartAddress = $spmcsRegister->address;
}
}
}
return $output;
}
public function getIspParameters(): IspParameters
{
$output = new IspParameters();
$output->programModeTimeout = $this->stringService->tryStringToInt(
$this->getPropertyValue('isp_interface', 'ispenterprogmode_timeout')
);
$output->programModeStabilizationDelay = $this->stringService->tryStringToInt(
$this->getPropertyValue('isp_interface', 'ispenterprogmode_stabdelay')
);
$output->programModeCommandExecutionDelay = $this->stringService->tryStringToInt(
$this->getPropertyValue('isp_interface', 'ispenterprogmode_cmdexedelay')
);
$output->programModeSyncLoops = $this->stringService->tryStringToInt(
$this->getPropertyValue('isp_interface', 'ispenterprogmode_synchloops')
);
$output->programModeByteDelay = $this->stringService->tryStringToInt(
$this->getPropertyValue('isp_interface', 'ispenterprogmode_bytedelay')
);
$output->programModePollValue = $this->stringService->tryStringToInt(
$this->getPropertyValue('isp_interface', 'ispenterprogmode_pollvalue')
);
$output->programModePollIndex = $this->stringService->tryStringToInt(
$this->getPropertyValue('isp_interface', 'ispenterprogmode_pollindex')
);
$output->programModePreDelay = $this->stringService->tryStringToInt(
$this->getPropertyValue('isp_interface', 'ispleaveprogmode_predelay')
);
$output->programModePostDelay = $this->stringService->tryStringToInt(
$this->getPropertyValue('isp_interface', 'ispleaveprogmode_postdelay')
);
$output->readSignaturePollIndex = $this->stringService->tryStringToInt(
$this->getPropertyValue('isp_interface', 'ispreadsign_pollindex')
);
$output->readFusePollIndex = $this->stringService->tryStringToInt(
$this->getPropertyValue('isp_interface', 'ispreadfuse_pollindex')
);
$output->readLockPollIndex = $this->stringService->tryStringToInt(
$this->getPropertyValue('isp_interface', 'ispreadlock_pollindex')
);
return $output;
}
public function getJtagParameters(): JtagParameters
{
$output = new JtagParameters();
$programMemorySegment = $this->getProgramMemorySegment();
if ($programMemorySegment instanceof MemorySegment) {
$output->flashStartAddress = $programMemorySegment->startAddress;
$output->flashSize = $programMemorySegment->size;
$output->flashPageSize = $programMemorySegment->pageSize;
}
$ramMemorySegment = $this->getRamSegment();
if ($ramMemorySegment instanceof MemorySegment) {
$output->ramStartAddress = $ramMemorySegment->startAddress;
}
$output->bootSections = $this->getBootSections();
$eepromMemorySegment = $this->getEepromSegment();
if ($eepromMemorySegment instanceof MemorySegment) {
$output->eepromSize = $eepromMemorySegment->size;
$output->eepromPageSize = $eepromMemorySegment->pageSize;
}
$output->ocdRevision = $this->stringService->tryStringToInt($this->getPropertyValue('ocd', 'ocd_revision'));
$output->ocdDataRegister = $this->stringService->tryStringToInt($this->getPropertyValue('ocd', 'ocd_datareg'));
$eepromPeripheral = $this->getTargetPeripheral('eeprom');
if ($eepromPeripheral instanceof TargetPeripheral) {
$eepromAddressRegister = $eepromPeripheral->getRegister('eeprom', 'eear');
if ($eepromAddressRegister instanceof TargetRegister) {
$output->eepromAddressRegisterLow = $eepromAddressRegister->address;
$output->eepromAddressRegisterHigh = ($eepromAddressRegister->size == 2)
? $eepromAddressRegister->address + 1
: $eepromAddressRegister->address;
} else {
$eepromAddressRegisterLow = $eepromPeripheral->getRegister('eeprom', 'eearl');
$eepromAddressRegisterHigh = $eepromPeripheral->getRegister('eeprom', 'eearh');
if ($eepromAddressRegisterLow instanceof TargetRegister) {
$output->eepromAddressRegisterLow = $eepromAddressRegisterLow->address;
$output->eepromAddressRegisterHigh = $eepromAddressRegisterLow->address;
}
if ($eepromAddressRegisterHigh instanceof TargetRegister) {
$output->eepromAddressRegisterHigh = $eepromAddressRegisterHigh->address;
}
}
$eepromDataRegister = $eepromPeripheral->getRegister('eeprom', 'eedr');
if ($eepromDataRegister instanceof TargetRegister) {
$output->eepromDataRegisterAddress = $eepromDataRegister->address;
}
$eepromControlRegister = $eepromPeripheral->getRegister('eeprom', 'eecr');
if ($eepromControlRegister instanceof TargetRegister) {
$output->eepromControlRegisterAddress = $eepromControlRegister->address;
}
}
$cpuPeripheral = $this->getTargetPeripheral('cpu');
if ($cpuPeripheral instanceof TargetPeripheral) {
$spmcsRegister = $cpuPeripheral->getRegister('cpu', 'spmcsr')
?? $cpuPeripheral->getRegister('cpu', 'spmcr');
if ($spmcsRegister instanceof TargetRegister) {
$output->spmcRegisterStartAddress = $spmcsRegister->address;
}
$osccalRegister = $cpuPeripheral->getRegister('cpu', 'osccal')
?? $cpuPeripheral->getRegister('cpu', 'osccal0')
?? $cpuPeripheral->getRegister('cpu', 'osccal1')
?? $cpuPeripheral->getRegister('cpu', 'fosccal')
?? $cpuPeripheral->getRegister('cpu', 'sosccala');
if ($osccalRegister instanceof TargetRegister) {
$output->osccalAddress = $osccalRegister->address;
}
}
if ($output->spmcRegisterStartAddress === null) {
$bootLoaderPeripheral = $this->getTargetPeripheral('boot_load');
if ($bootLoaderPeripheral instanceof TargetPeripheral) {
$spmcsRegister = $bootLoaderPeripheral->getRegister('boot_load', 'spmcr')
?? $bootLoaderPeripheral->getRegister('boot_load', 'spmcsr');
if ($spmcsRegister instanceof TargetRegister) {
$output->spmcRegisterStartAddress = $spmcsRegister->address;
}
}
}
return $output;
}
public function getPdiParameters(): PdiParameters
{
$output = new PdiParameters();
$output->appSectionOffset = $this->stringService->tryStringToInt(
$this->getPropertyValue('pdi_interface', 'app_section_offset')
);
$output->bootSectionOffset = $this->stringService->tryStringToInt(
$this->getPropertyValue('pdi_interface', 'boot_section_offset')
);
$output->ramOffset = $this->stringService->tryStringToInt(
$this->getPropertyValue('pdi_interface', 'datamem_offset')
);
$output->eepromOffset = $this->stringService->tryStringToInt(
$this->getPropertyValue('pdi_interface', 'eeprom_offset')
);
$output->userSignaturesOffset = $this->stringService->tryStringToInt(
$this->getPropertyValue('pdi_interface', 'user_signatures_offset')
);
$output->productSignaturesOffset = $this->stringService->tryStringToInt(
$this->getPropertyValue('pdi_interface', 'prod_signatures_offset')
);
$output->fuseRegistersOffset = $this->stringService->tryStringToInt(
$this->getPropertyValue('pdi_interface', 'fuse_registers_offset')
);
$output->lockRegistersOffset = $this->stringService->tryStringToInt(
$this->getPropertyValue('pdi_interface', 'lock_registers_offset')
);
$programMemorySegment = $this->getProgramMemorySegment();
if ($programMemorySegment instanceof MemorySegment) {
$output->flashPageSize = $programMemorySegment->pageSize;
$appSection = $programMemorySegment->getSection('app_section');
if ($appSection instanceof MemorySegmentSection) {
$output->appSectionSize = $appSection->size;
}
$bootSection = $programMemorySegment->getSection('boot_section');
if ($bootSection instanceof MemorySegmentSection) {
$output->bootSectionSize = $bootSection->size;
}
}
$eepromMemorySegment = $this->getEepromSegment();
if ($eepromMemorySegment instanceof MemorySegment) {
$output->eepromSize = $eepromMemorySegment->size;
$output->eepromPageSize = $eepromMemorySegment->pageSize;
}
$nvmModuleRegisterGroup = $this->getTargetRegisterGroup('nvm', 'nvm');
if ($nvmModuleRegisterGroup instanceof TargetRegisterGroup) {
$output->nvmModuleBaseAddress = $nvmModuleRegisterGroup->baseAddress;
}
$output->signatureOffset = $this->stringService->tryStringToInt(
$this->getPropertyValue('pdi_interface', 'signature_offset')
);
return $output;
}
public function getUpdiParameters(): UpdiParameters
{
$output = new UpdiParameters();
$output->programMemoryOffset = $this->stringService->tryStringToInt(
$this->getPropertyValue('updi_interface', 'progmem_offset')
);
$programMemorySegment = $this->getProgramMemorySegment();
if ($programMemorySegment instanceof MemorySegment) {
$output->flashSize = $programMemorySegment->size;
$output->flashPageSize = $programMemorySegment->pageSize;
}
$eepromMemorySegment = $this->getEepromSegment();
if ($eepromMemorySegment instanceof MemorySegment) {
$output->eepromStartAddress = $eepromMemorySegment->startAddress;
$output->eepromSize = $eepromMemorySegment->size;
$output->eepromPageSize = $eepromMemorySegment->pageSize;
}
$output->nvmModuleBaseAddress = $this->getTargetRegisterGroup(
'nvmctrl',
'nvmctrl'
)->baseAddress ?? null;
$output->ocdBaseAddress = $this->stringService->tryStringToInt(
$this->getPropertyValue('updi_interface', 'ocd_base_addr')
);
$signatureMemorySegment = $this->getMemorySegment(
'data',
'signatures'
);
if ($signatureMemorySegment instanceof MemorySegment) {
$output->signatureSegmentStartAddress = $signatureMemorySegment->startAddress;
}
$fuseMemorySegment = $this->getMemorySegment(
'data',
'fuses'
);
if ($fuseMemorySegment instanceof MemorySegment) {
$output->fuseSegmentSize = $fuseMemorySegment->size;
$output->fuseSegmentStartAddress = $fuseMemorySegment->startAddress;
}
$lockbitsMemorySegment = $this->getMemorySegment(
'data',
'lockbits'
);
if ($lockbitsMemorySegment instanceof MemorySegment) {
$output->lockbitsSegmentStartAddress = $lockbitsMemorySegment->startAddress;
}
return $output;
}
public function getFuseBitsDescriptor(string $fuseBitFieldKey): ?FuseBitsDescriptor
{
$peripheral = $this->getTargetPeripheral('fuse') ?? $this->getTargetPeripheral('nvm');
if ($peripheral instanceof TargetPeripheral) {
$fuseRegisterGroup = $peripheral->getRegisterGroup('fuse')
?? $peripheral->getRegisterGroup('nvm_fuses');
if ($fuseRegisterGroup instanceof TargetRegisterGroup) {
foreach ($fuseRegisterGroup->registers as $fuseRegister) {
foreach ($fuseRegister->bitFields as $bitField) {
if ($bitField->key === $fuseBitFieldKey) {
return new FuseBitsDescriptor($fuseRegister->name);
}
}
}
}
}
return null;
}
private function getProgramMemorySegment(): ?MemorySegment
{
return $this->getMemorySegment('prog', 'internal_program_memory');
}
private function getRamSegment(): ?MemorySegment
{
return $this->getMemorySegment('data', 'internal_ram');
}
private function getEepromSegment(): ?MemorySegment
{
return $this->getMemorySegment('data', 'internal_eeprom')
?? $this->getMemorySegment('eeprom', 'internal_eeprom');
}
private function getBootSections(): array
{
$output = [];
$bootSectionPropertyGroups = $this->getPropertyGroup('boot_sections')->subPropertyGroups ?? [];
foreach ($bootSectionPropertyGroups as $propertyGroup) {
$output[] = new BootSection(
$this->stringService->tryStringToInt($propertyGroup->getPropertyValue('start_address')),
$this->stringService->tryStringToInt($propertyGroup->getPropertyValue('size')),
$this->stringService->tryStringToInt($propertyGroup->getPropertyValue('page_size'))
);
}
return $output;
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Targets\TargetDescriptionFiles\Avr8;
enum AvrFamily: string
{
case MEGA = 'MEGA';
case TINY = 'TINY';
case XMEGA = 'XMEGA';
case DB = 'DB';
case DA = 'DA';
case DD = 'DD';
case EA = 'EA';
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Targets\TargetDescriptionFiles\Avr8;
enum AvrPhysicalInterface: string
{
case ISP = 'ISP';
case JTAG = 'JTAG';
case PDI = 'PDI';
case UPDI = 'UPDI';
case DEBUG_WIRE = 'DEBUG_WIRE';
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Targets\TargetDescriptionFiles\Avr8;
class BootSection
{
public ?int $startAddress = null;
public ?int $size = null;
public ?int $pageSize = null;
public function __construct(
?int $startAddress,
?int $size,
?int $pageSize
) {
$this->startAddress = $startAddress;
$this->size = $size;
$this->pageSize = $pageSize;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Targets\TargetDescriptionFiles\Avr8;
require_once __DIR__ . '/BootSection.php';
class DebugWireParameters
{
public ?int $flashPageSize = null;
public ?int $flashSize = null;
public ?int $flashStartAddress = null;
/** @var BootSection[] */
public array $bootSections = [];
public ?int $ramStartAddress = null;
public ?int $eepromSize = null;
public ?int $eepromPageSize = null;
public ?int $ocdRevision = null;
public ?int $ocdDataRegister = null;
public ?int $eepromAddressRegisterHigh = null;
public ?int $eepromAddressRegisterLow = null;
public ?int $eepromControlRegisterAddress = null;
public ?int $eepromDataRegisterAddress = null;
public ?int $spmcRegisterStartAddress = null;
public ?int $osccalAddress = null;
}

View File

@@ -0,0 +1,12 @@
<?php
namespace Targets\TargetDescriptionFiles\Avr8;
class FuseBitsDescriptor
{
public ?string $fuseType = null;
public function __construct(?string $fuseType)
{
$this->fuseType = strtolower($fuseType);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Targets\TargetDescriptionFiles\Avr8;
class IspParameters
{
public ?int $programModeTimeout = null;
public ?int $programModeStabilizationDelay = null;
public ?int $programModeCommandExecutionDelay = null;
public ?int $programModeSyncLoops = null;
public ?int $programModeByteDelay = null;
public ?int $programModePollValue = null;
public ?int $programModePollIndex = null;
public ?int $programModePreDelay = null;
public ?int $programModePostDelay = null;
public ?int $readSignaturePollIndex = null;
public ?int $readFusePollIndex = null;
public ?int $readLockPollIndex = null;
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Targets\TargetDescriptionFiles\Avr8;
require_once __DIR__ . '/BootSection.php';
class JtagParameters
{
public ?int $flashPageSize = null;
public ?int $flashSize = null;
public ?int $flashStartAddress = null;
/** @var BootSection[] */
public array $bootSections = [];
public ?int $ramStartAddress = null;
public ?int $eepromSize = null;
public ?int $eepromPageSize = null;
public ?int $ocdRevision = null;
public ?int $ocdDataRegister = null;
public ?int $eepromAddressRegisterHigh = null;
public ?int $eepromAddressRegisterLow = null;
public ?int $eepromControlRegisterAddress = null;
public ?int $eepromDataRegisterAddress = null;
public ?int $spmcRegisterStartAddress = null;
public ?int $osccalAddress = null;
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Targets\TargetDescriptionFiles\Avr8;
class PdiParameters
{
public ?int $appSectionOffset = null;
public ?int $bootSectionOffset = null;
public ?int $eepromOffset = null;
public ?int $fuseRegistersOffset = null;
public ?int $lockRegistersOffset = null;
public ?int $userSignaturesOffset = null;
public ?int $productSignaturesOffset = null;
public ?int $ramOffset = null;
public ?int $appSectionSize = null;
public ?int $bootSectionSize = null;
public ?int $flashPageSize = null;
public ?int $eepromSize = null;
public ?int $eepromPageSize = null;
public ?int $nvmModuleBaseAddress = null;
public ?int $signatureOffset = null;
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Targets\TargetDescriptionFiles\Avr8;
class Signature
{
public ?int $byteZero = null;
public ?int $byteOne = null;
public ?int $byteTwo = null;
public function toHex(): string
{
if ($this->byteZero === null || $this->byteOne === null || $this->byteTwo === null) {
throw new \Exception("Cannot generate hex string of incomplete AVR8 target signature.");
}
return '0x' . substr('0' . dechex($this->byteZero), -2)
. substr('0' . dechex($this->byteOne), -2)
. substr('0' . dechex($this->byteTwo), -2)
;
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Targets\TargetDescriptionFiles\Avr8;
class UpdiParameters
{
public ?int $programMemoryOffset = null;
public ?int $flashPageSize = null;
public ?int $eepromPageSize = null;
public ?int $nvmModuleBaseAddress = null;
public ?int $ocdBaseAddress = null;
public ?int $flashSize = null;
public ?int $eepromSize = null;
public ?int $eepromStartAddress = null;
public ?int $signatureSegmentStartAddress = null;
public ?int $fuseSegmentStartAddress = null;
public ?int $fuseSegmentSize = null;
public ?int $lockbitsSegmentStartAddress = null;
}

View File

@@ -0,0 +1,53 @@
<?php
namespace Targets\TargetDescriptionFiles;
require_once __DIR__ . "/MemorySegment.php";
class AddressSpace
{
public ?string $key = null;
public ?int $startAddress = null;
public ?int $size = null;
public ?string $endianness = null;
/** @var MemorySegment[] */
public array $memorySegments = [];
public function __construct(?string $key, ?int $startAddress, ?int $size, ?string $endianness)
{
$this->key = $key;
$this->startAddress = $startAddress;
$this->size = $size;
$this->endianness = $endianness;
}
public function totalSegmentSize(): int
{
return array_sum(
array_map(
fn (MemorySegment $segment): int => (int) $segment->size,
$this->memorySegments
)
);
}
public function segmentStartAddress(): int
{
return min(
array_map(
fn (MemorySegment $segment): int => (int) $segment->startAddress,
$this->memorySegments
)
);
}
public function segmentEndAddress(): int
{
return max(
array_map(
fn (MemorySegment $segment): int => (int) $segment->startAddress + $segment->size - 1,
$this->memorySegments
)
);
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace Targets\TargetDescriptionFiles;
class BitField
{
public ?string $key = null;
public ?string $name = null;
public ?string $description = null;
public ?int $mask = null;
public ?string $access = null;
public function __construct(
?string $key,
?string $name,
?string $description,
?int $mask,
?string $access
) {
$this->key = $key;
$this->name = $name;
$this->description = $description;
$this->mask = $mask;
$this->access = $access;
}
public function intersectsWith(BitField $other): bool
{
return
$this->mask !== null
&& $other->mask !== null
&& ($this->mask & $other->mask) !== 0
;
}
}

View File

@@ -0,0 +1,98 @@
<?php
namespace Targets\TargetDescriptionFiles;
require_once __DIR__ . "/MemorySegmentType.php";
require_once __DIR__ . "/MemorySegmentSection.php";
class MemorySegment
{
public ?string $key = null;
public ?string $name = null;
public ?MemorySegmentType $type = null;
public ?int $startAddress = null;
public ?int $size = null;
public ?int $pageSize = null;
public ?string $access = null;
/** @var MemorySegmentSection[] */
public array $sections = [];
public function __construct(
?string $key,
?string $name,
?MemorySegmentType $type,
?int $startAddress,
?int $size,
?int $pageSize,
?string $access,
array $sections
) {
$this->key = $key;
$this->name = $name;
$this->type = $type;
$this->startAddress = $startAddress;
$this->size = $size;
$this->pageSize = $pageSize;
$this->access = $access;
$this->sections = $sections;
}
public function getSection(string $sectionId): ?MemorySegmentSection
{
foreach ($this->sections as $section) {
if ($section->key !== $sectionId) {
continue;
}
return $section;
}
return null;
}
public function contains(MemorySegment $other): bool
{
$endAddress = !is_null($this->startAddress) && !is_null($this->size)
? ($this->startAddress + $this->size - 1) : null;
$otherEndAddress = !is_null($other->startAddress) && !is_null($other->size)
? ($other->startAddress + $other->size - 1) : null;
return
$this->startAddress !== null
&& $endAddress !== null
&& $other->startAddress !== null
&& $otherEndAddress !== null
&& $this->startAddress <= $other->startAddress
&& $endAddress >= $otherEndAddress
;
}
public function intersectsWith(MemorySegment $other): bool
{
$endAddress = !is_null($this->startAddress) && !is_null($this->size)
? ($this->startAddress + $this->size - 1) : null;
$otherEndAddress = !is_null($other->startAddress) && !is_null($other->size)
? ($other->startAddress + $other->size - 1) : null;
return
$this->startAddress !== null
&& $endAddress !== null
&& $other->startAddress !== null
&& $otherEndAddress !== null
&& (
($other->startAddress <= $this->startAddress && $otherEndAddress >= $this->startAddress)
|| ($other->startAddress >= $this->startAddress && $other->startAddress <= $endAddress)
)
;
}
public function totalSectionSize(): int
{
return array_sum(
array_map(
fn (MemorySegmentSection $section): int => (int) $section->size,
$this->sections
)
);
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace Targets\TargetDescriptionFiles;
class MemorySegmentSection
{
public ?string $key = null;
public ?string $name = null;
public ?int $startAddress = null;
public ?int $size = null;
/** @var MemorySegmentSection[] */
public array $subSections = [];
public function __construct(
?string $key,
?string $name,
?int $startAddress,
?int $size,
array $subSections
) {
$this->key = $key;
$this->name = $name;
$this->startAddress = $startAddress;
$this->size = $size;
$this->subSections = $subSections;
}
public function contains(MemorySegment $other): bool
{
$endAddress = !is_null($this->startAddress) && !is_null($this->size)
? ($this->startAddress + $this->size - 1) : null;
$otherEndAddress = !is_null($other->startAddress) && !is_null($other->size)
? ($other->startAddress + $other->size - 1) : null;
return
$this->startAddress !== null
&& $endAddress !== null
&& $other->startAddress !== null
&& $otherEndAddress !== null
&& $this->startAddress <= $other->startAddress
&& $endAddress >= $otherEndAddress
;
}
public function intersectsWith(MemorySegmentSection $other): bool
{
$endAddress = !is_null($this->startAddress) && !is_null($this->size)
? ($this->startAddress + $this->size - 1) : null;
$otherEndAddress = !is_null($other->startAddress) && !is_null($other->size)
? ($other->startAddress + $other->size - 1) : null;
return
$this->startAddress !== null
&& $endAddress !== null
&& $other->startAddress !== null
&& $otherEndAddress !== null
&& (
($other->startAddress <= $this->startAddress && $otherEndAddress >= $this->startAddress)
|| ($other->startAddress >= $this->startAddress && $other->startAddress <= $endAddress)
)
;
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Targets\TargetDescriptionFiles;
enum MemorySegmentType: string
{
case ALIASED = 'aliased';
case GENERAL_PURPOSE_REGISTERS = 'gp_registers';
case EEPROM = 'eeprom';
case FLASH = 'flash';
case FUSES = 'fuses';
case IO = 'io';
case RAM = 'ram';
case LOCKBITS = 'lockbits';
case OSCCAL = 'osccal';
case PRODUCTION_SIGNATURES = 'production_signatures';
case SIGNATURES = 'signatures';
case USER_SIGNATURES = 'user_signatures';
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Targets\TargetDescriptionFiles;
require_once __DIR__ . "/RegisterGroup.php";
class Module
{
public ?string $key = null;
public ?string $name = null;
public ?string $description = null;
/** @var RegisterGroup[] */
public array $registerGroups = [];
public function __construct(
?string $key,
?string $name,
?string $description,
array $registerGroups,
) {
$this->key = $key;
$this->name = $name;
$this->description = $description;
$this->registerGroups = $registerGroups;
}
public function getRegisterGroup(array|string $keys): ?RegisterGroup
{
if (is_string($keys)) {
$keys = explode('.', $keys);
}
$firstLevelSubGroupId = array_shift($keys);
foreach ($this->registerGroups as $registerGroup) {
if ($registerGroup->key === $firstLevelSubGroupId) {
return !empty($keys) ? $registerGroup->getSubGroup($keys) : $registerGroup;
}
}
return null;
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Targets\TargetDescriptionFiles;
require_once __DIR__ . "/RegisterGroup.php";
require_once __DIR__ . "/RegisterGroupReference.php";
require_once __DIR__ . "/Signal.php";
class Peripheral
{
public ?string $key = null;
public ?string $name = null;
public ?string $moduleKey = null;
public ?string $moduleName = null;
/** @var RegisterGroupReference[] */
public array $registerGroupReferences = [];
/** @var Signal[] */
public array $signals = [];
public function __construct(
?string $key,
?string $name,
?string $moduleKey,
array $registerGroupReferences,
array $signals
) {
$this->key = $key;
$this->name = $name;
$this->moduleKey = $moduleKey;
$this->registerGroupReferences = $registerGroupReferences;
$this->signals = $signals;
}
public function getRegisterGroupReference(string $key): ?RegisterGroupReference
{
foreach ($this->registerGroupReferences as $reference) {
if ($reference->key === $key) {
return $reference;
}
}
return null;
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Targets\TargetDescriptionFiles;
class PhysicalInterface
{
public ?string $name = null;
public ?string $type = null;
public function __construct(?string $name, ?string $type)
{
$this->name = $name;
$this->type = $type;
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Targets\TargetDescriptionFiles;
class Pin
{
public ?string $position = null;
public ?string $pad = null;
public function __construct(?string $position, ?string $pad)
{
$this->position = $position;
$this->pad = $pad;
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Targets\TargetDescriptionFiles;
require_once __DIR__ . "/PinoutType.php";
require_once __DIR__ . "/Pin.php";
class Pinout
{
public ?string $key = null;
public ?string $name = null;
public ?PinoutType $type = null;
public ?string $function = null;
/** @var Pin[] */
public array $pins = [];
public function __construct(
?string $key,
?string $name,
?PinoutType $type,
?string $function,
array $pins
) {
$this->key = $key;
$this->name = $name;
$this->type = $type;
$this->function = $function;
$this->pins = $pins;
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Targets\TargetDescriptionFiles;
enum PinoutType: string
{
case SOIC = 'soic';
case SSOP = 'ssop';
case DIP = 'dip';
case QFN = 'qfn';
case MLF = 'mlf';
case DUAL_ROW_QFN = 'drqfn';
case QFP = 'qfp';
case BGA = 'bga';
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Targets\TargetDescriptionFiles;
class Property
{
public ?string $key = null;
public ?string $value = null;
public function __construct(?string $key, ?string $value)
{
$this->key = $key;
$this->value = $value;
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace Targets\TargetDescriptionFiles;
require_once __DIR__ . "/Property.php";
class PropertyGroup
{
public ?string $key = null;
/** @var Property[] */
public array $properties = [];
/** @var PropertyGroup[] */
public array $subPropertyGroups = [];
public function __construct(
?string $key,
array $subPropertyGroups,
array $properties,
) {
$this->key = $key;
$this->subPropertyGroups = $subPropertyGroups;
$this->properties = $properties;
}
public function getSubGroup(array|string $subGroupKeys): ?PropertyGroup
{
if (is_string($subGroupKeys)) {
$subGroupKeys = explode('.', $subGroupKeys);
}
$firstLevelSubGroupKey = array_shift($subGroupKeys);
foreach ($this->subPropertyGroups as $subGroup) {
if ($subGroup->key === $firstLevelSubGroupKey) {
return !empty($subGroupKeys) ? $subGroup->getSubGroup($subGroupKeys) : $subGroup;
}
}
return null;
}
public function getProperty(string $propertyKey): ?Property
{
foreach ($this->properties as $property) {
if ($property->key === $propertyKey) {
return $property;
}
}
return null;
}
public function getPropertyValue(string $propertyKey): ?string
{
return ($property = $this->getProperty($propertyKey)) instanceof Property ? $property->value : null;
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace Targets\TargetDescriptionFiles;
require_once __DIR__ . "/BitField.php";
class Register
{
public ?string $key = null;
public ?string $name = null;
public ?string $description = null;
public ?int $offset = null;
public ?int $size = null;
public ?int $initialValue = null;
public ?string $access = null;
public ?bool $alternative = null;
/** @var BitField[] */
public array $bitFieldsByName = [];
/** @var BitField[] */
public array $bitFields = [];
public function __construct(
?string $key,
?string $name,
?string $description,
?int $offset,
?int $size,
?int $initialValue,
?string $access,
?bool $alternative,
array $bitFields
) {
$this->key = $key;
$this->name = $name;
$this->description = $description;
$this->offset = $offset;
$this->size = $size;
$this->initialValue = $initialValue;
$this->access = $access;
$this->alternative = $alternative;
$this->bitFields = $bitFields;
}
public function intersectsWith(Register $other): bool
{
$endAddress = !is_null($this->offset) && !is_null($this->size)
? ($this->offset + $this->size - 1) : null;
$otherEndAddress = !is_null($other->offset) && !is_null($other->size)
? ($other->offset + $other->size - 1) : null;
return
$this->offset !== null
&& $endAddress !== null
&& $other->offset !== null
&& $otherEndAddress !== null
&& (
($other->offset <= $this->offset && $otherEndAddress >= $this->offset)
|| ($other->offset >= $this->offset && $other->offset <= $endAddress)
)
;
}
}

View File

@@ -0,0 +1,76 @@
<?php
namespace Targets\TargetDescriptionFiles;
require_once __DIR__ . "/Register.php";
require_once __DIR__ . "/RegisterGroupReference.php";
class RegisterGroup
{
public ?string $key = null;
public ?string $name = null;
public ?int $offset = null;
/** @var Register[] */
public array $registersMappedByName = [];
/** @var Register[] */
public array $registers = [];
/** @var RegisterGroup[] */
public array $subGroups = [];
/** @var RegisterGroupReference[] */
public array $subGroupReferences = [];
public function __construct(
?string $key,
?string $name,
?int $offset,
array $registers,
array $subGroups,
array $subGroupReferences
) {
$this->key = $key;
$this->name = $name;
$this->offset = $offset;
$this->registers = $registers;
$this->subGroups = $subGroups;
$this->subGroupReferences = $subGroupReferences;
}
public function getRegister(array|string $keys): ?Register
{
if (is_string($keys)) {
$keys = explode('.', $keys);
}
$registerKey = array_pop($keys);
$group = !empty($keys) > 1 ? $this->getSubGroup($keys) : $this;
if ($group instanceof RegisterGroup) {
foreach ($group->registers as $register) {
if ($register->key === $registerKey) {
return $register;
}
}
}
return null;
}
public function getSubGroup(array|string $subGroupKeys): ?RegisterGroup
{
if (is_string($subGroupKeys)) {
$subGroupKeys = explode('.', $subGroupKeys);
}
$firstLevelSubGroupKey = array_shift($subGroupKeys);
foreach ($this->subGroups as $subGroup) {
if ($subGroup->key === $firstLevelSubGroupKey) {
return !empty($subGroupKeys) ? $subGroup->getSubGroup($subGroupKeys) : $subGroup;
}
}
return null;
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Targets\TargetDescriptionFiles;
require_once __DIR__ . "/Register.php";
class RegisterGroupReference
{
public ?string $key = null;
public ?string $name = null;
public ?string $registerGroupKey = null;
public ?int $offset = null;
public ?string $description = null;
public function __construct(
?string $key,
?string $name,
?string $registerGroupKey,
?int $offset,
?string $description
) {
$this->key = $key;
$this->name = $name;
$this->registerGroupKey = $registerGroupKey;
$this->offset = $offset;
$this->description = $description;
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Targets\TargetDescriptionFiles\Services;
class StringService
{
public function tryStringToInt(?string $value): ?int
{
if ($value === null || strlen($value) === 0) {
return null;
}
return stristr($value, '0x') !== false ? (int) hexdec($value) : (int) $value;
}
public function tryIntToHex(?int $value, int $pad = 0): string
{
if ($value === null) {
return '';
}
return '0x' . str_pad(strtoupper(dechex($value)), $pad, '0', STR_PAD_LEFT);
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Targets\TargetDescriptionFiles;
class Signal
{
public ?string $padId = null;
public ?int $index = null;
public ?string $function = null;
public ?string $group = null;
public ?string $field = null;
public function __construct(
?string $padId,
?int $index,
?string $function,
?string $group,
?string $field
) {
$this->padId = $padId;
$this->index = $index;
$this->function = $function;
$this->group = $group;
$this->field = $field;
}
}

View File

@@ -0,0 +1,331 @@
<?php
namespace Targets\TargetDescriptionFiles;
use Targets\TargetPeripheral;
use Targets\TargetRegister;
use Targets\TargetRegisterBitField;
use Targets\TargetRegisterGroup;
require_once __DIR__ . "/PropertyGroup.php";
require_once __DIR__ . "/AddressSpace.php";
require_once __DIR__ . "/PhysicalInterface.php";
require_once __DIR__ . "/Peripheral.php";
require_once __DIR__ . "/Signal.php";
require_once __DIR__ . "/Module.php";
require_once __DIR__ . "/RegisterGroup.php";
require_once __DIR__ . "/RegisterGroupReference.php";
require_once __DIR__ . "/Register.php";
require_once __DIR__ . "/Pinout.php";
require_once __DIR__ . "/Variant.php";
require_once __DIR__ . "/TargetFamily.php";
require_once __DIR__ . "/../TargetPeripheral.php";
require_once __DIR__ . "/../TargetRegisterGroup.php";
require_once __DIR__ . "/../TargetRegister.php";
require_once __DIR__ . "/../TargetRegisterBitField.php";
class TargetDescriptionFile
{
/** @var string[] */
public array $deviceAttributesByName = [];
/** @var PropertyGroup[] */
public array $propertyGroups = [];
/** @var AddressSpace[] */
public array $addressSpaces = [];
/** @var PhysicalInterface[] */
public array $physicalInterfaces = [];
/** @var Peripheral[] */
public array $peripherals = [];
/** @var Module[] */
public array $modules = [];
/** @var Pinout[] */
public array $pinouts = [];
/** @var Variant[] */
public array $variants = [];
public function getAdditionalDeviceAttributes(): array
{
return [];
}
public function getName(): ?string
{
return $this->deviceAttributesByName['name'] ?? null;
}
public function getFamily(): ?TargetFamily
{
return TargetFamily::tryFrom($this->deviceAttributesByName['family'] ?? null);
}
public function getConfigurationValue(): ?string
{
return $this->deviceAttributesByName['configuration-value'] ?? null;
}
public function getArchitecture(): ?string
{
return $this->deviceAttributesByName['architecture'] ?? null;
}
public function getVendor(): ?string
{
return $this->deviceAttributesByName['vendor'] ?? null;
}
public function getPropertyGroup(array|string $keys): ?PropertyGroup
{
if (is_string($keys)) {
$keys = explode('.', $keys);
}
$firstLevelGroupKey = array_shift($keys);
foreach ($this->propertyGroups as $propertyGroup) {
if ($propertyGroup->key === $firstLevelGroupKey) {
return !empty($keys) ? $propertyGroup->getSubGroup($keys) : $propertyGroup;
}
}
return null;
}
public function getProperty(array|string $propertyGroupKeys, $propertyKey): ?Property
{
return ($propertyGroup = $this->getPropertyGroup($propertyGroupKeys)) instanceof PropertyGroup
? $propertyGroup->getProperty($propertyKey)
: null;
}
public function getPropertyValue(array|string $propertyGroupKeys, $propertyKey): ?string
{
return ($property = $this->getProperty($propertyGroupKeys, $propertyKey)) instanceof Property
? $property->value
: null;
}
public function getAddressSpace(string $key): ?AddressSpace
{
foreach ($this->addressSpaces as $addressSpace) {
if ($addressSpace->key != $key) {
continue;
}
return $addressSpace;
}
return null;
}
public function getMemorySegment(string $addressSpaceKey, string $memorySegmentKey): ?MemorySegment
{
if (($addressSpace = $this->getAddressSpace($addressSpaceKey)) instanceof AddressSpace) {
foreach ($addressSpace->memorySegments as $memorySegment) {
if ($memorySegment->key !== $memorySegmentKey) {
continue;
}
return $memorySegment;
}
}
return null;
}
public function getMemorySegmentsFromAnyAddressSpace(string $key): ?MemorySegment
{
foreach ($this->addressSpaces as $addressSpace) {
foreach ($addressSpace->memorySegments as $memorySegment) {
if ($memorySegment->key === $key) {
return $memorySegment;
}
}
}
return null;
}
public function getPeripheral(string $key): ?Peripheral
{
foreach ($this->peripherals as $peripheral) {
if ($peripheral->key === $key) {
return $peripheral;
}
}
return null;
}
/**
* Gets all peripherals of a particular module
*
* @param string $moduleKey
* @return Peripheral[]
*/
public function getPeripheralsOfModule(string $moduleKey): array
{
return array_filter(
$this->peripherals,
fn (Peripheral $peripheral): bool => $peripheral->moduleKey === $moduleKey
);
}
public function removePeripheral(string $key): void
{
$this->peripherals = array_filter(
$this->peripherals,
fn (Peripheral $peripheral): bool => $peripheral->key !== $key
);
}
public function getModule(string $key): ?Module
{
foreach ($this->modules as $module) {
if ($module->key === $key) {
return $module;
}
}
return null;
}
/**
* Will rename the key of the given module, and update all associated peripherals.
*
* @param Module $module
* @param string $newKey
* @return void
*/
public function renameModuleKey(Module $module, string $newKey): void
{
foreach ($this->getPeripheralsOfModule($module->key) as $peripheral) {
$peripheral->moduleKey = $newKey;
}
$module->key = $newKey;
}
public function getPinout(string $key): ?Pinout
{
foreach ($this->pinouts as $pinout) {
if ($pinout->key === $key) {
return $pinout;
}
}
return null;
}
public function getTargetPeripheral(string $peripheralKey): ?TargetPeripheral
{
$peripheral = $this->getPeripheral($peripheralKey);
return $peripheral instanceof Peripheral ? $this->targetPeripheralFromPeripheral($peripheral) : null;
}
public function getTargetRegisterGroup(string $peripheralKey, array|string $registerGroupKeys): ?TargetRegisterGroup
{
$peripheral = $this->getPeripheral($peripheralKey);
return $peripheral instanceof Peripheral
? $this->targetPeripheralFromPeripheral($peripheral)->getRegisterGroup($registerGroupKeys)
: null;
}
public function getTargetRegister(
string $peripheralKey,
array|string $groupKeys,
array|string $registerKeys
): ?TargetRegister {
return ($peripheral = $this->getPeripheral($peripheralKey)) instanceof Peripheral
? $this->targetPeripheralFromPeripheral($peripheral)->getRegister($groupKeys, $registerKeys)
: null;
}
public function resolveRegisterGroupReference(
RegisterGroupReference $registerGroupReference,
string $moduleKey
): ?RegisterGroup {
$module = $this->getModule($moduleKey);
return $module instanceof Module ? $module->getRegisterGroup($registerGroupReference->registerGroupKey) : null;
}
private function targetPeripheralFromPeripheral(Peripheral $peripheral): TargetPeripheral
{
$output = new TargetPeripheral($peripheral->name, []);
foreach ($peripheral->registerGroupReferences as $registerGroupReference) {
$registerGroup = $this->resolveRegisterGroupReference($registerGroupReference, $peripheral->moduleKey);
if ($registerGroup instanceof RegisterGroup) {
$output->registerGroups[] = $this->targetRegisterGroupFromRegisterGroup(
$registerGroup,
$registerGroupReference->offset ?? 0,
$peripheral->moduleKey
);
}
}
return $output;
}
private function targetRegisterGroupFromRegisterGroup(
RegisterGroup $registerGroup,
int $addressOffset,
string $moduleKey
): TargetRegisterGroup {
$addressOffset += $registerGroup->offset ?? 0;
$output = new TargetRegisterGroup($registerGroup->key, $registerGroup->name, $addressOffset, [], []);
foreach ($registerGroup->subGroups as $subGroup) {
$output->subGroups[] = $this->targetRegisterGroupFromRegisterGroup($subGroup, $addressOffset, $moduleKey);
}
foreach ($registerGroup->subGroupReferences as $subGroupReference) {
$subGroup = $this->resolveRegisterGroupReference($subGroupReference, $moduleKey);
if ($subGroup instanceof RegisterGroup) {
$output->subGroups[] = $this->targetRegisterGroupFromRegisterGroup(
$subGroup,
$addressOffset,
$moduleKey
);
}
}
foreach ($registerGroup->registers as $register) {
$output->registers[] = $this->targetRegisterFromRegister($register, $addressOffset);
}
return $output;
}
private function targetRegisterFromRegister(Register $register, int $addressOffset): TargetRegister
{
return new TargetRegister(
$register->key,
$register->name,
$addressOffset + $register->offset,
$register->size,
$register->description,
array_map(
fn (BitField $bitField): TargetRegisterBitField => $this->targetRegisterBitFieldFromBitField($bitField),
$register->bitFields
)
);
}
private function targetRegisterBitFieldFromBitField(BitField $bitField): TargetRegisterBitField
{
return new TargetRegisterBitField(
$bitField->key,
$bitField->name,
$bitField->description,
$bitField->mask,
$bitField->access
);
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Targets\TargetDescriptionFiles;
enum TargetFamily: string
{
case AVR_8 = 'AVR8';
case RISC_V = 'RISCV';
}

View File

@@ -0,0 +1,16 @@
<?php
namespace Targets\TargetDescriptionFiles;
class Variant
{
public ?string $name = null;
public ?string $pinoutKey = null;
public ?string $package = null;
public function __construct(?string $name, ?string $pinoutKey, ?string $package)
{
$this->name = $name;
$this->pinoutKey = $pinoutKey;
$this->package = $package;
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace Targets;
use Targets\TargetDescriptionFiles\TargetDescriptionFile;
require_once __DIR__ . "/TargetRegisterGroup.php";
/**
* Do not confuse this with `TargetDescriptionFiles\Peripheral` - that class represents a <peripheral> element in a
* TDF, meaning it only contains references to register groups and their respective offsets. Those register group
* references are unresolved, meaning you can't access any of the referenced group's registers or subgroups.
*
* This class represents a **resolved** target peripheral - meaning all the referenced register groups are resolved,
* along with their respective addresses. With this class, we can access all peripheral registers/register groups, and
* their absolute addresses.
*
* This class is constructed from a `TargetDescriptionFiles\Peripheral` object.
* @see TargetDescriptionFile::getTargetPeripheral() for more.
*/
class TargetPeripheral
{
public ?string $name = null;
/** @var TargetRegisterGroup[] */
public array $registerGroups = [];
public function __construct(?string $name, array $registerGroups)
{
$this->name = $name;
$this->registerGroups = $registerGroups;
}
public function getRegisterGroup(array|string $keys): ?TargetRegisterGroup
{
if (is_string($keys)) {
$keys = explode('.', $keys);
}
$firstLevelSubGroupId = array_shift($keys);
foreach ($this->registerGroups as $registerGroup) {
if ($registerGroup->key === $firstLevelSubGroupId) {
return !empty($keys) ? $registerGroup->getSubGroup($keys) : $registerGroup;
}
}
return null;
}
public function getRegister(array|string $groupKeys, array|string $keys): ?TargetRegister
{
return ($group = $this->getRegisterGroup($groupKeys)) instanceof TargetRegisterGroup
? ($register = $group->getRegister($keys)) instanceof TargetRegister ? $register : null
: null;
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace Targets;
use Targets\TargetDescriptionFiles\TargetDescriptionFile;
require_once __DIR__ . "/TargetRegisterBitField.php";
/**
* Do not confuse this with `TargetDescriptionFiles\Register` - that class represents a <register> element in a TDF,
* which is part of some unresolved register group.
*
* This class represents a **resolved** target register, within a register group, within a target peripheral. With
* this class, we can access the absolute address of the register.
*
* This class is constructed from a `TargetDescriptionFiles\Register` object.
* @see TargetDescriptionFile::getTargetRegister() for more.
*/
class TargetRegister
{
public ?string $key = null;
public ?string $name = null;
public ?int $address = null;
public ?int $size = null;
public ?string $description = null;
/** @var TargetRegisterBitField[] */
public array $bitFields;
public function __construct(
?string $key,
?string $name,
?int $address,
?int $size,
?string $description,
array $bitFields
) {
$this->key = $key;
$this->name = $name;
$this->address = $address;
$this->size = $size;
$this->description = $description;
$this->bitFields = $bitFields;
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Targets;
class TargetRegisterBitField
{
public ?string $key = null;
public ?string $name = null;
public ?string $description = null;
public ?int $mask = null;
public ?string $access = null;
public function __construct(
?string $key,
?string $name,
?string $description,
?int $mask,
?string $access
) {
$this->key = $key;
$this->name = $name;
$this->description = $description;
$this->mask = $mask;
$this->access = $access;
}
}

View File

@@ -0,0 +1,75 @@
<?php
namespace Targets;
use Targets\TargetDescriptionFiles\TargetDescriptionFile;
require_once __DIR__ . "/TargetRegister.php";
/**
* Do not confuse this with `TargetDescriptionFiles\RegisterGroup` - that class represents a <register-group> element
* in a TDF. Any references to subgroups will be unresolved.
*
* This class represents a **resolved** target register group, within a target peripheral. With this class, we can
* access all subgroups, including referenced subgroups, along with their registers.
*
* This class is constructed from a `TargetDescriptionFiles\RegisterGroup` object.
* @see TargetDescriptionFile::getTargetRegisterGroup() for more.
*/
class TargetRegisterGroup
{
public ?string $key = null;
public ?string $name = null;
public ?int $baseAddress = null;
/** @var TargetRegisterGroup[] */
public array $subGroups = [];
/** @var TargetRegister[] */
public array $registers = [];
public function __construct(?string $key, ?string $name, ?int $baseAddress, array $subGroups, array $registers)
{
$this->key = $key;
$this->name = $name;
$this->baseAddress = $baseAddress;
$this->subGroups = $subGroups;
$this->registers = $registers;
}
public function getRegister(array|string $keys): ?TargetRegister
{
if (is_string($keys)) {
$keys = explode('.', $keys);
}
$registerKey = array_pop($keys);
$group = !empty($keys) > 1 ? $this->getSubGroup($keys) : $this;
if ($group instanceof TargetRegisterGroup) {
foreach ($group->registers as $register) {
if ($register->key === $registerKey) {
return $register;
}
}
}
return null;
}
public function getSubGroup(array|string $subGroupKeys): ?TargetRegisterGroup
{
if (is_string($subGroupKeys)) {
$subGroupKeys = explode('.', $subGroupKeys);
}
$firstLevelSubGroupKey = array_shift($subGroupKeys);
foreach ($this->subGroups as $subGroup) {
if ($subGroup->key === $firstLevelSubGroupKey) {
return !empty($subGroupKeys) ? $subGroup->getSubGroup($subGroupKeys) : $subGroup;
}
}
return null;
}
}