diff --git a/CMakeLists.txt b/CMakeLists.txt index 414e06d..d021ee7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,18 +142,34 @@ endif() # compile-time constant; a different PUREBOOT_TIMEOUT builds the re-timed # binary a self-update then installs. set(PUREBOOT_TIMEOUT 8 CACHE STRING "pureboot activation window, seconds") -# Every mega runs the loader from its hardware boot section and boots the -# application at word 0; the tinies get the trampoline surgery. All megas -# assume a 16 MHz crystal at 115200 Bd; the tinies their internal RC at -# 57600 Bd over the software UART. -if(LIBAVR_MCU STREQUAL "attiny13a") +# Per-family geometry. The boot-sectioned megas run the loader from the +# hardware boot section and boot the application at word 0; the tinies and +# the boot-section-less m48s get the trampoline surgery. All megas assume a +# 16 MHz crystal at 115200 Bd; the tinies their internal RC at 57600 Bd over +# the software UART. --pmem-wrap-around models AVR's modulo-flash PC where +# the flash is big enough to need it (an rjmp reaches all of 4 KiB by +# itself). +if(LIBAVR_MCU MATCHES "^attiny13a?$") set(_pb_flash 1024) set(_pb_wrap "") set(_pb_page 32) set(_pb_hz 9600000) set(_pb_baud 57600) set(_pb_eeprom 64) - set(_pb_limit 510) +elseif(LIBAVR_MCU STREQUAL "attiny25") + set(_pb_flash 2048) + set(_pb_wrap "") + set(_pb_page 32) + set(_pb_hz 8000000) + set(_pb_baud 57600) + set(_pb_eeprom 128) +elseif(LIBAVR_MCU STREQUAL "attiny45") + set(_pb_flash 4096) + set(_pb_wrap "") + set(_pb_page 64) + set(_pb_hz 8000000) + set(_pb_baud 57600) + set(_pb_eeprom 256) elseif(LIBAVR_MCU STREQUAL "attiny85") set(_pb_flash 8192) set(_pb_wrap -Wl,--pmem-wrap-around=8k) @@ -161,40 +177,47 @@ elseif(LIBAVR_MCU STREQUAL "attiny85") set(_pb_hz 8000000) set(_pb_baud 57600) set(_pb_eeprom 512) - set(_pb_limit 510) -elseif(LIBAVR_MCU MATCHES "^atmega8a?$") +elseif(LIBAVR_MCU MATCHES "^atmega48(a|p|pa)?$") + set(_pb_flash 4096) + set(_pb_wrap "") + set(_pb_page 64) + set(_pb_hz 16000000) + set(_pb_baud 115200) + set(_pb_eeprom 256) +elseif(LIBAVR_MCU MATCHES "^atmega8a?$" OR LIBAVR_MCU MATCHES "^atmega88(a|p|pa)?$") set(_pb_flash 8192) set(_pb_wrap -Wl,--pmem-wrap-around=8k) set(_pb_page 64) set(_pb_hz 16000000) set(_pb_baud 115200) set(_pb_eeprom 512) - set(_pb_limit 512) -elseif(LIBAVR_MCU STREQUAL "atmega16") +elseif(LIBAVR_MCU MATCHES "^atmega16a?$" OR LIBAVR_MCU MATCHES "^atmega168(a|p|pa)?$" OR + LIBAVR_MCU MATCHES "^atmega164(a|p|pa)$") set(_pb_flash 16384) set(_pb_wrap -Wl,--pmem-wrap-around=16k) set(_pb_page 128) set(_pb_hz 16000000) set(_pb_baud 115200) set(_pb_eeprom 512) - set(_pb_limit 512) -elseif(LIBAVR_MCU MATCHES "^atmega32a?$") +elseif(LIBAVR_MCU MATCHES "^atmega32a?$" OR LIBAVR_MCU MATCHES "^atmega328p?$" OR + LIBAVR_MCU MATCHES "^atmega324(a|p|pa)$") set(_pb_flash 32768) set(_pb_wrap -Wl,--pmem-wrap-around=32k) set(_pb_page 128) set(_pb_hz 16000000) set(_pb_baud 115200) set(_pb_eeprom 1024) - set(_pb_limit 512) -elseif(LIBAVR_MCU STREQUAL "atmega168a") - set(_pb_flash 16384) - set(_pb_wrap -Wl,--pmem-wrap-around=16k) - set(_pb_page 128) +elseif(LIBAVR_MCU MATCHES "^atmega644(a|p|pa)?$") + # 64 KiB is exactly the 16-bit byte space: plain LPM reaches everything, + # and the smallest boot section (1 KiB) holds the loader and its staging + # slot together (see pureboot/README.md). + set(_pb_flash 65536) + set(_pb_wrap -Wl,--pmem-wrap-around=64k) + set(_pb_page 256) set(_pb_hz 16000000) set(_pb_baud 115200) - set(_pb_eeprom 512) - set(_pb_limit 512) -elseif(LIBAVR_MCU STREQUAL "atmega1284p") + set(_pb_eeprom 2048) +elseif(LIBAVR_MCU MATCHES "^atmega1284p?$") # 128 KiB: wire flash addresses are word addresses, reads go through # ELPM, and the PC's modulo wrap exceeds what --pmem-wrap-around models. # The slot is 1 KiB — this chip's own smallest boot sector; the far @@ -205,36 +228,35 @@ elseif(LIBAVR_MCU STREQUAL "atmega1284p") set(_pb_hz 16000000) set(_pb_baud 115200) set(_pb_eeprom 4096) - set(_pb_limit 1024) set(_pb_slot 1024) + set(_pb_limit 1024) else() - set(_pb_flash 32768) - set(_pb_wrap -Wl,--pmem-wrap-around=32k) - set(_pb_page 128) - set(_pb_hz 16000000) - set(_pb_baud 115200) - set(_pb_eeprom 1024) - set(_pb_limit 512) + message(FATAL_ERROR "pureboot: no geometry for ${LIBAVR_MCU}") endif() if(NOT DEFINED _pb_slot) set(_pb_slot 512) endif() math(EXPR _pb_base "${_pb_flash} - ${_pb_slot}") math(EXPR _pb_base_hex "${_pb_base}" OUTPUT_FORMAT HEXADECIMAL) -if(LIBAVR_MCU MATCHES "^atmega") +# Patched-vector chips hand over through the trampoline word below the slot, +# which is also the slot's own last word — their budget is slot − 2. +if(LIBAVR_MCU MATCHES "^atmega" AND NOT LIBAVR_MCU MATCHES "^atmega48") set(_pb_app 0) + if(NOT DEFINED _pb_limit) + set(_pb_limit ${_pb_slot}) + endif() else() math(EXPR _pb_app "${_pb_base} - 2") + math(EXPR _pb_limit "${_pb_slot} - 2") endif() -# simavr names its cores after the base dies; the A revisions run on them. +# simavr names its cores after the base dies; the A revisions run on them +# (the 644PA on the 644P core). set(_pb_sim_mcu ${LIBAVR_MCU}) -if(LIBAVR_MCU STREQUAL "atmega8a") - set(_pb_sim_mcu atmega8) -elseif(LIBAVR_MCU STREQUAL "atmega32a") - set(_pb_sim_mcu atmega32) -elseif(LIBAVR_MCU STREQUAL "atmega168a") - set(_pb_sim_mcu atmega168) +if(LIBAVR_MCU MATCHES "^atmega(8|16|32|48|88|164|168|644)a$") + string(REGEX REPLACE "a$" "" _pb_sim_mcu ${LIBAVR_MCU}) +elseif(LIBAVR_MCU STREQUAL "atmega644pa") + set(_pb_sim_mcu atmega644p) endif() add_executable(pureboot pureboot/pureboot.cpp) diff --git a/CMakePresets.json b/CMakePresets.json index 2125036..9114944 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,517 +1,1813 @@ { - "version": 8, - "configurePresets": [ - { - "name": "base", - "hidden": true, - "generator": "Ninja", - "binaryDir": "${sourceDir}/build/${presetName}", - "toolchainFile": "$env{LIBAVR_ROOT}/cmake/avr-toolchain.cmake", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Release", - "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", - "CMAKE_COLOR_DIAGNOSTICS": "ON" - } - }, - { - "name": "atmega328p-generated", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega328p", - "LIBAVR_REFLECT": "OFF" - } - }, - { - "name": "atmega328p-reflect", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega328p", - "LIBAVR_REFLECT": "ON" - } - }, - { - "name": "attiny85-generated", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "attiny85", - "LIBAVR_REFLECT": "OFF" - } - }, - { - "name": "attiny85-reflect", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "attiny85", - "LIBAVR_REFLECT": "ON" - } - }, - { - "name": "attiny13a-generated", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "attiny13a", - "LIBAVR_REFLECT": "OFF" - } - }, - { - "name": "attiny13a-reflect", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "attiny13a", - "LIBAVR_REFLECT": "ON" - } - }, - { - "name": "atmega8-generated", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega8", - "LIBAVR_REFLECT": "OFF" - } - }, - { - "name": "atmega8-reflect", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega8", - "LIBAVR_REFLECT": "ON" - } - }, - { - "name": "atmega8a-generated", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega8a", - "LIBAVR_REFLECT": "OFF" - } - }, - { - "name": "atmega8a-reflect", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega8a", - "LIBAVR_REFLECT": "ON" - } - }, - { - "name": "atmega16-generated", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega16", - "LIBAVR_REFLECT": "OFF" - } - }, - { - "name": "atmega16-reflect", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega16", - "LIBAVR_REFLECT": "ON" - } - }, - { - "name": "atmega32-generated", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega32", - "LIBAVR_REFLECT": "OFF" - } - }, - { - "name": "atmega32-reflect", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega32", - "LIBAVR_REFLECT": "ON" - } - }, - { - "name": "atmega32a-generated", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega32a", - "LIBAVR_REFLECT": "OFF" - } - }, - { - "name": "atmega32a-reflect", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega32a", - "LIBAVR_REFLECT": "ON" - } - }, - { - "name": "atmega168a-generated", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega168a", - "LIBAVR_REFLECT": "OFF" - } - }, - { - "name": "atmega168a-reflect", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega168a", - "LIBAVR_REFLECT": "ON" - } - }, - { - "name": "atmega1284p-generated", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega1284p", - "LIBAVR_REFLECT": "OFF" - } - }, - { - "name": "atmega1284p-reflect", - "inherits": "base", - "cacheVariables": { - "LIBAVR_MCU": "atmega1284p", - "LIBAVR_REFLECT": "ON" - } - } - ], - "buildPresets": [ - { - "name": "atmega328p-generated", - "configurePreset": "atmega328p-generated" - }, - { - "name": "atmega328p-reflect", - "configurePreset": "atmega328p-reflect" - }, - { - "name": "attiny85-generated", - "configurePreset": "attiny85-generated" - }, - { - "name": "attiny85-reflect", - "configurePreset": "attiny85-reflect" - }, - { - "name": "attiny13a-generated", - "configurePreset": "attiny13a-generated" - }, - { - "name": "attiny13a-reflect", - "configurePreset": "attiny13a-reflect" - }, - { - "name": "atmega8-generated", - "configurePreset": "atmega8-generated" - }, - { - "name": "atmega8-reflect", - "configurePreset": "atmega8-reflect" - }, - { - "name": "atmega8a-generated", - "configurePreset": "atmega8a-generated" - }, - { - "name": "atmega8a-reflect", - "configurePreset": "atmega8a-reflect" - }, - { - "name": "atmega16-generated", - "configurePreset": "atmega16-generated" - }, - { - "name": "atmega16-reflect", - "configurePreset": "atmega16-reflect" - }, - { - "name": "atmega32-generated", - "configurePreset": "atmega32-generated" - }, - { - "name": "atmega32-reflect", - "configurePreset": "atmega32-reflect" - }, - { - "name": "atmega32a-generated", - "configurePreset": "atmega32a-generated" - }, - { - "name": "atmega32a-reflect", - "configurePreset": "atmega32a-reflect" - }, - { - "name": "atmega168a-generated", - "configurePreset": "atmega168a-generated" - }, - { - "name": "atmega168a-reflect", - "configurePreset": "atmega168a-reflect" - }, - { - "name": "atmega1284p-generated", - "configurePreset": "atmega1284p-generated" - }, - { - "name": "atmega1284p-reflect", - "configurePreset": "atmega1284p-reflect" - } - ], - "workflowPresets": [ - { - "name": "atmega328p-generated", - "steps": [ - { - "type": "configure", - "name": "atmega328p-generated" - }, - { - "type": "build", - "name": "atmega328p-generated" - }, - { - "type": "test", - "name": "atmega328p-generated" - } - ] - }, - { - "name": "attiny85-generated", - "steps": [ - { - "type": "configure", - "name": "attiny85-generated" - }, - { - "type": "build", - "name": "attiny85-generated" - }, - { - "type": "test", - "name": "attiny85-generated" - } - ] - }, - { - "name": "attiny13a-generated", - "steps": [ - { - "type": "configure", - "name": "attiny13a-generated" - }, - { - "type": "build", - "name": "attiny13a-generated" - }, - { - "type": "test", - "name": "attiny13a-generated" - } - ] - }, - { - "name": "atmega8-generated", - "steps": [ - { - "type": "configure", - "name": "atmega8-generated" - }, - { - "type": "build", - "name": "atmega8-generated" - } - ] - }, - { - "name": "atmega8-reflect", - "steps": [ - { - "type": "configure", - "name": "atmega8-reflect" - }, - { - "type": "build", - "name": "atmega8-reflect" - } - ] - }, - { - "name": "atmega8a-generated", - "steps": [ - { - "type": "configure", - "name": "atmega8a-generated" - }, - { - "type": "build", - "name": "atmega8a-generated" - } - ] - }, - { - "name": "atmega8a-reflect", - "steps": [ - { - "type": "configure", - "name": "atmega8a-reflect" - }, - { - "type": "build", - "name": "atmega8a-reflect" - } - ] - }, - { - "name": "atmega16-generated", - "steps": [ - { - "type": "configure", - "name": "atmega16-generated" - }, - { - "type": "build", - "name": "atmega16-generated" - } - ] - }, - { - "name": "atmega16-reflect", - "steps": [ - { - "type": "configure", - "name": "atmega16-reflect" - }, - { - "type": "build", - "name": "atmega16-reflect" - } - ] - }, - { - "name": "atmega32-generated", - "steps": [ - { - "type": "configure", - "name": "atmega32-generated" - }, - { - "type": "build", - "name": "atmega32-generated" - } - ] - }, - { - "name": "atmega32-reflect", - "steps": [ - { - "type": "configure", - "name": "atmega32-reflect" - }, - { - "type": "build", - "name": "atmega32-reflect" - } - ] - }, - { - "name": "atmega32a-generated", - "steps": [ - { - "type": "configure", - "name": "atmega32a-generated" - }, - { - "type": "build", - "name": "atmega32a-generated" - } - ] - }, - { - "name": "atmega32a-reflect", - "steps": [ - { - "type": "configure", - "name": "atmega32a-reflect" - }, - { - "type": "build", - "name": "atmega32a-reflect" - } - ] - }, - { - "name": "atmega168a-generated", - "steps": [ - { - "type": "configure", - "name": "atmega168a-generated" - }, - { - "type": "build", - "name": "atmega168a-generated" - } - ] - }, - { - "name": "atmega168a-reflect", - "steps": [ - { - "type": "configure", - "name": "atmega168a-reflect" - }, - { - "type": "build", - "name": "atmega168a-reflect" - } - ] - }, - { - "name": "atmega1284p-generated", - "steps": [ - { - "type": "configure", - "name": "atmega1284p-generated" - }, - { - "type": "build", - "name": "atmega1284p-generated" - } - ] - }, - { - "name": "atmega1284p-reflect", - "steps": [ - { - "type": "configure", - "name": "atmega1284p-reflect" - }, - { - "type": "build", - "name": "atmega1284p-reflect" - } - ] - } - ], - "testPresets": [ - { - "name": "atmega328p-generated", - "configurePreset": "atmega328p-generated", - "output": { - "outputOnFailure": true - } - }, - { - "name": "attiny85-generated", - "configurePreset": "attiny85-generated", - "output": { - "outputOnFailure": true - } - }, - { - "name": "attiny13a-generated", - "configurePreset": "attiny13a-generated", - "output": { - "outputOnFailure": true - } - } - ] + "version": 8, + "configurePresets": [ + { + "name": "base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/${presetName}", + "toolchainFile": "$env{LIBAVR_ROOT}/cmake/avr-toolchain.cmake", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", + "CMAKE_COLOR_DIAGNOSTICS": "ON" + } + }, + { + "name": "atmega328p-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega328p", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega328p-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega328p", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "attiny85-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "attiny85", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "attiny85-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "attiny85", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "attiny13a-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "attiny13a", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "attiny13a-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "attiny13a", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega8-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega8", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega8-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega8", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega8a-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega8a", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega8a-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega8a", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega16-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega16", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega16-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega16", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega32-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega32", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega32-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega32", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega32a-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega32a", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega32a-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega32a", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega168a-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega168a", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega168a-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega168a", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega1284p-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega1284p", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega1284p-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega1284p", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "attiny13-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "attiny13", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "attiny13-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "attiny13", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "attiny25-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "attiny25", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "attiny25-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "attiny25", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "attiny45-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "attiny45", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "attiny45-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "attiny45", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega16a-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega16a", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega16a-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega16a", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega48-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega48", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega48-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega48", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega48a-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega48a", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega48a-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega48a", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega48p-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega48p", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega48p-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega48p", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega48pa-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega48pa", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega48pa-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega48pa", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega88-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega88", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega88-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega88", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega88a-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega88a", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega88a-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega88a", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega88p-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega88p", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega88p-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega88p", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega88pa-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega88pa", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega88pa-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega88pa", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega168-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega168", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega168-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega168", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega168p-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega168p", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega168p-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega168p", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega168pa-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega168pa", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega168pa-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega168pa", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega328-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega328", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega328-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega328", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega164a-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega164a", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega164a-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega164a", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega164p-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega164p", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega164p-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega164p", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega164pa-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega164pa", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega164pa-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega164pa", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega324a-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega324a", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega324a-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega324a", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega324p-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega324p", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega324p-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega324p", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega324pa-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega324pa", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega324pa-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega324pa", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega644-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega644", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega644-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega644", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega644a-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega644a", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega644a-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega644a", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega644p-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega644p", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega644p-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega644p", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega644pa-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega644pa", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega644pa-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega644pa", + "LIBAVR_REFLECT": "ON" + } + }, + { + "name": "atmega1284-generated", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega1284", + "LIBAVR_REFLECT": "OFF" + } + }, + { + "name": "atmega1284-reflect", + "inherits": "base", + "cacheVariables": { + "LIBAVR_MCU": "atmega1284", + "LIBAVR_REFLECT": "ON" + } + } + ], + "buildPresets": [ + { + "name": "atmega328p-generated", + "configurePreset": "atmega328p-generated" + }, + { + "name": "atmega328p-reflect", + "configurePreset": "atmega328p-reflect" + }, + { + "name": "attiny85-generated", + "configurePreset": "attiny85-generated" + }, + { + "name": "attiny85-reflect", + "configurePreset": "attiny85-reflect" + }, + { + "name": "attiny13a-generated", + "configurePreset": "attiny13a-generated" + }, + { + "name": "attiny13a-reflect", + "configurePreset": "attiny13a-reflect" + }, + { + "name": "atmega8-generated", + "configurePreset": "atmega8-generated" + }, + { + "name": "atmega8-reflect", + "configurePreset": "atmega8-reflect" + }, + { + "name": "atmega8a-generated", + "configurePreset": "atmega8a-generated" + }, + { + "name": "atmega8a-reflect", + "configurePreset": "atmega8a-reflect" + }, + { + "name": "atmega16-generated", + "configurePreset": "atmega16-generated" + }, + { + "name": "atmega16-reflect", + "configurePreset": "atmega16-reflect" + }, + { + "name": "atmega32-generated", + "configurePreset": "atmega32-generated" + }, + { + "name": "atmega32-reflect", + "configurePreset": "atmega32-reflect" + }, + { + "name": "atmega32a-generated", + "configurePreset": "atmega32a-generated" + }, + { + "name": "atmega32a-reflect", + "configurePreset": "atmega32a-reflect" + }, + { + "name": "atmega168a-generated", + "configurePreset": "atmega168a-generated" + }, + { + "name": "atmega168a-reflect", + "configurePreset": "atmega168a-reflect" + }, + { + "name": "atmega1284p-generated", + "configurePreset": "atmega1284p-generated" + }, + { + "name": "atmega1284p-reflect", + "configurePreset": "atmega1284p-reflect" + }, + { + "name": "attiny13-generated", + "configurePreset": "attiny13-generated" + }, + { + "name": "attiny13-reflect", + "configurePreset": "attiny13-reflect" + }, + { + "name": "attiny25-generated", + "configurePreset": "attiny25-generated" + }, + { + "name": "attiny25-reflect", + "configurePreset": "attiny25-reflect" + }, + { + "name": "attiny45-generated", + "configurePreset": "attiny45-generated" + }, + { + "name": "attiny45-reflect", + "configurePreset": "attiny45-reflect" + }, + { + "name": "atmega16a-generated", + "configurePreset": "atmega16a-generated" + }, + { + "name": "atmega16a-reflect", + "configurePreset": "atmega16a-reflect" + }, + { + "name": "atmega48-generated", + "configurePreset": "atmega48-generated" + }, + { + "name": "atmega48-reflect", + "configurePreset": "atmega48-reflect" + }, + { + "name": "atmega48a-generated", + "configurePreset": "atmega48a-generated" + }, + { + "name": "atmega48a-reflect", + "configurePreset": "atmega48a-reflect" + }, + { + "name": "atmega48p-generated", + "configurePreset": "atmega48p-generated" + }, + { + "name": "atmega48p-reflect", + "configurePreset": "atmega48p-reflect" + }, + { + "name": "atmega48pa-generated", + "configurePreset": "atmega48pa-generated" + }, + { + "name": "atmega48pa-reflect", + "configurePreset": "atmega48pa-reflect" + }, + { + "name": "atmega88-generated", + "configurePreset": "atmega88-generated" + }, + { + "name": "atmega88-reflect", + "configurePreset": "atmega88-reflect" + }, + { + "name": "atmega88a-generated", + "configurePreset": "atmega88a-generated" + }, + { + "name": "atmega88a-reflect", + "configurePreset": "atmega88a-reflect" + }, + { + "name": "atmega88p-generated", + "configurePreset": "atmega88p-generated" + }, + { + "name": "atmega88p-reflect", + "configurePreset": "atmega88p-reflect" + }, + { + "name": "atmega88pa-generated", + "configurePreset": "atmega88pa-generated" + }, + { + "name": "atmega88pa-reflect", + "configurePreset": "atmega88pa-reflect" + }, + { + "name": "atmega168-generated", + "configurePreset": "atmega168-generated" + }, + { + "name": "atmega168-reflect", + "configurePreset": "atmega168-reflect" + }, + { + "name": "atmega168p-generated", + "configurePreset": "atmega168p-generated" + }, + { + "name": "atmega168p-reflect", + "configurePreset": "atmega168p-reflect" + }, + { + "name": "atmega168pa-generated", + "configurePreset": "atmega168pa-generated" + }, + { + "name": "atmega168pa-reflect", + "configurePreset": "atmega168pa-reflect" + }, + { + "name": "atmega328-generated", + "configurePreset": "atmega328-generated" + }, + { + "name": "atmega328-reflect", + "configurePreset": "atmega328-reflect" + }, + { + "name": "atmega164a-generated", + "configurePreset": "atmega164a-generated" + }, + { + "name": "atmega164a-reflect", + "configurePreset": "atmega164a-reflect" + }, + { + "name": "atmega164p-generated", + "configurePreset": "atmega164p-generated" + }, + { + "name": "atmega164p-reflect", + "configurePreset": "atmega164p-reflect" + }, + { + "name": "atmega164pa-generated", + "configurePreset": "atmega164pa-generated" + }, + { + "name": "atmega164pa-reflect", + "configurePreset": "atmega164pa-reflect" + }, + { + "name": "atmega324a-generated", + "configurePreset": "atmega324a-generated" + }, + { + "name": "atmega324a-reflect", + "configurePreset": "atmega324a-reflect" + }, + { + "name": "atmega324p-generated", + "configurePreset": "atmega324p-generated" + }, + { + "name": "atmega324p-reflect", + "configurePreset": "atmega324p-reflect" + }, + { + "name": "atmega324pa-generated", + "configurePreset": "atmega324pa-generated" + }, + { + "name": "atmega324pa-reflect", + "configurePreset": "atmega324pa-reflect" + }, + { + "name": "atmega644-generated", + "configurePreset": "atmega644-generated" + }, + { + "name": "atmega644-reflect", + "configurePreset": "atmega644-reflect" + }, + { + "name": "atmega644a-generated", + "configurePreset": "atmega644a-generated" + }, + { + "name": "atmega644a-reflect", + "configurePreset": "atmega644a-reflect" + }, + { + "name": "atmega644p-generated", + "configurePreset": "atmega644p-generated" + }, + { + "name": "atmega644p-reflect", + "configurePreset": "atmega644p-reflect" + }, + { + "name": "atmega644pa-generated", + "configurePreset": "atmega644pa-generated" + }, + { + "name": "atmega644pa-reflect", + "configurePreset": "atmega644pa-reflect" + }, + { + "name": "atmega1284-generated", + "configurePreset": "atmega1284-generated" + }, + { + "name": "atmega1284-reflect", + "configurePreset": "atmega1284-reflect" + } + ], + "workflowPresets": [ + { + "name": "atmega328p-generated", + "steps": [ + { + "type": "configure", + "name": "atmega328p-generated" + }, + { + "type": "build", + "name": "atmega328p-generated" + }, + { + "type": "test", + "name": "atmega328p-generated" + } + ] + }, + { + "name": "attiny85-generated", + "steps": [ + { + "type": "configure", + "name": "attiny85-generated" + }, + { + "type": "build", + "name": "attiny85-generated" + }, + { + "type": "test", + "name": "attiny85-generated" + } + ] + }, + { + "name": "attiny13a-generated", + "steps": [ + { + "type": "configure", + "name": "attiny13a-generated" + }, + { + "type": "build", + "name": "attiny13a-generated" + }, + { + "type": "test", + "name": "attiny13a-generated" + } + ] + }, + { + "name": "atmega8-generated", + "steps": [ + { + "type": "configure", + "name": "atmega8-generated" + }, + { + "type": "build", + "name": "atmega8-generated" + } + ] + }, + { + "name": "atmega8-reflect", + "steps": [ + { + "type": "configure", + "name": "atmega8-reflect" + }, + { + "type": "build", + "name": "atmega8-reflect" + } + ] + }, + { + "name": "atmega8a-generated", + "steps": [ + { + "type": "configure", + "name": "atmega8a-generated" + }, + { + "type": "build", + "name": "atmega8a-generated" + } + ] + }, + { + "name": "atmega8a-reflect", + "steps": [ + { + "type": "configure", + "name": "atmega8a-reflect" + }, + { + "type": "build", + "name": "atmega8a-reflect" + } + ] + }, + { + "name": "atmega16-generated", + "steps": [ + { + "type": "configure", + "name": "atmega16-generated" + }, + { + "type": "build", + "name": "atmega16-generated" + } + ] + }, + { + "name": "atmega16-reflect", + "steps": [ + { + "type": "configure", + "name": "atmega16-reflect" + }, + { + "type": "build", + "name": "atmega16-reflect" + } + ] + }, + { + "name": "atmega32-generated", + "steps": [ + { + "type": "configure", + "name": "atmega32-generated" + }, + { + "type": "build", + "name": "atmega32-generated" + } + ] + }, + { + "name": "atmega32-reflect", + "steps": [ + { + "type": "configure", + "name": "atmega32-reflect" + }, + { + "type": "build", + "name": "atmega32-reflect" + } + ] + }, + { + "name": "atmega32a-generated", + "steps": [ + { + "type": "configure", + "name": "atmega32a-generated" + }, + { + "type": "build", + "name": "atmega32a-generated" + } + ] + }, + { + "name": "atmega32a-reflect", + "steps": [ + { + "type": "configure", + "name": "atmega32a-reflect" + }, + { + "type": "build", + "name": "atmega32a-reflect" + } + ] + }, + { + "name": "atmega168a-generated", + "steps": [ + { + "type": "configure", + "name": "atmega168a-generated" + }, + { + "type": "build", + "name": "atmega168a-generated" + } + ] + }, + { + "name": "atmega168a-reflect", + "steps": [ + { + "type": "configure", + "name": "atmega168a-reflect" + }, + { + "type": "build", + "name": "atmega168a-reflect" + } + ] + }, + { + "name": "atmega1284p-generated", + "steps": [ + { + "type": "configure", + "name": "atmega1284p-generated" + }, + { + "type": "build", + "name": "atmega1284p-generated" + } + ] + }, + { + "name": "atmega1284p-reflect", + "steps": [ + { + "type": "configure", + "name": "atmega1284p-reflect" + }, + { + "type": "build", + "name": "atmega1284p-reflect" + } + ] + }, + { + "name": "attiny13-generated", + "steps": [ + { + "type": "configure", + "name": "attiny13-generated" + }, + { + "type": "build", + "name": "attiny13-generated" + }, + { + "type": "test", + "name": "attiny13-generated" + } + ] + }, + { + "name": "attiny25-generated", + "steps": [ + { + "type": "configure", + "name": "attiny25-generated" + }, + { + "type": "build", + "name": "attiny25-generated" + }, + { + "type": "test", + "name": "attiny25-generated" + } + ] + }, + { + "name": "attiny45-generated", + "steps": [ + { + "type": "configure", + "name": "attiny45-generated" + }, + { + "type": "build", + "name": "attiny45-generated" + }, + { + "type": "test", + "name": "attiny45-generated" + } + ] + }, + { + "name": "atmega16a-generated", + "steps": [ + { + "type": "configure", + "name": "atmega16a-generated" + }, + { + "type": "build", + "name": "atmega16a-generated" + }, + { + "type": "test", + "name": "atmega16a-generated" + } + ] + }, + { + "name": "atmega48-generated", + "steps": [ + { + "type": "configure", + "name": "atmega48-generated" + }, + { + "type": "build", + "name": "atmega48-generated" + }, + { + "type": "test", + "name": "atmega48-generated" + } + ] + }, + { + "name": "atmega48a-generated", + "steps": [ + { + "type": "configure", + "name": "atmega48a-generated" + }, + { + "type": "build", + "name": "atmega48a-generated" + }, + { + "type": "test", + "name": "atmega48a-generated" + } + ] + }, + { + "name": "atmega48p-generated", + "steps": [ + { + "type": "configure", + "name": "atmega48p-generated" + }, + { + "type": "build", + "name": "atmega48p-generated" + }, + { + "type": "test", + "name": "atmega48p-generated" + } + ] + }, + { + "name": "atmega48pa-generated", + "steps": [ + { + "type": "configure", + "name": "atmega48pa-generated" + }, + { + "type": "build", + "name": "atmega48pa-generated" + }, + { + "type": "test", + "name": "atmega48pa-generated" + } + ] + }, + { + "name": "atmega88-generated", + "steps": [ + { + "type": "configure", + "name": "atmega88-generated" + }, + { + "type": "build", + "name": "atmega88-generated" + }, + { + "type": "test", + "name": "atmega88-generated" + } + ] + }, + { + "name": "atmega88a-generated", + "steps": [ + { + "type": "configure", + "name": "atmega88a-generated" + }, + { + "type": "build", + "name": "atmega88a-generated" + }, + { + "type": "test", + "name": "atmega88a-generated" + } + ] + }, + { + "name": "atmega88p-generated", + "steps": [ + { + "type": "configure", + "name": "atmega88p-generated" + }, + { + "type": "build", + "name": "atmega88p-generated" + }, + { + "type": "test", + "name": "atmega88p-generated" + } + ] + }, + { + "name": "atmega88pa-generated", + "steps": [ + { + "type": "configure", + "name": "atmega88pa-generated" + }, + { + "type": "build", + "name": "atmega88pa-generated" + }, + { + "type": "test", + "name": "atmega88pa-generated" + } + ] + }, + { + "name": "atmega168-generated", + "steps": [ + { + "type": "configure", + "name": "atmega168-generated" + }, + { + "type": "build", + "name": "atmega168-generated" + }, + { + "type": "test", + "name": "atmega168-generated" + } + ] + }, + { + "name": "atmega168p-generated", + "steps": [ + { + "type": "configure", + "name": "atmega168p-generated" + }, + { + "type": "build", + "name": "atmega168p-generated" + }, + { + "type": "test", + "name": "atmega168p-generated" + } + ] + }, + { + "name": "atmega168pa-generated", + "steps": [ + { + "type": "configure", + "name": "atmega168pa-generated" + }, + { + "type": "build", + "name": "atmega168pa-generated" + }, + { + "type": "test", + "name": "atmega168pa-generated" + } + ] + }, + { + "name": "atmega328-generated", + "steps": [ + { + "type": "configure", + "name": "atmega328-generated" + }, + { + "type": "build", + "name": "atmega328-generated" + }, + { + "type": "test", + "name": "atmega328-generated" + } + ] + }, + { + "name": "atmega164a-generated", + "steps": [ + { + "type": "configure", + "name": "atmega164a-generated" + }, + { + "type": "build", + "name": "atmega164a-generated" + }, + { + "type": "test", + "name": "atmega164a-generated" + } + ] + }, + { + "name": "atmega164p-generated", + "steps": [ + { + "type": "configure", + "name": "atmega164p-generated" + }, + { + "type": "build", + "name": "atmega164p-generated" + }, + { + "type": "test", + "name": "atmega164p-generated" + } + ] + }, + { + "name": "atmega164pa-generated", + "steps": [ + { + "type": "configure", + "name": "atmega164pa-generated" + }, + { + "type": "build", + "name": "atmega164pa-generated" + }, + { + "type": "test", + "name": "atmega164pa-generated" + } + ] + }, + { + "name": "atmega324a-generated", + "steps": [ + { + "type": "configure", + "name": "atmega324a-generated" + }, + { + "type": "build", + "name": "atmega324a-generated" + }, + { + "type": "test", + "name": "atmega324a-generated" + } + ] + }, + { + "name": "atmega324p-generated", + "steps": [ + { + "type": "configure", + "name": "atmega324p-generated" + }, + { + "type": "build", + "name": "atmega324p-generated" + }, + { + "type": "test", + "name": "atmega324p-generated" + } + ] + }, + { + "name": "atmega324pa-generated", + "steps": [ + { + "type": "configure", + "name": "atmega324pa-generated" + }, + { + "type": "build", + "name": "atmega324pa-generated" + }, + { + "type": "test", + "name": "atmega324pa-generated" + } + ] + }, + { + "name": "atmega644-generated", + "steps": [ + { + "type": "configure", + "name": "atmega644-generated" + }, + { + "type": "build", + "name": "atmega644-generated" + }, + { + "type": "test", + "name": "atmega644-generated" + } + ] + }, + { + "name": "atmega644a-generated", + "steps": [ + { + "type": "configure", + "name": "atmega644a-generated" + }, + { + "type": "build", + "name": "atmega644a-generated" + }, + { + "type": "test", + "name": "atmega644a-generated" + } + ] + }, + { + "name": "atmega644p-generated", + "steps": [ + { + "type": "configure", + "name": "atmega644p-generated" + }, + { + "type": "build", + "name": "atmega644p-generated" + }, + { + "type": "test", + "name": "atmega644p-generated" + } + ] + }, + { + "name": "atmega644pa-generated", + "steps": [ + { + "type": "configure", + "name": "atmega644pa-generated" + }, + { + "type": "build", + "name": "atmega644pa-generated" + }, + { + "type": "test", + "name": "atmega644pa-generated" + } + ] + }, + { + "name": "atmega1284-generated", + "steps": [ + { + "type": "configure", + "name": "atmega1284-generated" + }, + { + "type": "build", + "name": "atmega1284-generated" + }, + { + "type": "test", + "name": "atmega1284-generated" + } + ] + } + ], + "testPresets": [ + { + "name": "atmega328p-generated", + "configurePreset": "atmega328p-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "attiny85-generated", + "configurePreset": "attiny85-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "attiny13a-generated", + "configurePreset": "attiny13a-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "attiny13-generated", + "configurePreset": "attiny13-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "attiny25-generated", + "configurePreset": "attiny25-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "attiny45-generated", + "configurePreset": "attiny45-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega16a-generated", + "configurePreset": "atmega16a-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega48-generated", + "configurePreset": "atmega48-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega48a-generated", + "configurePreset": "atmega48a-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega48p-generated", + "configurePreset": "atmega48p-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega48pa-generated", + "configurePreset": "atmega48pa-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega88-generated", + "configurePreset": "atmega88-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega88a-generated", + "configurePreset": "atmega88a-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega88p-generated", + "configurePreset": "atmega88p-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega88pa-generated", + "configurePreset": "atmega88pa-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega168-generated", + "configurePreset": "atmega168-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega168p-generated", + "configurePreset": "atmega168p-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega168pa-generated", + "configurePreset": "atmega168pa-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega328-generated", + "configurePreset": "atmega328-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega164a-generated", + "configurePreset": "atmega164a-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega164p-generated", + "configurePreset": "atmega164p-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega164pa-generated", + "configurePreset": "atmega164pa-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega324a-generated", + "configurePreset": "atmega324a-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega324p-generated", + "configurePreset": "atmega324p-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega324pa-generated", + "configurePreset": "atmega324pa-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega644-generated", + "configurePreset": "atmega644-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega644a-generated", + "configurePreset": "atmega644a-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega644p-generated", + "configurePreset": "atmega644p-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega644pa-generated", + "configurePreset": "atmega644pa-generated", + "output": { + "outputOnFailure": true + } + }, + { + "name": "atmega1284-generated", + "configurePreset": "atmega1284-generated", + "output": { + "outputOnFailure": true + } + } + ] } diff --git a/pureboot/README.md b/pureboot/README.md index 225063d..9a3e16d 100644 --- a/pureboot/README.md +++ b/pureboot/README.md @@ -2,13 +2,14 @@ A serial bootloader on [libavr](https://git.blackmark.me/avr/libavr), pure by constraint: one C++ source, no inline assembly, no global register variables -(attributes allowed), built for every chip libavr targets, **fitting each -chip's smallest boot sector**: 512 bytes everywhere — 488 B on the -ATtiny13A, 502 B on the ATtiny85, 466–504 B across the megas — except the -ATmega1284P, whose smallest boot sector is 1 KiB and whose far-flash +(attributes allowed), built for **every chip libavr targets — all 37 — +fitting each chip's smallest boot sector**: 512 bytes everywhere — 488 B on +the tiny13s, 498–502 B on the tiny25/45/85, 466–504 B across the megas +(474 B on the boot-section-less m48s, 498 B on the 644s) — except the +ATmega1284/1284P, whose smallest boot sector is 1 KiB and whose far-flash machinery (ELPM reads, RAMPZ page commands, word-addressed wire) lands at -558 B in a 1 KiB slot: the 512-byte figure is a hardware boundary that chip -simply does not have, and no implementation of this feature set fits it +558 B in a 1 KiB slot: the 512-byte figure is a hardware boundary those +chips simply do not have, and no implementation of this feature set fits it there. The device speaks primitives; every composite — verify, erase, reset-vector surgery, updating the loader itself — lives in the host tool (`pureboot.py`). @@ -29,19 +30,20 @@ belongs to the host-managed trampoline (below). | Chip | Serial | Baud | Clock assumed | |---|---|---|---| -| every ATmega (8/8A, 16, 32/32A, 168A, 328P, 1284P) | the hardware USART (USART0), RXD/TXD per pinout | 115200 8N1 | 16 MHz crystal | -| ATtiny85 | software UART, RX = PB0, TX = PB1 | 57600 8N1 | 8 MHz internal RC | -| ATtiny13A | software UART, RX = PB0, TX = PB1 | 57600 8N1 | 9.6 MHz internal RC | +| every ATmega | the hardware USART (USART0), RXD/TXD per pinout | 115200 8N1 | 16 MHz crystal | +| ATtiny25/45/85 | software UART, RX = PB0, TX = PB1 | 57600 8N1 | 8 MHz internal RC | +| ATtiny13/13A | software UART, RX = PB0, TX = PB1 | 57600 8N1 | 9.6 MHz internal RC | The tiny RX pin has its pull-up enabled; TX idles high. All multi-byte quantities on the wire are little-endian. ## Activation -Reset enters the loader (BOOTRST on the mega, the patched reset vector on the -tinies) — except a watchdog reset, which hands straight to the application -(the application owns its watchdog; it must clear WDRF itself, which also -releases the WDRF-forced WDE). +Reset enters the loader (BOOTRST on the boot-sectioned megas; the patched +reset vector on the tinies and the boot-section-less m48s) — except a +watchdog reset, which hands straight to the application (the application +owns its watchdog; it must clear WDRF itself, which also releases the +WDRF-forced WDE). The host then has one activation window per awaited byte to knock: `p` then `b`. Each awaited byte gets a fresh window; any other byte is discarded and @@ -61,9 +63,10 @@ write to finish and sends the prompt `+` (0x2b) — the prompt is therefore also the completion ack of the previous command. A session is: await `+`, send a command, read its reply, repeat. -On chips whose flash exceeds 64 KiB (the 1284P — info-block flag bit 1) the +On chips whose flash exceeds 64 KiB (the 1284s — info-block flag bit 1) the `R`/`W` flash addresses are **word** addresses; everywhere else they are byte -addresses. EEPROM addresses are always bytes, counts always bytes. +addresses (the 644s' 64 KiB is exactly the 16-bit byte space and stays +byte-addressed). EEPROM addresses are always bytes, counts always bytes. | Cmd | Arguments | Reply | |---|---|---| @@ -108,16 +111,23 @@ write `0xff` (per page for flash, per byte for EEPROM). ## Deployment -**Megas**: program the loader at `flash − slot` with an external programmer. -Every mega has a BOOTSZ step whose boot section is exactly the loader slot — -512 B, the m8/16/168A's second-smallest step, the m32/328P's smallest; on -the m1284P that step is its smallest, 512 words, which is why its slot is -1 KiB — so the ATmega328P profiles below apply to every mega with its own -addresses and slot size; the per-chip BOOTSZ ladders live in the host tool -(`BOOT_FUSE`). The 1284P's numbers: standalone = BOOTSZ 512 words (reset at -the loader base 0x1fc00); self-update = 1024 words, covering both 1 KiB -slots, the loader-first reset landing at 0x1f800 — the staging slot, walked -across when erased. +**Boot-sectioned megas**: program the loader at `flash − slot` with an +external programmer. Every such mega has a BOOTSZ step whose boot section +is exactly the loader slot — 512 B, the second-smallest step on the 8 KiB +and 16 KiB chips (m8, m88, m16, m168, m164), the smallest on the 32 KiB +ones (m32, m328, m324); on the 1284s that step is the smallest, 512 words, +which is why their slot is 1 KiB — so the ATmega328P profiles below apply +to every one of them with its own addresses and slot size; the per-chip +BOOTSZ ladders live in the host tool (`BOOT_FUSE`). The 1284s' numbers: +standalone = BOOTSZ 512 words (reset at the loader base 0x1fc00); +self-update = 1024 words, covering both 1 KiB slots, the loader-first +reset landing at 0x1f800 — the staging slot, walked across when erased. + +The **644s** are the geometry's sweet spot: their smallest boot section +(512 words = 1 KiB) is exactly *two* 512-byte slots, so the resident and +its staging slot both live inside the minimum section — self-update needs +no fuse step up, and the standalone profile does not exist (reset lands at +0xfc00, one erased slot below the loader: the loader-first walk built in). ATmega328P profiles (addresses for its 32 KiB): @@ -130,15 +140,18 @@ ATmega328P profiles (addresses for its 32 KiB): Applications are flashed unmodified — word 0 stays the application's own reset vector, and the hand-over jumps to 0. -**Tinies** (no boot section): program the loader at `flash − 512`; erased -flash below it walks up into the loader, so a virgin chip activates. When -flashing an application the host performs reset-vector surgery: word 0 is -rewritten to `rjmp` to the loader base, and the application's own entry is -re-encoded as a trampoline `rjmp` in the word just below the loader -(`base − 2`, where the hand-over jumps). Every other vector stays the -application's. The patched page 0 and the trampoline page are written -*first*, so from the first write on an interrupted flash still resets into -the loader; an erase runs top-down for the same reason. +**Patched-vector chips — the tinies and the m48s** (no boot section; the +m48s' SPM runs from the entire flash, Atmel-8271 §26): program the loader +at `flash − 512`; erased flash below it walks up into the loader, so a +virgin chip activates. When flashing an application the host performs +reset-vector surgery: word 0 is rewritten to `rjmp` to the loader base, and +the application's own entry is re-encoded as a trampoline `rjmp` in the +word just below the loader (`base − 2`, where the hand-over jumps). Every +other vector stays the application's. The patched page 0 and the trampoline +page are written *first*, so from the first write on an interrupted flash +still resets into the loader; an erase runs top-down for the same reason. +The m48s speak this profile over their hardware USART — no fuse preflight, +BOOTRST does not exist there. ## Updating the loader @@ -148,16 +161,18 @@ loader itself as its own staging loader. The image is the loader's own 512 bytes as a raw binary, or the Intel HEX the build emits beside it, which links the loader at its base inside an otherwise blank flash image: -1. The staging slot `[base−512, base)` is saved to a host-side state file - (on the 1 KB tiny13A that is the whole application, vectors included). -2. The resident installs the identical update image there. On the tinies the - host composes the slot's last word — the same address as the resident's - trampoline — as a jump to the resident base, so even an abandoned staging - copy times out into a loader, never into garbage. +1. The staging slot `[base−slot, base)` is saved to a host-side state file + (on the 1 KB tiny13s that is the whole application, vectors included). +2. The resident installs the identical update image there. On the + patched-vector chips the host composes the slot's last word — the same + address as the resident's trampoline — as a jump to the resident base, + so even an abandoned staging copy times out into a loader, never into + garbage. 3. `J` enters the staging copy, which rewrites the resident slot. On the - t85 the host first re-aims word 0 at the staging copy, so a power loss - mid-rewrite still resets into a loader; on the t13a the staging slot - carries the reset vector itself. + patched-vector chips whose staging slot sits away from page 0 the host + first re-aims word 0 at the staging copy, so a power loss mid-rewrite + still resets into a loader; on the tiny13s the staging slot carries the + reset vector itself. 4. `J` enters the new resident, which restores the staging slot's saved content (word 0 and the trampoline with it) and the state file is discarded. @@ -166,9 +181,10 @@ Every phase is idempotent and keyed off the actual flash state: re-running the same command after any interruption resumes and completes. The state file carries the only bytes not recoverable from the device; if it is lost mid-update the update still completes, and the staging region is restored by -reflashing the application. The mega needs its fuses for the preflight -(BOOTSZ gate, profile notes) — read from the device, or supplied with -`--assume-fuses` where reading is impossible (simulators). +reflashing the application. A boot-sectioned mega needs its fuses for the +preflight (BOOTSZ gate, profile notes) — read from the device, or supplied +with `--assume-fuses` where reading is impossible (simulators); the +patched-vector chips need none. ## Host tool diff --git a/pureboot/pureboot.cpp b/pureboot/pureboot.cpp index a4b386a..1195191 100644 --- a/pureboot/pureboot.cpp +++ b/pureboot/pureboot.cpp @@ -16,9 +16,10 @@ // resident — how pureboot updates itself, host-driven, with no other // firmware involved. // -// Entry: reset lands in avr::startup::entry below (BOOTRST on the mega; the -// patched reset vector — or erased flash walking up into the loader — on the -// tinies). A watchdog reset hands straight to the application. Otherwise the +// Entry: reset lands in avr::startup::entry below (BOOTRST on the +// boot-sectioned megas; the patched reset vector — or erased flash walking +// up into the loader — on the tinies and the boot-section-less m48s). A +// watchdog reset hands straight to the application. Otherwise the // host has one activation window per awaited knock byte ("pb"); an idle line // boots the application. A session then stays in the command loop until 'J' // jumps away or the chip resets. @@ -44,9 +45,10 @@ constexpr std::uint8_t ack = '+'; // from code. consteval avr::hertz_t clock() { - if (avr::hw::db.name == "ATtiny13A") + auto name = std::string_view{avr::hw::db.name}; + if (name.starts_with("ATtiny13")) return 9.6_MHz; - if (avr::hw::db.name == "ATtiny85") + if (name.starts_with("ATtiny")) return 8_MHz; return 16_MHz; } @@ -62,21 +64,19 @@ consteval std::int16_t wdrf_field() // Geometry: the resident loader owns the top slot of flash — 512 bytes, // except on the >64 KiB chips whose own smallest boot sector is 1 KiB (the -// 1284P): there the slot is 1 KiB, matching the hardware boundary the +// 1284s): there the slot is 1 KiB, matching the hardware boundary the // 512-byte figure comes from everywhere else. The word below the slot is // the trampoline (the application's relocated reset vector) on chips -// without a hardware boot section. The RWWSRE bit marks a separate boot -// section — on classic AVR the two capabilities coincide (the m8/m32 packs -// spell its register SPMCR). +// without a hardware boot section — the tinies and the m48s, whose SPM +// runs from anywhere (Atmel-8271 §26). A boot section also means the CPU +// runs on while the RWW section programs; everywhere else it halts through +// the operation. The m48s still carry RWWSRE as their temporary-buffer +// discard (§26.2), so the discard picks by that bit, not by the section. constexpr std::uint16_t slot_bytes = spm::flash_bytes > 65536 ? 1024 : 512; constexpr std::uint32_t base = spm::flash_bytes - slot_bytes; constexpr std::uint16_t page = spm::page_bytes; -constexpr bool boot_section = [] { - for (auto reg : {"SPMCSR", "SPMCR"}) - if (avr::hw::db.field_index(reg, "RWWSRE") >= 0) - return true; - return false; -}(); +constexpr bool boot_section = avr::hw::curated::has_boot_section(); +constexpr bool rww_discard = spm::detail::has_rww(); // Past 64 KiB a byte address no longer fits the wire's 16 bits, so on the // large chips every flash address on the wire — and all slot arithmetic — @@ -85,7 +85,8 @@ constexpr bool boot_section = [] { // 2 x 256 words), so the slot index is the high byte with its low bit // dropped everywhere. constexpr bool word_flash = spm::flash_bytes > 65536; -constexpr std::uint16_t wire_base = word_flash ? static_cast(base / 2) : static_cast(base); +constexpr std::uint16_t wire_base = + word_flash ? static_cast(base / 2) : static_cast(base); constexpr std::uint16_t wire_page_mask = word_flash ? (page / 2 - 1) : (page - 1); // The activation window, in seconds, is a compile-time constant (the build @@ -332,9 +333,10 @@ void program_flash(std::uint16_t wire_address, std::uint8_t slot_high) { // A buffer word cannot be loaded twice without an erase (§26.2.1), so a // refused page's drained data must not linger for the next write: - // discard the buffer up front — CTPB on the tinies; on the mega writing - // RWWSRE aborts a pending load (§26.2.2). - if constexpr (boot_section) + // discard the buffer up front — CTPB on the tinies; on the megas + // writing RWWSRE aborts a pending load (§26.2.2 — on the m48s that + // flush is the bit's whole documented job). + if constexpr (rww_discard) spm::rww_enable(); else spm::clear_buffer(); @@ -376,8 +378,9 @@ void program_flash(std::uint16_t wire_address, std::uint8_t slot_high) page_high = static_cast(address >> 8) & 0xfe; } if (page_high != slot_high) { - // The tinies halt the CPU through the erase and the write, so only - // the megas — running on while their RWW section programs — wait. + // The tinies and the m48s halt the CPU through the erase and the + // write, so only the boot-sectioned megas — running on while their + // RWW section programs — wait. spm::erase_page(address); if constexpr (boot_section) spm::wait(); @@ -416,8 +419,8 @@ void send_fuses() // program_flash refuses this one slot and the info block is addressed // from it, so both follow wherever the code was flashed. const std::uint16_t ra_words = reinterpret_cast(__builtin_return_address(0)); - const std::uint8_t slot_high = word_flash ? static_cast(ra_words >> 8) & 0xfe - : static_cast((ra_words >> 8) << 1); + const std::uint8_t slot_high = + word_flash ? static_cast(ra_words >> 8) & 0xfe : static_cast((ra_words >> 8) << 1); // The knock: 'p' then 'b', each under a fresh window; any other byte is // line noise and waits again. Falling out of a window runs the app. diff --git a/pureboot/pureboot.py b/pureboot/pureboot.py index 3ca660a..f97f8dd 100644 --- a/pureboot/pureboot.py +++ b/pureboot/pureboot.py @@ -518,15 +518,34 @@ def covered(pages, info, skip_blank): # Per-chip boot fuse geometry, keyed by the signature's family/part bytes: # which byte of the 'F' reply (low, lock, extended, high) carries BOOTSZ/ -# BOOTRST, and the BOOTSZ->words ladder. Sources: Atmel-2486/2466/2503 -# (HIGH fuse), Atmel-8271 (m168A: EXTENDED; m328P: HIGH), Atmel-42719. +# BOOTRST, and the BOOTSZ->words ladder. A die revision shares its base +# signature, so one row covers it. The m48s have no boot section and no +# row — their info block says patch-vector and this table is never +# consulted. Sources: Atmel-2486/2466/2503 (HIGH fuse), Atmel-2545/8271/ +# DS40002065 (x8: EXTENDED, except the m328s' HIGH), Atmel-8272/8011/2593/ +# 42719 (x4: HIGH). +_LADDER_128 = {0b11: 128, 0b10: 256, 0b01: 512, 0b00: 1024} +_LADDER_256 = {0b11: 256, 0b10: 512, 0b01: 1024, 0b00: 2048} +_LADDER_512 = {0b11: 512, 0b10: 1024, 0b01: 2048, 0b00: 4096} BOOT_FUSE = { - bytes((0x93, 0x07)): (3, {0b11: 128, 0b10: 256, 0b01: 512, 0b00: 1024}), # m8/8A - bytes((0x94, 0x03)): (3, {0b11: 128, 0b10: 256, 0b01: 512, 0b00: 1024}), # m16 - bytes((0x95, 0x02)): (3, {0b11: 256, 0b10: 512, 0b01: 1024, 0b00: 2048}), # m32/32A - bytes((0x94, 0x06)): (2, {0b11: 128, 0b10: 256, 0b01: 512, 0b00: 1024}), # m168A - bytes((0x95, 0x0F)): (3, {0b11: 256, 0b10: 512, 0b01: 1024, 0b00: 2048}), # m328P - bytes((0x97, 0x05)): (3, {0b11: 512, 0b10: 1024, 0b01: 2048, 0b00: 4096}), # 1284P + bytes((0x93, 0x07)): (3, _LADDER_128), # m8/8A + bytes((0x94, 0x03)): (3, _LADDER_128), # m16/16A + bytes((0x95, 0x02)): (3, _LADDER_256), # m32/32A + bytes((0x93, 0x0A)): (2, _LADDER_128), # m88/88A + bytes((0x93, 0x0F)): (2, _LADDER_128), # m88P/88PA + bytes((0x94, 0x06)): (2, _LADDER_128), # m168/168A + bytes((0x94, 0x0B)): (2, _LADDER_128), # m168P/168PA + bytes((0x95, 0x14)): (3, _LADDER_256), # m328 + bytes((0x95, 0x0F)): (3, _LADDER_256), # m328P + bytes((0x94, 0x0F)): (3, _LADDER_128), # m164A + bytes((0x94, 0x0A)): (3, _LADDER_128), # m164P/164PA + bytes((0x95, 0x15)): (3, _LADDER_256), # m324A + bytes((0x95, 0x08)): (3, _LADDER_256), # m324P + bytes((0x95, 0x11)): (3, _LADDER_256), # m324PA + bytes((0x96, 0x09)): (3, _LADDER_512), # m644/644A + bytes((0x96, 0x0A)): (3, _LADDER_512), # m644P/644PA + bytes((0x97, 0x06)): (3, _LADDER_512), # m1284 + bytes((0x97, 0x05)): (3, _LADDER_512), # m1284P } diff --git a/test/pbapp.cpp b/test/pbapp.cpp index b5bc3ba..a5ef5a0 100644 --- a/test/pbapp.cpp +++ b/test/pbapp.cpp @@ -17,17 +17,17 @@ namespace { consteval avr::hertz_t clock() { - if (avr::hw::db.name == "ATtiny13A") + auto name = std::string_view{avr::hw::db.name}; + if (name.starts_with("ATtiny13")) return 9.6_MHz; - if (avr::hw::db.name == "ATtiny85") + if (name.starts_with("ATtiny")) return 8_MHz; return 16_MHz; } using dev = avr::device<{.clock = clock()}>; -template +template struct link { using tx_t = avr::uart::usart0; static void tx(char c) diff --git a/test/pbsim.py b/test/pbsim.py index c7f0227..1cd77d6 100644 --- a/test/pbsim.py +++ b/test/pbsim.py @@ -11,7 +11,11 @@ class Device: def __init__(self, binary, elf, mcu, hz, base_hex, page, baud, dump, reset_hex=None, resume=None): cmd = [binary, elf, mcu, hz, base_hex, str(page), str(baud), dump] if reset_hex is not None or resume is not None: - cmd.append(reset_hex if reset_hex is not None else ("0" if not mcu.startswith("atmega") else base_hex)) + # Chips without a hardware boot section — the tinies and the + # m48s — reset to address 0 like silicon; the boot-sectioned + # megas re-vector to the loader base (BOOTRST). + patch = not mcu.startswith("atmega") or mcu.startswith("atmega48") + cmd.append(reset_hex if reset_hex is not None else ("0" if patch else base_hex)) if resume is not None: cmd.append(resume) self.log = open(dump + ".log", "a") diff --git a/test/pbtest.py b/test/pbtest.py index a2f45a5..eb7cacf 100644 --- a/test/pbtest.py +++ b/test/pbtest.py @@ -91,12 +91,14 @@ def main(): read_eeprom = os.path.join(workdir, "readback_eeprom.bin") # The geometry the host will discover, for computing the expected image: - # megas carry a boot section (no vector surgery), the large ones speak - # word addresses, and the page byte is the wire's 0-means-256. + # the boot-sectioned megas need no vector surgery (the tinies and the + # boot-section-less m48s do), the large chips speak word addresses, and + # the page byte is the wire's 0-means-256. mega = mcu.startswith("atmega") + patch = not mega or mcu.startswith("atmega48") word_flash = base + 512 > 0x10000 wire_base = base // 2 if word_flash else base - flags = (0 if mega else 1) | (2 if word_flash else 0) + flags = (1 if patch else 0) | (2 if word_flash else 0) info = pb.Info( bytes([ord("P"), ord("B"), 1, 0, 0, 0, page & 0xFF]) + bytes([wire_base & 0xFF, wire_base >> 8, eeprom_size & 0xFF, eeprom_size >> 8]) @@ -156,9 +158,9 @@ def main(): fail("loader region looks erased in the ground-truth dump") # The surgery, decoded independently: the patched vector must land on the - # loader, the trampoline on the application's own entry (tinies only — - # the megas' word 0 stays the application's). - if not mega: + # loader, the trampoline on the application's own entry (patched-vector + # chips only — a boot-sectioned mega's word 0 stays the application's). + if patch: flash_words = (base + 512) // 2 app = open(app_bin, "rb").read() word0 = flash_true[0] | (flash_true[1] << 8) diff --git a/test/pbupdate.py b/test/pbupdate.py index 453aaf0..a0cd7c4 100644 --- a/test/pbupdate.py +++ b/test/pbupdate.py @@ -5,12 +5,13 @@ replaces itself with a re-timed build through the host tool's killing the simulated device mid-write, restarting it from its flash dump, and letting a re-run complete the update. -The mega runs the BOOTRST-unprogrammed profile (reset boots the application; -the fixture application's 'L' jump is the application-owned loader entry), -with --assume-fuses standing in for the fuse read simavr cannot model. The -tinies reset into a loader at every phase by construction — the t13a because -its staging slot carries the reset vector itself, the t85 through the word-0 -redirect the tool plants around the resident rewrite. +The boot-sectioned megas run the BOOTRST-unprogrammed profile (reset boots +the application; the fixture application's 'L' jump is the application-owned +loader entry), with --assume-fuses standing in for the fuse read simavr +cannot model. The patched-vector chips — the tinies and the m48s — reset +into a loader at every phase by construction: the t13a because its staging +slot carries the reset vector itself, the others through the word-0 redirect +the tool plants around the resident rewrite. Usage: pbupdate.py @@ -89,8 +90,14 @@ def main(): (device_bin, elf, update_elf, mcu, hz, base_hex, page, baud, app_bin, tool, workdir) = sys.argv[1:] base, page, baud = int(base_hex, 0), int(page), int(baud) mega = mcu.startswith("atmega") - slot = 1024 if base + 1024 > 0x10000 and mega else 512 # word-addressed chips use the 1 KiB slot - reset_hex = "0" if mega else None # the mega runs BOOTRST-unprogrammed here + # The m48s are megas without a boot section: patched vector, no fuse + # preflight, and the same reset-to-0 the tinies get. + patch = not mega or mcu.startswith("atmega48") + # Word-addressed (>64 KiB) chips use the 1 KiB slot; their loader base + # itself sits beyond the 16-bit byte space — the 644's base + slot only + # touches the 64 KiB boundary and stays byte-addressed. + slot = 1024 if base >= 0x10000 and mega else 512 + reset_hex = "0" if mega else None # the boot-sectioned mega runs BOOTRST-unprogrammed here sys.path.insert(0, os.path.dirname(os.path.abspath(tool))) sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import pbsim @@ -107,7 +114,7 @@ def main(): fail("the update image is byte-identical to the resident build") dump = os.path.join(workdir, "dump.bin") state = os.path.join(workdir, "update.pbstate") - fuses = assumed_fuses(pb, images["v0"]) if mega else None + fuses = assumed_fuses(pb, images["v0"]) if mega and not patch else None def connect(device): port = pb.Port(device.pty, baud) @@ -147,7 +154,7 @@ def main(): # A clean CLI update, resident -> v9. args = ["--update-loader", os.path.join(workdir, "v9.bin"), "--state", state, "--stay"] - if mega: + if fuses: args += ["--assume-fuses", fuses.hex()] out = pbsim.run_tool(tool, device.pty, baud, *args) if "loader updated" not in out: @@ -172,7 +179,7 @@ def main(): # cost of that profile (README). for kill_region, kill_hits, kill_device in ( ("stage", 2, True), - ("resident", 1, not mega), + ("resident", 1, patch), ("stage_restore", 2, True), ): device.reset() # the previous round left the application running @@ -203,11 +210,11 @@ def main(): device.stop() # Ground truth: the simulator's own flash against the final state, and - # on the tinies an independent decode of the reset routing. + # on the patched-vector chips an independent decode of the reset routing. flash = open(dump, "rb").read() if flash[base : base + slot] != padded(images[final]): fail("ground-truth resident region does not match the final image") - if not mega: + if patch: flash_words = (base + slot) // 2 word0 = flash[0] | (flash[1] << 8) if rjmp_decode(word0, 0, flash_words) != base // 2: diff --git a/test/pureboot_device.c b/test/pureboot_device.c index 7496f38..67feb8c 100644 --- a/test/pureboot_device.c +++ b/test/pureboot_device.c @@ -49,6 +49,13 @@ static volatile sig_atomic_t reset_requested; // anywhere inside the page wipes half the neighbouring page in simulation // only. Wrap the mega's registered flash ioctl and re-dispatch page erases // with Z forced to the page boundary; everything else passes through. +// +// A second gap on the boot-section-less m48s: their RWWSRE bit is the +// temporary-buffer discard (Atmel-8271 §26.2/§26.3.1), but the stock model +// gates its RWWSRE branch on AVR_SELFPROG_HAVE_RWW — absent on the m48 +// core — so the discard store falls through into the buffer-fill branch and +// plants whatever Z/R1:R0 happen to hold. Perform the silicon's discard +// here instead. static avr_flash_t *mega_flash; static int (*mega_flash_ioctl)(avr_io_t *io, uint32_t ctl, void *param); @@ -64,6 +71,15 @@ static int fixed_flash_ioctl(avr_io_t *io, uint32_t ctl, void *param) io->avr->data[31] = (uint8_t)(z >> 8); return result; } + if (ctl == AVR_IOCTL_FLASH_SPM && !(mega_flash->flags & AVR_SELFPROG_HAVE_RWW) && + (io->avr->data[mega_flash->r_spm] & 0x11) == 0x11) { // RWWSRE|SELFPRGEN: the m48 buffer discard + for (int i = 0; i < mega_flash->spm_pagesize / 2; i++) { + mega_flash->tmppage[i] = 0xffff; + mega_flash->tmppage_used[i] = 0; + } + avr_regbit_clear(io->avr, mega_flash->selfprgen); + return 0; + } return mega_flash_ioctl(io, ctl, param); } @@ -306,11 +322,13 @@ int main(int argc, char *argv[]) } memcpy(avr->flash + base, fw.flash, fw.flashsize); } - // The mega enters the loader in hardware (BOOTRST, not modeled — the - // argument picks the modeled fuse's target); the tinies reset to word 0 - // like silicon — erased flash walks up into the loader, and after the - // host's surgery the patched vector routes there. - reset_pc = argc > 8 ? (uint32_t)strtoul(argv[8], NULL, 0) : (use_uart_pty ? base : 0); + // The boot-sectioned megas enter the loader in hardware (BOOTRST, not + // modeled — the argument picks the modeled fuse's target); the tinies + // and the boot-section-less m48s reset to word 0 like silicon — erased + // flash walks up into the loader, and after the host's surgery the + // patched vector routes there. + int boot_section = use_uart_pty && strncmp(mcu_name, "atmega48", 8) != 0; + reset_pc = argc > 8 ? (uint32_t)strtoul(argv[8], NULL, 0) : (boot_section ? base : 0); avr->pc = reset_pc; avr->codeend = avr->flashend; diff --git a/test/test_planner.py b/test/test_planner.py index bd9e62d..e600829 100644 --- a/test/test_planner.py +++ b/test/test_planner.py @@ -56,15 +56,26 @@ def main(): mega = info_of(pb, 0x7E00, 128, False, 0x8000, signature=(0x1E, 0x95, 0x0F)) # mega_boot: BOOTSZ words and the BOOTRST sense per chip — the fuse byte - # index (HIGH everywhere but the m168A's EXTENDED) and the per-family - # ladders (Atmel-2486/2466/2503/8271/42719). Synthetic 'F' replies: only - # the boot byte carries meaning. + # index (EXTENDED on the x8 line except the m328s' HIGH, HIGH elsewhere) + # and the per-family ladders (Atmel-2486/2466/2503/2545/8271/DS40002065/ + # 8272/8011/2593/42719). Synthetic 'F' replies: only the boot byte + # carries meaning. cases = ( ((0x1E, 0x93, 0x07), 0x2000, 3, {0b11: 0x1F00, 0b10: 0x1E00, 0b01: 0x1C00, 0b00: 0x1800}), # m8 ((0x1E, 0x94, 0x03), 0x4000, 3, {0b11: 0x3F00, 0b10: 0x3E00, 0b01: 0x3C00, 0b00: 0x3800}), # m16 ((0x1E, 0x95, 0x02), 0x8000, 3, {0b11: 0x7E00, 0b10: 0x7C00, 0b01: 0x7800, 0b00: 0x7000}), # m32 - ((0x1E, 0x94, 0x06), 0x4000, 2, {0b11: 0x3F00, 0b10: 0x3E00, 0b01: 0x3C00, 0b00: 0x3800}), # m168A + ((0x1E, 0x93, 0x0A), 0x2000, 2, {0b11: 0x1F00, 0b10: 0x1E00, 0b01: 0x1C00, 0b00: 0x1800}), # m88 + ((0x1E, 0x93, 0x0F), 0x2000, 2, {0b11: 0x1F00, 0b10: 0x1E00, 0b01: 0x1C00, 0b00: 0x1800}), # m88P + ((0x1E, 0x94, 0x06), 0x4000, 2, {0b11: 0x3F00, 0b10: 0x3E00, 0b01: 0x3C00, 0b00: 0x3800}), # m168/168A + ((0x1E, 0x94, 0x0B), 0x4000, 2, {0b11: 0x3F00, 0b10: 0x3E00, 0b01: 0x3C00, 0b00: 0x3800}), # m168P + ((0x1E, 0x95, 0x14), 0x8000, 3, {0b11: 0x7E00, 0b10: 0x7C00, 0b01: 0x7800, 0b00: 0x7000}), # m328 ((0x1E, 0x95, 0x0F), 0x8000, 3, {0b11: 0x7E00, 0b10: 0x7C00, 0b01: 0x7800, 0b00: 0x7000}), # m328P + ((0x1E, 0x94, 0x0F), 0x4000, 3, {0b11: 0x3F00, 0b10: 0x3E00, 0b01: 0x3C00, 0b00: 0x3800}), # m164A + ((0x1E, 0x94, 0x0A), 0x4000, 3, {0b11: 0x3F00, 0b10: 0x3E00, 0b01: 0x3C00, 0b00: 0x3800}), # m164P + ((0x1E, 0x95, 0x15), 0x8000, 3, {0b11: 0x7E00, 0b10: 0x7C00, 0b01: 0x7800, 0b00: 0x7000}), # m324A + ((0x1E, 0x96, 0x09), 0x10000, 3, {0b11: 0xFC00, 0b10: 0xF800, 0b01: 0xF000, 0b00: 0xE000}), # m644 + ((0x1E, 0x96, 0x0A), 0x10000, 3, {0b11: 0xFC00, 0b10: 0xF800, 0b01: 0xF000, 0b00: 0xE000}), # m644P + ((0x1E, 0x97, 0x06), 0x20000, 3, {0b11: 0x1FC00, 0b10: 0x1F800, 0b01: 0x1F000, 0b00: 0x1E000}), # 1284 ((0x1E, 0x97, 0x05), 0x20000, 3, {0b11: 0x1FC00, 0b10: 0x1F800, 0b01: 0x1F000, 0b00: 0x1E000}), # 1284P ) for signature, flash, which, ladder in cases: