diff --git a/Cargo.lock b/Cargo.lock index 23c0ed3..d1868aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,6 +31,8 @@ name = "avr-tester" version = "0.3.0" dependencies = [ "avr-simulator", + "indoc", + "pretty_assertions", "rand", ] @@ -89,6 +91,12 @@ dependencies = [ "libloading", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "either" version = "1.12.0" @@ -137,6 +145,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "indoc" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" + [[package]] name = "itertools" version = "0.12.1" @@ -226,6 +240,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "prettyplease" version = "0.2.20" @@ -549,3 +573,9 @@ name = "windows_x86_64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" diff --git a/Justfile b/Justfile index 378d61a..54f7a24 100644 --- a/Justfile +++ b/Justfile @@ -1,8 +1,14 @@ -test: +test *args: cd avr-tester-fixtures \ && cargo build --release - cargo test --release --workspace + cargo test --release --workspace -- {{ args }} + +test-ccb *args: + cd avr-tester-fixtures \ + && cargo build --release --features custom-compiler-builtins + + cargo test --release --workspace -- {{ args }} clean: cargo clean diff --git a/README.md b/README.md index 38288f0..a33e837 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ use avr_tester::*; fn avr() -> AvrTester { AvrTester::atmega328p() .with_clock_of_16_mhz() - .load("../../firmware/target/atmega328p/release/firmware.elf") + .load("../../firmware/target/avr-none/release/firmware.elf") } // Assuming `firmware` implements a ROT-13 encoder: @@ -76,7 +76,7 @@ fn long_text() { } ``` -... having the tests ready, just run `cargo test` inside `firmware-tests` :-) +... having the tests ready, just run `cargo test` inside `firmware-tests`. Since AvrTester emulates an actual AVR, you don't have to modify your firmware at all - it can use timers, GPIOs etc. and everything should just work ™. diff --git a/avr-tester-fixtures/.cargo/config.toml b/avr-tester-fixtures/.cargo/config.toml index 6399776..9343f71 100644 --- a/avr-tester-fixtures/.cargo/config.toml +++ b/avr-tester-fixtures/.cargo/config.toml @@ -1,5 +1,6 @@ [build] -target = "./.cargo/targets/atmega328p.json" +target = "avr-none" +rustflags = ["-C", "target-cpu=atmega328p"] [unstable] build-std = ["core"] diff --git a/avr-tester-fixtures/.cargo/targets/atmega328p.json b/avr-tester-fixtures/.cargo/targets/atmega328p.json deleted file mode 100644 index e3be9ae..0000000 --- a/avr-tester-fixtures/.cargo/targets/atmega328p.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "arch": "avr", - "cpu": "atmega328p", - "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", - "env": "", - "executables": true, - "linker": "avr-gcc", - "linker-flavor": "gcc", - "linker-is-gnu": true, - "llvm-target": "avr-unknown-unknown", - "os": "unknown", - "position-independent-executables": false, - "exe-suffix": ".elf", - "eh-frame-header": false, - "pre-link-args": { - "gcc": ["-mmcu=atmega328p"] - }, - "late-link-args": { - "gcc": ["-lgcc", "-lc"] - }, - "target-c-int-width": "16", - "target-endian": "little", - "target-pointer-width": "16", - "vendor": "unknown" -} diff --git a/avr-tester-fixtures/Cargo.lock b/avr-tester-fixtures/Cargo.lock index a6d79f1..03686d7 100644 --- a/avr-tester-fixtures/Cargo.lock +++ b/avr-tester-fixtures/Cargo.lock @@ -56,6 +56,7 @@ version = "0.0.0" dependencies = [ "atmega-hal", "avr-hal-generic", + "compiler_builtins", "embedded-hal", "panic-halt", ] @@ -75,6 +76,11 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "compiler_builtins" +version = "0.1.151" +source = "git+https://github.com/rust-lang/compiler-builtins#7bec089672eb5cd83d7902edd59479527bc9d8d1" + [[package]] name = "embedded-hal" version = "0.2.7" diff --git a/avr-tester-fixtures/Cargo.toml b/avr-tester-fixtures/Cargo.toml index bf9ea15..afe8c0b 100644 --- a/avr-tester-fixtures/Cargo.toml +++ b/avr-tester-fixtures/Cargo.toml @@ -10,6 +10,10 @@ path = "src/acc_bits.rs" name = "acc-eval" path = "src/acc_eval.rs" +[[bin]] +name = "acc-fractal" +path = "src/acc_fractal.rs" + [[bin]] name = "analog-pins" path = "src/analog_pins.rs" @@ -48,6 +52,18 @@ avr-hal-generic = { git = "https://github.com/Rahix/avr-hal" } embedded-hal = "0.2.3" panic-halt = "0.2" +[dependencies.custom-compiler-builtins] +package = "compiler_builtins" +optional = true + +# Override this dependency if you want to test avr-tester with customized +# compiler-builtins - then use `just test-ccb`: +git = "https://github.com/rust-lang/compiler-builtins" +# path = "/home/pwy/t/compiler-builtins" + +[features] +custom-compiler-builtins = ["dep:custom-compiler-builtins"] + [profile.release] codegen-units = 1 lto = "fat" diff --git a/avr-tester-fixtures/src/acc_bits.rs b/avr-tester-fixtures/src/acc_bits.rs index 094c31f..ebca037 100644 --- a/avr-tester-fixtures/src/acc_bits.rs +++ b/avr-tester-fixtures/src/acc_bits.rs @@ -3,6 +3,9 @@ #![no_std] #![no_main] +#[cfg(feature = "custom-compiler-builtins")] +extern crate custom_compiler_builtins; + use atmega_hal::{pins, Peripherals}; use avr_hal_generic::hal::digital::v2::OutputPin; use panic_halt as _; diff --git a/avr-tester-fixtures/src/acc_eval.rs b/avr-tester-fixtures/src/acc_eval.rs index 08d0a74..80b5213 100644 --- a/avr-tester-fixtures/src/acc_eval.rs +++ b/avr-tester-fixtures/src/acc_eval.rs @@ -3,6 +3,9 @@ #![no_std] #![no_main] +#[cfg(feature = "custom-compiler-builtins")] +extern crate custom_compiler_builtins; + use atmega_hal::clock::MHz16; use atmega_hal::usart::{BaudrateExt, Usart0}; use atmega_hal::{pins, Peripherals}; @@ -39,6 +42,34 @@ fn main() -> ! { } } +fn eval(uart: UartMut<'_>) -> T +where + T: Number, +{ + let tok = Token::read(uart); + + if let Token::Const = tok { + return T::read(uart); + } + + let lhs = eval::(uart); + let rhs = eval::(uart); + + match tok { + Token::Add => lhs + rhs, + Token::Sub => lhs - rhs, + Token::Mul => lhs * rhs, + Token::Div => lhs / rhs, + Token::Rem => lhs % rhs, + + Token::Const => { + unreachable!() + } + } +} + +type UartMut<'a> = &'a mut Usart0; + // ---- enum Type { @@ -97,38 +128,6 @@ impl Readable for Token { } } -// ---- - -fn eval(uart: UartMut<'_>) -> T -where - T: Number, -{ - let tok = Token::read(uart); - - if let Token::Const = tok { - return T::read(uart); - } - - let lhs = eval::(uart); - let rhs = eval::(uart); - - match tok { - Token::Add => lhs + rhs, - Token::Sub => lhs - rhs, - Token::Mul => lhs * rhs, - Token::Div => lhs / rhs, - Token::Rem => lhs % rhs, - - Token::Const => { - unreachable!() - } - } -} - -// ----- - -type UartMut<'a> = &'a mut Usart0; - // ----- trait Readable { @@ -194,25 +193,3 @@ macro_rules! numbers { } numbers!([u8, i8, u16, i16, u32, i32, u64, i64, u128, i128]); - -// ----- - -#[no_mangle] -extern "C" fn __divti3() { - panic!("not supported"); -} - -#[no_mangle] -extern "C" fn __modti3() { - panic!("not supported"); -} - -#[no_mangle] -extern "C" fn __udivti3() { - panic!("not supported"); -} - -#[no_mangle] -extern "C" fn __umodti3() { - panic!("not supported"); -} diff --git a/avr-tester-fixtures/src/acc_fractal.rs b/avr-tester-fixtures/src/acc_fractal.rs new file mode 100644 index 0000000..5ed0c3c --- /dev/null +++ b/avr-tester-fixtures/src/acc_fractal.rs @@ -0,0 +1,69 @@ +//! See: [../../avr-tester/tests/acceptance/fractal.rs]. + +#![no_std] +#![no_main] + +#[cfg(feature = "custom-compiler-builtins")] +extern crate custom_compiler_builtins; + +use atmega_hal::clock::MHz16; +use atmega_hal::usart::{BaudrateExt, Usart0}; +use atmega_hal::{pins, Peripherals}; +use panic_halt as _; + +#[atmega_hal::entry] +fn main() -> ! { + let dp = Peripherals::take().unwrap(); + let pins = pins!(dp); + + let mut uart = Usart0::::new( + dp.USART0, + pins.pd0, + pins.pd1.into_output(), + 115200u32.into_baudrate(), + ); + + mandelbrot(&mut uart, 40, 20, -2.05, -1.12, 0.47, 1.12, 50); + + loop { + // + } +} + +fn mandelbrot( + uart: &mut Usart0, + width: i64, + height: i64, + x1: f32, + y1: f32, + x2: f32, + y2: f32, + max_iters: i64, +) { + for viewport_y in 0..height { + let y0 = y1 + (y2 - y1) * ((viewport_y as f32) / (height as f32)); + + for viewport_x in 0..width { + let x0 = x1 + (x2 - x1) * ((viewport_x as f32) / (width as f32)); + + let mut x = 0.0; + let mut y = 0.0; + let mut iters = max_iters; + + while x * x + y * y <= 4.0 && iters > 0 { + let xtemp = x * x - y * y + x0; + + y = 2.0 * x * y + y0; + x = xtemp; + iters -= 1; + } + + let ch = (8.0 * ((iters as f32) / (max_iters as f32))) as usize; + let ch = b"#%=-:,. "[ch]; + + uart.write_byte(ch); + } + + uart.write_byte(b'\n'); + } +} diff --git a/avr-tester-fixtures/src/analog_pins.rs b/avr-tester-fixtures/src/analog_pins.rs index b541a1b..730f189 100644 --- a/avr-tester-fixtures/src/analog_pins.rs +++ b/avr-tester-fixtures/src/analog_pins.rs @@ -3,6 +3,9 @@ #![no_std] #![no_main] +#[cfg(feature = "custom-compiler-builtins")] +extern crate custom_compiler_builtins; + use atmega_hal::adc::{AdcSettings, ReferenceVoltage}; use atmega_hal::clock::MHz16; use atmega_hal::{pins, Adc, Peripherals}; diff --git a/avr-tester-fixtures/src/digital_pins.rs b/avr-tester-fixtures/src/digital_pins.rs index 95f192e..44f2800 100644 --- a/avr-tester-fixtures/src/digital_pins.rs +++ b/avr-tester-fixtures/src/digital_pins.rs @@ -3,6 +3,9 @@ #![no_std] #![no_main] +#[cfg(feature = "custom-compiler-builtins")] +extern crate custom_compiler_builtins; + use atmega_hal::clock::MHz16; use atmega_hal::delay::Delay; use atmega_hal::{pins, Peripherals}; diff --git a/avr-tester-fixtures/src/shift_register.rs b/avr-tester-fixtures/src/shift_register.rs index 4ae8e6d..a4ef514 100644 --- a/avr-tester-fixtures/src/shift_register.rs +++ b/avr-tester-fixtures/src/shift_register.rs @@ -3,6 +3,9 @@ #![no_std] #![no_main] +#[cfg(feature = "custom-compiler-builtins")] +extern crate custom_compiler_builtins; + use atmega_hal::{pins, Peripherals}; use avr_hal_generic::prelude::*; use panic_halt as _; @@ -25,7 +28,7 @@ fn main() -> ! { // Transmits eight bits to the shift register let mut out_u8 = |val: u8| { for n in 0..8 { - out_bool(val & (2 << n - 1) > 0); + out_bool(val & (2 << (n - 1)) > 0); } }; diff --git a/avr-tester-fixtures/src/spi.rs b/avr-tester-fixtures/src/spi.rs index e62501c..67c23c8 100644 --- a/avr-tester-fixtures/src/spi.rs +++ b/avr-tester-fixtures/src/spi.rs @@ -3,6 +3,9 @@ #![no_std] #![no_main] +#[cfg(feature = "custom-compiler-builtins")] +extern crate custom_compiler_builtins; + use atmega_hal::{pins, Peripherals}; use atmega_hal::{spi, Spi}; use avr_hal_generic::nb; diff --git a/avr-tester-fixtures/src/spi_component.rs b/avr-tester-fixtures/src/spi_component.rs index 9d220bc..6abf4ca 100644 --- a/avr-tester-fixtures/src/spi_component.rs +++ b/avr-tester-fixtures/src/spi_component.rs @@ -3,6 +3,9 @@ #![no_std] #![no_main] +#[cfg(feature = "custom-compiler-builtins")] +extern crate custom_compiler_builtins; + use atmega_hal::clock::MHz16; use atmega_hal::delay::Delay; use atmega_hal::{pins, Peripherals}; diff --git a/avr-tester-fixtures/src/timeout.rs b/avr-tester-fixtures/src/timeout.rs index 1f38ba5..ea463d5 100644 --- a/avr-tester-fixtures/src/timeout.rs +++ b/avr-tester-fixtures/src/timeout.rs @@ -3,6 +3,9 @@ #![no_std] #![no_main] +#[cfg(feature = "custom-compiler-builtins")] +extern crate custom_compiler_builtins; + use panic_halt as _; #[atmega_hal::entry] diff --git a/avr-tester-fixtures/src/twi.rs b/avr-tester-fixtures/src/twi.rs index 2f741aa..a581daa 100644 --- a/avr-tester-fixtures/src/twi.rs +++ b/avr-tester-fixtures/src/twi.rs @@ -3,6 +3,9 @@ #![no_std] #![no_main] +#[cfg(feature = "custom-compiler-builtins")] +extern crate custom_compiler_builtins; + use atmega_hal::clock::MHz16; use atmega_hal::usart::{BaudrateExt, Usart0}; use atmega_hal::{pins, Peripherals}; diff --git a/avr-tester-fixtures/src/uart.rs b/avr-tester-fixtures/src/uart.rs index 21d35ee..527a530 100644 --- a/avr-tester-fixtures/src/uart.rs +++ b/avr-tester-fixtures/src/uart.rs @@ -3,6 +3,9 @@ #![no_std] #![no_main] +#[cfg(feature = "custom-compiler-builtins")] +extern crate custom_compiler_builtins; + use atmega_hal::clock::MHz16; use atmega_hal::usart::{BaudrateExt, Usart0}; use atmega_hal::{pins, Peripherals}; diff --git a/avr-tester/Cargo.toml b/avr-tester/Cargo.toml index 979e3b4..63a99a2 100644 --- a/avr-tester/Cargo.toml +++ b/avr-tester/Cargo.toml @@ -13,4 +13,6 @@ keywords = ["avr", "test", "framework", "microcontroller", "simavr"] avr-simulator = { path = "../avr-simulator", version = "0.3.0" } [dev-dependencies] +indoc = "2.0.6" +pretty_assertions = "1.4.1" rand = "0.8" diff --git a/avr-tester/src/lib.rs b/avr-tester/src/lib.rs index 4d44a48..3f0ffae 100644 --- a/avr-tester/src/lib.rs +++ b/avr-tester/src/lib.rs @@ -9,7 +9,7 @@ //! fn test() { //! let mut avr = AvrTester::atmega328p() //! .with_clock_of_16_mhz() -//! .load("../../firmware/target/atmega328p/release/firmware.elf"); +//! .load("../../firmware/target/avr-none/release/firmware.elf"); //! //! // Let's give our firmware a moment to initialize: //! avr.run_for_ms(1); diff --git a/avr-tester/tests/acceptance.rs b/avr-tester/tests/acc.rs similarity index 52% rename from avr-tester/tests/acceptance.rs rename to avr-tester/tests/acc.rs index 59c9c26..872e6fc 100644 --- a/avr-tester/tests/acceptance.rs +++ b/avr-tester/tests/acc.rs @@ -1,4 +1,5 @@ -mod acceptance { +mod acc { mod bits; mod eval; + mod fractal; } diff --git a/avr-tester/tests/acceptance/bits.rs b/avr-tester/tests/acc/bits.rs similarity index 76% rename from avr-tester/tests/acceptance/bits.rs rename to avr-tester/tests/acc/bits.rs index fde1d58..74239d4 100644 --- a/avr-tester/tests/acceptance/bits.rs +++ b/avr-tester/tests/acc/bits.rs @@ -2,10 +2,10 @@ //! internal 4-bit counter, lightning up pins as bits in that counter are //! activated and deactivated. //! -//! This test allows us to ensure that we don't mix up various pins and ports -//! (e.g. by accidentally confusing `PB1` with `PB0`). +//! This test makes sure that avr-tester doesn't mix up pins and ports (e.g. by +//! accidentally confusing `PB1` with `PB0`). //! -//! See: [../../../avr-tester-fixtures/src/acc-bits.rs]. +//! See: [../../../avr-tester-fixtures/src/acc_bits.rs]. use avr_tester::AvrTester; @@ -13,7 +13,7 @@ use avr_tester::AvrTester; fn test() { let mut avr = AvrTester::atmega328() .with_clock_of_16_mhz() - .load("../avr-tester-fixtures/target/atmega328p/release/acc-bits.elf"); + .load("../avr-tester-fixtures/target/avr-none/release/acc-bits.elf"); avr.run_for_us(1); avr.pins().pb1().assert_low(); diff --git a/avr-tester/tests/acceptance/eval.rs b/avr-tester/tests/acc/eval.rs similarity index 79% rename from avr-tester/tests/acceptance/eval.rs rename to avr-tester/tests/acc/eval.rs index 3fd6b76..e29f51d 100644 --- a/avr-tester/tests/acceptance/eval.rs +++ b/avr-tester/tests/acc/eval.rs @@ -4,41 +4,35 @@ //! but represented in a binary protocol) and sends back a single number //! representing the expression's result. //! -//! The evaluator supports all Rust integer types, although certain operations -//! (e.g. 128-bit division) have to be skipped due to missing intrinsics. +//! This test makes sure that: //! -//! This test allows us to ensure that all the UART operations work correctly -//! (there's a lot of send/recv with custom (de)serializers and whatnot). +//! - UART operations work correctly (as there's a lot of send/recv with custom +//! serializers / deserializers), +//! +//! - AVR properly operates on all integer types. //! //! Also, this test serves as a proof that rustc + LLVM generate correct AVR -//! code that is able to work on 16+-bit numbers. +//! code that is able to work on all types of numbers. //! -//! See: [../../../avr-tester-fixtures/src/acc-eval.rs]. +//! See: [../../../avr-tester-fixtures/src/acc_eval.rs]. use avr_tester::{AvrTester, Uart, Writable, Writer, WriterHelper}; use rand::seq::SliceRandom; use rand::Rng; +use std::fmt; #[test] -fn primitives() { - const TRIES: usize = 100; +fn simple() { + const TRIES: usize = 128; let mut avr = AvrTester::atmega328() .with_clock_of_16_mhz() - .load("../avr-tester-fixtures/target/atmega328p/release/acc-eval.elf"); + .load("../avr-tester-fixtures/target/avr-none/release/acc-eval.elf"); avr.run_for_ms(1); for ty in Type::all() { for op in Op::all() { - if !ty.supports(op) { - println!( - "-> {:?}.{:?} (skipping; not supported on AVR)", - ty, op - ); - continue; - } - println!("-> {:?}.{:?}", ty, op); let mut tries = 0; @@ -52,27 +46,25 @@ fn primitives() { let lhs = random_value(ty); let rhs = random_value(ty); - let expected = if let Some(value) = op.apply()(lhs, rhs) { + let expected = if let Some(value) = op.as_fn()(lhs, rhs) { value } else { continue; }; + let expr = Expr::from_op(op)( + Box::new(Expr::Const(lhs)), + Box::new(Expr::Const(rhs)), + ); + avr.uart0().write(ty); - avr.uart0().write(Token::Op(op)); - avr.uart0().write(Token::Const); - avr.uart0().write(lhs); - avr.uart0().write(Token::Const); - avr.uart0().write(rhs); + avr.uart0().write(&expr); avr.run_for_ms(ty.weight()); let actual = Value::read(ty, &mut avr.uart0()); if actual != expected { - panic!( - "{:?} {:?} {:?} is equal to {:?}, but AVR returned {:?}", - lhs, op, rhs, expected, actual - ); + panic!("{expr} = {expected}, but AVR said {actual}"); } tries += 1; @@ -82,7 +74,7 @@ fn primitives() { } #[test] -fn expressions() { +fn complex() { const TRIES: usize = 10; const MAX_DEPTH: u64 = 8; @@ -90,7 +82,7 @@ fn expressions() { let mut avr = AvrTester::atmega328() .with_clock_of_16_mhz() - .load("../avr-tester-fixtures/target/atmega328p/release/acc-eval.elf"); + .load("../avr-tester-fixtures/target/avr-none/release/acc-eval.elf"); avr.run_for_ms(1); @@ -101,12 +93,11 @@ fn expressions() { let mut tries = 0; while tries < TRIES { - let mut expr = Expression::Const(Value::random_half(ty)); + let mut expr = Expr::Const(Value::random_half(ty)); for _ in 0..=depth { - let build_expression = Expression::from_op(Op::random(ty)); - let value = - Box::new(Expression::Const(Value::random_half(ty))); + let build_expression = Expr::from_op(Op::random()); + let value = Box::new(Expr::Const(Value::random_half(ty))); expr = if rng.gen::() { build_expression(Box::new(expr), value) @@ -128,10 +119,7 @@ fn expressions() { let actual = Value::read(ty, &mut avr.uart0()); if actual != expected { - panic!( - "{:?} is equal to {:?}, but AVR returned {:?}", - expr, expected, actual - ); + panic!("{expr} = {expected}, but AVR said {actual}"); } tries += 1; @@ -181,10 +169,6 @@ impl Type { Self::I128 | Self::U128 => 8, } } - - fn supports(self, op: Op) -> bool { - !matches!((self, op), (Self::I128 | Self::U128, Op::Div | Op::Rem)) - } } impl Writable for Type { @@ -209,20 +193,14 @@ impl Op { [Self::Add, Self::Sub, Self::Mul, Self::Div, Self::Rem] } - fn random(ty: Type) -> Self { - loop { - let op = Self::all() - .choose(&mut rand::thread_rng()) - .cloned() - .unwrap(); - - if ty.supports(op) { - break op; - } - } + fn random() -> Self { + Self::all() + .choose(&mut rand::thread_rng()) + .cloned() + .unwrap() } - fn apply(self) -> fn(Value, Value) -> Option { + fn as_fn(self) -> fn(Value, Value) -> Option { match self { Self::Add => Value::checked_add, Self::Sub => Value::checked_sub, @@ -340,6 +318,23 @@ impl Writable for Value { } } +impl fmt::Display for Value { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Value::I8(value) => write!(f, "{value}_i8"), + Value::U8(value) => write!(f, "{value}_u8"), + Value::I16(value) => write!(f, "{value}_i16"), + Value::U16(value) => write!(f, "{value}_u16"), + Value::I32(value) => write!(f, "{value}_i32"), + Value::U32(value) => write!(f, "{value}_u32"), + Value::I64(value) => write!(f, "{value}_i64"), + Value::U64(value) => write!(f, "{value}_u64"), + Value::I128(value) => write!(f, "{value}_i128"), + Value::U128(value) => write!(f, "{value}_u128"), + } + } +} + macro_rules! impl_ops { ( $value:ty, @@ -385,7 +380,7 @@ impl_ops!( // ---- #[derive(Clone, Debug)] -enum Expression { +enum Expr { Add(Box, Box), Sub(Box, Box), Mul(Box, Box), @@ -394,7 +389,7 @@ enum Expression { Const(Value), } -impl Expression { +impl Expr { fn from_op(op: Op) -> fn(Box, Box) -> Self { match op { Op::Add => Self::Add, @@ -427,7 +422,7 @@ impl Expression { } } -impl Writable for Expression { +impl Writable for Expr { fn write(&self, tx: &mut dyn Writer) { let (lhs, rhs, op) = match self { Self::Add(lhs, rhs) => (lhs, rhs, Op::Add), @@ -448,3 +443,16 @@ impl Writable for Expression { tx.write(&**rhs); } } + +impl fmt::Display for Expr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Expr::Add(lhs, rhs) => write!(f, "({lhs}) + ({rhs})"), + Expr::Sub(lhs, rhs) => write!(f, "({lhs}) - ({rhs})"), + Expr::Mul(lhs, rhs) => write!(f, "({lhs}) * ({rhs})"), + Expr::Div(lhs, rhs) => write!(f, "({lhs}) / ({rhs})"), + Expr::Rem(lhs, rhs) => write!(f, "({lhs}) % ({rhs})"), + Expr::Const(value) => write!(f, "{value}"), + } + } +} diff --git a/avr-tester/tests/acc/fractal.rs b/avr-tester/tests/acc/fractal.rs new file mode 100644 index 0000000..254ea0e --- /dev/null +++ b/avr-tester/tests/acc/fractal.rs @@ -0,0 +1,58 @@ +//! We're given an AVR that prints the Mandelbrot fractal; this test makes sure +//! that floating-point operations work correctly. +//! +//! See: [../../../avr-tester-fixtures/src/acc_fractal.rs]. + +use avr_tester::AvrTester; +use indoc::indoc; +use pretty_assertions as pa; + +#[test] +fn test() { + let mut avr = AvrTester::atmega328() + .with_clock_of_16_mhz() + .load("../avr-tester-fixtures/target/avr-none/release/acc-fractal.elf"); + + avr.run_for_s(8); + + let actual = avr.uart0().read::(); + + let expected = indoc! {r#" + . + ... + ..==.. + ..-###.. + ,,..,,,##,...... + ..############,##. + ..################.. + ....#....,################## + ...#####:,-################## + ...,##########################. + ####################################,. + ...,##########################. + ...#####:,-################## + ....#....,################## + ..################.. + ..############,##. + ,,..,,,##,...... + ..-###.. + ..==.. + ... + "#}; + + // --- + + let actual = actual + .lines() + .map(|line| line.trim_end().to_owned()) + .collect::>() + .join("\n"); + + let expected = expected + .lines() + .map(|line| format!(" {line}")) + .collect::>() + .join("\n"); + + pa::assert_eq!(expected, actual); +} diff --git a/avr-tester/tests/examples/analog_pins.rs b/avr-tester/tests/examples/analog_pins.rs index cf59fa9..4e5ec04 100644 --- a/avr-tester/tests/examples/analog_pins.rs +++ b/avr-tester/tests/examples/analog_pins.rs @@ -9,9 +9,9 @@ use avr_tester::AvrTester; #[test] fn test() { - let mut avr = AvrTester::atmega328().with_clock_of_16_mhz().load( - "../avr-tester-fixtures/target/atmega328p/release/analog-pins.elf", - ); + let mut avr = AvrTester::atmega328() + .with_clock_of_16_mhz() + .load("../avr-tester-fixtures/target/avr-none/release/analog-pins.elf"); // Give the firmware a moment to initialize avr.run_for_ms(1); diff --git a/avr-tester/tests/examples/digital_pins.rs b/avr-tester/tests/examples/digital_pins.rs index 959d9a0..a9dc8be 100644 --- a/avr-tester/tests/examples/digital_pins.rs +++ b/avr-tester/tests/examples/digital_pins.rs @@ -10,7 +10,7 @@ use avr_tester::{AvrDuration, AvrDurationExt, AvrTester}; #[test] fn simple() { let mut avr = AvrTester::atmega328().with_clock_of_16_mhz().load( - "../avr-tester-fixtures/target/atmega328p/release/digital-pins.elf", + "../avr-tester-fixtures/target/avr-none/release/digital-pins.elf", ); // Give the firmware a moment to initialize @@ -55,7 +55,7 @@ fn precise() { + 10, // Some leeway, just in case ) .load( - "../avr-tester-fixtures/target/atmega328p/release/digital-pins.elf", + "../avr-tester-fixtures/target/avr-none/release/digital-pins.elf", ); // Give the firmware a moment to initialize @@ -90,7 +90,7 @@ fn precise_idiomatic() { .with_clock_of_16_mhz() .with_timeout_of_s(2) .load( - "../avr-tester-fixtures/target/atmega328p/release/digital-pins.elf", + "../avr-tester-fixtures/target/avr-none/release/digital-pins.elf", ); // Give the firmware a moment to initialize @@ -154,7 +154,7 @@ fn precise_stuck() { .with_clock_of_16_mhz() .with_timeout_of_ms(100) .load( - "../avr-tester-fixtures/target/atmega328p/release/digital-pins.elf", + "../avr-tester-fixtures/target/avr-none/release/digital-pins.elf", ); while avr.pins().pd1().is_low() { diff --git a/avr-tester/tests/examples/shift_register.rs b/avr-tester/tests/examples/shift_register.rs index bc22176..9c9b7a8 100644 --- a/avr-tester/tests/examples/shift_register.rs +++ b/avr-tester/tests/examples/shift_register.rs @@ -48,7 +48,7 @@ async fn shift_register(numbers: Rc>>) { #[test] fn test() { let mut avr = AvrTester::atmega328().with_clock_of_16_mhz().load( - "../avr-tester-fixtures/target/atmega328p/release/shift-register.elf", + "../avr-tester-fixtures/target/avr-none/release/shift-register.elf", ); let numbers = Rc::new(RefCell::new(Vec::new())); @@ -67,7 +67,7 @@ fn test() { #[test] fn remove() { let mut avr = AvrTester::atmega328().with_clock_of_16_mhz().load( - "../avr-tester-fixtures/target/atmega328p/release/shift-register.elf", + "../avr-tester-fixtures/target/avr-none/release/shift-register.elf", ); let numbers = Rc::new(RefCell::new(Vec::new())); @@ -94,7 +94,7 @@ fn remove() { #[test] fn pause_and_resume() { let mut avr = AvrTester::atmega328().with_clock_of_16_mhz().load( - "../avr-tester-fixtures/target/atmega328p/release/shift-register.elf", + "../avr-tester-fixtures/target/avr-none/release/shift-register.elf", ); let numbers = Rc::new(RefCell::new(Vec::new())); diff --git a/avr-tester/tests/examples/spi.rs b/avr-tester/tests/examples/spi.rs index 8831612..d4850ae 100644 --- a/avr-tester/tests/examples/spi.rs +++ b/avr-tester/tests/examples/spi.rs @@ -11,7 +11,7 @@ use avr_tester::AvrTester; fn test() { let mut avr = AvrTester::atmega328() .with_clock_of_16_mhz() - .load("../avr-tester-fixtures/target/atmega328p/release/spi.elf"); + .load("../avr-tester-fixtures/target/avr-none/release/spi.elf"); avr.run_for_ms(1); diff --git a/avr-tester/tests/examples/spi_component.rs b/avr-tester/tests/examples/spi_component.rs index a5febb9..9f7f898 100644 --- a/avr-tester/tests/examples/spi_component.rs +++ b/avr-tester/tests/examples/spi_component.rs @@ -51,7 +51,7 @@ async fn spi_input_catcher( #[test] fn test() { let mut avr = AvrTester::atmega328().with_clock_of_16_mhz().load( - "../avr-tester-fixtures/target/atmega328p/release/spi-component.elf", + "../avr-tester-fixtures/target/avr-none/release/spi-component.elf", ); // Numbers transmitted through SPI when PD0 was high @@ -79,7 +79,7 @@ fn test() { 0xCA, 0xFE, 0xBA, 0xBE, // 0xCA, 0xFE, 0xBA, 0xBE, // 0xCA, 0xFE, 0xBA, 0xBE, // - 0xCA, + 0xCA, 0xFE, ], *low_numbers.borrow() ); diff --git a/avr-tester/tests/examples/timeout.rs b/avr-tester/tests/examples/timeout.rs index 8246c22..dc02030 100644 --- a/avr-tester/tests/examples/timeout.rs +++ b/avr-tester/tests/examples/timeout.rs @@ -15,7 +15,7 @@ fn test() { let mut avr = AvrTester::atmega328() .with_clock_of_16_mhz() .with_timeout_of_ms(100) // We think our AVR should complete within 100ms - .load("../avr-tester-fixtures/target/atmega328p/release/timeout.elf"); + .load("../avr-tester-fixtures/target/avr-none/release/timeout.elf"); avr.pins().pd0().pulse_in(); diff --git a/avr-tester/tests/examples/twi.rs b/avr-tester/tests/examples/twi.rs index b3ec629..733b4f8 100644 --- a/avr-tester/tests/examples/twi.rs +++ b/avr-tester/tests/examples/twi.rs @@ -11,7 +11,7 @@ use avr_tester::{AvrTester, Reader, TwiPacket, TwiSlave}; fn test() { let mut avr = AvrTester::atmega164pa() .with_clock_of_16_mhz() - .load("../avr-tester-fixtures/target/atmega328p/release/twi.elf"); + .load("../avr-tester-fixtures/target/avr-none/release/twi.elf"); avr.twi0().attach_slave(SimpleTwiRam::default()); avr.run_for_ms(250); diff --git a/avr-tester/tests/examples/uart.rs b/avr-tester/tests/examples/uart.rs index 1aedea1..bd3b188 100644 --- a/avr-tester/tests/examples/uart.rs +++ b/avr-tester/tests/examples/uart.rs @@ -11,7 +11,7 @@ use avr_tester::AvrTester; fn test() { let mut avr = AvrTester::atmega328() .with_clock_of_16_mhz() - .load("../avr-tester-fixtures/target/atmega328p/release/uart.elf"); + .load("../avr-tester-fixtures/target/avr-none/release/uart.elf"); avr.run_for_ms(1); diff --git a/rust-toolchain.toml b/rust-toolchain.toml index cb75a0c..6b1f90a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-10-29" +channel = "nightly-2025-04-15" components = ["cargo", "clippy", "rustc-dev", "rust-src", "rustfmt"] profile = "minimal"