working on adding support for immediate operands
[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 create_instr_variants_ov_cr!(add, addo, add_, addo_, i64);
70
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 {
78 rt: Some(result),
79 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
80 ..InstructionOutput::default()
81 })
82 }
83
84 create_instr_variants_ov_cr!(subf, subfo, subf_, subfo_, i64);
85
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 {
93 rt: Some(result),
94 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
95 ..InstructionOutput::default()
96 })
97 }
98
99 create_instr_variants_ov_cr!(addc, addco, addc_, addco_, i64);
100
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 {
110 rt: Some(result),
111 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
112 carry: Some(CarryFlags { ca, ca32 }),
113 ..InstructionOutput::default()
114 })
115 }
116
117 create_instr_variants_ov_cr!(subfc, subfco, subfc_, subfco_, i64);
118
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 {
128 rt: Some(result),
129 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
130 carry: Some(CarryFlags { ca, ca32 }),
131 ..InstructionOutput::default()
132 })
133 }
134
135 create_instr_variants_ov_cr!(adde, addeo, adde_, addeo_, i64);
136
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 {
151 rt: Some(result),
152 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
153 carry: Some(CarryFlags { ca, ca32 }),
154 ..InstructionOutput::default()
155 })
156 }
157
158 create_instr_variants_ov_cr!(subfe, subfeo, subfe_, subfeo_, i64);
159
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;
164 let not_ra = !ra;
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 {
175 rt: Some(result),
176 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
177 carry: Some(CarryFlags { ca, ca32 }),
178 ..InstructionOutput::default()
179 })
180 }
181
182 create_instr_variants_ov_cr!(addme, addmeo, addme_, addmeo_, i64);
183
184 pub fn addmeo(inputs: InstructionInput) -> InstructionResult {
185 let ra: u64 = inputs.try_get_ra()?;
186 let rb: u64 = !0;
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 {
198 rt: Some(result),
199 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
200 carry: Some(CarryFlags { ca, ca32 }),
201 ..InstructionOutput::default()
202 })
203 }
204
205 create_instr_variants_ov_cr!(subfme, subfmeo, subfme_, subfmeo_, i64);
206
207 pub fn subfmeo(inputs: InstructionInput) -> InstructionResult {
208 let ra: u64 = inputs.try_get_ra()?;
209 let rb: u64 = !0;
210 let carry_in = inputs.try_get_carry()?.ca;
211 let not_ra = !ra;
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 {
222 rt: Some(result),
223 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
224 carry: Some(CarryFlags { ca, ca32 }),
225 ..InstructionOutput::default()
226 })
227 }
228
229 create_instr_variants_ov_cr!(addze, addzeo, addze_, addzeo_, i64);
230
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 {
244 rt: Some(result),
245 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
246 carry: Some(CarryFlags { ca, ca32 }),
247 ..InstructionOutput::default()
248 })
249 }
250
251 create_instr_variants_ov_cr!(subfze, subfzeo, subfze_, subfzeo_, i64);
252
253 pub fn subfzeo(inputs: InstructionInput) -> InstructionResult {
254 let ra: u64 = inputs.try_get_ra()?;
255 let carry_in = inputs.try_get_carry()?.ca;
256 let not_ra = !ra;
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 {
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 pub fn addex(inputs: InstructionInput) -> InstructionResult {
275 let ra: u64 = inputs.try_get_ra()?;
276 let rb: u64 = inputs.try_get_rb()?;
277 let OverflowFlags {
278 ov: carry_in, so, ..
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 {
286 rt: Some(result),
287 // doesn't change `so` on purpose
288 overflow: Some(OverflowFlags {
289 so,
290 ov: carry,
291 ov32: carry32,
292 }),
293 ..InstructionOutput::default()
294 })
295 }
296
297 create_instr_variants_ov_cr!(neg, nego, neg_, nego_, i64);
298
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 {
305 rt: Some(result),
306 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
307 ..InstructionOutput::default()
308 })
309 }
310
311 create_instr_variants_ov_cr!(divde, divdeo, divde_, divdeo_, i64);
312
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);
316 let overflow;
317 let result;
318 if divisor == 0 || (divisor == -1 && dividend == i128::min_value()) {
319 result = 0;
320 overflow = true;
321 } else {
322 let result128 = dividend / divisor;
323 if result128 as i64 as i128 != result128 {
324 result = 0;
325 overflow = true;
326 } else {
327 result = result128 as u64;
328 overflow = false;
329 }
330 }
331 Ok(InstructionOutput {
332 rt: Some(result),
333 overflow: Some(propagate_so(
334 OverflowFlags::from_overflow(overflow),
335 inputs,
336 )?),
337 ..InstructionOutput::default()
338 })
339 }
340
341 create_instr_variants_ov_cr!(divdeu, divdeuo, divdeu_, divdeuo_, i64);
342
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()?);
346 let overflow;
347 let result;
348 if divisor == 0 {
349 result = 0;
350 overflow = true;
351 } else {
352 let resultu128 = dividend / divisor;
353 if resultu128 > u128::from(u64::max_value()) {
354 result = 0;
355 overflow = true;
356 } else {
357 result = resultu128 as u64;
358 overflow = false;
359 }
360 }
361 Ok(InstructionOutput {
362 rt: Some(result),
363 overflow: Some(propagate_so(
364 OverflowFlags::from_overflow(overflow),
365 inputs,
366 )?),
367 ..InstructionOutput::default()
368 })
369 }
370
371 create_instr_variants_ov_cr!(divd, divdo, divd_, divdo_, i64);
372
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;
376 let overflow;
377 let result;
378 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
379 result = 0;
380 overflow = true;
381 } else {
382 result = (dividend / divisor) as u64;
383 overflow = false;
384 }
385 Ok(InstructionOutput {
386 rt: Some(result),
387 overflow: Some(propagate_so(
388 OverflowFlags::from_overflow(overflow),
389 inputs,
390 )?),
391 ..InstructionOutput::default()
392 })
393 }
394
395 create_instr_variants_ov_cr!(divdu, divduo, divdu_, divduo_, i64);
396
397 pub fn divduo(inputs: InstructionInput) -> InstructionResult {
398 let dividend: u64 = inputs.try_get_ra()?;
399 let divisor: u64 = inputs.try_get_rb()?;
400 let overflow;
401 let result;
402 if divisor == 0 {
403 result = 0;
404 overflow = true;
405 } else {
406 result = dividend / divisor;
407 overflow = false;
408 }
409 Ok(InstructionOutput {
410 rt: Some(result),
411 overflow: Some(propagate_so(
412 OverflowFlags::from_overflow(overflow),
413 inputs,
414 )?),
415 ..InstructionOutput::default()
416 })
417 }
418
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);
421
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);
425 let overflow;
426 let result;
427 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
428 result = 0;
429 overflow = true;
430 } else {
431 let result64 = dividend / divisor;
432 if result64 as i32 as i64 != result64 {
433 result = 0;
434 overflow = true;
435 } else {
436 result = result64 as u32 as u64;
437 overflow = false;
438 }
439 }
440 Ok(InstructionOutput {
441 rt: Some(result),
442 overflow: Some(propagate_so(
443 OverflowFlags::from_overflow(overflow),
444 inputs,
445 )?),
446 ..InstructionOutput::default()
447 })
448 }
449
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);
452
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);
456 let overflow;
457 let result;
458 if divisor == 0 {
459 result = 0;
460 overflow = true;
461 } else {
462 let resultu64 = dividend / divisor;
463 if resultu64 > u64::from(u32::max_value()) {
464 result = 0;
465 overflow = true;
466 } else {
467 result = resultu64 as u32 as u64;
468 overflow = false;
469 }
470 }
471 Ok(InstructionOutput {
472 rt: Some(result),
473 overflow: Some(propagate_so(
474 OverflowFlags::from_overflow(overflow),
475 inputs,
476 )?),
477 ..InstructionOutput::default()
478 })
479 }
480
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);
483
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;
487 let overflow;
488 let result;
489 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
490 result = 0;
491 overflow = true;
492 } else {
493 result = (dividend / divisor) as u32 as u64;
494 overflow = false;
495 }
496 Ok(InstructionOutput {
497 rt: Some(result),
498 overflow: Some(propagate_so(
499 OverflowFlags::from_overflow(overflow),
500 inputs,
501 )?),
502 ..InstructionOutput::default()
503 })
504 }
505
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);
508
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;
512 let overflow;
513 let result;
514 if divisor == 0 {
515 result = 0;
516 overflow = true;
517 } else {
518 result = (dividend / divisor) as u64;
519 overflow = false;
520 }
521 Ok(InstructionOutput {
522 rt: Some(result),
523 overflow: Some(propagate_so(
524 OverflowFlags::from_overflow(overflow),
525 inputs,
526 )?),
527 ..InstructionOutput::default()
528 })
529 }
530
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;
534 let result;
535 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
536 result = 0;
537 } else {
538 result = (dividend % divisor) as u64;
539 }
540 Ok(InstructionOutput {
541 rt: Some(result),
542 ..InstructionOutput::default()
543 })
544 }
545
546 pub fn modud(inputs: InstructionInput) -> InstructionResult {
547 let dividend: u64 = inputs.try_get_ra()?;
548 let divisor: u64 = inputs.try_get_rb()?;
549 let result;
550 if divisor == 0 {
551 result = 0;
552 } else {
553 result = dividend % divisor;
554 }
555 Ok(InstructionOutput {
556 rt: Some(result),
557 ..InstructionOutput::default()
558 })
559 }
560
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;
564 let result;
565 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
566 result = 0;
567 } else {
568 result = (dividend % divisor) as u64;
569 }
570 Ok(InstructionOutput {
571 rt: Some(result),
572 ..InstructionOutput::default()
573 })
574 }
575
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;
579 let result;
580 if divisor == 0 {
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 create_instr_variants_ov_cr!(mullw, mullwo, mullw_, mullwo_, i64);
592
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 {
599 rt: Some(result),
600 overflow: Some(propagate_so(
601 OverflowFlags::from_overflow(overflow),
602 inputs,
603 )?),
604 ..InstructionOutput::default()
605 })
606 }
607
608 create_instr_variants_cr!(mulhw, mulhw_, i32);
609
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 {
617 rt: Some(result),
618 ..InstructionOutput::default()
619 })
620 }
621
622 create_instr_variants_cr!(mulhwu, mulhwu_, i32);
623
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 {
631 rt: Some(result),
632 ..InstructionOutput::default()
633 })
634 }
635
636 create_instr_variants_ov_cr!(mulld, mulldo, mulld_, mulldo_, i64);
637
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 {
644 rt: Some(result),
645 overflow: Some(propagate_so(
646 OverflowFlags::from_overflow(overflow),
647 inputs,
648 )?),
649 ..InstructionOutput::default()
650 })
651 }
652
653 create_instr_variants_cr!(mulhd, mulhd_, i64);
654
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 {
661 rt: Some(result),
662 ..InstructionOutput::default()
663 })
664 }
665
666 create_instr_variants_cr!(mulhdu, mulhdu_, i64);
667
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 {
673 rt: Some(result),
674 ..InstructionOutput::default()
675 })
676 }
677
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 {
684 rt: Some(result),
685 ..InstructionOutput::default()
686 })
687 }
688
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 {
695 rt: Some(result),
696 ..InstructionOutput::default()
697 })
698 }
699
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 {
706 rt: Some(result),
707 ..InstructionOutput::default()
708 })
709 }