-
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 #13 from 0xPolygonHermez/fractasy_develop
Integrate riscv2zisk
- Loading branch information
Showing
19 changed files
with
3,621 additions
and
5 deletions.
There are no files selected for viewing
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
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
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
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,35 @@ | ||
use riscv2zisk::Riscv2zisk; | ||
use std::{env, process}; | ||
|
||
fn main() { | ||
println!("riscv2zisk converts an ELF RISCV file into a ZISK ASM file"); | ||
|
||
// Get program arguments | ||
let args: Vec<String> = env::args().collect(); | ||
|
||
// Check program arguments length | ||
if args.len() != 3 { | ||
eprintln!("Error parsing arguments: number of arguments should be 2. Usage: riscv2zisk <elf_riscv_file> <zisk_asm_file>"); | ||
process::exit(1); | ||
} | ||
|
||
// Get the 2 input parameters: ELF (RISCV) file name (input data) and ZisK file name (output | ||
// data) | ||
let elf_file = args[1].clone(); | ||
let zisk_file = args[2].clone(); | ||
|
||
println!("ELF file: {elf_file}"); | ||
println!("ZISK file: {zisk_file}"); | ||
|
||
// Create an instance of the program converter | ||
let rv2zk = Riscv2zisk::new(elf_file, zisk_file); | ||
|
||
// Convert program | ||
if let Err(e) = rv2zk.runfile() { | ||
println!("Application error: {e}"); | ||
process::exit(1); | ||
} | ||
|
||
// 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 |
---|---|---|
@@ -0,0 +1,62 @@ | ||
//use core::num; | ||
use crate::{ | ||
zv2zisk::{add_entry_exit_jmp, add_zisk_code, add_zisk_init_data}, | ||
RoData, ZiskRom, RAM_ADDR, RAM_SIZE, ROM_ENTRY, | ||
}; | ||
use elf::{ | ||
abi::{SHF_EXECINSTR, SHF_WRITE, SHT_PROGBITS}, | ||
endian::AnyEndian, | ||
ElfBytes, | ||
}; | ||
use std::error::Error; | ||
|
||
/// Executes the file conversion process | ||
pub fn elf2rom(elf_file: String) -> Result<ZiskRom, Box<dyn Error>> { | ||
let path = std::path::PathBuf::from(elf_file.clone()); | ||
let file_data = std::fs::read(path).expect("Could not read ELF file"); | ||
let slice = file_data.as_slice(); | ||
let file = ElfBytes::<AnyEndian>::minimal_parse(slice).expect("Open test1"); | ||
//println!("file.section_headers={}", file.section_headers()) | ||
let mut rom: ZiskRom = ZiskRom { next_init_inst_addr: ROM_ENTRY, ..Default::default() }; | ||
if let Some(section_headers) = file.section_headers().as_ref() { | ||
//let number_of_sections = section_headers.len(); | ||
//println!("number of sections={}", number_of_sections); | ||
for section_header in section_headers.iter() { | ||
//println!("type={}", section_header.sh_type); | ||
//println!("flags={}", section_header.sh_flags); | ||
if section_header.sh_type == SHT_PROGBITS { | ||
//println!("progbits"); | ||
let (data_u8, _compression_header) = file.section_data(§ion_header)?; | ||
let mut data: Vec<u8> = data_u8.to_vec(); | ||
while (data.len()) % 4 != 0 { | ||
data.pop(); | ||
} | ||
let addr = section_header.sh_addr; | ||
//println!("addr={}", addr); | ||
if (section_header.sh_flags & (SHF_EXECINSTR as u64)) != 0 { | ||
add_zisk_code(&mut rom, addr, &data); | ||
} | ||
if (section_header.sh_flags & (SHF_WRITE as u64)) != 0 && | ||
addr >= RAM_ADDR && | ||
(addr + data.len() as u64) <= (RAM_ADDR + RAM_SIZE) | ||
{ | ||
add_zisk_init_data(&mut rom, addr, &data); | ||
} else { | ||
//let mut ro_data = RoData::new(addr, data.len(), data); | ||
rom.ro_data.push(RoData::new(addr, data.len(), data)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
add_entry_exit_jmp(&mut rom, file.ehdr.e_entry); | ||
|
||
Ok(rom) | ||
} | ||
|
||
/// Executes the file conversion process, and saves result into a file | ||
pub fn elf2romfile(elf_file: String, rom_file: String) -> Result<(), Box<dyn Error>> { | ||
let rom = elf2rom(elf_file)?; | ||
rom.save_to_file(&rom_file); | ||
Ok(()) | ||
} |
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,41 @@ | ||
/*pub fn add(left: usize, right: usize) -> usize { | ||
left + right | ||
} | ||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
#[test] | ||
fn it_works() { | ||
let result = add(2, 2); | ||
assert_eq!(result, 4); | ||
} | ||
}*/ | ||
|
||
mod riscv2zisk; | ||
pub use riscv2zisk::*; | ||
mod elf2rom; | ||
pub use elf2rom::*; | ||
mod zisk_rom; | ||
pub use zisk_rom::*; | ||
mod riscv_inst; | ||
pub use riscv_inst::*; | ||
mod riscv_rvd; | ||
pub use riscv_rvd::*; | ||
mod riscv_interpreter; | ||
pub use riscv_interpreter::*; | ||
mod zv2zisk; | ||
pub use zv2zisk::*; | ||
mod zisk_inst; | ||
pub use zisk_inst::*; | ||
mod zisk_inst_builder; | ||
pub use zisk_inst_builder::*; | ||
mod zisk_definitions; | ||
pub use zisk_definitions::*; | ||
mod zisk_operation; | ||
pub use zisk_operation::*; | ||
mod zisk_operations; | ||
pub use zisk_operations::*; | ||
mod utils; | ||
pub use utils::*; |
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,29 @@ | ||
use crate::{elf2rom, elf2romfile, ZiskRom}; | ||
use std::error::Error; | ||
|
||
/// RISCV-to-ZisK struct containing the input ELF RISCV file name and the output ZISK ASM file name | ||
pub struct Riscv2zisk { | ||
/// ELF RISC-V file name (input) | ||
pub elf_file: String, | ||
/// JSON ZISK file name (output) | ||
pub zisk_file: String, | ||
} | ||
|
||
impl Riscv2zisk { | ||
/// Creates a new Riscv2zisk struct with the provided input and output file names | ||
pub fn new(elf_file: String, zisk_file: String) -> Riscv2zisk { | ||
Riscv2zisk { elf_file, zisk_file } | ||
} | ||
|
||
/// Executes the file conversion process by calling elf2romfile() | ||
pub fn runfile(&self) -> Result<(), Box<dyn Error>> { | ||
elf2romfile(self.elf_file.clone(), self.zisk_file.clone())?; | ||
Ok(()) | ||
} | ||
|
||
/// Executes the file conversion process by calling elf2rom() | ||
pub fn run(&self) -> Result<ZiskRom, Box<dyn Error>> { | ||
let rom = elf2rom(self.elf_file.clone())?; | ||
Ok(rom) | ||
} | ||
} |
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 @@ | ||
/// Contains RISCV instruction data, split by functionality | ||
/// RISC-V comprises of a base user-level 32-bit integer instruction set. Called RV32I, it includes | ||
/// 47 instructions, which can be grouped into six types: R-type: register-register | ||
/// I-type: short immediates and loads | ||
/// S-type: stores | ||
/// B-type: conditional branches, a variation of S-type | ||
/// U-type: long immediates | ||
/// J-type: unconditional jumps, a variation of U-type | ||
/// | ||
/// RV32I instruction formats showing immediate variants: | ||
/// | ||
/// 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 | ||
/// | funct7 | rs2 | rs1 | funct3 | rd | opcode | R-type | ||
/// | imm[11:0] | rs1 | funct3 | rd | opcode | I-type | ||
/// | imm[11:5] | rs2 | rs1 | funct3 | imm[4:0] | opcode | S-type | ||
/// |12| imm[10:5] | rs2 | rs1 | funct3 |imm[4:1] |11| opcode | B-type | ||
/// | imm[31:12] | rd | opcode | U-type | ||
/// |20| imm[10:1] |11| imm[19:12] | rd | opcode | J-type | ||
/// | ||
/// RV32I has x0 register hardwired to constant 0, plus x1-x31 general purpose registers. | ||
/// All registers are 32 bits wide but in RV64I they become 64 bits wide. | ||
/// RV32I is a load-store architecture. This means that only load and store instructions access | ||
/// memory; arithmetic operations use only the registers. User space is 32-bit byte addressable and | ||
/// little endian. | ||
/// | ||
/// Correspondingly, RV64I is for 64-bit address space and RV128I is for 128-bit address space. The | ||
/// need for RV128I is debatable and its specification is evolving. We also have RV32E for embedded | ||
/// systems. RV32E has only 16 32-bit registers and makes the counters of RV32I optional. | ||
/// | ||
/// See https://devopedia.org/risc-v-instruction-sets | ||
pub struct RiscvInstruction { | ||
pub rvinst: u32, | ||
pub t: String, | ||
pub funct3: u32, | ||
pub funct5: u32, | ||
pub funct7: u32, | ||
pub rd: u32, | ||
pub rs1: u32, | ||
pub rs2: u32, | ||
pub imm: i32, | ||
pub imme: u32, | ||
pub inst: String, | ||
pub aq: u32, | ||
pub rl: u32, | ||
pub csr: u32, | ||
pub pred: u32, | ||
pub succ: u32, | ||
} | ||
|
||
/// Default constructor for RiscvInstruction structure | ||
impl Default for RiscvInstruction { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
impl RiscvInstruction { | ||
/// RISCV instruction instance constructor, setting all values to zero | ||
pub fn new() -> RiscvInstruction { | ||
RiscvInstruction { | ||
rvinst: 0, | ||
t: String::new(), | ||
funct3: 0, | ||
funct5: 0, | ||
funct7: 0, | ||
rd: 0, | ||
rs1: 0, | ||
rs2: 0, | ||
imm: 0, | ||
imme: 0, | ||
inst: String::new(), | ||
aq: 0, | ||
rl: 0, | ||
csr: 0, | ||
pred: 0, | ||
succ: 0, | ||
} | ||
} | ||
|
||
/// Creates a human-readable string containing RISCV data fields that are non-zero | ||
pub fn to_text(&self) -> String { | ||
let mut s = String::new(); | ||
s += &("t=".to_string() + &self.t); | ||
s += &(" inst=".to_string() + &self.inst); | ||
if self.rvinst != 0 { | ||
s += &(" rvinst=".to_string() + &self.rvinst.to_string()); | ||
} | ||
if self.funct3 != 0 { | ||
s += &(" funct3=".to_string() + &self.funct3.to_string()); | ||
} | ||
if self.funct5 != 0 { | ||
s += &(" funct5=".to_string() + &self.funct5.to_string()); | ||
} | ||
if self.funct7 != 0 { | ||
s += &(" funct7=".to_string() + &self.funct7.to_string()); | ||
} | ||
if self.rd != 0 { | ||
s += &(" rd=".to_string() + &self.rd.to_string()); | ||
} | ||
if self.rs1 != 0 { | ||
s += &(" rs1=".to_string() + &self.rs1.to_string()); | ||
} | ||
if self.rs2 != 0 { | ||
s += &(" rs2=".to_string() + &self.rs2.to_string()); | ||
} | ||
if self.imm != 0 { | ||
s += &(" imm=".to_string() + &self.imm.to_string()); | ||
} | ||
if self.imme != 0 { | ||
s += &(" imme=".to_string() + &self.imme.to_string()); | ||
} | ||
if self.aq != 0 { | ||
s += &(" aq=".to_string() + &self.aq.to_string()); | ||
} | ||
if self.rl != 0 { | ||
s += &(" rl=".to_string() + &self.rl.to_string()); | ||
} | ||
if self.csr != 0 { | ||
s += &(" csr=".to_string() + &self.csr.to_string()); | ||
} | ||
if self.pred != 0 { | ||
s += &(" pred=".to_string() + &self.pred.to_string()); | ||
} | ||
if self.succ != 0 { | ||
s += &(" succ=".to_string() + &self.succ.to_string()); | ||
} | ||
s | ||
} | ||
} |
Oops, something went wrong.