From f3e755efa0efd6b5f4d35290c40cb3c8b2a69bbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Wed, 3 Jan 2024 20:03:55 +0100 Subject: [PATCH 01/11] move all assembly to asm.rs --- .github/workflows/riscv-rt.yaml | 2 +- riscv-rt/CHANGELOG.md | 1 + riscv-rt/macros/src/lib.rs | 73 ++++++++++++--- riscv-rt/src/asm.rs | 161 +++++++++++++++++++++++--------- riscv-rt/src/lib.rs | 161 -------------------------------- 5 files changed, 183 insertions(+), 215 deletions(-) diff --git a/.github/workflows/riscv-rt.yaml b/.github/workflows/riscv-rt.yaml index 8e716b52..0c20eb31 100644 --- a/.github/workflows/riscv-rt.yaml +++ b/.github/workflows/riscv-rt.yaml @@ -1,6 +1,6 @@ on: push: - branches: [ master ] + branches: [ master, riscv-rt-asm ] pull_request: merge_group: diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index ecbb8a5d..b206df32 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Removed _start_rust. Now, assembly directly jumps to main - Removed U-mode interrupts to align with latest RISC-V specification - Changed `Vector` union. Now, it uses `Option`, which is more idiomatic in Rust - Removed riscv-target dependency for build diff --git a/riscv-rt/macros/src/lib.rs b/riscv-rt/macros/src/lib.rs index b48cc111..14021902 100644 --- a/riscv-rt/macros/src/lib.rs +++ b/riscv-rt/macros/src/lib.rs @@ -212,7 +212,8 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream { struct AsmLoopArgs { asm_template: String, - count: usize, + count_from: usize, + count_to: usize, } impl Parse for AsmLoopArgs { @@ -220,24 +221,35 @@ impl Parse for AsmLoopArgs { let template: LitStr = input.parse().unwrap(); _ = input.parse::().unwrap(); let count: LitInt = input.parse().unwrap(); - - Ok(Self { - asm_template: template.value(), - count: count.base10_parse().unwrap(), - }) + if input.parse::().is_ok() { + let count_to: LitInt = input.parse().unwrap(); + Ok(Self { + asm_template: template.value(), + count_from: count.base10_parse().unwrap(), + count_to: count_to.base10_parse().unwrap(), + }) + } else { + Ok(Self { + asm_template: template.value(), + count_from: 0, + count_to: 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. +/// `loop_asm!` takes 2 or 3 arguments, the first is a string literal and the rest are 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. +/// If 2 arguments are provided, the loop will start at 0 and end at the number provided in argument 2. +/// +/// If 3 arguments are provided, the loop will start at the number provided in argument 2 and end at +/// the number provided in argument 3. /// /// # Examples /// @@ -245,13 +257,14 @@ impl Parse for AsmLoopArgs { /// # 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") +/// loop_asm!("fmv.w.x f{}, x0", 1, 32); // => core::arch::asm!("fmv.w.x f1, 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) + let tokens = (args.count_from..args.count_to) .map(|i| { let i = i.to_string(); let asm = args.asm_template.replace("{}", &i); @@ -261,3 +274,41 @@ pub fn loop_asm(input: TokenStream) -> TokenStream { .join("\n"); tokens.parse().unwrap() } + +/// Loops a global_asm expression n times. +/// +/// `loop_global_asm!` takes 2 or 3 arguments, the first is a string literal and the rest are 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. +/// +/// If 2 arguments are provided, the loop will start at 0 and end at the number provided in argument 2. +/// +/// If 3 arguments are provided, the loop will start at the number provided in argument 2 and end at +/// the number provided in argument 3. +/// +/// # Examples +/// +/// ``` +/// # use riscv_rt_macros::loop_global_asm; +/// unsafe { +/// loop_global_asm!("fmv.w.x f{}, x0", 32); // => core::arch::global_asm!("fmv.w.x f0, x0") ... core::arch::global_asm!("fmv.w.x f31, x0") +/// loop_global_asm!("fmv.w.x f{}, x0", 1, 32); // => core::arch::global_asm!("fmv.w.x f1, x0") ... core::arch::global_asm!("fmv.w.x f31, x0") +/// } +/// ``` +#[proc_macro] +pub fn loop_global_asm(input: TokenStream) -> TokenStream { + let args = parse_macro_input!(input as AsmLoopArgs); + + let instructions = (args.count_from..args.count_to) + .map(|i| { + let i = i.to_string(); + args.asm_template.replace("{}", &i) + }) + .collect::>() + .join("\n"); + + let res = format!("core::arch::global_asm!(\n\"{}\"\n);", instructions); + res.parse().unwrap() +} diff --git a/riscv-rt/src/asm.rs b/riscv-rt/src/asm.rs index 0eedebe6..b83d304d 100644 --- a/riscv-rt/src/asm.rs +++ b/riscv-rt/src/asm.rs @@ -52,54 +52,36 @@ _abs_start: #[cfg(not(feature = "s-mode"))] "csrw mie, 0 csrw mip, 0", - "li x1, 0 - li x2, 0 - li x3, 0 - li x4, 0 - li x5, 0 - li x6, 0 - li x7, 0 - li x8, 0 - li x9, 0 - // a0..a2 (x10..x12) skipped - li x13, 0 - li x14, 0 - li x15, 0 - li x16, 0 - li x17, 0 - li x18, 0 - li x19, 0 - li x20, 0 - li x21, 0 - li x22, 0 - li x23, 0 - li x24, 0 - li x25, 0 - li x26, 0 - li x27, 0 - li x28, 0 - li x29, 0 - li x30, 0 - li x31, 0 +); + +// ZERO OUT GENERAL-PURPOSE REGISTERS +riscv_rt_macros::loop_global_asm!(" li x{}, 0", 1, 10); +// a0..a2 (x10..x12) skipped +riscv_rt_macros::loop_global_asm!(" li x{}, 0", 13, 32); - .option push +// INITIALIZE GLOBAL POINTER +cfg_global_asm!( + ".option push .option norelax la gp, __global_pointer$ - .option pop - // Allocate stacks", - #[cfg(all(not(feature = "single-hart"), feature = "s-mode"))] + .option pop", +); + +// INITIALIZE STACK POINTER AND FRAME POINTER +#[cfg(not(feature = "single-hart"))] +cfg_global_asm!( + #[cfg(feature = "s-mode")] "mv t2, a0 // the hartid is passed as parameter by SMODE", - #[cfg(all(not(feature = "single-hart"), not(feature = "s-mode")))] + #[cfg(not(feature = "s-mode"))] "csrr t2, mhartid", - #[cfg(not(feature = "single-hart"))] "lui t0, %hi(_max_hart_id) add t0, t0, %lo(_max_hart_id) bgtu t2, t0, abort lui t0, %hi(_hart_stack_size) add t0, t0, %lo(_hart_stack_size)", - #[cfg(all(not(feature = "single-hart"), riscvm))] + #[cfg(riscvm)] "mul t0, t2, t0", - #[cfg(all(not(feature = "single-hart"), not(riscvm)))] + #[cfg(not(riscvm))] "beqz t2, 2f // Jump if single-hart mv t1, t2 mv t3, t0 @@ -109,14 +91,109 @@ _abs_start: bnez t1, 1b 2: ", "la t1, _stack_start", - #[cfg(not(feature = "single-hart"))] "sub t1, t1, t0", - "andi sp, t1, -16 // Force 16-byte alignment - // Set frame pointer - add s0, sp, zero +); +cfg_global_asm!( + "andi sp, t1, -16 // align stack to 16-bytes + add s0, sp, zero", +); + +// STORE A0..A2 IN THE STACK, AS THEY WILL BE NEEDED LATER BY main +cfg_global_asm!( + #[cfg(riscv32)] + "addi sp, sp, -4 * 3 + sw a0, 4 * 0(sp) + sw a1, 4 * 1(sp) + sw a2, 4 * 2(sp)", + #[cfg(riscv64)] + "addi sp, sp, -8 * 3 + sd a0, 8 * 0(sp) + sd a1, 8 * 1(sp) + sd a2, 8 * 2(sp)", +); - jal zero, _start_rust +// SKIP RAM INITIALIZATION IF CURRENT HART IS NOT THE BOOT HART +#[cfg(not(feature = "single-hart"))] +cfg_global_asm!( + #[cfg(not(feature = "s-mode"))] + "csrr a0, mhartid", + "call _mp_hook + mv t0, a0 + + beqz a0, 4f", +); +// IF CURRENT HART IS THE BOOT HART CALL __pre_init AND INITIALIZE RAM +cfg_global_asm!( + "call __pre_init + // Copy .data from flash to RAM + la t0, _sdata + la t2, _edata + la t1, _sidata + bgeu t0, t2, 2f +1: ", + #[cfg(target_arch = "riscv32")] + "lw t3, 0(t1) + addi t1, t1, 4 + sw t3, 0(t0) + addi t0, t0, 4 + bltu t0, t2, 1b", + #[cfg(target_arch = "riscv64")] + "ld t3, 0(t1) + addi t1, t1, 8 + sd t3, 0(t0) + addi t0, t0, 8 + bltu t0, t2, 1b", + " +2: // Zero out .bss + la t0, _sbss + la t2, _ebss + bgeu t0, t2, 4f +3: ", + #[cfg(target_arch = "riscv32")] + "sw zero, 0(t0) + addi t0, t0, 4 + bltu t0, t2, 3b", + #[cfg(target_arch = "riscv64")] + "sd zero, 0(t0) + addi t0, t0, 8 + bltu t0, t2, 3b", + " +4: // RAM initilized", +); +// INITIALIZE FLOATING POINT UNIT +#[cfg(any(riscvf, riscvd))] +cfg_global_asm!( + #[cfg(feature = "s-mode")] + "csrrc x0, sstatus, 0x4000 + csrrs x0, sstatus, 0x2000", + #[cfg(not(feature = "s-mode"))] + "csrrc x0, mstatus, 0x4000 + csrrs x0, mstatus, 0x2000", + "fscsr x0", +); +// ZERO OUT FLOATING POINT REGISTERS +#[cfg(all(riscv32, riscvd))] +riscv_rt_macros::loop_global_asm!(" fcvt.d.w f{}, x0", 32); +#[cfg(all(riscv64, riscvd))] +riscv_rt_macros::loop_global_asm!(" fmv.d.x f{}, x0", 32); +#[cfg(all(riscvf, not(riscvd)))] +riscv_rt_macros::loop_global_asm!(" fmv.w.x f{}, x0", 32); + +// SET UP INTERRUPTS, RESTORE a0..a2, AND JUMP TO MAIN RUST FUNCTION +cfg_global_asm!( + "call _setup_interrupts", + #[cfg(riscv32)] + "lw a0, 4 * 0(sp) + lw a1, 4 * 1(sp) + lw a2, 4 * 2(sp) + addi sp, sp, 4 * 3", + #[cfg(riscv64)] + "ld a0, 8 * 0(sp) + ld a1, 8 * 1(sp) + ld a2, 8 * 2(sp) + addi sp, sp, 8 * 3", + "jal zero, main .cfi_endproc", ); diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index a7a900eb..242eb664 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -404,179 +404,18 @@ #[cfg(riscv)] mod asm; -use core::sync::atomic::{compiler_fence, Ordering}; - #[cfg(feature = "s-mode")] use riscv::register::{scause as xcause, stvec as xtvec, stvec::TrapMode as xTrapMode}; #[cfg(not(feature = "s-mode"))] use riscv::register::{mcause as xcause, mtvec as xtvec, mtvec::TrapMode as xTrapMode}; -#[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"] #[doc(hidden)] pub static __ONCE__: () = (); -/// Rust entry point (_start_rust) -/// -/// Zeros bss section, initializes data section and calls main. This function never returns. -/// -/// # Safety -/// -/// This function must be called only from assembly `_start` function. -/// Do **NOT** call this function directly. -#[link_section = ".init.rust"] -#[export_name = "_start_rust"] -pub unsafe extern "C" fn start_rust(a0: usize, a1: usize, a2: usize) -> ! { - #[rustfmt::skip] - extern "Rust" { - // This symbol will be provided by the user via `#[entry]` - fn main(a0: usize, a1: usize, a2: usize) -> !; - - // This symbol will be provided by the user via `#[pre_init]` - fn __pre_init(); - - fn _setup_interrupts(); - - fn _mp_hook(hartid: usize) -> bool; - } - - #[cfg(not(feature = "single-hart"))] - let run_init = { - // sbi passes hartid as first parameter (a0) - #[cfg(feature = "s-mode")] - let hartid = a0; - #[cfg(not(feature = "s-mode"))] - let hartid = mhartid::read(); - - _mp_hook(hartid) - }; - #[cfg(feature = "single-hart")] - let run_init = true; - - if run_init { - __pre_init(); - - // Initialize RAM - // 1. Copy over .data from flash to RAM - // 2. Zero out .bss - - #[cfg(target_arch = "riscv32")] - core::arch::asm!( - " - // Copy over .data - la {start},_sdata - la {end},_edata - la {input},_sidata - - bgeu {start},{end},2f - 1: - lw {a},0({input}) - addi {input},{input},4 - sw {a},0({start}) - addi {start},{start},4 - bltu {start},{end},1b - - 2: - li {a},0 - li {input},0 - - // Zero out .bss - la {start},_sbss - la {end},_ebss - - bgeu {start},{end},3f - 2: - sw zero,0({start}) - addi {start},{start},4 - bltu {start},{end},2b - - 3: - li {start},0 - li {end},0 - ", - start = out(reg) _, - end = out(reg) _, - input = out(reg) _, - a = out(reg) _, - ); - - #[cfg(target_arch = "riscv64")] - core::arch::asm!( - " - // Copy over .data - la {start},_sdata - la {end},_edata - la {input},_sidata - - bgeu {start},{end},2f - - 1: // .data Main Loop - ld {a},0({input}) - addi {input},{input},8 - sd {a},0({start}) - addi {start},{start},8 - bltu {start},{end},1b - - 2: // .data zero registers - li {a},0 - li {input},0 - - la {start},_sbss - la {end},_ebss - - bgeu {start},{end},4f - - 3: // .bss main loop - sd zero,0({start}) - addi {start},{start},8 - bltu {start},{end},3b - - 4: // .bss zero registers - // Zero out used registers - li {start},0 - li {end},0 - ", - start = out(reg) _, - end = out(reg) _, - input = out(reg) _, - a = out(reg) _, - ); - - compiler_fence(Ordering::SeqCst); - } - - #[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(); - - main(a0, a1, a2); -} - /// Registers saved in trap handler #[allow(missing_docs)] #[repr(C)] From b443cf31e523400cae799150f0362b7e91e2c05c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Wed, 3 Jan 2024 21:16:45 +0100 Subject: [PATCH 02/11] fix FPU initialization --- riscv-rt/src/asm.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/riscv-rt/src/asm.rs b/riscv-rt/src/asm.rs index b83d304d..4f9cdf52 100644 --- a/riscv-rt/src/asm.rs +++ b/riscv-rt/src/asm.rs @@ -164,12 +164,16 @@ cfg_global_asm!( // INITIALIZE FLOATING POINT UNIT #[cfg(any(riscvf, riscvd))] cfg_global_asm!( + " + li t0, 0x4000 // bit 14 is FS most significant bit + li t2, 0x2000 // bit 13 is FS least significant bit + ", #[cfg(feature = "s-mode")] - "csrrc x0, sstatus, 0x4000 - csrrs x0, sstatus, 0x2000", + "csrrc x0, sstatus, t0 + csrrs x0, sstatus, t2", #[cfg(not(feature = "s-mode"))] - "csrrc x0, mstatus, 0x4000 - csrrs x0, mstatus, 0x2000", + "csrrc x0, mstatus, t0 + csrrs x0, mstatus, t2", "fscsr x0", ); // ZERO OUT FLOATING POINT REGISTERS From 173ea431c3651c93fde8e93b5d9b74e1c9b1f80c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Wed, 10 Jan 2024 21:30:06 +0100 Subject: [PATCH 03/11] fix single-hart --- riscv-rt/src/asm.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/riscv-rt/src/asm.rs b/riscv-rt/src/asm.rs index 4f9cdf52..b24dc5c1 100644 --- a/riscv-rt/src/asm.rs +++ b/riscv-rt/src/asm.rs @@ -90,10 +90,11 @@ cfg_global_asm!( addi t1, t1, -1 bnez t1, 1b 2: ", - "la t1, _stack_start", - "sub t1, t1, t0", ); cfg_global_asm!( + "la t1, _stack_start", + #[cfg(not(feature = "single-hart"))] + "sub t1, t1, t0", "andi sp, t1, -16 // align stack to 16-bytes add s0, sp, zero", ); From 8baa254307956933f686859578d0969073752df8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Wed, 3 Jan 2024 20:03:55 +0100 Subject: [PATCH 04/11] move all assembly to asm.rs --- .github/workflows/riscv-rt.yaml | 2 +- riscv-rt/CHANGELOG.md | 1 + riscv-rt/macros/src/lib.rs | 73 ++++++++++++--- riscv-rt/src/asm.rs | 161 +++++++++++++++++++++++--------- riscv-rt/src/lib.rs | 161 -------------------------------- 5 files changed, 183 insertions(+), 215 deletions(-) diff --git a/.github/workflows/riscv-rt.yaml b/.github/workflows/riscv-rt.yaml index 8e716b52..0c20eb31 100644 --- a/.github/workflows/riscv-rt.yaml +++ b/.github/workflows/riscv-rt.yaml @@ -1,6 +1,6 @@ on: push: - branches: [ master ] + branches: [ master, riscv-rt-asm ] pull_request: merge_group: diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index 84967828..a9038b8b 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Removed _start_rust. Now, assembly directly jumps to main - Removed U-mode interrupts to align with latest RISC-V specification - Changed `Vector` union. Now, it uses `Option`, which is more idiomatic in Rust - Removed riscv-target dependency for build diff --git a/riscv-rt/macros/src/lib.rs b/riscv-rt/macros/src/lib.rs index b48cc111..14021902 100644 --- a/riscv-rt/macros/src/lib.rs +++ b/riscv-rt/macros/src/lib.rs @@ -212,7 +212,8 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream { struct AsmLoopArgs { asm_template: String, - count: usize, + count_from: usize, + count_to: usize, } impl Parse for AsmLoopArgs { @@ -220,24 +221,35 @@ impl Parse for AsmLoopArgs { let template: LitStr = input.parse().unwrap(); _ = input.parse::().unwrap(); let count: LitInt = input.parse().unwrap(); - - Ok(Self { - asm_template: template.value(), - count: count.base10_parse().unwrap(), - }) + if input.parse::().is_ok() { + let count_to: LitInt = input.parse().unwrap(); + Ok(Self { + asm_template: template.value(), + count_from: count.base10_parse().unwrap(), + count_to: count_to.base10_parse().unwrap(), + }) + } else { + Ok(Self { + asm_template: template.value(), + count_from: 0, + count_to: 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. +/// `loop_asm!` takes 2 or 3 arguments, the first is a string literal and the rest are 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. +/// If 2 arguments are provided, the loop will start at 0 and end at the number provided in argument 2. +/// +/// If 3 arguments are provided, the loop will start at the number provided in argument 2 and end at +/// the number provided in argument 3. /// /// # Examples /// @@ -245,13 +257,14 @@ impl Parse for AsmLoopArgs { /// # 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") +/// loop_asm!("fmv.w.x f{}, x0", 1, 32); // => core::arch::asm!("fmv.w.x f1, 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) + let tokens = (args.count_from..args.count_to) .map(|i| { let i = i.to_string(); let asm = args.asm_template.replace("{}", &i); @@ -261,3 +274,41 @@ pub fn loop_asm(input: TokenStream) -> TokenStream { .join("\n"); tokens.parse().unwrap() } + +/// Loops a global_asm expression n times. +/// +/// `loop_global_asm!` takes 2 or 3 arguments, the first is a string literal and the rest are 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. +/// +/// If 2 arguments are provided, the loop will start at 0 and end at the number provided in argument 2. +/// +/// If 3 arguments are provided, the loop will start at the number provided in argument 2 and end at +/// the number provided in argument 3. +/// +/// # Examples +/// +/// ``` +/// # use riscv_rt_macros::loop_global_asm; +/// unsafe { +/// loop_global_asm!("fmv.w.x f{}, x0", 32); // => core::arch::global_asm!("fmv.w.x f0, x0") ... core::arch::global_asm!("fmv.w.x f31, x0") +/// loop_global_asm!("fmv.w.x f{}, x0", 1, 32); // => core::arch::global_asm!("fmv.w.x f1, x0") ... core::arch::global_asm!("fmv.w.x f31, x0") +/// } +/// ``` +#[proc_macro] +pub fn loop_global_asm(input: TokenStream) -> TokenStream { + let args = parse_macro_input!(input as AsmLoopArgs); + + let instructions = (args.count_from..args.count_to) + .map(|i| { + let i = i.to_string(); + args.asm_template.replace("{}", &i) + }) + .collect::>() + .join("\n"); + + let res = format!("core::arch::global_asm!(\n\"{}\"\n);", instructions); + res.parse().unwrap() +} diff --git a/riscv-rt/src/asm.rs b/riscv-rt/src/asm.rs index ea4b5233..772626f5 100644 --- a/riscv-rt/src/asm.rs +++ b/riscv-rt/src/asm.rs @@ -72,54 +72,36 @@ _abs_start: #[cfg(not(feature = "s-mode"))] "csrw mie, 0 csrw mip, 0", - "li x1, 0 - li x2, 0 - li x3, 0 - li x4, 0 - li x5, 0 - li x6, 0 - li x7, 0 - li x8, 0 - li x9, 0 - // a0..a2 (x10..x12) skipped - li x13, 0 - li x14, 0 - li x15, 0 - li x16, 0 - li x17, 0 - li x18, 0 - li x19, 0 - li x20, 0 - li x21, 0 - li x22, 0 - li x23, 0 - li x24, 0 - li x25, 0 - li x26, 0 - li x27, 0 - li x28, 0 - li x29, 0 - li x30, 0 - li x31, 0 +); + +// ZERO OUT GENERAL-PURPOSE REGISTERS +riscv_rt_macros::loop_global_asm!(" li x{}, 0", 1, 10); +// a0..a2 (x10..x12) skipped +riscv_rt_macros::loop_global_asm!(" li x{}, 0", 13, 32); - .option push +// INITIALIZE GLOBAL POINTER +cfg_global_asm!( + ".option push .option norelax la gp, __global_pointer$ - .option pop - // Allocate stacks", - #[cfg(all(not(feature = "single-hart"), feature = "s-mode"))] + .option pop", +); + +// INITIALIZE STACK POINTER AND FRAME POINTER +#[cfg(not(feature = "single-hart"))] +cfg_global_asm!( + #[cfg(feature = "s-mode")] "mv t2, a0 // the hartid is passed as parameter by SMODE", - #[cfg(all(not(feature = "single-hart"), not(feature = "s-mode")))] + #[cfg(not(feature = "s-mode"))] "csrr t2, mhartid", - #[cfg(not(feature = "single-hart"))] "lui t0, %hi(_max_hart_id) add t0, t0, %lo(_max_hart_id) bgtu t2, t0, abort lui t0, %hi(_hart_stack_size) add t0, t0, %lo(_hart_stack_size)", - #[cfg(all(not(feature = "single-hart"), riscvm))] + #[cfg(riscvm)] "mul t0, t2, t0", - #[cfg(all(not(feature = "single-hart"), not(riscvm)))] + #[cfg(not(riscvm))] "beqz t2, 2f // Jump if single-hart mv t1, t2 mv t3, t0 @@ -129,14 +111,109 @@ _abs_start: bnez t1, 1b 2: ", "la t1, _stack_start", - #[cfg(not(feature = "single-hart"))] "sub t1, t1, t0", - "andi sp, t1, -16 // Force 16-byte alignment - // Set frame pointer - add s0, sp, zero +); +cfg_global_asm!( + "andi sp, t1, -16 // align stack to 16-bytes + add s0, sp, zero", +); + +// STORE A0..A2 IN THE STACK, AS THEY WILL BE NEEDED LATER BY main +cfg_global_asm!( + #[cfg(riscv32)] + "addi sp, sp, -4 * 3 + sw a0, 4 * 0(sp) + sw a1, 4 * 1(sp) + sw a2, 4 * 2(sp)", + #[cfg(riscv64)] + "addi sp, sp, -8 * 3 + sd a0, 8 * 0(sp) + sd a1, 8 * 1(sp) + sd a2, 8 * 2(sp)", +); - jal zero, _start_rust +// SKIP RAM INITIALIZATION IF CURRENT HART IS NOT THE BOOT HART +#[cfg(not(feature = "single-hart"))] +cfg_global_asm!( + #[cfg(not(feature = "s-mode"))] + "csrr a0, mhartid", + "call _mp_hook + mv t0, a0 + + beqz a0, 4f", +); +// IF CURRENT HART IS THE BOOT HART CALL __pre_init AND INITIALIZE RAM +cfg_global_asm!( + "call __pre_init + // Copy .data from flash to RAM + la t0, _sdata + la t2, _edata + la t1, _sidata + bgeu t0, t2, 2f +1: ", + #[cfg(target_arch = "riscv32")] + "lw t3, 0(t1) + addi t1, t1, 4 + sw t3, 0(t0) + addi t0, t0, 4 + bltu t0, t2, 1b", + #[cfg(target_arch = "riscv64")] + "ld t3, 0(t1) + addi t1, t1, 8 + sd t3, 0(t0) + addi t0, t0, 8 + bltu t0, t2, 1b", + " +2: // Zero out .bss + la t0, _sbss + la t2, _ebss + bgeu t0, t2, 4f +3: ", + #[cfg(target_arch = "riscv32")] + "sw zero, 0(t0) + addi t0, t0, 4 + bltu t0, t2, 3b", + #[cfg(target_arch = "riscv64")] + "sd zero, 0(t0) + addi t0, t0, 8 + bltu t0, t2, 3b", + " +4: // RAM initilized", +); +// INITIALIZE FLOATING POINT UNIT +#[cfg(any(riscvf, riscvd))] +cfg_global_asm!( + #[cfg(feature = "s-mode")] + "csrrc x0, sstatus, 0x4000 + csrrs x0, sstatus, 0x2000", + #[cfg(not(feature = "s-mode"))] + "csrrc x0, mstatus, 0x4000 + csrrs x0, mstatus, 0x2000", + "fscsr x0", +); +// ZERO OUT FLOATING POINT REGISTERS +#[cfg(all(riscv32, riscvd))] +riscv_rt_macros::loop_global_asm!(" fcvt.d.w f{}, x0", 32); +#[cfg(all(riscv64, riscvd))] +riscv_rt_macros::loop_global_asm!(" fmv.d.x f{}, x0", 32); +#[cfg(all(riscvf, not(riscvd)))] +riscv_rt_macros::loop_global_asm!(" fmv.w.x f{}, x0", 32); + +// SET UP INTERRUPTS, RESTORE a0..a2, AND JUMP TO MAIN RUST FUNCTION +cfg_global_asm!( + "call _setup_interrupts", + #[cfg(riscv32)] + "lw a0, 4 * 0(sp) + lw a1, 4 * 1(sp) + lw a2, 4 * 2(sp) + addi sp, sp, 4 * 3", + #[cfg(riscv64)] + "ld a0, 8 * 0(sp) + ld a1, 8 * 1(sp) + ld a2, 8 * 2(sp) + addi sp, sp, 8 * 3", + "jal zero, main .cfi_endproc", ); diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index b82fed40..de9b39e2 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -404,23 +404,12 @@ #[cfg(riscv)] mod asm; -use core::sync::atomic::{compiler_fence, Ordering}; - #[cfg(feature = "s-mode")] use riscv::register::{scause as xcause, stvec as xtvec, stvec::TrapMode as xTrapMode}; #[cfg(not(feature = "s-mode"))] use riscv::register::{mcause as xcause, mtvec as xtvec, mtvec::TrapMode as xTrapMode}; -#[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}; /// We export this static with an informative name so that if an application attempts to link @@ -431,156 +420,6 @@ pub use riscv_rt_macros::{entry, pre_init}; #[doc(hidden)] pub static __ONCE__: () = (); -/// Rust entry point (_start_rust) -/// -/// Zeros bss section, initializes data section and calls main. This function never returns. -/// -/// # Safety -/// -/// This function must be called only from assembly `_start` function. -/// Do **NOT** call this function directly. -#[link_section = ".init.rust"] -#[export_name = "_start_rust"] -pub unsafe extern "C" fn start_rust(a0: usize, a1: usize, a2: usize) -> ! { - #[rustfmt::skip] - extern "Rust" { - // This symbol will be provided by the user via `#[entry]` - fn main(a0: usize, a1: usize, a2: usize) -> !; - - // This symbol will be provided by the user via `#[pre_init]` - fn __pre_init(); - - fn _setup_interrupts(); - - fn _mp_hook(hartid: usize) -> bool; - } - - #[cfg(not(feature = "single-hart"))] - let run_init = { - // sbi passes hartid as first parameter (a0) - #[cfg(feature = "s-mode")] - let hartid = a0; - #[cfg(not(feature = "s-mode"))] - let hartid = mhartid::read(); - - _mp_hook(hartid) - }; - #[cfg(feature = "single-hart")] - let run_init = true; - - if run_init { - __pre_init(); - - // Initialize RAM - // 1. Copy over .data from flash to RAM - // 2. Zero out .bss - - #[cfg(target_arch = "riscv32")] - core::arch::asm!( - " - // Copy over .data - la {start},_sdata - la {end},_edata - la {input},_sidata - - bgeu {start},{end},2f - 1: - lw {a},0({input}) - addi {input},{input},4 - sw {a},0({start}) - addi {start},{start},4 - bltu {start},{end},1b - - 2: - li {a},0 - li {input},0 - - // Zero out .bss - la {start},_sbss - la {end},_ebss - - bgeu {start},{end},3f - 2: - sw zero,0({start}) - addi {start},{start},4 - bltu {start},{end},2b - - 3: - li {start},0 - li {end},0 - ", - start = out(reg) _, - end = out(reg) _, - input = out(reg) _, - a = out(reg) _, - ); - - #[cfg(target_arch = "riscv64")] - core::arch::asm!( - " - // Copy over .data - la {start},_sdata - la {end},_edata - la {input},_sidata - - bgeu {start},{end},2f - - 1: // .data Main Loop - ld {a},0({input}) - addi {input},{input},8 - sd {a},0({start}) - addi {start},{start},8 - bltu {start},{end},1b - - 2: // .data zero registers - li {a},0 - li {input},0 - - la {start},_sbss - la {end},_ebss - - bgeu {start},{end},4f - - 3: // .bss main loop - sd zero,0({start}) - addi {start},{start},8 - bltu {start},{end},3b - - 4: // .bss zero registers - // Zero out used registers - li {start},0 - li {end},0 - ", - start = out(reg) _, - end = out(reg) _, - input = out(reg) _, - a = out(reg) _, - ); - - compiler_fence(Ordering::SeqCst); - } - - #[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(); - - main(a0, a1, a2); -} - /// Registers saved in trap handler #[allow(missing_docs)] #[repr(C)] From 1241212e125b592778508fef7c5672bbc8d96e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Wed, 3 Jan 2024 21:16:45 +0100 Subject: [PATCH 05/11] fix FPU initialization --- riscv-rt/src/asm.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/riscv-rt/src/asm.rs b/riscv-rt/src/asm.rs index 772626f5..987b6ce5 100644 --- a/riscv-rt/src/asm.rs +++ b/riscv-rt/src/asm.rs @@ -184,12 +184,16 @@ cfg_global_asm!( // INITIALIZE FLOATING POINT UNIT #[cfg(any(riscvf, riscvd))] cfg_global_asm!( + " + li t0, 0x4000 // bit 14 is FS most significant bit + li t2, 0x2000 // bit 13 is FS least significant bit + ", #[cfg(feature = "s-mode")] - "csrrc x0, sstatus, 0x4000 - csrrs x0, sstatus, 0x2000", + "csrrc x0, sstatus, t0 + csrrs x0, sstatus, t2", #[cfg(not(feature = "s-mode"))] - "csrrc x0, mstatus, 0x4000 - csrrs x0, mstatus, 0x2000", + "csrrc x0, mstatus, t0 + csrrs x0, mstatus, t2", "fscsr x0", ); // ZERO OUT FLOATING POINT REGISTERS From d597a715485a17eac76c1510d45907e692dc5fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Wed, 10 Jan 2024 21:30:06 +0100 Subject: [PATCH 06/11] fix single-hart --- riscv-rt/src/asm.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/riscv-rt/src/asm.rs b/riscv-rt/src/asm.rs index 987b6ce5..810e263c 100644 --- a/riscv-rt/src/asm.rs +++ b/riscv-rt/src/asm.rs @@ -110,10 +110,11 @@ cfg_global_asm!( addi t1, t1, -1 bnez t1, 1b 2: ", - "la t1, _stack_start", - "sub t1, t1, t0", ); cfg_global_asm!( + "la t1, _stack_start", + #[cfg(not(feature = "single-hart"))] + "sub t1, t1, t0", "andi sp, t1, -16 // align stack to 16-bytes add s0, sp, zero", ); From db314d1c48d585fea6a1f34c7720d08bbd637675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas?= Date: Sun, 14 Jan 2024 11:11:32 +0100 Subject: [PATCH 07/11] minor changes --- riscv-rt/src/asm.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/riscv-rt/src/asm.rs b/riscv-rt/src/asm.rs index 810e263c..820b17f5 100644 --- a/riscv-rt/src/asm.rs +++ b/riscv-rt/src/asm.rs @@ -79,15 +79,13 @@ riscv_rt_macros::loop_global_asm!(" li x{}, 0", 1, 10); // a0..a2 (x10..x12) skipped riscv_rt_macros::loop_global_asm!(" li x{}, 0", 13, 32); -// INITIALIZE GLOBAL POINTER +// INITIALIZE GLOBAL POINTER, STACK POINTER, AND FRAME POINTER cfg_global_asm!( ".option push .option norelax la gp, __global_pointer$ .option pop", ); - -// INITIALIZE STACK POINTER AND FRAME POINTER #[cfg(not(feature = "single-hart"))] cfg_global_asm!( #[cfg(feature = "s-mode")] From 9356b4be5c4cbf157c8a784974c71d83207922cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Tue, 13 Feb 2024 17:02:32 +0100 Subject: [PATCH 08/11] minor error --- riscv-rt/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index de9b39e2..c3b6ae4d 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -476,7 +476,6 @@ pub unsafe extern "C" fn start_trap_rust(trap_frame: *const TrapFrame) { } else { ExceptionHandler(trap_frame); } - ExceptionHandler(trap_frame) } else if code < __INTERRUPTS.len() { let h = &__INTERRUPTS[code]; if let Some(handler) = h { From bd60e25ab91ee46ca7d17d55e8631b5f89c6de04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Wed, 14 Feb 2024 14:39:17 +0100 Subject: [PATCH 09/11] remove duplicates --- riscv-rt/CHANGELOG.md | 2 +- riscv-rt/src/asm.rs | 104 ------------------------------------------ 2 files changed, 1 insertion(+), 105 deletions(-) diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index 761f7442..2019a347 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Removed -- start_rust is no longer needed, as it is now wrtten in assembly +- `start_rust` is no longer needed, as it is now written in assembly ## [v0.12.1] - 2024-01-24 diff --git a/riscv-rt/src/asm.rs b/riscv-rt/src/asm.rs index 587141f2..820b17f5 100644 --- a/riscv-rt/src/asm.rs +++ b/riscv-rt/src/asm.rs @@ -203,110 +203,6 @@ riscv_rt_macros::loop_global_asm!(" fmv.d.x f{}, x0", 32); #[cfg(all(riscvf, not(riscvd)))] riscv_rt_macros::loop_global_asm!(" fmv.w.x f{}, x0", 32); -// SET UP INTERRUPTS, RESTORE a0..a2, AND JUMP TO MAIN RUST FUNCTION -cfg_global_asm!( - "call _setup_interrupts", - #[cfg(riscv32)] - "lw a0, 4 * 0(sp) - lw a1, 4 * 1(sp) - lw a2, 4 * 2(sp) - addi sp, sp, 4 * 3", - #[cfg(riscv64)] - "ld a0, 8 * 0(sp) - ld a1, 8 * 1(sp) - ld a2, 8 * 2(sp) - addi sp, sp, 8 * 3", - "jal zero, main - "andi sp, t1, -16 // align stack to 16-bytes - add s0, sp, zero", -); - -// STORE A0..A2 IN THE STACK, AS THEY WILL BE NEEDED LATER BY main -cfg_global_asm!( - #[cfg(riscv32)] - "addi sp, sp, -4 * 3 - sw a0, 4 * 0(sp) - sw a1, 4 * 1(sp) - sw a2, 4 * 2(sp)", - #[cfg(riscv64)] - "addi sp, sp, -8 * 3 - sd a0, 8 * 0(sp) - sd a1, 8 * 1(sp) - sd a2, 8 * 2(sp)", -); - -// SKIP RAM INITIALIZATION IF CURRENT HART IS NOT THE BOOT HART -#[cfg(not(feature = "single-hart"))] -cfg_global_asm!( - #[cfg(not(feature = "s-mode"))] - "csrr a0, mhartid", - "call _mp_hook - mv t0, a0 - - beqz a0, 4f", -); -// IF CURRENT HART IS THE BOOT HART CALL __pre_init AND INITIALIZE RAM -cfg_global_asm!( - "call __pre_init - // Copy .data from flash to RAM - la t0, _sdata - la t2, _edata - la t1, _sidata - bgeu t0, t2, 2f -1: ", - #[cfg(target_arch = "riscv32")] - "lw t3, 0(t1) - addi t1, t1, 4 - sw t3, 0(t0) - addi t0, t0, 4 - bltu t0, t2, 1b", - #[cfg(target_arch = "riscv64")] - "ld t3, 0(t1) - addi t1, t1, 8 - sd t3, 0(t0) - addi t0, t0, 8 - bltu t0, t2, 1b", - " -2: // Zero out .bss - la t0, _sbss - la t2, _ebss - bgeu t0, t2, 4f -3: ", - #[cfg(target_arch = "riscv32")] - "sw zero, 0(t0) - addi t0, t0, 4 - bltu t0, t2, 3b", - #[cfg(target_arch = "riscv64")] - "sd zero, 0(t0) - addi t0, t0, 8 - bltu t0, t2, 3b", - " -4: // RAM initilized", -); - -// INITIALIZE FLOATING POINT UNIT -#[cfg(any(riscvf, riscvd))] -cfg_global_asm!( - " - li t0, 0x4000 // bit 14 is FS most significant bit - li t2, 0x2000 // bit 13 is FS least significant bit - ", - #[cfg(feature = "s-mode")] - "csrrc x0, sstatus, t0 - csrrs x0, sstatus, t2", - #[cfg(not(feature = "s-mode"))] - "csrrc x0, mstatus, t0 - csrrs x0, mstatus, t2", - "fscsr x0", -); -// ZERO OUT FLOATING POINT REGISTERS -#[cfg(all(riscv32, riscvd))] -riscv_rt_macros::loop_global_asm!(" fcvt.d.w f{}, x0", 32); -#[cfg(all(riscv64, riscvd))] -riscv_rt_macros::loop_global_asm!(" fmv.d.x f{}, x0", 32); -#[cfg(all(riscvf, not(riscvd)))] -riscv_rt_macros::loop_global_asm!(" fmv.w.x f{}, x0", 32); - // SET UP INTERRUPTS, RESTORE a0..a2, AND JUMP TO MAIN RUST FUNCTION cfg_global_asm!( "call _setup_interrupts", From 0a789d4fadfdf483eb39ecb934c85bb53dd561d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Wed, 21 Feb 2024 11:37:51 +0100 Subject: [PATCH 10/11] minor changes --- riscv-rt/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index c3b6ae4d..c8c1cf62 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -311,13 +311,10 @@ //! //! This functions are called when corresponding interrupt is occured. //! You can define an interrupt handler with one of the following names: -//! * `UserSoft` //! * `SupervisorSoft` //! * `MachineSoft` -//! * `UserTimer` //! * `SupervisorTimer` //! * `MachineTimer` -//! * `UserExternal` //! * `SupervisorExternal` //! * `MachineExternal` //! From 09e1b143c496694ccf058d7d0d0f328267979241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Wed, 21 Feb 2024 11:58:46 +0100 Subject: [PATCH 11/11] update the docs --- riscv-rt/Cargo.toml | 2 +- riscv-rt/src/lib.rs | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/riscv-rt/Cargo.toml b/riscv-rt/Cargo.toml index 67e4b9e3..1c33bea1 100644 --- a/riscv-rt/Cargo.toml +++ b/riscv-rt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "riscv-rt" -version = "0.12.2" +version = "0.13.0" rust-version = "1.60" repository = "https://github.com/rust-embedded/riscv" authors = ["The RISC-V Team "] diff --git a/riscv-rt/src/lib.rs b/riscv-rt/src/lib.rs index d36bf240..863e7818 100644 --- a/riscv-rt/src/lib.rs +++ b/riscv-rt/src/lib.rs @@ -22,7 +22,8 @@ //! //! - A `_sheap` symbol at whose address you can locate a heap. //! -//! - Support for a runtime in supervisor mode, that can be bootstrapped via [Supervisor Binary Interface (SBI)](https://github.com/riscv-non-isa/riscv-sbi-doc) +//! - Support for a runtime in supervisor mode, that can be bootstrapped via +//! [Supervisor Binary Interface (SBI)](https://github.com/riscv-non-isa/riscv-sbi-doc). //! //! ``` text //! $ cargo new --bin app && cd $_ @@ -30,7 +31,7 @@ //! $ # add this crate as a dependency //! $ edit Cargo.toml && cat $_ //! [dependencies] -//! riscv-rt = "0.6.1" +//! riscv-rt = "0.13.0" //! panic-halt = "0.2.0" //! //! $ # memory layout of the device @@ -245,6 +246,8 @@ //! //! Default implementation of this function wakes hart 0 and busy-loops all the other harts. //! +//! `_mp_hook` is only necessary in multi-core targets. If the `single-hart` feature is enabled, +//! `_mp_hook` is not called, as it is assumed that there is only one hart on the target. //! //! ### Core exception handlers //! @@ -358,11 +361,12 @@ //! //! Default implementation of this function stucks in a busy-loop. //! -//! # Features +//! # Cargo Features //! //! ## `single-hart` //! //! This feature saves a little code size if there is only one hart on the target. +//! If the `single-hart` feature is enabled, `_mp_hook` is not called. //! //! ## `s-mode` //! @@ -373,9 +377,7 @@ //! [dependencies] //! riscv-rt = {features=["s-mode"]} //! ``` -//! Internally, riscv-rt uses different versions of precompiled static libraries -//! for (i) machine mode and (ii) supervisor mode. If the `s-mode` feature was activated, -//! the build script selects the s-mode library. While most registers/instructions have variants for +//! While most registers/instructions have variants for //! both `mcause` and `scause`, the `mhartid` hardware thread register is not available in supervisor //! mode. Instead, the hartid is passed as parameter by a bootstrapping firmware (i.e., SBI). //!