Compare commits

...

2 Commits

2
.gitignore vendored

@ -14,3 +14,5 @@ easy-fs-fuse/Cargo.lock
easy-fs-fuse/target/*
tools/
pushall.sh
Cargo.lock
target

@ -0,0 +1,13 @@
[workspace]
members=[
"easy-fs",
"easy-fs-fuse",
"os",
"user",
"third-party/k210-hal",
"third-party/k210-pac",
"third-party/k210-soc",
"third-party/riscv",
"third-party/virtio-drivers",
]

@ -7,16 +7,17 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
buddy_system_allocator = "0.6"
bitflags = "1.2.1"
xmas-elf = "0.7.0"
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers" }
k210-pac = { git = "https://github.com/wyfcyx/k210-pac" }
k210-hal = { git = "https://github.com/wyfcyx/k210-hal" }
k210-soc = { git = "https://github.com/wyfcyx/k210-soc" }
easy-fs = { path = "../easy-fs" }
riscv = { path = "../third-party/riscv", features = ["inline-asm"] }
virtio-drivers = { path = "../third-party/virtio-drivers" }
k210-pac = { path = "../third-party/k210-pac" }
k210-hal = { path = "../third-party/k210-hal" }
k210-soc = { path = "../third-party/k210-soc" }
[features]
board_qemu = []

@ -0,0 +1,16 @@
on: [push, pull_request]
name: Clippy Check
jobs:
clippy_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
components: clippy
override: true
- uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}

@ -0,0 +1,19 @@
on: [push, pull_request]
name: Cross Compile
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: riscv64gc-unknown-none-elf
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --target riscv64gc-unknown-none-elf

@ -0,0 +1,12 @@
name: Security Audit
on:
schedule:
- cron: '0 0 * * *'
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions-rs/audit-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}

@ -0,0 +1,3 @@
/target
**/*.rs.bk
Cargo.lock

@ -0,0 +1,37 @@
# The Rust Code of Conduct
## Conduct
**Contact**: [RISC-V team](https://github.com/rust-embedded/wg#the-riscv-team)
* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all.
* Please be kind and courteous. There's no need to be mean or rude.
* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [RISC-V team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
## Moderation
These are the policies for upholding our community's standards of conduct.
1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
3. Moderators will first respond to such remarks with a warning.
4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off.
5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed.
8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others.
In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely.
And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust.
The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org).
*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).*
[team]: https://github.com/rust-embedded/wg#the-riscv-team

@ -0,0 +1,19 @@
[package]
name = "k210-hal"
version = "0.2.0"
authors = ["The RISC-V Team <risc-v@teams.rust-embedded.org>"]
categories = ["embedded", "hardware-support", "no-std"]
description = "Hardware Abstract Layer (HAL) support for K210, dual-core RV64GC SoC"
repository = "https://github.com/riscv-rust/k210-hal"
keywords = ["riscv", "k210", "hal"]
license = "ISC"
edition = "2018"
[package.metadata.docs.rs]
targets = ["riscv64gc-unknown-none-elf"]
[dependencies]
embedded-hal = "=1.0.0-alpha.1"
nb = "0.1.1"
k210-pac = { path = "../k210-pac" }
bitflags = "1.2.1"

