Skip to content

Commit 289206a

Browse files
committed
Add riscv-target-parser crate
1 parent d6365e0 commit 289206a

File tree

14 files changed

+889
-110
lines changed

14 files changed

+889
-110
lines changed

.github/workflows/changelog.yaml

+15-5
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.'
+37
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 ] # windows shows weird linking errors
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

+1
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

+2
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/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ 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" }

riscv-rt/build.rs

+16-83
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
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};
45

56
fn add_linker_script(arch_width: u32) -> io::Result<()> {
67
// Read the file to a string and replace all occurrences of ${ARCH_WIDTH} with the arch width
@@ -17,96 +18,28 @@ fn add_linker_script(arch_width: u32) -> io::Result<()> {
1718
Ok(())
1819
}
1920

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-
7421
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)");
22+
// Required until target_feature risc-v is stable and in-use (rust 1.75)
7823
for ext in ['i', 'e', 'm', 'a', 'f', 'd', 'g', 'c'] {
7924
println!("cargo:rustc-check-cfg=cfg(riscv{})", ext);
8025
}
8126

8227
let target = env::var("TARGET").unwrap();
8328
let cargo_flags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap();
84-
let _name = env::var("CARGO_PKG_NAME").unwrap();
85-
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);
9229

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
102-
}
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);
30+
if let Ok(target) = RiscvTarget::build(&target, &cargo_flags) {
31+
let width = target.width();
32+
if matches!(width, riscv_target_parser::Width::W128) {
33+
panic!("Unsupported RISC-V target: {width}");
34+
}
35+
if target.base_extension().is_none() {
36+
panic!("Unsupported RISC-V target: no base extension");
37+
}
38+
for flag in target.rustc_flags() {
39+
// Required until target_feature risc-v is stable and in-use
40+
println!("cargo:rustc-check-cfg=cfg({flag})");
41+
println!("cargo:rustc-cfg={flag}");
11042
}
43+
add_linker_script(width.into()).unwrap();
11144
}
11245
}

riscv-rt/src/asm.rs

