Skip to content

Commit

Permalink
Merge pull request #243 from rust-embedded/rv32e-compat-asm
Browse files Browse the repository at this point in the history
`riscv-rt`: compatibility with RV32E and RV64E
  • Loading branch information
romancardenas authored Dec 12, 2024
2 parents ca4850a + da3b8ac commit 3cd758b
Show file tree
Hide file tree
Showing 18 changed files with 1,074 additions and 268 deletions.
20 changes: 15 additions & 5 deletions .github/workflows/changelog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ jobs:
- 'riscv-rt/**'
riscv-semihosting:
- 'riscv-semihosting/**'
riscv-target-parser:
- 'riscv-target-parser/**'
- name: Check for CHANGELOG.md (riscv)
if: steps.changes.outputs.riscv == 'true'
Expand All @@ -43,7 +45,15 @@ jobs:
changeLogPath: ./riscv-pac/CHANGELOG.md
skipLabels: 'skip changelog'
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-pac/CHANGELOG.md file.'


- name: Check for CHANGELOG.md (riscv-peripheral)
if: steps.changes.outputs.riscv-peripheral == 'true'
uses: dangoslen/changelog-enforcer@v3
with:
changeLogPath: ./riscv-peripheral/CHANGELOG.md
skipLabels: 'skip changelog'
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-peripheral/CHANGELOG.md file.'

- name: Check for CHANGELOG.md (riscv-rt)
if: steps.changes.outputs.riscv-rt == 'true'
uses: dangoslen/changelog-enforcer@v3
Expand All @@ -60,10 +70,10 @@ jobs:
skipLabels: 'skip changelog'
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-semihosting/CHANGELOG.md file.'

- name: Check for CHANGELOG.md (riscv-peripheral)
if: steps.changes.outputs.riscv-peripheral == 'true'
- name: Check for CHANGELOG.md (riscv-target-parser)
if: steps.changes.outputs.riscv-target-parser == 'true'
uses: dangoslen/changelog-enforcer@v3
with:
changeLogPath: ./riscv-peripheral/CHANGELOG.md
changeLogPath: ./riscv-target-parser/CHANGELOG.md
skipLabels: 'skip changelog'
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-peripheral/CHANGELOG.md file.'
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-target-parser/CHANGELOG.md file.'
7 changes: 7 additions & 0 deletions .github/workflows/riscv-rt.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ jobs:
toolchain: [ stable, nightly, 1.61.0 ]
target:
- riscv32i-unknown-none-elf
- riscv32im-unknown-none-elf
- riscv32imc-unknown-none-elf
- riscv32imac-unknown-none-elf
- riscv32imafc-unknown-none-elf
- riscv64imac-unknown-none-elf
- riscv64gc-unknown-none-elf
example:
Expand All @@ -25,6 +27,11 @@ jobs:
# Nightly is only for reference and allowed to fail
- toolchain: nightly
experimental: true
exclude:
- toolchain: 1.61.0
target: riscv32im-unknown-none-elf
- toolchain: 1.61.0
target: riscv32imafc-unknown-none-elf
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.experimental || false }}
steps:
Expand Down
37 changes: 37 additions & 0 deletions .github/workflows/riscv-target-parser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
on:
push:
branches: [ master ]
pull_request:
merge_group:

name: Run tests (riscv-target-parser)

jobs:
run-tests:
strategy:
matrix:
os: [ macos-latest, ubuntu-latest, windows-latest ]
toolchain: [ stable, nightly, 1.61.0 ]
include:
# Nightly is only for reference and allowed to fail
- rust: nightly
experimental: true
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental || false }}
steps:
- uses: actions/checkout@v4
- name: Update Rust toolchain
run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
- name: Build
run: cargo build --package riscv-target-parser
- name: Run tests
run: cargo test --package riscv-target-parser

