Skip to content

Commit f5a2da9

Browse files
Merge pull request #186 from rust-embedded/riscv-rt-asm
`riscv-rt`: move all the assembly code to `asm.rs`
2 parents 527b27d + 09e1b14 commit f5a2da9

File tree

6 files changed

+202
-225
lines changed

6 files changed

+202
-225
lines changed

.github/workflows/riscv-rt.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
on:
22
push:
3-
branches: [ master ]
3+
branches: [ master, riscv-rt-asm ]
44
pull_request:
55
merge_group:
66

riscv-rt/CHANGELOG.md

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

88
## [Unreleased]
99

10+
### Changed
11+
12+
- Moved all the assembly code to `asm.rs`
13+
14+
### Removed
15+
16+
- `start_rust` is no longer needed, as it is now written in assembly
17+
1018
## [v0.12.2] - 2024-02-15
1119

1220
### Added
@@ -33,6 +41,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
3341

3442
### Changed
3543

44+
- Removed _start_rust. Now, assembly directly jumps to main
3645
- Removed U-mode interrupts to align with latest RISC-V specification
3746
- Changed `Vector` union. Now, it uses `Option<fn>`, which is more idiomatic in Rust
3847
- Removed riscv-target dependency for build

riscv-rt/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "riscv-rt"
3-
version = "0.12.2"
3+
version = "0.13.0"
44
rust-version = "1.60"
55
repository = "https://github.com/rust-embedded/riscv"
66
authors = ["The RISC-V Team <risc-v@teams.rust-embedded.org>"]

riscv-rt/macros/src/lib.rs

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -212,46 +212,59 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
212212

213213
struct AsmLoopArgs {
214214
asm_template: String,
215-
count: usize,
215+
count_from: usize,
216+
count_to: usize,
216217
}
217218

218219
impl Parse for AsmLoopArgs {
219220
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
220221
let template: LitStr = input.parse().unwrap();
221222
_ = input.parse::<Token![,]>().unwrap();
222223
let count: LitInt = input.parse().unwrap();
223-
224-
Ok(Self {
225-
asm_template: template.value(),
226-
count: count.base10_parse().unwrap(),
227-
})
224+
if input.parse::<Token![,]>().is_ok() {
225+
let count_to: LitInt = input.parse().unwrap();
226+
Ok(Self {
227+
asm_template: template.value(),
228+
count_from: count.base10_parse().unwrap(),
229+
count_to: count_to.base10_parse().unwrap(),
230+
})
231+
} else {
232+
Ok(Self {
233+
asm_template: template.value(),
234+
count_from: 0,
235+
count_to: count.base10_parse().unwrap(),
236+
})
237+
}
228238
}
229239
}
230240

