From 95fdd1c4edbd91c0a02b772ba02aa2045101d2b0 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Mon, 6 Sep 2021 19:01:22 -0700 Subject: [PATCH] add cdtbcd, cbcdtd, and addg6s --- src/instr_models.rs | 104 ++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 18 ++++++++ 2 files changed, 122 insertions(+) diff --git a/src/instr_models.rs b/src/instr_models.rs index 89e4bdf..5a7cd88 100644 --- a/src/instr_models.rs +++ b/src/instr_models.rs @@ -866,3 +866,107 @@ pub fn cmprb_0(inputs: InstructionInput) -> InstructionResult { ..InstructionOutput::default() }) } + +macro_rules! unpack_bits { + ($v:expr => [$($bit:ident),*]) => { + unpack_bits!($v => [$($bit,)*] @reversed []); + }; + ($v:expr => [$bit:ident, $($forward_bits:ident,)*] @reversed [$($reversed_bits:ident,)*]) => { + unpack_bits!($v => [$($forward_bits,)*] @reversed [$bit, $($reversed_bits,)*]); + }; + ($v:expr => [] @reversed [$($reversed_bits:ident,)*]) => { + let mut bits = $v; + $( + let $reversed_bits = (bits & 1) != 0; + bits >>= 1; + )* + let _ = bits; + }; +} + +macro_rules! pack_bits { + ($($bit:expr),*) => { + { + let mut bits = 0; + $( + bits <<= 1; + if $bit { + bits |= 1; + } + )* + bits + } + }; +} + +fn dpd_to_bcd(dpd: u16) -> u16 { + // expressions taken from PowerISA v2.07B section B.2 (page 697 (728)) + unpack_bits!(dpd => [p, q, r, s, t, u, v, w, x, y]); + let a = (!s & v & w) | (t & v & w & s) | (v & w & !x); + let b = (p & s & x & !t) | (p & !w) | (p & !v); + let c = (q & s & x & !t) | (q & !w) | (q & !v); + let d = r; + let e = (v & !w & x) | (s & v & w & x) | (!t & v & x & w); + let f = (p & t & v & w & x & !s) | (s & !x & v) | (s & !v); + let g = (q & t & w & v & x & !s) | (t & !x & v) | (t & !v); + let h = u; + let i = (t & v & w & x) | (s & v & w & x) | (v & !w & !x); + let j = (p & !s & !t & w & v) | (s & v & !w & x) | (p & w & !x & v) | (w & !v); + let k = (q & !s & !t & v & w) | (t & v & !w & x) | (q & v & w & !x) | (x & !v); + let m = y; + pack_bits![a, b, c, d, e, f, g, h, i, j, k, m] +} + +fn bcd_to_dpd(bcd: u16) -> u16 { + // expressions taken from PowerISA v2.07B section B.1 (page 697 (728)) + unpack_bits!(bcd => [a, b, c, d, e, f, g, h, i, j, k, m]); + let p = (f & a & i & !e) | (j & a & !i) | (b & !a); + let q = (g & a & i & !e) | (k & a & !i) | (c & !a); + let r = d; + let s = (j & !a & e & !i) | (f & !i & !e) | (f & !a & !e) | (e & i); + let t = (k & !a & e & !i) | (g & !i & !e) | (g & !a & !e) | (a & i); + let u = h; + let v = a | e | i; + let w = (!e & j & !i) | (e & i) | a; + let x = (!a & k & !i) | (a & i) | e; + let y = m; + pack_bits![p, q, r, s, t, u, v, w, x, y] +} + +pub fn cdtbcd(inputs: InstructionInput) -> InstructionResult { + let ra = inputs.try_get_ra()?; + let mut rt = 0; + rt |= dpd_to_bcd((ra & 0x3FF) as u16) as u64; + rt |= (dpd_to_bcd(((ra >> 10) & 0x3FF) as u16) as u64) << 12; + rt |= (dpd_to_bcd(((ra >> 32) & 0x3FF) as u16) as u64) << 32; + rt |= (dpd_to_bcd(((ra >> 42) & 0x3FF) as u16) as u64) << 44; + Ok(InstructionOutput { + rt: Some(rt), + ..InstructionOutput::default() + }) +} + +pub fn cbcdtd(inputs: InstructionInput) -> InstructionResult { + let ra = inputs.try_get_ra()?; + let mut rt = 0; + rt |= bcd_to_dpd((ra & 0xFFF) as u16) as u64; + rt |= (bcd_to_dpd(((ra >> 12) & 0xFFF) as u16) as u64) << 10; + rt |= (bcd_to_dpd(((ra >> 32) & 0xFFF) as u16) as u64) << 32; + rt |= (bcd_to_dpd(((ra >> 44) & 0xFFF) as u16) as u64) << 42; + Ok(InstructionOutput { + rt: Some(rt), + ..InstructionOutput::default() + }) +} + +pub fn addg6s(inputs: InstructionInput) -> InstructionResult { + let ra = inputs.try_get_ra()?; + let rb = inputs.try_get_rb()?; + let sum = ra as u128 + rb as u128; + let need_sixes = ((!sum >> 4) as u64 ^ (ra >> 4) ^ (rb >> 4)) & 0x1111_1111_1111_1111; + let rt = 6 * need_sixes; + Ok(InstructionOutput { + rt: Some(rt), + ..InstructionOutput::default() + }) +} diff --git a/src/lib.rs b/src/lib.rs index 28c5b35..bb1e0c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -843,6 +843,24 @@ instructions! { fn cmprb_0(Ra("r3"), Rb("r4")) -> (CR0) { "cmprb_0" : "cmprb 0, 0, 3, 4" } + + #[enumerant = CDTBcd] + fn cdtbcd(Ra("r3")) -> (Rt("r4")) { + // work around LLVM not supporting cdtbcd instruction: + "cdtbcd" : ".long 0x7C640234 # cdtbcd r4, r3" + } + + #[enumerant = CBcdTD] + fn cbcdtd(Ra("r3")) -> (Rt("r4")) { + // work around LLVM not supporting cbcdtd instruction: + "cbcdtd" : ".long 0x7C640274 # cbcdtd r4, r3" + } + + #[enumerant = AddG6s] + fn addg6s(Ra("r3"), Rb("r4")) -> (Rt("r5")) { + // work around LLVM not supporting addg6s instruction: + "addg6s" : ".long 0x7CA32094 # addg6s r5, r3, r4" + } } // must be after instrs macro call since it uses a macro definition -- 2.30.2