# Job to check that all the builds succeeded
tests-check:
needs:
- run-tests
runs-on: ubuntu-latest
if: always()
steps:
- run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ members = [
"riscv-peripheral",
"riscv-rt",
"riscv-semihosting",
"riscv-target-parser",
"tests",
]
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This repository contains various crates useful for writing Rust programs on RISC
* [`riscv-peripheral`]: Interfaces for standard RISC-V peripherals
* [`riscv-rt`]: Startup code and interrupt handling
* [`riscv-semihosting`]: Semihosting for RISC-V processors
* [`riscv-target-parser`]: Utility crate for parsing RISC-V targets in build scripts

This project is developed and maintained by the [RISC-V team][team].

Expand All @@ -27,5 +28,6 @@ to intervene to uphold that code of conduct.
[`riscv-peripheral`]: https://crates.io/crates/riscv-peripheral
[`riscv-rt`]: https://crates.io/crates/riscv-rt
[`riscv-semihosting`]: https://crates.io/crates/riscv-semihosting
[`riscv-target-parser`]: https://crates.io/crates/riscv-target-parser
[team]: https://github.com/rust-embedded/wg#the-risc-v-team
[CoC]: CODE_OF_CONDUCT.md
8 changes: 8 additions & 0 deletions riscv-rt/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Changed

- Limit rustc cfg flags to `riscvi`, `riscvm`, `riscvf`, and `riscvd`.
- Temporary use of `RISCV_RT_LLVM_ARCH_PATCH` environment variable to include the
temporary patch required for avoid LLVM spurious errors.
- `riscv-rt` now use the `RISCV_RT_BASE_ISA` environment variable to configure the behavior
of `riscv-rt-macros` depending on aspects of the base ISA (e.g., RV32I or RV32E).
- Use `riscv-target-parser` in build script to identify target-specific configurations.
- Add documentation to trap frame fields.
- Avoid using `t3`+ in startup assembly to ensure compatibility with RVE.
- `link.x.in`: remove references to `eh_frame`.
- Rename start/end section symbols to align with `cortex-m-rt`:
- `_stext`: it remains, as linker files can modify it.
Expand Down
5 changes: 4 additions & 1 deletion riscv-rt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ targets = [
"riscv64imac-unknown-none-elf", "riscv64gc-unknown-none-elf",
]

[build-dependencies]
riscv-target-parser = { path = "../riscv-target-parser", version = "0.1.0" }

[dependencies]
riscv = { path = "../riscv", version = "0.12.0" }
riscv-pac = { path = "../riscv-pac", version = "0.2.0" }
riscv-rt-macros = { path = "macros", version = "0.2.2" }
riscv-rt-macros = { path = "macros", version = "0.3.0" }

[dev-dependencies]
panic-halt = "1.0.0"
Expand Down
115 changes: 31 additions & 84 deletions riscv-rt/build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// NOTE: Adapted from cortex-m/build.rs

use std::{collections::HashSet, env, fs, io, path::PathBuf};
use riscv_target_parser::RiscvTarget;
use std::{env, fs, io, path::PathBuf};

// List of all possible RISC-V configurations to check for in risv-rt
const RISCV_CFG: [&str; 4] = ["riscvi", "riscvm", "riscvf", "riscvd"];

