forked from M-Labs/artiq
libboard_misoc: vexriscv integration
Signed-off-by: occheung <dc@m-labs.hk>
This commit is contained in:
parent
2cf144a60c
commit
82b4052cd6
@ -16,6 +16,8 @@ build_misoc = { path = "../libbuild_misoc" }
|
||||
byteorder = { version = "1.0", default-features = false }
|
||||
log = { version = "0.4", 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]
|
||||
uart_console = []
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![no_std]
|
||||
#![feature(asm, try_from)]
|
||||
#![feature(llvm_asm)]
|
||||
|
||||
extern crate byteorder;
|
||||
#[cfg(feature = "log")]
|
||||
@ -11,6 +11,16 @@ extern crate smoltcp;
|
||||
#[path = "or1k/mod.rs"]
|
||||
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::*;
|
||||
|
||||
include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/mem.rs"));
|
||||
|
48
artiq/firmware/libboard_misoc/riscv32imac/boot.rs
Normal file
48
artiq/firmware/libboard_misoc/riscv32imac/boot.rs
Normal 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 {}
|
||||
}
|
35
artiq/firmware/libboard_misoc/riscv32imac/cache.rs
Normal file
35
artiq/firmware/libboard_misoc/riscv32imac/cache.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
46
artiq/firmware/libboard_misoc/riscv32imac/irq.rs
Normal file
46
artiq/firmware/libboard_misoc/riscv32imac/irq.rs
Normal 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
|
||||
}
|
3
artiq/firmware/libboard_misoc/riscv32imac/mod.rs
Normal file
3
artiq/firmware/libboard_misoc/riscv32imac/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod irq;
|
||||
pub mod cache;
|
||||
pub mod boot;
|
177
artiq/firmware/libboard_misoc/riscv32imac/vectors.S
Normal file
177
artiq/firmware/libboard_misoc/riscv32imac/vectors.S
Normal 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
|
Loading…
Reference in New Issue
Block a user