Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a generic AVR target: avr-none #131651

Merged
merged 2 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1990,6 +1990,7 @@ fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor)
if let Some(args) = sess.target.pre_link_args.get(&flavor) {
cmd.verbatim_args(args.iter().map(Deref::deref));
}

cmd.verbatim_args(&sess.opts.unstable_opts.pre_link_args);
}

Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_codegen_ssa/src/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ pub(crate) fn get_linker<'a>(
hinted_static: None,
is_ld: cc == Cc::No,
is_gnu: flavor.is_gnu(),
uses_lld: flavor.uses_lld(),
}) as Box<dyn Linker>,
LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>,
LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box<dyn Linker>,
Expand Down Expand Up @@ -361,6 +362,7 @@ struct GccLinker<'a> {
// Link as ld
is_ld: bool,
is_gnu: bool,
uses_lld: bool,
}

impl<'a> GccLinker<'a> {
Expand Down Expand Up @@ -552,6 +554,7 @@ impl<'a> Linker for GccLinker<'a> {
self.link_args(&["--entry", "_initialize"]);
}
}

// VxWorks compiler driver introduced `--static-crt` flag specifically for rustc,
// it switches linking for libc and similar system libraries to static without using
// any `#[link]` attributes in the `libc` crate, see #72782 for details.
Expand All @@ -567,6 +570,15 @@ impl<'a> Linker for GccLinker<'a> {
{
self.cc_arg("--static-crt");
}

// avr-none doesn't have default ISA, users must specify which specific
// CPU (well, microcontroller) they are targetting using `-Ctarget-cpu`.
//
// Currently this makes sense only when using avr-gcc as a linker, since
// it brings a couple of hand-written important intrinsics from libgcc.
if self.sess.target.arch == "avr" && !self.uses_lld {
self.verbatim_arg(format!("-mmcu={}", self.target_cpu));
}
}

fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,5 @@
use object::elf;

use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions};

/// A base target for AVR devices using the GNU toolchain.
///
/// Requires GNU avr-gcc and avr-binutils on the host system.
/// FIXME: Remove the second parameter when const string concatenation is possible.
pub(crate) fn target(target_cpu: &'static str, mmcu: &'static str) -> Target {
Target {
arch: "avr".into(),
metadata: crate::spec::TargetMetadata {
description: None,
tier: None,
host_tools: None,
std: None,
},
data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".into(),
llvm_target: "avr-unknown-unknown".into(),
pointer_width: 16,
options: TargetOptions {
env: "gnu".into(),

c_int_width: "16".into(),
cpu: target_cpu.into(),
exe_suffix: ".elf".into(),

linker: Some("avr-gcc".into()),
eh_frame_header: false,
pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[mmcu]),
late_link_args: TargetOptions::link_args(
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
&["-lgcc"],
),
max_atomic_width: Some(16),
atomic_cas: false,
relocation_model: RelocModel::Static,
..TargetOptions::default()
},
}
}

/// Resolve the value of the EF_AVR_ARCH field for AVR ELF files, given the
/// name of the target CPU / MCU.
///
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_target/src/spec/base/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pub(crate) mod aix;
pub(crate) mod android;
pub(crate) mod apple;
pub(crate) mod avr_gnu;
pub(crate) mod avr;
pub(crate) mod bpf;
pub(crate) mod cygwin;
pub(crate) mod dragonfly;
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub mod crt_objects;
mod base;
mod json;

pub use base::avr_gnu::ef_avr_arch;
pub use base::avr::ef_avr_arch;

