Refactored TDF processing PHP code to confirm to new TDF format
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 = [];
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
namespace Bloom\BuildScripts\TargetDescriptionFiles;
|
||||
|
||||
class BitField
|
||||
{
|
||||
public ?string $name = null;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 = [];
|
||||
}
|
||||
@@ -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 = [];
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<?php
|
||||
namespace Bloom\BuildScripts\TargetDescriptionFiles;
|
||||
|
||||
class PhysicalInterface
|
||||
{
|
||||
public ?string $name = null;
|
||||
public ?string $type = null;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<?php
|
||||
namespace Bloom\BuildScripts\TargetDescriptionFiles;
|
||||
|
||||
class Pin
|
||||
{
|
||||
public ?string $pad = null;
|
||||
public ?int $position = null;
|
||||
}
|
||||
@@ -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 = [];
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<?php
|
||||
namespace Bloom\BuildScripts\TargetDescriptionFiles;
|
||||
|
||||
class Property
|
||||
{
|
||||
public ?string $name = null;
|
||||
public ?string $value = null;
|
||||
}
|
||||
@@ -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 = [];
|
||||
}
|
||||
@@ -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 = [];
|
||||
}
|
||||
@@ -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 = [];
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
namespace Bloom\BuildScripts\TargetDescriptionFiles;
|
||||
|
||||
class Signal
|
||||
{
|
||||
public ?string $padName = null;
|
||||
public ?string $function = null;
|
||||
public ?int $index = null;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
namespace Bloom\BuildScripts\TargetDescriptionFiles\Avr8;
|
||||
namespace Targets\TargetDescriptionFiles\Avr8;
|
||||
|
||||
enum AvrFamily: string
|
||||
{
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
namespace Bloom\BuildScripts\TargetDescriptionFiles\Avr8;
|
||||
namespace Targets\TargetDescriptionFiles\Avr8;
|
||||
|
||||
enum AvrPhysicalInterface: string
|
||||
{
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace Targets\TargetDescriptionFiles\Avr8;
|
||||
|
||||
class FuseBitsDescriptor
|
||||
{
|
||||
public ?string $fuseType = null;
|
||||
|
||||
public function __construct(?string $fuseType)
|
||||
{
|
||||
$this->fuseType = strtolower($fuseType);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
namespace Bloom\BuildScripts\TargetDescriptionFiles\Avr8;
|
||||
namespace Targets\TargetDescriptionFiles\Avr8;
|
||||
|
||||
class IspParameters
|
||||
{
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
35
build/scripts/Targets/TargetDescriptionFiles/BitField.php
Normal file
35
build/scripts/Targets/TargetDescriptionFiles/BitField.php
Normal 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
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
42
build/scripts/Targets/TargetDescriptionFiles/Module.php
Normal file
42
build/scripts/Targets/TargetDescriptionFiles/Module.php
Normal 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;
|
||||
}
|
||||
}
|
||||
45
build/scripts/Targets/TargetDescriptionFiles/Peripheral.php
Normal file
45
build/scripts/Targets/TargetDescriptionFiles/Peripheral.php
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
14
build/scripts/Targets/TargetDescriptionFiles/Pin.php
Normal file
14
build/scripts/Targets/TargetDescriptionFiles/Pin.php
Normal 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;
|
||||
}
|
||||
}
|
||||
30
build/scripts/Targets/TargetDescriptionFiles/Pinout.php
Normal file
30
build/scripts/Targets/TargetDescriptionFiles/Pinout.php
Normal 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;
|
||||
}
|
||||
}
|
||||
14
build/scripts/Targets/TargetDescriptionFiles/PinoutType.php
Normal file
14
build/scripts/Targets/TargetDescriptionFiles/PinoutType.php
Normal 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';
|
||||
}
|
||||
14
build/scripts/Targets/TargetDescriptionFiles/Property.php
Normal file
14
build/scripts/Targets/TargetDescriptionFiles/Property.php
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
63
build/scripts/Targets/TargetDescriptionFiles/Register.php
Normal file
63
build/scripts/Targets/TargetDescriptionFiles/Register.php
Normal 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)
|
||||
)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
25
build/scripts/Targets/TargetDescriptionFiles/Signal.php
Normal file
25
build/scripts/Targets/TargetDescriptionFiles/Signal.php
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
namespace Bloom\BuildScripts\TargetDescriptionFiles;
|
||||
namespace Targets\TargetDescriptionFiles;
|
||||
|
||||
enum TargetFamily: string
|
||||
{
|
||||
16
build/scripts/Targets/TargetDescriptionFiles/Variant.php
Normal file
16
build/scripts/Targets/TargetDescriptionFiles/Variant.php
Normal 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;
|
||||
}
|
||||
}
|
||||
56
build/scripts/Targets/TargetPeripheral.php
Normal file
56
build/scripts/Targets/TargetPeripheral.php
Normal 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;
|
||||
}
|
||||
}
|
||||
44
build/scripts/Targets/TargetRegister.php
Normal file
44
build/scripts/Targets/TargetRegister.php
Normal 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;
|
||||
}
|
||||
}
|
||||
25
build/scripts/Targets/TargetRegisterBitField.php
Normal file
25
build/scripts/Targets/TargetRegisterBitField.php
Normal 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;
|
||||
}
|
||||
}
|
||||
75
build/scripts/Targets/TargetRegisterGroup.php
Normal file
75
build/scripts/Targets/TargetRegisterGroup.php
Normal 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user