Initial implementation of ram proc macro (#6)

* Add .iram section for ESP32C3, make it possible to use direct-boot or normal-boot

* Add ram proc-macro
This commit is contained in:
Björn Quentin 2022-01-18 19:02:40 +01:00 committed by GitHub
parent 9bbe5e0987
commit 70109ffe36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 720 additions and 15 deletions

View File

@ -17,6 +17,7 @@ paste = "1.0"
riscv = { version = "0.7", optional = true }
void = { version = "1.0", default-features = false }
xtensa-lx = { version = "0.4", optional = true }
procmacros = { path = "../esp-hal-procmacros", package = "esp-hal-procmacros" }
# IMPORTANT:
# Each supported device MUST have its PAC included below along with a
# corresponding feature.
@ -26,7 +27,7 @@ esp32s2_pac = { package = "esp32s2", git = "https://github.com/jessebraham/esp32
esp32s3_pac = { package = "esp32s3", git = "https://github.com/jessebraham/esp32s3.git", branch = "develop", optional = true }
[features]
esp32 = ["esp32_pac", "esp32_pac/rt", "xtensa-lx/lx6"]
esp32 = ["esp32_pac", "esp32_pac/rt", "xtensa-lx/lx6", "procmacros/rtc_slow"]
esp32c3 = ["esp32c3_pac", "esp32c3_pac/rt", "riscv"]
esp32s2 = ["esp32s2_pac", "esp32s2_pac/rt", "xtensa-lx/lx6"] # FIXME
esp32s3 = ["esp32s3_pac", "esp32s3_pac/rt", "xtensa-lx/lx6"] # FIXME
esp32s2 = ["esp32s2_pac", "esp32s2_pac/rt", "xtensa-lx/lx6", "procmacros/rtc_slow"] # FIXME
esp32s3 = ["esp32s3_pac", "esp32s3_pac/rt", "xtensa-lx/lx6", "procmacros/rtc_slow"] # FIXME

View File

@ -37,3 +37,6 @@ pub use delay::Delay;
pub use gpio::*;
pub use serial::Serial;
pub use timer::Timer;
use procmacros;
pub use procmacros::ram;

View File

@ -0,0 +1,24 @@
[package]
name = "esp-hal-procmacros"
version = "0.1.0"
authors = [
"Jesse Braham <jesse@beta7.io>",
"Björn Quentin <bjoern.quentin@mobile-j.de>",
]
edition = "2021"
description = "Procedural macros for ESP-HAL"
repository = "https://github.com/esp-rs/esp-hal"
license = "MIT OR Apache-2.0"
[lib]
proc-macro = true
[dependencies]
quote = "1.0"
proc-macro2 = "1.0"
darling = "0.10"
syn = {version = "1.0", features = ["extra-traits", "full"]}
proc-macro-error = "1.0.4"
[features]
rtc_slow = []

View File

@ -0,0 +1,91 @@
use darling::FromMeta;
use proc_macro::TokenStream;
use proc_macro::{self, Span};
use proc_macro_error::{abort, proc_macro_error};
use quote::quote;
use syn::{parse_macro_input, AttributeArgs};
#[derive(Debug, Default, FromMeta)]
#[darling(default)]
struct RamArgs {
rtc_fast: bool,
rtc_slow: bool,
uninitialized: bool,
zeroed: bool,
}
/// This attribute allows placing statics and functions into ram.
///
/// Options that can be specified are rtc_slow or rtc_fast to use the
/// RTC slow or RTC fast ram instead of the normal SRAM.
///
/// The uninitialized option will skip initialization of the memory
/// (e.g. to persist it across resets or deep sleep mode for the RTC RAM)
///
/// Not all targets support RTC slow ram.
#[proc_macro_attribute]
#[proc_macro_error]
pub fn ram(args: TokenStream, input: TokenStream) -> TokenStream {
let attr_args = parse_macro_input!(args as AttributeArgs);
let RamArgs {
rtc_fast,
rtc_slow,
uninitialized,
zeroed,
} = match FromMeta::from_list(&attr_args) {
Ok(v) => v,
Err(e) => {
return e.write_errors().into();
}
};
let item: syn::Item = syn::parse(input).expect("failed to parse input");
#[cfg(not(feature = "rtc_slow"))]
if rtc_slow {
abort!(
Span::call_site(),
"rtc_slow is not available for this target"
);
}
let is_fn = matches!(item, syn::Item::Fn(_));
let section_name = match (is_fn, rtc_fast, rtc_slow, uninitialized, zeroed) {
(true, false, false, false, false) => Ok(".rwtext"),
(true, true, false, false, false) => Ok(".rtc_fast.text"),
(true, false, true, false, false) => Ok(".rtc_slow.text"),
(false, false, false, false, false) => Ok(".data"),
(false, true, false, false, false) => Ok(".rtc_fast.data"),
(false, true, false, true, false) => Ok(".rtc_fast.noinit"),
(false, true, false, false, true) => Ok(".rtc_fast.bss"),
(false, false, true, false, false) => Ok(".rtc_slow.data"),
(false, false, true, true, false) => Ok(".rtc_slow.noinit"),
(false, false, true, false, true) => Ok(".rtc_slow.bss"),
_ => Err(()),
};
let section = match (is_fn, section_name) {
(true, Ok(section_name)) => quote! {
#[link_section = #section_name]
#[inline(never)] // make certain function is not inlined
},
(false, Ok(section_name)) => quote! {
#[link_section = #section_name]
},
(_, Err(_)) => {
abort!(Span::call_site(), "Invalid combination of ram arguments");
}
};
let output = quote! {
#section
#item
};
output.into()
}

91
esp32-hal/examples/ram.rs Normal file
View File

@ -0,0 +1,91 @@
#![no_std]
#![no_main]
use core::fmt::Write;
use esp32_hal::{
pac::{Peripherals, UART0},
prelude::*,
ram,
Serial,
Timer,
};
use nb::block;
use panic_halt as _;
use xtensa_lx_rt::entry;
#[ram(rtc_fast)]
static mut SOME_INITED_DATA: [u8; 2] = [0xaa, 0xbb];
#[ram(rtc_fast, uninitialized)]
static mut SOME_UNINITED_DATA: [u8; 2] = [0; 2];
#[ram(rtc_fast, zeroed)]
static mut SOME_ZEROED_DATA: [u8; 8] = [0; 8];
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take().unwrap();
let mut timer0 = Timer::new(peripherals.TIMG0);
let mut serial0 = Serial::new(peripherals.UART0).unwrap();
// Disable watchdog timer
timer0.disable();
timer0.start(10_000_000u64);
writeln!(
serial0,
"IRAM function located at {:p}",
function_in_ram as *const ()
)
.unwrap();
unsafe {
writeln!(serial0, "SOME_INITED_DATA {:x?}", SOME_INITED_DATA).unwrap();
writeln!(serial0, "SOME_UNINITED_DATA {:x?}", SOME_UNINITED_DATA).unwrap();
writeln!(serial0, "SOME_ZEROED_DATA {:x?}", SOME_ZEROED_DATA).unwrap();
SOME_INITED_DATA[0] = 0xff;
SOME_ZEROED_DATA[0] = 0xff;
writeln!(serial0, "SOME_INITED_DATA {:x?}", SOME_INITED_DATA).unwrap();
writeln!(serial0, "SOME_UNINITED_DATA {:x?}", SOME_UNINITED_DATA).unwrap();
writeln!(serial0, "SOME_ZEROED_DATA {:x?}", SOME_ZEROED_DATA).unwrap();
if SOME_UNINITED_DATA[0] != 0 {
SOME_UNINITED_DATA[0] = 0;
SOME_UNINITED_DATA[1] = 0;
}
if SOME_UNINITED_DATA[1] == 0xff {
SOME_UNINITED_DATA[1] = 0;
}
writeln!(serial0, "Counter {}", SOME_UNINITED_DATA[1]).unwrap();
SOME_UNINITED_DATA[1] += 1;
}
writeln!(
serial0,
"RTC_FAST function located at {:p}",
function_in_rtc_ram as *const ()
)
.unwrap();
writeln!(serial0, "Result {}", function_in_rtc_ram()).unwrap();
loop {
function_in_ram(&mut serial0);
block!(timer0.wait()).unwrap();
}
}
#[ram]
fn function_in_ram(serial0: &mut Serial<UART0>) {
writeln!(serial0, "Hello world!").unwrap();
}
#[ram(rtc_fast)]
fn function_in_rtc_ram() -> u32 {
42
}

View File

@ -78,16 +78,16 @@ SECTIONS {
.rtc_fast.data :
{
_rtc_fast_data_start = ABSOLUTE(.);
. = ALIGN(4);
_rtc_fast_data_start = ABSOLUTE(.);
*(.rtc_fast.data .rtc_fast.data.*)
_rtc_fast_data_end = ABSOLUTE(.);
} > rtc_fast_dram_seg AT > RODATA
.rtc_fast.bss (NOLOAD) :
{
_rtc_fast_bss_start = ABSOLUTE(.);
. = ALIGN(4);
_rtc_fast_bss_start = ABSOLUTE(.);
*(.rtc_fast.bss .rtc_fast.bss.*)
_rtc_fast_bss_end = ABSOLUTE(.);
} > rtc_fast_dram_seg
@ -106,16 +106,16 @@ SECTIONS {
.rtc_slow.data :
{
_rtc_slow_data_start = ABSOLUTE(.);
. = ALIGN(4);
_rtc_slow_data_start = ABSOLUTE(.);
*(.rtc_slow.data .rtc_slow.data.*)
_rtc_slow_data_end = ABSOLUTE(.);
} > rtc_slow_seg AT > RODATA
.rtc_slow.bss (NOLOAD) :
{
_rtc_slow_bss_start = ABSOLUTE(.);
. = ALIGN(4);
_rtc_slow_bss_start = ABSOLUTE(.);
*(.rtc_slow.bss .rtc_slow.bss.*)
_rtc_slow_bss_end = ABSOLUTE(.);
} > rtc_slow_seg

View File

@ -7,6 +7,8 @@ pub use self::gpio::IO;
pub mod gpio;
pub use esp_hal_common::ram;
#[no_mangle]
extern "C" fn DefaultHandler(_level: u32, _interrupt: pac::Interrupt) {}

View File

@ -1,6 +1,5 @@
[target.riscv32imc-unknown-none-elf]
rustflags = [
"-C", "link-arg=-Tesp32c3-link.x",
]
[build]

View File

@ -32,6 +32,7 @@ embedded-hal = { version = "0.2", features = ["unproven"] }
nb = "1.0"
riscv = "0.7"
void = { version = "1.0", default-features = false }
r0 = "1.0.0"
[dependencies.esp-hal-common]
path = "../esp-hal-common"
@ -48,3 +49,4 @@ panic-halt = "0.2"
[features]
default = ["rt"]
rt = ["riscv-rt"]
normalboot = []

View File

@ -0,0 +1,44 @@
MEMORY
{
/*
https://github.com/espressif/esptool/blob/master/esptool.py#L1919
MEMORY_MAP = [[0x00000000, 0x00010000, "PADDING"],
[0x3C000000, 0x3C800000, "DROM"],
[0x3FC80000, 0x3FCE0000, "DRAM"],
[0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"],
[0x3FF00000, 0x3FF20000, "DROM_MASK"],
[0x40000000, 0x40060000, "IROM_MASK"],
[0x42000000, 0x42800000, "IROM"],
[0x4037C000, 0x403E0000, "IRAM"],
[0x50000000, 0x50002000, "RTC_IRAM"],
[0x50000000, 0x50002000, "RTC_DRAM"],
[0x600FE000, 0x60100000, "MEM_INTERNAL2"]]
*/
/* 400K of on soc RAM, 16K reserved for cache */
ICACHE : ORIGIN = 0x4037C000, LENGTH = 0x4000
/* Instruction RAM */
IRAM : ORIGIN = 0x4037C000 + 0x4000, LENGTH = 400K - 0x4000
/* Data RAM */
DRAM : ORIGIN = 0x3FC80000, LENGTH = 0x50000
/* External flash */
/* Instruction ROM */
IROM : ORIGIN = 0x42000000 + 0x20, LENGTH = 0x400000 - 0x20
/* Data ROM */
DROM : ORIGIN = 0x3C000000, LENGTH = 0x400000
/* RTC fast memory (executable). Persists over deep sleep. */
RTC_FAST : ORIGIN = 0x50000000, LENGTH = 0x2000 /*- ESP_BOOTLOADER_RESERVE_RTC*/
}
REGION_ALIAS("REGION_TEXT", IROM);
REGION_ALIAS("REGION_RODATA", DROM);
REGION_ALIAS("REGION_DATA", DRAM);
REGION_ALIAS("REGION_BSS", DRAM);
REGION_ALIAS("REGION_HEAP", DRAM);
REGION_ALIAS("REGION_STACK", DRAM);
REGION_ALIAS("REGION_RWTEXT", IRAM);
REGION_ALIAS("REGION_RTC_FAST", RTC_FAST);

221
esp32c3-hal/bl-riscv-link.x Normal file
View File

@ -0,0 +1,221 @@
PROVIDE(_stext = ORIGIN(REGION_TEXT));
PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK));
PROVIDE(_max_hart_id = 0);
PROVIDE(_hart_stack_size = 2K);
PROVIDE(_heap_size = 0);
PROVIDE(UserSoft = DefaultHandler);
PROVIDE(SupervisorSoft = DefaultHandler);
PROVIDE(MachineSoft = DefaultHandler);
PROVIDE(UserTimer = DefaultHandler);
PROVIDE(SupervisorTimer = DefaultHandler);
PROVIDE(MachineTimer = DefaultHandler);
PROVIDE(UserExternal = DefaultHandler);
PROVIDE(SupervisorExternal = DefaultHandler);
PROVIDE(MachineExternal = DefaultHandler);
PROVIDE(DefaultHandler = DefaultInterruptHandler);
PROVIDE(ExceptionHandler = DefaultExceptionHandler);
/* # Pre-initialization function */
/* If the user overrides this using the `#[pre_init]` attribute or by creating a `__pre_init` function,
then the function this points to will be called before the RAM is initialized. */
PROVIDE(__pre_init = default_pre_init);
/* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */
PROVIDE(_setup_interrupts = default_setup_interrupts);
/* # Multi-processing hook function
fn _mp_hook() -> bool;
This function is called from all the harts and must return true only for one hart,
which will perform memory initialization. For other harts it must return false
and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt).
*/
PROVIDE(_mp_hook = default_mp_hook);
/* # Start trap function override
By default uses the riscv crates default trap handler
but by providing the `_start_trap` symbol external crates can override.
*/
PROVIDE(_start_trap = default_start_trap);
SECTIONS
{
.text.dummy (NOLOAD) :
{
/* This section is intended to make _stext address work */
. = ABSOLUTE(_stext);
} > REGION_TEXT
.text _stext :
{
_stext = .;
/* Put reset handler first in .text section so it ends up as the entry */
/* point of the program. */
KEEP(*(.init));
KEEP(*(.init.rust));
. = ALIGN(4);
(*(.trap));
(*(.trap.rust));
*(.text .text.*);
_etext = .;
} > REGION_TEXT
/**
* This dummy section represents the .text section but in rodata.
* Thus, it must have its alignement and (at least) its size.
*/
.text_dummy (NOLOAD):
{
/* Start at the same alignement constraint than .text */
. = ALIGN(ALIGNOF(.text));
/* Create an empty gap as big as .text section */
. = . + SIZEOF(.text);
/* Prepare the alignement of the section above. Few bytes (0x20) must be
* added for the mapping header. */
. = ALIGN(0x10000) + 0x20;
} > REGION_RODATA
.rodata : ALIGN(4)
{
_srodata = .;
*(.srodata .srodata.*);
*(.rodata .rodata.*);
/* 4-byte align the end (VMA) of this section.
This is required by LLD to ensure the LMA of the following .data
section will have the correct alignment. */
. = ALIGN(4);
_erodata = .;
} > REGION_RODATA
.rwtext : ALIGN(4) {
_irwtext = LOADADDR(.rwtext);
_srwtext = .;
*(.rwtext);
. = ALIGN(4);
_erwtext = .;
} > REGION_RWTEXT
/* similar as text_dummy */
.ram_dummy (NOLOAD) : {
. = ALIGN(ALIGNOF(.rwtext));
. = . + SIZEOF(.rwtext);
} > REGION_DATA
.data : ALIGN(4)
{
_sidata = LOADADDR(.data);
_sdata = .;
/* Must be called __global_pointer$ for linker relaxations to work. */
PROVIDE(__global_pointer$ = . + 0x800);
*(.sdata .sdata.* .sdata2 .sdata2.*);
*(.data .data.*);
. = ALIGN(4);
_edata = .;
} > REGION_DATA
.bss (NOLOAD) :
{
_sbss = .;
*(.sbss .sbss.* .bss .bss.*);
. = ALIGN(4);
_ebss = .;
} > REGION_BSS
/* fictitious region that represents the memory available for the heap */
.heap (NOLOAD) :
{
_sheap = .;
. += _heap_size;
. = ALIGN(4);
_eheap = .;
} > REGION_HEAP
/* fictitious region that represents the memory available for the stack */
.stack (NOLOAD) :
{
_estack = .;
. = ABSOLUTE(_stack_start);
_sstack = .;
} > REGION_STACK
.rtc_fast.text : ALIGN(4) {
*(.rtc_fast.literal .rtc_fast.text .rtc_fast.literal.* .rtc_fast.text.*)
} > REGION_RTC_FAST AT > REGION_RODATA
.rtc_fast.data : ALIGN(4)
{
_rtc_fast_data_start = ABSOLUTE(.);
*(.rtc_fast.data .rtc_fast.data.*)
_rtc_fast_data_end = ABSOLUTE(.);
} > REGION_RTC_FAST AT > REGION_RODATA
.rtc_fast.bss (NOLOAD) : ALIGN(4)
{
_rtc_fast_bss_start = ABSOLUTE(.);
*(.rtc_fast.bss .rtc_fast.bss.*)
_rtc_fast_bss_end = ABSOLUTE(.);
} > REGION_RTC_FAST
.rtc_fast.noinit (NOLOAD) : ALIGN(4)
{
*(.rtc_fast.noinit .rtc_fast.noinit.*)
} > REGION_RTC_FAST
.eh_frame (INFO) : { KEEP(*(.eh_frame)) }
.eh_frame_hdr (INFO) : { *(.eh_frame_hdr) }
}
/* Do not exceed this mark in the error messages above | */
ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
ASSERT(ORIGIN(REGION_RODATA) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_RODATA must be 4-byte aligned");
ASSERT(ORIGIN(REGION_DATA) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_DATA must be 4-byte aligned");
ASSERT(ORIGIN(REGION_HEAP) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_HEAP must be 4-byte aligned");
ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
ASSERT(ORIGIN(REGION_STACK) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_STACK must be 4-byte aligned");
ASSERT(_stext % 4 == 0, "
ERROR(riscv-rt): `_stext` must be 4-byte aligned");
ASSERT(_sdata % 4 == 0 && _edata % 4 == 0, "
BUG(riscv-rt): .data is not 4-byte aligned");
ASSERT(_sidata % 4 == 0, "
BUG(riscv-rt): the LMA of .data is not 4-byte aligned");
ASSERT(_sbss % 4 == 0 && _ebss % 4 == 0, "
BUG(riscv-rt): .bss is not 4-byte aligned");
ASSERT(_sheap % 4 == 0, "
BUG(riscv-rt): start of .heap is not 4-byte aligned");
ASSERT(_stext + SIZEOF(.text) < ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT), "
ERROR(riscv-rt): The .text section must be placed inside the REGION_TEXT region.
Set _stext to an address smaller than 'ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT)'");
ASSERT(SIZEOF(.stack) > (_max_hart_id + 1) * _hart_stack_size, "
ERROR(riscv-rt): .stack section is too small for allocating stacks for all the harts.
Consider changing `_max_hart_id` or `_hart_stack_size`.");
ASSERT(SIZEOF(.got) == 0, "
.got section detected in the input files. Dynamic relocations are not
supported. If you are linking to C code compiled using the `gcc` crate
then modify your build script to compile the C code _without_ the
-fPIC flag. See the documentation of the `gcc::Config.fpic` method for
details.");
/* Do not exceed this mark in the error messages above | */

View File

@ -1,27 +1,52 @@
use std::{env, fs::File, io::Write, path::PathBuf};
#[cfg(not(feature = "normalboot"))]
fn main() {
// Put the linker script somewhere the linker can find it
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x"))
.unwrap()
.write_all(include_bytes!("esp32c3-memory.x"))
.write_all(include_bytes!("db-esp32c3-memory.x"))
.unwrap();
File::create(out.join("esp32c3-link.x"))
.unwrap()
.write_all(include_bytes!("esp32c3-link.x"))
.write_all(include_bytes!("db-esp32c3-link.x"))
.unwrap();
File::create(out.join("riscv-link.x"))
.unwrap()
.write_all(include_bytes!("riscv-link.x"))
.unwrap();
.write_all(include_bytes!("db-riscv-link.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());
// Only re-run the build script when memory.x is changed,
// instead of when any part of the source code changes.
println!("cargo:rerun-if-changed=memory.x");
println!("cargo:rustc-link-arg=-Tesp32c3-link.x");
}
#[cfg(feature = "normalboot")]
fn main() {
// Put the linker script somewhere the linker can find it
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x"))
.unwrap()
.write_all(include_bytes!("bl-esp32c3-memory.x"))
.unwrap();
File::create(out.join("bl-riscv-link.x"))
.unwrap()
.write_all(include_bytes!("bl-riscv-link.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());
// Only re-run the build script when memory.x is changed,
// instead of when any part of the source code changes.
println!("cargo:rerun-if-changed=memory.x");
println!("cargo:rustc-link-arg=-Tmemory.x");
println!("cargo:rustc-link-arg=-Tbl-riscv-link.x");
}

View File

@ -27,6 +27,9 @@ MEMORY
IROM : ORIGIN = 0x42000000, LENGTH = 0x400000
/* Data ROM */
DROM : ORIGIN = 0x3C000000, LENGTH = 0x400000
/* RTC fast memory (executable). Persists over deep sleep. */
RTC_FAST : ORIGIN = 0x50000000, LENGTH = 0x2000 /*- ESP_BOOTLOADER_RESERVE_RTC*/
}
@ -36,4 +39,7 @@ REGION_ALIAS("REGION_RODATA", DROM);
REGION_ALIAS("REGION_DATA", DRAM);
REGION_ALIAS("REGION_BSS", DRAM);
REGION_ALIAS("REGION_HEAP", DRAM);
REGION_ALIAS("REGION_STACK", DRAM);
REGION_ALIAS("REGION_STACK", DRAM);
REGION_ALIAS("REGION_RWTEXT", IRAM);
REGION_ALIAS("REGION_RTC_FAST", RTC_FAST);

View File

@ -73,7 +73,6 @@ SECTIONS
_rodata_size = _erodata - _srodata + 8;
.data ORIGIN(DRAM) : AT(_text_size + _rodata_size)
{
_sidata = LOADADDR(.data);
_sdata = .;
/* Must be called __global_pointer$ for linker relaxations to work. */
PROVIDE(__global_pointer$ = . + 0x800);
@ -83,6 +82,7 @@ SECTIONS
_edata = .;
} > REGION_DATA
_data_size = _edata - _sdata + 8;
.bss (NOLOAD) :
{
_sbss = .;
@ -91,6 +91,14 @@ SECTIONS
_ebss = .;
} > REGION_BSS
.rwtext ORIGIN(REGION_RWTEXT) + _data_size : AT(_text_size + _rodata_size + _data_size){
_srwtext = .;
*(.rwtext);
. = ALIGN(4);
_erwtext = .;
} > REGION_RWTEXT
_rwtext_size = _erwtext - _srwtext + 8;
/* fictitious region that represents the memory available for the heap */
.heap (NOLOAD) :
{
@ -108,6 +116,36 @@ SECTIONS
_sstack = .;
} > REGION_STACK
.rtc_fast.text : AT(_text_size + _rodata_size + _data_size + _rwtext_size) {
_srtc_fast_text = .;
*(.rtc_fast.literal .rtc_fast.text .rtc_fast.literal.* .rtc_fast.text.*)
. = ALIGN(4);
_ertc_fast_text = .;
} > REGION_RTC_FAST
_fast_text_size = _ertc_fast_text - _srtc_fast_text + 8;
.rtc_fast.data : AT(_text_size + _rodata_size + _data_size + _rwtext_size + _fast_text_size)
{
_rtc_fast_data_start = ABSOLUTE(.);
*(.rtc_fast.data .rtc_fast.data.*)
. = ALIGN(4);
_rtc_fast_data_end = ABSOLUTE(.);
} > REGION_RTC_FAST
_rtc_fast_data_size = _rtc_fast_data_end - _rtc_fast_data_start + 8;
.rtc_fast.bss (NOLOAD) : ALIGN(4)
{
_rtc_fast_bss_start = ABSOLUTE(.);
*(.rtc_fast.bss .rtc_fast.bss.*)
. = ALIGN(4);
_rtc_fast_bss_end = ABSOLUTE(.);
} > REGION_RTC_FAST
.rtc_fast.noinit (NOLOAD) : ALIGN(4)
{
*(.rtc_fast.noinit .rtc_fast.noinit.*)
} > REGION_RTC_FAST
/* fake output .got section */
/* Dynamic relocations are unsupported. This section is only used to detect
relocatable code in the input files and raise an error if relocatable code
@ -121,6 +159,11 @@ SECTIONS
.eh_frame_hdr (INFO) : { *(.eh_frame_hdr) }
}
PROVIDE(_sidata = _erodata + 8);
PROVIDE(_irwtext = ORIGIN(DROM) + _text_size + _rodata_size + _data_size);
PROVIDE(_irtc_fast_text = ORIGIN(DROM) + _text_size + _rodata_size + _data_size + _rwtext_size);
PROVIDE(_irtc_fast_data = ORIGIN(DROM) + _text_size + _rodata_size + _data_size + _rwtext_size + _fast_text_size);
/* Do not exceed this mark in the error messages above | */
ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, "
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");

View File

@ -29,4 +29,4 @@ fn main() -> ! {
writeln!(serial0, "Hello world!").unwrap();
block!(timer0.wait()).unwrap();
}
}
}

View File

@ -0,0 +1,91 @@
#![no_std]
#![no_main]
use core::fmt::Write;
use esp32c3_hal::{
pac::{self, UART0},
prelude::*,
ram,
Serial,
Timer,
};
use nb::block;
use panic_halt as _;
use riscv_rt::entry;
#[ram(rtc_fast)]
static mut SOME_INITED_DATA: [u8; 2] = [0xaa, 0xbb];
#[ram(rtc_fast, uninitialized)]
static mut SOME_UNINITED_DATA: [u8; 2] = [0; 2];
#[ram(rtc_fast, zeroed)]
static mut SOME_ZEROED_DATA: [u8; 8] = [0; 8];
#[entry]
fn main() -> ! {
let peripherals = pac::Peripherals::take().unwrap();
let mut timer0 = Timer::new(peripherals.TIMG0);
let mut serial0 = Serial::new(peripherals.UART0).unwrap();
// don't disable WDTs ... we actually want it getting triggered in this example
timer0.disable();
timer0.start(10_000_000u64);
writeln!(
serial0,
"IRAM function located at {:p}",
function_in_ram as *const ()
)
.unwrap();
unsafe {
writeln!(serial0, "SOME_INITED_DATA {:x?}", SOME_INITED_DATA).unwrap();
writeln!(serial0, "SOME_UNINITED_DATA {:x?}", SOME_UNINITED_DATA).unwrap();
writeln!(serial0, "SOME_ZEROED_DATA {:x?}", SOME_ZEROED_DATA).unwrap();
SOME_INITED_DATA[0] = 0xff;
SOME_ZEROED_DATA[0] = 0xff;
writeln!(serial0, "SOME_INITED_DATA {:x?}", SOME_INITED_DATA).unwrap();
writeln!(serial0, "SOME_UNINITED_DATA {:x?}", SOME_UNINITED_DATA).unwrap();
writeln!(serial0, "SOME_ZEROED_DATA {:x?}", SOME_ZEROED_DATA).unwrap();
if SOME_UNINITED_DATA[0] != 0 {
SOME_UNINITED_DATA[0] = 0;
SOME_UNINITED_DATA[1] = 0;
}
if SOME_UNINITED_DATA[1] == 0xff {
SOME_UNINITED_DATA[1] = 0;
}
writeln!(serial0, "Counter {}", SOME_UNINITED_DATA[1]).unwrap();
SOME_UNINITED_DATA[1] += 1;
}
writeln!(
serial0,
"RTC_FAST function located at {:p}",
function_in_rtc_ram as *const ()
)
.unwrap();
writeln!(serial0, "Result {}", function_in_rtc_ram()).unwrap();
loop {
function_in_ram(&mut serial0);
block!(timer0.wait()).unwrap();
}
}
#[ram]
fn function_in_ram(serial0: &mut Serial<UART0>) {
writeln!(serial0, "Hello world!").unwrap();
}
#[ram(rtc_fast)]
fn function_in_rtc_ram() -> u32 {
42
}

View File

@ -2,8 +2,70 @@
pub use embedded_hal as ehal;
pub use esp_hal_common::{pac, prelude, Delay, Serial, Timer};
#[cfg(not(feature = "normalboot"))]
use riscv_rt::pre_init;
pub mod gpio;
pub mod rtc_cntl;
pub use esp_hal_common::ram;
pub use self::{gpio::IO, rtc_cntl::RtcCntl};
extern "C" {
// Boundaries of the .iram section
static mut _srwtext: u32;
static mut _erwtext: u32;
static mut _irwtext: u32;
// Boundaries of the .bss section
static mut _ebss: u32;
static mut _sbss: u32;
// Boundaries of the rtc .bss section
static mut _rtc_fast_bss_start: u32;
static mut _rtc_fast_bss_end: u32;
// Boundaries of the .rtc_fast.text section
static mut _srtc_fast_text: u32;
static mut _ertc_fast_text: u32;
static mut _irtc_fast_text: u32;
// Boundaries of the .rtc_fast.data section
static mut _rtc_fast_data_start: u32;
static mut _rtc_fast_data_end: u32;
static mut _irtc_fast_data: u32;
}
#[cfg(not(feature = "normalboot"))]
#[pre_init]
#[cfg(not(feature = "normalboot"))]
unsafe fn init() {
r0::init_data(&mut _srwtext, &mut _erwtext, &_irwtext);
r0::init_data(
&mut _rtc_fast_data_start,
&mut _rtc_fast_data_end,
&_irtc_fast_data,
);
r0::init_data(&mut _srtc_fast_text, &mut _ertc_fast_text, &_irtc_fast_text);
}
#[allow(unreachable_code)]
#[export_name = "_mp_hook"]
pub fn mp_hook() -> bool {
unsafe {
r0::zero_bss(&mut _rtc_fast_bss_start, &mut _rtc_fast_bss_end);
}
#[cfg(not(feature = "normalboot"))]
return true;
// no init data when using normal boot - but we need to zero out BSS
unsafe {
r0::zero_bss(&mut _sbss, &mut _ebss);
}
false
}