/// Linker is called through a C/C++ compiler.
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
Expand Down Expand Up @@ -1797,7 +1797,7 @@ supported_targets! {
("riscv64gc-unknown-fuchsia", riscv64gc_unknown_fuchsia),
("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia),

("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328),
("avr-none", avr_none),

("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc),

Expand Down Expand Up @@ -3062,7 +3062,10 @@ impl Target {
&self.post_link_args,
] {
for (&flavor, flavor_args) in args {
check!(!flavor_args.is_empty(), "linker flavor args must not be empty");
check!(
!flavor_args.is_empty() || self.arch == "avr",
"linker flavor args must not be empty"
);
// Check that flavors mentioned in link args are compatible with the default flavor.
match self.linker_flavor {
LinkerFlavor::Gnu(..) => {
Expand Down
32 changes: 32 additions & 0 deletions compiler/rustc_target/src/spec/targets/avr_none.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions};

pub(crate) fn target() -> Target {
Target {
arch: "avr".into(),
metadata: crate::spec::TargetMetadata {
description: None,
tier: None,
host_tools: None,
std: None,
},
data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".into(),
llvm_target: "avr-unknown-unknown".into(),
pointer_width: 16,
options: TargetOptions {
c_int_width: "16".into(),
exe_suffix: ".elf".into(),
linker: Some("avr-gcc".into()),
eh_frame_header: false,
pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[]),
late_link_args: TargetOptions::link_args(
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
&["-lgcc"],
),
max_atomic_width: Some(16),
atomic_cas: false,
relocation_model: RelocModel::Static,
need_explicit_cpu: true,
..TargetOptions::default()
},
}
}

This file was deleted.

2 changes: 1 addition & 1 deletion src/doc/rustc/src/platform-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ target | std | host | notes
[`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | | Bare Armv8-R, hardfloat
[`armv7a-nuttx-eabi`](platform-support/nuttx.md) | ✓ | | ARMv7-A with NuttX
[`armv7a-nuttx-eabihf`](platform-support/nuttx.md) | ✓ | | ARMv7-A with NuttX, hardfloat
`avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core`
`avr-none` | * | | AVR; requires `-Zbuild-std=core` and `-Ctarget-cpu=...`
`bpfeb-unknown-none` | * | | BPF (big endian)
`bpfel-unknown-none` | * | | BPF (little endian)
`csky-unknown-linux-gnuabiv2` | ✓ | | C-SKY abiv2 Linux (little endian)
Expand Down
81 changes: 81 additions & 0 deletions src/doc/rustc/src/platform-support/avr-none.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# `avr-none`

Series of microcontrollers from Atmel: ATmega8, ATmega328p etc.

**Tier: 3**

## Target maintainers

- [Patryk Wychowaniec](https://github.com/Patryk27) <pwychowaniec@pm.me>

## Requirements

This target is only cross-compiled; x86-64 Linux, x86-64 macOS and aarch64 macOS
hosts are confirmed to work, but in principle any machine able to run rustc and
avr-gcc should be good.

Compiling for this target requires `avr-gcc` installed, because a couple of
intrinsics (like 32-bit multiplication) rely on [`libgcc`](https://github.com/gcc-mirror/gcc/blob/3269a722b7a03613e9c4e2862bc5088c4a17cc11/libgcc/config/avr/lib1funcs.S)
and can't be provided through `compiler-builtins` yet. This is a limitation that
[we hope to lift in the future](https://github.com/rust-lang/compiler-builtins/issues/711).

You'll also need to setup the `.cargo/config` file - see below for details.

## Building the target

Rust comes with AVR support enabled, you don't have to rebuild the compiler.

## Building Rust programs

Install `avr-gcc`:

```console
# Ubuntu:
$ sudo apt-get install gcc-avr

# Mac:
$ brew tap osx-cross/avr && brew install avr-gcc

# NixOS (takes a couple of minutes, since it's not provided through Hydra):
$ nix shell nixpkgs#pkgsCross.avr.buildPackages.gcc11
```

... setup `.cargo/config` for your project:

```toml
[build]
target = "avr-none"
rustflags = ["-C", "target-cpu=atmega328p"]

[unstable]
build-std = ["core"]
```

... and then simply run:

```console
$ cargo build --release
```

The final binary will be placed into
`./target/avr-none/release/your-project.elf`.

Note that since AVRs have rather small amounts of registers, ROM and RAM, it's
recommended to always use `--release` to avoid running out of space.

Also, please note that specifying `-C target-cpu` is required - here's a list of
the possible variants:

https://github.com/llvm/llvm-project/blob/093d4db2f3c874d4683fb01194b00dbb20e5c713/clang/lib/Basic/Targets/AVR.cpp#L32

## Testing

You can use [`simavr`](https://github.com/buserror/simavr) to emulate the
resulting firmware on your machine:

```console
$ simavr -m atmega328p ./target/avr-none/release/your-project.elf
```

Alternatively, if you want to write a couple of actual `#[test]`s, you can use
[`avr-tester`](https://github.com/Patryk27/avr-tester).
3 changes: 3 additions & 0 deletions src/tools/compiletest/src/header/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,10 @@ fn profiler_runtime() {
#[test]
fn asm_support() {
let asms = [
#[cfg(bootstrap)]
("avr-unknown-gnu-atmega328", false),
#[cfg(not(bootstrap))]
("avr-none", false),
("i686-unknown-netbsd", true),
("riscv32gc-unknown-linux-gnu", true),
("riscv64imac-unknown-none-elf", true),
Expand Down
7 changes: 7 additions & 0 deletions src/tools/run-make-support/src/external_deps/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,13 @@ impl Rustc {
self
}

/// Specify the target CPU.
pub fn target_cpu<S: AsRef<str>>(&mut self, target_cpu: S) -> &mut Self {
let target_cpu = target_cpu.as_ref();
self.cmd.arg(format!("-Ctarget-cpu={target_cpu}"));
self
}

/// Specify the crate type.
pub fn crate_type(&mut self, crate_type: &str) -> &mut Self {
self.cmd.arg("--crate-type");
Expand Down
2 changes: 1 addition & 1 deletion tests/assembly/asm/avr-modifiers.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ add-core-stubs
//@ assembly-output: emit-asm
//@ compile-flags: --target avr-unknown-gnu-atmega328
//@ compile-flags: --target avr-none -C target-cpu=atmega328p
//@ needs-llvm-components: avr

#![feature(no_core, asm_experimental_arch)]
Expand Down
2 changes: 1 addition & 1 deletion tests/assembly/asm/avr-types.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ add-core-stubs
//@ assembly-output: emit-asm
//@ compile-flags: --target avr-unknown-gnu-atmega328
//@ compile-flags: --target avr-none -C target-cpu=atmega328p
//@ needs-llvm-components: avr

#![feature(no_core, asm_experimental_arch)]
Expand Down
6 changes: 3 additions & 3 deletions tests/assembly/targets/targets-pe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
//@ revisions: arm64ec_pc_windows_msvc
//@ [arm64ec_pc_windows_msvc] compile-flags: --target arm64ec-pc-windows-msvc
//@ [arm64ec_pc_windows_msvc] needs-llvm-components: aarch64
//@ revisions: avr_unknown_gnu_atmega328
//@ [avr_unknown_gnu_atmega328] compile-flags: --target avr-unknown-gnu-atmega328
//@ [avr_unknown_gnu_atmega328] needs-llvm-components: avr
//@ revisions: avr_none
//@ [avr_none] compile-flags: --target avr-none -C target-cpu=atmega328p
//@ [avr_none] needs-llvm-components: avr
//@ revisions: bpfeb_unknown_none
//@ [bpfeb_unknown_none] compile-flags: --target bpfeb-unknown-none
//@ [bpfeb_unknown_none] needs-llvm-components: bpf
Expand Down
2 changes: 1 addition & 1 deletion tests/codegen/asm/avr-clobbers.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ add-core-stubs
//@ assembly-output: emit-asm
//@ compile-flags: --target avr-unknown-gnu-atmega328
//@ compile-flags: --target avr-none -C target-cpu=atmega328p
//@ needs-llvm-components: avr

#![crate_type = "rlib"]
Expand Down
2 changes: 1 addition & 1 deletion tests/codegen/avr/avr-func-addrspace.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ compile-flags: -Copt-level=3 --target=avr-unknown-gnu-atmega328 --crate-type=rlib -C panic=abort
//@ compile-flags: -Copt-level=3 --target=avr-none -C target-cpu=atmega328p --crate-type=rlib -C panic=abort
//@ needs-llvm-components: avr

// This test validates that function pointers can be stored in global variables
Expand Down
8 changes: 7 additions & 1 deletion tests/run-make/avr-rjmp-offset/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ fn main() {
.input("avr-rjmp-offsets.rs")
.opt_level("s")
.panic("abort")
.target("avr-unknown-gnu-atmega328")
.target("avr-none")
// rust-lld has some troubles understanding the -mmcu flag, so for the
// time being let's tell rustc to emit binary that's compatible with the
// target CPU that lld defaults to, i.e. just `avr` (that's simply the
// minimal common instruction set across all AVRs)
.target_cpu("avr")
// normally one links with `avr-gcc`, but this is not available in CI,
// hence this test diverges from the default behavior to enable linking
// at all, which is necessary for the test (to resolve the labels). To
Expand All @@ -49,6 +54,7 @@ fn main() {
// of the Rust compiler did produce a label `rjmp .-4` (misses the first
// instruction in the loop).
assert!(disassembly.contains("<main>"), "no main function in output");

disassembly
.trim()
.lines()
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/feature-gates/feature-gate-abi-avr-interrupt.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@ needs-llvm-components: avr
//@ compile-flags: --target=avr-unknown-gnu-atmega328 --crate-type=rlib
//@ compile-flags: --target=avr-none -C target-cpu=atmega328p --crate-type=rlib
#![no_core]
#![feature(no_core, lang_items)]
#[lang="sized"]
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/repr/16-bit-repr-c-enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//@ revisions: avr msp430
//
//@ [avr] needs-llvm-components: avr
//@ [avr] compile-flags: --target=avr-unknown-gnu-atmega328 --crate-type=rlib
//@ [avr] compile-flags: --target=avr-none -C target-cpu=atmega328p --crate-type=rlib
//@ [msp430] needs-llvm-components: msp430
//@ [msp430] compile-flags: --target=msp430-none-elf --crate-type=rlib
#![feature(no_core, lang_items, intrinsics, staged_api, rustc_attrs)]
Expand Down
Loading