power_instruction_analyzer/
instr_models.rs

1use crate::{
2    CarryFlags, ConditionRegister, InstructionInput, InstructionOutput, InstructionResult,
3    MissingInstructionInput, OverflowFlags,
4};
5use std::convert::TryFrom;
6
7fn propagate_so(
8    mut overflow: OverflowFlags,
9    inputs: InstructionInput,
10) -> Result<OverflowFlags, MissingInstructionInput> {
11    if inputs.try_get_overflow()?.so {
12        overflow.so = true;
13    }
14    Ok(overflow)
15}
16
17macro_rules! create_instr_variants_ov_cr {
18    ($fn:ident, $fno:ident, $fn_:ident, $fno_:ident, $iwidth:ident) => {
19        pub fn $fn(mut inputs: InstructionInput) -> InstructionResult {
20            inputs.overflow = Some(OverflowFlags::default());
21            Ok(InstructionOutput {
22                overflow: None,
23                ..$fno(inputs)?
24            })
25        }
26        pub fn $fn_(inputs: InstructionInput) -> InstructionResult {
27            let mut retval = $fno_(inputs)?;
28            let mut cr0 = retval.cr0.as_mut().expect("expected cr0 to be set");
29            cr0.so = inputs.try_get_overflow()?.so;
30            retval.overflow = None;
31            Ok(retval)
32        }
33        pub fn $fno_(inputs: InstructionInput) -> InstructionResult {
34            let mut retval = $fno(inputs)?;
35            let result = retval.rt.expect("expected rt to be set");
36            let so = retval.overflow.expect("expected overflow to be set").so;
37            let cr0 = ConditionRegister::from_signed_int(result as $iwidth, so);
38            retval.cr0 = Some(cr0);
39            Ok(retval)
40        }
41    };
42}
43
44macro_rules! create_instr_variants_cr {
45    ($fn:ident, $fn_:ident, $iwidth:ident) => {
46        pub fn $fn_(inputs: InstructionInput) -> InstructionResult {
47            let mut retval = $fn(inputs)?;
48            let result = retval.rt.expect("expected rt to be set");
49            let cr0 = ConditionRegister::from_signed_int(
50                result as $iwidth,
51                inputs.try_get_overflow()?.so,
52            );
53            retval.cr0 = Some(cr0);
54            Ok(retval)
55        }
56    };
57}
58
59pub fn addi(inputs: InstructionInput) -> InstructionResult {
60    let ra = inputs.try_get_ra()? as i64;
61    let immediate = inputs.try_get_immediate_s16()? as i64;
62    let result = ra.wrapping_add(immediate) as u64;
63    Ok(InstructionOutput {
64        rt: Some(result),
65        ..InstructionOutput::default()
66    })
67}
68
69pub fn addis(inputs: InstructionInput) -> InstructionResult {
70    let ra = inputs.try_get_ra()? as i64;
71    let immediate = inputs.try_get_immediate_s16()? as i64;
72    let result = ra.wrapping_add(immediate << 16) as u64;
73    Ok(InstructionOutput {
74        rt: Some(result),
75        ..InstructionOutput::default()
76    })
77}
78
79create_instr_variants_ov_cr!(add, addo, add_, addo_, i64);
80
81pub fn addo(inputs: InstructionInput) -> InstructionResult {
82    let ra = inputs.try_get_ra()? as i64;
83    let rb = inputs.try_get_rb()? as i64;
84    let (result, ov) = ra.overflowing_add(rb);
85    let result = result as u64;
86    let ov32 = (ra as i32).overflowing_add(rb as i32).1;
87    Ok(InstructionOutput {
88        rt: Some(result),
89        overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
90        ..InstructionOutput::default()
91    })
92}
93
94create_instr_variants_cr!(addic, addic_, i64);
95
96pub fn addic(inputs: InstructionInput) -> InstructionResult {
97    let ra = inputs.try_get_ra()? as i64;
98    let immediate = inputs.try_get_immediate_s16()? as i64;
99    let result = ra.wrapping_add(immediate) as u64;
100    let ca = (ra as u64).overflowing_add(immediate as u64).1;
101    let ca32 = (ra as u32).overflowing_add(immediate as u32).1;
102    Ok(InstructionOutput {
103        rt: Some(result),
104        carry: Some(CarryFlags { ca, ca32 }),
105        ..InstructionOutput::default()
106    })
107}
108
109create_instr_variants_ov_cr!(subf, subfo, subf_, subfo_, i64);
110
111pub fn subfo(inputs: InstructionInput) -> InstructionResult {
112    let ra = inputs.try_get_ra()? as i64;
113    let rb = inputs.try_get_rb()? as i64;
114    let (result, ov) = rb.overflowing_sub(ra);
115    let result = result as u64;
116    let ov32 = (rb as i32).overflowing_sub(ra as i32).1;
117    Ok(InstructionOutput {
118        rt: Some(result),
119        overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
120        ..InstructionOutput::default()
121    })
122}
123
124pub fn subfic(inputs: InstructionInput) -> InstructionResult {
125    let ra: u64 = inputs.try_get_ra()?;
126    let immediate: u64 = inputs.try_get_immediate_s16()? as i64 as u64;
127    let not_ra = !ra;
128    let result = not_ra.wrapping_add(immediate).wrapping_add(1);
129    let ca = not_ra
130        .checked_add(immediate)
131        .and_then(|v| v.checked_add(1))
132        .is_none();
133    let ca32 = (not_ra as u32)
134        .checked_add(immediate as u32)
135        .and_then(|v| v.checked_add(1))
136        .is_none();
137    Ok(InstructionOutput {
138        rt: Some(result),
139        carry: Some(CarryFlags { ca, ca32 }),
140        ..InstructionOutput::default()
141    })
142}
143
144create_instr_variants_ov_cr!(addc, addco, addc_, addco_, i64);
145
146pub fn addco(inputs: InstructionInput) -> InstructionResult {
147    let ra = inputs.try_get_ra()? as i64;
148    let rb = inputs.try_get_rb()? as i64;
149    let (result, ov) = ra.overflowing_add(rb);
150    let result = result as u64;
151    let ov32 = (ra as i32).overflowing_add(rb as i32).1;
152    let ca = (ra as u64).overflowing_add(rb as u64).1;
153    let ca32 = (ra as u32).overflowing_add(rb as u32).1;
154    Ok(InstructionOutput {
155        rt: Some(result),
156        overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
157        carry: Some(CarryFlags { ca, ca32 }),
158        ..InstructionOutput::default()
159    })
160}
161
162create_instr_variants_ov_cr!(subfc, subfco, subfc_, subfco_, i64);
163
164pub fn subfco(inputs: InstructionInput) -> InstructionResult {
165    let ra = inputs.try_get_ra()? as i64;
166    let rb = inputs.try_get_rb()? as i64;
167    let (result, ov) = rb.overflowing_sub(ra);
168    let result = result as u64;
169    let ov32 = (rb as i32).overflowing_sub(ra as i32).1;
170    let ca = !(rb as u64).overflowing_sub(ra as u64).1;
171    let ca32 = !(rb as u32).overflowing_sub(ra as u32).1;
172    Ok(InstructionOutput {
173        rt: Some(result),
174        overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
175        carry: Some(CarryFlags { ca, ca32 }),
176        ..InstructionOutput::default()
177    })
178}
179
180create_instr_variants_ov_cr!(adde, addeo, adde_, addeo_, i64);
181
182pub fn addeo(inputs: InstructionInput) -> InstructionResult {
183    let ra: u64 = inputs.try_get_ra()?;
184    let rb: u64 = inputs.try_get_rb()?;
185    let carry_in = inputs.try_get_carry()?.ca;
186    let result_i128 = ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
187    let result_u128 = ra as u128 + rb as u128 + carry_in as u128;
188    let result32_i128 = ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
189    let result32_u128 = ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
190    let result = result_u128 as u64;
191    let ov = i64::try_from(result_i128).is_err();
192    let ov32 = i32::try_from(result32_i128).is_err();
193    let ca = u64::try_from(result_u128).is_err();
194    let ca32 = u32::try_from(result32_u128).is_err();
195    Ok(InstructionOutput {
196        rt: Some(result),
197        overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
198        carry: Some(CarryFlags { ca, ca32 }),
199        ..InstructionOutput::default()
200    })
201}
202
203create_instr_variants_ov_cr!(subfe, subfeo, subfe_, subfeo_, i64);
204
205pub fn subfeo(inputs: InstructionInput) -> InstructionResult {
206    let ra: u64 = inputs.try_get_ra()?;
207    let rb: u64 = inputs.try_get_rb()?;
208    let carry_in = inputs.try_get_carry()?.ca;
209    let not_ra = !ra;
210    let result_i128 = not_ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
211    let result_u128 = not_ra as u128 + rb as u128 + carry_in as u128;
212    let result32_i128 = not_ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
213    let result32_u128 = not_ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
214    let result = result_u128 as u64;
215    let ov = i64::try_from(result_i128).is_err();
216    let ov32 = i32::try_from(result32_i128).is_err();
217    let ca = u64::try_from(result_u128).is_err();
218    let ca32 = u32::try_from(result32_u128).is_err();
219    Ok(InstructionOutput {
220        rt: Some(result),
221        overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
222        carry: Some(CarryFlags { ca, ca32 }),
223        ..InstructionOutput::default()
224    })
225}
226
227create_instr_variants_ov_cr!(addme, addmeo, addme_, addmeo_, i64);
228
229pub fn addmeo(inputs: InstructionInput) -> InstructionResult {
230    let ra: u64 = inputs.try_get_ra()?;
231    let rb: u64 = !0;
232    let carry_in = inputs.try_get_carry()?.ca;
233    let result_i128 = ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
234    let result_u128 = ra as u128 + rb as u128 + carry_in as u128;
235    let result32_i128 = ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
236    let result32_u128 = ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
237    let result = result_u128 as u64;
238    let ov = i64::try_from(result_i128).is_err();
239    let ov32 = i32::try_from(result32_i128).is_err();
240    let ca = u64::try_from(result_u128).is_err();
241    let ca32 = u32::try_from(result32_u128).is_err();
242    Ok(InstructionOutput {
243        rt: Some(result),
244        overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
245        carry: Some(CarryFlags { ca, ca32 }),
246        ..InstructionOutput::default()
247    })
248}
249
250create_instr_variants_ov_cr!(subfme, subfmeo, subfme_, subfmeo_, i64);
251
252pub fn subfmeo(inputs: InstructionInput) -> InstructionResult {
253    let ra: u64 = inputs.try_get_ra()?;
254    let rb: u64 = !0;
255    let carry_in = inputs.try_get_carry()?.ca;
256    let not_ra = !ra;
257    let result_i128 = not_ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
258    let result_u128 = not_ra as u128 + rb as u128 + carry_in as u128;
259    let result32_i128 = not_ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
260    let result32_u128 = not_ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
261    let result = result_u128 as u64;
262    let ov = i64::try_from(result_i128).is_err();
263    let ov32 = i32::try_from(result32_i128).is_err();
264    let ca = u64::try_from(result_u128).is_err();
265    let ca32 = u32::try_from(result32_u128).is_err();
266    Ok(InstructionOutput {
267        rt: Some(result),
268        overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
269        carry: Some(CarryFlags { ca, ca32 }),
270        ..InstructionOutput::default()
271    })
272}
273
274create_instr_variants_ov_cr!(addze, addzeo, addze_, addzeo_, i64);
275
276pub fn addzeo(inputs: InstructionInput) -> InstructionResult {
277    let ra: u64 = inputs.try_get_ra()?;
278    let carry_in = inputs.try_get_carry()?.ca;
279    let result_i128 = ra as i64 as i128 + carry_in as i128;
280    let result_u128 = ra as u128 + carry_in as u128;
281    let result32_i128 = ra as i32 as i128 + carry_in as i128;
282    let result32_u128 = ra as u32 as u128 + carry_in as u128;
283    let result = result_u128 as u64;
284    let ov = i64::try_from(result_i128).is_err();
285    let ov32 = i32::try_from(result32_i128).is_err();
286    let ca = u64::try_from(result_u128).is_err();
287    let ca32 = u32::try_from(result32_u128).is_err();
288    Ok(InstructionOutput {
289        rt: Some(result),
290        overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
291        carry: Some(CarryFlags { ca, ca32 }),
292        ..InstructionOutput::default()
293    })
294}
295
296create_instr_variants_ov_cr!(subfze, subfzeo, subfze_, subfzeo_, i64);
297
298pub fn subfzeo(inputs: InstructionInput) -> InstructionResult {
299    let ra: u64 = inputs.try_get_ra()?;
300    let carry_in = inputs.try_get_carry()?.ca;
301    let not_ra = !ra;
302    let result_i128 = not_ra as i64 as i128 + carry_in as i128;
303    let result_u128 = not_ra as u128 + carry_in as u128;
304    let result32_i128 = not_ra as i32 as i128 + carry_in as i128;
305    let result32_u128 = not_ra as u32 as u128 + carry_in as u128;
306    let result = result_u128 as u64;
307    let ov = i64::try_from(result_i128).is_err();
308    let ov32 = i32::try_from(result32_i128).is_err();
309    let ca = u64::try_from(result_u128).is_err();
310    let ca32 = u32::try_from(result32_u128).is_err();
311    Ok(InstructionOutput {
312        rt: Some(result),
313        overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
314        carry: Some(CarryFlags { ca, ca32 }),
315        ..InstructionOutput::default()
316    })
317}
318
319pub fn addex(inputs: InstructionInput) -> InstructionResult {
320    let ra: u64 = inputs.try_get_ra()?;
321    let rb: u64 = inputs.try_get_rb()?;
322    let OverflowFlags {
323        ov: carry_in, so, ..
324    } = inputs.try_get_overflow()?;
325    let result_u128 = ra as u128 + rb as u128 + carry_in as u128;
326    let result32_u128 = ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
327    let result = result_u128 as u64;
328    let carry = u64::try_from(result_u128).is_err();
329    let carry32 = u32::try_from(result32_u128).is_err();
330    Ok(InstructionOutput {
331        rt: Some(result),
332        // doesn't change `so` on purpose
333        overflow: Some(OverflowFlags {
334            so,
335            ov: carry,
336            ov32: carry32,
337        }),
338        ..InstructionOutput::default()
339    })
340}
341
342create_instr_variants_ov_cr!(neg, nego, neg_, nego_, i64);
343
344pub fn nego(inputs: InstructionInput) -> InstructionResult {
345    let ra = inputs.try_get_ra()? as i64;
346    let result = ra.wrapping_neg() as u64;
347    let ov = ra.checked_neg().is_none();
348    let ov32 = (ra as i32).checked_neg().is_none();
349    Ok(InstructionOutput {
350        rt: Some(result),
351        overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
352        ..InstructionOutput::default()
353    })
354}
355
356create_instr_variants_ov_cr!(divde, divdeo, divde_, divdeo_, i64);
357
358pub fn divdeo(inputs: InstructionInput) -> InstructionResult {
359    let dividend = i128::from(inputs.try_get_ra()? as i64) << 64;
360    let divisor = i128::from(inputs.try_get_rb()? as i64);
361    let overflow;
362    let result;
363    if divisor == 0 || (divisor == -1 && dividend == i128::min_value()) {
364        result = 0;
365        overflow = true;
366    } else {
367        let result128 = dividend / divisor;
368        if result128 as i64 as i128 != result128 {
369            result = 0;
370            overflow = true;
371        } else {
372            result = result128 as u64;
373            overflow = false;
374        }
375    }
376    Ok(InstructionOutput {
377        rt: Some(result),
378        overflow: Some(propagate_so(
379            OverflowFlags::from_overflow(overflow),
380            inputs,
381        )?),
382        ..InstructionOutput::default()
383    })
384}
385
386create_instr_variants_ov_cr!(divdeu, divdeuo, divdeu_, divdeuo_, i64);
387
388pub fn divdeuo(inputs: InstructionInput) -> InstructionResult {
389    let dividend = u128::from(inputs.try_get_ra()?) << 64;
390    let divisor = u128::from(inputs.try_get_rb()?);
391    let overflow;
392    let result;
393    if divisor == 0 {
394        result = 0;
395        overflow = true;
396    } else {
397        let resultu128 = dividend / divisor;
398        if resultu128 > u128::from(u64::max_value()) {
399            result = 0;
400            overflow = true;
401        } else {
402            result = resultu128 as u64;
403            overflow = false;
404        }
405    }
406    Ok(InstructionOutput {
407        rt: Some(result),
408        overflow: Some(propagate_so(
409            OverflowFlags::from_overflow(overflow),
410            inputs,
411        )?),
412        ..InstructionOutput::default()
413    })
414}
415
416create_instr_variants_ov_cr!(divd, divdo, divd_, divdo_, i64);
417
418pub fn divdo(inputs: InstructionInput) -> InstructionResult {
419    let dividend = inputs.try_get_ra()? as i64;
420    let divisor = inputs.try_get_rb()? as i64;
421    let overflow;
422    let result;
423    if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
424        result = 0;
425        overflow = true;
426    } else {
427        result = (dividend / divisor) as u64;
428        overflow = false;
429    }
430    Ok(InstructionOutput {
431        rt: Some(result),
432        overflow: Some(propagate_so(
433            OverflowFlags::from_overflow(overflow),
434            inputs,
435        )?),
436        ..InstructionOutput::default()
437    })
438}
439
440create_instr_variants_ov_cr!(divdu, divduo, divdu_, divduo_, i64);
441
442pub fn divduo(inputs: InstructionInput) -> InstructionResult {
443    let dividend: u64 = inputs.try_get_ra()?;
444    let divisor: u64 = inputs.try_get_rb()?;
445    let overflow;
446    let result;
447    if divisor == 0 {
448        result = 0;
449        overflow = true;
450    } else {
451        result = dividend / divisor;
452        overflow = false;
453    }
454    Ok(InstructionOutput {
455        rt: Some(result),
456        overflow: Some(propagate_so(
457            OverflowFlags::from_overflow(overflow),
458            inputs,
459        )?),
460        ..InstructionOutput::default()
461    })
462}
463
464// ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
465create_instr_variants_ov_cr!(divwe, divweo, divwe_, divweo_, i64);
466
467pub fn divweo(inputs: InstructionInput) -> InstructionResult {
468    let dividend = i64::from(inputs.try_get_ra()? as i32) << 32;
469    let divisor = i64::from(inputs.try_get_rb()? as i32);
470    let overflow;
471    let result;
472    if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
473        result = 0;
474        overflow = true;
475    } else {
476        let result64 = dividend / divisor;
477        if result64 as i32 as i64 != result64 {
478            result = 0;
479            overflow = true;
480        } else {
481            result = result64 as u32 as u64;
482            overflow = false;
483        }
484    }
485    Ok(InstructionOutput {
486        rt: Some(result),
487        overflow: Some(propagate_so(
488            OverflowFlags::from_overflow(overflow),
489            inputs,
490        )?),
491        ..InstructionOutput::default()
492    })
493}
494
495// ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
496create_instr_variants_ov_cr!(divweu, divweuo, divweu_, divweuo_, i64);
497
498pub fn divweuo(inputs: InstructionInput) -> InstructionResult {
499    let dividend = u64::from(inputs.try_get_ra()? as u32) << 32;
500    let divisor = u64::from(inputs.try_get_rb()? as u32);
501    let overflow;
502    let result;
503    if divisor == 0 {
504        result = 0;
505        overflow = true;
506    } else {
507        let resultu64 = dividend / divisor;
508        if resultu64 > u64::from(u32::max_value()) {
509            result = 0;
510            overflow = true;
511        } else {
512            result = resultu64 as u32 as u64;
513            overflow = false;
514        }
515    }
516    Ok(InstructionOutput {
517        rt: Some(result),
518        overflow: Some(propagate_so(
519            OverflowFlags::from_overflow(overflow),
520            inputs,
521        )?),
522        ..InstructionOutput::default()
523    })
524}
525
526// ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
527create_instr_variants_ov_cr!(divw, divwo, divw_, divwo_, i64);
528
529pub fn divwo(inputs: InstructionInput) -> InstructionResult {
530    let dividend = inputs.try_get_ra()? as i32;
531    let divisor = inputs.try_get_rb()? as i32;
532    let overflow;
533    let result;
534    if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
535        result = 0;
536        overflow = true;
537    } else {
538        result = (dividend / divisor) as u32 as u64;
539        overflow = false;
540    }
541    Ok(InstructionOutput {
542        rt: Some(result),
543        overflow: Some(propagate_so(
544            OverflowFlags::from_overflow(overflow),
545            inputs,
546        )?),
547        ..InstructionOutput::default()
548    })
549}
550
551// ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
552create_instr_variants_ov_cr!(divwu, divwuo, divwu_, divwuo_, i64);
553
554pub fn divwuo(inputs: InstructionInput) -> InstructionResult {
555    let dividend = inputs.try_get_ra()? as u32;
556    let divisor = inputs.try_get_rb()? as u32;
557    let overflow;
558    let result;
559    if divisor == 0 {
560        result = 0;
561        overflow = true;
562    } else {
563        result = (dividend / divisor) as u64;
564        overflow = false;
565    }
566    Ok(InstructionOutput {
567        rt: Some(result),
568        overflow: Some(propagate_so(
569            OverflowFlags::from_overflow(overflow),
570            inputs,
571        )?),
572        ..InstructionOutput::default()
573    })
574}
575
576pub fn modsd(inputs: InstructionInput) -> InstructionResult {
577    let dividend = inputs.try_get_ra()? as i64;
578    let divisor = inputs.try_get_rb()? as i64;
579    let result;
580    if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
581        result = 0;
582    } else {
583        result = (dividend % divisor) as u64;
584    }
585    Ok(InstructionOutput {
586        rt: Some(result),
587        ..InstructionOutput::default()
588    })
589}
590
591pub fn modud(inputs: InstructionInput) -> InstructionResult {
592    let dividend: u64 = inputs.try_get_ra()?;
593    let divisor: u64 = inputs.try_get_rb()?;
594    let result;
595    if divisor == 0 {
596        result = 0;
597    } else {
598        result = dividend % divisor;
599    }
600    Ok(InstructionOutput {
601        rt: Some(result),
602        ..InstructionOutput::default()
603    })
604}
605
606pub fn modsw(inputs: InstructionInput) -> InstructionResult {
607    let dividend = inputs.try_get_ra()? as i32;
608    let divisor = inputs.try_get_rb()? as i32;
609    let result;
610    if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
611        result = 0;
612    } else {
613        result = (dividend % divisor) as u64;
614    }
615    Ok(InstructionOutput {
616        rt: Some(result),
617        ..InstructionOutput::default()
618    })
619}
620
621pub fn moduw(inputs: InstructionInput) -> InstructionResult {
622    let dividend = inputs.try_get_ra()? as u32;
623    let divisor = inputs.try_get_rb()? as u32;
624    let result;
625    if divisor == 0 {
626        result = 0;
627    } else {
628        result = (dividend % divisor) as u64;
629    }
630    Ok(InstructionOutput {
631        rt: Some(result),
632        ..InstructionOutput::default()
633    })
634}
635
636pub fn mulli(inputs: InstructionInput) -> InstructionResult {
637    let ra = inputs.try_get_ra()? as i64;
638    let immediate = inputs.try_get_immediate_s16()? as i64;
639    let result = ra.wrapping_mul(immediate) as u64;
640    Ok(InstructionOutput {
641        rt: Some(result),
642        ..InstructionOutput::default()
643    })
644}
645
646create_instr_variants_ov_cr!(mullw, mullwo, mullw_, mullwo_, i64);
647
648pub fn mullwo(inputs: InstructionInput) -> InstructionResult {
649    let ra = inputs.try_get_ra()? as i32 as i64;
650    let rb = inputs.try_get_rb()? as i32 as i64;
651    let result = ra.wrapping_mul(rb) as u64;
652    let overflow = result as i32 as i64 != result as i64;
653    Ok(InstructionOutput {
654        rt: Some(result),
655        overflow: Some(propagate_so(
656            OverflowFlags::from_overflow(overflow),
657            inputs,
658        )?),
659        ..InstructionOutput::default()
660    })
661}
662
663create_instr_variants_cr!(mulhw, mulhw_, i32);
664
665pub fn mulhw(inputs: InstructionInput) -> InstructionResult {
666    let ra = inputs.try_get_ra()? as i32 as i64;
667    let rb = inputs.try_get_rb()? as i32 as i64;
668    let result = (ra * rb) >> 32;
669    let mut result = result as u32 as u64;
670    result |= result << 32;
671    Ok(InstructionOutput {
672        rt: Some(result),
673        ..InstructionOutput::default()
674    })
675}
676
677create_instr_variants_cr!(mulhwu, mulhwu_, i32);
678
679pub fn mulhwu(inputs: InstructionInput) -> InstructionResult {
680    let ra = inputs.try_get_ra()? as u32 as u64;
681    let rb = inputs.try_get_rb()? as u32 as u64;
682    let result = (ra * rb) >> 32;
683    let mut result = result as u32 as u64;
684    result |= result << 32;
685    Ok(InstructionOutput {
686        rt: Some(result),
687        ..InstructionOutput::default()
688    })
689}
690
691create_instr_variants_ov_cr!(mulld, mulldo, mulld_, mulldo_, i64);
692
693pub fn mulldo(inputs: InstructionInput) -> InstructionResult {
694    let ra = inputs.try_get_ra()? as i64;
695    let rb = inputs.try_get_rb()? as i64;
696    let result = ra.wrapping_mul(rb) as u64;
697    let overflow = ra.checked_mul(rb).is_none();
698    Ok(InstructionOutput {
699        rt: Some(result),
700        overflow: Some(propagate_so(
701            OverflowFlags::from_overflow(overflow),
702            inputs,
703        )?),
704        ..InstructionOutput::default()
705    })
706}
707
708create_instr_variants_cr!(mulhd, mulhd_, i64);
709
710pub fn mulhd(inputs: InstructionInput) -> InstructionResult {
711    let ra = inputs.try_get_ra()? as i64 as i128;
712    let rb = inputs.try_get_rb()? as i64 as i128;
713    let result = ((ra * rb) >> 64) as i64;
714    let result = result as u64;
715    Ok(InstructionOutput {
716        rt: Some(result),
717        ..InstructionOutput::default()
718    })
719}
720
721create_instr_variants_cr!(mulhdu, mulhdu_, i64);
722
723pub fn mulhdu(inputs: InstructionInput) -> InstructionResult {
724    let ra = inputs.try_get_ra()? as u128;
725    let rb = inputs.try_get_rb()? as u128;
726    let result = ((ra * rb) >> 64) as u64;
727    Ok(InstructionOutput {
728        rt: Some(result),
729        ..InstructionOutput::default()
730    })
731}
732
733pub fn maddhd(inputs: InstructionInput) -> InstructionResult {
734    let ra = inputs.try_get_ra()? as i64 as i128;
735    let rb = inputs.try_get_rb()? as i64 as i128;
736    let rc = inputs.try_get_rc()? as i64 as i128;
737    let result = ((ra * rb + rc) >> 64) as u64;
738    Ok(InstructionOutput {
739        rt: Some(result),
740        ..InstructionOutput::default()
741    })
742}
743
744pub fn maddhdu(inputs: InstructionInput) -> InstructionResult {
745    let ra = inputs.try_get_ra()? as u128;
746    let rb = inputs.try_get_rb()? as u128;
747    let rc = inputs.try_get_rc()? as u128;
748    let result = ((ra * rb + rc) >> 64) as u64;
749    Ok(InstructionOutput {
750        rt: Some(result),
751        ..InstructionOutput::default()
752    })
753}
754
755pub fn maddld(inputs: InstructionInput) -> InstructionResult {
756    let ra = inputs.try_get_ra()? as i64;
757    let rb = inputs.try_get_rb()? as i64;
758    let rc = inputs.try_get_rc()? as i64;
759    let result = ra.wrapping_mul(rb).wrapping_add(rc) as u64;
760    Ok(InstructionOutput {
761        rt: Some(result),
762        ..InstructionOutput::default()
763    })
764}
765
766pub fn cmpdi(inputs: InstructionInput) -> InstructionResult {
767    let ra = inputs.try_get_ra()? as i64;
768    let immediate = inputs.try_get_immediate_s16()? as i64;
769    let so = inputs.try_get_overflow()?.so;
770    let cr0 = ConditionRegister::from_ordering(ra.cmp(&immediate), so);
771    Ok(InstructionOutput {
772        cr0: Some(cr0),
773        ..InstructionOutput::default()
774    })
775}
776
777pub fn cmpwi(inputs: InstructionInput) -> InstructionResult {
778    let ra = inputs.try_get_ra()? as i32;
779    let immediate = inputs.try_get_immediate_s16()? as i32;
780    let so = inputs.try_get_overflow()?.so;
781    let cr0 = ConditionRegister::from_ordering(ra.cmp(&immediate), so);
782    Ok(InstructionOutput {
783        cr0: Some(cr0),
784        ..InstructionOutput::default()
785    })
786}
787
788pub fn cmpldi(inputs: InstructionInput) -> InstructionResult {
789    let ra = inputs.try_get_ra()? as u64;
790    let immediate = inputs.try_get_immediate_u16()? as u64;
791    let so = inputs.try_get_overflow()?.so;
792    let cr0 = ConditionRegister::from_ordering(ra.cmp(&immediate), so);
793    Ok(InstructionOutput {
794        cr0: Some(cr0),
795        ..InstructionOutput::default()
796    })
797}
798
799pub fn cmplwi(inputs: InstructionInput) -> InstructionResult {
800    let ra = inputs.try_get_ra()? as u32;
801    let immediate = inputs.try_get_immediate_u16()? as u32;
802    let so = inputs.try_get_overflow()?.so;
803    let cr0 = ConditionRegister::from_ordering(ra.cmp(&immediate), so);
804    Ok(InstructionOutput {
805        cr0: Some(cr0),
806        ..InstructionOutput::default()
807    })
808}
809
810pub fn cmpd(inputs: InstructionInput) -> InstructionResult {
811    let ra = inputs.try_get_ra()? as i64;
812    let rb = inputs.try_get_rb()? as i64;
813    let so = inputs.try_get_overflow()?.so;
814    let cr0 = ConditionRegister::from_ordering(ra.cmp(&rb), so);
815    Ok(InstructionOutput {
816        cr0: Some(cr0),
817        ..InstructionOutput::default()
818    })
819}
820
821pub fn cmpw(inputs: InstructionInput) -> InstructionResult {
822    let ra = inputs.try_get_ra()? as i32;
823    let rb = inputs.try_get_rb()? as i32;
824    let so = inputs.try_get_overflow()?.so;
825    let cr0 = ConditionRegister::from_ordering(ra.cmp(&rb), so);
826    Ok(InstructionOutput {
827        cr0: Some(cr0),
828        ..InstructionOutput::default()
829    })
830}
831
832pub fn cmpld(inputs: InstructionInput) -> InstructionResult {
833    let ra = inputs.try_get_ra()? as u64;
834    let rb = inputs.try_get_rb()? as u64;
835    let so = inputs.try_get_overflow()?.so;
836    let cr0 = ConditionRegister::from_ordering(ra.cmp(&rb), so);
837    Ok(InstructionOutput {
838        cr0: Some(cr0),
839        ..InstructionOutput::default()
840    })
841}
842
843pub fn cmplw(inputs: InstructionInput) -> InstructionResult {
844    let ra = inputs.try_get_ra()? as u32;
845    let rb = inputs.try_get_rb()? as u32;
846    let so = inputs.try_get_overflow()?.so;
847    let cr0 = ConditionRegister::from_ordering(ra.cmp(&rb), so);
848    Ok(InstructionOutput {
849        cr0: Some(cr0),
850        ..InstructionOutput::default()
851    })
852}
853
854pub fn cmprb_0(inputs: InstructionInput) -> InstructionResult {
855    let ra = inputs.try_get_ra()? as u8;
856    let rb: u64 = inputs.try_get_rb()?;
857    let in_range = ra >= rb as u8 && ra <= (rb >> 8) as u8;
858    let cr0 = ConditionRegister {
859        lt: false,
860        gt: in_range,
861        eq: false,
862        so: false,
863    };
864    Ok(InstructionOutput {
865        cr0: Some(cr0),
866        ..InstructionOutput::default()
867    })
868}