Skip to content
This repository has been archived by the owner on Jul 17, 2024. It is now read-only.

Commit

Permalink
Remove chip features from xtensa-lx package, add a super simple CI …
Browse files Browse the repository at this point in the history
…workflow (#34)

* Remove chip features from `xtensa-lx` package

* Add `rustfmt.toml` config file, format source

* Add a CI workflow to check the `xtensa-lx` and `xtensa-lx-rt` packages
  • Loading branch information
jessebraham authored Feb 19, 2024
1 parent d42af19 commit 1a028a9
Show file tree
Hide file tree
Showing 15 changed files with 214 additions and 117 deletions.
88 changes: 88 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: CI

on:
pull_request:
paths-ignore:
- "**/README.md"
push:
paths-ignore:
- "**/README.md"
merge_group:
workflow_dispatch:

env:
CARGO_TERM_COLOR: always
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# Cancel any currently running workflows from the same PR, branch, or
# tag when a new workflow is triggered.
#
# https://stackoverflow.com/a/66336834
concurrency:
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}

jobs:
# --------------------------------------------------------------------------
# Check Packages

xtensa-lx:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: esp-rs/[email protected]
with:
default: true
ldproxy: false
- uses: Swatinem/rust-cache@v2

# Build the 'xtensa-lx' package:
- name: check (no features)
run: cd xtensa-lx/ && cargo build
- name: check (all features)
run: cd xtensa-lx/ && cargo build --features=float-save-restore,spin

# xtensa-lx-rt:
# runs-on: ubuntu-latest
#
# strategy:
# fail-fast: false
# matrix:
# chip: ["esp32", "esp32s2", "esp32s3"]
#
# steps:
# - uses: actions/checkout@v4
# - uses: esp-rs/[email protected]
# with:
# default: true
# ldproxy: false
# - uses: Swatinem/rust-cache@v2
#
# # Build the 'xtensa-lx-rt' package:
# - name: check (${{ matrix.chip }}, no features)
# run: cd xtensa-lx-rt/ && cargo build --features=${{ matrix.chip }}
# - name: check (${{ matrix.chip }}, all features)
# run: cd xtensa-lx-rt/ && cargo build --features=${{ matrix.chip }},float-save-restore

# --------------------------------------------------------------------------
# Lint

rustfmt:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
# Some of the configuration items in 'rustfmt.toml' require the 'nightly'
# release channel:
- uses: dtolnay/rust-toolchain@v1
with:
toolchain: nightly
components: rustfmt
- uses: Swatinem/rust-cache@v2

# Check the formatting of all packages:
- name: rustfmt (xtensa-lx)
run: cargo fmt --all --manifest-path=xtensa-lx/Cargo.toml -- --check
- name: rustfmt (xtensa-lx-rt)
run: cargo fmt --all --manifest-path=xtensa-lx-rt/Cargo.toml -- --check
9 changes: 9 additions & 0 deletions rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Comments
format_code_in_doc_comments = true
normalize_comments = true
wrap_comments = true

# Imports
group_imports = "StdExternalCrate"
imports_granularity = "Crate"
imports_layout = "HorizontalVertical"
15 changes: 9 additions & 6 deletions xtensa-lx-rt/build.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::collections::{HashMap, HashSet};
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::{
collections::{HashMap, HashSet},
env,
fs::File,
io::Write,
path::PathBuf,
};

use core_isa_parser::{get_config, Chip, Value};
use minijinja::{context, Environment};
Expand Down Expand Up @@ -35,7 +37,8 @@ fn handle_esp32() {

let mut features_to_disable: HashSet<String> = HashSet::new();

// Users can pass -Ctarget-feature to the compiler multiple times, so we have to handle that
// Users can pass -Ctarget-feature to the compiler multiple times, so we have to
// handle that
let target_flags = rustflags
.split(0x1f as char)
.filter(|s| s.starts_with("target-feature="))
Expand Down
20 changes: 11 additions & 9 deletions xtensa-lx-rt/procmacros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
let ty = &statik.ty;
let attrs = &statik.attrs;

// Note that we use an explicit `'static` lifetime for the entry point arguments. This makes
// it more flexible, and is sound here, since the entry will not be called again, ever.
// Note that we use an explicit `'static` lifetime for the entry point
// arguments. This makes it more flexible, and is sound here, since the
// entry will not be called again, ever.
syn::parse::<FnArg>(
quote!(#[allow(non_snake_case)] #(#attrs)* #ident: &'static mut #ty).into(),
)
Expand Down Expand Up @@ -201,12 +202,13 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
.into()
}

/// Marks a function as the interrupt handler, with optional interrupt level indicated
/// Marks a function as the interrupt handler, with optional interrupt level
/// indicated
///
/// When the function is also marked `#[naked]`, it is a low-level interrupt handler:
/// no entry and exit code to store processor state will be generated.
/// The user needs to ensure that all registers which are used are saved and restored and that
/// the proper return instruction is used.
/// When the function is also marked `#[naked]`, it is a low-level interrupt
/// handler: no entry and exit code to store processor state will be generated.
/// The user needs to ensure that all registers which are used are saved and
/// restored and that the proper return instruction is used.
#[proc_macro_attribute]
pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
let mut f: ItemFn = syn::parse(input).expect("`#[interrupt]` must be applied to a function");
Expand Down Expand Up @@ -403,8 +405,8 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
}
}

