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

@@ -1,903 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles\Avr8;
use Bloom\BuildScripts\TargetDescriptionFiles\AddressSpace;
use Bloom\BuildScripts\TargetDescriptionFiles\MemorySegment;
use Bloom\BuildScripts\TargetDescriptionFiles\Register;
use Bloom\BuildScripts\TargetDescriptionFiles\TargetDescriptionFile;
require_once __DIR__ . "/../TargetDescriptionFile.php";
require_once __DIR__ . "/AvrFamily.php";
require_once __DIR__ . "/AvrPhysicalInterface.php";
require_once __DIR__ . "/Signature.php";
require_once __DIR__ . "/TargetParameters.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
{
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->stringToInt($byteZero);
$signature->byteOne = $this->stringToInt($byteOne);
$signature->byteTwo = $this->stringToInt($byteTwo);
return $signature;
}
return null;
}
public function getAvrFamily(): ?AvrFamily
{
if (!empty($this->deviceAttributesByName['avr-family'])) {
if (stristr($this->deviceAttributesByName['avr-family'], 'xmega') !== false) {
return AvrFamily::XMEGA;
} else if (stristr($this->deviceAttributesByName['avr-family'], 'tiny') !== false) {
return AvrFamily::TINY;
} else if (stristr($this->deviceAttributesByName['avr-family'], 'mega') !== false) {
return AvrFamily::MEGA;
} else if (strtolower(trim($this->deviceAttributesByName['avr-family'])) == 'avr da') {
return AvrFamily::DA;
} else if (strtolower(trim($this->deviceAttributesByName['avr-family'])) == 'avr db') {
return AvrFamily::DB;
} else if (strtolower(trim($this->deviceAttributesByName['avr-family'])) == 'avr dd') {
return AvrFamily::DD;
} else if (strtolower(trim($this->deviceAttributesByName['avr-family'])) == 'avr ea') {
return AvrFamily::EA;
}
}
return null;
}
public function getSupportedPhysicalInterfaces(): array
{
$physicalInterfacesByName = [
'isp' => AvrPhysicalInterface::ISP,
'debugwire' => AvrPhysicalInterface::DEBUG_WIRE,
'updi' => AvrPhysicalInterface::UPDI,
'pdi' => AvrPhysicalInterface::PDI,
'jtag' => AvrPhysicalInterface::JTAG,
];
return array_filter(
$physicalInterfacesByName,
function(string $name) {
return isset($this->physicalInterfacesByName[$name]);
},
ARRAY_FILTER_USE_KEY
);
}
public function getSupportedDebugPhysicalInterfaces(): array
{
$physicalInterfacesByName = [
'debugwire' => AvrPhysicalInterface::DEBUG_WIRE,
'updi' => AvrPhysicalInterface::UPDI,
'pdi' => AvrPhysicalInterface::PDI,
'jtag' => AvrPhysicalInterface::JTAG,
];
return array_filter(
$physicalInterfacesByName,
function(string $name) {
return isset($this->physicalInterfacesByName[$name]);
},
ARRAY_FILTER_USE_KEY
);
}
public function getTargetParameters(): TargetParameters
{
$output = new TargetParameters();
$registerMemorySegment = $this->getMemorySegment('data', 'regs');
if ($registerMemorySegment instanceof MemorySegment) {
$output->gpRegisterSize = $registerMemorySegment->size;
$output->gpRegisterStartAddress = $registerMemorySegment->startAddress;
}
$programMemoryAddressSpace = $this->addressSpacesById['prog'] ?? null;
if ($programMemoryAddressSpace instanceof AddressSpace) {
$output->flashSize = $programMemoryAddressSpace->size;
$output->flashStartAddress = $programMemoryAddressSpace->startAddress;
}
$programMemorySegment = $this->getMemorySegment('prog', 'flash');
if ($programMemorySegment instanceof MemorySegment) {
$output->flashPageSize = $programMemorySegment->pageSize;
}
$ramMemorySegment = $this->getMemorySegment('data', 'ram');
if ($ramMemorySegment instanceof MemorySegment) {
$output->ramStartAddress = $ramMemorySegment->startAddress;
$output->ramSize = $ramMemorySegment->size;
}
$eepromMemorySegment = $this->getMemorySegment(
'data',
'eeprom',
'eeprom'
);
if ($eepromMemorySegment instanceof MemorySegment) {
$output->eepromStartAddress = $eepromMemorySegment->startAddress;
$output->eepromSize = $eepromMemorySegment->size;
$output->eepromPageSize = $eepromMemorySegment->pageSize;
} else if (isset($this->addressSpacesById['eeprom'])) {
$eepromAddressSpace = $this->addressSpacesById['eeprom'];
$output->eepromStartAddress = $eepromAddressSpace->startAddress;
$eepromMemorySegment = $this->getMemorySegment('eeprom', 'eeprom');
if ($eepromMemorySegment instanceof MemorySegment) {
$output->eepromSize = $eepromMemorySegment->size;
$output->eepromPageSize = $eepromMemorySegment->pageSize;
}
}
$eepromAddressRegister = $this->getModuleRegister(
'eeprom',
'eeprom',
'eear'
);
if ($eepromAddressRegister instanceof Register) {
$output->eepromAddressRegisterLow = $eepromAddressRegister->offset;
$output->eepromAddressRegisterHigh = ($eepromAddressRegister->size == 2)
? $eepromAddressRegister->offset + 1
: $eepromAddressRegister->offset;
} else {
$eepromAddressRegisterLow = $this->getModuleRegister(
'eeprom',
'eeprom',
'eearl'
);
if ($eepromAddressRegisterLow instanceof Register) {
$output->eepromAddressRegisterLow = $eepromAddressRegisterLow->offset;
$output->eepromAddressRegisterHigh = $eepromAddressRegisterLow->offset;
}
$eepromAddressRegisterHigh = $this->getModuleRegister(
'eeprom',
'eeprom',
'eearh'
);
if ($eepromAddressRegisterHigh instanceof Register) {
$output->eepromAddressRegisterHigh = $eepromAddressRegisterHigh->offset;
}
}
$eepromDataRegister = $this->getModuleRegister(
'eeprom',
'eeprom',
'eedr'
);
if ($eepromDataRegister instanceof Register) {
$output->eepromDataRegisterAddress = $eepromDataRegister->offset;
}
$eepromControlRegister = $this->getModuleRegister(
'eeprom',
'eeprom',
'eecr'
);
if ($eepromControlRegister instanceof Register) {
$output->eepromControlRegisterAddress = $eepromControlRegister->offset;
}
$statusRegister = $this->getModuleRegister(
'cpu',
'cpu',
'sreg'
);
if ($statusRegister instanceof Register) {
$output->statusRegisterStartAddress = $statusRegister->offset;
$output->statusRegisterSize = $statusRegister->size;
}
$stackPointerRegister = $this->getModuleRegister(
'cpu',
'cpu',
'sp'
);
if ($stackPointerRegister instanceof Register) {
$output->stackPointerRegisterLowAddress = $stackPointerRegister->offset;
$output->stackPointerRegisterSize = $stackPointerRegister->size;
} else {
$stackPointerRegisterLow = $this->getModuleRegister(
'cpu',
'cpu',
'spl'
);
if ($stackPointerRegisterLow instanceof Register) {
$output->stackPointerRegisterLowAddress = $stackPointerRegisterLow->offset;
$output->stackPointerRegisterSize = $stackPointerRegisterLow->size;
}
$stackPointerRegisterHigh = $this->getModuleRegister(
'cpu',
'cpu',
'sph'
);
if ($stackPointerRegisterHigh instanceof Register) {
$output->stackPointerRegisterSize += $stackPointerRegisterHigh->size;
}
}
return $output;
}
public function getDebugWireParameters(): DebugWireParameters
{
$output = new DebugWireParameters();
$output->ocdRevision = $this->stringToInt(
$this->getPropertyValue('ocd', 'ocd_revision')
);
$output->ocdDataRegister = $this->stringToInt(
$this->getPropertyValue('ocd', 'ocd_datareg')
);
$spmcsRegister = $this->getModuleRegister(
'cpu',
'cpu',
'spmcsr'
) ?? $this->getModuleRegister(
'cpu',
'cpu',
'spmcr'
) ?? $this->getModuleRegister(
'boot_load',
'boot_load',
'spmcr'
) ?? $this->getModuleRegister(
'boot_load',
'boot_load',
'spmcsr'
);
if ($spmcsRegister instanceof Register) {
$output->spmcRegisterStartAddress = $spmcsRegister->offset;
}
$osccalRegister = $this->getModuleRegister(
'cpu',
'cpu',
'osccal'
) ?? $this->getModuleRegister(
'cpu',
'cpu',
'osccal0'
) ?? $this->getModuleRegister(
'cpu',
'cpu',
'osccal1'
) ?? $this->getModuleRegister(
'cpu',
'cpu',
'fosccal'
) ?? $this->getModuleRegister(
'cpu',
'cpu',
'sosccala'
);
if ($osccalRegister instanceof Register) {
$output->osccalAddress = $osccalRegister->offset;
}
return $output;
}
public function getIspParameters(): IspParameters
{
$output = new IspParameters();
$output->programModeTimeout = $this->stringToInt(
$this->getPropertyValue('isp_interface', 'ispenterprogmode_timeout')
);
$output->programModeStabilizationDelay = $this->stringToInt(
$this->getPropertyValue('isp_interface', 'ispenterprogmode_stabdelay')
);
$output->programModeCommandExecutionDelay = $this->stringToInt(
$this->getPropertyValue('isp_interface', 'ispenterprogmode_cmdexedelay')
);
$output->programModeSyncLoops = $this->stringToInt(
$this->getPropertyValue('isp_interface', 'ispenterprogmode_synchloops')
);
$output->programModeByteDelay = $this->stringToInt(
$this->getPropertyValue('isp_interface', 'ispenterprogmode_bytedelay')
);
$output->programModePollValue = $this->stringToInt(
$this->getPropertyValue('isp_interface', 'ispenterprogmode_pollvalue')
);
$output->programModePollIndex = $this->stringToInt(
$this->getPropertyValue('isp_interface', 'ispenterprogmode_pollindex')
);
$output->programModePreDelay = $this->stringToInt(
$this->getPropertyValue('isp_interface', 'ispleaveprogmode_predelay')
);
$output->programModePostDelay = $this->stringToInt(
$this->getPropertyValue('isp_interface', 'ispleaveprogmode_postdelay')
);
$output->readSignaturePollIndex = $this->stringToInt(
$this->getPropertyValue('isp_interface', 'ispreadsign_pollindex')
);
$output->readFusePollIndex = $this->stringToInt(
$this->getPropertyValue('isp_interface', 'ispreadfuse_pollindex')
);
$output->readLockPollIndex = $this->stringToInt(
$this->getPropertyValue('isp_interface', 'ispreadlock_pollindex')
);
return $output;
}
public function getJtagParameters(): JtagParameters
{
$output = new JtagParameters();
$output->ocdRevision = $this->stringToInt(
$this->getPropertyValue('ocd', 'ocd_revision')
);
$output->ocdDataRegister = $this->stringToInt(
$this->getPropertyValue('ocd', 'ocd_datareg')
);
$spmcsRegister = $this->getModuleRegister(
'cpu',
'cpu',
'spmcsr'
) ?? $this->getModuleRegister(
'cpu',
'cpu',
'spmcr'
) ?? $this->getModuleRegister(
'boot_load',
'boot_load',
'spmcr'
) ?? $this->getModuleRegister(
'boot_load',
'boot_load',
'spmcsr'
);
if ($spmcsRegister instanceof Register) {
$output->spmcRegisterStartAddress = $spmcsRegister->offset;
}
$osccalRegister = $this->getModuleRegister(
'cpu',
'cpu',
'osccal'
) ?? $this->getModuleRegister(
'cpu',
'cpu',
'osccal0'
) ?? $this->getModuleRegister(
'cpu',
'cpu',
'osccal1'
) ?? $this->getModuleRegister(
'cpu',
'cpu',
'fosccal'
) ?? $this->getModuleRegister(
'cpu',
'cpu',
'sosccala'
);
if ($osccalRegister instanceof Register) {
$output->osccalAddress = $osccalRegister->offset;
}
return $output;
}
public function getPdiParameters(): PdiParameters
{
$output = new PdiParameters();
$applicationSectionMemorySegment = $this->getMemorySegment(
'prog',
'flash',
'app_section'
);
if ($applicationSectionMemorySegment instanceof MemorySegment) {
$output->appSectionStartAddress = $applicationSectionMemorySegment->startAddress;
$output->appSectionSize = $applicationSectionMemorySegment->size;
}
$bootSectionMemorySegment = $this->getMemorySegment(
'prog',
'flash',
'boot_section_1'
) ?? $this->getMemorySegment(
'prog',
'flash',
'boot_section'
);
if ($bootSectionMemorySegment instanceof MemorySegment) {
$output->bootSectionStartAddress = $bootSectionMemorySegment->startAddress;
$output->bootSectionSize = $bootSectionMemorySegment->size;
}
$output->appSectionPdiOffset = $this->stringToInt(
$this->getPropertyValue('pdi_interface', 'app_section_offset')
);
$output->bootSectionPdiOffset = $this->stringToInt(
$this->getPropertyValue('pdi_interface', 'boot_section_offset')
);
$output->ramPdiOffset = $this->stringToInt(
$this->getPropertyValue('pdi_interface', 'datamem_offset')
);
$output->eepromPdiOffset = $this->stringToInt(
$this->getPropertyValue('pdi_interface', 'eeprom_offset')
);
$output->userSignaturesPdiOffset = $this->stringToInt(
$this->getPropertyValue('pdi_interface', 'user_signatures_offset')
);
$output->productSignaturesPdiOffset = $this->stringToInt(
$this->getPropertyValue('pdi_interface', 'prod_signatures_offset')
);
$output->fuseRegistersPdiOffset = $this->stringToInt(
$this->getPropertyValue('pdi_interface', 'fuse_registers_offset')
);
$output->lockRegistersPdiOffset = $this->stringToInt(
$this->getPropertyValue('pdi_interface', 'lock_registers_offset')
);
$output->nvmModuleBaseAddress = $this->getPeripheralModuleRegisterGroupOffset(
'nvm',
'nvm',
'nvm'
);
$output->mcuModuleBaseAddress = $this->getPeripheralModuleRegisterGroupOffset(
'mcu',
'mcu',
'mcu'
);
return $output;
}
public function getUpdiParameters(): UpdiParameters
{
$output = new UpdiParameters();
$output->nvmModuleBaseAddress = $this->getPeripheralModuleRegisterGroupOffset(
'nvmctrl',
'nvmctrl',
'nvmctrl'
);
$output->ocdBaseAddress = $this->stringToInt(
$this->getPropertyValue('updi_interface', 'ocd_base_addr')
);
$output->programMemoryStartAddress = $this->stringToInt(
$this->getPropertyValue('updi_interface', 'progmem_offset')
);
$signatureMemorySegment = $this->getMemorySegment(
'data',
'signatures',
'signatures'
);
if ($signatureMemorySegment instanceof MemorySegment) {
$output->signatureSegmentSize = $signatureMemorySegment->size;
$output->signatureSegmentStartAddress = $signatureMemorySegment->startAddress;
}
$fuseMemorySegment = $this->getMemorySegment(
'data',
'fuses',
'fuses'
);
if ($fuseMemorySegment instanceof MemorySegment) {
$output->fuseSegmentSize = $fuseMemorySegment->size;
$output->fuseSegmentStartAddress = $fuseMemorySegment->startAddress;
}
$lockbitsMemorySegment = $this->getMemorySegment(
'data',
'lockbits',
'lockbits'
);
if ($lockbitsMemorySegment instanceof MemorySegment) {
$output->lockbitsSegmentStartAddress = $lockbitsMemorySegment->startAddress;
}
return $output;
}
public function getFuseBitsDescriptor(string $fuseBitName): ?FuseBitsDescriptor
{
$fuseModule = $this->modulesByName['fuse'] ?? null;
if (!empty($fuseModule)) {
$fuseRegisterGroup = $fuseModule->registerGroupsMappedByName['fuse'] ?? null;
if (empty($fuseRegisterGroup)) {
$fuseRegisterGroup = $fuseModule->registerGroupsMappedByName['nvm_fuses'] ?? null;
}
if (!empty($fuseRegisterGroup)) {
foreach ($fuseRegisterGroup->registersMappedByName as $fuseType => $fuseRegister) {
if (isset($fuseRegister->bitFieldsByName[$fuseBitName])) {
return new FuseBitsDescriptor($fuseType);
}
}
}
}
// Try the NVM module
$nvmModule = $this->modulesByName['nvm'] ?? null;
if (!empty($nvmModule)) {
$fuseRegisterGroup = $nvmModule->registerGroupsMappedByName['nvm_fuses'] ?? null;
if (!empty($fuseRegisterGroup)) {
foreach ($fuseRegisterGroup->registersMappedByName as $fuseType => $fuseRegister) {
if (isset($fuseRegister->bitFieldsByName[$fuseBitName])) {
return new FuseBitsDescriptor($fuseType);
}
}
}
}
return null;
}
public function validate(): array
{
$failures = parent::validate();
if (is_null($this->getSignature())) {
$failures[] = "Missing or incomplete AVR signature.";
}
$physicalInterfaces = $this->getSupportedPhysicalInterfaces();
$debugPhysicalInterfaces = $this->getSupportedDebugPhysicalInterfaces();
if (empty($debugPhysicalInterfaces)) {
$failures[] = 'Target does not support any known AVR8 debug interface - the TDF will need to be deleted.'
. ' Aborting validation.';
return $failures;
}
$family = $this->getAvrFamily();
if (is_null($family)) {
$failures[] = 'Unknown AVR8 family';
}
$targetParameters = $this->getTargetParameters();
if (is_null($targetParameters->stackPointerRegisterSize)) {
$failures[] = 'Missing stack pointer register size.';
}
if ($targetParameters->stackPointerRegisterSize > 2) {
// The AVR architecture implementation in GDB expects all SP registers to be a maximum of two bytes in size.
$failures[] = 'Stack pointer register size (' . $targetParameters->stackPointerRegisterSize . ') exceeds maximum (2).';
}
if ($targetParameters->stackPointerRegisterSize < 1) {
$failures[] = 'Stack pointer register size (' . $targetParameters->stackPointerRegisterSize . ') is less than 1.';
}
if (is_null($targetParameters->stackPointerRegisterLowAddress)) {
$failures[] = 'Missing stack pointer register start address.';
}
if (is_null($targetParameters->statusRegisterStartAddress)) {
$failures[] = 'Missing status register start address.';
}
if (is_null($targetParameters->statusRegisterSize)) {
$failures[] = 'Missing status register size.';
} else if ($targetParameters->statusRegisterSize > 1) {
$failures[] = 'Status register size exceeds 1';
}
if (is_null($targetParameters->flashSize)) {
$failures[] = 'Missing flash size.';
}
if (is_null($targetParameters->flashPageSize)) {
$failures[] = 'Missing flash page size.';
}
if (is_null($targetParameters->flashStartAddress)) {
$failures[] = 'Missing flash start address.';
}
if (is_null($targetParameters->ramStartAddress)) {
$failures[] = 'Missing ram start address.';
}
if (is_null($targetParameters->eepromSize)) {
$failures[] = 'Missing eeprom size.';
}
if ($targetParameters->eepromSize < 64) {
/*
* All AVR8 targets supported by Bloom have at least 64 bytes of EEPROM. This is assumed in some areas of
* Bloom's code.
*
* The purpose of this check is to remind me to address those areas of Bloom's code before adding support
* for an AVR8 target with no EEPROM.
*/
$failures[] = 'Unexpected eeprom size.';
}
if (is_null($targetParameters->eepromPageSize)) {
$failures[] = 'Missing eeprom page size.';
}
if (is_null($targetParameters->eepromStartAddress)) {
$failures[] = 'Missing eeprom start address.';
}
if (in_array(AvrPhysicalInterface::DEBUG_WIRE, $debugPhysicalInterfaces)) {
$debugWireParameters = $this->getDebugWireParameters();
$ispParameters = $this->getIspParameters();
if (is_null($debugWireParameters->ocdRevision)) {
$failures[] = 'Missing OCD revision.';
}
if (is_null($debugWireParameters->ocdDataRegister)) {
$failures[] = 'Missing OCD data register address.';
}
if (is_null($debugWireParameters->spmcRegisterStartAddress)) {
$failures[] = 'Missing store program memory control register start address.';
}
if (is_null($debugWireParameters->osccalAddress)) {
$failures[] = 'Missing oscillator calibration register address.';
}
if (!in_array(AvrPhysicalInterface::ISP, $physicalInterfaces)) {
$failures[] = 'Missing ISP interface for debugWire target.';
}
if (is_null($ispParameters->programModeTimeout)) {
$failures[] = 'Missing ispenterprogmode_timeout ISP parameter.';
}
if (is_null($ispParameters->programModeStabilizationDelay)) {
$failures[] = 'Missing ispenterprogmode_stabdelay ISP parameter.';
}
if (is_null($ispParameters->programModeCommandExecutionDelay)) {
$failures[] = 'Missing ispenterprogmode_cmdexedelay ISP parameter.';
}
if (is_null($ispParameters->programModeSyncLoops)) {
$failures[] = 'Missing ispenterprogmode_synchloops ISP parameter.';
}
if (is_null($ispParameters->programModeByteDelay)) {
$failures[] = 'Missing ispenterprogmode_bytedelay ISP parameter.';
}
if (is_null($ispParameters->programModePollValue)) {
$failures[] = 'Missing ispenterprogmode_pollvalue ISP parameter.';
}
if (is_null($ispParameters->programModePollIndex)) {
$failures[] = 'Missing ispenterprogmode_pollindex ISP parameter.';
}
if (is_null($ispParameters->programModePreDelay)) {
$failures[] = 'Missing ispleaveprogmode_predelay ISP parameter.';
}
if (is_null($ispParameters->programModePostDelay)) {
$failures[] = 'Missing ispleaveprogmode_postdelay ISP parameter.';
}
if (is_null($ispParameters->readSignaturePollIndex)) {
$failures[] = 'Missing ispreadsign_pollindex ISP parameter.';
}
if (is_null($ispParameters->readFusePollIndex)) {
$failures[] = 'Missing ispreadfuse_pollindex ISP parameter.';
}
if (is_null($ispParameters->readLockPollIndex)) {
$failures[] = 'Missing ispreadlock_pollindex ISP parameter.';
}
$dwenFuseBitDescriptor = $this->getFuseBitsDescriptor('dwen');
if (empty($dwenFuseBitDescriptor)) {
$failures[] = 'Could not find DWEN fuse bit field for debugWire target.';
} else {
static $validFuseTypes = [
FuseBitsDescriptor::FUSE_TYPE_LOW,
FuseBitsDescriptor::FUSE_TYPE_HIGH,
FuseBitsDescriptor::FUSE_TYPE_EXTENDED,
];
if (!in_array($dwenFuseBitDescriptor->fuseType, $validFuseTypes)) {
$failures[] = 'Invalid/unknown fuse byte type for DWEN fuse bit.';
}
}
}
if (
in_array(AvrPhysicalInterface::JTAG, $debugPhysicalInterfaces)
&& $family == AvrFamily::MEGA
) {
$jtagParameters = $this->getJtagParameters();
if (is_null($jtagParameters->ocdRevision)) {
$failures[] = 'Missing OCD revision.';
}
if (is_null($jtagParameters->ocdDataRegister)) {
$failures[] = 'Missing OCD data register address.';
}
if (is_null($jtagParameters->spmcRegisterStartAddress)) {
$failures[] = 'Missing store program memory control register start address.';
}
if (is_null($jtagParameters->osccalAddress)) {
$failures[] = 'Missing oscillator calibration register address.';
}
if (empty($this->getFuseBitsDescriptor('ocden'))) {
$failures[] = 'Could not find OCDEN fuse bit field for JTAG target.';
}
if (empty($this->getFuseBitsDescriptor('jtagen'))) {
$failures[] = 'Could not find JTAGEN fuse bit field for JTAG target.';
}
}
if (in_array(AvrPhysicalInterface::PDI, $debugPhysicalInterfaces)) {
$pdiParameters = $this->getPdiParameters();
if (is_null($pdiParameters->appSectionPdiOffset)) {
$failures[] = 'Missing app section PDI offset.';
}
if (is_null($pdiParameters->bootSectionPdiOffset)) {
$failures[] = 'Missing boot section PDI offset.';
}
if (is_null($pdiParameters->ramPdiOffset)) {
$failures[] = 'Missing datamem PDI offset.';
}
if (is_null($pdiParameters->eepromPdiOffset)) {
$failures[] = 'Missing eeprom PDI offset.';
}
if (is_null($pdiParameters->userSignaturesPdiOffset)) {
$failures[] = 'Missing user signatures PDI offset.';
}
if (is_null($pdiParameters->productSignaturesPdiOffset)) {
$failures[] = 'Missing product signatures PDI offset.';
}
if (is_null($pdiParameters->lockRegistersPdiOffset)) {
$failures[] = 'Missing lock registers PDI offset.';
}
if (is_null($pdiParameters->nvmModuleBaseAddress)) {
$failures[] = 'Missing NVM module base address.';
}
if (is_null($pdiParameters->mcuModuleBaseAddress)) {
$failures[] = 'Missing MCU module base address.';
}
if (is_null($pdiParameters->appSectionStartAddress)) {
$failures[] = 'Missing APP section start address';
}
if (is_null($pdiParameters->appSectionSize)) {
$failures[] = 'Missing APP section size';
}
}
if (in_array(AvrPhysicalInterface::UPDI, $debugPhysicalInterfaces)) {
$updiParameters = $this->getUpdiParameters();
if (is_null($updiParameters->nvmModuleBaseAddress)) {
$failures[] = 'Missing NVM base address.';
}
if (is_null($updiParameters->programMemoryStartAddress)) {
$failures[] = 'Missing UPDI program memory offset.';
} else if ($updiParameters->programMemoryStartAddress > 0xFFFFFF) {
/*
* Due to size constraints of EDBG AVR8 parameters for UPDI sessions, the program memory offset must
* fit into a 24-bit integer.
*/
$failures[] = 'UPDI program memory offset exceeds maximum value for 24-bit unsigned integer.';
}
if (!is_null($targetParameters->flashPageSize) && $targetParameters->flashPageSize > 0xFFFF) {
$failures[] = 'Flash page size exceeds maximum value for 16-bit unsigned integer.';
}
if (is_null($updiParameters->ocdBaseAddress)) {
$failures[] = 'Missing OCD base address.';
} else if ($updiParameters->ocdBaseAddress > 0xFFFF) {
$failures[] = 'UPDI OCD base address exceeds maximum value for 16-bit unsigned integer.';
}
if (is_null($updiParameters->signatureSegmentStartAddress)) {
$failures[] = 'Missing signature segment start address.';
}
if (is_null($updiParameters->fuseSegmentSize)) {
$failures[] = 'Missing fuse segment size.';
}
if (is_null($updiParameters->fuseSegmentStartAddress)) {
$failures[] = 'Missing fuses segment start address.';
}
if (is_null($updiParameters->lockbitsSegmentStartAddress)) {
$failures[] = 'Missing lockbits segment start address.';
}
}
if (
in_array(AvrPhysicalInterface::JTAG, $debugPhysicalInterfaces)
|| in_array(AvrPhysicalInterface::UPDI, $debugPhysicalInterfaces)
) {
if (empty($this->getFuseBitsDescriptor('eesave'))) {
$failures[] = 'Could not find EESAVE fuse bit field for JTAG/UPDI target.';
}
}
$portPeripheralModule = $this->peripheralModulesByName['port'] ?? null;
if (empty($portPeripheralModule)) {
$failures[] = 'PORT peripheral module not found.';
} else {
$portModule = $this->modulesByName['port'];
foreach ($portPeripheralModule->instancesMappedByName as $portName => $portInstance) {
if (strlen($portName) === 5 && strpos($portName, "port") === 0) {
$portSuffix = substr($portName, strlen($portName) - 1, 1);
if (empty($portInstance->signals)) {
$failures[] = 'No signals defined for port ' . $portInstance->name . ' in PORT peripheral module.';
}
if (empty($portModule->registerGroupsMappedByName['port' . $portSuffix])) {
if (empty($portModule->registerGroupsMappedByName['port']->registersMappedByName['dir'])) {
$failures[] = 'Could not find PORT register group in PORT module, for port '
. $portName . ', using suffix ' . $portSuffix;
}
}
}
}
}
return $failures;
}
}