231241
/// Loops an asm expression n times.
232242
///
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.
243+
/// `loop_asm!` takes 2 or 3 arguments, the first is a string literal and the rest are a number literal
244+
/// See [the formatting syntax documentation in `std::fmt`](../std/fmt/index.html) for details.
236245
///
237246
/// Argument 1 is an assembly expression, all "{}" in this assembly expression will be replaced with the
238247
/// current loop index.
239248
///
240-
/// Argument 2 is the number of loops to do with the provided expression.
249+
/// If 2 arguments are provided, the loop will start at 0 and end at the number provided in argument 2.
250+
///
251+
/// If 3 arguments are provided, the loop will start at the number provided in argument 2 and end at
252+
/// the number provided in argument 3.
241253
///
242254
/// # Examples
243255
///
244256
/// ```
245257
/// # use riscv_rt_macros::loop_asm;
246258
/// unsafe {
247259
/// loop_asm!("fmv.w.x f{}, x0", 32); // => core::arch::asm!("fmv.w.x f0, x0") ... core::arch::asm!("fmv.w.x f31, x0")
260+
/// 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")
248261
/// }
249262
/// ```
250263
#[proc_macro]
251264
pub fn loop_asm(input: TokenStream) -> TokenStream {
252265
let args = parse_macro_input!(input as AsmLoopArgs);
253266

254-
let tokens = (0..args.count)
267+
let tokens = (args.count_from..args.count_to)
255268
.map(|i| {
256269
let i = i.to_string();
257270
let asm = args.asm_template.replace("{}", &i);
@@ -261,3 +274,41 @@ pub fn loop_asm(input: TokenStream) -> TokenStream {
261274
.join("\n");
262275
tokens.parse().unwrap()
263276
}
277+
278+
/// Loops a global_asm expression n times.
279+
///
280+
/// `loop_global_asm!` takes 2 or 3 arguments, the first is a string literal and the rest are a number literal
281+
/// See [the formatting syntax documentation in `std::fmt`](../std/fmt/index.html) for details.
282+
///
283+
/// Argument 1 is an assembly expression, all "{}" in this assembly expression will be replaced with the
284+
/// current loop index.
285+
///
286+
/// If 2 arguments are provided, the loop will start at 0 and end at the number provided in argument 2.
287+
///
288+
/// If 3 arguments are provided, the loop will start at the number provided in argument 2 and end at
289+
/// the number provided in argument 3.
290+
///
291+
/// # Examples
292+
///
293+
/// ```
294+
/// # use riscv_rt_macros::loop_global_asm;
295+
/// unsafe {
296+
/// 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")
297+
/// 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")
298+
/// }
299+
/// ```
300+
#[proc_macro]
301+
pub fn loop_global_asm(input: TokenStream) -> TokenStream {
302+
let args = parse_macro_input!(input as AsmLoopArgs);
303+
304+
let instructions = (args.count_from..args.count_to)
305+
.map(|i| {
306+
let i = i.to_string();
307+
args.asm_template.replace("{}", &i)
308+
})
309+
.collect::<Vec<String>>()
310+
.join("\n");
311+
312+
let res = format!("core::arch::global_asm!(\n\"{}\"\n);", instructions);
313+
res.parse().unwrap()
314+
}

riscv-rt/src/asm.rs

Lines changed: 121 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -72,54 +72,34 @@ _abs_start:
7272
#[cfg(not(feature = "s-mode"))]
7373
"csrw mie, 0
7474
csrw mip, 0",
75-
"li x1, 0
76-
li x2, 0
77-
li x3, 0
78-
li x4, 0
79-
li x5, 0
80-
li x6, 0
81-
li x7, 0
82-
li x8, 0
83-
li x9, 0
84-
// a0..a2 (x10..x12) skipped
85-
li x13, 0
86-
li x14, 0
87-
li x15, 0
88-
li x16, 0
89-
li x17, 0
90-
li x18, 0
91-
li x19, 0
92-
li x20, 0
93-
li x21, 0
94-
li x22, 0
95-
li x23, 0
96-
li x24, 0
97-
li x25, 0
98-
li x26, 0
99-
li x27, 0
100-
li x28, 0
101-
li x29, 0
102-
li x30, 0
103-
li x31, 0
75+
);
76+
77+
// ZERO OUT GENERAL-PURPOSE REGISTERS
78+
riscv_rt_macros::loop_global_asm!(" li x{}, 0", 1, 10);
79+
// a0..a2 (x10..x12) skipped
80+
riscv_rt_macros::loop_global_asm!(" li x{}, 0", 13, 32);
10481

105-
.option push
82+
// INITIALIZE GLOBAL POINTER, STACK POINTER, AND FRAME POINTER
83+
cfg_global_asm!(
84+
".option push
10685
.option norelax
10786
la gp, __global_pointer$
108-
.option pop
109-
// Allocate stacks",
110-
#[cfg(all(not(feature = "single-hart"), feature = "s-mode"))]
87+
.option pop",
88+
);
89+
#[cfg(not(feature = "single-hart"))]
90+
cfg_global_asm!(
91+
#[cfg(feature = "s-mode")]
11192
"mv t2, a0 // the hartid is passed as parameter by SMODE",
112-
#[cfg(all(not(feature = "single-hart"), not(feature = "s-mode")))]
93+
#[cfg(not(feature = "s-mode"))]
11394
"csrr t2, mhartid",
114-
#[cfg(not(feature = "single-hart"))]
11595
"lui t0, %hi(_max_hart_id)
11696
add t0, t0, %lo(_max_hart_id)
11797
bgtu t2, t0, abort
11898
lui t0, %hi(_hart_stack_size)
11999
add t0, t0, %lo(_hart_stack_size)",
120-
#[cfg(all(not(feature = "single-hart"), riscvm))]
100+
#[cfg(riscvm)]
121101
"mul t0, t2, t0",
122-
#[cfg(all(not(feature = "single-hart"), not(riscvm)))]
102+
#[cfg(not(riscvm))]
123103
"beqz t2, 2f // Jump if single-hart
124104
mv t1, t2
125105
mv t3, t0
@@ -128,15 +108,115 @@ _abs_start:
128108
addi t1, t1, -1
129109
bnez t1, 1b
130110
2: ",
111+
);
112+
cfg_global_asm!(
131113
"la t1, _stack_start",
132114
#[cfg(not(feature = "single-hart"))]
133115
"sub t1, t1, t0",
134-
"andi sp, t1, -16 // Force 16-byte alignment
135-
// Set frame pointer
136-
add s0, sp, zero
116+
"andi sp, t1, -16 // align stack to 16-bytes
117+
add s0, sp, zero",
118+
);
137119

138-
jal zero, _start_rust
120+
// STORE A0..A2 IN THE STACK, AS THEY WILL BE NEEDED LATER BY main
121+
cfg_global_asm!(
122+
#[cfg(riscv32)]
123+
"addi sp, sp, -4 * 3
124+
sw a0, 4 * 0(sp)
125+
sw a1, 4 * 1(sp)
126+
sw a2, 4 * 2(sp)",
127+
#[cfg(riscv64)]
128+
"addi sp, sp, -8 * 3
129+
sd a0, 8 * 0(sp)
130+
sd a1, 8 * 1(sp)
131+
sd a2, 8 * 2(sp)",
132+
);
139133

134+
// SKIP RAM INITIALIZATION IF CURRENT HART IS NOT THE BOOT HART
135+
#[cfg(not(feature = "single-hart"))]
136+
cfg_global_asm!(
137+
#[cfg(not(feature = "s-mode"))]
138+
"csrr a0, mhartid",
139+
"call _mp_hook
140+
mv t0, a0
141+
142+
beqz a0, 4f",
143+
);
144+
// IF CURRENT HART IS THE BOOT HART CALL __pre_init AND INITIALIZE RAM
145+
cfg_global_asm!(
146+
"call __pre_init
147+
// Copy .data from flash to RAM
148+
la t0, _sdata
149+
la t2, _edata
150+
la t1, _sidata
151+
bgeu t0, t2, 2f
152+
1: ",
153+
#[cfg(target_arch = "riscv32")]
154+
"lw t3, 0(t1)
155+
addi t1, t1, 4
156+
sw t3, 0(t0)
157+
addi t0, t0, 4
158+
bltu t0, t2, 1b",
159+
#[cfg(target_arch = "riscv64")]
160+
"ld t3, 0(t1)
161+
addi t1, t1, 8
162+
sd t3, 0(t0)
163+
addi t0, t0, 8
164+
bltu t0, t2, 1b",
165+
"
166+
2: // Zero out .bss
167+
la t0, _sbss
168+
la t2, _ebss
169+
bgeu t0, t2, 4f
170+
3: ",
171+
#[cfg(target_arch = "riscv32")]
172+
"sw zero, 0(t0)
173+
addi t0, t0, 4
174+
bltu t0, t2, 3b",
175+
#[cfg(target_arch = "riscv64")]
176+
"sd zero, 0(t0)
177+
addi t0, t0, 8
178+
bltu t0, t2, 3b",
179+
"
180+
4: // RAM initilized",
181+
);
182+
183+
// INITIALIZE FLOATING POINT UNIT
184+
#[cfg(any(riscvf, riscvd))]
185+
cfg_global_asm!(
186+
"
187+
li t0, 0x4000 // bit 14 is FS most significant bit
188+
li t2, 0x2000 // bit 13 is FS least significant bit
189+
",
190+
#[cfg(feature = "s-mode")]
191+
"csrrc x0, sstatus, t0
192+
csrrs x0, sstatus, t2",
193+
#[cfg(not(feature = "s-mode"))]
194+
"csrrc x0, mstatus, t0
195+
csrrs x0, mstatus, t2",
196+
"fscsr x0",
197+
);
198+
// ZERO OUT FLOATING POINT REGISTERS
199+
#[cfg(all(riscv32, riscvd))]
200+
riscv_rt_macros::loop_global_asm!(" fcvt.d.w f{}, x0", 32);
201+
#[cfg(all(riscv64, riscvd))]
202+
riscv_rt_macros::loop_global_asm!(" fmv.d.x f{}, x0", 32);
203+
#[cfg(all(riscvf, not(riscvd)))]
204+
riscv_rt_macros::loop_global_asm!(" fmv.w.x f{}, x0", 32);
205+
206+
// SET UP INTERRUPTS, RESTORE a0..a2, AND JUMP TO MAIN RUST FUNCTION
207+
cfg_global_asm!(
208+
"call _setup_interrupts",
209+
#[cfg(riscv32)]
210+
"lw a0, 4 * 0(sp)
211+
lw a1, 4 * 1(sp)
212+
lw a2, 4 * 2(sp)
213+
addi sp, sp, 4 * 3",
214+
#[cfg(riscv64)]
215+
"ld a0, 8 * 0(sp)
216+
ld a1, 8 * 1(sp)
217+
ld a2, 8 * 2(sp)
218+
addi sp, sp, 8 * 3",
219+
"jal zero, main
140220
.cfi_endproc",
141221
);
142222

0 commit comments

Comments
 (0)