+18-16
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ macro_rules! cfg_global_asm {
3131
// - https://github.com/llvm/llvm-project/issues/61991
3232
cfg_global_asm!(
3333
"// Provisional patch to avoid LLVM spurious errors when compiling in release mode.",
34-
#[cfg(all(riscv32, riscvm))]
34+
#[cfg(all(target_arch = "riscv32", riscvm))]
3535
".attribute arch, \"rv32im\"",
36-
#[cfg(all(riscv64, riscvm, not(riscvg)))]
36+
#[cfg(all(target_arch = "riscv64", riscvm, not(riscvg)))]
3737
".attribute arch, \"rv64im\"",
38-
#[cfg(all(riscv64, riscvg))]
38+
#[cfg(all(target_arch = "riscv64", riscvg))]
3939
".attribute arch, \"rv64g\"",
4040
);
4141

@@ -47,10 +47,10 @@ cfg_global_asm!(
4747
.global _start
4848
4949
_start:",
50-
#[cfg(riscv32)]
50+
#[cfg(target_arch = "riscv32")]
5151
"lui ra, %hi(_abs_start)
5252
jr %lo(_abs_start)(ra)",
53-
#[cfg(riscv64)]
53+
#[cfg(target_arch = "riscv64")]
5454
".option push
5555
.option norelax // to prevent an unsupported R_RISCV_ALIGN relocation from being generated
5656
1:
@@ -84,7 +84,9 @@ _abs_start:
8484
// ZERO OUT GENERAL-PURPOSE REGISTERS
8585
riscv_rt_macros::loop_global_asm!(" li x{}, 0", 1, 10);
8686
// a0..a2 (x10..x12) skipped
87-
riscv_rt_macros::loop_global_asm!(" li x{}, 0", 13, 32);
87+
riscv_rt_macros::loop_global_asm!(" li x{}, 0", 13, 16);
88+
#[cfg(not(riscve))]
89+
riscv_rt_macros::loop_global_asm!(" li x{}, 0", 16, 32);
8890

8991
// INITIALIZE GLOBAL POINTER, STACK POINTER, AND FRAME POINTER
9092
cfg_global_asm!(
@@ -125,12 +127,12 @@ cfg_global_asm!(
125127

126128
// STORE A0..A2 IN THE STACK, AS THEY WILL BE NEEDED LATER BY main
127129
cfg_global_asm!(
128-
#[cfg(riscv32)]
130+
#[cfg(target_arch = "riscv32")]
129131
"addi sp, sp, -4 * 3
130132
sw a0, 4 * 0(sp)
131133
sw a1, 4 * 1(sp)
132134
sw a2, 4 * 2(sp)",
133-
#[cfg(riscv64)]
135+
#[cfg(target_arch = "riscv64")]
134136
"addi sp, sp, -8 * 3
135137
sd a0, 8 * 0(sp)
136138
sd a1, 8 * 1(sp)
@@ -202,22 +204,22 @@ cfg_global_asm!(
202204
"fscsr x0",
203205
);
204206
// ZERO OUT FLOATING POINT REGISTERS
205-
#[cfg(all(riscv32, riscvd))]
207+
#[cfg(all(target_arch = "riscv32", riscvd))]
206208
riscv_rt_macros::loop_global_asm!(" fcvt.d.w f{}, x0", 32);
207-
#[cfg(all(riscv64, riscvd))]
209+
#[cfg(all(target_arch = "riscv64", riscvd))]
208210
riscv_rt_macros::loop_global_asm!(" fmv.d.x f{}, x0", 32);
209211
#[cfg(all(riscvf, not(riscvd)))]
210212
riscv_rt_macros::loop_global_asm!(" fmv.w.x f{}, x0", 32);
211213

212214
// SET UP INTERRUPTS, RESTORE a0..a2, AND JUMP TO MAIN RUST FUNCTION
213215
cfg_global_asm!(
214216
"call _setup_interrupts",
215-
#[cfg(riscv32)]
217+
#[cfg(target_arch = "riscv32")]
216218
"lw a0, 4 * 0(sp)
217219
lw a1, 4 * 1(sp)
218220
lw a2, 4 * 2(sp)
219221
addi sp, sp, 4 * 3",
220-
#[cfg(riscv64)]
222+
#[cfg(target_arch = "riscv64")]
221223
"ld a0, 8 * 0(sp)
222224
ld a1, 8 * 1(sp)
223225
ld a2, 8 * 2(sp)
@@ -276,14 +278,14 @@ _pre_init_trap:
276278
j _pre_init_trap",
277279
);
278280

279-
#[cfg(riscv32)]
281+
#[cfg(target_arch = "riscv32")]
280282
riscv_rt_macros::weak_start_trap_riscv32!();
281-
#[cfg(riscv64)]
283+
#[cfg(target_arch = "riscv64")]
282284
riscv_rt_macros::weak_start_trap_riscv64!();
283285

284-
#[cfg(all(riscv32, feature = "v-trap"))]
286+
#[cfg(all(target_arch = "riscv32", feature = "v-trap"))]
285287
riscv_rt_macros::vectored_interrupt_trap_riscv32!();
286-
#[cfg(all(riscv64, feature = "v-trap"))]
288+
#[cfg(all(target_arch = "riscv64", feature = "v-trap"))]
287289
riscv_rt_macros::vectored_interrupt_trap_riscv64!();
288290

289291
#[rustfmt::skip]

riscv-rt/src/interrupts.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ pub unsafe extern "C" fn _dispatch_core_interrupt(code: usize) {
7171
}
7272

7373
// In vectored mode, we also must provide a vector table
74-
#[cfg(all(riscv, feature = "v-trap"))]
74+
#[cfg(all(
75+
any(target_arch = "riscv32", target_arch = "riscv64"),
76+
feature = "v-trap"
77+
))]
7578
core::arch::global_asm!(
7679
r#" .section .trap, "ax"
7780
.weak _vector_table

0 commit comments

Comments
 (0)