/// Marks a function as the pre_init function. This function is called before main and *before
/// the memory is initialized*.
/// Marks a function as the pre_init function. This function is called before
/// main and *before the memory is initialized*.
#[proc_macro_attribute]
pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
let f = parse_macro_input!(input as ItemFn);
Expand Down
34 changes: 16 additions & 18 deletions xtensa-lx-rt/src/exception.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,37 @@
//! Exception handling
//!
//! Currently specialized for ESP32 (LX6) configuration: which extra registers to store,
//! how many interrupt levels etc.
//! Currently specialized for ESP32 (LX6) configuration: which extra registers
//! to store, how many interrupt levels etc.
//!
//! First level interrupts and exceptions save full processor state to the user stack.
//! This includes the coprocessor registers contrary to the esp-idf where these are lazily saved.
//! (Kernel mode option is currently not used.)
//! First level interrupts and exceptions save full processor state to the user
//! stack. This includes the coprocessor registers contrary to the esp-idf where
//! these are lazily saved. (Kernel mode option is currently not used.)
//!
//! WindowUnder/Overflow and AllocA use default Xtensa implementation.
//!
//! LoadStoreError and Unaligned are not (yet) implemented: so all accesses to IRAM must
//! be word sized and aligned.
//! LoadStoreError and Unaligned are not (yet) implemented: so all accesses to
//! IRAM must be word sized and aligned.
//!
//! Syscall 0 is not (yet) implemented: it doesn't seem to be used in rust.
//!
//! Double Exceptions can only occur during the early setup of the exception handler. Afterwards
//! PS.EXCM is set to 0 to be able to handle WindowUnderflow/Overflow and recursive exceptions will
//! happen instead.
//!
//! In various places call0 are used as long jump: `j.l` syntax is not supported and `call0`
//! can always be expanded to `mov a0,label; call a0`. Care must be taken since A0 is overwritten.
//! Double Exceptions can only occur during the early setup of the exception
//! handler. Afterwards PS.EXCM is set to 0 to be able to handle
//! WindowUnderflow/Overflow and recursive exceptions will happen instead.
//!
//! In various places call0 are used as long jump: `j.l` syntax is not supported
//! and `call0` can always be expanded to `mov a0,label; call a0`. Care must be
//! taken since A0 is overwritten.
mod asm;
mod context;

pub use context::Context;


/// EXCCAUSE register values
///
/// General Exception Causes. (Values of EXCCAUSE special register set by general exceptions,
/// which vector to the user, kernel, or double-exception vectors).
///
/// General Exception Causes. (Values of EXCCAUSE special register set by
/// general exceptions, which vector to the user, kernel, or double-exception
/// vectors).
#[allow(unused)]
#[derive(Debug)]
#[repr(C)]
Expand Down Expand Up @@ -120,4 +119,3 @@ pub enum ExceptionCause {

None = 255,
}

34 changes: 21 additions & 13 deletions xtensa-lx-rt/src/exception/asm.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::cfg_asm;
use core::arch::{asm, global_asm};

use crate::cfg_asm;

// we could cfg symbols away and reduce frame size depending on features enabled
// i.e the frame size is a fixed size based on all the features right now
// we know at compile time if a target has loops for example, if it doesn't
// we could cut that memory usage.
// However in order to conveniently use `addmi` we need 256-byte alignment anyway
// so wasting a bit more stack space seems to be the better option.
// However in order to conveniently use `addmi` we need 256-byte alignment
// anyway so wasting a bit more stack space seems to be the better option.
// Additionally there is a chunk of memory reserved for spilled registers.
global_asm!(
"
Expand Down Expand Up @@ -481,8 +482,8 @@ global_asm!(
"#
);

/// Handle Other Exceptions or Level 1 interrupt by storing full context and then
/// calling regular function
/// Handle Other Exceptions or Level 1 interrupt by storing full context and
/// then calling regular function
///
/// # Input:
/// * A0 stored in EXCSAVE1
Expand Down Expand Up @@ -524,8 +525,9 @@ unsafe extern "C" fn __default_naked_exception() {
)
}

