Skip to content

Commit

Permalink
Merge pull request #14 from 0xPolygonHermez/fractasy_develop
Browse files Browse the repository at this point in the history
Fractasy develop
  • Loading branch information
fractasy authored Jul 22, 2024
2 parents b155d7e + f21c517 commit fc98b11
Show file tree
Hide file tree
Showing 9 changed files with 674 additions and 5 deletions.
11 changes: 7 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion simulator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
[package]
name = "zisk-simulator"
name = "zisksim"
version = "0.1.0"
edition = "2021"

[dependencies]
riscv2zisk = {path="../riscv/riscv2zisk"}

[lib]
name = "zisksim"
path = "src/lib.rs"

[[bin]]
name = "zisksim"
path = "src/bin/zisksim.rs"
123 changes: 123 additions & 0 deletions simulator/src/bin/zisksim.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use riscv2zisk::Riscv2zisk;
use std::{
env, fs,
fs::metadata,
path::{Path, PathBuf},
process,
};
use zisksim::{Sim, SimOptions};

fn _list_files(vec: &mut Vec<PathBuf>, path: &Path) {
if metadata(path).unwrap().is_dir() {
let paths = fs::read_dir(path).unwrap();
for path_result in paths {
let full_path = path_result.unwrap().path();
if metadata(&full_path).unwrap().is_dir() {
_list_files(vec, &full_path);
} else {
vec.push(full_path);
}
}
}
}

fn list_files(path: &Path) -> Vec<PathBuf> {
let mut vec = Vec::new();
_list_files(&mut vec, path);
vec
}

fn main() {
//println!("zisk_tester converts an ELF RISCV file into a ZISK ASM program, simulates it, and
// copies the output to console");

// Get program arguments
let args: Vec<String> = env::args().collect();

// Check program arguments length
if args.len() != 2 {
eprintln!("Error parsing arguments: number of arguments should be 1. Usage: zisk_tester <elf_riscv_file>");
process::exit(1);
}

let argument = &args[1];
let mut multiple_files = false;
let md = metadata(argument).unwrap();
let mut elf_files: Vec<String> = Vec::new();
if md.is_file() {
elf_files.push(argument.clone());
} else if md.is_dir() {
multiple_files = true;
let path = Path::new(argument);
let files = list_files(path);
for file in files {
let file_name = file.display().to_string();
if file_name.contains("dut") && file_name.ends_with(".elf") {
elf_files.push(file_name.to_string().clone());
println!("found DUT ELF file: {}", file_name);
}
}
}

let elf_files_len = elf_files.len();

if multiple_files {
println!("Going to process {} ELF files", elf_files_len);
}

//const FIRST_ELF_FILE: u64 = 0;

for (elf_file_counter, elf_file) in elf_files.into_iter().enumerate() {
// Get the input parameters: ELF (RISCV) file name (input data)
//let elf_file = args[1].clone();
let zisk_file = String::new();

if multiple_files {
println!("ELF file {}/{}: {}", elf_file_counter, elf_files_len, elf_file);
}
/*if (FIRST_ELF_FILE > 0) && (elf_file_counter < FIRST_ELF_FILE) {
println!("Skipping file {}", elf_file);
continue;
}*/

// Create an instance of the program converter
let rv2zk = Riscv2zisk::new(elf_file, zisk_file);

// Convert program to rom
let result = rv2zk.run();
if result.is_err() {
println!("Application error: {}", result.err().unwrap());
process::exit(1);
}
let rom = result.unwrap();

// Create an empty input
let input: Vec<u8> = Vec::new();

// Create a simulator instance with this rom and input
let mut sim = Sim::new(rom, input);

// Create a simulator options instance with the default values
let sim_options = SimOptions::new();

// Run the simulations
sim.run(sim_options);
if !sim.terminated() {
println!("Simulation did not complete");
process::exit(1);
}

if !multiple_files {
// Get the simulation outpus as a u32 vector
let output = sim.get_output_32();

// Log the output in console
for o in &output {
println!("{:08x}", o);
}
}
}

// Return successfully
process::exit(0);
}
10 changes: 10 additions & 0 deletions simulator/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
mod mem;
pub use mem::*;
mod mem_section;
pub use mem_section::*;

mod sim;
pub use sim::*;
mod sim_context;
pub use sim_context::*;
mod sim_options;
pub use sim_options::*;
129 changes: 129 additions & 0 deletions simulator/src/mem.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
use crate::MemSection;
use riscv2zisk::{read_u16_le, read_u32_le, read_u64_le, write_u16_le, write_u32_le, write_u64_le};

