Merge pull request #1203 from cpunion/esp-llvm

Build Target Task 2: Multi-Platform LLVM Support and Bootable Code Generation
This commit is contained in:
xushiwei
2025-08-24 08:36:02 +08:00
committed by GitHub
822 changed files with 89209 additions and 437 deletions

1
.github/codecov.yml vendored
View File

@@ -9,4 +9,5 @@ coverage:
- "internal/packages"
- "internal/typepatch"
- "internal/github"
- "internal/firmware"
- "xtool"

View File

@@ -36,145 +36,5 @@ jobs:
- name: Build targets
run: |
cd _demo/empty
for target in \
ae-rp2040 \
arduino-leonardo \
arduino-mega1280 \
arduino-mega2560 \
arduino-mkr1000 \
arduino-mkrwifi1010 \
arduino-nano-new \
arduino-nano \
arduino-nano33 \
arduino-zero \
arduino \
atmega1280 \
atmega1284p \
atmega2560 \
atmega328p \
atmega328pb \
atmega32u4 \
atsamd21e18a \
atsamd21g18a \
atsamd51g19a \
atsamd51j19a \
atsamd51j20a \
atsamd51p19a \
atsamd51p20a \
atsame51j19a \
atsame54-xpro \
atsame54p20a \
attiny1616 \
attiny85 \
badger2040-w \
badger2040 \
bluepill-clone \
bluepill \
btt-skr-pico \
challenger-rp2040 \
circuitplay-express \
cortex-m-qemu \
cortex-m0 \
cortex-m0plus \
cortex-m3 \
cortex-m33 \
cortex-m4 \
cortex-m7 \
digispark \
elecrow-rp2040 \
elecrow-rp2350 \
esp-c3-32s-kit \
esp32-c3-devkit-rust-1 \
esp32c3-12f \
esp32c3-supermini \
esp32c3 \
fe310 \
feather-m0-express \
feather-m0 \
feather-m4-can \
feather-m4 \
feather-rp2040 \
feather-stm32f405 \
gameboy-advance \
gemma-m0 \
gnse \
gobadge \
gopher-badge \
gopherbot \
grandcentral-m4 \
hifive1b \
itsybitsy-m0 \
itsybitsy-m4 \
k210 \
kb2040 \
lgt92 \
lorae5 \
m5stamp-c3 \
macropad-rp2040 \
maixbit \
makerfabs-esp32c3spi35 \
matrixportal-m4 \
metro-m4-airlift \
mksnanov3 \
nano-rp2040 \
nintendoswitch \
nucleo-f103rb \
nucleo-f722ze \
nucleo-l031k6 \
nucleo-l432kc \
nucleo-l476rg \
nucleo-l552ze \
nucleo-wl55jc \
p1am-100 \
pga2350 \
pico-plus2 \
pico-w \
pico \
pico2-w \
pico2 \
pybadge \
pygamer \
pyportal \
qtpy-esp32c3 \
qtpy-rp2040 \
qtpy \
riscv-qemu \
riscv32 \
riscv64 \
rp2040 \
rp2350 \
rp2350b \
simavr \
stm32f469disco \
stm32f4disco-1 \
stm32f4disco \
stm32l0x2 \
stm32wl5x_cm4 \
stm32wle5 \
swan \
teensy36 \
teensy40 \
teensy41 \
thingplus-rp2040 \
thumby \
tiny2350 \
tkey \
trinket-m0 \
trinkey-qt2040 \
tufty2040 \
wasip2 \
wasm-unknown \
waveshare-rp2040-tiny \
waveshare-rp2040-zero \
wioterminal \
xiao-esp32c3 \
xiao-rp2040 \
xiao; do
../../llgo.sh build -v -target $target -o hello.out . >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo ✅ $target `file hello.out`
else
echo ❌ $target
fi
done
cd _demo/targetsbuild
bash build.sh

View File

@@ -1,4 +0,0 @@
package main
func main() {
}

21
_demo/targetsbuild/C/c.go Normal file
View File

@@ -0,0 +1,21 @@
package C
func XhandleHardFault() {
}
func Reset_Handler() {
}
func XhandleInterrupt() {
}
type dyn64 struct {
// Fields for dynamic loader
}
// For nintendo switch
func X__dynamic_loader(base uintptr, dyn *dyn64) {
}

180
_demo/targetsbuild/build.sh Normal file
View File

