From 61328b9cc5ed4c218cdf51a5615b23f36c75e63b Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 8 Jul 2020 21:26:44 -0700 Subject: [PATCH] add initial implementation of mul* and madd* instructions --- src/instr_models.rs | 142 +++++++++++++++++++++++++++++++++++++++++--- src/lib.rs | 90 ++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+), 9 deletions(-) diff --git a/src/instr_models.rs b/src/instr_models.rs index 7ce6fef..de5232f 100644 --- a/src/instr_models.rs +++ b/src/instr_models.rs @@ -1,6 +1,6 @@ use crate::{ConditionRegister, InstructionInput, InstructionResult, OverflowFlags}; -macro_rules! create_instr_variants { +macro_rules! create_instr_variants_ov_cr { ($fn:ident, $fno:ident, $fn_:ident, $fno_:ident, $iwidth:ident) => { pub fn $fn(inputs: InstructionInput) -> InstructionResult { InstructionResult { @@ -26,7 +26,19 @@ macro_rules! create_instr_variants { }; } -create_instr_variants!(divde, divdeo, divde_, divdeo_, i64); +macro_rules! create_instr_variants_cr { + ($fn:ident, $fn_:ident, $iwidth:ident) => { + pub fn $fn_(inputs: InstructionInput) -> InstructionResult { + let mut retval = $fn(inputs); + let result = retval.rt.expect("expected rt to be set"); + let cr0 = ConditionRegister::from_signed_int(result as $iwidth, false); + retval.cr0 = Some(cr0); + retval + } + }; +} + +create_instr_variants_ov_cr!(divde, divdeo, divde_, divdeo_, i64); pub fn divdeo(inputs: InstructionInput) -> InstructionResult { let dividend = i128::from(inputs.ra as i64) << 64; @@ -53,7 +65,7 @@ pub fn divdeo(inputs: InstructionInput) -> InstructionResult { } } -create_instr_variants!(divdeu, divdeuo, divdeu_, divdeuo_, i64); +create_instr_variants_ov_cr!(divdeu, divdeuo, divdeu_, divdeuo_, i64); pub fn divdeuo(inputs: InstructionInput) -> InstructionResult { let dividend = u128::from(inputs.ra) << 64; @@ -80,7 +92,7 @@ pub fn divdeuo(inputs: InstructionInput) -> InstructionResult { } } -create_instr_variants!(divd, divdo, divd_, divdo_, i64); +create_instr_variants_ov_cr!(divd, divdo, divd_, divdo_, i64); pub fn divdo(inputs: InstructionInput) -> InstructionResult { let dividend = inputs.ra as i64; @@ -101,7 +113,7 @@ pub fn divdo(inputs: InstructionInput) -> InstructionResult { } } -create_instr_variants!(divdu, divduo, divdu_, divduo_, i64); +create_instr_variants_ov_cr!(divdu, divduo, divdu_, divduo_, i64); pub fn divduo(inputs: InstructionInput) -> InstructionResult { let dividend: u64 = inputs.ra; @@ -122,7 +134,7 @@ pub fn divduo(inputs: InstructionInput) -> InstructionResult { } } -create_instr_variants!(divwe, divweo, divwe_, divweo_, i32); +create_instr_variants_ov_cr!(divwe, divweo, divwe_, divweo_, i32); pub fn divweo(inputs: InstructionInput) -> InstructionResult { let dividend = i64::from(inputs.ra as i32) << 32; @@ -149,7 +161,7 @@ pub fn divweo(inputs: InstructionInput) -> InstructionResult { } } -create_instr_variants!(divweu, divweuo, divweu_, divweuo_, i32); +create_instr_variants_ov_cr!(divweu, divweuo, divweu_, divweuo_, i32); pub fn divweuo(inputs: InstructionInput) -> InstructionResult { let dividend = u64::from(inputs.ra as u32) << 32; @@ -176,7 +188,7 @@ pub fn divweuo(inputs: InstructionInput) -> InstructionResult { } } -create_instr_variants!(divw, divwo, divw_, divwo_, i32); +create_instr_variants_ov_cr!(divw, divwo, divw_, divwo_, i32); pub fn divwo(inputs: InstructionInput) -> InstructionResult { let dividend = inputs.ra as i32; @@ -197,7 +209,7 @@ pub fn divwo(inputs: InstructionInput) -> InstructionResult { } } -create_instr_variants!(divwu, divwuo, divwu_, divwuo_, i32); +create_instr_variants_ov_cr!(divwu, divwuo, divwu_, divwuo_, i32); pub fn divwuo(inputs: InstructionInput) -> InstructionResult { let dividend = inputs.ra as u32; @@ -277,3 +289,115 @@ pub fn moduw(inputs: InstructionInput) -> InstructionResult { ..InstructionResult::default() } } + +create_instr_variants_ov_cr!(mullw, mullwo, mullw_, mullwo_, i32); + +pub fn mullwo(inputs: InstructionInput) -> InstructionResult { + let ra = inputs.ra as i32; + let rb = inputs.rb as i32; + let result = ra.wrapping_mul(rb) as u64; + let overflow = ra.checked_mul(rb).is_none(); + InstructionResult { + rt: Some(result), + overflow: Some(OverflowFlags::from_overflow(overflow)), + ..InstructionResult::default() + } +} + +create_instr_variants_cr!(mulhw, mulhw_, i32); + +pub fn mulhw(inputs: InstructionInput) -> InstructionResult { + let ra = inputs.ra as i32 as i64; + let rb = inputs.rb as i32 as i64; + let result = ((ra * rb) >> 32) as i32; + let result = result as u64; + InstructionResult { + rt: Some(result), + ..InstructionResult::default() + } +} + +create_instr_variants_cr!(mulhwu, mulhwu_, i32); + +pub fn mulhwu(inputs: InstructionInput) -> InstructionResult { + let ra = inputs.ra as u32 as u64; + let rb = inputs.rb as u32 as u64; + let result = ((ra * rb) >> 32) as u32; + let result = result as u64; + InstructionResult { + rt: Some(result), + ..InstructionResult::default() + } +} + +create_instr_variants_ov_cr!(mulld, mulldo, mulld_, mulldo_, i64); + +pub fn mulldo(inputs: InstructionInput) -> InstructionResult { + let ra = inputs.ra as i64; + let rb = inputs.rb as i64; + let result = ra.wrapping_mul(rb) as u64; + let overflow = ra.checked_mul(rb).is_none(); + InstructionResult { + rt: Some(result), + overflow: Some(OverflowFlags::from_overflow(overflow)), + ..InstructionResult::default() + } +} + +create_instr_variants_cr!(mulhd, mulhd_, i64); + +pub fn mulhd(inputs: InstructionInput) -> InstructionResult { + let ra = inputs.ra as i64 as i128; + let rb = inputs.rb as i64 as i128; + let result = ((ra * rb) >> 64) as i64; + let result = result as u64; + InstructionResult { + rt: Some(result), + ..InstructionResult::default() + } +} + +create_instr_variants_cr!(mulhdu, mulhdu_, i64); + +pub fn mulhdu(inputs: InstructionInput) -> InstructionResult { + let ra = inputs.ra as u128; + let rb = inputs.rb as u128; + let result = ((ra * rb) >> 64) as u64; + InstructionResult { + rt: Some(result), + ..InstructionResult::default() + } +} + +pub fn maddhd(inputs: InstructionInput) -> InstructionResult { + let ra = inputs.ra as i64 as i128; + let rb = inputs.rb as i64 as i128; + let rc = inputs.rc as i64 as i128; + let result = ((ra * rb + rc) >> 64) as u64; + InstructionResult { + rt: Some(result), + ..InstructionResult::default() + } +} + +pub fn maddhdu(inputs: InstructionInput) -> InstructionResult { + let ra = inputs.ra as u128; + let rb = inputs.rb as u128; + let rc = inputs.rc as u128; + let result = ((ra * rb + rc) >> 64) as u64; + InstructionResult { + rt: Some(result), + ..InstructionResult::default() + } +} + +pub fn maddld(inputs: InstructionInput) -> InstructionResult { + let ra = inputs.ra as i64; + let rb = inputs.rb as i64; + let rc = inputs.rc as i64; + let result = ra.wrapping_mul(rb).wrapping_add(rc) as u64; + InstructionResult { + rt: Some(result), + ..InstructionResult::default() + } +} diff --git a/src/lib.rs b/src/lib.rs index ec31e6a..ba91f9b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -566,6 +566,96 @@ instrs! { fn moduw(ra, rb) -> (rt) { "moduw" } + + // mullw + #[enumerant = MulLW] + fn mullw(ra, rb) -> (rt) { + "mullw" + } + #[enumerant = MulLWO] + fn mullwo(ra, rb) -> (rt, ov) { + "mullwo" + } + #[enumerant = MulLW_] + fn mullw_(ra, rb) -> (rt, cr0) { + "mullw." + } + #[enumerant = MulLWO_] + fn mullwo_(ra, rb) -> (rt, ov, cr0) { + "mullwo." + } + + // mulhw + #[enumerant = MulHW] + fn mulhw(ra, rb) -> (rt) { + "mulhw" + } + #[enumerant = MulHW_] + fn mulhw_(ra, rb) -> (rt, cr0) { + "mulhw." + } + + // mulhwu + #[enumerant = MulHWU] + fn mulhwu(ra, rb) -> (rt) { + "mulhwu" + } + #[enumerant = MulHWU_] + fn mulhwu_(ra, rb) -> (rt, cr0) { + "mulhwu." + } + + // mulld + #[enumerant = MulLD] + fn mulld(ra, rb) -> (rt) { + "mulld" + } + #[enumerant = MulLDO] + fn mulldo(ra, rb) -> (rt, ov) { + "mulldo" + } + #[enumerant = MulLD_] + fn mulld_(ra, rb) -> (rt, cr0) { + "mulld." + } + #[enumerant = MulLDO_] + fn mulldo_(ra, rb) -> (rt, ov, cr0) { + "mulldo." + } + + // mulhd + #[enumerant = MulHD] + fn mulhd(ra, rb) -> (rt) { + "mulhd" + } + #[enumerant = MulHD_] + fn mulhd_(ra, rb) -> (rt, cr0) { + "mulhd." + } + + // mulhdu + #[enumerant = MulHDU] + fn mulhdu(ra, rb) -> (rt) { + "mulhdu" + } + #[enumerant = MulHDU_] + fn mulhdu_(ra, rb) -> (rt, cr0) { + "mulhdu." + } + + // madd* + #[enumerant = MAddHD] + fn maddhd(ra, rb, rc) -> (rt) { + "maddhd" + } + #[enumerant = MAddHDU] + fn maddhdu(ra, rb, rc) -> (rt) { + "maddhdu" + } + #[enumerant = MAddLD] + fn maddld(ra, rb, rc) -> (rt) { + "maddld" + } } // must be after instrs macro call since it uses a macro definition -- 2.30.2