Skip to content

Commit

Permalink
Merge pull request #166 from mini-ninja-64/add-fpu-support
Browse files Browse the repository at this point in the history
`riscv-rt`: Implement FPU initialization
  • Loading branch information
romancardenas authored Dec 19, 2023
2 parents d3bad8e + 124f64b commit 0452207
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 4 deletions.
1 change: 1 addition & 0 deletions riscv-rt/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added

- Add FPU initialization
- Static array for vectored-like handling of exceptions
- New GitHub workflow for checking invalid labels in PRs
- New GitHub workflow for checking modifications on CHANGELOG.md
Expand Down
32 changes: 30 additions & 2 deletions riscv-rt/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn add_linker_script(arch_width: u32) -> io::Result<()> {
}

/// Parse the target RISC-V architecture and returns its bit width and the extension set
fn parse_target(target: &str) -> (u32, HashSet<char>) {
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")
Expand All @@ -43,18 +43,46 @@ fn parse_target(target: &str) -> (u32, HashSet<char>) {
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() {
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");

let (bits, extensions) = parse_target(&target);
// 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 {
Expand Down
58 changes: 57 additions & 1 deletion riscv-rt/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ extern crate proc_macro2;
extern crate syn;

use proc_macro2::Span;
use syn::{parse, spanned::Spanned, FnArg, ItemFn, PathArguments, ReturnType, Type, Visibility};
use syn::{
parse::{self, Parse},
spanned::Spanned,
FnArg, ItemFn, LitInt, LitStr, PathArguments, ReturnType, Type, Visibility,
};

use proc_macro::TokenStream;

Expand Down Expand Up @@ -205,3 +209,55 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
)
.into()
}

struct AsmLoopArgs {
asm_template: String,
count: usize,
}

impl Parse for AsmLoopArgs {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let template: LitStr = input.parse().unwrap();
_ = input.parse::<Token![,]>().unwrap();
let count: LitInt = input.parse().unwrap();

Ok(Self {
asm_template: template.value(),
count: count.base10_parse().unwrap(),
})
}
}

/// Loops an asm expression n times.
///
/// `loop_asm!` takes 2 arguments, the first is a string literal and the second is a number literal
/// See [the formatting syntax documentation in `std::fmt`](../std/fmt/index.html)
/// for details.
///
/// Argument 1 is an assembly expression, all "{}" in this assembly expression will be replaced with the
/// current loop index.
///
/// Argument 2 is the number of loops to do with the provided expression.
///
/// # Examples
///
/// ```
/// # use riscv_rt_macros::loop_asm;
/// unsafe {
/// loop_asm!("fmv.w.x f{}, x0", 32); // => core::arch::asm!("fmv.w.x f0, x0") ... core::arch::asm!("fmv.w.x f31, x0")
/// }
/// ```
#[proc_macro]
pub fn loop_asm(input: TokenStream) -> TokenStream {
let args = parse_macro_input!(input as AsmLoopArgs);

let tokens = (0..args.count)
.map(|i| {
let i = i.to_string();
let asm = args.asm_template.replace("{}", &i);
format!("core::arch::asm!(\"{}\");", asm)
})
.collect::<Vec<String>>()
.join("\n");
tokens.parse().unwrap()
}
22 changes: 21 additions & 1 deletion riscv-rt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,12 @@ use riscv::register::{mcause as xcause, mtvec as xtvec, mtvec::TrapMode as xTrap
#[cfg(all(not(feature = "single-hart"), not(feature = "s-mode")))]
use riscv::register::mhartid;

#[cfg(all(feature = "s-mode", any(riscvf, riscvd)))]
use riscv::register::sstatus as xstatus;

#[cfg(all(not(feature = "s-mode"), any(riscvf, riscvd)))]
use riscv::register::mstatus as xstatus;

pub use riscv_rt_macros::{entry, pre_init};

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

// TODO: Enable FPU when available
#[cfg(any(riscvf, riscvd))]
{
xstatus::set_fs(xstatus::FS::Initial); // Enable fpu in xstatus
core::arch::asm!("fscsr x0"); // Zero out fcsr register csrrw x0, fcsr, x0

// Zero out floating point registers
#[cfg(all(target_arch = "riscv32", riscvd))]
riscv_rt_macros::loop_asm!("fcvt.d.w f{}, x0", 32);

#[cfg(all(target_arch = "riscv64", riscvd))]
riscv_rt_macros::loop_asm!("fmv.d.x f{}, x0", 32);

#[cfg(not(riscvd))]
riscv_rt_macros::loop_asm!("fmv.w.x f{}, x0", 32);
}

_setup_interrupts();

Expand Down

0 comments on commit 0452207

Please sign in to comment.