diff options
| author | Ian McIntyre <me@mciantyre.dev> | 2026-08-03 07:46:10 -0400 |
|---|---|---|
| committer | Ian McIntyre <me@mciantyre.dev> | 2026-08-03 07:46:10 -0400 |
| commit | 7ffc62ab8613b097485b2c664093e649907dc2a1 (patch) | |
| tree | 428e6e958af00e1022e663676fffe9c19f0174a6 /crates/qemu | |
First commit
Diffstat (limited to 'crates/qemu')
| -rw-r--r-- | crates/qemu/Cargo.toml | 15 | ||||
| -rw-r--r-- | crates/qemu/src/lib.rs | 37 | ||||
| -rw-r--r-- | crates/qemu/src/main.rs | 72 |
3 files changed, 124 insertions, 0 deletions
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<usize> = 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()); + } +} |