View File

@@ -1,10 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles\Avr8;
class DebugWireParameters
{
public ?int $ocdRevision = null;
public ?int $ocdDataRegister = null;
public ?int $spmcRegisterStartAddress = null;
public ?int $osccalAddress = null;
}

View File

@@ -1,16 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles\Avr8;
class FuseBitsDescriptor
{
const FUSE_TYPE_LOW = 'low';
const FUSE_TYPE_HIGH = 'high';
const FUSE_TYPE_EXTENDED = 'extended';
public ?string $fuseType = null;
public function __construct(?string $fuseType)
{
$this->fuseType = $fuseType;
}
}

View File

@@ -1,10 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles\Avr8;
class JtagParameters
{
public ?int $ocdRevision = null;
public ?int $ocdDataRegister = null;
public ?int $spmcRegisterStartAddress = null;
public ?int $osccalAddress = null;
}

View File

@@ -1,20 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles\Avr8;
class PdiParameters
{
public ?int $appSectionStartAddress = null;
public ?int $appSectionSize = null;
public ?int $bootSectionStartAddress = null;
public ?int $bootSectionSize = null;
public ?int $appSectionPdiOffset = null;
public ?int $bootSectionPdiOffset = null;
public ?int $eepromPdiOffset = null;
public ?int $ramPdiOffset = null;
public ?int $fuseRegistersPdiOffset = null;
public ?int $lockRegistersPdiOffset = null;
public ?int $userSignaturesPdiOffset = null;
public ?int $productSignaturesPdiOffset = null;
public ?int $nvmModuleBaseAddress = null;
public ?int $mcuModuleBaseAddress = null;
}

