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

riscv-rt: compatibility with RV32E and RV64E #243

Merged
merged 8 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
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
Loading