initial commit
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
commit
79114aa65a
9
.cargo/config
Normal file
9
.cargo/config
Normal file
@ -0,0 +1,9 @@
|
||||
[target.riscv32i-unknown-none-elf]
|
||||
#runner = "riscv64-unknown-elf-gdb -x gdb_init"
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tmemory.x",
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
]
|
||||
|
||||
[build]
|
||||
target = "riscv32i-unknown-none-elf"
|
18
.gitattributes
vendored
Normal file
18
.gitattributes
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
*.py text eol=lf
|
||||
*.dfu binary
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.bin binary
|
||||
*.elf binary
|
||||
*.h text eol=lf
|
||||
*.c text eol=lf
|
||||
*.s text eol=lf
|
||||
*.S text eol=lf
|
||||
README.* text eol=lf
|
||||
LICENSE text eol=lf
|
||||
Makefile text eol=lf
|
||||
*.mk text eol=lf
|
||||
*.sh text eol=lf
|
||||
*.ps1 text eol=crlf
|
||||
.gitignore text eol=lf
|
||||
.gitattributes text eol=lf
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
**/*.rs.bk
|
142
Cargo.lock
generated
Normal file
142
Cargo.lock
generated
Normal file
@ -0,0 +1,142 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "bare-metal"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r0"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "riscv-rt-macros"
|
||||
version = "0.1.6"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "xous-kernel"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"xous-riscv 0.5.4",
|
||||
"xous-riscv-rt 0.6.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xous-riscv"
|
||||
version = "0.5.4"
|
||||
dependencies = [
|
||||
"bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xous-riscv-rt"
|
||||
version = "0.6.1"
|
||||
dependencies = [
|
||||
"r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"riscv-rt-macros 0.1.6",
|
||||
"xous-riscv 0.5.4",
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3caf393d93b2d453e80638d0674597020cef3382ada454faacd43d1a55a735a"
|
||||
"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
|
||||
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
||||
"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f"
|
||||
"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9"
|
||||
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||
"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
16
Cargo.toml
Normal file
16
Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "xous-kernel"
|
||||
version = "0.1.0"
|
||||
authors = ["Sean Cross <sean@xobs.io>"]
|
||||
edition = "2018"
|
||||
description = "Core kernel for Xous, including task switching and memory management"
|
||||
|
||||
[dependencies]
|
||||
xous-riscv = { path = "xous-riscv" }
|
||||
xous-riscv-rt = { path = "xous-riscv-rt" }
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1 # 1 better optimizations
|
||||
debug = true # symbols are nice and they don't increase the size on Flash
|
||||
lto = true
|
||||
#opt-level=0
|
4
README.md
Normal file
4
README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Xous Kernel
|
||||
|
||||
This contains the core kernel for Xous. It is implemented as
|
||||
a library that you include with your `pid 0` program.
|
16
memory.x
Normal file
16
memory.x
Normal file
@ -0,0 +1,16 @@
|
||||
MEMORY
|
||||
{
|
||||
RAM : ORIGIN = 0x40000000, LENGTH = 16M
|
||||
FLASH : ORIGIN = 0x20500000, LENGTH = 16M
|
||||
MEMLCD: ORIGIN = 0xB0000000, LENGTH = 32k
|
||||
}
|
||||
|
||||
REGION_ALIAS("REGION_TEXT", FLASH);
|
||||
REGION_ALIAS("REGION_RODATA", FLASH);
|
||||
REGION_ALIAS("REGION_DATA", RAM);
|
||||
REGION_ALIAS("REGION_BSS", RAM);
|
||||
REGION_ALIAS("REGION_HEAP", RAM);
|
||||
REGION_ALIAS("REGION_STACK", RAM);
|
||||
|
||||
_lcdfb = ORIGIN(MEMLCD);
|
||||
_heap_size = LENGTH(RAM) - 1M;
|
18
src/main.rs
Normal file
18
src/main.rs
Normal file
@ -0,0 +1,18 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
extern crate xous_riscv;
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
#[panic_handler]
|
||||
fn handle_panic(arg: &PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
use xous_riscv_rt::entry;
|
||||
#[entry]
|
||||
fn xous_main() -> ! {
|
||||
loop {
|
||||
unsafe { xous_riscv::asm::wfi() };
|
||||
}
|
||||
}
|
18
xous-riscv-rt/Cargo.toml
Normal file
18
xous-riscv-rt/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "xous-riscv-rt"
|
||||
version = "0.6.1"
|
||||
repository = "https://github.com/xous/xous-riscv-rt"
|
||||
authors = ["Sean Cross <sean@xobs.io>", "The RISC-V Team <risc-v@teams.rust-embedded.org>"]
|
||||
categories = ["embedded", "no-std", "xous"]
|
||||
description = "Minimal runtime / startup for RISC-V CPU's"
|
||||
keywords = ["riscv", "runtime", "startup"]
|
||||
license = "ISC"
|
||||
|
||||
[dependencies]
|
||||
r0 = "0.2.2"
|
||||
xous-riscv = { path = "../xous-riscv", version = "0.5.1" }
|
||||
riscv-rt-macros = { path = "macros", version = "0.1.6" }
|
||||
|
||||
[dev-dependencies]
|
||||
xous-riscv = { path = "../xous-riscv", version = "0.5.1" }
|
||||
panic-halt = "0.2.0"
|
0
xous-riscv-rt/README.md
Normal file
0
xous-riscv-rt/README.md
Normal file
151
xous-riscv-rt/asm.S
Normal file
151
xous-riscv-rt/asm.S
Normal file
@ -0,0 +1,151 @@
|
||||
#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 (_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.
|
||||
*/
|
||||
|
||||
.section .text.init, "ax"
|
||||
.global _start
|
||||
|
||||
_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
|
||||
|
||||
.option push
|
||||
.option norelax
|
||||
la gp, __global_pointer$
|
||||
.option pop
|
||||
|
||||
#if !defined(SKIP_MULTICORE)
|
||||
// Check hart id
|
||||
csrr a2, mhartid
|
||||
lui t0, %hi(_max_hart_id)
|
||||
add t0, t0, %lo(_max_hart_id)
|
||||
bgtu a2, t0, abort
|
||||
#endif // SKIP_MULTICORE
|
||||
// Allocate stacks
|
||||
la sp, _stack_start
|
||||
#if !defined(SKIP_MULTICORE)
|
||||
lui t0, %hi(_hart_stack_size)
|
||||
add t0, t0, %lo(_hart_stack_size)
|
||||
mul t0, a2, t0
|
||||
sub sp, sp, t0
|
||||
#endif // SKIP_MULTICORE
|
||||
|
||||
// Set frame pointer
|
||||
add s0, sp, zero
|
||||
|
||||
// Set trap handler
|
||||
la t0, _start_trap
|
||||
csrw mtvec, t0
|
||||
|
||||
jal zero, _start_rust
|
||||
|
||||
.cfi_endproc
|
||||
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
.section .trap, "ax"
|
||||
.global _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)
|
||||
|
||||
jal ra, _start_trap_rust
|
||||
|
||||
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
|
||||
|
||||
|
||||
/* Make sure there is an abort when linking */
|
||||
.section .text.init
|
||||
.globl abort
|
||||
abort:
|
||||
j abort
|
17
xous-riscv-rt/assemble.ps1
Normal file
17
xous-riscv-rt/assemble.ps1
Normal file
@ -0,0 +1,17 @@
|
||||
# remove existing blobs because otherwise this will append object files to the old blobs
|
||||
Remove-Item -Force bin/*.a
|
||||
|
||||
$crate = "xous-riscv-rt"
|
||||
|
||||
riscv64-unknown-elf-gcc -ggdb3 -c -mabi=ilp32 -march=rv32imac asm.S -o bin/$crate.o
|
||||
riscv64-unknown-elf-ar crs bin/riscv32imac-unknown-none-elf.a bin/$crate.o
|
||||
riscv64-unknown-elf-ar crs bin/riscv32imc-unknown-none-elf.a bin/$crate.o
|
||||
|
||||
riscv64-unknown-elf-gcc -ggdb3 -c -mabi=ilp32 -march=rv32i asm.S -DSKIP_MULTICORE -o bin/$crate.o
|
||||
riscv64-unknown-elf-ar crs bin/riscv32i-unknown-none-elf.a bin/$crate.o
|
||||
|
||||
riscv64-unknown-elf-gcc -ggdb3 -c -mabi=lp64 -march=rv64imac asm.S -o bin/$crate.o
|
||||
riscv64-unknown-elf-ar crs bin/riscv64imac-unknown-none-elf.a bin/$crate.o
|
||||
riscv64-unknown-elf-ar crs bin/riscv64gc-unknown-none-elf.a bin/$crate.o
|
||||
|
||||
Remove-Item bin/$crate.o
|
21
xous-riscv-rt/assemble.sh
Normal file
21
xous-riscv-rt/assemble.sh
Normal file
@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
crate=riscv-rt
|
||||
|
||||
# remove existing blobs because otherwise this will append object files to the old blobs
|
||||
rm -f bin/*.a
|
||||
|
||||
riscv64-unknown-elf-gcc -c -mabi=ilp32 -march=rv32imac asm.S -o bin/$crate.o
|
||||
ar crs bin/riscv32imac-unknown-none-elf.a bin/$crate.o
|
||||
ar crs bin/riscv32imc-unknown-none-elf.a bin/$crate.o
|
||||
|
||||
riscv64-unknown-elf-gcc -c -mabi=ilp32 -march=rv32i asm.S -DSKIP_MULTICORE -o bin/$crate.o
|
||||
ar crs bin/riscv32i-unknown-none-elf.a bin/$crate.o
|
||||
|
||||
riscv64-unknown-elf-gcc -c -mabi=lp64 -march=rv64imac asm.S -o bin/$crate.o
|
||||
ar crs bin/riscv64imac-unknown-none-elf.a bin/$crate.o
|
||||
ar crs bin/riscv64gc-unknown-none-elf.a bin/$crate.o
|
||||
|
||||
rm bin/$crate.o
|
BIN
xous-riscv-rt/bin/riscv32i-unknown-none-elf.a
Normal file
BIN
xous-riscv-rt/bin/riscv32i-unknown-none-elf.a
Normal file
Binary file not shown.
BIN
xous-riscv-rt/bin/riscv32imac-unknown-none-elf.a
Normal file
BIN
xous-riscv-rt/bin/riscv32imac-unknown-none-elf.a
Normal file
Binary file not shown.
BIN
xous-riscv-rt/bin/riscv32imc-unknown-none-elf.a
Normal file
BIN
xous-riscv-rt/bin/riscv32imc-unknown-none-elf.a
Normal file
Binary file not shown.
BIN
xous-riscv-rt/bin/riscv64gc-unknown-none-elf.a
Normal file
BIN
xous-riscv-rt/bin/riscv64gc-unknown-none-elf.a
Normal file
Binary file not shown.
BIN
xous-riscv-rt/bin/riscv64imac-unknown-none-elf.a
Normal file
BIN
xous-riscv-rt/bin/riscv64imac-unknown-none-elf.a
Normal file
Binary file not shown.
32
xous-riscv-rt/build.rs
Normal file
32
xous-riscv-rt/build.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// NOTE: Adapted from cortex-m/build.rs
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
let name = env::var("CARGO_PKG_NAME").unwrap();
|
||||
|
||||
if target.starts_with("riscv") {
|
||||
fs::copy(
|
||||
format!("bin/{}.a", target),
|
||||
out_dir.join(format!("lib{}.a", name)),
|
||||
).unwrap();
|
||||
println!("cargo:rerun-if-changed=bin/{}.a", target);
|
||||
|
||||
println!("cargo:rustc-link-lib=static={}", name);
|
||||
println!("cargo:rustc-link-search={}", out_dir.display());
|
||||
}
|
||||
|
||||
// Put the linker script somewhere the linker can find it
|
||||
fs::File::create(out_dir.join("link.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("link.x"))
|
||||
.unwrap();
|
||||
println!("cargo:rustc-link-search={}", out_dir.display());
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=link.x");
|
||||
}
|
159
xous-riscv-rt/link.x
Normal file
159
xous-riscv-rt/link.x
Normal file
@ -0,0 +1,159 @@
|
||||
PROVIDE(_stext = ORIGIN(REGION_TEXT));
|
||||
PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK));
|
||||
PROVIDE(_max_hart_id = 0);
|
||||
PROVIDE(_hart_stack_size = 2K);
|
||||
PROVIDE(_heap_size = 0);
|
||||
|
||||
PROVIDE(trap_handler = default_trap_handler);
|
||||
|
||||
/* # Pre-initialization function */
|
||||
/* If the user overrides this using the `#[pre_init]` attribute or by creating a `__pre_init` function,
|
||||
then the function this points to will be called before the RAM is initialized. */
|
||||
PROVIDE(__pre_init = default_pre_init);
|
||||
|
||||
/* # Multi-processing hook function
|
||||
fn _mp_hook() -> bool;
|
||||
|
||||
This function is called from all the harts and must return true only for one hart,
|
||||
which will perform memory initialization. For other harts it must return false
|
||||
and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt).
|
||||
*/
|
||||
PROVIDE(_mp_hook = default_mp_hook);
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text.dummy (NOLOAD) :
|
||||
{
|
||||
/* This section is intended to make _stext address work */
|
||||
. = _stext;
|
||||
} > REGION_TEXT
|
||||
|
||||
.text _stext :
|
||||
{
|
||||
/* Put reset handler first in .text section so it ends up as the entry */
|
||||
/* point of the program. */
|
||||
KEEP(*(.text.init));
|
||||
KEEP(*(.init));
|
||||
KEEP(*(.init.rust));
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.trap));
|
||||
KEEP(*(.trap.rust));
|
||||
|
||||
*(.text .text.*);
|
||||
} > REGION_TEXT
|
||||
|
||||
.rodata : ALIGN(4)
|
||||
{
|
||||
*(.rodata .rodata.*);
|
||||
|
||||
/* 4-byte align the end (VMA) of this section.
|
||||
This is required by LLD to ensure the LMA of the following .data
|
||||
section will have the correct alignment. */
|
||||
. = ALIGN(4);
|
||||
} > REGION_RODATA
|
||||
|
||||
.data : ALIGN(4)
|
||||
{
|
||||
_sidata = LOADADDR(.data);
|
||||
_sdata = .;
|
||||
/* Must be called __global_pointer$ for linker relaxations to work. */
|
||||
PROVIDE(__global_pointer$ = . + 0x800);
|
||||
*(.sdata .sdata.* .sdata2 .sdata2.*);
|
||||
*(.data .data.*);
|
||||
. = ALIGN(4);
|
||||
_edata = .;
|
||||
} > REGION_DATA AT > REGION_RODATA
|
||||
|
||||
.bss (NOLOAD) :
|
||||
{
|
||||
_sbss = .;
|
||||
*(.sbss .sbss.* .bss .bss.*);
|
||||
. = ALIGN(4);
|
||||
_ebss = .;
|
||||
} > REGION_BSS
|
||||
|
||||
/* fictitious region that represents the memory available for the heap */
|
||||
.heap (NOLOAD) :
|
||||
{
|
||||
_sheap = .;
|
||||
. += _heap_size;
|
||||
. = ALIGN(4);
|
||||
_eheap = .;
|
||||
} > REGION_HEAP
|
||||
|
||||
/* fictitious region that represents the memory available for the stack */
|
||||
.stack (NOLOAD) :
|
||||
{
|
||||
_estack = .;
|
||||
. = _stack_start;
|
||||
_sstack = .;
|
||||
} > REGION_STACK
|
||||
|
||||
/* fake output .got section */
|
||||
/* Dynamic relocations are unsupported. This section is only used to detect
|
||||
relocatable code in the input files and raise an error if relocatable code
|
||||
is found */
|
||||
.got (INFO) :
|
||||
{
|
||||
KEEP(*(.got .got.*));
|
||||
}
|
||||
|
||||
/* Discard .eh_frame, we are not doing unwind on panic so it is not needed */
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.eh_frame);
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not exceed this mark in the error messages above | */
|
||||
ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
|
||||
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
|
||||
|
||||
ASSERT(ORIGIN(REGION_RODATA) % 4 == 0, "
|
||||
ERROR(riscv-rt): the start of the REGION_RODATA must be 4-byte aligned");
|
||||
|
||||
ASSERT(ORIGIN(REGION_DATA) % 4 == 0, "
|
||||
ERROR(riscv-rt): the start of the REGION_DATA must be 4-byte aligned");
|
||||
|
||||
ASSERT(ORIGIN(REGION_HEAP) % 4 == 0, "
|
||||
ERROR(riscv-rt): the start of the REGION_HEAP must be 4-byte aligned");
|
||||
|
||||
ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
|
||||
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
|
||||
|
||||
ASSERT(ORIGIN(REGION_STACK) % 4 == 0, "
|
||||
ERROR(riscv-rt): the start of the REGION_STACK must be 4-byte aligned");
|
||||
|
||||
ASSERT(_stext % 4 == 0, "
|
||||
ERROR(riscv-rt): `_stext` must be 4-byte aligned");
|
||||
|
||||
ASSERT(_sdata % 4 == 0 && _edata % 4 == 0, "
|
||||
BUG(riscv-rt): .data is not 4-byte aligned");
|
||||
|
||||
ASSERT(_sidata % 4 == 0, "
|
||||
BUG(riscv-rt): the LMA of .data is not 4-byte aligned");
|
||||
|
||||
ASSERT(_sbss % 4 == 0 && _ebss % 4 == 0, "
|
||||
BUG(riscv-rt): .bss is not 4-byte aligned");
|
||||
|
||||
ASSERT(_sheap % 4 == 0, "
|
||||
BUG(riscv-rt): start of .heap is not 4-byte aligned");
|
||||
|
||||
ASSERT(_stext + SIZEOF(.text) < ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT), "
|
||||
ERROR(riscv-rt): The .text section must be placed inside the REGION_TEXT region.
|
||||
Set _stext to an address smaller than 'ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT)'");
|
||||
|
||||
ASSERT(SIZEOF(.stack) > (_max_hart_id + 1) * _hart_stack_size, "
|
||||
ERROR(riscv-rt): .stack section is too small for allocating stacks for all the harts.
|
||||
Consider changing `_max_hart_id` or `_hart_stack_size`.");
|
||||
|
||||
ASSERT(SIZEOF(.got) == 0, "
|
||||
.got section detected in the input files. Dynamic relocations are not
|
||||
supported. If you are linking to C code compiled using the `gcc` crate
|
||||
then modify your build script to compile the C code _without_ the
|
||||
-fPIC flag. See the documentation of the `gcc::Config.fpic` method for
|
||||
details.");
|
||||
|
||||
/* Do not exceed this mark in the error messages above | */
|
28
xous-riscv-rt/macros/Cargo.toml
Normal file
28
xous-riscv-rt/macros/Cargo.toml
Normal file
@ -0,0 +1,28 @@
|
||||
[package]
|
||||
authors = [
|
||||
"The RISC-V Team <risc-v@teams.rust-embedded.org>",
|
||||
"Jorge Aparicio <jorge@japaric.io>",
|
||||
]
|
||||
categories = ["embedded", "no-std"]
|
||||
description = "Attributes re-exported in `riscv-rt`"
|
||||
documentation = "https://docs.rs/riscv-rt"
|
||||
keywords = ["riscv", "runtime", "startup"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
name = "riscv-rt-macros"
|
||||
repository = "https://github.com/rust-embedded/riscv-rt"
|
||||
version = "0.1.6"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "0.6.8"
|
||||
proc-macro2 = "0.4.20"
|
||||
|
||||
[dependencies.syn]
|
||||
features = ["extra-traits", "full"]
|
||||
version = "0.15.13"
|
||||
|
||||
[dependencies.rand]
|
||||
version = "0.5.5"
|
||||
default-features = false
|
210
xous-riscv-rt/macros/src/lib.rs
Normal file
210
xous-riscv-rt/macros/src/lib.rs
Normal file
@ -0,0 +1,210 @@
|
||||
#![deny(warnings)]
|
||||
|
||||
extern crate proc_macro;
|
||||
extern crate rand;
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
extern crate core;
|
||||
extern crate proc_macro2;
|
||||
#[macro_use]
|
||||
extern crate syn;
|
||||
|
||||
use proc_macro2::Span;
|
||||
use rand::Rng;
|
||||
use rand::SeedableRng;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use syn::{
|
||||
parse, spanned::Spanned, Ident, ItemFn, ReturnType, Type, Visibility,
|
||||
};
|
||||
|
||||
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
/// Attribute to declare the entry point of the program
|
||||
///
|
||||
/// **IMPORTANT**: This attribute must appear exactly *once* in the dependency graph. Also, if you
|
||||
/// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no
|
||||
/// private modules between the item and the root of the crate); if the item is in the root of the
|
||||
/// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer releases.
|
||||
///
|
||||
/// The specified function will be called by the reset handler *after* RAM has been initialized.
|
||||
/// If present, the FPU will also be enabled before the function is called.
|
||||
///
|
||||
/// The type of the specified function must be `[unsafe] fn() -> !` (never ending function)
|
||||
///
|
||||
/// # Properties
|
||||
///
|
||||
/// The entry point will be called by the reset handler.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// - Simple entry point
|
||||
///
|
||||
/// ``` no_run
|
||||
/// #![no_main]
|
||||
/// use xous_riscv_rt::entry;
|
||||
/// #[entry]
|
||||
/// fn main() -> ! {
|
||||
/// loop {
|
||||
/// /* .. */
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let f = parse_macro_input!(input as ItemFn);
|
||||
|
||||
// check the function signature
|
||||
let valid_signature = f.constness.is_none()
|
||||
&& f.vis == Visibility::Inherited
|
||||
&& f.abi.is_none()
|
||||
&& f.decl.inputs.is_empty()
|
||||
&& f.decl.generics.params.is_empty()
|
||||
&& f.decl.generics.where_clause.is_none()
|
||||
&& f.decl.variadic.is_none()
|
||||
&& match f.decl.output {
|
||||
ReturnType::Default => false,
|
||||
ReturnType::Type(_, ref ty) => match **ty {
|
||||
Type::Never(_) => true,
|
||||
_ => false,
|
||||
},
|
||||
};
|
||||
|
||||
if !valid_signature {
|
||||
return parse::Error::new(
|
||||
f.span(),
|
||||
"`#[entry]` function must have signature `[unsafe] fn() -> !`",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
if !args.is_empty() {
|
||||
return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
// XXX should we blacklist other attributes?
|
||||
let attrs = f.attrs;
|
||||
let unsafety = f.unsafety;
|
||||
let hash = random_ident();
|
||||
let stmts = f.block.stmts;
|
||||
|
||||
quote!(
|
||||
#[export_name = "xous_main"]
|
||||
#(#attrs)*
|
||||
pub #unsafety fn #hash() -> ! {
|
||||
#(#stmts)*
|
||||
}
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Attribute to mark which function will be called at the beginning of the reset handler.
|
||||
///
|
||||
/// **IMPORTANT**: This attribute can appear at most *once* in the dependency graph. Also, if you
|
||||
/// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no
|
||||
/// private modules between the item and the root of the crate); if the item is in the root of the
|
||||
/// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer
|
||||
/// releases.
|
||||
///
|
||||
/// The function must have the signature of `unsafe fn()`.
|
||||
///
|
||||
/// The function passed will be called before static variables are initialized. Any access of static
|
||||
/// variables will result in undefined behavior.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use riscv_rt_macros::pre_init;
|
||||
/// #[pre_init]
|
||||
/// unsafe fn before_main() {
|
||||
/// // do something here
|
||||
/// }
|
||||
///
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let f = parse_macro_input!(input as ItemFn);
|
||||
|
||||
// check the function signature
|
||||
let valid_signature = f.constness.is_none()
|
||||
&& f.vis == Visibility::Inherited
|
||||
&& f.unsafety.is_some()
|
||||
&& f.abi.is_none()
|
||||
&& f.decl.inputs.is_empty()
|
||||
&& f.decl.generics.params.is_empty()
|
||||
&& f.decl.generics.where_clause.is_none()
|
||||
&& f.decl.variadic.is_none()
|
||||
&& match f.decl.output {
|
||||
ReturnType::Default => true,
|
||||
ReturnType::Type(_, ref ty) => match **ty {
|
||||
Type::Tuple(ref tuple) => tuple.elems.is_empty(),
|
||||
_ => false,
|
||||
},
|
||||
};
|
||||
|
||||
if !valid_signature {
|
||||
return parse::Error::new(
|
||||
f.span(),
|
||||
"`#[pre_init]` function must have signature `unsafe fn()`",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
if !args.is_empty() {
|
||||
return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
// XXX should we blacklist other attributes?
|
||||
let attrs = f.attrs;
|
||||
let ident = f.ident;
|
||||
let block = f.block;
|
||||
|
||||
quote!(
|
||||
#[export_name = "__pre_init"]
|
||||
#(#attrs)*
|
||||
pub unsafe fn #ident() #block
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
// Creates a random identifier
|
||||
fn random_ident() -> Ident {
|
||||
let secs = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
let count: u64 = CALL_COUNT.fetch_add(1, Ordering::SeqCst) as u64;
|
||||
let mut seed: [u8; 16] = [0; 16];
|
||||
|
||||
for (i, v) in seed.iter_mut().take(8).enumerate() {
|
||||
*v = ((secs >> (i * 8)) & 0xFF) as u8
|
||||
}
|
||||
|
||||
for (i, v) in seed.iter_mut().skip(8).enumerate() {
|
||||
*v = ((count >> (i * 8)) & 0xFF) as u8
|
||||
}
|
||||
|
||||
let mut rng = rand::rngs::SmallRng::from_seed(seed);
|
||||
Ident::new(
|
||||
&(0..16)
|
||||
.map(|i| {
|
||||
if i == 0 || rng.gen() {
|
||||
('a' as u8 + rng.gen::<u8>() % 25) as char
|
||||
} else {
|
||||
('0' as u8 + rng.gen::<u8>() % 10) as char
|
||||
}
|
||||
})
|
||||
.collect::<String>(),
|
||||
Span::call_site(),
|
||||
)
|
||||
}
|
351
xous-riscv-rt/src/lib.rs
Normal file
351
xous-riscv-rt/src/lib.rs
Normal file
@ -0,0 +1,351 @@
|
||||
//! Minimal startup / runtime for RISC-V CPU's
|
||||
//!
|
||||
//! # Minimum Supported Rust Version (MSRV)
|
||||
//!
|
||||
//! This crate is guaranteed to compile on stable Rust 1.31 and up. It *might*
|
||||
//! compile with older versions but that may change in any new patch release.
|
||||
//!
|
||||
//! # Features
|
||||
//!
|
||||
//! This crate provides
|
||||
//!
|
||||
//! - Before main initialization of the `.bss` and `.data` sections.
|
||||
//!
|
||||
//! - `#[entry]` to declare the entry point of the program
|
||||
//! - `#[pre_init]` to run code *before* `static` variables are initialized
|
||||
//!
|
||||
//! - A linker script that encodes the memory layout of a generic RISC-V
|
||||
//! microcontroller. This linker script is missing some information that must
|
||||
//! be supplied through a `memory.x` file (see example below). This file
|
||||
//! must be supplied using rustflags and listed *before* `link.x`. Arbitrary
|
||||
//! filename can be use instead of `memory.x`.
|
||||
//!
|
||||
//! - A `_sheap` symbol at whose address you can locate a heap.
|
||||
//!
|
||||
//! ``` text
|
||||
//! $ cargo new --bin app && cd $_
|
||||
//!
|
||||
//! $ # add this crate as a dependency
|
||||
//! $ edit Cargo.toml && cat $_
|
||||
//! [dependencies]
|
||||
//! riscv-rt = "0.6.1"
|
||||
//! panic-halt = "0.2.0"
|
||||
//!
|
||||
//! $ # memory layout of the device
|
||||
//! $ edit memory.x && cat $_
|
||||
//! MEMORY
|
||||
//! {
|
||||
//! RAM : ORIGIN = 0x80000000, LENGTH = 16K
|
||||
//! FLASH : ORIGIN = 0x20000000, LENGTH = 16M
|
||||
//! }
|
||||
//!
|
||||
//! REGION_ALIAS("REGION_TEXT", FLASH);
|
||||
//! REGION_ALIAS("REGION_RODATA", FLASH);
|
||||
//! REGION_ALIAS("REGION_DATA", RAM);
|
||||
//! REGION_ALIAS("REGION_BSS", RAM);
|
||||
//! REGION_ALIAS("REGION_HEAP", RAM);
|
||||
//! REGION_ALIAS("REGION_STACK", RAM);
|
||||
//!
|
||||
//! $ edit src/main.rs && cat $_
|
||||
//! ```
|
||||
//!
|
||||
//! ``` ignore,no_run
|
||||
//! #![no_std]
|
||||
//! #![no_main]
|
||||
//!
|
||||
//! extern crate panic_halt;
|
||||
//!
|
||||
//! use riscv_rt::entry;
|
||||
//!
|
||||
//! // use `main` as the entry point of this application
|
||||
//! // `main` is not allowed to return
|
||||
//! #[entry]
|
||||
//! fn main() -> ! {
|
||||
//! // do something here
|
||||
//! loop { }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ``` text
|
||||
//! $ mkdir .cargo && edit .cargo/config && cat $_
|
||||
//! [target.riscv32imac-unknown-none-elf]
|
||||
//! rustflags = [
|
||||
//! "-C", "link-arg=-Tmemory.x",
|
||||
//! "-C", "link-arg=-Tlink.x",
|
||||
//! ]
|
||||
//!
|
||||
//! [build]
|
||||
//! target = "riscv32imac-unknown-none-elf"
|
||||
//! $ edit build.rs && cat $_
|
||||
//! ```
|
||||
//!
|
||||
//! ``` ignore,no_run
|
||||
//! use std::env;
|
||||
//! use std::fs::File;
|
||||
//! use std::io::Write;
|
||||
//! use std::path::Path;
|
||||
//!
|
||||
//! /// Put the linker script somewhere the linker can find it.
|
||||
//! fn main() {
|
||||
//! let out_dir = env::var("OUT_DIR").expect("No out dir");
|
||||
//! let dest_path = Path::new(&out_dir);
|
||||
//! let mut f = File::create(&dest_path.join("memory.x"))
|
||||
//! .expect("Could not create file");
|
||||
//!
|
||||
//! f.write_all(include_bytes!("memory.x"))
|
||||
//! .expect("Could not write file");
|
||||
//!
|
||||
//! println!("cargo:rustc-link-search={}", dest_path.display());
|
||||
//!
|
||||
//! println!("cargo:rerun-if-changed=memory.x");
|
||||
//! println!("cargo:rerun-if-changed=build.rs");
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ``` text
|
||||
//! $ cargo build
|
||||
//!
|
||||
//! $ riscv32-unknown-elf-objdump -Cd $(find target -name app) | head
|
||||
//!
|
||||
//! Disassembly of section .text:
|
||||
//!
|
||||
//! 20000000 <_start>:
|
||||
//! 20000000: 800011b7 lui gp,0x80001
|
||||
//! 20000004: 80018193 addi gp,gp,-2048 # 80000800 <_stack_start+0xffffc800>
|
||||
//! 20000008: 80004137 lui sp,0x80004
|
||||
//! ```
|
||||
//!
|
||||
//! # Symbol interfaces
|
||||
//!
|
||||
//! This crate makes heavy use of symbols, linker sections and linker scripts to
|
||||
//! provide most of its functionality. Below are described the main symbol
|
||||
//! interfaces.
|
||||
//!
|
||||
//! ## `memory.x`
|
||||
//!
|
||||
//! This file supplies the information about the device to the linker.
|
||||
//!
|
||||
//! ### `MEMORY`
|
||||
//!
|
||||
//! The main information that this file must provide is the memory layout of
|
||||
//! the device in the form of the `MEMORY` command. The command is documented
|
||||
//! [here][2], but at a minimum you'll want to create at least one memory region.
|
||||
//!
|
||||
//! [2]: https://sourceware.org/binutils/docs/ld/MEMORY.html
|
||||
//!
|
||||
//! To support different relocation models (RAM-only, FLASH+RAM) multiple regions are used:
|
||||
//!
|
||||
//! - `REGION_TEXT` - for `.init`, `.trap` and `.text` sections
|
||||
//! - `REGION_RODATA` - for `.rodata` section and storing initial values for `.data` section
|
||||
//! - `REGION_DATA` - for `.data` section
|
||||
//! - `REGION_BSS` - for `.bss` section
|
||||
//! - `REGION_HEAP` - for the heap area
|
||||
//! - `REGION_STACK` - for hart stacks
|
||||
//!
|
||||
//! Specific aliases for these regions must be defined in `memory.x` file (see example below).
|
||||
//!
|
||||
//! ### `_stext`
|
||||
//!
|
||||
//! This symbol provides the loading address of `.text` section. This value can be changed
|
||||
//! to override the loading address of the firmware (for example, in case of bootloader present).
|
||||
//!
|
||||
//! If omitted this symbol value will default to `ORIGIN(REGION_TEXT)`.
|
||||
//!
|
||||
//! ### `_stack_start`
|
||||
//!
|
||||
//! This symbol provides the address at which the call stack will be allocated.
|
||||
//! The call stack grows downwards so this address is usually set to the highest
|
||||
//! valid RAM address plus one (this *is* an invalid address but the processor
|
||||
//! will decrement the stack pointer *before* using its value as an address).
|
||||
//!
|
||||
//! In case of multiple harts present, this address defines the initial stack pointer for hart 0.
|
||||
//! Stack pointer for hart `N` is calculated as `_stack_start - N * _hart_stack_size`.
|
||||
//!
|
||||
//! If omitted this symbol value will default to `ORIGIN(REGION_STACK) + LENGTH(REGION_STACK)`.
|
||||
//!
|
||||
//! #### Example
|
||||
//!
|
||||
//! Allocating the call stack on a different RAM region.
|
||||
//!
|
||||
//! ``` text
|
||||
//! MEMORY
|
||||
//! {
|
||||
//! L2_LIM : ORIGIN = 0x08000000, LENGTH = 1M
|
||||
//! RAM : ORIGIN = 0x80000000, LENGTH = 16K
|
||||
//! FLASH : ORIGIN = 0x20000000, LENGTH = 16M
|
||||
//! }
|
||||
//!
|
||||
//! REGION_ALIAS("REGION_TEXT", FLASH);
|
||||
//! REGION_ALIAS("REGION_RODATA", FLASH);
|
||||
//! REGION_ALIAS("REGION_DATA", RAM);
|
||||
//! REGION_ALIAS("REGION_BSS", RAM);
|
||||
//! REGION_ALIAS("REGION_HEAP", RAM);
|
||||
//! REGION_ALIAS("REGION_STACK", L2_LIM);
|
||||
//!
|
||||
//! _stack_start = ORIGIN(L2_LIM) + LENGTH(L2_LIM);
|
||||
//! ```
|
||||
//!
|
||||
//! ### `_max_hart_id`
|
||||
//!
|
||||
//! This symbol defines the maximum hart id suppoted. All harts with id
|
||||
//! greater than `_max_hart_id` will be redirected to `abort()`.
|
||||
//!
|
||||
//! This symbol is supposed to be redefined in platform support crates for
|
||||
//! multi-core targets.
|
||||
//!
|
||||
//! If omitted this symbol value will default to 0 (single core).
|
||||
//!
|
||||
//! ### `_hart_stack_size`
|
||||
//!
|
||||
//! This symbol defines stack area size for *one* hart.
|
||||
//!
|
||||
//! If omitted this symbol value will default to 2K.
|
||||
//!
|
||||
//! ### `_heap_size`
|
||||
//!
|
||||
//! This symbol provides the size of a heap region. The default value is 0. You can set `_heap_size`
|
||||
//! to a non-zero value if you are planning to use heap allocations.
|
||||
//!
|
||||
//! ### `_sheap`
|
||||
//!
|
||||
//! This symbol is located in RAM right after the `.bss` and `.data` sections.
|
||||
//! You can use the address of this symbol as the start address of a heap
|
||||
//! region. This symbol is 4 byte aligned so that address will be a multiple of 4.
|
||||
//!
|
||||
//! #### Example
|
||||
//!
|
||||
//! ``` no_run
|
||||
//! extern crate some_allocator;
|
||||
//!
|
||||
//! extern "C" {
|
||||
//! static _sheap: u8;
|
||||
//! static _heap_size: u8;
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! unsafe {
|
||||
//! let heap_bottom = &_sheap as *const u8 as usize;
|
||||
//! let heap_size = &_heap_size as *const u8 as usize;
|
||||
//! some_allocator::initialize(heap_bottom, heap_size);
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ### `_mp_hook`
|
||||
//!
|
||||
//! This function is called from all the harts and must return true only for one hart,
|
||||
//! which will perform memory initialization. For other harts it must return false
|
||||
//! and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt).
|
||||
//!
|
||||
//! This function can be redefined in the following way:
|
||||
//!
|
||||
//! ``` no_run
|
||||
//! #[export_name = "_mp_hook"]
|
||||
//! pub extern "Rust" fn mp_hook() -> bool {
|
||||
//! // ...
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Default implementation of this function wakes hart 0 and busy-loops all the other harts.
|
||||
|
||||
// NOTE: Adapted from cortex-m/src/lib.rs
|
||||
#![no_std]
|
||||
#![deny(missing_docs)]
|
||||
#![deny(warnings)]
|
||||
|
||||
extern crate xous_riscv;
|
||||
extern crate riscv_rt_macros as macros;
|
||||
extern crate r0;
|
||||
|
||||
pub use macros::{entry, pre_init};
|
||||
|
||||
use xous_riscv::register::mstatus;
|
||||
|
||||
#[export_name = "error: riscv-rt appears more than once in the dependency graph"]
|
||||
#[doc(hidden)]
|
||||
pub static __ONCE__: () = ();
|
||||
|
||||
extern "C" {
|
||||
// Boundaries of the .bss section
|
||||
static mut _ebss: u32;
|
||||
static mut _sbss: u32;
|
||||
|
||||
// Boundaries of the .data section
|
||||
static mut _edata: u32;
|
||||
static mut _sdata: u32;
|
||||
|
||||
// Initial values of the .data section (stored in Flash)
|
||||
static _sidata: u32;
|
||||
}
|
||||
|
||||
|
||||
/// Rust entry point (_start_rust)
|
||||
///
|
||||
/// Zeros bss section, initializes data section and calls main. This function
|
||||
/// never returns.
|
||||
#[link_section = ".init.rust"]
|
||||
#[export_name = "_start_rust"]
|
||||
pub unsafe extern "C" fn start_rust() -> ! {
|
||||
extern "Rust" {
|
||||
// This symbol will be provided by the kernel
|
||||
fn xous_main() -> !;
|
||||
|
||||
// This symbol will be provided by the user via `#[pre_init]`
|
||||
fn __pre_init();
|
||||
|
||||
fn _mp_hook() -> bool;
|
||||
}
|
||||
|
||||
if _mp_hook() {
|
||||
__pre_init();
|
||||
|
||||
r0::zero_bss(&mut _sbss, &mut _ebss);
|
||||
r0::init_data(&mut _sdata, &mut _edata, &_sidata);
|
||||
}
|
||||
|
||||
xous_main();
|
||||
}
|
||||
|
||||
|
||||
/// Trap entry point rust (_start_trap_rust)
|
||||
///
|
||||
/// mcause is read to determine the cause of the trap. XLEN-1 bit indicates
|
||||
/// if it's an interrupt or an exception. The result is converted to an element
|
||||
/// of the Interrupt or Exception enum and passed to handle_interrupt or
|
||||
/// handle_exception.
|
||||
#[link_section = ".trap.rust"]
|
||||
#[export_name = "_start_trap_rust"]
|
||||
pub extern "C" fn start_trap_rust() {
|
||||
extern "C" {
|
||||
fn trap_handler();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// dispatch trap to handler
|
||||
trap_handler();
|
||||
|
||||
// mstatus, remain in M-mode after mret
|
||||
mstatus::set_mpp(mstatus::MPP::Machine);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[doc(hidden)]
|
||||
#[no_mangle]
|
||||
pub fn default_trap_handler() {}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "Rust" fn default_pre_init() {}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[no_mangle]
|
||||
pub extern "Rust" fn default_mp_hook() -> bool {
|
||||
use xous_riscv::register::mhartid;
|
||||
match mhartid::read() {
|
||||
0 => true,
|
||||
_ => loop {
|
||||
unsafe { xous_riscv::asm::wfi() }
|
||||
},
|
||||
}
|
||||
}
|
16
xous-riscv/Cargo.toml
Normal file
16
xous-riscv/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "xous-riscv"
|
||||
version = "0.5.4"
|
||||
repository = "https://github.com/rust-embedded/riscv"
|
||||
authors = ["The RISC-V Team <risc-v@teams.rust-embedded.org>"]
|
||||
categories = ["embedded", "hardware-support", "no-std"]
|
||||
description = "Low level access to RISC-V processors"
|
||||
keywords = ["riscv", "register", "peripheral"]
|
||||
license = "ISC"
|
||||
|
||||
[dependencies]
|
||||
bare-metal = ">=0.2.0,<0.2.5"
|
||||
bit_field = "0.9.0"
|
||||
|
||||
[features]
|
||||
inline-asm = []
|
317
xous-riscv/asm.S
Normal file
317
xous-riscv/asm.S
Normal file
@ -0,0 +1,317 @@
|
||||
#define REG_READ(name, offset) \
|
||||
.section .text.__read_ ## name; \
|
||||
.global __read_ ## name; \
|
||||
__read_ ## name: \
|
||||
csrrs a0, offset, x0; \
|
||||
ret
|
||||
|
||||
#define REG_WRITE(name, offset) \
|
||||
.section .text.__write_ ## name; \
|
||||
.global __write_ ## name; \
|
||||
__write_ ## name: \
|
||||
csrrw x0, offset, a0; \
|
||||
ret
|
||||
|
||||
#define REG_SET(name, offset) \
|
||||
.section .text.__set_ ## name; \
|
||||
.global __set_ ## name; \
|
||||
__set_ ## name: \
|
||||
csrrs x0, offset, a0; \
|
||||
ret
|
||||
|
||||
#define REG_CLEAR(name, offset) \
|
||||
.section .text.__clear_ ## name; \
|
||||
.global __clear_ ## name; \
|
||||
__clear_ ## name: \
|
||||
csrrc x0, offset, a0; \
|
||||
ret
|
||||
|
||||
|
||||
#define REG_READ_WRITE(name, offset) REG_READ(name, offset); REG_WRITE(name, offset)
|
||||
#define REG_SET_CLEAR(name, offset) REG_SET(name, offset); REG_CLEAR(name, offset)
|
||||
|
||||
#define RW(offset, name) REG_READ_WRITE(name, offset); REG_SET_CLEAR(name, offset)
|
||||
#define RO(offset, name) REG_READ(name, offset)
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
#define RW32(offset, name) RW(offset, name)
|
||||
#define RO32(offset, name) RO(offset, name)
|
||||
#else
|
||||
#define RW32(offset, name)
|
||||
#define RO32(offset, name)
|
||||
#endif
|
||||
// ----------------------- //
|
||||
|
||||
.section .text.__ebreak
|
||||
.global __ebreak
|
||||
__ebreak:
|
||||
ebreak
|
||||
ret
|
||||
|
||||
.section .text.__wfi
|
||||
.global __wfi
|
||||
__wfi:
|
||||
wfi
|
||||
ret
|
||||
|
||||
.section .text.__sfence_vma_all
|
||||
.global __sfence_vma_all
|
||||
__sfence_vma_all:
|
||||
sfence.vma
|
||||
ret
|
||||
|
||||
.section .text.__sfence_vma
|
||||
.global __sfence_vma
|
||||
__sfence_vma:
|
||||
sfence.vma a0, a1
|
||||
ret
|
||||
|
||||
// User Trap Setup
|
||||
RW(0x000, ustatus) // User status register
|
||||
RW(0x004, uie) // User interrupt-enable register
|
||||
RW(0x005, utvec) // User trap handler base address
|
||||
|
||||
// User Trap Handling
|
||||
RW(0x040, uscratch) // Scratch register for user trap handlers
|
||||
RW(0x041, uepc) // User exception program counter
|
||||
RW(0x042, ucause) // User trap cause
|
||||
RW(0x043, utval) // User bad address or instruction
|
||||
RW(0x044, uip) // User interrupt pending
|
||||
|
||||
// User Floating-Point CSRs
|
||||
RW(0x001, fflags) // Floating-Point Accrued Exceptions
|
||||
RW(0x002, frm) // Floating-Point Dynamic Rounding Mode
|
||||
RW(0x003, fcsr) // Floating-Point Control and Status Register (frm + fflags)
|
||||
|
||||
// User Counter/Timers
|
||||
RO( 0xC00, cycle) // Cycle counter for RDCYCLE instruction
|
||||
RO( 0xC01, time) // Timer for RDTIME instruction
|
||||
RO( 0xC02, instret) // Instructions-retired counter for RDINSTRET instruction
|
||||
RO( 0xC03, hpmcounter3) // Performance-monitoring counter
|
||||
RO( 0xC04, hpmcounter4) // Performance-monitoring counter
|
||||
RO( 0xC05, hpmcounter5) // Performance-monitoring counter
|
||||
RO( 0xC06, hpmcounter6) // Performance-monitoring counter
|
||||
RO( 0xC07, hpmcounter7) // Performance-monitoring counter
|
||||
RO( 0xC08, hpmcounter8) // Performance-monitoring counter
|
||||
RO( 0xC09, hpmcounter9) // Performance-monitoring counter
|
||||
RO( 0xC0A, hpmcounter10) // Performance-monitoring counter
|
||||
RO( 0xC0B, hpmcounter11) // Performance-monitoring counter
|
||||
RO( 0xC0C, hpmcounter12) // Performance-monitoring counter
|
||||
RO( 0xC0D, hpmcounter13) // Performance-monitoring counter
|
||||
RO( 0xC0E, hpmcounter14) // Performance-monitoring counter
|
||||
RO( 0xC0F, hpmcounter15) // Performance-monitoring counter
|
||||
RO( 0xC10, hpmcounter16) // Performance-monitoring counter
|
||||
RO( 0xC11, hpmcounter17) // Performance-monitoring counter
|
||||
RO( 0xC12, hpmcounter18) // Performance-monitoring counter
|
||||
RO( 0xC13, hpmcounter19) // Performance-monitoring counter
|
||||
RO( 0xC14, hpmcounter20) // Performance-monitoring counter
|
||||
RO( 0xC15, hpmcounter21) // Performance-monitoring counter
|
||||
RO( 0xC16, hpmcounter22) // Performance-monitoring counter
|
||||
RO( 0xC17, hpmcounter23) // Performance-monitoring counter
|
||||
RO( 0xC18, hpmcounter24) // Performance-monitoring counter
|
||||
RO( 0xC19, hpmcounter25) // Performance-monitoring counter
|
||||
RO( 0xC1A, hpmcounter26) // Performance-monitoring counter
|
||||
RO( 0xC1B, hpmcounter27) // Performance-monitoring counter
|
||||
RO( 0xC1C, hpmcounter28) // Performance-monitoring counter
|
||||
RO( 0xC1D, hpmcounter29) // Performance-monitoring counter
|
||||
RO( 0xC1E, hpmcounter30) // Performance-monitoring counter
|
||||
RO( 0xC1F, hpmcounter31) // Performance-monitoring counter
|
||||
RO32(0xC80, cycleh) // Upper 32 bits of cycle, RV32I only
|
||||
RO32(0xC81, timeh) // Upper 32 bits of time, RV32I only
|
||||
RO32(0xC82, instreth) // Upper 32 bits of instret, RV32I only
|
||||
RO32(0xC83, hpmcounter3h) // Upper 32 bits of hpmcounter3, RV32I only
|
||||
RO32(0xC84, hpmcounter4h)
|
||||
RO32(0xC85, hpmcounter5h)
|
||||
RO32(0xC86, hpmcounter6h)
|
||||
RO32(0xC87, hpmcounter7h)
|
||||
RO32(0xC88, hpmcounter8h)
|
||||
RO32(0xC89, hpmcounter9h)
|
||||
RO32(0xC8A, hpmcounter10h)
|
||||
RO32(0xC8B, hpmcounter11h)
|
||||
RO32(0xC8C, hpmcounter12h)
|
||||
RO32(0xC8D, hpmcounter13h)
|
||||
RO32(0xC8E, hpmcounter14h)
|
||||
RO32(0xC8F, hpmcounter15h)
|
||||
RO32(0xC90, hpmcounter16h)
|
||||
RO32(0xC91, hpmcounter17h)
|
||||
RO32(0xC92, hpmcounter18h)
|
||||
RO32(0xC93, hpmcounter19h)
|
||||
RO32(0xC94, hpmcounter20h)
|
||||
RO32(0xC95, hpmcounter21h)
|
||||
RO32(0xC96, hpmcounter22h)
|
||||
RO32(0xC97, hpmcounter23h)
|
||||
RO32(0xC98, hpmcounter24h)
|
||||
RO32(0xC99, hpmcounter25h)
|
||||
RO32(0xC9A, hpmcounter26h)
|
||||
RO32(0xC9B, hpmcounter27h)
|
||||
RO32(0xC9C, hpmcounter28h)
|
||||
RO32(0xC9D, hpmcounter29h)
|
||||
RO32(0xC9E, hpmcounter30h)
|
||||
RO32(0xC9F, hpmcounter31h)
|
||||
|
||||
// Supervisor Trap Setup
|
||||
RW(0x100, sstatus) // Supervisor status register
|
||||
RW(0x102, sedeleg) // Supervisor exception delegation register
|
||||
RW(0x103, sideleg) // Supervisor interrupt delegation register
|
||||
RW(0x104, sie) // Supervisor interrupt-enable register
|
||||
RW(0x105, stvec) // Supervisor trap handler base address
|
||||
RW(0x106, scounteren) // Supervisor counter enable
|
||||
|
||||
// Supervisor Trap Handling
|
||||
RW(0x140, sscratch) // Scratch register for supervisor trap handlers
|
||||
RW(0x141, sepc) // Supervisor exception program counter
|
||||
RW(0x142, scause) // Supervisor trap cause
|
||||
RW(0x143, stval) // Supervisor bad address or instruction
|
||||
RW(0x144, sip) // Supervisor interrupt pending
|
||||
|
||||
// Supervisor Protection and Translation
|
||||
RW(0x180, satp) // Supervisor address translation and protection
|
||||
|
||||
// Machine Information Registers
|
||||
RO(0xF11, mvendorid) // Vendor ID
|
||||
RO(0xF12, marchid) // Architecture ID
|
||||
RO(0xF13, mimpid) // Implementation ID
|
||||
RO(0xF14, mhartid) // Hardware thread ID
|
||||
|
||||
// Machine Trap Setup
|
||||
RW(0x300, mstatus) // Machine status register
|
||||
RW(0x301, misa) // ISA and extensions
|
||||
RW(0x302, medeleg) // Machine exception delegation register
|
||||
RW(0x303, mideleg) // Machine interrupt delegation register
|
||||
RW(0x304, mie) // Machine interrupt-enable register
|
||||
RW(0x305, mtvec) // Machine trap handler base address
|
||||
RW(0x306, mcounteren) // Machine counter enable
|
||||
|
||||
// Machine Trap Handling
|
||||
RW(0x340, mscratch) // Scratch register for machine trap handlers
|
||||
RW(0x341, mepc) // Machine exception program counter
|
||||
RW(0x342, mcause) // Machine trap cause
|
||||
RW(0x343, mtval) // Machine bad address or instruction
|
||||
RW(0x344, mip) // Machine interrupt pending
|
||||
|
||||
// Machine Protection and Translation
|
||||
RW( 0x3A0, pmpcfg0) // Physical memory protection configuration
|
||||
RW32(0x3A1, pmpcfg1) // Physical memory protection configuration, RV32 only
|
||||
RW( 0x3A2, pmpcfg2) // Physical memory protection configuration
|
||||
RW32(0x3A3, pmpcfg3) // Physical memory protection configuration, RV32 only
|
||||
RW( 0x3B0, pmpaddr0) // Physical memory protection address register
|
||||
RW( 0x3B1, pmpaddr1) // Physical memory protection address register
|
||||
RW( 0x3B2, pmpaddr2) // Physical memory protection address register
|
||||
RW( 0x3B3, pmpaddr3) // Physical memory protection address register
|
||||
RW( 0x3B4, pmpaddr4) // Physical memory protection address register
|
||||
RW( 0x3B5, pmpaddr5) // Physical memory protection address register
|
||||
RW( 0x3B6, pmpaddr6) // Physical memory protection address register
|
||||
RW( 0x3B7, pmpaddr7) // Physical memory protection address register
|
||||
RW( 0x3B8, pmpaddr8) // Physical memory protection address register
|
||||
RW( 0x3B9, pmpaddr9) // Physical memory protection address register
|
||||
RW( 0x3BA, pmpaddr10) // Physical memory protection address register
|
||||
RW( 0x3BB, pmpaddr11) // Physical memory protection address register
|
||||
RW( 0x3BC, pmpaddr12) // Physical memory protection address register
|
||||
RW( 0x3BD, pmpaddr13) // Physical memory protection address register
|
||||
RW( 0x3BE, pmpaddr14) // Physical memory protection address register
|
||||
RW( 0x3BF, pmpaddr15) // Physical memory protection address register
|
||||
|
||||
// Machine Counter/Timers
|
||||
RO( 0xB00, mcycle) // Machine cycle counter
|
||||
RO( 0xB02, minstret) // Machine instructions-retired counter
|
||||
RO( 0xB03, mhpmcounter3) // Machine performance-monitoring counter
|
||||
RO( 0xB04, mhpmcounter4) // Machine performance-monitoring counter
|
||||
RO( 0xB05, mhpmcounter5) // Machine performance-monitoring counter
|
||||
RO( 0xB06, mhpmcounter6) // Machine performance-monitoring counter
|
||||
RO( 0xB07, mhpmcounter7) // Machine performance-monitoring counter
|
||||
RO( 0xB08, mhpmcounter8) // Machine performance-monitoring counter
|
||||
RO( 0xB09, mhpmcounter9) // Machine performance-monitoring counter
|
||||
RO( 0xB0A, mhpmcounter10) // Machine performance-monitoring counter
|
||||
RO( 0xB0B, mhpmcounter11) // Machine performance-monitoring counter
|
||||
RO( 0xB0C, mhpmcounter12) // Machine performance-monitoring counter
|
||||
RO( 0xB0D, mhpmcounter13) // Machine performance-monitoring counter
|
||||
RO( 0xB0E, mhpmcounter14) // Machine performance-monitoring counter
|
||||
RO( 0xB0F, mhpmcounter15) // Machine performance-monitoring counter
|
||||
RO( 0xB10, mhpmcounter16) // Machine performance-monitoring counter
|
||||
RO( 0xB11, mhpmcounter17) // Machine performance-monitoring counter
|
||||
RO( 0xB12, mhpmcounter18) // Machine performance-monitoring counter
|
||||
RO( 0xB13, mhpmcounter19) // Machine performance-monitoring counter
|
||||
RO( 0xB14, mhpmcounter20) // Machine performance-monitoring counter
|
||||
RO( 0xB15, mhpmcounter21) // Machine performance-monitoring counter
|
||||
RO( 0xB16, mhpmcounter22) // Machine performance-monitoring counter
|
||||
RO( 0xB17, mhpmcounter23) // Machine performance-monitoring counter
|
||||
RO( 0xB18, mhpmcounter24) // Machine performance-monitoring counter
|
||||
RO( 0xB19, mhpmcounter25) // Machine performance-monitoring counter
|
||||
RO( 0xB1A, mhpmcounter26) // Machine performance-monitoring counter
|
||||
RO( 0xB1B, mhpmcounter27) // Machine performance-monitoring counter
|
||||
RO( 0xB1C, mhpmcounter28) // Machine performance-monitoring counter
|
||||
RO( 0xB1D, mhpmcounter29) // Machine performance-monitoring counter
|
||||
RO( 0xB1E, mhpmcounter30) // Machine performance-monitoring counter
|
||||
RO( 0xB1F, mhpmcounter31) // Machine performance-monitoring counter
|
||||
RO32(0xB80, mcycleh) // Upper 32 bits of mcycle, RV32I only
|
||||
RO32(0xB82, minstreth) // Upper 32 bits of minstret, RV32I only
|
||||
RO32(0xB83, mhpmcounter3h) // Upper 32 bits of mhpmcounter3, RV32I only
|
||||
RO32(0xB84, mhpmcounter4h)
|
||||
RO32(0xB85, mhpmcounter5h)
|
||||
RO32(0xB86, mhpmcounter6h)
|
||||
RO32(0xB87, mhpmcounter7h)
|
||||
RO32(0xB88, mhpmcounter8h)
|
||||
RO32(0xB89, mhpmcounter9h)
|
||||
RO32(0xB8A, mhpmcounter10h)
|
||||
RO32(0xB8B, mhpmcounter11h)
|
||||
RO32(0xB8C, mhpmcounter12h)
|
||||
RO32(0xB8D, mhpmcounter13h)
|
||||
RO32(0xB8E, mhpmcounter14h)
|
||||
RO32(0xB8F, mhpmcounter15h)
|
||||
RO32(0xB90, mhpmcounter16h)
|
||||
RO32(0xB91, mhpmcounter17h)
|
||||
RO32(0xB92, mhpmcounter18h)
|
||||
RO32(0xB93, mhpmcounter19h)
|
||||
RO32(0xB94, mhpmcounter20h)
|
||||
RO32(0xB95, mhpmcounter21h)
|
||||
RO32(0xB96, mhpmcounter22h)
|
||||
RO32(0xB97, mhpmcounter23h)
|
||||
RO32(0xB98, mhpmcounter24h)
|
||||
RO32(0xB99, mhpmcounter25h)
|
||||
RO32(0xB9A, mhpmcounter26h)
|
||||
RO32(0xB9B, mhpmcounter27h)
|
||||
RO32(0xB9C, mhpmcounter28h)
|
||||
RO32(0xB9D, mhpmcounter29h)
|
||||
RO32(0xB9E, mhpmcounter30h)
|
||||
RO32(0xB9F, mhpmcounter31h)
|
||||
|
||||
RW(0x323, mhpmevent3) // Machine performance-monitoring event selector
|
||||
RW(0x324, mhpmevent4) // Machine performance-monitoring event selector
|
||||
RW(0x325, mhpmevent5) // Machine performance-monitoring event selector
|
||||
RW(0x326, mhpmevent6) // Machine performance-monitoring event selector
|
||||
RW(0x327, mhpmevent7) // Machine performance-monitoring event selector
|
||||
RW(0x328, mhpmevent8) // Machine performance-monitoring event selector
|
||||
RW(0x329, mhpmevent9) // Machine performance-monitoring event selector
|
||||
RW(0x32A, mhpmevent10) // Machine performance-monitoring event selector
|
||||
RW(0x32B, mhpmevent11) // Machine performance-monitoring event selector
|
||||
RW(0x32C, mhpmevent12) // Machine performance-monitoring event selector
|
||||
RW(0x32D, mhpmevent13) // Machine performance-monitoring event selector
|
||||
RW(0x32E, mhpmevent14) // Machine performance-monitoring event selector
|
||||
RW(0x32F, mhpmevent15) // Machine performance-monitoring event selector
|
||||
RW(0x330, mhpmevent16) // Machine performance-monitoring event selector
|
||||
RW(0x331, mhpmevent17) // Machine performance-monitoring event selector
|
||||
RW(0x332, mhpmevent18) // Machine performance-monitoring event selector
|
||||
RW(0x333, mhpmevent19) // Machine performance-monitoring event selector
|
||||
RW(0x334, mhpmevent20) // Machine performance-monitoring event selector
|
||||
RW(0x335, mhpmevent21) // Machine performance-monitoring event selector
|
||||
RW(0x336, mhpmevent22) // Machine performance-monitoring event selector
|
||||
RW(0x337, mhpmevent23) // Machine performance-monitoring event selector
|
||||
RW(0x338, mhpmevent24) // Machine performance-monitoring event selector
|
||||
RW(0x339, mhpmevent25) // Machine performance-monitoring event selector
|
||||
RW(0x33A, mhpmevent26) // Machine performance-monitoring event selector
|
||||
RW(0x33B, mhpmevent27) // Machine performance-monitoring event selector
|
||||
RW(0x33C, mhpmevent28) // Machine performance-monitoring event selector
|
||||
RW(0x33D, mhpmevent29) // Machine performance-monitoring event selector
|
||||
RW(0x33E, mhpmevent30) // Machine performance-monitoring event selector
|
||||
RW(0x33F, mhpmevent31) // Machine performance-monitoring event selector
|
||||
|
||||
// Debug/Trace Registers (shared with Debug Mode)
|
||||
RW(0x7A0, tselect) // Debug/Trace trigger register select
|
||||
RW(0x7A1, tdata1) // First Debug/Trace trigger data register
|
||||
RW(0x7A2, tdata2) // Second Debug/Trace trigger data register
|
||||
RW(0x7A3, tdata3) // Third Debug/Trace trigger data register
|
||||
|
||||
// Debug Mode Registers
|
||||
RW(0x7B0, dcsr) // Debug control and status register
|
||||
RW(0x7B1, dpc) // Debug PC
|
||||
RW(0x7B2, dscratch) // Debug scratch register
|
19
xous-riscv/assemble.ps1
Normal file
19
xous-riscv/assemble.ps1
Normal file
@ -0,0 +1,19 @@
|
||||
New-Item -Force -Name bin -Type Directory
|
||||
|
||||
# remove existing blobs because otherwise this will append object files to the old blobs
|
||||
Remove-Item -Force bin/*.a
|
||||
|
||||
$crate = "xous-riscv"
|
||||
|
||||
riscv64-unknown-elf-gcc -c -mabi=ilp32 -march=rv32imac asm.S -o bin/$crate.o
|
||||
riscv64-unknown-elf-ar crs bin/riscv32imac-unknown-none-elf.a bin/$crate.o
|
||||
riscv64-unknown-elf-ar crs bin/riscv32imc-unknown-none-elf.a bin/$crate.o
|
||||
|
||||
riscv64-unknown-elf-gcc -c -mabi=ilp32 -march=rv32i asm.S -DSKIP_MULTICORE -o bin/$crate.o
|
||||
riscv64-unknown-elf-ar crs bin/riscv32i-unknown-none-elf.a bin/$crate.o
|
||||
|
||||
riscv64-unknown-elf-gcc -c -mabi=lp64 -march=rv64imac asm.S -o bin/$crate.o
|
||||
riscv64-unknown-elf-ar crs bin/riscv64imac-unknown-none-elf.a bin/$crate.o
|
||||
riscv64-unknown-elf-ar crs bin/riscv64gc-unknown-none-elf.a bin/$crate.o
|
||||
|
||||
Remove-Item bin/$crate.o
|
21
xous-riscv/assemble.sh
Normal file
21
xous-riscv/assemble.sh
Normal file
@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
crate=riscv-rt
|
||||
|
||||
# remove existing blobs because otherwise this will append object files to the old blobs
|
||||
rm -f bin/*.a
|
||||
|
||||
riscv64-unknown-elf-gcc -c -mabi=ilp32 -march=rv32imac asm.S -o bin/$crate.o
|
||||
ar crs bin/riscv32imac-unknown-none-elf.a bin/$crate.o
|
||||
ar crs bin/riscv32imc-unknown-none-elf.a bin/$crate.o
|
||||
|
||||
riscv64-unknown-elf-gcc -c -mabi=ilp32 -march=rv32i asm.S -DSKIP_MULTICORE -o bin/$crate.o
|
||||
ar crs bin/riscv32i-unknown-none-elf.a bin/$crate.o
|
||||
|
||||
riscv64-unknown-elf-gcc -c -mabi=lp64 -march=rv64imac asm.S -o bin/$crate.o
|
||||
ar crs bin/riscv64imac-unknown-none-elf.a bin/$crate.o
|
||||
ar crs bin/riscv64gc-unknown-none-elf.a bin/$crate.o
|
||||
|
||||
rm bin/$crate.o
|
BIN
xous-riscv/bin/riscv32i-unknown-none-elf.a
Normal file
BIN
xous-riscv/bin/riscv32i-unknown-none-elf.a
Normal file
Binary file not shown.
BIN
xous-riscv/bin/riscv32imac-unknown-none-elf.a
Normal file
BIN
xous-riscv/bin/riscv32imac-unknown-none-elf.a
Normal file
Binary file not shown.
BIN
xous-riscv/bin/riscv32imc-unknown-none-elf.a
Normal file
BIN
xous-riscv/bin/riscv32imc-unknown-none-elf.a
Normal file
Binary file not shown.
BIN
xous-riscv/bin/riscv64gc-unknown-none-elf.a
Normal file
BIN
xous-riscv/bin/riscv64gc-unknown-none-elf.a
Normal file
Binary file not shown.
BIN
xous-riscv/bin/riscv64imac-unknown-none-elf.a
Normal file
BIN
xous-riscv/bin/riscv64imac-unknown-none-elf.a
Normal file
Binary file not shown.
26
xous-riscv/build.rs
Normal file
26
xous-riscv/build.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use std::path::PathBuf;
|
||||
use std::{env, fs};
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
let name = env::var("CARGO_PKG_NAME").unwrap();
|
||||
|
||||
if target.starts_with("riscv") && env::var_os("CARGO_FEATURE_INLINE_ASM").is_none() {
|
||||
fs::copy(
|
||||
format!("bin/{}.a", target),
|
||||
out_dir.join(format!("lib{}.a", name)),
|
||||
).unwrap();
|
||||
|
||||
println!("cargo:rustc-link-lib=static={}", name);
|
||||
println!("cargo:rustc-link-search={}", out_dir.display());
|
||||
}
|
||||
|
||||
if target.starts_with("riscv32") {
|
||||
println!("cargo:rustc-cfg=riscv");
|
||||
println!("cargo:rustc-cfg=riscv32");
|
||||
} else if target.starts_with("riscv64") {
|
||||
println!("cargo:rustc-cfg=riscv");
|
||||
println!("cargo:rustc-cfg=riscv64");
|
||||
}
|
||||
}
|
77
xous-riscv/src/asm.rs
Normal file
77
xous-riscv/src/asm.rs
Normal file
@ -0,0 +1,77 @@
|
||||
//! Assembly instructions
|
||||
|
||||
macro_rules! instruction {
|
||||
($(#[$attr:meta])*, $fnname:ident, $asm:expr, $asm_fn:ident) => (
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
pub unsafe fn $fnname() {
|
||||
match () {
|
||||
#[cfg(all(riscv, feature = "inline-asm"))]
|
||||
() => asm!($asm :::: "volatile"),
|
||||
|
||||
#[cfg(all(riscv, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn();
|
||||
}
|
||||
|
||||
$asm_fn();
|
||||
}
|
||||
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
instruction!(
|
||||
/// `EBREAK` instruction wrapper
|
||||
///
|
||||
/// Generates a breakpoint exception.
|
||||
, ebreak, "ebreak", __ebreak);
|
||||
instruction!(
|
||||
/// `WFI` instruction wrapper
|
||||
///
|
||||
/// Provides a hint to the implementation that the current hart can be stalled until an interrupt might need servicing.
|
||||
/// The WFI instruction is just a hint, and a legal implementation is to implement WFI as a NOP.
|
||||
, wfi, "wfi", __wfi);
|
||||
instruction!(
|
||||
/// `SFENCE.VMA` instruction wrapper (all address spaces and page table levels)
|
||||
///
|
||||
/// Synchronizes updates to in-memory memory-management data structures with current execution.
|
||||
/// Instruction execution causes implicit reads and writes to these data structures; however, these implicit references
|
||||
/// are ordinarily not ordered with respect to loads and stores in the instruction stream.
|
||||
/// Executing an `SFENCE.VMA` instruction guarantees that any stores in the instruction stream prior to the
|
||||
/// `SFENCE.VMA` are ordered before all implicit references subsequent to the `SFENCE.VMA`.
|
||||
, sfence_vma_all, "sfence.vma", __sfence_vma_all);
|
||||
|
||||
|
||||
/// `SFENCE.VMA` instruction wrapper
|
||||
///
|
||||
/// Synchronizes updates to in-memory memory-management data structures with current execution.
|
||||
/// Instruction execution causes implicit reads and writes to these data structures; however, these implicit references
|
||||
/// are ordinarily not ordered with respect to loads and stores in the instruction stream.
|
||||
/// Executing an `SFENCE.VMA` instruction guarantees that any stores in the instruction stream prior to the
|
||||
/// `SFENCE.VMA` are ordered before all implicit references subsequent to the `SFENCE.VMA`.
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
pub unsafe fn sfence_vma(asid: usize, addr: usize) {
|
||||
match () {
|
||||
#[cfg(all(riscv, feature = "inline-asm"))]
|
||||
() => asm!("sfence.vma $0, $1" :: "r"(asid), "r"(addr) :: "volatile"),
|
||||
|
||||
#[cfg(all(riscv, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn __sfence_vma(asid: usize, addr: usize);
|
||||
}
|
||||
|
||||
__sfence_vma(asid, addr);
|
||||
}
|
||||
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
54
xous-riscv/src/interrupt.rs
Normal file
54
xous-riscv/src/interrupt.rs
Normal file
@ -0,0 +1,54 @@
|
||||
//! Interrupts
|
||||
|
||||
// NOTE: Adapted from cortex-m/src/interrupt.rs
|
||||
pub use bare_metal::{CriticalSection, Mutex, Nr};
|
||||
use register::mstatus;
|
||||
|
||||
/// Disables all interrupts
|
||||
#[inline]
|
||||
pub unsafe fn disable() {
|
||||
match () {
|
||||
#[cfg(riscv)]
|
||||
() => mstatus::clear_mie(),
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enables all the interrupts
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - Do not call this function inside an `interrupt::free` critical section
|
||||
#[inline]
|
||||
pub unsafe fn enable() {
|
||||
match () {
|
||||
#[cfg(riscv)]
|
||||
() => mstatus::set_mie(),
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute closure `f` in an interrupt-free context.
|
||||
///
|
||||
/// This as also known as a "critical section".
|
||||
pub fn free<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce(&CriticalSection) -> R,
|
||||
{
|
||||
let mstatus = mstatus::read();
|
||||
|
||||
// disable interrupts
|
||||
unsafe { disable(); }
|
||||
|
||||
let r = f(unsafe { &CriticalSection::new() });
|
||||
|
||||
// If the interrupts were active before our `disable` call, then re-enable
|
||||
// them. Otherwise, keep them disabled
|
||||
if mstatus.mie() {
|
||||
unsafe { enable(); }
|
||||
}
|
||||
|
||||
r
|
||||
}
|
27
xous-riscv/src/lib.rs
Normal file
27
xous-riscv/src/lib.rs
Normal file
@ -0,0 +1,27 @@
|
||||
//! Low level access to RISC-V processors
|
||||
//!
|
||||
//! # Minimum Supported Rust Version (MSRV)
|
||||
//!
|
||||
//! This crate is guaranteed to compile on stable Rust 1.30 and up. It *might*
|
||||
//! compile with older versions but that may change in any new patch release.
|
||||
//! Note that `riscv64imac-unknown-none-elf` and `riscv64gc-unknown-none-elf` targets
|
||||
//! are not supported on stable yet.
|
||||
//!
|
||||
//! # Features
|
||||
//!
|
||||
//! This crate provides:
|
||||
//!
|
||||
//! - Access to core registers like `mstatus` or `mcause`.
|
||||
//! - Interrupt manipulation mechanisms.
|
||||
//! - Wrappers around assembly instructions like `WFI`.
|
||||
|
||||
#![no_std]
|
||||
#![deny(warnings)]
|
||||
#![cfg_attr(feature = "inline-asm", feature(asm))]
|
||||
|
||||
extern crate bare_metal;
|
||||
extern crate bit_field;
|
||||
|
||||
pub mod asm;
|
||||
pub mod interrupt;
|
||||
pub mod register;
|
132
xous-riscv/src/register/fcsr.rs
Normal file
132
xous-riscv/src/register/fcsr.rs
Normal file
@ -0,0 +1,132 @@
|
||||
//! Floating-point control and status register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// Floating-point control and status register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct FCSR {
|
||||
bits: u32,
|
||||
}
|
||||
|
||||
/// Accrued Exception Flags
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Flags(u32);
|
||||
|
||||
/// Accrued Exception Flag
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Flag {
|
||||
/// Inexact
|
||||
NX = 0b00001,
|
||||
|
||||
/// Underflow
|
||||
UF = 0b00010,
|
||||
|
||||
/// Overflow
|
||||
OF = 0b00100,
|
||||
|
||||
/// Divide by Zero
|
||||
DZ = 0b01000,
|
||||
|
||||
/// Invalid Operation
|
||||
NV = 0b10000,
|
||||
}
|
||||
|
||||
impl Flags {
|
||||
/// Inexact
|
||||
#[inline]
|
||||
pub fn nx(&self) -> bool {
|
||||
self.0.get_bit(0)
|
||||
}
|
||||
|
||||
/// Underflow
|
||||
#[inline]
|
||||
pub fn uf(&self) -> bool {
|
||||
self.0.get_bit(1)
|
||||
}
|
||||
|
||||
/// Overflow
|
||||
#[inline]
|
||||
pub fn of(&self) -> bool {
|
||||
self.0.get_bit(2)
|
||||
}
|
||||
|
||||
/// Divide by Zero
|
||||
#[inline]
|
||||
pub fn dz(&self) -> bool {
|
||||
self.0.get_bit(3)
|
||||
}
|
||||
|
||||
/// Invalid Operation
|
||||
#[inline]
|
||||
pub fn nv(&self) -> bool {
|
||||
self.0.get_bit(4)
|
||||
}
|
||||
}
|
||||
|
||||
/// Rounding Mode
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum RoundingMode {
|
||||
RoundToNearestEven = 0b000,
|
||||
RoundTowardsZero = 0b001,
|
||||
RoundDown = 0b010,
|
||||
RoundUp = 0b011,
|
||||
RoundToNearestMaxMagnitude = 0b100,
|
||||
Invalid = 0b111,
|
||||
}
|
||||
|
||||
impl FCSR {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> u32 {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Accrued Exception Flags
|
||||
#[inline]
|
||||
pub fn fflags(&self) -> Flags {
|
||||
Flags(self.bits.get_bits(0..5))
|
||||
}
|
||||
|
||||
/// Rounding Mode
|
||||
#[inline]
|
||||
pub fn frm(&self) -> RoundingMode {
|
||||
match self.bits.get_bits(5..8) {
|
||||
0b000 => RoundingMode::RoundToNearestEven,
|
||||
0b001 => RoundingMode::RoundTowardsZero,
|
||||
0b010 => RoundingMode::RoundDown,
|
||||
0b011 => RoundingMode::RoundUp,
|
||||
0b100 => RoundingMode::RoundToNearestMaxMagnitude,
|
||||
_ => RoundingMode::Invalid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
read_csr!(0x003, __read_fcsr);
|
||||
write_csr!(0x003, __write_fcsr);
|
||||
clear!(0x003, __clear_fcsr);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> FCSR {
|
||||
FCSR { bits: unsafe{ _read() as u32 } }
|
||||
}
|
||||
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
pub unsafe fn set_rounding_mode(frm: RoundingMode) {
|
||||
let old = read();
|
||||
let bits = ((frm as u32) << 5) | old.fflags().0;
|
||||
_write(bits as usize);
|
||||
}
|
||||
|
||||
/// Resets `fflags` field bits
|
||||
#[inline]
|
||||
pub unsafe fn clear_flags() {
|
||||
let mask = 0b11111;
|
||||
_clear(mask);
|
||||
}
|
||||
|
||||
/// Resets `fflags` field bit
|
||||
#[inline]
|
||||
pub unsafe fn clear_flag(flag: Flag) {
|
||||
_clear(flag as usize);
|
||||
}
|
82
xous-riscv/src/register/hpmcounterx.rs
Normal file
82
xous-riscv/src/register/hpmcounterx.rs
Normal file
@ -0,0 +1,82 @@
|
||||
macro_rules! reg {
|
||||
(
|
||||
$addr:expr, $csrl:ident, $csrh:ident, $readf:ident, $writef:ident
|
||||
) => {
|
||||
/// Performance-monitoring counter
|
||||
pub mod $csrl {
|
||||
read_csr_as_usize!($addr, $readf);
|
||||
read_composite_csr!(super::$csrh::read(), read());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! regh {
|
||||
(
|
||||
$addr:expr, $csrh:ident, $readf:ident, $writef:ident
|
||||
) => {
|
||||
/// Upper 32 bits of performance-monitoring counter (RV32I only)
|
||||
pub mod $csrh {
|
||||
read_csr_as_usize_rv32!($addr, $readf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reg!(0xC03, hpmcounter3, hpmcounter3h, __read_hpmcounter3, __write_hpmcounter3);
|
||||
reg!(0xC04, hpmcounter4, hpmcounter4h, __read_hpmcounter4, __write_hpmcounter4);
|
||||
reg!(0xC05, hpmcounter5, hpmcounter5h, __read_hpmcounter5, __write_hpmcounter5);
|
||||
reg!(0xC06, hpmcounter6, hpmcounter6h, __read_hpmcounter6, __write_hpmcounter6);
|
||||
reg!(0xC07, hpmcounter7, hpmcounter7h, __read_hpmcounter7, __write_hpmcounter7);
|
||||
reg!(0xC08, hpmcounter8, hpmcounter8h, __read_hpmcounter8, __write_hpmcounter8);
|
||||
reg!(0xC09, hpmcounter9, hpmcounter9h, __read_hpmcounter9, __write_hpmcounter9);
|
||||
reg!(0xC0A, hpmcounter10, hpmcounter10h, __read_hpmcounter10, __write_hpmcounter10);
|
||||
reg!(0xC0B, hpmcounter11, hpmcounter11h, __read_hpmcounter11, __write_hpmcounter11);
|
||||
reg!(0xC0C, hpmcounter12, hpmcounter12h, __read_hpmcounter12, __write_hpmcounter12);
|
||||
reg!(0xC0D, hpmcounter13, hpmcounter13h, __read_hpmcounter13, __write_hpmcounter13);
|
||||
reg!(0xC0E, hpmcounter14, hpmcounter14h, __read_hpmcounter14, __write_hpmcounter14);
|
||||
reg!(0xC0F, hpmcounter15, hpmcounter15h, __read_hpmcounter15, __write_hpmcounter15);
|
||||
reg!(0xC10, hpmcounter16, hpmcounter16h, __read_hpmcounter16, __write_hpmcounter16);
|
||||
reg!(0xC11, hpmcounter17, hpmcounter17h, __read_hpmcounter17, __write_hpmcounter17);
|
||||
reg!(0xC12, hpmcounter18, hpmcounter18h, __read_hpmcounter18, __write_hpmcounter18);
|
||||
reg!(0xC13, hpmcounter19, hpmcounter19h, __read_hpmcounter19, __write_hpmcounter19);
|
||||
reg!(0xC14, hpmcounter20, hpmcounter20h, __read_hpmcounter20, __write_hpmcounter20);
|
||||
reg!(0xC15, hpmcounter21, hpmcounter21h, __read_hpmcounter21, __write_hpmcounter21);
|
||||
reg!(0xC16, hpmcounter22, hpmcounter22h, __read_hpmcounter22, __write_hpmcounter22);
|
||||
reg!(0xC17, hpmcounter23, hpmcounter23h, __read_hpmcounter23, __write_hpmcounter23);
|
||||
reg!(0xC18, hpmcounter24, hpmcounter24h, __read_hpmcounter24, __write_hpmcounter24);
|
||||
reg!(0xC19, hpmcounter25, hpmcounter25h, __read_hpmcounter25, __write_hpmcounter25);
|
||||
reg!(0xC1A, hpmcounter26, hpmcounter26h, __read_hpmcounter26, __write_hpmcounter26);
|
||||
reg!(0xC1B, hpmcounter27, hpmcounter27h, __read_hpmcounter27, __write_hpmcounter27);
|
||||
reg!(0xC1C, hpmcounter28, hpmcounter28h, __read_hpmcounter28, __write_hpmcounter28);
|
||||
reg!(0xC1D, hpmcounter29, hpmcounter29h, __read_hpmcounter29, __write_hpmcounter29);
|
||||
reg!(0xC1E, hpmcounter30, hpmcounter30h, __read_hpmcounter30, __write_hpmcounter30);
|
||||
reg!(0xC1F, hpmcounter31, hpmcounter31h, __read_hpmcounter31, __write_hpmcounter31);
|
||||
|
||||
regh!(0xC83, hpmcounter3h, __read_hpmcounter3h, __write_hpmcounter3h);
|
||||
regh!(0xC84, hpmcounter4h, __read_hpmcounter4h, __write_hpmcounter4h);
|
||||
regh!(0xC85, hpmcounter5h, __read_hpmcounter5h, __write_hpmcounter5h);
|
||||
regh!(0xC86, hpmcounter6h, __read_hpmcounter6h, __write_hpmcounter6h);
|
||||
regh!(0xC87, hpmcounter7h, __read_hpmcounter7h, __write_hpmcounter7h);
|
||||
regh!(0xC88, hpmcounter8h, __read_hpmcounter8h, __write_hpmcounter8h);
|
||||
regh!(0xC89, hpmcounter9h, __read_hpmcounter9h, __write_hpmcounter9h);
|
||||
regh!(0xC8A, hpmcounter10h, __read_hpmcounter10h, __write_hpmcounter10h);
|
||||
regh!(0xC8B, hpmcounter11h, __read_hpmcounter11h, __write_hpmcounter11h);
|
||||
regh!(0xC8C, hpmcounter12h, __read_hpmcounter12h, __write_hpmcounter12h);
|
||||
regh!(0xC8D, hpmcounter13h, __read_hpmcounter13h, __write_hpmcounter13h);
|
||||
regh!(0xC8E, hpmcounter14h, __read_hpmcounter14h, __write_hpmcounter14h);
|
||||
regh!(0xC8F, hpmcounter15h, __read_hpmcounter15h, __write_hpmcounter15h);
|
||||
regh!(0xC90, hpmcounter16h, __read_hpmcounter16h, __write_hpmcounter16h);
|
||||
regh!(0xC91, hpmcounter17h, __read_hpmcounter17h, __write_hpmcounter17h);
|
||||
regh!(0xC92, hpmcounter18h, __read_hpmcounter18h, __write_hpmcounter18h);
|
||||
regh!(0xC93, hpmcounter19h, __read_hpmcounter19h, __write_hpmcounter19h);
|
||||
regh!(0xC94, hpmcounter20h, __read_hpmcounter20h, __write_hpmcounter20h);
|
||||
regh!(0xC95, hpmcounter21h, __read_hpmcounter21h, __write_hpmcounter21h);
|
||||
regh!(0xC96, hpmcounter22h, __read_hpmcounter22h, __write_hpmcounter22h);
|
||||
regh!(0xC97, hpmcounter23h, __read_hpmcounter23h, __write_hpmcounter23h);
|
||||
regh!(0xC98, hpmcounter24h, __read_hpmcounter24h, __write_hpmcounter24h);
|
||||
regh!(0xC99, hpmcounter25h, __read_hpmcounter25h, __write_hpmcounter25h);
|
||||
regh!(0xC9A, hpmcounter26h, __read_hpmcounter26h, __write_hpmcounter26h);
|
||||
regh!(0xC9B, hpmcounter27h, __read_hpmcounter27h, __write_hpmcounter27h);
|
||||
regh!(0xC9C, hpmcounter28h, __read_hpmcounter28h, __write_hpmcounter28h);
|
||||
regh!(0xC9D, hpmcounter29h, __read_hpmcounter29h, __write_hpmcounter29h);
|
||||
regh!(0xC9E, hpmcounter30h, __read_hpmcounter30h, __write_hpmcounter30h);
|
||||
regh!(0xC9F, hpmcounter31h, __read_hpmcounter31h, __write_hpmcounter31h);
|
270
xous-riscv/src/register/macros.rs
Normal file
270
xous-riscv/src/register/macros.rs
Normal file
@ -0,0 +1,270 @@
|
||||
macro_rules! read_csr {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
unsafe fn _read() -> usize {
|
||||
match () {
|
||||
#[cfg(all(riscv, feature = "inline-asm"))]
|
||||
() => {
|
||||
let r: usize;
|
||||
asm!("csrrs $0, $1, x0" : "=r"(r) : "i"($csr_number) :: "volatile");
|
||||
r
|
||||
}
|
||||
|
||||
#[cfg(all(riscv, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn() -> usize;
|
||||
}
|
||||
|
||||
$asm_fn()
|
||||
}
|
||||
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! read_csr_rv32 {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
unsafe fn _read() -> usize {
|
||||
match () {
|
||||
#[cfg(all(riscv32, feature = "inline-asm"))]
|
||||
() => {
|
||||
let r: usize;
|
||||
asm!("csrrs $0, $1, x0" : "=r"(r) : "i"($csr_number) :: "volatile");
|
||||
r
|
||||
}
|
||||
|
||||
#[cfg(all(riscv32, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn() -> usize;
|
||||
}
|
||||
|
||||
$asm_fn()
|
||||
}
|
||||
|
||||
#[cfg(not(riscv32))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! read_csr_as {
|
||||
($register:ident, $csr_number:expr, $asm_fn: ident) => {
|
||||
read_csr!($csr_number, $asm_fn);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> $register {
|
||||
$register { bits: unsafe{ _read() } }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! read_csr_as_usize {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
read_csr!($csr_number, $asm_fn);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> usize {
|
||||
unsafe{ _read() }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! read_csr_as_usize_rv32 {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
read_csr_rv32!($csr_number, $asm_fn);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> usize {
|
||||
unsafe{ _read() }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! write_csr {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
unsafe fn _write(bits: usize) {
|
||||
match () {
|
||||
#[cfg(all(riscv, feature = "inline-asm"))]
|
||||
() => asm!("csrrw x0, $1, $0" :: "r"(bits), "i"($csr_number) :: "volatile"),
|
||||
|
||||
#[cfg(all(riscv, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn(bits: usize);
|
||||
}
|
||||
|
||||
$asm_fn(bits);
|
||||
}
|
||||
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! write_csr_rv32 {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
unsafe fn _write(bits: usize) {
|
||||
match () {
|
||||
#[cfg(all(riscv32, feature = "inline-asm"))]
|
||||
() => asm!("csrrw x0, $1, $0" :: "r"(bits), "i"($csr_number) :: "volatile"),
|
||||
|
||||
#[cfg(all(riscv32, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn(bits: usize);
|
||||
}
|
||||
|
||||
$asm_fn(bits);
|
||||
}
|
||||
|
||||
#[cfg(not(riscv32))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! write_csr_as_usize {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
write_csr!($csr_number, $asm_fn);
|
||||
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
pub fn write(bits: usize) {
|
||||
unsafe{ _write(bits) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! write_csr_as_usize_rv32 {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
write_csr_rv32!($csr_number, $asm_fn);
|
||||
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
pub fn write(bits: usize) {
|
||||
unsafe{ _write(bits) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! set {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
/// Set the CSR
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
unsafe fn _set(bits: usize) {
|
||||
match () {
|
||||
#[cfg(all(riscv, feature = "inline-asm"))]
|
||||
() => asm!("csrrs x0, $1, $0" :: "r"(bits), "i"($csr_number) :: "volatile"),
|
||||
|
||||
#[cfg(all(riscv, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn(bits: usize);
|
||||
}
|
||||
|
||||
$asm_fn(bits);
|
||||
}
|
||||
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! clear {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
/// Clear the CSR
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
unsafe fn _clear(bits: usize) {
|
||||
match () {
|
||||
#[cfg(all(riscv, feature = "inline-asm"))]
|
||||
() => asm!("csrrc x0, $1, $0" :: "r"(bits), "i"($csr_number) :: "volatile"),
|
||||
|
||||
#[cfg(all(riscv, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn(bits: usize);
|
||||
}
|
||||
|
||||
$asm_fn(bits);
|
||||
}
|
||||
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! set_csr {
|
||||
($(#[$attr:meta])*, $set_field:ident, $e:expr) => {
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
pub unsafe fn $set_field() {
|
||||
_set($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! clear_csr {
|
||||
($(#[$attr:meta])*, $clear_field:ident, $e:expr) => {
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
pub unsafe fn $clear_field() {
|
||||
_clear($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! set_clear_csr {
|
||||
($(#[$attr:meta])*, $set_field:ident, $clear_field:ident, $e:expr) => {
|
||||
set_csr!($(#[$attr])*, $set_field, $e);
|
||||
clear_csr!($(#[$attr])*, $clear_field, $e);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! read_composite_csr {
|
||||
($hi:expr, $lo:expr) => {
|
||||
/// Reads the CSR as a 64-bit value
|
||||
#[inline]
|
||||
pub fn read64() -> u64 {
|
||||
match () {
|
||||
#[cfg(riscv32)]
|
||||
() => loop {
|
||||
let hi = $hi;
|
||||
let lo = $lo;
|
||||
if hi == $hi {
|
||||
return ((hi as u64) << 32) | lo as u64;
|
||||
}
|
||||
},
|
||||
|
||||
#[cfg(not(riscv32))]
|
||||
() => $lo as u64,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
27
xous-riscv/src/register/marchid.rs
Normal file
27
xous-riscv/src/register/marchid.rs
Normal file
@ -0,0 +1,27 @@
|
||||
//! marchid register
|
||||
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
/// marchid register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Marchid {
|
||||
bits: NonZeroUsize,
|
||||
}
|
||||
|
||||
impl Marchid {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits.get()
|
||||
}
|
||||
}
|
||||
|
||||
read_csr!(0xF11, __read_marchid);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> Option<Marchid> {
|
||||
let r = unsafe{ _read() };
|
||||
// When marchid is hardwired to zero it means that the marchid
|
||||
// csr isn't implemented.
|
||||
NonZeroUsize::new(r).map(|bits| Marchid { bits })
|
||||
}
|
139
xous-riscv/src/register/mcause.rs
Normal file
139
xous-riscv/src/register/mcause.rs
Normal file
@ -0,0 +1,139 @@
|
||||
//! mcause register
|
||||
|
||||
/// mcause register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mcause {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
/// Trap Cause
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Trap {
|
||||
Interrupt(Interrupt),
|
||||
Exception(Exception),
|
||||
}
|
||||
|
||||
/// Interrupt
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Interrupt {
|
||||
UserSoft,
|
||||
SupervisorSoft,
|
||||
MachineSoft,
|
||||
UserTimer,
|
||||
SupervisorTimer,
|
||||
MachineTimer,
|
||||
UserExternal,
|
||||
SupervisorExternal,
|
||||
MachineExternal,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
/// Exception
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Exception {
|
||||
InstructionMisaligned,
|
||||
InstructionFault,
|
||||
IllegalInstruction,
|
||||
Breakpoint,
|
||||
LoadMisaligned,
|
||||
LoadFault,
|
||||
StoreMisaligned,
|
||||
StoreFault,
|
||||
UserEnvCall,
|
||||
SupervisorEnvCall,
|
||||
MachineEnvCall,
|
||||
InstructionPageFault,
|
||||
LoadPageFault,
|
||||
StorePageFault,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl Interrupt {
|
||||
pub fn from(nr: usize) -> Self {
|
||||
match nr {
|
||||
0 => Interrupt::UserSoft,
|
||||
1 => Interrupt::SupervisorSoft,
|
||||
3 => Interrupt::MachineSoft,
|
||||
4 => Interrupt::UserTimer,
|
||||
5 => Interrupt::SupervisorTimer,
|
||||
7 => Interrupt::MachineTimer,
|
||||
8 => Interrupt::UserExternal,
|
||||
9 => Interrupt::SupervisorExternal,
|
||||
11 => Interrupt::MachineExternal,
|
||||
_ => Interrupt::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Exception {
|
||||
pub fn from(nr: usize) -> Self {
|
||||
match nr {
|
||||
0 => Exception::InstructionMisaligned,
|
||||
1 => Exception::InstructionFault,
|
||||
2 => Exception::IllegalInstruction,
|
||||
3 => Exception::Breakpoint,
|
||||
4 => Exception::LoadMisaligned,
|
||||
5 => Exception::LoadFault,
|
||||
6 => Exception::StoreMisaligned,
|
||||
7 => Exception::StoreFault,
|
||||
8 => Exception::UserEnvCall,
|
||||
9 => Exception::SupervisorEnvCall,
|
||||
11 => Exception::MachineEnvCall,
|
||||
12 => Exception::InstructionPageFault,
|
||||
13 => Exception::LoadPageFault,
|
||||
15 => Exception::StorePageFault,
|
||||
_ => Exception::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Mcause {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Returns the code field
|
||||
pub fn code(&self) -> usize {
|
||||
match () {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
() => self.bits & !(1 << 31),
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
() => self.bits & !(1 << 63),
|
||||
#[cfg(target_pointer_width = "128")]
|
||||
() => self.bits & !(1 << 127),
|
||||
}
|
||||
}
|
||||
|
||||
/// Trap Cause
|
||||
#[inline]
|
||||
pub fn cause(&self) -> Trap {
|
||||
if self.is_interrupt() {
|
||||
Trap::Interrupt(Interrupt::from(self.code()))
|
||||
} else {
|
||||
Trap::Exception(Exception::from(self.code()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Is trap cause an interrupt.
|
||||
#[inline]
|
||||
pub fn is_interrupt(&self) -> bool {
|
||||
match () {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
() => self.bits & (1 << 31) == 1 << 31,
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
() => self.bits & (1 << 63) == 1 << 63,
|
||||
#[cfg(target_pointer_width = "128")]
|
||||
() => self.bits & (1 << 127) == 1 << 127,
|
||||
}
|
||||
}
|
||||
|
||||
/// Is trap cause an exception.
|
||||
#[inline]
|
||||
pub fn is_exception(&self) -> bool {
|
||||
!self.is_interrupt()
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Mcause, 0x342, __read_mcause);
|
4
xous-riscv/src/register/mcycle.rs
Normal file
4
xous-riscv/src/register/mcycle.rs
Normal file
@ -0,0 +1,4 @@
|
||||
//! mcycle register
|
||||
|
||||
read_csr_as_usize!(0xB00, __read_mcycle);
|
||||
read_composite_csr!(super::mcycleh::read(), read());
|
3
xous-riscv/src/register/mcycleh.rs
Normal file
3
xous-riscv/src/register/mcycleh.rs
Normal file
@ -0,0 +1,3 @@
|
||||
//! mcycleh register
|
||||
|
||||
read_csr_as_usize_rv32!(0xB80, __read_mcycleh);
|
4
xous-riscv/src/register/mepc.rs
Normal file
4
xous-riscv/src/register/mepc.rs
Normal file
@ -0,0 +1,4 @@
|
||||
//! mepc register
|
||||
|
||||
read_csr_as_usize!(0x341, __read_mepc);
|
||||
write_csr_as_usize!(0x341, __write_mepc);
|
3
xous-riscv/src/register/mhartid.rs
Normal file
3
xous-riscv/src/register/mhartid.rs
Normal file
@ -0,0 +1,3 @@
|
||||
//! mhartid register
|
||||
|
||||
read_csr_as_usize!(0xf14, __read_mhartid);
|
84
xous-riscv/src/register/mhpmcounterx.rs
Normal file
84
xous-riscv/src/register/mhpmcounterx.rs
Normal file
@ -0,0 +1,84 @@
|
||||
macro_rules! reg {
|
||||
(
|
||||
$addr:expr, $csrl:ident, $csrh:ident, $readf:ident, $writef:ident
|
||||
) => {
|
||||
/// Machine performance-monitoring counter
|
||||
pub mod $csrl {
|
||||
read_csr_as_usize!($addr, $readf);
|
||||
write_csr_as_usize!($addr, $writef);
|
||||
read_composite_csr!(super::$csrh::read(), read());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! regh {
|
||||
(
|
||||
$addr:expr, $csrh:ident, $readf:ident, $writef:ident
|
||||
) => {
|
||||
/// Upper 32 bits of machine performance-monitoring counter (RV32I only)
|
||||
pub mod $csrh {
|
||||
read_csr_as_usize_rv32!($addr, $readf);
|
||||
write_csr_as_usize_rv32!($addr, $writef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reg!(0xB03, mhpmcounter3, mhpmcounter3h, __read_mhpmcounter3, __write_mhpmcounter3);
|
||||
reg!(0xB04, mhpmcounter4, mhpmcounter4h, __read_mhpmcounter4, __write_mhpmcounter4);
|
||||
reg!(0xB05, mhpmcounter5, mhpmcounter5h, __read_mhpmcounter5, __write_mhpmcounter5);
|
||||
reg!(0xB06, mhpmcounter6, mhpmcounter6h, __read_mhpmcounter6, __write_mhpmcounter6);
|
||||
reg!(0xB07, mhpmcounter7, mhpmcounter7h, __read_mhpmcounter7, __write_mhpmcounter7);
|
||||
reg!(0xB08, mhpmcounter8, mhpmcounter8h, __read_mhpmcounter8, __write_mhpmcounter8);
|
||||
reg!(0xB09, mhpmcounter9, mhpmcounter9h, __read_mhpmcounter9, __write_mhpmcounter9);
|
||||
reg!(0xB0A, mhpmcounter10, mhpmcounter10h, __read_mhpmcounter10, __write_mhpmcounter10);
|
||||
reg!(0xB0B, mhpmcounter11, mhpmcounter11h, __read_mhpmcounter11, __write_mhpmcounter11);
|
||||
reg!(0xB0C, mhpmcounter12, mhpmcounter12h, __read_mhpmcounter12, __write_mhpmcounter12);
|
||||
reg!(0xB0D, mhpmcounter13, mhpmcounter13h, __read_mhpmcounter13, __write_mhpmcounter13);
|
||||
reg!(0xB0E, mhpmcounter14, mhpmcounter14h, __read_mhpmcounter14, __write_mhpmcounter14);
|
||||
reg!(0xB0F, mhpmcounter15, mhpmcounter15h, __read_mhpmcounter15, __write_mhpmcounter15);
|
||||
reg!(0xB10, mhpmcounter16, mhpmcounter16h, __read_mhpmcounter16, __write_mhpmcounter16);
|
||||
reg!(0xB11, mhpmcounter17, mhpmcounter17h, __read_mhpmcounter17, __write_mhpmcounter17);
|
||||
reg!(0xB12, mhpmcounter18, mhpmcounter18h, __read_mhpmcounter18, __write_mhpmcounter18);
|
||||
reg!(0xB13, mhpmcounter19, mhpmcounter19h, __read_mhpmcounter19, __write_mhpmcounter19);
|
||||
reg!(0xB14, mhpmcounter20, mhpmcounter20h, __read_mhpmcounter20, __write_mhpmcounter20);
|
||||
reg!(0xB15, mhpmcounter21, mhpmcounter21h, __read_mhpmcounter21, __write_mhpmcounter21);
|
||||
reg!(0xB16, mhpmcounter22, mhpmcounter22h, __read_mhpmcounter22, __write_mhpmcounter22);
|
||||
reg!(0xB17, mhpmcounter23, mhpmcounter23h, __read_mhpmcounter23, __write_mhpmcounter23);
|
||||
reg!(0xB18, mhpmcounter24, mhpmcounter24h, __read_mhpmcounter24, __write_mhpmcounter24);
|
||||
reg!(0xB19, mhpmcounter25, mhpmcounter25h, __read_mhpmcounter25, __write_mhpmcounter25);
|
||||
reg!(0xB1A, mhpmcounter26, mhpmcounter26h, __read_mhpmcounter26, __write_mhpmcounter26);
|
||||
reg!(0xB1B, mhpmcounter27, mhpmcounter27h, __read_mhpmcounter27, __write_mhpmcounter27);
|
||||
reg!(0xB1C, mhpmcounter28, mhpmcounter28h, __read_mhpmcounter28, __write_mhpmcounter28);
|
||||
reg!(0xB1D, mhpmcounter29, mhpmcounter29h, __read_mhpmcounter29, __write_mhpmcounter29);
|
||||
reg!(0xB1E, mhpmcounter30, mhpmcounter30h, __read_mhpmcounter30, __write_mhpmcounter30);
|
||||
reg!(0xB1F, mhpmcounter31, mhpmcounter31h, __read_mhpmcounter31, __write_mhpmcounter31);
|
||||
|
||||
regh!(0xB83, mhpmcounter3h, __read_mhpmcounter3h, __write_mhpmcounter3h);
|
||||
regh!(0xB84, mhpmcounter4h, __read_mhpmcounter4h, __write_mhpmcounter4h);
|
||||
regh!(0xB85, mhpmcounter5h, __read_mhpmcounter5h, __write_mhpmcounter5h);
|
||||
regh!(0xB86, mhpmcounter6h, __read_mhpmcounter6h, __write_mhpmcounter6h);
|
||||
regh!(0xB87, mhpmcounter7h, __read_mhpmcounter7h, __write_mhpmcounter7h);
|
||||
regh!(0xB88, mhpmcounter8h, __read_mhpmcounter8h, __write_mhpmcounter8h);
|
||||
regh!(0xB89, mhpmcounter9h, __read_mhpmcounter9h, __write_mhpmcounter9h);
|
||||
regh!(0xB8A, mhpmcounter10h, __read_mhpmcounter10h, __write_mhpmcounter10h);
|
||||
regh!(0xB8B, mhpmcounter11h, __read_mhpmcounter11h, __write_mhpmcounter11h);
|
||||
regh!(0xB8C, mhpmcounter12h, __read_mhpmcounter12h, __write_mhpmcounter12h);
|
||||
regh!(0xB8D, mhpmcounter13h, __read_mhpmcounter13h, __write_mhpmcounter13h);
|
||||
regh!(0xB8E, mhpmcounter14h, __read_mhpmcounter14h, __write_mhpmcounter14h);
|
||||
regh!(0xB8F, mhpmcounter15h, __read_mhpmcounter15h, __write_mhpmcounter15h);
|
||||
regh!(0xB90, mhpmcounter16h, __read_mhpmcounter16h, __write_mhpmcounter16h);
|
||||
regh!(0xB91, mhpmcounter17h, __read_mhpmcounter17h, __write_mhpmcounter17h);
|
||||
regh!(0xB92, mhpmcounter18h, __read_mhpmcounter18h, __write_mhpmcounter18h);
|
||||
regh!(0xB93, mhpmcounter19h, __read_mhpmcounter19h, __write_mhpmcounter19h);
|
||||
regh!(0xB94, mhpmcounter20h, __read_mhpmcounter20h, __write_mhpmcounter20h);
|
||||
regh!(0xB95, mhpmcounter21h, __read_mhpmcounter21h, __write_mhpmcounter21h);
|
||||
regh!(0xB96, mhpmcounter22h, __read_mhpmcounter22h, __write_mhpmcounter22h);
|
||||
regh!(0xB97, mhpmcounter23h, __read_mhpmcounter23h, __write_mhpmcounter23h);
|
||||
regh!(0xB98, mhpmcounter24h, __read_mhpmcounter24h, __write_mhpmcounter24h);
|
||||
regh!(0xB99, mhpmcounter25h, __read_mhpmcounter25h, __write_mhpmcounter25h);
|
||||
regh!(0xB9A, mhpmcounter26h, __read_mhpmcounter26h, __write_mhpmcounter26h);
|
||||
regh!(0xB9B, mhpmcounter27h, __read_mhpmcounter27h, __write_mhpmcounter27h);
|
||||
regh!(0xB9C, mhpmcounter28h, __read_mhpmcounter28h, __write_mhpmcounter28h);
|
||||
regh!(0xB9D, mhpmcounter29h, __read_mhpmcounter29h, __write_mhpmcounter29h);
|
||||
regh!(0xB9E, mhpmcounter30h, __read_mhpmcounter30h, __write_mhpmcounter30h);
|
||||
regh!(0xB9F, mhpmcounter31h, __read_mhpmcounter31h, __write_mhpmcounter31h);
|
41
xous-riscv/src/register/mhpmeventx.rs
Normal file
41
xous-riscv/src/register/mhpmeventx.rs
Normal file
@ -0,0 +1,41 @@
|
||||
macro_rules! reg {
|
||||
(
|
||||
$addr:expr, $csr:ident, $readf:ident, $writef:ident
|
||||
) => {
|
||||
/// Machine performance-monitoring event selector
|
||||
pub mod $csr {
|
||||
read_csr_as_usize!($addr, $readf);
|
||||
write_csr_as_usize!($addr, $writef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reg!(0x323, mhpmevent3, __read_mhpmevent3, __write_mhpmevent3);
|
||||
reg!(0x324, mhpmevent4, __read_mhpmevent4, __write_mhpmevent4);
|
||||
reg!(0x325, mhpmevent5, __read_mhpmevent5, __write_mhpmevent5);
|
||||
reg!(0x326, mhpmevent6, __read_mhpmevent6, __write_mhpmevent6);
|
||||
reg!(0x327, mhpmevent7, __read_mhpmevent7, __write_mhpmevent7);
|
||||
reg!(0x328, mhpmevent8, __read_mhpmevent8, __write_mhpmevent8);
|
||||
reg!(0x329, mhpmevent9, __read_mhpmevent9, __write_mhpmevent9);
|
||||
reg!(0x32A, mhpmevent10, __read_mhpmevent10, __write_mhpmevent10);
|
||||
reg!(0x32B, mhpmevent11, __read_mhpmevent11, __write_mhpmevent11);
|
||||
reg!(0x32C, mhpmevent12, __read_mhpmevent12, __write_mhpmevent12);
|
||||
reg!(0x32D, mhpmevent13, __read_mhpmevent13, __write_mhpmevent13);
|
||||
reg!(0x32E, mhpmevent14, __read_mhpmevent14, __write_mhpmevent14);
|
||||
reg!(0x32F, mhpmevent15, __read_mhpmevent15, __write_mhpmevent15);
|
||||
reg!(0x330, mhpmevent16, __read_mhpmevent16, __write_mhpmevent16);
|
||||
reg!(0x331, mhpmevent17, __read_mhpmevent17, __write_mhpmevent17);
|
||||
reg!(0x332, mhpmevent18, __read_mhpmevent18, __write_mhpmevent18);
|
||||
reg!(0x333, mhpmevent19, __read_mhpmevent19, __write_mhpmevent19);
|
||||
reg!(0x334, mhpmevent20, __read_mhpmevent20, __write_mhpmevent20);
|
||||
reg!(0x335, mhpmevent21, __read_mhpmevent21, __write_mhpmevent21);
|
||||
reg!(0x336, mhpmevent22, __read_mhpmevent22, __write_mhpmevent22);
|
||||
reg!(0x337, mhpmevent23, __read_mhpmevent23, __write_mhpmevent23);
|
||||
reg!(0x338, mhpmevent24, __read_mhpmevent24, __write_mhpmevent24);
|
||||
reg!(0x339, mhpmevent25, __read_mhpmevent25, __write_mhpmevent25);
|
||||
reg!(0x33A, mhpmevent26, __read_mhpmevent26, __write_mhpmevent26);
|
||||
reg!(0x33B, mhpmevent27, __read_mhpmevent27, __write_mhpmevent27);
|
||||
reg!(0x33C, mhpmevent28, __read_mhpmevent28, __write_mhpmevent28);
|
||||
reg!(0x33D, mhpmevent29, __read_mhpmevent29, __write_mhpmevent29);
|
||||
reg!(0x33E, mhpmevent30, __read_mhpmevent30, __write_mhpmevent30);
|
||||
reg!(0x33F, mhpmevent31, __read_mhpmevent31, __write_mhpmevent31);
|
103
xous-riscv/src/register/mie.rs
Normal file
103
xous-riscv/src/register/mie.rs
Normal file
@ -0,0 +1,103 @@
|
||||
//! mie register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// mie register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mie {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Mie {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// User Software Interrupt Enable
|
||||
#[inline]
|
||||
pub fn usoft(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// Supervisor Software Interrupt Enable
|
||||
#[inline]
|
||||
pub fn ssoft(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
|
||||
/// Machine Software Interrupt Enable
|
||||
#[inline]
|
||||
pub fn msoft(&self) -> bool {
|
||||
self.bits.get_bit(3)
|
||||
}
|
||||
|
||||
/// User Timer Interrupt Enable
|
||||
#[inline]
|
||||
pub fn utimer(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// Supervisor Timer Interrupt Enable
|
||||
#[inline]
|
||||
pub fn stimer(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
|
||||
/// Machine Timer Interrupt Enable
|
||||
#[inline]
|
||||
pub fn mtimer(&self) -> bool {
|
||||
self.bits.get_bit(7)
|
||||
}
|
||||
|
||||
/// User External Interrupt Enable
|
||||
#[inline]
|
||||
pub fn uext(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
|
||||
/// Supervisor External Interrupt Enable
|
||||
#[inline]
|
||||
pub fn sext(&self) -> bool {
|
||||
self.bits.get_bit(9)
|
||||
}
|
||||
|
||||
/// Machine External Interrupt Enable
|
||||
#[inline]
|
||||
pub fn mext(&self) -> bool {
|
||||
self.bits.get_bit(11)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Mie, 0x304, __read_mie);
|
||||
set!(0x304, __set_mie);
|
||||
clear!(0x304, __clear_mie);
|
||||
|
||||
set_clear_csr!(
|
||||
/// User Software Interrupt Enable
|
||||
, set_usoft, clear_usoft, 1 << 0);
|
||||
set_clear_csr!(
|
||||
/// Supervisor Software Interrupt Enable
|
||||
, set_ssoft, clear_ssoft, 1 << 1);
|
||||
set_clear_csr!(
|
||||
/// Machine Software Interrupt Enable
|
||||
, set_msoft, clear_msoft, 1 << 3);
|
||||
set_clear_csr!(
|
||||
/// User Timer Interrupt Enable
|
||||
, set_utimer, clear_utimer, 1 << 4);
|
||||
set_clear_csr!(
|
||||
/// Supervisor Timer Interrupt Enable
|
||||
, set_stimer, clear_stimer, 1 << 5);
|
||||
set_clear_csr!(
|
||||
/// Machine Timer Interrupt Enable
|
||||
, set_mtimer, clear_mtimer, 1 << 7);
|
||||
set_clear_csr!(
|
||||
/// User External Interrupt Enable
|
||||
, set_uext, clear_uext, 1 << 8);
|
||||
set_clear_csr!(
|
||||
/// Supervisor External Interrupt Enable
|
||||
, set_sext, clear_sext, 1 << 9);
|
||||
set_clear_csr!(
|
||||
/// Machine External Interrupt Enable
|
||||
, set_mext, clear_mext, 1 << 11);
|
27
xous-riscv/src/register/mimpid.rs
Normal file
27
xous-riscv/src/register/mimpid.rs
Normal file
@ -0,0 +1,27 @@
|
||||
//! mimpid register
|
||||
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
/// mimpid register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mimpid {
|
||||
bits: NonZeroUsize,
|
||||
}
|
||||
|
||||
impl Mimpid {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits.get()
|
||||
}
|
||||
}
|
||||
|
||||
read_csr!(0xF11, __read_mimpid);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> Option<Mimpid> {
|
||||
let r = unsafe{ _read() };
|
||||
// When mimpid is hardwired to zero it means that the mimpid
|
||||
// csr isn't implemented.
|
||||
NonZeroUsize::new(r).map(|bits| Mimpid { bits })
|
||||
}
|
4
xous-riscv/src/register/minstret.rs
Normal file
4
xous-riscv/src/register/minstret.rs
Normal file
@ -0,0 +1,4 @@
|
||||
//! minstret register
|
||||
|
||||
read_csr_as_usize!(0xB02, __read_minstret);
|
||||
read_composite_csr!(super::minstreth::read(), read());
|
3
xous-riscv/src/register/minstreth.rs
Normal file
3
xous-riscv/src/register/minstreth.rs
Normal file
@ -0,0 +1,3 @@
|
||||
//! minstreth register
|
||||
|
||||
read_csr_as_usize_rv32!(0xB82, __read_minstreth);
|
73
xous-riscv/src/register/mip.rs
Normal file
73
xous-riscv/src/register/mip.rs
Normal file
@ -0,0 +1,73 @@
|
||||
//! mip register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// mip register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mip {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Mip {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// User Software Interrupt Pending
|
||||
#[inline]
|
||||
pub fn usoft(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// Supervisor Software Interrupt Pending
|
||||
#[inline]
|
||||
pub fn ssoft(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
|
||||
/// Machine Software Interrupt Pending
|
||||
#[inline]
|
||||
pub fn msoft(&self) -> bool {
|
||||
self.bits.get_bit(3)
|
||||
}
|
||||
|
||||
/// User Timer Interrupt Pending
|
||||
#[inline]
|
||||
pub fn utimer(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// Supervisor Timer Interrupt Pending
|
||||
#[inline]
|
||||
pub fn stimer(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
|
||||
/// Machine Timer Interrupt Pending
|
||||
#[inline]
|
||||
pub fn mtimer(&self) -> bool {
|
||||
self.bits.get_bit(7)
|
||||
}
|
||||
|
||||
/// User External Interrupt Pending
|
||||
#[inline]
|
||||
pub fn uext(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
|
||||
/// Supervisor External Interrupt Pending
|
||||
#[inline]
|
||||
pub fn sext(&self) -> bool {
|
||||
self.bits.get_bit(9)
|
||||
}
|
||||
|
||||
/// Machine External Interrupt Pending
|
||||
#[inline]
|
||||
pub fn mext(&self) -> bool {
|
||||
self.bits.get_bit(11)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Mip, 0x344, __read_mip);
|
60
xous-riscv/src/register/misa.rs
Normal file
60
xous-riscv/src/register/misa.rs
Normal file
@ -0,0 +1,60 @@
|
||||
//! misa register
|
||||
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
/// misa register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Misa {
|
||||
bits: NonZeroUsize,
|
||||
}
|
||||
|
||||
/// Machine XLEN
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum MXL {
|
||||
XLEN32,
|
||||
XLEN64,
|
||||
XLEN128,
|
||||
}
|
||||
|
||||
impl Misa {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits.get()
|
||||
}
|
||||
|
||||
/// Returns the machine xlen.
|
||||
pub fn mxl(&self) -> MXL {
|
||||
let value = match () {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
() => (self.bits() >> 30) as u8,
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
() => (self.bits() >> 62) as u8,
|
||||
};
|
||||
match value {
|
||||
1 => MXL::XLEN32,
|
||||
2 => MXL::XLEN64,
|
||||
3 => MXL::XLEN128,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true when the atomic extension is implemented.
|
||||
pub fn has_extension(&self, extension: char) -> bool {
|
||||
let bit = extension as u8 - 65;
|
||||
if bit > 25 {
|
||||
return false;
|
||||
}
|
||||
self.bits() & (1 << bit) == (1 << bit)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr!(0x301, __read_misa);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> Option<Misa> {
|
||||
let r = unsafe{ _read() };
|
||||
// When misa is hardwired to zero it means that the misa csr
|
||||
// isn't implemented.
|
||||
NonZeroUsize::new(r).map(|bits| Misa { bits })
|
||||
}
|
109
xous-riscv/src/register/mod.rs
Normal file
109
xous-riscv/src/register/mod.rs
Normal file
@ -0,0 +1,109 @@
|
||||
//! RISC-V CSR's
|
||||
//!
|
||||
//! The following registers are not available on 64-bit implementations.
|
||||
//!
|
||||
//! - cycleh
|
||||
//! - timeh
|
||||
//! - instreth
|
||||
//! - hpmcounter[3-31]h
|
||||
//! - mcycleh
|
||||
//! - minstreth
|
||||
//! - mhpmcounter[3-31]h
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
// User Trap Setup
|
||||
pub mod ustatus;
|
||||
pub mod uie;
|
||||
pub mod utvec;
|
||||
|
||||
// User Trap Handling
|
||||
pub mod uscratch;
|
||||
pub mod uepc;
|
||||
pub mod ucause;
|
||||
pub mod utval;
|
||||
pub mod uip;
|
||||
|
||||
// User Floating-Point CSRs
|
||||
// TODO: frm, fflags
|
||||
pub mod fcsr;
|
||||
|
||||
|
||||
// User Counter/Timers
|
||||
// TODO: cycle[h], instret[h]
|
||||
pub mod time;
|
||||
mod hpmcounterx;
|
||||
pub use self::hpmcounterx::*;
|
||||
pub mod timeh;
|
||||
|
||||
|
||||
// Supervisor Trap Setup
|
||||
// TODO: sedeleg, sideleg
|
||||
pub mod sstatus;
|
||||
pub mod sie;
|
||||
pub mod stvec;
|
||||
// TODO: scounteren
|
||||
|
||||
|
||||
// Supervisor Trap Handling
|
||||
pub mod sscratch;
|
||||
pub mod sepc;
|
||||
pub mod scause;
|
||||
pub mod stval;
|
||||
pub mod sip;
|
||||
|
||||
|
||||
// Supervisor Protection and Translation
|
||||
pub mod satp;
|
||||
|
||||
|
||||
// Machine Information Registers
|
||||
pub mod mvendorid;
|
||||
pub mod marchid;
|
||||
pub mod mimpid;
|
||||
pub mod mhartid;
|
||||
|
||||
|
||||
// Machine Trap Setup
|
||||
pub mod mstatus;
|
||||
pub mod misa;
|
||||
// TODO: medeleg, mideleg
|
||||
pub mod mie;
|
||||
pub mod mtvec;
|
||||
// TODO: mcounteren
|
||||
|
||||
|
||||
// Machine Trap Handling
|
||||
pub mod mscratch;
|
||||
pub mod mepc;
|
||||
pub mod mcause;
|
||||
pub mod mtval;
|
||||
pub mod mip;
|
||||
|
||||
|
||||
// Machine Protection and Translation
|
||||
mod pmpcfgx;
|
||||
pub use self::pmpcfgx::*;
|
||||
mod pmpaddrx;
|
||||
pub use self::pmpaddrx::*;
|
||||
|
||||
|
||||
// Machine Counter/Timers
|
||||
pub mod mcycle;
|
||||
pub mod minstret;
|
||||
mod mhpmcounterx;
|
||||
pub use self::mhpmcounterx::*;
|
||||
pub mod mcycleh;
|
||||
pub mod minstreth;
|
||||
|
||||
|
||||
// Machine Counter Setup
|
||||
mod mhpmeventx;
|
||||
pub use self::mhpmeventx::*;
|
||||
|
||||
|
||||
// TODO: Debug/Trace Registers (shared with Debug Mode)
|
||||
|
||||
|
||||
// TODO: Debug Mode Registers
|
4
xous-riscv/src/register/mscratch.rs
Normal file
4
xous-riscv/src/register/mscratch.rs
Normal file
@ -0,0 +1,4 @@
|
||||
//! mscratch register
|
||||
|
||||
read_csr_as_usize!(0x340, __read_mscratch);
|
||||
write_csr_as_usize!(0x340, __write_mscratch);
|
200
xous-riscv/src/register/mstatus.rs
Normal file
200
xous-riscv/src/register/mstatus.rs
Normal file
@ -0,0 +1,200 @@
|
||||
//! mstatus register
|
||||
// TODO: Virtualization, Memory Privilege and Extension Context Fields
|
||||
|
||||
use bit_field::BitField;
|
||||
use core::mem::size_of;
|
||||
|
||||
/// mstatus register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mstatus {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
/// Additional extension state
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum XS {
|
||||
/// All off
|
||||
AllOff = 0,
|
||||
|
||||
/// None dirty or clean, some on
|
||||
NoneDirtyOrClean = 1,
|
||||
|
||||
/// None dirty, some clean
|
||||
NoneDirtySomeClean = 2,
|
||||
|
||||
/// Some dirty
|
||||
SomeDirty = 3,
|
||||
}
|
||||
|
||||
/// Floating-point extension state
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum FS {
|
||||
Off = 0,
|
||||
Initial = 1,
|
||||
Clean = 2,
|
||||
Dirty = 3,
|
||||
}
|
||||
|
||||
/// Machine Previous Privilege Mode
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum MPP {
|
||||
Machine = 3,
|
||||
Supervisor = 1,
|
||||
User = 0,
|
||||
}
|
||||
|
||||
/// Supervisor Previous Privilege Mode
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum SPP {
|
||||
Supervisor = 1,
|
||||
User = 0,
|
||||
}
|
||||
|
||||
impl Mstatus {
|
||||
/// User Interrupt Enable
|
||||
#[inline]
|
||||
pub fn uie(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// Supervisor Interrupt Enable
|
||||
#[inline]
|
||||
pub fn sie(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
|
||||
/// Machine Interrupt Enable
|
||||
#[inline]
|
||||
pub fn mie(&self) -> bool {
|
||||
self.bits.get_bit(3)
|
||||
}
|
||||
|
||||
/// User Previous Interrupt Enable
|
||||
#[inline]
|
||||
pub fn upie(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// Supervisor Previous Interrupt Enable
|
||||
#[inline]
|
||||
pub fn spie(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
|
||||
/// Machine Previous Interrupt Enable
|
||||
#[inline]
|
||||
pub fn mpie(&self) -> bool {
|
||||
self.bits.get_bit(7)
|
||||
}
|
||||
|
||||
/// Supervisor Previous Privilege Mode
|
||||
#[inline]
|
||||
pub fn spp(&self) -> SPP {
|
||||
match self.bits.get_bit(8) {
|
||||
true => SPP::Supervisor,
|
||||
false => SPP::User,
|
||||
}
|
||||
}
|
||||
|
||||
/// Machine Previous Privilege Mode
|
||||
#[inline]
|
||||
pub fn mpp(&self) -> MPP {
|
||||
match self.bits.get_bits(11..13) {
|
||||
0b00 => MPP::User,
|
||||
0b01 => MPP::Supervisor,
|
||||
0b11 => MPP::Machine,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Floating-point extension state
|
||||
///
|
||||
/// Encodes the status of the floating-point unit,
|
||||
/// including the CSR `fcsr` and floating-point data registers `f0–f31`.
|
||||
#[inline]
|
||||
pub fn fs(&self) -> FS {
|
||||
match self.bits.get_bits(13..15) {
|
||||
0b00 => FS::Off,
|
||||
0b01 => FS::Initial,
|
||||
0b10 => FS::Clean,
|
||||
0b11 => FS::Dirty,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Additional extension state
|
||||
///
|
||||
/// Encodes the status of additional user-mode extensions and associated state.
|
||||
#[inline]
|
||||
pub fn xs(&self) -> XS {
|
||||
match self.bits.get_bits(15..17) {
|
||||
0b00 => XS::AllOff,
|
||||
0b01 => XS::NoneDirtyOrClean,
|
||||
0b10 => XS::NoneDirtySomeClean,
|
||||
0b11 => XS::SomeDirty,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether either the FS field or XS field
|
||||
/// signals the presence of some dirty state
|
||||
#[inline]
|
||||
pub fn sd(&self) -> bool {
|
||||
self.bits.get_bit(size_of::<usize>() * 8 - 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
read_csr_as!(Mstatus, 0x300, __read_mstatus);
|
||||
write_csr!(0x300, __write_mstatus);
|
||||
set!(0x300, __set_mstatus);
|
||||
clear!(0x300, __clear_mstatus);
|
||||
|
||||
set_clear_csr!(
|
||||
/// User Interrupt Enable
|
||||
, set_uie, clear_uie, 1 << 0);
|
||||
|
||||
set_clear_csr!(
|
||||
/// Supervisor Interrupt Enable
|
||||
, set_sie, clear_sie, 1 << 1);
|
||||
|
||||
set_clear_csr!(
|
||||
/// Machine Interrupt Enable
|
||||
, set_mie, clear_mie, 1 << 3);
|
||||
|
||||
set_csr!(
|
||||
/// User Previous Interrupt Enable
|
||||
, set_upie, 1 << 4);
|
||||
|
||||
set_csr!(
|
||||
/// Supervisor Previous Interrupt Enable
|
||||
, set_spie, 1 << 5);
|
||||
|
||||
set_csr!(
|
||||
/// Machine Previous Interrupt Enable
|
||||
, set_mpie, 1 << 7);
|
||||
|
||||
/// Supervisor Previous Privilege Mode
|
||||
#[inline]
|
||||
pub unsafe fn set_spp(spp: SPP) {
|
||||
match spp {
|
||||
SPP::Supervisor => _set(1 << 8),
|
||||
SPP::User => _clear(1 << 8),
|
||||
}
|
||||
}
|
||||
|
||||
/// Machine Previous Privilege Mode
|
||||
#[inline]
|
||||
pub unsafe fn set_mpp(mpp: MPP) {
|
||||
let mut value = _read();
|
||||
value.set_bits(11..13, mpp as usize);
|
||||
_write(value);
|
||||
}
|
||||
|
||||
/// Floating-point extension state
|
||||
#[inline]
|
||||
pub unsafe fn set_fs(fs: FS) {
|
||||
let mut value = _read();
|
||||
value.set_bits(13..15, fs as usize);
|
||||
_write(value);
|
||||
}
|
3
xous-riscv/src/register/mtval.rs
Normal file
3
xous-riscv/src/register/mtval.rs
Normal file
@ -0,0 +1,3 @@
|
||||
//! mtval register
|
||||
|
||||
read_csr_as_usize!(0x343, __read_mtval);
|
47
xous-riscv/src/register/mtvec.rs
Normal file
47
xous-riscv/src/register/mtvec.rs
Normal file
@ -0,0 +1,47 @@
|
||||
//! mtvec register
|
||||
|
||||
/// mtvec register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mtvec {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
/// Trap mode
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum TrapMode {
|
||||
Direct = 0,
|
||||
Vectored = 1,
|
||||
}
|
||||
|
||||
impl Mtvec {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Returns the trap-vector base-address
|
||||
pub fn address(&self) -> usize {
|
||||
self.bits - (self.bits & 0b11)
|
||||
}
|
||||
|
||||
/// Returns the trap-vector mode
|
||||
pub fn trap_mode(&self) -> TrapMode {
|
||||
let mode = self.bits & 0b11;
|
||||
match mode {
|
||||
0 => TrapMode::Direct,
|
||||
1 => TrapMode::Vectored,
|
||||
_ => unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Mtvec, 0x305, __read_mtvec);
|
||||
|
||||
write_csr!(0x305, __write_mtvec);
|
||||
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
pub unsafe fn write(addr: usize, mode: TrapMode) {
|
||||
let bits = addr + mode as usize;
|
||||
_write(bits);
|
||||
}
|
32
xous-riscv/src/register/mvendorid.rs
Normal file
32
xous-riscv/src/register/mvendorid.rs
Normal file
@ -0,0 +1,32 @@
|
||||
//! mvendorid register
|
||||
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
/// mvendorid register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mvendorid {
|
||||
bits: NonZeroUsize,
|
||||
}
|
||||
|
||||
impl Mvendorid {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits.get()
|
||||
}
|
||||
|
||||
/// Returns the JEDEC manufacturer ID
|
||||
pub fn jedec_manufacturer(&self) -> usize {
|
||||
self.bits() >> 7
|
||||
}
|
||||
}
|
||||
|
||||
read_csr!(0xF11, __read_mvendorid);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> Option<Mvendorid> {
|
||||
let r = unsafe{ _read() };
|
||||
// When mvendorid is hardwired to zero it means that the mvendorid
|
||||
// csr isn't implemented.
|
||||
NonZeroUsize::new(r).map(|bits| Mvendorid { bits })
|
||||
}
|
28
xous-riscv/src/register/pmpaddrx.rs
Normal file
28
xous-riscv/src/register/pmpaddrx.rs
Normal file
@ -0,0 +1,28 @@
|
||||
macro_rules! reg {
|
||||
(
|
||||
$addr:expr, $csr:ident, $readf:ident, $writef:ident
|
||||
) => {
|
||||
/// Physical memory protection address register
|
||||
pub mod $csr {
|
||||
read_csr_as_usize!($addr, $readf);
|
||||
write_csr_as_usize!($addr, $writef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reg!(0x3B0, pmpaddr0, __read_pmpaddr0, __write_pmpaddr0);
|
||||
reg!(0x3B1, pmpaddr1, __read_pmpaddr1, __write_pmpaddr1);
|
||||
reg!(0x3B2, pmpaddr2, __read_pmpaddr2, __write_pmpaddr2);
|
||||
reg!(0x3B3, pmpaddr3, __read_pmpaddr3, __write_pmpaddr3);
|
||||
reg!(0x3B4, pmpaddr4, __read_pmpaddr4, __write_pmpaddr4);
|
||||
reg!(0x3B5, pmpaddr5, __read_pmpaddr5, __write_pmpaddr5);
|
||||
reg!(0x3B6, pmpaddr6, __read_pmpaddr6, __write_pmpaddr6);
|
||||
reg!(0x3B7, pmpaddr7, __read_pmpaddr7, __write_pmpaddr7);
|
||||
reg!(0x3B8, pmpaddr8, __read_pmpaddr8, __write_pmpaddr8);
|
||||
reg!(0x3B9, pmpaddr9, __read_pmpaddr9, __write_pmpaddr9);
|
||||
reg!(0x3BA, pmpaddr10, __read_pmpaddr10, __write_pmpaddr10);
|
||||
reg!(0x3BB, pmpaddr11, __read_pmpaddr11, __write_pmpaddr11);
|
||||
reg!(0x3BC, pmpaddr12, __read_pmpaddr12, __write_pmpaddr12);
|
||||
reg!(0x3BD, pmpaddr13, __read_pmpaddr13, __write_pmpaddr13);
|
||||
reg!(0x3BE, pmpaddr14, __read_pmpaddr14, __write_pmpaddr14);
|
||||
reg!(0x3BF, pmpaddr15, __read_pmpaddr15, __write_pmpaddr15);
|
23
xous-riscv/src/register/pmpcfgx.rs
Normal file
23
xous-riscv/src/register/pmpcfgx.rs
Normal file
@ -0,0 +1,23 @@
|
||||
/// Physical memory protection configuration
|
||||
pub mod pmpcfg0 {
|
||||
read_csr_as_usize!(0x3A0, __read_pmpcfg0);
|
||||
write_csr_as_usize!(0x3A0, __write_pmpcfg0);
|
||||
}
|
||||
|
||||
/// Physical memory protection configuration, RV32 only
|
||||
pub mod pmpcfg1 {
|
||||
read_csr_as_usize_rv32!(0x3A1, __read_pmpcfg1);
|
||||
write_csr_as_usize_rv32!(0x3A1, __write_pmpcfg1);
|
||||
}
|
||||
|
||||
/// Physical memory protection configuration
|
||||
pub mod pmpcfg2 {
|
||||
read_csr_as_usize!(0x3A2, __read_pmpcfg2);
|
||||
write_csr_as_usize!(0x3A2, __write_pmpcfg2);
|
||||
}
|
||||
|
||||
/// Physical memory protection configuration, RV32 only
|
||||
pub mod pmpcfg3 {
|
||||
read_csr_as_usize_rv32!(0x3A3, __read_pmpcfg3);
|
||||
write_csr_as_usize_rv32!(0x3A3, __write_pmpcfg3);
|
||||
}
|
110
xous-riscv/src/register/satp.rs
Normal file
110
xous-riscv/src/register/satp.rs
Normal file
@ -0,0 +1,110 @@
|
||||
//! satp register
|
||||
|
||||
#[cfg(riscv)]
|
||||
use bit_field::BitField;
|
||||
|
||||
/// satp register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Satp {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Satp {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Current address-translation scheme
|
||||
#[inline]
|
||||
#[cfg(riscv32)]
|
||||
pub fn mode(&self) -> Mode {
|
||||
match self.bits.get_bit(31) {
|
||||
false => Mode::Bare,
|
||||
true => Mode::Sv32,
|
||||
}
|
||||
}
|
||||
|
||||
/// Current address-translation scheme
|
||||
#[inline]
|
||||
#[cfg(riscv64)]
|
||||
pub fn mode(&self) -> Mode {
|
||||
match self.bits.get_bits(60..64) {
|
||||
0 => Mode::Bare,
|
||||
8 => Mode::Sv39,
|
||||
9 => Mode::Sv48,
|
||||
10 => Mode::Sv57,
|
||||
11 => Mode::Sv64,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Address space identifier
|
||||
#[inline]
|
||||
#[cfg(riscv32)]
|
||||
pub fn asid(&self) -> usize {
|
||||
self.bits.get_bits(22..31)
|
||||
}
|
||||
|
||||
/// Address space identifier
|
||||
#[inline]
|
||||
#[cfg(riscv64)]
|
||||
pub fn asid(&self) -> usize {
|
||||
self.bits.get_bits(44..60)
|
||||
}
|
||||
|
||||
/// Physical page number
|
||||
#[inline]
|
||||
#[cfg(riscv32)]
|
||||
pub fn ppn(&self) -> usize {
|
||||
self.bits.get_bits(0..22)
|
||||
}
|
||||
|
||||
/// Physical page number
|
||||
#[inline]
|
||||
#[cfg(riscv64)]
|
||||
pub fn ppn(&self) -> usize {
|
||||
self.bits.get_bits(0..44)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(riscv32)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Mode {
|
||||
Bare = 0,
|
||||
Sv32 = 1,
|
||||
}
|
||||
|
||||
#[cfg(riscv64)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Mode {
|
||||
Bare = 0,
|
||||
Sv39 = 8,
|
||||
Sv48 = 9,
|
||||
Sv57 = 10,
|
||||
Sv64 = 11,
|
||||
}
|
||||
|
||||
read_csr_as!(Satp, 0x180, __read_satp);
|
||||
write_csr!(0x180, __write_satp);
|
||||
|
||||
#[inline]
|
||||
#[cfg(riscv32)]
|
||||
pub unsafe fn set(mode: Mode, asid: usize, ppn: usize) {
|
||||
let mut bits = 0usize;
|
||||
bits.set_bits(31..32, mode as usize);
|
||||
bits.set_bits(22..31, asid);
|
||||
bits.set_bits(0..22, ppn);
|
||||
_write(bits);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(riscv64)]
|
||||
pub unsafe fn set(mode: Mode, asid: usize, ppn: usize) {
|
||||
let mut bits = 0usize;
|
||||
bits.set_bits(60..64, mode as usize);
|
||||
bits.set_bits(44..60, asid);
|
||||
bits.set_bits(0..44, ppn);
|
||||
_write(bits);
|
||||
}
|
117
xous-riscv/src/register/scause.rs
Normal file
117
xous-riscv/src/register/scause.rs
Normal file
@ -0,0 +1,117 @@
|
||||
//! scause register
|
||||
|
||||
use bit_field::BitField;
|
||||
use core::mem::size_of;
|
||||
|
||||
/// scause register
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Scause {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
/// Trap Cause
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Trap {
|
||||
Interrupt(Interrupt),
|
||||
Exception(Exception),
|
||||
}
|
||||
|
||||
/// Interrupt
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Interrupt {
|
||||
UserSoft,
|
||||
SupervisorSoft,
|
||||
UserTimer,
|
||||
SupervisorTimer,
|
||||
UserExternal,
|
||||
SupervisorExternal,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
/// Exception
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Exception {
|
||||
InstructionMisaligned,
|
||||
InstructionFault,
|
||||
IllegalInstruction,
|
||||
Breakpoint,
|
||||
LoadFault,
|
||||
StoreMisaligned,
|
||||
StoreFault,
|
||||
UserEnvCall,
|
||||
InstructionPageFault,
|
||||
LoadPageFault,
|
||||
StorePageFault,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl Interrupt {
|
||||
pub fn from(nr: usize) -> Self {
|
||||
match nr {
|
||||
0 => Interrupt::UserSoft,
|
||||
1 => Interrupt::SupervisorSoft,
|
||||
4 => Interrupt::UserTimer,
|
||||
5 => Interrupt::SupervisorTimer,
|
||||
8 => Interrupt::UserExternal,
|
||||
9 => Interrupt::SupervisorExternal,
|
||||
_ => Interrupt::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Exception {
|
||||
pub fn from(nr: usize) -> Self {
|
||||
match nr {
|
||||
0 => Exception::InstructionMisaligned,
|
||||
1 => Exception::InstructionFault,
|
||||
2 => Exception::IllegalInstruction,
|
||||
3 => Exception::Breakpoint,
|
||||
5 => Exception::LoadFault,
|
||||
6 => Exception::StoreMisaligned,
|
||||
7 => Exception::StoreFault,
|
||||
8 => Exception::UserEnvCall,
|
||||
12 => Exception::InstructionPageFault,
|
||||
13 => Exception::LoadPageFault,
|
||||
15 => Exception::StorePageFault,
|
||||
_ => Exception::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Scause {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Returns the code field
|
||||
pub fn code(&self) -> usize {
|
||||
let bit = 1 << (size_of::<usize>() * 8 - 1);
|
||||
self.bits & !bit
|
||||
}
|
||||
|
||||
/// Trap Cause
|
||||
#[inline]
|
||||
pub fn cause(&self) -> Trap {
|
||||
if self.is_interrupt() {
|
||||
Trap::Interrupt(Interrupt::from(self.code()))
|
||||
} else {
|
||||
Trap::Exception(Exception::from(self.code()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Is trap cause an interrupt.
|
||||
#[inline]
|
||||
pub fn is_interrupt(&self) -> bool {
|
||||
self.bits.get_bit(size_of::<usize>() * 8 - 1)
|
||||
}
|
||||
|
||||
/// Is trap cause an exception.
|
||||
#[inline]
|
||||
pub fn is_exception(&self) -> bool {
|
||||
!self.is_interrupt()
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Scause, 0x142, __read_scause);
|
4
xous-riscv/src/register/sepc.rs
Normal file
4
xous-riscv/src/register/sepc.rs
Normal file
@ -0,0 +1,4 @@
|
||||
//! sepc register
|
||||
|
||||
read_csr_as_usize!(0x141, __read_sepc);
|
||||
write_csr_as_usize!(0x141, __write_sepc);
|
76
xous-riscv/src/register/sie.rs
Normal file
76
xous-riscv/src/register/sie.rs
Normal file
@ -0,0 +1,76 @@
|
||||
//! sie register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// sie register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Sie {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Sie {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// User Software Interrupt Enable
|
||||
#[inline]
|
||||
pub fn usoft(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// Supervisor Software Interrupt Enable
|
||||
#[inline]
|
||||
pub fn ssoft(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
|
||||
/// User Timer Interrupt Enable
|
||||
#[inline]
|
||||
pub fn utimer(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// Supervisor Timer Interrupt Enable
|
||||
#[inline]
|
||||
pub fn stimer(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
|
||||
/// User External Interrupt Enable
|
||||
#[inline]
|
||||
pub fn uext(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
|
||||
/// Supervisor External Interrupt Enable
|
||||
#[inline]
|
||||
pub fn sext(&self) -> bool {
|
||||
self.bits.get_bit(9)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Sie, 0x104, __read_sie);
|
||||
set!(0x104, __set_sie);
|
||||
clear!(0x104, __clear_sie);
|
||||
|
||||
set_clear_csr!(
|
||||
/// User Software Interrupt Enable
|
||||
, set_usoft, clear_usoft, 1 << 0);
|
||||
set_clear_csr!(
|
||||
/// Supervisor Software Interrupt Enable
|
||||
, set_ssoft, clear_ssoft, 1 << 1);
|
||||
set_clear_csr!(
|
||||
/// User Timer Interrupt Enable
|
||||
, set_utimer, clear_utimer, 1 << 4);
|
||||
set_clear_csr!(
|
||||
/// Supervisor Timer Interrupt Enable
|
||||
, set_stimer, clear_stimer, 1 << 5);
|
||||
set_clear_csr!(
|
||||
/// User External Interrupt Enable
|
||||
, set_uext, clear_uext, 1 << 8);
|
||||
set_clear_csr!(
|
||||
/// Supervisor External Interrupt Enable
|
||||
, set_sext, clear_sext, 1 << 9);
|
55
xous-riscv/src/register/sip.rs
Normal file
55
xous-riscv/src/register/sip.rs
Normal file
@ -0,0 +1,55 @@
|
||||
//! sip register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// sip register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Sip {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Sip {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// User Software Interrupt Pending
|
||||
#[inline]
|
||||
pub fn usoft(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// Supervisor Software Interrupt Pending
|
||||
#[inline]
|
||||
pub fn ssoft(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
|
||||
/// User Timer Interrupt Pending
|
||||
#[inline]
|
||||
pub fn utimer(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// Supervisor Timer Interrupt Pending
|
||||
#[inline]
|
||||
pub fn stimer(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
|
||||
/// User External Interrupt Pending
|
||||
#[inline]
|
||||
pub fn uext(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
|
||||
/// Supervisor External Interrupt Pending
|
||||
#[inline]
|
||||
pub fn sext(&self) -> bool {
|
||||
self.bits.get_bit(9)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Sip, 0x144, __read_sip);
|
4
xous-riscv/src/register/sscratch.rs
Normal file
4
xous-riscv/src/register/sscratch.rs
Normal file
@ -0,0 +1,4 @@
|
||||
//! sscratch register
|
||||
|
||||
read_csr_as_usize!(0x140, __read_sscratch);
|
||||
write_csr_as_usize!(0x140, __write_sscratch);
|
140
xous-riscv/src/register/sstatus.rs
Normal file
140
xous-riscv/src/register/sstatus.rs
Normal file
@ -0,0 +1,140 @@
|
||||
//! sstatus register
|
||||
|
||||
use bit_field::BitField;
|
||||
use core::mem::size_of;
|
||||
pub use super::mstatus::FS;
|
||||
|
||||
/// Supervisor Status Register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Sstatus {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
/// Supervisor Previous Privilege Mode
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum SPP {
|
||||
Supervisor = 1,
|
||||
User = 0,
|
||||
}
|
||||
|
||||
impl Sstatus {
|
||||
/// User Interrupt Enable
|
||||
#[inline]
|
||||
pub fn uie(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// Supervisor Interrupt Enable
|
||||
#[inline]
|
||||
pub fn sie(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
|
||||
/// User Previous Interrupt Enable
|
||||
#[inline]
|
||||
pub fn upie(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// Supervisor Previous Interrupt Enable
|
||||
#[inline]
|
||||
pub fn spie(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
|
||||
/// Supervisor Previous Privilege Mode
|
||||
#[inline]
|
||||
pub fn spp(&self) -> SPP {
|
||||
match self.bits.get_bit(8) {
|
||||
true => SPP::Supervisor,
|
||||
false => SPP::User,
|
||||
}
|
||||
}
|
||||
|
||||
/// The status of the floating-point unit
|
||||
#[inline]
|
||||
pub fn fs(&self) -> FS {
|
||||
match self.bits.get_bits(13..15) {
|
||||
0 => FS::Off,
|
||||
1 => FS::Initial,
|
||||
2 => FS::Clean,
|
||||
3 => FS::Dirty,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The status of additional user-mode extensions
|
||||
/// and associated state
|
||||
#[inline]
|
||||
pub fn xs(&self) -> FS {
|
||||
match self.bits.get_bits(15..17) {
|
||||
0 => FS::Off,
|
||||
1 => FS::Initial,
|
||||
2 => FS::Clean,
|
||||
3 => FS::Dirty,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Permit Supervisor User Memory access
|
||||
#[inline]
|
||||
pub fn sum(&self) -> bool {
|
||||
self.bits.get_bit(18)
|
||||
}
|
||||
|
||||
/// Make eXecutable Readable
|
||||
#[inline]
|
||||
pub fn mxr(&self) -> bool {
|
||||
self.bits.get_bit(19)
|
||||
}
|
||||
|
||||
/// Whether either the FS field or XS field
|
||||
/// signals the presence of some dirty state
|
||||
#[inline]
|
||||
pub fn sd(&self) -> bool {
|
||||
self.bits.get_bit(size_of::<usize>() * 8 - 1)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Sstatus, 0x100, __read_sstatus);
|
||||
write_csr!(0x100, __write_sstatus);
|
||||
set!(0x100, __set_sstatus);
|
||||
clear!(0x100, __clear_sstatus);
|
||||
|
||||
set_clear_csr!(
|
||||
/// User Interrupt Enable
|
||||
, set_uie, clear_uie, 1 << 0);
|
||||
set_clear_csr!(
|
||||
/// Supervisor Interrupt Enable
|
||||
, set_sie, clear_sie, 1 << 1);
|
||||
set_csr!(
|
||||
/// User Previous Interrupt Enable
|
||||
, set_upie, 1 << 4);
|
||||
set_csr!(
|
||||
/// Supervisor Previous Interrupt Enable
|
||||
, set_spie, 1 << 5);
|
||||
set_clear_csr!(
|
||||
/// Make eXecutable Readable
|
||||
, set_mxr, clear_mxr, 1 << 19);
|
||||
set_clear_csr!(
|
||||
/// Permit Supervisor User Memory access
|
||||
, set_sum, clear_sum, 1 << 18);
|
||||
|
||||
/// Supervisor Previous Privilege Mode
|
||||
#[inline]
|
||||
#[cfg(riscv)]
|
||||
pub unsafe fn set_spp(spp: SPP) {
|
||||
match spp {
|
||||
SPP::Supervisor => _set(1 << 8),
|
||||
SPP::User => _clear(1 << 8),
|
||||
}
|
||||
}
|
||||
|
||||
/// The status of the floating-point unit
|
||||
#[inline]
|
||||
#[cfg(riscv)]
|
||||
pub unsafe fn set_fs(fs: FS) {
|
||||
let mut value = _read();
|
||||
value.set_bits(13..15, fs as usize);
|
||||
_write(value);
|
||||
}
|
3
xous-riscv/src/register/stval.rs
Normal file
3
xous-riscv/src/register/stval.rs
Normal file
@ -0,0 +1,3 @@
|
||||
//! stval register
|
||||
|
||||
read_csr_as_usize!(0x143, __read_stval);
|
40
xous-riscv/src/register/stvec.rs
Normal file
40
xous-riscv/src/register/stvec.rs
Normal file
@ -0,0 +1,40 @@
|
||||
//! stvec register
|
||||
|
||||
pub use crate::register::mtvec::TrapMode;
|
||||
|
||||
/// stvec register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Stvec {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Stvec {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Returns the trap-vector base-address
|
||||
pub fn address(&self) -> usize {
|
||||
self.bits - (self.bits & 0b11)
|
||||
}
|
||||
|
||||
/// Returns the trap-vector mode
|
||||
pub fn trap_mode(&self) -> TrapMode {
|
||||
let mode = self.bits & 0b11;
|
||||
match mode {
|
||||
0 => TrapMode::Direct,
|
||||
1 => TrapMode::Vectored,
|
||||
_ => unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Stvec, 0x105, __read_stvec);
|
||||
write_csr!(0x105, __write_stvec);
|
||||
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
pub unsafe fn write(addr: usize, mode: TrapMode) {
|
||||
_write(addr + mode as usize);
|
||||
}
|
4
xous-riscv/src/register/time.rs
Normal file
4
xous-riscv/src/register/time.rs
Normal file
@ -0,0 +1,4 @@
|
||||
//! time register
|
||||
|
||||
read_csr_as_usize!(0xC01, __read_time);
|
||||
read_composite_csr!(super::timeh::read(), read());
|
3
xous-riscv/src/register/timeh.rs
Normal file
3
xous-riscv/src/register/timeh.rs
Normal file
@ -0,0 +1,3 @@
|
||||
//! timeh register
|
||||
|
||||
read_csr_as_usize_rv32!(0xC81, __read_timeh);
|
17
xous-riscv/src/register/ucause.rs
Normal file
17
xous-riscv/src/register/ucause.rs
Normal file
@ -0,0 +1,17 @@
|
||||
//! ucause register
|
||||
|
||||
/// ucause register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Ucause {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Ucause {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Ucause, 0x042, __read_ucause);
|
4
xous-riscv/src/register/uepc.rs
Normal file
4
xous-riscv/src/register/uepc.rs
Normal file
@ -0,0 +1,4 @@
|
||||
//! uepc register
|
||||
|
||||
read_csr_as_usize!(0x041, __read_uepc);
|
||||
write_csr_as_usize!(0x041, __write_uepc);
|
49
xous-riscv/src/register/uie.rs
Normal file
49
xous-riscv/src/register/uie.rs
Normal file
@ -0,0 +1,49 @@
|
||||
//! uie register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// uie register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Uie {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Uie {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// User Software Interrupt Enable
|
||||
#[inline]
|
||||
pub fn usoft(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// User Timer Interrupt Enable
|
||||
#[inline]
|
||||
pub fn utimer(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// User External Interrupt Enable
|
||||
#[inline]
|
||||
pub fn uext(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Uie, 0x004, __read_uie);
|
||||
set!(0x004, __set_uie);
|
||||
clear!(0x004, __clear_uie);
|
||||
|
||||
set_clear_csr!(
|
||||
/// User Software Interrupt Enable
|
||||
, set_usoft, clear_usoft, 1 << 0);
|
||||
set_clear_csr!(
|
||||
/// User Timer Interrupt Enable
|
||||
, set_utimer, clear_utimer, 1 << 4);
|
||||
set_clear_csr!(
|
||||
/// User External Interrupt Enable
|
||||
, set_uext, clear_uext, 1 << 8);
|
37
xous-riscv/src/register/uip.rs
Normal file
37
xous-riscv/src/register/uip.rs
Normal file
@ -0,0 +1,37 @@
|
||||
//! uip register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// uip register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Uip {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Uip {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// User Software Interrupt Pending
|
||||
#[inline]
|
||||
pub fn usoft(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// User Timer Interrupt Pending
|
||||
#[inline]
|
||||
pub fn utimer(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// User External Interrupt Pending
|
||||
#[inline]
|
||||
pub fn uext(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Uip, 0x044, __read_uip);
|
4
xous-riscv/src/register/uscratch.rs
Normal file
4
xous-riscv/src/register/uscratch.rs
Normal file
@ -0,0 +1,4 @@
|
||||
//! uscratch register
|
||||
|
||||
read_csr_as_usize!(0x040, __read_uscratch);
|
||||
write_csr_as_usize!(0x040, __write_uscratch);
|
37
xous-riscv/src/register/ustatus.rs
Normal file
37
xous-riscv/src/register/ustatus.rs
Normal file
@ -0,0 +1,37 @@
|
||||
//! ustatus register
|
||||
// TODO: Virtualization, Memory Privilege and Extension Context Fields
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// ustatus register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Ustatus {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Ustatus {
|
||||
/// User Interrupt Enable
|
||||
#[inline]
|
||||
pub fn uie(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// User Previous Interrupt Enable
|
||||
#[inline]
|
||||
pub fn upie(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Ustatus, 0x000, __read_ustatus);
|
||||
write_csr!(0x000, __write_ustatus);
|
||||
set!(0x000, __set_ustatus);
|
||||
clear!(0x000, __clear_ustatus);
|
||||
|
||||
set_clear_csr!(
|
||||
/// User Interrupt Enable
|
||||
, set_uie, clear_uie, 1 << 0);
|
||||
|
||||
set_csr!(
|
||||
/// User Previous Interrupt Enable
|
||||
, set_upie, 1 << 4);
|
3
xous-riscv/src/register/utval.rs
Normal file
3
xous-riscv/src/register/utval.rs
Normal file
@ -0,0 +1,3 @@
|
||||
//! utval register
|
||||
|
||||
read_csr_as_usize!(0x043, __read_utval);
|
40
xous-riscv/src/register/utvec.rs
Normal file
40
xous-riscv/src/register/utvec.rs
Normal file
@ -0,0 +1,40 @@
|
||||
//! stvec register
|
||||
|
||||
pub use crate::register::mtvec::TrapMode;
|
||||
|
||||
/// stvec register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Utvec {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Utvec {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Returns the trap-vector base-address
|
||||
pub fn address(&self) -> usize {
|
||||
self.bits - (self.bits & 0b11)
|
||||
}
|
||||
|
||||
/// Returns the trap-vector mode
|
||||
pub fn trap_mode(&self) -> TrapMode {
|
||||
let mode = self.bits & 0b11;
|
||||
match mode {
|
||||
0 => TrapMode::Direct,
|
||||
1 => TrapMode::Vectored,
|
||||
_ => unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Utvec, 0x005, __read_utvec);
|
||||
write_csr!(0x005, __write_utvec);
|
||||
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
pub unsafe fn write(addr: usize, mode: TrapMode) {
|
||||
_write(addr + mode as usize);
|
||||
}
|
Loading…
Reference in New Issue
Block a user