View File

@@ -1,15 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
require_once __DIR__ . "/MemorySegment.php";
class AddressSpace
{
public ?string $id = null;
public ?string $name = null;
public ?int $startAddress = null;
public ?int $size = null;
/** @var MemorySegment[][] */
public array $memorySegmentsByTypeAndName = [];
}

View File

@@ -1,7 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
class BitField
{
public ?string $name = null;
}

View File

@@ -1,52 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
use Bloom\BuildScripts\TargetDescriptionFiles\Avr8\Avr8TargetDescriptionFile;
require_once __DIR__ . "/TargetDescriptionFile.php";
require_once __DIR__ . "/TargetFamily.php";
require_once __DIR__ . "/AVR8/Avr8TargetDescriptionFile.php";
class Factory
{
/**
* Loads a target description file with the appropriate class.
*
* @param string $filePath
* @return TargetDescriptionFile
*/
public static function loadTdfFromFile(string $filePath): TargetDescriptionFile
{
$tdf = new TargetDescriptionFile($filePath);
if ($tdf->targetFamily == TargetFamily::AVR_8) {
return new Avr8TargetDescriptionFile($filePath);
}
return $tdf;
}
/**
* Recursively finds all XML files within a given directory.
*
* @param string $dirPath
* @return \SplFileInfo[]
*/
public static function findXmlFiles(string $dirPath): array
{
$output = [];
$directory = new \DirectoryIterator($dirPath);
foreach ($directory as $entry) {
if ($entry->isFile() && $entry->getExtension() == 'xml') {
$output[] = clone $entry;
} else if ($entry->isDir() && !$entry->isDot()) {
$output = array_merge($output, self::findXmlFiles($entry->getPathname()));
}
}
return $output;
}
}

