2023-03-29 16:26:27 +02:00
//! # Instruction
//!
//! This module describes the internal representation of an
//!
2023-03-29 16:08:06 +02:00
use core ::num ::Wrapping ; // Permet d'autoriser les overflow pour les opérations voulues
use super ::global ::* ;
const NAMES_OP : [ & str ; 8 ] = [ " add " , " sll " , " slt " , " sltu " , " xor " , " sr " , " or " , " and " ] ;
const NAMES_OPI : [ & str ; 8 ] = [ " addi " , " slli " , " slti " , " sltiu " , " xori " , " slri " , " ori " , " andi " ] ;
const NAMES_MUL : [ & str ; 8 ] = [ " mul " , " mulh " , " mulhsu " , " mulhu " , " div " , " divu " , " rem " , " remu " ] ;
const NAMES_BR : [ & str ; 8 ] = [ " beq " , " bne " , " " , " " , " blt " , " bge " , " bltu " , " bgeu " ] ;
const NAMES_ST : [ & str ; 4 ] = [ " sb " , " sh " , " sw " , " sd " ] ;
const NAMES_LD : [ & str ; 7 ] = [ " lb " , " lh " , " lw " , " ld " , " lbu " , " lhu " , " lwu " ] ;
const NAMES_OPW : [ & str ; 8 ] = [ " addw " , " sllw " , " " , " " , " " , " srw " , " " , " " ] ;
const NAMES_OPIW : [ & str ; 8 ] = [ " addiw " , " slliw " , " " , " " , " " , " sri " , " " , " " ] ;
// 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 " ] ;
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 " ] ;
#[ derive(Debug) ]
pub struct Instruction {
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 ,
}
2023-03-29 16:26:27 +02:00
impl Instruction {
2023-03-29 16:08:06 +02:00
2023-03-29 16:26:27 +02:00
pub fn new ( val : u64 ) -> Self {
2023-03-29 16:08:06 +02:00
2023-03-29 16:26:27 +02:00
let value = val ;
2023-03-29 16:08:06 +02:00
2023-03-29 16:26:27 +02:00
let opcode = ( val & 0x7f ) as u8 ;
let rs1 = ( ( val > > 15 ) & 0x1f ) as u8 ;
let rs2 = ( ( val > > 20 ) & 0x1f ) as u8 ;
let rs3 = ( ( val > > 27 ) & 0x1f ) as u8 ;
let rd = ( ( val > > 7 ) & 0x1f ) as u8 ;
let funct7 = ( ( val > > 25 ) & 0x7f ) as u8 ;
let funct7_smaller = funct7 & 0x3e ;
let funct3 = ( ( val > > 12 ) & 0x7 ) as u8 ;
let imm12_I = ( ( val > > 20 ) & 0xfff ) as u16 ;
let imm12_S = ( ( ( val > > 20 ) & 0xfe0 ) + ( ( val > > 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 = ( ( ( val > > 19 ) & 0x1000 ) + ( ( val > > 20 ) & 0x7e0 ) +
( ( val > > 7 ) & 0x1e ) + ( ( val < < 4 ) & 0x800 ) ) as i16 ;
let imm13_signed = if imm13 > = 4096 { imm13 - 8192 } else { imm13 } ;
let imm31_12 = ( val & 0xfffff000 ) as u32 ;
let imm31_12_signed = imm31_12 as i32 ;
let imm21_1 = ( ( val & 0xff000 ) + ( ( val > > 9 ) & 0x800 ) +
( ( val > > 20 ) & 0x7fe ) + ( ( val > > 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 = ( ( val > > 20 ) & 0x3f ) as u8 ;
Instruction {
value ,
2023-03-29 16:08:06 +02:00
2023-03-29 16:26:27 +02:00
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
}
2023-03-29 16:08:06 +02:00
}
2023-03-29 16:26:27 +02:00
2023-03-29 16:08:06 +02:00
}
2023-03-29 16:26:27 +02:00
pub fn print_instruction_debug ( ins : & Instruction , pc : i32 ) -> String { //TODO pc should be u64
2023-03-29 16:08:06 +02:00
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
}
}
2023-03-29 16:26:27 +02:00
2023-03-29 16:08:06 +02:00
#[ cfg(test) ]
mod test {
#![ allow(clippy::unusual_byte_groupings) ]
use crate ::simulator ::instruction ::* ;
#[ test ]
fn test_op ( ) {
2023-03-29 16:26:27 +02:00
let sub = Instruction ::new ( 0b0100000_10000_10001_000_11100_0110011 ) ;
let add = Instruction ::new ( 0b0000000_10000_10001_000_11100_0110011 ) ;
let xor = Instruction ::new ( 0b0000000_10000_10001_100_11100_0110011 ) ;
let slr = Instruction ::new ( 0b0000000_10000_10001_101_11100_0110011 ) ;
let sra = Instruction ::new ( 0b0100000_10000_10001_101_11100_0110011 ) ;
assert_eq! ( " sub \t t3,a7,a6 " , print_instruction_debug ( & sub , 0 ) ) ;
assert_eq! ( " xor \t t3,a7,a6 " , print_instruction_debug ( & xor , 0 ) ) ;
assert_eq! ( " srl \t t3,a7,a6 " , print_instruction_debug ( & slr , 0 ) ) ;
assert_eq! ( " sra \t t3,a7,a6 " , print_instruction_debug ( & sra , 0 ) ) ;
assert_eq! ( " add \t t3,a7,a6 " , print_instruction_debug ( & add , 0 ) ) ;
2023-03-29 16:08:06 +02:00
}
#[ test ]
fn test_opi ( ) {
2023-03-29 16:26:27 +02:00
let addi = Instruction ::new ( 0b0000000000_10001_000_11100_0010011 ) ;
let slli = Instruction ::new ( 0b0000000000_10001_001_11100_0010011 ) ;
let slti = Instruction ::new ( 0b0000000000_10001_010_11100_0010011 ) ;
let sltiu = Instruction ::new ( 0b0000000000_10001_011_11100_0010011 ) ;
let xori = Instruction ::new ( 0b_0000000000010001_100_11100_0010011 ) ;
let ori = Instruction ::new ( 0b00000000000_10001_110_11100_0010011 ) ;
let andi = Instruction ::new ( 0b000000000000_10001_111_11100_0010011 ) ;
assert_eq! ( " andi \t t3,a7,0 " , print_instruction_debug ( & andi , 0 ) ) ;
assert_eq! ( " addi \t t3,a7,0 " , print_instruction_debug ( & addi , 0 ) ) ;
assert_eq! ( " slli \t t3,a7,0 " , print_instruction_debug ( & slli , 0 ) ) ;
assert_eq! ( " slti \t t3,a7,0 " , print_instruction_debug ( & slti , 0 ) ) ;
assert_eq! ( " sltiu \t t3,a7,0 " , print_instruction_debug ( & sltiu , 0 ) ) ;
assert_eq! ( " xori \t t3,a7,0 " , print_instruction_debug ( & xori , 0 ) ) ;
assert_eq! ( " ori \t t3,a7,0 " , print_instruction_debug ( & ori , 0 ) ) ;
2023-03-29 16:08:06 +02:00
}
#[ test ]
fn test_lui ( ) {
2023-03-29 16:26:27 +02:00
let lui = Instruction ::new ( 0b01110001000011111000_11100_0110111 ) ;
let lui_negatif = Instruction ::new ( 0b11110001000011111000_11100_0110111 ) ;
assert_eq! ( " lui \t t3,710f8000 " , print_instruction_debug ( & lui , 0 ) ) ;
assert_eq! ( " lui \t t3,f10f8000 " , print_instruction_debug ( & lui_negatif , 0 ) ) ;
2023-03-29 16:08:06 +02:00
}
#[ test ]
fn test_ld ( ) {
// imm rs1 f3 rd opcode
2023-03-29 16:26:27 +02:00
let lb = Instruction ::new ( 0b010111110000_10001_000_11100_0000011 ) ;
let lh = Instruction ::new ( 0b010111110000_10001_001_11100_0000011 ) ;
let lw = Instruction ::new ( 0b010111110000_10001_010_11100_0000011 ) ;
let lbu = Instruction ::new ( 0b010111110000_10001_100_11100_0000011 ) ;
let lhu = Instruction ::new ( 0b010111110000_10001_101_11100_0000011 ) ;
let ld = Instruction ::new ( 0b010111110000_10001_011_11100_0000011 ) ;
let lwu = Instruction ::new ( 0b010111110000_10001_110_11100_0000011 ) ;
assert_eq! ( " lb \t t3,1520(a7) " , print_instruction_debug ( & lb , 0 ) ) ;
assert_eq! ( " lh \t t3,1520(a7) " , print_instruction_debug ( & lh , 0 ) ) ;
assert_eq! ( " lw \t t3,1520(a7) " , print_instruction_debug ( & lw , 0 ) ) ;
assert_eq! ( " lbu \t t3,1520(a7) " , print_instruction_debug ( & lbu , 0 ) ) ;
assert_eq! ( " lhu \t t3,1520(a7) " , print_instruction_debug ( & lhu , 0 ) ) ;
assert_eq! ( " ld \t t3,1520(a7) " , print_instruction_debug ( & ld , 0 ) ) ;
assert_eq! ( " lwu \t t3,1520(a7) " , print_instruction_debug ( & lwu , 0 ) ) ;
2023-03-29 16:08:06 +02:00
}
#[ test ]
fn test_opw ( ) {
2023-03-29 16:26:27 +02:00
let addw : Instruction = Instruction ::new ( 0b0000000_10000_10001_000_11100_0111011 ) ;
let sllw : Instruction = Instruction ::new ( 0b0000000_10000_10001_001_11100_0111011 ) ;
let srlw : Instruction = Instruction ::new ( 0b0000000_10000_10001_101_11100_0111011 ) ;
let sraw : Instruction = Instruction ::new ( 0b0100000_10000_10001_101_11100_0111011 ) ;
assert_eq! ( " addw \t t3,a7,a6 " , print_instruction_debug ( & addw , 0 ) ) ;
assert_eq! ( " sllw \t t3,a7,a6 " , print_instruction_debug ( & sllw , 0 ) ) ;
assert_eq! ( " srlw \t t3,a7,a6 " , print_instruction_debug ( & srlw , 0 ) ) ;
assert_eq! ( " sraw \t t3,a7,a6 " , print_instruction_debug ( & sraw , 0 ) ) ;
2023-03-29 16:08:06 +02:00
}
#[ test ]
fn test_opwi ( ) {
2023-03-29 16:26:27 +02:00
let addiw : Instruction = Instruction ::new ( 0b000000000000_10001_000_11100_0011011 ) ;
let slliw : Instruction = Instruction ::new ( 0b0000000_10000_10001_001_11100_0011011 ) ;
let srai : Instruction = Instruction ::new ( 0b010000010001_10001_101_11100_0010011 ) ;
assert_eq! ( " addiw \t t3,a7,0x0 " , print_instruction_debug ( & addiw , 0 ) ) ;
assert_eq! ( " slliw \t t3,a7,0x10 " , print_instruction_debug ( & slliw , 0 ) ) ;
assert_eq! ( " srai \t t3,a7,17 " , print_instruction_debug ( & srai , 0 ) ) ;
2023-03-29 16:08:06 +02:00
}
#[ test ]
fn test_br ( ) {
2023-03-29 16:26:27 +02:00
let beq : Instruction = Instruction ::new ( 0b0000000_10000_10001_000_00000_1100011 ) ;
let bne : Instruction = Instruction ::new ( 0b0000000_10000_10001_001_00000_1100011 ) ;
let blt : Instruction = Instruction ::new ( 0b0000000_10000_10001_100_00000_1100011 ) ;
let bge : Instruction = Instruction ::new ( 0b0000000_10000_10001_101_00000_1100011 ) ;
let bge2 : Instruction = Instruction ::new ( 0x00f75863 ) ;
let bltu : Instruction = Instruction ::new ( 0b0000000_10000_10001_110_00000_1100011 ) ;
let bgeu : Instruction = Instruction ::new ( 0b0000000_10000_10001_111_00000_1100011 ) ;
assert_eq! ( " blt \t a7,a6,0 " , print_instruction_debug ( & blt , 0 ) ) ;
assert_eq! ( " bge \t a7,a6,0 " , print_instruction_debug ( & bge , 0 ) ) ;
assert_eq! ( " bge \t a4,a5,104d4 " , print_instruction_debug ( & bge2 , 0x104c4 ) ) ;
assert_eq! ( " bltu \t a7,a6,0 " , print_instruction_debug ( & bltu , 0 ) ) ;
assert_eq! ( " bgeu \t a7,a6,0 " , print_instruction_debug ( & bgeu , 0 ) ) ;
assert_eq! ( " bne \t a7,a6,0 " , print_instruction_debug ( & bne , 0 ) ) ;
assert_eq! ( " beq \t a7,a6,0 " , print_instruction_debug ( & beq , 0 ) ) ;
2023-03-29 16:08:06 +02:00
}
#[ test ]
fn test_small_program ( ) {
/* Code for :
int a = 0 ;
int b = 5 ;
a = b ;
a = a * b ;
a = a + b ;
b = a - b ;
* /
2023-03-29 16:26:27 +02:00
assert_eq! ( " addi sp,sp,-32 " , print_instruction_debug ( & Instruction ::new ( 0xfe010113 ) , 0 ) ) ;
assert_eq! ( " sd s0,24(sp) " , print_instruction_debug ( & Instruction ::new ( 0x00813c23 ) , 0 ) ) ;
assert_eq! ( " addi s0,sp,32 " , print_instruction_debug ( & Instruction ::new ( 0x02010413 ) , 0 ) ) ;
assert_eq! ( " sw zero,-20(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfe042623 ) , 0 ) ) ;
assert_eq! ( " addi a5,zero,5 " , print_instruction_debug ( & Instruction ::new ( 0x00500793 ) , 0 ) ) ;
assert_eq! ( " sw a5,-24(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfef42423 ) , 0 ) ) ;
assert_eq! ( " lw a5,-24(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfe842783 ) , 0 ) ) ;
assert_eq! ( " sw a5,-20(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfef42623 ) , 0 ) ) ;
assert_eq! ( " lw a5,-20(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfec42783 ) , 0 ) ) ;
assert_eq! ( " addi a4,a5,0 " , print_instruction_debug ( & Instruction ::new ( 0x00078713 ) , 0 ) ) ;
assert_eq! ( " lw a5,-24(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfe842783 ) , 0 ) ) ;
assert_eq! ( " mulw a5,a4,a5 " , print_instruction_debug ( & Instruction ::new ( 0x02f707bb ) , 0 ) ) ;
assert_eq! ( " sw a5,-20(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfef42623 ) , 0 ) ) ;
assert_eq! ( " lw a5,-20(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfec42783 ) , 0 ) ) ;
assert_eq! ( " addi a4,a5,0 " , print_instruction_debug ( & Instruction ::new ( 0x00078713 ) , 0 ) ) ;
assert_eq! ( " lw a5,-24(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfe842783 ) , 0 ) ) ;
assert_eq! ( " addw a5,a4,a5 " , print_instruction_debug ( & Instruction ::new ( 0x00f707bb ) , 0 ) ) ;
assert_eq! ( " sw a5,-20(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfef42623 ) , 0 ) ) ;
assert_eq! ( " lw a5,-20(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfec42783 ) , 0 ) ) ;
assert_eq! ( " addi a4,a5,0 " , print_instruction_debug ( & Instruction ::new ( 0x00078713 ) , 0 ) ) ;
assert_eq! ( " lw a5,-24(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfe842783 ) , 0 ) ) ;
assert_eq! ( " subw a5,a4,a5 " , print_instruction_debug ( & Instruction ::new ( 0x40f707bb ) , 0 ) ) ;
assert_eq! ( " sw a5,-24(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfef42423 ) , 0 ) ) ;
assert_eq! ( " addi a5,zero,0 " , print_instruction_debug ( & Instruction ::new ( 0x00000793 ) , 0 ) ) ;
assert_eq! ( " addi a0,a5,0 " , print_instruction_debug ( & Instruction ::new ( 0x00078513 ) , 0 ) ) ;
assert_eq! ( " ld s0,24(sp) " , print_instruction_debug ( & Instruction ::new ( 0x01813403 ) , 0 ) ) ;
assert_eq! ( " addi sp,sp,32 " , print_instruction_debug ( & Instruction ::new ( 0x02010113 ) , 0 ) ) ;
assert_eq! ( " jalr zero,0(ra) " , print_instruction_debug ( & Instruction ::new ( 0x00008067 ) , 0 ) ) ;
2023-03-29 16:08:06 +02:00
}
#[ test ]
fn test_fibo ( ) {
2023-03-29 16:26:27 +02:00
assert_eq! ( " jal zero,10504 " , print_instruction_debug ( & Instruction ::new ( 0x0500006f ) , 0x104b4 ) ) ;
assert_eq! ( " blt a4,a5,104b8 " , print_instruction_debug ( & Instruction ::new ( 0xfaf740e3 ) , 0x10518 ) ) ;
2023-03-29 16:08:06 +02:00
}
#[ test ]
fn test_mul_prog ( ) {
2023-03-29 16:26:27 +02:00
assert_eq! ( " addi sp,sp,-32 " , print_instruction_debug ( & Instruction ::new ( 0xfe010113 ) , 0 ) ) ;
assert_eq! ( " sd s0,24(sp) " , print_instruction_debug ( & Instruction ::new ( 0x00813c23 ) , 0 ) ) ;
assert_eq! ( " addi s0,sp,32 " , print_instruction_debug ( & Instruction ::new ( 0x02010413 ) , 0 ) ) ;
assert_eq! ( " addi a5,zero,5 " , print_instruction_debug ( & Instruction ::new ( 0x00500793 ) , 0 ) ) ;
assert_eq! ( " sw a5,-20(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfef42623 ) , 0 ) ) ;
assert_eq! ( " lw a5,-20(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfec42783 ) , 0 ) ) ;
assert_eq! ( " addi a4,a5,0 " , print_instruction_debug ( & Instruction ::new ( 0x00078713 ) , 0 ) ) ;
assert_eq! ( " addi a5,a4,0 " , print_instruction_debug ( & Instruction ::new ( 0x00070793 ) , 0 ) ) ;
assert_eq! ( " slliw a5,a5,0x2 " , print_instruction_debug ( & Instruction ::new ( 0x0027979b ) , 0 ) ) ;
assert_eq! ( " addw a5,a5,a4 " , print_instruction_debug ( & Instruction ::new ( 0x00e787bb ) , 0 ) ) ;
assert_eq! ( " sw a5,-24(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfef42423 ) , 0 ) ) ;
assert_eq! ( " lw a5,-20(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfec42783 ) , 0 ) ) ;
assert_eq! ( " addi a4,a5,0 " , print_instruction_debug ( & Instruction ::new ( 0x00078713 ) , 0 ) ) ;
assert_eq! ( " lw a5,-24(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfe842783 ) , 0 ) ) ;
assert_eq! ( " mulw a5,a4,a5 " , print_instruction_debug ( & Instruction ::new ( 0x02f707bb ) , 0 ) ) ;
assert_eq! ( " sw a5,-28(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfef42223 ) , 0 ) ) ;
assert_eq! ( " lw a5,-28(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfe442783 ) , 0 ) ) ;
assert_eq! ( " addi a4,a5,0 " , print_instruction_debug ( & Instruction ::new ( 0x00078713 ) , 0 ) ) ;
assert_eq! ( " lw a5,-24(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfe842783 ) , 0 ) ) ;
assert_eq! ( " divw a5,a4,a5 " , print_instruction_debug ( & Instruction ::new ( 0x02f747bb ) , 0 ) ) ;
assert_eq! ( " sw a5,-20(s0) " , print_instruction_debug ( & Instruction ::new ( 0xfef42623 ) , 0 ) ) ;
assert_eq! ( " addi a5,zero,0 " , print_instruction_debug ( & Instruction ::new ( 0x00000793 ) , 0 ) ) ;
assert_eq! ( " addi a0,a5,0 " , print_instruction_debug ( & Instruction ::new ( 0x00078513 ) , 0 ) ) ;
assert_eq! ( " ld s0,24(sp) " , print_instruction_debug ( & Instruction ::new ( 0x01813403 ) , 0 ) ) ;
assert_eq! ( " addi sp,sp,32 " , print_instruction_debug ( & Instruction ::new ( 0x02010113 ) , 0 ) ) ;
assert_eq! ( " jalr zero,0(ra) " , print_instruction_debug ( & Instruction ::new ( 0x00008067 ) , 0 ) ) ;
2023-03-29 16:08:06 +02:00
}
}