rust-embedded / wg

Coordination repository of the embedded devices Working Group
1.91k stars 98 forks source link

Transfer riscv-rust repos to rust-embedded org #152

Closed dvc94ch closed 6 years ago

dvc94ch commented 6 years ago

Crates to transfer are riscv-rt, riscv and riscv-quickstart.

dvc94ch commented 6 years ago

Marking only use stable features as wont-fix because there's not much point if you have to build a gcc riscv toolchain from source...

Moved add a cargo template for riscv to the riscv-quickstart repos https://github.com/riscv-rust/riscv-rust-quickstart/issues/3

japaric commented 6 years ago

@dvc94ch I have enabled branch protection in the riscv and riscv-rt repos. Now everything must go through PRs and bors before landing.

Marking only use stable features as wont-fix because there's not much point if you have to build a gcc riscv toolchain from source...

You mean there won't be an option to use these crates on stable? I would ask you to reconsider: there are some people that value stability very highly and would be OK with depending on a C toolchain if that means their program won't break overnight -- it would be great if these crates had an option to work on stable.

dvc94ch commented 6 years ago

@japaric is there a way to leverage the built-in llvm as an assembler? Also I don't mind reviewing PRs if someone else wants to do it...

japaric commented 6 years ago

@dvc94ch that would be asm! and global_asm! but they are unstable because makes no stability promise about their assembly syntax.

dvc94ch commented 6 years ago

I can understand why asm! isn't stable since it depends on the llvm-ir. But global_asm! uses plain assembly which should conform to the target architecture's assembler manual. Other options would be distribute the llvm-mc with rust or porting llvm-mc to rust https://github.com/llvm-mirror/llvm/blob/master/tools/llvm-mc/llvm-mc.cpp

NOTE: People who aren't willing to use nightly likely aren't willing to use the llvm riscv backend yet either...

danc86 commented 6 years ago

I was curious how the ARM crates had got around this issue.

If I understand rightly, there are LLVM "intrinsics" for all the important instructions, which are exposed as Rust functions in the stdsimd crate (have to admit, how this bit works is a mystery to me) and then re-exported in std::arch, and then the embedded ARM crates are using those to avoid having any inline assembly...?

At least that is how I understood it from reading over the various old issues, but now that I am looking through the cortex-m and cortex-m-rt crates I don't see any calls to stuff in std::arch. Can the ARM crates get away without invoking any special CPU instructions because on ARM everything is doing by writing to special registers using normal load instructions? I also don't see where the stack pointer or global pointer are being set... are they zeroed by hardware on the Cortex-M or something like that?

Anyway... I guess doing the above (with LLVM intrinsics exposed as Rust functions) is the most viable way forward to avoid inline assembly in the RISCV crates.

But our first problem is there are no LLVM intrinsics for RISCV yet...

japaric commented 6 years ago

have to admit, how this bit works is a mystery to me

The "intrinsics" are just thin wrappers around inline assembly (see rust-lang-nursery/stdsimd#518); they are not proper LLVM intrinsics.

everything is doing by writing to special registers using normal load instructions?

Modifying special registers require the MSR and MRS instructions. Normal loads use the LDR instruction. You need assembly (or intrinsics) to modify any special register; you can't modify those registers with pure Rust code because they have no address.

I also don't see where the stack pointer or global pointer are being set

The initial value of the stack pointer is stored in nonvolatile memory (see first entry of the vector table). The processor sets the stack pointer on boot.

I don't see any calls to stuff in std::arch

That's because they have not been stabilized yet. Those two crates compile on beta and stable because they are currently using external assembly (see https://github.com/rust-embedded/cortex-m/tree/master/asm). To replace the external assembly with the core::arch functions the API would have to be stabilized first.

But our first problem is there are no LLVM intrinsics for RISCV yet...

You don't need LLVM intrinsics. You can implement the inttrinsics using inline assembly but you need a standard or similar that says how the special registers are to be modified using a C API (see ACLE and CMSIS) then the C API can be ported to Rust.

danc86 commented 6 years ago

Thanks for the explanation @japaric , turns out I did not understand it at all. :-)

I didn't notice the external assembly files in cortex-m. It's using the cc crate to invoke a C compiler at build time to compile the assembly files, right? I guess that's what @dvc94ch was referring to when he said:

there's not much point if you have to build a gcc riscv toolchain from source...

particularly since it looks like we won't need a GNU ld anymore now either. It would be a shame if people still had to build a GNU cross toolchain for these bits of asm.

I'm curious about how the ACLE and CMSIS APIs work for ARM... These are just some functions/macros that are built into the compiler, or provided by some special headers included with the toolchain? And then the compiler takes care of emitting the right privileged instructions? When you say "then the C API can be ported to Rust" do you mean, the core::arch functions will just be wrappers that call into the C API using this technique: https://doc.rust-lang.org/nomicon/ffi.html ? Does that mean the ARM toolchains provide like a static library with all the symbols like __get_IPSR etc, which you can then link into your Rust program? Doesn't that mean you still end up depending on an external toolchain then?

Sorry for all the dumb questions, this is all very mysterious to me still :-)

danc86 commented 6 years ago

Anyway from what I can tell there is no such standard C API for manipulating the special registers in RISCV. The answer is "just use inline asm". :grimacing:

In light of that, would it make sense to pursue the idea of LLVM intrinsics for RISCV? I'm still unsure how they could be exposed in Rust though.

dvc94ch commented 6 years ago

I think @japaric meant writing the equivalent of the CMSIS API in rust and add that to for example libcore so that it doesn't matter if there is any inline assembly.

In light of that, would it make sense to pursue the idea of LLVM intrinsics for RISCV? I'm still unsure how they could be exposed in Rust though.

I think we should wait for the cortex-m crate to do this. They do a lot of work for us by opening RFC's etc. xD

danc86 commented 6 years ago

Ahh gotcha. It's okay to use inline asm in the implementation of core, even in stable Rust, because it's not exposed directly to users.

Why does the Rust implementation need to follow a "standard" C API from some vendor toolchain? In the case of RISCV where no standard C API exists, could we just make one up?

Anyway yes I agree, it seems like we should let the cortex-m folks blaze the trail for us here. :-)

japaric commented 6 years ago

These are just some functions/macros that are built into the compiler, or provided by some special headers included with the toolchain?

In the case CMSIS they are headers that provide the API implemented on top of whatever the underlying compiler supports (e.g. the assembly macro). See https://github.com/ARM-software/CMSIS_5/blob/develop/CMSIS/Core/Include/cmsis_gcc.h , which is a reference implementation.

From what I understand ACLE is supposed to be supported at the compiler level but I never have used a compiler that supports ACLE so I'm not sure.

Why does the Rust implementation need to follow a "standard" C API from some vendor toolchain?

Because there's a precedent: there's an accepted RFC that says that we can add SIMD API to core::arch if it exactly matches a vendor API. Thus we only need a simpler RFC to add non-SIMD Cortex-M API that matches a vendor specification (e.g. CMSIS or ACLE) to core::arch.

could we just make one up?

You can but it would be harder to get an RFC for that accepted. i.e. the Rust team may prefer not to accept a custom API and instead way for a vendor spec to appear.

dvc94ch commented 6 years ago

Why does the Rust implementation need to follow a "standard" C API from some vendor toolchain? In the case of RISCV where no standard C API exists, could we just make one up?

You can but it would be harder to get an RFC for that accepted. i.e. the Rust team may prefer not to accept a custom API and instead way for a vendor spec to appear.

That's exactly what I was just writing...

danc86 commented 6 years ago

Makes sense, thanks for explaining.