forked from M-Labs/artiq
1
0
Fork 0

libboard_misoc: vexriscv integration

Signed-off-by: occheung <dc@m-labs.hk>
This commit is contained in:
occheung 2021-07-14 17:44:44 +08:00
parent 2cf144a60c
commit 82b4052cd6
7 changed files with 322 additions and 1 deletions

View File

@ -16,6 +16,8 @@ build_misoc = { path = "../libbuild_misoc" }
byteorder = { version = "1.0", default-features = false } byteorder = { version = "1.0", default-features = false }
log = { version = "0.4", default-features = false, optional = true } log = { version = "0.4", default-features = false, optional = true }
smoltcp = { version = "0.6.0", default-features = false, optional = true } smoltcp = { version = "0.6.0", default-features = false, optional = true }
riscv = { version = "0.6.0", features = ["inline-asm"] }
vexriscv = { git = "https://github.com/occheung/vexriscv-rust.git", features = ["inline-asm"] }
[features] [features]
uart_console = [] uart_console = []

View File

@ -1,5 +1,5 @@
#![no_std] #![no_std]
#![feature(asm, try_from)] #![feature(llvm_asm)]
extern crate byteorder; extern crate byteorder;
#[cfg(feature = "log")] #[cfg(feature = "log")]
@ -11,6 +11,16 @@ extern crate smoltcp;
#[path = "or1k/mod.rs"] #[path = "or1k/mod.rs"]
mod arch; mod arch;
#[cfg(target_arch = "riscv32")]
#[path = "riscv32imac/mod.rs"]
mod arch;
#[cfg(target_arch = "riscv32")]
extern crate riscv;
#[cfg(target_arch = "riscv32")]
extern crate vexriscv;
pub use arch::*; pub use arch::*;
include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/mem.rs")); include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/mem.rs"));

View File

