Compare commits

...

10 Commits

Author SHA1 Message Date
730dcec440 Mandelbrot 2025-12-02 17:52:01 +01:00
d5699f2da3 Mandelbrot 2025-12-02 17:31:46 +01:00
fc2a63d7f1 Working cube 2025-12-02 16:22:15 +01:00
80a78441ef Merges Cargo.toml 2025-12-02 14:19:32 +01:00
54ec7106ed Rust: Color pub u8 2025-12-02 14:17:52 +01:00
d757633816 Fixed mandelbrot 2025-12-02 14:16:55 +01:00
a32fcea47e Add already compiled bitstreams 2025-11-28 14:16:07 +01:00
1c0ee18ba6 Add game 2048 2025-11-28 14:13:42 +01:00
6190053330 Add game 2048 2025-11-28 13:04:03 +01:00
da6e1ea7b0 Simple mandelbrot in rust 2025-11-25 17:16:32 +01:00
22 changed files with 897 additions and 107 deletions

1
.gitignore vendored
View File

@@ -14,4 +14,5 @@ bench/mem
clockInfo.txt
*.csv
*.bit
!bitstreams/*.bit
*.dcp

View File

@@ -34,6 +34,4 @@ SECTIONS
PROVIDE(_stack_size = 1024); /* 1 KiB */
PROVIDE(_stack_start = _memory_end);
PROVIDE(_stack_end = _stack_start - _stack_size);
}

View File

