Skip to content

Commit 6273c5b

Browse files
authored
Add instruction enum and parser (#1)
* parse: add instruction enum and parser Add an enum of all (supported) ARM and RISC-V instructions and implement a parser from a text file of asm to the instruction enums. * **Instruction Enum**: Add `Instruction` enum in `src/instruction.rs` with all ARM and RISC-V instructions. * **Parser Implementation**: Implement `parse_asm` function in `src/main.rs` to parse asm text files into `Instruction` enums. * **Binary Translation**: Update `binary_translate` function in `src/main.rs` to use `parse_asm` for translation. * **Dependencies**: Add `strum` and `strum_macros` dependencies in `Cargo.toml` for enum parsing. * **Tests**: Add tests in `test/parse_asm.rs` to verify parsing functionality and in `test/binary_translate.rs` to verify translation functionality. * test: store testing binaries in separate folder * parse: fix deserialization to use strum
1 parent deceef4 commit 6273c5b

15 files changed

Lines changed: 236 additions & 4 deletions

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ version = "0.1.0"
44
edition = "2021"
55

66
[dependencies]
7+
strum = "0.21.0"
8+
strum_macros = "0.21.1"
File renamed without changes.

flake.nix

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
description = "A very basic flake";
3+
4+
inputs = {
5+
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
6+
};
7+
8+
9+
outputs = { self, nixpkgs }: let
10+
pkgs = import nixpkgs {
11+
system = "x86_64-linux";
12+
};
13+
in {
14+
devShells.x86_64-linux.default = pkgs.mkShell {
15+
# Use the same mkShell as documented above
16+
packages = with pkgs; [
17+
# TODO: @Anthony, you can change this to use Fenix if you would like
18+
rustup
19+
];
20+
};
21+
};
22+
}

src/instruction.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/// This file defines all the supported ARM and RISC-V instructions we support.
2+
/// We use `strum` to assist in serializing asm files to our [`Instruction`] enum.
3+
///
4+
/// We do not aim for completness of translating every possible instruction,
5+
/// but we do want to thoroughly test for correctness.
6+
use strum_macros::EnumString;
7+
8+
#[derive(Debug, EnumString)]
9+
pub enum Instruction {
10+
// RISC-V Instructions
11+
#[strum(serialize = "addi")]
12+
Addi,
13+
#[strum(serialize = "sd")]
14+
Sd,
15+
#[strum(serialize = "ld")]
16+
Ld,
17+
#[strum(serialize = "sw")]
18+
Sw,
19+
#[strum(serialize = "lw")]
20+
Lw,
21+
#[strum(serialize = "mv")]
22+
Mv,
23+
#[strum(serialize = "addw")]
24+
Addw,
25+
#[strum(serialize = "sext.w")]
26+
SextW,
27+
#[strum(serialize = "jr")]
28+
Jr,
29+
#[strum(serialize = "li")]
30+
Li,
31+
32+
// ARM Instructions
33+
#[strum(serialize = "add")]
34+
Add,
35+
#[strum(serialize = "sub")]
36+
Sub,
37+
#[strum(serialize = "mov")]
38+
Mov,
39+
#[strum(serialize = "ldr")]
40+
Ldr,
41+
#[strum(serialize = "str")]
42+
Str,
43+
#[strum(serialize = "b")]
44+
B,
45+
#[strum(serialize = "bl")]
46+
Bl,
47+
#[strum(serialize = "bx")]
48+
Bx,
49+
#[strum(serialize = "cmp")]
50+
Cmp,
51+
#[strum(serialize = "beq")]
52+
Beq,
53+
}
54+

src/main.rs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,42 @@
11
use std::fs;
2+
use std::str::FromStr;
3+
mod instruction;
4+
use instruction::Instruction;
25

3-
fn binary_translate(riscv_asm: &str) -> &str {
4-
"noop"
6+
/// Parse a text file into our enum.
7+
fn parse_asm(asm: &str) -> Vec<Instruction> {
8+
asm.lines()
9+
.filter_map(|line| {
10+
// TODO (Samir): Not sure that this will handle assembly labels
11+
// We probably need to construct a map for those to find the
12+
// original instruction they map to.
13+
let parts: Vec<&str> = line.split_whitespace().collect();
14+
if parts.is_empty() {
15+
None
16+
} else {
17+
Instruction::from_str(parts[0]).ok()
18+
}
19+
})
20+
.collect()
521
}
622

23+
/// Runs binary translation
24+
/// text file -> [`Instruction`] enum array -> text file
25+
fn binary_translate(riscv_asm: &str) -> String {
26+
let instructions = parse_asm(riscv_asm);
27+
instructions
28+
.into_iter()
29+
.map(|instr| format!("{:?}", instr))
30+
.collect::<Vec<String>>()
31+
.join("\n")
32+
}
33+
34+
// Samir: I am using main for testing, but it not needed since you can run
35+
// `cargo test` instead.
736
fn main() {
837
// Hard code the arguments for now.
9-
let path = "./test/hello_world.s";
10-
let output_path = "./test/hello_world_translated.s";
38+
let path = "../test/binaries/hello_world.s";
39+
let output_path = "../test/binaries/hello_world_translated.s";
1140
let riscv_asm = fs::read_to_string(path).expect("Unable to read file");
1241

1342
let translated_asm = binary_translate(&riscv_asm);
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)