2 CarryFlags, ConditionRegister, InstructionInput, InstructionOutput, InstructionResult,
3 MissingInstructionInput, OverflowFlags,
5 use std::convert::TryFrom;
8 mut overflow: OverflowFlags,
9 inputs: InstructionInput,
10 ) -> Result<OverflowFlags, MissingInstructionInput> {
11 if inputs.try_get_overflow()?.so {
17 macro_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 {
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;
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);
44 macro_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(
51 inputs.try_get_overflow()?.so,
53 retval.cr0 = Some(cr0);
59 pub 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 {
65 ..InstructionOutput::default()
69 create_instr_variants_ov_cr!(add, addo, add_, addo_, i64);
71 pub fn addo(inputs: InstructionInput) -> InstructionResult {
72 let ra = inputs.try_get_ra()? as i64;
73 let rb = inputs.try_get_rb()? as i64;
74 let (result, ov) = ra.overflowing_add(rb);
75 let result = result as u64;
76 let ov32 = (ra as i32).overflowing_add(rb as i32).1;
77 Ok(InstructionOutput {
79 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
80 ..InstructionOutput::default()
84 create_instr_variants_ov_cr!(subf, subfo, subf_, subfo_, i64);
86 pub fn subfo(inputs: InstructionInput) -> InstructionResult {
87 let ra = inputs.try_get_ra()? as i64;
88 let rb = inputs.try_get_rb()? as i64;
89 let (result, ov) = rb.overflowing_sub(ra);
90 let result = result as u64;
91 let ov32 = (rb as i32).overflowing_sub(ra as i32).1;
92 Ok(InstructionOutput {
94 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
95 ..InstructionOutput::default()
99 create_instr_variants_ov_cr!(addc, addco, addc_, addco_, i64);
101 pub fn addco(inputs: InstructionInput) -> InstructionResult {
102 let ra = inputs.try_get_ra()? as i64;
103 let rb = inputs.try_get_rb()? as i64;
104 let (result, ov) = ra.overflowing_add(rb);
105 let result = result as u64;
106 let ov32 = (ra as i32).overflowing_add(rb as i32).1;
107 let ca = (ra as u64).overflowing_add(rb as u64).1;
108 let ca32 = (ra as u32).overflowing_add(rb as u32).1;
109 Ok(InstructionOutput {
111 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
112 carry: Some(CarryFlags { ca, ca32 }),
113 ..InstructionOutput::default()
117 create_instr_variants_ov_cr!(subfc, subfco, subfc_, subfco_, i64);
119 pub fn subfco(inputs: InstructionInput) -> InstructionResult {
120 let ra = inputs.try_get_ra()? as i64;
121 let rb = inputs.try_get_rb()? as i64;
122 let (result, ov) = rb.overflowing_sub(ra);
123 let result = result as u64;
124 let ov32 = (rb as i32).overflowing_sub(ra as i32).1;
125 let ca = !(rb as u64).overflowing_sub(ra as u64).1;
126 let ca32 = !(rb as u32).overflowing_sub(ra as u32).1;
127 Ok(InstructionOutput {
129 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
130 carry: Some(CarryFlags { ca, ca32 }),
131 ..InstructionOutput::default()
135 create_instr_variants_ov_cr!(adde, addeo, adde_, addeo_, i64);
137 pub fn addeo(inputs: InstructionInput) -> InstructionResult {
138 let ra: u64 = inputs.try_get_ra()?;
139 let rb: u64 = inputs.try_get_rb()?;
140 let carry_in = inputs.try_get_carry()?.ca;
141 let result_i128 = ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
142 let result_u128 = ra as u128 + rb as u128 + carry_in as u128;
143 let result32_i128 = ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
144 let result32_u128 = ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
145 let result = result_u128 as u64;
146 let ov = i64::try_from(result_i128).is_err();
147 let ov32 = i32::try_from(result32_i128).is_err();
148 let ca = u64::try_from(result_u128).is_err();
149 let ca32 = u32::try_from(result32_u128).is_err();
150 Ok(InstructionOutput {
152 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
153 carry: Some(CarryFlags { ca, ca32 }),
154 ..InstructionOutput::default()
158 create_instr_variants_ov_cr!(subfe, subfeo, subfe_, subfeo_, i64);
160 pub fn subfeo(inputs: InstructionInput) -> InstructionResult {
161 let ra: u64 = inputs.try_get_ra()?;
162 let rb: u64 = inputs.try_get_rb()?;
163 let carry_in = inputs.try_get_carry()?.ca;
165 let result_i128 = not_ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
166 let result_u128 = not_ra as u128 + rb as u128 + carry_in as u128;
167 let result32_i128 = not_ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
168 let result32_u128 = not_ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
169 let result = result_u128 as u64;
170 let ov = i64::try_from(result_i128).is_err();
171 let ov32 = i32::try_from(result32_i128).is_err();
172 let ca = u64::try_from(result_u128).is_err();
173 let ca32 = u32::try_from(result32_u128).is_err();
174 Ok(InstructionOutput {
176 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
177 carry: Some(CarryFlags { ca, ca32 }),
178 ..InstructionOutput::default()
182 create_instr_variants_ov_cr!(addme, addmeo, addme_, addmeo_, i64);
184 pub fn addmeo(inputs: InstructionInput) -> InstructionResult {
185 let ra: u64 = inputs.try_get_ra()?;
187 let carry_in = inputs.try_get_carry()?.ca;
188 let result_i128 = ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
189 let result_u128 = ra as u128 + rb as u128 + carry_in as u128;
190 let result32_i128 = ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
191 let result32_u128 = ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
192 let result = result_u128 as u64;
193 let ov = i64::try_from(result_i128).is_err();
194 let ov32 = i32::try_from(result32_i128).is_err();
195 let ca = u64::try_from(result_u128).is_err();
196 let ca32 = u32::try_from(result32_u128).is_err();
197 Ok(InstructionOutput {
199 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
200 carry: Some(CarryFlags { ca, ca32 }),
201 ..InstructionOutput::default()
205 create_instr_variants_ov_cr!(subfme, subfmeo, subfme_, subfmeo_, i64);
207 pub fn subfmeo(inputs: InstructionInput) -> InstructionResult {
208 let ra: u64 = inputs.try_get_ra()?;
210 let carry_in = inputs.try_get_carry()?.ca;
212 let result_i128 = not_ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
213 let result_u128 = not_ra as u128 + rb as u128 + carry_in as u128;
214 let result32_i128 = not_ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
215 let result32_u128 = not_ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
216 let result = result_u128 as u64;
217 let ov = i64::try_from(result_i128).is_err();
218 let ov32 = i32::try_from(result32_i128).is_err();
219 let ca = u64::try_from(result_u128).is_err();
220 let ca32 = u32::try_from(result32_u128).is_err();
221 Ok(InstructionOutput {
223 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
224 carry: Some(CarryFlags { ca, ca32 }),
225 ..InstructionOutput::default()
229 create_instr_variants_ov_cr!(addze, addzeo, addze_, addzeo_, i64);
231 pub fn addzeo(inputs: InstructionInput) -> InstructionResult {
232 let ra: u64 = inputs.try_get_ra()?;
233 let carry_in = inputs.try_get_carry()?.ca;
234 let result_i128 = ra as i64 as i128 + carry_in as i128;
235 let result_u128 = ra as u128 + carry_in as u128;
236 let result32_i128 = ra as i32 as i128 + carry_in as i128;
237 let result32_u128 = ra as u32 as u128 + carry_in as u128;
238 let result = result_u128 as u64;
239 let ov = i64::try_from(result_i128).is_err();
240 let ov32 = i32::try_from(result32_i128).is_err();
241 let ca = u64::try_from(result_u128).is_err();
242 let ca32 = u32::try_from(result32_u128).is_err();
243 Ok(InstructionOutput {
245 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
246 carry: Some(CarryFlags { ca, ca32 }),
247 ..InstructionOutput::default()
251 create_instr_variants_ov_cr!(subfze, subfzeo, subfze_, subfzeo_, i64);
253 pub fn subfzeo(inputs: InstructionInput) -> InstructionResult {
254 let ra: u64 = inputs.try_get_ra()?;
255 let carry_in = inputs.try_get_carry()?.ca;
257 let result_i128 = not_ra as i64 as i128 + carry_in as i128;
258 let result_u128 = not_ra as u128 + carry_in as u128;
259 let result32_i128 = not_ra as i32 as i128 + carry_in as i128;
260 let result32_u128 = not_ra 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 {
268 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
269 carry: Some(CarryFlags { ca, ca32 }),
270 ..InstructionOutput::default()
274 pub fn addex(inputs: InstructionInput) -> InstructionResult {
275 let ra: u64 = inputs.try_get_ra()?;
276 let rb: u64 = inputs.try_get_rb()?;
279 } = inputs.try_get_overflow()?;
280 let result_u128 = ra as u128 + rb as u128 + carry_in as u128;
281 let result32_u128 = ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
282 let result = result_u128 as u64;
283 let carry = u64::try_from(result_u128).is_err();
284 let carry32 = u32::try_from(result32_u128).is_err();
285 Ok(InstructionOutput {
287 // doesn't change `so` on purpose
288 overflow: Some(OverflowFlags {
293 ..InstructionOutput::default()
297 create_instr_variants_ov_cr!(neg, nego, neg_, nego_, i64);
299 pub fn nego(inputs: InstructionInput) -> InstructionResult {
300 let ra = inputs.try_get_ra()? as i64;
301 let result = ra.wrapping_neg() as u64;
302 let ov = ra.checked_neg().is_none();
303 let ov32 = (ra as i32).checked_neg().is_none();
304 Ok(InstructionOutput {
306 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
307 ..InstructionOutput::default()
311 create_instr_variants_ov_cr!(divde, divdeo, divde_, divdeo_, i64);
313 pub fn divdeo(inputs: InstructionInput) -> InstructionResult {
314 let dividend = i128::from(inputs.try_get_ra()? as i64) << 64;
315 let divisor = i128::from(inputs.try_get_rb()? as i64);
318 if divisor == 0 || (divisor == -1 && dividend == i128::min_value()) {
322 let result128 = dividend / divisor;
323 if result128 as i64 as i128 != result128 {
327 result = result128 as u64;
331 Ok(InstructionOutput {
333 overflow: Some(propagate_so(
334 OverflowFlags::from_overflow(overflow),
337 ..InstructionOutput::default()
341 create_instr_variants_ov_cr!(divdeu, divdeuo, divdeu_, divdeuo_, i64);
343 pub fn divdeuo(inputs: InstructionInput) -> InstructionResult {
344 let dividend = u128::from(inputs.try_get_ra()?) << 64;
345 let divisor = u128::from(inputs.try_get_rb()?);
352 let resultu128 = dividend / divisor;
353 if resultu128 > u128::from(u64::max_value()) {
357 result = resultu128 as u64;
361 Ok(InstructionOutput {
363 overflow: Some(propagate_so(
364 OverflowFlags::from_overflow(overflow),
367 ..InstructionOutput::default()
371 create_instr_variants_ov_cr!(divd, divdo, divd_, divdo_, i64);
373 pub fn divdo(inputs: InstructionInput) -> InstructionResult {
374 let dividend = inputs.try_get_ra()? as i64;
375 let divisor = inputs.try_get_rb()? as i64;
378 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
382 result = (dividend / divisor) as u64;
385 Ok(InstructionOutput {
387 overflow: Some(propagate_so(
388 OverflowFlags::from_overflow(overflow),
391 ..InstructionOutput::default()
395 create_instr_variants_ov_cr!(divdu, divduo, divdu_, divduo_, i64);
397 pub fn divduo(inputs: InstructionInput) -> InstructionResult {
398 let dividend: u64 = inputs.try_get_ra()?;
399 let divisor: u64 = inputs.try_get_rb()?;
406 result = dividend / divisor;
409 Ok(InstructionOutput {
411 overflow: Some(propagate_so(
412 OverflowFlags::from_overflow(overflow),
415 ..InstructionOutput::default()
419 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
420 create_instr_variants_ov_cr!(divwe, divweo, divwe_, divweo_, i64);
422 pub fn divweo(inputs: InstructionInput) -> InstructionResult {
423 let dividend = i64::from(inputs.try_get_ra()? as i32) << 32;
424 let divisor = i64::from(inputs.try_get_rb()? as i32);
427 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
431 let result64 = dividend / divisor;
432 if result64 as i32 as i64 != result64 {
436 result = result64 as u32 as u64;
440 Ok(InstructionOutput {
442 overflow: Some(propagate_so(
443 OverflowFlags::from_overflow(overflow),
446 ..InstructionOutput::default()
450 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
451 create_instr_variants_ov_cr!(divweu, divweuo, divweu_, divweuo_, i64);
453 pub fn divweuo(inputs: InstructionInput) -> InstructionResult {
454 let dividend = u64::from(inputs.try_get_ra()? as u32) << 32;
455 let divisor = u64::from(inputs.try_get_rb()? as u32);
462 let resultu64 = dividend / divisor;
463 if resultu64 > u64::from(u32::max_value()) {
467 result = resultu64 as u32 as u64;
471 Ok(InstructionOutput {
473 overflow: Some(propagate_so(
474 OverflowFlags::from_overflow(overflow),
477 ..InstructionOutput::default()
481 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
482 create_instr_variants_ov_cr!(divw, divwo, divw_, divwo_, i64);
484 pub fn divwo(inputs: InstructionInput) -> InstructionResult {
485 let dividend = inputs.try_get_ra()? as i32;
486 let divisor = inputs.try_get_rb()? as i32;
489 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
493 result = (dividend / divisor) as u32 as u64;
496 Ok(InstructionOutput {
498 overflow: Some(propagate_so(
499 OverflowFlags::from_overflow(overflow),
502 ..InstructionOutput::default()
506 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
507 create_instr_variants_ov_cr!(divwu, divwuo, divwu_, divwuo_, i64);
509 pub fn divwuo(inputs: InstructionInput) -> InstructionResult {
510 let dividend = inputs.try_get_ra()? as u32;
511 let divisor = inputs.try_get_rb()? as u32;
518 result = (dividend / divisor) as u64;
521 Ok(InstructionOutput {
523 overflow: Some(propagate_so(
524 OverflowFlags::from_overflow(overflow),
527 ..InstructionOutput::default()
531 pub fn modsd(inputs: InstructionInput) -> InstructionResult {
532 let dividend = inputs.try_get_ra()? as i64;
533 let divisor = inputs.try_get_rb()? as i64;
535 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
538 result = (dividend % divisor) as u64;
540 Ok(InstructionOutput {
542 ..InstructionOutput::default()
546 pub fn modud(inputs: InstructionInput) -> InstructionResult {
547 let dividend: u64 = inputs.try_get_ra()?;
548 let divisor: u64 = inputs.try_get_rb()?;
553 result = dividend % divisor;
555 Ok(InstructionOutput {
557 ..InstructionOutput::default()
561 pub fn modsw(inputs: InstructionInput) -> InstructionResult {
562 let dividend = inputs.try_get_ra()? as i32;
563 let divisor = inputs.try_get_rb()? as i32;
565 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
568 result = (dividend % divisor) as u64;
570 Ok(InstructionOutput {
572 ..InstructionOutput::default()
576 pub fn moduw(inputs: InstructionInput) -> InstructionResult {
577 let dividend = inputs.try_get_ra()? as u32;
578 let divisor = inputs.try_get_rb()? as u32;
583 result = (dividend % divisor) as u64;
585 Ok(InstructionOutput {
587 ..InstructionOutput::default()
591 create_instr_variants_ov_cr!(mullw, mullwo, mullw_, mullwo_, i64);
593 pub fn mullwo(inputs: InstructionInput) -> InstructionResult {
594 let ra = inputs.try_get_ra()? as i32 as i64;
595 let rb = inputs.try_get_rb()? as i32 as i64;
596 let result = ra.wrapping_mul(rb) as u64;
597 let overflow = result as i32 as i64 != result as i64;
598 Ok(InstructionOutput {
600 overflow: Some(propagate_so(
601 OverflowFlags::from_overflow(overflow),
604 ..InstructionOutput::default()
608 create_instr_variants_cr!(mulhw, mulhw_, i32);
610 pub fn mulhw(inputs: InstructionInput) -> InstructionResult {
611 let ra = inputs.try_get_ra()? as i32 as i64;
612 let rb = inputs.try_get_rb()? as i32 as i64;
613 let result = (ra * rb) >> 32;
614 let mut result = result as u32 as u64;
615 result |= result << 32;
616 Ok(InstructionOutput {
618 ..InstructionOutput::default()
622 create_instr_variants_cr!(mulhwu, mulhwu_, i32);
624 pub fn mulhwu(inputs: InstructionInput) -> InstructionResult {
625 let ra = inputs.try_get_ra()? as u32 as u64;
626 let rb = inputs.try_get_rb()? as u32 as u64;
627 let result = (ra * rb) >> 32;
628 let mut result = result as u32 as u64;
629 result |= result << 32;
630 Ok(InstructionOutput {
632 ..InstructionOutput::default()
636 create_instr_variants_ov_cr!(mulld, mulldo, mulld_, mulldo_, i64);
638 pub fn mulldo(inputs: InstructionInput) -> InstructionResult {
639 let ra = inputs.try_get_ra()? as i64;
640 let rb = inputs.try_get_rb()? as i64;
641 let result = ra.wrapping_mul(rb) as u64;
642 let overflow = ra.checked_mul(rb).is_none();
643 Ok(InstructionOutput {
645 overflow: Some(propagate_so(
646 OverflowFlags::from_overflow(overflow),
649 ..InstructionOutput::default()
653 create_instr_variants_cr!(mulhd, mulhd_, i64);
655 pub fn mulhd(inputs: InstructionInput) -> InstructionResult {
656 let ra = inputs.try_get_ra()? as i64 as i128;
657 let rb = inputs.try_get_rb()? as i64 as i128;
658 let result = ((ra * rb) >> 64) as i64;
659 let result = result as u64;
660 Ok(InstructionOutput {
662 ..InstructionOutput::default()
666 create_instr_variants_cr!(mulhdu, mulhdu_, i64);
668 pub fn mulhdu(inputs: InstructionInput) -> InstructionResult {
669 let ra = inputs.try_get_ra()? as u128;
670 let rb = inputs.try_get_rb()? as u128;
671 let result = ((ra * rb) >> 64) as u64;
672 Ok(InstructionOutput {
674 ..InstructionOutput::default()
678 pub fn maddhd(inputs: InstructionInput) -> InstructionResult {
679 let ra = inputs.try_get_ra()? as i64 as i128;
680 let rb = inputs.try_get_rb()? as i64 as i128;
681 let rc = inputs.try_get_rc()? as i64 as i128;
682 let result = ((ra * rb + rc) >> 64) as u64;
683 Ok(InstructionOutput {
685 ..InstructionOutput::default()
689 pub fn maddhdu(inputs: InstructionInput) -> InstructionResult {
690 let ra = inputs.try_get_ra()? as u128;
691 let rb = inputs.try_get_rb()? as u128;
692 let rc = inputs.try_get_rc()? as u128;
693 let result = ((ra * rb + rc) >> 64) as u64;
694 Ok(InstructionOutput {
696 ..InstructionOutput::default()
700 pub fn maddld(inputs: InstructionInput) -> InstructionResult {
701 let ra = inputs.try_get_ra()? as i64;
702 let rb = inputs.try_get_rb()? as i64;
703 let rc = inputs.try_get_rc()? as i64;
704 let result = ra.wrapping_mul(rb).wrapping_add(rc) as u64;
705 Ok(InstructionOutput {
707 ..InstructionOutput::default()