@@ -0,0 +1,180 @@
#!/bin/bash
# Function to display usage information
show_usage() {
cat << EOF
Usage: $(basename "$0") [OPTIONS] [TARGET_FILE]
Build targets for llgo across multiple platforms.
OPTIONS:
-h, --help Show this help message and exit
ARGUMENTS:
TARGET_FILE Optional. A text file containing target names, one per line.
Lines starting with # are treated as comments and ignored.
Empty lines are also ignored.
BEHAVIOR:
Without TARGET_FILE:
- Automatically discovers all targets from ../../targets/*.json files
- Extracts target names from JSON filenames
With TARGET_FILE:
- Reads target names from the specified file
- Supports comments (lines starting with #)
- Ignores empty lines and whitespace
IGNORED TARGETS:
The following targets are automatically ignored and not built:
atmega1280, atmega2560, atmega328p, atmega32u4, attiny85,
fe310, k210, riscv32, riscv64, rp2040
RESULT CATEGORIES:
✅ Successful: Build completed successfully
🔕 Ignored: Target is in the ignore list
⚠️ Warned: Build failed with configuration warnings
❌ Failed: Build failed with errors
EXIT CODES:
0 All builds successful, ignored, or warned only
1 One or more builds failed with errors
EXAMPLES:
$(basename "$0") # Build all targets from JSON files
$(basename "$0") my-targets.txt # Build targets from file
$(basename "$0") --help # Show this help
TARGET FILE FORMAT:
# This is a comment
esp32
cortex-m4
# Another comment
riscv64
EOF
}
# Check for help flag
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
show_usage
exit 0
fi
# Check for invalid number of arguments
if [ $# -gt 1 ]; then
echo "Error: Too many arguments."
echo "Use '$(basename "$0") --help' for usage information."
exit 1
fi
# Initialize arrays to store results
successful_targets=()
ignored_targets=()
warned_targets=()
failed_targets=()
targets_to_build=()
# Define ignore list
ignore_list=(
"atmega1280"
"atmega2560"
"atmega328p"
"atmega32u4"
"attiny85"
"fe310"
"k210"
"riscv32"
"riscv64"
"rp2040"
)
# Build the targets list based on input method
if [ $# -eq 1 ]; then
# Read targets from file
target_file="$1"
if [ ! -f "$target_file" ]; then
echo "Error: Target file '$target_file' not found."
echo "Use '$(basename "$0") --help' for usage information."
exit 1
fi
while IFS= read -r target || [[ -n "$target" ]]; do
# Skip empty lines and comments
if [[ -z "$target" || "$target" =~ ^[[:space:]]*# ]]; then
continue
fi
# Trim whitespace
target=$(echo "$target" | xargs)
targets_to_build+=("$target")
done < "$target_file"
else
# Use targets from *.json files
for target_file in ../../targets/*.json; do
# Extract target name from filename (remove path and .json extension)
target=$(basename "$target_file" .json)
targets_to_build+=("$target")
done
fi
# Process each target
for target in "${targets_to_build[@]}"; do
# Check if target is in ignore list
if [[ " ${ignore_list[@]} " =~ " ${target} " ]]; then
echo 🔕 $target "(ignored)"
ignored_targets+=("$target")
continue
fi
output=$(../../llgo.sh build -target $target -o hello.out . 2>&1)
if [ $? -eq 0 ]; then
echo$target `file hello.out`
successful_targets+=("$target")
else
# Check if output contains warning messages
if echo "$output" | grep -q "does not have a valid LLVM target triple\|does not have a valid CPU configuration"; then
echo ⚠️ $target
echo "$output"
warned_targets+=("$target")
else
echo$target
echo "$output"
failed_targets+=("$target")
fi
fi
done
echo ""
echo "----------------------------------------"
# Output successful targets
echo "Successful targets (${#successful_targets[@]} total):"
for target in "${successful_targets[@]}"; do
echo "$target"
done
echo ""
echo "Ignored targets (${#ignored_targets[@]} total):"
for target in "${ignored_targets[@]}"; do
echo "$target"
done
echo ""
echo "Warned targets (${#warned_targets[@]} total):"
for target in "${warned_targets[@]}"; do
echo "$target"
done
echo ""
echo "Failed targets (${#failed_targets[@]} total):"
for target in "${failed_targets[@]}"; do
echo "$target"
done
# Exit with error code if there are any failed targets
if [ ${#failed_targets[@]} -gt 0 ]; then
echo ""
echo "Build failed with ${#failed_targets[@]} failed targets."
exit 1
fi

View File

@@ -0,0 +1,6 @@
package main
import _ "github.com/goplus/llgo/_demo/targetsbuild/C"
func main() {
}

2
go.mod
View File

@@ -15,6 +15,8 @@ require (
golang.org/x/tools v0.36.0
)
require github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1
require (
golang.org/x/mod v0.27.0 // indirect
golang.org/x/sync v0.16.0 // indirect

2
go.sum
View File

@@ -12,6 +12,8 @@ github.com/goplus/mod v0.17.1 h1:ITovxDcc5zbURV/Wrp3/SBsYLgC1KrxY6pq1zMM2V94=
github.com/goplus/mod v0.17.1/go.mod h1:iXEszBKqi38BAyQApBPyQeurLHmQN34YMgC2ZNdap50=
github.com/qiniu/x v1.15.1 h1:avE+YQaowp8ZExjylOeSM73rUo3MQKBAYVxh4NJ8dY8=
github.com/qiniu/x v1.15.1/go.mod h1:AiovSOCaRijaf3fj+0CBOpR1457pn24b0Vdb1JpwhII=
github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1 h1:NVK+OqnavpyFmUiKfUMHrpvbCi2VFoWTrcpI7aDaJ2I=
github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=

View File

@@ -39,13 +39,14 @@ import (
"github.com/goplus/llgo/cl"
"github.com/goplus/llgo/internal/cabi"
"github.com/goplus/llgo/internal/clang"
"github.com/goplus/llgo/internal/crosscompile"
"github.com/goplus/llgo/internal/env"
"github.com/goplus/llgo/internal/firmware"
"github.com/goplus/llgo/internal/mockable"
"github.com/goplus/llgo/internal/packages"
"github.com/goplus/llgo/internal/typepatch"
"github.com/goplus/llgo/ssa/abi"
"github.com/goplus/llgo/xtool/clang"
xenv "github.com/goplus/llgo/xtool/env"
"github.com/goplus/llgo/xtool/env/llvm"
@@ -156,7 +157,7 @@ func Do(args []string, conf *Config) ([]Package, error) {
conf.Goarch = runtime.GOARCH
}
// Handle crosscompile configuration first to set correct GOOS/GOARCH
export, err := crosscompile.UseWithTarget(conf.Goos, conf.Goarch, IsWasiThreadsEnabled(), conf.Target)
export, err := crosscompile.Use(conf.Goos, conf.Goarch, IsWasiThreadsEnabled(), conf.Target)
if err != nil {
return nil, fmt.Errorf("failed to setup crosscompile: %w", err)
}
@@ -389,19 +390,27 @@ type context struct {
}
func (c *context) compiler() *clang.Cmd {
cmd := c.env.Clang()
if c.crossCompile.CC != "" {
cmd = clang.New(c.crossCompile.CC)
}
config := clang.NewConfig(
c.crossCompile.CC,
c.crossCompile.CCFLAGS,
c.crossCompile.CFLAGS,
c.crossCompile.LDFLAGS,
c.crossCompile.Linker,
)
cmd := clang.NewCompiler(config)
cmd.Verbose = c.buildConf.Verbose
return cmd
}
func (c *context) linker() *clang.Cmd {
cmd := c.env.Clang()
if c.crossCompile.Linker != "" {
cmd = clang.New(c.crossCompile.Linker)
}
config := clang.NewConfig(
c.crossCompile.CC,
c.crossCompile.CCFLAGS,
c.crossCompile.CFLAGS,
c.crossCompile.LDFLAGS,
c.crossCompile.Linker,
)
cmd := clang.NewLinker(config)
cmd.Verbose = c.buildConf.Verbose
return cmd
}
@@ -552,23 +561,145 @@ func createGlobals(ctx *context, prog llssa.Program, pkgs []*aPackage) (llssa.Pa
return global, nil
}
func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, global llssa.Package, conf *Config, mode Mode, verbose bool) {
pkgPath := pkg.PkgPath
name := path.Base(pkgPath)
app := conf.OutFile
if app == "" {
if mode == ModeBuild && len(ctx.initial) > 1 {
// compileExtraFiles compiles extra files (.s/.c) from target configuration and returns object files
func compileExtraFiles(ctx *context, verbose bool) ([]string, error) {
if len(ctx.crossCompile.ExtraFiles) == 0 {
return nil, nil
}
var objFiles []string
llgoRoot := env.LLGoROOT()
for _, extraFile := range ctx.crossCompile.ExtraFiles {
// Resolve the file path relative to llgo root
srcFile := filepath.Join(llgoRoot, extraFile)
// Check if file exists
if _, err := os.Stat(srcFile); os.IsNotExist(err) {
return nil, fmt.Errorf("extra file not found: %s", srcFile)
}
// Generate output file name
objFile, err := os.CreateTemp("", "extra-*"+filepath.Base(extraFile))
if err != nil {
return nil, fmt.Errorf("failed to create temp file for %s: %w", extraFile, err)
}
objFile.Close()
var outputFile string
ext := filepath.Ext(srcFile)
if ctx.buildConf.GenLL {
outputFile = objFile.Name() + ".ll"
} else {
outputFile = objFile.Name() + ".o"
}
// Prepare compilation arguments
var args []string
// Handle different file types
switch ext {
case ".c":
args = append(args, "-x", "c")
case ".S", ".s":
args = append(args, "-x", "assembler-with-cpp")
}
// Add output flags
if ctx.buildConf.GenLL {
args = append(args, "-emit-llvm", "-S", "-o", outputFile, "-c", srcFile)
} else {
args = append(args, "-o", outputFile, "-c", srcFile)
}
if verbose {
fmt.Fprintf(os.Stderr, "Compiling extra file: clang %s\n", strings.Join(args, " "))
}
// Compile the file
cmd := ctx.compiler()
if err := cmd.Compile(args...); err != nil {
return nil, fmt.Errorf("failed to compile extra file %s: %w", srcFile, err)
}
objFiles = append(objFiles, outputFile)
os.Remove(objFile.Name()) // Remove the temp file we created for naming
}
return objFiles, nil
}
// generateOutputFilenames generates the final output filename (app) and intermediate filename (orgApp)
// based on configuration and build context.
func generateOutputFilenames(outFile, binPath, appExt, binExt, pkgName string, mode Mode, isMultiplePkgs bool) (app, orgApp string, err error) {
if outFile == "" {
if mode == ModeBuild && isMultiplePkgs {
// For multiple packages in ModeBuild mode, use temporary file
tmpFile, err := os.CreateTemp("", name+"*"+conf.AppExt)
check(err)
name := pkgName
if binExt != "" {
name += "*" + binExt
} else {
name += "*" + appExt
}
tmpFile, err := os.CreateTemp("", name)
if err != nil {
return "", "", err
}
app = tmpFile.Name()
tmpFile.Close()
} else {
app = filepath.Join(conf.BinPath, name+conf.AppExt)
app = filepath.Join(binPath, pkgName+appExt)
}
} else if filepath.Ext(app) == "" {
app += conf.AppExt
orgApp = app
} else {
// outFile is not empty, use it as base part
base := outFile
if binExt != "" {
// If binExt has value, use temporary file as orgApp for firmware conversion
tmpFile, err := os.CreateTemp("", "llgo-*"+appExt)
if err != nil {
return "", "", err
}
orgApp = tmpFile.Name()
tmpFile.Close()
// Check if base already ends with binExt, if so, don't add it again
if strings.HasSuffix(base, binExt) {
app = base
} else {
app = base + binExt
}
} else {
// No binExt, use base + AppExt directly
if filepath.Ext(base) == "" {
app = base + appExt
} else {
app = base
}
orgApp = app
}
}
return app, orgApp, nil
}
func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, global llssa.Package, conf *Config, mode Mode, verbose bool) {
pkgPath := pkg.PkgPath
name := path.Base(pkgPath)
binFmt := ctx.crossCompile.BinaryFormat
binExt := firmware.BinaryExt(binFmt)
// app: converted firmware output file or executable file
// orgApp: before converted output file
app, orgApp, err := generateOutputFilenames(
conf.OutFile,
conf.BinPath,
conf.AppExt,
binExt,
name,
mode,
len(ctx.initial) > 1,
)
check(err)
needRuntime := false
needPyInit := false
@@ -600,6 +731,11 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, global l
// defer os.Remove(entryLLFile)
objFiles = append(objFiles, entryObjFile)
// Compile extra files from target configuration
extraObjFiles, err := compileExtraFiles(ctx, verbose)
check(err)
objFiles = append(objFiles, extraObjFiles...)
if global != nil {
export, err := exportObject(ctx, pkg.PkgPath+".global", pkg.ExportFile+"-global", []byte(global.String()))
check(err)
@@ -619,9 +755,15 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, global l
linkArgs = append(linkArgs, exargs...)
}
err = linkObjFiles(ctx, app, objFiles, linkArgs, verbose)
err = linkObjFiles(ctx, orgApp, objFiles, linkArgs, verbose)
check(err)
if orgApp != app {
fmt.Printf("cross compile: %#v\n", ctx.crossCompile)
err = firmware.MakeFirmwareImage(orgApp, app, ctx.crossCompile.BinaryFormat, ctx.crossCompile.FormatDetail)
check(err)
}
switch mode {
case ModeTest:
cmd := exec.Command(app, conf.RunArgs...)
@@ -685,8 +827,6 @@ func linkObjFiles(ctx *context, app string, objFiles, linkArgs []string, verbose
buildArgs = append(buildArgs, "-gdwarf-4")
}
buildArgs = append(buildArgs, ctx.crossCompile.LDFLAGS...)
buildArgs = append(buildArgs, ctx.crossCompile.EXTRAFLAGS...)
buildArgs = append(buildArgs, objFiles...)
cmd := ctx.linker()
@@ -698,6 +838,18 @@ func isWasmTarget(goos string) bool {
return slices.Contains([]string{"wasi", "js", "wasip1"}, goos)
}
func needStart(conf *Config) bool {
if conf.Target == "" {
return !isWasmTarget(conf.Goos)
}
switch conf.Target {
case "wasip2":
return false
default:
return true
}
}
func genMainModuleFile(ctx *context, rtPkgPath string, pkg *packages.Package, needRuntime, needPyInit bool) (path string, err error) {
var (
pyInitDecl string
@@ -751,8 +903,10 @@ define weak void @_start() {
}
`
mainDefine := "define i32 @main(i32 noundef %0, ptr nocapture noundef readnone %1) local_unnamed_addr"
if isWasmTarget(ctx.buildConf.Goos) {
if !needStart(ctx.buildConf) && isWasmTarget(ctx.buildConf.Goos) {
mainDefine = "define hidden noundef i32 @__main_argc_argv(i32 noundef %0, ptr nocapture noundef readnone %1) local_unnamed_addr"
}
if !needStart(ctx.buildConf) {
startDefine = ""
}
mainCode := fmt.Sprintf(`; ModuleID = 'main'
@@ -883,8 +1037,6 @@ func exportObject(ctx *context, pkgPath string, exportFile string, data []byte)
}
exportFile += ".o"
args := []string{"-o", exportFile, "-c", f.Name(), "-Wno-override-module"}
args = append(args, ctx.crossCompile.CCFLAGS...)
args = append(args, ctx.crossCompile.CFLAGS...)
if ctx.buildConf.Verbose {
fmt.Fprintln(os.Stderr, "clang", args)
}
@@ -1126,8 +1278,6 @@ func clFile(ctx *context, args []string, cFile, expFile string, procFile func(li
llFile += ".o"
args = append(args, "-o", llFile, "-c", cFile)
}
args = append(args, ctx.crossCompile.CCFLAGS...)
args = append(args, ctx.crossCompile.CFLAGS...)
if verbose {
fmt.Fprintln(os.Stderr, "clang", args)
}

View File

@@ -8,6 +8,7 @@ import (
"fmt"
"io"
"os"
"strings"
"testing"
"github.com/goplus/llgo/internal/mockable"
@@ -93,3 +94,173 @@ func TestExtest(t *testing.T) {
func TestCmpTest(t *testing.T) {
mockRun([]string{"../../cl/_testgo/runtest"}, &Config{Mode: ModeCmpTest})
}
func TestGenerateOutputFilenames(t *testing.T) {
tests := []struct {
name string
outFile string
binPath string
appExt string
binExt string
pkgName string
mode Mode
isMultiplePkgs bool
wantAppSuffix string
wantOrgAppDiff bool // true if orgApp should be different from app
wantErr bool
}{
{
name: "empty outFile, single package",
outFile: "",
binPath: "/usr/local/bin",
appExt: "",
binExt: "",
pkgName: "hello",
mode: ModeBuild,
isMultiplePkgs: false,
wantAppSuffix: "/usr/local/bin/hello",
wantOrgAppDiff: false,
},
{
name: "empty outFile with appExt",
outFile: "",
binPath: "/usr/local/bin",
appExt: ".exe",
binExt: "",
pkgName: "hello",
mode: ModeBuild,
isMultiplePkgs: false,
wantAppSuffix: "/usr/local/bin/hello.exe",
wantOrgAppDiff: false,
},
{
name: "outFile without binExt",
outFile: "myapp",
binPath: "/usr/local/bin",
appExt: ".exe",
binExt: "",
pkgName: "hello",
mode: ModeBuild,
isMultiplePkgs: false,
wantAppSuffix: "myapp.exe",
wantOrgAppDiff: false,
},
{
name: "outFile with existing extension, no binExt",
outFile: "myapp.exe",
binPath: "/usr/local/bin",
appExt: ".exe",
binExt: "",
pkgName: "hello",
mode: ModeBuild,
isMultiplePkgs: false,
wantAppSuffix: "myapp.exe",
wantOrgAppDiff: false,
},
{
name: "outFile with binExt, different from existing extension",
outFile: "myapp",
binPath: "/usr/local/bin",
appExt: ".exe",
binExt: ".bin",
pkgName: "hello",
mode: ModeBuild,
isMultiplePkgs: false,
wantAppSuffix: "myapp.bin",
wantOrgAppDiff: true,
},
{
name: "outFile already ends with binExt",
outFile: "t.bin",
binPath: "/usr/local/bin",
appExt: ".exe",
binExt: ".bin",
pkgName: "hello",
mode: ModeBuild,
isMultiplePkgs: false,
wantAppSuffix: "t.bin",
wantOrgAppDiff: true,
},
{
name: "outFile with full path already ends with binExt",
outFile: "/path/to/t.bin",
binPath: "/usr/local/bin",
appExt: ".exe",
binExt: ".bin",
pkgName: "hello",
mode: ModeBuild,
isMultiplePkgs: false,
wantAppSuffix: "/path/to/t.bin",
wantOrgAppDiff: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
app, orgApp, err := generateOutputFilenames(
tt.outFile,
tt.binPath,
tt.appExt,
tt.binExt,
tt.pkgName,
tt.mode,
tt.isMultiplePkgs,
)
if (err != nil) != tt.wantErr {
t.Errorf("generateOutputFilenames() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantAppSuffix != "" {
if app != tt.wantAppSuffix {
t.Errorf("generateOutputFilenames() app = %v, want %v", app, tt.wantAppSuffix)
}
}
if tt.wantOrgAppDiff {
if app == orgApp {
t.Errorf("generateOutputFilenames() orgApp should be different from app, but both are %v", app)
}
// Clean up temp file
if orgApp != "" && strings.Contains(orgApp, "llgo-") {
os.Remove(orgApp)
}
} else {
if app != orgApp {
t.Errorf("generateOutputFilenames() orgApp = %v, want %v (same as app)", orgApp, app)
}
}
})
}
}
func TestGenerateOutputFilenames_EdgeCases(t *testing.T) {
// Test case where outFile has same extension as binExt
app, orgApp, err := generateOutputFilenames(
"firmware.bin",
"/usr/local/bin",
".exe",
".bin",
"esp32app",
ModeBuild,
false,
)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if app != "firmware.bin" {
t.Errorf("Expected app to be 'firmware.bin', got '%s'", app)
}
if app == orgApp {
t.Errorf("Expected orgApp to be different from app when binExt is present, but both are '%s'", app)
}
// Clean up temp file
if orgApp != "" && strings.Contains(orgApp, "llgo-") {
os.Remove(orgApp)
}
}

202
internal/clang/clang.go Normal file
View File

@@ -0,0 +1,202 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package clang
import (
"fmt"
"io"
"os"
"os/exec"
"runtime"
"strings"
"github.com/goplus/llgo/xtool/safesplit"
)
// Config represents clang configuration parameters.
type Config struct {
CC string // Compiler to use (e.g., "clang", "clang++")
CCFLAGS []string // Compiler flags for C/C++ compilation
CFLAGS []string // C-specific flags
LDFLAGS []string // Linker flags
Linker string // Linker to use (e.g., "ld.lld", "avr-ld")
}
// NewConfig creates a new Config with the specified parameters.
func NewConfig(cc string, ccflags, cflags, ldflags []string, linker string) Config {
return Config{
CC: cc,
CCFLAGS: ccflags,
CFLAGS: cflags,
LDFLAGS: ldflags,
Linker: linker,
}
}
// Cmd represents a clang command with environment and configuration support.
type Cmd struct {
app string
config Config
Env []string
Verbose bool
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
}
// New creates a new clang command with configuration.
func New(app string, config Config) *Cmd {
if app == "" {
app = "clang"
}
return &Cmd{
app: app,
config: config,
Env: nil,
Verbose: false,
Stdin: nil,
Stdout: os.Stdout,
Stderr: os.Stderr,
}
}
// NewCompiler creates a compiler command with proper flag merging.
func NewCompiler(config Config) *Cmd {
app := "clang"
if config.CC != "" {
app = config.CC
}
return New(app, config)
}
// NewLinker creates a linker command with proper flag merging.
func NewLinker(config Config) *Cmd {
app := "clang"
if config.Linker != "" {
app = config.Linker
} else if config.CC != "" {
app = config.CC
}
return New(app, config)
}
// Compile executes a compilation command with merged flags.
func (c *Cmd) Compile(args ...string) error {
flags := c.mergeCompilerFlags()
allArgs := make([]string, 0, len(flags)+len(args))
allArgs = append(allArgs, flags...)
allArgs = append(allArgs, args...)
return c.exec(allArgs...)
}
// Link executes a linking command with merged flags.
func (c *Cmd) Link(args ...string) error {
flags := c.mergeLinkerFlags()
allArgs := make([]string, 0, len(flags)+len(args))
allArgs = append(allArgs, flags...)
allArgs = append(allArgs, args...)
return c.exec(allArgs...)
}
// mergeCompilerFlags merges environment CCFLAGS/CFLAGS with config flags.
func (c *Cmd) mergeCompilerFlags() []string {
var flags []string
// Add environment CCFLAGS
if envCCFlags := os.Getenv("CCFLAGS"); envCCFlags != "" {
flags = append(flags, safesplit.SplitPkgConfigFlags(envCCFlags)...)
}
// Add environment CFLAGS
if envCFlags := os.Getenv("CFLAGS"); envCFlags != "" {
flags = append(flags, safesplit.SplitPkgConfigFlags(envCFlags)...)
}
// Add config CCFLAGS
flags = append(flags, c.config.CCFLAGS...)
// Add config CFLAGS
flags = append(flags, c.config.CFLAGS...)
return flags
}
// mergeLinkerFlags merges environment CCFLAGS/LDFLAGS with config flags.
func (c *Cmd) mergeLinkerFlags() []string {
var flags []string
// Add environment CCFLAGS (for linker)
if envCCFlags := os.Getenv("CCFLAGS"); envCCFlags != "" {
flags = append(flags, safesplit.SplitPkgConfigFlags(envCCFlags)...)
}
// Add environment LDFLAGS
if envLDFlags := os.Getenv("LDFLAGS"); envLDFlags != "" {
flags = append(flags, safesplit.SplitPkgConfigFlags(envLDFlags)...)
}
// Add config LDFLAGS
flags = append(flags, c.config.LDFLAGS...)
return flags
}
// exec executes the clang command with given arguments.
func (c *Cmd) exec(args ...string) error {
cmd := exec.Command(c.app, args...)
if c.Verbose {
fmt.Fprintf(os.Stderr, "%v\n", cmd)
}
cmd.Stdin = c.Stdin
cmd.Stdout = c.Stdout
cmd.Stderr = c.Stderr
if c.Env != nil {
cmd.Env = c.Env
}
return cmd.Run()
}
// CheckLinkArgs validates linking arguments by attempting a test compile.
func (c *Cmd) CheckLinkArgs(cmdArgs []string, wasm bool) error {
// Create a temporary file with appropriate extension
extension := ""
if wasm {
extension = ".wasm"
} else if runtime.GOOS == "windows" {
extension = ".exe"
}
tmpFile, err := os.CreateTemp("", "llgo_check*"+extension)
if err != nil {
return fmt.Errorf("failed to create temporary file: %w", err)
}
tmpFile.Close()
tmpPath := tmpFile.Name()
// Make sure to delete the temporary file when done
defer os.Remove(tmpPath)
// Set up compilation arguments
args := append([]string{}, cmdArgs...)
args = append(args, []string{"-x", "c", "-o", tmpPath, "-"}...)
src := "int main() {return 0;}"
srcIn := strings.NewReader(src)
c.Stdin = srcIn
// Execute the command with linker flags
return c.Link(args...)
}

View File

@@ -0,0 +1,513 @@
//go:build !llgo
// +build !llgo
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package clang
import (
"bytes"
"os"
"reflect"
"strings"
"testing"
)
func TestConfig(t *testing.T) {
t.Run("NewConfig", func(t *testing.T) {
ccflags := []string{"-O2", "-g"}
cflags := []string{"-std=c99"}
ldflags := []string{"-lm"}
config := NewConfig("clang++", ccflags, cflags, ldflags, "ld.lld")
if config.CC != "clang++" {
t.Errorf("Expected CC to be 'clang++', got %q", config.CC)
}
if !reflect.DeepEqual(config.CCFLAGS, ccflags) {
t.Errorf("Expected CCFLAGS %v, got %v", ccflags, config.CCFLAGS)
}
if !reflect.DeepEqual(config.CFLAGS, cflags) {
t.Errorf("Expected CFLAGS %v, got %v", cflags, config.CFLAGS)
}
if !reflect.DeepEqual(config.LDFLAGS, ldflags) {
t.Errorf("Expected LDFLAGS %v, got %v", ldflags, config.LDFLAGS)
}
if config.Linker != "ld.lld" {
t.Errorf("Expected Linker to be 'ld.lld', got %q", config.Linker)
}
})
}
func TestNew(t *testing.T) {
t.Run("WithApp", func(t *testing.T) {
config := Config{CC: "gcc"}
cmd := New("clang++", config)
if cmd.app != "clang++" {
t.Errorf("Expected app to be 'clang++', got %q", cmd.app)
}
if !reflect.DeepEqual(cmd.config, config) {
t.Errorf("Expected config %+v, got %+v", config, cmd.config)
}
if cmd.Stdout != os.Stdout {
t.Error("Expected Stdout to be os.Stdout")
}
if cmd.Stderr != os.Stderr {
t.Error("Expected Stderr to be os.Stderr")
}
})
t.Run("WithoutApp", func(t *testing.T) {
config := Config{}
cmd := New("", config)
if cmd.app != "clang" {
t.Errorf("Expected app to be 'clang', got %q", cmd.app)
}
})
}
func TestNewCompiler(t *testing.T) {
t.Run("WithCC", func(t *testing.T) {
config := Config{CC: "gcc"}
cmd := NewCompiler(config)
if cmd.app != "gcc" {
t.Errorf("Expected app to be 'gcc', got %q", cmd.app)
}
})
t.Run("WithoutCC", func(t *testing.T) {
config := Config{}
cmd := NewCompiler(config)
if cmd.app != "clang" {
t.Errorf("Expected app to be 'clang', got %q", cmd.app)
}
})
}
func TestNewLinker(t *testing.T) {
t.Run("WithLinker", func(t *testing.T) {
config := Config{Linker: "ld.lld"}
cmd := NewLinker(config)
if cmd.app != "ld.lld" {
t.Errorf("Expected app to be 'ld.lld', got %q", cmd.app)
}
})
t.Run("WithoutLinkerButWithCC", func(t *testing.T) {
config := Config{CC: "gcc"}
cmd := NewLinker(config)
if cmd.app != "gcc" {
t.Errorf("Expected app to be 'gcc', got %q", cmd.app)
}
})
t.Run("WithoutLinkerAndCC", func(t *testing.T) {
config := Config{}
cmd := NewLinker(config)
if cmd.app != "clang" {
t.Errorf("Expected app to be 'clang', got %q", cmd.app)
}
})
}
func TestMergeCompilerFlags(t *testing.T) {
// Save original environment
origCCFlags := os.Getenv("CCFLAGS")
origCFlags := os.Getenv("CFLAGS")
defer func() {
os.Setenv("CCFLAGS", origCCFlags)
os.Setenv("CFLAGS", origCFlags)
}()
t.Run("WithEnvironmentAndConfig", func(t *testing.T) {
os.Setenv("CCFLAGS", "-O2 -g")
os.Setenv("CFLAGS", "-std=c99")
config := Config{
CCFLAGS: []string{"-Wall"},
CFLAGS: []string{"-pedantic"},
}
cmd := New("clang", config)
flags := cmd.mergeCompilerFlags()
expected := []string{"-O2", "-g", "-std=c99", "-Wall", "-pedantic"}
if !reflect.DeepEqual(flags, expected) {
t.Errorf("Expected flags %v, got %v", expected, flags)
}
})
t.Run("WithOnlyConfig", func(t *testing.T) {
os.Unsetenv("CCFLAGS")
os.Unsetenv("CFLAGS")
config := Config{
CCFLAGS: []string{"-Wall"},
CFLAGS: []string{"-pedantic"},
}
cmd := New("clang", config)
flags := cmd.mergeCompilerFlags()
expected := []string{"-Wall", "-pedantic"}
if !reflect.DeepEqual(flags, expected) {
t.Errorf("Expected flags %v, got %v", expected, flags)
}
})
t.Run("WithOnlyEnvironment", func(t *testing.T) {
os.Setenv("CCFLAGS", "-O3")
os.Setenv("CFLAGS", "-fPIC")
config := Config{}
cmd := New("clang", config)
flags := cmd.mergeCompilerFlags()
expected := []string{"-O3", "-fPIC"}
if !reflect.DeepEqual(flags, expected) {
t.Errorf("Expected flags %v, got %v", expected, flags)
}
})
t.Run("Empty", func(t *testing.T) {
os.Unsetenv("CCFLAGS")
os.Unsetenv("CFLAGS")
config := Config{}
cmd := New("clang", config)
flags := cmd.mergeCompilerFlags()
if len(flags) != 0 {
t.Errorf("Expected empty flags, got %v", flags)
}
})
}
func TestMergeLinkerFlags(t *testing.T) {
// Save original environment
origCCFlags := os.Getenv("CCFLAGS")
origLDFlags := os.Getenv("LDFLAGS")
defer func() {
os.Setenv("CCFLAGS", origCCFlags)
os.Setenv("LDFLAGS", origLDFlags)
}()
t.Run("WithEnvironmentAndConfig", func(t *testing.T) {
os.Setenv("CCFLAGS", "-O2")
os.Setenv("LDFLAGS", "-lm -lpthread")
config := Config{
LDFLAGS: []string{"-static"},
}
cmd := New("clang", config)
flags := cmd.mergeLinkerFlags()
expected := []string{"-O2", "-lm", "-lpthread", "-static"}
if !reflect.DeepEqual(flags, expected) {
t.Errorf("Expected flags %v, got %v", expected, flags)
}
})
t.Run("WithOnlyConfig", func(t *testing.T) {
os.Unsetenv("CCFLAGS")
os.Unsetenv("LDFLAGS")
config := Config{
LDFLAGS: []string{"-static", "-lm"},
}
cmd := New("clang", config)
flags := cmd.mergeLinkerFlags()
expected := []string{"-static", "-lm"}
if !reflect.DeepEqual(flags, expected) {
t.Errorf("Expected flags %v, got %v", expected, flags)
}
})
}
func TestCompile(t *testing.T) {
// This test uses echo instead of clang to avoid dependency on clang installation
config := Config{
CCFLAGS: []string{"-Wall"},
CFLAGS: []string{"-std=c99"},
}
cmd := New("echo", config)
var stdout bytes.Buffer
cmd.Stdout = &stdout
err := cmd.Compile("-c", "test.c")
if err != nil {
t.Errorf("Compile failed: %v", err)
}
output := strings.TrimSpace(stdout.String())
expectedArgs := "-Wall -std=c99 -c test.c"
if output != expectedArgs {
t.Errorf("Expected output %q, got %q", expectedArgs, output)
}
}
func TestLink(t *testing.T) {
// This test uses echo instead of clang to avoid dependency on clang installation
config := Config{
LDFLAGS: []string{"-lm"},
}
cmd := New("echo", config)
var stdout bytes.Buffer
cmd.Stdout = &stdout
err := cmd.Link("test.o", "-o", "test")
if err != nil {
t.Errorf("Link failed: %v", err)
}
output := strings.TrimSpace(stdout.String())
expectedArgs := "-lm test.o -o test"
if output != expectedArgs {
t.Errorf("Expected output %q, got %q", expectedArgs, output)
}
}
func TestVerboseMode(t *testing.T) {
config := Config{}
cmd := New("echo", config)
cmd.Verbose = true
// Since verbose output goes to os.Stderr directly, we'll test
// that verbose flag is set and command executes successfully
var stderr bytes.Buffer
cmd.Stderr = &stderr
cmd.Stdout = &bytes.Buffer{} // Suppress stdout
err := cmd.Compile("-c", "test.c")
if err != nil {
t.Errorf("Compile failed: %v", err)
}
// The test passes if verbose is set and no error occurred
if !cmd.Verbose {
t.Error("Expected Verbose to be true")
}
}
func TestCmdEnvironment(t *testing.T) {
config := Config{}
cmd := New("echo", config)
cmd.Env = []string{"TEST_VAR=test_value"}
var stdout bytes.Buffer
cmd.Stdout = &stdout
// Use a command that will show environment variables
// Note: This is a simplified test that just ensures the Env field is set
err := cmd.Compile("-c", "test.c")
if err != nil {
t.Errorf("Compile failed: %v", err)
}
if len(cmd.Env) != 1 || cmd.Env[0] != "TEST_VAR=test_value" {
t.Errorf("Expected environment to be set correctly")
}
}
func TestCmdIO(t *testing.T) {
config := Config{}
cmd := New("cat", config) // Use cat to test stdin/stdout
input := "test input"
cmd.Stdin = strings.NewReader(input)
var stdout bytes.Buffer
cmd.Stdout = &stdout
// cat will read from stdin and write to stdout
err := cmd.exec() // Call exec directly with no args
if err != nil {
t.Errorf("exec failed: %v", err)
}
output := stdout.String()
if output != input {
t.Errorf("Expected output %q, got %q", input, output)
}
}
func TestCheckLinkArgs(t *testing.T) {
t.Run("BasicTest", func(t *testing.T) {
// Use echo instead of clang to avoid dependency
config := Config{}
cmd := New("echo", config)
// Redirect output to avoid clutter
cmd.Stdout = &bytes.Buffer{}
cmd.Stderr = &bytes.Buffer{}
// This should succeed with echo
err := cmd.CheckLinkArgs([]string{"-o"}, false)
if err != nil {
t.Errorf("CheckLinkArgs failed: %v", err)
}
})
t.Run("WasmExtension", func(t *testing.T) {
config := Config{}
cmd := New("echo", config)
cmd.Stdout = &bytes.Buffer{}
cmd.Stderr = &bytes.Buffer{}
// Test with wasm=true
err := cmd.CheckLinkArgs([]string{"-o"}, true)
if err != nil {
t.Errorf("CheckLinkArgs with wasm failed: %v", err)
}
})
}
// Additional table-driven test for flag merging scenarios
func TestFlagMergingScenarios(t *testing.T) {
tests := []struct {
name string
envCCFlags string
envCFlags string
envLDFlags string
config Config
expectComp []string
expectLink []string
}{
{
name: "empty everything",
envCCFlags: "",
envCFlags: "",
envLDFlags: "",
config: Config{},
expectComp: []string{},
expectLink: []string{},
},
{
name: "only environment flags",
envCCFlags: "-O2",
envCFlags: "-std=c99",
envLDFlags: "-lm",
config: Config{},
expectComp: []string{"-O2", "-std=c99"},
expectLink: []string{"-O2", "-lm"},
},
{
name: "only config flags",
envCCFlags: "",
envCFlags: "",
envLDFlags: "",
config: Config{
CCFLAGS: []string{"-Wall"},
CFLAGS: []string{"-pedantic"},
LDFLAGS: []string{"-static"},
},
expectComp: []string{"-Wall", "-pedantic"},
expectLink: []string{"-static"},
},
{
name: "mixed environment and config",
envCCFlags: "-O3",
envCFlags: "-fPIC",
envLDFlags: "-lm -lpthread",
config: Config{
CCFLAGS: []string{"-Wall", "-Wextra"},
CFLAGS: []string{"-std=c11"},
LDFLAGS: []string{"-static"},
},
expectComp: []string{"-O3", "-fPIC", "-Wall", "-Wextra", "-std=c11"},
expectLink: []string{"-O3", "-lm", "-lpthread", "-static"},
},
}
// Save original environment
origCCFlags := os.Getenv("CCFLAGS")
origCFlags := os.Getenv("CFLAGS")
origLDFlags := os.Getenv("LDFLAGS")
defer func() {
os.Setenv("CCFLAGS", origCCFlags)
os.Setenv("CFLAGS", origCFlags)
os.Setenv("LDFLAGS", origLDFlags)
}()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Set environment variables
os.Setenv("CCFLAGS", tt.envCCFlags)
os.Setenv("CFLAGS", tt.envCFlags)
os.Setenv("LDFLAGS", tt.envLDFlags)
cmd := New("clang", tt.config)
// Test compiler flags
compFlags := cmd.mergeCompilerFlags()
if len(tt.expectComp) == 0 && len(compFlags) == 0 {
// Both are empty, consider them equal
} else if !reflect.DeepEqual(compFlags, tt.expectComp) {
t.Errorf("mergeCompilerFlags() = %v, want %v", compFlags, tt.expectComp)
}
// Test linker flags
linkFlags := cmd.mergeLinkerFlags()
if len(tt.expectLink) == 0 && len(linkFlags) == 0 {
// Both are empty, consider them equal
} else if !reflect.DeepEqual(linkFlags, tt.expectLink) {
t.Errorf("mergeLinkerFlags() = %v, want %v", linkFlags, tt.expectLink)
}
})
}
}
// Benchmark tests
func BenchmarkMergeCompilerFlags(b *testing.B) {
config := Config{
CCFLAGS: []string{"-Wall", "-O2"},
CFLAGS: []string{"-std=c99", "-pedantic"},
}
cmd := New("clang", config)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = cmd.mergeCompilerFlags()
}
}
func BenchmarkMergeLinkerFlags(b *testing.B) {
config := Config{
LDFLAGS: []string{"-lm", "-lpthread", "-static"},
}
cmd := New("clang", config)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = cmd.mergeLinkerFlags()
}
}

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"io/fs"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
@@ -19,36 +20,257 @@ type Export struct {
CCFLAGS []string
CFLAGS []string
LDFLAGS []string
EXTRAFLAGS []string
// Additional fields from target configuration
LLVMTarget string
CPU string
Features string
BuildTags []string
GOOS string
GOARCH string
Linker string // Linker to use (e.g., "ld.lld", "avr-ld")
ExtraFiles []string // Extra files to compile and link (e.g., .s, .c files)
ClangRoot string // Root directory of custom clang installation
ClangBinPath string // Path to clang binary directory
BinaryFormat string // Binary format (e.g., "elf", "esp", "uf2")
FormatDetail string // For uf2, it's uf2FamilyID
}
const wasiSdkUrl = "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-macos.tar.gz"
// URLs and configuration that can be overridden for testing
var (
wasiSdkUrl = "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-macos.tar.gz"
wasiMacosSubdir = "wasi-sdk-25.0-x86_64-macos"
)
var (
espClangBaseUrl = "https://github.com/goplus/espressif-llvm-project-prebuilt/releases/download/19.1.2_20250820"
espClangVersion = "19.1.2_20250820"
)
// cacheRoot can be overridden for testing
var cacheRoot = env.LLGoCacheDir
func cacheDir() string {
return filepath.Join(env.LLGoCacheDir(), "crosscompile")
return filepath.Join(cacheRoot(), "crosscompile")
}
func Use(goos, goarch string, wasiThreads bool) (export Export, err error) {
// expandEnv expands template variables in a string
// Supports variables like {port}, {hex}, {bin}, {root}, {tmpDir}, etc.
// Special case: {} expands to the first available file variable (hex, bin, img, zip)
func expandEnv(template string, envs map[string]string) string {
return expandEnvWithDefault(template, envs)
}
// expandEnvWithDefault expands template variables with optional default for {}
func expandEnvWithDefault(template string, envs map[string]string, defaultValue ...string) string {
if template == "" {
return ""
}
result := template
// Handle special case of {} - use provided default or first available file variable
if strings.Contains(result, "{}") {
defaultVal := ""
if len(defaultValue) > 0 && defaultValue[0] != "" {
defaultVal = defaultValue[0]
} else {
// Priority order: hex, bin, img, zip
for _, key := range []string{"hex", "bin", "img", "zip"} {
if value, exists := envs[key]; exists && value != "" {
defaultVal = value
break
}
}
}
result = strings.ReplaceAll(result, "{}", defaultVal)
}
// Replace named variables
for key, value := range envs {
if key != "" { // Skip empty key used for {} default
result = strings.ReplaceAll(result, "{"+key+"}", value)
}
}
return result
}
// expandEnvSlice expands template variables in a slice of strings
func expandEnvSlice(templates []string, envs map[string]string) []string {
return expandEnvSliceWithDefault(templates, envs)
}
// expandEnvSliceWithDefault expands template variables in a slice with optional default for {}
func expandEnvSliceWithDefault(templates []string, envs map[string]string, defaultValue ...string) []string {
if len(templates) == 0 {
return templates
}
result := make([]string, len(templates))
for i, template := range templates {
result[i] = expandEnvWithDefault(template, envs, defaultValue...)
}
return result
}
// buildEnvMap creates a map of template variables for the current context
func buildEnvMap(llgoRoot string) map[string]string {
envs := make(map[string]string)
// Basic paths
envs["root"] = llgoRoot
envs["tmpDir"] = os.TempDir()
// These will typically be set by calling code when actual values are known
// envs["port"] = "" // Serial port (e.g., "/dev/ttyUSB0", "COM3")
// envs["hex"] = "" // Path to hex file
// envs["bin"] = "" // Path to binary file
// envs["img"] = "" // Path to image file
// envs["zip"] = "" // Path to zip file
return envs
}
// getCanonicalArchName returns the canonical architecture name for a target triple
func getCanonicalArchName(triple string) string {
arch := strings.Split(triple, "-")[0]
if arch == "arm64" {
return "aarch64"
}
if strings.HasPrefix(arch, "arm") || strings.HasPrefix(arch, "thumb") {
return "arm"
}
if arch == "mipsel" {
return "mips"
}
return arch
}
// getMacOSSysroot returns the macOS SDK path using xcrun
func getMacOSSysroot() (string, error) {
cmd := exec.Command("xcrun", "--sdk", "macosx", "--show-sdk-path")
output, err := cmd.Output()
if err != nil {
return "", err
}
return strings.TrimSpace(string(output)), nil
}
// getESPClangRoot returns the ESP Clang root directory, checking LLGoROOT first,
// then downloading if needed and platform is supported
func getESPClangRoot() (clangRoot string, err error) {
llgoRoot := env.LLGoROOT()
// First check if clang exists in LLGoROOT
espClangRoot := filepath.Join(llgoRoot, "crosscompile", "clang")
if _, err = os.Stat(espClangRoot); err == nil {
clangRoot = espClangRoot
return
}
// Try to download ESP Clang if platform is supported
platformSuffix := getESPClangPlatform(runtime.GOOS, runtime.GOARCH)
if platformSuffix != "" {
cacheClangDir := filepath.Join(cacheRoot(), "crosscompile", "esp-clang-"+espClangVersion)
if _, err = os.Stat(cacheClangDir); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return
}
fmt.Fprintln(os.Stderr, "ESP Clang not found in LLGO_ROOT or cache, will download.")
if err = checkDownloadAndExtractESPClang(platformSuffix, cacheClangDir); err != nil {
return
}
}
clangRoot = cacheClangDir
return
}
err = fmt.Errorf("ESP Clang not found in LLGoROOT and platform %s/%s is not supported for download", runtime.GOOS, runtime.GOARCH)
return
}
// getESPClangPlatform returns the platform suffix for ESP Clang downloads
func getESPClangPlatform(goos, goarch string) string {
switch goos {
case "darwin":
switch goarch {
case "amd64":
return "x86_64-apple-darwin"
case "arm64":
return "aarch64-apple-darwin"
}
case "linux":
switch goarch {
case "amd64":
return "x86_64-linux-gnu"
case "arm64":
return "aarch64-linux-gnu"
case "arm":
return "arm-linux-gnueabihf"
}
case "windows":
switch goarch {
case "amd64":
return "x86_64-w64-mingw32"
}
}
return ""
}
func use(goos, goarch string, wasiThreads bool) (export Export, err error) {
targetTriple := llvm.GetTargetTriple(goos, goarch)
llgoRoot := env.LLGoROOT()
// Check for ESP Clang support for target-based builds
clangRoot, err := getESPClangRoot()
if err != nil {
return
}
// Set ClangRoot and CC if clang is available
export.ClangRoot = clangRoot
export.CC = filepath.Join(clangRoot, "bin", "clang++")
if runtime.GOOS == goos && runtime.GOARCH == goarch {
clangLib := filepath.Join(clangRoot, "lib")
clangInc := filepath.Join(clangRoot, "include")
// not cross compile
// Set up basic flags for non-cross-compile
export.LDFLAGS = []string{
"-L" + clangLib,
"-target", targetTriple,
"-Wno-override-module",
"-Qunused-arguments",
"-Wno-unused-command-line-argument",
"-Wl,--error-limit=0",
"-fuse-ld=lld",
}
export.CFLAGS = append(export.CFLAGS, "-I"+clangInc)
export.CCFLAGS = []string{
"-Qunused-arguments",
"-Wno-unused-command-line-argument",
}
// Add platform-specific rpath flags
switch goos {
case "darwin":
export.LDFLAGS = append(export.LDFLAGS, "-Wl,-rpath,"+clangLib)
case "linux":
export.LDFLAGS = append(export.LDFLAGS, "-Wl,-rpath,"+clangLib)
case "windows":
// Windows doesn't support rpath, DLLs should be in PATH or same directory
default:
// For other Unix-like systems, try the generic rpath
export.LDFLAGS = append(export.LDFLAGS, "-Wl,-rpath,"+clangLib)
}
// Add sysroot for macOS only
if goos == "darwin" {
sysrootPath, sysrootErr := getMacOSSysroot()
if sysrootErr != nil {
err = fmt.Errorf("failed to get macOS SDK path: %w", sysrootErr)
return
}
export.CCFLAGS = append(export.CCFLAGS, []string{"--sysroot=" + sysrootPath}...)
export.LDFLAGS = append(export.LDFLAGS, []string{"--sysroot=" + sysrootPath}...)
}
// Add OS-specific flags
switch goos {
@@ -85,13 +307,13 @@ func Use(goos, goarch string, wasiThreads bool) (export Export, err error) {
// Configure based on GOOS
switch goos {
case "wasip1":
sdkDir := filepath.Join(cacheDir(), llvm.GetTargetTriple(goos, goarch))
if _, err = os.Stat(sdkDir); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return
}
// Set wasiSdkRoot path
wasiSdkRoot := filepath.Join(llgoRoot, "crosscompile", "wasi-libc")
if err = downloadAndExtract(wasiSdkUrl, sdkDir); err != nil {
// If not exists in LLGoROOT, download and use cached wasiSdkRoot
if _, err = os.Stat(wasiSdkRoot); err != nil {
sdkDir := filepath.Join(cacheDir(), llvm.GetTargetTriple(goos, goarch))
if wasiSdkRoot, err = checkDownloadAndExtractWasiSDK(sdkDir); err != nil {
return
}
}
@@ -101,8 +323,7 @@ func Use(goos, goarch string, wasiThreads bool) (export Export, err error) {
triple = "wasm32-wasip1-threads"
}
// Set up flags for the WASI-SDK
wasiSdkRoot := filepath.Join(sdkDir, "wasi-sdk-25.0-x86_64-macos")
// Set up flags for the WASI-SDK or wasi-libc
sysrootDir := filepath.Join(wasiSdkRoot, "share", "wasi-sysroot")
libclangDir := filepath.Join(wasiSdkRoot, "lib", "clang", "19")
includeDir := filepath.Join(sysrootDir, "include", triple)
@@ -119,6 +340,8 @@ func Use(goos, goarch string, wasiThreads bool) (export Export, err error) {
}
export.CFLAGS = []string{
"-I" + includeDir,
"-Qunused-arguments",
"-Wno-unused-command-line-argument",
}
// Add WebAssembly linker flags
export.LDFLAGS = append(export.LDFLAGS, export.CCFLAGS...)
@@ -169,6 +392,8 @@ func Use(goos, goarch string, wasiThreads bool) (export Export, err error) {
// Add compiler flags
export.CCFLAGS = []string{
"-target", targetTriple,
"-Qunused-arguments",
"-Wno-unused-command-line-argument",
}
export.CFLAGS = []string{}
// Add WebAssembly linker flags for Emscripten
@@ -186,7 +411,7 @@ func Use(goos, goarch string, wasiThreads bool) (export Export, err error) {
// "-z", "stack-size=10485760", // 10MB
// "-Wl,--export=malloc", "-Wl,--export=free",
}
export.EXTRAFLAGS = []string{
export.LDFLAGS = append(export.LDFLAGS, []string{
"-sENVIRONMENT=web,worker",
"-DPLATFORM_WEB",
"-sEXPORT_KEEPALIVE=1",
@@ -198,7 +423,7 @@ func Use(goos, goarch string, wasiThreads bool) (export Export, err error) {
"-sEXPORT_ALL=1",
"-sASYNCIFY=1",
"-sSTACK_SIZE=5242880", // 50MB
}
}...)
default:
err = errors.New("unsupported GOOS for WebAssembly: " + goos)
@@ -216,25 +441,55 @@ func useTarget(targetName string) (export Export, err error) {
return export, fmt.Errorf("failed to resolve target %s: %w", targetName, err)
}
target := config.LLVMTarget
if target == "" {
return export, fmt.Errorf("target '%s' does not have a valid LLVM target triple", targetName)
}
cpu := config.CPU
if cpu == "" {
return export, fmt.Errorf("target '%s' does not have a valid CPU configuration", targetName)
}
// Check for ESP Clang support for target-based builds
clangRoot, err := getESPClangRoot()
if err != nil {
return
}
// Set ClangRoot and CC if clang is available
export.ClangRoot = clangRoot
export.CC = filepath.Join(clangRoot, "bin", "clang++")
// Convert target config to Export - only export necessary fields
export.BuildTags = config.BuildTags
export.GOOS = config.GOOS
export.GOARCH = config.GOARCH
export.ExtraFiles = config.ExtraFiles
export.BinaryFormat = config.BinaryFormat
export.FormatDetail = config.FormatDetail()
// Build environment map for template variable expansion
envs := buildEnvMap(env.LLGoROOT())
// Convert LLVMTarget, CPU, Features to CCFLAGS/LDFLAGS
var ccflags []string
var ldflags []string
target := config.LLVMTarget
if target == "" {
target = llvm.GetTargetTriple(config.GOOS, config.GOARCH)
cflags := []string{"-Wno-override-module", "-Qunused-arguments", "-Wno-unused-command-line-argument"}
if config.LLVMTarget != "" {
cflags = append(cflags, "--target="+config.LLVMTarget)
ccflags = append(ccflags, "--target="+config.LLVMTarget)
}
// Expand template variables in cflags
expandedCFlags := expandEnvSlice(config.CFlags, envs)
cflags = append(cflags, expandedCFlags...)
ccflags = append(ccflags, "-Wno-override-module", "--target="+config.LLVMTarget)
// Inspired by tinygo
cpu := config.CPU
// The following parameters are inspired by tinygo/builder/library.go
// Handle CPU configuration
if cpu != "" {
// X86 has deprecated the -mcpu flag, so we need to use -march instead.
// However, ARM has not done this.
if strings.HasPrefix(target, "i386") || strings.HasPrefix(target, "x86_64") {
ccflags = append(ccflags, "-march="+cpu)
} else if strings.HasPrefix(target, "avr") {
@@ -242,12 +497,50 @@ func useTarget(targetName string) (export Export, err error) {
} else {
ccflags = append(ccflags, "-mcpu="+cpu)
}
// Only add -mllvm flags for non-WebAssembly linkers
// For ld.lld linker, also add CPU info to linker flags
if config.Linker == "ld.lld" {
ldflags = append(ldflags, "-mllvm", "-mcpu="+cpu)
}
}
// Handle architecture-specific flags
canonicalArch := getCanonicalArchName(target)
switch canonicalArch {
case "arm":
if strings.Split(target, "-")[2] == "linux" {
ccflags = append(ccflags, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
} else {
ccflags = append(ccflags, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
}
case "avr":
// AVR defaults to C float and double both being 32-bit. This deviates
// from what most code (and certainly compiler-rt) expects. So we need
// to force the compiler to use 64-bit floating point numbers for
// double.
ccflags = append(ccflags, "-mdouble=64")
case "riscv32":
ccflags = append(ccflags, "-march=rv32imac", "-fforce-enable-int128")
case "riscv64":
ccflags = append(ccflags, "-march=rv64gc")
case "mips":
ccflags = append(ccflags, "-fno-pic")
}
// Handle soft float
if strings.Contains(config.Features, "soft-float") || strings.Contains(strings.Join(config.CFlags, " "), "soft-float") {
// Use softfloat instead of floating point instructions. This is
// supported on many architectures.
ccflags = append(ccflags, "-msoft-float")
} else {
if strings.HasPrefix(target, "armv5") {
// On ARMv5 we need to explicitly enable hardware floating point
// instructions: Clang appears to assume the hardware doesn't have a
// FPU otherwise.
ccflags = append(ccflags, "-mfpu=vfpv2")
}
}
// Handle Features
if config.Features != "" {
// Only add -mllvm flags for non-WebAssembly linkers
@@ -256,64 +549,45 @@ func useTarget(targetName string) (export Export, err error) {
}
}
// Handle Linker - keep it for external usage
export.Linker = config.Linker
// Handle code generation configuration
if config.CodeModel != "" {
ccflags = append(ccflags, "-mcmodel="+config.CodeModel)
}
if config.TargetABI != "" {
ccflags = append(ccflags, "-mabi="+config.TargetABI)
}
if config.RelocationModel != "" {
switch config.RelocationModel {
case "pic":
ccflags = append(ccflags, "-fPIC")
case "static":
ccflags = append(ccflags, "-fno-pic")
}
}
// Combine with config flags
export.CFLAGS = config.CFlags
// Handle Linker - keep it for external usage
if config.Linker != "" {
export.Linker = filepath.Join(clangRoot, "bin", config.Linker)
}
if config.LinkerScript != "" {
ldflags = append(ldflags, "-T", config.LinkerScript)
}
ldflags = append(ldflags, "-L", env.LLGoROOT()) // search targets/*.ld
// Combine with config flags and expand template variables
export.CFLAGS = cflags
export.CCFLAGS = ccflags
export.LDFLAGS = append(ldflags, filterCompatibleLDFlags(config.LDFlags)...)
export.EXTRAFLAGS = []string{}
expandedLDFlags := expandEnvSlice(config.LDFlags, envs)
export.LDFLAGS = append(ldflags, expandedLDFlags...)
return export, nil
}
// UseWithTarget extends the original Use function to support target-based configuration
// Use extends the original Use function to support target-based configuration
// If targetName is provided, it takes precedence over goos/goarch
func UseWithTarget(goos, goarch string, wasiThreads bool, targetName string) (export Export, err error) {
func Use(goos, goarch string, wasiThreads bool, targetName string) (export Export, err error) {
if targetName != "" {
return useTarget(targetName)
}
return Use(goos, goarch, wasiThreads)
}
// filterCompatibleLDFlags filters out linker flags that are incompatible with clang/lld
func filterCompatibleLDFlags(ldflags []string) []string {
if len(ldflags) == 0 {
return ldflags
}
var filtered []string
incompatiblePrefixes := []string{
"--defsym=", // Use -Wl,--defsym= instead
"-T", // Linker script, needs special handling
}
i := 0
for i < len(ldflags) {
flag := ldflags[i]
// Check incompatible prefixes
skip := false
for _, prefix := range incompatiblePrefixes {
if strings.HasPrefix(flag, prefix) {
skip = true
break
}
}
if skip {
// Skip -T and its argument if separate
if flag == "-T" && i+1 < len(ldflags) {
i += 2 // Skip both -T and the script path
} else {
i++
}
continue
}
filtered = append(filtered, flag)
i++
}
return filtered
return use(goos, goarch, wasiThreads)
}

View File

@@ -37,10 +37,10 @@ func TestUseCrossCompileSDK(t *testing.T) {
name: "Same Platform",
goos: runtime.GOOS,
goarch: runtime.GOARCH,
expectSDK: false,
expectCCFlags: false,
expectCFlags: false,
expectLDFlags: false,
expectSDK: true, // Changed: now we expect flags even for same platform
expectCCFlags: true, // Changed: CCFLAGS will contain sysroot
expectCFlags: true, // Changed: CFLAGS will contain include paths
expectLDFlags: true, // Changed: LDFLAGS will contain library paths
},
{
name: "WASM Target",
@@ -55,10 +55,10 @@ func TestUseCrossCompileSDK(t *testing.T) {
name: "Unsupported Target",
goos: "windows",
goarch: "amd64",
expectSDK: false,
expectCCFlags: false,
expectCFlags: false,
expectLDFlags: false,
expectSDK: false, // Still false as it won't set up specific SDK
expectCCFlags: false, // No cross-compile specific flags
expectCFlags: false, // No cross-compile specific flags
expectLDFlags: false, // No cross-compile specific flags
},
}
@@ -76,7 +76,7 @@ func TestUseCrossCompileSDK(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
export, err := Use(tc.goos, tc.goarch, false)
export, err := use(tc.goos, tc.goarch, false)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
@@ -111,12 +111,21 @@ func TestUseCrossCompileSDK(t *testing.T) {
}
}
// For WASM target, both sysroot and resource-dir are expected
if tc.name == "WASM Target" {
if !hasSysroot {
t.Error("Missing --sysroot flag in CCFLAGS")
}
if !hasResourceDir {
t.Error("Missing -resource-dir flag in CCFLAGS")
}
} else if tc.name == "Same Platform" {
// For same platform, we expect sysroot only on macOS
if runtime.GOOS == "darwin" && !hasSysroot {
t.Error("Missing --sysroot flag in CCFLAGS on macOS")
}
// On Linux and other platforms, sysroot is not necessarily required
}
}
if tc.expectCFlags {
@@ -147,9 +156,11 @@ func TestUseCrossCompileSDK(t *testing.T) {
}
}
} else {
if /*len(export.CCFLAGS) != 0 ||*/ len(export.CFLAGS) != 0 {
t.Errorf("Expected empty export, got CCFLAGS=%v, CFLAGS=%v, LDFLAGS=%v",
export.CCFLAGS, export.CFLAGS, export.LDFLAGS)
// For unsupported targets, we still expect some basic flags to be set
// since the implementation now always sets up ESP Clang environment
// Only check that we don't have specific SDK-related flags for unsupported targets
if tc.name == "Unsupported Target" && len(export.CFLAGS) != 0 {
t.Errorf("Expected empty CFLAGS for unsupported target, got CFLAGS=%v", export.CFLAGS)
}
}
})
@@ -182,7 +193,7 @@ func TestUseTarget(t *testing.T) {
{
name: "Cortex-M Target",
targetName: "cortex-m",
expectError: false,
expectError: true,
expectLLVM: "",
expectCPU: "",
},
@@ -230,9 +241,21 @@ func TestUseTarget(t *testing.T) {
}
}
// Check if CPU is in CCFLAGS
// Check if CPU is in LDFLAGS (for ld.lld linker) or CCFLAGS (for other cases)
if tc.expectCPU != "" {
found := false
// First check LDFLAGS for -mllvm -mcpu= pattern
for i, flag := range export.LDFLAGS {
if flag == "-mllvm" && i+1 < len(export.LDFLAGS) {
nextFlag := export.LDFLAGS[i+1]
if nextFlag == "-mcpu="+tc.expectCPU {
found = true
break
}
}
}
// If not found in LDFLAGS, check CCFLAGS for direct CPU flags
if !found {
expectedFlags := []string{"-mmcu=" + tc.expectCPU, "-mcpu=" + tc.expectCPU}
for _, flag := range export.CCFLAGS {
for _, expectedFlag := range expectedFlags {
@@ -242,8 +265,9 @@ func TestUseTarget(t *testing.T) {
}
}
}
}
if !found {
t.Errorf("Expected CPU %s in CCFLAGS, got %v", tc.expectCPU, export.CCFLAGS)
t.Errorf("Expected CPU %s in LDFLAGS or CCFLAGS, got LDFLAGS=%v, CCFLAGS=%v", tc.expectCPU, export.LDFLAGS, export.CCFLAGS)
}
}
@@ -255,7 +279,7 @@ func TestUseTarget(t *testing.T) {
func TestUseWithTarget(t *testing.T) {
// Test target-based configuration takes precedence
export, err := UseWithTarget("linux", "amd64", false, "wasi")
export, err := Use("linux", "amd64", false, "wasi")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
@@ -267,7 +291,7 @@ func TestUseWithTarget(t *testing.T) {
}
// Test fallback to goos/goarch when no target specified
export, err = UseWithTarget(runtime.GOOS, runtime.GOARCH, false, "")
export, err = Use(runtime.GOOS, runtime.GOARCH, false, "")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
@@ -278,58 +302,125 @@ func TestUseWithTarget(t *testing.T) {
}
}
func TestFilterCompatibleLDFlags(t *testing.T) {
testCases := []struct {
name string
input []string
expected []string
func TestExpandEnv(t *testing.T) {
envs := map[string]string{
"port": "/dev/ttyUSB0",
"hex": "firmware.hex",
"bin": "firmware.bin",
"root": "/usr/local/llgo",
}
tests := []struct {
template string
expected string
}{
{
name: "Empty flags",
input: []string{},
expected: []string{},
"avrdude -c arduino -p atmega328p -P {port} -U flash:w:{hex}:i",
"avrdude -c arduino -p atmega328p -P /dev/ttyUSB0 -U flash:w:firmware.hex:i",
},
{
name: "Compatible flags only",
input: []string{"-lm", "-lpthread"},
expected: []string{"-lm", "-lpthread"},
"simavr -m atmega328p -f 16000000 {}",
"simavr -m atmega328p -f 16000000 firmware.hex", // {} expands to hex (first priority)
},
{
name: "Incompatible flags filtered",
input: []string{"--gc-sections", "-lm", "--emit-relocs", "-lpthread"},
expected: []string{"--gc-sections", "-lm", "--emit-relocs", "-lpthread"},
"-I{root}/lib/CMSIS/CMSIS/Include",
"-I/usr/local/llgo/lib/CMSIS/CMSIS/Include",
},
{
name: "Defsym flags filtered",
input: []string{"--defsym=_stack_size=512", "-lm", "--defsym=_bootloader_size=512"},
expected: []string{"-lm"},
"no variables here",
"no variables here",
},
{
name: "Linker script flags filtered",
input: []string{"-T", "script.ld", "-lm"},
expected: []string{"-lm"},
},
{
name: "Mixed compatible and incompatible",
input: []string{"-lm", "--gc-sections", "--defsym=test=1", "-lpthread", "--no-demangle"},
expected: []string{"-lm", "--gc-sections", "-lpthread", "--no-demangle"},
"",
"",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := filterCompatibleLDFlags(tc.input)
if len(result) != len(tc.expected) {
t.Errorf("Expected %d flags, got %d: %v", len(tc.expected), len(result), result)
return
for _, test := range tests {
result := expandEnv(test.template, envs)
if result != test.expected {
t.Errorf("expandEnv(%q) = %q, want %q", test.template, result, test.expected)
}
}
}
for i, expected := range tc.expected {
if result[i] != expected {
t.Errorf("Expected flag[%d] = %s, got %s", i, expected, result[i])
func TestExpandEnvSlice(t *testing.T) {
envs := map[string]string{
"root": "/usr/local/llgo",
"port": "/dev/ttyUSB0",
}
input := []string{
"-I{root}/include",
"-DPORT={port}",
"static-flag",
}
expected := []string{
"-I/usr/local/llgo/include",
"-DPORT=/dev/ttyUSB0",
"static-flag",
}
result := expandEnvSlice(input, envs)
if len(result) != len(expected) {
t.Fatalf("expandEnvSlice length mismatch: got %d, want %d", len(result), len(expected))
}
for i, exp := range expected {
if result[i] != exp {
t.Errorf("expandEnvSlice[%d] = %q, want %q", i, result[i], exp)
}
}
})
}
func TestExpandEnvWithDefault(t *testing.T) {
envs := map[string]string{
"port": "/dev/ttyUSB0",
"hex": "firmware.hex",
"bin": "firmware.bin",
"img": "image.img",
}
tests := []struct {
template string
defaultValue string
expected string
}{
{
"simavr {}",
"", // No default - should use hex (priority)
"simavr firmware.hex",
},
{
"simavr {}",
"custom.elf", // Explicit default
"simavr custom.elf",
},
{
"qemu -kernel {}",
"vmlinux", // Custom kernel
"qemu -kernel vmlinux",
},
{
"no braces here",
"ignored",
"no braces here",
},
}
for i, test := range tests {
var result string
if test.defaultValue == "" {
result = expandEnvWithDefault(test.template, envs)
} else {
result = expandEnvWithDefault(test.template, envs, test.defaultValue)
}
if result != test.expected {
t.Errorf("Test %d: expandEnvWithDefault(%q, envs, %q) = %q, want %q",
i, test.template, test.defaultValue, result, test.expected)
}
}
}

View File

@@ -7,39 +7,149 @@ import (
"io"
"net/http"
"os"
"os/exec"
"path/filepath"
"strings"
"syscall"
)
func downloadAndExtract(url, dir string) (err error) {
if _, err = os.Stat(dir); err == nil {
os.RemoveAll(dir)
}
tempDir := dir + ".temp"
os.RemoveAll(tempDir)
if err = os.MkdirAll(tempDir, 0755); err != nil {
return fmt.Errorf("failed to create temporary directory: %w", err)
// checkDownloadAndExtractWasiSDK downloads and extracts WASI SDK
func checkDownloadAndExtractWasiSDK(dir string) (wasiSdkRoot string, err error) {
wasiSdkRoot = filepath.Join(dir, wasiMacosSubdir)
// Check if already exists
if _, err := os.Stat(wasiSdkRoot); err == nil {
return wasiSdkRoot, nil
}
// Create lock file path for the parent directory (dir) since that's what we're operating on
lockPath := dir + ".lock"
lockFile, err := acquireLock(lockPath)
if err != nil {
return "", fmt.Errorf("failed to acquire lock: %w", err)
}
defer releaseLock(lockFile)
// Double-check after acquiring lock
if _, err := os.Stat(wasiSdkRoot); err == nil {
return wasiSdkRoot, nil
}
err = downloadAndExtractArchive(wasiSdkUrl, dir, "WASI SDK")
return wasiSdkRoot, err
}
// checkDownloadAndExtractESPClang downloads and extracts ESP Clang binaries and libraries
func checkDownloadAndExtractESPClang(platformSuffix, dir string) error {
// Check if already exists
if _, err := os.Stat(dir); err == nil {
return nil
}
// Create lock file path for the final destination
lockPath := dir + ".lock"
lockFile, err := acquireLock(lockPath)
if err != nil {
return fmt.Errorf("failed to acquire lock: %w", err)
}
defer releaseLock(lockFile)
// Double-check after acquiring lock
if _, err := os.Stat(dir); err == nil {
return nil
}
clangUrl := fmt.Sprintf("%s/clang-esp-%s-%s.tar.xz", espClangBaseUrl, espClangVersion, platformSuffix)
description := fmt.Sprintf("ESP Clang %s-%s", espClangVersion, platformSuffix)
// Use temporary extraction directory for ESP Clang special handling
tempExtractDir := dir + ".extract"
if err := downloadAndExtractArchive(clangUrl, tempExtractDir, description); err != nil {
return err
}
defer os.RemoveAll(tempExtractDir)
// ESP Clang needs special handling: move esp-clang subdirectory to final destination
espClangDir := filepath.Join(tempExtractDir, "esp-clang")
if err := os.Rename(espClangDir, dir); err != nil {
return fmt.Errorf("failed to rename esp-clang directory: %w", err)
}
return nil
}
// acquireLock creates and locks a file to prevent concurrent operations
func acquireLock(lockPath string) (*os.File, error) {
// Ensure the parent directory exists
if err := os.MkdirAll(filepath.Dir(lockPath), 0755); err != nil {
return nil, fmt.Errorf("failed to create lock directory: %w", err)
}
lockFile, err := os.OpenFile(lockPath, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return nil, fmt.Errorf("failed to create lock file: %w", err)
}
if err := syscall.Flock(int(lockFile.Fd()), syscall.LOCK_EX); err != nil {
lockFile.Close()
return nil, fmt.Errorf("failed to acquire lock: %w", err)
}
return lockFile, nil
}
// releaseLock unlocks and removes the lock file
func releaseLock(lockFile *os.File) error {
if lockFile == nil {
return nil
}
lockPath := lockFile.Name()
syscall.Flock(int(lockFile.Fd()), syscall.LOCK_UN)
lockFile.Close()
os.Remove(lockPath)
return nil
}
// downloadAndExtractArchive downloads and extracts an archive to the destination directory (without locking)
func downloadAndExtractArchive(url, destDir, description string) error {
fmt.Fprintf(os.Stderr, "Downloading %s...\n", description)
// Use temporary extraction directory
tempDir := destDir + ".temp"
os.RemoveAll(tempDir)
if err := os.MkdirAll(tempDir, 0755); err != nil {
return fmt.Errorf("failed to create temporary directory: %w", err)
}
defer os.RemoveAll(tempDir)
// Download the archive
urlPath := strings.Split(url, "/")
filename := urlPath[len(urlPath)-1]
localFile := filepath.Join(tempDir, filename)
if err = downloadFile(url, localFile); err != nil {
return fmt.Errorf("failed to download file: %w", err)
if err := downloadFile(url, localFile); err != nil {
return fmt.Errorf("failed to download %s from %s: %w", description, url, err)
}
defer os.Remove(localFile)
// Extract the archive
fmt.Fprintf(os.Stderr, "Extracting %s...\n", description)
if strings.HasSuffix(filename, ".tar.gz") || strings.HasSuffix(filename, ".tgz") {
err = extractTarGz(localFile, tempDir)
err := extractTarGz(localFile, tempDir)
if err != nil {
return fmt.Errorf("failed to extract %s archive: %w", description, err)
}
} else if strings.HasSuffix(filename, ".tar.xz") {
err := extractTarXz(localFile, tempDir)
if err != nil {
return fmt.Errorf("failed to extract %s archive: %w", description, err)
}
} else {
return fmt.Errorf("unsupported archive format: %s", filename)
}
if err != nil {
return fmt.Errorf("failed to extract archive: %w", err)
}
if err = os.Rename(tempDir, dir); err != nil {
// Rename temp directory to target directory
if err := os.Rename(tempDir, destDir); err != nil {
return fmt.Errorf("failed to rename directory: %w", err)
}
fmt.Fprintf(os.Stderr, "%s downloaded and extracted successfully.\n", description)
return nil
}
@@ -107,3 +217,9 @@ func extractTarGz(tarGzFile, dest string) error {
}
return nil
}
func extractTarXz(tarXzFile, dest string) error {
// Use external tar command to extract .tar.xz files
cmd := exec.Command("tar", "-xf", tarXzFile, "-C", dest)
return cmd.Run()
}

View File

@@ -0,0 +1,492 @@
//go:build !llgo
// +build !llgo
package crosscompile
import (
"archive/tar"
"compress/gzip"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"sync"
"testing"
"time"
)
// Helper function to create a test tar.gz archive
func createTestTarGz(t *testing.T, files map[string]string) string {
tempFile, err := os.CreateTemp("", "test*.tar.gz")
if err != nil {
t.Fatalf("Failed to create temp file: %v", err)
}
defer tempFile.Close()
gzw := gzip.NewWriter(tempFile)
defer gzw.Close()
tw := tar.NewWriter(gzw)
defer tw.Close()
for name, content := range files {
hdr := &tar.Header{
Name: name,
Mode: 0644,
Size: int64(len(content)),
}
if err := tw.WriteHeader(hdr); err != nil {
t.Fatalf("Failed to write tar header: %v", err)
}
if _, err := tw.Write([]byte(content)); err != nil {
t.Fatalf("Failed to write tar content: %v", err)
}
}
return tempFile.Name()
}
// Helper function to create a test HTTP server
func createTestServer(t *testing.T, files map[string]string) *httptest.Server {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
path := strings.TrimPrefix(r.URL.Path, "/")
if content, exists := files[path]; exists {
w.Header().Set("Content-Type", "application/octet-stream")
w.Write([]byte(content))
} else {
w.WriteHeader(http.StatusNotFound)
}
}))
}
func TestAcquireAndReleaseLock(t *testing.T) {
tempDir := t.TempDir()
lockPath := filepath.Join(tempDir, "test.lock")
// Test acquiring lock
lockFile, err := acquireLock(lockPath)
if err != nil {
t.Fatalf("Failed to acquire lock: %v", err)
}
// Check lock file exists
if _, err := os.Stat(lockPath); os.IsNotExist(err) {
t.Error("Lock file should exist")
}
// Test releasing lock
if err := releaseLock(lockFile); err != nil {
t.Errorf("Failed to release lock: %v", err)
}
// Check lock file is removed
if _, err := os.Stat(lockPath); !os.IsNotExist(err) {
t.Error("Lock file should be removed after release")
}
}
func TestAcquireLockConcurrency(t *testing.T) {
tempDir := t.TempDir()
lockPath := filepath.Join(tempDir, "concurrent.lock")
var wg sync.WaitGroup
var results []int
var resultsMu sync.Mutex
// Start multiple goroutines trying to acquire the same lock
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
lockFile, err := acquireLock(lockPath)
if err != nil {
t.Errorf("Goroutine %d failed to acquire lock: %v", id, err)
return
}
// Hold the lock for a short time
resultsMu.Lock()
results = append(results, id)
resultsMu.Unlock()
time.Sleep(10 * time.Millisecond)
if err := releaseLock(lockFile); err != nil {
t.Errorf("Goroutine %d failed to release lock: %v", id, err)
}
}(i)
}
wg.Wait()
// All goroutines should have successfully acquired and released the lock
if len(results) != 5 {
t.Errorf("Expected 5 successful lock acquisitions, got %d", len(results))
}
}
func TestDownloadFile(t *testing.T) {
// Create test server
testContent := "test file content"
server := createTestServer(t, map[string]string{
"test.txt": testContent,
})
defer server.Close()
tempDir := t.TempDir()
targetFile := filepath.Join(tempDir, "downloaded.txt")
// Test successful download
err := downloadFile(server.URL+"/test.txt", targetFile)
if err != nil {
t.Fatalf("Failed to download file: %v", err)
}
// Check file content
content, err := os.ReadFile(targetFile)
if err != nil {
t.Fatalf("Failed to read downloaded file: %v", err)
}
if string(content) != testContent {
t.Errorf("Expected content %q, got %q", testContent, string(content))
}
// Test download failure (404)
err = downloadFile(server.URL+"/nonexistent.txt", targetFile)
if err == nil {
t.Error("Expected error for non-existent file, got nil")
}
}
func TestExtractTarGz(t *testing.T) {
// Create test archive
files := map[string]string{
"test-dir/file1.txt": "content of file1",
"test-dir/file2.txt": "content of file2",
"file3.txt": "content of file3",
}
archivePath := createTestTarGz(t, files)
defer os.Remove(archivePath)
// Extract to temp directory
tempDir := t.TempDir()
err := extractTarGz(archivePath, tempDir)
if err != nil {
t.Fatalf("Failed to extract tar.gz: %v", err)
}
// Check extracted files
for name, expectedContent := range files {
filePath := filepath.Join(tempDir, name)
content, err := os.ReadFile(filePath)
if err != nil {
t.Errorf("Failed to read extracted file %s: %v", name, err)
continue
}
if string(content) != expectedContent {
t.Errorf("File %s: expected content %q, got %q", name, expectedContent, string(content))
}
}
}
func TestExtractTarGzPathTraversal(t *testing.T) {
// Create a malicious archive with path traversal
tempFile, err := os.CreateTemp("", "malicious*.tar.gz")
if err != nil {
t.Fatalf("Failed to create temp file: %v", err)
}
defer tempFile.Close()
defer os.Remove(tempFile.Name())
gzw := gzip.NewWriter(tempFile)
tw := tar.NewWriter(gzw)
// Add a file with path traversal attack
hdr := &tar.Header{
Name: "../../../etc/passwd",
Mode: 0644,
Size: 5,
Typeflag: tar.TypeReg,
}
if err := tw.WriteHeader(hdr); err != nil {
t.Fatalf("Failed to write tar header: %v", err)
}
if _, err := tw.Write([]byte("pwned")); err != nil {
t.Fatalf("Failed to write tar content: %v", err)
}
// Close writers to flush all data
if err := tw.Close(); err != nil {
t.Fatalf("Failed to close tar writer: %v", err)
}
if err := gzw.Close(); err != nil {
t.Fatalf("Failed to close gzip writer: %v", err)
}
if err := tempFile.Close(); err != nil {
t.Fatalf("Failed to close temp file: %v", err)
}
tempDir := t.TempDir()
err = extractTarGz(tempFile.Name(), tempDir)
if err == nil {
t.Error("Expected error for path traversal attack, got nil")
}
if !strings.Contains(err.Error(), "illegal file path") {
t.Errorf("Expected 'illegal file path' error, got: %v", err)
}
}
func TestDownloadAndExtractArchive(t *testing.T) {
// Create test archive
files := map[string]string{
"test-app/bin/app": "#!/bin/bash\necho hello",
"test-app/lib/lib.so": "fake library content",
"test-app/README": "This is a test application",
}
archivePath := createTestTarGz(t, files)
defer os.Remove(archivePath)
// Create test server to serve the archive
archiveContent, err := os.ReadFile(archivePath)
if err != nil {
t.Fatalf("Failed to read test archive: %v", err)
}
server := createTestServer(t, map[string]string{
"test-app.tar.gz": string(archiveContent),
})
defer server.Close()
// Test download and extract
tempDir := t.TempDir()
destDir := filepath.Join(tempDir, "extracted")
err = downloadAndExtractArchive(server.URL+"/test-app.tar.gz", destDir, "Test App")
if err != nil {
t.Fatalf("Failed to download and extract: %v", err)
}
// Check extracted files
for name, expectedContent := range files {
filePath := filepath.Join(destDir, name)
content, err := os.ReadFile(filePath)
if err != nil {
t.Errorf("Failed to read extracted file %s: %v", name, err)
continue
}
if string(content) != expectedContent {
t.Errorf("File %s: expected content %q, got %q", name, expectedContent, string(content))
}
}
}
func TestDownloadAndExtractArchiveUnsupportedFormat(t *testing.T) {
server := createTestServer(t, map[string]string{
"test.zip": "fake zip content",
})
defer server.Close()
tempDir := t.TempDir()
destDir := filepath.Join(tempDir, "extracted")
err := downloadAndExtractArchive(server.URL+"/test.zip", destDir, "Test Archive")
if err == nil {
t.Error("Expected error for unsupported format, got nil")
}
if !strings.Contains(err.Error(), "unsupported archive format") {
t.Errorf("Expected 'unsupported archive format' error, got: %v", err)
}
}
// Mock test for WASI SDK (without actual download)
func TestWasiSDKExtractionLogic(t *testing.T) {
tempDir := t.TempDir()
// Create fake WASI SDK directory structure
wasiSdkDir := filepath.Join(tempDir, wasiMacosSubdir)
binDir := filepath.Join(wasiSdkDir, "bin")
err := os.MkdirAll(binDir, 0755)
if err != nil {
t.Fatalf("Failed to create fake WASI SDK structure: %v", err)
}
// Create fake clang binary
clangPath := filepath.Join(binDir, "clang")
err = os.WriteFile(clangPath, []byte("fake clang"), 0755)
if err != nil {
t.Fatalf("Failed to create fake clang: %v", err)
}
// Test that function returns correct path for existing SDK
sdkRoot, err := checkDownloadAndExtractWasiSDK(tempDir)
if err != nil {
t.Fatalf("checkDownloadAndExtractWasiSDK failed: %v", err)
}
expectedRoot := filepath.Join(tempDir, wasiMacosSubdir)
if sdkRoot != expectedRoot {
t.Errorf("Expected SDK root %q, got %q", expectedRoot, sdkRoot)
}
}
// Test ESP Clang extraction logic with existing directory
func TestESPClangExtractionLogic(t *testing.T) {
tempDir := t.TempDir()
espClangDir := filepath.Join(tempDir, "esp-clang")
// Create fake ESP Clang directory structure
binDir := filepath.Join(espClangDir, "bin")
err := os.MkdirAll(binDir, 0755)
if err != nil {
t.Fatalf("Failed to create fake ESP Clang structure: %v", err)
}
// Create fake clang binary
clangPath := filepath.Join(binDir, "clang")
err = os.WriteFile(clangPath, []byte("fake esp clang"), 0755)
if err != nil {
t.Fatalf("Failed to create fake esp clang: %v", err)
}
// Test that function skips download for existing directory
err = checkDownloadAndExtractESPClang("linux", espClangDir)
if err != nil {
t.Fatalf("checkDownloadAndExtractESPClang failed: %v", err)
}
// Check that the directory still exists and has the right content
if _, err := os.Stat(clangPath); os.IsNotExist(err) {
t.Error("ESP Clang binary should exist")
}
}
// Test WASI SDK download and extraction when directory doesn't exist
func TestWasiSDKDownloadWhenNotExists(t *testing.T) {
// Create fake WASI SDK archive with proper structure
files := map[string]string{
"wasi-sdk-25.0-x86_64-macos/bin/clang": "fake wasi clang binary",
"wasi-sdk-25.0-x86_64-macos/lib/libm.a": "fake math library",
"wasi-sdk-25.0-x86_64-macos/include/stdio.h": "#include <stdio.h>",
}
archivePath := createTestTarGz(t, files)
defer os.Remove(archivePath)
// Create test server to serve the archive
archiveContent, err := os.ReadFile(archivePath)
if err != nil {
t.Fatalf("Failed to read test archive: %v", err)
}
server := createTestServer(t, map[string]string{
"wasi-sdk-25.0-x86_64-macos.tar.gz": string(archiveContent),
})
defer server.Close()
// Override cacheRoot to use a temporary directory
tempCacheRoot := t.TempDir()
originalCacheRoot := cacheRoot
cacheRoot = func() string { return tempCacheRoot }
defer func() { cacheRoot = originalCacheRoot }()
// Override wasiSdkUrl to use our test server
originalWasiSdkUrl := wasiSdkUrl
wasiSdkUrl = server.URL + "/wasi-sdk-25.0-x86_64-macos.tar.gz"
defer func() { wasiSdkUrl = originalWasiSdkUrl }()
// Use the cache directory structure
extractDir := filepath.Join(tempCacheRoot, "crosscompile", "wasi")
// Test download and extract when directory doesn't exist
sdkRoot, err := checkDownloadAndExtractWasiSDK(extractDir)
if err != nil {
t.Fatalf("checkDownloadAndExtractWasiSDK failed: %v", err)
}
expectedRoot := filepath.Join(extractDir, wasiMacosSubdir)
if sdkRoot != expectedRoot {
t.Errorf("Expected SDK root %q, got %q", expectedRoot, sdkRoot)
}
// Check that files were extracted correctly
for name, expectedContent := range files {
filePath := filepath.Join(extractDir, name)
content, err := os.ReadFile(filePath)
if err != nil {
t.Errorf("Failed to read extracted file %s: %v", name, err)
continue
}
if string(content) != expectedContent {
t.Errorf("File %s: expected content %q, got %q", name, expectedContent, string(content))
}
}
}
// Test ESP Clang download and extraction when directory doesn't exist
func TestESPClangDownloadWhenNotExists(t *testing.T) {
// Create fake ESP Clang archive with proper structure
files := map[string]string{
"esp-clang/bin/clang": "fake esp clang binary",
"esp-clang/lib/libc.a": "fake c library",
"esp-clang/include/esp32.h": "#define ESP32 1",
}
archivePath := createTestTarGz(t, files)
defer os.Remove(archivePath)
// Read the archive content
archiveContent, err := os.ReadFile(archivePath)
if err != nil {
t.Fatalf("Failed to read test archive: %v", err)
}
server := createTestServer(t, map[string]string{
"clang-esp-19.1.2_20250820-linux.tar.xz": string(archiveContent),
})
defer server.Close()
// Override cacheRoot to use a temporary directory
tempCacheRoot := t.TempDir()
originalCacheRoot := cacheRoot
cacheRoot = func() string { return tempCacheRoot }
defer func() { cacheRoot = originalCacheRoot }()
// Override espClangBaseUrl to use our test server
originalEspClangBaseUrl := espClangBaseUrl
espClangBaseUrl = server.URL
defer func() { espClangBaseUrl = originalEspClangBaseUrl }()
// Use a fresh temp directory that doesn't have ESP Clang
espClangDir := filepath.Join(tempCacheRoot, "esp-clang-test")
// Test download and extract when directory doesn't exist
err = checkDownloadAndExtractESPClang("linux", espClangDir)
if err != nil {
t.Fatalf("checkDownloadAndExtractESPClang failed: %v", err)
}
// Check that the target directory exists
if _, err := os.Stat(espClangDir); os.IsNotExist(err) {
t.Error("ESP Clang directory should exist after extraction")
}
// Check that files were extracted correctly to the final destination
for name, expectedContent := range files {
// Remove "esp-clang/" prefix since it gets moved to the final destination
relativePath := strings.TrimPrefix(name, "esp-clang/")
filePath := filepath.Join(espClangDir, relativePath)
content, err := os.ReadFile(filePath)
if err != nil {
t.Errorf("Failed to read extracted file %s: %v", relativePath, err)
continue
}
if string(content) != expectedContent {
t.Errorf("File %s: expected content %q, got %q", relativePath, expectedContent, string(content))
}
}
}

188
internal/firmware/esp.go Normal file
View File

@@ -0,0 +1,188 @@
// From tinygo/builder/esp.go
package firmware
import (
"bytes"
"crypto/sha256"
"debug/elf"
"encoding/binary"
"fmt"
"os"
"sort"
"strings"
)
type espImageSegment struct {
addr uint32
data []byte
}
// makeESPFirmareImage converts an input ELF file to an image file for an ESP32 or
// ESP8266 chip. This is a special purpose image format just for the ESP chip
// family, and is parsed by the on-chip mask ROM bootloader.
//
// The following documentation has been used:
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format
// https://github.com/espressif/esp-idf/blob/8fbb63c2a701c22ccf4ce249f43aded73e134a34/components/bootloader_support/include/esp_image_format.h#L58
// https://github.com/espressif/esptool/blob/master/esptool.py
func makeESPFirmareImage(infile, outfile, format string) error {
inf, err := elf.Open(infile)
if err != nil {
return err
}
defer inf.Close()
// Load all segments to be written to the image. These are actually ELF
// sections, not true ELF segments (similar to how esptool does it).
var segments []*espImageSegment
for _, section := range inf.Sections {
if section.Type != elf.SHT_PROGBITS || section.Size == 0 || section.Flags&elf.SHF_ALLOC == 0 {
continue
}
data, err := section.Data()
if err != nil {
return fmt.Errorf("failed to read section data: %w", err)
}
for len(data)%4 != 0 {
// Align segment to 4 bytes.
data = append(data, 0)
}
if uint64(uint32(section.Addr)) != section.Addr {
return fmt.Errorf("section address too big: 0x%x", section.Addr)
}
segments = append(segments, &espImageSegment{
addr: uint32(section.Addr),
data: data,
})
}
// Sort the segments by address. This is what esptool does too.
sort.SliceStable(segments, func(i, j int) bool { return segments[i].addr < segments[j].addr })
// Calculate checksum over the segment data. This is used in the image
// footer.
checksum := uint8(0xef)
for _, segment := range segments {
for _, b := range segment.data {
checksum ^= b
}
}
// Write first to an in-memory buffer, primarily so that we can easily
// calculate a hash over the entire image.
// An added benefit is that we don't need to check for errors all the time.
outf := &bytes.Buffer{}
// Separate esp32 and esp32-img. The -img suffix indicates we should make an
// image, not just a binary to be flashed at 0x1000 for example.
chip := format
makeImage := false
if strings.HasSuffix(format, "-img") {
makeImage = true
chip = format[:len(format)-len("-img")]
}
if makeImage {
// The bootloader starts at 0x1000, or 4096.
// TinyGo doesn't use a separate bootloader and runs the entire
// application in the bootloader location.
outf.Write(make([]byte, 4096))
}
// Chip IDs. Source:
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L22
chip_id := map[string]uint16{
"esp32": 0x0000,
"esp32c3": 0x0005,
}[chip]
// Image header.
switch chip {
case "esp32", "esp32c3":
// Header format:
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
// Note: not adding a SHA256 hash as the binary is modified by
// esptool.py while flashing and therefore the hash won't be valid
// anymore.
binary.Write(outf, binary.LittleEndian, struct {
magic uint8
segment_count uint8
spi_mode uint8
spi_speed_size uint8
entry_addr uint32
wp_pin uint8
spi_pin_drv [3]uint8
chip_id uint16
min_chip_rev uint8
reserved [8]uint8
hash_appended bool
}{
magic: 0xE9,
segment_count: byte(len(segments)),
spi_mode: 2, // ESP_IMAGE_SPI_MODE_DIO
spi_speed_size: 0x1f, // ESP_IMAGE_SPI_SPEED_80M, ESP_IMAGE_FLASH_SIZE_2MB
entry_addr: uint32(inf.Entry),
wp_pin: 0xEE, // disable WP pin
chip_id: chip_id,
hash_appended: true, // add a SHA256 hash
})
case "esp8266":
// Header format:
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format
// Basically a truncated version of the ESP32 header.
binary.Write(outf, binary.LittleEndian, struct {
magic uint8
segment_count uint8
spi_mode uint8
spi_speed_size uint8
entry_addr uint32
}{
magic: 0xE9,
segment_count: byte(len(segments)),
spi_mode: 0, // irrelevant, replaced by esptool when flashing
spi_speed_size: 0x20, // spi_speed, spi_size: replaced by esptool when flashing
entry_addr: uint32(inf.Entry),
})
default:
return fmt.Errorf("builder: unknown binary format %#v, expected esp32 or esp8266", format)
}
// Write all segments to the image.
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format#segment
for _, segment := range segments {
binary.Write(outf, binary.LittleEndian, struct {
addr uint32
length uint32
}{
addr: segment.addr,
length: uint32(len(segment.data)),
})
outf.Write(segment.data)
}
// Footer, including checksum.
// The entire image size must be a multiple of 16, so pad the image to one
// byte less than that before writing the checksum.
outf.Write(make([]byte, 15-outf.Len()%16))
outf.WriteByte(checksum)
if chip != "esp8266" {
// SHA256 hash (to protect against image corruption, not for security).
hash := sha256.Sum256(outf.Bytes())
outf.Write(hash[:])
}
// QEMU (or more precisely, qemu-system-xtensa from Espressif) expects the
// image to be a certain size.
if makeImage {
// Use a default image size of 4MB.
grow := 4096*1024 - outf.Len()
if grow > 0 {
outf.Write(make([]byte, grow))
}
}
// Write the image to the output file.
return os.WriteFile(outfile, outf.Bytes(), 0666)
}

16
internal/firmware/ext.go Normal file
View File

@@ -0,0 +1,16 @@
package firmware
import "strings"
// BinaryExt returns the binary file extension based on the binary format
// Returns ".bin" for ESP-based formats, "" for others
func BinaryExt(binaryFormat string) string {
if strings.HasPrefix(binaryFormat, "esp") {
return ".bin"
} else if strings.HasPrefix(binaryFormat, "uf2") {
return ".uf2"
} else if strings.HasPrefix(binaryFormat, "nrf-dfu") {
return ".zip"
}
return ""
}

View File

@@ -0,0 +1,31 @@
//go:build !llgo
// +build !llgo
package firmware
import "testing"
func TestBinaryExt(t *testing.T) {
tests := []struct {
name string
binaryFormat string
expected string
}{
{"ESP32", "esp32", ".bin"},
{"ESP8266", "esp8266", ".bin"},
{"ESP32C3", "esp32c3", ".bin"},
{"UF2", "uf2", ".uf2"},
{"ELF", "elf", ""},
{"Empty", "", ""},
{"NRF-DFU", "nrf-dfu", ".zip"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := BinaryExt(tt.binaryFormat)
if result != tt.expected {
t.Errorf("BinaryExt() = %q, want %q", result, tt.expected)
}
})
}
}

View File

@@ -0,0 +1,19 @@
package firmware
import (
"fmt"
"strings"
)
// MakeFirmwareImage creates a firmware image from the given input file.
func MakeFirmwareImage(infile, outfile, format, fmtDetail string) error {
if strings.HasPrefix(format, "esp") {
return makeESPFirmareImage(infile, outfile, format)
} else if format == "uf2" {
uf2Family := fmtDetail
return convertELFFileToUF2File(infile, outfile, uf2Family)
} else if format == "nrf-dfu" {
return makeDFUFirmwareImage(infile, outfile)
}
return fmt.Errorf("unsupported firmware format: %s", format)
}

View File

@@ -0,0 +1,118 @@
// From tinygo/builder/nrfutil.go
package firmware
import (
"archive/zip"
"bytes"
"encoding/binary"
"encoding/json"
"os"
"github.com/sigurn/crc16"
)
// Structure of the manifest.json file.
type jsonManifest struct {
Manifest struct {
Application struct {
BinaryFile string `json:"bin_file"`
DataFile string `json:"dat_file"`
InitPacketData nrfInitPacket `json:"init_packet_data"`
} `json:"application"`
DFUVersion float64 `json:"dfu_version"` // yes, this is a JSON number, not a string
} `json:"manifest"`
}
// Structure of the init packet.
// Source:
// https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/master/lib/sdk11/components/libraries/bootloader_dfu/dfu_init.h#L47-L57
type nrfInitPacket struct {
ApplicationVersion uint32 `json:"application_version"`
DeviceRevision uint16 `json:"device_revision"`
DeviceType uint16 `json:"device_type"`
FirmwareCRC16 uint16 `json:"firmware_crc16"`
SoftDeviceRequired []uint16 `json:"softdevice_req"` // this is actually a variable length array
}
// Create the init packet (the contents of application.dat).
func (p nrfInitPacket) createInitPacket() []byte {
buf := &bytes.Buffer{}
binary.Write(buf, binary.LittleEndian, p.DeviceType) // uint16_t device_type;
binary.Write(buf, binary.LittleEndian, p.DeviceRevision) // uint16_t device_rev;
binary.Write(buf, binary.LittleEndian, p.ApplicationVersion) // uint32_t app_version;
binary.Write(buf, binary.LittleEndian, uint16(len(p.SoftDeviceRequired))) // uint16_t softdevice_len;
binary.Write(buf, binary.LittleEndian, p.SoftDeviceRequired) // uint16_t softdevice[1];
binary.Write(buf, binary.LittleEndian, p.FirmwareCRC16)
return buf.Bytes()
}
// Make a Nordic DFU firmware image from an ELF file.
func makeDFUFirmwareImage(infile, outfile string) error {
// Read ELF file as input and convert it to a binary image file.
_, data, err := extractROM(infile)
if err != nil {
return err
}
// Create the zip file in memory.
// It won't be very large anyway.
buf := &bytes.Buffer{}
w := zip.NewWriter(buf)
// Write the application binary to the zip file.
binw, err := w.Create("application.bin")
if err != nil {
return err
}
_, err = binw.Write(data)
if err != nil {
return err
}
// Create the init packet.
initPacket := nrfInitPacket{
ApplicationVersion: 0xffff_ffff, // appears to be unused by the Adafruit bootloader
DeviceRevision: 0xffff, // DFU_DEVICE_REVISION_EMPTY
DeviceType: 0x0052, // ADAFRUIT_DEVICE_TYPE
FirmwareCRC16: crc16.Checksum(data, crc16.MakeTable(crc16.CRC16_CCITT_FALSE)),
SoftDeviceRequired: []uint16{0xfffe}, // DFU_SOFTDEVICE_ANY
}
// Write the init packet to the zip file.
datw, err := w.Create("application.dat")
if err != nil {
return err
}
_, err = datw.Write(initPacket.createInitPacket())
if err != nil {
return err
}
// Create the JSON manifest.
manifest := &jsonManifest{}
manifest.Manifest.Application.BinaryFile = "application.bin"
manifest.Manifest.Application.DataFile = "application.dat"
manifest.Manifest.Application.InitPacketData = initPacket
manifest.Manifest.DFUVersion = 0.5
// Write the JSON manifest to the file.
jsonw, err := w.Create("manifest.json")
if err != nil {
return err
}
enc := json.NewEncoder(jsonw)
enc.SetIndent("", " ")
err = enc.Encode(manifest)
if err != nil {
return err
}
// Finish the zip file.
err = w.Close()
if err != nil {
return err
}
return os.WriteFile(outfile, buf.Bytes(), 0o666)
}

View File

@@ -0,0 +1,133 @@
// From tinygo/builder/objcopy.go
package firmware
import (
"debug/elf"
"io"
"os"
"sort"
)
// maxPadBytes is the maximum allowed bytes to be padded in a rom extraction
// this value is currently defined by Nintendo Switch Page Alignment (4096 bytes)
const maxPadBytes = 4095
// objcopyError is an error returned by functions that act like objcopy.
type objcopyError struct {
Op string
Err error
}
func (e objcopyError) Error() string {
if e.Err == nil {
return e.Op
}
return e.Op + ": " + e.Err.Error()
}
type progSlice []*elf.Prog
func (s progSlice) Len() int { return len(s) }
func (s progSlice) Less(i, j int) bool { return s[i].Paddr < s[j].Paddr }
func (s progSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// extractROM extracts a firmware image and the first load address from the
// given ELF file. It tries to emulate the behavior of objcopy.
func extractROM(path string) (uint64, []byte, error) {
f, err := elf.Open(path)
if err != nil {
return 0, nil, objcopyError{"failed to open ELF file to extract text segment", err}
}
defer f.Close()
// The GNU objcopy command does the following for firmware extraction (from
// the man page):
// > When objcopy generates a raw binary file, it will essentially produce a
// > memory dump of the contents of the input object file. All symbols and
// > relocation information will be discarded. The memory dump will start at
// > the load address of the lowest section copied into the output file.
// Find the lowest section address.
startAddr := ^uint64(0)
for _, section := range f.Sections {
if section.Type != elf.SHT_PROGBITS || section.Flags&elf.SHF_ALLOC == 0 {
continue
}
if section.Addr < startAddr {
startAddr = section.Addr
}
}
progs := make(progSlice, 0, 2)
for _, prog := range f.Progs {
if prog.Type != elf.PT_LOAD || prog.Filesz == 0 || prog.Off == 0 {
continue
}
progs = append(progs, prog)
}
if len(progs) == 0 {
return 0, nil, objcopyError{"file does not contain ROM segments: " + path, nil}
}
sort.Sort(progs)
var rom []byte
for _, prog := range progs {
romEnd := progs[0].Paddr + uint64(len(rom))
if prog.Paddr > romEnd && prog.Paddr < romEnd+16 {
// Sometimes, the linker seems to insert a bit of padding between
// segments. Simply zero-fill these parts.
rom = append(rom, make([]byte, prog.Paddr-romEnd)...)
}
if prog.Paddr != progs[0].Paddr+uint64(len(rom)) {
diff := prog.Paddr - (progs[0].Paddr + uint64(len(rom)))
if diff > maxPadBytes {
return 0, nil, objcopyError{"ROM segments are non-contiguous: " + path, nil}
}
// Pad the difference
rom = append(rom, make([]byte, diff)...)
}
data, err := io.ReadAll(prog.Open())
if err != nil {
return 0, nil, objcopyError{"failed to extract segment from ELF file: " + path, err}
}
rom = append(rom, data...)
}
if progs[0].Paddr < startAddr {
// The lowest memory address is before the first section. This means
// that there is some extra data loaded at the start of the image that
// should be discarded.
// Example: ELF files where .text doesn't start at address 0 because
// there is a bootloader at the start.
return startAddr, rom[startAddr-progs[0].Paddr:], nil
} else {
return progs[0].Paddr, rom, nil
}
}
// objcopy converts an ELF file to a different (simpler) output file format:
// .bin or .hex. It extracts only the .text section.
func objcopy(infile, outfile, binaryFormat string) error {
f, err := os.OpenFile(outfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer f.Close()
// Read the .text segment.
_, data, err := extractROM(infile)
if err != nil {
return err
}
// Write to the file, in the correct format.
switch binaryFormat {
case "bin":
// The start address is not stored in raw firmware files (therefore you
// should use .hex files in most cases).
_, err := f.Write(data)
return err
default:
panic("unreachable")
}
}

155
internal/firmware/uf2.go Normal file
View File

@@ -0,0 +1,155 @@
// From tinygo/builder/uf2.go
package firmware
// This file converts firmware files from BIN to UF2 format before flashing.
//
// For more information about the UF2 firmware file format, please see:
// https://github.com/Microsoft/uf2
//
//
import (
"bytes"
"encoding/binary"
"os"
"strconv"
)
// convertELFFileToUF2File converts an ELF file to a UF2 file.
func convertELFFileToUF2File(infile, outfile string, uf2FamilyID string) error {
// Read the .text segment.
targetAddress, data, err := extractROM(infile)
if err != nil {
return err
}
output, _, err := convertBinToUF2(data, uint32(targetAddress), uf2FamilyID)
if err != nil {
return err
}
return os.WriteFile(outfile, output, 0644)
}
// convertBinToUF2 converts the binary bytes in input to UF2 formatted data.
func convertBinToUF2(input []byte, targetAddr uint32, uf2FamilyID string) ([]byte, int, error) {
blocks := split(input, 256)
output := make([]byte, 0)
bl, err := newUF2Block(targetAddr, uf2FamilyID)
if err != nil {
return nil, 0, err
}
bl.SetNumBlocks(len(blocks))
for i := 0; i < len(blocks); i++ {
bl.SetBlockNo(i)
bl.SetData(blocks[i])
output = append(output, bl.Bytes()...)
bl.IncrementAddress(bl.payloadSize)
}
return output, len(blocks), nil
}
const (
uf2MagicStart0 = 0x0A324655 // "UF2\n"
uf2MagicStart1 = 0x9E5D5157 // Randomly selected
uf2MagicEnd = 0x0AB16F30 // Ditto
)
// uf2Block is the structure used for each UF2 code block sent to device.
type uf2Block struct {
magicStart0 uint32
magicStart1 uint32
flags uint32
targetAddr uint32
payloadSize uint32
blockNo uint32
numBlocks uint32
familyID uint32
data []uint8
magicEnd uint32
}
// newUF2Block returns a new uf2Block struct that has been correctly populated
func newUF2Block(targetAddr uint32, uf2FamilyID string) (*uf2Block, error) {
var flags uint32
var familyID uint32
if uf2FamilyID != "" {
flags |= flagFamilyIDPresent
v, err := strconv.ParseUint(uf2FamilyID, 0, 32)
if err != nil {
return nil, err
}
familyID = uint32(v)
}
return &uf2Block{magicStart0: uf2MagicStart0,
magicStart1: uf2MagicStart1,
magicEnd: uf2MagicEnd,
targetAddr: targetAddr,
flags: flags,
familyID: familyID,
payloadSize: 256,
data: make([]byte, 476),
}, nil
}
const (
flagFamilyIDPresent = 0x00002000
)
// Bytes converts the uf2Block to a slice of bytes that can be written to file.
func (b *uf2Block) Bytes() []byte {
buf := bytes.NewBuffer(make([]byte, 0, 512))
binary.Write(buf, binary.LittleEndian, b.magicStart0)
binary.Write(buf, binary.LittleEndian, b.magicStart1)
binary.Write(buf, binary.LittleEndian, b.flags)
binary.Write(buf, binary.LittleEndian, b.targetAddr)
binary.Write(buf, binary.LittleEndian, b.payloadSize)
binary.Write(buf, binary.LittleEndian, b.blockNo)
binary.Write(buf, binary.LittleEndian, b.numBlocks)
binary.Write(buf, binary.LittleEndian, b.familyID)
binary.Write(buf, binary.LittleEndian, b.data)
binary.Write(buf, binary.LittleEndian, b.magicEnd)
return buf.Bytes()
}
// IncrementAddress moves the target address pointer forward by count bytes.
func (b *uf2Block) IncrementAddress(count uint32) {
b.targetAddr += b.payloadSize
}
// SetData sets the data to be used for the current block.
func (b *uf2Block) SetData(d []byte) {
b.data = make([]byte, 476)
copy(b.data[:], d)
}
// SetBlockNo sets the current block number to be used.
func (b *uf2Block) SetBlockNo(bn int) {
b.blockNo = uint32(bn)
}
// SetNumBlocks sets the total number of blocks for this UF2 file.
func (b *uf2Block) SetNumBlocks(total int) {
b.numBlocks = uint32(total)
}
// split splits a slice of bytes into a slice of byte slices of a specific size limit.
func split(input []byte, limit int) [][]byte {
var block []byte
output := make([][]byte, 0, len(input)/limit+1)
for len(input) >= limit {
// add all blocks
block, input = input[:limit], input[limit:]
output = append(output, block)
}
if len(input) > 0 {
// add remaining block (that isn't full sized)
output = append(output, input)
}
return output
}

View File

@@ -17,8 +17,41 @@ type Config struct {
// Compiler and linker configuration
Linker string `json:"linker"`
LinkerScript string `json:"linkerscript"`
CFlags []string `json:"cflags"`
LDFlags []string `json:"ldflags"`
ExtraFiles []string `json:"extra-files"`
// Code generation configuration
CodeModel string `json:"code-model"`
TargetABI string `json:"target-abi"`
RelocationModel string `json:"relocation-model"`
// Binary and firmware configuration
BinaryFormat string `json:"binary-format"`
// UF2 configuration
UF2FamilyID string `json:"uf2-family-id"`
// Flash and deployment configuration
FlashCommand string `json:"flash-command"`
FlashMethod string `json:"flash-method"`
Flash1200BpsReset string `json:"flash-1200-bps-reset"`
// Mass storage device configuration
MSDVolumeName []string `json:"msd-volume-name"`
MSDFirmwareName string `json:"msd-firmware-name"`
// Device-specific configuration
RP2040BootPatch bool `json:"rp2040-boot-patch"`
// Debug and emulation configuration
Emulator string `json:"emulator"`
GDB []string `json:"gdb"`
// OpenOCD configuration
OpenOCDInterface string `json:"openocd-interface"`
OpenOCDTransport string `json:"openocd-transport"`
OpenOCDTarget string `json:"openocd-target"`
}
// RawConfig represents the raw JSON configuration before inheritance resolution
@@ -32,6 +65,13 @@ func (c *Config) IsEmpty() bool {
return c.Name == "" && c.LLVMTarget == "" && c.GOOS == "" && c.GOARCH == ""
}
func (c *Config) FormatDetail() string {
if c.BinaryFormat == "uf2" {
return c.UF2FamilyID
}
return ""
}
// HasInheritance returns true if this config inherits from other configs
func (rc *RawConfig) HasInheritance() bool {
return len(rc.Inherits) > 0

View File

@@ -137,6 +137,51 @@ func (l *Loader) mergeConfig(dst, src *Config) {
if src.Linker != "" {
dst.Linker = src.Linker
}
if src.LinkerScript != "" {
dst.LinkerScript = src.LinkerScript
}
if src.CodeModel != "" {
dst.CodeModel = src.CodeModel
}
if src.TargetABI != "" {
dst.TargetABI = src.TargetABI
}
if src.RelocationModel != "" {
dst.RelocationModel = src.RelocationModel
}
if src.BinaryFormat != "" {
dst.BinaryFormat = src.BinaryFormat
}
if src.FlashCommand != "" {
dst.FlashCommand = src.FlashCommand
}
if src.FlashMethod != "" {
dst.FlashMethod = src.FlashMethod
}
if src.Flash1200BpsReset != "" {
dst.Flash1200BpsReset = src.Flash1200BpsReset
}
if src.MSDFirmwareName != "" {
dst.MSDFirmwareName = src.MSDFirmwareName
}
if src.UF2FamilyID != "" {
dst.UF2FamilyID = src.UF2FamilyID
}
if src.RP2040BootPatch {
dst.RP2040BootPatch = src.RP2040BootPatch
}
if src.Emulator != "" {
dst.Emulator = src.Emulator
}
if src.OpenOCDInterface != "" {
dst.OpenOCDInterface = src.OpenOCDInterface
}
if src.OpenOCDTransport != "" {
dst.OpenOCDTransport = src.OpenOCDTransport
}
if src.OpenOCDTarget != "" {
dst.OpenOCDTarget = src.OpenOCDTarget
}
// Merge slices (append, don't replace)
if len(src.BuildTags) > 0 {
@@ -148,6 +193,15 @@ func (l *Loader) mergeConfig(dst, src *Config) {
if len(src.LDFlags) > 0 {
dst.LDFlags = append(dst.LDFlags, src.LDFlags...)
}
if len(src.ExtraFiles) > 0 {
dst.ExtraFiles = append(dst.ExtraFiles, src.ExtraFiles...)
}
if len(src.MSDVolumeName) > 0 {
dst.MSDVolumeName = append(dst.MSDVolumeName, src.MSDVolumeName...)
}
if len(src.GDB) > 0 {
dst.GDB = append(dst.GDB, src.GDB...)
}
}
// GetTargetsDir returns the targets directory path

View File

@@ -61,7 +61,8 @@ func TestLoaderLoadRaw(t *testing.T) {
"goarch": "arm",
"build-tags": ["test", "embedded"],
"cflags": ["-Os", "-g"],
"ldflags": ["--gc-sections"]
"ldflags": ["--gc-sections"],
"binary-format": "uf2"
}`
configPath := filepath.Join(tempDir, "test-target.json")
@@ -87,6 +88,9 @@ func TestLoaderLoadRaw(t *testing.T) {
if len(config.BuildTags) != 2 || config.BuildTags[0] != "test" || config.BuildTags[1] != "embedded" {
t.Errorf("Expected build-tags [test, embedded], got %v", config.BuildTags)
}
if config.BinaryFormat != "uf2" {
t.Errorf("Expected binary-format 'uf2', got '%s'", config.BinaryFormat)
}
}
func TestLoaderInheritance(t *testing.T) {
@@ -99,7 +103,8 @@ func TestLoaderInheritance(t *testing.T) {
"goos": "linux",
"goarch": "arm",
"cflags": ["-Os"],
"ldflags": ["--gc-sections"]
"ldflags": ["--gc-sections"],
"binary-format": "elf"
}`
// Create child config that inherits from parent
@@ -108,7 +113,8 @@ func TestLoaderInheritance(t *testing.T) {
"cpu": "cortex-m4",
"build-tags": ["child"],
"cflags": ["-O2"],
"ldflags": ["-g"]
"ldflags": ["-g"],
"binary-format": "uf2"
}`
parentPath := filepath.Join(tempDir, "parent.json")
@@ -143,6 +149,11 @@ func TestLoaderInheritance(t *testing.T) {
t.Errorf("Expected overridden cpu 'cortex-m4', got '%s'", config.CPU)
}
// Check binary-format override
if config.BinaryFormat != "uf2" {
t.Errorf("Expected overridden binary-format 'uf2', got '%s'", config.BinaryFormat)
}
// Check merged arrays
expectedCFlags := []string{"-Os", "-O2"}
if len(config.CFlags) != 2 || config.CFlags[0] != "-Os" || config.CFlags[1] != "-O2" {

View File

@@ -6,9 +6,9 @@
"ldflags": [
"--defsym=_stack_size=512"
],
"linkerscript": "src/device/avr/atmega1280.ld",
"linkerscript": "targets/device/avr/atmega1280.ld",
"extra-files": [
"targets/avr.S",
"src/device/avr/atmega1280.s"
"targets/device/avr/atmega1280.s"
]
}

View File

@@ -7,10 +7,10 @@
"--defsym=_bootloader_size=0",
"--defsym=_stack_size=512"
],
"linkerscript": "src/device/avr/atmega1284p.ld",
"linkerscript": "targets/device/avr/atmega1284p.ld",
"extra-files": [
"targets/avr.S",
"src/device/avr/atmega1284p.s"
"targets/device/avr/atmega1284p.s"
],
"emulator": "simavr -m atmega1284p -f 20000000 {}"
}

View File

@@ -6,9 +6,9 @@
"ldflags": [
"--defsym=_stack_size=512"
],
"linkerscript": "src/device/avr/atmega2560.ld",
"linkerscript": "targets/device/avr/atmega2560.ld",
"extra-files": [
"targets/avr.S",
"src/device/avr/atmega2560.s"
"targets/device/avr/atmega2560.s"
]
}

View File

@@ -3,9 +3,9 @@
"cpu": "atmega328p",
"build-tags": ["atmega328p", "atmega", "avr5"],
"serial": "uart",
"linkerscript": "src/device/avr/atmega328p.ld",
"linkerscript": "targets/device/avr/atmega328p.ld",
"extra-files": [
"targets/avr.S",
"src/device/avr/atmega328p.s"
"targets/device/avr/atmega328p.s"
]
}

View File

@@ -7,9 +7,9 @@
"--defsym=_stack_size=512"
],
"serial": "uart",
"linkerscript": "src/device/avr/atmega328pb.ld",
"linkerscript": "targets/device/avr/atmega328pb.ld",
"extra-files": [
"targets/avr.S",
"src/device/avr/atmega328pb.s"
"targets/device/avr/atmega328pb.s"
]
}

View File

@@ -3,9 +3,9 @@
"cpu": "atmega32u4",
"build-tags": ["atmega32u4", "avr5"],
"serial": "none",
"linkerscript": "src/device/avr/atmega32u4.ld",
"linkerscript": "targets/device/avr/atmega32u4.ld",
"extra-files": [
"targets/avr.S",
"src/device/avr/atmega32u4.s"
"targets/device/avr/atmega32u4.s"
]
}

View File

@@ -4,7 +4,7 @@
"serial": "usb",
"linkerscript": "targets/atsamd21.ld",
"extra-files": [
"src/device/sam/atsamd21e18a.s"
"targets/device/sam/atsamd21e18a.s"
],
"openocd-transport": "swd",
"openocd-target": "at91samdXX"

View File

@@ -4,7 +4,7 @@
"serial": "usb",
"linkerscript": "targets/atsamd21.ld",
"extra-files": [
"src/device/sam/atsamd21g18a.s"
"targets/device/sam/atsamd21g18a.s"
],
"openocd-transport": "swd",
"openocd-target": "at91samdXX"

View File

@@ -3,7 +3,7 @@
"build-tags": ["atsamd51g19a", "atsamd51g19", "atsamd51", "sam"],
"linkerscript": "targets/atsamd51.ld",
"extra-files": [
"src/device/sam/atsamd51g19a.s"
"targets/device/sam/atsamd51g19a.s"
],
"openocd-transport": "swd",
"openocd-target": "atsame5x"

View File

@@ -3,7 +3,7 @@
"build-tags": ["atsamd51j19a", "atsamd51j19", "atsamd51", "sam"],
"linkerscript": "targets/atsamd51.ld",
"extra-files": [
"src/device/sam/atsamd51j19a.s"
"targets/device/sam/atsamd51j19a.s"
],
"openocd-transport": "swd",
"openocd-target": "atsame5x"

View File

@@ -3,7 +3,7 @@
"build-tags": ["sam", "atsamd51", "atsamd51j20", "atsamd51j20a"],
"linkerscript": "targets/atsamd51j20a.ld",
"extra-files": [
"src/device/sam/atsamd51j20a.s"
"targets/device/sam/atsamd51j20a.s"
],
"openocd-transport": "swd",
"openocd-target": "atsame5x"

View File

@@ -3,7 +3,7 @@
"build-tags": ["atsamd51p19a", "atsamd51p19", "atsamd51", "sam"],
"linkerscript": "targets/atsamd51.ld",
"extra-files": [
"src/device/sam/atsamd51p19a.s"
"targets/device/sam/atsamd51p19a.s"
],
"openocd-transport": "swd",
"openocd-target": "atsame5x"

View File

@@ -3,7 +3,7 @@
"build-tags": ["sam", "atsamd51", "atsamd51p20", "atsamd51p20a"],
"linkerscript": "targets/atsamd51p20a.ld",
"extra-files": [
"src/device/sam/atsamd51p20a.s"
"targets/device/sam/atsamd51p20a.s"
],
"openocd-transport": "swd",
"openocd-target": "atsame5x"

View File

@@ -3,7 +3,7 @@
"build-tags": ["atsame51j19a", "atsame51j19", "atsame51", "atsame5x", "sam"],
"linkerscript": "targets/atsame5xx19.ld",
"extra-files": [
"src/device/sam/atsame51j19a.s"
"targets/device/sam/atsame51j19a.s"
],
"openocd-transport": "swd",
"openocd-target": "atsame5x"

View File

@@ -3,7 +3,7 @@
"build-tags": ["sam", "atsame5x", "atsame54", "atsame54p20", "atsame54p20a"],
"linkerscript": "targets/atsame5xx20-no-bootloader.ld",
"extra-files": [
"src/device/sam/atsame54p20a.s"
"targets/device/sam/atsame54p20a.s"
],
"openocd-transport": "swd",
"openocd-target": "atsame5x"

View File

@@ -6,9 +6,9 @@
"cflags": [
"-D__AVR_ARCH__=103"
],
"linkerscript": "src/device/avr/attiny1616.ld",
"linkerscript": "targets/device/avr/attiny1616.ld",
"extra-files": [
"src/device/avr/attiny1616.s"
"targets/device/avr/attiny1616.s"
],
"flash-command": "pymcuprog write -f {hex} --erase --verify -d attiny1616 -t uart -u {port}"
}

View File

@@ -5,9 +5,9 @@
"cflags": [
"-D__AVR_ARCH__=25"
],
"linkerscript": "src/device/avr/attiny85.ld",
"linkerscript": "targets/device/avr/attiny85.ld",
"extra-files": [
"targets/avr.S",
"src/device/avr/attiny85.s"
"targets/device/avr/attiny85.s"
]
}

View File

@@ -16,9 +16,5 @@
"-T", "targets/avr.ld",
"--gc-sections"
],
"extra-files": [
"src/internal/task/task_stack_avr.S",
"src/runtime/asm_avr.S"
],
"gdb": ["avr-gdb"]
}

View File

@@ -17,8 +17,6 @@
"--gc-sections"
],
"extra-files": [
"src/internal/task/task_stack_avr.S",
"src/runtime/asm_avr.S",
"targets/avrtiny.S"
],
"gdb": ["avr-gdb"]

View File

@@ -4,7 +4,7 @@
"serial": "uart",
"linkerscript": "targets/stm32.ld",
"extra-files": [
"src/device/stm32/stm32f103.s"
"targets/device/stm32/stm32f103.s"
],
"flash-method": "openocd",
"openocd-interface": "stlink-v2",

View File

@@ -22,9 +22,7 @@
"--gc-sections"
],
"extra-files": [
"src/device/arm/cortexm.S",
"src/internal/task/task_stack_cortexm.S",
"src/runtime/asm_arm.S"
"targets/device/arm/cortexm.S"
],
"gdb": ["gdb-multiarch", "arm-none-eabi-gdb", "gdb"]
}

View File

@@ -0,0 +1,37 @@
.syntax unified
.cfi_sections .debug_frame
.section .text.HardFault_Handler
.global HardFault_Handler
.type HardFault_Handler, %function
HardFault_Handler:
.cfi_startproc
// Put the old stack pointer in the first argument, for easy debugging. This
// is especially useful on Cortex-M0, which supports far fewer debug
// facilities.
mov r0, sp
// Load the default stack pointer from address 0 so that we can call normal
// functions again that expect a working stack. However, it will corrupt the
// old stack so the function below must not attempt to recover from this
// fault.
movs r3, #0
ldr r3, [r3]
mov sp, r3
// Continue handling this error in Go.
bl handleHardFault
.cfi_endproc
.size HardFault_Handler, .-HardFault_Handler
// This is a convenience function for semihosting support.
// At some point, this should be replaced by inline assembly.
.section .text.SemihostingCall
.global SemihostingCall
.type SemihostingCall, %function
SemihostingCall:
.cfi_startproc
bkpt 0xab
bx lr
.cfi_endproc
.size SemihostingCall, .-SemihostingCall

View File

@@ -0,0 +1,22 @@
#include <stdint.h>
void EnableInterrupts(uintptr_t mask) {
asm volatile(
"msr PRIMASK, %0"
:
: "r"(mask)
: "memory"
);
}
uintptr_t DisableInterrupts() {
uintptr_t mask;
asm volatile(
"mrs %0, PRIMASK\n\t"
"cpsid i"
: "=r"(mask)
:
: "memory"
);
return mask;
}

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90CAN128.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x20000;
__ram_start = 0x100;
__ram_size = 0x1000;
__num_isrs = 37;

View File

@@ -0,0 +1,98 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90CAN128.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_TIMER2_COMP
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMP
jmp __vector_TIMER0_OVF
jmp __vector_CANIT
jmp __vector_OVRIT
jmp __vector_SPI_STC
jmp __vector_USART0_RX
jmp __vector_USART0_UDRE
jmp __vector_USART0_TX
jmp __vector_ANALOG_COMP
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_COMPC
jmp __vector_TIMER3_OVF
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_TWI
jmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_TIMER2_COMP
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMP
IRQ __vector_TIMER0_OVF
IRQ __vector_CANIT
IRQ __vector_OVRIT
IRQ __vector_SPI_STC
IRQ __vector_USART0_RX
IRQ __vector_USART0_UDRE
IRQ __vector_USART0_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_COMPC
IRQ __vector_TIMER3_OVF
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_TWI
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90CAN32.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x8000;
__ram_start = 0x100;
__ram_size = 0x800;
__num_isrs = 37;

View File

@@ -0,0 +1,98 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90CAN32.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_TIMER2_COMP
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMP
jmp __vector_TIMER0_OVF
jmp __vector_CANIT
jmp __vector_OVRIT
jmp __vector_SPI_STC
jmp __vector_USART0_RX
jmp __vector_USART0_UDRE
jmp __vector_USART0_TX
jmp __vector_ANALOG_COMP
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_COMPC
jmp __vector_TIMER3_OVF
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_TWI
jmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_TIMER2_COMP
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMP
IRQ __vector_TIMER0_OVF
IRQ __vector_CANIT
IRQ __vector_OVRIT
IRQ __vector_SPI_STC
IRQ __vector_USART0_RX
IRQ __vector_USART0_UDRE
IRQ __vector_USART0_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_COMPC
IRQ __vector_TIMER3_OVF
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_TWI
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90CAN64.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x10000;
__ram_start = 0x100;
__ram_size = 0x1000;
__num_isrs = 37;

View File

@@ -0,0 +1,98 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90CAN64.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_TIMER2_COMP
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMP
jmp __vector_TIMER0_OVF
jmp __vector_CANIT
jmp __vector_OVRIT
jmp __vector_SPI_STC
jmp __vector_USART0_RX
jmp __vector_USART0_UDRE
jmp __vector_USART0_TX
jmp __vector_ANALOG_COMP
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_COMPC
jmp __vector_TIMER3_OVF
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_TWI
jmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_TIMER2_COMP
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMP
IRQ __vector_TIMER0_OVF
IRQ __vector_CANIT
IRQ __vector_OVRIT
IRQ __vector_SPI_STC
IRQ __vector_USART0_RX
IRQ __vector_USART0_UDRE
IRQ __vector_USART0_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_COMPC
IRQ __vector_TIMER3_OVF
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_TWI
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90PWM1.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x2000;
__ram_start = 0x100;
__ram_size = 0x200;
__num_isrs = 32;

View File

@@ -0,0 +1,88 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90PWM1.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
rjmp __vector_RESET
rjmp __vector_PSC2_CAPT
rjmp __vector_PSC2_EC
rjmp __vector_PSC1_CAPT
rjmp __vector_PSC1_EC
rjmp __vector_PSC0_CAPT
rjmp __vector_PSC0_EC
rjmp __vector_ANALOG_COMP_0
rjmp __vector_ANALOG_COMP_1
rjmp __vector_ANALOG_COMP_2
rjmp __vector_INT0
rjmp __vector_TIMER1_CAPT
rjmp __vector_TIMER1_COMPA
rjmp __vector_TIMER1_COMPB
rjmp __vector_RESERVED15
rjmp __vector_TIMER1_OVF
rjmp __vector_TIMER0_COMP_A
rjmp __vector_TIMER0_OVF
rjmp __vector_ADC
rjmp __vector_INT1
rjmp __vector_SPI_STC
rjmp __vector_USART_RX
rjmp __vector_USART_UDRE
rjmp __vector_USART_TX
rjmp __vector_INT2
rjmp __vector_WDT
rjmp __vector_EE_READY
rjmp __vector_TIMER0_COMPB
rjmp __vector_INT3
rjmp __vector_RESERVED30
rjmp __vector_RESERVED31
rjmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_PSC2_CAPT
IRQ __vector_PSC2_EC
IRQ __vector_PSC1_CAPT
IRQ __vector_PSC1_EC
IRQ __vector_PSC0_CAPT
IRQ __vector_PSC0_EC
IRQ __vector_ANALOG_COMP_0
IRQ __vector_ANALOG_COMP_1
IRQ __vector_ANALOG_COMP_2
IRQ __vector_INT0
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_RESERVED15
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMP_A
IRQ __vector_TIMER0_OVF
IRQ __vector_ADC
IRQ __vector_INT1
IRQ __vector_SPI_STC
IRQ __vector_USART_RX
IRQ __vector_USART_UDRE
IRQ __vector_USART_TX
IRQ __vector_INT2
IRQ __vector_WDT
IRQ __vector_EE_READY
IRQ __vector_TIMER0_COMPB
IRQ __vector_INT3
IRQ __vector_RESERVED30
IRQ __vector_RESERVED31
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90PWM161.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x4000;
__ram_start = 0x100;
__ram_size = 0x400;
__num_isrs = 20;

View File

@@ -0,0 +1,64 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90PWM161.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_PSC2_CAPT
jmp __vector_PSC2_EC
jmp __vector_PSC2_EEC
jmp __vector_PSC0_CAPT
jmp __vector_PSC0_EC
jmp __vector_PSC0_EEC
jmp __vector_ANALOG_COMP_1
jmp __vector_ANALOG_COMP_2
jmp __vector_ANALOG_COMP_3
jmp __vector_INT0
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_OVF
jmp __vector_ADC
jmp __vector_INT1
jmp __vector_SPI_STC
jmp __vector_INT2
jmp __vector_WDT
jmp __vector_EE_READY
jmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_PSC2_CAPT
IRQ __vector_PSC2_EC
IRQ __vector_PSC2_EEC
IRQ __vector_PSC0_CAPT
IRQ __vector_PSC0_EC
IRQ __vector_PSC0_EEC
IRQ __vector_ANALOG_COMP_1
IRQ __vector_ANALOG_COMP_2
IRQ __vector_ANALOG_COMP_3
IRQ __vector_INT0
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_OVF
IRQ __vector_ADC
IRQ __vector_INT1
IRQ __vector_SPI_STC
IRQ __vector_INT2
IRQ __vector_WDT
IRQ __vector_EE_READY
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90PWM216.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x4000;
__ram_start = 0x100;
__ram_size = 0x400;
__num_isrs = 32;

View File

@@ -0,0 +1,88 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90PWM216.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_PSC2_CAPT
jmp __vector_PSC2_EC
jmp __vector_PSC1_CAPT
jmp __vector_PSC1_EC
jmp __vector_PSC0_CAPT
jmp __vector_PSC0_EC
jmp __vector_ANALOG_COMP_0
jmp __vector_ANALOG_COMP_1
jmp __vector_ANALOG_COMP_2
jmp __vector_INT0
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_RESERVED15
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMP_A
jmp __vector_TIMER0_OVF
jmp __vector_ADC
jmp __vector_INT1
jmp __vector_SPI_STC
jmp __vector_USART_RX
jmp __vector_USART_UDRE
jmp __vector_USART_TX
jmp __vector_INT2
jmp __vector_WDT
jmp __vector_EE_READY
jmp __vector_TIMER0_COMPB
jmp __vector_INT3
jmp __vector_RESERVED30
jmp __vector_RESERVED31
jmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_PSC2_CAPT
IRQ __vector_PSC2_EC
IRQ __vector_PSC1_CAPT
IRQ __vector_PSC1_EC
IRQ __vector_PSC0_CAPT
IRQ __vector_PSC0_EC
IRQ __vector_ANALOG_COMP_0
IRQ __vector_ANALOG_COMP_1
IRQ __vector_ANALOG_COMP_2
IRQ __vector_INT0
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_RESERVED15
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMP_A
IRQ __vector_TIMER0_OVF
IRQ __vector_ADC
IRQ __vector_INT1
IRQ __vector_SPI_STC
IRQ __vector_USART_RX
IRQ __vector_USART_UDRE
IRQ __vector_USART_TX
IRQ __vector_INT2
IRQ __vector_WDT
IRQ __vector_EE_READY
IRQ __vector_TIMER0_COMPB
IRQ __vector_INT3
IRQ __vector_RESERVED30
IRQ __vector_RESERVED31
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90PWM2B.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x2000;
__ram_start = 0x100;
__ram_size = 0x200;
__num_isrs = 32;

View File

@@ -0,0 +1,88 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90PWM2B.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
rjmp __vector_RESET
rjmp __vector_PSC2_CAPT
rjmp __vector_PSC2_EC
rjmp __vector_PSC1_CAPT
rjmp __vector_PSC1_EC
rjmp __vector_PSC0_CAPT
rjmp __vector_PSC0_EC
rjmp __vector_ANALOG_COMP_0
rjmp __vector_ANALOG_COMP_1
rjmp __vector_ANALOG_COMP_2
rjmp __vector_INT0
rjmp __vector_TIMER1_CAPT
rjmp __vector_TIMER1_COMPA
rjmp __vector_TIMER1_COMPB
rjmp __vector_RESERVED15
rjmp __vector_TIMER1_OVF
rjmp __vector_TIMER0_COMPA
rjmp __vector_TIMER0_OVF
rjmp __vector_ADC
rjmp __vector_INT1
rjmp __vector_SPI_STC
rjmp __vector_USART_RX
rjmp __vector_USART_UDRE
rjmp __vector_USART_TX
rjmp __vector_INT2
rjmp __vector_WDT
rjmp __vector_EE_READY
rjmp __vector_TIMER0_COMPB
rjmp __vector_INT3
rjmp __vector_RESERVED30
rjmp __vector_RESERVED31
rjmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_PSC2_CAPT
IRQ __vector_PSC2_EC
IRQ __vector_PSC1_CAPT
IRQ __vector_PSC1_EC
IRQ __vector_PSC0_CAPT
IRQ __vector_PSC0_EC
IRQ __vector_ANALOG_COMP_0
IRQ __vector_ANALOG_COMP_1
IRQ __vector_ANALOG_COMP_2
IRQ __vector_INT0
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_RESERVED15
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_OVF
IRQ __vector_ADC
IRQ __vector_INT1
IRQ __vector_SPI_STC
IRQ __vector_USART_RX
IRQ __vector_USART_UDRE
IRQ __vector_USART_TX
IRQ __vector_INT2
IRQ __vector_WDT
IRQ __vector_EE_READY
IRQ __vector_TIMER0_COMPB
IRQ __vector_INT3
IRQ __vector_RESERVED30
IRQ __vector_RESERVED31
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90PWM316.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x4000;
__ram_start = 0x100;
__ram_size = 0x400;
__num_isrs = 32;

View File

@@ -0,0 +1,88 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90PWM316.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_PSC2_CAPT
jmp __vector_PSC2_EC
jmp __vector_PSC1_CAPT
jmp __vector_PSC1_EC
jmp __vector_PSC0_CAPT
jmp __vector_PSC0_EC
jmp __vector_ANALOG_COMP_0
jmp __vector_ANALOG_COMP_1
jmp __vector_ANALOG_COMP_2
jmp __vector_INT0
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_RESERVED15
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMP_A
jmp __vector_TIMER0_OVF
jmp __vector_ADC
jmp __vector_INT1
jmp __vector_SPI_STC
jmp __vector_USART_RX
jmp __vector_USART_UDRE
jmp __vector_USART_TX
jmp __vector_INT2
jmp __vector_WDT
jmp __vector_EE_READY
jmp __vector_TIMER0_COMPB
jmp __vector_INT3
jmp __vector_RESERVED30
jmp __vector_RESERVED31
jmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_PSC2_CAPT
IRQ __vector_PSC2_EC
IRQ __vector_PSC1_CAPT
IRQ __vector_PSC1_EC
IRQ __vector_PSC0_CAPT
IRQ __vector_PSC0_EC
IRQ __vector_ANALOG_COMP_0
IRQ __vector_ANALOG_COMP_1
IRQ __vector_ANALOG_COMP_2
IRQ __vector_INT0
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_RESERVED15
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMP_A
IRQ __vector_TIMER0_OVF
IRQ __vector_ADC
IRQ __vector_INT1
IRQ __vector_SPI_STC
IRQ __vector_USART_RX
IRQ __vector_USART_UDRE
IRQ __vector_USART_TX
IRQ __vector_INT2
IRQ __vector_WDT
IRQ __vector_EE_READY
IRQ __vector_TIMER0_COMPB
IRQ __vector_INT3
IRQ __vector_RESERVED30
IRQ __vector_RESERVED31
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90PWM3B.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x2000;
__ram_start = 0x100;
__ram_size = 0x200;
__num_isrs = 32;

View File

@@ -0,0 +1,88 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90PWM3B.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
rjmp __vector_RESET
rjmp __vector_PSC2_CAPT
rjmp __vector_PSC2_EC
rjmp __vector_PSC1_CAPT
rjmp __vector_PSC1_EC
rjmp __vector_PSC0_CAPT
rjmp __vector_PSC0_EC
rjmp __vector_ANALOG_COMP_0
rjmp __vector_ANALOG_COMP_1
rjmp __vector_ANALOG_COMP_2
rjmp __vector_INT0
rjmp __vector_TIMER1_CAPT
rjmp __vector_TIMER1_COMPA
rjmp __vector_TIMER1_COMPB
rjmp __vector_RESERVED15
rjmp __vector_TIMER1_OVF
rjmp __vector_TIMER0_COMPA
rjmp __vector_TIMER0_OVF
rjmp __vector_ADC
rjmp __vector_INT1
rjmp __vector_SPI_STC
rjmp __vector_USART_RX
rjmp __vector_USART_UDRE
rjmp __vector_USART_TX
rjmp __vector_INT2
rjmp __vector_WDT
rjmp __vector_EE_READY
rjmp __vector_TIMER0_COMPB
rjmp __vector_INT3
rjmp __vector_RESERVED30
rjmp __vector_RESERVED31
rjmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_PSC2_CAPT
IRQ __vector_PSC2_EC
IRQ __vector_PSC1_CAPT
IRQ __vector_PSC1_EC
IRQ __vector_PSC0_CAPT
IRQ __vector_PSC0_EC
IRQ __vector_ANALOG_COMP_0
IRQ __vector_ANALOG_COMP_1
IRQ __vector_ANALOG_COMP_2
IRQ __vector_INT0
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_RESERVED15
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_OVF
IRQ __vector_ADC
IRQ __vector_INT1
IRQ __vector_SPI_STC
IRQ __vector_USART_RX
IRQ __vector_USART_UDRE
IRQ __vector_USART_TX
IRQ __vector_INT2
IRQ __vector_WDT
IRQ __vector_EE_READY
IRQ __vector_TIMER0_COMPB
IRQ __vector_INT3
IRQ __vector_RESERVED30
IRQ __vector_RESERVED31
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90PWM81.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x2000;
__ram_start = 0x100;
__ram_size = 0x100;
__num_isrs = 20;

View File

@@ -0,0 +1,64 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90PWM81.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
rjmp __vector_RESET
rjmp __vector_PSC2_CAPT
rjmp __vector_PSC2_EC
rjmp __vector_PSC2_EEC
rjmp __vector_PSC0_CAPT
rjmp __vector_PSC0_EC
rjmp __vector_PSC0_EEC
rjmp __vector_ANALOG_COMP_1
rjmp __vector_ANALOG_COMP_2
rjmp __vector_ANALOG_COMP_3
rjmp __vector_INT0
rjmp __vector_TIMER1_CAPT
rjmp __vector_TIMER1_OVF
rjmp __vector_ADC
rjmp __vector_INT1
rjmp __vector_SPI_STC
rjmp __vector_INT2
rjmp __vector_WDT
rjmp __vector_EE_READY
rjmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_PSC2_CAPT
IRQ __vector_PSC2_EC
IRQ __vector_PSC2_EEC
IRQ __vector_PSC0_CAPT
IRQ __vector_PSC0_EC
IRQ __vector_PSC0_EEC
IRQ __vector_ANALOG_COMP_1
IRQ __vector_ANALOG_COMP_2
IRQ __vector_ANALOG_COMP_3
IRQ __vector_INT0
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_OVF
IRQ __vector_ADC
IRQ __vector_INT1
IRQ __vector_SPI_STC
IRQ __vector_INT2
IRQ __vector_WDT
IRQ __vector_EE_READY
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90USB1286.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x20000;
__ram_start = 0x100;
__ram_size = 0x2000;
__num_isrs = 38;

View File

@@ -0,0 +1,100 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90USB1286.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_PCINT0
jmp __vector_USB_GEN
jmp __vector_USB_COM
jmp __vector_WDT
jmp __vector_TIMER2_COMPA
jmp __vector_TIMER2_COMPB
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMPA
jmp __vector_TIMER0_COMPB
jmp __vector_TIMER0_OVF
jmp __vector_SPI_STC
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_ANALOG_COMP
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_COMPC
jmp __vector_TIMER3_OVF
jmp __vector_TWI
jmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_PCINT0
IRQ __vector_USB_GEN
IRQ __vector_USB_COM
IRQ __vector_WDT
IRQ __vector_TIMER2_COMPA
IRQ __vector_TIMER2_COMPB
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_COMPB
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_COMPC
IRQ __vector_TIMER3_OVF
IRQ __vector_TWI
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90USB1287.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x20000;
__ram_start = 0x100;
__ram_size = 0x2000;
__num_isrs = 38;

View File

@@ -0,0 +1,100 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90USB1287.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_PCINT0
jmp __vector_USB_GEN
jmp __vector_USB_COM
jmp __vector_WDT
jmp __vector_TIMER2_COMPA
jmp __vector_TIMER2_COMPB
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMPA
jmp __vector_TIMER0_COMPB
jmp __vector_TIMER0_OVF
jmp __vector_SPI_STC
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_ANALOG_COMP
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_COMPC
jmp __vector_TIMER3_OVF
jmp __vector_TWI
jmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_PCINT0
IRQ __vector_USB_GEN
IRQ __vector_USB_COM
IRQ __vector_WDT
IRQ __vector_TIMER2_COMPA
IRQ __vector_TIMER2_COMPB
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_COMPB
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_COMPC
IRQ __vector_TIMER3_OVF
IRQ __vector_TWI
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90USB162.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x4000;
__ram_start = 0x100;
__ram_size = 0x200;
__num_isrs = 29;

View File

@@ -0,0 +1,82 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90USB162.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_PCINT0
jmp __vector_PCINT1
jmp __vector_USB_GEN
jmp __vector_USB_COM
jmp __vector_WDT
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMPA
jmp __vector_TIMER0_COMPB
jmp __vector_TIMER0_OVF
jmp __vector_SPI_STC
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_ANALOG_COMP
jmp __vector_EE_READY
jmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_PCINT0
IRQ __vector_PCINT1
IRQ __vector_USB_GEN
IRQ __vector_USB_COM
IRQ __vector_WDT
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_COMPB
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_EE_READY
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90USB646.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x10000;
__ram_start = 0x100;
__ram_size = 0x1000;
__num_isrs = 38;

View File

@@ -0,0 +1,100 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90USB646.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_PCINT0
jmp __vector_USB_GEN
jmp __vector_USB_COM
jmp __vector_WDT
jmp __vector_TIMER2_COMPA
jmp __vector_TIMER2_COMPB
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMPA
jmp __vector_TIMER0_COMPB
jmp __vector_TIMER0_OVF
jmp __vector_SPI_STC
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_ANALOG_COMP
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_COMPC
jmp __vector_TIMER3_OVF
jmp __vector_TWI
jmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_PCINT0
IRQ __vector_USB_GEN
IRQ __vector_USB_COM
IRQ __vector_WDT
IRQ __vector_TIMER2_COMPA
IRQ __vector_TIMER2_COMPB
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_COMPB
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_COMPC
IRQ __vector_TIMER3_OVF
IRQ __vector_TWI
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90USB647.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x10000;
__ram_start = 0x100;
__ram_size = 0x1000;
__num_isrs = 38;

View File

@@ -0,0 +1,100 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90USB647.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_PCINT0
jmp __vector_USB_GEN
jmp __vector_USB_COM
jmp __vector_WDT
jmp __vector_TIMER2_COMPA
jmp __vector_TIMER2_COMPB
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMPA
jmp __vector_TIMER0_COMPB
jmp __vector_TIMER0_OVF
jmp __vector_SPI_STC
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_ANALOG_COMP
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_COMPC
jmp __vector_TIMER3_OVF
jmp __vector_TWI
jmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_PCINT0
IRQ __vector_USB_GEN
IRQ __vector_USB_COM
IRQ __vector_WDT
IRQ __vector_TIMER2_COMPA
IRQ __vector_TIMER2_COMPB
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_COMPB
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_COMPC
IRQ __vector_TIMER3_OVF
IRQ __vector_TWI
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from AT90USB82.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x2000;
__ram_start = 0x100;
__ram_size = 0x200;
__num_isrs = 29;

View File

@@ -0,0 +1,82 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from AT90USB82.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
rjmp __vector_RESET
rjmp __vector_INT0
rjmp __vector_INT1
rjmp __vector_INT2
rjmp __vector_INT3
rjmp __vector_INT4
rjmp __vector_INT5
rjmp __vector_INT6
rjmp __vector_INT7
rjmp __vector_PCINT0
rjmp __vector_PCINT1
rjmp __vector_USB_GEN
rjmp __vector_USB_COM
rjmp __vector_WDT
rjmp __vector_TIMER1_CAPT
rjmp __vector_TIMER1_COMPA
rjmp __vector_TIMER1_COMPB
rjmp __vector_TIMER1_COMPC
rjmp __vector_TIMER1_OVF
rjmp __vector_TIMER0_COMPA
rjmp __vector_TIMER0_COMPB
rjmp __vector_TIMER0_OVF
rjmp __vector_SPI_STC
rjmp __vector_USART1_RX
rjmp __vector_USART1_UDRE
rjmp __vector_USART1_TX
rjmp __vector_ANALOG_COMP
rjmp __vector_EE_READY
rjmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_PCINT0
IRQ __vector_PCINT1
IRQ __vector_USB_GEN
IRQ __vector_USB_COM
IRQ __vector_WDT
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_COMPB
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_EE_READY
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from ATmega128.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x20000;
__ram_start = 0x100;
__ram_size = 0x1000;
__num_isrs = 35;

View File

@@ -0,0 +1,94 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from ATmega128.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_TIMER2_COMP
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMP
jmp __vector_TIMER0_OVF
jmp __vector_SPI_STC
jmp __vector_USART0_RX
jmp __vector_USART0_UDRE
jmp __vector_USART0_TX
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_ANALOG_COMP
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_COMPC
jmp __vector_TIMER3_OVF
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_TWI
jmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_TIMER2_COMP
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMP
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART0_RX
IRQ __vector_USART0_UDRE
IRQ __vector_USART0_TX
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_ANALOG_COMP
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_COMPC
IRQ __vector_TIMER3_OVF
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_TWI
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from ATmega1280.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x20000;
__ram_start = 0x200;
__ram_size = 0x2000;
__num_isrs = 57;

View File

@@ -0,0 +1,138 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from ATmega1280.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_PCINT0
jmp __vector_PCINT1
jmp __vector_PCINT2
jmp __vector_WDT
jmp __vector_TIMER2_COMPA
jmp __vector_TIMER2_COMPB
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMPA
jmp __vector_TIMER0_COMPB
jmp __vector_TIMER0_OVF
jmp __vector_SPI_STC
jmp __vector_USART0_RX
jmp __vector_USART0_UDRE
jmp __vector_USART0_TX
jmp __vector_ANALOG_COMP
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_COMPC
jmp __vector_TIMER3_OVF
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_TWI
jmp __vector_SPM_READY
jmp __vector_TIMER4_CAPT
jmp __vector_TIMER4_COMPA
jmp __vector_TIMER4_COMPB
jmp __vector_TIMER4_COMPC
jmp __vector_TIMER4_OVF
jmp __vector_TIMER5_CAPT
jmp __vector_TIMER5_COMPA
jmp __vector_TIMER5_COMPB
jmp __vector_TIMER5_COMPC
jmp __vector_TIMER5_OVF
jmp __vector_USART2_RX
jmp __vector_USART2_UDRE
jmp __vector_USART2_TX
jmp __vector_USART3_RX
jmp __vector_USART3_UDRE
jmp __vector_USART3_TX
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_PCINT0
IRQ __vector_PCINT1
IRQ __vector_PCINT2
IRQ __vector_WDT
IRQ __vector_TIMER2_COMPA
IRQ __vector_TIMER2_COMPB
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_COMPB
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART0_RX
IRQ __vector_USART0_UDRE
IRQ __vector_USART0_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_COMPC
IRQ __vector_TIMER3_OVF
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_TWI
IRQ __vector_SPM_READY
IRQ __vector_TIMER4_CAPT
IRQ __vector_TIMER4_COMPA
IRQ __vector_TIMER4_COMPB
IRQ __vector_TIMER4_COMPC
IRQ __vector_TIMER4_OVF
IRQ __vector_TIMER5_CAPT
IRQ __vector_TIMER5_COMPA
IRQ __vector_TIMER5_COMPB
IRQ __vector_TIMER5_COMPC
IRQ __vector_TIMER5_OVF
IRQ __vector_USART2_RX
IRQ __vector_USART2_UDRE
IRQ __vector_USART2_TX
IRQ __vector_USART3_RX
IRQ __vector_USART3_UDRE
IRQ __vector_USART3_TX

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from ATmega1281.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x20000;
__ram_start = 0x200;
__ram_size = 0x2000;
__num_isrs = 57;

View File

@@ -0,0 +1,138 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from ATmega1281.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_PCINT0
jmp __vector_PCINT1
jmp __vector_PCINT2
jmp __vector_WDT
jmp __vector_TIMER2_COMPA
jmp __vector_TIMER2_COMPB
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMPA
jmp __vector_TIMER0_COMPB
jmp __vector_TIMER0_OVF
jmp __vector_SPI_STC
jmp __vector_USART0_RX
jmp __vector_USART0_UDRE
jmp __vector_USART0_TX
jmp __vector_ANALOG_COMP
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_COMPC
jmp __vector_TIMER3_OVF
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_TWI
jmp __vector_SPM_READY
jmp __vector_TIMER4_CAPT
jmp __vector_TIMER4_COMPA
jmp __vector_TIMER4_COMPB
jmp __vector_TIMER4_COMPC
jmp __vector_TIMER4_OVF
jmp __vector_TIMER5_CAPT
jmp __vector_TIMER5_COMPA
jmp __vector_TIMER5_COMPB
jmp __vector_TIMER5_COMPC
jmp __vector_TIMER5_OVF
jmp __vector_USART2_RX
jmp __vector_USART2_UDRE
jmp __vector_USART2_TX
jmp __vector_USART3_RX
jmp __vector_USART3_UDRE
jmp __vector_USART3_TX
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_PCINT0
IRQ __vector_PCINT1
IRQ __vector_PCINT2
IRQ __vector_WDT
IRQ __vector_TIMER2_COMPA
IRQ __vector_TIMER2_COMPB
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_COMPB
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART0_RX
IRQ __vector_USART0_UDRE
IRQ __vector_USART0_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_COMPC
IRQ __vector_TIMER3_OVF
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_TWI
IRQ __vector_SPM_READY
IRQ __vector_TIMER4_CAPT
IRQ __vector_TIMER4_COMPA
IRQ __vector_TIMER4_COMPB
IRQ __vector_TIMER4_COMPC
IRQ __vector_TIMER4_OVF
IRQ __vector_TIMER5_CAPT
IRQ __vector_TIMER5_COMPA
IRQ __vector_TIMER5_COMPB
IRQ __vector_TIMER5_COMPC
IRQ __vector_TIMER5_OVF
IRQ __vector_USART2_RX
IRQ __vector_USART2_UDRE
IRQ __vector_USART2_TX
IRQ __vector_USART3_RX
IRQ __vector_USART3_UDRE
IRQ __vector_USART3_TX

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from ATmega1284.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x20000;
__ram_start = 0x100;
__ram_size = 0x4000;
__num_isrs = 35;

View File

@@ -0,0 +1,94 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from ATmega1284.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_PCINT0
jmp __vector_PCINT1
jmp __vector_PCINT2
jmp __vector_PCINT3
jmp __vector_WDT
jmp __vector_TIMER2_COMPA
jmp __vector_TIMER2_COMPB
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMPA
jmp __vector_TIMER0_COMPB
jmp __vector_TIMER0_OVF
jmp __vector_SPI_STC
jmp __vector_USART0_RX
jmp __vector_USART0_UDRE
jmp __vector_USART0_TX
jmp __vector_ANALOG_COMP
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_TWI
jmp __vector_SPM_READY
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_OVF
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_PCINT0
IRQ __vector_PCINT1
IRQ __vector_PCINT2
IRQ __vector_PCINT3
IRQ __vector_WDT
IRQ __vector_TIMER2_COMPA
IRQ __vector_TIMER2_COMPB
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_COMPB
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART0_RX
IRQ __vector_USART0_UDRE
IRQ __vector_USART0_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_TWI
IRQ __vector_SPM_READY
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_OVF

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from ATmega1284P.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x20000;
__ram_start = 0x100;
__ram_size = 0x4000;
__num_isrs = 35;

View File

@@ -0,0 +1,94 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from ATmega1284P.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_PCINT0
jmp __vector_PCINT1
jmp __vector_PCINT2
jmp __vector_PCINT3
jmp __vector_WDT
jmp __vector_TIMER2_COMPA
jmp __vector_TIMER2_COMPB
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMPA
jmp __vector_TIMER0_COMPB
jmp __vector_TIMER0_OVF
jmp __vector_SPI_STC
jmp __vector_USART0_RX
jmp __vector_USART0_UDRE
jmp __vector_USART0_TX
jmp __vector_ANALOG_COMP
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_TWI
jmp __vector_SPM_READY
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_OVF
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_PCINT0
IRQ __vector_PCINT1
IRQ __vector_PCINT2
IRQ __vector_PCINT3
IRQ __vector_WDT
IRQ __vector_TIMER2_COMPA
IRQ __vector_TIMER2_COMPB
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_COMPB
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART0_RX
IRQ __vector_USART0_UDRE
IRQ __vector_USART0_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_TWI
IRQ __vector_SPM_READY
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_OVF

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from ATmega1284RFR2.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x20000;
__ram_start = 0x200;
__ram_size = 0x4000;
__num_isrs = 71;

View File

@@ -0,0 +1,172 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from ATmega1284RFR2.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_PCINT0
jmp __vector_PCINT1
jmp __vector_PCINT2
jmp __vector_WDT
jmp __vector_TIMER2_COMPA
jmp __vector_TIMER2_COMPB
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMPA
jmp __vector_TIMER0_COMPB
jmp __vector_TIMER0_OVF
jmp __vector_SPI_STC
jmp __vector_USART0_RX
jmp __vector_USART0_UDRE
jmp __vector_USART0_TX
jmp __vector_ANALOG_COMP
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_COMPC
jmp __vector_TIMER3_OVF
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_TWI
jmp __vector_SPM_READY
jmp __vector_TIMER4_CAPT
jmp __vector_TIMER4_COMPA
jmp __vector_TIMER4_COMPB
jmp __vector_TIMER4_COMPC
jmp __vector_TIMER4_OVF
jmp __vector_TIMER5_CAPT
jmp __vector_TIMER5_COMPA
jmp __vector_TIMER5_COMPB
jmp __vector_TIMER5_COMPC
jmp __vector_TIMER5_OVF
jmp __vector_default
jmp __vector_default
jmp __vector_default
jmp __vector_default
jmp __vector_default
jmp __vector_default
jmp __vector_TRX24_PLL_LOCK
jmp __vector_TRX24_PLL_UNLOCK
jmp __vector_TRX24_RX_START
jmp __vector_TRX24_RX_END
jmp __vector_TRX24_CCA_ED_DONE
jmp __vector_TRX24_XAH_AMI
jmp __vector_TRX24_TX_END
jmp __vector_TRX24_AWAKE
jmp __vector_SCNT_CMP1
jmp __vector_SCNT_CMP2
jmp __vector_SCNT_CMP3
jmp __vector_SCNT_OVFL
jmp __vector_SCNT_BACKOFF
jmp __vector_AES_READY
jmp __vector_BAT_LOW
jmp __vector_TRX24_TX_START
jmp __vector_TRX24_AMI0
jmp __vector_TRX24_AMI1
jmp __vector_TRX24_AMI2
jmp __vector_TRX24_AMI3
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_PCINT0
IRQ __vector_PCINT1
IRQ __vector_PCINT2
IRQ __vector_WDT
IRQ __vector_TIMER2_COMPA
IRQ __vector_TIMER2_COMPB
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_COMPB
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART0_RX
IRQ __vector_USART0_UDRE
IRQ __vector_USART0_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_COMPC
IRQ __vector_TIMER3_OVF
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_TWI
IRQ __vector_SPM_READY
IRQ __vector_TIMER4_CAPT
IRQ __vector_TIMER4_COMPA
IRQ __vector_TIMER4_COMPB
IRQ __vector_TIMER4_COMPC
IRQ __vector_TIMER4_OVF
IRQ __vector_TIMER5_CAPT
IRQ __vector_TIMER5_COMPA
IRQ __vector_TIMER5_COMPB
IRQ __vector_TIMER5_COMPC
IRQ __vector_TIMER5_OVF
IRQ __vector_TRX24_PLL_LOCK
IRQ __vector_TRX24_PLL_UNLOCK
IRQ __vector_TRX24_RX_START
IRQ __vector_TRX24_RX_END
IRQ __vector_TRX24_CCA_ED_DONE
IRQ __vector_TRX24_XAH_AMI
IRQ __vector_TRX24_TX_END
IRQ __vector_TRX24_AWAKE
IRQ __vector_SCNT_CMP1
IRQ __vector_SCNT_CMP2
IRQ __vector_SCNT_CMP3
IRQ __vector_SCNT_OVFL
IRQ __vector_SCNT_BACKOFF
IRQ __vector_AES_READY
IRQ __vector_BAT_LOW
IRQ __vector_TRX24_TX_START
IRQ __vector_TRX24_AMI0
IRQ __vector_TRX24_AMI1
IRQ __vector_TRX24_AMI2
IRQ __vector_TRX24_AMI3

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from ATmega128A.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x20000;
__ram_start = 0x100;
__ram_size = 0x1000;
__num_isrs = 35;

View File

@@ -0,0 +1,94 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from ATmega128A.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_TIMER2_COMP
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMP
jmp __vector_TIMER0_OVF
jmp __vector_SPI_STC
jmp __vector_USART0_RX
jmp __vector_USART0_UDRE
jmp __vector_USART0_TX
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_ANALOG_COMP
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_COMPC
jmp __vector_TIMER3_OVF
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_TWI
jmp __vector_SPM_READY
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_TIMER2_COMP
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMP
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART0_RX
IRQ __vector_USART0_UDRE
IRQ __vector_USART0_TX
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_ANALOG_COMP
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_COMPC
IRQ __vector_TIMER3_OVF
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_TWI
IRQ __vector_SPM_READY

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from ATmega128RFA1.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x20000;
__ram_start = 0x200;
__ram_size = 0x4000;
__num_isrs = 72;

View File

@@ -0,0 +1,168 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from ATmega128RFA1.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_PCINT0
jmp __vector_PCINT1
jmp __vector_PCINT2
jmp __vector_WDT
jmp __vector_TIMER2_COMPA
jmp __vector_TIMER2_COMPB
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMPA
jmp __vector_TIMER0_COMPB
jmp __vector_TIMER0_OVF
jmp __vector_SPI_STC
jmp __vector_USART0_RX
jmp __vector_USART0_UDRE
jmp __vector_USART0_TX
jmp __vector_ANALOG_COMP
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_COMPC
jmp __vector_TIMER3_OVF
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_TWI
jmp __vector_SPM_READY
jmp __vector_TIMER4_CAPT
jmp __vector_TIMER4_COMPA
jmp __vector_TIMER4_COMPB
jmp __vector_TIMER4_COMPC
jmp __vector_TIMER4_OVF
jmp __vector_TIMER5_CAPT
jmp __vector_TIMER5_COMPA
jmp __vector_TIMER5_COMPB
jmp __vector_TIMER5_COMPC
jmp __vector_TIMER5_OVF
jmp __vector_USART2_RX
jmp __vector_USART2_UDRE
jmp __vector_USART2_TX
jmp __vector_USART3_RX
jmp __vector_USART3_UDRE
jmp __vector_USART3_TX
jmp __vector_TRX24_PLL_LOCK
jmp __vector_TRX24_PLL_UNLOCK
jmp __vector_TRX24_RX_START
jmp __vector_TRX24_RX_END
jmp __vector_TRX24_CCA_ED_DONE
jmp __vector_TRX24_XAH_AMI
jmp __vector_TRX24_TX_END
jmp __vector_TRX24_AWAKE
jmp __vector_SCNT_CMP1
jmp __vector_SCNT_CMP2
jmp __vector_SCNT_CMP3
jmp __vector_SCNT_OVFL
jmp __vector_SCNT_BACKOFF
jmp __vector_AES_READY
jmp __vector_BAT_LOW
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_PCINT0
IRQ __vector_PCINT1
IRQ __vector_PCINT2
IRQ __vector_WDT
IRQ __vector_TIMER2_COMPA
IRQ __vector_TIMER2_COMPB
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_COMPB
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART0_RX
IRQ __vector_USART0_UDRE
IRQ __vector_USART0_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_COMPC
IRQ __vector_TIMER3_OVF
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_TWI
IRQ __vector_SPM_READY
IRQ __vector_TIMER4_CAPT
IRQ __vector_TIMER4_COMPA
IRQ __vector_TIMER4_COMPB
IRQ __vector_TIMER4_COMPC
IRQ __vector_TIMER4_OVF
IRQ __vector_TIMER5_CAPT
IRQ __vector_TIMER5_COMPA
IRQ __vector_TIMER5_COMPB
IRQ __vector_TIMER5_COMPC
IRQ __vector_TIMER5_OVF
IRQ __vector_USART2_RX
IRQ __vector_USART2_UDRE
IRQ __vector_USART2_TX
IRQ __vector_USART3_RX
IRQ __vector_USART3_UDRE
IRQ __vector_USART3_TX
IRQ __vector_TRX24_PLL_LOCK
IRQ __vector_TRX24_PLL_UNLOCK
IRQ __vector_TRX24_RX_START
IRQ __vector_TRX24_RX_END
IRQ __vector_TRX24_CCA_ED_DONE
IRQ __vector_TRX24_XAH_AMI
IRQ __vector_TRX24_TX_END
IRQ __vector_TRX24_AWAKE
IRQ __vector_SCNT_CMP1
IRQ __vector_SCNT_CMP2
IRQ __vector_SCNT_CMP3
IRQ __vector_SCNT_OVFL
IRQ __vector_SCNT_BACKOFF
IRQ __vector_AES_READY
IRQ __vector_BAT_LOW

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from ATmega128RFR2.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x20000;
__ram_start = 0x200;
__ram_size = 0x4000;
__num_isrs = 71;

View File

@@ -0,0 +1,172 @@
; Automatically generated file. DO NOT EDIT.
; Generated by gen-device-avr.go from ATmega128RFR2.atdf, see http://packs.download.atmel.com/
; This is the default handler for interrupts, if triggered but not defined.
; Sleep inside so that an accidentally triggered interrupt won't drain the
; battery of a battery-powered device.
.section .text.__vector_default
.global __vector_default
__vector_default:
sleep
rjmp __vector_default
; Avoid the need for repeated .weak and .set instructions.
.macro IRQ handler
.weak \handler
.set \handler, __vector_default
.endm
; The interrupt vector of this device. Must be placed at address 0 by the linker.
.section .vectors, "a", %progbits
.global __vectors
jmp __vector_RESET
jmp __vector_INT0
jmp __vector_INT1
jmp __vector_INT2
jmp __vector_INT3
jmp __vector_INT4
jmp __vector_INT5
jmp __vector_INT6
jmp __vector_INT7
jmp __vector_PCINT0
jmp __vector_PCINT1
jmp __vector_PCINT2
jmp __vector_WDT
jmp __vector_TIMER2_COMPA
jmp __vector_TIMER2_COMPB
jmp __vector_TIMER2_OVF
jmp __vector_TIMER1_CAPT
jmp __vector_TIMER1_COMPA
jmp __vector_TIMER1_COMPB
jmp __vector_TIMER1_COMPC
jmp __vector_TIMER1_OVF
jmp __vector_TIMER0_COMPA
jmp __vector_TIMER0_COMPB
jmp __vector_TIMER0_OVF
jmp __vector_SPI_STC
jmp __vector_USART0_RX
jmp __vector_USART0_UDRE
jmp __vector_USART0_TX
jmp __vector_ANALOG_COMP
jmp __vector_ADC
jmp __vector_EE_READY
jmp __vector_TIMER3_CAPT
jmp __vector_TIMER3_COMPA
jmp __vector_TIMER3_COMPB
jmp __vector_TIMER3_COMPC
jmp __vector_TIMER3_OVF
jmp __vector_USART1_RX
jmp __vector_USART1_UDRE
jmp __vector_USART1_TX
jmp __vector_TWI
jmp __vector_SPM_READY
jmp __vector_TIMER4_CAPT
jmp __vector_TIMER4_COMPA
jmp __vector_TIMER4_COMPB
jmp __vector_TIMER4_COMPC
jmp __vector_TIMER4_OVF
jmp __vector_TIMER5_CAPT
jmp __vector_TIMER5_COMPA
jmp __vector_TIMER5_COMPB
jmp __vector_TIMER5_COMPC
jmp __vector_TIMER5_OVF
jmp __vector_default
jmp __vector_default
jmp __vector_default
jmp __vector_default
jmp __vector_default
jmp __vector_default
jmp __vector_TRX24_PLL_LOCK
jmp __vector_TRX24_PLL_UNLOCK
jmp __vector_TRX24_RX_START
jmp __vector_TRX24_RX_END
jmp __vector_TRX24_CCA_ED_DONE
jmp __vector_TRX24_XAH_AMI
jmp __vector_TRX24_TX_END
jmp __vector_TRX24_AWAKE
jmp __vector_SCNT_CMP1
jmp __vector_SCNT_CMP2
jmp __vector_SCNT_CMP3
jmp __vector_SCNT_OVFL
jmp __vector_SCNT_BACKOFF
jmp __vector_AES_READY
jmp __vector_BAT_LOW
jmp __vector_TRX24_TX_START
jmp __vector_TRX24_AMI0
jmp __vector_TRX24_AMI1
jmp __vector_TRX24_AMI2
jmp __vector_TRX24_AMI3
; Define default implementations for interrupts, redirecting to
; __vector_default when not implemented.
IRQ __vector_RESET
IRQ __vector_INT0
IRQ __vector_INT1
IRQ __vector_INT2
IRQ __vector_INT3
IRQ __vector_INT4
IRQ __vector_INT5
IRQ __vector_INT6
IRQ __vector_INT7
IRQ __vector_PCINT0
IRQ __vector_PCINT1
IRQ __vector_PCINT2
IRQ __vector_WDT
IRQ __vector_TIMER2_COMPA
IRQ __vector_TIMER2_COMPB
IRQ __vector_TIMER2_OVF
IRQ __vector_TIMER1_CAPT
IRQ __vector_TIMER1_COMPA
IRQ __vector_TIMER1_COMPB
IRQ __vector_TIMER1_COMPC
IRQ __vector_TIMER1_OVF
IRQ __vector_TIMER0_COMPA
IRQ __vector_TIMER0_COMPB
IRQ __vector_TIMER0_OVF
IRQ __vector_SPI_STC
IRQ __vector_USART0_RX
IRQ __vector_USART0_UDRE
IRQ __vector_USART0_TX
IRQ __vector_ANALOG_COMP
IRQ __vector_ADC
IRQ __vector_EE_READY
IRQ __vector_TIMER3_CAPT
IRQ __vector_TIMER3_COMPA
IRQ __vector_TIMER3_COMPB
IRQ __vector_TIMER3_COMPC
IRQ __vector_TIMER3_OVF
IRQ __vector_USART1_RX
IRQ __vector_USART1_UDRE
IRQ __vector_USART1_TX
IRQ __vector_TWI
IRQ __vector_SPM_READY
IRQ __vector_TIMER4_CAPT
IRQ __vector_TIMER4_COMPA
IRQ __vector_TIMER4_COMPB
IRQ __vector_TIMER4_COMPC
IRQ __vector_TIMER4_OVF
IRQ __vector_TIMER5_CAPT
IRQ __vector_TIMER5_COMPA
IRQ __vector_TIMER5_COMPB
IRQ __vector_TIMER5_COMPC
IRQ __vector_TIMER5_OVF
IRQ __vector_TRX24_PLL_LOCK
IRQ __vector_TRX24_PLL_UNLOCK
IRQ __vector_TRX24_RX_START
IRQ __vector_TRX24_RX_END
IRQ __vector_TRX24_CCA_ED_DONE
IRQ __vector_TRX24_XAH_AMI
IRQ __vector_TRX24_TX_END
IRQ __vector_TRX24_AWAKE
IRQ __vector_SCNT_CMP1
IRQ __vector_SCNT_CMP2
IRQ __vector_SCNT_CMP3
IRQ __vector_SCNT_OVFL
IRQ __vector_SCNT_BACKOFF
IRQ __vector_AES_READY
IRQ __vector_BAT_LOW
IRQ __vector_TRX24_TX_START
IRQ __vector_TRX24_AMI0
IRQ __vector_TRX24_AMI1
IRQ __vector_TRX24_AMI2
IRQ __vector_TRX24_AMI3

View File

@@ -0,0 +1,7 @@
/* Automatically generated file. DO NOT EDIT. */
/* Generated by gen-device-avr.go from ATmega16.atdf, see http://packs.download.atmel.com/ */
__flash_size = 0x4000;
__ram_start = 0x60;
__ram_size = 0x400;
__num_isrs = 21;

Some files were not shown because too many files have changed in this diff Show More