-
-
Couldn't load subscription status.
- Fork 780
Add initial RISC-V support + HiFive board #1317
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| [package] | ||
| name = "rv32i" | ||
| version = "0.1.0" | ||
| authors = ["Tock Project Developers <[email protected]>"] | ||
| edition = "2018" | ||
|
|
||
| [dependencies] | ||
| kernel = { path = "../../kernel" } | ||
| tock_rt0 = { path = "../../libraries/tock-rt0" } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| RISC-V 32 Bit Integer Architecture (rv32i) | ||
| ========================================== | ||
|
|
||
| This crate contains startup code and other base support for 32 bit RISC-V | ||
| chips. | ||
|
|
||
|
|
||
| ISA Documentation | ||
| ----------------- | ||
|
|
||
| - [Specifications](https://github.com/riscv/riscv-isa-manual/releases) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| #![crate_name = "rv32i"] | ||
| #![crate_type = "rlib"] | ||
| #![feature(asm, const_fn, lang_items, global_asm)] | ||
| #![feature(crate_visibility_modifier)] | ||
| #![no_std] | ||
|
|
||
| pub mod machine_timer; | ||
| pub mod plic; | ||
| pub mod support; | ||
|
|
||
| extern "C" { | ||
| // Where the end of the stack region is (and hence where the stack should | ||
| // start). | ||
| static _estack: u32; | ||
|
|
||
| // Address of _start_trap. | ||
| static _start_trap: u32; | ||
|
|
||
| // Boundaries of the .bss section. | ||
| static mut _szero: u32; | ||
| static mut _ezero: u32; | ||
|
|
||
| // Where the .data section is stored in flash. | ||
| static mut _etext: u32; | ||
|
|
||
| // Boundaries of the .data section. | ||
| static mut _srelocate: u32; | ||
| static mut _erelocate: u32; | ||
| } | ||
|
|
||
| // Entry point of all programs (_start). | ||
| // | ||
| // It initializes DWARF call frame information, the stack pointer, the | ||
| // frame pointer (needed for closures to work in start_rust) and the global | ||
| // pointer. Then it calls _start_rust. | ||
| #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] | ||
| global_asm!( | ||
| r#" | ||
| .section .riscv.start, "ax" | ||
| .globl _start | ||
| _start: | ||
| .cfi_startproc | ||
| .cfi_undefined ra | ||
|
|
||
| // Set the global pointer register using the variable defined in the linker | ||
| // script. This register is only set once. The global pointer is a method | ||
| // for sharing state between the linker and the CPU so that the linker can | ||
| // emit code with offsets that are relative to the gp register, and the CPU | ||
| // can successfully execute them. | ||
| // | ||
| // https://gnu-mcu-eclipse.github.io/arch/riscv/programmer/#the-gp-global-pointer-register | ||
| // https://groups.google.com/a/groups.riscv.org/forum/#!msg/sw-dev/60IdaZj27dY/5MydPLnHAQAJ | ||
| // https://www.sifive.com/blog/2017/08/28/all-aboard-part-3-linker-relaxation-in-riscv-toolchain/ | ||
| // | ||
| lui gp, %hi(__global_pointer$) | ||
| addi gp, gp, %lo(__global_pointer$) | ||
|
|
||
| // Initialize the stack pointer register. This comes directly from the linker | ||
| // script. | ||
| lui sp, %hi(_estack) | ||
| addi sp, sp, %lo(_estack) | ||
|
|
||
| // Set s0 (the frame pointer) to the start of the stack. | ||
| add s0, sp, zero | ||
|
|
||
| // With that initial setup out of the way, we now branch to the main code, | ||
| // likely defined in a board's main.rs. | ||
| jal zero, reset_handler | ||
|
|
||
| .cfi_endproc | ||
| "# | ||
| ); | ||
|
|
||
| /// Setup memory for the kernel. | ||
| /// | ||
| /// This moves the data segment from flash to RAM and zeros out the BSS section. | ||
| pub unsafe fn init_memory() { | ||
bradjc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| tock_rt0::init_data(&mut _etext, &mut _srelocate, &mut _erelocate); | ||
| tock_rt0::zero_bss(&mut _szero, &mut _ezero); | ||
| } | ||
|
|
||
| /// Tell the MCU what address the trap handler is located at. | ||
| /// | ||
| /// The trap handler is called on exceptions and for interrupts. | ||
| pub unsafe fn configure_trap_handler() { | ||
| asm!(" | ||
| // The csrw instruction writes a Control and Status Register (CSR) | ||
| // with a new value. | ||
| // | ||
| // CSR 0x305 (mtvec, 'Machine trap-handler base address.') sets the address | ||
| // of the trap handler. We do not care about its old value, so we don't | ||
| // bother reading it. | ||
| csrw 0x305, $0 // Write the mtvec CSR. | ||
| " | ||
| : | ||
| : "r"(&_start_trap) | ||
| : | ||
| : "volatile"); | ||
| } | ||
|
|
||
| // Trap entry point (_start_trap) | ||
| // | ||
| // Saves caller saved registers ra, t0..6, a0..7, calls _start_trap_rust, | ||
| // restores caller saved registers and then returns. | ||
| #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] | ||
| global_asm!( | ||
| r#" | ||
| .section .riscv.trap, "ax" | ||
| .align 6 | ||
| //.p2align 6 | ||
| .global _start_trap | ||
|
|
||
| _start_trap: | ||
|
|
||
| // No usermode support, so we unconditionally assume we came from the kernel. | ||
|
|
||
| addi sp, sp, -16*4 | ||
|
|
||
| sw ra, 0*4(sp) | ||
| sw t0, 1*4(sp) | ||
| sw t1, 2*4(sp) | ||
| sw t2, 3*4(sp) | ||
| sw t3, 4*4(sp) | ||
| sw t4, 5*4(sp) | ||
| sw t5, 6*4(sp) | ||
| sw t6, 7*4(sp) | ||
| sw a0, 8*4(sp) | ||
| sw a1, 9*4(sp) | ||
| sw a2, 10*4(sp) | ||
| sw a3, 11*4(sp) | ||
| sw a4, 12*4(sp) | ||
| sw a5, 13*4(sp) | ||
| sw a6, 14*4(sp) | ||
| sw a7, 15*4(sp) | ||
|
|
||
| jal ra, _start_trap_rust | ||
|
|
||
| lw ra, 0*4(sp) | ||
| lw t0, 1*4(sp) | ||
| lw t1, 2*4(sp) | ||
| lw t2, 3*4(sp) | ||
| lw t3, 4*4(sp) | ||
| lw t4, 5*4(sp) | ||
| lw t5, 6*4(sp) | ||
| lw t6, 7*4(sp) | ||
| lw a0, 8*4(sp) | ||
| lw a1, 9*4(sp) | ||
| lw a2, 10*4(sp) | ||
| lw a3, 11*4(sp) | ||
| lw a4, 12*4(sp) | ||
| lw a5, 13*4(sp) | ||
| lw a6, 14*4(sp) | ||
| lw a7, 15*4(sp) | ||
|
|
||
| addi sp, sp, 16*4 | ||
|
|
||
| mret | ||
| "# | ||
| ); | ||
|
|
||
| /// Trap entry point rust (_start_trap_rust) | ||
| #[export_name = "_start_trap_rust"] | ||
| pub extern "C" fn start_trap_rust() {} | ||
|
|
||
| // Make sure there is an abort when linking. | ||
| // | ||
| // I don't know why we need this, or why cortex-m doesn't seem to have it. | ||
| #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] | ||
| global_asm!( | ||
| r#" | ||
| .section .init | ||
| .globl abort | ||
| abort: | ||
| jal zero, _start | ||
| "# | ||
| ); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| //! Create a timer using the Machine Timer registers. | ||
|
|
||
| use kernel::common::cells::OptionalCell; | ||
| use kernel::common::registers::{register_bitfields, ReadOnly, ReadWrite}; | ||
| use kernel::common::StaticRef; | ||
| use kernel::hil; | ||
|
|
||
| const MTIME_BASE: StaticRef<MachineTimerRegisters> = | ||
| unsafe { StaticRef::new(0x0200_0000 as *const MachineTimerRegisters) }; | ||
|
|
||
| #[repr(C)] | ||
| struct MachineTimerRegisters { | ||
| _reserved0: [u8; 0x4000], | ||
| mtimecmp: ReadWrite<u64, MTimeCmp::Register>, | ||
| _reserved1: [u8; 0x7FF0], | ||
| mtime: ReadOnly<u64, MTime::Register>, | ||
| } | ||
|
|
||
| register_bitfields![u64, | ||
| MTimeCmp [ | ||
| MTIMECMP OFFSET(0) NUMBITS(64) [] | ||
| ], | ||
| MTime [ | ||
| MTIME OFFSET(0) NUMBITS(64) [] | ||
| ] | ||
| ]; | ||
|
|
||
| pub static mut MACHINETIMER: MachineTimer = MachineTimer::new(); | ||
|
|
||
| pub struct MachineTimer { | ||
| registers: StaticRef<MachineTimerRegisters>, | ||
| client: OptionalCell<&'static hil::time::Client>, | ||
| } | ||
|
|
||
| impl MachineTimer { | ||
| const fn new() -> MachineTimer { | ||
| MachineTimer { | ||
| registers: MTIME_BASE, | ||
| client: OptionalCell::empty(), | ||
| } | ||
| } | ||
|
|
||
| pub fn set_client(&self, client: &'static hil::time::Client) { | ||
| self.client.set(client); | ||
| } | ||
|
|
||
| pub fn handle_interrupt(&self) { | ||
| self.disable_machine_timer(); | ||
|
|
||
| self.client.map(|client| { | ||
| client.fired(); | ||
| }); | ||
| } | ||
|
|
||
| fn disable_machine_timer(&self) { | ||
| // Disable by setting the mtimecmp register to its max value, which | ||
| // we will never hit. | ||
| self.registers | ||
| .mtimecmp | ||
| .write(MTimeCmp::MTIMECMP.val(0xFFFF_FFFF_FFFF_FFFF)); | ||
| } | ||
| } | ||
|
|
||
| impl hil::time::Time for MachineTimer { | ||
| type Frequency = hil::time::Freq32KHz; | ||
|
|
||
| fn disable(&self) { | ||
| self.disable_machine_timer(); | ||
| } | ||
|
|
||
| fn is_armed(&self) -> bool { | ||
| // Check if mtimecmp is the max value. If it is, then we are not armed, | ||
| // otherwise we assume we have a value set. | ||
| self.registers.mtimecmp.get() != 0xFFFF_FFFF_FFFF_FFFF | ||
| } | ||
| } | ||
|
|
||
| impl hil::time::Alarm for MachineTimer { | ||
| fn now(&self) -> u32 { | ||
| self.registers.mtime.get() as u32 | ||
| } | ||
|
|
||
| fn set_alarm(&self, tics: u32) { | ||
| self.registers | ||
| .mtimecmp | ||
| .write(MTimeCmp::MTIMECMP.val(tics as u64)); | ||
| } | ||
|
|
||
| fn get_alarm(&self) -> u32 { | ||
| self.registers.mtimecmp.get() as u32 | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A while ago we talked about migrating away from inline assembly and instead just relying on assembly, linked as C functions. IIRC this was because of the optimization tricks the compiler does such that the generated assembly may (unless you get all of the annotations right) not be what you wrote.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, yes, this will be fixed in the next PR. It's fixed in the
riscv2branch.