From 7ffc62ab8613b097485b2c664093e649907dc2a1 Mon Sep 17 00:00:00 2001 From: Ian McIntyre Date: Mon, 3 Aug 2026 07:46:10 -0400 Subject: First commit --- crates/qemu/Cargo.toml | 15 +++++++++++ crates/qemu/src/lib.rs | 37 +++++++++++++++++++++++++ crates/qemu/src/main.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 crates/qemu/Cargo.toml create mode 100644 crates/qemu/src/lib.rs create mode 100644 crates/qemu/src/main.rs (limited to 'crates/qemu') diff --git a/crates/qemu/Cargo.toml b/crates/qemu/Cargo.toml new file mode 100644 index 0000000..904f696 --- /dev/null +++ b/crates/qemu/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rust-threadx-qemu" +version = "0.1.0" +edition = "2024" +publish = false + +[dependencies] +cortex-m = { workspace = true } +cortex-m-rt = { workspace = true } +cortex-m-semihosting = { workspace = true } +lm3s6965 = { workspace = true } +panic-semihosting = { version = "0.6", features = ["exit"] } + +rust-threadx-cortex-m = { workspace = true } +rust-threadx-stdio-semihosting = { workspace = true } diff --git a/crates/qemu/src/lib.rs b/crates/qemu/src/lib.rs new file mode 100644 index 0000000..dc91465 --- /dev/null +++ b/crates/qemu/src/lib.rs @@ -0,0 +1,37 @@ +#![no_std] + +use cortex_m_rt as _; +use lm3s6965 as _; + +use rust_threadx_cortex_m as _; +use rust_threadx_stdio_semihosting as _; + +pub fn exit_success() -> ! { + use cortex_m_semihosting::debug::*; + exit(EXIT_SUCCESS); + unreachable!() +} + +// Designed for ARMv6-M. Just enough to get the example +// running in QEMU with a meaningless system tick. +#[unsafe(no_mangle)] +pub extern "C" fn _tx_initialize_low_level() { + use cortex_m::{Peripherals, peripheral::scb::SystemHandler}; + + cortex_m::interrupt::disable(); + + let Peripherals { + mut SYST, mut SCB, .. + } = Peripherals::take().unwrap(); + + SYST.set_reload(80000 - 1); + SYST.clear_current(); + SYST.enable_interrupt(); + SYST.enable_counter(); + + unsafe { + SCB.set_priority(SystemHandler::SysTick, 0x40); + SCB.set_priority(SystemHandler::PendSV, 0xff); + SCB.set_priority(SystemHandler::SVCall, 0xff); + } +} diff --git a/crates/qemu/src/main.rs b/crates/qemu/src/main.rs new file mode 100644 index 0000000..3a3df38 --- /dev/null +++ b/crates/qemu/src/main.rs @@ -0,0 +1,72 @@ +use rust_threadx_qemu::exit_success; +use std::{ + sync::{Arc, Condvar, Mutex}, + time::Duration, +}; + +fn main() { + println!("Hello, world!"); + println!("Testing allocations in 0.25 seconds..."); + std::thread::sleep(Duration::from_millis(250)); + test_heap_allocation(); + + let mtx = Arc::new(Mutex::new(0_u32)); + let cv = Arc::new(Condvar::new()); + + std::thread::scope(|s| { + s.spawn(|| { + println!("Hello from one thread!"); + let mut guard = mtx.lock().unwrap(); + *guard += 1; + cv.notify_all(); + }); + }); + + let (m, c) = (mtx.clone(), cv.clone()); + std::thread::spawn(move || { + println!("Hello from another thread!"); + + let guard = m.lock().unwrap(); + let mut guard = c.wait_while(guard, |c| *c != 1).unwrap(); + *guard += 1; + c.notify_all(); + }) + .join() + .unwrap(); + + let guard = mtx.lock().unwrap(); + let guard = cv.wait_while(guard, |c| *c != 2).unwrap(); + assert_eq!(*guard, 2); + + echo_stdin(); + exit_success(); +} + +fn echo_stdin() { + use std::io::{self, Write}; + + print!("Enter a message: "); + // `print!` does not flush, so make sure the prompt reaches the host before + // we block waiting on input. + io::stdout().flush().ok(); + + let mut message = String::new(); + match io::stdin().read_line(&mut message) { + Ok(0) => println!("No message received (EOF)"), + Ok(_) => println!("You said: {}", message.trim_end()), + Err(e) => println!("Failed to read message: {e}"), + } +} + +fn test_heap_allocation() { + use core::hint::black_box; + + for len in [32usize, 64, 128] { + let mut v: Vec = Vec::with_capacity(len); + for i in 0..len { + v.push(black_box(i)); + } + let v = black_box(v); + println!("Allocated vector with {} elements", v.len()); + } +} -- cgit v1.2.3