Skip to content

Commit 3cd758b

Browse files
Merge pull request #243 from rust-embedded/rv32e-compat-asm
`riscv-rt`: compatibility with RV32E and RV64E
2 parents ca4850a + da3b8ac commit 3cd758b

File tree

18 files changed

+1074
-268
lines changed

18 files changed

+1074
-268
lines changed

.github/workflows/changelog.yaml

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ jobs:
2727
- 'riscv-rt/**'
2828
riscv-semihosting:
2929
- 'riscv-semihosting/**'
30+
riscv-target-parser:
31+
- 'riscv-target-parser/**'
3032
3133
- name: Check for CHANGELOG.md (riscv)
3234
if: steps.changes.outputs.riscv == 'true'
@@ -43,7 +45,15 @@ jobs:
4345
changeLogPath: ./riscv-pac/CHANGELOG.md
4446
skipLabels: 'skip changelog'
4547
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-pac/CHANGELOG.md file.'
46-
48+
49+
- name: Check for CHANGELOG.md (riscv-peripheral)
50+
if: steps.changes.outputs.riscv-peripheral == 'true'
51+
uses: dangoslen/changelog-enforcer@v3
52+
with:
53+
changeLogPath: ./riscv-peripheral/CHANGELOG.md
54+
skipLabels: 'skip changelog'
55+
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-peripheral/CHANGELOG.md file.'
56+
4757
- name: Check for CHANGELOG.md (riscv-rt)
4858
if: steps.changes.outputs.riscv-rt == 'true'
4959
uses: dangoslen/changelog-enforcer@v3
@@ -60,10 +70,10 @@ jobs:
6070
skipLabels: 'skip changelog'
6171
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-semihosting/CHANGELOG.md file.'
6272

63-
- name: Check for CHANGELOG.md (riscv-peripheral)
64-
if: steps.changes.outputs.riscv-peripheral == 'true'
73+
- name: Check for CHANGELOG.md (riscv-target-parser)
74+
if: steps.changes.outputs.riscv-target-parser == 'true'
6575
uses: dangoslen/changelog-enforcer@v3
6676
with:
67-
changeLogPath: ./riscv-peripheral/CHANGELOG.md
77+
changeLogPath: ./riscv-target-parser/CHANGELOG.md
6878
skipLabels: 'skip changelog'
69-
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-peripheral/CHANGELOG.md file.'
79+
missingUpdateErrorMessage: 'Please add a changelog entry in the riscv-target-parser/CHANGELOG.md file.'

.github/workflows/riscv-rt.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ jobs:
1414
toolchain: [ stable, nightly, 1.61.0 ]
1515
target:
1616
- riscv32i-unknown-none-elf
17+
- riscv32im-unknown-none-elf
1718
- riscv32imc-unknown-none-elf
1819
- riscv32imac-unknown-none-elf
20+
- riscv32imafc-unknown-none-elf
1921
- riscv64imac-unknown-none-elf
2022
- riscv64gc-unknown-none-elf
2123
example:
@@ -25,6 +27,11 @@ jobs:
2527
# Nightly is only for reference and allowed to fail
2628
- toolchain: nightly
2729
experimental: true
30+
exclude:
31+
- toolchain: 1.61.0
32+
target: riscv32im-unknown-none-elf
33+
- toolchain: 1.61.0
34+
target: riscv32imafc-unknown-none-elf
2835
runs-on: ubuntu-latest
2936
continue-on-error: ${{ matrix.experimental || false }}
3037
steps:
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
on:
2+
push:
3+
branches: [ master ]
4+
pull_request:
5+
merge_group:
6+
7+
name: Run tests (riscv-target-parser)
8+
9+
jobs:
10+
run-tests:
11+
strategy:
12+
matrix:
13+
os: [ macos-latest, ubuntu-latest, windows-latest ]
14+
toolchain: [ stable, nightly, 1.61.0 ]
15+
include:
16+
# Nightly is only for reference and allowed to fail
17+
- rust: nightly
18+
experimental: true
19+
runs-on: ${{ matrix.os }}
20+
continue-on-error: ${{ matrix.experimental || false }}
21+
steps:
22+
- uses: actions/checkout@v4
23+
- name: Update Rust toolchain
24+
run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
25+
- name: Build
26+
run: cargo build --package riscv-target-parser
27+
- name: Run tests
28+
run: cargo test --package riscv-target-parser
29+
30+
# Job to check that all the builds succeeded
31+
tests-check:
32+
needs:
33+
- run-tests
34+
runs-on: ubuntu-latest
35+
if: always()
36+
steps:
37+
- run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ members = [
66
"riscv-peripheral",
77
"riscv-rt",
88
"riscv-semihosting",
9+
"riscv-target-parser",
910
"tests",
1011
]

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This repository contains various crates useful for writing Rust programs on RISC
77
* [`riscv-peripheral`]: Interfaces for standard RISC-V peripherals
88
* [`riscv-rt`]: Startup code and interrupt handling
99
* [`riscv-semihosting`]: Semihosting for RISC-V processors
10+
* [`riscv-target-parser`]: Utility crate for parsing RISC-V targets in build scripts
1011

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

