use crate::isa::op::AluOp;
const WORD_BITS: u32 = 32;
const XLEN_BITS: u32 = 64;
pub const fn execute(op: AluOp, a: u64, b: u64, is32: bool) -> u64 {
match op {
AluOp::Add => {
if is32 {
(a as i32).wrapping_add(b as i32) as i64 as u64
} else {
a.wrapping_add(b)
}
}
AluOp::Sub => {
if is32 {
(a as i32).wrapping_sub(b as i32) as i64 as u64
} else {
a.wrapping_sub(b)
}
}
AluOp::Mul => {
if is32 {
(a as i32).wrapping_mul(b as i32) as i64 as u64
} else {
a.wrapping_mul(b)
}
}
AluOp::Mulh => {
if is32 {
((a as i32 as i64 * b as i32 as i64) >> WORD_BITS) as u64
} else {
(((a as i64 as i128) * (b as i64 as i128)) >> XLEN_BITS) as u64
}
}
AluOp::Mulhsu => {
if is32 {
((a as i32 as i64 * (b as u32) as i64) >> WORD_BITS) as u64
} else {
(((a as i64 as i128) * (b as u128 as i128)) >> XLEN_BITS) as u64
}
}
AluOp::Mulhu => {
if is32 {
(((a as u32) as u64 * (b as u32) as u64) >> WORD_BITS) as i64 as u64
} else {
(((a as u128) * (b as u128)) >> XLEN_BITS) as u64
}
}
AluOp::Div => {
if is32 {
if (b as i32) == 0 {
-1i64 as u64
} else {
(a as i32).wrapping_div(b as i32) as i64 as u64
}
} else if b == 0 {
-1i64 as u64
} else {
(a as i64).wrapping_div(b as i64) as u64
}
}
AluOp::Divu => {
if is32 {
match (a as u32).checked_div(b as u32) {
Some(q) => q as i32 as i64 as u64,
None => -1i64 as u64,
}
} else {
match a.checked_div(b) {
Some(q) => q,
None => -1i64 as u64,
}
}
}
AluOp::Rem => {
if is32 {
if (b as i32) == 0 {
(a as i32) as i64 as u64
} else {
(a as i32).wrapping_rem(b as i32) as i64 as u64
}
} else if b == 0 {
a
} else {
(a as i64).wrapping_rem(b as i64) as u64
}
}
AluOp::Remu => {
if is32 {
if (b as u32) == 0 {
(a as u32) as i32 as i64 as u64
} else {
((a as u32) % (b as u32)) as i32 as i64 as u64
}
} else if b == 0 {
a
} else {
a % b
}
}
_ => 0,
}
}