/// Handle Double Exceptions by storing full context and then calling regular function
/// Double exceptions are not a normal occurrence. They indicate a bug of some kind.
/// Handle Double Exceptions by storing full context and then calling regular
/// function Double exceptions are not a normal occurrence. They indicate a bug
/// of some kind.
///
/// # Input:
/// * A0 stored in EXCSAVE1
Expand Down Expand Up @@ -602,7 +604,8 @@ global_asm!(
"#
);

/// Handle Level 2 Interrupt by storing full context and then calling regular function
/// Handle Level 2 Interrupt by storing full context and then calling regular
/// function
///
/// # Input:
/// * A0 stored in EXCSAVE2
Expand All @@ -613,7 +616,8 @@ unsafe extern "C" fn __default_naked_level_2_interrupt() {
asm!("HANDLE_INTERRUPT_LEVEL 2", options(noreturn));
}

/// Handle Level 3 Interrupt by storing full context and then calling regular function
/// Handle Level 3 Interrupt by storing full context and then calling regular
/// function
///
/// # Input:
/// * A0 stored in EXCSAVE3
Expand All @@ -624,7 +628,8 @@ unsafe extern "C" fn __default_naked_level_3_interrupt() {
asm!("HANDLE_INTERRUPT_LEVEL 3", options(noreturn));
}

/// Handle Level 4 Interrupt by storing full context and then calling regular function
/// Handle Level 4 Interrupt by storing full context and then calling regular
/// function
///
/// # Input:
/// * A0 stored in EXCSAVE4
Expand All @@ -635,7 +640,8 @@ unsafe extern "C" fn __default_naked_level_4_interrupt() {
asm!("HANDLE_INTERRUPT_LEVEL 4", options(noreturn));
}

/// Handle Level 5 Interrupt by storing full context and then calling regular function
/// Handle Level 5 Interrupt by storing full context and then calling regular
/// function
///
/// # Input:
/// * A0 stored in EXCSAVE5
Expand All @@ -646,7 +652,8 @@ unsafe extern "C" fn __default_naked_level_5_interrupt() {
asm!("HANDLE_INTERRUPT_LEVEL 5", options(noreturn));
}

/// Handle Level 6 (=Debug) Interrupt by storing full context and then calling regular function
/// Handle Level 6 (=Debug) Interrupt by storing full context and then calling
/// regular function
///
/// # Input:
/// * A0 stored in EXCSAVE6
Expand All @@ -657,7 +664,8 @@ unsafe extern "C" fn __default_naked_level_6_interrupt() {
asm!("HANDLE_INTERRUPT_LEVEL 6", options(noreturn));
}

/// Handle Level 7 (=NMI) Interrupt by storing full context and then calling regular function
/// Handle Level 7 (=NMI) Interrupt by storing full context and then calling
/// regular function
///
/// # Input:
/// * A0 stored in EXCSAVE7
Expand Down
12 changes: 7 additions & 5 deletions xtensa-lx-rt/src/exception/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ extern "Rust" {
fn __exception(cause: ExceptionCause, save_frame: &mut Context);
/// This symbol will be provided by the user via `#[exception]`
fn __user_exception(cause: ExceptionCause, save_frame: &mut Context);
/// No attribute is supplied for this symbol as the double exception can hardly occur
/// No attribute is supplied for this symbol as the double exception can
/// hardly occur
fn __double_exception(cause: ExceptionCause, save_frame: &mut Context);

/// This symbol will be provided by the user via `#[interrupt(1)]`
Expand Down Expand Up @@ -139,10 +140,11 @@ extern "C" fn __default_double_exception(cause: ExceptionCause, save_frame: &Con
//
// The interrupt handlers all use special return instructions.
// rust still generates a ret.w instruction, which will never be reached.
// generation of the ret.w can be prevented by using core::intrinsics::unreachable,
// but then a break 15,1 will be generated (which takes 3 bytes instead of 2) or a 'loop {}',
// but then a jump to own address will be generated which is also 3 bytes.
// No way found yet to prevent this generation altogether.
// generation of the ret.w can be prevented by using
// core::intrinsics::unreachable, but then a break 15,1 will be generated (which
// takes 3 bytes instead of 2) or a 'loop {}', but then a jump to own address
// will be generated which is also 3 bytes. No way found yet to prevent this
// generation altogether.

#[naked]
#[no_mangle]
Expand Down
4 changes: 2 additions & 2 deletions xtensa-lx-rt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ pub unsafe extern "C" fn Reset() -> ! {

// Copy of data segment is done by bootloader

// According to 4.4.6.2 of the xtensa isa, ccount and compare are undefined on reset,
// set all values to zero to disable
// According to 4.4.6.2 of the xtensa isa, ccount and compare are undefined on
// reset, set all values to zero to disable
reset_internal_timers();

// move vec table
Expand Down
Loading

0 comments on commit 1a028a9

Please sign in to comment.