@@ -27,5 +28,6 @@ to intervene to uphold that code of conduct.
2728
[`riscv-peripheral`]: https://crates.io/crates/riscv-peripheral
2829
[`riscv-rt`]: https://crates.io/crates/riscv-rt
2930
[`riscv-semihosting`]: https://crates.io/crates/riscv-semihosting
31+
[`riscv-target-parser`]: https://crates.io/crates/riscv-target-parser
3032
[team]: https://github.com/rust-embedded/wg#the-risc-v-team
3133
[CoC]: CODE_OF_CONDUCT.md

riscv-rt/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Changed
1111

12+
- Limit rustc cfg flags to `riscvi`, `riscvm`, `riscvf`, and `riscvd`.
13+
- Temporary use of `RISCV_RT_LLVM_ARCH_PATCH` environment variable to include the
14+
temporary patch required for avoid LLVM spurious errors.
15+
- `riscv-rt` now use the `RISCV_RT_BASE_ISA` environment variable to configure the behavior
16+
of `riscv-rt-macros` depending on aspects of the base ISA (e.g., RV32I or RV32E).
17+
- Use `riscv-target-parser` in build script to identify target-specific configurations.
18+
- Add documentation to trap frame fields.
19+
- Avoid using `t3`+ in startup assembly to ensure compatibility with RVE.
1220
- `link.x.in`: remove references to `eh_frame`.
1321
- Rename start/end section symbols to align with `cortex-m-rt`:
1422
- `_stext`: it remains, as linker files can modify it.

riscv-rt/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@ targets = [
1919
"riscv64imac-unknown-none-elf", "riscv64gc-unknown-none-elf",
2020
]
2121

22+
[build-dependencies]
23+
riscv-target-parser = { path = "../riscv-target-parser", version = "0.1.0" }
24+
2225
[dependencies]
2326
riscv = { path = "../riscv", version = "0.12.0" }
2427
riscv-pac = { path = "../riscv-pac", version = "0.2.0" }
25-
riscv-rt-macros = { path = "macros", version = "0.2.2" }
28+
riscv-rt-macros = { path = "macros", version = "0.3.0" }
2629

2730
[dev-dependencies]
2831
panic-halt = "1.0.0"

riscv-rt/build.rs

Lines changed: 31 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
// NOTE: Adapted from cortex-m/build.rs
22

3-
use std::{collections::HashSet, env, fs, io, path::PathBuf};
3+
use riscv_target_parser::RiscvTarget;
4+
use std::{env, fs, io, path::PathBuf};
5+
6+
// List of all possible RISC-V configurations to check for in risv-rt
7+
const RISCV_CFG: [&str; 4] = ["riscvi", "riscvm", "riscvf", "riscvd"];
48

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

