Merge branch 'rust'
This commit is contained in:
11
.gitignore
vendored
11
.gitignore
vendored
@@ -6,7 +6,12 @@ mill*
|
|||||||
bench/mem
|
bench/mem
|
||||||
.metals
|
.metals
|
||||||
.bloop
|
.bloop
|
||||||
.rpt
|
*.rpt
|
||||||
.Xil
|
*.jou
|
||||||
|
*.log
|
||||||
|
*.mmi
|
||||||
|
*.Xil
|
||||||
clockInfo.txt
|
clockInfo.txt
|
||||||
.csv
|
*.csv
|
||||||
|
*.bit
|
||||||
|
*.dcp
|
||||||
|
|||||||
15
Makefile
15
Makefile
@@ -61,13 +61,18 @@ TEST_MAX_PROCS := $$(($$(nproc) - 2)) ## Garde un processeur libre
|
|||||||
|
|
||||||
.PRECIOUS: $(MEM_DIR)/%.elf
|
.PRECIOUS: $(MEM_DIR)/%.elf
|
||||||
|
|
||||||
.PHONY: synthese fpga clean compile autotest simulation
|
.PHONY: synthese fpga clean compile autotest simulation force
|
||||||
|
force:
|
||||||
|
|
||||||
compile: $(MEM)
|
compile: $(MEM)
|
||||||
$(MEM_DIR):
|
$(MEM_DIR):
|
||||||
@mkdir -p $@/tests/op
|
@mkdir -p $@/tests/op
|
||||||
@mkdir -p $@/programs
|
@mkdir -p $@/programs
|
||||||
|
@mkdir -p $@/programs_rust
|
||||||
|
|
||||||
|
$(MEM_DIR)/programs_rust/%.elf: bench/programs_rust/% force |$(MEM_DIR)
|
||||||
|
cd bench/programs_rust && cargo build --release --bin=$(basename $(notdir $@))
|
||||||
|
cp -f bench/programs_rust/target/riscv64i/release/$(basename $(notdir $@)) $@
|
||||||
$(MEM_DIR)/crt.o: $(BENCH_DIR)/crt.S |$(MEM_DIR)
|
$(MEM_DIR)/crt.o: $(BENCH_DIR)/crt.S |$(MEM_DIR)
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
$(MEM_DIR)/%.elf: $(BENCH_DIR)/%.c $(MEM_DIR)/crt.o |$(MEM_DIR)
|
$(MEM_DIR)/%.elf: $(BENCH_DIR)/%.c $(MEM_DIR)/crt.o |$(MEM_DIR)
|
||||||
@@ -106,14 +111,16 @@ mill:
|
|||||||
|
|
||||||
autotest: mill test-bench/mem/tests/$(PROG).mem ##! Lance la simulation automatique pour tous les tests ou juste celui fourni dans PROG
|
autotest: mill test-bench/mem/tests/$(PROG).mem ##! Lance la simulation automatique pour tous les tests ou juste celui fourni dans PROG
|
||||||
|
|
||||||
testall: mill compile
|
testall: mill compile ##! Lance la simulation automatique pour tous les tests en parallèle
|
||||||
@# Limite le nombre de processeurs et la ram utilisée pour les tests parellèle
|
@# Limite le nombre de processeurs et la ram utilisée pour les tests parallèle
|
||||||
@( \
|
@( \
|
||||||
ulimit -v $(TEST_MAX_RAM); \
|
ulimit -v $(TEST_MAX_RAM); \
|
||||||
PROOT=$(PWD) taskset -c 0-$(TEST_MAX_PROCS) ./mill TPchisel.test.testOnly $(TOP_REP).ZzTopAllSpec \
|
PROOT=$(PWD) taskset -c 0-$(TEST_MAX_PROCS) ./mill TPchisel.test.testOnly $(TOP_REP).ZzTopAllSpec \
|
||||||
)
|
)
|
||||||
|
|
||||||
simulation: mill compile ##! Lance gtkwave sur le test fourni dans PROG
|
$(PROG): $(MEM_DIR)/$(PROG).mem
|
||||||
|
|
||||||
|
simulation: mill $(PROG) ##! Lance gtkwave sur le test fourni dans PROG
|
||||||
@$(call check_vars,PROG)
|
@$(call check_vars,PROG)
|
||||||
@PROOT=$(PWD) PROG=$(PROG) CYCLES=$(CYCLES) ./mill TPchisel.test.testOnly $(TOP_REP).$(TOP_TEST) -- -DemitVcd=1 -z "gtkwave"
|
@PROOT=$(PWD) PROG=$(PROG) CYCLES=$(CYCLES) ./mill TPchisel.test.testOnly $(TOP_REP).$(TOP_TEST) -- -DemitVcd=1 -z "gtkwave"
|
||||||
@gtkwave -a common/config.gtkw ./build/chiselsim/ZzTopSpec/Simulation-pour-gtkwave/workdir-verilator/trace.vcd
|
@gtkwave -a common/config.gtkw ./build/chiselsim/ZzTopSpec/Simulation-pour-gtkwave/workdir-verilator/trace.vcd
|
||||||
|
|||||||
14
bench/programs_rust/.cargo/config.toml
Normal file
14
bench/programs_rust/.cargo/config.toml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[build]
|
||||||
|
target = "riscv64i.json"
|
||||||
|
|
||||||
|
[target.riscv64i]
|
||||||
|
linker = "riscv64-unknown-elf-ld"
|
||||||
|
# linker = "rust-lld"
|
||||||
|
|
||||||
|
rustflags = [
|
||||||
|
# "-C", "link-arg=-nostartfiles",
|
||||||
|
"-C", "link-arg=-T../link.ld",
|
||||||
|
]
|
||||||
|
|
||||||
|
[unstable]
|
||||||
|
build-std = ["core", "compiler_builtins"]
|
||||||
3
bench/programs_rust/.gitignore
vendored
Normal file
3
bench/programs_rust/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.helix/
|
||||||
|
target/
|
||||||
|
Cargo.lock
|
||||||
13
bench/programs_rust/Cargo.toml
Normal file
13
bench/programs_rust/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[workspace]
|
||||||
|
resolver = "3"
|
||||||
|
members = ["fpga-lib", "fpga-lib-macros", "hello-rust"]
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
|
codegen-units = 1 # better optimizations
|
||||||
|
lto = true # better optimizations
|
||||||
|
strip = true
|
||||||
|
opt-level = "z"
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
BIN
bench/programs_rust/fontplate.png
Normal file
BIN
bench/programs_rust/fontplate.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
14
bench/programs_rust/fpga-lib-macros/Cargo.toml
Normal file
14
bench/programs_rust/fpga-lib-macros/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "fpga-lib-macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
image = "0.25.5"
|
||||||
|
regex = "1.11.1"
|
||||||
|
proc-macro2 = "1.0"
|
||||||
|
quote = "1.0"
|
||||||
|
syn = { version = "2.0", features = ["full"] }
|
||||||
106
bench/programs_rust/fpga-lib-macros/src/image.rs
Normal file
106
bench/programs_rust/fpga-lib-macros/src/image.rs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
use image::{ImageBuffer, Luma};
|
||||||
|
use proc_macro::{Span, TokenStream};
|
||||||
|
use quote::quote;
|
||||||
|
use regex::Regex;
|
||||||
|
use syn::parse::Parse;
|
||||||
|
|
||||||
|
fn remove_non_alphanumeric(input: &str) -> String {
|
||||||
|
let re = Regex::new(r"[^a-zA-Z0-9_]+").unwrap();
|
||||||
|
re.replace_all(input, "").to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_format(img: ImageBuffer<Luma<u8>, Vec<u8>>, width: usize, height: usize) -> Vec<u8> {
|
||||||
|
let mut output = Vec::new();
|
||||||
|
|
||||||
|
let mut bit: u8 = 0;
|
||||||
|
let mut byte: u8 = 0;
|
||||||
|
for y in 0..height {
|
||||||
|
for x in 0..width {
|
||||||
|
let pixel = img.get_pixel(x as u32, y as u32)[0];
|
||||||
|
if pixel >= 127 {
|
||||||
|
byte |= 1 << bit;
|
||||||
|
}
|
||||||
|
bit += 1;
|
||||||
|
if bit == 8 {
|
||||||
|
output.push(byte);
|
||||||
|
byte = 0;
|
||||||
|
bit = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if bit != 0 {
|
||||||
|
output.push(byte);
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path_to_image(path: &str) -> (Vec<u8>, String, usize, usize) {
|
||||||
|
let img = match image::open(path) {
|
||||||
|
Ok(img) => img.to_luma8(),
|
||||||
|
Err(e) => panic!("failed to open image {}: {}", path, e),
|
||||||
|
};
|
||||||
|
|
||||||
|
let width = img.width() as usize;
|
||||||
|
let height = img.height() as usize;
|
||||||
|
|
||||||
|
let bytes = to_format(img, width, height);
|
||||||
|
|
||||||
|
let path = path
|
||||||
|
.split('/')
|
||||||
|
.next_back()
|
||||||
|
.expect("failed to get last part of path");
|
||||||
|
let split: Vec<_> = path.split('.').collect();
|
||||||
|
let name = remove_non_alphanumeric(&split[0..split.len() - 1].join(".")).to_uppercase();
|
||||||
|
|
||||||
|
(bytes, name, width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ParsedArgs {
|
||||||
|
path: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for ParsedArgs {
|
||||||
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||||
|
let path: syn::LitStr = input.parse()?;
|
||||||
|
let path = path.value();
|
||||||
|
Ok(ParsedArgs { path })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_image(
|
||||||
|
input: TokenStream,
|
||||||
|
) -> Result<
|
||||||
|
(
|
||||||
|
u8,
|
||||||
|
u8,
|
||||||
|
proc_macro2::Ident,
|
||||||
|
usize,
|
||||||
|
Vec<proc_macro2::TokenStream>,
|
||||||
|
),
|
||||||
|
syn::Error,
|
||||||
|
> {
|
||||||
|
// parse the input into a comma separated list of arguments
|
||||||
|
let parsed_args = syn::parse::<ParsedArgs>(input)?;
|
||||||
|
// let parsed_args = parse_macro_input!(input as ParsedArgs);
|
||||||
|
let (bytes, name, width, height) = path_to_image(&parsed_args.path);
|
||||||
|
|
||||||
|
let width = width as u8;
|
||||||
|
let height = height as u8;
|
||||||
|
|
||||||
|
let byte_array = bytes.as_slice();
|
||||||
|
let byte_count = byte_array.len();
|
||||||
|
|
||||||
|
let name_ident = syn::Ident::new(&name, Span::call_site().into());
|
||||||
|
|
||||||
|
let byte_tokens = bytes.iter().map(|b| quote! { #b }).collect::<Vec<_>>();
|
||||||
|
Ok((width, height, name_ident, byte_count, byte_tokens))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn include_font_plate_impl(input: TokenStream) -> TokenStream {
|
||||||
|
let (_, _, _, _, byte_tokens) = parse_image(input).unwrap();
|
||||||
|
|
||||||
|
let output = quote! {
|
||||||
|
[#(#byte_tokens),*]
|
||||||
|
};
|
||||||
|
output.into()
|
||||||
|
}
|
||||||
40
bench/programs_rust/fpga-lib-macros/src/lib.rs
Normal file
40
bench/programs_rust/fpga-lib-macros/src/lib.rs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
mod image;
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::{format_ident, quote};
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn define_regs(_input: TokenStream) -> TokenStream {
|
||||||
|
let mut tokens = proc_macro2::TokenStream::new();
|
||||||
|
|
||||||
|
for n in 0..32usize {
|
||||||
|
let load = format!("li x{}, {{}}", n);
|
||||||
|
let store = format!("mv {{}}, x{}", n);
|
||||||
|
let ident = format_ident!("X{}", n);
|
||||||
|
let t = quote! {
|
||||||
|
impl Reg<#n> {
|
||||||
|
pub fn write_const<const X: u64>() {
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(#load, const X)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn read() -> u64 {
|
||||||
|
let out: u64;
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(#store, out(reg) out)
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub type #ident = Reg<#n>;
|
||||||
|
};
|
||||||
|
tokens.extend(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn include_font_plate(input: TokenStream) -> TokenStream {
|
||||||
|
image::include_font_plate_impl(input)
|
||||||
|
}
|
||||||
7
bench/programs_rust/fpga-lib/Cargo.toml
Normal file
7
bench/programs_rust/fpga-lib/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "fpga-lib"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
fpga-lib-macros = { path = "../fpga-lib-macros" }
|
||||||
14
bench/programs_rust/fpga-lib/src/lib.rs
Normal file
14
bench/programs_rust/fpga-lib/src/lib.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#![no_std]
|
||||||
|
|
||||||
|
pub mod register;
|
||||||
|
pub mod vga;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! panic_handler {
|
||||||
|
() => {
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
3
bench/programs_rust/fpga-lib/src/register.rs
Normal file
3
bench/programs_rust/fpga-lib/src/register.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub struct Reg<const N: usize> {}
|
||||||
|
|
||||||
|
fpga_lib_macros::define_regs! {}
|
||||||
48
bench/programs_rust/fpga-lib/src/vga.rs
Normal file
48
bench/programs_rust/fpga-lib/src/vga.rs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
use fpga_lib_macros::include_font_plate;
|
||||||
|
|
||||||
|
pub const VGA_ADDRESS: *mut Color = 0x80000000 as *mut Color;
|
||||||
|
pub const WIDTH: usize = 320;
|
||||||
|
pub const HEIGHT: usize = 240;
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Color(pub(crate) u8);
|
||||||
|
|
||||||
|
impl Color {
|
||||||
|
pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self {
|
||||||
|
Self(((r >> 6) << 6) | ((g >> 5) << 3) | (b >> 5))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const WHITE: Color = Color::from_rgb(255, 255, 255);
|
||||||
|
pub const GRAY: Color = Color::from_rgb(128, 128, 128);
|
||||||
|
pub const LIGHT_GRAY: Color = Color::from_rgb(128, 64, 64);
|
||||||
|
pub const BLACK: Color = Color::from_rgb(0, 0, 0);
|
||||||
|
pub const RED: Color = Color::from_rgb(255, 0, 0);
|
||||||
|
pub const GREEN: Color = Color::from_rgb(0, 255, 0);
|
||||||
|
pub const BLUE: Color = Color::from_rgb(0, 0, 255);
|
||||||
|
|
||||||
|
pub struct 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) {
|
||||||
|
unsafe { *VGA_ADDRESS.add(x as usize + y as usize * WIDTH) = color }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn draw_char(x: u16, y: u16, c: char) {
|
||||||
|
let c = c as u8 - b' ';
|
||||||
|
for i in 0..FONT_HEIGHT {
|
||||||
|
for j in 0..FONT_WIDTH {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const FONT_WIDTH: usize = 6;
|
||||||
|
pub const FONT_HEIGHT: usize = 13;
|
||||||
|
pub const FONTPLATE_WIDTH: usize = 32 * FONT_WIDTH;
|
||||||
|
pub const FONTPLATE_HEIGHT: usize = 3 * FONT_HEIGHT;
|
||||||
|
pub const FONTPLATE_SIZE: usize = FONTPLATE_WIDTH * FONTPLATE_HEIGHT / 8;
|
||||||
|
pub const FONTPLATE: [u8; FONTPLATE_SIZE] = include_font_plate! {"fontplate.png"};
|
||||||
7
bench/programs_rust/hello-rust/Cargo.toml
Normal file
7
bench/programs_rust/hello-rust/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "hello-rust"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
fpga-lib = { path = "../fpga-lib" }
|
||||||
28
bench/programs_rust/hello-rust/src/main.rs
Normal file
28
bench/programs_rust/hello-rust/src/main.rs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
use fpga_lib::{
|
||||||
|
panic_handler,
|
||||||
|
register::X31,
|
||||||
|
vga::{VGA, WHITE},
|
||||||
|
};
|
||||||
|
|
||||||
|
panic_handler! {}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn _start() -> ! {
|
||||||
|
X31::write_const::<0xdead1ffffffff>();
|
||||||
|
let test = X31::read() + 10;
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
"add x31, x0, x0",
|
||||||
|
"add x31, x0, {}", in(reg) test
|
||||||
|
);
|
||||||
|
|
||||||
|
VGA::write_pixel_unsafe(0, 0, WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
21
bench/programs_rust/riscv64i.json
Normal file
21
bench/programs_rust/riscv64i.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"llvm-target": "riscv64",
|
||||||
|
"llvm-abiname": "lp64",
|
||||||
|
"abi": "lp64",
|
||||||
|
"data-layout": "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
|
||||||
|
"target-endian": "little",
|
||||||
|
"target-pointer-width": 64,
|
||||||
|
"arch": "riscv64",
|
||||||
|
"os": "none",
|
||||||
|
"vendor": "unknown",
|
||||||
|
"env": "",
|
||||||
|
"features": "+i",
|
||||||
|
"linker-flavor": "ld.lld",
|
||||||
|
"linker": "riscv64-unknown-elf-ld",
|
||||||
|
"executables": true,
|
||||||
|
"panic-strategy": "abort",
|
||||||
|
"relocation-model": "static",
|
||||||
|
"disable-redzone": true,
|
||||||
|
"emit-debug-gdb-scripts": false,
|
||||||
|
"eh-frame-header": false
|
||||||
|
}
|
||||||
2
bench/programs_rust/rust-toolchain.toml
Normal file
2
bench/programs_rust/rust-toolchain.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly"
|
||||||
Reference in New Issue
Block a user