@ -0,0 +1,37 @@
[![crates.io](https://img.shields.io/crates/d/k210-hal.svg)](https://crates.io/crates/k210-hal)
[![crates.io](https://img.shields.io/crates/v/k210-hal.svg)](https://crates.io/crates/k210-hal)
[![Build Status](https://travis-ci.org/riscv-rust/k210-hal.svg?branch=master)](https://travis-ci.org/riscv-rust/k210-hal)
# `k210-hal`
> Hardware abstract layer (HAL) for K210 chip, a dual RV64GC SoC with hardware
> accelerated AI peripherals.
This project is developed and maintained by the [RISC-V team][team].
## [Documentation](https://docs.rs/k210-hal)
## License
Copyright 2019 [RISC-V team][team]
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
## Code of Conduct
Contribution to this crate is organized under the terms of the [Rust Code of
Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises
to intervene to uphold that code of conduct.
[CoC]: CODE_OF_CONDUCT.md
[team]: https://github.com/rust-embedded/wg#the-risc-v-team

@ -0,0 +1,79 @@
//! (TODO) Hardware AES calculator (AES)
use core::marker::PhantomData;
use crate::pac::AES;
pub struct Aes<MODE, KLEN> {
aes: AES,
_mode: PhantomData<MODE>,
_klen: PhantomData<KLEN>,
}
pub struct Ecb;
pub struct Cbc;
pub struct Gcm;
pub struct K128;
pub struct K192;
pub struct K256;
#[allow(unused)] // todo: remove
impl<MODE, KLEN> Aes<MODE, KLEN> {
pub fn ecb128(aes: AES) -> Aes<Ecb, K128> {
todo!()
}
pub fn ecb192(aes: AES) -> Aes<Ecb, K192> {
todo!()
}
pub fn ecb256(aes: AES) -> Aes<Ecb, K256> {
todo!()
}
pub fn cbc128(aes: AES) -> Aes<Cbc, K128> {
todo!()
}
pub fn cbc192(aes: AES) -> Aes<Cbc, K192> {
todo!()
}
pub fn cbc256(aes: AES) -> Aes<Cbc, K256> {
todo!()
}
pub fn gcm128(aes: AES) -> Aes<Gcm, K128> {
todo!()
}
pub fn gcm192(aes: AES) -> Aes<Gcm, K192> {
todo!()
}
pub fn gcm256(aes: AES) -> Aes<Gcm, K256> {
todo!()
}
}
impl<MODE, KLEN> Aes<MODE, KLEN> {
// todo: clock
pub fn free(self) -> AES {
self.aes
}
}
#[allow(unused)] // todo: remove
impl<MODE, KLEN> Aes<MODE, KLEN> {
// entrypt block in-place
pub fn encrypt_block(&self, block: &mut [u8], key: &[u8]) {
todo!()
}
// decrypt block in-place
pub fn decrypt_block(&self, block: &mut [u8], key: &[u8]) {
todo!()
}
}

@ -0,0 +1 @@
//! (TODO) Audio Processor Unit (APU)

@ -0,0 +1,117 @@
//! (TODO) Bypass cache
//!
//! Todo: verify this module!
use core::slice;
use core::str;
/// Convert a buffer or a pointer into ones with uncached address.
///
/// Section 3.4.1, Kendryte K210 Datasheet
pub fn uncached<T: Uncache>(buf: T) -> T {
buf.uncache()
}
/// Uncacheable buffer or pointer.
pub trait Uncache {
/// Convert this buffer or pointer to uncached addressed ones
fn uncache(self) -> Self;
}
impl<T> Uncache for &T {
#[inline]
fn uncache(self) -> Self {
let addr = self as *const T as usize;
assert_addr_cached(addr);
// note(unsafe): safe for source address is safe
unsafe { &*((addr - 0x4000_0000) as *const T) }
}
}
impl<T> Uncache for &mut T {
#[inline]
fn uncache(self) -> Self {
let addr = self as *mut T as usize;
assert_addr_cached(addr);
// note(unsafe): safe for source address is safe
unsafe { &mut *((addr - 0x4000_0000) as *mut T) }
}
}
impl<T> Uncache for &[T] {
#[inline]
fn uncache(self) -> Self {
let addr = self.as_ptr() as usize;
assert_addr_cached(addr);
let new_ptr = (addr - 0x4000_0000) as *const T;
// note(unsafe): source address is safe; passing ownership
unsafe { slice::from_raw_parts(new_ptr, self.len()) }
}
}
impl<T> Uncache for &mut [T] {
#[inline]
fn uncache(self) -> Self {
let addr = self.as_ptr() as usize;
assert_addr_cached(addr);
let new_ptr = (addr - 0x4000_0000) as *mut T;
// note(unsafe): source address is safe; passing ownership
unsafe { slice::from_raw_parts_mut(new_ptr, self.len()) }
}
}
impl Uncache for &str {
#[inline]
fn uncache(self) -> Self {
let addr = self.as_ptr() as usize;
assert_addr_cached(addr);
let new_ptr = (addr - 0x4000_0000) as *const u8;
// note(unsafe): source address is safe; passing ownership
let slice = unsafe { slice::from_raw_parts(new_ptr, self.len()) };
// note(unsafe): source slice is guaranteed valid in UTF-8
unsafe { str::from_utf8_unchecked(slice) }
}
}
impl Uncache for &mut str {
#[inline]
fn uncache(self) -> Self {
let addr = self.as_ptr() as usize;
assert_addr_cached(addr);
let new_ptr = (addr - 0x4000_0000) as *mut u8;
// note(unsafe): source address is safe; passing ownership
let slice = unsafe { slice::from_raw_parts_mut(new_ptr, self.len()) };
// note(unsafe): source slice is guaranteed valid in UTF-8
unsafe { str::from_utf8_unchecked_mut(slice) }
}
}
impl<T> Uncache for *const T {
#[inline]
fn uncache(self) -> Self {
assert_addr_cached(self as usize);
(self as usize - 0x4000_0000) as *const T
}
}
impl<T> Uncache for *mut T {
#[inline]
fn uncache(self) -> Self {
assert_addr_cached(self as usize);
(self as usize - 0x4000_0000) as *mut T
}
}
#[inline]
fn assert_addr_cached(addr: usize) {
/*
SRAM memory: 0x8000_0000 to 0x805F_FFFF
AI memory: 0x8060_0000 to 0x807F_FFFF
SRAM memory includes two parts: MEM0 and MEM1
MEM0 memory: 0x8000_0000 to 0x803F_FFFF
MEM1 memory: 0x8040_0000 to 0x805F_FFFF
*/
// assure that memory is within SRAM or AI
// todo: should we exclude AI?
assert!(addr <= 0x807F_FFFF && addr >= 0x8000_0000);
}

@ -0,0 +1,49 @@
//! Core Local Interruptor (CLINT)
//!
//! TODO: Should this module designed in a somehow IP-core peripheral create?
/// mtime register
pub mod mtime {
use crate::pac;
/// Read mtime register.
pub fn read() -> u64 {
unsafe { (*pac::CLINT::ptr()).mtime.read().bits() }
}
}
/// msip register
pub mod msip {
use crate::pac;
/// set IPI interrupt flag for one given hart
pub fn set_ipi(hart_id: usize) {
unsafe {
(*pac::CLINT::ptr()).msip[hart_id].write(|w|
w.bits(1))
}
}
/// clear IPI interrupt flag for one given hart
pub fn clear_ipi(hart_id: usize) {
unsafe {
(*pac::CLINT::ptr()).msip[hart_id].write(|w|
w.bits(0))
}
}
}
/// mtimecmp register
pub mod mtimecmp {
use crate::pac;
/// Read 64-bit mtimecmp register for certain hart id
pub fn read(hart_id: usize) -> u64 {
unsafe { (*pac::CLINT::ptr()).mtimecmp[hart_id].read().bits() }
}
/// Write 64-bit mtimecmp register for certain hart id
pub fn write(hart_id: usize, bits: u64) {
// Volume II: RISC-V Privileged Architectures V1.10 p.31, figure 3.15
unsafe { (*pac::CLINT::ptr()).mtimecmp[hart_id].write(|w|
w.bits(bits)) };
}
}

@ -0,0 +1,42 @@
//! Clock configuration
//use crate::pac::PRCI;
use crate::time::Hertz;
/// Frozen clock frequencies
///
/// The existence of this value indicates that the clock configuration can no
/// longer be changed.
#[derive(Clone, Copy)]
pub struct Clocks {
cpu: Hertz,
apb0: Hertz,
}
impl Clocks {
#[doc(hidden)]
pub fn new() -> Self {
/*
[MAIXPY]Pll0:freq:806000000
[MAIXPY]Pll1:freq:398666666
[MAIXPY]Pll2:freq:45066666
[MAIXPY]cpu:freq:403000000
[MAIXPY]kpu:freq:398666666
in freq: 26000000
cpu_freq: 390000000
*/
Self {
cpu: Hertz(403_000_000),
apb0: Hertz(195_000_000),
}
}
/// Returns CPU frequency
pub fn cpu(&self) -> Hertz {
Hertz(self.cpu.0)
}
/// Returns APB0 frequency
pub fn apb0(&self) -> Hertz {
self.apb0
}
}

@ -0,0 +1,34 @@
//! (TODO) Direct Memory Access Controller (DMAC)
use crate::{pac, sysctl};
pub fn dmac_id() -> u64 {
unsafe { (*pac::DMAC::ptr()).id.read().bits() }
}
pub fn dmac_version() -> u64 {
unsafe { (*pac::DMAC::ptr()).compver.read().bits() }
}
pub trait DmacExt {
fn configure(self, /* sysctl ACLK clock */) -> Dmac;
}
impl DmacExt for pac::DMAC {
fn configure(self, /* sysctl ACLK clock */) -> Dmac {
// enable
sysctl::clk_en_peri().modify(|_, w| w.dma_clk_en().set_bit());
// todo: reset
Dmac {} // todo
}
}
pub struct Dmac {
}
// pub struct C0 {
// // todo
// pub async fn poll() {
// }
// }

@ -0,0 +1 @@
//! (TODO) Fast Fourier Transform (FFT)

@ -0,0 +1,486 @@
//! Field Programmable IO Array (FPIOA)
/*
new design: Split FPIOA into several IO pins (IO0, IO1, .., IO47)
with ownership of IOx struct we may change their functions.
For GPIOs and GPIOHS's we should split them into another GpioXx structs.
note: other modules do not need to require for ownership of certain IOx struct
for that pins and peripherals are considered separate modules.
If this design results in inconvenience or violent of Rust's ownership role
please fire an issue to tell us.
*/
use crate::pac::FPIOA;
use crate::sysctl::{self, APB0};
use core::marker::PhantomData;
/// FPIOA function
pub trait Function {
const INDEX: u8;
}
/// Pull direction
#[derive(Copy, Clone)]
pub enum Pull {
/// No pulls
None,
/// Pull down
Down,
/// Pull up
Up,
}
/// FPIOA I/O Pin
pub trait IoPin {
const INDEX: u8;
fn set_io_pull(&mut self, pull: Pull) {
unsafe {
let fpioa = &*FPIOA::ptr();
fpioa.io[Self::INDEX as usize].modify(|_, w| match pull {
Pull::None => w.pu().bit(false).pd().bit(false),
Pull::Down => w.pu().bit(false).pd().bit(true),
Pull::Up => w.pu().bit(true).pd().bit(false),
});
}
}
}
/// Marker trait for I/O pin function detection
pub trait Mode<FUNC> {}
/// Extension trait to split a FPIOA peripheral in independent pins and registers
pub trait FpioaExt {
/// Splits the FPIOA block into independent pins and registers
///
/// todo: split sysctl into two apb's, then use the APB0 to split Fpioa
fn split(self, apb0: &mut APB0) -> Parts;
}
/// All I/O pins
macro_rules! def_io_pin {
($($IoX: ident: ($id: expr, $iox: ident, $func: ident);)+) => {
impl FpioaExt for FPIOA {
fn split(self, apb0: &mut APB0) -> Parts {
// enable APB0 bus
apb0.enable();
// enable sysctl peripheral
sysctl::clk_en_peri().modify(|_r, w| w.fpioa_clk_en().set_bit());
// return ownership
Parts {
$( $iox: $IoX { _function: PhantomData }, )+
}
}
}
/// FPIOA Parts
pub struct Parts {
$(
/// Programmable I/O pin
pub $iox: $IoX<$func>,
)+
// todo: tie controller Tie (force set high or low as input)
}
pub use io_pins::*;
/// All I/O pins
pub mod io_pins {
use core::marker::PhantomData;
use super::{Function, IoPin, Mode, FUNCTION_DEFAULTS};
use crate::pac::FPIOA;
$(
/// Programmable I/O pin
pub struct $IoX<FUNC> {
pub(crate) _function: PhantomData<FUNC>
}
impl<FUNC> $IoX<FUNC> {
/// Change the programmable I/O pin into given function
///
/// You may refer to module [functions] for all functions.
///
/// [functions]: ../functions/index.html
pub fn into_function<F: Function>(self, func: F) -> $IoX<F> {
let _ = func; // note(discard): Zero-sized typestate value
unsafe { &(*FPIOA::ptr()).io[$id].write(|w|
w.bits(FUNCTION_DEFAULTS[F::INDEX as usize])
) };
$IoX { _function: PhantomData }
}
}
impl<FUNC> IoPin for $IoX<FUNC> {
const INDEX: u8 = $id;
}
impl<FUNC> Mode<FUNC> for $IoX<FUNC> {}
)+
}
};
}
def_io_pin! {
Io0: (0, io0, JTAG_TCLK);
Io1: (1, io1, JTAG_TDI);
Io2: (2, io2, JTAG_TMS);
Io3: (3, io3, JTAG_TDO);
Io4: (4, io4, UARTHS_RX);
Io5: (5, io5, UARTHS_TX);
Io6: (6, io6, RESV0); // (FLOAT*): no default function
Io7: (7, io7, RESV0); // (FLOAT*): no default function
Io8: (8, io8, GPIO0);
Io9: (9, io9, GPIO1);
Io10: (10, io10, GPIO2);
Io11: (11, io11, GPIO3);
Io12: (12, io12, GPIO4);
Io13: (13, io13, GPIO5);
Io14: (14, io14, GPIO6);
Io15: (15, io15, GPIO7);
Io16: (16, io16, GPIOHS0);
Io17: (17, io17, GPIOHS1);
Io18: (18, io18, GPIOHS2);
Io19: (19, io19, GPIOHS3);
Io20: (20, io20, GPIOHS4);
Io21: (21, io21, GPIOHS5);
Io22: (22, io22, GPIOHS6);
Io23: (23, io23, GPIOHS7);
Io24: (24, io24, GPIOHS8);
Io25: (25, io25, GPIOHS9);
Io26: (26, io26, GPIOHS10);
Io27: (27, io27, GPIOHS11);
Io28: (28, io28, GPIOHS12);
Io29: (29, io29, GPIOHS13);
Io30: (30, io30, GPIOHS14);
Io31: (31, io31, GPIOHS15);
Io32: (32, io32, GPIOHS16);
Io33: (33, io33, GPIOHS17);
Io34: (34, io34, GPIOHS18);
Io35: (35, io35, GPIOHS19);
Io36: (36, io36, GPIOHS20);
Io37: (37, io37, GPIOHS21);
Io38: (38, io38, GPIOHS22);
Io39: (39, io39, GPIOHS23);
Io40: (40, io40, GPIOHS24);
Io41: (41, io41, GPIOHS25);
Io42: (42, io42, GPIOHS26);
Io43: (43, io43, GPIOHS27);
Io44: (44, io44, GPIOHS28);
Io45: (45, io45, GPIOHS29);
Io46: (46, io46, GPIOHS30);
Io47: (47, io47, GPIOHS31);
}
/** Defaults per function (from Kendryte fpioa.c) */
#[rustfmt::skip]
static FUNCTION_DEFAULTS: &[u32] = &[
0x00900000, 0x00900001, 0x00900002, 0x00001f03, 0x00b03f04, 0x00b03f05, 0x00b03f06, 0x00b03f07,
0x00b03f08, 0x00b03f09, 0x00b03f0a, 0x00b03f0b, 0x00001f0c, 0x00001f0d, 0x00001f0e, 0x00001f0f,
0x03900010, 0x00001f11, 0x00900012, 0x00001f13, 0x00900014, 0x00900015, 0x00001f16, 0x00001f17,
0x00901f18, 0x00901f19, 0x00901f1a, 0x00901f1b, 0x00901f1c, 0x00901f1d, 0x00901f1e, 0x00901f1f,
0x00901f20, 0x00901f21, 0x00901f22, 0x00901f23, 0x00901f24, 0x00901f25, 0x00901f26, 0x00901f27,
0x00901f28, 0x00901f29, 0x00901f2a, 0x00901f2b, 0x00901f2c, 0x00901f2d, 0x00901f2e, 0x00901f2f,
0x00901f30, 0x00901f31, 0x00901f32, 0x00901f33, 0x00901f34, 0x00901f35, 0x00901f36, 0x00901f37,
0x00901f38, 0x00901f39, 0x00901f3a, 0x00901f3b, 0x00901f3c, 0x00901f3d, 0x00901f3e, 0x00901f3f,
0x00900040, 0x00001f41, 0x00900042, 0x00001f43, 0x00900044, 0x00001f45, 0x00b03f46, 0x00b03f47,
0x00b03f48, 0x00b03f49, 0x00b03f4a, 0x00b03f4b, 0x00b03f4c, 0x00b03f4d, 0x00001f4e, 0x00001f4f,
0x00001f50, 0x00001f51, 0x03900052, 0x00001f53, 0x00b03f54, 0x00900055, 0x00900056, 0x00001f57,
0x00001f58, 0x00001f59, 0x0090005a, 0x0090005b, 0x0090005c, 0x0090005d, 0x00001f5e, 0x00001f5f,
0x00001f60, 0x00001f61, 0x00001f62, 0x00001f63, 0x00001f64, 0x00900065, 0x00900066, 0x00900067,
0x00900068, 0x00001f69, 0x00001f6a, 0x00001f6b, 0x00001f6c, 0x00001f6d, 0x00001f6e, 0x00001f6f,
0x00900070, 0x00900071, 0x00900072, 0x00900073, 0x00001f74, 0x00001f75, 0x00001f76, 0x00001f77,
0x00000078, 0x00000079, 0x0000007a, 0x0000007b, 0x0000007c, 0x0000007d, 0x0099107e, 0x0099107f,
0x00991080, 0x00991081, 0x00991082, 0x00991083, 0x00001f84, 0x00001f85, 0x00001f86, 0x00900087,
0x00900088, 0x00900089, 0x0090008a, 0x0090008b, 0x0090008c, 0x0090008d, 0x0090008e, 0x0090008f,
0x00900090, 0x00900091, 0x00993092, 0x00993093, 0x00900094, 0x00900095, 0x00900096, 0x00900097,
0x00900098, 0x00001f99, 0x00001f9a, 0x00001f9b, 0x00001f9c, 0x00001f9d, 0x00001f9e, 0x00001f9f,
0x00001fa0, 0x00001fa1, 0x009000a2, 0x009000a3, 0x009000a4, 0x009000a5, 0x009000a6, 0x00001fa7,
0x00001fa8, 0x00001fa9, 0x00001faa, 0x00001fab, 0x00001fac, 0x00001fad, 0x00001fae, 0x00001faf,
0x009000b0, 0x009000b1, 0x009000b2, 0x009000b3, 0x009000b4, 0x00001fb5, 0x00001fb6, 0x00001fb7,
0x00001fb8, 0x00001fb9, 0x00001fba, 0x00001fbb, 0x00001fbc, 0x00001fbd, 0x00001fbe, 0x00001fbf,
0x00001fc0, 0x00001fc1, 0x00001fc2, 0x00001fc3, 0x00001fc4, 0x00001fc5, 0x00001fc6, 0x00001fc7,
0x00001fc8, 0x00001fc9, 0x00001fca, 0x00001fcb, 0x00001fcc, 0x00001fcd, 0x00001fce, 0x00001fcf,
0x00001fd0, 0x00001fd1, 0x00001fd2, 0x00001fd3, 0x00001fd4, 0x009000d5, 0x009000d6, 0x009000d7,
0x009000d8, 0x009100d9, 0x00991fda, 0x009000db, 0x009000dc, 0x009000dd, 0x000000de, 0x009000df,
0x00001fe0, 0x00001fe1, 0x00001fe2, 0x00001fe3, 0x00001fe4, 0x00001fe5, 0x00001fe6, 0x00001fe7,
0x00001fe8, 0x00001fe9, 0x00001fea, 0x00001feb, 0x00001fec, 0x00001fed, 0x00001fee, 0x00001fef,
0x00001ff0, 0x00001ff1, 0x00001ff2, 0x00001ff3, 0x00001ff4, 0x00001ff5, 0x00001ff6, 0x00001ff7,
0x00001ff8, 0x00001ff9, 0x00001ffa, 0x00001ffb, 0x00001ffc, 0x00001ffd, 0x00001ffe, 0x00001fff,
];
pub use functions::*;
/// All programmable functions
pub mod functions {
use super::Function;
macro_rules! def_function {
($($name: ident: ($index: expr, $doc: expr);)+) => {
$(
#[doc = $doc]
#[allow(non_camel_case_types)]
pub struct $name;
impl Function for $name {
const INDEX: u8 = $index;
}
)+
};
}
def_function! {
JTAG_TCLK: (0, "JTAG Test Clock");
JTAG_TDI: (1, "JTAG Test Data In");
JTAG_TMS: (2, "JTAG Test Mode Select");
JTAG_TDO: (3, "JTAG Test Data Out");
SPI0_D0: (4, "SPI0 Data 0");
SPI0_D1: (5, "SPI0 Data 1");
SPI0_D2: (6, "SPI0 Data 2");
SPI0_D3: (7, "SPI0 Data 3");
SPI0_D4: (8, "SPI0 Data 4");
SPI0_D5: (9, "SPI0 Data 5");
SPI0_D6: (10, "SPI0 Data 6");
SPI0_D7: (11, "SPI0 Data 7");
SPI0_SS0: (12, "SPI0 Chip Select 0");
SPI0_SS1: (13, "SPI0 Chip Select 1");
SPI0_SS2: (14, "SPI0 Chip Select 2");
SPI0_SS3: (15, "SPI0 Chip Select 3");
SPI0_ARB: (16, "SPI0 Arbitration");
SPI0_SCLK: (17, "SPI0 Serial Clock");
UARTHS_RX: (18, "UART High speed Receiver");
UARTHS_TX: (19, "UART High speed Transmitter");
RESV6: (20, "Reserved function");
RESV7: (21, "Reserved function");
CLK_SPI1: (22, "Clock SPI1");
CLK_I2C1: (23, "Clock I2C1");
GPIOHS0: (24, "GPIO High speed 0");
GPIOHS1: (25, "GPIO High speed 1");
GPIOHS2: (26, "GPIO High speed 2");
GPIOHS3: (27, "GPIO High speed 3");
GPIOHS4: (28, "GPIO High speed 4");
GPIOHS5: (29, "GPIO High speed 5");
GPIOHS6: (30, "GPIO High speed 6");
GPIOHS7: (31, "GPIO High speed 7");
GPIOHS8: (32, "GPIO High speed 8");
GPIOHS9: (33, "GPIO High speed 9");
GPIOHS10: (34, "GPIO High speed 10");
GPIOHS11: (35, "GPIO High speed 11");
GPIOHS12: (36, "GPIO High speed 12");
GPIOHS13: (37, "GPIO High speed 13");
GPIOHS14: (38, "GPIO High speed 14");
GPIOHS15: (39, "GPIO High speed 15");
GPIOHS16: (40, "GPIO High speed 16");
GPIOHS17: (41, "GPIO High speed 17");
GPIOHS18: (42, "GPIO High speed 18");
GPIOHS19: (43, "GPIO High speed 19");
GPIOHS20: (44, "GPIO High speed 20");
GPIOHS21: (45, "GPIO High speed 21");
GPIOHS22: (46, "GPIO High speed 22");
GPIOHS23: (47, "GPIO High speed 23");
GPIOHS24: (48, "GPIO High speed 24");
GPIOHS25: (49, "GPIO High speed 25");
GPIOHS26: (50, "GPIO High speed 26");
GPIOHS27: (51, "GPIO High speed 27");
GPIOHS28: (52, "GPIO High speed 28");
GPIOHS29: (53, "GPIO High speed 29");
GPIOHS30: (54, "GPIO High speed 30");
GPIOHS31: (55, "GPIO High speed 31");
GPIO0: (56, "GPIO pin 0");
GPIO1: (57, "GPIO pin 1");
GPIO2: (58, "GPIO pin 2");
GPIO3: (59, "GPIO pin 3");
GPIO4: (60, "GPIO pin 4");
GPIO5: (61, "GPIO pin 5");
GPIO6: (62, "GPIO pin 6");
GPIO7: (63, "GPIO pin 7");
UART1_RX: (64, "UART1 Receiver");
UART1_TX: (65, "UART1 Transmitter");
UART2_RX: (66, "UART2 Receiver");
UART2_TX: (67, "UART2 Transmitter");
UART3_RX: (68, "UART3 Receiver");
UART3_TX: (69, "UART3 Transmitter");
SPI1_D0: (70, "SPI1 Data 0");
SPI1_D1: (71, "SPI1 Data 1");
SPI1_D2: (72, "SPI1 Data 2");
SPI1_D3: (73, "SPI1 Data 3");
SPI1_D4: (74, "SPI1 Data 4");
SPI1_D5: (75, "SPI1 Data 5");
SPI1_D6: (76, "SPI1 Data 6");
SPI1_D7: (77, "SPI1 Data 7");
SPI1_SS0: (78, "SPI1 Chip Select 0");
SPI1_SS1: (79, "SPI1 Chip Select 1");
SPI1_SS2: (80, "SPI1 Chip Select 2");
SPI1_SS3: (81, "SPI1 Chip Select 3");
SPI1_ARB: (82, "SPI1 Arbitration");
SPI1_SCLK: (83, "SPI1 Serial Clock");
SPI_SLAVE_D0: (84, "SPI Slave Data 0");
SPI_SLAVE_SS: (85, "SPI Slave Select");
SPI_SLAVE_SCLK: (86, "SPI Slave Serial Clock");
I2S0_MCLK: (87, "I2S0 Master Clock");
I2S0_SCLK: (88, "I2S0 Serial Clock(BCLK)");
I2S0_WS: (89, "I2S0 Word Select(LRCLK)");
I2S0_IN_D0: (90, "I2S0 Serial Data Input 0");
I2S0_IN_D1: (91, "I2S0 Serial Data Input 1");
I2S0_IN_D2: (92, "I2S0 Serial Data Input 2");
I2S0_IN_D3: (93, "I2S0 Serial Data Input 3");
I2S0_OUT_D0: (94, "I2S0 Serial Data Output 0");
I2S0_OUT_D1: (95, "I2S0 Serial Data Output 1");
I2S0_OUT_D2: (96, "I2S0 Serial Data Output 2");
I2S0_OUT_D3: (97, "I2S0 Serial Data Output 3");
I2S1_MCLK: (98, "I2S1 Master Clock");
I2S1_SCLK: (99, "I2S1 Serial Clock(BCLK)");
I2S1_WS: (100, "I2S1 Word Select(LRCLK)");
I2S1_IN_D0: (101, "I2S1 Serial Data Input 0");
I2S1_IN_D1: (102, "I2S1 Serial Data Input 1");
I2S1_IN_D2: (103, "I2S1 Serial Data Input 2");
I2S1_IN_D3: (104, "I2S1 Serial Data Input 3");
I2S1_OUT_D0: (105, "I2S1 Serial Data Output 0");
I2S1_OUT_D1: (106, "I2S1 Serial Data Output 1");
I2S1_OUT_D2: (107, "I2S1 Serial Data Output 2");
I2S1_OUT_D3: (108, "I2S1 Serial Data Output 3");
I2S2_MCLK: (109, "I2S2 Master Clock");
I2S2_SCLK: (110, "I2S2 Serial Clock(BCLK)");
I2S2_WS: (111, "I2S2 Word Select(LRCLK)");
I2S2_IN_D0: (112, "I2S2 Serial Data Input 0");
I2S2_IN_D1: (113, "I2S2 Serial Data Input 1");
I2S2_IN_D2: (114, "I2S2 Serial Data Input 2");
I2S2_IN_D3: (115, "I2S2 Serial Data Input 3");
I2S2_OUT_D0: (116, "I2S2 Serial Data Output 0");
I2S2_OUT_D1: (117, "I2S2 Serial Data Output 1");
I2S2_OUT_D2: (118, "I2S2 Serial Data Output 2");
I2S2_OUT_D3: (119, "I2S2 Serial Data Output 3");
RESV0: (120, "Reserved function");
RESV1: (121, "Reserved function");
RESV2: (122, "Reserved function");
RESV3: (123, "Reserved function");
RESV4: (124, "Reserved function");
RESV5: (125, "Reserved function");
I2C0_SCLK: (126, "I2C0 Serial Clock");
I2C0_SDA: (127, "I2C0 Serial Data");
I2C1_SCLK: (128, "I2C1 Serial Clock");
I2C1_SDA: (129, "I2C1 Serial Data");
I2C2_SCLK: (130, "I2C2 Serial Clock");
I2C2_SDA: (131, "I2C2 Serial Data");
CMOS_XCLK: (132, "DVP System Clock");
CMOS_RST: (133, "DVP System Reset");
CMOS_PWDN: (134, "DVP Power Down Mode");
CMOS_VSYNC: (135, "DVP Vertical Sync");
CMOS_HREF: (136, "DVP Horizontal Reference output");
CMOS_PCLK: (137, "Pixel Clock");
CMOS_D0: (138, "Data Bit 0");
CMOS_D1: (139, "Data Bit 1");
CMOS_D2: (140, "Data Bit 2");
CMOS_D3: (141, "Data Bit 3");
CMOS_D4: (142, "Data Bit 4");
CMOS_D5: (143, "Data Bit 5");
CMOS_D6: (144, "Data Bit 6");
CMOS_D7: (145, "Data Bit 7");
SCCB_SCLK: (146, "SCCB Serial Clock");
SCCB_SDA: (147, "SCCB Serial Data");
UART1_CTS: (148, "UART1 Clear To Send");
UART1_DSR: (149, "UART1 Data Set Ready");
UART1_DCD: (150, "UART1 Data Carrier Detect");
UART1_RI: (151, "UART1 Ring Indicator");
UART1_SIR_IN: (152, "UART1 Serial Infrared Input");
UART1_DTR: (153, "UART1 Data Terminal Ready");
UART1_RTS: (154, "UART1 Request To Send");
UART1_OUT2: (155, "UART1 User-designated Output 2");
UART1_OUT1: (156, "UART1 User-designated Output 1");
UART1_SIR_OUT: (157, "UART1 Serial Infrared Output");
UART1_BAUD: (158, "UART1 Transmit Clock Output");
UART1_RE: (159, "UART1 Receiver Output Enable");
UART1_DE: (160, "UART1 Driver Output Enable");
UART1_RS485_EN: (161, "UART1 RS485 Enable");
UART2_CTS: (162, "UART2 Clear To Send");
UART2_DSR: (163, "UART2 Data Set Ready");
UART2_DCD: (164, "UART2 Data Carrier Detect");
UART2_RI: (165, "UART2 Ring Indicator");
UART2_SIR_IN: (166, "UART2 Serial Infrared Input");
UART2_DTR: (167, "UART2 Data Terminal Ready");
UART2_RTS: (168, "UART2 Request To Send");
UART2_OUT2: (169, "UART2 User-designated Output 2");
UART2_OUT1: (170, "UART2 User-designated Output 1");
UART2_SIR_OUT: (171, "UART2 Serial Infrared Output");
UART2_BAUD: (172, "UART2 Transmit Clock Output");
UART2_RE: (173, "UART2 Receiver Output Enable");
UART2_DE: (174, "UART2 Driver Output Enable");
UART2_RS485_EN: (175, "UART2 RS485 Enable");
UART3_CTS: (176, "UART3 Clear To Send");
UART3_DSR: (177, "UART3 Data Set Ready");
UART3_DCD: (178, "UART3 Data Carrier Detect");
UART3_RI: (179, "UART3 Ring Indicator");
UART3_SIR_IN: (180, "UART3 Serial Infrared Input");
UART3_DTR: (181, "UART3 Data Terminal Ready");
UART3_RTS: (182, "UART3 Request To Send");
UART3_OUT2: (183, "UART3 User-designated Output 2");
UART3_OUT1: (184, "UART3 User-designated Output 1");
UART3_SIR_OUT: (185, "UART3 Serial Infrared Output");
UART3_BAUD: (186, "UART3 Transmit Clock Output");
UART3_RE: (187, "UART3 Receiver Output Enable");
UART3_DE: (188, "UART3 Driver Output Enable");
UART3_RS485_EN: (189, "UART3 RS485 Enable");
TIMER0_TOGGLE1: (190, "TIMER0 Toggle Output 1");
TIMER0_TOGGLE2: (191, "TIMER0 Toggle Output 2");
TIMER0_TOGGLE3: (192, "TIMER0 Toggle Output 3");
TIMER0_TOGGLE4: (193, "TIMER0 Toggle Output 4");
TIMER1_TOGGLE1: (194, "TIMER1 Toggle Output 1");
TIMER1_TOGGLE2: (195, "TIMER1 Toggle Output 2");
TIMER1_TOGGLE3: (196, "TIMER1 Toggle Output 3");
TIMER1_TOGGLE4: (197, "TIMER1 Toggle Output 4");
TIMER2_TOGGLE1: (198, "TIMER2 Toggle Output 1");
TIMER2_TOGGLE2: (199, "TIMER2 Toggle Output 2");
TIMER2_TOGGLE3: (200, "TIMER2 Toggle Output 3");
TIMER2_TOGGLE4: (201, "TIMER2 Toggle Output 4");
CLK_SPI2: (202, "Clock SPI2");
CLK_I2C2: (203, "Clock I2C2");
INTERNAL0: (204, "Internal function signal 0");
INTERNAL1: (205, "Internal function signal 1");
INTERNAL2: (206, "Internal function signal 2");
INTERNAL3: (207, "Internal function signal 3");
INTERNAL4: (208, "Internal function signal 4");
INTERNAL5: (209, "Internal function signal 5");
INTERNAL6: (210, "Internal function signal 6");
INTERNAL7: (211, "Internal function signal 7");
INTERNAL8: (212, "Internal function signal 8");
INTERNAL9: (213, "Internal function signal 9");
INTERNAL10: (214, "Internal function signal 10");
INTERNAL11: (215, "Internal function signal 11");
INTERNAL12: (216, "Internal function signal 12");
INTERNAL13: (217, "Internal function signal 13");
INTERNAL14: (218, "Internal function signal 14");
INTERNAL15: (219, "Internal function signal 15");
INTERNAL16: (220, "Internal function signal 16");
INTERNAL17: (221, "Internal function signal 17");
CONSTANT: (222, "Constant function");
INTERNAL18: (223, "Internal function signal 18");
DEBUG0: (224, "Debug function 0");
DEBUG1: (225, "Debug function 1");
DEBUG2: (226, "Debug function 2");
DEBUG3: (227, "Debug function 3");
DEBUG4: (228, "Debug function 4");
DEBUG5: (229, "Debug function 5");
DEBUG6: (230, "Debug function 6");
DEBUG7: (231, "Debug function 7");
DEBUG8: (232, "Debug function 8");
DEBUG9: (233, "Debug function 9");
DEBUG10: (234, "Debug function 10");
DEBUG11: (235, "Debug function 11");
DEBUG12: (236, "Debug function 12");
DEBUG13: (237, "Debug function 13");
DEBUG14: (238, "Debug function 14");
DEBUG15: (239, "Debug function 15");
DEBUG16: (240, "Debug function 16");
DEBUG17: (241, "Debug function 17");
DEBUG18: (242, "Debug function 18");
DEBUG19: (243, "Debug function 19");
DEBUG20: (244, "Debug function 20");
DEBUG21: (245, "Debug function 21");
DEBUG22: (246, "Debug function 22");
DEBUG23: (247, "Debug function 23");
DEBUG24: (248, "Debug function 24");
DEBUG25: (249, "Debug function 25");
DEBUG26: (250, "Debug function 26");
DEBUG27: (251, "Debug function 27");
DEBUG28: (252, "Debug function 28");
DEBUG29: (253, "Debug function 29");
DEBUG30: (254, "Debug function 30");
DEBUG31: (255, "Debug function 31");
}
}

@ -0,0 +1,233 @@
//! General Purpose Input/Output (GPIO)
use core::marker::PhantomData;
use crate::pac;
use crate::sysctl::{self, APB0};
use crate::fpioa::{IoPin, Pull, Mode};
use crate::bit_utils::{u32_set_bit, u32_toggle_bit, u32_bit_is_set, u32_bit_is_clear};
use embedded_hal::digital::{OutputPin, StatefulOutputPin, InputPin, ToggleableOutputPin};
/// Extension trait to split a GPIO peripheral into independent pins
pub trait GpioExt {
/// Split the GPIO peripheral into parts
fn split(self, apb0: &mut APB0) -> Parts;
}
macro_rules! def_gpio_pins {
($($GPIOX: ident: ($num: expr, $gpiox: ident, $func: ident);)+) => {
impl GpioExt for pac::GPIO {
fn split(self, apb0: &mut APB0) -> Parts {
// enable APB0 bus
apb0.enable();
// enable sysctl peripheral
sysctl::clk_en_peri().modify(|_r, w| w.gpio_clk_en().set_bit());
// return ownership
Parts {
$( $gpiox: $GPIOX { _ownership: () }, )+
}
}
}
/// GPIO peripheral parts
pub struct Parts {
$(
/// GPIO pin
pub $gpiox: $GPIOX,
)+
}
pub use gpio_pins::*;
/// All GPIO pins
pub mod gpio_pins {
use super::GpioIndex;
$(
/// GPIO pin
pub struct $GPIOX {
pub(crate) _ownership: ()
}
impl GpioIndex for $GPIOX {
type FUNC = crate::fpioa::functions::$func;
const INDEX: u8 = $num;
}
)+
}
};
}
def_gpio_pins! {
GPIO0: (0, gpio0, GPIO0);
GPIO1: (1, gpio1, GPIO1);
GPIO2: (2, gpio2, GPIO2);
GPIO3: (3, gpio3, GPIO3);
GPIO4: (4, gpio4, GPIO4);
GPIO5: (5, gpio5, GPIO5);
GPIO6: (6, gpio6, GPIO6);
GPIO7: (7, gpio7, GPIO7);
}
/// GPIO Index
pub trait GpioIndex {
type FUNC;
const INDEX: u8;
}
/// Unknown mode (type state)
pub struct Unknown;
/// Input mode (type state)
pub struct Input<MODE>(MODE);
/// Floating input (type state)
pub struct Floating;
/// Pull down input (type state)
pub struct PullDown;
/// Pull up input (type state)
pub struct PullUp;
/// Output mode (type state)
pub struct Output;
/// Marker trait for active states
pub trait Active {}
impl Active for Unknown {}
impl Active for Input<Floating> {}
impl Active for Input<PullUp> {}
impl Active for Input<PullDown> {}
impl Active for Output {}
/// GPIO wrapper struct
pub struct Gpio<GPIO, PIN, MODE> {
gpio: GPIO,
pin: PIN,
_mode: PhantomData<MODE>,
}
impl<GPIO: GpioIndex, PIN: Mode<GPIO::FUNC>> Gpio<GPIO, PIN, Unknown> {
pub fn new(gpio: GPIO, pin: PIN) -> Gpio<GPIO, PIN, Unknown> {
Gpio { gpio, pin, _mode: PhantomData }
}
}
impl<GPIO, PIN, MODE> Gpio<GPIO, PIN, MODE> {
pub fn free(self) -> (GPIO, PIN) {
(self.gpio, self.pin)
}
}
impl<GPIO: GpioIndex, PIN: IoPin, MODE: Active> Gpio<GPIO, PIN, MODE> {
pub fn into_floating_input(mut self) -> Gpio<GPIO, PIN, Input<Floating>> {
self.pin.set_io_pull(Pull::None);
self.direction_in();
Gpio { gpio: self.gpio, pin: self.pin, _mode: PhantomData }
}
pub fn into_pull_up_input(mut self) -> Gpio<GPIO, PIN, Input<PullUp>> {
self.pin.set_io_pull(Pull::Up);
self.direction_in();
Gpio { gpio: self.gpio, pin: self.pin, _mode: PhantomData }
}
pub fn into_pull_down_input(mut self) -> Gpio<GPIO, PIN, Input<PullDown>> {
self.pin.set_io_pull(Pull::Down);
self.direction_in();
Gpio { gpio: self.gpio, pin: self.pin, _mode: PhantomData }
}
pub fn into_push_pull_output(mut self) -> Gpio<GPIO, PIN, Output> {
self.pin.set_io_pull(Pull::Down);
self.direction_out();
Gpio { gpio: self.gpio, pin: self.pin, _mode: PhantomData }
}
#[inline]
fn direction_in(&mut self) {
unsafe {
let p = &(*pac::GPIO::ptr()).direction as *const _ as *mut _;
u32_set_bit(p, false, GPIO::INDEX as usize);
}
}
#[inline]
fn direction_out(&mut self) {
unsafe {
let p = &(*pac::GPIO::ptr()).direction as *const _ as *mut _;
u32_set_bit(p, true, GPIO::INDEX as usize);
}
}
}
impl<GPIO: GpioIndex, PIN, MODE> InputPin for Gpio<GPIO, PIN, Input<MODE>> {
type Error = core::convert::Infallible;
fn try_is_high(&self) -> Result<bool, Self::Error> {
Ok(unsafe {
let p = &(*pac::GPIO::ptr()).data_input as *const _ as *const _;
u32_bit_is_set(p, GPIO::INDEX as usize)
})
}
fn try_is_low(&self) -> Result<bool, Self::Error> {
Ok(unsafe {
let p = &(*pac::GPIO::ptr()).data_input as *const _ as *const _;
u32_bit_is_clear(p, GPIO::INDEX as usize)
})
}
}
impl<GPIO: GpioIndex, PIN> OutputPin for Gpio<GPIO, PIN, Output> {
type Error = core::convert::Infallible;
fn try_set_high(&mut self) -> Result<(), Self::Error> {
unsafe {
let p = &(*pac::GPIO::ptr()).data_output as *const _ as *mut _;
u32_set_bit(p, true, GPIO::INDEX as usize);
}
Ok(())
}
fn try_set_low(&mut self) -> Result<(), Self::Error> {
unsafe {
let p = &(*pac::GPIO::ptr()).data_output as *const _ as *mut _;
u32_set_bit(p, false, GPIO::INDEX as usize);
}
Ok(())
}
}
impl<GPIO: GpioIndex, PIN> StatefulOutputPin for Gpio<GPIO, PIN, Output> {
fn try_is_set_high(&self) -> Result<bool, Self::Error> {
Ok(unsafe {
let p = &(*pac::GPIO::ptr()).data_output as *const _ as *const _;
u32_bit_is_set(p, GPIO::INDEX as usize)
})
}
fn try_is_set_low(&self) -> Result<bool, Self::Error> {
Ok(unsafe {
let p = &(*pac::GPIO::ptr()).data_output as *const _ as *const _;
u32_bit_is_clear(p, GPIO::INDEX as usize)
})
}
}
impl<GPIO: GpioIndex, PIN> ToggleableOutputPin for Gpio<GPIO, PIN, Output> {
type Error = core::convert::Infallible;
fn try_toggle(&mut self) -> Result<(), Self::Error> {
unsafe {
let p = &(*pac::GPIO::ptr()).data_output as *const _ as *mut _;
u32_toggle_bit(p, GPIO::INDEX as usize);
}
Ok(())
}
}

@ -0,0 +1,346 @@
//! High-speed GPIO peripheral (GPIOHS)
use crate::pac::GPIOHS;
use core::marker::PhantomData;
use crate::bit_utils::{u32_set_bit, u32_toggle_bit, u32_bit_is_set, u32_bit_is_clear};
use embedded_hal::digital::{InputPin, OutputPin};
// todo: verify
/// Floating mode (type state)
pub struct Floating;
/// PullUp mode (type state)
pub struct PullUp;
/// Input mode (type state)
pub struct Input<MODE>(MODE);
/// Output mode (type state)
pub struct Output<MODE>(MODE);
pub trait GpiohsExt {
fn split(self) -> Parts;
}
impl GpiohsExt for GPIOHS {
fn split(self) -> Parts {
Parts {
gpiohs0: Gpiohs0 { _mode: PhantomData },
}
}
}
pub struct Parts {
pub gpiohs0: Gpiohs0<Input<Floating>>,
}
pub struct Gpiohs0<MODE> {
_mode: PhantomData<MODE>,
}
impl<MODE> Gpiohs0<MODE> {
pub fn into_pull_up_input(self) -> Gpiohs0<Input<PullUp>> {
GPIOHS::set_output_en(0, false);
GPIOHS::set_input_en(0, true);
GPIOHS::set_pullup_en(0, true);
Gpiohs0 { _mode: PhantomData }
}
// todo: all modes
}
bitflags::bitflags! {
pub struct Edge: u8 {
const RISING = 0b00000001;
const FALLING = 0b00000010;
const HIGH = 0b00000100;
const LOW = 0b00001000;
}
}
impl<MODE> Gpiohs0<MODE> {
pub fn trigger_on_edge(&mut self, edge: Edge) {
// clear all pending bits
GPIOHS::clear_rise_ip(0);
GPIOHS::clear_fall_ip(0);
GPIOHS::clear_high_ip(0);
GPIOHS::clear_low_ip(0);
// enable interrupts according to flags
GPIOHS::set_rise_ie(0, edge.contains(Edge::RISING));
GPIOHS::set_fall_ie(0, edge.contains(Edge::FALLING));
GPIOHS::set_high_ie(0, edge.contains(Edge::HIGH));
GPIOHS::set_low_ie(0, edge.contains(Edge::LOW));
}
pub fn check_edges(&self) -> Edge {
let mut ans = Edge::empty();
if GPIOHS::has_rise_ip(0) {
ans |= Edge::RISING;
}
if GPIOHS::has_fall_ip(0) {
ans |= Edge::FALLING;
}
if GPIOHS::has_high_ip(0) {
ans |= Edge::HIGH;
}
if GPIOHS::has_low_ip(0) {
ans |= Edge::LOW;
}
ans
}
pub fn clear_interrupt_pending_bits(&mut self) {
if GPIOHS::has_rise_ie(0) {
GPIOHS::set_rise_ie(0, false);
GPIOHS::clear_rise_ip(0);
GPIOHS::set_rise_ie(0, true);
}
if GPIOHS::has_fall_ie(0) {
GPIOHS::set_fall_ie(0, false);
GPIOHS::clear_fall_ip(0);
GPIOHS::set_fall_ie(0, true);
}
if GPIOHS::has_high_ie(0) {
GPIOHS::set_high_ie(0, false);
GPIOHS::clear_high_ip(0);
GPIOHS::set_high_ie(0, true);
}
if GPIOHS::has_low_ie(0) {
GPIOHS::set_low_ie(0, false);
GPIOHS::clear_low_ip(0);
GPIOHS::set_low_ie(0, true);
}
}
}
impl<MODE> InputPin for Gpiohs0<Input<MODE>> {
type Error = core::convert::Infallible;
fn try_is_high(&self) -> Result<bool, Self::Error> {
Ok(unsafe {
let p = &(*GPIOHS::ptr()).input_val as *const _ as *const _;
u32_bit_is_set(p, 0)
})
}
fn try_is_low(&self) -> Result<bool, Self::Error> {
Ok(unsafe {
let p = &(*GPIOHS::ptr()).input_val as *const _ as *const _;
u32_bit_is_clear(p, 0)
})
}
}
impl<MODE> OutputPin for Gpiohs0<Output<MODE>> {
type Error = core::convert::Infallible;
fn try_set_high(&mut self) -> Result<(), Self::Error> {
unsafe {
let p = &(*GPIOHS::ptr()).output_val as *const _ as *mut _;
u32_set_bit(p, true, 0);
}
Ok(())
}
fn try_set_low(&mut self) -> Result<(), Self::Error> {
unsafe {
let p = &(*GPIOHS::ptr()).output_val as *const _ as *mut _;
u32_set_bit(p, false, 0);
}
Ok(())
}
}
trait GpiohsAccess {
fn peripheral() -> &'static mut crate::pac::gpiohs::RegisterBlock;
fn set_drive(index: usize, bit: bool) {
unsafe {
let p = &mut Self::peripheral().drive as *mut _ as *mut _;
u32_set_bit(p, bit, index);
}
}
fn input_value(index: usize) -> bool {
unsafe {
let p = &mut Self::peripheral().input_val as *mut _ as *mut _;
u32_bit_is_set(p, index)
}
}
fn set_input_en(index: usize, bit: bool) {
unsafe {
let p = &mut Self::peripheral().input_en as *mut _ as *mut _;
u32_set_bit(p, bit, index);
}
}
fn set_iof_en(index: usize, bit: bool) {
unsafe {
let p = &mut Self::peripheral().iof_en as *mut _ as *mut _;
u32_set_bit(p, bit, index);
}
}
fn set_iof_sel(index: usize, bit: bool) {
unsafe {
let p = &mut Self::peripheral().iof_sel as *mut _ as *mut _;
u32_set_bit(p, bit, index);
}
}
fn set_output_en(index: usize, bit: bool) {
unsafe {
let p = &mut Self::peripheral().output_en as *mut _ as *mut _;
u32_set_bit(p, bit, index);
}
}
fn set_output_value(index: usize, bit: bool) {
unsafe {
let p = &mut Self::peripheral().output_val as *mut _ as *mut _;
u32_set_bit(p, bit, index);
}
}
fn set_output_xor(index: usize, bit: bool) {
unsafe {
let p = &mut Self::peripheral().output_xor as *mut _ as *mut _;
u32_set_bit(p, bit, index);
}
}
fn toggle_pin(index: usize) {
unsafe {
let p = &mut Self::peripheral().output_val as *mut _ as *mut _;
u32_toggle_bit(p, index);
}
}
fn set_pullup_en(index: usize, bit: bool) {
unsafe {
let p = &mut Self::peripheral().pullup_en as *mut _ as *mut _;
u32_set_bit(p, bit, index);
}
}
fn set_rise_ie(index: usize, bit: bool) {
unsafe {
let p = &mut Self::peripheral().rise_ie as *mut _ as *mut _;
u32_set_bit(p, bit, index);
}
}
fn clear_rise_ip(index: usize) {
unsafe {
let p = &mut Self::peripheral().rise_ip as *mut _ as *mut _;
u32_set_bit(p, true, index);
}
}
fn set_fall_ie(index: usize, bit: bool) {
unsafe {
let p = &mut Self::peripheral().fall_ie as *mut _ as *mut _;
u32_set_bit(p, bit, index);
}
}
fn clear_fall_ip(index: usize) {
unsafe {
let p = &mut Self::peripheral().fall_ip as *mut _ as *mut _;
u32_set_bit(p, true, index);
}
}
fn set_high_ie(index: usize, bit: bool) {
unsafe {
let p = &mut Self::peripheral().high_ie as *mut _ as *mut _;
u32_set_bit(p, bit, index);
}
}
fn clear_high_ip(index: usize,) {
unsafe {
let p = &mut Self::peripheral().high_ip as *mut _ as *mut _;
u32_set_bit(p, true, index);
}
}
fn set_low_ie(index: usize, bit: bool) {
unsafe {
let p = &mut Self::peripheral().low_ie as *mut _ as *mut _;
u32_set_bit(p, bit, index);
}
}
fn clear_low_ip(index: usize) {
unsafe {
let p = &mut Self::peripheral().low_ip as *mut _ as *mut _;
u32_set_bit(p, true, index);
}
}
fn has_rise_ie(index: usize) -> bool {
unsafe {
let p = &mut Self::peripheral().rise_ie as *mut _ as *mut _;
u32_bit_is_set(p, index)
}
}
fn has_fall_ie(index: usize) -> bool {
unsafe {
let p = &mut Self::peripheral().fall_ie as *mut _ as *mut _;
u32_bit_is_set(p, index)
}
}
fn has_high_ie(index: usize) -> bool {
unsafe {
let p = &mut Self::peripheral().high_ie as *mut _ as *mut _;
u32_bit_is_set(p, index)
}
}
fn has_low_ie(index: usize) -> bool {
unsafe {
let p = &mut Self::peripheral().low_ie as *mut _ as *mut _;
u32_bit_is_set(p, index)
}
}
fn has_rise_ip(index: usize) -> bool {
unsafe {
let p = &mut Self::peripheral().rise_ip as *mut _ as *mut _;
u32_bit_is_set(p, index)
}
}
fn has_fall_ip(index: usize) -> bool {
unsafe {
let p = &mut Self::peripheral().fall_ip as *mut _ as *mut _;
u32_bit_is_set(p, index)
}
}
fn has_high_ip(index: usize) -> bool {
unsafe {
let p = &mut Self::peripheral().high_ip as *mut _ as *mut _;
u32_bit_is_set(p, index)
}
}
fn has_low_ip(index: usize) -> bool {
unsafe {
let p = &mut Self::peripheral().low_ip as *mut _ as *mut _;
u32_bit_is_set(p, index)
}
}
}
impl GpiohsAccess for GPIOHS {
fn peripheral() -> &'static mut crate::pac::gpiohs::RegisterBlock {
unsafe { &mut *(GPIOHS::ptr() as *mut _) }
}
}

@ -0,0 +1,67 @@
//! HAL for the K210 SoC
//!
//! This is an implementation of the [`embedded-hal`] traits for the K210 SoC
// #![deny(missing_docs)] // uncomment for every releases
#![no_std]
pub use k210_pac as pac;
pub mod aes;
pub mod apu;
pub mod cache;
pub mod clint;
pub mod clock;
pub mod dmac;
pub mod fft;
pub mod fpioa;
pub mod gpio;
pub mod gpiohs;
pub mod plic;
pub mod serial;
pub mod spi;
pub mod sha256;
pub mod stdout;
pub mod sysctl;
pub mod time;
/// Prelude
pub mod prelude {
pub use embedded_hal::prelude::*;
pub use crate::serial::SerialExt as _k210_hal_serial_SerialExt;
pub use crate::stdout::Write as _k210_hal_stdout_Write;
pub use crate::time::U32Ext as _k210_hal_time_U32Ext;
pub use crate::fpioa::FpioaExt as _k210_hal_fpioa_FpioaExt;
pub use crate::sysctl::SysctlExt as _k210_hal_sysctl_SysctlExt;
pub use crate::gpio::GpioExt as _k210_hal_gpio_GpioExt;
pub use crate::gpiohs::GpiohsExt as _k210_hal_gpiohs_GpiohsExt;
pub use crate::plic::PlicExt as _k210_hal_plic_PlicExt;
}
mod bit_utils {
#[inline(always)]
pub(crate) unsafe fn u32_set_bit(p: *mut u32, bit: bool, index: usize) {
let mask = 1 << index;
if bit {
*p |= mask;
} else {
*p &= !mask;
}
}
#[inline(always)]
pub(crate) unsafe fn u32_toggle_bit(p: *mut u32, index: usize) {
let mask = 1 << index;
*p ^= mask;
}
#[inline(always)]
pub(crate) unsafe fn u32_bit_is_set(r: *const u32, index: usize) -> bool {
(*r & 1 << index) != 0
}
#[inline(always)]
pub(crate) unsafe fn u32_bit_is_clear(r: *const u32, index: usize) -> bool {
(*r & 1 << index) == 0
}
}

@ -0,0 +1,239 @@
//! Platform-Level Interrupt Controller (PLIC)
// I don't know if this part should be implemented in runtime
// keep by now, may be replaced on further designs
// #[doc(hidden)]
// #[link_name = "MachineExternal"]
// pub extern fn machine_external() {
// }
use crate::pac::{PLIC, Interrupt};
/// Extension trait for PLIC interrupt controller peripheral
pub trait PlicExt {
/// Interrupt wrapper type
type Interrupt: Nr;
/// Is this M-Mode interrupt enabled on given hart?
fn is_enabled(hart_id: usize, interrupt: Self::Interrupt) -> bool;
/// Enable an interrupt for a given hart
unsafe fn unmask(hart_id: usize, interrupt: Self::Interrupt);
/// Disable an interrupt for a given hart
fn mask(hart_id: usize, interrupt: Self::Interrupt);
/// Get global priority for one interrupt
fn get_priority(interrupt: Self::Interrupt) -> Priority;
/// Globally set priority for one interrupt
unsafe fn set_priority(interrupt: Self::Interrupt, prio: Priority);
/// Get priority threshold for a given hart
fn get_threshold(hart_id: usize) -> Priority;
/// Set the priority threshold for a given hart
unsafe fn set_threshold(hart_id: usize, threshold: Priority);
/// Mark that given hart have claimed to handle this interrupt
fn claim(hart_id: usize) -> Option<Self::Interrupt>;
/// Mark that given hart have completed handling this interrupt
fn complete(hart_id: usize, interrupt: Self::Interrupt);
/// Is this interrupt claimed and under procceeding?
fn is_pending(interrupt: Self::Interrupt) -> bool;
}
impl PlicExt for PLIC {
type Interrupt = Interrupt;
fn is_enabled(hart_id: usize, interrupt: Interrupt) -> bool {
let irq_number = interrupt.into_bits() as usize;
unsafe {
(*PLIC::ptr()).target_enables[hart_id].enable[irq_number / 32]
.read().bits() & 1 << (irq_number % 32) != 0
}
}
unsafe fn unmask(hart_id: usize, interrupt: Interrupt) {
let irq_number = interrupt.into_bits() as usize;
(*PLIC::ptr()).target_enables[hart_id].enable[irq_number / 32]
.modify(|r, w|
w.bits(r.bits() | 1 << (irq_number % 32)));
}
fn mask(hart_id: usize, interrupt: Interrupt) {
let irq_number = interrupt.into_bits() as usize;
unsafe {
(*PLIC::ptr()).target_enables[hart_id].enable[irq_number / 32]
.modify(|r, w|
w.bits(r.bits() & !(1 << (irq_number % 32))));
}
}
fn get_priority(interrupt: Interrupt) -> Priority {
let irq_number = interrupt.into_bits() as usize;
let bits = unsafe {
(*PLIC::ptr()).priority[irq_number].read().bits()
};
Priority::from_bits(bits)
}
unsafe fn set_priority(interrupt: Interrupt, prio: Priority) {
let irq_number = interrupt.into_bits() as usize;
(*PLIC::ptr()).priority[irq_number].write(
|w|
w.bits(prio.into_bits()));
}
fn get_threshold(hart_id: usize) -> Priority {
let bits = unsafe {
(*PLIC::ptr()).targets[hart_id].threshold.read().bits()
};
Priority::from_bits(bits)
}
unsafe fn set_threshold(hart_id: usize, threshold: Priority) {
(*PLIC::ptr()).targets[hart_id].threshold.write(
|w|
w.bits(threshold.into_bits()));
}
fn claim(hart_id: usize) -> Option<Interrupt> {
let bits = unsafe {
(*PLIC::ptr()).targets[hart_id].claim.read().bits()
};
Nr::from_bits(bits)
}
fn complete(hart_id: usize, interrupt: Interrupt) {
unsafe {
(*PLIC::ptr()).targets[hart_id].claim.write(
|w|
w.bits(interrupt.into_bits()));
}
}
fn is_pending(interrupt: Interrupt) -> bool {
let irq_number = interrupt.into_bits() as usize;
unsafe {
(*PLIC::ptr()).pending[irq_number / 32]
.read().bits() & 1 << (irq_number % 32) != 0
}
}
}
impl Nr for Interrupt {
fn into_bits(&self) -> u32 {
*self as u8 as u32
}
fn from_bits(bits: u32) -> Option<Self> {
use Interrupt::*;
match bits {
0 => None,
1 => Some(SPI0),
2 => Some(SPI1),
3 => Some(SPI_SLAVE),
4 => Some(SPI3),
5 => Some(I2S0),
6 => Some(I2S1),
7 => Some(I2S2),
8 => Some(I2C0),
9 => Some(I2C1),
10 => Some(I2C2),
11 => Some(UART1),
12 => Some(UART2),
13 => Some(UART3),
14 => Some(TIMER0A),
15 => Some(TIMER0B),
16 => Some(TIMER1A),
17 => Some(TIMER1B),
18 => Some(TIMER2A),
19 => Some(TIMER2B),
20 => Some(RTC),
21 => Some(WDT0),
22 => Some(WDT1),
23 => Some(APB_GPIO),
24 => Some(DVP),
25 => Some(KPU),
26 => Some(FFT),
27 => Some(DMA0),
28 => Some(DMA1),
29 => Some(DMA2),
30 => Some(DMA3),
31 => Some(DMA4),
32 => Some(DMA5),
33 => Some(UARTHS),
34 => Some(GPIOHS0),
35 => Some(GPIOHS1),
36 => Some(GPIOHS2),
37 => Some(GPIOHS3),
38 => Some(GPIOHS4),
39 => Some(GPIOHS5),
40 => Some(GPIOHS6),
41 => Some(GPIOHS7),
42 => Some(GPIOHS8),
43 => Some(GPIOHS9),
44 => Some(GPIOHS10),
45 => Some(GPIOHS11),
46 => Some(GPIOHS12),
47 => Some(GPIOHS13),
48 => Some(GPIOHS14),
49 => Some(GPIOHS15),
50 => Some(GPIOHS16),
51 => Some(GPIOHS17),
52 => Some(GPIOHS18),
53 => Some(GPIOHS19),
54 => Some(GPIOHS20),
55 => Some(GPIOHS21),
56 => Some(GPIOHS22),
57 => Some(GPIOHS23),
58 => Some(GPIOHS24),
59 => Some(GPIOHS25),
60 => Some(GPIOHS26),
61 => Some(GPIOHS27),
62 => Some(GPIOHS28),
63 => Some(GPIOHS29),
64 => Some(GPIOHS30),
65 => Some(GPIOHS31),
_ => panic!("invalid interrupt bits")
}
}
}
#[doc(hidden)]
pub trait Nr: Sized {
fn into_bits(&self) -> u32;
fn from_bits(bits: u32) -> Option<Self>;
}
/// Priority of an interrupt
#[derive(Clone, Copy, Debug)]
pub enum Priority {
/// Priority 0: Never interrupt
P0,
/// Priority 1: Lowest active priority
P1,
/// Priority 2
P2,
/// Priority 3
P3,
/// Priority 4
P4,
/// Priority 5
P5,
/// Priority 6
P6,
/// Priority 7: Highest priority
P7,
}
impl Priority {
fn into_bits(self) -> u32 {
match self {
Priority::P0 => 0,
Priority::P1 => 1,
Priority::P2 => 2,
Priority::P3 => 3,
Priority::P4 => 4,
Priority::P5 => 5,
Priority::P6 => 6,
Priority::P7 => 7,
}
}
fn from_bits(prio: u32) -> Priority {
match prio {
0 => Priority::P0,
1 => Priority::P1,
2 => Priority::P2,
3 => Priority::P3,
4 => Priority::P4,
5 => Priority::P5,
6 => Priority::P6,
7 => Priority::P7,
_ => panic!("Invalid priority"),
}
}
}

@ -0,0 +1,235 @@
//! Serial interface
//!
//! You can use the `Serial` interface with these UART instances:
//! * [`UARTHS`](crate::pac::UARTHS)
//! * [`UART1`](crate::pac::UART1)
//! * [`UART2`](crate::pac::UART2)
//! * [`UART3`](crate::pac::UART3)
use core::mem;
use core::convert::Infallible;
use embedded_hal::serial;
use crate::pac::{UARTHS,uart1,UART1,UART2,UART3};
use crate::clock::Clocks;
use crate::time::Bps;
/// Extension trait that constrains UART peripherals
pub trait SerialExt: Sized {
/// Configures a UART peripheral to provide serial communication
fn configure(self, baud_rate: Bps, clocks: &Clocks) -> Serial<Self>;
}
/// Serial abstraction
pub struct Serial<UART> {
uart: UART,
}
impl<UART> Serial<UART> {
/// Splits the `Serial` abstraction into a transmitter and a
/// receiver half
pub fn split(self) -> (Tx<UART>, Rx<UART>) {
(
Tx {
uart: self.uart,
},
Rx {
uart: unsafe { mem::MaybeUninit::uninit().assume_init() },
}
)
}
/// Forms `Serial` abstraction from a transmitter and a
/// receiver half
pub fn join(tx: Tx<UART>, rx: Rx<UART>) -> Self {
let _ = rx; // note(discard): Zero-sized typestate struct
Serial { uart: tx.uart }
}
/// Releases the UART peripheral
pub fn free(self) -> UART {
// todo: power down this UART
self.uart
}
}
/// Serial transmitter
pub struct Tx<UART> {
uart: UART,
}
/// Serial receiver
pub struct Rx<UART> {
uart: UART,
}
impl SerialExt for UARTHS {
fn configure(self, baud_rate: Bps, clocks: &Clocks) -> Serial<UARTHS>
{
let uart = self;
let div = clocks.cpu().0 / baud_rate.0 - 1;
unsafe {
uart.div.write(|w| w.bits(div));
}
uart.txctrl.write(|w| w.txen().bit(true));
uart.rxctrl.write(|w| w.rxen().bit(true));
Serial { uart }
}
}
impl Serial<UARTHS> {
/// Starts listening for an interrupt event
pub fn listen(self) -> Self {
self.uart.ie.write(|w| w.txwm().bit(false).rxwm().bit(true));
self
}
/// Stops listening for an interrupt event
pub fn unlisten(self) -> Self {
self.uart
.ie
.write(|w| w.txwm().bit(false).rxwm().bit(false));
self
}
}
impl serial::Read<u8> for Rx<UARTHS> {
type Error = Infallible;
fn try_read(&mut self) -> nb::Result<u8, Infallible> {
let rxdata = self.uart.rxdata.read();
if rxdata.empty().bit_is_set() {
Err(nb::Error::WouldBlock)
} else {
Ok(rxdata.data().bits() as u8)
}
}
}
impl serial::Write<u8> for Tx<UARTHS> {
type Error = Infallible;
fn try_write(&mut self, byte: u8) -> nb::Result<(), Infallible> {
let txdata = self.uart.txdata.read();
if txdata.full().bit_is_set() {
Err(nb::Error::WouldBlock)
} else {
unsafe {
(*UARTHS::ptr()).txdata.write(|w| w.data().bits(byte));
}
Ok(())
}
}
fn try_flush(&mut self) -> nb::Result<(), Infallible> {
let txdata = self.uart.txdata.read();
if txdata.full().bit_is_set() {
Err(nb::Error::WouldBlock)
} else {
Ok(())
}
}
}
mod closed_trait {
use core::ops::Deref;
/// Trait to be able to generalize over UART1/UART2/UART3
pub trait UartX: Deref<Target = super::uart1::RegisterBlock> {
const INDEX: u8;
}
}
use closed_trait::UartX;
impl UartX for UART1 { const INDEX: u8 = 1; }
impl UartX for UART2 { const INDEX: u8 = 2; }
impl UartX for UART3 { const INDEX: u8 = 3; }
const UART_RECEIVE_FIFO_1: u32 = 0;
const UART_SEND_FIFO_8: u32 = 3;
impl<UART: UartX> SerialExt for UART {
fn configure(self, baud_rate: Bps, clocks: &Clocks) -> Serial<UART> {
let uart = self;
// Hardcode these for now:
let data_width = 8; // 8 data bits
let stopbit_val = 0; // 1 stop bit
let parity_val = 0; // No parity
// Note: need to make sure that UARTx clock is enabled through sysctl before here
let divisor = clocks.apb0().0 / baud_rate.0;
let dlh = ((divisor >> 12) & 0xff) as u8;
let dll = ((divisor >> 4) & 0xff) as u8;
let dlf = (divisor & 0xf) as u8;
unsafe {
// Set Divisor Latch Access Bit (enables DLL DLH) to set baudrate
uart.lcr.write(|w| w.bits(1 << 7));
uart.dlh_ier.write(|w| w.bits(dlh.into()));
uart.rbr_dll_thr.write(|w| w.bits(dll.into()));
uart.dlf.write(|w| w.bits(dlf.into()));
// Clear Divisor Latch Access Bit after setting baudrate
uart.lcr.write(|w| w.bits((data_width - 5) | (stopbit_val << 2) | (parity_val << 3)));
// Write IER
uart.dlh_ier.write(|w| w.bits(0x80)); /* THRE */
// Write FCT
uart.fcr_iir.write(|w| w.bits(UART_RECEIVE_FIFO_1 << 6 | UART_SEND_FIFO_8 << 4 | 0x1 << 3 | 0x1));
}
Serial { uart }
}
}
impl<UART: UartX> Serial<UART> {
/// Starts listening for an interrupt event
pub fn listen(self) -> Self {
self
}
/// Stops listening for an interrupt event
pub fn unlisten(self) -> Self {
self
}
}
impl<UART: UartX> serial::Read<u8> for Rx<UART> {
type Error = Infallible;
fn try_read(&mut self) -> nb::Result<u8, Infallible> {
let lsr = self.uart.lsr.read();
if (lsr.bits() & (1<<0)) == 0 { // Data Ready bit
Err(nb::Error::WouldBlock)
} else {
let rbr = self.uart.rbr_dll_thr.read();
Ok((rbr.bits() & 0xff) as u8)
}
}
}
impl<UART: UartX> serial::Write<u8> for Tx<UART> {
type Error = Infallible;
fn try_write(&mut self, byte: u8) -> nb::Result<(), Infallible> {
let lsr = self.uart.lsr.read();
if (lsr.bits() & (1<<5)) != 0 { // Transmit Holding Register Empty bit
Err(nb::Error::WouldBlock)
} else {
unsafe {
self.uart.rbr_dll_thr.write(|w| w.bits(byte.into()));
}
Ok(())
}
}
fn try_flush(&mut self) -> nb::Result<(), Infallible> {
// TODO
Ok(())
}
}

@ -0,0 +1,52 @@
//! Secure Hash Algorithm-256 (SHA256)
use crate::pac::SHA256;
use crate::sysctl::{self, APB0};
/// SHA256 module abstraction
pub struct Sha256 {
sha256: SHA256,
}
impl Sha256 {
pub fn sha256(sha256: SHA256, apb0: &mut APB0) -> Sha256 {
apb0.enable();
sysctl::clk_en_peri().modify(|_r, w|
w.sha_clk_en().set_bit());
sysctl::peri_reset().modify(|_r, w|
w.sha_reset().set_bit());
sysctl::peri_reset().modify(|_r, w|
w.sha_reset().clear_bit());
Sha256 { sha256 }
}
pub fn new_digest(self) -> Digest {
todo!()
}
pub fn release(self) -> SHA256 {
sysctl::clk_en_peri().modify(|_r, w|
w.sha_clk_en().clear_bit());
self.sha256
}
}
pub struct Digest {
sha256: SHA256,
}
impl Digest {
pub fn write_u32(&mut self, n: u32) {
let _todo = n;
todo!()
}
pub fn finish(&self, out: &mut [u8; 32]) {
let _todo = out;
todo!()
}
pub fn free(self) -> Sha256 {
Sha256 { sha256: self.sha256 }
}
}

@ -0,0 +1,122 @@
//! (TODO) Serial Peripheral Interface (SPI)
use crate::pac::SPI0;
use crate::clock::Clocks;
use crate::sysctl::{self, APB0};
pub use embedded_hal::spi::{Mode, Polarity, Phase};
use core::convert::Infallible;
///
pub struct Spi<SPI> {
spi: SPI
}
impl Spi<SPI0> {
pub fn spi0(
spi: SPI0,
mode: Mode,
frame_format: FrameFormat,
endian: Endian,
clock: &Clocks,
apb0: &mut APB0
) -> Self {
let work_mode = hal_mode_to_pac(mode);
let frame_format = frame_format_to_pac(frame_format);
let tmod = crate::pac::spi0::ctrlr0::TMOD_A::TRANS_RECV; // todo other modes
let endian = endian as u32;
let data_bit_length = 8; // todo more length
let _ = clock; // todo
unsafe {
// no interrupts for now
spi.imr.write(|w| w.bits(0x00));
// no dma for now
spi.dmacr.write(|w| w.bits(0x00));
spi.dmatdlr.write(|w| w.bits(0x10));
spi.dmardlr.write(|w| w.bits(0x00));
// no slave access for now
spi.ser.write(|w| w.bits(0x00));
spi.ssienr.write(|w| w.bits(0x00));
// set control registers
spi.ctrlr0.write(|w| {
w.work_mode()
.variant(work_mode)
.tmod()
.variant(tmod)
.frame_format()
.variant(frame_format)
.data_length()
.bits(data_bit_length - 1)
});
spi.spi_ctrlr0.reset(); // standard
spi.endian.write(|w| w.bits(endian));
}
// enable APB0 bus
apb0.enable();
// enable peripheral via sysctl
sysctl::clk_en_peri().modify(|_r, w|
w.spi0_clk_en().set_bit());
Spi { spi }
}
pub fn release(self) -> SPI0 {
// power off
sysctl::clk_en_peri().modify(|_r, w|
w.spi0_clk_en().clear_bit());
self.spi
}
}
impl embedded_hal::spi::FullDuplex<u8> for Spi<SPI0> {
/// An enumeration of SPI errors
type Error = Infallible;
/// Reads the word stored in the shift register
///
/// **NOTE** A word must be sent to the slave before attempting to call this
/// method.
fn try_read(&mut self) -> nb::Result<u8, Self::Error> {
todo!()
}
/// Sends a word to the slave
fn try_send(&mut self, word: u8) -> nb::Result<(), Self::Error> {
todo!("{}", word)
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum FrameFormat {
Standard,
Dual,
Quad,
Octal,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum Endian {
Little = 0,
Big = 1,
}
#[inline]
fn hal_mode_to_pac(mode: Mode) -> crate::pac::spi0::ctrlr0::WORK_MODE_A {
use crate::pac::spi0::ctrlr0::WORK_MODE_A;
use {Polarity::*, Phase::*};
match (mode.polarity, mode.phase) {
(IdleLow, CaptureOnFirstTransition) => WORK_MODE_A::MODE0,
(IdleLow, CaptureOnSecondTransition) => WORK_MODE_A::MODE1,
(IdleHigh, CaptureOnFirstTransition) => WORK_MODE_A::MODE2,
(IdleHigh, CaptureOnSecondTransition) => WORK_MODE_A::MODE3,
}
}
#[inline]
fn frame_format_to_pac(frame_format: FrameFormat) -> crate::pac::spi0::ctrlr0::FRAME_FORMAT_A {
use crate::pac::spi0::ctrlr0::FRAME_FORMAT_A;
match frame_format {
FrameFormat::Standard => FRAME_FORMAT_A::STANDARD,
FrameFormat::Dual => FRAME_FORMAT_A::DUAL,
FrameFormat::Quad => FRAME_FORMAT_A::QUAD,
FrameFormat::Octal => FRAME_FORMAT_A::OCTAL,
}
}

@ -0,0 +1,31 @@
//! Stdout
pub use core::fmt::Write;
use nb::block;
/// Stdout implements the core::fmt::Write trait for hal::serial::Write
/// implementations.
pub struct Stdout<'p, T>(pub &'p mut T);
impl<'p, T> Write for Stdout<'p, T>
where
T: embedded_hal::serial::Write<u8>,
{
fn write_str(&mut self, s: &str) -> core::fmt::Result {
for byte in s.as_bytes() {
if *byte == b'\n' {
let res = block!(self.0.try_write(b'\r'));
if res.is_err() {
return Err(core::fmt::Error);
}
}
let res = block!(self.0.try_write(*byte));
if res.is_err() {
return Err(core::fmt::Error);
}
}
Ok(())
}
}

@ -0,0 +1,61 @@
//! (TODO) System Controller (SYSCTL)
use crate::pac::{sysctl, SYSCTL};
pub(crate) fn sysctl<'a>() -> &'a sysctl::RegisterBlock {
unsafe { &*(SYSCTL::ptr()) }
}
pub(crate) fn clk_en_cent<'a>() -> &'a sysctl::CLK_EN_CENT {
&sysctl().clk_en_cent
}
pub(crate) fn clk_en_peri<'a>() -> &'a sysctl::CLK_EN_PERI {
&sysctl().clk_en_peri
}
pub(crate) fn peri_reset<'a>() -> &'a sysctl::PERI_RESET {
&sysctl().peri_reset
}
pub trait SysctlExt {
fn constrain(self) -> Parts;
}
impl SysctlExt for SYSCTL {
fn constrain(self) -> Parts {
Parts {
apb0: APB0 { _ownership: () },
}
}
}
// ref: sysctl.c
pub struct Parts {
// todo: PLL0, PLL1, PLL2
// todo: CPU, SRAM, APB-bus, ROM, DMA, AI
pub apb0: APB0,
// pub apb1: APB1,
// pub apb2: APB2,
}
pub struct APB0 {
_ownership: ()
}
impl APB0 {
pub(crate) fn enable(&mut self) {
clk_en_cent().modify(
|_r, w|
w.apb0_clk_en().set_bit()
);
}
}
// pub struct APB1 {
// _ownership: ()
// }
// pub struct APB2 {
// _ownership: ()
// }

@ -0,0 +1,68 @@
//! Time units
/// Bits per second
#[derive(Clone, Copy)]
pub struct Bps(pub u32);
/// Hertz
#[derive(Clone, Copy)]
pub struct Hertz(pub u32);
/// KiloHertz
#[derive(Clone, Copy)]
pub struct KiloHertz(pub u32);
/// MegaHertz
#[derive(Clone, Copy)]
pub struct MegaHertz(pub u32);
/// Extension trait that adds convenience methods to the `u32` type
pub trait U32Ext {
/// Wrap in `Bps`
fn bps(self) -> Bps;
/// Wrap in `Hertz`
fn hz(self) -> Hertz;
/// Wrap in `KiloHertz`
fn khz(self) -> KiloHertz;
/// Wrap in `MegaHertz`
fn mhz(self) -> MegaHertz;
}
impl U32Ext for u32 {
fn bps(self) -> Bps {
Bps(self)
}
fn hz(self) -> Hertz {
Hertz(self)
}
fn khz(self) -> KiloHertz {
KiloHertz(self)
}
fn mhz(self) -> MegaHertz {
MegaHertz(self)
}
}
impl Into<Hertz> for KiloHertz {
fn into(self) -> Hertz {
Hertz(self.0 * 1_000)
}
}
impl Into<Hertz> for MegaHertz {
fn into(self) -> Hertz {
Hertz(self.0 * 1_000_000)
}
}
impl Into<KiloHertz> for MegaHertz {
fn into(self) -> KiloHertz {
KiloHertz(self.0 * 1_000)
}
}

@ -0,0 +1,3 @@
/target
**/*.rs.bk
Cargo.lock

@ -0,0 +1,28 @@
language: rust
env:
- TARGET=x86_64-unknown-linux-gnu
- TARGET=riscv64gc-unknown-none-elf
rust:
- nightly
- stable
if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master)
install:
- ci/install.sh
script:
- ci/script.sh
branches:
only:
- master
- staging
- trying
notifications:
email:
on_success: never

@ -0,0 +1,37 @@
# The Rust Code of Conduct
## Conduct
**Contact**: [RISC-V team](https://github.com/rust-embedded/wg#the-riscv-team)
* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all.
* Please be kind and courteous. There's no need to be mean or rude.
* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [RISC-V team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
## Moderation
These are the policies for upholding our community's standards of conduct.
1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
3. Moderators will first respond to such remarks with a warning.
4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off.
5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed.
8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others.
In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely.
And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust.
The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org).
*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).*
[team]: https://github.com/rust-embedded/wg#the-riscv-team

@ -0,0 +1,19 @@
[package]
name = "k210-pac"
version = "0.2.0"
authors = ["The RISC-V Team <risc-v@teams.rust-embedded.org>"]
categories = ["embedded", "hardware-support", "no-std"]
description = "Peripheral access API for K210 SoC"
repository = "https://github.com/riscv-rust/k210-pac"
keywords = ["riscv", "k210", "register", "peripheral"]
license = "ISC"
edition = "2018"
[dependencies]
bare-metal = "0.2.4"
riscv = "0.6.0"
riscv-rt = { version = "0.8", optional = true }
vcell = "0.1.2"
[features]
rt = ["riscv-rt"]

@ -0,0 +1,36 @@
[![crates.io](https://img.shields.io/crates/d/k210-pac.svg)](https://crates.io/crates/k210-pac)
[![crates.io](https://img.shields.io/crates/v/k210-pac.svg)](https://crates.io/crates/k210-pac)
[![Build Status](https://travis-ci.org/riscv-rust/k210-pac.svg?branch=master)](https://travis-ci.org/riscv-rust/k210-pac)
# `k210-pac`
> Peripheral access API for K210 SoC
This project is developed and maintained by the [RISC-V team][team].
## [Documentation](https://docs.rs/crate/k210-pac)
## License
Copyright 2019 [RISC-V team][team]
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
## Code of Conduct
Contribution to this crate is organized under the terms of the [Rust Code of
Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises
to intervene to uphold that code of conduct.
[CoC]: CODE_OF_CONDUCT.md
[team]: https://github.com/rust-embedded/wg#the-risc-v-team

@ -0,0 +1,15 @@
use std::io::Write;
use std::path::PathBuf;
use std::{env, fs};
fn main() {
// Put the linker script somewhere the linker can find it
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
println!("cargo:rustc-link-search={}", out_dir.display());
fs::File::create(out_dir.join("memory-k210.x"))
.unwrap()
.write_all(include_bytes!("memory-k210.x"))
.unwrap();
println!("cargo:rerun-if-changed=memory-k210.x");
}

@ -0,0 +1,5 @@
#!/bin/bash
set -euxo pipefail
rustup target add $TARGET

@ -0,0 +1,6 @@
#!/bin/bash
set -euxo pipefail
cargo check --target $TARGET
cargo check --target $TARGET --features rt

File diff suppressed because it is too large Load Diff

@ -0,0 +1,9 @@
_max_hart_id = 1;
MEMORY
{
SRAM : ORIGIN = 0x80000000, LENGTH = 6M
AI_SRAM : ORIGIN = 0x80600000, LENGTH = 2M
SRAM_NOCACHE : ORIGIN = 0x40000000, LENGTH = 6M
AI_SRAM_NOCACHE : ORIGIN = 0x40600000, LENGTH = 2M
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -x
set -e
rm -rf src
mkdir src
svd2rust --target riscv -i k210.svd
mv lib.rs src/
cargo fmt

@ -0,0 +1,3 @@
/target
Cargo.lock
.idea/

@ -0,0 +1,12 @@
[package]
name = "k210-soc"
version = "0.1.0"
authors = ["Yifan Wu <shinbokuow@163.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
k210-hal = { path = "../k210-hal" }
k210-pac = { path = "../k210-pac" }
riscv = { path = "../riscv", features = ["inline-asm"] }

@ -0,0 +1 @@
From [here](https://github.com/laanwj/k210-sdk-stuff/tree/master/rust/k210-shared/src/soc).

@ -0,0 +1,637 @@
#![allow(unused)]
#![allow(non_camel_case_types)]
//! DMAC peripheral
//use k210_hal::pac;
use k210_pac as pac;
use pac::dmac::channel::cfg::{TT_FC_A,HS_SEL_SRC_A};
use pac::dmac::channel::ctl::{SMS_A};
use super::sysctl;
/** Extension trait for adding configure() to DMAC peripheral */
pub trait DMACExt: Sized {
/// Constrains DVP peripheral
fn configure(self) -> DMAC;
}
impl DMACExt for pac::DMAC {
fn configure(self) -> DMAC { DMAC::new(self) }
}
/** DMAC peripheral abstraction */
pub struct DMAC {
dmac: pac::DMAC,
}
/*
typedef struct _dmac_context
{
dmac_channel_number_t dmac_channel;
plic_irq_callback_t callback;
void *ctx;
} dmac_context_t;
dmac_context_t dmac_context[6];
*/
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum src_dst_select {
SRC = 0x1,
DST = 0x2,
SRC_DST = 0x3,
}
pub use super::sysctl::dma_channel;
pub type master_number = pac::dmac::channel::ctl::SMS_A;
pub type address_increment = pac::dmac::channel::ctl::SINC_A;
pub type burst_length = pac::dmac::channel::ctl::SRC_MSIZE_A;
pub type transfer_width = pac::dmac::channel::ctl::SRC_TR_WIDTH_A;
/** Return whether a specific address considered considered memory or peripheral */
fn is_memory(address: u64) -> bool {
let mem_len = 6 * 1024 * 1024;
let mem_no_cache_len = 8 * 1024 * 1024;
// Note: This comes from the Kendryte SDK as-is. No, I have no idea why the AES accelerator
// input address 0x50450040 is considered memory, either.
((address >= 0x80000000) && (address < 0x80000000 + mem_len))
|| ((address >= 0x40000000) && (address < 0x40000000 + mem_no_cache_len))
|| (address == 0x50450040)
}
impl DMAC {
fn new(dmac: pac::DMAC) -> Self {
let rv = Self { dmac };
rv.init();
rv
}
/** Get DMAC ID */
pub fn read_id(&self) -> u64 {
return self.dmac.id.read().bits();
}
/** Get DMAC version */
pub fn read_version(&self) -> u64 {
return self.dmac.compver.read().bits();
}
/** Get AXI ID for channel */
pub fn read_channel_id(&self, channel_num: dma_channel) -> u64 {
return self.dmac.channel[channel_num.idx()].axi_id.read().bits();
}
/** Enable DMAC peripheral. */
fn enable(&self) {
self.dmac.cfg.modify(|_,w| w.dmac_en().set_bit()
.int_en().set_bit());
}
/** Disable DMAC peripheral. */
pub fn disable(&self) {
self.dmac.cfg.modify(|_,w| w.dmac_en().clear_bit()
.int_en().clear_bit());
}
pub fn src_transaction_complete_int_enable(&self, channel_num: dma_channel) {
self.dmac.channel[channel_num.idx()].intstatus_en.modify(
|_,w| w.src_transcomp().set_bit());
}
/** Enable a DMA channel. */
pub fn channel_enable(&self, channel_num: dma_channel) {
use dma_channel::*;
// Note: chX bit names start counting from 1, while channels start counting from 0
match channel_num {
CHANNEL0 => {
self.dmac.chen.modify(|_,w| w.ch1_en().set_bit()
.ch1_en_we().set_bit());
}
CHANNEL1 => {
self.dmac.chen.modify(|_,w| w.ch2_en().set_bit()
.ch2_en_we().set_bit());
}
CHANNEL2 => {
self.dmac.chen.modify(|_,w| w.ch3_en().set_bit()
.ch3_en_we().set_bit());
}
CHANNEL3 => {
self.dmac.chen.modify(|_,w| w.ch4_en().set_bit()
.ch4_en_we().set_bit());
}
CHANNEL4 => {
self.dmac.chen.modify(|_,w| w.ch5_en().set_bit()
.ch5_en_we().set_bit());
}
CHANNEL5 => {
self.dmac.chen.modify(|_,w| w.ch6_en().set_bit()
.ch6_en_we().set_bit());
}
}
}
/** Disable a DMA channel. */
pub fn channel_disable(&self, channel_num: dma_channel) {
use dma_channel::*;
// Note: chX bit names start counting from 1, while channels start counting from 0
match channel_num {
CHANNEL0 => {
self.dmac.chen.modify(|_,w| w.ch1_en().clear_bit()
.ch1_en_we().set_bit());
}
CHANNEL1 => {
self.dmac.chen.modify(|_,w| w.ch2_en().clear_bit()
.ch2_en_we().set_bit());
}
CHANNEL2 => {
self.dmac.chen.modify(|_,w| w.ch3_en().clear_bit()
.ch3_en_we().set_bit());
}
CHANNEL3 => {
self.dmac.chen.modify(|_,w| w.ch4_en().clear_bit()
.ch4_en_we().set_bit());
}
CHANNEL4 => {
self.dmac.chen.modify(|_,w| w.ch5_en().clear_bit()
.ch5_en_we().set_bit());
}
CHANNEL5 => {
self.dmac.chen.modify(|_,w| w.ch6_en().clear_bit()
.ch6_en_we().set_bit());
}
}
}
/** Check if a DMA channel is busy. */
pub fn check_channel_busy(&self, channel_num: dma_channel) -> bool {
use dma_channel::*;
match channel_num {
CHANNEL0 => self.dmac.chen.read().ch1_en().bit(),
CHANNEL1 => self.dmac.chen.read().ch2_en().bit(),
CHANNEL2 => self.dmac.chen.read().ch3_en().bit(),
CHANNEL3 => self.dmac.chen.read().ch4_en().bit(),
CHANNEL4 => self.dmac.chen.read().ch5_en().bit(),
CHANNEL5 => self.dmac.chen.read().ch6_en().bit(),
}
// Note: Kendryte SDK writes back the value after reading it,
// is this necessary? It seems not.
}
pub fn set_list_master_select(&self, channel_num: dma_channel, sd_sel: src_dst_select, mst_num: master_number) -> Result<(),()> {
if !self.check_channel_busy(channel_num) {
use src_dst_select::*;
self.dmac.channel[channel_num.idx()].ctl.modify(|_,w| {
let w = if sd_sel == SRC || sd_sel == SRC_DST {
w.sms().variant(mst_num)
} else {
w
};
if sd_sel == DST || sd_sel == SRC_DST {
w.dms().variant(mst_num)
} else {
w
}
});
// Note: there's some weird tmp|= line here in the Kendryte SDK
// with the result going unused. I've decided to leave this out
// because I assume it's another C UB workaround.
Ok(())
} else {
Err(())
}
}
pub fn enable_common_interrupt_status(&self) {
self.dmac.com_intstatus_en.modify(|_,w|
w.slvif_dec_err().set_bit()
.slvif_wr2ro_err().set_bit()
.slvif_rd2wo_err().set_bit()
.slvif_wronhold_err().set_bit()
.slvif_undefinedreg_dec_err().set_bit()
);
}
pub fn enable_common_interrupt_signal(&self) {
self.dmac.com_intsignal_en.modify(|_,w|
w.slvif_dec_err().set_bit()
.slvif_wr2ro_err().set_bit()
.slvif_rd2wo_err().set_bit()
.slvif_wronhold_err().set_bit()
.slvif_undefinedreg_dec_err().set_bit()
);
}
fn enable_channel_interrupt(&self, channel_num: dma_channel) {
unsafe {
let ch = &self.dmac.channel[channel_num.idx()];
ch.intclear.write(|w| w.bits(0xffffffff));
ch.intstatus_en.write(|w| w.bits(0x2));
}
}
pub fn disable_channel_interrupt(&self, channel_num: dma_channel) {
unsafe {
self.dmac.channel[channel_num.idx()].intstatus_en.write(
|w| w.bits(0x0));
}
}
fn channel_interrupt_clear(&self, channel_num: dma_channel) {
unsafe {
self.dmac.channel[channel_num.idx()].intclear.write(
|w| w.bits(0xffffffff));
}
}
/** Set DMA channel parameters. */
pub fn set_channel_param(&self, channel_num: dma_channel,
src: u64, dest: u64, src_inc: address_increment, dest_inc: address_increment,
burst_size: burst_length,
trans_width: transfer_width,
block_size: u32) {
unsafe {
let ch = &self.dmac.channel[channel_num.idx()];
let src_is_mem = is_memory(src);
let dest_is_mem = is_memory(dest);
let flow_control = match (src_is_mem, dest_is_mem) {
(false, false) => TT_FC_A::PRF2PRF_DMA,
(true, false) => TT_FC_A::MEM2PRF_DMA,
(false, true) => TT_FC_A::PRF2MEM_DMA,
(true, true) => TT_FC_A::MEM2MEM_DMA,
};
/*
* cfg register must configure before ts_block and
* sar dar register
*/
ch.cfg.modify(|_,w|
w.tt_fc().variant(flow_control)
.hs_sel_src().variant(if src_is_mem { HS_SEL_SRC_A::SOFTWARE } else { HS_SEL_SRC_A::HARDWARE } )
.hs_sel_dst().variant(if dest_is_mem { HS_SEL_SRC_A::SOFTWARE } else { HS_SEL_SRC_A::HARDWARE } )
// Note: from SVD: "Assign a hardware handshaking interface to source of channel",
// these are set using sysctl::dma_select; this configuration seems to indicate
// that in principle, it's possible to use a different source and destination
// handshaking interface for a channel, but that would sacrifice the interface of
// another channel.
.src_per().bits(channel_num as u8)
.dst_per().bits(channel_num as u8)
.src_multblk_type().bits(0)
.dst_multblk_type().bits(0)
);
ch.sar.write(|w| w.bits(src));
ch.dar.write(|w| w.bits(dest));
ch.ctl.modify(|_,w|
w.sms().variant(SMS_A::AXI_MASTER_1)
.dms().variant(SMS_A::AXI_MASTER_2)
/* master select */
.sinc().variant(src_inc)
.dinc().variant(dest_inc)
/* address incrememt */
.src_tr_width().variant(trans_width)
.dst_tr_width().variant(trans_width)
/* transfer width */
.src_msize().variant(burst_size)
.dst_msize().variant(burst_size)
);
ch.block_ts.write(|w| w.block_ts().bits(block_size - 1));
/*the number of (blcok_ts +1) data of width SRC_TR_WIDTF to be */
/* transferred in a dma block transfer */
}
}
/*
pub void set_address(&self, dmac_channel_number_t channel_num, uint64_t src_addr,
uint64_t dst_addr) {
writeq(src_addr, &dmac->channel[channel_num].sar);
writeq(dst_addr, &dmac->channel[channel_num].dar);
}
*/
/*
pub void set_block_ts(&self, dmac_channel_number_t channel_num,
uint32_t block_size) {
uint32_t block_ts;
block_ts = block_size & 0x3fffff;
writeq(block_ts, &dmac->channel[channel_num].block_ts);
}
*/
/*
pub void source_control(&self, dmac_channel_number_t channel_num,
dmac_master_number_t master_select,
dmac_address_increment_t address_mode,
dmac_transfer_width_t tr_width,
dmac_burst_length_t burst_length) {
dmac_ch_ctl_u_t ctl_u;
ctl_u.data = readq(&dmac->channel[channel_num].ctl);
ctl_u.ch_ctl.sms = master_select;
ctl_u.ch_ctl.sinc = address_mode;
ctl_u.ch_ctl.src_tr_width = tr_width;
ctl_u.ch_ctl.src_msize = burst_length;
writeq(ctl_u.data, &dmac->channel[channel_num].ctl);
}
*/
/*
pub void master_control(&self, dmac_channel_number_t channel_num,
dmac_master_number_t master_select,
dmac_address_increment_t address_mode,
dmac_transfer_width_t tr_width,
dmac_burst_length_t burst_length) {
dmac_ch_ctl_u_t ctl_u;
ctl_u.data = readq(&dmac->channel[channel_num].ctl);
ctl_u.ch_ctl.dms = master_select;
ctl_u.ch_ctl.dinc = address_mode;
ctl_u.ch_ctl.dst_tr_width = tr_width;
ctl_u.ch_ctl.dst_msize = burst_length;
writeq(ctl_u.data, &dmac->channel[channel_num].ctl);
}
*/
/*
pub void set_source_transfer_control(&self, dmac_channel_number_t channel_num,
dmac_multiblk_transfer_type_t transfer_type,
dmac_sw_hw_hs_select_t handshak_select) {
dmac_ch_cfg_u_t cfg_u;
cfg_u.data = readq(&dmac->channel[channel_num].cfg);
cfg_u.ch_cfg.src_multblk_type = transfer_type;
cfg_u.ch_cfg.hs_sel_src = handshak_select;
writeq(cfg_u.data, &dmac->channel[channel_num].cfg);
}
*/
/*
pub void set_destination_transfer_control(&self, dmac_channel_number_t channel_num,
dmac_multiblk_transfer_type_t transfer_type,
dmac_sw_hw_hs_select_t handshak_select) {
dmac_ch_cfg_u_t cfg_u;
cfg_u.data = readq(&dmac->channel[channel_num].cfg);
cfg_u.ch_cfg.dst_multblk_type = transfer_type;
cfg_u.ch_cfg.hs_sel_dst = handshak_select;
writeq(cfg_u.data, &dmac->channel[channel_num].cfg);
}
*/
/*
pub void set_flow_control(&self, dmac_channel_number_t channel_num,
dmac_transfer_flow_t flow_control) {
dmac_ch_cfg_u_t cfg_u;
cfg_u.data = readq(&dmac->channel[channel_num].cfg);
cfg_u.ch_cfg.tt_fc = flow_control;
writeq(cfg_u.data, &dmac->channel[channel_num].cfg);
}
*/
/*
pub void set_linked_list_addr_point(&self, dmac_channel_number_t channel_num,
uint64_t *addr) {
dmac_ch_llp_u_t llp_u;
llp_u.data = readq(&dmac->channel[channel_num].llp);
/* Cast pointer to uint64_t */
llp_u.llp.loc = (uint64_t)addr;
writeq(llp_u.data, &dmac->channel[channel_num].llp);
}
*/
/** Initialize DMA controller */
pub fn init(&self) {
sysctl::clock_enable(sysctl::clock::DMA);
/* reset dmac */
self.dmac.reset.modify(|_,w| w.rst().set_bit());
while self.dmac.reset.read().rst().bit() {
// IDLE
}
/* clear common register interrupt */
self.dmac.com_intclear.modify(|_,w|
w.slvif_dec_err().set_bit()
.slvif_wr2ro_err().set_bit()
.slvif_rd2wo_err().set_bit()
.slvif_wronhold_err().set_bit()
.slvif_undefinedreg_dec_err().set_bit()
);
/* disable dmac and disable interrupt */
self.dmac.cfg.modify(|_,w|
w.dmac_en().clear_bit()
.int_en().clear_bit()
);
while self.dmac.cfg.read().bits() != 0 {
// IDLE
}
/* disable all channel before configure */
/* Note: changed from the SDK code, which doesn't clear channel 4 and 5,
* and doesn't set associated _we bits */
self.dmac.chen.modify(|_,w|
w.ch1_en().clear_bit()
.ch1_en_we().set_bit()
.ch2_en().clear_bit()
.ch2_en_we().set_bit()
.ch3_en().clear_bit()
.ch3_en_we().set_bit()
.ch4_en().clear_bit()
.ch4_en_we().set_bit()
.ch5_en().clear_bit()
.ch5_en_we().set_bit()
);
self.enable();
}
// TODO: list (scatter/gather) functionality
/*
static void list_add(struct list_head_t *new, struct list_head_t *prev,
struct list_head_t *next) {
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
*/
/*
pub void list_add_tail(struct list_head_t *new, struct list_head_t *head) {
list_add(new, head->prev, head);
}
*/
/*
pub void INIT_LIST_HEAD(struct list_head_t *list) {
list->next = list;
list->prev = list;
}
*/
/*
pub void link_list_item(dmac_channel_number_t channel_num,
uint8_t LLI_row_num, int8_t LLI_last_row,
dmac_lli_item_t *lli_item,
dmac_channel_config_t *cfg_param) {
dmac_ch_ctl_u_t ctl;
dmac_ch_llp_u_t llp_u;
lli_item[LLI_row_num].sar = cfg_param->sar;
lli_item[LLI_row_num].dar = cfg_param->dar;
ctl.data = readq(&dmac->channel[channel_num].ctl);
ctl.ch_ctl.sms = cfg_param->ctl_sms;
ctl.ch_ctl.dms = cfg_param->ctl_dms;
ctl.ch_ctl.sinc = cfg_param->ctl_sinc;
ctl.ch_ctl.dinc = cfg_param->ctl_dinc;
ctl.ch_ctl.src_tr_width = cfg_param->ctl_src_tr_width;
ctl.ch_ctl.dst_tr_width = cfg_param->ctl_dst_tr_width;
ctl.ch_ctl.src_msize = cfg_param->ctl_src_msize;
ctl.ch_ctl.dst_msize = cfg_param->ctl_drc_msize;
ctl.ch_ctl.src_stat_en = cfg_param->ctl_src_stat_en;
ctl.ch_ctl.dst_stat_en = cfg_param->ctl_dst_stat_en;
if(LLI_last_row != LAST_ROW)
{
ctl.ch_ctl.shadowreg_or_lli_valid = 1;
ctl.ch_ctl.shadowreg_or_lli_last = 0;
} else
{
ctl.ch_ctl.shadowreg_or_lli_valid = 1;
ctl.ch_ctl.shadowreg_or_lli_last = 1;
}
lli_item[LLI_row_num].ctl = ctl.data;
lli_item[LLI_row_num].ch_block_ts = cfg_param->ctl_block_ts;
lli_item[LLI_row_num].sstat = 0;
lli_item[LLI_row_num].dstat = 0;
llp_u.data = readq(&dmac->channel[channel_num].llp);
if(LLI_last_row != LAST_ROW)
llp_u.llp.loc = ((uint64_t)&lli_item[LLI_row_num + 1]) >> 6;
else
llp_u.llp.loc = 0;
lli_item[LLI_row_num].llp = llp_u.data;
}
pub void update_shadow_register(&self, dmac_channel_number_t channel_num,
int8_t last_block, dmac_channel_config_t *cfg_param) {
dmac_ch_ctl_u_t ctl_u;
do
{
ctl_u.data = readq(&dmac->channel[channel_num].ctl);
} while(ctl_u.ch_ctl.shadowreg_or_lli_valid);
writeq(cfg_param->sar, &dmac->channel[channel_num].sar);
writeq(cfg_param->dar, &dmac->channel[channel_num].dar);
writeq(cfg_param->ctl_block_ts, &dmac->channel[channel_num].block_ts);
ctl_u.ch_ctl.sms = cfg_param->ctl_sms;
ctl_u.ch_ctl.dms = cfg_param->ctl_dms;
ctl_u.ch_ctl.sinc = cfg_param->ctl_sinc;
ctl_u.ch_ctl.dinc = cfg_param->ctl_dinc;
ctl_u.ch_ctl.src_tr_width = cfg_param->ctl_src_tr_width;
ctl_u.ch_ctl.dst_tr_width = cfg_param->ctl_dst_tr_width;
ctl_u.ch_ctl.src_msize = cfg_param->ctl_src_msize;
ctl_u.ch_ctl.dst_msize = cfg_param->ctl_drc_msize;
ctl_u.ch_ctl.src_stat_en = cfg_param->ctl_src_stat_en;
ctl_u.ch_ctl.dst_stat_en = cfg_param->ctl_dst_stat_en;
if(last_block != LAST_ROW)
{
ctl_u.ch_ctl.shadowreg_or_lli_valid = 1;
ctl_u.ch_ctl.shadowreg_or_lli_last = 0;
} else
{
ctl_u.ch_ctl.shadowreg_or_lli_valid = 1;
ctl_u.ch_ctl.shadowreg_or_lli_last = 1;
}
writeq(ctl_u.data, &dmac->channel[channel_num].ctl);
writeq(0, &dmac->channel[channel_num].blk_tfr);
}
*/
/*
pub void set_shadow_invalid_flag(&self, dmac_channel_number_t channel_num) {
dmac_ch_ctl_u_t ctl_u;
ctl_u.data = readq(&dmac->channel[channel_num].ctl);
ctl_u.ch_ctl.shadowreg_or_lli_valid = 1;
ctl_u.ch_ctl.shadowreg_or_lli_last = 0;
writeq(ctl_u.data, &dmac->channel[channel_num].ctl);
}
*/
/** Start a single DMA transfer. */
pub fn set_single_mode(&self, channel_num: dma_channel,
src: u64, dest: u64, src_inc: address_increment,
dest_inc: address_increment,
burst_size: burst_length,
trans_width: transfer_width,
block_size: u32) {
self.channel_interrupt_clear(channel_num);
self.channel_disable(channel_num);
self.wait_idle(channel_num);
self.set_channel_param(channel_num, src, dest, src_inc, dest_inc,
burst_size, trans_width, block_size);
self.enable();
self.channel_enable(channel_num);
}
/*
pub int is_done(&self, dmac_channel_number_t channel_num) {
if(readq(&dmac->channel[channel_num].intstatus) & 0x2)
return 1;
else
return 0;
}
*/
/** Wait for dmac work done. */
pub fn wait_done(&self, channel_num: dma_channel) {
self.wait_idle(channel_num);
}
/** Determine if a DMA channel is idle or not. */
pub fn is_idle(&self, channel_num: dma_channel) -> bool {
!self.check_channel_busy(channel_num)
}
/** Wait for a DMA channel to be idle. */
pub fn wait_idle(&self, channel_num: dma_channel) {
while !self.is_idle(channel_num) {
}
self.channel_interrupt_clear(channel_num); /* clear interrupt */
}
/*
pub void set_src_dest_length(&self, dmac_channel_number_t channel_num, const void *src, void *dest, size_t len) {
if(src != NULL)
dmac->channel[channel_num].sar = (uint64_t)src;
if(dest != NULL)
dmac->channel[channel_num].dar = (uint64_t)dest;
if(len > 0)
dmac_set_block_ts(channel_num, len - 1);
dmac_channel_enable(channel_num);
}
*/
// TODO: completion IRQ functionality
}

@ -0,0 +1,481 @@
//! FPIOA peripheral
#![allow(unused)]
#![allow(non_camel_case_types)]
//use k210_hal::pac;
use k210_pac as pac;
#[derive(Copy, Clone)]
pub enum function {
JTAG_TCLK = 0, /* JTAG Test Clock */
JTAG_TDI = 1, /* JTAG Test Data In */
JTAG_TMS = 2, /* JTAG Test Mode Select */
JTAG_TDO = 3, /* JTAG Test Data Out */
SPI0_D0 = 4, /* SPI0 Data 0 */
SPI0_D1 = 5, /* SPI0 Data 1 */
SPI0_D2 = 6, /* SPI0 Data 2 */
SPI0_D3 = 7, /* SPI0 Data 3 */
SPI0_D4 = 8, /* SPI0 Data 4 */
SPI0_D5 = 9, /* SPI0 Data 5 */
SPI0_D6 = 10, /* SPI0 Data 6 */
SPI0_D7 = 11, /* SPI0 Data 7 */
SPI0_SS0 = 12, /* SPI0 Chip Select 0 */
SPI0_SS1 = 13, /* SPI0 Chip Select 1 */
SPI0_SS2 = 14, /* SPI0 Chip Select 2 */
SPI0_SS3 = 15, /* SPI0 Chip Select 3 */
SPI0_ARB = 16, /* SPI0 Arbitration */
SPI0_SCLK = 17, /* SPI0 Serial Clock */
UARTHS_RX = 18, /* UART High speed Receiver */
UARTHS_TX = 19, /* UART High speed Transmitter */
RESV6 = 20, /* Reserved function */
RESV7 = 21, /* Reserved function */
CLK_SPI1 = 22, /* Clock SPI1 */
CLK_I2C1 = 23, /* Clock I2C1 */
GPIOHS0 = 24, /* GPIO High speed 0 */
GPIOHS1 = 25, /* GPIO High speed 1 */
GPIOHS2 = 26, /* GPIO High speed 2 */
GPIOHS3 = 27, /* GPIO High speed 3 */
GPIOHS4 = 28, /* GPIO High speed 4 */
GPIOHS5 = 29, /* GPIO High speed 5 */
GPIOHS6 = 30, /* GPIO High speed 6 */
GPIOHS7 = 31, /* GPIO High speed 7 */
GPIOHS8 = 32, /* GPIO High speed 8 */
GPIOHS9 = 33, /* GPIO High speed 9 */
GPIOHS10 = 34, /* GPIO High speed 10 */
GPIOHS11 = 35, /* GPIO High speed 11 */
GPIOHS12 = 36, /* GPIO High speed 12 */
GPIOHS13 = 37, /* GPIO High speed 13 */
GPIOHS14 = 38, /* GPIO High speed 14 */
GPIOHS15 = 39, /* GPIO High speed 15 */
GPIOHS16 = 40, /* GPIO High speed 16 */
GPIOHS17 = 41, /* GPIO High speed 17 */
GPIOHS18 = 42, /* GPIO High speed 18 */
GPIOHS19 = 43, /* GPIO High speed 19 */
GPIOHS20 = 44, /* GPIO High speed 20 */
GPIOHS21 = 45, /* GPIO High speed 21 */
GPIOHS22 = 46, /* GPIO High speed 22 */
GPIOHS23 = 47, /* GPIO High speed 23 */
GPIOHS24 = 48, /* GPIO High speed 24 */
GPIOHS25 = 49, /* GPIO High speed 25 */
GPIOHS26 = 50, /* GPIO High speed 26 */
GPIOHS27 = 51, /* GPIO High speed 27 */
GPIOHS28 = 52, /* GPIO High speed 28 */
GPIOHS29 = 53, /* GPIO High speed 29 */
GPIOHS30 = 54, /* GPIO High speed 30 */
GPIOHS31 = 55, /* GPIO High speed 31 */
GPIO0 = 56, /* GPIO pin 0 */
GPIO1 = 57, /* GPIO pin 1 */
GPIO2 = 58, /* GPIO pin 2 */
GPIO3 = 59, /* GPIO pin 3 */
GPIO4 = 60, /* GPIO pin 4 */
GPIO5 = 61, /* GPIO pin 5 */
GPIO6 = 62, /* GPIO pin 6 */
GPIO7 = 63, /* GPIO pin 7 */
UART1_RX = 64, /* UART1 Receiver */
UART1_TX = 65, /* UART1 Transmitter */
UART2_RX = 66, /* UART2 Receiver */
UART2_TX = 67, /* UART2 Transmitter */
UART3_RX = 68, /* UART3 Receiver */
UART3_TX = 69, /* UART3 Transmitter */
SPI1_D0 = 70, /* SPI1 Data 0 */
SPI1_D1 = 71, /* SPI1 Data 1 */
SPI1_D2 = 72, /* SPI1 Data 2 */
SPI1_D3 = 73, /* SPI1 Data 3 */
SPI1_D4 = 74, /* SPI1 Data 4 */
SPI1_D5 = 75, /* SPI1 Data 5 */
SPI1_D6 = 76, /* SPI1 Data 6 */
SPI1_D7 = 77, /* SPI1 Data 7 */
SPI1_SS0 = 78, /* SPI1 Chip Select 0 */
SPI1_SS1 = 79, /* SPI1 Chip Select 1 */
SPI1_SS2 = 80, /* SPI1 Chip Select 2 */
SPI1_SS3 = 81, /* SPI1 Chip Select 3 */
SPI1_ARB = 82, /* SPI1 Arbitration */
SPI1_SCLK = 83, /* SPI1 Serial Clock */
SPI_SLAVE_D0 = 84, /* SPI Slave Data 0 */
SPI_SLAVE_SS = 85, /* SPI Slave Select */
SPI_SLAVE_SCLK = 86, /* SPI Slave Serial Clock */
I2S0_MCLK = 87, /* I2S0 Master Clock */
I2S0_SCLK = 88, /* I2S0 Serial Clock(BCLK) */
I2S0_WS = 89, /* I2S0 Word Select(LRCLK) */
I2S0_IN_D0 = 90, /* I2S0 Serial Data Input 0 */
I2S0_IN_D1 = 91, /* I2S0 Serial Data Input 1 */
I2S0_IN_D2 = 92, /* I2S0 Serial Data Input 2 */
I2S0_IN_D3 = 93, /* I2S0 Serial Data Input 3 */
I2S0_OUT_D0 = 94, /* I2S0 Serial Data Output 0 */
I2S0_OUT_D1 = 95, /* I2S0 Serial Data Output 1 */
I2S0_OUT_D2 = 96, /* I2S0 Serial Data Output 2 */
I2S0_OUT_D3 = 97, /* I2S0 Serial Data Output 3 */
I2S1_MCLK = 98, /* I2S1 Master Clock */
I2S1_SCLK = 99, /* I2S1 Serial Clock(BCLK) */
I2S1_WS = 100, /* I2S1 Word Select(LRCLK) */
I2S1_IN_D0 = 101, /* I2S1 Serial Data Input 0 */
I2S1_IN_D1 = 102, /* I2S1 Serial Data Input 1 */
I2S1_IN_D2 = 103, /* I2S1 Serial Data Input 2 */
I2S1_IN_D3 = 104, /* I2S1 Serial Data Input 3 */
I2S1_OUT_D0 = 105, /* I2S1 Serial Data Output 0 */
I2S1_OUT_D1 = 106, /* I2S1 Serial Data Output 1 */
I2S1_OUT_D2 = 107, /* I2S1 Serial Data Output 2 */
I2S1_OUT_D3 = 108, /* I2S1 Serial Data Output 3 */
I2S2_MCLK = 109, /* I2S2 Master Clock */
I2S2_SCLK = 110, /* I2S2 Serial Clock(BCLK) */
I2S2_WS = 111, /* I2S2 Word Select(LRCLK) */
I2S2_IN_D0 = 112, /* I2S2 Serial Data Input 0 */
I2S2_IN_D1 = 113, /* I2S2 Serial Data Input 1 */
I2S2_IN_D2 = 114, /* I2S2 Serial Data Input 2 */
I2S2_IN_D3 = 115, /* I2S2 Serial Data Input 3 */
I2S2_OUT_D0 = 116, /* I2S2 Serial Data Output 0 */
I2S2_OUT_D1 = 117, /* I2S2 Serial Data Output 1 */
I2S2_OUT_D2 = 118, /* I2S2 Serial Data Output 2 */
I2S2_OUT_D3 = 119, /* I2S2 Serial Data Output 3 */
RESV0 = 120, /* Reserved function */
RESV1 = 121, /* Reserved function */
RESV2 = 122, /* Reserved function */
RESV3 = 123, /* Reserved function */
RESV4 = 124, /* Reserved function */
RESV5 = 125, /* Reserved function */
I2C0_SCLK = 126, /* I2C0 Serial Clock */
I2C0_SDA = 127, /* I2C0 Serial Data */
I2C1_SCLK = 128, /* I2C1 Serial Clock */
I2C1_SDA = 129, /* I2C1 Serial Data */
I2C2_SCLK = 130, /* I2C2 Serial Clock */
I2C2_SDA = 131, /* I2C2 Serial Data */
CMOS_XCLK = 132, /* DVP System Clock */
CMOS_RST = 133, /* DVP System Reset */
CMOS_PWDN = 134, /* DVP Power Down Mode */
CMOS_VSYNC = 135, /* DVP Vertical Sync */
CMOS_HREF = 136, /* DVP Horizontal Reference output */
CMOS_PCLK = 137, /* Pixel Clock */
CMOS_D0 = 138, /* Data Bit 0 */
CMOS_D1 = 139, /* Data Bit 1 */
CMOS_D2 = 140, /* Data Bit 2 */
CMOS_D3 = 141, /* Data Bit 3 */
CMOS_D4 = 142, /* Data Bit 4 */
CMOS_D5 = 143, /* Data Bit 5 */
CMOS_D6 = 144, /* Data Bit 6 */
CMOS_D7 = 145, /* Data Bit 7 */
SCCB_SCLK = 146, /* SCCB Serial Clock */
SCCB_SDA = 147, /* SCCB Serial Data */
UART1_CTS = 148, /* UART1 Clear To Send */
UART1_DSR = 149, /* UART1 Data Set Ready */
UART1_DCD = 150, /* UART1 Data Carrier Detect */
UART1_RI = 151, /* UART1 Ring Indicator */
UART1_SIR_IN = 152, /* UART1 Serial Infrared Input */
UART1_DTR = 153, /* UART1 Data Terminal Ready */
UART1_RTS = 154, /* UART1 Request To Send */
UART1_OUT2 = 155, /* UART1 User-designated Output 2 */
UART1_OUT1 = 156, /* UART1 User-designated Output 1 */
UART1_SIR_OUT = 157, /* UART1 Serial Infrared Output */
UART1_BAUD = 158, /* UART1 Transmit Clock Output */
UART1_RE = 159, /* UART1 Receiver Output Enable */
UART1_DE = 160, /* UART1 Driver Output Enable */
UART1_RS485_EN = 161, /* UART1 RS485 Enable */
UART2_CTS = 162, /* UART2 Clear To Send */
UART2_DSR = 163, /* UART2 Data Set Ready */
UART2_DCD = 164, /* UART2 Data Carrier Detect */
UART2_RI = 165, /* UART2 Ring Indicator */
UART2_SIR_IN = 166, /* UART2 Serial Infrared Input */
UART2_DTR = 167, /* UART2 Data Terminal Ready */
UART2_RTS = 168, /* UART2 Request To Send */
UART2_OUT2 = 169, /* UART2 User-designated Output 2 */
UART2_OUT1 = 170, /* UART2 User-designated Output 1 */
UART2_SIR_OUT = 171, /* UART2 Serial Infrared Output */
UART2_BAUD = 172, /* UART2 Transmit Clock Output */
UART2_RE = 173, /* UART2 Receiver Output Enable */
UART2_DE = 174, /* UART2 Driver Output Enable */
UART2_RS485_EN = 175, /* UART2 RS485 Enable */
UART3_CTS = 176, /* UART3 Clear To Send */
UART3_DSR = 177, /* UART3 Data Set Ready */
UART3_DCD = 178, /* UART3 Data Carrier Detect */
UART3_RI = 179, /* UART3 Ring Indicator */
UART3_SIR_IN = 180, /* UART3 Serial Infrared Input */
UART3_DTR = 181, /* UART3 Data Terminal Ready */
UART3_RTS = 182, /* UART3 Request To Send */
UART3_OUT2 = 183, /* UART3 User-designated Output 2 */
UART3_OUT1 = 184, /* UART3 User-designated Output 1 */
UART3_SIR_OUT = 185, /* UART3 Serial Infrared Output */
UART3_BAUD = 186, /* UART3 Transmit Clock Output */
UART3_RE = 187, /* UART3 Receiver Output Enable */
UART3_DE = 188, /* UART3 Driver Output Enable */
UART3_RS485_EN = 189, /* UART3 RS485 Enable */
TIMER0_TOGGLE1 = 190, /* TIMER0 Toggle Output 1 */
TIMER0_TOGGLE2 = 191, /* TIMER0 Toggle Output 2 */
TIMER0_TOGGLE3 = 192, /* TIMER0 Toggle Output 3 */
TIMER0_TOGGLE4 = 193, /* TIMER0 Toggle Output 4 */
TIMER1_TOGGLE1 = 194, /* TIMER1 Toggle Output 1 */
TIMER1_TOGGLE2 = 195, /* TIMER1 Toggle Output 2 */
TIMER1_TOGGLE3 = 196, /* TIMER1 Toggle Output 3 */
TIMER1_TOGGLE4 = 197, /* TIMER1 Toggle Output 4 */
TIMER2_TOGGLE1 = 198, /* TIMER2 Toggle Output 1 */
TIMER2_TOGGLE2 = 199, /* TIMER2 Toggle Output 2 */
TIMER2_TOGGLE3 = 200, /* TIMER2 Toggle Output 3 */
TIMER2_TOGGLE4 = 201, /* TIMER2 Toggle Output 4 */
CLK_SPI2 = 202, /* Clock SPI2 */
CLK_I2C2 = 203, /* Clock I2C2 */
INTERNAL0 = 204, /* Internal function signal 0 */
INTERNAL1 = 205, /* Internal function signal 1 */
INTERNAL2 = 206, /* Internal function signal 2 */
INTERNAL3 = 207, /* Internal function signal 3 */
INTERNAL4 = 208, /* Internal function signal 4 */
INTERNAL5 = 209, /* Internal function signal 5 */
INTERNAL6 = 210, /* Internal function signal 6 */
INTERNAL7 = 211, /* Internal function signal 7 */
INTERNAL8 = 212, /* Internal function signal 8 */
INTERNAL9 = 213, /* Internal function signal 9 */
INTERNAL10 = 214, /* Internal function signal 10 */
INTERNAL11 = 215, /* Internal function signal 11 */
INTERNAL12 = 216, /* Internal function signal 12 */
INTERNAL13 = 217, /* Internal function signal 13 */
INTERNAL14 = 218, /* Internal function signal 14 */
INTERNAL15 = 219, /* Internal function signal 15 */
INTERNAL16 = 220, /* Internal function signal 16 */
INTERNAL17 = 221, /* Internal function signal 17 */
CONSTANT = 222, /* Constant function */
INTERNAL18 = 223, /* Internal function signal 18 */
DEBUG0 = 224, /* Debug function 0 */
DEBUG1 = 225, /* Debug function 1 */
DEBUG2 = 226, /* Debug function 2 */
DEBUG3 = 227, /* Debug function 3 */
DEBUG4 = 228, /* Debug function 4 */
DEBUG5 = 229, /* Debug function 5 */
DEBUG6 = 230, /* Debug function 6 */
DEBUG7 = 231, /* Debug function 7 */
DEBUG8 = 232, /* Debug function 8 */
DEBUG9 = 233, /* Debug function 9 */
DEBUG10 = 234, /* Debug function 10 */
DEBUG11 = 235, /* Debug function 11 */
DEBUG12 = 236, /* Debug function 12 */
DEBUG13 = 237, /* Debug function 13 */
DEBUG14 = 238, /* Debug function 14 */
DEBUG15 = 239, /* Debug function 15 */
DEBUG16 = 240, /* Debug function 16 */
DEBUG17 = 241, /* Debug function 17 */
DEBUG18 = 242, /* Debug function 18 */
DEBUG19 = 243, /* Debug function 19 */
DEBUG20 = 244, /* Debug function 20 */
DEBUG21 = 245, /* Debug function 21 */
DEBUG22 = 246, /* Debug function 22 */
DEBUG23 = 247, /* Debug function 23 */
DEBUG24 = 248, /* Debug function 24 */
DEBUG25 = 249, /* Debug function 25 */
DEBUG26 = 250, /* Debug function 26 */
DEBUG27 = 251, /* Debug function 27 */
DEBUG28 = 252, /* Debug function 28 */
DEBUG29 = 253, /* Debug function 29 */
DEBUG30 = 254, /* Debug function 30 */
DEBUG31 = 255, /* Debug function 31 */
}
impl function {
/** GPIOHS pin to function */
pub fn gpiohs(num: u8) -> function {
use function::*;
match num {
0 => GPIOHS0,
1 => GPIOHS1,
2 => GPIOHS2,
3 => GPIOHS3,
4 => GPIOHS4,
5 => GPIOHS5,
6 => GPIOHS6,
7 => GPIOHS7,
8 => GPIOHS8,
9 => GPIOHS9,
10 => GPIOHS10,
11 => GPIOHS11,
12 => GPIOHS12,
13 => GPIOHS13,
14 => GPIOHS14,
15 => GPIOHS15,
16 => GPIOHS16,
17 => GPIOHS17,
18 => GPIOHS18,
19 => GPIOHS19,
20 => GPIOHS20,
21 => GPIOHS21,
22 => GPIOHS22,
23 => GPIOHS23,
24 => GPIOHS24,
25 => GPIOHS25,
26 => GPIOHS26,
27 => GPIOHS27,
28 => GPIOHS28,
29 => GPIOHS29,
30 => GPIOHS30,
31 => GPIOHS31,
_ => panic!("no such GPIO pin"),
}
}
}
#[derive(Copy, Clone)]
pub enum pull {
/** No Pull */
NONE,
/** Pull Down */
DOWN,
/** Pull Up */
UP,
}
/** Defaults per function (from Kendryte fpioa.c) */
#[cfg_attr(rustfmt, rustfmt_skip)]
static FUNCTION_DEFAULTS: &[u32] = &[
0x00900000, 0x00900001, 0x00900002, 0x00001f03, 0x00b03f04, 0x00b03f05, 0x00b03f06, 0x00b03f07,
0x00b03f08, 0x00b03f09, 0x00b03f0a, 0x00b03f0b, 0x00001f0c, 0x00001f0d, 0x00001f0e, 0x00001f0f,
0x03900010, 0x00001f11, 0x00900012, 0x00001f13, 0x00900014, 0x00900015, 0x00001f16, 0x00001f17,
0x00901f18, 0x00901f19, 0x00901f1a, 0x00901f1b, 0x00901f1c, 0x00901f1d, 0x00901f1e, 0x00901f1f,
0x00901f20, 0x00901f21, 0x00901f22, 0x00901f23, 0x00901f24, 0x00901f25, 0x00901f26, 0x00901f27,
0x00901f28, 0x00901f29, 0x00901f2a, 0x00901f2b, 0x00901f2c, 0x00901f2d, 0x00901f2e, 0x00901f2f,
0x00901f30, 0x00901f31, 0x00901f32, 0x00901f33, 0x00901f34, 0x00901f35, 0x00901f36, 0x00901f37,
0x00901f38, 0x00901f39, 0x00901f3a, 0x00901f3b, 0x00901f3c, 0x00901f3d, 0x00901f3e, 0x00901f3f,
0x00900040, 0x00001f41, 0x00900042, 0x00001f43, 0x00900044, 0x00001f45, 0x00b03f46, 0x00b03f47,
0x00b03f48, 0x00b03f49, 0x00b03f4a, 0x00b03f4b, 0x00b03f4c, 0x00b03f4d, 0x00001f4e, 0x00001f4f,
0x00001f50, 0x00001f51, 0x03900052, 0x00001f53, 0x00b03f54, 0x00900055, 0x00900056, 0x00001f57,
0x00001f58, 0x00001f59, 0x0090005a, 0x0090005b, 0x0090005c, 0x0090005d, 0x00001f5e, 0x00001f5f,
0x00001f60, 0x00001f61, 0x00001f62, 0x00001f63, 0x00001f64, 0x00900065, 0x00900066, 0x00900067,
0x00900068, 0x00001f69, 0x00001f6a, 0x00001f6b, 0x00001f6c, 0x00001f6d, 0x00001f6e, 0x00001f6f,
0x00900070, 0x00900071, 0x00900072, 0x00900073, 0x00001f74, 0x00001f75, 0x00001f76, 0x00001f77,
0x00000078, 0x00000079, 0x0000007a, 0x0000007b, 0x0000007c, 0x0000007d, 0x0099107e, 0x0099107f,
0x00991080, 0x00991081, 0x00991082, 0x00991083, 0x00001f84, 0x00001f85, 0x00001f86, 0x00900087,
0x00900088, 0x00900089, 0x0090008a, 0x0090008b, 0x0090008c, 0x0090008d, 0x0090008e, 0x0090008f,
0x00900090, 0x00900091, 0x00993092, 0x00993093, 0x00900094, 0x00900095, 0x00900096, 0x00900097,
0x00900098, 0x00001f99, 0x00001f9a, 0x00001f9b, 0x00001f9c, 0x00001f9d, 0x00001f9e, 0x00001f9f,
0x00001fa0, 0x00001fa1, 0x009000a2, 0x009000a3, 0x009000a4, 0x009000a5, 0x009000a6, 0x00001fa7,
0x00001fa8, 0x00001fa9, 0x00001faa, 0x00001fab, 0x00001fac, 0x00001fad, 0x00001fae, 0x00001faf,
0x009000b0, 0x009000b1, 0x009000b2, 0x009000b3, 0x009000b4, 0x00001fb5, 0x00001fb6, 0x00001fb7,
0x00001fb8, 0x00001fb9, 0x00001fba, 0x00001fbb, 0x00001fbc, 0x00001fbd, 0x00001fbe, 0x00001fbf,
0x00001fc0, 0x00001fc1, 0x00001fc2, 0x00001fc3, 0x00001fc4, 0x00001fc5, 0x00001fc6, 0x00001fc7,
0x00001fc8, 0x00001fc9, 0x00001fca, 0x00001fcb, 0x00001fcc, 0x00001fcd, 0x00001fce, 0x00001fcf,
0x00001fd0, 0x00001fd1, 0x00001fd2, 0x00001fd3, 0x00001fd4, 0x009000d5, 0x009000d6, 0x009000d7,
0x009000d8, 0x009100d9, 0x00991fda, 0x009000db, 0x009000dc, 0x009000dd, 0x000000de, 0x009000df,
0x00001fe0, 0x00001fe1, 0x00001fe2, 0x00001fe3, 0x00001fe4, 0x00001fe5, 0x00001fe6, 0x00001fe7,
0x00001fe8, 0x00001fe9, 0x00001fea, 0x00001feb, 0x00001fec, 0x00001fed, 0x00001fee, 0x00001fef,
0x00001ff0, 0x00001ff1, 0x00001ff2, 0x00001ff3, 0x00001ff4, 0x00001ff5, 0x00001ff6, 0x00001ff7,
0x00001ff8, 0x00001ff9, 0x00001ffa, 0x00001ffb, 0x00001ffc, 0x00001ffd, 0x00001ffe, 0x00001fff,
];
pub fn set_function<N: Into<usize>>(number: N, function: function) {
// TODO: check for overlapping assignments and assign to RESV0 as the Kendryte SDK does?
unsafe {
let ptr = pac::FPIOA::ptr();
(*ptr).io[number.into()].write(|w| w.bits(FUNCTION_DEFAULTS[function as usize]));
}
}
pub fn set_io_pull<N: Into<usize>>(number: N, pull: pull) {
unsafe {
(*pac::FPIOA::ptr()).io[number.into()].modify(|_, w| match pull {
pull::NONE => w.pu().bit(false).pd().bit(false),
pull::DOWN => w.pu().bit(false).pd().bit(true),
pull::UP => w.pu().bit(true).pd().bit(false),
});
}
}
/** I/O pins for FPIOA */
#[derive(Copy, Clone)]
pub enum io {
/** JTAG TCK */
JTAG_TCK = 0,
/** JTAG TDI */
JTAG_TDI = 1,
/** JTAG TMS */
JTAG_TMS = 2,
/** JTAG TDO */
JTAG_TDO = 3,
/** Host RX (from STM32F103C8) */
ISP_RX = 4,
/** Host TX (to STM32F103C8) */
ISP_TX = 5,
/** WIFI serial TX (from perspective of ESP8285, so our RX) */
WIFI_TX = 6,
/** WIFI serial RX (from perspective of ESP8285, so our TX) */
WIFI_RX = 7,
/** WIFI enable (to ESP8285) */
WIFI_EN = 8,
/** Unused */
BPSK_P = 9,
/** Unused */
BPSK_N = 10,
/** General purpose I/O pin */
IO11 = 11,
/** Blue led (output) */
LED_B = 12,
/** Green led (output) */
LED_G = 13,
/** Red led (output) */
LED_R = 14,
/** Key direction 1 press (input) */
KEY1 = 15,
/** Key center press (input) */
BOOT_KEY0 = 16,
/** Key direction 2 press (input) */
KEY2 = 17,
/** Microphone I2S BCK */
MIC_BCK = 18,
/** Microphone I2S WS */
MIC_WS = 19,
/** Microphone I2S DAT3 */
MIC_DAT3 = 20,
/** Microphone I2S DAT2 */
MIC_DAT2 = 21,
/** Microphone I2S DAT1 */
MIC_DAT1 = 22,
/** Microphone I2S DAT0 */
MIC_DAT0 = 23,
/** Microphone LED DAT */
MIC_LED_DAT = 24,
/** Microphone LED CLK */
MIC_LED_CLK = 25,
/** SDCARD SPI MISO */
SPI0_MISO = 26,
/** SDCARD SPI SCLK */
SPI0_SCLK = 27,
/** SDCARD SPI MOSI */
SPI0_MOSI = 28,
/** SDCARD SPI CS */
SPI0_CS0 = 29,
/** I2C bus 1 SCLK (NS2009, MSA300) */
I2C1_SCL = 30,
/** I2C bus 2 SDA (NS2009, MSA300) */
I2C1_SDA = 31,
/** General purpose I/O pin */
IO32 = 32,
/** DAC I2S WS */
I2S_WS = 33,
/** DAC I2S DA */
I2S_DA = 34,
/** DAC I2S BCK */
I2S_BCK = 35,
/** LCD chip select (output) */
LCD_CS = 36,
/** LCD reset (output) */
LCD_RST = 37,
/** LCD Data/Command */
LCD_DC = 38,
/** LCD SPI SCLK */
LCD_WR = 39,
/** Camera DVP SDA */
DVP_SDA = 40,
/** Camera DVP SCL */
DVP_SCL = 41,
/** Camera DVP RST */
DVP_RST = 42,
/** Camera DVP VSYNC */
DVP_VSYNC = 43,
/** Camera DVP PWDN */
DVP_PWDN = 44,
/** Camera DVP HSYNC */
DVP_HSYNC = 45,
/** Camera DVP XCLK */
DVP_XCLK = 46,
/** Camera DVP PCLK */
DVP_PCLK = 47,
}
impl From<io> for usize {
fn from(io: io) -> Self {
io as usize
}
}

@ -0,0 +1,11 @@
//! GPIO peripheral
#![allow(non_camel_case_types)]
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum direction {
INPUT,
OUTPUT,
}
// TODO

@ -0,0 +1,41 @@
#![allow(unused)]
//! GPIOHS peripheral
//use k210_hal::pac;
use k210_pac as pac;
use super::gpio;
use super::utils::{set_bit,get_bit};
// TODO embedded-hal::digital::v2::{InputPin, OutputPin}
/** Set input/output direction for a GPIOHS pin */
pub fn set_direction(pin: u8, direction: gpio::direction) {
unsafe {
let ptr = pac::GPIOHS::ptr();
(*ptr)
.output_en
.modify(|r, w| w.bits(set_bit(r.bits(), pin, direction == gpio::direction::OUTPUT)));
(*ptr)
.input_en
.modify(|r, w| w.bits(set_bit(r.bits(), pin, direction == gpio::direction::INPUT)));
}
}
/** Set output value for a GPIOHS pin */
pub fn set_pin(pin: u8, value: bool) {
unsafe {
let ptr = pac::GPIOHS::ptr();
(*ptr)
.output_val
.modify(|r, w| w.bits(set_bit(r.bits(), pin, value)));
}
}
/** Get input value for a GPIOHS pin */
pub fn get_pin(pin: u8) -> bool {
unsafe {
let ptr = pac::GPIOHS::ptr();
get_bit((*ptr).input_val.read().bits(), pin)
}
}

@ -0,0 +1,10 @@
#![no_std]
pub mod dmac;
pub mod fpioa;
pub mod gpio;
pub mod gpiohs;
pub mod sleep;
pub mod spi;
pub mod sysctl;
pub mod utils;

@ -0,0 +1,12 @@
use super::sysctl;
use riscv::register::time;
pub fn time_sleep(n: usize) {
let start = time::read();
while time::read() < start + n {}
}
pub fn usleep(n: usize) {
let freq = sysctl::clock_get_freq(sysctl::clock::CPU) as usize / 62;
time_sleep(freq * n / 1000000);
}

@ -0,0 +1,316 @@
//! SPI peripherals handling
use core::cmp;
use core::convert::TryInto;
use core::ops::Deref;
//use k210_hal::pac;
use k210_pac as pac;
use pac::{SPI0,SPI1,spi0};
use pac::spi0::ctrlr0;
use pac::spi0::spi_ctrlr0;
//use super::sysctl;
use super::sysctl::{dma_channel, self};
use super::dmac::{DMAC, address_increment, burst_length, transfer_width};
/// Extension trait that constrains SPI peripherals
pub trait SPIExt: Sized {
/// Constrains SPI peripheral so it plays nicely with the other abstractions
fn constrain(self) -> SPIImpl<Self>;
}
/// Trait for generalizing over SPI0 and SPI1 (SPI2 is slave-only and SPI3 is !!!special!!!)
pub trait SPI01: Deref<Target = spi0::RegisterBlock> {
#[doc(hidden)]
const CLK: sysctl::clock;
#[doc(hidden)]
const DIV: sysctl::threshold;
#[doc(hidden)]
const DMA_RX: sysctl::dma_select;
#[doc(hidden)]
const DMA_TX: sysctl::dma_select;
}
impl SPI01 for SPI0 {
const CLK: sysctl::clock = sysctl::clock::SPI0;
const DIV: sysctl::threshold = sysctl::threshold::SPI0;
const DMA_RX: sysctl::dma_select = sysctl::dma_select::SSI0_RX_REQ;
const DMA_TX: sysctl::dma_select = sysctl::dma_select::SSI0_TX_REQ;
}
impl SPI01 for SPI1 {
const CLK: sysctl::clock = sysctl::clock::SPI1;
const DIV: sysctl::threshold = sysctl::threshold::SPI1;
const DMA_RX: sysctl::dma_select = sysctl::dma_select::SSI1_RX_REQ;
const DMA_TX: sysctl::dma_select = sysctl::dma_select::SSI1_TX_REQ;
}
impl<SPI: SPI01> SPIExt for SPI {
fn constrain(self) -> SPIImpl<SPI> {
SPIImpl::<SPI>::new(self)
}
}
pub struct SPIImpl<IF> {
spi: IF,
}
/** Borrow work mode from pac */
pub use ctrlr0::WORK_MODE_A as work_mode;
/** Borrow frame format from pac */
pub use ctrlr0::FRAME_FORMAT_A as frame_format;
/** Borrow aitm from pac */
pub use spi_ctrlr0::AITM_A as aitm;
/** Borrow tmod from pac */
pub use ctrlr0::TMOD_A as tmod;
pub trait SPI {
fn configure(
&self,
work_mode: work_mode,
frame_format: frame_format,
data_bit_length: u8,
endian: u32,
instruction_length: u8,
address_length: u8,
wait_cycles: u8,
instruction_address_trans_mode: aitm,
tmod: tmod,
);
fn set_clk_rate(&self, spi_clk: u32) -> u32;
fn recv_data<X: TruncU32>(&self, chip_select: u32, rx: &mut [X]);
fn recv_data_dma(&self, dmac: &DMAC, channel_num: dma_channel, chip_select: u32, rx: &mut [u32]);
fn send_data<X: Into<u32> + Copy>(&self, chip_select: u32, tx: &[X]);
fn send_data_dma(&self, dmac: &DMAC, channel_num: dma_channel, chip_select: u32, tx: &[u32]);
fn fill_data(&self, chip_select: u32, value: u32, tx_len: usize);
fn fill_data_dma(&self, dmac: &DMAC, channel_num: dma_channel, chip_select: u32, value: u32, tx_len: usize);
}
impl<IF: SPI01> SPIImpl<IF> {
pub fn new(spi: IF) -> Self {
Self { spi }
}
}
/** Trait for trunction of a SPI frame from u32 register to other unsigned integer types. */
pub trait TruncU32 {
fn trunc(val: u32)-> Self;
}
impl TruncU32 for u32 { fn trunc(val: u32) -> u32 { return val; } }
impl TruncU32 for u16 { fn trunc(val: u32) -> u16 { return (val & 0xffff) as u16; } }
impl TruncU32 for u8 { fn trunc(val: u32) -> u8 { return (val & 0xff) as u8; } }
impl<IF: SPI01> SPI for SPIImpl<IF> {
/// Configure SPI transaction
fn configure(
&self,
work_mode: work_mode,
frame_format: frame_format,
data_bit_length: u8,
endian: u32,
instruction_length: u8,
address_length: u8,
wait_cycles: u8,
instruction_address_trans_mode: aitm,
tmod: tmod,
) {
assert!(data_bit_length >= 4 && data_bit_length <= 32);
assert!(wait_cycles < (1 << 5));
let inst_l: u8 = match instruction_length {
0 => 0,
4 => 1,
8 => 2,
16 => 3,
_ => panic!("unhandled intruction length"),
};
assert!(address_length % 4 == 0 && address_length <= 60);
let addr_l: u8 = address_length / 4;
unsafe {
self.spi.imr.write(|w| w.bits(0x00));
self.spi.dmacr.write(|w| w.bits(0x00));
self.spi.dmatdlr.write(|w| w.bits(0x10));
self.spi.dmardlr.write(|w| w.bits(0x00));
self.spi.ser.write(|w| w.bits(0x00));
self.spi.ssienr.write(|w| w.bits(0x00));
self.spi.ctrlr0.write(|w| {
w.work_mode()
.variant(work_mode)
.tmod()
.variant(tmod)
.frame_format()
.variant(frame_format)
.data_length()
.bits(data_bit_length - 1)
});
self.spi.spi_ctrlr0.write(|w| {
w.aitm()
.variant(instruction_address_trans_mode)
.addr_length()
.bits(addr_l)
.inst_length()
.bits(inst_l)
.wait_cycles()
.bits(wait_cycles)
});
self.spi.endian.write(|w| w.bits(endian));
}
}
/// Set SPI clock rate
fn set_clk_rate(&self, spi_clk: u32) -> u32 {
sysctl::clock_enable(IF::CLK);
sysctl::clock_set_threshold(IF::DIV, 0);
let clock_freq: u32 = sysctl::clock_get_freq(sysctl::clock::SPI0);
let spi_baudr = clock_freq / spi_clk;
// Clamp baudrate divider to valid range
let spi_baudr = cmp::min(cmp::max(spi_baudr, 2), 65534);
unsafe {
self.spi.baudr.write(|w| w.bits(spi_baudr));
}
clock_freq / spi_baudr
}
/// Receive arbitrary data
// make sure to set tmod to tmod::RECV
fn recv_data<X: TruncU32>(&self, chip_select: u32, rx: &mut [X]) {
if rx.len() == 0 {
return;
}
unsafe {
self.spi.ctrlr1.write(|w| w.bits((rx.len() - 1).try_into().unwrap()));
self.spi.ssienr.write(|w| w.bits(0x01));
self.spi.dr[0].write(|w| w.bits(0xffffffff));
self.spi.ser.write(|w| w.bits(1 << chip_select));
let mut fifo_len = 0;
for val in rx.iter_mut() {
while fifo_len == 0 {
fifo_len = self.spi.rxflr.read().bits();
}
*val = X::trunc(self.spi.dr[0].read().bits());
fifo_len -= 1;
}
self.spi.ser.write(|w| w.bits(0x00));
self.spi.ssienr.write(|w| w.bits(0x00));
}
}
/// Receive 32-bit data using DMA.
// make sure to set tmod to tmod::RECV
fn recv_data_dma(&self, dmac: &DMAC, channel_num: dma_channel, chip_select: u32, rx: &mut [u32]) {
if rx.len() == 0 {
return;
}
unsafe {
self.spi.ctrlr1.write(|w| w.bits((rx.len() - 1).try_into().unwrap()));
self.spi.ssienr.write(|w| w.bits(0x01));
self.spi.dmacr.write(|w| w.bits(0x3)); /*enable dma receive */
sysctl::dma_select(channel_num, IF::DMA_RX);
dmac.set_single_mode(channel_num, self.spi.dr.as_ptr() as u64, rx.as_ptr() as u64,
address_increment::NOCHANGE, address_increment::INCREMENT,
burst_length::LENGTH_1, transfer_width::WIDTH_32, rx.len() as u32);
self.spi.dr[0].write(|w| w.bits(0xffffffff));
self.spi.ser.write(|w| w.bits(1 << chip_select));
dmac.wait_done(channel_num);
self.spi.ser.write(|w| w.bits(0x00));
self.spi.ssienr.write(|w| w.bits(0x00));
}
}
/// Send arbitrary data
fn send_data<X: Into<u32> + Copy>(&self, chip_select: u32, tx: &[X]) {
unsafe {
self.spi.ser.write(|w| w.bits(1 << chip_select));
self.spi.ssienr.write(|w| w.bits(0x01));
let mut fifo_len = 0;
for &val in tx {
while fifo_len == 0 {
fifo_len = 32 - self.spi.txflr.read().bits();
}
self.spi.dr[0].write(|f| f.bits(val.into()));
fifo_len -= 1;
}
while (self.spi.sr.read().bits() & 0x05) != 0x04 {
// IDLE
}
self.spi.ser.write(|w| w.bits(0x00));
self.spi.ssienr.write(|w| w.bits(0x00));
}
}
/// Send 32-bit data using DMA.
/// If you want to use this function to send 8-bit or 16-bit data, you need to wrap each
/// data unit in a 32-bit word.
/// This is intentionally left to the caller: the difficulty here is to avoid the need for alloc/freeing()
/// buffers every time as the SDK does because this is highly undesirable!
fn send_data_dma(&self, dmac: &DMAC, channel_num: dma_channel, chip_select: u32, tx: &[u32]) {
unsafe {
self.spi.dmacr.write(|w| w.bits(0x2)); /*enable dma transmit*/
self.spi.ssienr.write(|w| w.bits(0x01));
sysctl::dma_select(channel_num, IF::DMA_TX);
dmac.set_single_mode(channel_num, tx.as_ptr() as u64, self.spi.dr.as_ptr() as u64,
address_increment::INCREMENT, address_increment::NOCHANGE,
burst_length::LENGTH_4, transfer_width::WIDTH_32, tx.len() as u32);
self.spi.ser.write(|w| w.bits(1 << chip_select));
dmac.wait_done(channel_num);
while (self.spi.sr.read().bits() & 0x05) != 0x04 {
// IDLE
}
self.spi.ser.write(|w| w.bits(0x00));
self.spi.ssienr.write(|w| w.bits(0x00));
}
}
/// Send repeated data
fn fill_data(&self, chip_select: u32, value: u32, mut tx_len: usize) {
unsafe {
self.spi.ser.write(|w| w.bits(1 << chip_select));
self.spi.ssienr.write(|w| w.bits(0x01));
while tx_len != 0 {
let fifo_len = (32 - self.spi.txflr.read().bits()) as usize;
let fifo_len = cmp::min(fifo_len, tx_len);
for _ in 0..fifo_len {
self.spi.dr[0].write(|f| f.bits(value));
}
tx_len -= fifo_len;
}
while (self.spi.sr.read().bits() & 0x05) != 0x04 {
// IDLE
}
self.spi.ser.write(|w| w.bits(0x00));
self.spi.ssienr.write(|w| w.bits(0x00));
}
}
/// Send repeated data (using DMA)
fn fill_data_dma(&self, dmac: &DMAC, channel_num: dma_channel, chip_select: u32, value: u32, tx_len: usize) {
unsafe {
self.spi.dmacr.write(|w| w.bits(0x2)); /*enable dma transmit*/
self.spi.ssienr.write(|w| w.bits(0x01));
sysctl::dma_select(channel_num, IF::DMA_TX);
let val = [value];
// simple trick to repeating a value: don't increment the source address
dmac.set_single_mode(channel_num, val.as_ptr() as u64, self.spi.dr.as_ptr() as u64,
address_increment::NOCHANGE, address_increment::NOCHANGE,
burst_length::LENGTH_4, transfer_width::WIDTH_32, tx_len.try_into().unwrap());
self.spi.ser.write(|w| w.bits(1 << chip_select));
dmac.wait_done(channel_num);
while (self.spi.sr.read().bits() & 0x05) != 0x04 {
// IDLE
}
self.spi.ser.write(|w| w.bits(0x00));
self.spi.ssienr.write(|w| w.bits(0x00));
}
}
}

@ -0,0 +1,854 @@
#![allow(unused)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
//! SYSCTL peripheral
//use k210_hal::pac;
use k210_pac as pac;
use core::convert::TryInto;
use super::utils::set_bit;
use super::sleep::usleep;
mod pll_compute;
const SYSCTRL_CLOCK_FREQ_IN0: u32 = 26000000;
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum pll {
/** PLL0 can usually be selected as alternative to IN0, for example the CPU
* clock speed. It can be used as source for PLL2. */
PLL0,
/** PLL1 is used for the KPU clock, and can be used as source for PLL2. */
PLL1,
/** PLL2 is used for I2S clocks. */
PLL2,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum clock_source {
IN0,
PLL0,
PLL1,
PLL2,
ACLK,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum clock {
PLL0,
PLL1,
PLL2,
CPU,
SRAM0,
SRAM1,
APB0,
APB1,
APB2,
ROM,
DMA,
AI,
DVP,
FFT,
GPIO,
SPI0,
SPI1,
SPI2,
SPI3,
I2S0,
I2S1,
I2S2,
I2C0,
I2C1,
I2C2,
UART1,
UART2,
UART3,
AES,
FPIOA,
TIMER0,
TIMER1,
TIMER2,
WDT0,
WDT1,
SHA,
OTP,
RTC,
ACLK,
HCLK,
IN0,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum threshold {
ACLK,
APB0,
APB1,
APB2,
SRAM0,
SRAM1,
AI,
DVP,
ROM,
SPI0,
SPI1,
SPI2,
SPI3,
TIMER0,
TIMER1,
TIMER2,
I2S0,
I2S1,
I2S2,
I2S0_M,
I2S1_M,
I2S2_M,
I2C0,
I2C1,
I2C2,
WDT0,
WDT1,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum clock_select {
PLL0_BYPASS,
PLL1_BYPASS,
PLL2_BYPASS,
PLL2,
ACLK,
SPI3,
TIMER0,
TIMER1,
TIMER2,
SPI3_SAMPLE,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum io_power_mode {
V33,
V18,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum power_bank {
BANK0 = 0,
BANK1,
BANK2,
BANK3,
BANK4,
BANK5,
BANK6,
BANK7,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum reset {
SOC,
ROM,
DMA,
AI,
DVP,
FFT,
GPIO,
SPI0,
SPI1,
SPI2,
SPI3,
I2S0,
I2S1,
I2S2,
I2C0,
I2C1,
I2C2,
UART1,
UART2,
UART3,
AES,
FPIOA,
TIMER0,
TIMER1,
TIMER2,
WDT0,
WDT1,
SHA,
RTC,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum dma_channel {
CHANNEL0 = 0,
CHANNEL1 = 1,
CHANNEL2 = 2,
CHANNEL3 = 3,
CHANNEL4 = 4,
CHANNEL5 = 5,
}
impl dma_channel {
pub fn idx(self) -> usize { self as usize }
}
pub type dma_select = pac::sysctl::dma_sel0::DMA_SEL0_A;
fn clock_bus_en(clock: clock, en: bool) {
/*
* The timer is under APB0, to prevent apb0_clk_en1 and apb0_clk_en0
* on same register, we split it to peripheral and central two
* registers, to protect CPU close apb0 clock accidentally.
*
* The apb0_clk_en0 and apb0_clk_en1 have same function,
* one of them set, the APB0 clock enable.
*/
/* The APB clock should carefully disable */
if en {
match clock {
/*
* These peripheral devices are under APB0
* GPIO, UART1, UART2, UART3, SPI_SLAVE, I2S0, I2S1,
* I2S2, I2C0, I2C1, I2C2, FPIOA, SHA256, TIMER0,
* TIMER1, TIMER2
*/
clock::GPIO
| clock::SPI2
| clock::I2S0
| clock::I2S1
| clock::I2S2
| clock::I2C0
| clock::I2C1
| clock::I2C2
| clock::UART1
| clock::UART2
| clock::UART3
| clock::FPIOA
| clock::TIMER0
| clock::TIMER1
| clock::TIMER2
| clock::SHA => unsafe {
(*pac::SYSCTL::ptr())
.clk_en_cent
.modify(|_, w| w.apb0_clk_en().bit(en));
},
/*
* These peripheral devices are under APB1
* WDT, AES, OTP, DVP, SYSCTL
*/
clock::AES | clock::WDT0 | clock::WDT1 | clock::OTP | clock::RTC => unsafe {
(*pac::SYSCTL::ptr())
.clk_en_cent
.modify(|_, w| w.apb1_clk_en().bit(en));
},
/*
* These peripheral devices are under APB2
* SPI0, SPI1
*/
clock::SPI0 | clock::SPI1 => unsafe {
(*pac::SYSCTL::ptr())
.clk_en_cent
.modify(|_, w| w.apb2_clk_en().bit(en));
},
_ => {}
}
}
}
fn clock_device_en(clock: clock, en: bool) {
unsafe {
let ptr = pac::SYSCTL::ptr();
match clock {
clock::PLL0 => (*ptr).pll0.modify(|_, w| w.out_en().bit(en)),
clock::PLL1 => (*ptr).pll1.modify(|_, w| w.out_en().bit(en)),
clock::PLL2 => (*ptr).pll2.modify(|_, w| w.out_en().bit(en)),
clock::CPU => (*ptr).clk_en_cent.modify(|_, w| w.cpu_clk_en().bit(en)),
clock::SRAM0 => (*ptr).clk_en_cent.modify(|_, w| w.sram0_clk_en().bit(en)),
clock::SRAM1 => (*ptr).clk_en_cent.modify(|_, w| w.sram1_clk_en().bit(en)),
clock::APB0 => (*ptr).clk_en_cent.modify(|_, w| w.apb0_clk_en().bit(en)),
clock::APB1 => (*ptr).clk_en_cent.modify(|_, w| w.apb1_clk_en().bit(en)),
clock::APB2 => (*ptr).clk_en_cent.modify(|_, w| w.apb2_clk_en().bit(en)),
clock::ROM => (*ptr).clk_en_peri.modify(|_, w| w.rom_clk_en().bit(en)),
clock::DMA => (*ptr).clk_en_peri.modify(|_, w| w.dma_clk_en().bit(en)),
clock::AI => (*ptr).clk_en_peri.modify(|_, w| w.ai_clk_en().bit(en)),
clock::DVP => (*ptr).clk_en_peri.modify(|_, w| w.dvp_clk_en().bit(en)),
clock::FFT => (*ptr).clk_en_peri.modify(|_, w| w.fft_clk_en().bit(en)),
clock::SPI3 => (*ptr).clk_en_peri.modify(|_, w| w.spi3_clk_en().bit(en)),
clock::GPIO => (*ptr).clk_en_peri.modify(|_, w| w.gpio_clk_en().bit(en)),
clock::SPI2 => (*ptr).clk_en_peri.modify(|_, w| w.spi2_clk_en().bit(en)),
clock::I2S0 => (*ptr).clk_en_peri.modify(|_, w| w.i2s0_clk_en().bit(en)),
clock::I2S1 => (*ptr).clk_en_peri.modify(|_, w| w.i2s1_clk_en().bit(en)),
clock::I2S2 => (*ptr).clk_en_peri.modify(|_, w| w.i2s2_clk_en().bit(en)),
clock::I2C0 => (*ptr).clk_en_peri.modify(|_, w| w.i2c0_clk_en().bit(en)),
clock::I2C1 => (*ptr).clk_en_peri.modify(|_, w| w.i2c1_clk_en().bit(en)),
clock::I2C2 => (*ptr).clk_en_peri.modify(|_, w| w.i2c2_clk_en().bit(en)),
clock::UART1 => (*ptr).clk_en_peri.modify(|_, w| w.uart1_clk_en().bit(en)),
clock::UART2 => (*ptr).clk_en_peri.modify(|_, w| w.uart2_clk_en().bit(en)),
clock::UART3 => (*ptr).clk_en_peri.modify(|_, w| w.uart3_clk_en().bit(en)),
clock::FPIOA => (*ptr).clk_en_peri.modify(|_, w| w.fpioa_clk_en().bit(en)),
clock::TIMER0 => (*ptr).clk_en_peri.modify(|_, w| w.timer0_clk_en().bit(en)),
clock::TIMER1 => (*ptr).clk_en_peri.modify(|_, w| w.timer1_clk_en().bit(en)),
clock::TIMER2 => (*ptr).clk_en_peri.modify(|_, w| w.timer2_clk_en().bit(en)),
clock::SHA => (*ptr).clk_en_peri.modify(|_, w| w.sha_clk_en().bit(en)),
clock::AES => (*ptr).clk_en_peri.modify(|_, w| w.aes_clk_en().bit(en)),
clock::WDT0 => (*ptr).clk_en_peri.modify(|_, w| w.wdt0_clk_en().bit(en)),
clock::WDT1 => (*ptr).clk_en_peri.modify(|_, w| w.wdt1_clk_en().bit(en)),
clock::OTP => (*ptr).clk_en_peri.modify(|_, w| w.otp_clk_en().bit(en)),
clock::RTC => (*ptr).clk_en_peri.modify(|_, w| w.rtc_clk_en().bit(en)),
clock::SPI0 => (*ptr).clk_en_peri.modify(|_, w| w.spi0_clk_en().bit(en)),
clock::SPI1 => (*ptr).clk_en_peri.modify(|_, w| w.spi1_clk_en().bit(en)),
clock::ACLK | clock::HCLK | clock::IN0 => { /* no separate enables */ }
}
}
}
pub fn clock_enable(clock: clock) {
clock_bus_en(clock, true);
clock_device_en(clock, true);
}
pub fn sysctl_clock_disable(clock: clock) {
clock_bus_en(clock, false);
clock_device_en(clock, false);
}
/// Set clock divider
pub fn clock_set_threshold(which: threshold, threshold: u32) {
// TODO: this should take a multiplier directly, not a peripheral specific value
unsafe {
let ptr = pac::SYSCTL::ptr();
match which {
/* 2 bit wide */
threshold::ACLK => (*ptr).clk_sel0.modify(|_, w| w.aclk_divider_sel().bits(threshold as u8)),
/* 3 bit wide */
threshold::APB0 => (*ptr).clk_sel0.modify(|_, w| w.apb0_clk_sel().bits(threshold as u8)),
threshold::APB1 => (*ptr).clk_sel0.modify(|_, w| w.apb1_clk_sel().bits(threshold as u8)),
threshold::APB2 => (*ptr).clk_sel0.modify(|_, w| w.apb2_clk_sel().bits(threshold as u8)),
/* 4 bit wide */
threshold::SRAM0 => (*ptr).clk_th0.modify(|_, w| w.sram0_gclk().bits(threshold as u8)),
threshold::SRAM1 => (*ptr).clk_th0.modify(|_, w| w.sram1_gclk().bits(threshold as u8)),
threshold::AI => (*ptr).clk_th0.modify(|_, w| w.ai_gclk().bits(threshold as u8)),
threshold::DVP => (*ptr).clk_th0.modify(|_, w| w.dvp_gclk().bits(threshold as u8)),
threshold::ROM => (*ptr).clk_th0.modify(|_, w| w.rom_gclk().bits(threshold as u8)),
/* 8 bit wide */
threshold::SPI0 => (*ptr).clk_th1.modify(|_, w| w.spi0_clk().bits(threshold as u8)),
threshold::SPI1 => (*ptr).clk_th1.modify(|_, w| w.spi1_clk().bits(threshold as u8)),
threshold::SPI2 => (*ptr).clk_th1.modify(|_, w| w.spi2_clk().bits(threshold as u8)),
threshold::SPI3 => (*ptr).clk_th1.modify(|_, w| w.spi3_clk().bits(threshold as u8)),
threshold::TIMER0 => (*ptr).clk_th2.modify(|_, w| w.timer0_clk().bits(threshold as u8)),
threshold::TIMER1 => (*ptr).clk_th2.modify(|_, w| w.timer1_clk().bits(threshold as u8)),
threshold::TIMER2 => (*ptr).clk_th2.modify(|_, w| w.timer2_clk().bits(threshold as u8)),
threshold::I2S0_M => (*ptr).clk_th4.modify(|_, w| w.i2s0_mclk().bits(threshold as u8)),
threshold::I2S1_M => (*ptr).clk_th4.modify(|_, w| w.i2s1_mclk().bits(threshold as u8)),
threshold::I2S2_M => (*ptr).clk_th5.modify(|_, w| w.i2s2_mclk().bits(threshold as u8)),
threshold::I2C0 => (*ptr).clk_th5.modify(|_, w| w.i2c0_clk().bits(threshold as u8)),
threshold::I2C1 => (*ptr).clk_th5.modify(|_, w| w.i2c1_clk().bits(threshold as u8)),
threshold::I2C2 => (*ptr).clk_th5.modify(|_, w| w.i2c2_clk().bits(threshold as u8)),
threshold::WDT0 => (*ptr).clk_th6.modify(|_, w| w.wdt0_clk().bits(threshold as u8)),
threshold::WDT1 => (*ptr).clk_th6.modify(|_, w| w.wdt1_clk().bits(threshold as u8)),
/* 16 bit wide */
threshold::I2S0 => (*ptr).clk_th3.modify(|_, w| w.i2s0_clk().bits(threshold as u16)),
threshold::I2S1 => (*ptr).clk_th3.modify(|_, w| w.i2s1_clk().bits(threshold as u16)),
threshold::I2S2 => (*ptr).clk_th4.modify(|_, w| w.i2s2_clk().bits(threshold as u16)),
}
}
}
/// Get clock divider
pub fn clock_get_threshold(which: threshold) -> u32 {
unsafe {
// TODO: this should return a multiplier directly, not a peripheral specific value
let ptr = pac::SYSCTL::ptr();
match which {
/* 2 bit wide */
threshold::ACLK => (*ptr).clk_sel0.read().aclk_divider_sel().bits().into(),
/* 3 bit wide */
threshold::APB0 => (*ptr).clk_sel0.read().apb0_clk_sel().bits().into(),
threshold::APB1 => (*ptr).clk_sel0.read().apb1_clk_sel().bits().into(),
threshold::APB2 => (*ptr).clk_sel0.read().apb2_clk_sel().bits().into(),
/* 4 bit wide */
threshold::SRAM0 => (*ptr).clk_th0.read().sram0_gclk().bits().into(),
threshold::SRAM1 => (*ptr).clk_th0.read().sram1_gclk().bits().into(),
threshold::AI => (*ptr).clk_th0.read().ai_gclk().bits().into(),
threshold::DVP => (*ptr).clk_th0.read().dvp_gclk().bits().into(),
threshold::ROM => (*ptr).clk_th0.read().rom_gclk().bits().into(),
/* 8 bit wide */
threshold::SPI0 => (*ptr).clk_th1.read().spi0_clk().bits().into(),
threshold::SPI1 => (*ptr).clk_th1.read().spi1_clk().bits().into(),
threshold::SPI2 => (*ptr).clk_th1.read().spi2_clk().bits().into(),
threshold::SPI3 => (*ptr).clk_th1.read().spi3_clk().bits().into(),
threshold::TIMER0 => (*ptr).clk_th2.read().timer0_clk().bits().into(),
threshold::TIMER1 => (*ptr).clk_th2.read().timer1_clk().bits().into(),
threshold::TIMER2 => (*ptr).clk_th2.read().timer2_clk().bits().into(),
threshold::I2S0_M => (*ptr).clk_th4.read().i2s0_mclk().bits().into(),
threshold::I2S1_M => (*ptr).clk_th4.read().i2s1_mclk().bits().into(),
threshold::I2S2_M => (*ptr).clk_th5.read().i2s2_mclk().bits().into(),
threshold::I2C0 => (*ptr).clk_th5.read().i2c0_clk().bits().into(),
threshold::I2C1 => (*ptr).clk_th5.read().i2c1_clk().bits().into(),
threshold::I2C2 => (*ptr).clk_th5.read().i2c2_clk().bits().into(),
threshold::WDT0 => (*ptr).clk_th6.read().wdt0_clk().bits().into(),
threshold::WDT1 => (*ptr).clk_th6.read().wdt1_clk().bits().into(),
/* 16 bit wide */
threshold::I2S0 => (*ptr).clk_th3.read().i2s0_clk().bits().into(),
threshold::I2S1 => (*ptr).clk_th3.read().i2s1_clk().bits().into(),
threshold::I2S2 => (*ptr).clk_th4.read().i2s2_clk().bits().into(),
}
}
}
pub fn set_power_mode(power_bank: power_bank, mode: io_power_mode) {
unsafe {
(*pac::SYSCTL::ptr()).power_sel.modify(|r, w| {
w.bits(set_bit(
r.bits(),
power_bank as u8,
match mode {
io_power_mode::V33 => false,
io_power_mode::V18 => true,
},
))
});
}
}
/** Route SPI0_D0-D7 DVP_D0-D7 functions to SPI and DVP data pins (bypassing FPIOA). */
pub fn set_spi0_dvp_data(status: bool) {
unsafe {
(*pac::SYSCTL::ptr())
.misc
.modify(|_, w| w.spi_dvp_data_enable().bit(status));
}
}
/** Map PLL2 cksel value to clock source */
fn pll2_cksel_to_source(bits: u8) -> clock_source {
match bits {
0 => clock_source::IN0,
1 => clock_source::PLL0,
2 => clock_source::PLL1,
_ => panic!("invalid value for PLL2 ckin_sel"),
}
}
/** Map clock source to PLL2 cksel value */
fn pll2_source_to_cksel(source: clock_source) -> u8 {
match source {
clock_source::IN0 => 0,
clock_source::PLL0 => 1,
clock_source::PLL1 => 2,
_ => panic!("unsupported clock source for PLL2"),
}
}
pub fn pll_get_freq(pll: pll) -> u32 {
let freq_in;
let nr;
let nf;
let od;
match pll {
pll::PLL0 => {
freq_in = clock_source_get_freq(clock_source::IN0);
unsafe {
let val = (*pac::SYSCTL::ptr()).pll0.read();
nr = val.clkr().bits() + 1;
nf = val.clkf().bits() + 1;
od = val.clkod().bits() + 1;
}
}
pll::PLL1 => {
freq_in = clock_source_get_freq(clock_source::IN0);
unsafe {
let val = (*pac::SYSCTL::ptr()).pll1.read();
nr = val.clkr().bits() + 1;
nf = val.clkf().bits() + 1;
od = val.clkod().bits() + 1;
}
}
pll::PLL2 => {
/* Get input freq accrording to select register. */
freq_in = clock_source_get_freq(pll2_cksel_to_source(clock_get_clock_select(clock_select::PLL2)));
unsafe {
let val = (*pac::SYSCTL::ptr()).pll2.read();
nr = val.clkr().bits() + 1;
nf = val.clkf().bits() + 1;
od = val.clkod().bits() + 1;
}
}
}
/*
* Get final PLL output freq
* FOUT = FIN / NR * NF / OD
* (rewritten as integer expression)
*/
((u64::from(freq_in) * u64::from(nf)) / (u64::from(nr) * u64::from(od))).try_into().unwrap()
}
pub fn clock_source_get_freq(source: clock_source) -> u32 {
match source {
clock_source::IN0 => SYSCTRL_CLOCK_FREQ_IN0,
clock_source::PLL0 => pll_get_freq(pll::PLL0),
clock_source::PLL1 => pll_get_freq(pll::PLL1),
clock_source::PLL2 => pll_get_freq(pll::PLL2),
clock_source::ACLK => clock_get_freq(clock::ACLK),
}
}
pub fn clock_set_clock_select(which: clock_select, select: u8) {
unsafe {
let ptr = pac::SYSCTL::ptr();
// Seems that PLL2 is the only one that takes a non-boolean clock select
// TODO: take a clock_source directly when we know the meanings of these bits
match which {
clock_select::PLL0_BYPASS => (*ptr).pll0.modify(|_, w| w.bypass().bit(select != 0)),
clock_select::PLL1_BYPASS => (*ptr).pll1.modify(|_, w| w.bypass().bit(select != 0)),
clock_select::PLL2_BYPASS => (*ptr).pll2.modify(|_, w| w.bypass().bit(select != 0)),
clock_select::PLL2 => (*ptr).pll2.modify(|_, w| w.ckin_sel().bits(select)),
clock_select::ACLK => (*ptr).clk_sel0.modify(|_, w| w.aclk_sel().bit(select != 0)),
clock_select::SPI3 => (*ptr).clk_sel0.modify(|_, w| w.spi3_clk_sel().bit(select != 0)),
clock_select::TIMER0 => (*ptr).clk_sel0.modify(|_, w| w.timer0_clk_sel().bit(select != 0)),
clock_select::TIMER1 => (*ptr).clk_sel0.modify(|_, w| w.timer1_clk_sel().bit(select != 0)),
clock_select::TIMER2 => (*ptr).clk_sel0.modify(|_, w| w.timer2_clk_sel().bit(select != 0)),
clock_select::SPI3_SAMPLE => (*ptr).clk_sel1.modify(|_, w| w.spi3_sample_clk_sel().bit(select != 0)),
}
}
}
pub fn clock_get_clock_select(which: clock_select) -> u8 {
unsafe {
let ptr = pac::SYSCTL::ptr();
// Seems that PLL2 is the only one that has a non-boolean clock select
// TODO: return a clock_source directly when we know the meanings of these bits
// meaning seems to be usually:
// 0 IN0
// 1 PLL0
// (2 PLL1)
// it's likely different for _BYPASS, which, I suspect, wires the PLL output to the
// input (IN0 for PLL0 and PLL1, selectable for PLL2)
match which {
clock_select::PLL0_BYPASS => (*ptr).pll0.read().bypass().bit().into(),
clock_select::PLL1_BYPASS => (*ptr).pll1.read().bypass().bit().into(),
clock_select::PLL2_BYPASS => (*ptr).pll2.read().bypass().bit().into(),
clock_select::PLL2 => (*ptr).pll2.read().ckin_sel().bits().into(),
clock_select::ACLK => (*ptr).clk_sel0.read().aclk_sel().bit().into(),
clock_select::SPI3 => (*ptr).clk_sel0.read().spi3_clk_sel().bit().into(),
clock_select::TIMER0 => (*ptr).clk_sel0.read().timer0_clk_sel().bit().into(),
clock_select::TIMER1 => (*ptr).clk_sel0.read().timer1_clk_sel().bit().into(),
clock_select::TIMER2 => (*ptr).clk_sel0.read().timer2_clk_sel().bit().into(),
clock_select::SPI3_SAMPLE => (*ptr).clk_sel1.read().spi3_sample_clk_sel().bit().into(),
}
}
}
pub fn clock_get_freq(clock: clock) -> u32 {
// TODO: all of these are source / threshold, where source can depend on clock_select: generalize this
// to some kind of clock tree
// TODO: clock_source_get_freq(ACLK) calls back into here, don't do this
match clock {
clock::IN0 => clock_source_get_freq(clock_source::IN0),
clock::PLL0 => clock_source_get_freq(clock_source::PLL0),
clock::PLL1 => clock_source_get_freq(clock_source::PLL1),
clock::PLL2 => clock_source_get_freq(clock_source::PLL2),
clock::CPU | clock::DMA | clock::FFT | clock::ACLK | clock::HCLK => match clock_get_clock_select(clock_select::ACLK) {
0 => clock_source_get_freq(clock_source::IN0),
1 => {
clock_source_get_freq(clock_source::PLL0)
/ (2 << clock_get_threshold(threshold::ACLK))
}
_ => panic!("invalid cpu clock select"),
},
clock::SRAM0 => clock_source_get_freq(clock_source::ACLK) / (clock_get_threshold(threshold::SRAM0) + 1),
clock::SRAM1 => clock_source_get_freq(clock_source::ACLK) / (clock_get_threshold(threshold::SRAM1) + 1),
clock::ROM => clock_source_get_freq(clock_source::ACLK) / (clock_get_threshold(threshold::ROM) + 1),
clock::DVP => clock_source_get_freq(clock_source::ACLK) / (clock_get_threshold(threshold::DVP) + 1),
clock::APB0 | clock::GPIO | clock::UART1 | clock::UART2 | clock::UART3 | clock::FPIOA | clock::SHA =>
clock_source_get_freq(clock_source::ACLK) / (clock_get_threshold(threshold::APB0) + 1),
clock::APB1 | clock::AES | clock::OTP =>
clock_source_get_freq(clock_source::ACLK) / (clock_get_threshold(threshold::APB1) + 1),
clock::APB2 => clock_source_get_freq(clock_source::ACLK) / (clock_get_threshold(threshold::APB2) + 1),
clock::AI => clock_source_get_freq(clock_source::PLL1) / (clock_get_threshold(threshold::AI) + 1),
clock::I2S0 => clock_source_get_freq(clock_source::PLL2) / ((clock_get_threshold(threshold::I2S0) + 1) * 2),
clock::I2S1 => clock_source_get_freq(clock_source::PLL2) / ((clock_get_threshold(threshold::I2S1) + 1) * 2),
clock::I2S2 => clock_source_get_freq(clock_source::PLL2) / ((clock_get_threshold(threshold::I2S2) + 1) * 2),
clock::WDT0 => clock_source_get_freq(clock_source::IN0) / ((clock_get_threshold(threshold::WDT0) + 1) * 2),
clock::WDT1 => clock_source_get_freq(clock_source::IN0) / ((clock_get_threshold(threshold::WDT1) + 1) * 2),
clock::SPI0 => clock_source_get_freq(clock_source::PLL0) / ((clock_get_threshold(threshold::SPI0) + 1) * 2),
clock::SPI1 => clock_source_get_freq(clock_source::PLL0) / ((clock_get_threshold(threshold::SPI1) + 1) * 2),
clock::SPI2 => clock_source_get_freq(clock_source::PLL0) / ((clock_get_threshold(threshold::SPI2) + 1) * 2),
clock::I2C0 => clock_source_get_freq(clock_source::PLL0) / ((clock_get_threshold(threshold::I2C0) + 1) * 2),
clock::I2C1 => clock_source_get_freq(clock_source::PLL0) / ((clock_get_threshold(threshold::I2C1) + 1) * 2),
clock::I2C2 => clock_source_get_freq(clock_source::PLL0) / ((clock_get_threshold(threshold::I2C2) + 1) * 2),
clock::SPI3 => {
let source = match clock_get_clock_select(clock_select::SPI3) {
0 => clock_source_get_freq(clock_source::IN0),
1 => clock_source_get_freq(clock_source::PLL0),
_ => panic!("unimplemented clock source"),
};
source / ((clock_get_threshold(threshold::SPI3) + 1) * 2)
}
clock::TIMER0 => {
let source = match clock_get_clock_select(clock_select::TIMER0) {
0 => clock_source_get_freq(clock_source::IN0),
1 => clock_source_get_freq(clock_source::PLL0),
_ => panic!("unimplemented clock source"),
};
source / ((clock_get_threshold(threshold::TIMER0) + 1) * 2)
}
clock::TIMER1 => {
let source = match clock_get_clock_select(clock_select::TIMER1) {
0 => clock_source_get_freq(clock_source::IN0),
1 => clock_source_get_freq(clock_source::PLL0),
_ => panic!("unimplemented clock source"),
};
source / ((clock_get_threshold(threshold::TIMER1) + 1) * 2)
}
clock::TIMER2 => {
let source = match clock_get_clock_select(clock_select::TIMER2) {
0 => clock_source_get_freq(clock_source::IN0),
1 => clock_source_get_freq(clock_source::PLL0),
_ => panic!("unimplemented clock source"),
};
source / ((clock_get_threshold(threshold::TIMER2) + 1) * 2)
}
clock::RTC => clock_source_get_freq(clock_source::IN0),
}
}
fn reset_ctl(reset: reset, rst_value: bool) {
unsafe {
let ptr = pac::SYSCTL::ptr();
match reset {
reset::SOC => (*ptr).soft_reset.modify(|_, w| w.soft_reset().bit(rst_value)),
reset::ROM => (*ptr).peri_reset.modify(|_, w| w.rom_reset().bit(rst_value)),
reset::DMA => (*ptr).peri_reset.modify(|_, w| w.dma_reset().bit(rst_value)),
reset::AI => (*ptr).peri_reset.modify(|_, w| w.ai_reset().bit(rst_value)),
reset::DVP => (*ptr).peri_reset.modify(|_, w| w.dvp_reset().bit(rst_value)),
reset::FFT => (*ptr).peri_reset.modify(|_, w| w.fft_reset().bit(rst_value)),
reset::GPIO => (*ptr).peri_reset.modify(|_, w| w.gpio_reset().bit(rst_value)),
reset::SPI0 => (*ptr).peri_reset.modify(|_, w| w.spi0_reset().bit(rst_value)),
reset::SPI1 => (*ptr).peri_reset.modify(|_, w| w.spi1_reset().bit(rst_value)),
reset::SPI2 => (*ptr).peri_reset.modify(|_, w| w.spi2_reset().bit(rst_value)),
reset::SPI3 => (*ptr).peri_reset.modify(|_, w| w.spi3_reset().bit(rst_value)),
reset::I2S0 => (*ptr).peri_reset.modify(|_, w| w.i2s0_reset().bit(rst_value)),
reset::I2S1 => (*ptr).peri_reset.modify(|_, w| w.i2s1_reset().bit(rst_value)),
reset::I2S2 => (*ptr).peri_reset.modify(|_, w| w.i2s2_reset().bit(rst_value)),
reset::I2C0 => (*ptr).peri_reset.modify(|_, w| w.i2c0_reset().bit(rst_value)),
reset::I2C1 => (*ptr).peri_reset.modify(|_, w| w.i2c1_reset().bit(rst_value)),
reset::I2C2 => (*ptr).peri_reset.modify(|_, w| w.i2c2_reset().bit(rst_value)),
reset::UART1 => (*ptr).peri_reset.modify(|_, w| w.uart1_reset().bit(rst_value)),
reset::UART2 => (*ptr).peri_reset.modify(|_, w| w.uart2_reset().bit(rst_value)),
reset::UART3 => (*ptr).peri_reset.modify(|_, w| w.uart3_reset().bit(rst_value)),
reset::AES => (*ptr).peri_reset.modify(|_, w| w.aes_reset().bit(rst_value)),
reset::FPIOA => (*ptr).peri_reset.modify(|_, w| w.fpioa_reset().bit(rst_value)),
reset::TIMER0 => (*ptr).peri_reset.modify(|_, w| w.timer0_reset().bit(rst_value)),
reset::TIMER1 => (*ptr).peri_reset.modify(|_, w| w.timer1_reset().bit(rst_value)),
reset::TIMER2 => (*ptr).peri_reset.modify(|_, w| w.timer2_reset().bit(rst_value)),
reset::WDT0 => (*ptr).peri_reset.modify(|_, w| w.wdt0_reset().bit(rst_value)),
reset::WDT1 => (*ptr).peri_reset.modify(|_, w| w.wdt1_reset().bit(rst_value)),
reset::SHA => (*ptr).peri_reset.modify(|_, w| w.sha_reset().bit(rst_value)),
reset::RTC => (*ptr).peri_reset.modify(|_, w| w.rtc_reset().bit(rst_value)),
}
}
}
pub fn reset(reset: reset) {
reset_ctl(reset, true);
usleep(10);
reset_ctl(reset, false);
}
/** Select DMA handshake for a channel */
pub fn dma_select(channel: dma_channel, select: dma_select)
{
unsafe {
use dma_channel::*;
let ptr = pac::SYSCTL::ptr();
match channel {
CHANNEL0 => (*ptr).dma_sel0.modify(|_,w| w.dma_sel0().variant(select)),
CHANNEL1 => (*ptr).dma_sel0.modify(|_,w| w.dma_sel1().variant(select)),
CHANNEL2 => (*ptr).dma_sel0.modify(|_,w| w.dma_sel2().variant(select)),
CHANNEL3 => (*ptr).dma_sel0.modify(|_,w| w.dma_sel3().variant(select)),
CHANNEL4 => (*ptr).dma_sel0.modify(|_,w| w.dma_sel4().variant(select)),
CHANNEL5 => (*ptr).dma_sel1.modify(|_,w| w.dma_sel5().variant(select)),
}
}
}
/** Return whether the selected PLL has achieved lock */
fn pll_is_lock(pll: pll) -> bool {
let ptr = pac::SYSCTL::ptr();
let pll_lock = unsafe { (*ptr).pll_lock.read() };
match pll {
pll::PLL0 => pll_lock.pll_lock0().bits() == 3,
pll::PLL1 => (pll_lock.pll_lock1().bits() & 1) == 1,
pll::PLL2 => (pll_lock.pll_lock2().bits() & 1) == 1,
}
}
/** Clear PLL slip, this is done repeatedly until lock is achieved */
fn pll_clear_slip(pll: pll) -> bool {
let ptr = pac::SYSCTL::ptr();
unsafe {
(*ptr).pll_lock.modify(|_,w|
match pll {
pll::PLL0 => w.pll_slip_clear0().set_bit(),
pll::PLL1 => w.pll_slip_clear1().set_bit(),
pll::PLL2 => w.pll_slip_clear2().set_bit(),
}
);
}
pll_is_lock(pll)
}
fn pll_source_set_freq(pll: pll, source: clock_source, freq: u32) -> Result<u32,()> {
use pll::*;
/* PLL0 and 1 can only source from IN0 */
if (pll == PLL0 || pll == PLL1) && source != clock_source::IN0 {
return Err(());
}
let freq_in = clock_source_get_freq(source);
if freq_in == 0 {
return Err(());
}
if let Some(found) = pll_compute::compute_params(freq_in, freq) {
let ptr = pac::SYSCTL::ptr();
unsafe {
match pll {
PLL0 => {
(*ptr).pll0.modify(|_,w|
w.clkr().bits(found.clkr)
.clkf().bits(found.clkf)
.clkod().bits(found.clkod)
.bwadj().bits(found.bwadj)
);
}
PLL1 => {
(*ptr).pll1.modify(|_,w|
w.clkr().bits(found.clkr)
.clkf().bits(found.clkf)
.clkod().bits(found.clkod)
.bwadj().bits(found.bwadj)
);
}
PLL2 => {
(*ptr).pll2.modify(|_,w|
w.ckin_sel().bits(pll2_source_to_cksel(source))
.clkr().bits(found.clkr)
.clkf().bits(found.clkf)
.clkod().bits(found.clkod)
.bwadj().bits(found.bwadj)
);
}
}
}
Ok(pll_get_freq(pll))
} else {
Err(())
}
}
/**
* @brief Init PLL freqency
* @param[in] pll The PLL id
* @param[in] pll_freq The desired frequency in Hz
*/
pub fn pll_set_freq(pll: pll, freq: u32) -> Result<u32,()> {
let ptr = pac::SYSCTL::ptr();
use pll::*;
/* 1. Change CPU CLK to XTAL */
if pll == PLL0 {
clock_set_clock_select(clock_select::ACLK, 0 /* clock_source::IN0 */);
}
/* 2. Disable PLL output */
unsafe {
match pll {
PLL0 => (*ptr).pll0.modify(|_,w| w.out_en().clear_bit()),
PLL1 => (*ptr).pll1.modify(|_,w| w.out_en().clear_bit()),
PLL2 => (*ptr).pll2.modify(|_,w| w.out_en().clear_bit()),
};
}
/* 3. Turn off PLL */
unsafe {
match pll {
PLL0 => (*ptr).pll0.modify(|_,w| w.pwrd().clear_bit()),
PLL1 => (*ptr).pll1.modify(|_,w| w.pwrd().clear_bit()),
PLL2 => (*ptr).pll2.modify(|_,w| w.pwrd().clear_bit()),
};
}
/* 4. Set PLL to new value */
let result = if pll == PLL2 {
pll_source_set_freq(pll, pll2_cksel_to_source(clock_get_clock_select(clock_select::PLL2)), freq)
} else {
pll_source_set_freq(pll, clock_source::IN0, freq)
};
/* 5. Power on PLL */
unsafe {
match pll {
PLL0 => (*ptr).pll0.modify(|_,w| w.pwrd().set_bit()),
PLL1 => (*ptr).pll1.modify(|_,w| w.pwrd().set_bit()),
PLL2 => (*ptr).pll2.modify(|_,w| w.pwrd().set_bit()),
};
}
/* wait >100ns */
usleep(1);
/* 6. Reset PLL then Release Reset*/
unsafe {
match pll {
PLL0 => (*ptr).pll0.modify(|_,w| w.reset().clear_bit()),
PLL1 => (*ptr).pll1.modify(|_,w| w.reset().clear_bit()),
PLL2 => (*ptr).pll2.modify(|_,w| w.reset().clear_bit()),
};
match pll {
PLL0 => (*ptr).pll0.modify(|_,w| w.reset().set_bit()),
PLL1 => (*ptr).pll1.modify(|_,w| w.reset().set_bit()),
PLL2 => (*ptr).pll2.modify(|_,w| w.reset().set_bit()),
};
}
/* wait >100ns */
usleep(1);
unsafe {
match pll {
PLL0 => (*ptr).pll0.modify(|_,w| w.reset().clear_bit()),
PLL1 => (*ptr).pll1.modify(|_,w| w.reset().clear_bit()),
PLL2 => (*ptr).pll2.modify(|_,w| w.reset().clear_bit()),
};
}
/* 7. Get lock status, wait PLL stable */
while !pll_is_lock(pll) {
pll_clear_slip(pll);
}
/* 8. Enable PLL output */
unsafe {
match pll {
PLL0 => (*ptr).pll0.modify(|_,w| w.out_en().set_bit()),
PLL1 => (*ptr).pll1.modify(|_,w| w.out_en().set_bit()),
PLL2 => (*ptr).pll2.modify(|_,w| w.out_en().set_bit()),
};
}
/* 9. Change CPU CLK to PLL */
if pll == PLL0 {
clock_set_clock_select(clock_select::ACLK, 1 /*clock_source::PLL0*/);
}
result
}

@ -0,0 +1,569 @@
/** PLL configuration */
#[derive(Debug, PartialEq, Eq)]
pub struct Params {
pub clkr: u8,
pub clkf: u8,
pub clkod: u8,
pub bwadj: u8,
}
/*
* The PLL included with the Kendryte K210 appears to be a True Circuits, Inc.
* General-Purpose PLL. The logical layout of the PLL with internal feedback is
* approximately the following:
*
* +---------------+
* |reference clock|
* +---------------+
* |
* v
* +--+
* |/r|
* +--+
* |
* v
* +-------------+
* |divided clock|
* +-------------+
* |
* v
* +--------------+
* |phase detector|<---+
* +--------------+ |
* | |
* v +--------------+
* +---+ |feedback clock|
* |VCO| +--------------+
* +---+ ^
* | +--+ |
* +--->|/f|---+
* | +--+
* v
* +---+
* |/od|
* +---+
* |
* v
* +------+
* |output|
* +------+
*
* The k210 PLLs have three factors: r, f, and od. Because of the feedback mode,
* the effect of the division by f is to multiply the input frequency. The
* equation for the output rate is
* rate = (rate_in * f) / (r * od).
* Moving knowns to one side of the equation, we get
* rate / rate_in = f / (r * od)
* Rearranging slightly,
* abs_error = abs((rate / rate_in) - (f / (r * od))).
* To get relative, error, we divide by the expected ratio
* error = abs((rate / rate_in) - (f / (r * od))) / (rate / rate_in).
* Simplifying,
* error = abs(1 - f / (r * od)) / (rate / rate_in)
* error = abs(1 - (f * rate_in) / (r * od * rate))
* Using the constants ratio = rate / rate_in and inv_ratio = rate_in / rate,
* error = abs((f * inv_ratio) / (r * od) - 1)
* This is the error used in evaluating parameters.
*
* r and od are four bits each, while f is six bits. Because r and od are
* multiplied together, instead of the full 256 values possible if both bits
* were used fully, there are only 97 distinct products. Combined with f, there
* are 6208 theoretical settings for the PLL. However, most of these settings
* can be ruled out immediately because they do not have the correct ratio.
*
* In addition to the constraint of approximating the desired ratio, parameters
* must also keep internal pll frequencies within acceptable ranges. The divided
* clock's minimum and maximum frequencies have a ratio of around 128. This
* leaves fairly substantial room to work with, especially since the only
* affected parameter is r. The VCO's minimum and maximum frequency have a ratio
* of 5, which is considerably more restrictive.
*
* The r and od factors are stored in a table. This is to make it easy to find
* the next-largest product. Some products have multiple factorizations, but
* only when one factor has at least a 2.5x ratio to the factors of the other
* factorization. This is because any smaller ratio would not make a difference
* when ensuring the VCO's frequency is within spec.
*
* Throughout the calculation function, fixed point arithmetic is used. Because
* the range of rate and rate_in may be up to 1.75 GHz, or around 2^30, 64-bit
* 32.32 fixed-point numbers are used to represent ratios. In general, to
* implement division, the numerator is first multiplied by 2^32. This gives a
* result where the whole number part is in the upper 32 bits, and the fraction
* is in the lower 32 bits.
*
* In general, rounding is done to the closest integer. This helps find the best
* approximation for the ratio. Rounding in one direction (e.g down) could cause
* the function to miss a better ratio with one of the parameters increased by
* one.
*/
const VCO_MIN: u64 = 340_000_000;
const VCO_MAX: u64 = 1_750_000_000;
const DIV_MIN: u32 = 13_300_000;
const DIV_MAX: u32 = 1_750_000_000;
const R_MIN: u32 = 1;
const R_MAX: u32 = 16;
const F_MIN: u32 = 1;
const F_MAX: u32 = 64;
const OD_MIN: u32 = 1;
const OD_MAX: u32 = 16;
const OUT_MIN: u32 = (VCO_MIN as u32) / OD_MAX; /* 21_250_000 */
const OUT_MAX: u32 = (VCO_MAX as u32) / OD_MIN; /* 1_750_000_000 */
const IN_MIN: u32 = DIV_MIN * R_MIN; /* 13_300_000 */
const IN_MAX: u32 = OUT_MAX; /* 1_750_000_000 */
/*
* The factors table was generated with the following python code:
*
* def p(x, y):
* return (1.0*x/y > 2.5) or (1.0*y/x > 2.5)
*
* factors = {}
* for i in range(1, 17):
* for j in range(1, 17):
* fs = factors.get(i*j) or []
* if fs == [] or all([
* (p(i, x) and p(i, y)) or (p(j, x) and p(j, y))
* for (x, y) in fs]):
* fs.append((i, j))
* factors[i*j] = fs
*
* for k, l in sorted(factors.items()):
* for v in l:
* print("pack(%s, %s)," % v)
*/
struct Factor {
packed: u8,
}
/* Apologies, but there are no native bitfields (yet) afaik */
const fn pack(r: u32, od: u32) -> Factor {
Factor { packed: (((((r as u8) - 1) & 0xF) << 4) | (((od as u8) - 1) & 0xF)) }
}
const fn unpack_r(factor: &&Factor) -> u32 {
(((factor.packed as u32) >> 4) & 0xF) + 1
}
const fn unpack_od(factor: &&Factor) -> u32 {
((factor.packed as u32) & 0xF) + 1
}
static FACTORS: &'static [Factor] = &[
pack(1, 1),
pack(1, 2),
pack(1, 3),
pack(1, 4),
pack(1, 5),
pack(1, 6),
pack(1, 7),
pack(1, 8),
pack(1, 9),
pack(3, 3),
pack(1, 10),
pack(1, 11),
pack(1, 12),
pack(3, 4),
pack(1, 13),
pack(1, 14),
pack(1, 15),
pack(3, 5),
pack(1, 16),
pack(4, 4),
pack(2, 9),
pack(2, 10),
pack(3, 7),
pack(2, 11),
pack(2, 12),
pack(5, 5),
pack(2, 13),
pack(3, 9),
pack(2, 14),
pack(2, 15),
pack(2, 16),
pack(3, 11),
pack(5, 7),
pack(3, 12),
pack(3, 13),
pack(4, 10),
pack(3, 14),
pack(4, 11),
pack(3, 15),
pack(3, 16),
pack(7, 7),
pack(5, 10),
pack(4, 13),
pack(6, 9),
pack(5, 11),
pack(4, 14),
pack(4, 15),
pack(7, 9),
pack(4, 16),
pack(5, 13),
pack(6, 11),
pack(5, 14),
pack(6, 12),
pack(5, 15),
pack(7, 11),
pack(6, 13),
pack(5, 16),
pack(9, 9),
pack(6, 14),
pack(8, 11),
pack(6, 15),
pack(7, 13),
pack(6, 16),
pack(7, 14),
pack(9, 11),
pack(10, 10),
pack(8, 13),
pack(7, 15),
pack(9, 12),
pack(10, 11),
pack(7, 16),
pack(9, 13),
pack(8, 15),
pack(11, 11),
pack(9, 14),
pack(8, 16),
pack(10, 13),
pack(11, 12),
pack(9, 15),
pack(10, 14),
pack(11, 13),
pack(9, 16),
pack(10, 15),
pack(11, 14),
pack(12, 13),
pack(10, 16),
pack(11, 15),
pack(12, 14),
pack(13, 13),
pack(11, 16),
pack(12, 15),
pack(13, 14),
pack(12, 16),
pack(13, 15),
pack(14, 14),
pack(13, 16),
pack(14, 15),
pack(14, 16),
pack(15, 15),
pack(15, 16),
pack(16, 16),
];
/* Divide and round to the closest integer */
fn div_round_closest(n: u64, d: u32) -> u64 {
let _d: u64 = d as u64;
(n + (_d / 2)) / _d
}
/* Integer with that bit set */
fn bit(bit: u8) -> u64 {
1 << bit
}
/* | a - b | */
fn abs_diff(a: u32, b: u32) -> u32 {
if a > b {
a - b
} else {
b - a
}
}
pub fn compute_params(freq_in: u32, freq_out: u32) -> Option<Params> {
let mut best: Option<Params> = None;
let mut factors = FACTORS.iter().peekable();
let (mut error, mut best_error): (i64, i64);
let (ratio, inv_ratio): (u64, u64); /* fixed point 32.32 ratio of the freqs */
let max_r: u32;
let (mut r, mut f, mut od): (u32, u32, u32);
/*
* Can't go over 1.75 GHz or under 21.25 MHz due to limitations on the
* VCO frequency. These are not the same limits as below because od can
* reduce the output frequency by 16.
*/
if freq_out > OUT_MAX || freq_out < OUT_MIN {
return None;
}
/* Similar restrictions on the input ratio */
if freq_in > IN_MAX || freq_in < IN_MIN {
return None;
}
ratio = div_round_closest((freq_out as u64) << 32, freq_in);
inv_ratio = div_round_closest((freq_in as u64) << 32, freq_out);
/* Can't increase by more than 64 or reduce by more than 256 */
if freq_out > freq_in && ratio > (64 << 32) {
return None;
} else if freq_out <= freq_in && inv_ratio > (256 << 32) {
return None;
}
/*
* The divided clock (freq_in / r) must stay between 1.75 GHz and 13.3
* MHz. There is no minimum, since the only way to get a higher input
* clock than 26 MHz is to use a clock generated by a PLL. Because PLLs
* cannot output frequencies greater than 1.75 GHz, the minimum would
* never be greater than one.
*/
max_r = freq_in / DIV_MIN;
/* Variables get immediately incremented, so start at -1th iteration */
f = 0;
r = 0;
od = 0;
best_error = i64::max_value();
error = best_error;
/* Always try at least one ratio */
'outer: loop {
/*
* Whether we swapped r and od while enforcing frequency limits
*/
let mut swapped: bool = false;
let last_od: u32 = od;
let last_r: u32 = r;
/*
* Try the next largest value for f (or r and od) and
* recalculate the other parameters based on that
*/
if freq_out > freq_in {
/*
* Skip factors of the same product if we already tried
* out that product
*/
while r * od == last_r * last_od {
match factors.next() {
Some(factor) => {
r = unpack_r(&factor);
od = unpack_od(&factor);
},
None => break 'outer,
}
}
/* Round close */
f = ((((r * od) as u64) * ratio + bit(31)) >> 32) as u32;
if f > F_MAX {
f = F_MAX;
}
} else {
f += 1;
let tmp: u64 = (f as u64) * inv_ratio;
let round_up: bool = tmp & bit(31) != 0;
let goal: u32 = ((tmp >> 32) as u32) + (round_up as u32);
let (err, last_err): (u32, u32);
/*
* Get the next r/od pair in factors. If the last_* pair is better,
* then we will use it instead, so don't call next until after we're
* sure we won't need this pair.
*/
loop {
match factors.peek() {
Some(factor) => {
r = unpack_r(factor);
od = unpack_od(factor)
},
None => break 'outer,
}
if r * od < goal {
factors.next();
} else {
break;
}
}
/*
* This is a case of double rounding. If we rounded up
* above, we need to round down (in cases of ties) here.
* This prevents off-by-one errors resulting from
* choosing X+2 over X when X.Y rounds up to X+1 and
* there is no r * od = X+1. For the converse, when X.Y
* is rounded down to X, we should choose X+1 over X-1.
*/
err = abs_diff(r * od, goal);
last_err = abs_diff(last_r * last_od, goal);
if last_err < err || (round_up && last_err == err) {
r = last_r;
od = last_od;
} else {
factors.next();
}
}
/*
* Enforce limits on internal clock frequencies. If we
* aren't in spec, try swapping r and od. If everything is
* in-spec, calculate the relative error.
*/
loop {
/*
* Whether the intermediate frequencies are out-of-spec
*/
let mut out_of_spec: bool = false;
if r > max_r {
out_of_spec = true;
} else {
/*
* There is no way to only divide once; we need
* to examine the frequency with and without the
* effect of od.
*/
let vco: u64 = div_round_closest((freq_in as u64) * (f as u64), r);
if vco > VCO_MAX || vco < VCO_MIN {
out_of_spec = true;
}
}
if out_of_spec {
if !swapped {
let tmp: u32 = r;
r = od;
od = tmp;
swapped = true;
continue;
} else {
/*
* Try looking ahead to see if there are
* additional factors for the same
* product.
*/
match factors.peek() {
Some(factor) => {
let new_r: u32 = unpack_r(factor);
let new_od: u32 = unpack_od(factor);
if r * od == new_r * new_od {
factors.next();
r = new_r;
od = new_od;
swapped = false;
continue;
} else {
break;
}
},
None => break 'outer,
}
}
}
error = div_round_closest((f as u64) * inv_ratio, r * od) as i64;
/* The lower 16 bits are spurious */
error = i64::abs(error - (bit(32) as i64)) >> 16;
if error < best_error {
best_error = error;
best = Some(Params {
clkr: (r - 1) as u8,
clkf: (f - 1) as u8,
clkod: (od - 1) as u8,
bwadj: (f - 1) as u8,
});
}
break;
}
if error == 0 {
break;
}
}
return best;
}
#[cfg(test)]
mod tests {
use super::*;
fn brute_force_params(freq_in: u32, freq_out: u32) -> Option<Params> {
let mut best: Option<Params> = None;
let (mut error, mut best_error): (i64, i64);
let (max_r, inv_ratio): (u32, u64);
best_error = i64::max_value();
max_r = u32::min(R_MAX, (freq_in / DIV_MIN) as u32);
inv_ratio = div_round_closest((freq_in as u64) << 32, freq_out);
/* Brute force it */
for r in R_MIN..=max_r {
for f in F_MIN..=F_MAX {
for od in OD_MIN..=OD_MAX {
let vco: u64 = div_round_closest((freq_in as u64) * (f as u64), r);
if vco > VCO_MAX || vco < VCO_MIN {
continue;
}
error = div_round_closest((f as u64) * inv_ratio, r * od) as i64;
/* The lower 16 bits are spurious */
error = i64::abs(error - (bit(32) as i64)) >> 16;
if error < best_error {
best_error = error;
best = Some(Params {
clkr: (r - 1) as u8,
clkf: (f - 1) as u8,
clkod: (od - 1) as u8,
bwadj: (f - 1) as u8,
});
}
}
}
}
return best;
}
fn params_equal(_a: Option<Params>, _b: Option<Params>) -> bool {
match (_a, _b) {
(None, None) => true,
(Some(_), None) => false,
(None, Some(_)) => false,
(Some(a), Some(b)) => {
let ar: u32 = (a.clkr + 1) as u32;
let af: u32 = (a.clkf + 1) as u32;
let aod: u32 = (a.clkod + 1) as u32;
let br: u32 = (b.clkr + 1) as u32;
let bf: u32 = (b.clkf + 1) as u32;
let bod: u32 = (b.clkod + 1) as u32;
af * br * bod == bf * ar * aod
}
}
}
fn verify_compute_params(freq_in: u32, freq_out: u32) -> bool {
params_equal(compute_params(freq_in, freq_out), brute_force_params(freq_in, freq_out))
}
#[test]
fn test_compute_params() {
assert_eq!(compute_params(26_000_000, 0), None);
assert_eq!(compute_params(0, 390_000_000), None);
assert_eq!(compute_params(26_000_000, 2_000_000_000), None);
assert_eq!(compute_params(2_000_000_000, 390_000_000), None);
assert_eq!(compute_params(20_000_000, 1_500_000_000), None);
assert!(verify_compute_params(26_000_000, 1_500_000_000));
assert!(verify_compute_params(26_000_000, 1_000_000_000));
assert!(verify_compute_params(26_000_000, 800_000_000));
assert!(verify_compute_params(26_000_000, 700_000_000));
assert!(verify_compute_params(26_000_000, 300_000_000));
assert!(verify_compute_params(26_000_000, 45_158_400));
assert!(verify_compute_params(26_000_000, 27_000_000));
assert!(verify_compute_params(27_000_000, 26_000_000));
assert!(verify_compute_params(390_000_000, 26_000_000));
assert!(verify_compute_params(390_000_000, 383_846_400));
}
}

@ -0,0 +1,15 @@
#![allow(unused)]
//! Miscelleneous utilities for SoC functions (private)
pub fn set_bit(inval: u32, bit: u8, state: bool) -> u32 {
if state {
inval | (1 << u32::from(bit))
} else {
inval & !(1 << u32::from(bit))
}
}
pub fn get_bit(inval: u32, bit: u8) -> bool {
(inval & (1 << u32::from(bit))) != 0
}

@ -0,0 +1 @@
* @rust-embedded/riscv

@ -0,0 +1,4 @@
block_labels = ["needs-decision"]
delete_merged_branches = true
required_approvals = 1
status = ["continuous-integration/travis-ci/push"]

@ -0,0 +1,5 @@
Cargo.lock
target/
bin/*.after
bin/*.before
bin/*.o

@ -0,0 +1,51 @@
language: rust
env:
- TARGET=x86_64-unknown-linux-gnu
- TARGET=riscv32imac-unknown-none-elf
- TARGET=riscv64imac-unknown-none-elf
- TARGET=riscv64gc-unknown-none-elf
rust:
- nightly
- stable
- 1.42.0 # MSRV
if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master)
matrix:
allow_failures:
- rust: nightly
include:
- env: CHECK_BLOBS=1
rust:
language: bash
if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master)
- env: RUSTFMT=1
rust: stable
if: (branch = staging OR branch = trying OR branch = master) OR (type = pull_request AND branch = master)
install:
- ci/install.sh
script:
- ci/script.sh
cache:
cargo: true
directories:
- gcc
branches:
only:
- master
- staging
- trying
notifications:
email:
on_success: never

@ -0,0 +1,45 @@
# Change Log
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
## [v0.6.0] - 2020-06-20
### Changed
- `Mtvec::trap_mode()`, `Stvec::trap_mode()` and `Utvec::trap_mode()` functions now return `Option<TrapMode>` (breaking change)
- Updated Minimum Supported Rust Version to 1.42.0
- Use `llvm_asm!` instead of `asm!`
### Removed
- vexriscv-specific registers were moved to the `vexriscv` crate
## [v0.5.6] - 2020-03-14
### Added
- Added vexriscv-specific registers
## [v0.5.5] - 2020-02-28
### Added
- Added `riscv32i-unknown-none-elf` target support
- Added user trap setup and handling registers
- Added write methods for the `mip` and `satp` registers
- Added `mideleg` register
- Added Changelog
### Changed
- Fixed MSRV by restricting the upper bound of `bare-metal` version
[Unreleased]: https://github.com/rust-embedded/riscv/compare/v0.6.0...HEAD
[v0.6.0]: https://github.com/rust-embedded/riscv/compare/v0.5.6...v0.6.0
[v0.5.6]: https://github.com/rust-embedded/riscv/compare/v0.5.5...v0.5.6
[v0.5.5]: https://github.com/rust-embedded/riscv/compare/v0.5.4...v0.5.5

@ -0,0 +1,37 @@
# The Rust Code of Conduct
## Conduct
**Contact**: [RISC-V team](https://github.com/rust-embedded/wg#the-riscv-team)
* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all.
* Please be kind and courteous. There's no need to be mean or rude.
* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [RISC-V team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
## Moderation
These are the policies for upholding our community's standards of conduct.
1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
3. Moderators will first respond to such remarks with a warning.
4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off.
5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed.
8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others.
In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely.
And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust.
The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org).
*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).*
[team]: https://github.com/rust-embedded/wg#the-riscv-team

@ -0,0 +1,21 @@
[package]
name = "riscv"
version = "0.6.0"
repository = "https://github.com/rust-embedded/riscv"
authors = ["The RISC-V Team <risc-v@teams.rust-embedded.org>"]
categories = ["embedded", "hardware-support", "no-std"]
description = "Low level access to RISC-V processors"
keywords = ["riscv", "register", "peripheral"]
license = "ISC"
[dependencies]
bare-metal = "0.2.5"
bitflags = "1.0"
bit_field = "0.10.0"
log = "0.4"
[build-dependencies]
riscv-target = "0.1.2"
[features]
inline-asm = []

@ -0,0 +1,41 @@
[![crates.io](https://img.shields.io/crates/d/riscv.svg)](https://crates.io/crates/riscv)
[![crates.io](https://img.shields.io/crates/v/riscv.svg)](https://crates.io/crates/riscv)
[![Build Status](https://travis-ci.org/rust-embedded/riscv.svg?branch=master)](https://travis-ci.org/rust-embedded/riscv)
# `riscv`
> Low level access to RISC-V processors
This project is developed and maintained by the [RISC-V team][team].
## [Documentation](https://docs.rs/crate/riscv)
## Minimum Supported Rust Version (MSRV)
This crate is guaranteed to compile on stable Rust 1.42.0 and up. It *might*
compile with older versions but that may change in any new patch release.
## License
Copyright 2019-2020 [RISC-V team][team]
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
## Code of Conduct
Contribution to this crate is organized under the terms of the [Rust Code of
Conduct][CoC], the maintainer of this crate, the [RISC-V team][team], promises
to intervene to uphold that code of conduct.
[CoC]: CODE_OF_CONDUCT.md
[team]: https://github.com/rust-embedded/wg#the-riscv-team

@ -0,0 +1,454 @@
#include "asm.h"
.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
// RISC-V hypervisor instructions.
// The switch for enabling LLVM support for asm generation.
// #define LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
.section .text.__hfence_gvma
.global __hfence_gvma
__hfence_gvma:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hfence.gvma a0, a1
#else
.word 1656029299
#endif
ret
.section .text.__hfence_vvma
.global __hfence_vvma
__hfence_vvma:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hfence.vvma a0, a1
#else
.word 582287475
#endif
ret
.section .text.__hlv_b
.global __hlv_b
__hlv_b:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hlv.b a0, a0
#else
.word 1610958195
#endif
ret
.section .text.__hlv_bu
.global __hlv_bu
__hlv_bu:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hlv.bu a0, a0
#else
.word 1612006771
#endif
ret
.section .text.__hlv_h
.global __hlv_h
__hlv_h:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hlv.h a0, a0
#else
.word 1678067059
#endif
ret
.section .text.__hlv_hu
.global __hlv_hu
__hlv_hu:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hlv.hu a0, a0
#else
.word 1679115635
#endif
ret
.section .text.__hlvx_hu
.global __hlvx_hu
__hlvx_hu:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hlvx.hu a0, a0
#else
.word 1681212787
#endif
ret
.section .text.__hlv_w
.global __hlv_w
__hlv_w:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hlv.w a0, a0
#else
.word 1745175923
#endif
ret
.section .text.__hlvx_wu
.global __hlvx_wu
__hlvx_wu:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hlvx.wu a0, a0
#else
.word 1748321651
#endif
ret
.section .text.__hsv_b
.global __hsv_b
__hsv_b:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hsv.b a0, a1
#else
.word 1656045683
#endif
ret
.section .text.__hsv_h
.global __hsv_h
__hsv_h:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hsv.h a0, a1
#else
.word 1723154547
#endif
ret
.section .text.__hsv_w
.global __hsv_w
__hsv_w:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hsv.w a0, a1
#else
.word 1790263411
#endif
ret
.section .text.__hlv_wu
.global __hlv_wu
__hlv_wu:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hlv.wu a0, a0
#else
.word 1746224499
#endif
ret
.section .text.__hlv_d
.global __hlv_d
__hlv_d:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hlv.d a0, a0
#else
.word 1812284787
#endif
ret
.section .text.__hsv_d
.global __hsv_d
__hsv_d:
#ifdef LLVM_RISCV_HYPERVISOR_EXTENSION_SUPPORT
hsv.d a0, a1
#else
.word 1857372275
#endif
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
// Hypervisor Trap Setup
RW(0x600, hstatus) // Hypervisor status register
RW(0x602, hedeleg) // Hypervisor exception delegation register
RW(0x603, hideleg) // Hypervisor interrupt delegation register
RW(0x604, hie) // Hypervisor interrupt-enable register
RW(0x606, hcounteren) // Hypervisor counter enable
RW(0x607, hgeie) // Hypervisor guest external interrupt-enable register
// Hypervisor Trap Handling
RW(0x643, htval) // Hypervisor bad guest physical address
RW(0x644, hip) // Hypervisor interrupt pending
RW(0x645, hvip) // Hypervisor virtual interrupt pending
RW(0x64a, htinst) // Hypervisor trap instruction (transformed)
RW(0xe12, hgeip) // Hypervisor guest external interrupt pending
// Hypervisor Protection and Translation
RO(0x680, hgatp) // Hypervisor guest address translation and protection
// Debug/Trace Registers
RW(0x6a8, hcontext) // Hypervisor-mode context register
// Hypervisor Counter/Timer Virtualization Registers
RW(0x605, htimedelta) // Delta for VS/VU-mode timer
RW32(0x615, htimedeltah) // Upper 32 bits of {\tt htimedelta}, RV32 only
// Virtual Supervisor Registers
RW(0x200, vsstatus) // Virtual supervisor status register
RW(0x204, vsie) // Virtual supervisor interrupt-enable register
RW(0x205, vstvec) // Virtual supervisor trap handler base address
RW(0x240, vsscratch) // Virtual supervisor scratch register
RW(0x241, vsepc) // Virtual supervisor exception program counter
RW(0x242, vscause) // Virtual supervisor trap cause
RW(0x243, vstval) // Virtual supervisor bad address or instruction
RW(0x244, vsip) // Virtual supervisor interrupt pending
RW(0x280, vsatp) // Virtual supervisor address translation and protection

@ -0,0 +1,48 @@
#ifndef __ASM_H
#define __ASM_H
#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
#endif /* __ASM_H */

@ -0,0 +1,20 @@
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 = "riscv"
riscv64-unknown-elf-gcc -c -mabi=ilp32 -march=rv32i asm.S -o bin/$crate.o
riscv64-unknown-elf-ar crs bin/riscv32i-unknown-none-elf.a bin/$crate.o
riscv64-unknown-elf-gcc -c -mabi=ilp32 -march=rv32ic asm.S -o bin/$crate.o
riscv64-unknown-elf-ar crs bin/riscv32ic-unknown-none-elf.a bin/$crate.o
riscv64-unknown-elf-gcc -c -mabi=lp64 -march=rv64i asm.S -o bin/$crate.o
riscv64-unknown-elf-ar crs bin/riscv64i-unknown-none-elf.a bin/$crate.o
riscv64-unknown-elf-gcc -c -mabi=lp64 -march=rv64ic asm.S -o bin/$crate.o
riscv64-unknown-elf-ar crs bin/riscv64ic-unknown-none-elf.a bin/$crate.o
Remove-Item bin/$crate.o

@ -0,0 +1,22 @@
#!/bin/bash
set -euxo pipefail
crate=riscv
# 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=rv32i asm.S -o bin/$crate.o
ar crs bin/riscv32i-unknown-none-elf.a bin/$crate.o
riscv64-unknown-elf-gcc -c -mabi=ilp32 -march=rv32ic asm.S -o bin/$crate.o
ar crs bin/riscv32ic-unknown-none-elf.a bin/$crate.o
riscv64-unknown-elf-gcc -c -mabi=lp64 -march=rv64i asm.S -o bin/$crate.o
ar crs bin/riscv64i-unknown-none-elf.a bin/$crate.o
riscv64-unknown-elf-gcc -c -mabi=lp64 -march=rv64ic asm.S -o bin/$crate.o
ar crs bin/riscv64ic-unknown-none-elf.a bin/$crate.o
rm bin/$crate.o

@ -0,0 +1,35 @@
extern crate riscv_target;
use riscv_target::Target;
use std::path::PathBuf;
use std::{env, fs};
fn main() {
let target = env::var("TARGET").unwrap();
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let name = env::var("CARGO_PKG_NAME").unwrap();
if target.starts_with("riscv") && env::var_os("CARGO_FEATURE_INLINE_ASM").is_none() {
let mut target = Target::from_target_str(&target);
target.retain_extensions("ic");
let target = target.to_string();
fs::copy(
format!("bin/{}.a", target),
out_dir.join(format!("lib{}.a", name)),
)
.unwrap();
println!("cargo:rustc-link-lib=static={}", name);
println!("cargo:rustc-link-search={}", out_dir.display());
}
if target.contains("riscv32") {
println!("cargo:rustc-cfg=riscv");
println!("cargo:rustc-cfg=riscv32");
} else if target.contains("riscv64") {
println!("cargo:rustc-cfg=riscv");
println!("cargo:rustc-cfg=riscv64");
}
}

@ -0,0 +1,21 @@
#!/bin/bash
# Checks that the blobs are up to date with the committed assembly files
set -euxo pipefail
for lib in $(ls bin/*.a); do
filename=$(basename $lib)
riscv64-unknown-elf-objdump -Cd $lib > bin/${filename%.a}.before
done
./assemble.sh
for lib in $(ls bin/*.a); do
filename=$(basename $lib)
riscv64-unknown-elf-objdump -Cd $lib > bin/${filename%.a}.after
done
for cksum in $(ls bin/*.after); do
diff -u $cksum ${cksum%.after}.before
done

@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -euxo pipefail
if [ -n "${TARGET:-}" ]; then
rustup target add $TARGET
fi
if [ -n "${CHECK_BLOBS:-}" ]; then
if [ ! -d gcc/bin ]; then
mkdir -p gcc
curl -L https://static.dev.sifive.com/dev-tools/riscv64-unknown-elf-gcc-8.1.0-2018.12.0-x86_64-linux-ubuntu14.tar.gz | tar --strip-components=1 -C gcc -xz
fi
fi
if [ -n "${RUSTFMT:-}" ]; then
rustup component add rustfmt
fi

@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euxo pipefail
export PATH=$PATH:~/.cargo/bin
if [ -n "${TARGET:-}" ]; then
cargo check --target $TARGET
if [ $TRAVIS_RUST_VERSION = nightly ]; then
cargo check --target $TARGET --features inline-asm
fi
fi
if [ -n "${CHECK_BLOBS:-}" ]; then
PATH="$PATH:$PWD/gcc/bin"
./check-blobs.sh
fi
if [ -n "${RUSTFMT:-}" ]; then
cargo fmt -- --check
fi

@ -0,0 +1,8 @@
#!/bin/bash
rustc generator.rs
rm -f ../src/register/hypervisorx64/mod.rs;
for i in *.txt; do
./generator <$i > ../src/register/hypervisorx64/`basename -s .txt $i`.rs;
echo "pub mod $(basename -s .txt $i);" >> ../src/register/hypervisorx64/mod.rs;
done
rm -f generator

@ -0,0 +1,355 @@
use std::fmt::*;
macro_rules! CSR_ACCESSOR {
() => {
r#"
pub mod csr {{
pub const CSR_ID: usize = {};
#[inline]
pub unsafe fn csrrw(rs1: usize)->usize{{
let mut rd;
llvm_asm!("csrrw $0, $2, $1" :"=r"(rd): "r"(rs1), "i"(CSR_ID) :: "volatile");
rd
}}
#[inline]
pub unsafe fn csrrw_x0(rs1: usize){{
llvm_asm!("csrrw x0, $1, $0" :: "r"(rs1), "i"(CSR_ID) :: "volatile");
}}
#[inline]
pub unsafe fn csrrs(rs1: usize)->usize{{
let mut rd;
llvm_asm!("csrrs $0, $2, $1" :"=r"(rd): "r"(rs1), "i"(CSR_ID) :: "volatile");
rd
}}
#[inline]
pub unsafe fn csrrs_x0()->usize{{
let mut rd;
llvm_asm!("csrrs $0, $1, x0" :"=r"(rd): "i"(CSR_ID) :: "volatile");
rd
}}
#[inline]
pub unsafe fn csrrc(rs1: usize)->usize{{
let mut rd;
llvm_asm!("csrrc $0, $2, $1" :"=r"(rd): "r"(rs1), "i"(CSR_ID) :: "volatile");
rd
}}
#[inline]
pub unsafe fn csrrc_x0()->usize{{
let mut rd;
llvm_asm!("csrrc $0, $1, x0" :"=r"(rd): "i"(CSR_ID) :: "volatile");
rd
}}
}}
"#
};
}
macro_rules! as_str_polyfill {
($x: expr, $r: expr) => {{
let mut y = $x.clone();
if let Some(x) = y.next() {
$r.split_at(x.as_ptr() as usize - $r.as_ptr() as usize).1
} else {
""
}
}};
}
#[derive(Debug, Clone)]
struct EnumerationDescriptor<'a> {
enumerations: Vec<(&'a str, usize)>,
}
impl<'a> EnumerationDescriptor<'a> {
pub fn parse(enums: &'a str) -> Self {
let mut counter = 0;
let list = enums.split(";");
let mut e = Vec::new();
for tup in list {
let mut t = tup.split("=");
let n = t.next().unwrap();
if let Some(new_id) = t.next() {
counter = new_id.parse().unwrap();
}
e.push((n, counter));
counter += 1;
}
EnumerationDescriptor { enumerations: e }
}
fn generate_enum(&self, name: &str) -> String {
let mut ret = String::new();
write!(
&mut ret,
"#[derive(Copy, Clone, Debug)]
#[repr(usize)]
"
)
.unwrap();
write!(&mut ret, "pub enum {}{{\n", name).unwrap();
let mut branches = String::new();
for e in self.enumerations.iter() {
write!(&mut ret, " {} = {},\n", e.0, e.1).unwrap();
write!(&mut branches, " {} => Self::{},\n", e.1, e.0).unwrap();
}
write!(
&mut ret,
"}}
impl {}{{
fn from(x: usize)->Self{{
match x{{
{} _ => unreachable!()
}}
}}
}}
",
name, branches
)
.unwrap();
return ret;
}
}
#[derive(Debug, Clone)]
struct BitFieldDescriptor<'a> {
name: &'a str,
description: &'a str,
lo: usize,
hi: usize,
ed: Option<(&'a str, EnumerationDescriptor<'a>)>,
}
impl<'a> BitFieldDescriptor<'a> {
pub fn parse(desc: &'a str) -> Self {
let mut parts = desc.split(",");
let name = parts.next().unwrap();
let hi = parts.next().unwrap().parse::<usize>().unwrap();
let lo = parts.next().unwrap().parse::<usize>().unwrap();
let (lo, hi) = if lo < hi { (lo, hi) } else { (hi, lo) };
let use_enum = parts.next().unwrap();
let ed = if use_enum != "number" {
let opts = parts.next().unwrap();
Some((use_enum, EnumerationDescriptor::parse(opts)))
} else {
None
};
let description = as_str_polyfill!(parts, desc);
BitFieldDescriptor {
name,
lo,
hi,
description,
ed,
}
}
pub fn generate_enum(&self) -> Option<String> {
if let Some((n, e)) = &self.ed {
Some(e.generate_enum(n))
} else {
None
}
}
pub fn flag_type(&self) -> &str {
if let Some((n, _)) = self.ed {
n
} else {
if self.lo == self.hi {
"bool"
} else {
"usize"
}
}
}
fn mask(&self) -> String {
format!("{}", (1usize << (self.hi - self.lo + 1)) - 1)
}
fn getter(&self) -> String {
if self.lo == self.hi {
return format!("self.bits.get_bit({})", self.lo);
} else if self.flag_type() != "usize" {
return format!(
"{}::from(self.bits.get_bits({}..{}))",
self.flag_type(),
self.lo,
self.hi + 1
);
} else {
return format!("self.bits.get_bits({}..{})", self.lo, self.hi + 1);
}
}
fn setter(&self) -> String {
if self.lo == self.hi {
return format!("self.bits.set_bit({}, val);", self.lo);
} else if self.flag_type() != "usize" {
return format!(
"self.bits.set_bits({}..{}, val as usize);",
self.lo,
self.hi + 1
);
} else {
return format!("self.bits.set_bits({}..{}, val);", self.lo, self.hi + 1);
}
}
fn generate_read_write(&self) -> String {
format!(
" /// {}
#[inline]
pub fn {}(&self)->{}{{
{}
}}
#[inline]
pub fn set_{}(&mut self, val: {}){{
{}
}}\n",
self.description,
self.name,
self.flag_type(),
self.getter(),
self.name,
self.flag_type(),
self.setter()
)
}
fn generate_bit_set(&self) -> String {
format!(
" pub fn set_{}()->bool{{
unsafe {{csr::csrrc({}) & {} !=0}}
}}
pub fn clear_{}()->bool{{
unsafe {{csr::csrrs({}) & {} !=0 }}
}}\n",
self.name,
1usize << self.lo,
1usize << self.lo,
self.name,
1usize << self.lo,
1usize << self.lo
)
}
fn generate_bitops(&self) -> String {
format!(
" set_clear_csr!(
///{}
, set_{}, clear_{}, 1 << {});\n",
self.description, self.name, self.name, self.lo
)
}
}
#[derive(Debug, Clone)]
struct CSRDescriptor<'a> {
name: &'a str,
id: usize,
description: &'a str,
bfs: Vec<BitFieldDescriptor<'a>>,
}
impl<'a> CSRDescriptor<'a> {
fn canonical_name(&self) -> String {
self.name.to_lowercase()
}
pub fn parse(d: &'a str) -> Self {
let mut parts = d.split("\n");
let name = parts.next().unwrap();
let id = parts.next().unwrap().parse::<usize>().unwrap();
let mut bfs = Vec::new();
while let Some(x) = parts.next() {
if x == "end" {
break;
} else {
bfs.push(BitFieldDescriptor::parse(x));
}
}
CSRDescriptor {
name,
id,
description: as_str_polyfill!(parts, d),
bfs,
}
}
pub fn generate(&self) -> String {
let mut trait_impls = String::new();
let mut bit_sets = String::new();
let mut enums = String::new();
for bf in self.bfs.iter() {
if bf.lo == bf.hi {
write!(&mut bit_sets, "{}", bf.generate_bitops()).unwrap();
//write!(&mut trait_impls, "{}",bf.generate_bit_set()).unwrap();
}
write!(&mut trait_impls, "{}", bf.generate_read_write()).unwrap();
if let Some(x) = bf.generate_enum() {
write!(&mut enums, "{}", x).unwrap();
}
}
if &trait_impls == "" && &bit_sets == "" {
format!(
"
//! {}
read_csr_as_usize!({}, __read_{});
write_csr_as_usize!({}, __write_{});
",
self.description,
self.id,
self.canonical_name(),
self.id,
self.canonical_name()
)
} else {
format!(
"
//! {}
use bit_field::BitField;
#[derive(Copy, Clone, Debug)]
pub struct {}{{\n bits: usize,\n}}
impl {}{{
#[inline]
pub fn bits(&self) -> usize{{
return self.bits;
}}
#[inline]
pub fn from_bits(x: usize) -> Self{{
return {}{{bits: x}};
}}
#[inline]
pub unsafe fn write(&self){{
_write(self.bits);
}}
{}
}}
read_csr_as!({}, {}, __read_{});
write_csr!({}, __write_{});
set!({}, __set_{});
clear!({}, __clear_{});
// bit ops
{}
// enums
{}
",
self.description,
self.name,
self.name,
self.name,
trait_impls,
self.name,
self.id,
self.canonical_name(),
self.id,
self.canonical_name(),
self.id,
self.canonical_name(),
self.id,
self.canonical_name(),
bit_sets,
enums,
)
}
}
}
fn main() {
use std::io::Read;
let mut buffer = String::new();
std::io::stdin().read_to_string(&mut buffer).unwrap();
let csr = CSRDescriptor::parse(&buffer);
println!("{}", csr.generate());
}

@ -0,0 +1,36 @@
Hcounteren
3602
cy,0,0,number,
tm,1,1,number,
ir,2,2,number,
hpm3,3,3,number,
hpm4,4,4,number,
hpm5,5,5,number,
hpm6,6,6,number,
hpm7,7,7,number,
hpm8,8,8,number,
hpm9,9,9,number,
hpm10,10,10,number,
hpm11,11,11,number,
hpm12,12,12,number,
hpm13,13,13,number,
hpm14,14,14,number,
hpm15,15,15,number,
hpm16,16,16,number,
hpm17,17,17,number,
hpm18,18,18,number,
hpm19,19,19,number,
hpm20,20,20,number,
hpm21,21,21,number,
hpm22,22,22,number,
hpm23,23,23,number,
hpm24,24,24,number,
hpm25,25,25,number,
hpm26,26,26,number,
hpm27,27,27,number,
hpm28,28,28,number,
hpm29,29,29,number,
hpm30,30,30,number,
hpm31,31,31,number,
end
Hypervisor Guest External Interrupt Pending Register.

@ -0,0 +1,16 @@
Hedeleg
1538
ex0,0,0,number,Instruction address misaligned
ex1,1,1,number,Instruction access fault
ex2,2,2,number,Illegal instruction
ex3,3,3,number,Breakpoint
ex4,4,4,number,Load address misaligned
ex5,5,5,number,Load access fault
ex6,6,6,number,Store/AMO address misaligned
ex7,7,7,number,Store/AMO access fault
ex8,8,8,number,Environment call from U-mode or VU-mode
ex12,12,12,number,Instruction page fault
ex13,13,13,number,Load page fault
ex15,15,15,number,Store/AMO page fault
end
Hypervisor Exception Delegation Register.

@ -0,0 +1,7 @@
Hgatp
1664
mode,63,60,HgatpValues,Bare=0;Sv39x4=8;Sv48x4=9,Guest address translation mode.
vmid,57,44,number,Virtual machine ID.
ppn,43,0,number,Physical Page Number for root page table.
end
Hypervisor Guest Address Translation and Protection Register.

@ -0,0 +1,4 @@
Hgeie
1543
end
Hypervisor Guest External Interrupt Enable Register.

@ -0,0 +1,4 @@
Hgeip
3602
end
Hypervisor Guest External Interrupt Pending Register.

@ -0,0 +1,7 @@
Hideleg
1539
sip,2,2,number,Software Interrupt
tip,6,6,number,Timer Interrupt
eip,10,10,number,External Interrupt
end
Hypervisor Interrupt Delegation Register.

@ -0,0 +1,8 @@
Hie
1540
vssie,2,2,number,Software Interrupt
vstie,6,6,number,Timer Interrupt
vseie,10,10,number,External Interrupt
sgeie,12,12,number,Guest External Interrupt
end
Hypervisor Interrupt Enable Register.

@ -0,0 +1,8 @@
Hip
1604
vssip,2,2,number,Software Interrupt
vstip,6,6,number,Timer Interrupt
vseip,10,10,number,External Interrupt
sgeip,12,12,number,Guest External Interrupt
end
Hypervisor Interrupt Pending Register.

@ -0,0 +1,14 @@
Hstatus
1536
vsxl,33,32,VsxlValues,Vsxl32=1;Vsxl64;Vsxl128,Effective XLEN for VM.
vtsr,22,22,number,TSR for VM.
vtw,21,21,number,TW for VM.
vtvm,20,20,number,TVM for VM.
vgein,17,12,number,Virtual Guest External Interrupt Number.
hu,9,9,number,Hypervisor User mode.
spvp,8,8,number,Supervisor Previous Virtual Privilege.
spv,7,7,number,Supervisor Previous Virtualization mode.
gva,6,6,number,Guest Virtual Address.
vsbe,5,5,number,VS access endianness.
end
HStatus Register.

@ -0,0 +1,5 @@
Htimedelta
1541
end
Hypervisor Time Delta Register.
read_composite_csr!(super::htimedeltah::read(), read());

@ -0,0 +1,4 @@
Htimedeltah
1557
end
Hypervisor Time Delta Register.

@ -0,0 +1,4 @@
Htinst
1610
end
Hypervisor Trap Instruction Register.

@ -0,0 +1,4 @@
Htval
1603
end
Hypervisor Trap Value Register.

@ -0,0 +1,7 @@
Hvip
1605
vssip,2,2,number,Software Interrupt
vstip,6,6,number,Timer Interrupt
vseip,10,10,number,External Interrupt
end
Hypervisor Virtual Interrupt Pending Register.

@ -0,0 +1,7 @@
Vsatp
640
mode,63,60,HgatpValues,Bare=0;Sv39x4=8;Sv48x4=9,Guest address translation mode.
asid,59,44,number,ASID.
ppn,43,0,number,Physical Page Number for root page table.
end
Virtual Supervisor Guest Address Translation and Protection Register.

@ -0,0 +1,6 @@
Vscause
578
interrupt,63,63,number,Is cause interrupt.
code,62,0,number,Exception code
end
Virtual Supervisor Cause Register.

@ -0,0 +1,4 @@
Vsepc
577
end
Virtual Supervisor Exception Program Counter.

@ -0,0 +1,7 @@
Vsie
516
ssie,1,1,number,Software Interrupt
stie,5,5,number,Timer Interrupt
seie,9,9,number,External Interrupt
end
Virtual Supevisor Interrupt Enable Register.

@ -0,0 +1,7 @@
Vsip
580
ssip,1,1,number,Software Interrupt
stip,5,5,number,Timer Interrupt
seip,9,9,number,External Interrupt
end
Virtual Supevisor Interrupt Pending Register.

@ -0,0 +1,4 @@
Vsscratch
576
end
Virtual Supervisor Scratch Register.

@ -0,0 +1,14 @@
Vsstatus
512
sd,63,60,number,
uxl,33,32,UxlValues,Uxl32=1;Uxl64;Uxl128,Effective User XLEN.
mxr,19,19,number,
sum,18,18,number,
xs,16,15,number,
fs,14,13,number,
spp,8,8,number,
ube,6,6,number,
spie,5,5,number,
sie,1,1,number,
end
Hypervisor Guest External Interrupt Pending Register.

@ -0,0 +1,4 @@
Vstval
579
end
Virtual Supervisor Trap Value Register.

@ -0,0 +1,6 @@
Vstvec
517
base,63,2,number,
mode,1,0,number,
end
Virtual Supervisor Trap Vector Base Address Register.

@ -0,0 +1,211 @@
use super::*;
use bit_field::BitField;
use core::convert::TryInto;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct GPAddrSv32X4(u64);
impl Address for GPAddrSv32X4 {
fn new(addr: usize) -> Self {
Self::new_u64(addr as u64)
}
fn as_usize(&self) -> usize {
self.0 as usize
}
fn page_number(&self) -> usize {
self.0.get_bits(12..34) as usize
}
fn page_offset(&self) -> usize {
self.0.get_bits(0..12) as usize
}
fn to_4k_aligned(&self) -> Self {
GPAddrSv32X4((self.0 >> 12) << 12)
}
}
impl VirtualAddress for GPAddrSv32X4 {
unsafe fn as_mut<'a, 'b, T>(&'a self) -> &'b mut T {
&mut *(self.0 as *mut T)
}
}
impl AddressL2 for GPAddrSv32X4 {
fn p2_index(&self) -> usize {
self.0.get_bits(22..34) as usize
}
fn p1_index(&self) -> usize {
self.0.get_bits(12..22) as usize
}
fn from_page_table_indices(p2_index: usize, p1_index: usize, offset: usize) -> Self {
let p2_index = p2_index as u64;
let p1_index = p1_index as u64;
let offset = offset as u64;
assert!(p2_index.get_bits(12..) == 0, "p2_index exceeding 12 bits");
assert!(p1_index.get_bits(10..) == 0, "p1_index exceeding 10 bits");
assert!(offset.get_bits(12..) == 0, "offset exceeding 12 bits");
GPAddrSv32X4::new_u64((p2_index << 22) | (p1_index << 12) | offset)
}
}
impl AddressX64 for GPAddrSv32X4 {
fn new_u64(addr: u64) -> Self {
assert!(
addr.get_bits(34..64) == 0,
"Sv32x4 does not allow pa 34..64!=0"
);
GPAddrSv32X4(addr)
}
fn as_u64(&self) -> u64 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct GPAddrSv39X4(u64);
impl Address for GPAddrSv39X4 {
fn new(addr: usize) -> Self {
GPAddrSv39X4(addr.try_into().unwrap())
}
fn as_usize(&self) -> usize {
self.0 as usize
}
fn page_number(&self) -> usize {
self.0.get_bits(12..41) as usize
}
fn page_offset(&self) -> usize {
self.0.get_bits(0..12) as usize
}
fn to_4k_aligned(&self) -> Self {
GPAddrSv39X4((self.0 >> 12) << 12)
}
}
impl VirtualAddress for GPAddrSv39X4 {
unsafe fn as_mut<'a, 'b, T>(&'a self) -> &'b mut T {
&mut *(self.0 as *mut T)
}
}
impl AddressL3 for GPAddrSv39X4 {
fn p3_index(&self) -> usize {
self.0.get_bits(30..41) as usize
}
fn p2_index(&self) -> usize {
self.0.get_bits(21..30) as usize
}
fn p1_index(&self) -> usize {
self.0.get_bits(12..21) as usize
}
fn from_page_table_indices(
p3_index: usize,
p2_index: usize,
p1_index: usize,
offset: usize,
) -> Self {
let p3_index = p3_index as u64;
let p2_index = p2_index as u64;
let p1_index = p1_index as u64;
let offset = offset as u64;
assert!(p3_index.get_bits(11..) == 0, "p3_index exceeding 11 bits");
assert!(p2_index.get_bits(9..) == 0, "p2_index exceeding 9 bits");
assert!(p1_index.get_bits(9..) == 0, "p1_index exceeding 9 bits");
assert!(offset.get_bits(12..) == 0, "offset exceeding 12 bits");
GPAddrSv39X4::new_u64(
(p3_index << 12 << 9 << 9) | (p2_index << 12 << 9) | (p1_index << 12) | offset,
)
}
}
impl AddressX64 for GPAddrSv39X4 {
fn new_u64(addr: u64) -> Self {
assert!(
addr.get_bits(41..64) == 0,
"Sv39x4 does not allow pa 41..64!=0"
);
GPAddrSv39X4(addr)
}
fn as_u64(&self) -> u64 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct GPAddrSv48X4(u64);
impl Address for GPAddrSv48X4 {
fn new(addr: usize) -> Self {
GPAddrSv48X4(addr.try_into().unwrap())
}
fn as_usize(&self) -> usize {
self.0 as usize
}
fn page_number(&self) -> usize {
self.0.get_bits(12..50) as usize
}
fn page_offset(&self) -> usize {
self.0.get_bits(0..12) as usize
}
fn to_4k_aligned(&self) -> Self {
GPAddrSv48X4((self.0 >> 12) << 12)
}
}
impl VirtualAddress for GPAddrSv48X4 {
unsafe fn as_mut<'a, 'b, T>(&'a self) -> &'b mut T {
&mut *(self.0 as *mut T)
}
}
impl AddressL4 for GPAddrSv48X4 {
fn p4_index(&self) -> usize {
self.0.get_bits(39..50) as usize
}
fn p3_index(&self) -> usize {
self.0.get_bits(30..39) as usize
}
fn p2_index(&self) -> usize {
self.0.get_bits(21..30) as usize
}
fn p1_index(&self) -> usize {
self.0.get_bits(12..21) as usize
}
fn from_page_table_indices(
p4_index: usize,
p3_index: usize,
p2_index: usize,
p1_index: usize,
offset: usize,
) -> Self {
let p4_index = p4_index as u64;
let p3_index = p3_index as u64;
let p2_index = p2_index as u64;
let p1_index = p1_index as u64;
let offset = offset as u64;
assert!(p4_index.get_bits(11..) == 0, "p4_index exceeding 11 bits");
assert!(p3_index.get_bits(9..) == 0, "p3_index exceeding 9 bits");
assert!(p2_index.get_bits(9..) == 0, "p2_index exceeding 9 bits");
assert!(p1_index.get_bits(9..) == 0, "p1_index exceeding 9 bits");
assert!(offset.get_bits(12..) == 0, "offset exceeding 12 bits");
GPAddrSv48X4::new_u64(
(p4_index << 12 << 9 << 9 << 9)
| (p3_index << 12 << 9 << 9)
| (p2_index << 12 << 9)
| (p1_index << 12)
| offset,
)
}
}
impl AddressX64 for GPAddrSv48X4 {
fn new_u64(addr: u64) -> Self {
assert!(
addr.get_bits(50..64) == 0,
"Sv48x4 does not allow pa 50..64!=0"
);
GPAddrSv48X4(addr)
}
fn as_u64(&self) -> u64 {
self.0
}
}

@ -0,0 +1,98 @@
pub trait Address: core::fmt::Debug + Copy + Clone + PartialEq + Eq + PartialOrd + Ord {
fn new(addr: usize) -> Self;
fn page_number(&self) -> usize;
fn page_offset(&self) -> usize;
fn to_4k_aligned(&self) -> Self;
fn as_usize(&self) -> usize;
}
pub trait VirtualAddress: Address {
unsafe fn as_mut<'a, 'b, T>(&'a self) -> &'b mut T;
}
pub trait AddressX32: Address {
fn new_u32(addr: u32) -> Self;
fn as_u32(&self) -> u32;
}
pub trait AddressX64: Address {
fn new_u64(addr: u64) -> Self;
fn as_u64(&self) -> u64;
}
pub trait PhysicalAddress: AddressX64 {}
pub trait AddressL3: Address {
fn p3_index(&self) -> usize;
fn p2_index(&self) -> usize;
fn p1_index(&self) -> usize;
fn from_page_table_indices(
p3_index: usize,
p2_index: usize,
p1_index: usize,
offset: usize,
) -> Self;
}
pub trait AddressL4: Address {
fn p4_index(&self) -> usize;
fn p3_index(&self) -> usize;
fn p2_index(&self) -> usize;
fn p1_index(&self) -> usize;
fn from_page_table_indices(
p4_index: usize,
p3_index: usize,
p2_index: usize,
p1_index: usize,
offset: usize,
) -> Self;
}
pub trait AddressL2: Address {
fn p2_index(&self) -> usize;
fn p1_index(&self) -> usize;
fn from_page_table_indices(p2_index: usize, p1_index: usize, offset: usize) -> Self;
}
pub mod gpax4;
pub mod page;
pub mod sv32;
pub mod sv39;
pub mod sv48;
pub use self::gpax4::*;
pub use self::page::*;
pub use self::sv32::*;
pub use self::sv39::*;
pub use self::sv48::*;
#[macro_export]
macro_rules! use_sv32 {
() => {
pub type VirtAddr = VirtAddrSv32;
pub type PhysAddr = PhysAddrSv32;
pub type Page = PageWith<VirtAddr>;
pub type Frame = FrameWith<PhysAddr>;
};
}
#[macro_export]
macro_rules! use_sv39 {
() => {
pub type VirtAddr = VirtAddrSv39;
pub type PhysAddr = PhysAddrSv39;
pub type Page = PageWith<VirtAddr>;
pub type Frame = FrameWith<PhysAddr>;
};
}
#[macro_export]
macro_rules! use_sv48 {
() => {
pub type VirtAddr = VirtAddrSv48;
pub type PhysAddr = PhysAddrSv48;
pub type Page = PageWith<VirtAddr>;
pub type Frame = FrameWith<PhysAddr>;
};
}
#[cfg(target_arch = "riscv64")]
use_sv48!();
#[cfg(target_arch = "riscv32")]
use_sv32!();

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save