From f77e8988e221660672046485b9150fa275821455 Mon Sep 17 00:00:00 2001 From: Samir Rashid Date: Sat, 8 Feb 2025 20:46:41 -0800 Subject: [PATCH 1/5] instruction: split arm, riscv opcodes and add registers --- src/instruction.rs | 220 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 199 insertions(+), 21 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index 564e52a..9e36b3c 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -3,17 +3,31 @@ /// /// We do not aim for completness of translating every possible instruction, /// but we do want to thoroughly test for correctness. +/// +/// Some relevant references for making enums of instructions +/// https://github.com/lmcad-unicamp/riscv-sbt/blob/93bd48525362d00c6a2d7b320dc9cd9e62bc8fa9/sbt/Instruction.h#L62 +/// https://github.com/nbdd0121/r2vm/blob/5118be6b9e757c6fef2f019385873f403c23c548/lib/riscv/src/op.rs#L30 use strum_macros::EnumString; +/// RISC-V Instructions +/// +/// To make a function call in RISC-V you use the `jal` (jump and link) +/// instruction. This would require us ensure that we translate the RISC-V +/// calling convention into ARM. (`https://riscv.org/wp-content/uploads/2024/12/riscv-calling.pdf) #[derive(Debug, EnumString)] -pub enum Instruction { - // RISC-V Instructions +pub enum RiscVInstruction { #[strum(serialize = "addi")] - Addi, + Addi { + dest: RiscVRegister, + src: RiscVRegister, + imm: i32, + }, #[strum(serialize = "sd")] Sd, #[strum(serialize = "ld")] Ld, + #[strum(serialize = "lw")] + Lw, #[strum(serialize = "sw")] Sw, #[strum(serialize = "lw")] @@ -28,27 +42,191 @@ pub enum Instruction { Jr, #[strum(serialize = "li")] Li, +} - // ARM Instructions +/// ARM Instructions +/// `https://iitd-plos.github.io/col718/ref/arm-instructionset.pdf#page=3` +#[derive(Debug, EnumString)] +pub enum ArmInstruction { + /// ADC Add with carry + /// + /// `Rd := Rn + Op2 + Carry` + #[strum(serialize = "adc")] + Adc, + /// ADD Add Rd := Rn + Op2 #[strum(serialize = "add")] - Add, - #[strum(serialize = "sub")] - Sub, - #[strum(serialize = "mov")] - Mov, - #[strum(serialize = "ldr")] - Ldr, - #[strum(serialize = "str")] - Str, + Add { + dest: ArmRegister, + arg1: ArmRegister, + arg2: ArmRegister, + }, + /// AND AND Rd := Rn AND Op2 + #[strum(serialize = "and")] + And, + /// B Branch R15 := address #[strum(serialize = "b")] B, - #[strum(serialize = "bl")] - Bl, - #[strum(serialize = "bx")] - Bx, - #[strum(serialize = "cmp")] - Cmp, - #[strum(serialize = "beq")] - Beq, } +/// RISC-V Registers +/// https://msyksphinz-self.github.io/riscv-isadoc/html/regs.html +#[derive(Debug, EnumString)] +pub enum RiscVRegister { + /// This is for arguments to opcodes which have an offset + /// I'm not sure how to make strum happy, so this doesn't auto parse. + #[strum(disabled)] + Offset { + register: Box, + offset: usize, + }, + #[strum(serialize = "x0")] + /// Hard-wired zero + X0, + #[strum(serialize = "ra")] + /// Return address + RA, + #[strum(serialize = "sp")] + /// Stack pointer + SP, + #[strum(serialize = "gp")] + /// Global pointer + GP, + #[strum(serialize = "tp")] + /// Thread pointer + TP, + #[strum(serialize = "t0")] + /// Temporary/alternate link register + T0, + #[strum(serialize = "t1")] + /// Temporaries + T1, + #[strum(serialize = "t2")] + /// Temporaries + T2, + #[strum(serialize = "s0", serialize = "fp")] + /// Saved register/frame pointer + S0FP, + #[strum(serialize = "s1")] + /// Saved registers + S1, + #[strum(serialize = "a0")] + /// Function arguments/return values + A0, + #[strum(serialize = "a1")] + /// Function arguments/return values + A1, + #[strum(serialize = "a2")] + /// Function arguments + A2, + #[strum(serialize = "a3")] + /// Function arguments + A3, + #[strum(serialize = "a4")] + /// Function arguments + A4, + #[strum(serialize = "a5")] + /// Function arguments + A5, + #[strum(serialize = "a6")] + /// Function arguments + A6, + #[strum(serialize = "a7")] + /// Function arguments + A7, + #[strum(serialize = "s2")] + /// Saved registers + S2, + #[strum(serialize = "s3")] + /// Saved registers + S3, + #[strum(serialize = "s4")] + /// Saved registers + S4, + #[strum(serialize = "s5")] + /// Saved registers + S5, + #[strum(serialize = "s6")] + /// Saved registers + S6, + #[strum(serialize = "s7")] + /// Saved registers + S7, + #[strum(serialize = "s8")] + /// Saved registers + S8, + #[strum(serialize = "s9")] + /// Saved registers + S9, + #[strum(serialize = "s10")] + /// Saved registers + S10, + #[strum(serialize = "s11")] + /// Saved registers + S11, + #[strum(serialize = "t3")] + /// Temporaries + T3, + #[strum(serialize = "t4")] + /// Temporaries + T4, + #[strum(serialize = "t5")] + /// Temporaries + T5, + #[strum(serialize = "t6")] + /// Temporaries + T6, +} + +/// ARM Registers +/// https://developer.arm.com/documentation/dui0056/d/using-the-procedure-call-standard/register-roles-and-names/register-names +#[derive(Debug, EnumString)] +pub enum ArmRegister { + #[strum(serialize = "pc")] + /// Program counter. + Pc, + #[strum(serialize = "lr")] + /// Link register. + Lr, + #[strum(serialize = "sp")] + /// Stack pointer. + Sp, + #[strum(serialize = "ip")] + /// Intra-procedure-call scratch register. + Ip, + #[strum(serialize = "v8")] + /// ARM-state variable register 8. + V8, + #[strum(serialize = "sl")] + /// ARM-state variable register 7. Stack limit pointer in stack-checked variants. + Sl, + #[strum(serialize = "sb")] + /// ARM-state variable register 6. Static base in RWPI variants. + Sb, + #[strum(serialize = "v5")] + /// ARM-state variable register 5. + V5, + #[strum(serialize = "v4")] + /// Variable register 4. + V4, + #[strum(serialize = "v3")] + /// Variable register 3. + V3, + #[strum(serialize = "v2")] + /// Variable register 2. + V2, + #[strum(serialize = "v1")] + /// Variable register 1. + V1, + #[strum(serialize = "a4")] + /// Argument/result/scratch register 4. + A4, + #[strum(serialize = "a3")] + /// Argument/result/scratch register 3. + A3, + #[strum(serialize = "a2")] + /// Argument/result/scratch register 2. + A2, + #[strum(serialize = "a1")] + /// Argument/result/scratch register 1. + A1, +} From 98fe35ea398601562df7db50bd52f9b291d82112 Mon Sep 17 00:00:00 2001 From: Samir Rashid Date: Sat, 8 Feb 2025 20:47:25 -0800 Subject: [PATCH 2/5] translate: add minimal riscv translation map --- src/main.rs | 7 ++++--- src/translate.rs | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 src/translate.rs diff --git a/src/main.rs b/src/main.rs index 87c6374..81ef70b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,11 @@ use std::fs; use std::str::FromStr; mod instruction; -use instruction::Instruction; +pub mod translate; +use instruction::RiscVInstruction; /// Parse a text file into our enum. -fn parse_asm(asm: &str) -> Vec { +fn parse_asm(asm: &str) -> Vec { asm.lines() .filter_map(|line| { // TODO (Samir): Not sure that this will handle assembly labels @@ -14,7 +15,7 @@ fn parse_asm(asm: &str) -> Vec { if parts.is_empty() { None } else { - Instruction::from_str(parts[0]).ok() + RiscVInstruction::from_str(parts[0]).ok() } }) .collect() diff --git a/src/translate.rs b/src/translate.rs new file mode 100644 index 0000000..6c6eca3 --- /dev/null +++ b/src/translate.rs @@ -0,0 +1,19 @@ +use crate::instruction::{ArmInstruction, RiscVInstruction}; + +/// Run the core logic to match from RISC-V to ARM Instructions. + +/// Translate one instruction at a time. +pub fn translate(riscv_instr: RiscVInstruction) -> ArmInstruction { + match riscv_instr { + RiscVInstruction::Addi => add, + RiscVInstruction::Sd => todo!(), + RiscVInstruction::Ld => todo!(), + RiscVInstruction::Sw => todo!(), + RiscVInstruction::Lw => todo!(), + RiscVInstruction::Mv => todo!(), + RiscVInstruction::Addw => todo!(), + RiscVInstruction::SextW => todo!(), + RiscVInstruction::Jr => todo!(), + RiscVInstruction::Li => todo!(), + } +} From 89f727653b76863a22ef6d08bcbae1c63832e03e Mon Sep 17 00:00:00 2001 From: Samir Rashid Date: Sat, 8 Feb 2025 20:47:57 -0800 Subject: [PATCH 3/5] meta: rename `test/` -> `tests/` --- test/binaries/add.c | 7 ---- test/test_parse_asm.rs | 48 ------------------------- test/test_translation.rs | 50 -------------------------- {test => tests}/binaries/Makefile | 0 {test => tests}/binaries/README.md | 0 tests/binaries/add.c | 41 +++++++++++++++++++++ {test => tests}/binaries/add.riscv.s | 0 {test => tests}/binaries/add.x86.s | 0 {test => tests}/binaries/flake.lock | 0 {test => tests}/binaries/flake.nix | 0 {test => tests}/binaries/hello_world.c | 0 tests/test_parse_asm.rs | 49 +++++++++++++++++++++++++ tests/test_translation.rs | 50 ++++++++++++++++++++++++++ 13 files changed, 140 insertions(+), 105 deletions(-) delete mode 100644 test/binaries/add.c delete mode 100644 test/test_parse_asm.rs delete mode 100644 test/test_translation.rs rename {test => tests}/binaries/Makefile (100%) rename {test => tests}/binaries/README.md (100%) create mode 100644 tests/binaries/add.c rename {test => tests}/binaries/add.riscv.s (100%) rename {test => tests}/binaries/add.x86.s (100%) rename {test => tests}/binaries/flake.lock (100%) rename {test => tests}/binaries/flake.nix (100%) rename {test => tests}/binaries/hello_world.c (100%) create mode 100644 tests/test_parse_asm.rs create mode 100644 tests/test_translation.rs diff --git a/test/binaries/add.c b/test/binaries/add.c deleted file mode 100644 index c8fff0f..0000000 --- a/test/binaries/add.c +++ /dev/null @@ -1,7 +0,0 @@ -int main(void) { - int x = 3; - int y = 4; - - return x + y; -} - diff --git a/test/test_parse_asm.rs b/test/test_parse_asm.rs deleted file mode 100644 index 6c6050a..0000000 --- a/test/test_parse_asm.rs +++ /dev/null @@ -1,48 +0,0 @@ -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parse_asm() { - let asm = " - addi sp,sp,-32 - sd ra,24(sp) - ld s0,16(sp) - addi s0,sp,32 - li a5,3 - sw a5,-20(s0) - li a5,4 - sw a5,-24(s0) - lw a5,-20(s0) - mv a4,a5 - lw a5,-24(s0) - addw a5,a4,a5 - sext.w a5,a5 - mv a0,a5 - ld ra,24(sp) - ld s0,16(sp) - addi sp,sp,32 - jr ra - "; - let instructions = parse_asm(asm); - assert_eq!(instructions.len(), 17); - assert_eq!(instructions[0], Instruction::Addi); - assert_eq!(instructions[1], Instruction::Sd); - assert_eq!(instructions[2], Instruction::Ld); - assert_eq!(instructions[3], Instruction::Addi); - assert_eq!(instructions[4], Instruction::Li); - assert_eq!(instructions[5], Instruction::Sw); - assert_eq!(instructions[6], Instruction::Li); - assert_eq!(instructions[7], Instruction::Sw); - assert_eq!(instructions[8], Instruction::Lw); - assert_eq!(instructions[9], Instruction::Mv); - assert_eq!(instructions[10], Instruction::Lw); - assert_eq!(instructions[11], Instruction::Addw); - assert_eq!(instructions[12], Instruction::SextW); - assert_eq!(instructions[13], Instruction::Mv); - assert_eq!(instructions[14], Instruction::Ld); - assert_eq!(instructions[15], Instruction::Ld); - assert_eq!(instructions[16], Instruction::Addi); - assert_eq!(instructions[17], Instruction::Jr); - } -} diff --git a/test/test_translation.rs b/test/test_translation.rs deleted file mode 100644 index a652bd4..0000000 --- a/test/test_translation.rs +++ /dev/null @@ -1,50 +0,0 @@ -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_binary_translate() { - let riscv_asm = " - addi sp,sp,-32 - sd ra,24(sp) - ld s0,16(sp) - addi s0,sp,32 - li a5,3 - sw a5,-20(s0) - li a5,4 - sw a5,-24(s0) - lw a5,-20(s0) - mv a4,a5 - lw a5,-24(s0) - addw a5,a4,a5 - sext.w a5,a5 - mv a0,a5 - ld ra,24(sp) - ld s0,16(sp) - addi sp,sp,32 - jr ra - "; - let translated_asm = binary_translate(riscv_asm); - let expected_output = " - Addi - Sd - Ld - Addi - Li - Sw - Li - Sw - Lw - Mv - Lw - Addw - SextW - Mv - Ld - Ld - Addi - Jr - "; - assert_eq!(translated_asm, expected_output); - } -} diff --git a/test/binaries/Makefile b/tests/binaries/Makefile similarity index 100% rename from test/binaries/Makefile rename to tests/binaries/Makefile diff --git a/test/binaries/README.md b/tests/binaries/README.md similarity index 100% rename from test/binaries/README.md rename to tests/binaries/README.md diff --git a/tests/binaries/add.c b/tests/binaries/add.c new file mode 100644 index 0000000..c5750d5 --- /dev/null +++ b/tests/binaries/add.c @@ -0,0 +1,41 @@ +int main(void) { + int x = 3; + int y = 4; + + return x + y; +} + +//////////////// arm +// main: +// sub sp, sp, #16 +// mov w0, 3 +// str w0, [sp, 12] +// mov w0, 4 +// str w0, [sp, 8] +// ldr w1, [sp, 12] +// ldr w0, [sp, 8] +// add w0, w1, w0 +// add sp, sp, 16 +// ret + +//////////// riscv +// https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:1,endLineNumber:8,positionColumn:1,positionLineNumber:8,selectionStartColumn:1,selectionStartLineNumber:8,startColumn:1,startLineNumber:8),source:'int+main(void)+%7B%0A%09int+x+%3D+3%3B%0A%09int+y+%3D+4%3B%0A%0A%09return+x+%2B+y%3B%0A%7D%0A%0A'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:rv64-gcc1420,filters:(b:'0',binary:'1',binaryObject:'1',commentOnly:'0',debugCalls:'1',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1',verboseDemangling:'0'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!(),options:'',overrides:!(),selection:(endColumn:19,endLineNumber:19,positionColumn:19,positionLineNumber:19,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'+RISC-V+(64-bits)+gcc+14.2.0+(Editor+%231)',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4 +// main: +// addi sp,sp,-32 +// sd ra,24(sp) +// sd s0,16(sp) +// addi s0,sp,32 +// li a5,3 +// sw a5,-20(s0) +// li a5,4 +// sw a5,-24(s0) +// lw a5,-20(s0) +// mv a4,a5 +// lw a5,-24(s0) +// addw a5,a4,a5 +// sext.w a5,a5 +// mv a0,a5 +// ld ra,24(sp) +// ld ß s0,16(sp) +// addi sp,sp,32 +// jr ra diff --git a/test/binaries/add.riscv.s b/tests/binaries/add.riscv.s similarity index 100% rename from test/binaries/add.riscv.s rename to tests/binaries/add.riscv.s diff --git a/test/binaries/add.x86.s b/tests/binaries/add.x86.s similarity index 100% rename from test/binaries/add.x86.s rename to tests/binaries/add.x86.s diff --git a/test/binaries/flake.lock b/tests/binaries/flake.lock similarity index 100% rename from test/binaries/flake.lock rename to tests/binaries/flake.lock diff --git a/test/binaries/flake.nix b/tests/binaries/flake.nix similarity index 100% rename from test/binaries/flake.nix rename to tests/binaries/flake.nix diff --git a/test/binaries/hello_world.c b/tests/binaries/hello_world.c similarity index 100% rename from test/binaries/hello_world.c rename to tests/binaries/hello_world.c diff --git a/tests/test_parse_asm.rs b/tests/test_parse_asm.rs new file mode 100644 index 0000000..0532a2b --- /dev/null +++ b/tests/test_parse_asm.rs @@ -0,0 +1,49 @@ +// #[cfg(test)] +// mod tests { +// use super::RiscVInstruction; +// use super::*; + +// #[test] +// fn test_parse_asm() { +// let asm = " +// addi sp,sp,-32 +// sd ra,24(sp) +// ld s0,16(sp) +// addi s0,sp,32 +// li a5,3 +// sw a5,-20(s0) +// li a5,4 +// sw a5,-24(s0) +// lw a5,-20(s0) +// mv a4,a5 +// lw a5,-24(s0) +// addw a5,a4,a5 +// sext.w a5,a5 +// mv a0,a5 +// ld ra,24(sp) +// ld s0,16(sp) +// addi sp,sp,32 +// jr ra +// "; +// let instructions = parse_asm(asm); +// assert_eq!(instructions.len(), 17); +// assert_eq!(instructions[0], RiscVInstruction::Addi); +// assert_eq!(instructions[1], RiscVInstruction::Sd); +// assert_eq!(instructions[2], RiscVInstruction::Ld); +// assert_eq!(instructions[3], RiscVInstruction::Addi); +// assert_eq!(instructions[4], RiscVInstruction::Li); +// assert_eq!(instructions[5], RiscVInstruction::Sw); +// assert_eq!(instructions[6], RiscVInstruction::Li); +// assert_eq!(instructions[7], RiscVInstruction::Sw); +// assert_eq!(instructions[8], RiscVInstruction::Lw); +// assert_eq!(instructions[9], RiscVInstruction::Mv); +// assert_eq!(instructions[10], RiscVInstruction::Lw); +// assert_eq!(instructions[11], RiscVInstruction::Addw); +// assert_eq!(instructions[12], RiscVInstruction::SextW); +// assert_eq!(instructions[13], RiscVInstruction::Mv); +// assert_eq!(instructions[14], RiscVInstruction::Ld); +// assert_eq!(instructions[15], RiscVInstruction::Ld); +// assert_eq!(instructions[16], RiscVInstruction::Addi); +// assert_eq!(instructions[17], RiscVInstruction::Jr); +// } +// } diff --git a/tests/test_translation.rs b/tests/test_translation.rs new file mode 100644 index 0000000..4ac049e --- /dev/null +++ b/tests/test_translation.rs @@ -0,0 +1,50 @@ +// #[cfg(test)] +// mod tests { +// use super::*; + +// #[test] +// fn test_binary_translate() { +// let riscv_asm = " +// addi sp,sp,-32 +// sd ra,24(sp) +// ld s0,16(sp) +// addi s0,sp,32 +// li a5,3 +// sw a5,-20(s0) +// li a5,4 +// sw a5,-24(s0) +// lw a5,-20(s0) +// mv a4,a5 +// lw a5,-24(s0) +// addw a5,a4,a5 +// sext.w a5,a5 +// mv a0,a5 +// ld ra,24(sp) +// ld s0,16(sp) +// addi sp,sp,32 +// jr ra +// "; +// let translated_asm = binary_translate(riscv_asm); +// let expected_output = " +// Addi +// Sd +// Ld +// Addi +// Li +// Sw +// Li +// Sw +// Lw +// Mv +// Lw +// Addw +// SextW +// Mv +// Ld +// Ld +// Addi +// Jr +// "; +// assert_eq!(translated_asm, expected_output); +// } +// } From c0d863bf92492321871802355e5612ac6688508a Mon Sep 17 00:00:00 2001 From: David Tran Date: Thu, 20 Mar 2025 20:31:32 -0700 Subject: [PATCH 4/5] fibonacci and prime int tests --- src/instruction.rs | 96 ++++++++- src/translate.rs | 90 +++++++- src/utils.rs | 21 ++ tests/fib/fib.arm.s | 65 ++++++ tests/fib/fib.riscv.s | 59 ++++++ tests/fib/test_fib.rs | 308 ++++++++++++++++++++++++++++ tests/prime/prime.arm.s | 91 +++++++++ tests/prime/prime.riscv.s | 92 +++++++++ tests/prime/test_prime.rs | 417 ++++++++++++++++++++++++++++++++++++++ tests/tests.rs | 6 + 10 files changed, 1243 insertions(+), 2 deletions(-) create mode 100644 tests/fib/fib.arm.s create mode 100644 tests/fib/fib.riscv.s create mode 100644 tests/fib/test_fib.rs create mode 100644 tests/prime/prime.arm.s create mode 100644 tests/prime/prime.riscv.s create mode 100644 tests/prime/test_prime.rs diff --git a/src/instruction.rs b/src/instruction.rs index d8cfa43..58de7b7 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -70,13 +70,50 @@ pub enum RiscVInstruction { arg1: RiscVRegister, arg2: RiscVRegister, }, + #[strum(serialize = "subw")] + Sub { + // dest = arg1 - arg2 + width: RiscVWidth, + dest: RiscVRegister, + arg1: RiscVRegister, + arg2: RiscVRegister, + }, /// branch if less than or equal - #[strum(serialize = "call")] + #[strum(serialize = "ble")] Ble { arg1: RiscVRegister, arg2: RiscVRegister, target: RiscVVal, }, + /// branch if greater than or equal + #[strum(serialize = "bge")] + Bge { + arg1: RiscVRegister, + arg2: RiscVRegister, + target: RiscVVal, + }, + /// branch if less than + #[strum(serialize = "blt")] + Blt { + arg1: RiscVRegister, + arg2: RiscVRegister, + target: RiscVVal, + }, + /// branch if greater than + #[strum(serialize = "bgt")] + Bgt { + arg1: RiscVRegister, + arg2: RiscVRegister, + target: RiscVVal, + }, + /// branch if greater than + #[strum(serialize = "bne")] + Bne { + arg1: RiscVRegister, + arg2: RiscVRegister, + target: RiscVVal, + }, + /// branch if greater than or equal to /// call label #[strum(serialize = "call")] Call { @@ -91,6 +128,13 @@ pub enum RiscVInstruction { src: RiscVRegister, dest: RiscVVal, }, + /// Rd := Rs << Imm + #[strum(serialize = "Slli")] + Slli { + dest: RiscVRegister, + src: RiscVRegister, + imm: i32 + }, /// Loads a value from memory into register rd for RV64I. /// /// `x[rd] = M[x[rs1] + sext(offset)]` @@ -268,6 +312,34 @@ pub enum ArmInstruction { arg2: ArmRegister, target: ArmVal, }, + /// BGE label + #[strum(serialize = "bge")] + Bge { + arg1: ArmRegister, + arg2: ArmRegister, + target: ArmVal, + }, + /// BLT label + #[strum(serialize = "blt")] + Blt { + arg1: ArmRegister, + arg2: ArmRegister, + target: ArmVal, + }, + /// BGT label + #[strum(serialize = "bgt")] + Bgt { + arg1: ArmRegister, + arg2: ArmRegister, + target: ArmVal, + }, + /// BNE label + #[strum(serialize = "bne")] + Bne { + arg1: ArmRegister, + arg2: ArmRegister, + target: ArmVal, + }, /// BL label #[strum(serialize = "bl")] Bl { @@ -296,6 +368,13 @@ pub enum ArmInstruction { }, #[strum(serialize = "ret")] Ret, + /// Rd := Rs << Imm + #[strum(serialize = "Lsl")] + Lsl { + dest: ArmRegister, + src: ArmRegister, + imm: i32 + }, /// Str [r2 + offset] = r1 #[strum(serialize = "str")] Str { @@ -582,6 +661,18 @@ impl Into for ArmInstruction { ArmInstruction::Ble { arg1, arg2, target } => { format!("cmp {}, {}\nble {}", arg1, arg2, target) } + ArmInstruction::Bge { arg1, arg2, target } => { + format!("cmp {}, {}\nbge {}", arg1, arg2, target) + } + ArmInstruction::Blt { arg1, arg2, target } => { + format!("cmp {}, {}\nblt {}", arg1, arg2, target) + } + ArmInstruction::Bgt { arg1, arg2, target } => { + format!("cmp {}, {}\nbgt {}", arg1, arg2, target) + } + ArmInstruction::Bne { arg1, arg2, target } => { + format!("cmp {}, {}\nbne {}", arg1, arg2, target) + } ArmInstruction::Blr { target } => { format!("blr {}", Into::::into(target)) } @@ -598,6 +689,9 @@ impl Into for ArmInstruction { ArmWidth::Double => format!("str {}, {}", src, dest), _ => todo!("{:?}", width), }, + ArmInstruction::Lsl { dest, src, imm } => { + format!("lsl {}, {}, {}", dest, src, imm) + } ArmInstruction::Sub { dest, arg1, arg2 } => { format!("sub {}, {}, {}", dest, arg1, arg2) } diff --git a/src/translate.rs b/src/translate.rs index f1d0a98..0b49440 100644 --- a/src/translate.rs +++ b/src/translate.rs @@ -44,6 +44,38 @@ pub fn translate(riscv_instr: RiscVInstruction) -> Vec { target: map_val(target, &width), } }], + RiscVInstruction::Bge { arg1, arg2, target } => vec![{ + let width = RiscVWidth::Double; + ArmInstruction::Bge { + arg1: map_register(arg1, &width), + arg2: map_register(arg2, &width), + target: map_val(target, &width), + } + }], + RiscVInstruction::Blt { arg1, arg2, target } => vec![{ + let width = RiscVWidth::Double; + ArmInstruction::Blt { + arg1: map_register(arg1, &width), + arg2: map_register(arg2, &width), + target: map_val(target, &width), + } + }], + RiscVInstruction::Bgt { arg1, arg2, target } => vec![{ + let width = RiscVWidth::Double; + ArmInstruction::Bgt { + arg1: map_register(arg1, &width), + arg2: map_register(arg2, &width), + target: map_val(target, &width), + } + }], + RiscVInstruction::Bne { arg1, arg2, target } => vec![{ + let width = RiscVWidth::Double; + ArmInstruction::Bne { + arg1: map_register(arg1, &width), + arg2: map_register(arg2, &width), + target: map_val(target, &width), + } + }], RiscVInstruction::J { target } => vec![ArmInstruction::B { target: map_val(target, &RiscVWidth::Double), }], @@ -52,6 +84,14 @@ pub fn translate(riscv_instr: RiscVInstruction) -> Vec { src: map_register(src, &width), dest: map_val(dest, &width), }], + RiscVInstruction::Slli { dest, src, imm } => { + let width = RiscVWidth::Double; + vec![ArmInstruction::Lsl { + dest: map_register(dest, &width), + src: map_register(src, &width), + imm: imm + }] + }, RiscVInstruction::L { width, dest, src } => vec![ArmInstruction::Ldr { width: map_width(&width), dest: map_register(dest, &width), @@ -101,7 +141,55 @@ pub fn translate(riscv_instr: RiscVInstruction) -> Vec { name: map_register_name(arg2), }), }], - RiscVWidth::Double => sorry!(), + RiscVWidth::Double => vec![ArmInstruction::Add { + dest: ArmRegister { + width: ArmWidth::Double, + name: map_register_name(dest), + }, + arg1: ArmRegister { + width: ArmWidth::Double, + name: map_register_name(arg1), + }, + arg2: ArmVal::Reg(ArmRegister { + width: ArmWidth::Double, + name: map_register_name(arg2), + }), + }], + }, + RiscVInstruction::Sub { + width, + dest, + arg1, + arg2, + } => match width { + RiscVWidth::Word => vec![ArmInstruction::Sub { + dest: ArmRegister { + width: ArmWidth::Word, + name: map_register_name(dest), + }, + arg1: ArmRegister { + width: ArmWidth::Word, + name: map_register_name(arg1), + }, + arg2: ArmVal::Reg(ArmRegister { + width: ArmWidth::Word, + name: map_register_name(arg2), + }), + }], + RiscVWidth::Double => vec![ArmInstruction::Sub { + dest: ArmRegister { + width: ArmWidth::Double, + name: map_register_name(dest), + }, + arg1: ArmRegister { + width: ArmWidth::Double, + name: map_register_name(arg1), + }, + arg2: ArmVal::Reg(ArmRegister { + width: ArmWidth::Double, + name: map_register_name(arg2), + }), + }], }, RiscVInstruction::SextW { dest, src } => vec![ArmInstruction::Sxtw { dest: ArmRegister { diff --git a/src/utils.rs b/src/utils.rs index eb35249..9e034b1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -19,6 +19,27 @@ _main: main: "#; +pub const START_NO_MAIN: &str = r#" +.text + +.global _start +.global _main + +.balign 4 +_start: +bl main +mov x8, #93 +svc #0 +"#; + +/// Assembler directives for main only, used when another +/// function defined before main +pub const START_MAIN: &str = r#" +.balign 4 +_main: +main: +"#; + pub fn translate_to_file(instrs: Vec, path: String) { let arm_instrs = translate_instrs(instrs); let mut contents = String::new(); diff --git a/tests/fib/fib.arm.s b/tests/fib/fib.arm.s new file mode 100644 index 0000000..7d7d84c --- /dev/null +++ b/tests/fib/fib.arm.s @@ -0,0 +1,65 @@ + +.text + +.global _start +.global _main + +.balign 4 +_start: +bl main +mov x8, #93 +svc #0 + +.balign 4 +_main: +main: + +sub sp, sp, 64 +str x29, [sp, 56] +add x29, sp, 64 +str xzr, [x29, -64] +str xzr, [x29, -56] +str xzr, [x29, -48] +str xzr, [x29, -40] +str xzr, [x29, -32] +mov x5, 1 +str w5, [x29, -60] +mov x5, 2 +str w5, [x29, -20] +b .L2 +.L3: +ldr w5, [x29, -20] +sub x5, x5, 1 +sxtw x5, w5 +lsl x5, x5, 2 +sub x5, x5, 16 +add x5, x5, x29 +ldr x4, [x5, -48] +ldr x5, [x29, -20] +sub x5, x5, 2 +sxtw x5, w5 +lsl x5, x5, 2 +sub x5, x5, 16 +add x5, x5, x29 +ldr x5, [x5, -48] +add x5, x4, x5 +sxtw x4, w5 +ldr x5, [x29, -20] +lsl x5, x5, 2 +sub x5, x5, 16 +add x5, x5, x29 +str x4, [x5, -48] +ldr x5, [x29, -20] +add x5, x5, 1 +str w5, [x29, -20] +.L2: +ldr x5, [x29, -20] +sxtw x4, w5 +mov x5, 9 +cmp x4, x5 +ble .L3 +ldr w5, [x29, -28] +add x0, x5, 0 +ldr x29, [sp, 56] +add sp, sp, 64 +blr lr diff --git a/tests/fib/fib.riscv.s b/tests/fib/fib.riscv.s new file mode 100644 index 0000000..7277c1e --- /dev/null +++ b/tests/fib/fib.riscv.s @@ -0,0 +1,59 @@ +; int main() { +; int i; +; int a[10] = {}; +; a[1] = 1; +; for (i = 2; i < 10; i++) { +; a[i] = a[i-1] + a[i-2]; +; } +; return a[9]; +; } + +main: +addi sp,sp,-64 +sd s0,56(sp) +addi s0,sp,64 +sd zero,-64(s0) +sd zero,-56(s0) +sd zero,-48(s0) +sd zero,-40(s0) +sd zero,-32(s0) +li a5,1 +sw a5,-60(s0) +li a5,2 +sw a5,-20(s0) +j .L2 +.L3: +lw a5,-20(s0) +addiw a5,a5,-1 +sext.w a5,a5 +slli a5,a5,2 +addi a5,a5,-16 +add a5,a5,s0 +lw a4,-48(a5) +lw a5,-20(s0) +addiw a5,a5,-2 +sext.w a5,a5 +slli a5,a5,2 +addi a5,a5,-16 +add a5,a5,s0 +lw a5,-48(a5) +addw a5,a4,a5 +sext.w a4,a5 +lw a5,-20(s0) +slli a5,a5,2 +addi a5,a5,-16 +add a5,a5,s0 +sw a4,-48(a5) +lw a5,-20(s0) +addiw a5,a5,1 +sw a5,-20(s0) +.L2: +lw a5,-20(s0) +sext.w a4,a5 +li a5,9 +ble a4,a5,.L3 +lw a5,-28(s0) +mv a0,a5 +ld s0,56(sp) +addi sp,sp,64 +jr ra \ No newline at end of file diff --git a/tests/fib/test_fib.rs b/tests/fib/test_fib.rs new file mode 100644 index 0000000..bd1465d --- /dev/null +++ b/tests/fib/test_fib.rs @@ -0,0 +1,308 @@ +#[cfg(test)] +mod tests { + use binary_room::instruction::*; + use binary_room::utils::translate_to_file; + use binary_room::utils::START; + + #[test] + fn test_binary_translate() { + let riscv_asm: Vec = vec![ + RiscVInstruction::Verbatim { + text: START.to_string(), + }, + RiscVInstruction::Addi { + dest: RiscVRegister::SP, + src: RiscVRegister::SP, + imm: -64, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::S0FP, + dest: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 56, + }, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::S0FP, + src: RiscVRegister::SP, + imm: 64, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::X0, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -64, + }, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::X0, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -56, + }, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::X0, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -48, + }, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::X0, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -40, + }, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::X0, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -32, + }, + }, + RiscVInstruction::Li { + dest: RiscVRegister::A5, + imm: 1, + }, + RiscVInstruction::S { + width: RiscVWidth::Word, + src: RiscVRegister::A5, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -60, + }, + }, + RiscVInstruction::Li { + dest: RiscVRegister::A5, + imm: 2, + }, + RiscVInstruction::S { + width: RiscVWidth::Word, + src: RiscVRegister::A5, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::J { + target: RiscVVal::LabelOffset { + label: ".L2".to_string(), + offset: 0, + }, + }, + RiscVInstruction::Label { + name: ".L3".to_string(), + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + imm: -1, + }, + RiscVInstruction::SextW { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + }, + RiscVInstruction::Slli { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + imm: 2, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + imm: -16, + }, + RiscVInstruction::Add { + width: RiscVWidth::Double, + dest: RiscVRegister::A5, + arg1: RiscVRegister::A5, + arg2: RiscVRegister::S0FP, + }, + RiscVInstruction::L { + width: RiscVWidth::Double, + dest: RiscVRegister::A4, + src: RiscVVal::Offset { + register: RiscVRegister::A5, + offset: -48, + }, + }, + RiscVInstruction::L { + width: RiscVWidth::Double, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + imm: -2, + }, + RiscVInstruction::SextW { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + }, + RiscVInstruction::Slli { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + imm: 2, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + imm: -16, + }, + RiscVInstruction::Add { + width: RiscVWidth::Double, + dest: RiscVRegister::A5, + arg1: RiscVRegister::A5, + arg2: RiscVRegister::S0FP, + }, + RiscVInstruction::L { + width: RiscVWidth::Double, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::A5, + offset: -48, + }, + }, + RiscVInstruction::Add { + width: RiscVWidth::Double, + dest: RiscVRegister::A5, + arg1: RiscVRegister::A4, + arg2: RiscVRegister::A5, + }, + RiscVInstruction::SextW { + dest: RiscVRegister::A4, + src: RiscVRegister::A5, + }, + RiscVInstruction::L { + width: RiscVWidth::Double, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::Slli { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + imm: 2, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + imm: -16, + }, + RiscVInstruction::Add { + width: RiscVWidth::Double, + dest: RiscVRegister::A5, + arg1: RiscVRegister::A5, + arg2: RiscVRegister::S0FP, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::A4, + dest: RiscVVal::Offset { + register: RiscVRegister::A5, + offset: -48, + }, + }, + RiscVInstruction::L { + width: RiscVWidth::Double, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + imm: 1, + }, + RiscVInstruction::S { + width: RiscVWidth::Word, + src: RiscVRegister::A5, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::Label { + name: ".L2".to_string(), + }, + RiscVInstruction::L { + width: RiscVWidth::Double, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::SextW { + dest: RiscVRegister::A4, + src: RiscVRegister::A5, + }, + RiscVInstruction::Li { + dest: RiscVRegister::A5, + imm: 9, + }, + RiscVInstruction::Ble { + arg1: RiscVRegister::A4, + arg2: RiscVRegister::A5, + target: RiscVVal::LabelOffset { + label: ".L3".to_string(), + offset: 0, + }, + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -28, + }, + }, + RiscVInstruction::Mv { + dest: RiscVRegister::A0, + src: RiscVRegister::A5, + }, + RiscVInstruction::L { + width: RiscVWidth::Double, + dest: RiscVRegister::S0FP, + src: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 56, + }, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::SP, + src: RiscVRegister::SP, + imm: 64, + }, + RiscVInstruction::Jr { + target: RiscVRegister::RA, + }, + ]; + + translate_to_file(riscv_asm, "./tests/fib/fib.arm.s".to_string()); + } +} diff --git a/tests/prime/prime.arm.s b/tests/prime/prime.arm.s new file mode 100644 index 0000000..1e5fcff --- /dev/null +++ b/tests/prime/prime.arm.s @@ -0,0 +1,91 @@ + +.text + +.global _start +.global _main + +.balign 4 +_start: +bl main +mov x8, #93 +svc #0 + +is_prime: +sub sp, sp, 48 +str x29, [sp, 40] +add x29, sp, 48 +add x5, x0, 0 +str w5, [x29, -36] +ldr w5, [x29, -36] +sxtw x4, w5 +mov x5, 1 +cmp x4, x5 +bgt .L2 +mov x5, 0 +b .L3 +.L2: +mov x5, 2 +str w5, [x29, -20] +b .L4 +.L8: +ldr w5, [x29, -36] +add x4, x5, 0 +ldr w5, [x29, -20] +sub w5, w4, w5 +str w5, [x29, -24] +b .L5 +.L6: +ldr w5, [x29, -24] +add x4, x5, 0 +ldr w5, [x29, -20] +sub w5, w4, w5 +str w5, [x29, -24] +.L5: +ldr w5, [x29, -24] +add x4, x5, 0 +ldr w5, [x29, -20] +sxtw x4, w4 +sxtw x5, w5 +cmp x4, x5 +bge .L6 +ldr w5, [x29, -24] +sxtw x5, w5 +cmp x5, xzr +bne .L7 +mov x5, 0 +b .L3 +.L7: +ldr w5, [x29, -20] +add x5, x5, 1 +str x5, [x29, -20] +.L4: +ldr w5, [x29, -20] +add x4, x5, 0 +ldr w5, [x29, -36] +sxtw x4, w4 +sxtw x5, w5 +cmp x4, x5 +blt .L8 +mov x5, 1 +.L3: +add x0, x5, 0 +ldr x29, [sp, 40] +add sp, sp, 48 +blr lr + +.balign 4 +_main: +main: + +sub sp, sp, 16 +str lr, [sp, 8] +str x29, [sp, 0] +add x29, sp, 16 +mov x0, 4093 +bl is_prime +add x5, x0, 0 +add x0, x5, 0 +ldr lr, [sp, 8] +ldr x29, [sp, 16] +add sp, sp, 16 +blr lr diff --git a/tests/prime/prime.riscv.s b/tests/prime/prime.riscv.s new file mode 100644 index 0000000..8cb9828 --- /dev/null +++ b/tests/prime/prime.riscv.s @@ -0,0 +1,92 @@ +; int is_prime(int n) { +; if (n <= 1) { +; return 0; +; } +; for (int i = 2; i < n; i++) { +; int temp = n - i; +; while (temp >= i) { +; temp = temp - i; +; } +; if (temp == 0) { +; // i divides n +; return 0; +; } +; } +; return 1; +; } +; int main(void) { +; return is_prime(4093); +; } + +is_prime(int): +addi sp,sp,-48 +sd s0,40(sp) +addi s0,sp,48 +mv a5,a0 +sw a5,-36(s0) +lw a5,-36(s0) +sext.w a4,a5 +li a5,1 +bgt a4,a5,.L2 +li a5,0 +j .L3 +.L2: +li a5,2 +sw a5,-20(s0) +j .L4 +.L8: +lw a5,-36(s0) +mv a4,a5 +lw a5,-20(s0) +subw a5,a4,a5 +sw a5,-24(s0) +j .L5 +.L6: +lw a5,-24(s0) +mv a4,a5 +lw a5,-20(s0) +subw a5,a4,a5 +sw a5,-24(s0) +.L5: +lw a5,-24(s0) +mv a4,a5 +lw a5,-20(s0) +sext.w a4,a4 +sext.w a5,a5 +bge a4,a5,.L6 +lw a5,-24(s0) +sext.w a5,a5 +bne a5,zero,.L7 +li a5,0 +j .L3 +.L7: +lw a5,-20(s0) +addiw a5,a5,1 +sw a5,-20(s0) +.L4: +lw a5,-20(s0) +mv a4,a5 +lw a5,-36(s0) +sext.w a4,a4 +sext.w a5,a5 +blt a4,a5,.L8 +li a5,1 +.L3: +mv a0,a5 +ld s0,40(sp) +addi sp,sp,48 +jr ra +main: +addi sp,sp,-16 +sd ra,8(sp) +sd s0,0(sp) +addi s0,sp,16 +li a0,4093 +call is_prime(int) +mv a5,a0 +nop +mv a0,a5 +ld ra,8(sp) +ld s0,0(sp) +addi sp,sp,16 +jr ra \ No newline at end of file diff --git a/tests/prime/test_prime.rs b/tests/prime/test_prime.rs new file mode 100644 index 0000000..488875d --- /dev/null +++ b/tests/prime/test_prime.rs @@ -0,0 +1,417 @@ +#[cfg(test)] +mod tests { + use binary_room::instruction::*; + use binary_room::utils::translate_to_file; + use binary_room::utils::START_MAIN; + use binary_room::utils::START_NO_MAIN; + const N: i32 = 4093; + + #[test] + fn test_binary_translate() { + let riscv_asm: Vec = vec![ + RiscVInstruction::Verbatim { + text: START_NO_MAIN.to_string(), + }, + RiscVInstruction::Label { + name: "is_prime".to_string(), + }, + RiscVInstruction::Addi { + dest: RiscVRegister::SP, + src: RiscVRegister::SP, + imm: -48, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::S0FP, + dest: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 40, + }, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::S0FP, + src: RiscVRegister::SP, + imm: 48, + }, + RiscVInstruction::Mv { + dest: RiscVRegister::A5, + src: RiscVRegister::A0, + }, + RiscVInstruction::S { + width: RiscVWidth::Word, + src: RiscVRegister::A5, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -36, + }, + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -36, + }, + }, + RiscVInstruction::SextW { + dest: RiscVRegister::A4, + src: RiscVRegister::A5, + }, + RiscVInstruction::Li { + dest: RiscVRegister::A5, + imm: 1, + }, + RiscVInstruction::Bgt { + arg1: RiscVRegister::A4, + arg2: RiscVRegister::A5, + target: RiscVVal::LabelOffset { + label: ".L2".to_string(), + offset: 0, + }, + }, + RiscVInstruction::Li { + dest: RiscVRegister::A5, + imm: 0, + }, + RiscVInstruction::J { + target: RiscVVal::LabelOffset { + label: ".L3".to_string(), + offset: 0, + }, + }, + RiscVInstruction::Label { + name: ".L2".to_string(), + }, + RiscVInstruction::Li { + dest: RiscVRegister::A5, + imm: 2, + }, + RiscVInstruction::S { + width: RiscVWidth::Word, + src: RiscVRegister::A5, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::J { + target: RiscVVal::LabelOffset { + label: ".L4".to_string(), + offset: 0, + }, + }, + RiscVInstruction::Label { + name: ".L8".to_string(), + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -36, + }, + }, + RiscVInstruction::Mv { + dest: RiscVRegister::A4, + src: RiscVRegister::A5, + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::Sub { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + arg1: RiscVRegister::A4, + arg2: RiscVRegister::A5, + }, + RiscVInstruction::S { + width: RiscVWidth::Word, + src: RiscVRegister::A5, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -24, + }, + }, + RiscVInstruction::J { + target: RiscVVal::LabelOffset { + label: ".L5".to_string(), + offset: 0, + }, + }, + RiscVInstruction::Label { + name: ".L6".to_string(), + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -24, + }, + }, + RiscVInstruction::Mv { + dest: RiscVRegister::A4, + src: RiscVRegister::A5, + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::Sub { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + arg1: RiscVRegister::A4, + arg2: RiscVRegister::A5, + }, + RiscVInstruction::S { + width: RiscVWidth::Word, + src: RiscVRegister::A5, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -24, + }, + }, + RiscVInstruction::Label { + name: ".L5".to_string(), + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -24, + }, + }, + RiscVInstruction::Mv { + dest: RiscVRegister::A4, + src: RiscVRegister::A5, + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::SextW { + dest: RiscVRegister::A4, + src: RiscVRegister::A4, + }, + RiscVInstruction::SextW { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + }, + RiscVInstruction::Bge { + arg1: RiscVRegister::A4, + arg2: RiscVRegister::A5, + target: RiscVVal::LabelOffset { + label: ".L6".to_string(), + offset: 0, + }, + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -24, + }, + }, + RiscVInstruction::SextW { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + }, + RiscVInstruction::Bne { + arg1: RiscVRegister::A5, + arg2: RiscVRegister::X0, + target: RiscVVal::LabelOffset { + label: ".L7".to_string(), + offset: 0, + }, + }, + RiscVInstruction::Li { + dest: RiscVRegister::A5, + imm: 0, + }, + RiscVInstruction::J { + target: RiscVVal::LabelOffset { + label: ".L3".to_string(), + offset: 0, + }, + }, + RiscVInstruction::Label { + name: ".L7".to_string(), + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + imm: 1, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::A5, + dest: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::Label { + name: ".L4".to_string(), + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -20, + }, + }, + RiscVInstruction::Mv { + dest: RiscVRegister::A4, + src: RiscVRegister::A5, + }, + RiscVInstruction::L { + width: RiscVWidth::Word, + dest: RiscVRegister::A5, + src: RiscVVal::Offset { + register: RiscVRegister::S0FP, + offset: -36, + }, + }, + RiscVInstruction::SextW { + dest: RiscVRegister::A4, + src: RiscVRegister::A4, + }, + RiscVInstruction::SextW { + dest: RiscVRegister::A5, + src: RiscVRegister::A5, + }, + RiscVInstruction::Blt { + arg1: RiscVRegister::A4, + arg2: RiscVRegister::A5, + target: RiscVVal::LabelOffset { + label: ".L8".to_string(), + offset: 0, + }, + }, + RiscVInstruction::Li { + dest: RiscVRegister::A5, + imm: 1, + }, + RiscVInstruction::Label { + name: ".L3".to_string(), + }, + RiscVInstruction::Mv { + dest: RiscVRegister::A0, + src: RiscVRegister::A5, + }, + RiscVInstruction::L { + width: RiscVWidth::Double, + dest: RiscVRegister::S0FP, + src: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 40, + }, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::SP, + src: RiscVRegister::SP, + imm: 48, + }, + RiscVInstruction::Jr { + target: RiscVRegister::RA, + }, + RiscVInstruction::Verbatim { + text: START_MAIN.to_string(), + }, + RiscVInstruction::Addi { + dest: RiscVRegister::SP, + src: RiscVRegister::SP, + imm: -16, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::RA, + dest: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 8, + }, + }, + RiscVInstruction::S { + width: RiscVWidth::Double, + src: RiscVRegister::S0FP, + dest: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 0, + }, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::S0FP, + src: RiscVRegister::SP, + imm: 16, + }, + RiscVInstruction::Li { + dest: RiscVRegister::A0, + imm: N, + }, + RiscVInstruction::Call { + label: RiscVVal::LabelOffset { + label: "is_prime".to_string(), + offset: 0, + }, + }, + RiscVInstruction::Mv { + dest: RiscVRegister::A5, + src: RiscVRegister::A0, + }, + RiscVInstruction::Mv { + dest: RiscVRegister::A0, + src: RiscVRegister::A5, + }, + RiscVInstruction::L { + width: RiscVWidth::Double, + dest: RiscVRegister::RA, + src: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 8, + }, + }, + RiscVInstruction::L { + width: RiscVWidth::Double, + dest: RiscVRegister::S0FP, + src: RiscVVal::Offset { + register: RiscVRegister::SP, + offset: 16, + }, + }, + RiscVInstruction::Addi { + dest: RiscVRegister::SP, + src: RiscVRegister::SP, + imm: 16, + }, + RiscVInstruction::Jr { + target: RiscVRegister::RA, + }, + ]; + + translate_to_file(riscv_asm, "./tests/prime/prime.arm.s".to_string()); + } +} diff --git a/tests/tests.rs b/tests/tests.rs index 3bfde3f..5c9591f 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -6,3 +6,9 @@ mod echo; #[path = "print/test_print.rs"] mod print; + +#[path = "fib/test_fib.rs"] +mod fib; + +#[path = "prime/test_prime.rs"] +mod prime; \ No newline at end of file From 6e70538dcfa637da92ddbfbad79e4a8c2409f9b3 Mon Sep 17 00:00:00 2001 From: Samir Rashid Date: Fri, 21 Mar 2025 17:18:01 -0700 Subject: [PATCH 5/5] fix: comment instruction `b`ranch formatting hack, fix riscv asm --- src/instruction.rs | 4 ++++ tests/fib/fib.riscv.s | 18 ++++++++-------- tests/prime/prime.riscv.s | 44 +++++++++++++++++++-------------------- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index 58de7b7..d099e2f 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -658,6 +658,10 @@ impl Into for ArmInstruction { ArmInstruction::B { target } => { format!("b {}", target) } + // TODO: Fix these branching instructions need to map to + // multiple instructions. Would be better separation of concerns + // if this was produced by the translation function instead of a + // hack in the string formatting. ArmInstruction::Ble { arg1, arg2, target } => { format!("cmp {}, {}\nble {}", arg1, arg2, target) } diff --git a/tests/fib/fib.riscv.s b/tests/fib/fib.riscv.s index 7277c1e..0d2561a 100644 --- a/tests/fib/fib.riscv.s +++ b/tests/fib/fib.riscv.s @@ -1,12 +1,12 @@ -; int main() { -; int i; -; int a[10] = {}; -; a[1] = 1; -; for (i = 2; i < 10; i++) { -; a[i] = a[i-1] + a[i-2]; -; } -; return a[9]; -; } +# int main() { +# int i; +# int a[10] = {}; +# a[1] = 1; +# for (i = 2; i < 10; i++) { +# a[i] = a[i-1] + a[i-2]; +# } +# return a[9]; +# } main: addi sp,sp,-64 diff --git a/tests/prime/prime.riscv.s b/tests/prime/prime.riscv.s index 8cb9828..04128fe 100644 --- a/tests/prime/prime.riscv.s +++ b/tests/prime/prime.riscv.s @@ -1,24 +1,24 @@ -; int is_prime(int n) { -; if (n <= 1) { -; return 0; -; } -; for (int i = 2; i < n; i++) { -; int temp = n - i; -; while (temp >= i) { -; temp = temp - i; -; } -; if (temp == 0) { -; // i divides n -; return 0; -; } -; } -; return 1; -; } -; int main(void) { -; return is_prime(4093); -; } +# int is_prime(int n) { +# if (n <= 1) { +# return 0; +# } +# for (int i = 2; i < n; i++) { +# int temp = n - i; +# while (temp >= i) { +# temp = temp - i; +# } +# if (temp == 0) { +# // i divides n +# return 0; +# } +# } +# return 1; +# } +# int main(void) { +# return is_prime(4093); +# } -is_prime(int): +is_prime: # is_prime(int): addi sp,sp,-48 sd s0,40(sp) addi s0,sp,48 @@ -82,11 +82,11 @@ sd ra,8(sp) sd s0,0(sp) addi s0,sp,16 li a0,4093 -call is_prime(int) +call is_prime mv a5,a0 nop mv a0,a5 ld ra,8(sp) ld s0,0(sp) addi sp,sp,16 -jr ra \ No newline at end of file +jr ra