1 Commits

Author SHA1 Message Date
Robin Mueller
e2e5215435 prepare run-time patch release
Some checks failed
ci / Check build (push) Has been cancelled
ci / Check formatting (push) Has been cancelled
ci / Check Documentation Build (push) Has been cancelled
ci / Clippy (push) Has been cancelled
ci / Check build (pull_request) Has been cancelled
ci / Check formatting (pull_request) Has been cancelled
ci / Check Documentation Build (pull_request) Has been cancelled
ci / Clippy (pull_request) Has been cancelled
2025-11-28 17:47:55 +01:00
24 changed files with 177 additions and 76 deletions

2
tools/Cargo.lock generated
View File

@@ -725,7 +725,7 @@ dependencies = [
[[package]]
name = "zynq7000-rt"
version = "0.1.1"
version = "0.1.2"
dependencies = [
"aarch32-cpu",
"arbitrary-int 2.0.0",

View File

@@ -21,23 +21,28 @@ use zynq7000_hal::{
};
use zynq7000::Peripherals;
use zynq7000_rt as _;
// Define the clock frequency as a constant
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300);
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
/// Try to talk to a DHT22 sensor connected at MIO0.
const DHT22_AT_MIO0: bool = true;
/// Open drain pin testing. MIO9 needs to be tied to MIO14.
const OPEN_DRAIN_PINS_MIO9_TO_MIO14: bool = false;
/// Entry point which calls the embassy main method.
#[zynq7000_rt::entry]
fn entry_point() -> ! {
main();
}
#[embassy_executor::main]
#[unsafe(export_name = "main")]
async fn main(_spawner: Spawner) -> ! {
let mut dp = Peripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);

View File

@@ -15,13 +15,17 @@ use zynq7000_rt as _;
// Define the clock frequency as a constant
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300);
/// Entry point which calls the embassy main method.
#[zynq7000_rt::entry]
fn entry_point() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
#[embassy_executor::main]
#[unsafe(export_name = "main")]
async fn main(_spawner: Spawner) -> ! {
let periphs = zynq7000_hal::init(zynq7000_hal::Config {
init_l2_cache: true,

View File

@@ -26,12 +26,16 @@ use zynq7000_rt as _;
// Define the clock frequency as a constant
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300);
/// Entry point which calls the embassy main method.
#[zynq7000_rt::entry]
fn entry_point() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
#[unsafe(export_name = "main")]
#[embassy_executor::main]
async fn main(spawner: Spawner) -> ! {
let mut dp = Peripherals::take().unwrap();

View File

@@ -32,13 +32,17 @@ use zynq7000_rt as _;
// Define the clock frequency as a constant
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300);
/// Entry point which calls the embassy main method.
#[zynq7000_rt::entry]
fn entry_point() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
#[embassy_executor::main]
#[unsafe(export_name = "main")]
async fn main(_spawner: Spawner) -> ! {
let mut dp = Peripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);

View File

@@ -9,16 +9,22 @@ use embedded_hal::digital::StatefulOutputPin;
use log::error;
use zynq7000_hal::{InteruptConfig, clocks, gic, gpio, gtc, time::Hertz};
use zynq7000_rt as _;
// Define the clock frequency as a constant
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300);
/// Entry point which calls the embassy main method.
#[zynq7000_rt::entry]
fn entry_point() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
#[embassy_executor::main]
#[unsafe(export_name = "main")]
async fn main(_spawner: Spawner) -> ! {
let periphs = zynq7000_hal::init(zynq7000_hal::Config {
init_l2_cache: true,

View File

@@ -13,6 +13,7 @@ use zynq7000_hal::{
priv_tim::CpuPrivateTimer,
time::Hertz,
};
use zynq7000_rt as _;
pub const LIB: Lib = Lib::Hal;
@@ -30,8 +31,17 @@ pub enum Lib {
Hal,
}
#[zynq7000_rt::entry]
fn main() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
#[unsafe(export_name = "main")]
pub fn main() -> ! {
l2_cache::init_with_defaults(&mut unsafe { zynq7000::l2_cache::Registers::new_mmio_fixed() });
match LIB {
Lib::Pac => {

View File

@@ -18,13 +18,24 @@ use zynq7000_hal::{
uart::{ClockConfig, Config, Uart},
};
use zynq7000_rt as _;
// Define the clock frequency as a constant
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_333);
static MS_TICKS: AtomicU64 = AtomicU64::new(0);
#[zynq7000_rt::entry]
fn main() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
#[unsafe(export_name = "main")]
pub fn main() -> ! {
let mut dp = zynq7000::Peripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);

View File

@@ -19,13 +19,24 @@ use zynq7000_hal::{
uart::{ClockConfig, Config, Uart},
};
use zynq7000_rt as _;
// Define the clock frequency as a constant
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300);
static MS_TICKS: AtomicU64 = AtomicU64::new(0);
#[zynq7000_rt::entry]
fn main() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
#[unsafe(export_name = "main")]
pub fn main() -> ! {
let mut dp = zynq7000::Peripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);

View File

@@ -4,9 +4,19 @@
use aarch32_cpu::asm::nop;
use core::panic::PanicInfo;
use zynq7000_rt as _;
#[zynq7000_rt::entry]
fn main() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
#[unsafe(export_name = "main")]
pub fn main() -> ! {
loop {
nop();
}

View File

@@ -104,9 +104,12 @@ pub enum IpMode {
StackReady,
}
/// Entry point which calls the embassy main method.
#[zynq7000_rt::entry]
fn entry_point() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
@@ -201,6 +204,7 @@ async fn tcp_task(mut tcp: TcpSocket<'static>) -> ! {
}
#[embassy_executor::main]
#[unsafe(export_name = "main")]
async fn main(spawner: Spawner) -> ! {
let mut dp = Peripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);

View File

@@ -36,13 +36,17 @@ use zynq7000_rt as _;
const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300);
const I2C_ADDR_SEL: I2cAddr = I2cAddr::Sa0Low;
/// Entry point which calls the embassy main method.
#[zynq7000_rt::entry]
fn entry_point() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
#[embassy_executor::main]
#[unsafe(export_name = "main")]
async fn main(_spawner: Spawner) -> ! {
let mut dp = Peripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);

View File

@@ -39,13 +39,17 @@ const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300);
const DEBUG_SPI_CLK_CONFIG: bool = false;
const BLOCKING: bool = false;
/// Entry point which calls the embassy main method.
#[zynq7000_rt::entry]
fn entry_point() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
#[embassy_executor::main]
#[unsafe(export_name = "main")]
async fn main(spawner: Spawner) -> ! {
let mut dp = Peripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);

View File

@@ -21,15 +21,19 @@ const QSPI_DEV_COMBINATION: qspi::QspiDeviceCombination = qspi::QspiDeviceCombin
two_devices: false,
};
/// Entry point which calls the embassy main method.
#[zynq7000_rt::entry]
fn entry_point() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
const ERASE_PROGRAM_READ_TEST: bool = false;
#[embassy_executor::main]
#[unsafe(export_name = "main")]
async fn main(_spawner: Spawner) -> ! {
let periphs = zynq7000_hal::init(zynq7000_hal::Config {
init_l2_cache: true,

View File

@@ -31,9 +31,12 @@ const INIT_STRING: &str = "-- Zynq 7000 Zedboard blocking UART example --\n\r";
const AXI_UARTLITE_BASE_ADDR: u32 = 0x42C0_0000;
const AXI_UAR16550_BASE_ADDR: u32 = 0x43C0_0000;
/// Entry point which calls the embassy main method.
#[zynq7000_rt::entry]
fn entry_point() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
@@ -96,6 +99,7 @@ impl UartMultiplexer {
}
}
#[embassy_executor::main]
#[unsafe(export_name = "main")]
async fn main(_spawner: Spawner) -> ! {
let mut dp = Peripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);

View File

@@ -95,9 +95,12 @@ static UARTLITE_PROD: Mutex<RefCell<Option<heapless::spsc::Producer<'static, u8,
static UART16550_PROD: Mutex<RefCell<Option<heapless::spsc::Producer<'static, u8, RB_SIZE>>>> =
Mutex::new(RefCell::new(None));
/// Entry point which calls the embassy main method.
#[zynq7000_rt::entry]
fn entry_point() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
@@ -161,6 +164,7 @@ impl UartMultiplexer {
}
#[embassy_executor::main]
#[unsafe(export_name = "main")]
async fn main(spawner: Spawner) -> ! {
let mut dp = Peripherals::take().unwrap();
l2_cache::init_with_defaults(&mut dp.l2c);

View File

@@ -15,13 +15,17 @@ use zynq7000_rt as _;
const INIT_STRING: &str = "-- Zynq 7000 Zedboard GPIO blinky example --\n\r";
/// Entry point which calls the embassy main method.
#[zynq7000_rt::entry]
fn entry_point() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
#[embassy_executor::main]
#[unsafe(export_name = "main")]
async fn main(_spawner: Spawner) -> ! {
let periphs = zynq7000_hal::init(zynq7000_hal::Config {
init_l2_cache: true,

View File

@@ -29,6 +29,7 @@ use zynq7000_hal::{
time::Hertz,
uart::{ClockConfig, Config, Uart},
};
use zynq7000_rt as _;
// PS clock input frequency.
const PS_CLK: Hertz = Hertz::from_raw(33_333_333);
@@ -59,8 +60,17 @@ pub const ELF_BASE_ADDR: usize = 0x100000;
/// 8 MB reserved for application ELF.
pub const BOOT_BIN_STAGING_OFFSET: usize = 8 * 1024 * 1024;
#[zynq7000_rt::entry]
fn main() -> ! {
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
#[unsafe(export_name = "main")]
pub fn main() -> ! {
let boot_mode = BootMode::new_from_regs();
// The unwraps are okay here, the provided clock frequencies are standard values also used
// by other Xilinx tools.

View File

@@ -36,10 +36,19 @@ const QSPI_DEV_COMBINATION: qspi::QspiDeviceCombination = qspi::QspiDeviceCombin
two_devices: false,
};
/// Entry point (not called like a normal main function)
#[unsafe(no_mangle)]
pub extern "C" fn boot_core(cpu_id: u32) -> ! {
if cpu_id != 0 {
panic!("unexpected CPU ID {}", cpu_id);
}
main();
}
const INIT_STRING: &str = "-- Zynq 7000 Zedboard QSPI flasher --\n\r";
#[zynq7000_rt::entry]
fn main() -> ! {
#[unsafe(export_name = "main")]
pub fn main() -> ! {
let periphs = zynq7000_hal::init(zynq7000_hal::Config {
init_l2_cache: true,
level_shifter_config: Some(LevelShifterConfig::EnableAll),

View File

@@ -8,15 +8,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased]
# [v0.1.2] 2025-11-28
Bugfixes in startup assembler code.
## Changed
- `.data` initialization is skipped if it is already in place, which is usually the default
case because it is flashed to RAM.
- Runtime now calls a `kmain` method similar to the re-export `aarch32-rt` crate.
Former `boot_core` method must be renamed to `kmain`, but it is recommended to use
the `zynq7000-rt::entry` proc macro to annotate the main method.
## Fixed
@@ -32,6 +31,7 @@ Documentation fixes.
Initial release
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-rt-v0.1.0...HEAD
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-rt-v0.1.2...HEAD
[v0.1.2]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-rt-v0.1.1...zynq7000-rt-v0.1.2
[v0.1.1]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-rt-v0.1.0...zynq7000-rt-v0.1.1
[v0.1.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/tag/zynq7000-rt-v0.1.0

View File

@@ -1,6 +1,6 @@
[package]
name = "zynq7000-rt"
version = "0.1.1"
version = "0.1.2"
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
edition = "2024"
description = "Run-time support for the Zynq7000 family of SoCs for running bare-metal applications"

View File

@@ -9,18 +9,15 @@ Startup code and minimal runtime for the AMD Zynq7000 SoC to write bare metal Ru
This run-time crate is strongly based on the
[startup code provided by AMD](https://github.com/Xilinx/embeddedsw/blob/master/lib/bsp/standalone/src/arm/cortexa9/gcc/boot.S).
It mostly builds on [aarch32-rt](https://github.com/rust-embedded/aarch32/tree/main/aarch32-rt).
It activates the `fpu-d32` feature on that crate and overrides the `_default_start` method
to add necessary setup code for the Zynq7000. It re-exports the `aarch32-rt` crate, including
the attributes macros. The [documentation](https://docs.rs/aarch32-rt/latest/aarch32_rt/) specifies
these in detail.
Some major differences to the startup code provided by AMD:
Some major differences:
- No L2 cache initialization is performed.
- MMU table is specified as Rust code.
- Modification to the stack setup code, because a different linker script is used.
This crate pulls in the [aarch32-rt](https://github.com/rust-embedded/aarch32/tree/main/aarch32-rt)
crate to provide ARM vectors and the linker script.
## Features
- `rt` is a default feature which activates the run-time.

View File

@@ -1,16 +1,8 @@
//! # Rust bare metal run-time support for the AMD Zynq 7000 SoCs
//!
//! Startup code and minimal runtime for the AMD Zynq7000 SoC to write bare metal Rust code.
//! This run-time crate is strongly based on the
//! [startup code provided by AMD](https://github.com/Xilinx/embeddedsw/blob/master/lib/bsp/standalone/src/arm/cortexa9/gcc/boot.S).
//!
//! It mostly builds on [aarch32-rt](https://github.com/rust-embedded/aarch32/tree/main/aarch32-rt).
//! It activates the `fpu-d32` feature on that crate and overrides the `_default_start` method
//! to add necessary setup code for the Zynq7000. It re-exports the `aarch32-rt` crate, including
//! the attributes macros. The [documentation](https://docs.rs/aarch32-rt/latest/aarch32_rt/) specifies
//! these in detail.
//!
//! Some major differences to the startup code provided by AMD:
//! This includes basic low-level startup code similar to the bare-metal boot routines
//! [provided by Xilinx](https://github.com/Xilinx/embeddedsw/tree/master/lib/bsp/standalone/src/arm/cortexa9/gcc).
//! Some major differences:
//!
//! - No L2 cache initialization is performed.
//! - MMU table is specified as Rust code.

View File

@@ -213,7 +213,7 @@ data_init_done:
// Jump to application
// Load CPU ID 0, which will be used as a function argument to the boot_core function.
mov r0, #0x0
bl kmain
bl boot_core
// In case the application returns, loop forever
b .
.size _start, . - _start