@@ -14,3 +14,4 @@ rustflags = [
[unstable]
build-std = ["core", "compiler_builtins"]
build-std-features = ["compiler-builtins-mem"]

View File

@@ -1,6 +1,6 @@
[workspace]
resolver = "3"
members = ["fpga-lib", "fpga-lib-macros", "hello-rust"]
members = ["fpga-lib", "fpga-lib-macros", "hello-rust", "game-2048", "rot-cube"]
[profile.release]
panic = "abort"

View File

@@ -1,28 +1,29 @@
pub struct Buttons {}
impl Buttons
{
pub unsafe fn get_button(button_id: u8) -> bool
{
unsafe { *LED_IP_ADDRESS >> (button_id) & 0b1 == 0b1 }
impl Buttons {
pub unsafe fn get_button(button_id: u8) -> bool {
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 }
}
}
pub struct Leds {}
impl Leds
{
pub unsafe fn set_led(led_id: u8, state: bool)
{
if state
{
unsafe { *LED_IP_ADDRESS |= (state as u32) << (led_id + 4) }
}
else
{
unsafe { *LED_IP_ADDRESS &= !((state as u32) << (led_id + 4)) }
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 {
core::ptr::write_volatile(LED_IP_ADDRESS, value | (state as u64) << (led_id + 4))
}
} else {
unsafe {
core::ptr::write_volatile(LED_IP_ADDRESS, value & !((state as u64) << (led_id + 4)))
}
}
}
}
pub const LED_IP_ADDRESS: *mut u32 = 0x30000000 as *mut u32;
pub const LED_IP_ADDRESS: *mut u64 = 0x30000000 as *mut u64;

View File

@@ -8,10 +8,11 @@ pub mod vga;
macro_rules! panic_handler {
() => {
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> !
{
loop
{}
fn panic(_info: &core::panic::PanicInfo) -> ! {
unsafe {
$crate::vga::VGA::draw_string(0, 0, "PANIC !", $crate::vga::WHITE);
}
loop {}
}
};
}

View File

@@ -1,3 +1,5 @@
use core::ptr::write_bytes;
use fpga_lib_macros::include_font_plate;
pub const VGA_ADDRESS: *mut Color = 0x80000000 as *mut Color;
@@ -6,12 +8,10 @@ pub const HEIGHT: usize = 240;
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct Color(pub(crate) u8);
pub struct Color(pub u8);
impl Color
{
pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self
{
impl Color {
pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self {
Self(((r >> 6) << 6) | ((g >> 5) << 3) | (b >> 5))
}
}
@@ -26,12 +26,10 @@ pub const BLUE: Color = Color::from_rgb(0, 0, 255);
pub struct VGA {}
impl VGA
{
impl VGA {
/// # Safety
/// `x` must be less than `WIDTH` and `y` must be less than `HEIGHT`
pub unsafe fn write_pixel_unsafe(x: u16, y: u16, color: Color)
{
pub unsafe fn write_pixel_unsafe(x: u16, y: u16, color: Color) {
let pixel_index = x as usize + y as usize * WIDTH;
let word_index = pixel_index / 4; // Get index of the word in which the pixel is
let byte_index = pixel_index % 4; // Get index of the byte within the word for the pixel
@@ -41,14 +39,10 @@ impl VGA
/// # Safety
/// `x` must be less than `WIDTH` and `y` must be less than `HEIGHT`
pub unsafe fn draw_char(x: u16, y: u16, c: char, color: Color)
{
let c = if (c as u8 > b'~') || ((c as u8) < b' ')
{
pub unsafe fn draw_char(x: u16, y: u16, c: char, color: Color) {
let c = if (c as u8 > b'~') || ((c as u8) < b' ') {
b'/' - b' '
}
else
{
} else {
c as u8 - b' '
};
@@ -56,10 +50,8 @@ impl VGA
let char_x = (c as usize % 32) * FONT_WIDTH;
let char_y = (c as usize / 32) * FONT_HEIGHT;
for i in 0..(FONT_WIDTH as u16)
{
for j in 0..(FONT_HEIGHT as u16)
{
for i in 0..(FONT_WIDTH as u16) {
for j in 0..(FONT_HEIGHT as u16) {
let xx = x + i;
let yy = y + j;
@@ -73,14 +65,10 @@ impl VGA
}
}
pub unsafe fn draw_char_bg(x: u16, y: u16, c: char, color: Color, bg_color: Color)
{
let c = if (c as u8 > b'~') || ((c as u8) < b' ')
{
pub unsafe fn draw_char_bg(x: u16, y: u16, c: char, color: Color, bg_color: Color) {
let c = if (c as u8 > b'~') || ((c as u8) < b' ') {
b'/' - b' '
}
else
{
} else {
c as u8 - b' '
};
@@ -88,21 +76,15 @@ impl VGA
let char_x = (c as usize % 32) * FONT_WIDTH;
let char_y = (c as usize / 32) * FONT_HEIGHT;
for i in 0..(FONT_WIDTH as u16)
{
for j in 0..(FONT_HEIGHT as u16)
{
for i in 0..(FONT_WIDTH as u16) {
for j in 0..(FONT_HEIGHT as u16) {
let xx = x + i;
let yy = y + j;
if xx < (WIDTH as u16) && yy < (HEIGHT as u16)
{
if unsafe { Self::font_plate_index(char_x as u16 + i, char_y as u16 + j) }
{
if xx < (WIDTH as u16) && yy < (HEIGHT as u16) {
if unsafe { Self::font_plate_index(char_x as u16 + i, char_y as u16 + j) } {
unsafe { Self::write_pixel_unsafe(xx, yy, color) }
}
else
{
} else {
unsafe { Self::write_pixel_unsafe(xx, yy, bg_color) }
}
}
@@ -112,18 +94,18 @@ impl VGA
/// # Safety
/// The text must have a length that can fit within a `u16`
pub unsafe fn draw_string(x: u16, y: u16, str: &str, color: Color)
{
pub unsafe fn draw_string(x: u16, y: u16, str: &str, color: Color) {
str.chars().enumerate().for_each(|(i, c)| unsafe {
Self::draw_char(x + i as u16 * (FONT_WIDTH as u16), y, c as char, color)
});
}
pub fn clear_screen(color: Color) {
unsafe { write_bytes(VGA_ADDRESS, color.0, WIDTH * HEIGHT) };
}
fn digit_count(mut val: u64) -> u64
{
fn digit_count(mut val: u64) -> u64 {
let mut i = 0;
while val != 0
{
while val != 0 {
val /= 10;
i += 1;
}
@@ -131,17 +113,14 @@ impl VGA
i
}
pub unsafe fn draw_u64(x: u16, y: u16, mut val: u64, color: Color, bg_color: Color)
{
if val == 0
{
pub unsafe fn draw_u64(x: u16, y: u16, mut val: u64, color: Color, bg_color: Color) {
if val == 0 {
unsafe { Self::draw_char_bg(x, y, '0', color, bg_color) }
return;
}
let digit_count = Self::digit_count(val) - 1;
let mut i = digit_count as u16;
while val != 0
{
while val != 0 {
let digit = val % 10;
val /= 10;
@@ -160,8 +139,7 @@ impl VGA
}
}
unsafe fn font_plate_index(x: u16, y: u16) -> bool
{
unsafe fn font_plate_index(x: u16, y: u16) -> bool {
let pixel_index = (y as usize) * FONTPLATE_WIDTH + (x as usize);
let byte_index = pixel_index / 8;
let bit_index = pixel_index % 8;

View File

@@ -0,0 +1 @@
/target

View File

@@ -0,0 +1,9 @@
[package]
name = "game-2048"
version = "0.1.0"
edition = "2024"
[dependencies]
compile-rand = "1.0.0"
fpga-lib = { path = "../fpga-lib" }
rand = {version = "0.9.2", default-features = false, features = ["small_rng"]}

View File

@@ -0,0 +1,3 @@
# 2048
A terminal version of the 2048 game.

View File

@@ -0,0 +1,324 @@
#![no_std]
#![no_main]
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
use core::{
mem::MaybeUninit,
ops::{Index, IndexMut},
};
use fpga_lib::{
panic_handler,
vga::{Color, BLACK, FONT_HEIGHT, FONT_WIDTH, RED, WHITE},
};
use rand::{seq::IndexedRandom, Rng, SeedableRng};
const fn get_color(x: u64) -> Color {
match x {
2 => Color::from_rgb(238, 228, 222),
4 => Color::from_rgb(237, 224, 200),
8 => Color::from_rgb(242, 177, 120),
16 => Color::from_rgb(245, 149, 99),
32 => Color::from_rgb(246, 124, 95),
64 => Color::from_rgb(246, 94, 59),
128 => Color::from_rgb(237, 207, 114),
256 => Color::from_rgb(237, 204, 97),
512 => Color::from_rgb(237, 200, 80),
1024 => Color::from_rgb(237, 197, 63),
2048 => Color::from_rgb(237, 194, 46),
4096 => Color::from_rgb(238, 102, 106),
8192 => Color::from_rgb(238, 78, 90),
16384 => Color::from_rgb(241, 65, 65),
32768 => Color::from_rgb(114, 178, 212),
65536 => Color::from_rgb(88, 159, 226),
131072 => Color::from_rgb(23, 129, 204),
_ => Color::from_rgb(255, 255, 255),
}
}
pub struct NZip<T, const N: usize> {
iters: [T; N],
}
impl<T: Iterator, const N: usize> Iterator for NZip<T, N> {
type Item = [T::Item; N];
fn next(&mut self) -> Option<Self::Item> {
let mut res = MaybeUninit::<[T::Item; N]>::uninit();
for (cpt, iter) in self.iters.iter_mut().enumerate() {
unsafe { *(res.as_mut_ptr() as *mut T::Item).add(cpt) = iter.next()? };
}
Some(unsafe { res.assume_init() })
}
}
impl<T: DoubleEndedIterator, const N: usize> DoubleEndedIterator for NZip<T, N> {
fn next_back(&mut self) -> Option<Self::Item> {
let mut res = MaybeUninit::<[T::Item; N]>::uninit();
for (cpt, iter) in self.iters.iter_mut().enumerate() {
unsafe { *(res.as_mut_ptr() as *mut T::Item).add(cpt) = iter.next_back()? };
}
Some(unsafe { res.assume_init() })
}
}
#[derive(Clone)]
pub struct Game<const SIZE: usize>
where
[(); SIZE * SIZE]:,
{
grid: [u64; SIZE * SIZE],
rng: rand::rngs::SmallRng,
score: u64,
}
impl<const SIZE: usize> Index<(usize, usize)> for Game<SIZE>
where
[(); SIZE * SIZE]:,
{
type Output = u64;
fn index(&self, index: (usize, usize)) -> &Self::Output {
&self.grid[index.1 * SIZE + index.0]
}
}
impl<const SIZE: usize> IndexMut<(usize, usize)> for Game<SIZE>
where
[(); SIZE * SIZE]:,
{
fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
&mut self.grid[index.1 * SIZE + index.0]
}
}
impl<const SIZE: usize> Game<SIZE>
where
[(); SIZE * SIZE]:,
{
pub fn new() -> Self {
Self {
grid: [0; SIZE * SIZE],
rng: rand::rngs::SmallRng::seed_from_u64(compile_rand::compile_rand!(u64)),
score: 0,
}
}
pub fn init() -> Self {
let mut g = Self::new();
g.add();
g.add();
g
}
pub fn reset(&mut self) {
*self = Self::new()
}
pub fn add(&mut self) {
let mut pos = [(0, 0); SIZE * SIZE];
let mut cpt = 0;
for y in 0..SIZE {
for x in 0..SIZE {
if self[(x, y)] == 0 {
pos[cpt] = (x, y);
cpt += 1;
}
}
}
let pos = *pos[0..cpt].choose(&mut self.rng).unwrap();
self[pos] = (self.rng.random_range(0..=1) + 1) * 2;
}
pub fn lost(&self) -> bool {
let mut copy = self.clone();
!(copy.left() || copy.down() || copy.right() || copy.up())
}
fn rotate(&mut self) {
let mut out = self.grid;
for i in 0..SIZE {
for j in 0..SIZE {
out[j * SIZE + (SIZE - i - 1)] = self.grid[i * SIZE + j];
}
}
self.grid = out;
}
fn rotate_back(&mut self) {
let mut out = self.grid;
for i in 0..SIZE {
for j in 0..SIZE {
out[(SIZE - j - 1) * SIZE + i] = self.grid[i * SIZE + j];
}
}
self.grid = out;
}
pub fn left(&mut self) -> bool {
let mut changed = false;
for y in 0..SIZE {
let mut index = 0;
let mut fixed = false;
let mut zero_found = false;
for x in 0..SIZE {
if self[(x, y)] == 0 {
zero_found = true;
continue;
} else if zero_found {
changed = true;
}
if index != 0 && self[(index - 1, y)] == (self[(x, y)]) && !fixed {
self[(index - 1, y)] = self[(x, y)] * 2;
self[(x, y)] = 0;
self.score += self[(index - 1, y)];
fixed = true;
changed = true;
} else {
self[(index, y)] = self[(x, y)];
if index != x {
self[(x, y)] = 0;
}
fixed = false;
index += 1;
}
}
}
changed
}
pub fn down(&mut self) -> bool {
self.rotate();
let res = self.left();
self.rotate_back();
res
}
pub fn right(&mut self) -> bool {
self.rotate();
self.rotate();
let res = self.left();
self.rotate_back();
self.rotate_back();
res
}
pub fn up(&mut self) -> bool {
self.rotate_back();
let res = self.left();
self.rotate();
res
}
pub fn run(&mut self) -> ! {
let mut buttons = [false; 4];
let funcs = [Self::right, Self::left, Self::up, Self::down];
let mut lost = false;
self.draw();
loop {
for direction in 0..4 {
let button = unsafe { fpga_lib::interface::Buttons::get_button(direction as u8) };
if button && !buttons[direction] {
buttons[direction] = true;
if funcs[direction](self) {
self.add();
self.draw();
if self.lost() {
lost = true;
break;
}
}
} else if !button && buttons[direction] {
buttons[direction] = false
}
}
if lost {
unsafe {
fpga_lib::vga::VGA::draw_string(
OFFSET,
OFFSET + (SIZE as u16) * BLOCK_SIZE + FONT_HEIGHT as u16 + 10,
"Game Over !",
RED,
)
};
loop {}
}
}
}
}
impl<const SIZE: usize> Default for Game<SIZE>
where
[(); SIZE * SIZE]:,
{
fn default() -> Self {
Self::new()
}
}
impl<const SIZE: usize> Game<SIZE>
where
[(); SIZE * SIZE]:,
{
fn draw(&self) {
fpga_lib::vga::VGA::clear_screen(BLACK);
for i in 0..SIZE as u16 + 1 {
for x in 0..BLOCK_SIZE * SIZE as u16 {
unsafe {
fpga_lib::vga::VGA::write_pixel_unsafe(
OFFSET + x,
OFFSET + i * BLOCK_SIZE,
WHITE,
)
};
unsafe {
fpga_lib::vga::VGA::write_pixel_unsafe(
OFFSET + i * BLOCK_SIZE,
OFFSET + x,
WHITE,
)
};
}
}
for y in 0..SIZE {
for x in 0..SIZE {
if self[(x, y)] != 0 {
unsafe {
fpga_lib::vga::VGA::draw_u64(
OFFSET + x as u16 * BLOCK_SIZE + BLOCK_SIZE / 2
- (fpga_lib::vga::FONT_WIDTH as u16
* (self[(x, y)].ilog10() as u16 + 1))
/ 2,
OFFSET + y as u16 * BLOCK_SIZE + BLOCK_SIZE / 2
- fpga_lib::vga::FONT_HEIGHT as u16 / 2,
self[(x, y)],
get_color(self[(x, y)]),
BLACK,
)
};
}
}
}
unsafe {
fpga_lib::vga::VGA::draw_string(
OFFSET,
OFFSET + (SIZE as u16) * BLOCK_SIZE + 5,
"Score :",
WHITE,
);
fpga_lib::vga::VGA::draw_u64(
OFFSET + FONT_WIDTH as u16 * 8,
OFFSET + (SIZE as u16) * BLOCK_SIZE + 5,
self.score,
WHITE,
BLACK,
);
}
}
}
panic_handler! {}
#[unsafe(no_mangle)]
pub extern "C" fn main() -> ! {
let mut g = Game::<4>::init();
g.run()
}
const BLOCK_SIZE: u16 = 40;
const OFFSET: u16 = 20;

View File

@@ -5,3 +5,4 @@ edition = "2024"
[dependencies]
fpga-lib = { path = "../fpga-lib" }
libm = "0.2.11"

View File

@@ -1,49 +1,125 @@
#![no_std]
#![no_main]
use core::arch::asm;
use core::ops::{Add, Mul};
use fpga_lib::{
interface::{Buttons, Leds},
interface::Buttons,
panic_handler,
register::X31,
vga::{BLACK, BLUE, FONT_WIDTH, GREEN, RED, VGA, WHITE},
vga::{Color, BLACK, HEIGHT, VGA, WIDTH},
};
type Float = f32;
pub const ITERATIONS_SHOWN: usize = 300;
pub const ASPECT_RATIO: f32 = WIDTH as f32 / HEIGHT as f32;
#[derive(Clone, Copy)]
struct Complex(f64, f64);
impl Complex {
pub fn sq_mag(&self) -> f64 {
self.0 * self.0 + self.1 * self.1
}
}
impl Add for Complex {
type Output = Complex;
fn add(self, Self(a, b): Self) -> Self::Output {
Complex(self.0 + a, self.1 + b)
}
}
impl Mul for Complex {
type Output = Complex;
fn mul(self, Self(a, b): Self) -> Self::Output {
Complex(self.0 * a - self.1 * b, self.0 * b + self.1 * a)
}
}
panic_handler! {}
#[unsafe(no_mangle)]
pub extern "C" fn main() -> !
{
loop
{
unsafe {
VGA::draw_string(10, 10, "Running RUST !", GREEN);
VGA::draw_string(10, 23, "LedIp state :", RED);
pub extern "C" fn main() -> ! {
let mut iterations: usize = 300;
let color_lut: [Color; ITERATIONS_SHOWN] = {
let mut tab = [BLACK; _];
(0..(ITERATIONS_SHOWN - 1)).for_each(|i| {
let val = ((i as Float / ITERATIONS_SHOWN as Float) * 255.) as u8;
tab[i] = Color(val);
});
let clint_time: *mut u64 = 0x0200bff8 as *mut u64;
tab
};
let clocks = *clint_time;
let seconds = clocks / 80_000_000;
VGA::draw_string(100, 10, "CLint:", BLUE);
VGA::draw_u64(150, 10, clocks, BLUE, BLACK);
VGA::draw_string(100, 23, "(s)", BLUE);
VGA::draw_u64(150, 23, seconds, BLUE, BLACK);
let mut zoom_int = 60;
const DELTA: f64 = 0.1;
let mut current_pos = Complex(1.002_674_971_219_186_5, 0.296_764_969_447_543_66);
for i in 0..4
{
VGA::draw_char(10 + i * 16, 46, 'B', RED);
VGA::draw_char(16 + i * 16, 46, (b'0' + i as u8) as char, RED);
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,
);
let mut acc = pos;
let mut iter = 0;
if Buttons::get_button(i as u8)
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.
{
Leds::set_led(i as u8, true);
VGA::draw_char_bg(10 + i * 16, 59, '1', GREEN, BLACK);
unsafe { VGA::write_pixel_unsafe(x as u16, y as u16, BLACK) };
continue;
}
else
{
Leds::set_led(i as u8, false);
VGA::draw_char_bg(10 + i * 16, 59, '0', RED, BLACK);
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,
_ => {}
}
while unsafe { fpga_lib::interface::Buttons::get_button(direction as u8) } {}
break 'outer;
}
}
}

View File

@@ -0,0 +1,8 @@
[package]
name = "rot-cube"
version = "0.1.0"
edition = "2024"
[dependencies]
fpga-lib = { path = "../fpga-lib" }
libm = "0.2.11"

View File

@@ -0,0 +1,291 @@
#![no_std]
#![no_main]
use core::{
arch::asm,
f32::consts::PI,
ops::{Add, Mul, Sub},
slice::Chunks,
};
use fpga_lib::{
interface::{Buttons, Leds},
panic_handler,
register::X31,
vga::{self, BLACK, BLUE, Color, FONT_WIDTH, GREEN, HEIGHT, RED, VGA, WHITE, WIDTH},
};
panic_handler! {}
#[derive(Clone, Copy)]
pub struct Vec3(f32, f32, f32);
#[derive(Clone, Copy)]
pub struct Mat3x3([[f32; 3]; 3]);
pub fn map_float(x: f32, xmin: f32, xmax: f32, ymin: f32, ymax: f32) -> f32
{
((x - xmin) / (xmax - xmin)) * (ymax - ymin) + ymin
}
impl Mat3x3
{
fn rot_x(amount: f32) -> Self
{
Mat3x3([
[libm::cosf(amount), -libm::sinf(amount), 0.],
[libm::sinf(amount), libm::cosf(amount), 0.],
[0., 0., 1.],
])
}
fn rot_y(amount: f32) -> Self
{
Mat3x3([
[1., 0., 0.],
[0., libm::cosf(amount), -libm::sinf(amount)],
[0., libm::sinf(amount), libm::cosf(amount)],
])
}
fn rot_z(amount: f32) -> Self
{
Mat3x3([
[libm::cosf(amount), 0., -libm::sinf(amount)],
[0., 1., 0.],
[libm::sinf(amount), 0., libm::cosf(amount)],
])
}
}
impl Mul<Mat3x3> for Mat3x3
{
type Output = Mat3x3;
fn mul(self, rhs: Mat3x3) -> Self::Output
{
Mat3x3([
[
self.0[0][0] * rhs.0[0][0]
+ self.0[0][1] * rhs.0[1][0]
+ self.0[0][2] * rhs.0[2][0],
self.0[0][0] * rhs.0[0][1]
+ self.0[0][1] * rhs.0[1][1]
+ self.0[0][2] * rhs.0[2][1],
self.0[0][0] * rhs.0[0][2]
+ self.0[0][1] * rhs.0[1][2]
+ self.0[0][2] * rhs.0[2][2],
],
[
self.0[1][0] * rhs.0[0][0]
+ self.0[1][1] * rhs.0[1][0]
+ self.0[1][2] * rhs.0[2][0],
self.0[1][0] * rhs.0[0][1]
+ self.0[1][1] * rhs.0[1][1]
+ self.0[1][2] * rhs.0[2][1],
self.0[1][0] * rhs.0[0][2]
+ self.0[1][1] * rhs.0[1][2]
+ self.0[1][2] * rhs.0[2][2],
],
[
self.0[2][0] * rhs.0[0][0]
+ self.0[2][1] * rhs.0[1][0]
+ self.0[2][2] * rhs.0[2][0],
self.0[2][0] * rhs.0[0][1]
+ self.0[2][1] * rhs.0[1][1]
+ self.0[2][2] * rhs.0[2][1],
self.0[2][0] * rhs.0[0][2]
+ self.0[2][1] * rhs.0[1][2]
+ self.0[2][2] * rhs.0[2][2],
],
])
}
}
impl Mul<Vec3> for Mat3x3
{
type Output = Vec3;
fn mul(self, rhs: Vec3) -> Self::Output
{
Vec3(
self.0[0][0] * rhs.0 + self.0[0][1] * rhs.1 + self.0[0][2] * rhs.2,
self.0[1][0] * rhs.0 + self.0[1][1] * rhs.1 + self.0[1][2] * rhs.2,
self.0[2][0] * rhs.0 + self.0[2][1] * rhs.1 + self.0[2][2] * rhs.2,
)
}
}
impl Mul<f32> for Vec3
{
type Output = Vec3;
fn mul(self, rhs: f32) -> Self::Output
{
Vec3(self.0 * rhs, self.1 * rhs, self.2 * rhs)
}
}
const CUBE: [Vec3; 8] = [
Vec3(1., 1., 1.),
Vec3(1., 1., -1.),
Vec3(1., -1., -1.),
Vec3(1., -1., 1.),
Vec3(-1., 1., 1.),
Vec3(-1., 1., -1.),
Vec3(-1., -1., -1.),
Vec3(-1., -1., 1.),
];
#[rustfmt::skip]
const LINES: [(usize, usize); 12] = [
// Face 1
(0, 1),
(1, 2),
(2, 3),
(3, 0),
// Face 2
(4, 5),
(5, 6),
(6, 7),
(7, 4),
// Cross faces
(0, 4),
(1, 5),
(2, 6),
(3, 7)
];
const PRISM: [Vec3; 5] = [
Vec3(-1., 1., 1.),
Vec3(-1., 1., -1.),
Vec3(-1., -1., -1.),
Vec3(-1., -1., 1.),
Vec3(1., 0., 0.),
];
const PRISM_LINES: [(usize, usize); 8] = [
(0, 1),
(1, 2),
(2, 3),
(3, 0),
(0, 4),
(1, 4),
(2, 4),
(3, 4),
];
fn draw_line(xa: u16, ya: u16, xb: u16, yb: u16, color: Color)
{
// calculate dx & dy
let dx = xb as i16 - xa as i16;
let dy = yb as i16 - ya as i16;
// calculate steps required for generating pixels
let steps = if dx.abs() > dy.abs()
{
dx.abs()
}
else
{
dy.abs()
};
// calculate increment in x & y for each steps
let x_inc: f32 = dx as f32 / steps as f32;
let y_inc: f32 = dy as f32 / steps as f32;
// Put pixel for each step
let mut x = xa as f32;
let mut y = ya as f32;
for _ in 0..steps
{
//putpixel(round(X), round(Y), RED); // put pixel at (X,Y)
unsafe {
VGA::write_pixel_unsafe(x as u16, y as u16, color);
}
x += x_inc; // increment in x at each step
y += y_inc; // increment in y at each step
// generation step by step
}
}
pub fn draw_shape(positions: &[Vec3], lines: &[(usize, usize)], color: Color)
{
for (la, lb) in lines
{
let a = positions[*la] * 0.5;
let b = positions[*lb] * 0.5;
let xa = map_float(a.0, -1., 1., 0., 320.);
let ya = map_float(a.1, -1., 1., 0., 240.);
let xb = map_float(b.0, -1., 1., 0., 320.);
let yb = map_float(b.1, -1., 1., 0., 240.);
draw_line(xa as u16, ya as u16, xb as u16, yb as u16, color);
}
}
const CPU_FREQ: usize = 80_000_000;
#[unsafe(no_mangle)]
pub extern "C" fn main() -> !
{
// CLEAR
for i in 0..320
{
for j in 0..240
{
unsafe {
VGA::write_pixel_unsafe(i, j, BLACK);
}
}
}
//draw_cube(&CUBE, WHITE);
let mut rx = 0.;
let mut ry = 0.;
let mut rz = 0.;
let mut prev_cube = CUBE;
let mut prev_prism = PRISM;
loop
{
rx += 0.03;
ry += 0.02;
rz += 0.05;
let mut cube = CUBE;
let mut prism = PRISM;
let mc = Mat3x3::rot_x(rx) * Mat3x3::rot_y(ry) * Mat3x3::rot_z(rz);
let mp = Mat3x3::rot_x(-PI / 2.) * Mat3x3::rot_y(rx) * Mat3x3::rot_z(0.1);
for x in cube.iter_mut()
{
*x = mc * *x;
}
for x in prism.iter_mut()
{
*x = mp * *x;
*x = *x * 0.5;
}
draw_shape(&prev_prism, &PRISM_LINES, BLACK);
draw_shape(&prism, &PRISM_LINES, BLUE);
draw_shape(&prev_cube, &LINES, BLACK);
draw_shape(&cube, &LINES, WHITE);
for _ in 0..(CPU_FREQ / 60)
{
unsafe {
asm!("nop");
}
}
prev_cube = cube;
prev_prism = prism;
}
}

BIN
bitstreams/cube.bit Normal file

Binary file not shown.

BIN
bitstreams/game-2048.bit Normal file

Binary file not shown.

Binary file not shown.

BIN
bitstreams/mandelbrot.bit Normal file

Binary file not shown.

View File

@@ -20,7 +20,7 @@ set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { io_swi
set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { io_push[0] }]; #IO_L20N_T3_34 Sch=BTN0
set_property -dict { PACKAGE_PIN P16 IOSTANDARD LVCMOS33 } [get_ports { io_push[1] }]; #IO_L24N_T3_34 Sch=BTN1
set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { io_push[2] }]; #IO_L18P_T2_34 Sch=BTN2
set_property -dict { PACKAGE_PIN Y16 IOSTANDARD LVCMOS33 } [get_ports { reset }]; #IO_L7P_T1_34 Sch=BTN3
set_property -dict { PACKAGE_PIN Y16 IOSTANDARD LVCMOS33 } [get_ports { reset }]; #IO_L7P_T1_34 Sch=BTN3
# LEDs

View File

@@ -27,7 +27,7 @@ class LedIp extends Module {
when(io.bus.be.asUInt.orR) { // Écriture dans le registre des leds internes
dinReg := io.bus.wdata
}.otherwise { // Lecture des boutons poussoirs, pas de débounce car lus par le soft
btnReg := Fill(29, 0.U) ## io.button
btnReg := Fill(25, 0.U) ## io.switch ## io.button
}
}

97
tight_setup_hold_pins.txt Normal file
View File

@@ -0,0 +1,97 @@
+====================+====================+============================================+
| Launch Setup Clock | Launch Hold Clock | Pin |
+====================+====================+============================================+
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | clnt/clintRegValue_reg[11]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | clnt/clintRegValue_reg[3]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | clnt/clintRegValue_reg[55]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | clnt/clintRegValue_reg[50]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | clnt/clintRegValue_reg[48]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[61]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[60]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[57]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[56]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[53]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[52]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[49]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[48]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[45]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[44]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[38]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[41]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[40]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[37]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[36]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[33]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[32]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[29]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[28]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[27]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[25]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[24]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[21]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[20]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[19]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[17]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[16]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[13]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[12]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[11]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[9]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[8]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[5]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[4]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/reg_pc_reg[1]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_dividend_reg[56]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_dividend_reg[55]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_dividend_reg[51]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_dividend_reg[47]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_dividend_reg[46]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_dividend_reg[22]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_dividend_reg[18]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[116]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_dividend_reg[16]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_dividend_reg[13]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[119]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_dividend_reg[8]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/cycles_remaining_reg[6]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[114]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[124]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[113]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[64]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[117]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[103]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[122]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[100]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[75]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[80]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[112]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[96]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[115]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[107]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[120]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[73]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[104]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[121]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[118]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[71]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[84]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[101]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[88]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[98]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[95]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[94]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[99]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/is_stalled_reg/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[92]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[79]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[85]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[83]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[77]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[86]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[82]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[81]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[72]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[66]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/divider/reg_divisor_reg[69]/D |
| clk_out1_clk_wiz_0 | clk_out1_clk_wiz_0 | core/alu/in_computation_reg/D |
+--------------------+--------------------+--------------------------------------------+