Mandelbrot
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
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]
|
[profile.release]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ pub struct Buttons {}
|
|||||||
|
|
||||||
impl Buttons {
|
impl Buttons {
|
||||||
pub unsafe fn get_button(button_id: u8) -> bool {
|
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 {
|
impl Leds {
|
||||||
pub unsafe fn set_led(led_id: u8, state: bool) {
|
pub unsafe fn set_led(led_id: u8, state: bool) {
|
||||||
|
let value = unsafe { core::ptr::read_volatile(LED_IP_ADDRESS) };
|
||||||
if state {
|
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 {
|
} 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)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ where
|
|||||||
}
|
}
|
||||||
pub fn run(&mut self) -> ! {
|
pub fn run(&mut self) -> ! {
|
||||||
let mut buttons = [false; 4];
|
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;
|
let mut lost = false;
|
||||||
self.draw();
|
self.draw();
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
@@ -1,115 +1,39 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use core::{
|
use core::ops::{Add, Mul};
|
||||||
arch::asm,
|
|
||||||
ops::{Add, Mul, Sub},
|
|
||||||
};
|
|
||||||
|
|
||||||
use fpga_lib::{
|
use fpga_lib::{
|
||||||
interface::{Buttons, Leds},
|
interface::Buttons,
|
||||||
panic_handler,
|
panic_handler,
|
||||||
register::X31,
|
vga::{Color, BLACK, HEIGHT, VGA, WIDTH},
|
||||||
vga::{BLACK, BLUE, Color, FONT_WIDTH, GREEN, HEIGHT, RED, VGA, WHITE, WIDTH},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type Float = f32;
|
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;
|
pub const ASPECT_RATIO: f32 = WIDTH as f32 / HEIGHT as f32;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
struct Complex(Q3x29, Q3x29);
|
struct Complex(f64, f64);
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
impl Complex {
|
||||||
struct Q3x29(i32);
|
pub fn sq_mag(&self) -> f64 {
|
||||||
|
|
||||||
impl From<f32> 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<f64> 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
|
|
||||||
{
|
|
||||||
self.0 * self.0 + self.1 * self.1
|
self.0 * self.0 + self.1 * self.1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map(x: Float, xmin: Float, xmax: Float, ymin: Float, ymax: Float) -> Float
|
impl Add for Complex {
|
||||||
{
|
|
||||||
((x - xmin) / (xmax - xmin)) * (ymax - ymin) + ymin
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add for Complex
|
|
||||||
{
|
|
||||||
type Output = 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)
|
Complex(self.0 + a, self.1 + b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mul for Complex
|
impl Mul for Complex {
|
||||||
{
|
|
||||||
type Output = 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)
|
Complex(self.0 * a - self.1 * b, self.0 * b + self.1 * a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,58 +41,87 @@ impl Mul for Complex
|
|||||||
panic_handler! {}
|
panic_handler! {}
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub extern "C" fn main() -> !
|
pub extern "C" fn main() -> ! {
|
||||||
{
|
let mut iterations: usize = 100;
|
||||||
let color_lut: [Color; ITERATIONS] = {
|
let color_lut: [Color; ITERATIONS_SHOWN] = {
|
||||||
let mut tab = [BLACK; _];
|
let mut tab = [BLACK; _];
|
||||||
for i in 0..(ITERATIONS - 1)
|
(0..(ITERATIONS_SHOWN - 1)).for_each(|i| {
|
||||||
{
|
let val = ((i as Float / ITERATIONS_SHOWN as Float) * 255.) as u8;
|
||||||
let val = ((i as Float / ITERATIONS as Float) * 255.) as u8;
|
|
||||||
//tab[i] = Color::from_rgb(val, val, val);
|
|
||||||
tab[i] = Color(val);
|
tab[i] = Color(val);
|
||||||
}
|
});
|
||||||
|
|
||||||
tab
|
tab
|
||||||
};
|
};
|
||||||
|
|
||||||
let zoom_int = 1;
|
let mut zoom_int = 2;
|
||||||
let zoom = Q3x29::from(1. / zoom_int as f32);
|
const DELTA: f64 = 0.1;
|
||||||
for x in 0..WIDTH
|
let mut current_pos = Complex(0.4, 0.);
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
for i in 0..ITERATIONS
|
loop {
|
||||||
{
|
let zoom = 1. / zoom_int as f64;
|
||||||
//acc = acc * acc + pos;
|
for y in 0..HEIGHT {
|
||||||
acc = Complex(
|
if unsafe { Buttons::is_button_pressed() } {
|
||||||
pos.0 + acc.0 * acc.0 - acc.1 * acc.1,
|
break;
|
||||||
pos.1 + Q3x29::from(2.) * acc.1 * acc.0,
|
}
|
||||||
|
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;
|
unsafe { VGA::write_pixel_unsafe(x as u16, y as u16, BLACK) };
|
||||||
break;
|
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 {
|
while unsafe { fpga_lib::interface::Buttons::get_button(direction as u8) } {}
|
||||||
VGA::write_pixel_unsafe(x as u16, y as u16, color_lut[iter]);
|
break 'outer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loop
|
|
||||||
{
|
|
||||||
core::hint::spin_loop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
BIN
bitstreams/mandelbrot.bit
Normal file
BIN
bitstreams/mandelbrot.bit
Normal file
Binary file not shown.
Reference in New Issue
Block a user