904 lines
33 KiB
PHP
904 lines
33 KiB
PHP
<?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;
|
|
}
|
|
}
|