aboutsummaryrefslogtreecommitdiff
path: root/crates/qemu/src
diff options
context:
space:
mode:
authorIan McIntyre <me@mciantyre.dev>2026-08-03 07:46:10 -0400
committerIan McIntyre <me@mciantyre.dev>2026-08-03 07:46:10 -0400
commit7ffc62ab8613b097485b2c664093e649907dc2a1 (patch)
tree428e6e958af00e1022e663676fffe9c19f0174a6 /crates/qemu/src
First commit
Diffstat (limited to 'crates/qemu/src')
-rw-r--r--crates/qemu/src/lib.rs37
-rw-r--r--crates/qemu/src/main.rs72
2 files changed, 109 insertions, 0 deletions
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());
+ }
+}