From 79114aa65aa03a21f25e3972a4b28b81501a110e Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Wed, 18 Dec 2019 09:59:00 +0800 Subject: [PATCH] initial commit Signed-off-by: Sean Cross --- .cargo/config | 9 + .gitattributes | 18 + .gitignore | 2 + Cargo.lock | 142 +++++++ Cargo.toml | 16 + README.md | 4 + memory.x | 16 + src/main.rs | 18 + xous-riscv-rt/Cargo.toml | 18 + xous-riscv-rt/README.md | 0 xous-riscv-rt/asm.S | 151 ++++++++ xous-riscv-rt/assemble.ps1 | 17 + xous-riscv-rt/assemble.sh | 21 ++ xous-riscv-rt/bin/riscv32i-unknown-none-elf.a | Bin 0 -> 6654 bytes .../bin/riscv32imac-unknown-none-elf.a | Bin 0 -> 7114 bytes .../bin/riscv32imc-unknown-none-elf.a | Bin 0 -> 7114 bytes .../bin/riscv64gc-unknown-none-elf.a | Bin 0 -> 11338 bytes .../bin/riscv64imac-unknown-none-elf.a | Bin 0 -> 11338 bytes xous-riscv-rt/build.rs | 32 ++ xous-riscv-rt/link.x | 159 ++++++++ xous-riscv-rt/macros/Cargo.toml | 28 ++ xous-riscv-rt/macros/src/lib.rs | 210 +++++++++++ xous-riscv-rt/src/lib.rs | 351 ++++++++++++++++++ xous-riscv/Cargo.toml | 16 + xous-riscv/asm.S | 317 ++++++++++++++++ xous-riscv/assemble.ps1 | 19 + xous-riscv/assemble.sh | 21 ++ xous-riscv/bin/riscv32i-unknown-none-elf.a | Bin 0 -> 70954 bytes xous-riscv/bin/riscv32imac-unknown-none-elf.a | Bin 0 -> 69970 bytes xous-riscv/bin/riscv32imc-unknown-none-elf.a | Bin 0 -> 69970 bytes xous-riscv/bin/riscv64gc-unknown-none-elf.a | Bin 0 -> 76768 bytes xous-riscv/bin/riscv64imac-unknown-none-elf.a | Bin 0 -> 76768 bytes xous-riscv/build.rs | 26 ++ xous-riscv/src/asm.rs | 77 ++++ xous-riscv/src/interrupt.rs | 54 +++ xous-riscv/src/lib.rs | 27 ++ xous-riscv/src/register/fcsr.rs | 132 +++++++ xous-riscv/src/register/hpmcounterx.rs | 82 ++++ xous-riscv/src/register/macros.rs | 270 ++++++++++++++ xous-riscv/src/register/marchid.rs | 27 ++ xous-riscv/src/register/mcause.rs | 139 +++++++ xous-riscv/src/register/mcycle.rs | 4 + xous-riscv/src/register/mcycleh.rs | 3 + xous-riscv/src/register/mepc.rs | 4 + xous-riscv/src/register/mhartid.rs | 3 + xous-riscv/src/register/mhpmcounterx.rs | 84 +++++ xous-riscv/src/register/mhpmeventx.rs | 41 ++ xous-riscv/src/register/mie.rs | 103 +++++ xous-riscv/src/register/mimpid.rs | 27 ++ xous-riscv/src/register/minstret.rs | 4 + xous-riscv/src/register/minstreth.rs | 3 + xous-riscv/src/register/mip.rs | 73 ++++ xous-riscv/src/register/misa.rs | 60 +++ xous-riscv/src/register/mod.rs | 109 ++++++ xous-riscv/src/register/mscratch.rs | 4 + xous-riscv/src/register/mstatus.rs | 200 ++++++++++ xous-riscv/src/register/mtval.rs | 3 + xous-riscv/src/register/mtvec.rs | 47 +++ xous-riscv/src/register/mvendorid.rs | 32 ++ xous-riscv/src/register/pmpaddrx.rs | 28 ++ xous-riscv/src/register/pmpcfgx.rs | 23 ++ xous-riscv/src/register/satp.rs | 110 ++++++ xous-riscv/src/register/scause.rs | 117 ++++++ xous-riscv/src/register/sepc.rs | 4 + xous-riscv/src/register/sie.rs | 76 ++++ xous-riscv/src/register/sip.rs | 55 +++ xous-riscv/src/register/sscratch.rs | 4 + xous-riscv/src/register/sstatus.rs | 140 +++++++ xous-riscv/src/register/stval.rs | 3 + xous-riscv/src/register/stvec.rs | 40 ++ xous-riscv/src/register/time.rs | 4 + xous-riscv/src/register/timeh.rs | 3 + xous-riscv/src/register/ucause.rs | 17 + xous-riscv/src/register/uepc.rs | 4 + xous-riscv/src/register/uie.rs | 49 +++ xous-riscv/src/register/uip.rs | 37 ++ xous-riscv/src/register/uscratch.rs | 4 + xous-riscv/src/register/ustatus.rs | 37 ++ xous-riscv/src/register/utval.rs | 3 + xous-riscv/src/register/utvec.rs | 40 ++ 80 files changed, 4021 insertions(+) create mode 100644 .cargo/config create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 memory.x create mode 100644 src/main.rs create mode 100644 xous-riscv-rt/Cargo.toml create mode 100644 xous-riscv-rt/README.md create mode 100644 xous-riscv-rt/asm.S create mode 100644 xous-riscv-rt/assemble.ps1 create mode 100644 xous-riscv-rt/assemble.sh create mode 100644 xous-riscv-rt/bin/riscv32i-unknown-none-elf.a create mode 100644 xous-riscv-rt/bin/riscv32imac-unknown-none-elf.a create mode 100644 xous-riscv-rt/bin/riscv32imc-unknown-none-elf.a create mode 100644 xous-riscv-rt/bin/riscv64gc-unknown-none-elf.a create mode 100644 xous-riscv-rt/bin/riscv64imac-unknown-none-elf.a create mode 100644 xous-riscv-rt/build.rs create mode 100644 xous-riscv-rt/link.x create mode 100644 xous-riscv-rt/macros/Cargo.toml create mode 100644 xous-riscv-rt/macros/src/lib.rs create mode 100644 xous-riscv-rt/src/lib.rs create mode 100644 xous-riscv/Cargo.toml create mode 100644 xous-riscv/asm.S create mode 100644 xous-riscv/assemble.ps1 create mode 100644 xous-riscv/assemble.sh create mode 100644 xous-riscv/bin/riscv32i-unknown-none-elf.a create mode 100644 xous-riscv/bin/riscv32imac-unknown-none-elf.a create mode 100644 xous-riscv/bin/riscv32imc-unknown-none-elf.a create mode 100644 xous-riscv/bin/riscv64gc-unknown-none-elf.a create mode 100644 xous-riscv/bin/riscv64imac-unknown-none-elf.a create mode 100644 xous-riscv/build.rs create mode 100644 xous-riscv/src/asm.rs create mode 100644 xous-riscv/src/interrupt.rs create mode 100644 xous-riscv/src/lib.rs create mode 100644 xous-riscv/src/register/fcsr.rs create mode 100644 xous-riscv/src/register/hpmcounterx.rs create mode 100644 xous-riscv/src/register/macros.rs create mode 100644 xous-riscv/src/register/marchid.rs create mode 100644 xous-riscv/src/register/mcause.rs create mode 100644 xous-riscv/src/register/mcycle.rs create mode 100644 xous-riscv/src/register/mcycleh.rs create mode 100644 xous-riscv/src/register/mepc.rs create mode 100644 xous-riscv/src/register/mhartid.rs create mode 100644 xous-riscv/src/register/mhpmcounterx.rs create mode 100644 xous-riscv/src/register/mhpmeventx.rs create mode 100644 xous-riscv/src/register/mie.rs create mode 100644 xous-riscv/src/register/mimpid.rs create mode 100644 xous-riscv/src/register/minstret.rs create mode 100644 xous-riscv/src/register/minstreth.rs create mode 100644 xous-riscv/src/register/mip.rs create mode 100644 xous-riscv/src/register/misa.rs create mode 100644 xous-riscv/src/register/mod.rs create mode 100644 xous-riscv/src/register/mscratch.rs create mode 100644 xous-riscv/src/register/mstatus.rs create mode 100644 xous-riscv/src/register/mtval.rs create mode 100644 xous-riscv/src/register/mtvec.rs create mode 100644 xous-riscv/src/register/mvendorid.rs create mode 100644 xous-riscv/src/register/pmpaddrx.rs create mode 100644 xous-riscv/src/register/pmpcfgx.rs create mode 100644 xous-riscv/src/register/satp.rs create mode 100644 xous-riscv/src/register/scause.rs create mode 100644 xous-riscv/src/register/sepc.rs create mode 100644 xous-riscv/src/register/sie.rs create mode 100644 xous-riscv/src/register/sip.rs create mode 100644 xous-riscv/src/register/sscratch.rs create mode 100644 xous-riscv/src/register/sstatus.rs create mode 100644 xous-riscv/src/register/stval.rs create mode 100644 xous-riscv/src/register/stvec.rs create mode 100644 xous-riscv/src/register/time.rs create mode 100644 xous-riscv/src/register/timeh.rs create mode 100644 xous-riscv/src/register/ucause.rs create mode 100644 xous-riscv/src/register/uepc.rs create mode 100644 xous-riscv/src/register/uie.rs create mode 100644 xous-riscv/src/register/uip.rs create mode 100644 xous-riscv/src/register/uscratch.rs create mode 100644 xous-riscv/src/register/ustatus.rs create mode 100644 xous-riscv/src/register/utval.rs create mode 100644 xous-riscv/src/register/utvec.rs diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 0000000..95f24e4 --- /dev/null +++ b/.cargo/config @@ -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" \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..d1725ed --- /dev/null +++ b/.gitattributes @@ -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 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53eaa21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..f642efa --- /dev/null +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..06b7379 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "xous-kernel" +version = "0.1.0" +authors = ["Sean Cross "] +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 diff --git a/README.md b/README.md new file mode 100644 index 0000000..18bcf1c --- /dev/null +++ b/README.md @@ -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. diff --git a/memory.x b/memory.x new file mode 100644 index 0000000..63598ca --- /dev/null +++ b/memory.x @@ -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; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..43098f8 --- /dev/null +++ b/src/main.rs @@ -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() }; + } +} diff --git a/xous-riscv-rt/Cargo.toml b/xous-riscv-rt/Cargo.toml new file mode 100644 index 0000000..f7f808e --- /dev/null +++ b/xous-riscv-rt/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "xous-riscv-rt" +version = "0.6.1" +repository = "https://github.com/xous/xous-riscv-rt" +authors = ["Sean Cross ", "The RISC-V Team "] +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" diff --git a/xous-riscv-rt/README.md b/xous-riscv-rt/README.md new file mode 100644 index 0000000..e69de29 diff --git a/xous-riscv-rt/asm.S b/xous-riscv-rt/asm.S new file mode 100644 index 0000000..d616c36 --- /dev/null +++ b/xous-riscv-rt/asm.S @@ -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 diff --git a/xous-riscv-rt/assemble.ps1 b/xous-riscv-rt/assemble.ps1 new file mode 100644 index 0000000..f411870 --- /dev/null +++ b/xous-riscv-rt/assemble.ps1 @@ -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 diff --git a/xous-riscv-rt/assemble.sh b/xous-riscv-rt/assemble.sh new file mode 100644 index 0000000..8994b7e --- /dev/null +++ b/xous-riscv-rt/assemble.sh @@ -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 diff --git a/xous-riscv-rt/bin/riscv32i-unknown-none-elf.a b/xous-riscv-rt/bin/riscv32i-unknown-none-elf.a new file mode 100644 index 0000000000000000000000000000000000000000..c59bd6e4bb4035074de65662fec700ec5fda3e3f GIT binary patch literal 6654 zcmdT|U2Ggz8NIXPIEnL9yPMW-U0^a}U%SCsZ*14K)1Sa5 z`edAw4WBzOa?tZU3?ku~cTCERxqOG{eR0!iT1>MkA0Emh`z}Gt!h8vt&7ehQam|;I z**dhy>^ii_Y&}|Jc0F2Tb^}^ub|YG37WaDzncajInca*QncadGnca#OnY|4y@_CNC zhk<3*W~}{tvB9X4m`6Q4jVsOGRx75 z@pGQHoE!H1?j>)zd&TqHz07j^aK^VwnPt0@@jEcn#L<8sS~=noMK;iF$u)>(=(I`~(@( zhSZbRI3<;24ei@KcA{J?mB-4nlco8wee+Yru~F<2V^0=KbH$ml$x@+GERWS}9OmIi zPXxoqf}UJ&k1;n9Y1LcNHkG{395vo~&uiV1S7IprwP_9P*X%_6+{g?hRzKb#6UP2J=Zv*Ewj~Ye$2L^MvF+4w-jjs*lY2KhUQ5!g zJiUMM2TnhqrG)f%CRESwa(FsV;+MUcCgB5)e~-h59KPS-ha5iQ@WT#2?(k8Ek2(CL z!>1g6#^Ey#UvPNE;pZHF-r*M<{*1$)bNFS4zu@pI4!`Q~YgK#|0{EuhS)an|R!zb; zIDE6i)AcC+ZBBoS!_)OB{=n&Pb9kr2yBwabN2%B6^ba^ZU60})a{Bi>{E)*(9Gsss>7R1=8Hdj}JYA1cuj2Hdb9lNQ#ec!+f5zd@I{Z0@Ut8t!`M>V) zi>qA5Tcx^Rxc;(zea-4@rw&q5914l_G^@hDW&GQ#dgif`2{izV;Ezro?lasL?^cDxk0^6bYiQX-&1cFo!F}957e#b#8y4;Q11|( z*sABR)H_8dw(7Y_{a(?Dt$NmZ(07PVY}K=g`ujyEw(4o3-X%J*RS)08!(*ZoTlKV3 z*Dq*dtDYS7y!eT2x8OeNyHae`vzvO4=)_h%L)3dkC${Q2NWD*VVym7J>i3CGY}Ip= zdcWwzRz0KC?-!les^OZ_3yiLH9RM14qfVym9Z)Q3eUw(9vB^$& ze@JvE-{7VnJ<=639z6wIyD zD+rG3d|YsR?k5EE+-NMt9jeE59v7W;q9;<^q51|$-bY1`ukA6xas5%j@wI(SaDZlT zo!~Y!(ascisBUuQPtR5g6KE?XY0o66Qao2Nxv4^>U~&`XvdNW-Gld-0-1OWux`gu| zRe@8*iN(|7Gt+a$8ew|w)I93MorQ^sQt@m}ccE06J6%M1abWbC?xZ&!taxVpRH-n_ z`uyKESEy7<(-VvMQ$}v>KRUL;g-5>nn^U*4)pP3CZGQ>vbx@H!RbpPsmHCZy541+%=1}~>olo10-T%! zXt=NX86t_Kk6T7{y(=g-uwLqM9+G-ow#hlHP{ss>1R6;nmu_{vUuBKq_QUII&^})8 zG%`5{(0m#7ZYR)4`p$zVm|fT4>r@XLUL)gE$m($ee0YvS>O6oYV!L1Zyz9i>$79 z74_Pnu^#7#eXREi5|_S!CXOj|=+DELb1X*nnB*7W%j5ap2|R;jJznQVBrmC VB|=iK2|~5+r?|dX6BF9R_fMQW&AR{q literal 0 HcmV?d00001 diff --git a/xous-riscv-rt/bin/riscv32imac-unknown-none-elf.a b/xous-riscv-rt/bin/riscv32imac-unknown-none-elf.a new file mode 100644 index 0000000000000000000000000000000000000000..8e8db7d601cfdc28685afc1cdc2192f3b5d21681 GIT binary patch literal 7114 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 L$@~B1Kk5GuTT=yA literal 0 HcmV?d00001 diff --git a/xous-riscv-rt/bin/riscv64imac-unknown-none-elf.a b/xous-riscv-rt/bin/riscv64imac-unknown-none-elf.a new file mode 100644 index 0000000000000000000000000000000000000000..23e0a1383321f82bca78a43304724277c4c4c488 GIT binary patch literal 11338 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 L$@~B1Kk5GuTT=yA literal 0 HcmV?d00001 diff --git a/xous-riscv-rt/build.rs b/xous-riscv-rt/build.rs new file mode 100644 index 0000000..4589309 --- /dev/null +++ b/xous-riscv-rt/build.rs @@ -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"); +} diff --git a/xous-riscv-rt/link.x b/xous-riscv-rt/link.x new file mode 100644 index 0000000..048bef0 --- /dev/null +++ b/xous-riscv-rt/link.x @@ -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 | */ diff --git a/xous-riscv-rt/macros/Cargo.toml b/xous-riscv-rt/macros/Cargo.toml new file mode 100644 index 0000000..31de3cb --- /dev/null +++ b/xous-riscv-rt/macros/Cargo.toml @@ -0,0 +1,28 @@ +[package] +authors = [ + "The RISC-V Team ", + "Jorge Aparicio ", +] +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 diff --git a/xous-riscv-rt/macros/src/lib.rs b/xous-riscv-rt/macros/src/lib.rs new file mode 100644 index 0000000..8efe092 --- /dev/null +++ b/xous-riscv-rt/macros/src/lib.rs @@ -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::() % 25) as char + } else { + ('0' as u8 + rng.gen::() % 10) as char + } + }) + .collect::(), + Span::call_site(), + ) +} diff --git a/xous-riscv-rt/src/lib.rs b/xous-riscv-rt/src/lib.rs new file mode 100644 index 0000000..5624697 --- /dev/null +++ b/xous-riscv-rt/src/lib.rs @@ -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() } + }, + } +} diff --git a/xous-riscv/Cargo.toml b/xous-riscv/Cargo.toml new file mode 100644 index 0000000..34eee8c --- /dev/null +++ b/xous-riscv/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "xous-riscv" +version = "0.5.4" +repository = "https://github.com/rust-embedded/riscv" +authors = ["The RISC-V Team "] +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 = [] \ No newline at end of file diff --git a/xous-riscv/asm.S b/xous-riscv/asm.S new file mode 100644 index 0000000..e861189 --- /dev/null +++ b/xous-riscv/asm.S @@ -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 diff --git a/xous-riscv/assemble.ps1 b/xous-riscv/assemble.ps1 new file mode 100644 index 0000000..079eae1 --- /dev/null +++ b/xous-riscv/assemble.ps1 @@ -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 diff --git a/xous-riscv/assemble.sh b/xous-riscv/assemble.sh new file mode 100644 index 0000000..8994b7e --- /dev/null +++ b/xous-riscv/assemble.sh @@ -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 diff --git a/xous-riscv/bin/riscv32i-unknown-none-elf.a b/xous-riscv/bin/riscv32i-unknown-none-elf.a new file mode 100644 index 0000000000000000000000000000000000000000..72d93bc2de9797b69936552fe9e17f17f8589670 GIT binary patch literal 70954 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 F{|h?c6&U~k literal 0 HcmV?d00001 diff --git a/xous-riscv/bin/riscv32imc-unknown-none-elf.a b/xous-riscv/bin/riscv32imc-unknown-none-elf.a new file mode 100644 index 0000000000000000000000000000000000000000..799dc790cbf2c88c53613b1e0eea1fdb517f54ae GIT binary patch literal 69970 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 F{|h?c6&U~k literal 0 HcmV?d00001 diff --git a/xous-riscv/bin/riscv64gc-unknown-none-elf.a b/xous-riscv/bin/riscv64gc-unknown-none-elf.a new file mode 100644 index 0000000000000000000000000000000000000000..223145178ee1e17a73e093141c4109061b808241 GIT binary patch literal 76768 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 ( + $(#[$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!(), + } +} diff --git a/xous-riscv/src/interrupt.rs b/xous-riscv/src/interrupt.rs new file mode 100644 index 0000000..dcc04de --- /dev/null +++ b/xous-riscv/src/interrupt.rs @@ -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: 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 +} diff --git a/xous-riscv/src/lib.rs b/xous-riscv/src/lib.rs new file mode 100644 index 0000000..00bd91c --- /dev/null +++ b/xous-riscv/src/lib.rs @@ -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; diff --git a/xous-riscv/src/register/fcsr.rs b/xous-riscv/src/register/fcsr.rs new file mode 100644 index 0000000..e8e9559 --- /dev/null +++ b/xous-riscv/src/register/fcsr.rs @@ -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); +} diff --git a/xous-riscv/src/register/hpmcounterx.rs b/xous-riscv/src/register/hpmcounterx.rs new file mode 100644 index 0000000..d97ba2a --- /dev/null +++ b/xous-riscv/src/register/hpmcounterx.rs @@ -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); diff --git a/xous-riscv/src/register/macros.rs b/xous-riscv/src/register/macros.rs new file mode 100644 index 0000000..b58c310 --- /dev/null +++ b/xous-riscv/src/register/macros.rs @@ -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, + } + } + } +} diff --git a/xous-riscv/src/register/marchid.rs b/xous-riscv/src/register/marchid.rs new file mode 100644 index 0000000..00761ea --- /dev/null +++ b/xous-riscv/src/register/marchid.rs @@ -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 { + 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 }) +} diff --git a/xous-riscv/src/register/mcause.rs b/xous-riscv/src/register/mcause.rs new file mode 100644 index 0000000..d19b2e6 --- /dev/null +++ b/xous-riscv/src/register/mcause.rs @@ -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); diff --git a/xous-riscv/src/register/mcycle.rs b/xous-riscv/src/register/mcycle.rs new file mode 100644 index 0000000..a6ad46d --- /dev/null +++ b/xous-riscv/src/register/mcycle.rs @@ -0,0 +1,4 @@ +//! mcycle register + +read_csr_as_usize!(0xB00, __read_mcycle); +read_composite_csr!(super::mcycleh::read(), read()); diff --git a/xous-riscv/src/register/mcycleh.rs b/xous-riscv/src/register/mcycleh.rs new file mode 100644 index 0000000..0acd217 --- /dev/null +++ b/xous-riscv/src/register/mcycleh.rs @@ -0,0 +1,3 @@ +//! mcycleh register + +read_csr_as_usize_rv32!(0xB80, __read_mcycleh); diff --git a/xous-riscv/src/register/mepc.rs b/xous-riscv/src/register/mepc.rs new file mode 100644 index 0000000..5527419 --- /dev/null +++ b/xous-riscv/src/register/mepc.rs @@ -0,0 +1,4 @@ +//! mepc register + +read_csr_as_usize!(0x341, __read_mepc); +write_csr_as_usize!(0x341, __write_mepc); diff --git a/xous-riscv/src/register/mhartid.rs b/xous-riscv/src/register/mhartid.rs new file mode 100644 index 0000000..d129254 --- /dev/null +++ b/xous-riscv/src/register/mhartid.rs @@ -0,0 +1,3 @@ +//! mhartid register + +read_csr_as_usize!(0xf14, __read_mhartid); diff --git a/xous-riscv/src/register/mhpmcounterx.rs b/xous-riscv/src/register/mhpmcounterx.rs new file mode 100644 index 0000000..ce532dd --- /dev/null +++ b/xous-riscv/src/register/mhpmcounterx.rs @@ -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); diff --git a/xous-riscv/src/register/mhpmeventx.rs b/xous-riscv/src/register/mhpmeventx.rs new file mode 100644 index 0000000..2e8b976 --- /dev/null +++ b/xous-riscv/src/register/mhpmeventx.rs @@ -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); diff --git a/xous-riscv/src/register/mie.rs b/xous-riscv/src/register/mie.rs new file mode 100644 index 0000000..f03d8b0 --- /dev/null +++ b/xous-riscv/src/register/mie.rs @@ -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); diff --git a/xous-riscv/src/register/mimpid.rs b/xous-riscv/src/register/mimpid.rs new file mode 100644 index 0000000..1ba26cb --- /dev/null +++ b/xous-riscv/src/register/mimpid.rs @@ -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 { + 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 }) +} diff --git a/xous-riscv/src/register/minstret.rs b/xous-riscv/src/register/minstret.rs new file mode 100644 index 0000000..8ffb6f3 --- /dev/null +++ b/xous-riscv/src/register/minstret.rs @@ -0,0 +1,4 @@ +//! minstret register + +read_csr_as_usize!(0xB02, __read_minstret); +read_composite_csr!(super::minstreth::read(), read()); diff --git a/xous-riscv/src/register/minstreth.rs b/xous-riscv/src/register/minstreth.rs new file mode 100644 index 0000000..f0315b5 --- /dev/null +++ b/xous-riscv/src/register/minstreth.rs @@ -0,0 +1,3 @@ +//! minstreth register + +read_csr_as_usize_rv32!(0xB82, __read_minstreth); diff --git a/xous-riscv/src/register/mip.rs b/xous-riscv/src/register/mip.rs new file mode 100644 index 0000000..a595b38 --- /dev/null +++ b/xous-riscv/src/register/mip.rs @@ -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); diff --git a/xous-riscv/src/register/misa.rs b/xous-riscv/src/register/misa.rs new file mode 100644 index 0000000..bd9da1d --- /dev/null +++ b/xous-riscv/src/register/misa.rs @@ -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 { + 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 }) +} diff --git a/xous-riscv/src/register/mod.rs b/xous-riscv/src/register/mod.rs new file mode 100644 index 0000000..1660e41 --- /dev/null +++ b/xous-riscv/src/register/mod.rs @@ -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 diff --git a/xous-riscv/src/register/mscratch.rs b/xous-riscv/src/register/mscratch.rs new file mode 100644 index 0000000..533483b --- /dev/null +++ b/xous-riscv/src/register/mscratch.rs @@ -0,0 +1,4 @@ +//! mscratch register + +read_csr_as_usize!(0x340, __read_mscratch); +write_csr_as_usize!(0x340, __write_mscratch); diff --git a/xous-riscv/src/register/mstatus.rs b/xous-riscv/src/register/mstatus.rs new file mode 100644 index 0000000..21bd75d --- /dev/null +++ b/xous-riscv/src/register/mstatus.rs @@ -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::() * 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); +} diff --git a/xous-riscv/src/register/mtval.rs b/xous-riscv/src/register/mtval.rs new file mode 100644 index 0000000..6c7fb28 --- /dev/null +++ b/xous-riscv/src/register/mtval.rs @@ -0,0 +1,3 @@ +//! mtval register + +read_csr_as_usize!(0x343, __read_mtval); diff --git a/xous-riscv/src/register/mtvec.rs b/xous-riscv/src/register/mtvec.rs new file mode 100644 index 0000000..b62ee4a --- /dev/null +++ b/xous-riscv/src/register/mtvec.rs @@ -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); +} diff --git a/xous-riscv/src/register/mvendorid.rs b/xous-riscv/src/register/mvendorid.rs new file mode 100644 index 0000000..f6eeba4 --- /dev/null +++ b/xous-riscv/src/register/mvendorid.rs @@ -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 { + 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 }) +} diff --git a/xous-riscv/src/register/pmpaddrx.rs b/xous-riscv/src/register/pmpaddrx.rs new file mode 100644 index 0000000..75f7984 --- /dev/null +++ b/xous-riscv/src/register/pmpaddrx.rs @@ -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); diff --git a/xous-riscv/src/register/pmpcfgx.rs b/xous-riscv/src/register/pmpcfgx.rs new file mode 100644 index 0000000..1dbcf8d --- /dev/null +++ b/xous-riscv/src/register/pmpcfgx.rs @@ -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); +} diff --git a/xous-riscv/src/register/satp.rs b/xous-riscv/src/register/satp.rs new file mode 100644 index 0000000..b22189c --- /dev/null +++ b/xous-riscv/src/register/satp.rs @@ -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); +} diff --git a/xous-riscv/src/register/scause.rs b/xous-riscv/src/register/scause.rs new file mode 100644 index 0000000..663309d --- /dev/null +++ b/xous-riscv/src/register/scause.rs @@ -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::() * 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::() * 8 - 1) + } + + /// Is trap cause an exception. + #[inline] + pub fn is_exception(&self) -> bool { + !self.is_interrupt() + } +} + +read_csr_as!(Scause, 0x142, __read_scause); diff --git a/xous-riscv/src/register/sepc.rs b/xous-riscv/src/register/sepc.rs new file mode 100644 index 0000000..934bf59 --- /dev/null +++ b/xous-riscv/src/register/sepc.rs @@ -0,0 +1,4 @@ +//! sepc register + +read_csr_as_usize!(0x141, __read_sepc); +write_csr_as_usize!(0x141, __write_sepc); diff --git a/xous-riscv/src/register/sie.rs b/xous-riscv/src/register/sie.rs new file mode 100644 index 0000000..47dbc89 --- /dev/null +++ b/xous-riscv/src/register/sie.rs @@ -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); diff --git a/xous-riscv/src/register/sip.rs b/xous-riscv/src/register/sip.rs new file mode 100644 index 0000000..a267584 --- /dev/null +++ b/xous-riscv/src/register/sip.rs @@ -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); diff --git a/xous-riscv/src/register/sscratch.rs b/xous-riscv/src/register/sscratch.rs new file mode 100644 index 0000000..fe36ce1 --- /dev/null +++ b/xous-riscv/src/register/sscratch.rs @@ -0,0 +1,4 @@ +//! sscratch register + +read_csr_as_usize!(0x140, __read_sscratch); +write_csr_as_usize!(0x140, __write_sscratch); diff --git a/xous-riscv/src/register/sstatus.rs b/xous-riscv/src/register/sstatus.rs new file mode 100644 index 0000000..0c5f53a --- /dev/null +++ b/xous-riscv/src/register/sstatus.rs @@ -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::() * 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); +} diff --git a/xous-riscv/src/register/stval.rs b/xous-riscv/src/register/stval.rs new file mode 100644 index 0000000..304047c --- /dev/null +++ b/xous-riscv/src/register/stval.rs @@ -0,0 +1,3 @@ +//! stval register + +read_csr_as_usize!(0x143, __read_stval); diff --git a/xous-riscv/src/register/stvec.rs b/xous-riscv/src/register/stvec.rs new file mode 100644 index 0000000..ae77132 --- /dev/null +++ b/xous-riscv/src/register/stvec.rs @@ -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); +} diff --git a/xous-riscv/src/register/time.rs b/xous-riscv/src/register/time.rs new file mode 100644 index 0000000..8fa15d0 --- /dev/null +++ b/xous-riscv/src/register/time.rs @@ -0,0 +1,4 @@ +//! time register + +read_csr_as_usize!(0xC01, __read_time); +read_composite_csr!(super::timeh::read(), read()); diff --git a/xous-riscv/src/register/timeh.rs b/xous-riscv/src/register/timeh.rs new file mode 100644 index 0000000..923bb50 --- /dev/null +++ b/xous-riscv/src/register/timeh.rs @@ -0,0 +1,3 @@ +//! timeh register + +read_csr_as_usize_rv32!(0xC81, __read_timeh); diff --git a/xous-riscv/src/register/ucause.rs b/xous-riscv/src/register/ucause.rs new file mode 100644 index 0000000..d3bbfcf --- /dev/null +++ b/xous-riscv/src/register/ucause.rs @@ -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); diff --git a/xous-riscv/src/register/uepc.rs b/xous-riscv/src/register/uepc.rs new file mode 100644 index 0000000..b511525 --- /dev/null +++ b/xous-riscv/src/register/uepc.rs @@ -0,0 +1,4 @@ +//! uepc register + +read_csr_as_usize!(0x041, __read_uepc); +write_csr_as_usize!(0x041, __write_uepc); diff --git a/xous-riscv/src/register/uie.rs b/xous-riscv/src/register/uie.rs new file mode 100644 index 0000000..81e0728 --- /dev/null +++ b/xous-riscv/src/register/uie.rs @@ -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); diff --git a/xous-riscv/src/register/uip.rs b/xous-riscv/src/register/uip.rs new file mode 100644 index 0000000..06b3886 --- /dev/null +++ b/xous-riscv/src/register/uip.rs @@ -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); diff --git a/xous-riscv/src/register/uscratch.rs b/xous-riscv/src/register/uscratch.rs new file mode 100644 index 0000000..a2d1cb0 --- /dev/null +++ b/xous-riscv/src/register/uscratch.rs @@ -0,0 +1,4 @@ +//! uscratch register + +read_csr_as_usize!(0x040, __read_uscratch); +write_csr_as_usize!(0x040, __write_uscratch); diff --git a/xous-riscv/src/register/ustatus.rs b/xous-riscv/src/register/ustatus.rs new file mode 100644 index 0000000..2995ebb --- /dev/null +++ b/xous-riscv/src/register/ustatus.rs @@ -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); diff --git a/xous-riscv/src/register/utval.rs b/xous-riscv/src/register/utval.rs new file mode 100644 index 0000000..c765f94 --- /dev/null +++ b/xous-riscv/src/register/utval.rs @@ -0,0 +1,3 @@ +//! utval register + +read_csr_as_usize!(0x043, __read_utval); diff --git a/xous-riscv/src/register/utvec.rs b/xous-riscv/src/register/utvec.rs new file mode 100644 index 0000000..a081035 --- /dev/null +++ b/xous-riscv/src/register/utvec.rs @@ -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); +}