20-
/// Parse the target RISC-V architecture and returns its bit width and the extension set
21-
fn parse_target(target: &str, cargo_flags: &str) -> (u32, HashSet<char>) {
22-
// isolate bit width and extensions from the rest of the target information
23-
let arch = target
24-
.trim_start_matches("riscv")
25-
.split('-')
26-
.next()
27-
.unwrap();
28-
29-
let bits = arch
30-
.chars()
31-
.take_while(|c| c.is_ascii_digit())
32-
.collect::<String>()
33-
.parse::<u32>()
34-
.unwrap();
35-
36-
let mut extensions: HashSet<char> = arch.chars().skip_while(|c| c.is_ascii_digit()).collect();
37-
// expand the 'g' shorthand extension
38-
if extensions.contains(&'g') {
39-
extensions.insert('i');
40-
extensions.insert('m');
41-
extensions.insert('a');
42-
extensions.insert('f');
43-
extensions.insert('d');
44-
}
45-
46-
let cargo_flags = cargo_flags
47-
.split(0x1fu8 as char)
48-
.filter(|arg| !arg.is_empty());
49-
50-
cargo_flags
51-
.filter(|k| k.starts_with("target-feature="))
52-
.flat_map(|str| {
53-
let flags = str.split('=').collect::<Vec<&str>>()[1];
54-
flags.split(',')
55-
})
56-
.for_each(|feature| {
57-
let chars = feature.chars().collect::<Vec<char>>();
58-
match chars[0] {
59-
'+' => {
60-
extensions.insert(chars[1]);
61-
}
62-
'-' => {
63-
extensions.remove(&chars[1]);
64-
}
65-
_ => {
66-
panic!("Unsupported target feature operation");
67-
}
68-
}
69-
});
70-
71-
(bits, extensions)
72-
}
73-
7424
fn main() {
75-
println!("cargo:rustc-check-cfg=cfg(riscv)");
76-
println!("cargo:rustc-check-cfg=cfg(riscv32)");
77-
println!("cargo:rustc-check-cfg=cfg(riscv64)");
78-
for ext in ['i', 'e', 'm', 'a', 'f', 'd', 'g', 'c'] {
79-
println!("cargo:rustc-check-cfg=cfg(riscv{})", ext);
25+
// Required until target_feature risc-v is stable and in-use (rust 1.75)
26+
for ext in RISCV_CFG.iter() {
27+
println!("cargo:rustc-check-cfg=cfg({ext})");
8028
}
8129

8230
let target = env::var("TARGET").unwrap();
8331
let cargo_flags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap();
84-
let _name = env::var("CARGO_PKG_NAME").unwrap();
8532

86-
// set configuration flags depending on the target
87-
if target.starts_with("riscv") {
88-
println!("cargo:rustc-cfg=riscv");
89-
// This is required until target_arch & target_feature risc-v work is
90-
// stable and in-use (rust 1.75.0)
91-
let (bits, extensions) = parse_target(&target, &cargo_flags);
92-
93-
// generate the linker script and expose the ISA width
94-
let arch_width = match bits {
95-
32 => {
96-
println!("cargo:rustc-cfg=riscv32");
97-
4
98-
}
99-
64 => {
100-
println!("cargo:rustc-cfg=riscv64");
101-
8
33+
if let Ok(target) = RiscvTarget::build(&target, &cargo_flags) {
34+
let width = target.width();
35+
36+
// set environmet variable RISCV_RT_BASE_ISA to the base ISA of the target.
37+
println!(
38+
"cargo:rustc-env=RISCV_RT_BASE_ISA={}",
39+
target.llvm_base_isa()
40+
);
41+
// set environment variable RISCV_RT_LLVM_ARCH_PATCH to patch LLVM bug.
42+
// (this env variable is temporary and will be removed after LLVM being fixed)
43+
println!(
44+
"cargo:rustc-env=RISCV_RT_LLVM_ARCH_PATCH={}",
45+
target.llvm_arch_patch()
46+
);
47+
// make sure that these env variables are not changed without notice.
48+
println!("cargo:rerun-if-env-changed=RISCV_RT_BASE_ISA");
49+
println!("cargo:rerun-if-env-changed=RISCV_RT_LLVM_ARCH_PATCH");
50+
51+
for flag in target.rustc_flags() {
52+
// Required until target_feature risc-v is stable and in-use
53+
if RISCV_CFG.contains(&flag.as_str()) {
54+
println!("cargo:rustc-cfg={flag}");
10255
}
103-
_ => panic!("Unsupported bit width"),
104-
};
105-
add_linker_script(arch_width).unwrap();
106-
107-
// expose the ISA extensions
108-
for ext in &extensions {
109-
println!("cargo:rustc-cfg=riscv{}", ext);
11056
}
57+
add_linker_script(width.into()).unwrap();
11158
}
11259
}

riscv-rt/macros/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ keywords = ["riscv", "runtime", "startup"]
1010
license = "MIT OR Apache-2.0"
1111
name = "riscv-rt-macros"
1212
repository = "https://github.com/rust-embedded/riscv"
13-
version = "0.2.2"
13+
version = "0.3.0"
1414
edition = "2021"
1515

1616
[lib]

0 commit comments

Comments
 (0)