Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASIC-specific examples #60

Merged
merged 20 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/headsail-bsp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ sysctrl = []
alloc = ["dep:good_memory_allocator", "hpc"]
sdram = []
vp = []
asic = []

# This is generated by the above options, don't use directly
rt = ["dep:riscv-rt"]
Expand Down
23 changes: 21 additions & 2 deletions examples/headsail-bsp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#![no_std]

pub mod sprintln;
#[cfg(feature = "sysctrl")]
pub mod sysctrl;
pub mod uart;
pub mod timer {
/*!
Expand Down Expand Up @@ -38,8 +40,6 @@ pub mod alloc;
#[cfg(feature = "hpc")]
mod hpc;
mod mmap;
#[cfg(feature = "sysctrl")]
mod sysctrl;
#[cfg(feature = "panic-uart")]
mod ufmt_panic;

Expand Down Expand Up @@ -69,6 +69,25 @@ pub fn write_u32(addr: usize, val: u32) {
unsafe { core::ptr::write_volatile(addr as *mut _, val) }
}

#[inline(always)]
pub fn mask_u32(addr: usize, mask: u32) {
let r = unsafe { core::ptr::read_volatile(addr as *const u32) };
unsafe { core::ptr::write_volatile(addr as *mut _, r | mask) }
}

#[inline(always)]
pub fn unmask_u32(addr: usize, unmask: u32) {
let r = unsafe { core::ptr::read_volatile(addr as *const u32) };
unsafe { core::ptr::write_volatile(addr as *mut _, r & !unmask) }
}

#[inline(always)]
pub fn toggle_u32(addr: usize, toggle_bits: u32) {
let mut r = read_u32(addr);
r ^= toggle_bits;
write_u32(addr, r);
}

#[cfg(feature = "alloc")]
pub fn init_alloc() {
unsafe { alloc::init_heap() };
Expand Down
18 changes: 18 additions & 0 deletions examples/headsail-bsp/src/mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,26 @@
pub(crate) const UART0_ADDR: usize = 0x1FFF00000;
#[cfg(not(feature = "hpc"))]
pub(crate) const UART0_ADDR: usize = 0xFFF00000;
pub(crate) const UART0_THR: usize = UART0_ADDR;

// NOTE: (20240614 [email protected]) This applies to renode NS16550 uart, but might not apply to headsail ASIC
pub(crate) const UART_DATA_READY_OFFSET: usize = 5;

#[cfg(feature = "asic")]
mod asic_uart {
use super::UART0_ADDR;

pub(crate) const UART0_DIV_LSB: usize = UART0_ADDR + 0;
pub(crate) const UART0_DIV_MSB: usize = UART0_ADDR + 1;
pub(crate) const UART0_INTERRUPT_ENABLE: usize = UART0_ADDR + 1;
pub(crate) const UART0_FIFO_CONTROL: usize = UART0_ADDR + 2;
pub(crate) const UART0_LINE_CONTROL: usize = UART0_ADDR + 3;
pub(crate) const UART0_MODEM_CONTROL: usize = UART0_ADDR + 4;
pub(crate) const UART0_LINE_STATUS: usize = UART0_ADDR + 5;
}
#[cfg(feature = "asic")]
pub(crate) use self::asic_uart::*;

pub(crate) const TIMER0_ADDR: usize = 0x5_0000;
pub(crate) const TIMER1_ADDR: usize = 0x5_0010;
pub(crate) const TIMER2_ADDR: usize = 0x5_0020;
Expand Down
92 changes: 92 additions & 0 deletions examples/headsail-bsp/src/sysctrl/gpio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use core::marker::PhantomData;

use super::{mmap, soc_ctrl};
use crate::{mask_u32, toggle_u32, unmask_u32};

/// Type-state trait for GPIO in different states
pub trait GpioState {}

pub struct Uninit;
impl GpioState for Uninit {}

pub struct Input;
impl GpioState for Input {}

pub struct Output;
impl GpioState for Output {}

/// To obtain an instance:
///
/// 1. Obtain [Pads] with [sysctrl::soc_ctrl::Pads::take]
/// 2. Pick pin: `pads.p9`
/// 3. Convert pin into GPIO [systcrl::soc_ctrl::Pad::into_gpio]
pub struct Gpio<const IDX: u32, State: GpioState = Uninit> {
_pd: PhantomData<State>,
}

pub type Gpio9<S> = Gpio<9, S>;

#[repr(u32)]
enum Dir {
In = 0,
Out = 1,
}

impl<const IDX: u32> Gpio<IDX, Uninit> {
pub(crate) fn new() -> Self {
Self { _pd: PhantomData }
}

pub fn into_input(self) -> Gpio<IDX, Input> {
mask_u32(mmap::GPIO_DIR, Dir::In as u32);

Gpio { _pd: PhantomData }
}

pub fn into_output(self) -> Gpio<IDX, Output> {
mask_u32(mmap::GPIO_DIR, Dir::Out as u32);

Gpio { _pd: PhantomData }
}
}

impl<const IDX: u32> Gpio<IDX, Output> {
pub fn toggle(&mut self) {
toggle_u32(mmap::GPIO_OUT, 1 << IDX);
}

pub fn set_high(&mut self) {
mask_u32(mmap::GPIO_OUT, 1 << IDX);
}

pub fn set_low(&mut self) {
unmask_u32(mmap::GPIO_OUT, 1 << IDX);
}
}

impl<const IDX: u32, S: GpioState> Gpio<IDX, S> {
/// Release pad back to its original function
///
/// Pins can be released in any state. GPIO register configurations will
/// retain their state (until overridden again by HAL methods).
pub fn release(self) -> soc_ctrl::Pad<IDX> {
unmask_u32(
if IDX <= 15 {
mmap::PADMUX0
} else {
mmap::PADMUX1
},
(soc_ctrl::PadFn::Gpio as u32) << (IDX * 2),
);

soc_ctrl::Pad::<IDX> {}
}

/// # Safety
///
/// This will not configure the pin in any way (i.e., for use as GPIO or
/// direction).
pub unsafe fn steal() -> Self {
Self { _pd: PhantomData }
}
}
15 changes: 15 additions & 0 deletions examples/headsail-bsp/src/sysctrl/mmap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/// SysCtrl-specific memory maps

pub(crate) const SYSCTRL_ADDR: usize = 0x1a10_0000;

pub(crate) const GPIO_ADDR: usize = SYSCTRL_ADDR + 0x1000;
pub(crate) const GPIO_DIR: usize = GPIO_ADDR + 0x0;
pub(crate) const GPIO_OUT: usize = GPIO_ADDR + 0xc;

pub(crate) const SOC_CONTROL_ADDR: usize = SYSCTRL_ADDR + 0x4000;
pub(crate) const PADMUX0: usize = SOC_CONTROL_ADDR + 0x10;
pub(crate) const PADMUX1: usize = SOC_CONTROL_ADDR + 0x14;

pub(crate) const SS_RESET_EN: usize = SOC_CONTROL_ADDR + 0xb0;
pub(crate) const SS_CLK_CTRL2: usize = SOC_CONTROL_ADDR + 0x9c;
pub(crate) const SS_CLK_CTRL3: usize = SOC_CONTROL_ADDR + 0xb8;
4 changes: 4 additions & 0 deletions examples/headsail-bsp/src/sysctrl/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
//! Abstractions that only exist on SysCtrl
pub mod gpio;
pub mod soc_ctrl;

mod interrupt;
mod mmap;
103 changes: 103 additions & 0 deletions examples/headsail-bsp/src/sysctrl/soc_ctrl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use riscv::interrupt;

use super::{gpio::Gpio, mmap};
use crate::{mask_u32, write_u32};

#[repr(u32)]
pub(crate) enum PadFn {
//Default = 0,
Gpio = 1,
}

/// ~Pin
pub struct Pad<const IDX: u32> {}

pub struct Pads {
pub p0: Pad<0>,
pub p1: Pad<1>,
pub p2: Pad<2>,
pub p3: Pad<3>,
pub p4: Pad<4>,
pub p5: Pad<5>,
pub p6: Pad<6>,
pub p7: Pad<7>,
pub p8: Pad<8>,
pub p9: Pad<9>,
pub p10: Pad<10>,
pub p11: Pad<11>,
pub p12: Pad<12>,
pub p13: Pad<13>,
pub p14: Pad<14>,
pub p15: Pad<15>,
pub p16: Pad<16>,
pub p17: Pad<17>,
pub p18: Pad<18>,
}

/// Set to `true` when `take` or `steal` was called to make `Peripherals` a singleton.
static mut PADS_TAKEN: bool = false;

impl Pads {
#[inline]
pub fn take() -> Option<Self> {
interrupt::free(|| {
if unsafe { PADS_TAKEN } {
None
} else {
Some(unsafe { Self::steal() })
}
})
}

#[inline]
pub unsafe fn steal() -> Self {
Self {
p0: Pad {},
p1: Pad {},
p2: Pad {},
p3: Pad {},
p4: Pad {},
p5: Pad {},
p6: Pad {},
p7: Pad {},
p8: Pad {},
p9: Pad {},
p10: Pad {},
p11: Pad {},
p12: Pad {},
p13: Pad {},
p14: Pad {},
p15: Pad {},
p16: Pad {},
p17: Pad {},
p18: Pad {},
}
}
}

impl<const IDX: u32> Pad<IDX> {
pub fn into_gpio(self) -> Gpio<IDX> {
mask_u32(
if IDX <= 15 {
mmap::PADMUX0
} else {
mmap::PADMUX1
},
(PadFn::Gpio as u32) << (IDX * 2),
);

Gpio::<IDX>::new()
}
}

pub fn ss_enable(ss_bits: u32) {
write_u32(mmap::SS_RESET_EN, ss_bits);
}

pub fn clk2_set(conf_val: u32) {
write_u32(mmap::SS_CLK_CTRL2, conf_val);
}

pub fn clk3_set(conf_val: u32) {
write_u32(mmap::SS_CLK_CTRL3, conf_val);
}
53 changes: 50 additions & 3 deletions examples/headsail-bsp/src/uart.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,53 @@
use crate::{mmap::UART0_ADDR, mmap::UART_DATA_READY_OFFSET, read_u8, write_u8};
use crate::{
mmap::{UART0_ADDR, UART0_THR, UART_DATA_READY_OFFSET},
read_u8, write_u8,
};

#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;

#[cfg(feature = "asic")]
#[inline]
pub fn init_uart(freq: u32, baud: u32) {
use crate::mmap::{
UART0_DIV_LSB, UART0_DIV_MSB, UART0_FIFO_CONTROL, UART0_INTERRUPT_ENABLE,
UART0_LINE_CONTROL, UART0_MODEM_CONTROL,
};
const PERIPH_CLK_DIV: u32 = 2;
let divisor: u32 = freq / PERIPH_CLK_DIV / (baud << 4);

// Safety: unknown; we don't know if 8-bit writes will succeed
unsafe {
// Disable all interrupts
write_u8(UART0_INTERRUPT_ENABLE, 0x00);
// Enable DLAB (set baud rate divisor)
write_u8(UART0_LINE_CONTROL, 0x80);
// Divisor (lo byte)
write_u8(UART0_DIV_LSB, divisor as u8);
// Divisor (hi byte)
write_u8(UART0_DIV_MSB, (divisor >> 8) as u8);
// 8 bits, no parity, one stop bit
write_u8(UART0_LINE_CONTROL, 0x03);
// Enable FIFO, clear them, with 14-byte threshold
write_u8(UART0_FIFO_CONTROL, 0xC7);
// Autoflow mode
write_u8(UART0_MODEM_CONTROL, 0x20);
}
}

/// Dummy definition for VP, as the UART on VP does not require configuration
#[cfg(feature = "vp")]
pub fn init_uart(_freq: u32, _baud: u32) {}

#[cfg(feature = "asic")]
#[inline]
fn is_transmit_empty() -> bool {
// Safety: UART_LINE_STATUS is 4-byte aligned
unsafe { (read_u8(crate::mmap::UART0_LINE_STATUS) & 0x20) != 0 }
}

#[inline]
pub fn uart_write(s: &str) {
for b in s.as_bytes() {
Expand All @@ -14,8 +57,12 @@ pub fn uart_write(s: &str) {

#[inline]
pub fn putc(c: u8) {
// Safety: we don't know if u8 writes work for all target architectures
unsafe { write_u8(UART0_ADDR, c) };
// Wait for hardware to report completion
#[cfg(feature = "asic")]
while !is_transmit_empty() {}

// Safety: UART_THR is 4-byte aligned
unsafe { write_u8(UART0_THR, c) };
}

#[inline]
Expand Down
3 changes: 3 additions & 0 deletions examples/sysctrl/hello-sysctrl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
asic = ["headsail-bsp/asic"]

[dependencies]
headsail-bsp = { version = "0.1.0", path = "../../headsail-bsp", features = [
"sysctrl-rt",
Expand Down
Loading