Skip to content

Commit 012aa79

Browse files
committed
HAL implementations
1 parent 13deb05 commit 012aa79

File tree

14 files changed

+473
-46
lines changed

14 files changed

+473
-46
lines changed

.github/workflows/clippy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ jobs:
3737
runs-on: ubuntu-latest
3838
if: always()
3939
steps:
40-
- run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
40+
- run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9+
embedded-hal = "1.0.0-rc.1"
10+
embedded-hal-async = { version = "1.0.0-rc.1", optional = true }
911
riscv = { git = "https://github.com/rust-embedded/riscv", branch = "master" }
1012

13+
[features]
14+
hal-async = ["embedded-hal-async"]
15+
1116
[package.metadata.docs.rs]
1217
default-target = "riscv64imac-unknown-none-elf"
1318
targets = [

examples/e310x.rs

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
use riscv_peripheral::{
2+
aclint::HartIdNumber,
3+
plic::{ContextNumber, InterruptNumber, PriorityNumber},
4+
};
5+
6+
#[repr(u16)]
7+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8+
pub enum HartId {
9+
H0 = 0,
10+
}
11+
12+
unsafe impl HartIdNumber for HartId {
13+
const MAX_HART_ID_NUMBER: u16 = 0;
14+
15+
#[inline]
16+
fn number(self) -> u16 {
17+
self as _
18+
}
19+
20+
#[inline]
21+
fn from_number(number: u16) -> Result<Self, u16> {
22+
if number > Self::MAX_HART_ID_NUMBER {
23+
Err(number)
24+
} else {
25+
// SAFETY: valid context number
26+
Ok(unsafe { core::mem::transmute(number) })
27+
}
28+
}
29+
}
30+
31+
unsafe impl ContextNumber for HartId {
32+
const MAX_CONTEXT_NUMBER: u16 = 0;
33+
34+
#[inline]
35+
fn number(self) -> u16 {
36+
self as _
37+
}
38+
39+
#[inline]
40+
fn from_number(number: u16) -> Result<Self, u16> {
41+
if number > Self::MAX_CONTEXT_NUMBER {
42+
Err(number)
43+
} else {
44+
// SAFETY: valid context number
45+
Ok(unsafe { core::mem::transmute(number) })
46+
}
47+
}
48+
}
49+
50+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
51+
#[repr(u16)]
52+
pub enum Interrupt {
53+
WATCHDOG = 1,
54+
RTC = 2,
55+
UART0 = 3,
56+
UART1 = 4,
57+
QSPI0 = 5,
58+
QSPI1 = 6,
59+
QSPI2 = 7,
60+
GPIO0 = 8,
61+
GPIO1 = 9,
62+
GPIO2 = 10,
63+
GPIO3 = 11,
64+
GPIO4 = 12,
65+
GPIO5 = 13,
66+
GPIO6 = 14,
67+
GPIO7 = 15,
68+
GPIO8 = 16,
69+
GPIO9 = 17,
70+
GPIO10 = 18,
71+
GPIO11 = 19,
72+
GPIO12 = 20,
73+
GPIO13 = 21,
74+
GPIO14 = 22,
75+
GPIO15 = 23,
76+
GPIO16 = 24,
77+
GPIO17 = 25,
78+
GPIO18 = 26,
79+
GPIO19 = 27,
80+
GPIO20 = 28,
81+
GPIO21 = 29,
82+
GPIO22 = 30,
83+
GPIO23 = 31,
84+
GPIO24 = 32,
85+
GPIO25 = 33,
86+
GPIO26 = 34,
87+
GPIO27 = 35,
88+
GPIO28 = 36,
89+
GPIO29 = 37,
90+
GPIO30 = 38,
91+
GPIO31 = 39,
92+
PWM0CMP0 = 40,
93+
PWM0CMP1 = 41,
94+
PWM0CMP2 = 42,
95+
PWM0CMP3 = 43,
96+
PWM1CMP0 = 44,
97+
PWM1CMP1 = 45,
98+
PWM1CMP2 = 46,
99+
PWM1CMP3 = 47,
100+
PWM2CMP0 = 48,
101+
PWM2CMP1 = 49,
102+
PWM2CMP2 = 50,
103+
PWM2CMP3 = 51,
104+
I2C0 = 52,
105+
}
106+
107+
unsafe impl InterruptNumber for Interrupt {
108+
const MAX_INTERRUPT_NUMBER: u16 = 52;
109+
110+
#[inline]
111+
fn number(self) -> u16 {
112+
self as _
113+
}
114+
115+
#[inline]
116+
fn from_number(number: u16) -> Result<Self, u16> {
117+
if number == 0 || number > Self::MAX_INTERRUPT_NUMBER {
118+
Err(number)
119+
} else {
120+
// SAFETY: valid interrupt number
121+
Ok(unsafe { core::mem::transmute(number) })
122+
}
123+
}
124+
}
125+
126+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
127+
#[repr(u8)]
128+
pub enum Priority {
129+
P0 = 0,
130+
P1 = 1,
131+
P2 = 2,
132+
P3 = 3,
133+
P4 = 4,
134+
P5 = 5,
135+
P6 = 6,
136+
P7 = 7,
137+
}
138+
139+
unsafe impl PriorityNumber for Priority {
140+
const MAX_PRIORITY_NUMBER: u8 = 7;
141+
142+
#[inline]
143+
fn number(self) -> u8 {
144+
self as _
145+
}
146+
147+
#[inline]
148+
fn from_number(number: u8) -> Result<Self, u8> {
149+
if number > Self::MAX_PRIORITY_NUMBER {
150+
Err(number)
151+
} else {
152+
// SAFETY: valid priority number
153+
Ok(unsafe { core::mem::transmute(number) })
154+
}
155+
}
156+
}
157+
158+
riscv_peripheral::clint_codegen!(
159+
base 0x0200_0000,
160+
freq 32_768,
161+
mtimecmps [mtimecmp0=(HartId::H0,"`H0`")],
162+
msips [msip0=(HartId::H0,"`H0`")],
163+
);
164+
165+
fn main() {}

src/aclint.rs

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ pub(crate) mod test {
136136
crate::clint_codegen!(
137137
base 0x0200_0000,
138138
mtimecmps [mtimecmp0=(HartId::H0,"`H0`"), mtimecmp1=(HartId::H1,"`H1`"), mtimecmp2=(HartId::H2,"`H2`")],
139+
msips [msip0=(HartId::H0,"`H0`"), msip1=(HartId::H1,"`H1`"), msip2=(HartId::H2,"`H2`")],
139140
);
140141

141142
let mswi = CLINT::mswi();
@@ -150,25 +151,16 @@ pub(crate) mod test {
150151
let mtimecmp2 = mtimer.mtimecmp(HartId::H2);
151152

152153
assert_eq!(mtimecmp0.get_ptr() as usize, 0x0200_4000);
153-
assert_eq!(mtimecmp1.get_ptr() as usize, 0x0200_4000 + 1 * 8); // 8 bytes per register
154+
assert_eq!(mtimecmp1.get_ptr() as usize, 0x0200_4000 + 8); // 8 bytes per register
154155
assert_eq!(mtimecmp2.get_ptr() as usize, 0x0200_4000 + 2 * 8);
155156

156-
// Check that the mtimecmpX functions are equivalent to the mtimer.mtimecmp(X) function.
157-
let mtimecmp0 = CLINT::mtimecmp0();
158-
let mtimecmp1 = CLINT::mtimecmp1();
159-
let mtimecmp2 = CLINT::mtimecmp2();
157+
assert_eq!(CLINT::mtime(), mtimer.mtime);
158+
assert_eq!(CLINT::mtimecmp0(), mtimer.mtimecmp(HartId::H0));
159+
assert_eq!(CLINT::mtimecmp1(), mtimer.mtimecmp(HartId::H1));
160+
assert_eq!(CLINT::mtimecmp2(), mtimer.mtimecmp(HartId::H2));
160161

161-
assert_eq!(
162-
mtimecmp0.get_ptr() as usize,
163-
mtimer.mtimecmp(HartId::H0).get_ptr() as usize
164-
);
165-
assert_eq!(
166-
mtimecmp1.get_ptr() as usize,
167-
mtimer.mtimecmp(HartId::H1).get_ptr() as usize
168-
);
169-
assert_eq!(
170-
mtimecmp2.get_ptr() as usize,
171-
mtimer.mtimecmp(HartId::H2).get_ptr() as usize
172-
);
162+
assert_eq!(CLINT::msip0(), mswi.msip(HartId::H0));
163+
assert_eq!(CLINT::msip1(), mswi.msip(HartId::H1));
164+
assert_eq!(CLINT::msip2(), mswi.msip(HartId::H2));
173165
}
174166
}

src/aclint/mswi.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,30 @@ impl MSIP {
5858
self.register.write(0);
5959
}
6060
}
61+
62+
#[cfg(test)]
63+
mod test {
64+
use super::super::test::HartId;
65+
use super::*;
66+
67+
#[test]
68+
fn test_mswi() {
69+
// slice to emulate the interrupt pendings register
70+
let raw_reg = [0u32; HartId::MAX_HART_ID_NUMBER as usize + 1];
71+
// SAFETY: valid memory address
72+
let mswi = unsafe { MSWI::new(raw_reg.as_ptr() as _) };
73+
74+
for i in 0..=HartId::MAX_HART_ID_NUMBER {
75+
let hart_id = HartId::from_number(i).unwrap();
76+
let msip = mswi.msip(hart_id);
77+
assert!(!msip.is_pending());
78+
assert_eq!(raw_reg[i as usize], 0);
79+
msip.pend();
80+
assert!(msip.is_pending());
81+
assert_ne!(raw_reg[i as usize], 0);
82+
msip.unpend();
83+
assert!(!msip.is_pending());
84+
assert_eq!(raw_reg[i as usize], 0);
85+
}
86+
}
87+
}