View File

@@ -1,11 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
class MemorySegment
{
public ?string $name = null;
public ?string $type = null;
public ?int $startAddress = null;
public ?int $size = null;
public ?int $pageSize = null;
}

View File

@@ -1,16 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
require_once __DIR__ . "/RegisterGroup.php";
require_once __DIR__ . "/ModuleInstance.php";
class Module
{
public ?string $name = null;
/** @var RegisterGroup[] */
public array $registerGroupsMappedByName = [];
/** @var ModuleInstance[] */
public array $instancesMappedByName = [];
}

View File

@@ -1,16 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
require_once __DIR__ . "/RegisterGroup.php";
require_once __DIR__ . "/Signal.php";
class ModuleInstance
{
public ?string $name = null;
/** @var RegisterGroup[] */
public array $registerGroupsMappedByName = [];
/** @var Signal[] */
public array $signals = [];
}

View File

@@ -1,8 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
class PhysicalInterface
{
public ?string $name = null;
public ?string $type = null;
}

View File

@@ -1,8 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
class Pin
{
public ?string $pad = null;
public ?int $position = null;
}

View File

@@ -1,26 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
require_once __DIR__ . "/PinoutType.php";
require_once __DIR__ . "/Pin.php";
class Pinout
{
public ?string $name = null;
public ?string $function = null;
public ?PinoutType $type = null;
/**
* The name of the pinouts typically include the number of pins. We extract this if we can, so that we can
* validate against it.
*
* For example, for an SOIC pinout with 20 pins, the name of the pinout would be something like "SOIC20"
* or "SOIC_20".
*
* @var int|null
*/
public ?int $expectedPinCount = null;
/** @var Pin[] */
public array $pins = [];
}

