Skip to content

Commit

Permalink
Merge pull request #13 from 0xPolygonHermez/fractasy_develop
Browse files Browse the repository at this point in the history
Integrate riscv2zisk
  • Loading branch information
fractasy authored Jul 22, 2024
2 parents 68a2b62 + 3613e6d commit b155d7e
Show file tree
Hide file tree
Showing 19 changed files with 3,621 additions and 5 deletions.
6 changes: 3 additions & 3 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ runs:
~/.cargo/git/db/
target/
~/.rustup/
key: rust-nightly-2024-04-17-${{ hashFiles('**/Cargo.toml') }}
restore-keys: rust-nightly-2024-04-17-
key: rust-nightly-2024-07-21-${{ hashFiles('**/Cargo.toml') }}
restore-keys: rust-nightly-2024-07-21-

- name: Setup toolchain
id: rustc-toolchain
shell: bash
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain nightly-2024-04-17 -y
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain nightly-2024-07-21 -y
4 changes: 2 additions & 2 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: check
toolchain: nightly-2024-04-17
toolchain: nightly-2024-07-21
args: --all-targets --all-features

- name: Run cargo test
uses: actions-rs/cargo@v1
with:
command: test
toolchain: nightly-2024-04-17
toolchain: nightly-2024-07-21
args: --release
env:
RUSTFLAGS: -Copt-level=3 -Cdebug-assertions -Coverflow-checks=y -Cdebuginfo=0 -C target-cpu=native
Expand Down
16 changes: 16 additions & 0 deletions Cargo.lock

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

12 changes: 12 additions & 0 deletions riscv/riscv2zisk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,16 @@ name = "riscv2zisk"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
elf = "0.7.4"
json = "0.12.4"

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

[[bin]]
name = "riscv2zisk"
path = "src/bin/riscv2zisk.rs"
35 changes: 35 additions & 0 deletions riscv/riscv2zisk/src/bin/riscv2zisk.rs
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);
}
62 changes: 62 additions & 0 deletions riscv/riscv2zisk/src/elf2rom.rs
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(&section_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(())
}
40 changes: 40 additions & 0 deletions riscv/riscv2zisk/src/lib.rs
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::*;
29 changes: 29 additions & 0 deletions riscv/riscv2zisk/src/riscv2zisk.rs
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)
}
}
129 changes: 129 additions & 0 deletions riscv/riscv2zisk/src/riscv_inst.rs
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
}
}
Loading

0 comments on commit b155d7e

Please sign in to comment.