src/aclint/mtimer.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl MTIMER {
1818
///
1919
/// # Safety
2020
///
21-
/// The base address must point to a valid `MTIMER` peripheral.
21+
/// The base addresses must point to valid `MTIMECMP` and `MTIME` peripherals.
2222
#[inline]
2323
pub const unsafe fn new(mtimecmp: usize, mtime: usize) -> Self {
2424
Self {
@@ -44,3 +44,36 @@ safe_peripheral!(MTIMECMP, u64, RW);
4444

4545
// MTIME register.
4646
safe_peripheral!(MTIME, u64, RW);
47+
48+
#[cfg(test)]
49+
mod test {
50+
use super::super::test::HartId;
51+
use super::*;
52+
53+
#[test]
54+
fn check_mtimer() {
55+
// slice to emulate the mtimecmp registers
56+
let raw_mtimecmp = [0u64; HartId::MAX_HART_ID_NUMBER as usize + 1];
57+
let raw_mtime = 0u64;
58+
// SAFETY: valid memory addresses
59+
let mtimer =
60+
unsafe { MTIMER::new(raw_mtimecmp.as_ptr() as _, &raw_mtime as *const u64 as _) };
61+
62+
assert_eq!(
63+
mtimer.mtimecmp(HartId::H0).get_ptr() as usize,
64+
raw_mtimecmp.as_ptr() as usize
65+
);
66+
assert_eq!(mtimer.mtimecmp(HartId::H1).get_ptr() as usize, unsafe {
67+
raw_mtimecmp.as_ptr().offset(1)
68+
}
69+
as usize);
70+
assert_eq!(mtimer.mtimecmp(HartId::H2).get_ptr() as usize, unsafe {
71+
raw_mtimecmp.as_ptr().offset(2)
72+
}
73+
as usize);
74+
assert_eq!(
75+
mtimer.mtime.get_ptr() as usize,
76+
&raw_mtime as *const u64 as _
77+
);
78+
}
79+
}

src/aclint/sswi.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,30 @@ impl SETSSIP {
8989
self.register.write(0);
9090
}
9191
}
92+
93+
#[cfg(test)]
94+
mod test {
95+
use super::super::test::HartId;
96+
use super::*;
97+
98+
#[test]
99+
fn test_sswi() {
100+
// slice to emulate the interrupt pendings register
101+
let raw_reg = [0u32; HartId::MAX_HART_ID_NUMBER as usize + 1];
102+
// SAFETY: valid memory address
103+
let mswi = unsafe { SSWI::new(raw_reg.as_ptr() as _) };
104+
105+
for i in 0..=HartId::MAX_HART_ID_NUMBER {
106+
let hart_id = HartId::from_number(i).unwrap();
107+
let setssip = mswi.setssip(hart_id);
108+
assert!(!setssip.is_pending());
109+
assert_eq!(raw_reg[i as usize], 0);
110+
setssip.pend();
111+
assert!(setssip.is_pending());
112+
assert_ne!(raw_reg[i as usize], 0);
113+
setssip.unpend();
114+
assert!(!setssip.is_pending());
115+
assert_eq!(raw_reg[i as usize], 0);
116+
}
117+
}
118+
}

src/hal.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//! trait implementations for embedded-hal
2+
3+
pub use embedded_hal::*; // re-export embedded-hal to allow macros to use it
4+
5+
pub mod aclint; // ACLINT and CLINT peripherals

src/hal/aclint.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//! Delay trait implementation for (A)CLINT peripherals
2+
3+
use crate::aclint::mtimer::MTIME;
4+
pub use crate::hal::delay::DelayUs;
5+
6+
/// Delay implementation for (A)CLINT peripherals.
7+
pub struct Delay {
8+
mtime: MTIME,
9+
freq: usize,
10+
}
11+
12+
impl Delay {
13+
/// Creates a new `Delay` instance.
14+
#[inline]
15+
pub const fn new(mtime: MTIME, freq: usize) -> Self {
16+
Self { mtime, freq }
17+
}
18+
19+
/// Returns the frequency of the `MTIME` register.
20+
#[inline]
21+
pub const fn get_freq(&self) -> usize {
22+
self.freq
23+
}
24+
25+
/// Sets the frequency of the `MTIME` register.
26+
#[inline]
27+
pub fn set_freq(&mut self, freq: usize) {
28+
self.freq = freq;
29+
}
30+
31+
/// Returns the `MTIME` register.
32+
#[inline]
33+
pub const fn get_mtime(&self) -> MTIME {
34+
self.mtime
35+
}
36+
}
37+
38+
impl DelayUs for Delay {
39+
#[inline]
40+
fn delay_us(&mut self, us: u32) {
41+
let time_from = self.mtime.read();
42+
let time_to = time_from.wrapping_add(us as u64 * self.freq as u64 / 1_000_000);
43+
44+
while time_to < self.mtime.read() {} // wait for overflow
45+
while time_to > self.mtime.read() {} // wait for time to pass
46+
}
47+
}

src/hal_async.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//! async trait implementations for embedded-hal
2+
3+
pub use embedded_hal_async::*; // re-export embedded-hal-async to allow macros to use it
4+
5+
pub mod aclint; // ACLINT and CLINT peripherals

0 commit comments

Comments
 (0)