diff --git a/bench/programs_rust/Cargo.toml b/bench/programs_rust/Cargo.toml index 9fcbd7c..886b6fe 100644 --- a/bench/programs_rust/Cargo.toml +++ b/bench/programs_rust/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "3" -members = ["fpga-lib", "fpga-lib-macros", "hello-rust", "rot-cube", "rot-cube"] +members = ["fpga-lib", "fpga-lib-macros", "hello-rust", "game-2048", "rot-cube"] [profile.release] panic = "abort" diff --git a/bench/programs_rust/fpga-lib/src/interface.rs b/bench/programs_rust/fpga-lib/src/interface.rs index 8636949..d4ecc0d 100644 --- a/bench/programs_rust/fpga-lib/src/interface.rs +++ b/bench/programs_rust/fpga-lib/src/interface.rs @@ -2,7 +2,10 @@ pub struct Buttons {} impl Buttons { pub unsafe fn get_button(button_id: u8) -> bool { - unsafe { ((*LED_IP_ADDRESS) >> button_id) & 0b1 == 0b1 } + unsafe { (core::ptr::read_volatile(LED_IP_ADDRESS) >> button_id) & 0b1 == 0b1 } + } + pub unsafe fn is_button_pressed() -> bool { + unsafe { core::ptr::read_volatile(LED_IP_ADDRESS) != 0 } } } @@ -10,10 +13,15 @@ pub struct Leds {} impl Leds { pub unsafe fn set_led(led_id: u8, state: bool) { + let value = unsafe { core::ptr::read_volatile(LED_IP_ADDRESS) }; if state { - unsafe { *LED_IP_ADDRESS |= (state as u64) << (led_id + 4) } + unsafe { + core::ptr::write_volatile(LED_IP_ADDRESS, value | (state as u64) << (led_id + 4)) + } } else { - unsafe { *LED_IP_ADDRESS &= !((state as u64) << (led_id + 4)) } + unsafe { + core::ptr::write_volatile(LED_IP_ADDRESS, value & !((state as u64) << (led_id + 4))) + } } } } diff --git a/bench/programs_rust/game-2048/src/main.rs b/bench/programs_rust/game-2048/src/main.rs index 71a7871..c5e9c18 100644 --- a/bench/programs_rust/game-2048/src/main.rs +++ b/bench/programs_rust/game-2048/src/main.rs @@ -206,7 +206,7 @@ where } pub fn run(&mut self) -> ! { let mut buttons = [false; 4]; - let funcs = [Self::left, Self::right, Self::up, Self::down]; + let funcs = [Self::right, Self::left, Self::up, Self::down]; let mut lost = false; self.draw(); loop { diff --git a/bench/programs_rust/hello-rust/src/main.rs b/bench/programs_rust/hello-rust/src/main.rs index 5bdb78c..22a16a3 100644 --- a/bench/programs_rust/hello-rust/src/main.rs +++ b/bench/programs_rust/hello-rust/src/main.rs @@ -1,115 +1,39 @@ #![no_std] #![no_main] -use core::{ - arch::asm, - ops::{Add, Mul, Sub}, -}; +use core::ops::{Add, Mul}; use fpga_lib::{ - interface::{Buttons, Leds}, + interface::Buttons, panic_handler, - register::X31, - vga::{BLACK, BLUE, Color, FONT_WIDTH, GREEN, HEIGHT, RED, VGA, WHITE, WIDTH}, + vga::{Color, BLACK, HEIGHT, VGA, WIDTH}, }; type Float = f32; -pub const ITERATIONS: usize = 100; +pub const ITERATIONS_SHOWN: usize = 100; pub const ASPECT_RATIO: f32 = WIDTH as f32 / HEIGHT as f32; #[derive(Clone, Copy)] -struct Complex(Q3x29, Q3x29); +struct Complex(f64, f64); -#[derive(Clone, Copy)] -struct Q3x29(i32); - -impl From for Q3x29 -{ - fn from(x: f32) -> Q3x29 - { - const SCALE: f32 = 16.0; - const MAX_Q28_4: f32 = (u32::MAX as f32) / SCALE; - - let clamped = x.clamp(0.0, MAX_Q28_4); - let scaled = clamped * SCALE; - - Q3x29(scaled as i32) - } -} - -impl From for Q3x29 -{ - fn from(x: f64) -> Q3x29 - { - const SCALE: f64 = 16.0; - const MAX_Q28_4: f64 = (u32::MAX as f64) / SCALE; - - let clamped = x.clamp(0.0, MAX_Q28_4); - let scaled = clamped * SCALE; - - Q3x29(scaled as i32) - } -} - -impl Add for Q3x29 -{ - type Output = Q3x29; - - fn add(self, rhs: Self) -> Self::Output - { - Q3x29(self.0 + rhs.0) - } -} - -impl Sub for Q3x29 -{ - type Output = Q3x29; - - fn sub(self, rhs: Self) -> Self::Output - { - Q3x29(self.0 - rhs.0) - } -} - -impl Mul for Q3x29 -{ - type Output = Q3x29; - - fn mul(self, rhs: Self) -> Self::Output - { - let prod: i64 = self.0 as i64 * rhs.0 as i64; - Q3x29(((prod >> 28) & 0xFFFFFFFF) as i32) - } -} -impl Complex -{ - pub fn sq_mag(&self) -> Q3x29 - { +impl Complex { + pub fn sq_mag(&self) -> f64 { self.0 * self.0 + self.1 * self.1 } } -pub fn map(x: Float, xmin: Float, xmax: Float, ymin: Float, ymax: Float) -> Float -{ - ((x - xmin) / (xmax - xmin)) * (ymax - ymin) + ymin -} - -impl Add for Complex -{ +impl Add for Complex { type Output = Complex; - fn add(self, Self(a, b): Self) -> Self::Output - { + fn add(self, Self(a, b): Self) -> Self::Output { Complex(self.0 + a, self.1 + b) } } -impl Mul for Complex -{ +impl Mul for Complex { type Output = Complex; - fn mul(self, Self(a, b): Self) -> Self::Output - { + fn mul(self, Self(a, b): Self) -> Self::Output { Complex(self.0 * a - self.1 * b, self.0 * b + self.1 * a) } } @@ -117,58 +41,87 @@ impl Mul for Complex panic_handler! {} #[unsafe(no_mangle)] -pub extern "C" fn main() -> ! -{ - let color_lut: [Color; ITERATIONS] = { +pub extern "C" fn main() -> ! { + let mut iterations: usize = 100; + let color_lut: [Color; ITERATIONS_SHOWN] = { let mut tab = [BLACK; _]; - for i in 0..(ITERATIONS - 1) - { - let val = ((i as Float / ITERATIONS as Float) * 255.) as u8; - //tab[i] = Color::from_rgb(val, val, val); + (0..(ITERATIONS_SHOWN - 1)).for_each(|i| { + let val = ((i as Float / ITERATIONS_SHOWN as Float) * 255.) as u8; tab[i] = Color(val); - } + }); tab }; - let zoom_int = 1; - let zoom = Q3x29::from(1. / zoom_int as f32); - for x in 0..WIDTH - { - for y in 0..HEIGHT - { - // -0.761574,-0.0847596) - let pos = Complex( - Q3x29((x as i32 - WIDTH as i32 / 2) * (0x1FFFFFFF / WIDTH as i32)) * zoom - - Q3x29::from(0.761574), - Q3x29((y as i32 - HEIGHT as i32 / 2) * (0x1FFFFFFF / WIDTH as i32)) * zoom - - Q3x29::from(0.0847596), - ); - let mut acc = pos; - let mut iter = 0; + let mut zoom_int = 2; + const DELTA: f64 = 0.1; + let mut current_pos = Complex(0.4, 0.); - for i in 0..ITERATIONS - { - //acc = acc * acc + pos; - acc = Complex( - pos.0 + acc.0 * acc.0 - acc.1 * acc.1, - pos.1 + Q3x29::from(2.) * acc.1 * acc.0, + loop { + let zoom = 1. / zoom_int as f64; + for y in 0..HEIGHT { + if unsafe { Buttons::is_button_pressed() } { + break; + } + for x in 0..WIDTH { + // -0.761574,-0.0847596 + let pos = Complex( + ((x as i64 - WIDTH as i64 / 2) as f64 * 5. / WIDTH as f64) * zoom + - current_pos.0, + ((y as i64 - HEIGHT as i64 / 2) as f64 * 5. / WIDTH as f64) * zoom + - current_pos.1, ); - if acc.sq_mag().0 > Q3x29::from(3.8).0 + let mut acc = pos; + let mut iter = 0; + + let p = (pos.0 - 1. / 4.) * (pos.0 - 1. / 4.) + pos.1 * pos.1; + if pos.0 < libm::sqrt(p) - 2. * p + 1. / 4. + || (pos.0 + 1.) * (pos.0 + 1.) + pos.1 * pos.1 < 1. / 16. { - iter = i; - break; + unsafe { VGA::write_pixel_unsafe(x as u16, y as u16, BLACK) }; + continue; + } + + for i in 0..iterations { + acc = Complex( + pos.0 + acc.0 * acc.0 - acc.1 * acc.1, + pos.1 + acc.1 * acc.0 + acc.1 * acc.0, + ); + if acc.sq_mag() > 4. { + iter = i; + break; + } + } + + unsafe { + VGA::write_pixel_unsafe( + x as u16, + y as u16, + color_lut + [(iter as f32 / iterations as f32 * ITERATIONS_SHOWN as f32) as usize], + ); } } + } + 'outer: loop { + for direction in 0..7 { + let button = unsafe { fpga_lib::interface::Buttons::get_button(direction as u8) }; + if button { + match direction { + 0 => current_pos.0 += DELTA * zoom, + 1 => current_pos.0 -= DELTA * zoom, + 2 => current_pos.1 += DELTA * zoom, + 3 => current_pos.1 -= DELTA * zoom, + 4 => zoom_int += 1, + 5 => zoom_int -= 1, + 6 => iterations += 50, + _ => {} + } - unsafe { - VGA::write_pixel_unsafe(x as u16, y as u16, color_lut[iter]); + while unsafe { fpga_lib::interface::Buttons::get_button(direction as u8) } {} + break 'outer; + } } } } - - loop - { - core::hint::spin_loop(); - } } diff --git a/bitstreams/game-2048.bit b/bitstreams/game-2048.bit index 2b45c44..6076f5f 100644 Binary files a/bitstreams/game-2048.bit and b/bitstreams/game-2048.bit differ diff --git a/bitstreams/mandelbrot.bit b/bitstreams/mandelbrot.bit new file mode 100644 index 0000000..8e2bc97 Binary files /dev/null and b/bitstreams/mandelbrot.bit differ