/// Memory structure, containing several read sections and one single write section
pub struct Mem {
pub read_sections: Vec<MemSection>,
pub write_section: MemSection,
}

/// Default constructor for Mem structure
impl Default for Mem {
fn default() -> Self {
Self::new()
}
}

/// Memory structure implementation
impl Mem {
/// Memory structue constructor
pub fn new() -> Mem {
Mem { read_sections: Vec::new(), write_section: MemSection::new() }
}

/// Adds a read section to the memory structure
pub fn add_read_section(&mut self, start: u64, buffer: &[u8]) {
let mem_section =
MemSection { start, end: start + buffer.len() as u64, buffer: buffer.to_owned() };
self.read_sections.push(mem_section);
}

/// Adds a write section to the memory structure, which cannot be written twice
pub fn add_write_section(&mut self, start: u64, size: u64) {
//println!("Mem::add_write_section() start={} size={}", start, size);

// Check the start address is not zero
if start == 0 {
panic!("add_write_section() got invalid start={}", start);
}

// Check the write section address has been set before this call
if self.write_section.start != 0 {
panic!(
"add_write_section() only one write section allowed, write_section.start={}",
self.write_section.start
);
}

// Create an empty vector of size bytes
let mem: Vec<u8> = vec![0; size as usize];

// Store as the write section
self.write_section.start = start;
self.write_section.end = start + mem.len() as u64;
self.write_section.buffer = mem;
}

/// Read a u64 value from the memory read sections, based on the provided address and width
pub fn read(&self, addr: u64, width: u64) -> u64 {
// First try to read in the write section
if (addr >= self.write_section.start) && (addr <= (self.write_section.end - width)) {
// Calculate the read position
let read_position: usize = (addr - self.write_section.start) as usize;

// Read the requested data based on the provided width
let value: u64 = match width {
1 => self.write_section.buffer[read_position] as u64,
2 => read_u16_le(&self.write_section.buffer, read_position) as u64,
4 => read_u32_le(&self.write_section.buffer, read_position) as u64,
8 => read_u64_le(&self.write_section.buffer, read_position),
_ => panic!("Mem::read() invalid width={}", width),
};

//println!("Mem::read() addr={:x} width={} value={:x}={}", addr, width, value, value);
return value;
}

// For all read sections
for i in 0..self.read_sections.len() {
// Get a section reference
let section = &self.read_sections[i];

// If the provided address and size are between this section address range, then we
// found the section
if (addr >= section.start) && (addr <= (section.end - width)) {
// Calculate the read position
let read_position: usize = (addr - section.start) as usize;

// Read the requested data based on the provided width
let value: u64 = match width {
1 => section.buffer[read_position] as u64,
2 => read_u16_le(&section.buffer, read_position) as u64,
4 => read_u32_le(&section.buffer, read_position) as u64,
8 => read_u64_le(&section.buffer, read_position),
_ => panic!("Mem::read() invalid width={}", width),
};

//println!("Mem::read() addr={:x} width={} value={:x}={}", addr, width, value,
// value);
return value;
}
}
panic!("Read out of Range: 0x{:08}", addr);
}

/// Write a u64 value to the memory write section, based on the provided address and width
pub fn write(&mut self, addr: u64, val: u64, width: u64) {
//println!("Mem::write() addr={:x} width={} value={:x}={}", addr, width, val, val);

// Get a reference to the write section
let section = &mut self.write_section;

// Check that the address and width fall into this section address range
if (addr < section.start) || ((addr + width) > section.end) {
panic!("Mem::write() invalid addr={}", addr);
}

// Calculate the write position
let write_position: usize = (addr - section.start) as usize;

// Write the value based on the provided width
match width {
1 => section.buffer[write_position] = (val & 0xFF) as u8,
2 => write_u16_le(&mut section.buffer, write_position, (val & 0xFFFF) as u16),
4 => write_u32_le(&mut section.buffer, write_position, (val & 0xFFFFFFFF) as u32),
8 => write_u64_le(&mut section.buffer, write_position, val),
_ => panic!("Mem::write() invalid width={}", width),
}
}
}
21 changes: 21 additions & 0 deletions simulator/src/mem_section.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/// Memory section data, including a buffer vector, and start and end addresses
pub struct MemSection {
pub start: u64,
pub end: u64,
pub buffer: Vec<u8>,
}

/// Default constructor for MemSection structure
impl Default for MemSection {
fn default() -> Self {
Self::new()
}
}

/// Memory section structure implementation
impl MemSection {
/// Memory section constructor
pub fn new() -> MemSection {
MemSection { start: 0, end: 0, buffer: Vec::new() }
}
}
Loading

0 comments on commit fc98b11

Please sign in to comment.