View File

@@ -1,12 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
enum PinoutType: string
{
case SOIC = 'SOIC';
case SSOP = 'SSOP';
case DIP = 'DIP';
case QFN = 'QFN';
case QFP = 'QFP';
case BGA = 'BGA';
}

View File

@@ -1,8 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
class Property
{
public ?string $name = null;
public ?string $value = null;
}

View File

@@ -1,12 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
require_once __DIR__ . "/Property.php";
class PropertyGroup
{
public ?string $name = null;
/** @var Property[] */
public array $propertiesMappedByName = [];
}

View File

@@ -1,14 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
require_once __DIR__ . "/BitField.php";
class Register
{
public ?string $name = null;
public ?int $offset = null;
public ?int $size = null;
/** @var BitField[] */
public array $bitFieldsByName = [];
}

View File

@@ -1,13 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
require_once __DIR__ . "/Register.php";
class RegisterGroup
{
public ?string $name = null;
public ?int $offset = null;
/** @var Register[] */
public array $registersMappedByName = [];
}

View File

@@ -1,9 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
class Signal
{
public ?string $padName = null;
public ?string $function = null;
public ?int $index = null;
}

View File

@@ -1,526 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
use Exception;
use SimpleXMLElement;
require_once __DIR__ . "/TargetFamily.php";
require_once __DIR__ . "/Variant.php";
require_once __DIR__ . "/AddressSpace.php";
require_once __DIR__ . "/PropertyGroup.php";
require_once __DIR__ . "/Module.php";
require_once __DIR__ . "/PhysicalInterface.php";
require_once __DIR__ . "/Signal.php";
require_once __DIR__ . "/Pinout.php";
class TargetDescriptionFile
{
public string $filePath;
public ?SimpleXMLElement $xml = null;
public ?string $targetName = null;
public ?TargetFamily $targetFamily = null;
public ?string $configurationValue = null;
/** @var string[] */
public array $deviceAttributesByName = [];
/** @var AddressSpace[] */
protected array $addressSpacesById = [];
/** @var PropertyGroup[] */
protected array $propertyGroupsByName = [];
/** @var Module[] */
protected array $modulesByName = [];
/** @var Module[] */
protected array $peripheralModulesByName = [];
/** @var PhysicalInterface[] */
protected array $physicalInterfacesByName = [];
/** @var Variant[] */
public array $variants = [];
/** @var Pinout[] */
public array $pinoutsMappedByName = [];
public function __construct(string $filePath)
{
$this->filePath = $filePath;
$this->init();
}
protected function init()
{
if (!file_exists($this->filePath)) {
throw new Exception("Invalid TDF file path - file does not exist.");
}
$xml = simplexml_load_file($this->filePath);
if ($xml === false) {
throw new Exception("Failed to parse TDF XML.");
}
$this->xml = $xml;
$device = $this->xml->device;
if (!empty($device)) {
$this->deviceAttributesByName = current((array)$device->attributes());
if (!empty($this->deviceAttributesByName['name'])) {
$this->targetName = $device['name'];
$this->configurationValue = strtolower($device['name']);
}
if (!empty($this->deviceAttributesByName['family'])) {
$this->targetFamily = TargetFamily::tryFrom($device['family']);
}
}
$this->loadVariants();
$this->loadAddressSpaces();
$this->loadPropertyGroups();
$this->loadModules();
$this->loadPeripheralModules();
$this->loadPhysicalInterfaces();
$this->loadPinouts();
}
protected function stringToInt(?string $value): ?int
{
if (is_null($value)) {
return null;
}
return stristr($value, '0x') !== false
? (int) hexdec($value)
: (strlen($value) > 0 ? (int) $value : null);
}
protected function getPeripheralModuleRegisterGroupOffset(
string $moduleName,
string $instanceName,
string $registerGroupName
): ?int {
if (isset($this->peripheralModulesByName[$moduleName])) {
$module = $this->peripheralModulesByName[$moduleName];
if (isset($module->instancesMappedByName[$instanceName])) {
$instance = $module->instancesMappedByName[$instanceName];
if (isset($instance->registerGroupsMappedByName[$registerGroupName])) {
return $instance->registerGroupsMappedByName[$registerGroupName]->offset;
}
}
}
return null;
}
protected function getPropertyValue(string $propertyGroupName, string $propertyName): ?string
{
if (isset($this->propertyGroupsByName[$propertyGroupName])) {
$propertyGroup = $this->propertyGroupsByName[$propertyGroupName];
if (isset($propertyGroup->propertiesMappedByName[$propertyName])) {
return $propertyGroup->propertiesMappedByName[$propertyName]->value;
}
}
return null;
}
protected function getMemorySegment(
string $addressSpaceId,
string $memorySegmentType,
?string $memorySegmentName = null
): ?MemorySegment {
if (isset($this->addressSpacesById[$addressSpaceId])) {
$addressSpace = $this->addressSpacesById[$addressSpaceId];
if (isset($addressSpace->memorySegmentsByTypeAndName[$memorySegmentType])) {
$memorySegmentsByName = $addressSpace->memorySegmentsByTypeAndName[$memorySegmentType];
return !is_null($memorySegmentName)
? $memorySegmentsByName[$memorySegmentName] ?? null
: reset($memorySegmentsByName);
}
}
return null;
}
protected function getMemorySegmentSize(
string $addressSpaceId,
string $memorySegmentType,
?string $memorySegmentName = null
): ?int {
$memorySegment = $this->getMemorySegment($addressSpaceId, $memorySegmentType, $memorySegmentName);
return $memorySegment instanceof MemorySegment ? $this->stringToInt($memorySegment->size) : null;
}
protected function getModuleRegister(
string $moduleName,
string $registerGroupName,
string $registerName
): ?Register {
if (isset($this->modulesByName[$moduleName])) {
$module = $this->modulesByName[$moduleName];
if (isset($module->registerGroupsMappedByName[$registerGroupName])) {
return $module->registerGroupsMappedByName[$registerGroupName]->registersMappedByName[$registerName]
?? null;
}
}
return null;
}
private function loadVariants(): void
{
$variantElements = $this->xml->xpath('variants/variant');
foreach ($variantElements as $variantElement) {
$variantAttributes = $variantElement->attributes();
$variant = new Variant();
if (!empty($variantAttributes['name'])) {
$variant->name = $variantAttributes['name'];
}
if (!empty($variantAttributes['package'])) {
$variant->package = $variantAttributes['package'];
}
if (!empty($variantAttributes['pinout'])) {
$variant->pinout = $variantAttributes['pinout'];
}
$this->variants[] = $variant;
}
}
private function loadAddressSpaces(): void
{
$addressSpaceElements = $this->xml->xpath('device/address-spaces/address-space');
foreach ($addressSpaceElements as $addressSpaceElement) {
$addressSpaceAttrs = $addressSpaceElement->attributes();
$addressSpace = new AddressSpace();
$addressSpace->id = isset($addressSpaceElement['id']) ? $addressSpaceElement['id'] : null;
if (is_null($addressSpace->id)) {
// All address spaces must have an ID - don't bother if one isn't found
continue;
}
$addressSpace->name = isset($addressSpaceAttrs['name']) ? $addressSpaceAttrs['name'] : null;
$addressSpace->startAddress = isset($addressSpaceAttrs['start'])
? $this->stringToInt($addressSpaceAttrs['start']) : null;
$addressSpace->size = isset($addressSpaceAttrs['size'])
? $this->stringToInt($addressSpaceAttrs['size']) : null;
$memorySegmentElements = $addressSpaceElement->xpath('memory-segment');
foreach ($memorySegmentElements as $memorySegmentElement) {
$memorySegmentAttrs = $memorySegmentElement->attributes();
$memorySegment = new MemorySegment();
$memorySegment->name = isset($memorySegmentAttrs['name']) ? $memorySegmentAttrs['name'] : null;
$memorySegment->startAddress = isset($memorySegmentAttrs['start'])
? $this->stringToInt($memorySegmentAttrs['start']) : null;
$memorySegment->type = isset($memorySegmentAttrs['type']) ? $memorySegmentAttrs['type'] : null;
$memorySegment->size = isset($memorySegmentAttrs['size'])
? $this->stringToInt($memorySegmentAttrs['size']) : null;
$memorySegment->pageSize = isset($memorySegmentAttrs['pagesize'])
? $this->stringToInt($memorySegmentAttrs['pagesize']) : null;
$addressSpace->memorySegmentsByTypeAndName[strtolower($memorySegment->type)]
[strtolower($memorySegment->name)] = $memorySegment;
}
$this->addressSpacesById[strtolower($addressSpace->id)] = $addressSpace;
}
}
private function loadPropertyGroups(): void
{
$propertyGroupElements = $this->xml->xpath('device/property-groups/property-group');
foreach ($propertyGroupElements as $propertyGroupElement) {
$propertyGroupAttrs = $propertyGroupElement->attributes();
$propertyGroup = new PropertyGroup();
$propertyGroup->name = isset($propertyGroupAttrs['name']) ? $propertyGroupAttrs['name'] : null;
if (empty($propertyGroup->name)) {
continue;
}
$propertyElements = $propertyGroupElement->xpath('property');
foreach ($propertyElements as $propertyElement) {
$propertyAttrs = $propertyElement->attributes();
$property = new Property();
$property->name = isset($propertyAttrs['name']) ? $propertyAttrs['name'] : null;
if (empty($propertyGroup->name)) {
continue;
}
$property->value = isset($propertyAttrs['value']) ? $propertyAttrs['value'] : null;
$propertyGroup->propertiesMappedByName[strtolower($property->name)] = $property;
}
$this->propertyGroupsByName[strtolower($propertyGroup->name)] = $propertyGroup;
}
}
private function generateRegisterGroupFromElement(SimpleXMLElement $registerGroupElement): ?RegisterGroup
{
$registerGroupAttrs = $registerGroupElement->attributes();
$registerGroup = new RegisterGroup();
$registerGroup->name = isset($registerGroupAttrs['name']) ? $registerGroupAttrs['name'] : null;
if (empty($registerGroup->name)) {
return null;
}
$registerGroup->offset = isset($registerGroupAttrs['offset'])
? $this->stringToInt($registerGroupAttrs['offset']) : null;
$registerElements = $registerGroupElement->xpath('register');
foreach ($registerElements as $registerElement) {
$registerAttrs = $registerElement->attributes();
$register = new Register();
$register->name = isset($registerAttrs['name']) ? $registerAttrs['name'] : null;
if (empty($register->name)) {
continue;
}
$register->offset = isset($registerAttrs['offset'])
? $this->stringToInt($registerAttrs['offset']) : null;
$register->size = isset($registerAttrs['size'])
? $this->stringToInt($registerAttrs['size']) : null;
$bitFieldElements = $registerElement->xpath('bitfield');
foreach ($bitFieldElements as $bitFieldElement) {
$bitFieldAttrs = $bitFieldElement->attributes();
$bitField = new BitField();
$bitField->name = isset($bitFieldAttrs['name']) ? $bitFieldAttrs['name'] : null;
if (empty($bitField->name)) {
continue;
}
$register->bitFieldsByName[strtolower($bitField->name)] = $bitField;
}
$registerGroup->registersMappedByName[strtolower($register->name)] = $register;
}
return $registerGroup;
}
private function generateModuleFromElement(SimpleXMLElement $moduleElement): ?Module
{
$moduleAttrs = $moduleElement->attributes();
$module = new Module();
$module->name = isset($moduleAttrs['name']) ? $moduleAttrs['name'] : null;
if (empty($module->name)) {
return null;
}
$registerGroupElements = $moduleElement->xpath('register-group');
foreach ($registerGroupElements as $registerGroupElement) {
$registerGroup = $this->generateRegisterGroupFromElement($registerGroupElement);
if ($registerGroup instanceof RegisterGroup) {
$module->registerGroupsMappedByName[strtolower($registerGroup->name)] = $registerGroup;
}
}
$instanceElements = $moduleElement->xpath('instance');
foreach ($instanceElements as $instanceElement) {
$instanceAttrs = $instanceElement->attributes();
$moduleInstance = new ModuleInstance();
$moduleInstance->name = isset($instanceAttrs['name']) ? $instanceAttrs['name'] : null;
if (empty($moduleInstance->name)) {
continue;
}
$registerGroupElements = $instanceElement->xpath('register-group');
foreach ($registerGroupElements as $registerGroupElement) {
$registerGroup = $this->generateRegisterGroupFromElement($registerGroupElement);
if ($registerGroup instanceof RegisterGroup) {
$moduleInstance->registerGroupsMappedByName[strtolower($registerGroup->name)] = $registerGroup;
}
}
$signalElements = $instanceElement->xpath('signals/signal');
foreach ($signalElements as $signalElement) {
$signalAttrs = $signalElement->attributes();
$signal = new Signal();
$signal->padName = isset($signalAttrs['pad']) ? $signalAttrs['pad'] : null;
$signal->function = isset($signalAttrs['function']) ? $signalAttrs['function'] : null;
$signal->index = isset($signalAttrs['index']) ? $this->stringToInt($signalAttrs['index']) : null;
$moduleInstance->signals[] = $signal;
}
$module->instancesMappedByName[strtolower($moduleInstance->name)] = $moduleInstance;
}
return $module;
}
private function loadModules(): void
{
$moduleElements = $this->xml->xpath('modules/module');
foreach ($moduleElements as $moduleElement) {
$module = $this->generateModuleFromElement($moduleElement);
if ($module instanceof Module) {
$this->modulesByName[strtolower($module->name)] = $module;
}
}
}
private function loadPeripheralModules(): void
{
$moduleElements = $this->xml->xpath('device/peripherals/module');
foreach ($moduleElements as $moduleElement) {
$module = $this->generateModuleFromElement($moduleElement);
if ($module instanceof Module) {
$this->peripheralModulesByName[strtolower($module->name)] = $module;
}
}
}
private function loadPhysicalInterfaces(): void
{
$interfaceElements = $this->xml->xpath('device/interfaces/interface');
foreach ($interfaceElements as $interfaceElement) {
$interfaceAttrs = $interfaceElement->attributes();
$physicalInterface = new PhysicalInterface();
$physicalInterface->name = isset($interfaceAttrs['name']) ? $interfaceAttrs['name'] : null;
if (empty($physicalInterface->name)) {
continue;
}
$physicalInterface->type = isset($interfaceAttrs['type']) ? $interfaceAttrs['type'] : null;
$this->physicalInterfacesByName[strtolower($physicalInterface->name)] = $physicalInterface;
}
}
private function loadPinouts(): void
{
$pinoutElements = $this->xml->xpath('pinouts/pinout');
foreach ($pinoutElements as $pinoutElement) {
$pinoutAttrs = $pinoutElement->attributes();
$pinout = new Pinout();
$pinout->name = isset($pinoutAttrs['name']) ? $pinoutAttrs['name'] : null;
$pinout->function = isset($pinoutAttrs['function']) ? $pinoutAttrs['function'] : null;
$pinout->type = PinoutType::tryFrom($pinout->name);
// Attempt to extract the number of expected pins for this pinout, from the pinout name
$expectedPinCount = filter_var($pinout->name, FILTER_SANITIZE_NUMBER_INT);
if (is_numeric($expectedPinCount)) {
$pinout->expectedPinCount = (int) $expectedPinCount;
}
$pinElements = $pinoutElement->xpath('pin');
foreach ($pinElements as $pinElement) {
$pinAttrs = $pinElement->attributes();
$pin = new Pin();
$pin->pad = isset($pinAttrs['pad']) ? $pinAttrs['pad'] : null;
$pin->position = isset($pinAttrs['position']) ? $this->stringToInt($pinAttrs['position']) : null;
$pinout->pins[] = $pin;
}
$this->pinoutsMappedByName[strtolower($pinout->name)] = $pinout;
}
}
public function validate(): array
{
$failures = [];
if (empty($this->targetName)) {
$failures[] = 'Target name not found';
}
if (str_contains($this->targetName, ' ')) {
$failures[] = 'Target name cannot contain whitespaces';
}
if (empty($this->targetFamily)) {
$failures[] = 'Missing/invalid target family';
}
if (empty($this->variants)) {
$failures[] = 'Missing target variants';
}
foreach ($this->variants as $variant) {
$variantValidationFailures = $variant->validate();
if (!empty($variantValidationFailures)) {
$failures[] = 'Variant validation failures: ' . implode(", ", $variantValidationFailures);
}
if (empty($this->pinoutsMappedByName[strtolower($variant->pinout)])) {
$failures[] = 'Pinout ("' . $variant->pinout . '") for variant "' . $variant->name . '" not found.';
}
}
if (empty($this->pinoutsMappedByName)) {
$failures[] = 'No pinouts found';
}
foreach ($this->pinoutsMappedByName as $pinout) {
if (!is_null($pinout->expectedPinCount)) {
if ($pinout->expectedPinCount != count($pinout->pins)) {
$failures[] = 'Pin count (' . count($pinout->pins) . ') for pinout "' . $pinout->name
. '" does not match expected pin count (' . $pinout->expectedPinCount . ')';
}
} else {
$failures[] = 'Could not deduce expected pin count for pinout "' . $pinout->name . '"';
}
if (in_array($pinout->type, [PinoutType::DIP, PinoutType::QFN, PinoutType::SOIC])) {
foreach ($pinout->pins as $index => $pin) {
if (is_null($pin->position)) {
$failures[] = 'Missing/invalid pin position for pin (index: ' . $index . ').';
}
if (is_null($pin->pad)) {
$failures[] = 'Missing/invalid pin pad for pin (index: ' . $index . ').';
}
}
}
if (
in_array($pinout->type, [PinoutType::SOIC, PinoutType::DIP, PinoutType::SSOP])
&& count($pinout->pins) % 2 != 0
) {
$failures[] = 'DIP/SOIC/SSOP pinout (' . $pinout->name . ') pin count is not a multiple of two.';
}
if (in_array($pinout->type, [PinoutType::QFN, PinoutType::QFP]) && count($pinout->pins) % 4 != 0) {
$failures[] = 'QFP/QFN pinout (' . $pinout->name . ') pin count is not a multiple of four.';
}
}
return $failures;
}
}

