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

Remove chip features from xtensa-lx package, add a super simple CI workflow #34

Merged
merged 3 commits into from
Feb 19, 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
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/xtensa-toolchain@v1.5
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/xtensa-toolchain@v1.5
# 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