dd8c0373eee3e19229abf7801b82696564a455da
[power-instruction-analyzer.git] / src / instr_models.rs
1 use crate::{
2 CarryFlags, ConditionRegister, InstructionInput, InstructionOutput, InstructionResult,
3 MissingInstructionInput, OverflowFlags,
4 };
5 use std::convert::TryFrom;
6
7 fn 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
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 {
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
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(
50 result as $iwidth,
51 inputs.try_get_overflow()?.so,
52 );
53 retval.cr0 = Some(cr0);
54 Ok(retval)
55 }
56 };
57 }
58
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 {
64 rt: Some(result),
65 ..InstructionOutput::default()
66 })
67 }
68
69 pub 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
79 create_instr_variants_ov_cr!(add, addo, add_, addo_, i64);
80
81 pub 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
94 create_instr_variants_cr!(addic, addic_, i64);
95
96 pub 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
109 create_instr_variants_ov_cr!(subf, subfo, subf_, subfo_, i64);
110
111 pub 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
124 pub 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
144 create_instr_variants_ov_cr!(addc, addco, addc_, addco_, i64);
145
146 pub 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
162 create_instr_variants_ov_cr!(subfc, subfco, subfc_, subfco_, i64);
163
164 pub 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
180 create_instr_variants_ov_cr!(adde, addeo, adde_, addeo_, i64);
181
182 pub 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
203 create_instr_variants_ov_cr!(subfe, subfeo, subfe_, subfeo_, i64);
204
205 pub 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
227 create_instr_variants_ov_cr!(addme, addmeo, addme_, addmeo_, i64);
228
229 pub 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
250 create_instr_variants_ov_cr!(subfme, subfmeo, subfme_, subfmeo_, i64);
251
252 pub 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
274 create_instr_variants_ov_cr!(addze, addzeo, addze_, addzeo_, i64);
275
276 pub 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
296 create_instr_variants_ov_cr!(subfze, subfzeo, subfze_, subfzeo_, i64);
297
298 pub 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
319 pub 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
342 create_instr_variants_ov_cr!(neg, nego, neg_, nego_, i64);
343
344 pub 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
356 create_instr_variants_ov_cr!(divde, divdeo, divde_, divdeo_, i64);
357
358 pub 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
386 create_instr_variants_ov_cr!(divdeu, divdeuo, divdeu_, divdeuo_, i64);
387
388 pub 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
416 create_instr_variants_ov_cr!(divd, divdo, divd_, divdo_, i64);
417
418 pub 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
440 create_instr_variants_ov_cr!(divdu, divduo, divdu_, divduo_, i64);
441
442 pub 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
465 create_instr_variants_ov_cr!(divwe, divweo, divwe_, divweo_, i64);
466
467 pub 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
496 create_instr_variants_ov_cr!(divweu, divweuo, divweu_, divweuo_, i64);
497
498 pub 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
527 create_instr_variants_ov_cr!(divw, divwo, divw_, divwo_, i64);
528
529 pub 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
552 create_instr_variants_ov_cr!(divwu, divwuo, divwu_, divwuo_, i64);
553
554 pub 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
576 pub 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
591 pub 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
606 pub 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
621 pub 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
636 pub 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
646 create_instr_variants_ov_cr!(mullw, mullwo, mullw_, mullwo_, i64);
647
648 pub 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
663 create_instr_variants_cr!(mulhw, mulhw_, i32);
664
665 pub 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
677 create_instr_variants_cr!(mulhwu, mulhwu_, i32);
678
679 pub 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
691 create_instr_variants_ov_cr!(mulld, mulldo, mulld_, mulldo_, i64);
692
693 pub 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
708 create_instr_variants_cr!(mulhd, mulhd_, i64);
709
710 pub 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
721 create_instr_variants_cr!(mulhdu, mulhdu_, i64);
722
723 pub 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
733 pub 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
744 pub 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
755 pub 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
766 pub 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
777 pub 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
788 pub 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
799 pub 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
810 pub 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
821 pub 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
832 pub 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
843 pub 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 }