@ -0,0 +1,48 @@
use super::{irq, cache};
pub unsafe fn reset() -> ! {
irq::set_ie(false);
llvm_asm!(r#"
j _reset_handler
nop
"# : : : : "volatile");
loop {}
}
pub unsafe fn jump(addr: usize) -> ! {
irq::set_ie(false);
cache::flush_cpu_icache();
llvm_asm!(r#"
jalr x0, 0($0)
nop
"# : : "r"(addr) : : "volatile");
loop {}
}
pub unsafe fn hotswap(firmware: &[u8]) -> ! {
irq::set_ie(false);
llvm_asm!(r#"
# This loop overwrites itself, but it's structured in such a way
# that before that happens, it loads itself into I$$ fully.
lui a1, %hi(_reset_handler)
ori a1, a1, %lo(_reset_handler)
or a4, a1, zero
0: bnez a2, 1f
nop
jr a4
nop
1: lw a3, 0(a0)
sw a3, 0(a1)
addi a0, a0, 4
addi a1, a1, 4
addi a2, a2, -4
bnez a2, 0b
nop
"#
:
: "{a0}"(firmware.as_ptr() as usize),
"{a2}"(firmware.len())
:
: "volatile");
loop {}
}

View File

@ -0,0 +1,35 @@
#[cfg(has_ddrphy)]
use core::ptr;
#[cfg(has_ddrphy)]
use csr;
#[cfg(has_ddrphy)]
use mem;
pub fn flush_cpu_icache() {
unsafe {
llvm_asm!(r#"
fence.i
nop
nop
nop
nop
nop
"# : : : : "volatile");
}
}
pub fn flush_cpu_dcache() {
unsafe {
llvm_asm!(".word(0x500F)" : : : : "volatile");
}
}
#[cfg(has_ddrphy)]
pub fn flush_l2_cache() {
unsafe {
for i in 0..2 * (csr::CONFIG_L2_SIZE as usize) / 4 {
let addr = mem::MAIN_RAM_BASE + i * 4;
ptr::read_volatile(addr as *const usize);
}
}
}

View File

@ -0,0 +1,46 @@
use core::{convert::TryFrom};
use riscv::register::mstatus;
use vexriscv::register::{vmim, vmip};
#[inline]
pub fn get_ie() -> bool {
mstatus::read().mie()
}
#[inline]
pub fn set_ie(ie: bool) {
unsafe {
if ie {
mstatus::set_mie()
} else {
mstatus::clear_mie()
}
}
}
#[inline]
pub fn get_mask() -> u32 {
u32::try_from(vmim::read()).unwrap()
}
#[inline]
pub fn set_mask(mask: u32) {
vmim::write(usize::try_from(mask).unwrap())
}
#[inline]
pub fn pending_mask() -> u32 {
u32::try_from(vmip::read()).unwrap()
}
pub fn enable(irq: u32) {
set_mask(get_mask() | (1 << irq))
}
pub fn disable(irq: u32) {
set_mask(get_mask() & !(1 << irq))
}
pub fn is_pending(irq: u32) -> bool {
get_mask() & (1 << irq) != 0
}

View File

@ -0,0 +1,3 @@
pub mod irq;
pub mod cache;
pub mod boot;

View File

@ -0,0 +1,177 @@
# Adapted from riscv-rt project, with the following license:
#
# Copyright 2018 RISC-V team
#
# Permission to use, copy, modify, and/or distribute this software for any purpose
# with or without fee is hereby granted, provided that the above copyright notice and
# this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
# ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#if __riscv_xlen == 64
# define STORE sd
# define LOAD ld
# define LOG_REGBYTES 3
#else
# define STORE sw
# define LOAD lw
# define LOG_REGBYTES 2
#endif
#define REGBYTES (1 << LOG_REGBYTES)
/*
Entry point of all programs (_reset_handler).
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.
*/
.section .vectors, "ax", @progbits
.global _reset_handler
_reset_handler:
/* Jump to the absolute address defined by the linker script. */
// for 32bit
.if __riscv_xlen == 32
lui ra, %hi(_abs_start)
jr %lo(_abs_start)(ra)
.endif
// for 64bit
.if __riscv_xlen == 64
.option push
.option norelax // to prevent an unsupported R_RISCV_ALIGN relocation from being generated
1:
auipc ra, %pcrel_hi(1f)
ld ra, %pcrel_lo(1b)(ra)
jr ra
.align 3
1:
.dword _abs_start
.option pop
.endif
_abs_start:
.cfi_startproc
.cfi_undefined ra
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
li x10,0
li x11,0
li x12,0
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
// Check hart id
csrr a2, mhartid
// Allocate stacks
la sp, _fstack
// Set frame pointer
add s0, sp, zero
// Set trap vector
la t0, _start_trap
csrw mtvec, t0
// Zero initialize .bss
la t0, _fbss
la t1, _ebss
beq t0, t1, 2f
1: STORE zero, 0(t0)
addi t0, t0, REGBYTES
bne t0, t1, 1b
2:
// Enter main firmware
jal zero, main
.cfi_endproc
/*
Trap entry point (_start_trap)
Saves caller saved registers ra, t0..6, a0..7, calls exception,
restores caller saved registers and then returns.
*/
.section .trap, "ax"
.global _start_trap
/* Make it .weak so PAC/HAL can provide their own if needed. */
.weak _start_trap
_start_trap:
addi sp, sp, -16*REGBYTES
STORE ra, 0*REGBYTES(sp)
STORE t0, 1*REGBYTES(sp)
STORE t1, 2*REGBYTES(sp)
STORE t2, 3*REGBYTES(sp)
STORE t3, 4*REGBYTES(sp)
STORE t4, 5*REGBYTES(sp)
STORE t5, 6*REGBYTES(sp)
STORE t6, 7*REGBYTES(sp)
STORE a0, 8*REGBYTES(sp)
STORE a1, 9*REGBYTES(sp)
STORE a2, 10*REGBYTES(sp)
STORE a3, 11*REGBYTES(sp)
STORE a4, 12*REGBYTES(sp)
STORE a5, 13*REGBYTES(sp)
STORE a6, 14*REGBYTES(sp)
STORE a7, 15*REGBYTES(sp)
add a0, sp, zero
jal ra, exception
LOAD ra, 0*REGBYTES(sp)
LOAD t0, 1*REGBYTES(sp)
LOAD t1, 2*REGBYTES(sp)
LOAD t2, 3*REGBYTES(sp)
LOAD t3, 4*REGBYTES(sp)
LOAD t4, 5*REGBYTES(sp)
LOAD t5, 6*REGBYTES(sp)
LOAD t6, 7*REGBYTES(sp)
LOAD a0, 8*REGBYTES(sp)
LOAD a1, 9*REGBYTES(sp)
LOAD a2, 10*REGBYTES(sp)
LOAD a3, 11*REGBYTES(sp)
LOAD a4, 12*REGBYTES(sp)
LOAD a5, 13*REGBYTES(sp)
LOAD a6, 14*REGBYTES(sp)
LOAD a7, 15*REGBYTES(sp)
addi sp, sp, 16*REGBYTES
mret