From 436cfcf83d1c9836d37622464fe879f3d0069b46 Mon Sep 17 00:00:00 2001 From: Lou Knauer Date: Fri, 23 Aug 2024 12:13:30 +0200 Subject: [PATCH] old stale changes --- rust/examples/Makefile | 4 +- rust/examples/grayscale.c | 172 ++++++++++++++++++++++++++++++++++++++ rust/src/cpu.rs | 2 +- rust/src/insts.rs | 9 +- rust/src/main.rs | 148 +++++++++++++++++++------------- rust/src/tbs.rs | 4 +- 6 files changed, 271 insertions(+), 68 deletions(-) create mode 100644 rust/examples/grayscale.c diff --git a/rust/examples/Makefile b/rust/examples/Makefile index 71b7d0b..fa97335 100644 --- a/rust/examples/Makefile +++ b/rust/examples/Makefile @@ -14,11 +14,11 @@ else endif %.elf: %.c - riscv64-elf-gcc -Wall -Werror -mabi=lp64 -march=rv64imac -g -O1 -static -o $@ $< + riscv64-elf-gcc -Wall -mabi=lp64 -march=rv64imac -g -O1 -static -o $@ $< .PHONY: all clean -all: hello-world.elf bubblesort.elf nqueens.elf +all: hello-world.elf bubblesort.elf nqueens.elf grayscale.elf clean: rm -rf ./*.elf ./*.dump diff --git a/rust/examples/grayscale.c b/rust/examples/grayscale.c new file mode 100644 index 0000000..faf2f50 --- /dev/null +++ b/rust/examples/grayscale.c @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include +#include + +static void die(const char msg[]) { + fprintf(stderr, "error(%s): %s\n", msg, strerror(errno)); + exit(EXIT_FAILURE); +} + +static inline uint8_t *encode_uint32(uint8_t *pos, uint32_t value) { + *(pos++) = value & 0xff; + *(pos++) = (value >> 8) & 0xff; + *(pos++) = (value >> 16) & 0xff; + *(pos++) = (value >> 24) & 0xff; + return pos; +} + +struct color_palette { + uint8_t R; + uint8_t G; + uint8_t B; + uint8_t reserved; +}; + +static void print_grayscale_bmp(const char *filepath, size_t N, size_t M, + const uint8_t image[N][M]) { + FILE *f = NULL; + if (strcmp(filepath, "-") == 0) { + f = stdout; + } else { + f = fopen(filepath, "w"); + if (!f) + die(filepath); + } + + uint8_t header[54]; + uint8_t *pos = &header[0]; + + /* BMP header */ + *(pos++) = 'B'; + *(pos++) = 'M'; + pos = encode_uint32(pos, sizeof(header) + + N * M * sizeof(uint8_t)); // BMP file size + pos = encode_uint32(pos, 0x0); // unused + pos = encode_uint32( + pos, + sizeof(header) + 256 * sizeof(struct color_palette)); // pixel data offset + + /* DIB header */ + pos = encode_uint32(pos, 40); // DIB header length + pos = encode_uint32(pos, N); // height + pos = encode_uint32(pos, M); // width + *(pos++) = 1; // color Planes + *(pos++) = 0; + *(pos++) = 8; // bits per Pixel + *(pos++) = 0; + pos = encode_uint32(pos, 0); // Compression + pos = encode_uint32(pos, N * M * sizeof(uint8_t)); // RAW data size + pos = encode_uint32(pos, 0); // horizontal print resolution + pos = encode_uint32(pos, 0); // vertical print resolution + pos = + encode_uint32(pos, 0); // number of colors (0 is the default, means 2**N) + pos = encode_uint32(pos, 0); // important colors + assert(pos - 1 == &header[sizeof(header) - 1]); + + if (fwrite(&header[0], sizeof(uint8_t), sizeof(header), f) != sizeof(header)) + die("fwrite failed"); + + /* The color map. */ + struct color_palette color_palette[256]; + for (size_t i = 0; i < 256; i++) { + color_palette[i] = (struct color_palette){.R = i, .G = i, .B = i}; + } + + if (fwrite(&color_palette[0], sizeof(struct color_palette), 256, f) != 256) + die("fwrite failed"); + + /* The pixel data. */ + if (fwrite(&image[0][0], sizeof(uint8_t), N * M, f) != N * M) + die("fwrite failed"); + + if (fflush(f) != 0) + die("fflush failed"); + + if (f != stdout && fclose(f) != 0) + die(filepath); +} + +static int sqrti(int x) { + if (x == 0 || x == 1) + return x; + + int i = 1, result = 1; + while (result <= x) { + i++; + result = i * i; + } + return i - 1; +} + +static void draw_circle(size_t radius, int center_x, int center_y, size_t N, + size_t M, uint8_t image[N][M], uint8_t circle_color) { + for (size_t i = 0; i < N; i++) { + for (size_t j = 0; j < M; j++) { + int x = ((int)i - (int)(N / 2)) + center_x; + int y = ((int)j - (int)(M / 2)) + center_y; + int distance = sqrti(x * x + y * y); + if (distance < radius) { + image[i][j] = circle_color; + } + } + } +} + +static void blur(size_t N, size_t M, const uint8_t image_src[N][M], + uint8_t image_dst[N][M]) { + for (size_t i = 1; i < N - 1; i++) { + for (size_t j = 1; j < M - 1; j++) { + uint64_t pixel = image_src[i - 1][j - 1] + image_src[i - 1][j - 0] + + image_src[i - 1][j + 1] + image_src[i - 0][j - 1] + + image_src[i - 0][j - 0] + image_src[i - 0][j + 1] + + image_src[i + 1][j - 1] + image_src[i + 1][j - 0] + + image_src[i + 1][j + 1]; + image_dst[i][j] = (uint8_t)(pixel / 9); + } + } +} + +__attribute__((noinline)) static void init(size_t N, size_t M, + uint8_t (*image)[M], uint8_t val) { + for (size_t i = 0; i < N; i++) + for (size_t j = 0; j < M; j++) + image[i][j] = val; +} + +int main() { + // fprintf(stderr, "debug: main started...\n"); + + size_t N = 500; + size_t M = 500; + uint8_t(*image)[M] = malloc(N * M * sizeof(uint8_t)); + + init(N, M, image, 0x00); + + // fprintf(stderr, "debug: image allocated...\n"); + // fprintf(stderr, "debug: image initialized...\n"); + +#if 1 + draw_circle(150, 100, 100, N, M, image, 0xff); + draw_circle(100, -50, -100, N, M, image, 0xb0); + draw_circle(200, 200, -100, N, M, image, 0x80); + draw_circle(100, -50, 100, N, M, image, 0x40); + draw_circle(50, 50, 200, N, M, image, 0xb0); + draw_circle(200, -250, -250, N, M, image, 0x80); + fprintf(stderr, "debug: circles drawn...\n"); + + uint8_t(*tmp_image)[M] = malloc(N * M * sizeof(uint8_t)); + for (size_t i = 0; i < 10; i++) { + blur(N, M, image, tmp_image); + blur(N, M, tmp_image, image); + } + fprintf(stderr, "debug: blured...\n"); + + print_grayscale_bmp("-", N, M, image); + fprintf(stderr, "debug: done!\n"); +#endif + return EXIT_SUCCESS; +} diff --git a/rust/src/cpu.rs b/rust/src/cpu.rs index 27055f5..6b48960 100644 --- a/rust/src/cpu.rs +++ b/rust/src/cpu.rs @@ -58,7 +58,7 @@ impl CPU { } /* TODO: There must be a better way... What address to use as TOS? */ - let top_of_stack = 0x10000u64 as usize; + let top_of_stack = MAX_ADDR - (MAX_ADDR >> 2); self.set_reg(REG_SP, top_of_stack as u64); if let Some(argv) = argv { /* diff --git a/rust/src/insts.rs b/rust/src/insts.rs index d38aa11..49b66a3 100644 --- a/rust/src/insts.rs +++ b/rust/src/insts.rs @@ -49,13 +49,17 @@ pub enum RoundingMode { #[derive(Debug, Clone)] pub enum Inst { Unknown, - NOP, + NOP, // RV does not actually have a NOP, but its still usefull as explicit entry. + + // Not even the non-privileged CSRs are implemented yet. + #[allow(dead_code)] + CtrlStatusReg { op: CSR, dst: Reg, src: Reg, csr: u16 }, + Load { dst: Reg, width: u8, base: Reg, offset: i32, signext: bool }, Store { src: Reg, width: u8, base: Reg, offset: i32 }, JumpAndLink { dst: Reg, offset: i32 }, JumpAndLinkReg { dst: Reg, base: Reg, offset: i32 }, Branch { pred: Predicate, src1: Reg, src2: Reg, offset: i32 }, - CtrlStatusReg { op: CSR, dst: Reg, src: Reg, csr: u16 }, ECall { _priv: u8 }, EBreak { _priv: u8 }, ALUImm { op: ALU, dst: Reg, src1: Reg, imm: u32 }, @@ -759,4 +763,3 @@ impl Inst { Inst::JumpAndLinkReg { dst: REG_ZR, base: REG_RA, offset: 0 }) } } - diff --git a/rust/src/main.rs b/rust/src/main.rs index e077537..20da747 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -1,17 +1,16 @@ -#![feature(fs_try_exists)] #![allow(clippy::just_underscores_and_digits)] #![allow(clippy::upper_case_acronyms)] -mod insts; mod cpu; mod dbg; +mod insts; mod syms; mod tbs; use std::io::Write; -use clap::Parser; use crate::insts::Inst; +use clap::Parser; #[derive(clap::Parser)] #[command(author, version, about)] @@ -34,13 +33,14 @@ struct Args { #[arg(short, long)] tb_stats: bool, - args: Vec + args: Vec, } fn dump_hottest_tbs(elf_file: &elf::ElfBytes<'_, elf::endian::AnyEndian>, jit: &tbs::JIT) { let _ = elf_file; const MIN_TB_FREQ: i64 = 5; - let mut tbs = jit.tbs + let mut tbs = jit + .tbs .values() .filter_map(|tb| { let freq = tb.exec_count.load(std::sync::atomic::Ordering::Relaxed); @@ -52,10 +52,17 @@ fn dump_hottest_tbs(elf_file: &elf::ElfBytes<'_, elf::endian::AnyEndian>, jit: & }) .collect::>(); tbs.sort_by(|(f1, _), (f2, _)| f2.cmp(f1)); - eprintln!("[simrv64i] JIT: TBs, #total={}, #freq-above-{}={}", - jit.tbs.len(), MIN_TB_FREQ, tbs.len()); + eprintln!( + "[simrv64i] JIT: TBs, #total={}, #freq-above-{}={}", + jit.tbs.len(), + MIN_TB_FREQ, + tbs.len() + ); for (i, (freq, tb)) in tbs.into_iter().take(25).enumerate() { - eprintln!("[simrv64i] JIT: Top-TB #{:08?}: {:#08x?} (freq={})", i, tb.start, freq); + eprintln!( + "[simrv64i] JIT: Top-TB #{:08?}: {:#08x?} (freq={})", + i, tb.start, freq + ); } } @@ -77,16 +84,18 @@ fn execute(args: &Args, elf_file: elf::ElfBytes<'_, elf::endian::AnyEndian>, _: dump_hottest_tbs(&elf_file, &jit); } std::process::exit(exitcode); - }, + } Err(e) => { - eprintln!("[simrv64i]: error: {:?}", e); + eprintln!("[simrv64i]: error(pc={:#08x?}): {:?}", cpu.pc, e); std::process::exit(1); } } } -fn dump_text_section(elf_file: elf::ElfBytes<'_, elf::endian::AnyEndian>, _: &Vec) - -> std::io::Result<()> { +fn dump_text_section( + elf_file: elf::ElfBytes<'_, elf::endian::AnyEndian>, + _: &Vec, +) -> std::io::Result<()> { let text_section = match elf_file.section_header_by_name(".text") { Ok(Some(hdr)) => hdr, Ok(None) | Err(_) => { @@ -107,11 +116,10 @@ fn dump_text_section(elf_file: elf::ElfBytes<'_, elf::endian::AnyEndian>, _: &Ve let mut offset: usize = 0; while offset + 2 < text_section.sh_size as usize { let addr = text_section.sh_addr as usize + offset; - let raw = - (bytes[offset] as u32) | - ((bytes[offset + 1] as u32) << 8) | - ((bytes[offset + 2] as u32) << 16) | - ((bytes[offset + 3] as u32) << 24); + let raw = (bytes[offset] as u32) + | ((bytes[offset + 1] as u32) << 8) + | ((bytes[offset + 2] as u32) << 16) + | ((bytes[offset + 3] as u32) << 24); let (inst, size) = match Inst::parse(raw) { Ok(res) => res, Err(_) => { @@ -124,16 +132,13 @@ fn dump_text_section(elf_file: elf::ElfBytes<'_, elf::endian::AnyEndian>, _: &Ve }; if size == 2 { - let raw = - (bytes[offset] as u32) | - ((bytes[offset + 1] as u32) << 8); + let raw = (bytes[offset] as u32) | ((bytes[offset + 1] as u32) << 8); write!(&mut stdout, "{:8x}:\t{:04x} \t", addr, raw)?; } else if size == 4 { - let raw = - (bytes[offset] as u32) | - ((bytes[offset + 1] as u32) << 8) | - ((bytes[offset + 2] as u32) << 16) | - ((bytes[offset + 3] as u32) << 24); + let raw = (bytes[offset] as u32) + | ((bytes[offset + 1] as u32) << 8) + | ((bytes[offset + 2] as u32) << 16) + | ((bytes[offset + 3] as u32) << 24); write!(&mut stdout, "{:8x}:\t{:08x} \t", addr, raw)?; } else { panic!() @@ -153,25 +158,28 @@ fn main() { let raw_file = match std::fs::read(path) { Ok(bytes) => bytes, Err(e) => { - eprintln!("[simrv64i]: error reading {:?}: {:?}", &args.file, e); + eprintln!("[simrv64i]: error reading {:?}: {}", &args.file, e); std::process::exit(1); } }; - let elf_file: elf::ElfBytes<'_, elf::endian::AnyEndian> = match - elf::ElfBytes::minimal_parse(raw_file.as_slice()) { - Ok(elf_file) => elf_file, - Err(e) => { - eprintln!("[simrv64i]: error parsing ELF file {:?}: {:?}", &args.file, e); - std::process::exit(1); - } - }; + let elf_file: elf::ElfBytes<'_, elf::endian::AnyEndian> = + match elf::ElfBytes::minimal_parse(raw_file.as_slice()) { + Ok(elf_file) => elf_file, + Err(e) => { + eprintln!("[simrv64i]: error parsing ELF file {:?}: {}", &args.file, e); + std::process::exit(1); + } + }; if elf_file.ehdr.class != elf::file::Class::ELF64 || elf_file.ehdr.e_type != elf::abi::ET_EXEC - || elf_file.ehdr.e_machine != elf::abi::EM_RISCV { - eprintln!("[simrv64i]: error processing ELF file {:?}: Not a RV64 executable", - &args.file); + || elf_file.ehdr.e_machine != elf::abi::EM_RISCV + { + eprintln!( + "[simrv64i]: error processing ELF file {:?}: Not a RV64 executable", + &args.file + ); std::process::exit(1); } @@ -191,31 +199,34 @@ mod test { use std::os::fd::FromRawFd; use std::path::PathBuf; - const JIT_ENABLED: Option<&str> = option_env!("JIT_ENABLED"); - fn run_example( - filename: &str, argv: Option>, - stdin: Option<&[u8]>) -> (String, i32) { + filename: &str, + argv: Option>, + stdin: Option<&[u8]>, + jit_enabled: bool, + ) -> (String, i32) { let mut filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR")); filepath.push(filename); - if !std::fs::try_exists(&filepath).unwrap() { - let cmd = format!("make -C {} {}", + if !filepath.exists() { + let cmd = format!( + "make -C {} {}", filepath.parent().unwrap().to_str().unwrap(), - filepath.file_name().unwrap().to_str().unwrap()); - assert_eq!(unsafe { - libc::system(cmd.as_ptr() as *const i8) - }, 0); + filepath.file_name().unwrap().to_str().unwrap() + ); + assert_eq!(unsafe { libc::system(cmd.as_ptr() as *const i8) }, 0); } let binary_file = std::fs::read(filepath).unwrap(); let elf_file = elf::ElfBytes::<'_, elf::endian::AnyEndian>::minimal_parse(&binary_file).unwrap(); - assert!(elf_file.ehdr.class == elf::file::Class::ELF64 - && elf_file.ehdr.e_type == elf::abi::ET_EXEC - && elf_file.ehdr.e_machine == elf::abi::EM_RISCV); + assert!( + elf_file.ehdr.class == elf::file::Class::ELF64 + && elf_file.ehdr.e_type == elf::abi::ET_EXEC + && elf_file.ehdr.e_machine == elf::abi::EM_RISCV + ); - let mut cpu = crate::cpu::CPU::new(JIT_ENABLED == Some("1")); + let mut cpu = crate::cpu::CPU::new(jit_enabled); /* Avoid that the guest closes stderr. */ let stderr_dupped = unsafe { libc::dup(2) }; @@ -228,12 +239,14 @@ mod test { * pipe in a parallel thread? */ let mut stdout_pipe: [i32; 2] = [-1, -1]; assert!(0 == unsafe { libc::pipe(stdout_pipe.as_mut_ptr()) }); - cpu.remapped_filenos.insert(/*stdout:*/ 1, stdout_pipe[1] as usize); + cpu.remapped_filenos + .insert(/*stdout:*/ 1, stdout_pipe[1] as usize); if let Some(stdin) = stdin { let mut stdin_pipe: [i32; 2] = [-1, -1]; assert!(0 == unsafe { libc::pipe(stdin_pipe.as_mut_ptr()) }); - cpu.remapped_filenos.insert(/*stdin:*/ 0, stdin_pipe[0] as usize); + cpu.remapped_filenos + .insert(/*stdin:*/ 0, stdin_pipe[0] as usize); /* If the input is larger than what the kernel is willing to buffer in * the kernel, then this will block and the test will never finish. @@ -247,7 +260,9 @@ mod test { let mut example_stdout_file = unsafe { std::fs::File::from_raw_fd(stdout_pipe[0]) }; let mut example_stdout = String::new(); - example_stdout_file.read_to_string(&mut example_stdout).unwrap(); + example_stdout_file + .read_to_string(&mut example_stdout) + .unwrap(); (example_stdout, exitcode) } @@ -255,17 +270,23 @@ mod test { #[test] fn example_hello_world() { let argv = vec!["hello-world.elf", "foo"]; - let (stdout, exitcode) = run_example("./examples/hello-world.elf", Some(argv), None); + let (stdout, exitcode) = run_example("./examples/hello-world.elf", Some(argv), None, false); assert_eq!(exitcode, 42); - assert_eq!(stdout.as_str(), - "Hello, World! (argc=2)\nargv[0] = 'hello-world.elf'\nargv[1] = 'foo'\n"); + assert_eq!( + stdout.as_str(), + "Hello, World! (argc=2)\nargv[0] = 'hello-world.elf'\nargv[1] = 'foo'\n" + ); } #[test] fn example_bubblesort() { let input = "8\n3\n5\n6\n9\n1\n4\n2\n7\n"; let (stdout, exitcode) = run_example( - "./examples/bubblesort.elf", None, Some(input.as_bytes())); + "./examples/bubblesort.elf", + None, + Some(input.as_bytes()), + false, + ); assert_eq!(exitcode, 0); assert_eq!(stdout.as_str(), "1\n2\n3\n4\n5\n6\n7\n8\n9\n"); } @@ -273,9 +294,16 @@ mod test { #[test] fn example_nqueens() { let argv = vec!["nqueens.elf", "8"]; - let (stdout, exitcode) = run_example("./examples/nqueens.elf", Some(argv), None); + let (stdout, exitcode) = run_example("./examples/nqueens.elf", Some(argv), None, false); assert_eq!(exitcode, 0); assert_eq!(stdout.as_str(), "#solutions: 92 (grid_size=8)\n"); } -} + #[test] + fn example_nqueens_jitted() { + let argv = vec!["nqueens.elf", "8"]; + let (stdout, exitcode) = run_example("./examples/nqueens.elf", Some(argv), None, true); + assert_eq!(exitcode, 0); + assert_eq!(stdout.as_str(), "#solutions: 92 (grid_size=8)\n"); + } +} diff --git a/rust/src/tbs.rs b/rust/src/tbs.rs index 7435cb4..0ab0a35 100644 --- a/rust/src/tbs.rs +++ b/rust/src/tbs.rs @@ -1,6 +1,6 @@ use crate::insts::*; -pub const TB_KICK_IN_JIT: i64 = 5_000; +pub const TB_KICK_IN_JIT: i64 = 1_000; #[allow(dead_code)] pub struct TranslationBlock { @@ -55,7 +55,7 @@ impl JIT { for tb in self.tbs.values_mut().filter(|tb| !tb.jit_failed && tb.jit_fn.is_none() && - tb.exec_count.load(std::sync::atomic::Ordering::Relaxed) > 1_000) { + tb.exec_count.load(std::sync::atomic::Ordering::Relaxed) > 100) { // eprintln!("[simrv64i] JIT: TB candidate: {:#08x} (freq={})", // tb.start, tb.exec_count.load(std::sync::atomic::Ordering::Relaxed));