Skip to content

Commit 0452207

Browse files
Merge pull request #166 from mini-ninja-64/add-fpu-support
`riscv-rt`: Implement FPU initialization
2 parents d3bad8e + 124f64b commit 0452207

File tree

4 files changed

+109
-4
lines changed

4 files changed

+109
-4
lines changed

riscv-rt/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Added
1111

12+
- Add FPU initialization
1213
- Static array for vectored-like handling of exceptions
1314
- New GitHub workflow for checking invalid labels in PRs
1415
- New GitHub workflow for checking modifications on CHANGELOG.md

riscv-rt/build.rs

+30-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ fn add_linker_script(arch_width: u32) -> io::Result<()> {
1818
}
1919

2020
/// Parse the target RISC-V architecture and returns its bit width and the extension set
21-
fn parse_target(target: &str) -> (u32, HashSet<char>) {
21+
fn parse_target(target: &str, cargo_flags: &str) -> (u32, HashSet<char>) {
2222
// isolate bit width and extensions from the rest of the target information
2323
let arch = target
2424
.trim_start_matches("riscv")
@@ -43,18 +43,46 @@ fn parse_target(target: &str) -> (u32, HashSet<char>) {
4343
extensions.insert('d');
4444
}
4545

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+
4671
(bits, extensions)
4772
}
4873

4974
fn main() {
5075
let target = env::var("TARGET").unwrap();
76+
let cargo_flags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap();
5177
let _name = env::var("CARGO_PKG_NAME").unwrap();
5278

5379
// set configuration flags depending on the target
5480
if target.starts_with("riscv") {
5581
println!("cargo:rustc-cfg=riscv");
5682

57-
let (bits, extensions) = parse_target(&target);
83+
// This is required until target_arch & target_feature risc-v work is
84+
// stable and in-use (rust 1.75.0)
85+
let (bits, extensions) = parse_target(&target, &cargo_flags);
5886

5987
// generate the linker script and expose the ISA width
6088
let arch_width = match bits {

riscv-rt/macros/src/lib.rs

+57-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ extern crate proc_macro2;
99
extern crate syn;
1010

1111
use proc_macro2::Span;
12-
use syn::{parse, spanned::Spanned, FnArg, ItemFn, PathArguments, ReturnType, Type, Visibility};
12+
use syn::{
13+
parse::{self, Parse},
14+
spanned::Spanned,
15+
FnArg, ItemFn, LitInt, LitStr, PathArguments, ReturnType, Type, Visibility,
16+
};
1317

1418
use proc_macro::TokenStream;
1519

@@ -205,3 +209,55 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
205209
)
206210
.into()
207211
}
212+
213+
struct AsmLoopArgs {
214+
asm_template: String,
215+
count: usize,
216+
}
217+
218+
impl Parse for AsmLoopArgs {
219+
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
220+
let template: LitStr = input.parse().unwrap();
221+
_ = input.parse::<Token![,]>().unwrap();
222+
let count: LitInt = input.parse().unwrap();
223+
224+
Ok(Self {
225+
asm_template: template.value(),
226+
count: count.base10_parse().unwrap(),
227+
})
228+
}
229+
}
230+
231+
/// Loops an asm expression n times.
232+
///
233+
/// `loop_asm!` takes 2 arguments, the first is a string literal and the second is a number literal
234+
/// See [the formatting syntax documentation in `std::fmt`](../std/fmt/index.html)
235+
/// for details.
236+
///
237+
/// Argument 1 is an assembly expression, all "{}" in this assembly expression will be replaced with the
238+
/// current loop index.
239+
///
240+
/// Argument 2 is the number of loops to do with the provided expression.
241+
///
242+
/// # Examples
243+
///
244+
/// ```
245+
/// # use riscv_rt_macros::loop_asm;
246+
/// unsafe {
247+
/// loop_asm!("fmv.w.x f{}, x0", 32); // => core::arch::asm!("fmv.w.x f0, x0") ... core::arch::asm!("fmv.w.x f31, x0")
248+
/// }
249+
/// ```
250+
#[proc_macro]
251+
pub fn loop_asm(input: TokenStream) -> TokenStream {
252+
let args = parse_macro_input!(input as AsmLoopArgs);
253+
254+
let tokens = (0..args.count)
255+
.map(|i| {
256+
let i = i.to_string();
257+
let asm = args.asm_template.replace("{}", &i);
258+
format!("core::arch::asm!(\"{}\");", asm)
259+
})
260+
.collect::<Vec<String>>()
261+
.join("\n");
262+
tokens.parse().unwrap()
263+
}

riscv-rt/src/lib.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,12 @@ use riscv::register::{mcause as xcause, mtvec as xtvec, mtvec::TrapMode as xTrap
415415
#[cfg(all(not(feature = "single-hart"), not(feature = "s-mode")))]
416416
use riscv::register::mhartid;
417417

418+
#[cfg(all(feature = "s-mode", any(riscvf, riscvd)))]
419+
use riscv::register::sstatus as xstatus;
420+
421+
#[cfg(all(not(feature = "s-mode"), any(riscvf, riscvd)))]
422+
use riscv::register::mstatus as xstatus;
423+
418424
pub use riscv_rt_macros::{entry, pre_init};
419425

420426
#[export_name = "error: riscv-rt appears more than once in the dependency graph"]
@@ -550,7 +556,21 @@ pub unsafe extern "C" fn start_rust(a0: usize, a1: usize, a2: usize) -> ! {
550556
compiler_fence(Ordering::SeqCst);
551557
}
552558

553-
// TODO: Enable FPU when available
559+
#[cfg(any(riscvf, riscvd))]
560+
{
561+
xstatus::set_fs(xstatus::FS::Initial); // Enable fpu in xstatus
562+
core::arch::asm!("fscsr x0"); // Zero out fcsr register csrrw x0, fcsr, x0
563+
564+
// Zero out floating point registers
565+
#[cfg(all(target_arch = "riscv32", riscvd))]
566+
riscv_rt_macros::loop_asm!("fcvt.d.w f{}, x0", 32);
567+
568+
#[cfg(all(target_arch = "riscv64", riscvd))]
569+
riscv_rt_macros::loop_asm!("fmv.d.x f{}, x0", 32);
570+
571+
#[cfg(not(riscvd))]
572+
riscv_rt_macros::loop_asm!("fmv.w.x f{}, x0", 32);
573+
}
554574

555575
_setup_interrupts();
556576

0 commit comments

Comments
 (0)