Skip to content
Closed
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
49 changes: 45 additions & 4 deletions esp-hal-common/src/interrupt/riscv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,50 @@ mod vectored {
}
}

/// Similar to [intrinsics::cttz], except we are able to place the lookup
/// table in SRAM
#[link_section = ".rwtext"]
fn ctz(n: u128) -> u32 {
// this isn't quite what LLVM does, they lower cttz to `ctpop(~X & (X-1))`,
// which use some kind of binary-search-like-algorithm plus a lookup
// table
#[inline(always)]
fn ctz32(n: u32) -> u32 {
// cf. https://en.wikipedia.org/wiki/Find_first_set#CTZ
#[link_section = ".data"]
static TABLE: [u8; 32] = {
let mut t = [0u8; 32];
let mut i = 0;
while i < 32 {
t[((0x077CB531_u32.wrapping_mul(1 << i)) >> 27) as usize] = i;
i += 1;
}
t
};

let n = n & (n as i32).wrapping_neg() as u32; // isolate lowest 1 bit
TABLE[(n.wrapping_mul(0x077CB531) >> 27) as usize] as u32
}

let n = n.to_ne_bytes();
let (n, _) = n.as_chunks::<4>();
for (i, b) in n.iter().enumerate() {
let n = u32::from_ne_bytes(*b);
if n != 0 {
return ctz32(n) + i as u32 * 32;
}
}
u128::BITS
}

/// Get the interrupts configured for the core
#[inline]
fn get_configured_interrupts(_core: Cpu, mut status: u128) -> [u128; 16] {
unsafe {
let mut prios = [0u128; 16];

while status != 0 {
let interrupt_nr = status.trailing_zeros() as u16;
let interrupt_nr = ctz(status) as u16;
// safety: cast is safe because of repr(u16)
let cpu_interrupt: CpuInterrupt =
get_assigned_cpu_interrupt(core::mem::transmute(interrupt_nr as u16));
Expand Down Expand Up @@ -220,9 +256,9 @@ mod vectored {

let configured_interrupts = get_configured_interrupts(crate::get_core(), status);
let mut interrupt_mask =
status & configured_interrupts[INTERRUPT_TO_PRIORITY[cpu_intr as usize - 1]];
status & configured_interrupts[interrupt_to_priority(cpu_intr as usize)];
while interrupt_mask != 0 {
let interrupt_nr = interrupt_mask.trailing_zeros();
let interrupt_nr = ctz(interrupt_mask);
// Interrupt::try_from can fail if interrupt already de-asserted:
// silently ignore
if let Ok(interrupt) = peripherals::Interrupt::try_from(interrupt_nr as u8) {
Expand All @@ -232,7 +268,7 @@ mod vectored {
}
}

#[ram]
#[inline(always)]
unsafe fn handle_interrupt(interrupt: Interrupt, save_frame: &mut TrapFrame) {
extern "C" {
// defined in each hal
Expand Down Expand Up @@ -606,6 +642,11 @@ mod classic {
use super::{CpuInterrupt, InterruptKind, Priority};
use crate::Cpu;

#[inline(always)]
pub(super) const fn interrupt_to_priority(irq: usize) -> usize {
irq
}

pub(super) const PRIORITY_TO_INTERRUPT: [usize; 15] =
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];

Expand Down
3 changes: 3 additions & 0 deletions esp-hal-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
feature(impl_trait_projections)
)]
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
#![feature(const_mut_refs)]
#![feature(slice_as_chunks)]

#[cfg(riscv)]
pub use esp_riscv_rt::{self, entry, riscv};
Expand Down Expand Up @@ -167,6 +169,7 @@ pub enum Cpu {
AppCpu,
}

#[inline(always)]
pub fn get_core() -> Cpu {
#[cfg(all(xtensa, multi_core))]
match ((xtensa_lx::get_processor_id() >> 13) & 1) != 0 {
Expand Down
3 changes: 3 additions & 0 deletions esp32c3-hal/.cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
runner = "espflash flash --monitor"
rustflags = [
"-C", "link-arg=-Tlinkall.x",
"-C", "force-frame-pointers",

"-C", "llvm-args=--max-jump-table-size=0",

# comment the cfgs below if you do _not_ wish to emulate atomics.
# enable the atomic codegen option for RISCV
Expand Down
8 changes: 7 additions & 1 deletion esp32c3-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,13 @@ embassy-time-timg0 = ["esp-hal-common/embassy-time-timg0", "embassy-time/tick-hz
interrupt-preemption = ["esp-hal-common/interrupt-preemption"]

[profile.dev]
opt-level = 1
opt-level = 2
lto = "thin"

[profile.release]
debug = true
opt-level = 2
lto = "thin"

[[example]]
name = "spi_eh1_loopback"
Expand Down Expand Up @@ -101,3 +104,6 @@ required-features = ["embassy", "async"]
[[example]]
name = "embassy_i2c"
required-features = ["embassy", "async"]

[patch.crates-io]
esp32c3 = { git = "https://github.com/rustbox/esp-pacs", rev = "c8e7cbb1cef4f6b3fd565c8fbb30e37674657877" }
8 changes: 7 additions & 1 deletion esp32c3-hal/examples/gpio_interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,15 @@ fn main() -> ! {
}

#[interrupt]
#[ram]
fn GPIO() {
critical_section::with(|cs| {
esp_println::println!("GPIO interrupt");
// can't use println! here, because it delegates to `core::write!` which in turn
// is opaquely "stuck" in Flash
{
use core::fmt::Write;
(esp_println::Printer).write_str("GPIO interrupt\n").ok();
}
BUTTON
.borrow_ref_mut(cs)
.as_mut()
Expand Down
4 changes: 2 additions & 2 deletions esp32c3-hal/ld/db-riscv-link.x
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ SECTIONS
KEEP(*(.init.rust));
KEEP(*(.text.abort));
. = ALIGN(4);
KEEP(*(.trap));
KEEP(*(.trap.rust));

*(.text .text.*);
_etext = .;
Expand Down Expand Up @@ -91,6 +89,8 @@ SECTIONS
_data_size = _data_end - _data_start + 8;
.rwtext ORIGIN(REGION_RWTEXT) + _data_size : AT(_text_size + _rodata_size + _data_size){
_srwtext = .;
KEEP(*(.trap));
KEEP(*(.trap.rust));
*(.rwtext);
. = ALIGN(4);
_erwtext = .;
Expand Down
40 changes: 40 additions & 0 deletions esp32c3-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,46 @@ pub mod analog {
pub use esp_hal_common::analog::{AvailableAnalog, SarAdcExt};
}

mod mem {
#[no_mangle]
#[link_section = ".rwtext"]
pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
let r = dest;
let (n, m) = (n / 4, n % 4);
for i in 0..m {
*dest.add(i) = *src.add(i);
}
let dest = dest.add(m).cast::<usize>();
let src = src.add(m).cast::<usize>();
for i in 0..n {
*dest.add(i) = *src.add(i);
}
r
}

#[no_mangle]
#[link_section = ".rwtext"]
pub unsafe extern "C" fn memset(
p: *mut u8,
c: i32, // equivalent to a c int
n: usize,
) -> *mut u8 {
let s = p;
let (n, m) = (n / 4, n % 4);
let b = c as u8;
for i in 0..m {
*p.add(i) = b
}
let p = p.add(m).cast::<usize>();

let w = usize::from_ne_bytes([b; 4]);
for i in 0..n {
*p.add(i) = w;
}
s
}
}

extern "C" {
cfg_if::cfg_if! {
if #[cfg(feature = "mcu-boot")] {
Expand Down