fn add_linker_script(arch_width: u32) -> io::Result<()> {
// Read the file to a string and replace all occurrences of ${ARCH_WIDTH} with the arch width
Expand All @@ -17,96 +21,39 @@ fn add_linker_script(arch_width: u32) -> io::Result<()> {
Ok(())
}

/// Parse the target RISC-V architecture and returns its bit width and the extension set
fn parse_target(target: &str, cargo_flags: &str) -> (u32, HashSet<char>) {
// isolate bit width and extensions from the rest of the target information
let arch = target
.trim_start_matches("riscv")
.split('-')
.next()
.unwrap();

let bits = arch
.chars()
.take_while(|c| c.is_ascii_digit())
.collect::<String>()
.parse::<u32>()
.unwrap();

let mut extensions: HashSet<char> = arch.chars().skip_while(|c| c.is_ascii_digit()).collect();
// expand the 'g' shorthand extension
if extensions.contains(&'g') {
extensions.insert('i');
extensions.insert('m');
extensions.insert('a');
extensions.insert('f');
extensions.insert('d');
}

let cargo_flags = cargo_flags
.split(0x1fu8 as char)
.filter(|arg| !arg.is_empty());

cargo_flags
.filter(|k| k.starts_with("target-feature="))
.flat_map(|str| {
let flags = str.split('=').collect::<Vec<&str>>()[1];
flags.split(',')
})
.for_each(|feature| {
let chars = feature.chars().collect::<Vec<char>>();
match chars[0] {
'+' => {
extensions.insert(chars[1]);
}
'-' => {
extensions.remove(&chars[1]);
}
_ => {
panic!("Unsupported target feature operation");
}
}
});

(bits, extensions)
}

fn main() {
println!("cargo:rustc-check-cfg=cfg(riscv)");
println!("cargo:rustc-check-cfg=cfg(riscv32)");
println!("cargo:rustc-check-cfg=cfg(riscv64)");
for ext in ['i', 'e', 'm', 'a', 'f', 'd', 'g', 'c'] {
println!("cargo:rustc-check-cfg=cfg(riscv{})", ext);
// Required until target_feature risc-v is stable and in-use (rust 1.75)
for ext in RISCV_CFG.iter() {
println!("cargo:rustc-check-cfg=cfg({ext})");
}

let target = env::var("TARGET").unwrap();
let cargo_flags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap();
let _name = env::var("CARGO_PKG_NAME").unwrap();

// set configuration flags depending on the target
if target.starts_with("riscv") {
println!("cargo:rustc-cfg=riscv");
// This is required until target_arch & target_feature risc-v work is
// stable and in-use (rust 1.75.0)
let (bits, extensions) = parse_target(&target, &cargo_flags);

// generate the linker script and expose the ISA width
let arch_width = match bits {
32 => {
println!("cargo:rustc-cfg=riscv32");
4
}
64 => {
println!("cargo:rustc-cfg=riscv64");
8
if let Ok(target) = RiscvTarget::build(&target, &cargo_flags) {
let width = target.width();

// set environmet variable RISCV_RT_BASE_ISA to the base ISA of the target.
println!(
"cargo:rustc-env=RISCV_RT_BASE_ISA={}",
target.llvm_base_isa()
);
// set environment variable RISCV_RT_LLVM_ARCH_PATCH to patch LLVM bug.
// (this env variable is temporary and will be removed after LLVM being fixed)
println!(
"cargo:rustc-env=RISCV_RT_LLVM_ARCH_PATCH={}",
target.llvm_arch_patch()
);
// make sure that these env variables are not changed without notice.
println!("cargo:rerun-if-env-changed=RISCV_RT_BASE_ISA");
println!("cargo:rerun-if-env-changed=RISCV_RT_LLVM_ARCH_PATCH");

for flag in target.rustc_flags() {
// Required until target_feature risc-v is stable and in-use
if RISCV_CFG.contains(&flag.as_str()) {
println!("cargo:rustc-cfg={flag}");
}
_ => panic!("Unsupported bit width"),
};
add_linker_script(arch_width).unwrap();

// expose the ISA extensions
for ext in &extensions {
println!("cargo:rustc-cfg=riscv{}", ext);
}
add_linker_script(width.into()).unwrap();
}
}
2 changes: 1 addition & 1 deletion riscv-rt/macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ keywords = ["riscv", "runtime", "startup"]
license = "MIT OR Apache-2.0"
name = "riscv-rt-macros"
repository = "https://github.com/rust-embedded/riscv"
version = "0.2.2"
version = "0.3.0"
edition = "2021"

[lib]
Expand Down
Loading

0 comments on commit 3cd758b

Please sign in to comment.