532 lines
25 KiB
Rust
532 lines
25 KiB
Rust
//! # Instruction
|
|
//!
|
|
//! This module describes the internal representation of a RISC-V Instruction,
|
|
//! its constructor from raw data, and a debug print method.
|
|
#![allow(clippy::missing_docs_in_private_items, non_snake_case)]
|
|
|
|
use core::num::Wrapping; // Permet d'autoriser les overflow pour les opérations voulues
|
|
use super::global::*;
|
|
|
|
/// OP instruction name mapping
|
|
const NAMES_OP: [&str; 8] = ["add", "sll", "slt", "sltu", "xor", "sr", "or", "and"];
|
|
/// OPI instruction name mapping
|
|
const NAMES_OPI: [&str; 8] = ["addi", "slli", "slti", "sltiu", "xori", "slri", "ori", "andi"];
|
|
/// OPW instruction name mapping
|
|
const NAMES_OPW: [&str; 8] = ["addw", "sllw", "", "", "", "srw", "", ""];
|
|
/// OPIW instruction name mapping
|
|
const NAMES_OPIW: [&str; 8] = ["addiw", "slliw", "", "", "", "sri", "", ""];
|
|
/// MUL instruction name mapping
|
|
const NAMES_MUL: [&str; 8] = ["mul", "mulh", "mulhsu", "mulhu", "div", "divu", "rem", "remu"];
|
|
/// BR instruction name mapping
|
|
const NAMES_BR: [&str; 8] = ["beq", "bne", "", "", "blt", "bge", "bltu", "bgeu"];
|
|
/// ST instruction name mapping
|
|
const NAMES_ST: [&str; 4] = ["sb", "sh", "sw", "sd"];
|
|
/// LD instruction name mapping
|
|
const NAMES_LD: [&str; 7] = ["lb", "lh", "lw", "ld", "lbu", "lhu", "lwu"];
|
|
|
|
|
|
/// Integer register name mapping
|
|
pub const REG_X: [&str; 32] = ["zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1",
|
|
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
|
|
"s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11",
|
|
"t3", "t4", "t5", "t6"];
|
|
|
|
/// Floating-point register name mapping
|
|
const REG_F: [&str; 32] = ["ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", "fs0", "fs1",
|
|
"fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa7",
|
|
"fs2", "fs3", "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", "fs10", "fs11",
|
|
"ft8", "ft9", "ft10", "ft11"];
|
|
|
|
/// RISC-V Instruction
|
|
#[derive(Debug)]
|
|
pub struct Instruction {
|
|
/// Original value used to construct self
|
|
pub value : u64,
|
|
|
|
pub opcode : u8,
|
|
pub rs1 : u8,
|
|
pub rs2 : u8,
|
|
pub rs3 : u8,
|
|
pub rd : u8,
|
|
pub funct7 : u8,
|
|
pub funct7_smaller : u8,
|
|
pub funct3 : u8,
|
|
pub shamt : u8, // shamt = imm[5:0] or imm[4:0] (depend of opcode)
|
|
|
|
pub imm12_I : u16,
|
|
pub imm12_S : u16,
|
|
|
|
pub imm12_I_signed : i16,
|
|
pub imm12_S_signed : i16,
|
|
pub imm13 : i16,
|
|
pub imm13_signed : i16,
|
|
|
|
pub imm31_12 : u32,
|
|
pub imm21_1 : u32,
|
|
|
|
pub imm31_12_signed : i32,
|
|
pub imm21_1_signed : i32,
|
|
}
|
|
|
|
impl Instruction {
|
|
|
|
/// Construct a new instruction from a big endian raw binary instruction
|
|
pub fn new(value : u64) -> Self {
|
|
|
|
let opcode = (value & 0x7f) as u8;
|
|
let rs1 = ((value >> 15) & 0x1f) as u8;
|
|
let rs2 = ((value >> 20) & 0x1f) as u8;
|
|
let rs3 = ((value >> 27) & 0x1f) as u8;
|
|
let rd = ((value >> 7) & 0x1f) as u8;
|
|
let funct7 = ((value >> 25) & 0x7f) as u8;
|
|
let funct7_smaller = funct7 & 0x3e;
|
|
|
|
let funct3 = ((value >> 12) & 0x7) as u8;
|
|
let imm12_I = ((value >> 20) & 0xfff) as u16;
|
|
let imm12_S = (((value >> 20) & 0xfe0) + ((value >> 7) & 0x1f)) as u16;
|
|
|
|
let imm12_I_signed = if imm12_I >= 2048 { (Wrapping(imm12_I) - Wrapping(4096)).0 } else { imm12_I } as i16;
|
|
let imm12_S_signed = if imm12_S >= 2048 { (Wrapping(imm12_S) - Wrapping(4096)).0 } else { imm12_S } as i16;
|
|
|
|
let imm13 = (((value >> 19) & 0x1000) + ((value >> 20) & 0x7e0) +
|
|
((value >> 7) & 0x1e) + ((value << 4) & 0x800)) as i16;
|
|
let imm13_signed = if imm13 >= 4096 { imm13 - 8192 } else { imm13 };
|
|
|
|
let imm31_12 = (value & 0xfffff000) as u32;
|
|
let imm31_12_signed = imm31_12 as i32;
|
|
|
|
let imm21_1 = ((value & 0xff000) + ((value >> 9) & 0x800) +
|
|
((value >> 20) & 0x7fe) + ((value >> 11) & 0x100000)) as u32;
|
|
let imm21_1_signed = if imm21_1 >= 1048576 { (Wrapping(imm21_1) - Wrapping(2097152)).0 } else { imm21_1 } as i32;
|
|
|
|
let shamt = ((value >> 20) & 0x3f) as u8;
|
|
|
|
Instruction {
|
|
value,
|
|
|
|
opcode,
|
|
rs1,
|
|
rs2,
|
|
rs3,
|
|
rd,
|
|
funct7,
|
|
funct7_smaller,
|
|
|
|
funct3,
|
|
imm12_I,
|
|
imm12_S,
|
|
|
|
imm12_I_signed,
|
|
imm12_S_signed,
|
|
|
|
imm13,
|
|
imm13_signed,
|
|
|
|
imm31_12,
|
|
imm31_12_signed,
|
|
|
|
imm21_1,
|
|
imm21_1_signed,
|
|
|
|
shamt
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/// Converts an Instruction to a prettified debug String
|
|
///
|
|
/// ### Usage
|
|
///
|
|
/// ```
|
|
/// let m = Machine::new();
|
|
/// let i = Instruction::new(inst);
|
|
/// println!("{}", instruction_debug(i, m.pc));
|
|
/// ```
|
|
pub fn instruction_debug(ins: &Instruction, pc: i32) -> String {
|
|
let rd = ins.rd as usize;
|
|
let rs1 = ins.rs1 as usize;
|
|
let rs2 = ins.rs2 as usize;
|
|
let rs3 = ins.rs3 as usize;
|
|
|
|
match ins.opcode {
|
|
RISCV_OP => {
|
|
let name: &str;
|
|
if ins.funct7 == 1 { // Use mul array
|
|
name = NAMES_MUL[ins.funct3 as usize]
|
|
} else if ins.funct3 == RISCV_OP_ADD {
|
|
// Add or Sub
|
|
if ins.funct7 == RISCV_OP_ADD_ADD {
|
|
name = "add";
|
|
} else {
|
|
name = "sub";
|
|
}
|
|
} else if ins.funct3 == RISCV_OP_SR {
|
|
// Srl or Sra
|
|
if ins.funct7 == RISCV_OP_SR_SRL {
|
|
name = "srl";
|
|
} else {
|
|
name = "sra";
|
|
}
|
|
} else {
|
|
name = NAMES_OP[ins.funct3 as usize];
|
|
}
|
|
format!("{}\t{},{},{}", name, REG_X[rd], REG_X[rs1], REG_X[rs2])
|
|
},
|
|
RISCV_OPI => {
|
|
// SHAMT OR IMM
|
|
if ins.funct3 == RISCV_OPI_SRI {
|
|
if ins.funct7 == RISCV_OPI_SRI_SRLI {
|
|
format!("srli\t{},{},{}", REG_X[rd], REG_X[rs1], ins.shamt)
|
|
} else {
|
|
format!("srai\t{},{},{}", REG_X[rd], REG_X[rs1], ins.shamt)
|
|
}
|
|
} else if ins.funct3 == RISCV_OPI_SLLI {
|
|
format!("{}\t{},{},{}", NAMES_OPI[ins.funct3 as usize], REG_X[rd], REG_X[rs1], ins.shamt)
|
|
} else {
|
|
format!("{}\t{},{},{}", NAMES_OPI[ins.funct3 as usize], REG_X[rd], REG_X[rs1], ins.imm12_I_signed)
|
|
}
|
|
},
|
|
RISCV_LUI => {
|
|
format!("lui\t{},{:x}", REG_X[rd], ins.imm31_12)
|
|
},
|
|
RISCV_AUIPC => {
|
|
format!("auipc\t{},{:x}", REG_X[rd], ins.imm31_12)
|
|
},
|
|
RISCV_JAL => {
|
|
format!("jal\t{},{:x}", REG_X[rd], (pc + ins.imm21_1_signed))
|
|
},
|
|
RISCV_JALR => {
|
|
format!("jalr\t{},{:x}({})", REG_X[rd], ins.imm12_I_signed, REG_X[rs1])
|
|
},
|
|
RISCV_BR => {
|
|
format!("{}\t{},{},{:x}", NAMES_BR[ins.funct3 as usize], REG_X[rs1], REG_X[rs2], pc + (ins.imm13_signed as i32))
|
|
},
|
|
RISCV_LD => {
|
|
format!("{}\t{},{}({})", NAMES_LD[ins.funct3 as usize], REG_X[rd], ins.imm12_I_signed, REG_X[rs1])
|
|
},
|
|
RISCV_ST => {
|
|
format!("{}\t{},{}({})", NAMES_ST[ins.funct3 as usize], REG_X[rs2], ins.imm12_S_signed, REG_X[rs1])
|
|
},
|
|
RISCV_OPIW => {
|
|
if ins.funct3 == RISCV_OPIW_SRW {
|
|
if ins.funct7 == RISCV_OPIW_SRW_SRLIW {
|
|
format!("srliw\t{},{},{}", REG_X[rd], REG_X[rs1], REG_X[rs2])
|
|
} else {
|
|
format!("sraiw\t{},{},{}", REG_X[rd], REG_X[rs1], REG_X[rs2])
|
|
}
|
|
} else {
|
|
format!("{}\t{},{},0x{:x}", NAMES_OPIW[ins.funct3 as usize], REG_X[rd], REG_X[rs1], ins.imm12_I_signed)
|
|
}
|
|
},
|
|
RISCV_OPW => {
|
|
if ins.funct7 == 1 {
|
|
format!("{}w\t{},{},{}", NAMES_MUL[ins.funct3 as usize], REG_X[rd], REG_X[rs1], REG_X[rs2])
|
|
} else if ins.funct3 == RISCV_OP_ADD {
|
|
if ins.funct7 == RISCV_OPW_ADDSUBW_ADDW {
|
|
format!("addw\t{},{},{}", REG_X[rd], REG_X[rs1], REG_X[rs2])
|
|
} else {
|
|
format!("subw\t{},{},{}", REG_X[rd], REG_X[rs1], REG_X[rs2])
|
|
}
|
|
} else if ins.funct3 == RISCV_OPW_SRW {
|
|
if ins.funct7 == RISCV_OPW_SRW_SRLW {
|
|
format!("srlw\t{},{},{}", REG_X[rd], REG_X[rs1], REG_X[rs2])
|
|
} else {
|
|
format!("sraw\t{},{},{}", REG_X[rd], REG_X[rs1], REG_X[rs2])
|
|
}
|
|
} else {
|
|
format!("{}\t{},{},{}", NAMES_OPW[ins.funct3 as usize], REG_X[rd], REG_X[rs1], REG_X[rs2])
|
|
}
|
|
},
|
|
// RV32F Standard Extension
|
|
RISCV_FLW => {
|
|
format!("flw\t{},{},({})", REG_F[rd], ins.imm12_I_signed, REG_F[rs1])
|
|
},
|
|
RISCV_FSW => {
|
|
format!("fsw\t{},{},({})", REG_F[rs2], "OFFSET TODO", REG_F[rs1]) // TODO Offset in decode
|
|
},
|
|
RISCV_FMADD => {
|
|
format!("fmadd\t{}{}{}{}", REG_F[rd], REG_F[rs1], REG_F[rs2], REG_F[rs3])
|
|
},
|
|
RISCV_FMSUB => {
|
|
format!("fmsub\t{}{}{}{}", REG_F[rd], REG_F[rs1], REG_F[rs2], REG_F[rs3])
|
|
},
|
|
RISCV_FNMSUB => {
|
|
format!("fnmsub\t{}{}{}{}", REG_F[rd], REG_F[rs1], REG_F[rs2], REG_F[rs3])
|
|
},
|
|
RISCV_FNMADD => {
|
|
format!("fnmadd\t{}{}{}{}", REG_F[rd], REG_F[rs1], REG_F[rs2], REG_F[rs3])
|
|
},
|
|
RISCV_FP => {
|
|
match ins.funct7 {
|
|
RISCV_FP_ADD => {
|
|
format!("{}\t{}{}{}", "fadd", REG_F[rd], REG_F[rs1], REG_F[rs2])
|
|
},
|
|
RISCV_FP_SUB => {
|
|
format!("{}\t{}{}{}", "fsub.s", REG_F[rd], REG_F[rs1], REG_F[rs2])
|
|
},
|
|
RISCV_FP_MUL => {
|
|
format!("{}\t{}{}{}", "fmul.s", REG_F[rd], REG_F[rs1], REG_F[rs2])
|
|
},
|
|
RISCV_FP_DIV => {
|
|
format!("{}\t{}{}{}", "fdiv.s", REG_F[rd], REG_F[rs1], REG_F[rs2])
|
|
},
|
|
RISCV_FP_SQRT => {
|
|
format!("{}\t{}{}", "fsqrt.s", REG_F[rd], REG_F[rs1])
|
|
},
|
|
RISCV_FP_FSGN => {
|
|
match ins.funct3 {
|
|
RISCV_FP_FSGN_J => {
|
|
format!("{}\t{}{}{}", "fsgnj.s", REG_F[rd], REG_F[rs1], REG_F[rs2])
|
|
},
|
|
RISCV_FP_FSGN_JN => {
|
|
format!("{}\t{}{}{}", "fsgnn.s", REG_F[rd], REG_F[rs1], REG_F[rs2])
|
|
},
|
|
RISCV_FP_FSGN_JX => {
|
|
format!("{}\t{}{}{}", "fsgnx.s", REG_F[rd], REG_F[rs1], REG_F[rs2])
|
|
},
|
|
_ => todo!("Unknown code")
|
|
}
|
|
},
|
|
RISCV_FP_MINMAX => {
|
|
if ins.funct3 == 0 {
|
|
format!("{}\t{}{}{}", "fmin.s", REG_F[rd], REG_F[rs1], REG_F[rs2])
|
|
} else {
|
|
format!("{}\t{}{}{}", "fmax.s", REG_F[rd], REG_F[rs1], REG_F[rs2])
|
|
}
|
|
},
|
|
RISCV_FP_FCVTW => {
|
|
if rs2 == 0 {
|
|
format!("{}\t{}{}", "fcvt.w.s", REG_F[rd], REG_F[rs1])
|
|
} else {
|
|
format!("{}\t{}{}", "fcvt.wu.s", REG_F[rd], REG_F[rs1])
|
|
}
|
|
},
|
|
RISCV_FP_FMVXFCLASS => {
|
|
if ins.funct3 == 0 {
|
|
format!("{}\t{}{}", "fmv.x.w", REG_F[rd], REG_F[rs1])
|
|
} else {
|
|
format!("{}\t{}{}", "fclass.s", REG_F[rd], REG_F[rs1])
|
|
}
|
|
},
|
|
RISCV_FP_FCMP => {
|
|
if ins.funct3 == 0 {
|
|
format!("{}\t{}{}{}", "fle.s", REG_F[rd], REG_F[rs1], REG_F[rs2])
|
|
} else if ins.funct3 == 1 {
|
|
format!("{}\t{}{}{}", "flt.s", REG_F[rd], REG_F[rs1], REG_F[rs2])
|
|
} else {
|
|
format!("{}\t{}{}{}", "feq.s", REG_F[rd], REG_F[rs1], REG_F[rs2])
|
|
}
|
|
},
|
|
RISCV_FP_FCVTS => {
|
|
if rs2 == 0 {
|
|
format!("{}\t{}{}", "fcvt.s.w", REG_F[rd], REG_F[rs1])
|
|
} else {
|
|
format!("{}\t{}{}", "fcvt.s.wu", REG_F[rd], REG_F[rs1])
|
|
}
|
|
},
|
|
RISCV_FP_FMVW => {
|
|
format!("{}\t{}{}", "fmv.w.x", REG_F[rd], REG_F[rs1])
|
|
},
|
|
_ => todo!("Unknown code")
|
|
}
|
|
},
|
|
|
|
RISCV_SYSTEM => {
|
|
"ecall".to_string()
|
|
},
|
|
_ => todo!("{:x} opcode non géré pc : {:x}, value : {:x}", ins.opcode, pc, ins.value) // Change todo! to panic! in the future, I put todo! because there's a lot of opcode currently not implemented
|
|
}
|
|
|
|
}
|
|
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
#![allow(clippy::unusual_byte_groupings)]
|
|
|
|
use crate::simulator::instruction::*;
|
|
|
|
#[test]
|
|
fn test_op() {
|
|
let sub = Instruction::new(0b0100000_10000_10001_000_11100_0110011_u64.to_le());
|
|
let add = Instruction::new(0b0000000_10000_10001_000_11100_0110011_u64.to_le());
|
|
let xor = Instruction::new(0b0000000_10000_10001_100_11100_0110011_u64.to_le());
|
|
let slr = Instruction::new(0b0000000_10000_10001_101_11100_0110011_u64.to_le());
|
|
let sra = Instruction::new(0b0100000_10000_10001_101_11100_0110011_u64.to_le());
|
|
|
|
assert_eq!("sub\tt3,a7,a6", instruction_debug(&sub, 0));
|
|
assert_eq!("xor\tt3,a7,a6", instruction_debug(&xor, 0));
|
|
assert_eq!("srl\tt3,a7,a6", instruction_debug(&slr, 0));
|
|
assert_eq!("sra\tt3,a7,a6", instruction_debug(&sra, 0));
|
|
assert_eq!("add\tt3,a7,a6", instruction_debug(&add, 0));
|
|
|
|
}
|
|
|
|
#[test]
|
|
fn test_opi() {
|
|
let addi = Instruction::new(0b0000000000_10001_000_11100_0010011_u64.to_le());
|
|
let slli = Instruction::new(0b0000000000_10001_001_11100_0010011_u64.to_le());
|
|
let slti = Instruction::new(0b0000000000_10001_010_11100_0010011_u64.to_le());
|
|
let sltiu = Instruction::new(0b0000000000_10001_011_11100_0010011_u64.to_le());
|
|
let xori = Instruction::new(0b_0000000000010001_100_11100_0010011_u64.to_le());
|
|
let ori = Instruction::new(0b00000000000_10001_110_11100_0010011_u64.to_le());
|
|
let andi = Instruction::new(0b000000000000_10001_111_11100_0010011_u64.to_le());
|
|
assert_eq!("andi\tt3,a7,0", instruction_debug(&andi, 0));
|
|
assert_eq!("addi\tt3,a7,0", instruction_debug(&addi, 0));
|
|
assert_eq!("slli\tt3,a7,0", instruction_debug(&slli, 0));
|
|
assert_eq!("slti\tt3,a7,0", instruction_debug(&slti, 0));
|
|
assert_eq!("sltiu\tt3,a7,0", instruction_debug(&sltiu, 0));
|
|
assert_eq!("xori\tt3,a7,0", instruction_debug(&xori, 0));
|
|
assert_eq!("ori\tt3,a7,0", instruction_debug(&ori, 0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_lui() {
|
|
let lui = Instruction::new(0b01110001000011111000_11100_0110111_u64.to_le());
|
|
let lui_negatif = Instruction::new(0b11110001000011111000_11100_0110111_u64.to_le());
|
|
assert_eq!("lui\tt3,710f8000", instruction_debug(&lui, 0));
|
|
assert_eq!("lui\tt3,f10f8000", instruction_debug(&lui_negatif, 0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_ld() {
|
|
// imm rs1 f3 rd opcode
|
|
let lb = Instruction::new(0b010111110000_10001_000_11100_0000011_u64.to_le());
|
|
let lh = Instruction::new(0b010111110000_10001_001_11100_0000011_u64.to_le());
|
|
let lw = Instruction::new(0b010111110000_10001_010_11100_0000011_u64.to_le());
|
|
let lbu = Instruction::new(0b010111110000_10001_100_11100_0000011_u64.to_le());
|
|
let lhu = Instruction::new(0b010111110000_10001_101_11100_0000011_u64.to_le());
|
|
let ld = Instruction::new(0b010111110000_10001_011_11100_0000011_u64.to_le());
|
|
let lwu = Instruction::new(0b010111110000_10001_110_11100_0000011_u64.to_le());
|
|
|
|
assert_eq!("lb\tt3,1520(a7)", instruction_debug(&lb, 0));
|
|
assert_eq!("lh\tt3,1520(a7)", instruction_debug(&lh, 0));
|
|
assert_eq!("lw\tt3,1520(a7)", instruction_debug(&lw, 0));
|
|
assert_eq!("lbu\tt3,1520(a7)", instruction_debug(&lbu, 0));
|
|
assert_eq!("lhu\tt3,1520(a7)", instruction_debug(&lhu, 0));
|
|
assert_eq!("ld\tt3,1520(a7)", instruction_debug(&ld, 0));
|
|
assert_eq!("lwu\tt3,1520(a7)", instruction_debug(&lwu, 0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_opw() {
|
|
let addw: Instruction = Instruction::new(0b0000000_10000_10001_000_11100_0111011_u64.to_le());
|
|
let sllw: Instruction = Instruction::new(0b0000000_10000_10001_001_11100_0111011_u64.to_le());
|
|
let srlw: Instruction = Instruction::new(0b0000000_10000_10001_101_11100_0111011_u64.to_le());
|
|
let sraw: Instruction = Instruction::new(0b0100000_10000_10001_101_11100_0111011_u64.to_le());
|
|
|
|
assert_eq!("addw\tt3,a7,a6", instruction_debug(&addw, 0));
|
|
assert_eq!("sllw\tt3,a7,a6", instruction_debug(&sllw, 0));
|
|
assert_eq!("srlw\tt3,a7,a6", instruction_debug(&srlw, 0));
|
|
assert_eq!("sraw\tt3,a7,a6", instruction_debug(&sraw, 0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_opwi() {
|
|
let addiw: Instruction =Instruction::new(0b000000000000_10001_000_11100_0011011_u64.to_le());
|
|
let slliw: Instruction = Instruction::new(0b0000000_10000_10001_001_11100_0011011_u64.to_le());
|
|
let srai: Instruction = Instruction::new(0b010000010001_10001_101_11100_0010011_u64.to_le());
|
|
assert_eq!("addiw\tt3,a7,0x0", instruction_debug(&addiw, 0));
|
|
assert_eq!("slliw\tt3,a7,0x10", instruction_debug(&slliw, 0));
|
|
assert_eq!("srai\tt3,a7,17", instruction_debug(&srai, 0));
|
|
|
|
}
|
|
|
|
#[test]
|
|
fn test_br() {
|
|
let beq: Instruction = Instruction::new(0b0000000_10000_10001_000_00000_1100011_u64.to_le());
|
|
let bne: Instruction = Instruction::new(0b0000000_10000_10001_001_00000_1100011_u64.to_le());
|
|
let blt: Instruction = Instruction::new(0b0000000_10000_10001_100_00000_1100011_u64.to_le());
|
|
let bge: Instruction = Instruction::new(0b0000000_10000_10001_101_00000_1100011_u64.to_le());
|
|
let bge2: Instruction = Instruction::new(0x00f75863_u64.to_le());
|
|
let bltu: Instruction = Instruction::new(0b0000000_10000_10001_110_00000_1100011_u64.to_le());
|
|
let bgeu: Instruction = Instruction::new(0b0000000_10000_10001_111_00000_1100011_u64.to_le());
|
|
assert_eq!("blt\ta7,a6,0", instruction_debug(&blt, 0));
|
|
assert_eq!("bge\ta7,a6,0", instruction_debug(&bge, 0));
|
|
assert_eq!("bge\ta4,a5,104d4", instruction_debug(&bge2, 0x104c4));
|
|
assert_eq!("bltu\ta7,a6,0", instruction_debug(&bltu, 0));
|
|
assert_eq!("bgeu\ta7,a6,0", instruction_debug(&bgeu, 0));
|
|
assert_eq!("bne\ta7,a6,0", instruction_debug(&bne, 0));
|
|
assert_eq!("beq\ta7,a6,0", instruction_debug(&beq, 0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_small_program() {
|
|
/* Code for :
|
|
int a = 0;
|
|
int b = 5;
|
|
a = b;
|
|
a = a * b;
|
|
a = a + b;
|
|
b = a - b;
|
|
*/
|
|
assert_eq!("addi sp,sp,-32", instruction_debug(&Instruction::new(0xfe010113_u64.to_le()), 0));
|
|
assert_eq!("sd s0,24(sp)", instruction_debug(&Instruction::new(0x00813c23_u64.to_le()), 0));
|
|
assert_eq!("addi s0,sp,32", instruction_debug(&Instruction::new(0x02010413_u64.to_le()), 0));
|
|
assert_eq!("sw zero,-20(s0)", instruction_debug(&Instruction::new(0xfe042623_u64.to_le()), 0));
|
|
assert_eq!("addi a5,zero,5", instruction_debug(&Instruction::new(0x00500793_u64.to_le()), 0));
|
|
assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423_u64.to_le()), 0));
|
|
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0));
|
|
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0));
|
|
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0));
|
|
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0));
|
|
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0));
|
|
assert_eq!("mulw a5,a4,a5", instruction_debug(&Instruction::new(0x02f707bb_u64.to_le()), 0));
|
|
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0));
|
|
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0));
|
|
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0));
|
|
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0));
|
|
assert_eq!("addw a5,a4,a5", instruction_debug(&Instruction::new(0x00f707bb_u64.to_le()), 0));
|
|
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0));
|
|
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0));
|
|
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0));
|
|
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0));
|
|
assert_eq!("subw a5,a4,a5", instruction_debug(&Instruction::new(0x40f707bb_u64.to_le()), 0));
|
|
assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423_u64.to_le()), 0));
|
|
assert_eq!("addi a5,zero,0", instruction_debug(&Instruction::new(0x00000793_u64.to_le()), 0));
|
|
assert_eq!("addi a0,a5,0", instruction_debug(&Instruction::new(0x00078513_u64.to_le()), 0));
|
|
assert_eq!("ld s0,24(sp)", instruction_debug(&Instruction::new(0x01813403_u64.to_le()), 0));
|
|
assert_eq!("addi sp,sp,32", instruction_debug(&Instruction::new(0x02010113_u64.to_le()), 0));
|
|
assert_eq!("jalr zero,0(ra)", instruction_debug(&Instruction::new(0x00008067_u64.to_le()), 0));
|
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
fn test_fibo() {
|
|
assert_eq!("jal zero,10504", instruction_debug(&Instruction::new(0x0500006f_u64.to_le()), 0x104b4));
|
|
assert_eq!("blt a4,a5,104b8", instruction_debug(&Instruction::new(0xfaf740e3_u64.to_le()), 0x10518));
|
|
}
|
|
|
|
#[test]
|
|
fn test_mul_prog() {
|
|
assert_eq!("addi sp,sp,-32", instruction_debug(&Instruction::new(0xfe010113_u64.to_le()), 0));
|
|
assert_eq!("sd s0,24(sp)", instruction_debug(&Instruction::new(0x00813c23_u64.to_le()), 0));
|
|
assert_eq!("addi s0,sp,32", instruction_debug(&Instruction::new(0x02010413_u64.to_le()), 0));
|
|
assert_eq!("addi a5,zero,5", instruction_debug(&Instruction::new(0x00500793_u64.to_le()), 0));
|
|
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0));
|
|
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0));
|
|
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0));
|
|
assert_eq!("addi a5,a4,0", instruction_debug(&Instruction::new(0x00070793_u64.to_le()), 0));
|
|
assert_eq!("slliw a5,a5,0x2", instruction_debug(&Instruction::new(0x0027979b_u64.to_le()), 0));
|
|
assert_eq!("addw a5,a5,a4", instruction_debug(&Instruction::new(0x00e787bb_u64.to_le()), 0));
|
|
assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423_u64.to_le()), 0));
|
|
assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783_u64.to_le()), 0));
|
|
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0));
|
|
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0));
|
|
assert_eq!("mulw a5,a4,a5", instruction_debug(&Instruction::new(0x02f707bb_u64.to_le()), 0));
|
|
assert_eq!("sw a5,-28(s0)", instruction_debug(&Instruction::new(0xfef42223_u64.to_le()), 0));
|
|
assert_eq!("lw a5,-28(s0)", instruction_debug(&Instruction::new(0xfe442783_u64.to_le()), 0));
|
|
assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713_u64.to_le()), 0));
|
|
assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783_u64.to_le()), 0));
|
|
assert_eq!("divw a5,a4,a5", instruction_debug(&Instruction::new(0x02f747bb_u64.to_le()), 0));
|
|
assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623_u64.to_le()), 0));
|
|
assert_eq!("addi a5,zero,0", instruction_debug(&Instruction::new(0x00000793_u64.to_le()), 0));
|
|
assert_eq!("addi a0,a5,0", instruction_debug(&Instruction::new(0x00078513_u64.to_le()), 0));
|
|
assert_eq!("ld s0,24(sp)", instruction_debug(&Instruction::new(0x01813403_u64.to_le()), 0));
|
|
assert_eq!("addi sp,sp,32", instruction_debug(&Instruction::new(0x02010113_u64.to_le()), 0));
|
|
assert_eq!("jalr zero,0(ra)", instruction_debug(&Instruction::new(0x00008067_u64.to_le()), 0));
|
|
}
|
|
|
|
} |