diff --git a/.github/.cspell/project-dictionary.txt b/.github/.cspell/project-dictionary.txt
index 523ddb4..b86ba05 100644
--- a/.github/.cspell/project-dictionary.txt
+++ b/.github/.cspell/project-dictionary.txt
@@ -11,6 +11,7 @@ ebreak
EINTR
EINVAL
errno
+espup
fipe
FLEN
fopen
@@ -39,6 +40,7 @@ nlink
norvc
nsec
OMAP
+openocd
opensbi
pcnet
plog
@@ -55,12 +57,14 @@ requirechecksums
rustfilt
sdbbp
Seekable
+simcall
slli
srai
subarch
subcode
syscall
TDMI
+Tensilica
tickfreq
timespec
TMPNAM
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4406402..2124de4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -93,7 +93,7 @@ jobs:
- run: cargo test --workspace --features $TEST_FEATURES --release --target ${{ matrix.target }} $DOCTEST_XCOMPILE $BUILD_STD
- run: cargo careful test --workspace --features $TEST_FEATURES --target ${{ matrix.target }} $DOCTEST_XCOMPILE $BUILD_STD
if: startsWith(matrix.rust, 'nightly')
- - run: cargo hack build --workspace --no-private --feature-powerset --depth 2 --optional-deps=portable-atomic --exclude-features panic-unwind,backtrace --target ${{ matrix.target }} $BUILD_STD
+ - run: cargo hack build --workspace --no-private --feature-powerset --depth 2 --optional-deps=portable-atomic --exclude-features panic-unwind,backtrace,openocd-semihosting --target ${{ matrix.target }} $BUILD_STD
- run: cargo minimal-versions build --workspace --no-private --detach-path-deps=skip-exact --features $TEST_FEATURES --target ${{ matrix.target }} $BUILD_STD
- run: cargo minimal-versions build --workspace --no-private --detach-path-deps=skip-exact --features $TEST_FEATURES --target ${{ matrix.target }} $BUILD_STD --direct
@@ -117,6 +117,12 @@ jobs:
- uses: taiki-e/checkout-action@v1
- name: Install Rust
run: rustup toolchain add ${{ matrix.rust }} --no-self-update --component rust-src && rustup default ${{ matrix.rust }}
+ - uses: taiki-e/install-action@v2
+ with:
+ tool: espup
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ if: startsWith(matrix.rust, 'nightly') && (startsWith(matrix.os, 'ubuntu') || matrix.os == '')
- run: |
set -eEuxo pipefail
sudo apt-get -o Acquire::Retries=10 -qq update && sudo apt-get -o Acquire::Retries=10 -o Dpkg::Use-Pty=0 install -y --no-install-recommends \
@@ -164,6 +170,12 @@ jobs:
echo "C:\Program Files\qemu" >>"${GITHUB_PATH}"
"C:\Program Files\qemu\qemu-system-arm" --version
if: startsWith(matrix.os, 'windows')
+ - run: espup install --targets esp32
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ if: startsWith(matrix.rust, 'nightly') && (startsWith(matrix.os, 'ubuntu') || matrix.os == '')
- run: tools/no-std.sh
- run: TEST_RUNNER=qemu-user tools/no-std.sh
if: startsWith(matrix.os, 'ubuntu') || matrix.os == ''
+ - run: cargo +esp build --target xtensa-esp32-none-elf -Z build-std=core,alloc --features $TEST_FEATURES,openocd-semihosting
+ if: startsWith(matrix.rust, 'nightly') && (startsWith(matrix.os, 'ubuntu') || matrix.os == '')
diff --git a/Cargo.toml b/Cargo.toml
index a91c210..907131e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,7 +9,7 @@ keywords = ["qemu"]
categories = ["embedded", "hardware-support", "no-std", "no-std::no-alloc"]
exclude = ["/.*", "/tools", "/target-specs"]
description = """
-Semihosting for AArch64, ARM, RISC-V, MIPS32, and MIPS64.
+Semihosting for AArch64, ARM, RISC-V, MIPS32, MIPS64, and Xtensa.
"""
[package.metadata.docs.rs]
@@ -77,6 +77,11 @@ backtrace = ["stdio", "unwinding", "unwinding/hide-trace"]
# See readme for details.
portable-atomic = ["dep:portable-atomic"]
+# Xtensa-specific: Use OpenOCD Semihosting.
+#
+# See readme for details.
+openocd-semihosting = []
+
[dependencies]
portable-atomic = { version = "1.3", optional = true, default-features = false, features = ["require-cas"] }
unwinding = { version = "0.2", optional = true, default-features = false, features = ["unwinder"] }
diff --git a/README.md b/README.md
index 1ad3e24..c4206ae 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
[![github actions](https://img.shields.io/github/actions/workflow/status/taiki-e/semihosting/ci.yml?branch=main&style=flat-square&logo=github)](https://github.com/taiki-e/semihosting/actions)
-Semihosting for AArch64, ARM, RISC-V, MIPS32, and MIPS64.
+Semihosting for AArch64, ARM, RISC-V, MIPS32, MIPS64, and Xtensa.
This library provides access to semihosting, a mechanism for programs running on the real or virtual (e.g., QEMU) target to communicate with I/O facilities on the host system. See the [ARM documentation](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst) for more information on semihosting.
@@ -36,11 +36,12 @@ Additionally, this library provides a panic handler for semihosting, `-C panic=u
The following target architectures are supported:
-| target_arch | Specification | `semihosting::sys` module |
-| ----------- | ------------- | ------------------------- |
-| arm/aarch64 | [Semihosting for AArch32 and AArch64](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst) | `sys::arm_compat` |
-| riscv32/riscv64 | [RISC-V Semihosting](https://github.com/riscv-software-src/riscv-semihosting/blob/HEAD/riscv-semihosting-spec.adoc) | `sys::arm_compat` |
-| mips/mips32r6/mips64/mips64r6 | Unified Hosting Interface (MD01069) | `sys::mips` |
+| target_arch | Specification | `semihosting::sys` module | Note |
+| ----------- | ------------- | ------------------------- | ---- |
+| arm/aarch64 | [Semihosting for AArch32 and AArch64](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst) | `sys::arm_compat` | |
+| riscv32/riscv64 | [RISC-V Semihosting](https://github.com/riscv-software-src/riscv-semihosting/blob/HEAD/riscv-semihosting-spec.adoc) | `sys::arm_compat` | |
+| xtensa | [OpenOCD Semihosting](https://github.com/espressif/openocd-esp32/blob/HEAD/src/target/espressif/esp_xtensa_semihosting.c) | `sys::arm_compat` | requires the [`openocd-semihosting` feature](#optional-features-openocd-semihosting) |
+| mips/mips32r6/mips64/mips64r6 | Unified Hosting Interface (MD01069) | `sys::mips` | |
The host must be running an emulator or a debugger attached to the target.
@@ -98,6 +99,16 @@ semihosting = { version = "0.1", features = ["stdio", "panic-handler"] }
If the `stdio` feature is also enabled, this attempt to output panic message and
location to stderr.
+- **`openocd-semihosting`**
+ Xtensa-specific: Use OpenOCD Semihosting.
+
+ Xtensa has two semihosting interfaces:
+
+ - Tensilica ISS SIMCALL used in Cadence tools and [QEMU](https://www.qemu.org/docs/master/about/emulation.html#supported-targets).
+ - ARM-semihosting-compatible semihosting interface used in [OpenOCD](https://github.com/espressif/openocd-esp32/blob/HEAD/src/target/espressif/esp_xtensa_semihosting.c) and [probe-rs](https://github.com/probe-rs/probe-rs/pull/2303). (This crate calls it "OpenOCD Semihosting", which is the same as the option name in [newlib](https://github.com/espressif/newlib-esp32/blob/esp_based_on_4_1_0/libgloss/xtensa/syscalls.c#L23).)
+
+ This crate does not currently support SIMCALL-based semihosting, but users need to explicitly enable the feature to avoid accidentally selecting a different one than one actually want to use.
+
- **`portable-atomic`**
Use [portable-atomic]'s atomic types.
diff --git a/src/experimental/env.rs b/src/experimental/env.rs
index 7e2cb30..9b95d9c 100644
--- a/src/experimental/env.rs
+++ b/src/experimental/env.rs
@@ -81,6 +81,7 @@ mod sys {
target_arch = "arm",
target_arch = "riscv32",
target_arch = "riscv64",
+ all(target_arch = "xtensa", feature = "openocd-semihosting"),
))]
mod imp {
use core::cell::Cell;
diff --git a/src/experimental/time.rs b/src/experimental/time.rs
index d2ed8b3..a5d7b1b 100644
--- a/src/experimental/time.rs
+++ b/src/experimental/time.rs
@@ -206,6 +206,7 @@ mod sys {
target_arch = "arm",
target_arch = "riscv32",
target_arch = "riscv64",
+ all(target_arch = "xtensa", feature = "openocd-semihosting"),
))]
mod inner {
use super::{SystemTime, Timespec};
diff --git a/src/lib.rs b/src/lib.rs
index e5b01db..d818c7a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,7 +2,7 @@
/*!
-Semihosting for AArch64, ARM, RISC-V, MIPS32, and MIPS64.
+Semihosting for AArch64, ARM, RISC-V, MIPS32, MIPS64, and Xtensa.
This library provides access to semihosting, a mechanism for programs running on the real or virtual (e.g., QEMU) target to communicate with I/O facilities on the host system. See the [ARM documentation](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst) for more information on semihosting.
@@ -31,11 +31,12 @@ Additionally, this library provides a panic handler for semihosting, `-C panic=u
The following target architectures are supported:
-| target_arch | Specification | `semihosting::sys` module |
-| ----------- | ------------- | ------------------------- |
-| arm/aarch64 | [Semihosting for AArch32 and AArch64](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst) | `sys::arm_compat` |
-| riscv32/riscv64 | [RISC-V Semihosting](https://github.com/riscv-software-src/riscv-semihosting/blob/HEAD/riscv-semihosting-spec.adoc) | `sys::arm_compat` |
-| mips/mips32r6/mips64/mips64r6 | Unified Hosting Interface (MD01069) | `sys::mips` |
+| target_arch | Specification | `semihosting::sys` module | Note |
+| ----------- | ------------- | ------------------------- | ---- |
+| arm/aarch64 | [Semihosting for AArch32 and AArch64](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst) | `sys::arm_compat` | |
+| riscv32/riscv64 | [RISC-V Semihosting](https://github.com/riscv-software-src/riscv-semihosting/blob/HEAD/riscv-semihosting-spec.adoc) | `sys::arm_compat` | |
+| xtensa | [OpenOCD Semihosting](https://github.com/espressif/openocd-esp32/blob/HEAD/src/target/espressif/esp_xtensa_semihosting.c) | `sys::arm_compat` | requires the [`openocd-semihosting` feature](#optional-features-openocd-semihosting) |
+| mips/mips32r6/mips64/mips64r6 | Unified Hosting Interface (MD01069) | `sys::mips` | |
The host must be running an emulator or a debugger attached to the target.
@@ -93,6 +94,16 @@ semihosting = { version = "0.1", features = ["stdio", "panic-handler"] }
If the `stdio` feature is also enabled, this attempt to output panic message and
location to stderr.
+- **`openocd-semihosting`**
+ Xtensa-specific: Use OpenOCD Semihosting.
+
+ Xtensa has two semihosting interfaces:
+
+ - Tensilica ISS SIMCALL used in Cadence tools and [QEMU](https://www.qemu.org/docs/master/about/emulation.html#supported-targets).
+ - ARM-semihosting-compatible semihosting interface used in [OpenOCD](https://github.com/espressif/openocd-esp32/blob/HEAD/src/target/espressif/esp_xtensa_semihosting.c) and [probe-rs](https://github.com/probe-rs/probe-rs/pull/2303). (This crate calls it "OpenOCD Semihosting", which is the same as the option name in [newlib](https://github.com/espressif/newlib-esp32/blob/esp_based_on_4_1_0/libgloss/xtensa/syscalls.c#L23).)
+
+ This crate does not currently support SIMCALL-based semihosting, but users need to explicitly enable the feature to avoid accidentally selecting a different one than one actually want to use.
+
- **`portable-atomic`**
Use [portable-atomic]'s atomic types.
@@ -212,6 +223,7 @@ semihosting = { version = "0.1", features = ["stdio", "panic-handler"] }
target_arch = "mips32r6",
target_arch = "mips64",
target_arch = "mips64r6",
+ target_arch = "xtensa",
),
feature(asm_experimental_arch)
)]
@@ -227,8 +239,19 @@ semihosting = { version = "0.1", features = ["stdio", "panic-handler"] }
target_arch = "mips32r6",
target_arch = "mips64",
target_arch = "mips64r6",
+ target_arch = "xtensa",
)))]
compile_error!("unsupported target");
+#[cfg(target_arch = "xtensa")]
+#[cfg(not(feature = "openocd-semihosting"))]
+compile_error!(
+ "xtensa has two semihosting interfaces so you have to select implementation;\n\
+ please enable `openocd-semihosting` feature if you want to use OpenOCD Semihosting used in OpenOCD and probe-rs.\n\
+ see for more."
+);
+#[cfg(not(target_arch = "xtensa"))]
+#[cfg(feature = "openocd-semihosting")]
+compile_error!("`openocd-semihosting` feature does not compatible with this target");
#[cfg(feature = "alloc")]
extern crate alloc;
diff --git a/src/sys/arm_compat/mod.rs b/src/sys/arm_compat/mod.rs
index 7e92f61..7d11822 100644
--- a/src/sys/arm_compat/mod.rs
+++ b/src/sys/arm_compat/mod.rs
@@ -7,6 +7,7 @@
//! - Semihosting for AArch32 and AArch64
//! - RISC-V Semihosting
//! -
+//! -
#![allow(clippy::missing_safety_doc)] // TODO
diff --git a/src/sys/arm_compat/syscall/mod.rs b/src/sys/arm_compat/syscall/mod.rs
index f88ae4c..4a9f096 100644
--- a/src/sys/arm_compat/syscall/mod.rs
+++ b/src/sys/arm_compat/syscall/mod.rs
@@ -8,6 +8,7 @@ pub use arch::{syscall, syscall_readonly};
#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")]
#[cfg_attr(target_arch = "arm", path = "arm.rs")]
#[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), path = "riscv.rs")]
+#[cfg_attr(target_arch = "xtensa", path = "xtensa.rs")]
mod arch;
pub use crate::sys::reg::{ParamRegR, ParamRegW, RetReg};
diff --git a/src/sys/arm_compat/syscall/xtensa.rs b/src/sys/arm_compat/syscall/xtensa.rs
new file mode 100644
index 0000000..db817fa
--- /dev/null
+++ b/src/sys/arm_compat/syscall/xtensa.rs
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+use core::arch::asm;
+
+use super::{OperationNumber, ParamRegR, ParamRegW, RetReg};
+
+/// Raw semihosting call with a parameter that will be read + modified by the host
+#[inline]
+pub unsafe fn syscall(number: OperationNumber, parameter: ParamRegW<'_>) -> RetReg {
+ unsafe {
+ let r;
+ asm!(
+ "break 1, 14",
+ inout("a2") number.0 as usize => r, // OPERATION NUMBER REGISTER => RETURN REGISTER
+ // Use inout because operation such as SYS_ELAPSED suggest that
+ // PARAMETER REGISTER may be changed.
+ inout("a3") parameter.0 => _, // PARAMETER REGISTER
+ options(nostack, preserves_flags),
+ );
+ RetReg(r)
+ }
+}
+
+/// Raw semihosting call with a parameter that will be read (but not modified) by the host
+#[inline]
+pub unsafe fn syscall_readonly(number: OperationNumber, parameter: ParamRegR<'_>) -> RetReg {
+ unsafe {
+ let r;
+ asm!(
+ "break 1, 14",
+ inout("a2") number.0 as usize => r, // OPERATION NUMBER REGISTER => RETURN REGISTER
+ // Use inout because operation such as SYS_ELAPSED suggest that
+ // PARAMETER REGISTER may be changed.
+ inout("a3") parameter.0 => _, // PARAMETER REGISTER
+ options(nostack, preserves_flags, readonly),
+ );
+ RetReg(r)
+ }
+}
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index b6aec6d..17bc084 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -14,6 +14,7 @@
target_arch = "arm",
target_arch = "riscv32",
target_arch = "riscv64",
+ all(target_arch = "xtensa", feature = "openocd-semihosting"),
))]
use arm_compat as arch;
#[cfg(any(
@@ -21,6 +22,7 @@ use arm_compat as arch;
target_arch = "arm",
target_arch = "riscv32",
target_arch = "riscv64",
+ all(target_arch = "xtensa", feature = "openocd-semihosting"),
))]
#[cfg_attr(
semihosting_doc_cfg,
@@ -29,6 +31,7 @@ use arm_compat as arch;
target_arch = "arm",
target_arch = "riscv32",
target_arch = "riscv64",
+ all(target_arch = "xtensa", feature = "openocd-semihosting"),
)))
)]
pub mod arm_compat;
diff --git a/src/sys/reg.rs b/src/sys/reg.rs
index ba88d3d..6aa8ce6 100644
--- a/src/sys/reg.rs
+++ b/src/sys/reg.rs
@@ -51,6 +51,7 @@ impl<'a> ParamRegW<'a> {
target_arch = "arm",
target_arch = "riscv32",
target_arch = "riscv64",
+ all(target_arch = "xtensa", feature = "openocd-semihosting"),
))]
impl<'a> ParamRegW<'a> {
#[inline]
@@ -100,6 +101,7 @@ impl<'a> ParamRegR<'a> {
target_arch = "arm",
target_arch = "riscv32",
target_arch = "riscv64",
+ all(target_arch = "xtensa", feature = "openocd-semihosting"),
))]
impl<'a> ParamRegR<'a> {
#[inline]
@@ -157,6 +159,7 @@ impl RetReg {
target_arch = "arm",
target_arch = "riscv32",
target_arch = "riscv64",
+ all(target_arch = "xtensa", feature = "openocd-semihosting"),
))]
impl RetReg {
#[allow(clippy::cast_possible_truncation)]