-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from 0xPolygonHermez/fractasy_develop
Fractasy develop
- Loading branch information
Showing
9 changed files
with
674 additions
and
5 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(§ion.buffer, read_position) as u64, | ||
4 => read_u32_le(§ion.buffer, read_position) as u64, | ||
8 => read_u64_le(§ion.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), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() } | ||
} | ||
} |
Oops, something went wrong.