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 create_instr_variants_ov_cr!(add, addo, add_, addo_, i64);
61 pub fn addo(inputs: InstructionInput) -> InstructionResult {
62 let ra = inputs.try_get_ra()? as i64;
63 let rb = inputs.try_get_rb()? as i64;
64 let (result, ov) = ra.overflowing_add(rb);
65 let result = result as u64;
66 let ov32 = (ra as i32).overflowing_add(rb as i32).1;
67 Ok(InstructionOutput {
69 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
70 ..InstructionOutput::default()
74 create_instr_variants_ov_cr!(subf, subfo, subf_, subfo_, i64);
76 pub fn subfo(inputs: InstructionInput) -> InstructionResult {
77 let ra = inputs.try_get_ra()? as i64;
78 let rb = inputs.try_get_rb()? as i64;
79 let (result, ov) = rb.overflowing_sub(ra);
80 let result = result as u64;
81 let ov32 = (rb as i32).overflowing_sub(ra as i32).1;
82 Ok(InstructionOutput {
84 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
85 ..InstructionOutput::default()
89 create_instr_variants_ov_cr!(addc, addco, addc_, addco_, i64);
91 pub fn addco(inputs: InstructionInput) -> InstructionResult {
92 let ra = inputs.try_get_ra()? as i64;
93 let rb = inputs.try_get_rb()? as i64;
94 let (result, ov) = ra.overflowing_add(rb);
95 let result = result as u64;
96 let ov32 = (ra as i32).overflowing_add(rb as i32).1;
97 let ca = (ra as u64).overflowing_add(rb as u64).1;
98 let ca32 = (ra as u32).overflowing_add(rb as u32).1;
99 Ok(InstructionOutput {
101 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
102 carry: Some(CarryFlags { ca, ca32 }),
103 ..InstructionOutput::default()
107 create_instr_variants_ov_cr!(subfc, subfco, subfc_, subfco_, i64);
109 pub fn subfco(inputs: InstructionInput) -> InstructionResult {
110 let ra = inputs.try_get_ra()? as i64;
111 let rb = inputs.try_get_rb()? as i64;
112 let (result, ov) = rb.overflowing_sub(ra);
113 let result = result as u64;
114 let ov32 = (rb as i32).overflowing_sub(ra as i32).1;
115 let ca = !(rb as u64).overflowing_sub(ra as u64).1;
116 let ca32 = !(rb as u32).overflowing_sub(ra as u32).1;
117 Ok(InstructionOutput {
119 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
120 carry: Some(CarryFlags { ca, ca32 }),
121 ..InstructionOutput::default()
125 create_instr_variants_ov_cr!(adde, addeo, adde_, addeo_, i64);
127 pub fn addeo(inputs: InstructionInput) -> InstructionResult {
128 let ra: u64 = inputs.try_get_ra()?;
129 let rb: u64 = inputs.try_get_rb()?;
130 let carry_in = inputs.try_get_carry()?.ca;
131 let result_i128 = ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
132 let result_u128 = ra as u128 + rb as u128 + carry_in as u128;
133 let result32_i128 = ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
134 let result32_u128 = ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
135 let result = result_u128 as u64;
136 let ov = i64::try_from(result_i128).is_err();
137 let ov32 = i32::try_from(result32_i128).is_err();
138 let ca = u64::try_from(result_u128).is_err();
139 let ca32 = u32::try_from(result32_u128).is_err();
140 Ok(InstructionOutput {
142 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
143 carry: Some(CarryFlags { ca, ca32 }),
144 ..InstructionOutput::default()
148 create_instr_variants_ov_cr!(subfe, subfeo, subfe_, subfeo_, i64);
150 pub fn subfeo(inputs: InstructionInput) -> InstructionResult {
151 let ra: u64 = inputs.try_get_ra()?;
152 let rb: u64 = inputs.try_get_rb()?;
153 let carry_in = inputs.try_get_carry()?.ca;
155 let result_i128 = not_ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
156 let result_u128 = not_ra as u128 + rb as u128 + carry_in as u128;
157 let result32_i128 = not_ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
158 let result32_u128 = not_ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
159 let result = result_u128 as u64;
160 let ov = i64::try_from(result_i128).is_err();
161 let ov32 = i32::try_from(result32_i128).is_err();
162 let ca = u64::try_from(result_u128).is_err();
163 let ca32 = u32::try_from(result32_u128).is_err();
164 Ok(InstructionOutput {
166 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
167 carry: Some(CarryFlags { ca, ca32 }),
168 ..InstructionOutput::default()
172 create_instr_variants_ov_cr!(addme, addmeo, addme_, addmeo_, i64);
174 pub fn addmeo(inputs: InstructionInput) -> InstructionResult {
175 let ra: u64 = inputs.try_get_ra()?;
177 let carry_in = inputs.try_get_carry()?.ca;
178 let result_i128 = ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
179 let result_u128 = ra as u128 + rb as u128 + carry_in as u128;
180 let result32_i128 = ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
181 let result32_u128 = ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
182 let result = result_u128 as u64;
183 let ov = i64::try_from(result_i128).is_err();
184 let ov32 = i32::try_from(result32_i128).is_err();
185 let ca = u64::try_from(result_u128).is_err();
186 let ca32 = u32::try_from(result32_u128).is_err();
187 Ok(InstructionOutput {
189 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
190 carry: Some(CarryFlags { ca, ca32 }),
191 ..InstructionOutput::default()
195 create_instr_variants_ov_cr!(subfme, subfmeo, subfme_, subfmeo_, i64);
197 pub fn subfmeo(inputs: InstructionInput) -> InstructionResult {
198 let ra: u64 = inputs.try_get_ra()?;
200 let carry_in = inputs.try_get_carry()?.ca;
202 let result_i128 = not_ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
203 let result_u128 = not_ra as u128 + rb as u128 + carry_in as u128;
204 let result32_i128 = not_ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
205 let result32_u128 = not_ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
206 let result = result_u128 as u64;
207 let ov = i64::try_from(result_i128).is_err();
208 let ov32 = i32::try_from(result32_i128).is_err();
209 let ca = u64::try_from(result_u128).is_err();
210 let ca32 = u32::try_from(result32_u128).is_err();
211 Ok(InstructionOutput {
213 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
214 carry: Some(CarryFlags { ca, ca32 }),
215 ..InstructionOutput::default()
219 create_instr_variants_ov_cr!(addze, addzeo, addze_, addzeo_, i64);
221 pub fn addzeo(inputs: InstructionInput) -> InstructionResult {
222 let ra: u64 = inputs.try_get_ra()?;
223 let carry_in = inputs.try_get_carry()?.ca;
224 let result_i128 = ra as i64 as i128 + carry_in as i128;
225 let result_u128 = ra as u128 + carry_in as u128;
226 let result32_i128 = ra as i32 as i128 + carry_in as i128;
227 let result32_u128 = ra as u32 as u128 + carry_in as u128;
228 let result = result_u128 as u64;
229 let ov = i64::try_from(result_i128).is_err();
230 let ov32 = i32::try_from(result32_i128).is_err();
231 let ca = u64::try_from(result_u128).is_err();
232 let ca32 = u32::try_from(result32_u128).is_err();
233 Ok(InstructionOutput {
235 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
236 carry: Some(CarryFlags { ca, ca32 }),
237 ..InstructionOutput::default()
241 create_instr_variants_ov_cr!(subfze, subfzeo, subfze_, subfzeo_, i64);
243 pub fn subfzeo(inputs: InstructionInput) -> InstructionResult {
244 let ra: u64 = inputs.try_get_ra()?;
245 let carry_in = inputs.try_get_carry()?.ca;
247 let result_i128 = not_ra as i64 as i128 + carry_in as i128;
248 let result_u128 = not_ra as u128 + carry_in as u128;
249 let result32_i128 = not_ra as i32 as i128 + carry_in as i128;
250 let result32_u128 = not_ra as u32 as u128 + carry_in as u128;
251 let result = result_u128 as u64;
252 let ov = i64::try_from(result_i128).is_err();
253 let ov32 = i32::try_from(result32_i128).is_err();
254 let ca = u64::try_from(result_u128).is_err();
255 let ca32 = u32::try_from(result32_u128).is_err();
256 Ok(InstructionOutput {
258 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
259 carry: Some(CarryFlags { ca, ca32 }),
260 ..InstructionOutput::default()
264 pub fn addex(inputs: InstructionInput) -> InstructionResult {
265 let ra: u64 = inputs.try_get_ra()?;
266 let rb: u64 = inputs.try_get_ra()?;
269 } = inputs.try_get_overflow()?;
270 let result_u128 = ra as u128 + rb as u128 + carry_in as u128;
271 let result32_u128 = ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
272 let result = result_u128 as u64;
273 let carry = u64::try_from(result_u128).is_err();
274 let carry32 = u32::try_from(result32_u128).is_err();
275 Ok(InstructionOutput {
277 // doesn't change `so` on purpose
278 overflow: Some(OverflowFlags {
283 ..InstructionOutput::default()
287 create_instr_variants_ov_cr!(divde, divdeo, divde_, divdeo_, i64);
289 pub fn divdeo(inputs: InstructionInput) -> InstructionResult {
290 let dividend = i128::from(inputs.try_get_ra()? as i64) << 64;
291 let divisor = i128::from(inputs.try_get_rb()? as i64);
294 if divisor == 0 || (divisor == -1 && dividend == i128::min_value()) {
298 let result128 = dividend / divisor;
299 if result128 as i64 as i128 != result128 {
303 result = result128 as u64;
307 Ok(InstructionOutput {
309 overflow: Some(propagate_so(
310 OverflowFlags::from_overflow(overflow),
313 ..InstructionOutput::default()
317 create_instr_variants_ov_cr!(divdeu, divdeuo, divdeu_, divdeuo_, i64);
319 pub fn divdeuo(inputs: InstructionInput) -> InstructionResult {
320 let dividend = u128::from(inputs.try_get_ra()?) << 64;
321 let divisor = u128::from(inputs.try_get_rb()?);
328 let resultu128 = dividend / divisor;
329 if resultu128 > u128::from(u64::max_value()) {
333 result = resultu128 as u64;
337 Ok(InstructionOutput {
339 overflow: Some(propagate_so(
340 OverflowFlags::from_overflow(overflow),
343 ..InstructionOutput::default()
347 create_instr_variants_ov_cr!(divd, divdo, divd_, divdo_, i64);
349 pub fn divdo(inputs: InstructionInput) -> InstructionResult {
350 let dividend = inputs.try_get_ra()? as i64;
351 let divisor = inputs.try_get_rb()? as i64;
354 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
358 result = (dividend / divisor) as u64;
361 Ok(InstructionOutput {
363 overflow: Some(propagate_so(
364 OverflowFlags::from_overflow(overflow),
367 ..InstructionOutput::default()
371 create_instr_variants_ov_cr!(divdu, divduo, divdu_, divduo_, i64);
373 pub fn divduo(inputs: InstructionInput) -> InstructionResult {
374 let dividend: u64 = inputs.try_get_ra()?;
375 let divisor: u64 = inputs.try_get_rb()?;
382 result = dividend / divisor;
385 Ok(InstructionOutput {
387 overflow: Some(propagate_so(
388 OverflowFlags::from_overflow(overflow),
391 ..InstructionOutput::default()
395 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
396 create_instr_variants_ov_cr!(divwe, divweo, divwe_, divweo_, i64);
398 pub fn divweo(inputs: InstructionInput) -> InstructionResult {
399 let dividend = i64::from(inputs.try_get_ra()? as i32) << 32;
400 let divisor = i64::from(inputs.try_get_rb()? as i32);
403 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
407 let result64 = dividend / divisor;
408 if result64 as i32 as i64 != result64 {
412 result = result64 as u32 as u64;
416 Ok(InstructionOutput {
418 overflow: Some(propagate_so(
419 OverflowFlags::from_overflow(overflow),
422 ..InstructionOutput::default()
426 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
427 create_instr_variants_ov_cr!(divweu, divweuo, divweu_, divweuo_, i64);
429 pub fn divweuo(inputs: InstructionInput) -> InstructionResult {
430 let dividend = u64::from(inputs.try_get_ra()? as u32) << 32;
431 let divisor = u64::from(inputs.try_get_rb()? as u32);
438 let resultu64 = dividend / divisor;
439 if resultu64 > u64::from(u32::max_value()) {
443 result = resultu64 as u32 as u64;
447 Ok(InstructionOutput {
449 overflow: Some(propagate_so(
450 OverflowFlags::from_overflow(overflow),
453 ..InstructionOutput::default()
457 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
458 create_instr_variants_ov_cr!(divw, divwo, divw_, divwo_, i64);
460 pub fn divwo(inputs: InstructionInput) -> InstructionResult {
461 let dividend = inputs.try_get_ra()? as i32;
462 let divisor = inputs.try_get_rb()? as i32;
465 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
469 result = (dividend / divisor) as u32 as u64;
472 Ok(InstructionOutput {
474 overflow: Some(propagate_so(
475 OverflowFlags::from_overflow(overflow),
478 ..InstructionOutput::default()
482 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
483 create_instr_variants_ov_cr!(divwu, divwuo, divwu_, divwuo_, i64);
485 pub fn divwuo(inputs: InstructionInput) -> InstructionResult {
486 let dividend = inputs.try_get_ra()? as u32;
487 let divisor = inputs.try_get_rb()? as u32;
494 result = (dividend / divisor) as u64;
497 Ok(InstructionOutput {
499 overflow: Some(propagate_so(
500 OverflowFlags::from_overflow(overflow),
503 ..InstructionOutput::default()
507 pub fn modsd(inputs: InstructionInput) -> InstructionResult {
508 let dividend = inputs.try_get_ra()? as i64;
509 let divisor = inputs.try_get_rb()? as i64;
511 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
514 result = (dividend % divisor) as u64;
516 Ok(InstructionOutput {
518 ..InstructionOutput::default()
522 pub fn modud(inputs: InstructionInput) -> InstructionResult {
523 let dividend: u64 = inputs.try_get_ra()?;
524 let divisor: u64 = inputs.try_get_rb()?;
529 result = dividend % divisor;
531 Ok(InstructionOutput {
533 ..InstructionOutput::default()
537 pub fn modsw(inputs: InstructionInput) -> InstructionResult {
538 let dividend = inputs.try_get_ra()? as i32;
539 let divisor = inputs.try_get_rb()? as i32;
541 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
544 result = (dividend % divisor) as u64;
546 Ok(InstructionOutput {
548 ..InstructionOutput::default()
552 pub fn moduw(inputs: InstructionInput) -> InstructionResult {
553 let dividend = inputs.try_get_ra()? as u32;
554 let divisor = inputs.try_get_rb()? as u32;
559 result = (dividend % divisor) as u64;
561 Ok(InstructionOutput {
563 ..InstructionOutput::default()
567 create_instr_variants_ov_cr!(mullw, mullwo, mullw_, mullwo_, i64);
569 pub fn mullwo(inputs: InstructionInput) -> InstructionResult {
570 let ra = inputs.try_get_ra()? as i32 as i64;
571 let rb = inputs.try_get_rb()? as i32 as i64;
572 let result = ra.wrapping_mul(rb) as u64;
573 let overflow = result as i32 as i64 != result as i64;
574 Ok(InstructionOutput {
576 overflow: Some(propagate_so(
577 OverflowFlags::from_overflow(overflow),
580 ..InstructionOutput::default()
584 create_instr_variants_cr!(mulhw, mulhw_, i32);
586 pub fn mulhw(inputs: InstructionInput) -> InstructionResult {
587 let ra = inputs.try_get_ra()? as i32 as i64;
588 let rb = inputs.try_get_rb()? as i32 as i64;
589 let result = (ra * rb) >> 32;
590 let mut result = result as u32 as u64;
591 result |= result << 32;
592 Ok(InstructionOutput {
594 ..InstructionOutput::default()
598 create_instr_variants_cr!(mulhwu, mulhwu_, i32);
600 pub fn mulhwu(inputs: InstructionInput) -> InstructionResult {
601 let ra = inputs.try_get_ra()? as u32 as u64;
602 let rb = inputs.try_get_rb()? as u32 as u64;
603 let result = (ra * rb) >> 32;
604 let mut result = result as u32 as u64;
605 result |= result << 32;
606 Ok(InstructionOutput {
608 ..InstructionOutput::default()
612 create_instr_variants_ov_cr!(mulld, mulldo, mulld_, mulldo_, i64);
614 pub fn mulldo(inputs: InstructionInput) -> InstructionResult {
615 let ra = inputs.try_get_ra()? as i64;
616 let rb = inputs.try_get_rb()? as i64;
617 let result = ra.wrapping_mul(rb) as u64;
618 let overflow = ra.checked_mul(rb).is_none();
619 Ok(InstructionOutput {
621 overflow: Some(propagate_so(
622 OverflowFlags::from_overflow(overflow),
625 ..InstructionOutput::default()
629 create_instr_variants_cr!(mulhd, mulhd_, i64);
631 pub fn mulhd(inputs: InstructionInput) -> InstructionResult {
632 let ra = inputs.try_get_ra()? as i64 as i128;
633 let rb = inputs.try_get_rb()? as i64 as i128;
634 let result = ((ra * rb) >> 64) as i64;
635 let result = result as u64;
636 Ok(InstructionOutput {
638 ..InstructionOutput::default()
642 create_instr_variants_cr!(mulhdu, mulhdu_, i64);
644 pub fn mulhdu(inputs: InstructionInput) -> InstructionResult {
645 let ra = inputs.try_get_ra()? as u128;
646 let rb = inputs.try_get_rb()? as u128;
647 let result = ((ra * rb) >> 64) as u64;
648 Ok(InstructionOutput {
650 ..InstructionOutput::default()
654 pub fn maddhd(inputs: InstructionInput) -> InstructionResult {
655 let ra = inputs.try_get_ra()? as i64 as i128;
656 let rb = inputs.try_get_rb()? as i64 as i128;
657 let rc = inputs.try_get_rc()? as i64 as i128;
658 let result = ((ra * rb + rc) >> 64) as u64;
659 Ok(InstructionOutput {
661 ..InstructionOutput::default()
665 pub fn maddhdu(inputs: InstructionInput) -> InstructionResult {
666 let ra = inputs.try_get_ra()? as u128;
667 let rb = inputs.try_get_rb()? as u128;
668 let rc = inputs.try_get_rc()? as u128;
669 let result = ((ra * rb + rc) >> 64) as u64;
670 Ok(InstructionOutput {
672 ..InstructionOutput::default()
676 pub fn maddld(inputs: InstructionInput) -> InstructionResult {
677 let ra = inputs.try_get_ra()? as i64;
678 let rb = inputs.try_get_rb()? as i64;
679 let rc = inputs.try_get_rc()? as i64;
680 let result = ra.wrapping_mul(rb).wrapping_add(rc) as u64;
681 Ok(InstructionOutput {
683 ..InstructionOutput::default()