Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
Go
Haskell
HLSL
Hook
Hylo
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Nim
Objective-C
Objective-C++
OCaml
OpenCL C
Pascal
Pony
Python
Racket
Ruby
Rust
Snowball
Scala
Solidity
Spice
Swift
LLVM TableGen
Toit
TypeScript Native
V
Vala
Visual Basic
Zig
Javascript
GIMPLE
c++ source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
6502-c++ 11.1.0
ARM GCC 10.2.0
ARM GCC 10.3.0
ARM GCC 10.4.0
ARM GCC 10.5.0
ARM GCC 11.1.0
ARM GCC 11.2.0
ARM GCC 11.3.0
ARM GCC 11.4.0
ARM GCC 12.1.0
ARM GCC 12.2.0
ARM GCC 12.3.0
ARM GCC 13.1.0
ARM GCC 13.2.0
ARM GCC 13.2.0 (unknown-eabi)
ARM GCC 4.5.4
ARM GCC 4.6.4
ARM GCC 5.4
ARM GCC 6.3.0
ARM GCC 6.4.0
ARM GCC 7.3.0
ARM GCC 7.5.0
ARM GCC 8.2.0
ARM GCC 8.5.0
ARM GCC 9.3.0
ARM GCC 9.4.0
ARM GCC 9.5.0
ARM GCC trunk
ARM gcc 10.2.1 (none)
ARM gcc 10.3.1 (2021.07 none)
ARM gcc 10.3.1 (2021.10 none)
ARM gcc 11.2.1 (none)
ARM gcc 5.4.1 (none)
ARM gcc 7.2.1 (none)
ARM gcc 8.2 (WinCE)
ARM gcc 8.3.1 (none)
ARM gcc 9.2.1 (none)
ARM msvc v19.0 (WINE)
ARM msvc v19.10 (WINE)
ARM msvc v19.14 (WINE)
ARM64 Morello gcc 10.1 Alpha 2
ARM64 gcc 10.2
ARM64 gcc 10.3
ARM64 gcc 10.4
ARM64 gcc 10.5.0
ARM64 gcc 11.1
ARM64 gcc 11.2
ARM64 gcc 11.3
ARM64 gcc 11.4.0
ARM64 gcc 12.1
ARM64 gcc 12.2.0
ARM64 gcc 12.3.0
ARM64 gcc 13.1.0
ARM64 gcc 13.2.0
ARM64 gcc 5.4
ARM64 gcc 6.3
ARM64 gcc 6.4
ARM64 gcc 7.3
ARM64 gcc 7.5
ARM64 gcc 8.2
ARM64 gcc 8.5
ARM64 gcc 9.3
ARM64 gcc 9.4
ARM64 gcc 9.5
ARM64 gcc trunk
ARM64 msvc v19.14 (WINE)
AVR gcc 10.3.0
AVR gcc 11.1.0
AVR gcc 12.1.0
AVR gcc 12.2.0
AVR gcc 12.3.0
AVR gcc 13.1.0
AVR gcc 13.2.0
AVR gcc 4.5.4
AVR gcc 4.6.4
AVR gcc 5.4.0
AVR gcc 9.2.0
AVR gcc 9.3.0
Arduino Mega (1.8.9)
Arduino Uno (1.8.9)
BPF clang (trunk)
BPF clang 13.0.0
BPF clang 14.0.0
BPF clang 15.0.0
BPF clang 16.0.0
BPF clang 17.0.1
BPF clang 18.1.0
BPF gcc 13.1.0
BPF gcc 13.2.0
BPF gcc trunk
EDG (experimental reflection)
EDG 6.5
EDG 6.5 (GNU mode gcc 13)
EDG 6.6
EDG 6.6 (GNU mode gcc 13)
FRC 2019
FRC 2020
FRC 2023
KVX ACB 4.1.0 (GCC 7.5.0)
KVX ACB 4.1.0-cd1 (GCC 7.5.0)
KVX ACB 4.10.0 (GCC 10.3.1)
KVX ACB 4.11.1 (GCC 10.3.1)
KVX ACB 4.12.0 (GCC 11.3.0)
KVX ACB 4.2.0 (GCC 7.5.0)
KVX ACB 4.3.0 (GCC 7.5.0)
KVX ACB 4.4.0 (GCC 7.5.0)
KVX ACB 4.6.0 (GCC 9.4.1)
KVX ACB 4.8.0 (GCC 9.4.1)
KVX ACB 4.9.0 (GCC 9.4.1)
M68K gcc 13.1.0
M68K gcc 13.2.0
M68k clang (trunk)
MRISC32 gcc (trunk)
MSP430 gcc 4.5.3
MSP430 gcc 5.3.0
MSP430 gcc 6.2.1
MinGW clang 14.0.3
MinGW clang 14.0.6
MinGW clang 15.0.7
MinGW clang 16.0.0
MinGW clang 16.0.2
MinGW gcc 11.3.0
MinGW gcc 12.1.0
MinGW gcc 12.2.0
MinGW gcc 13.1.0
RISC-V (32-bits) gcc (trunk)
RISC-V (32-bits) gcc 10.2.0
RISC-V (32-bits) gcc 10.3.0
RISC-V (32-bits) gcc 11.2.0
RISC-V (32-bits) gcc 11.3.0
RISC-V (32-bits) gcc 11.4.0
RISC-V (32-bits) gcc 12.1.0
RISC-V (32-bits) gcc 12.2.0
RISC-V (32-bits) gcc 12.3.0
RISC-V (32-bits) gcc 13.1.0
RISC-V (32-bits) gcc 13.2.0
RISC-V (32-bits) gcc 8.2.0
RISC-V (32-bits) gcc 8.5.0
RISC-V (32-bits) gcc 9.4.0
RISC-V (64-bits) gcc (trunk)
RISC-V (64-bits) gcc 10.2.0
RISC-V (64-bits) gcc 10.3.0
RISC-V (64-bits) gcc 11.2.0
RISC-V (64-bits) gcc 11.3.0
RISC-V (64-bits) gcc 11.4.0
RISC-V (64-bits) gcc 12.1.0
RISC-V (64-bits) gcc 12.2.0
RISC-V (64-bits) gcc 12.3.0
RISC-V (64-bits) gcc 13.1.0
RISC-V (64-bits) gcc 13.2.0
RISC-V (64-bits) gcc 8.2.0
RISC-V (64-bits) gcc 8.5.0
RISC-V (64-bits) gcc 9.4.0
RISC-V rv32gc clang (trunk)
RISC-V rv32gc clang 10.0.0
RISC-V rv32gc clang 10.0.1
RISC-V rv32gc clang 11.0.0
RISC-V rv32gc clang 11.0.1
RISC-V rv32gc clang 12.0.0
RISC-V rv32gc clang 12.0.1
RISC-V rv32gc clang 13.0.0
RISC-V rv32gc clang 13.0.1
RISC-V rv32gc clang 14.0.0
RISC-V rv32gc clang 15.0.0
RISC-V rv32gc clang 16.0.0
RISC-V rv32gc clang 17.0.1
RISC-V rv32gc clang 18.1.0
RISC-V rv32gc clang 9.0.0
RISC-V rv32gc clang 9.0.1
RISC-V rv64gc clang (trunk)
RISC-V rv64gc clang 10.0.0
RISC-V rv64gc clang 10.0.1
RISC-V rv64gc clang 11.0.0
RISC-V rv64gc clang 11.0.1
RISC-V rv64gc clang 12.0.0
RISC-V rv64gc clang 12.0.1
RISC-V rv64gc clang 13.0.0
RISC-V rv64gc clang 13.0.1
RISC-V rv64gc clang 14.0.0
RISC-V rv64gc clang 15.0.0
RISC-V rv64gc clang 16.0.0
RISC-V rv64gc clang 17.0.1
RISC-V rv64gc clang 18.1.0
RISC-V rv64gc clang 9.0.0
RISC-V rv64gc clang 9.0.1
Raspbian Buster
Raspbian Stretch
SPARC LEON gcc 12.2.0
SPARC LEON gcc 12.3.0
SPARC LEON gcc 13.1.0
SPARC LEON gcc 13.2.0
SPARC gcc 12.2.0
SPARC gcc 12.3.0
SPARC gcc 13.1.0
SPARC gcc 13.2.0
SPARC64 gcc 12.2.0
SPARC64 gcc 12.3.0
SPARC64 gcc 13.1.0
SPARC64 gcc 13.2.0
TI C6x gcc 12.2.0
TI C6x gcc 12.3.0
TI C6x gcc 13.1.0
TI C6x gcc 13.2.0
TI CL430 21.6.1
VAX gcc NetBSDELF 10.4.0
VAX gcc NetBSDELF 10.5.0 (Nov 15 03:50:22 2023)
WebAssembly clang (trunk)
Xtensa ESP32 gcc 11.2.0 (2022r1)
Xtensa ESP32 gcc 12.2.0 (20230208)
Xtensa ESP32 gcc 8.2.0 (2019r2)
Xtensa ESP32 gcc 8.2.0 (2020r1)
Xtensa ESP32 gcc 8.2.0 (2020r2)
Xtensa ESP32 gcc 8.4.0 (2020r3)
Xtensa ESP32 gcc 8.4.0 (2021r1)
Xtensa ESP32 gcc 8.4.0 (2021r2)
Xtensa ESP32-S2 gcc 11.2.0 (2022r1)
Xtensa ESP32-S2 gcc 12.2.0 (20230208)
Xtensa ESP32-S2 gcc 8.2.0 (2019r2)
Xtensa ESP32-S2 gcc 8.2.0 (2020r1)
Xtensa ESP32-S2 gcc 8.2.0 (2020r2)
Xtensa ESP32-S2 gcc 8.4.0 (2020r3)
Xtensa ESP32-S2 gcc 8.4.0 (2021r1)
Xtensa ESP32-S2 gcc 8.4.0 (2021r2)
Xtensa ESP32-S3 gcc 11.2.0 (2022r1)
Xtensa ESP32-S3 gcc 12.2.0 (20230208)
Xtensa ESP32-S3 gcc 8.4.0 (2020r3)
Xtensa ESP32-S3 gcc 8.4.0 (2021r1)
Xtensa ESP32-S3 gcc 8.4.0 (2021r2)
arm64 msvc v19.28 VS16.9
arm64 msvc v19.29 VS16.10
arm64 msvc v19.29 VS16.11
arm64 msvc v19.30
arm64 msvc v19.31
arm64 msvc v19.32
arm64 msvc v19.33
arm64 msvc v19.34
arm64 msvc v19.35
arm64 msvc v19.36
arm64 msvc v19.37
arm64 msvc v19.38
arm64 msvc v19.latest
armv7-a clang (trunk)
armv7-a clang 10.0.0
armv7-a clang 10.0.1
armv7-a clang 11.0.0
armv7-a clang 11.0.1
armv7-a clang 9.0.0
armv7-a clang 9.0.1
armv8-a clang (all architectural features, trunk)
armv8-a clang (trunk)
armv8-a clang 10.0.0
armv8-a clang 10.0.1
armv8-a clang 11.0.0
armv8-a clang 11.0.1
armv8-a clang 12.0.0
armv8-a clang 13.0.0
armv8-a clang 14.0.0
armv8-a clang 15.0.0
armv8-a clang 16.0.0
armv8-a clang 17.0.1
armv8-a clang 18.1.0
armv8-a clang 9.0.0
armv8-a clang 9.0.1
ellcc 0.1.33
ellcc 0.1.34
ellcc 2017-07-16
hexagon-clang 16.0.5
llvm-mos atari2600-3e
llvm-mos atari2600-4k
llvm-mos atari2600-common
llvm-mos atari5200-supercart
llvm-mos atari8-cart-megacart
llvm-mos atari8-cart-std
llvm-mos atari8-cart-xegs
llvm-mos atari8-common
llvm-mos atari8-dos
llvm-mos c128
llvm-mos c64
llvm-mos commodore
llvm-mos cpm65
llvm-mos cx16
llvm-mos dodo
llvm-mos eater
llvm-mos mega65
llvm-mos nes
llvm-mos nes-action53
llvm-mos nes-cnrom
llvm-mos nes-gtrom
llvm-mos nes-mmc1
llvm-mos nes-mmc3
llvm-mos nes-nrom
llvm-mos nes-unrom
llvm-mos nes-unrom-512
llvm-mos osi-c1p
llvm-mos pce
llvm-mos pce-cd
llvm-mos pce-common
llvm-mos pet
llvm-mos rp6502
llvm-mos rpc8e
llvm-mos supervision
llvm-mos vic20
loongarch64 gcc 12.2.0
loongarch64 gcc 12.3.0
loongarch64 gcc 13.1.0
loongarch64 gcc 13.2.0
mips clang 13.0.0
mips clang 14.0.0
mips clang 15.0.0
mips clang 16.0.0
mips clang 17.0.1
mips clang 18.1.0
mips gcc 11.2.0
mips gcc 12.1.0
mips gcc 12.2.0
mips gcc 12.3.0
mips gcc 13.1.0
mips gcc 13.2.0
mips gcc 4.9.4
mips gcc 5.4
mips gcc 5.5.0
mips gcc 9.3.0 (codescape)
mips gcc 9.5.0
mips64 (el) gcc 12.1.0
mips64 (el) gcc 12.2.0
mips64 (el) gcc 12.3.0
mips64 (el) gcc 13.1.0
mips64 (el) gcc 13.2.0
mips64 (el) gcc 4.9.4
mips64 (el) gcc 5.4.0
mips64 (el) gcc 5.5.0
mips64 (el) gcc 9.5.0
mips64 clang 13.0.0
mips64 clang 14.0.0
mips64 clang 15.0.0
mips64 clang 16.0.0
mips64 clang 17.0.1
mips64 clang 18.1.0
mips64 gcc 11.2.0
mips64 gcc 12.1.0
mips64 gcc 12.2.0
mips64 gcc 12.3.0
mips64 gcc 13.1.0
mips64 gcc 13.2.0
mips64 gcc 4.9.4
mips64 gcc 5.4.0
mips64 gcc 5.5.0
mips64 gcc 9.5.0
mips64el clang 13.0.0
mips64el clang 14.0.0
mips64el clang 15.0.0
mips64el clang 16.0.0
mips64el clang 17.0.1
mips64el clang 18.1.0
mipsel clang 13.0.0
mipsel clang 14.0.0
mipsel clang 15.0.0
mipsel clang 16.0.0
mipsel clang 17.0.1
mipsel clang 18.1.0
mipsel gcc 12.1.0
mipsel gcc 12.2.0
mipsel gcc 12.3.0
mipsel gcc 13.1.0
mipsel gcc 13.2.0
mipsel gcc 4.9.4
mipsel gcc 5.4.0
mipsel gcc 5.5.0
mipsel gcc 9.5.0
nanoMIPS gcc 6.3.0 (mtk)
power gcc 11.2.0
power gcc 12.1.0
power gcc 12.2.0
power gcc 12.3.0
power gcc 13.1.0
power gcc 13.2.0
power gcc 4.8.5
power64 AT12.0 (gcc8)
power64 AT13.0 (gcc9)
power64 gcc 11.2.0
power64 gcc 12.1.0
power64 gcc 12.2.0
power64 gcc 12.3.0
power64 gcc 13.1.0
power64 gcc 13.2.0
power64 gcc trunk
power64le AT12.0 (gcc8)
power64le AT13.0 (gcc9)
power64le clang (trunk)
power64le gcc 11.2.0
power64le gcc 12.1.0
power64le gcc 12.2.0
power64le gcc 12.3.0
power64le gcc 13.1.0
power64le gcc 13.2.0
power64le gcc 6.3.0
power64le gcc trunk
powerpc64 clang (trunk)
s390x gcc 11.2.0
s390x gcc 12.1.0
s390x gcc 12.2.0
s390x gcc 12.3.0
s390x gcc 13.1.0
s390x gcc 13.2.0
sh gcc 12.2.0
sh gcc 12.3.0
sh gcc 13.1.0
sh gcc 13.2.0
sh gcc 4.9.4
sh gcc 9.5.0
vast (trunk)
x64 msvc v19.0 (WINE)
x64 msvc v19.10 (WINE)
x64 msvc v19.14
x64 msvc v19.14 (WINE)
x64 msvc v19.15
x64 msvc v19.16
x64 msvc v19.20
x64 msvc v19.21
x64 msvc v19.22
x64 msvc v19.23
x64 msvc v19.24
x64 msvc v19.25
x64 msvc v19.26
x64 msvc v19.27
x64 msvc v19.28
x64 msvc v19.28 VS16.9
x64 msvc v19.29 VS16.10
x64 msvc v19.29 VS16.11
x64 msvc v19.30
x64 msvc v19.31
x64 msvc v19.32
x64 msvc v19.33
x64 msvc v19.34
x64 msvc v19.35
x64 msvc v19.36
x64 msvc v19.37
x64 msvc v19.38
x64 msvc v19.latest
x86 djgpp 4.9.4
x86 djgpp 5.5.0
x86 djgpp 6.4.0
x86 djgpp 7.2.0
x86 msvc v19.0 (WINE)
x86 msvc v19.10 (WINE)
x86 msvc v19.14
x86 msvc v19.14 (WINE)
x86 msvc v19.15
x86 msvc v19.16
x86 msvc v19.20
x86 msvc v19.21
x86 msvc v19.22
x86 msvc v19.23
x86 msvc v19.24
x86 msvc v19.25
x86 msvc v19.26
x86 msvc v19.27
x86 msvc v19.28
x86 msvc v19.28 VS16.9
x86 msvc v19.29 VS16.10
x86 msvc v19.29 VS16.11
x86 msvc v19.30
x86 msvc v19.31
x86 msvc v19.32
x86 msvc v19.33
x86 msvc v19.34
x86 msvc v19.35
x86 msvc v19.36
x86 msvc v19.37
x86 msvc v19.38
x86 msvc v19.latest
x86 nvc++ 22.11
x86 nvc++ 22.7
x86 nvc++ 22.9
x86 nvc++ 23.1
x86 nvc++ 23.11
x86 nvc++ 23.3
x86 nvc++ 23.5
x86 nvc++ 23.7
x86 nvc++ 23.9
x86 nvc++ 24.1
x86 nvc++ 24.3
x86-64 Zapcc 190308
x86-64 clang (amd-stg-open)
x86-64 clang (assertions trunk)
x86-64 clang (clangir)
x86-64 clang (experimental -Wlifetime)
x86-64 clang (experimental P1061)
x86-64 clang (experimental P1144)
x86-64 clang (experimental P1221)
x86-64 clang (experimental P2996)
x86-64 clang (experimental metaprogramming - P2632)
x86-64 clang (experimental pattern matching)
x86-64 clang (old concepts branch)
x86-64 clang (reflection)
x86-64 clang (resugar)
x86-64 clang (thephd.dev)
x86-64 clang (trunk)
x86-64 clang (variadic friends - P2893)
x86-64 clang (widberg)
x86-64 clang 10.0.0
x86-64 clang 10.0.0 (assertions)
x86-64 clang 10.0.1
x86-64 clang 11.0.0
x86-64 clang 11.0.0 (assertions)
x86-64 clang 11.0.1
x86-64 clang 12.0.0
x86-64 clang 12.0.0 (assertions)
x86-64 clang 12.0.1
x86-64 clang 13.0.0
x86-64 clang 13.0.0 (assertions)
x86-64 clang 13.0.1
x86-64 clang 14.0.0
x86-64 clang 14.0.0 (assertions)
x86-64 clang 15.0.0
x86-64 clang 15.0.0 (assertions)
x86-64 clang 16.0.0
x86-64 clang 16.0.0 (assertions)
x86-64 clang 17.0.1
x86-64 clang 17.0.1 (assertions)
x86-64 clang 18.1.0
x86-64 clang 18.1.0 (assertions)
x86-64 clang 2.6.0 (assertions)
x86-64 clang 2.7.0 (assertions)
x86-64 clang 2.8.0 (assertions)
x86-64 clang 2.9.0 (assertions)
x86-64 clang 3.0.0
x86-64 clang 3.0.0 (assertions)
x86-64 clang 3.1
x86-64 clang 3.1 (assertions)
x86-64 clang 3.2
x86-64 clang 3.2 (assertions)
x86-64 clang 3.3
x86-64 clang 3.3 (assertions)
x86-64 clang 3.4 (assertions)
x86-64 clang 3.4.1
x86-64 clang 3.5
x86-64 clang 3.5 (assertions)
x86-64 clang 3.5.1
x86-64 clang 3.5.2
x86-64 clang 3.6
x86-64 clang 3.6 (assertions)
x86-64 clang 3.7
x86-64 clang 3.7 (assertions)
x86-64 clang 3.7.1
x86-64 clang 3.8
x86-64 clang 3.8 (assertions)
x86-64 clang 3.8.1
x86-64 clang 3.9.0
x86-64 clang 3.9.0 (assertions)
x86-64 clang 3.9.1
x86-64 clang 4.0.0
x86-64 clang 4.0.0 (assertions)
x86-64 clang 4.0.1
x86-64 clang 5.0.0
x86-64 clang 5.0.0 (assertions)
x86-64 clang 5.0.1
x86-64 clang 5.0.2
x86-64 clang 6.0.0
x86-64 clang 6.0.0 (assertions)
x86-64 clang 6.0.1
x86-64 clang 7.0.0
x86-64 clang 7.0.0 (assertions)
x86-64 clang 7.0.1
x86-64 clang 7.1.0
x86-64 clang 8.0.0
x86-64 clang 8.0.0 (assertions)
x86-64 clang 8.0.1
x86-64 clang 9.0.0
x86-64 clang 9.0.0 (assertions)
x86-64 clang 9.0.1
x86-64 clang rocm-4.5.2
x86-64 clang rocm-5.0.2
x86-64 clang rocm-5.1.3
x86-64 clang rocm-5.2.3
x86-64 clang rocm-5.3.3
x86-64 clang rocm-5.7.0
x86-64 gcc (contract labels)
x86-64 gcc (contracts natural syntax)
x86-64 gcc (contracts)
x86-64 gcc (coroutines)
x86-64 gcc (modules)
x86-64 gcc (trunk)
x86-64 gcc 10.1
x86-64 gcc 10.2
x86-64 gcc 10.3
x86-64 gcc 10.4
x86-64 gcc 10.5
x86-64 gcc 11.1
x86-64 gcc 11.2
x86-64 gcc 11.3
x86-64 gcc 11.4
x86-64 gcc 12.1
x86-64 gcc 12.2
x86-64 gcc 12.3
x86-64 gcc 13.1
x86-64 gcc 13.2
x86-64 gcc 4.1.2
x86-64 gcc 4.4.7
x86-64 gcc 4.5.3
x86-64 gcc 4.6.4
x86-64 gcc 4.7.1
x86-64 gcc 4.7.2
x86-64 gcc 4.7.3
x86-64 gcc 4.7.4
x86-64 gcc 4.8.1
x86-64 gcc 4.8.2
x86-64 gcc 4.8.3
x86-64 gcc 4.8.4
x86-64 gcc 4.8.5
x86-64 gcc 4.9.0
x86-64 gcc 4.9.1
x86-64 gcc 4.9.2
x86-64 gcc 4.9.3
x86-64 gcc 4.9.4
x86-64 gcc 5.1
x86-64 gcc 5.2
x86-64 gcc 5.3
x86-64 gcc 5.4
x86-64 gcc 5.5
x86-64 gcc 6.1
x86-64 gcc 6.2
x86-64 gcc 6.3
x86-64 gcc 6.4
x86-64 gcc 7.1
x86-64 gcc 7.2
x86-64 gcc 7.3
x86-64 gcc 7.4
x86-64 gcc 7.5
x86-64 gcc 8.1
x86-64 gcc 8.2
x86-64 gcc 8.3
x86-64 gcc 8.4
x86-64 gcc 8.5
x86-64 gcc 9.1
x86-64 gcc 9.2
x86-64 gcc 9.3
x86-64 gcc 9.4
x86-64 gcc 9.5
x86-64 icc 13.0.1
x86-64 icc 16.0.3
x86-64 icc 17.0.0
x86-64 icc 18.0.0
x86-64 icc 19.0.0
x86-64 icc 19.0.1
x86-64 icc 2021.1.2
x86-64 icc 2021.10.0
x86-64 icc 2021.2.0
x86-64 icc 2021.3.0
x86-64 icc 2021.4.0
x86-64 icc 2021.5.0
x86-64 icc 2021.6.0
x86-64 icc 2021.7.0
x86-64 icc 2021.7.1
x86-64 icc 2021.8.0
x86-64 icc 2021.9.0
x86-64 icx (latest)
x86-64 icx 2021.1.2
x86-64 icx 2021.2.0
x86-64 icx 2021.3.0
x86-64 icx 2021.4.0
x86-64 icx 2022.0.0
x86-64 icx 2022.1.0
x86-64 icx 2022.2.0
x86-64 icx 2022.2.1
x86-64 icx 2023.0.0
x86-64 icx 2023.1.0
x86-64 icx 2023.2.1
x86-64 icx 2024.0.0
zig c++ 0.10.0
zig c++ 0.11.0
zig c++ 0.12.0
zig c++ 0.6.0
zig c++ 0.7.0
zig c++ 0.7.1
zig c++ 0.8.0
zig c++ 0.9.0
zig c++ trunk
Options
Source code
//#pragma once #include <avr/io.h> #include <stdbool.h> /*----------------------------------------------------------------------------- bootloader - avr0/1 tiny, mega user set defines for both tiny and mega ALT_PINS - use alternate pins? (0,1) LEDUSE - use status led? (0,1) LEDPORT - led port (A-x) LEDPIN - led pin (0-7) LEDONVAL - out value for on (0,1) BOOTSIZE - bootloader section size in bytes if you have a mega, also select which usart UARTN - usart number (0-3) -----------------------------------------------------------------------------*/ #define ALT_PINS 1 //use uart alternate usart pins = 1 #define LEDUSE 1 //use led? #define LEDPORT PORTB #define LEDPIN 5 #define LEDONVAL 0 //0=low is on, 1=high is on #define USARTN 0 //tiny is always 0, mega is 0-3 #define BOOTSIZE 512 //multiple of 256 /*----------------------------------------------------------------------------- fuses - change as needed the BOOTEND value will need to be set, if the bootloader size is <=512 bytes it can be set to 2 (the value is n*256) linker script, change fuse section- >fuse -> AT>fuse which along with const will allow us to get these values at compile time if wanted (we already have BOOTSIZE in a define so can use that instead of the __fuse[8] value, but we can use to see if watchdog is fused on) it seems will need to make this an array [9] instead of FUSE_t, as compiler will otherwise generate code to access instead of treating as a compiler time known value (so need to access values as __fuse[n]) can also create defines as done with BOOTSIZE -----------------------------------------------------------------------------*/ //tiny0/1 const uint8_t __fuse[9] __attribute((used, section(".fuse"))) = { 0, // WDTCFG {PERIOD=OFF, WINDOW=OFF} 0, // BODCFG {SLEEP=DIS, ACTIVE=DIS, SAMPFREQ=1KHZ, LVL=BODLEVEL0} 2, // OSCCFG {FREQSEL=20MHZ, OSCLOCK=CLEAR} 0, // unused 0, // TCD0CFG 0xF6, // SYSCFG0 {EESAVE=CLEAR, RSTPINCFG=UPDI, CRCSRC=NOCRC} 7, // SYSCFG1 {SUT=64MS} 0, // APPEND (0 means it starts at BOOTEND) BOOTSIZE/256 // BOOTEND (n * 256) }; //============================================================================= //== no need to change anything below this line == //============================================================================= /*----------------------------------------------------------------------------- pin functions user pins defined as &PORTn,PIN #define LED &PORTA,2 -----------------------------------------------------------------------------*/ typedef uint8_t u8; typedef volatile u8 vu8; #define SII static inline __attribute((always_inline)) #define VPORT(pt) (*(VPORT_t*)((((int)pt - (int)&PORTA)/0x20)*4)) //PORTx to VPORTx #define BM(pn) (1<<(pn&7)) SII void pinCtrl (PORT_t* pt, u8 pn, u8 v) { (&pt->PIN0CTRL)[pn&7] = v; } SII void pinPullOn (PORT_t* pt, u8 pn) { pinCtrl(pt,pn,PORT_PULLUPEN_bm); } //no other bits preserved SII void pinPullOff (PORT_t* pt, u8 pn) { pinCtrl(pt,pn,0); } //no other bits preserved SII void pinOutput (PORT_t* pt, u8 pn) { VPORT(pt).DIR |= BM(pn); } SII void pinHigh (PORT_t* pt, u8 pn) { VPORT(pt).OUT |= BM(pn); } SII void pinLow (PORT_t* pt, u8 pn) { VPORT(pt).OUT &= ~BM(pn); } SII bool pinIsHigh (PORT_t* pt, u8 pn) { return VPORT(pt).IN & BM(pn); } SII bool pinIsLow (PORT_t* pt, u8 pn) { return !pinIsHigh(pt,pn); } SII void pinSet (PORT_t* pt, u8 pn, bool highison) { highison ? pinHigh(pt,pn) : pinLow(pt,pn); } #undef VPORT #undef BM //only mega has USART2, tiny's only USART0 except tiny2's have USART1 #if defined USART2 /*----------------------------------------------------------------------------- pin defines - mega -----------------------------------------------------------------------------*/ //avr0 mega, usart0-3 = port a,c,f,b, tx=pin0,rx=pin1, alt tx=pin4,rx=pin5 //no need to specify pins for mega #if USARTN == 0 #define USARTPORT PORTA #elif USARTN == 1 #define USARTPORT PORTC #elif USARTN == 2 #define USARTPORT PORTF #elif USARTN = 3 #define USARTPORT PORTB #endif #if ALT_PINS #define TXPIN 4 #define RXPIN 5 #else #define TXPIN 0 #define RXPIN 1 #endif #define USARTMUXVAL (ALT_PINS ? 1<<(USARTN*2) : 0) #define USARTMUX USARTROUTEA #define USART (*(volatile USART_t*)((int)&USART0 + USARTN*0x20)) //using (int) so addition is byte addition and we do //our own addition based on usart peripheral spacing //(0x20) and not the USART_t size, which does not //include PINxCTRL registers #elif defined USART1 /*----------------------------------------------------------------------------- pin defines - tiny2's -----------------------------------------------------------------------------*/ #else /*----------------------------------------------------------------------------- pin defines - tiny -----------------------------------------------------------------------------*/ //PB2/3 is default pins except on 8 pins devices, which are PA6/7 //PA1/2 is alternate pins on all #if ALT_PINS #define USARTPORT PORTA #define TXPIN 1 #define RXPIN 2 #else #if defined PORTB #define USARTPORT PORTB #define TXPIN 2 #define RXPIN 3 #else #define USARTPORT PORTA #define TXPIN 6 #define RXPIN 7 #endif #endif #define USARTMUXVAL (ALT_PINS ? 1 : 0) #define USARTMUX CTRLB #define USART USART0 //only has usart0 #endif //#if defined MEGA /*----------------------------------------------------------------------------- other common defines -----------------------------------------------------------------------------*/ #define TX &USARTPORT,TXPIN #define RX &USARTPORT,RXPIN #if LEDUSE #define LEDon() pinOutput(&LEDPORT,LEDPIN); pinSet(&LEDPORT,LEDPIN,LEDONVAL) #define LEDoff() pinSet(&LEDPORT,LEDPIN,!LEDONVAL) #else #define LEDon() #define LEDoff() #endif //main.c /*----------------------------------------------------------------------------- bootloader for avr0 mega, avr0/1 tiny tested- 3217 curiosity nano- led = PA3 (low is on), usart0 default pins 416 xplained mini - led = PB5 (low is on), usart0 alternate pins linker script- avrxmega3.xn, copy to project folder comment out .vectors so vectors not linked in add .reset_vector and .avr_info add option in linkers settings- -Xlinker -script=avrxmega3.xn */ // /* *(.vectors) KEEP(*(.vectors)) */ /* *(.reset_vector) KEEP(*(.reset_vector)) *(.avr_info) KEEP(*(.avr_info)) -----------------------------------------------------------------------------*/ #define TESTING 0 //1 = force bootloader to run, 0 = normal /*----------------------------------------------------------------------------- includes -----------------------------------------------------------------------------*/ #include <avr/io.h> #include <stdbool.h> // #include "mcu.h" /*----------------------------------------------------------------------------- typedef, defines, and similar -----------------------------------------------------------------------------*/ typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; #define SI static inline // inline prevents unused function warnings #define SYNC 0x55 // sync char after timing byte and // last byte in command/data packet /*----------------------------------------------------------------------------- vars -----------------------------------------------------------------------------*/ union { u8 buf[64]; // the complete buffer struct { // these are buf[0]-buf[2] u8* addr; // buf[0,1], LL HH address u8 nbytes : 7; // buf[2], NN 6:0 0-127 -> 1-128 u8 wr : 1; // NN 7 0=read, 1=write }; } rxbuf __attribute(( section(".noinit") )); //no need to init to 0 // store mcu info to access from pc typedef struct { u8 info_size; void(*write_ccp)(u8*,u8); //for app use u16 flash_start; //mapped u16 flash_size; u16 flash_page_size; u16 eeprom_size; u16 eeprom_page_size; u16 sram_start; u16 sram_size; } INFO_t; void writeCCP(u8* addr, u8 v); //declare, so can use its address now // put in .avr_info section (address 0x0002) // this info can also be figured out just by getting the mcu signature, // but this allows the pc to skip having to keep a list of mcu's and // their proterties (and no need to update the list as new mcu's are added) __attribute(( section(".avr_info") )) const INFO_t __info = { .info_size = sizeof(INFO_t)-1, //16 .write_ccp = writeCCP, .flash_start = MAPPED_PROGMEM_START, .flash_size = MAPPED_PROGMEM_SIZE, .flash_page_size = MAPPED_PROGMEM_PAGE_SIZE, .eeprom_size = EEPROM_SIZE, .eeprom_page_size = EEPROM_PAGE_SIZE, .sram_start = INTERNAL_SRAM_START, .sram_size = INTERNAL_SRAM_SIZE, }; /*----------------------------------------------------------------------------- functions -----------------------------------------------------------------------------*/ // .vectors commented out of linker script so no vector table // will be linked in (but all other normal C startup things remain) // will use .reset_vector section to place this at address 0 void __attribute((section(".reset_vector"), naked)) reset () { asm("rjmp __init"); //rjmp ok for any mcu, all our code is reachable } // location for writeCCP is found in __info struct (u16@0x0003) // no inline so is also available as a callable function from // outside the bootloader // write to *addr with v value, if a protected nvm command then // use spm unlock value, otherwise uses io unlock value // to use from the app space- // static void (*writeCCP)(u8*,u8) = (void(*)(u8*,u8))(*(u16*)0x0003); // *(u8*)(0x8200) = 1; //wrote to page buffer (app address 0) // writeCCP( 0x1000, 3 ); //erase and write page void __attribute(( noinline )) writeCCP (u8* addr, u8 v) { CCP = (addr == (u8*)0x1000 ? 0x9D : 0xD8); *addr = v; } // watchdog 1,2,4, or 8sec SI void watchdogOn (u8 sec) { sec = (sec<=1?8 : sec<=2?9 : sec<=4?10 : 11); writeCCP( (u8*)&WDT.CTRLA, sec ); } // cpu clock prescale DIV2 (8MHz or 10MHz), so we are in a // safe range for >=2.7V (if lower, then need to lower cpu freq) SI void clockInit () { writeCCP( (u8*)&CLKCTRL.MCLKCTRLB, 1 ); } /*............................................................. stay in bootloader if- app section byte 0 = 0xFF (no app code) flash last byte = 0 (app signal to bootloader) stay in bootloader WITH watchdog enabled if- rx pin is low anything else- jump to app any valid command will disable watchdog (if fused on will need a valid command every 8 seconds to prevent timeout) can erase last flash address via writeCCP call from app to force bootloader to run after a reset .............................................................*/ SI void entryCheck () { //will need rx pullup on, if we jump to app we will turn back off pinPullOn(RX); // app first byte (read from memory mapped flash) // if app first byte is erased (0xFF)) stay in bootloader // or if last byte in flash cleared (0), stay in bootloader if( TESTING || *(u8*)(MAPPED_PROGMEM_START|BOOTSIZE) == 0xFF || *(u8*)(MAPPED_PROGMEM_START+MAPPED_PROGMEM_SIZE-1) == 0 ) return; // if rx pin is low, stay in bootloader with watchdog on // which then requires a valid command in 8 seconds in case // was inadvertant for some reason (rx pin activity when reset) if( pinIsLow(RX) ){ while( pinIsLow(RX) ){} // wait for release watchdogOn(8); // need a valid command in 8 seconds return; } // go to app (need word address to call) pinPullOff(RX); ((void(*)())(BOOTSIZE/2))(); } SI void uartInit () { if( USARTMUXVAL ) PORTMUX.USARTMUX = USARTMUXVAL; //if alternate pin USART.CTRLB = (USART_TXEN_bm); //tx only (also gets tx pin to idle state) USART.TXDATAL = 0; //to set txcif (baud register is still 0) //RX pin pullup was enabled in entryCheck pinOutput(TX); } // blocking, tx 1 byte SI void putByte (u8 c) { while( (USART.STATUS & USART_DREIF_bm) == 0 ){} //wait for tx buffer USART.TXDATAL = c; USART.STATUS = USART_TXCIF_bm; //clear txcif } // blocking, with timeout ( >13ms+ between bytes will cause timeout) // rx data into buffer, return true if ends with SYNC and no errors SI bool getBytes (u8 n) { u8* pb = rxbuf.buf; u8 rxstatus; //no init value ok u8 err = 0; // need 1 more than n for SYNC, so use i <= n // n WILL be 1 - 128, so no infinite loop possible (n cannot be 255) for( u8 i = 0; i <= n ; i++ ){ TCB0.CNT = 0; //reset counter while( rxstatus = USART.RXDATAH, !(rxstatus & USART_RXCIF_bm) ){ if( TCB0.CNT > 0xFF00 ) return false; //timeout } *pb = USART.RXDATAL; putByte(*pb++); //echo all incoming bytes err |= (rxstatus & ~USART_RXCIF_bm); //save any err bits // get all bytes even if error so we do not try to autobaud // on any remaining incoming bytes } return !err && (pb[-1] == SYNC); //no error and correct end = true } // use 0x80 as timing byte (8bits low), which will use TCB timer // in div2 mode, which will result in a value that can directly // transfer to the BAUD register SI void getCommand () { while(1){ // wait for any tx in progress before baud register is changed while( ! (USART.STATUS & USART_TXCIF_bm) ){} // disable rx, but leave tx on so tx pin stays idle/high USART.CTRLB = (USART_TXEN_bm); TCB0.CTRLA = 3; // tcb0 on w/clk div2 LEDon(); // on until valid timing byte // will assume a pulse H->L->H stays within 16bit tcb count // which is about 16ms ( 9600+ baud will be ok ) TCB0.CNTL = 0; // preset L to 0 (TEMP = 0) while( pinIsHigh(RX) ){} // wait for 1->0 (idle->start) TCB0.CNTH = 0; // reset counter (H:TEMP -> CNT) while( pinIsLow(RX) ){} // wait for 0->1 (bit6->bit7) u16 cnt = TCB0.CNT; // get copy of CNT // if >= minimum value, get sync, then command bytes+sync // 0x55 (done separately to verify), [LL][HH][NN]+0x55 // if all looks ok, return and let caller process command if( cnt >= 64 ){ USART.CTRLB = (USART_RXEN_bm|USART_TXEN_bm); //enable rx LEDoff(); // off until we get back to the start USART.BAUD = cnt; // baud register=tcb count (1:1) putByte(0x80); // manually echo the timing byte if( getBytes(0) && getBytes(3) ) return; //0x55, then LLHHNN55 } // else try again }// while(1) } int main () { entryCheck(); // if we are here, we are now in bootloader clockInit(); uartInit(); while(1){ getCommand(); // we have a valid command // reset watchdog on any valid command // if watchdog fused on, will require a valid command // every 8 seconds to get to this wdr instruction // (code will be optimized to choose only one version below) if( __fuse[0] ) asm("wdr"); // if not fused on, then first valid command will disable the // watchdog so there will be no watchdog timeout and pc code // has no need to make sure the watchdog does not timeout else writeCCP( (u8*)&WDT.CTRLA, 0 ); // pc can read watchdog fuse register to see what its dealing // with, and if it needs to keep the watchdog from timing out // copy needed info before using buf again u8 nbytes = rxbuf.nbytes+1; //0-127-> 1-128 u8* addr = rxbuf.addr; u8* pbuf = rxbuf.buf; switch( rxbuf.wr ){ case 0: //read while( nbytes-- ) putByte(*addr++); break; default: //write if( ! getBytes(nbytes) ) break; // if is a 1 byte write, do a protectd write // if > 1, copy buf data to destination if( nbytes == 1 ) writeCCP(addr, *pbuf ); else while( nbytes-- ) *addr++ = *pbuf++; } } //while(1) } //main
Become a Patron
Sponsor on GitHub
Donate via PayPal
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
About the author
Statistics
Changelog
Version tree