use std::num::FpCategory; pub fn add(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1].wrapping_add(registers[rs2]); } pub fn sub(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1].wrapping_sub(registers[rs2]); } pub fn xor(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1] ^ registers[rs2]; } pub fn or(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1] | registers[rs2]; } pub fn and(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1] & registers[rs2]; } pub fn sll(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1] << (registers[rs2] & 0b11111); } pub fn srl(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1] >> (registers[rs2] & 0b11111); } pub fn sra(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = ((registers[rs1] as i32) >> (registers[rs2] & 0b11111)) as u32; } pub fn slt(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { let rs1_signed = registers[rs1] as i32; let rs2_signed = registers[rs2] as i32; registers[rd] = if rs1_signed < rs2_signed { 1 } else { 0 }; } pub fn sltu(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = if registers[rs1] < registers[rs2] { 1 } else { 0 }; } pub fn mul(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1].wrapping_mul(registers[rs2]); } pub fn mulh(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = (((registers[rs1] as i32 as i64) * (registers[rs2] as i32 as i64)) >> 32) as u32; } pub fn mulhsu(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { let rs1_signed = (registers[rs1] as i32) as i64; let rs2_unsigned = registers[rs2] as i64; registers[rd] = ((rs1_signed * rs2_unsigned) >> 32) as u32; } pub fn mulhu(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = ((registers[rs1] as u64 * registers[rs2] as u64) >> 32) as u32; } pub fn div(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { let a = registers[rs1] as i32; let b = registers[rs2] as i32; registers[rd] = if b == 0 { u32::MAX } else if a == i32::MIN && b == -1 { a as u32 } else { (a / b) as u32 }; } pub fn divu(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = if registers[rs2] == 0 { u32::MAX } else { registers[rs1] / registers[rs2] }; } pub fn rem(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { let a = registers[rs1] as i32; let b = registers[rs2] as i32; registers[rd] = if b == 0 { a as u32 } else if a == i32::MIN && b == -1 { 0 } else { (a % b) as u32 }; } pub fn remu(registers: &mut [u32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = if registers[rs2] == 0 { registers[rs1] } else { registers[rs1] % registers[rs2] }; } pub fn addi(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { registers[rd] = registers[rs1].wrapping_add(imm); } pub fn xori(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { registers[rd] = registers[rs1] ^ imm; } pub fn ori(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { registers[rd] = registers[rs1] | imm; } pub fn andi(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { registers[rd] = registers[rs1] & imm; } pub fn slli(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { registers[rd] = registers[rs1] << (imm & 0b11111); } pub fn srli(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { registers[rd] = registers[rs1] >> (imm & 0b11111); } pub fn srai(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { registers[rd] = ((registers[rs1] as i32) >> (imm & 0b11111)) as u32; } pub fn slti(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { registers[rd] = if (registers[rs1] as i32) < (imm as i32) { 1 } else { 0 }; } pub fn sltiu(registers: &mut [u32; 32], rd: usize, rs1: usize, imm: u32) { registers[rd] = if registers[rs1] < imm { 1 } else { 0 }; } pub fn lb(registers: &mut [u32; 32], memory: &[u8], rd: usize, rs1: usize, imm: u32) { let byte = memory[(registers[rs1] + imm) as usize]; registers[rd] = (byte as i8) as u32; } pub fn lh(registers: &mut [u32; 32], memory: &[u8], rd: usize, rs1: usize, imm: u32) { let low = memory[(registers[rs1] + imm) as usize]; let high = memory[(registers[rs1] + imm + 1) as usize]; registers[rd] = (((high as u16) << 8 | low as u16) as i16) as u32; } pub fn lw(registers: &mut [u32; 32], memory: &[u8], rd: usize, rs1: usize, imm: u32) { let addr = (registers[rs1] + imm) as usize; let slice = memory.get(addr..addr + 4).unwrap(); let number = u32::from_le_bytes(slice.try_into().unwrap()); registers[rd] = number; } pub fn lbu(registers: &mut [u32; 32], memory: &[u8], rd: usize, rs1: usize, imm: u32) { registers[rd] = memory[(registers[rs1] + imm) as usize] as u32; } pub fn lhu(registers: &mut [u32; 32], memory: &[u8], rd: usize, rs1: usize, imm: u32) { let low = memory[(registers[rs1] + imm) as usize]; let high = memory[(registers[rs1] + imm + 1) as usize]; registers[rd] = ((high as u16) << 8 | low as u16) as u32; } pub fn sb(registers: &[u32; 32], memory: &mut [u8], rs1: usize, rs2: usize, imm: u32) { memory[(registers[rs1] + imm) as usize] = registers[rs2] as u8; } pub fn sh(registers: &[u32; 32], memory: &mut [u8], rs1: usize, rs2: usize, imm: u32) { let halfword = registers[rs2] & 0xFFFF; let index = (registers[rs1] + imm) as usize; memory[index] = (halfword & 0xFF) as u8; memory[index + 1] = (halfword >> 8) as u8; } pub fn sw(registers: &[u32; 32], memory: &mut [u8], rs1: usize, rs2: usize, imm: u32) { let index = (registers[rs1] + imm) as usize; memory[index..index + 4].copy_from_slice(®isters[rs2].to_le_bytes()); } pub fn beq(registers: &[u32; 32], pc: &mut u32, rs1: usize, rs2: usize, imm: u32) { if registers[rs1] == registers[rs2] { *pc += imm; } } pub fn bne(registers: &[u32; 32], pc: &mut u32, rs1: usize, rs2: usize, imm: u32) { if registers[rs1] != registers[rs2] { *pc += imm; } } pub fn blt(registers: &[u32; 32], pc: &mut u32, rs1: usize, rs2: usize, imm: u32) { if (registers[rs1] as i32) < (registers[rs2] as i32) { *pc += imm; } } pub fn bge(registers: &[u32; 32], pc: &mut u32, rs1: usize, rs2: usize, imm: u32) { if (registers[rs1] as i32) >= (registers[rs2] as i32) { *pc += imm; } } pub fn bltu(registers: &[u32; 32], pc: &mut u32, rs1: usize, rs2: usize, imm: u32) { if registers[rs1] < registers[rs2] { *pc += imm; } } pub fn bgeu(registers: &[u32; 32], pc: &mut u32, rs1: usize, rs2: usize, imm: u32) { if registers[rs1] >= registers[rs2] { *pc += imm; } } pub fn jal(registers: &mut [u32; 32], pc: &mut u32, rd: usize, imm: u32) { registers[rd] = *pc + 4; *pc += imm; } pub fn jalr(registers: &mut [u32; 32], pc: &mut u32, rd: usize, rs1: usize, imm: u32) { registers[rd] = *pc + 4; *pc = registers[rs1] + imm; } pub fn lui(registers: &mut [u32; 32], rd: usize, imm: u32) { registers[rd] = imm << 12; } pub fn auipc(registers: &mut [u32; 32], pc: u32, rd: usize, imm: u32) { registers[rd] = pc + (imm << 12); } pub fn fmadd_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize, rs3: usize) { registers[rd] = registers[rs1] * registers[rs2] + registers[rs3]; } pub fn fmsub_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize, rs3: usize) { registers[rd] = registers[rs1] * registers[rs2] - registers[rs3]; } pub fn fnmadd_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize, rs3: usize) { registers[rd] = -registers[rs1] * registers[rs2] + registers[rs3]; } pub fn fnmsub_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize, rs3: usize) { registers[rd] = -registers[rs1] * registers[rs2] - registers[rs3]; } pub fn fadd_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1] + registers[rs2]; } pub fn fsub_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1] - registers[rs2]; } pub fn fmul_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1] * registers[rs2]; } pub fn fdiv_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { let a = registers[rs1]; let b = registers[rs2]; registers[rd] = if b == 0.0 { f32::NAN // todo: raise division by zero in csr } else { a / b } } pub fn fsqrt_s(registers: &mut [f32; 32], rd: usize, rs1: usize) { registers[rd] = registers[rs1].sqrt(); } pub fn fsgnj_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1].abs() * registers[rs2].signum(); } pub fn fsgnjn_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1].abs() * -registers[rs2].signum(); } pub fn fsgnjx_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1] * registers[rs2].signum(); } pub fn fmin_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1].min(registers[rs2]); } pub fn fmax_s(registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize) { registers[rd] = registers[rs1].max(registers[rs2]); } pub fn fcvt_s_w(registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize) { f_registers[rd] = registers[rs1] as i32 as f32; } pub fn fcvt_s_wu(registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize) { f_registers[rd] = registers[rs1] as f32; } pub fn fcvt_w_s(registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize) { registers[rd] = f_registers[rs1] as i32 as u32; } pub fn fcvt_wu_s(registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize) { registers[rd] = f_registers[rs1] as u32; } pub fn fmv_x_w(registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize) { registers[rd] = u32::from_le_bytes(f_registers[rs1].to_le_bytes()); } pub fn fmv_w_x(registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize) { f_registers[rd] = f32::from_le_bytes(registers[rs1].to_le_bytes()); } pub fn feq_s( registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize, ) { registers[rd] = if f_registers[rs1] == f_registers[rs2] { 1 } else { 0 } } pub fn flt_s( registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize, ) { registers[rd] = if f_registers[rs1] < f_registers[rs2] { 1 } else { 0 } } pub fn fle_s( registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize, rs2: usize, ) { registers[rd] = if f_registers[rs1] <= f_registers[rs2] { 1 } else { 0 } } pub fn fclass_s(registers: &mut [u32; 32], f_registers: &mut [f32; 32], rd: usize, rs1: usize) { let number = f_registers[rs1]; let class = number.classify(); let frac_msb = (number.to_bits() >> 22) & 0x01; registers[rd] = match class { FpCategory::Nan => { if frac_msb == 0 { 0b1 } else { 0b10 } } FpCategory::Infinite => { if number.is_sign_negative() { 0b100 } else { 0b100000000 } } FpCategory::Zero => { if number.is_sign_negative() { 0b10000 } else { 0b100000 } } FpCategory::Subnormal => { if number.is_sign_negative() { 0b1000 } else { 0b1000000 } } FpCategory::Normal => { if number.is_sign_negative() { 0b100 } else { 0b10000000 } } } }