fix addex
[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 create_instr_variants_ov_cr!(add, addo, add_, addo_, i64);
60
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 {
68 rt: Some(result),
69 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
70 ..InstructionOutput::default()
71 })
72 }
73
74 create_instr_variants_ov_cr!(subf, subfo, subf_, subfo_, i64);
75
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 {
83 rt: Some(result),
84 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
85 ..InstructionOutput::default()
86 })
87 }
88
89 create_instr_variants_ov_cr!(addc, addco, addc_, addco_, i64);
90
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 {
100 rt: Some(result),
101 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
102 carry: Some(CarryFlags { ca, ca32 }),
103 ..InstructionOutput::default()
104 })
105 }
106
107 create_instr_variants_ov_cr!(subfc, subfco, subfc_, subfco_, i64);
108
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 {
118 rt: Some(result),
119 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
120 carry: Some(CarryFlags { ca, ca32 }),
121 ..InstructionOutput::default()
122 })
123 }
124
125 create_instr_variants_ov_cr!(adde, addeo, adde_, addeo_, i64);
126
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 {
141 rt: Some(result),
142 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
143 carry: Some(CarryFlags { ca, ca32 }),
144 ..InstructionOutput::default()
145 })
146 }
147
148 create_instr_variants_ov_cr!(subfe, subfeo, subfe_, subfeo_, i64);
149
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;
154 let not_ra = !ra;
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 {
165 rt: Some(result),
166 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
167 carry: Some(CarryFlags { ca, ca32 }),
168 ..InstructionOutput::default()
169 })
170 }
171
172 create_instr_variants_ov_cr!(addme, addmeo, addme_, addmeo_, i64);
173
174 pub fn addmeo(inputs: InstructionInput) -> InstructionResult {
175 let ra: u64 = inputs.try_get_ra()?;
176 let rb: u64 = !0;
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 {
188 rt: Some(result),
189 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
190 carry: Some(CarryFlags { ca, ca32 }),
191 ..InstructionOutput::default()
192 })
193 }
194
195 create_instr_variants_ov_cr!(subfme, subfmeo, subfme_, subfmeo_, i64);
196
197 pub fn subfmeo(inputs: InstructionInput) -> InstructionResult {
198 let ra: u64 = inputs.try_get_ra()?;
199 let rb: u64 = !0;
200 let carry_in = inputs.try_get_carry()?.ca;
201 let not_ra = !ra;
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 {
212 rt: Some(result),
213 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
214 carry: Some(CarryFlags { ca, ca32 }),
215 ..InstructionOutput::default()
216 })
217 }
218
219 create_instr_variants_ov_cr!(addze, addzeo, addze_, addzeo_, i64);
220
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 {
234 rt: Some(result),
235 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
236 carry: Some(CarryFlags { ca, ca32 }),
237 ..InstructionOutput::default()
238 })
239 }
240
241 create_instr_variants_ov_cr!(subfze, subfzeo, subfze_, subfzeo_, i64);
242
243 pub fn subfzeo(inputs: InstructionInput) -> InstructionResult {
244 let ra: u64 = inputs.try_get_ra()?;
245 let carry_in = inputs.try_get_carry()?.ca;
246 let not_ra = !ra;
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 {
257 rt: Some(result),
258 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
259 carry: Some(CarryFlags { ca, ca32 }),
260 ..InstructionOutput::default()
261 })
262 }
263
264 pub fn addex(inputs: InstructionInput) -> InstructionResult {
265 let ra: u64 = inputs.try_get_ra()?;
266 let rb: u64 = inputs.try_get_ra()?;
267 let OverflowFlags {
268 ov: carry_in, so, ..
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 {
276 rt: Some(result),
277 // doesn't change `so` on purpose
278 overflow: Some(OverflowFlags {
279 so,
280 ov: carry,
281 ov32: carry32,
282 }),
283 ..InstructionOutput::default()
284 })
285 }
286
287 create_instr_variants_ov_cr!(divde, divdeo, divde_, divdeo_, i64);
288
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);
292 let overflow;
293 let result;
294 if divisor == 0 || (divisor == -1 && dividend == i128::min_value()) {
295 result = 0;
296 overflow = true;
297 } else {
298 let result128 = dividend / divisor;
299 if result128 as i64 as i128 != result128 {
300 result = 0;
301 overflow = true;
302 } else {
303 result = result128 as u64;
304 overflow = false;
305 }
306 }
307 Ok(InstructionOutput {
308 rt: Some(result),
309 overflow: Some(propagate_so(
310 OverflowFlags::from_overflow(overflow),
311 inputs,
312 )?),
313 ..InstructionOutput::default()
314 })
315 }
316
317 create_instr_variants_ov_cr!(divdeu, divdeuo, divdeu_, divdeuo_, i64);
318
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()?);
322 let overflow;
323 let result;
324 if divisor == 0 {
325 result = 0;
326 overflow = true;
327 } else {
328 let resultu128 = dividend / divisor;
329 if resultu128 > u128::from(u64::max_value()) {
330 result = 0;
331 overflow = true;
332 } else {
333 result = resultu128 as u64;
334 overflow = false;
335 }
336 }
337 Ok(InstructionOutput {
338 rt: Some(result),
339 overflow: Some(propagate_so(
340 OverflowFlags::from_overflow(overflow),
341 inputs,
342 )?),
343 ..InstructionOutput::default()
344 })
345 }
346
347 create_instr_variants_ov_cr!(divd, divdo, divd_, divdo_, i64);
348
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;
352 let overflow;
353 let result;
354 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
355 result = 0;
356 overflow = true;
357 } else {
358 result = (dividend / divisor) as u64;
359 overflow = false;
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!(divdu, divduo, divdu_, divduo_, i64);
372
373 pub fn divduo(inputs: InstructionInput) -> InstructionResult {
374 let dividend: u64 = inputs.try_get_ra()?;
375 let divisor: u64 = inputs.try_get_rb()?;
376 let overflow;
377 let result;
378 if divisor == 0 {
379 result = 0;
380 overflow = true;
381 } else {
382 result = dividend / divisor;
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 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
396 create_instr_variants_ov_cr!(divwe, divweo, divwe_, divweo_, i64);
397
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);
401 let overflow;
402 let result;
403 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
404 result = 0;
405 overflow = true;
406 } else {
407 let result64 = dividend / divisor;
408 if result64 as i32 as i64 != result64 {
409 result = 0;
410 overflow = true;
411 } else {
412 result = result64 as u32 as u64;
413 overflow = false;
414 }
415 }
416 Ok(InstructionOutput {
417 rt: Some(result),
418 overflow: Some(propagate_so(
419 OverflowFlags::from_overflow(overflow),
420 inputs,
421 )?),
422 ..InstructionOutput::default()
423 })
424 }
425
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);
428
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);
432 let overflow;
433 let result;
434 if divisor == 0 {
435 result = 0;
436 overflow = true;
437 } else {
438 let resultu64 = dividend / divisor;
439 if resultu64 > u64::from(u32::max_value()) {
440 result = 0;
441 overflow = true;
442 } else {
443 result = resultu64 as u32 as u64;
444 overflow = false;
445 }
446 }
447 Ok(InstructionOutput {
448 rt: Some(result),
449 overflow: Some(propagate_so(
450 OverflowFlags::from_overflow(overflow),
451 inputs,
452 )?),
453 ..InstructionOutput::default()
454 })
455 }
456
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);
459
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;
463 let overflow;
464 let result;
465 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
466 result = 0;
467 overflow = true;
468 } else {
469 result = (dividend / divisor) as u32 as u64;
470 overflow = false;
471 }
472 Ok(InstructionOutput {
473 rt: Some(result),
474 overflow: Some(propagate_so(
475 OverflowFlags::from_overflow(overflow),
476 inputs,
477 )?),
478 ..InstructionOutput::default()
479 })
480 }
481
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);
484
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;
488 let overflow;
489 let result;
490 if divisor == 0 {
491 result = 0;
492 overflow = true;
493 } else {
494 result = (dividend / divisor) as u64;
495 overflow = false;
496 }
497 Ok(InstructionOutput {
498 rt: Some(result),
499 overflow: Some(propagate_so(
500 OverflowFlags::from_overflow(overflow),
501 inputs,
502 )?),
503 ..InstructionOutput::default()
504 })
505 }
506
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;
510 let result;
511 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
512 result = 0;
513 } else {
514 result = (dividend % divisor) as u64;
515 }
516 Ok(InstructionOutput {
517 rt: Some(result),
518 ..InstructionOutput::default()
519 })
520 }
521
522 pub fn modud(inputs: InstructionInput) -> InstructionResult {
523 let dividend: u64 = inputs.try_get_ra()?;
524 let divisor: u64 = inputs.try_get_rb()?;
525 let result;
526 if divisor == 0 {
527 result = 0;
528 } else {
529 result = dividend % divisor;
530 }
531 Ok(InstructionOutput {
532 rt: Some(result),
533 ..InstructionOutput::default()
534 })
535 }
536
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;
540 let result;
541 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
542 result = 0;
543 } else {
544 result = (dividend % divisor) as u64;
545 }
546 Ok(InstructionOutput {
547 rt: Some(result),
548 ..InstructionOutput::default()
549 })
550 }
551
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;
555 let result;
556 if divisor == 0 {
557 result = 0;
558 } else {
559 result = (dividend % divisor) as u64;
560 }
561 Ok(InstructionOutput {
562 rt: Some(result),
563 ..InstructionOutput::default()
564 })
565 }
566
567 create_instr_variants_ov_cr!(mullw, mullwo, mullw_, mullwo_, i64);
568
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 {
575 rt: Some(result),
576 overflow: Some(propagate_so(
577 OverflowFlags::from_overflow(overflow),
578 inputs,
579 )?),
580 ..InstructionOutput::default()
581 })
582 }
583
584 create_instr_variants_cr!(mulhw, mulhw_, i32);
585
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 {
593 rt: Some(result),
594 ..InstructionOutput::default()
595 })
596 }
597
598 create_instr_variants_cr!(mulhwu, mulhwu_, i32);
599
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 {
607 rt: Some(result),
608 ..InstructionOutput::default()
609 })
610 }
611
612 create_instr_variants_ov_cr!(mulld, mulldo, mulld_, mulldo_, i64);
613
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 {
620 rt: Some(result),
621 overflow: Some(propagate_so(
622 OverflowFlags::from_overflow(overflow),
623 inputs,
624 )?),
625 ..InstructionOutput::default()
626 })
627 }
628
629 create_instr_variants_cr!(mulhd, mulhd_, i64);
630
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 {
637 rt: Some(result),
638 ..InstructionOutput::default()
639 })
640 }
641
642 create_instr_variants_cr!(mulhdu, mulhdu_, i64);
643
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 {
649 rt: Some(result),
650 ..InstructionOutput::default()
651 })
652 }
653
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 {
660 rt: Some(result),
661 ..InstructionOutput::default()
662 })
663 }
664
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 {
671 rt: Some(result),
672 ..InstructionOutput::default()
673 })
674 }
675
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 {
682 rt: Some(result),
683 ..InstructionOutput::default()
684 })
685 }