View File

@@ -1,28 +0,0 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
class Variant
{
public ?string $name = null;
public ?string $package = null;
public ?string $pinout = null;
public function validate(): array
{
$failures = [];
if (empty($this->name)) {
$failures[] = 'Name not found';
}
if ($this->name == "standard") {
$failures[] = 'Name set to "standard" - needs attention';
}
if (empty($this->package)) {
$failures[] = 'Package not found';
}
return $failures;
}
}

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

@@ -1,5 +1,5 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles\Avr8;
namespace Targets\TargetDescriptionFiles\Avr8;
enum AvrFamily: string
{

View File

@@ -1,5 +1,5 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles\Avr8;
namespace Targets\TargetDescriptionFiles\Avr8;
enum AvrPhysicalInterface: string
{

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

@@ -1,24 +1,26 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles\Avr8;
namespace Targets\TargetDescriptionFiles\Avr8;
class TargetParameters
require_once __DIR__ . '/BootSection.php';
class DebugWireParameters
{
public ?int $gpRegisterStartAddress = null;
public ?int $gpRegisterSize = null;
public ?int $flashStartAddress = null;
public ?int $flashSize = null;
public ?int $flashPageSize = null;
public ?int $flashSize = null;
public ?int $flashStartAddress = null;
/** @var BootSection[] */
public array $bootSections = [];
public ?int $ramStartAddress = null;
public ?int $ramSize = null;
public ?int $eepromSize = null;
public ?int $eepromPageSize = null;
public ?int $eepromStartAddress = null;
public ?int $ocdRevision = null;
public ?int $ocdDataRegister = null;
public ?int $eepromAddressRegisterHigh = null;
public ?int $eepromAddressRegisterLow = null;
public ?int $eepromDataRegisterAddress = null;
public ?int $eepromControlRegisterAddress = null;
public ?int $statusRegisterStartAddress = null;
public ?int $statusRegisterSize = null;
public ?int $stackPointerRegisterLowAddress = null;
public ?int $stackPointerRegisterSize = 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

@@ -1,5 +1,5 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles\Avr8;
namespace Targets\TargetDescriptionFiles\Avr8;
class IspParameters
{

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

@@ -1,5 +1,5 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles\Avr8;
namespace Targets\TargetDescriptionFiles\Avr8;
class Signature
{
@@ -9,7 +9,7 @@ class Signature
public function toHex(): string
{
if (is_null($this->byteZero) || is_null($this->byteOne) || is_null($this->byteTwo)) {
if ($this->byteZero === null || $this->byteOne === null || $this->byteTwo === null) {
throw new \Exception("Cannot generate hex string of incomplete AVR8 target signature.");
}

View File

@@ -1,13 +1,17 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles\Avr8;
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 $programMemoryStartAddress = null;
public ?int $flashSize = null;
public ?int $eepromSize = null;
public ?int $eepromStartAddress = null;
public ?int $signatureSegmentStartAddress = null;
public ?int $signatureSegmentSize = 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

@@ -1,5 +1,5 @@
<?php
namespace Bloom\BuildScripts\TargetDescriptionFiles;
namespace Targets\TargetDescriptionFiles;
enum TargetFamily: string
{

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;
}
}