1 use crate::{ConditionRegister, InstructionInput, InstructionResult, OverflowFlags};
3 macro_rules! create_instr_variants_ov_cr {
4 ($fn:ident, $fno:ident, $fn_:ident, $fno_:ident, $iwidth:ident) => {
5 pub fn $fn(inputs: InstructionInput) -> InstructionResult {
11 pub fn $fn_(inputs: InstructionInput) -> InstructionResult {
12 let mut retval = $fno_(inputs);
13 let mut cr0 = retval.cr0.as_mut().expect("expected cr0 to be set");
15 retval.overflow = None;
18 pub fn $fno_(inputs: InstructionInput) -> InstructionResult {
19 let mut retval = $fno(inputs);
20 let result = retval.rt.expect("expected rt to be set");
21 let so = retval.overflow.expect("expected overflow to be set").so;
22 let cr0 = ConditionRegister::from_signed_int(result as $iwidth, so);
23 retval.cr0 = Some(cr0);
29 macro_rules! create_instr_variants_cr {
30 ($fn:ident, $fn_:ident, $iwidth:ident) => {
31 pub fn $fn_(inputs: InstructionInput) -> InstructionResult {
32 let mut retval = $fn(inputs);
33 let result = retval.rt.expect("expected rt to be set");
34 let cr0 = ConditionRegister::from_signed_int(result as $iwidth, false);
35 retval.cr0 = Some(cr0);
41 create_instr_variants_ov_cr!(add, addo, add_, addo_, i64);
43 pub fn addo(inputs: InstructionInput) -> InstructionResult {
44 let ra = inputs.ra as i64;
45 let rb = inputs.rb as i64;
46 let (result, overflow) = ra.overflowing_add(rb);
47 let result = result as u64;
50 overflow: Some(OverflowFlags::from_overflow(overflow)),
51 ..InstructionResult::default()
55 create_instr_variants_ov_cr!(divde, divdeo, divde_, divdeo_, i64);
57 pub fn divdeo(inputs: InstructionInput) -> InstructionResult {
58 let dividend = i128::from(inputs.ra as i64) << 64;
59 let divisor = i128::from(inputs.rb as i64);
62 if divisor == 0 || (divisor == -1 && dividend == i128::min_value()) {
66 let result128 = dividend / divisor;
67 if result128 as i64 as i128 != result128 {
71 result = result128 as u64;
77 overflow: Some(OverflowFlags::from_overflow(overflow)),
78 ..InstructionResult::default()
82 create_instr_variants_ov_cr!(divdeu, divdeuo, divdeu_, divdeuo_, i64);
84 pub fn divdeuo(inputs: InstructionInput) -> InstructionResult {
85 let dividend = u128::from(inputs.ra) << 64;
86 let divisor = u128::from(inputs.rb);
93 let resultu128 = dividend / divisor;
94 if resultu128 > u128::from(u64::max_value()) {
98 result = resultu128 as u64;
104 overflow: Some(OverflowFlags::from_overflow(overflow)),
105 ..InstructionResult::default()
109 create_instr_variants_ov_cr!(divd, divdo, divd_, divdo_, i64);
111 pub fn divdo(inputs: InstructionInput) -> InstructionResult {
112 let dividend = inputs.ra as i64;
113 let divisor = inputs.rb as i64;
116 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
120 result = (dividend / divisor) as u64;
125 overflow: Some(OverflowFlags::from_overflow(overflow)),
126 ..InstructionResult::default()
130 create_instr_variants_ov_cr!(divdu, divduo, divdu_, divduo_, i64);
132 pub fn divduo(inputs: InstructionInput) -> InstructionResult {
133 let dividend: u64 = inputs.ra;
134 let divisor: u64 = inputs.rb;
141 result = dividend / divisor;
146 overflow: Some(OverflowFlags::from_overflow(overflow)),
147 ..InstructionResult::default()
151 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
152 create_instr_variants_ov_cr!(divwe, divweo, divwe_, divweo_, i64);
154 pub fn divweo(inputs: InstructionInput) -> InstructionResult {
155 let dividend = i64::from(inputs.ra as i32) << 32;
156 let divisor = i64::from(inputs.rb as i32);
159 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
163 let result64 = dividend / divisor;
164 if result64 as i32 as i64 != result64 {
168 result = result64 as u32 as u64;
174 overflow: Some(OverflowFlags::from_overflow(overflow)),
175 ..InstructionResult::default()
179 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
180 create_instr_variants_ov_cr!(divweu, divweuo, divweu_, divweuo_, i64);
182 pub fn divweuo(inputs: InstructionInput) -> InstructionResult {
183 let dividend = u64::from(inputs.ra as u32) << 32;
184 let divisor = u64::from(inputs.rb as u32);
191 let resultu64 = dividend / divisor;
192 if resultu64 > u64::from(u32::max_value()) {
196 result = resultu64 as u32 as u64;
202 overflow: Some(OverflowFlags::from_overflow(overflow)),
203 ..InstructionResult::default()
207 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
208 create_instr_variants_ov_cr!(divw, divwo, divw_, divwo_, i64);
210 pub fn divwo(inputs: InstructionInput) -> InstructionResult {
211 let dividend = inputs.ra as i32;
212 let divisor = inputs.rb as i32;
215 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
219 result = (dividend / divisor) as u32 as u64;
224 overflow: Some(OverflowFlags::from_overflow(overflow)),
225 ..InstructionResult::default()
229 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
230 create_instr_variants_ov_cr!(divwu, divwuo, divwu_, divwuo_, i64);
232 pub fn divwuo(inputs: InstructionInput) -> InstructionResult {
233 let dividend = inputs.ra as u32;
234 let divisor = inputs.rb as u32;
241 result = (dividend / divisor) as u64;
246 overflow: Some(OverflowFlags::from_overflow(overflow)),
247 ..InstructionResult::default()
251 pub fn modsd(inputs: InstructionInput) -> InstructionResult {
252 let dividend = inputs.ra as i64;
253 let divisor = inputs.rb as i64;
255 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
258 result = (dividend % divisor) as u64;
262 ..InstructionResult::default()
266 pub fn modud(inputs: InstructionInput) -> InstructionResult {
267 let dividend: u64 = inputs.ra;
268 let divisor: u64 = inputs.rb;
273 result = dividend % divisor;
277 ..InstructionResult::default()
281 pub fn modsw(inputs: InstructionInput) -> InstructionResult {
282 let dividend = inputs.ra as i32;
283 let divisor = inputs.rb as i32;
285 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
288 result = (dividend % divisor) as u64;
292 ..InstructionResult::default()
296 pub fn moduw(inputs: InstructionInput) -> InstructionResult {
297 let dividend = inputs.ra as u32;
298 let divisor = inputs.rb as u32;
303 result = (dividend % divisor) as u64;
307 ..InstructionResult::default()
311 create_instr_variants_ov_cr!(mullw, mullwo, mullw_, mullwo_, i64);
313 pub fn mullwo(inputs: InstructionInput) -> InstructionResult {
314 let ra = inputs.ra as i32 as i64;
315 let rb = inputs.rb as i32 as i64;
316 let result = ra.wrapping_mul(rb) as u64;
317 let overflow = result as i32 as i64 != result as i64;
320 overflow: Some(OverflowFlags::from_overflow(overflow)),
321 ..InstructionResult::default()
325 create_instr_variants_cr!(mulhw, mulhw_, i32);
327 pub fn mulhw(inputs: InstructionInput) -> InstructionResult {
328 let ra = inputs.ra as i32 as i64;
329 let rb = inputs.rb as i32 as i64;
330 let result = (ra * rb) >> 32;
331 let mut result = result as u32 as u64;
332 result |= result << 32;
335 ..InstructionResult::default()
339 create_instr_variants_cr!(mulhwu, mulhwu_, i32);
341 pub fn mulhwu(inputs: InstructionInput) -> InstructionResult {
342 let ra = inputs.ra as u32 as u64;
343 let rb = inputs.rb as u32 as u64;
344 let result = (ra * rb) >> 32;
345 let mut result = result as u32 as u64;
346 result |= result << 32;
349 ..InstructionResult::default()
353 create_instr_variants_ov_cr!(mulld, mulldo, mulld_, mulldo_, i64);
355 pub fn mulldo(inputs: InstructionInput) -> InstructionResult {
356 let ra = inputs.ra as i64;
357 let rb = inputs.rb as i64;
358 let result = ra.wrapping_mul(rb) as u64;
359 let overflow = ra.checked_mul(rb).is_none();
362 overflow: Some(OverflowFlags::from_overflow(overflow)),
363 ..InstructionResult::default()
367 create_instr_variants_cr!(mulhd, mulhd_, i64);
369 pub fn mulhd(inputs: InstructionInput) -> InstructionResult {
370 let ra = inputs.ra as i64 as i128;
371 let rb = inputs.rb as i64 as i128;
372 let result = ((ra * rb) >> 64) as i64;
373 let result = result as u64;
376 ..InstructionResult::default()
380 create_instr_variants_cr!(mulhdu, mulhdu_, i64);
382 pub fn mulhdu(inputs: InstructionInput) -> InstructionResult {
383 let ra = inputs.ra as u128;
384 let rb = inputs.rb as u128;
385 let result = ((ra * rb) >> 64) as u64;
388 ..InstructionResult::default()
392 pub fn maddhd(inputs: InstructionInput) -> InstructionResult {
393 let ra = inputs.ra as i64 as i128;
394 let rb = inputs.rb as i64 as i128;
395 let rc = inputs.rc as i64 as i128;
396 let result = ((ra * rb + rc) >> 64) as u64;
399 ..InstructionResult::default()
403 pub fn maddhdu(inputs: InstructionInput) -> InstructionResult {
404 let ra = inputs.ra as u128;
405 let rb = inputs.rb as u128;
406 let rc = inputs.rc as u128;
407 let result = ((ra * rb + rc) >> 64) as u64;
410 ..InstructionResult::default()
414 pub fn maddld(inputs: InstructionInput) -> InstructionResult {
415 let ra = inputs.ra as i64;
416 let rb = inputs.rb as i64;
417 let rc = inputs.rc as i64;
418 let result = ra.wrapping_mul(rb).wrapping_add(rc) as u64;
421 ..InstructionResult::default()