add addis and addic[.]
[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 create_instr_variants_ov_cr!(addc, addco, addc_, addco_, i64);
125
126 pub fn addco(inputs: InstructionInput) -> InstructionResult {
127 let ra = inputs.try_get_ra()? as i64;
128 let rb = inputs.try_get_rb()? as i64;
129 let (result, ov) = ra.overflowing_add(rb);
130 let result = result as u64;
131 let ov32 = (ra as i32).overflowing_add(rb as i32).1;
132 let ca = (ra as u64).overflowing_add(rb as u64).1;
133 let ca32 = (ra as u32).overflowing_add(rb as u32).1;
134 Ok(InstructionOutput {
135 rt: Some(result),
136 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
137 carry: Some(CarryFlags { ca, ca32 }),
138 ..InstructionOutput::default()
139 })
140 }
141
142 create_instr_variants_ov_cr!(subfc, subfco, subfc_, subfco_, i64);
143
144 pub fn subfco(inputs: InstructionInput) -> InstructionResult {
145 let ra = inputs.try_get_ra()? as i64;
146 let rb = inputs.try_get_rb()? as i64;
147 let (result, ov) = rb.overflowing_sub(ra);
148 let result = result as u64;
149 let ov32 = (rb as i32).overflowing_sub(ra as i32).1;
150 let ca = !(rb as u64).overflowing_sub(ra as u64).1;
151 let ca32 = !(rb as u32).overflowing_sub(ra as u32).1;
152 Ok(InstructionOutput {
153 rt: Some(result),
154 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
155 carry: Some(CarryFlags { ca, ca32 }),
156 ..InstructionOutput::default()
157 })
158 }
159
160 create_instr_variants_ov_cr!(adde, addeo, adde_, addeo_, i64);
161
162 pub fn addeo(inputs: InstructionInput) -> InstructionResult {
163 let ra: u64 = inputs.try_get_ra()?;
164 let rb: u64 = inputs.try_get_rb()?;
165 let carry_in = inputs.try_get_carry()?.ca;
166 let result_i128 = ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
167 let result_u128 = ra as u128 + rb as u128 + carry_in as u128;
168 let result32_i128 = ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
169 let result32_u128 = ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
170 let result = result_u128 as u64;
171 let ov = i64::try_from(result_i128).is_err();
172 let ov32 = i32::try_from(result32_i128).is_err();
173 let ca = u64::try_from(result_u128).is_err();
174 let ca32 = u32::try_from(result32_u128).is_err();
175 Ok(InstructionOutput {
176 rt: Some(result),
177 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
178 carry: Some(CarryFlags { ca, ca32 }),
179 ..InstructionOutput::default()
180 })
181 }
182
183 create_instr_variants_ov_cr!(subfe, subfeo, subfe_, subfeo_, i64);
184
185 pub fn subfeo(inputs: InstructionInput) -> InstructionResult {
186 let ra: u64 = inputs.try_get_ra()?;
187 let rb: u64 = inputs.try_get_rb()?;
188 let carry_in = inputs.try_get_carry()?.ca;
189 let not_ra = !ra;
190 let result_i128 = not_ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
191 let result_u128 = not_ra as u128 + rb as u128 + carry_in as u128;
192 let result32_i128 = not_ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
193 let result32_u128 = not_ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
194 let result = result_u128 as u64;
195 let ov = i64::try_from(result_i128).is_err();
196 let ov32 = i32::try_from(result32_i128).is_err();
197 let ca = u64::try_from(result_u128).is_err();
198 let ca32 = u32::try_from(result32_u128).is_err();
199 Ok(InstructionOutput {
200 rt: Some(result),
201 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
202 carry: Some(CarryFlags { ca, ca32 }),
203 ..InstructionOutput::default()
204 })
205 }
206
207 create_instr_variants_ov_cr!(addme, addmeo, addme_, addmeo_, i64);
208
209 pub fn addmeo(inputs: InstructionInput) -> InstructionResult {
210 let ra: u64 = inputs.try_get_ra()?;
211 let rb: u64 = !0;
212 let carry_in = inputs.try_get_carry()?.ca;
213 let result_i128 = ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
214 let result_u128 = ra as u128 + rb as u128 + carry_in as u128;
215 let result32_i128 = ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
216 let result32_u128 = ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
217 let result = result_u128 as u64;
218 let ov = i64::try_from(result_i128).is_err();
219 let ov32 = i32::try_from(result32_i128).is_err();
220 let ca = u64::try_from(result_u128).is_err();
221 let ca32 = u32::try_from(result32_u128).is_err();
222 Ok(InstructionOutput {
223 rt: Some(result),
224 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
225 carry: Some(CarryFlags { ca, ca32 }),
226 ..InstructionOutput::default()
227 })
228 }
229
230 create_instr_variants_ov_cr!(subfme, subfmeo, subfme_, subfmeo_, i64);
231
232 pub fn subfmeo(inputs: InstructionInput) -> InstructionResult {
233 let ra: u64 = inputs.try_get_ra()?;
234 let rb: u64 = !0;
235 let carry_in = inputs.try_get_carry()?.ca;
236 let not_ra = !ra;
237 let result_i128 = not_ra as i64 as i128 + rb as i64 as i128 + carry_in as i128;
238 let result_u128 = not_ra as u128 + rb as u128 + carry_in as u128;
239 let result32_i128 = not_ra as i32 as i128 + rb as i32 as i128 + carry_in as i128;
240 let result32_u128 = not_ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
241 let result = result_u128 as u64;
242 let ov = i64::try_from(result_i128).is_err();
243 let ov32 = i32::try_from(result32_i128).is_err();
244 let ca = u64::try_from(result_u128).is_err();
245 let ca32 = u32::try_from(result32_u128).is_err();
246 Ok(InstructionOutput {
247 rt: Some(result),
248 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
249 carry: Some(CarryFlags { ca, ca32 }),
250 ..InstructionOutput::default()
251 })
252 }
253
254 create_instr_variants_ov_cr!(addze, addzeo, addze_, addzeo_, i64);
255
256 pub fn addzeo(inputs: InstructionInput) -> InstructionResult {
257 let ra: u64 = inputs.try_get_ra()?;
258 let carry_in = inputs.try_get_carry()?.ca;
259 let result_i128 = ra as i64 as i128 + carry_in as i128;
260 let result_u128 = ra as u128 + carry_in as u128;
261 let result32_i128 = ra as i32 as i128 + carry_in as i128;
262 let result32_u128 = ra as u32 as u128 + carry_in as u128;
263 let result = result_u128 as u64;
264 let ov = i64::try_from(result_i128).is_err();
265 let ov32 = i32::try_from(result32_i128).is_err();
266 let ca = u64::try_from(result_u128).is_err();
267 let ca32 = u32::try_from(result32_u128).is_err();
268 Ok(InstructionOutput {
269 rt: Some(result),
270 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
271 carry: Some(CarryFlags { ca, ca32 }),
272 ..InstructionOutput::default()
273 })
274 }
275
276 create_instr_variants_ov_cr!(subfze, subfzeo, subfze_, subfzeo_, i64);
277
278 pub fn subfzeo(inputs: InstructionInput) -> InstructionResult {
279 let ra: u64 = inputs.try_get_ra()?;
280 let carry_in = inputs.try_get_carry()?.ca;
281 let not_ra = !ra;
282 let result_i128 = not_ra as i64 as i128 + carry_in as i128;
283 let result_u128 = not_ra as u128 + carry_in as u128;
284 let result32_i128 = not_ra as i32 as i128 + carry_in as i128;
285 let result32_u128 = not_ra as u32 as u128 + carry_in as u128;
286 let result = result_u128 as u64;
287 let ov = i64::try_from(result_i128).is_err();
288 let ov32 = i32::try_from(result32_i128).is_err();
289 let ca = u64::try_from(result_u128).is_err();
290 let ca32 = u32::try_from(result32_u128).is_err();
291 Ok(InstructionOutput {
292 rt: Some(result),
293 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
294 carry: Some(CarryFlags { ca, ca32 }),
295 ..InstructionOutput::default()
296 })
297 }
298
299 pub fn addex(inputs: InstructionInput) -> InstructionResult {
300 let ra: u64 = inputs.try_get_ra()?;
301 let rb: u64 = inputs.try_get_rb()?;
302 let OverflowFlags {
303 ov: carry_in, so, ..
304 } = inputs.try_get_overflow()?;
305 let result_u128 = ra as u128 + rb as u128 + carry_in as u128;
306 let result32_u128 = ra as u32 as u128 + rb as u32 as u128 + carry_in as u128;
307 let result = result_u128 as u64;
308 let carry = u64::try_from(result_u128).is_err();
309 let carry32 = u32::try_from(result32_u128).is_err();
310 Ok(InstructionOutput {
311 rt: Some(result),
312 // doesn't change `so` on purpose
313 overflow: Some(OverflowFlags {
314 so,
315 ov: carry,
316 ov32: carry32,
317 }),
318 ..InstructionOutput::default()
319 })
320 }
321
322 create_instr_variants_ov_cr!(neg, nego, neg_, nego_, i64);
323
324 pub fn nego(inputs: InstructionInput) -> InstructionResult {
325 let ra = inputs.try_get_ra()? as i64;
326 let result = ra.wrapping_neg() as u64;
327 let ov = ra.checked_neg().is_none();
328 let ov32 = (ra as i32).checked_neg().is_none();
329 Ok(InstructionOutput {
330 rt: Some(result),
331 overflow: Some(propagate_so(OverflowFlags { so: ov, ov, ov32 }, inputs)?),
332 ..InstructionOutput::default()
333 })
334 }
335
336 create_instr_variants_ov_cr!(divde, divdeo, divde_, divdeo_, i64);
337
338 pub fn divdeo(inputs: InstructionInput) -> InstructionResult {
339 let dividend = i128::from(inputs.try_get_ra()? as i64) << 64;
340 let divisor = i128::from(inputs.try_get_rb()? as i64);
341 let overflow;
342 let result;
343 if divisor == 0 || (divisor == -1 && dividend == i128::min_value()) {
344 result = 0;
345 overflow = true;
346 } else {
347 let result128 = dividend / divisor;
348 if result128 as i64 as i128 != result128 {
349 result = 0;
350 overflow = true;
351 } else {
352 result = result128 as u64;
353 overflow = false;
354 }
355 }
356 Ok(InstructionOutput {
357 rt: Some(result),
358 overflow: Some(propagate_so(
359 OverflowFlags::from_overflow(overflow),
360 inputs,
361 )?),
362 ..InstructionOutput::default()
363 })
364 }
365
366 create_instr_variants_ov_cr!(divdeu, divdeuo, divdeu_, divdeuo_, i64);
367
368 pub fn divdeuo(inputs: InstructionInput) -> InstructionResult {
369 let dividend = u128::from(inputs.try_get_ra()?) << 64;
370 let divisor = u128::from(inputs.try_get_rb()?);
371 let overflow;
372 let result;
373 if divisor == 0 {
374 result = 0;
375 overflow = true;
376 } else {
377 let resultu128 = dividend / divisor;
378 if resultu128 > u128::from(u64::max_value()) {
379 result = 0;
380 overflow = true;
381 } else {
382 result = resultu128 as u64;
383 overflow = false;
384 }
385 }
386 Ok(InstructionOutput {
387 rt: Some(result),
388 overflow: Some(propagate_so(
389 OverflowFlags::from_overflow(overflow),
390 inputs,
391 )?),
392 ..InstructionOutput::default()
393 })
394 }
395
396 create_instr_variants_ov_cr!(divd, divdo, divd_, divdo_, i64);
397
398 pub fn divdo(inputs: InstructionInput) -> InstructionResult {
399 let dividend = inputs.try_get_ra()? as i64;
400 let divisor = inputs.try_get_rb()? as i64;
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 result = (dividend / divisor) as u64;
408 overflow = false;
409 }
410 Ok(InstructionOutput {
411 rt: Some(result),
412 overflow: Some(propagate_so(
413 OverflowFlags::from_overflow(overflow),
414 inputs,
415 )?),
416 ..InstructionOutput::default()
417 })
418 }
419
420 create_instr_variants_ov_cr!(divdu, divduo, divdu_, divduo_, i64);
421
422 pub fn divduo(inputs: InstructionInput) -> InstructionResult {
423 let dividend: u64 = inputs.try_get_ra()?;
424 let divisor: u64 = inputs.try_get_rb()?;
425 let overflow;
426 let result;
427 if divisor == 0 {
428 result = 0;
429 overflow = true;
430 } else {
431 result = dividend / divisor;
432 overflow = false;
433 }
434 Ok(InstructionOutput {
435 rt: Some(result),
436 overflow: Some(propagate_so(
437 OverflowFlags::from_overflow(overflow),
438 inputs,
439 )?),
440 ..InstructionOutput::default()
441 })
442 }
443
444 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
445 create_instr_variants_ov_cr!(divwe, divweo, divwe_, divweo_, i64);
446
447 pub fn divweo(inputs: InstructionInput) -> InstructionResult {
448 let dividend = i64::from(inputs.try_get_ra()? as i32) << 32;
449 let divisor = i64::from(inputs.try_get_rb()? as i32);
450 let overflow;
451 let result;
452 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
453 result = 0;
454 overflow = true;
455 } else {
456 let result64 = dividend / divisor;
457 if result64 as i32 as i64 != result64 {
458 result = 0;
459 overflow = true;
460 } else {
461 result = result64 as u32 as u64;
462 overflow = false;
463 }
464 }
465 Ok(InstructionOutput {
466 rt: Some(result),
467 overflow: Some(propagate_so(
468 OverflowFlags::from_overflow(overflow),
469 inputs,
470 )?),
471 ..InstructionOutput::default()
472 })
473 }
474
475 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
476 create_instr_variants_ov_cr!(divweu, divweuo, divweu_, divweuo_, i64);
477
478 pub fn divweuo(inputs: InstructionInput) -> InstructionResult {
479 let dividend = u64::from(inputs.try_get_ra()? as u32) << 32;
480 let divisor = u64::from(inputs.try_get_rb()? as u32);
481 let overflow;
482 let result;
483 if divisor == 0 {
484 result = 0;
485 overflow = true;
486 } else {
487 let resultu64 = dividend / divisor;
488 if resultu64 > u64::from(u32::max_value()) {
489 result = 0;
490 overflow = true;
491 } else {
492 result = resultu64 as u32 as u64;
493 overflow = false;
494 }
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!(divw, divwo, divw_, divwo_, i64);
508
509 pub fn divwo(inputs: InstructionInput) -> InstructionResult {
510 let dividend = inputs.try_get_ra()? as i32;
511 let divisor = inputs.try_get_rb()? as i32;
512 let overflow;
513 let result;
514 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
515 result = 0;
516 overflow = true;
517 } else {
518 result = (dividend / divisor) as u32 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 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
532 create_instr_variants_ov_cr!(divwu, divwuo, divwu_, divwuo_, i64);
533
534 pub fn divwuo(inputs: InstructionInput) -> InstructionResult {
535 let dividend = inputs.try_get_ra()? as u32;
536 let divisor = inputs.try_get_rb()? as u32;
537 let overflow;
538 let result;
539 if divisor == 0 {
540 result = 0;
541 overflow = true;
542 } else {
543 result = (dividend / divisor) as u64;
544 overflow = false;
545 }
546 Ok(InstructionOutput {
547 rt: Some(result),
548 overflow: Some(propagate_so(
549 OverflowFlags::from_overflow(overflow),
550 inputs,
551 )?),
552 ..InstructionOutput::default()
553 })
554 }
555
556 pub fn modsd(inputs: InstructionInput) -> InstructionResult {
557 let dividend = inputs.try_get_ra()? as i64;
558 let divisor = inputs.try_get_rb()? as i64;
559 let result;
560 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
561 result = 0;
562 } else {
563 result = (dividend % divisor) as u64;
564 }
565 Ok(InstructionOutput {
566 rt: Some(result),
567 ..InstructionOutput::default()
568 })
569 }
570
571 pub fn modud(inputs: InstructionInput) -> InstructionResult {
572 let dividend: u64 = inputs.try_get_ra()?;
573 let divisor: u64 = inputs.try_get_rb()?;
574 let result;
575 if divisor == 0 {
576 result = 0;
577 } else {
578 result = dividend % divisor;
579 }
580 Ok(InstructionOutput {
581 rt: Some(result),
582 ..InstructionOutput::default()
583 })
584 }
585
586 pub fn modsw(inputs: InstructionInput) -> InstructionResult {
587 let dividend = inputs.try_get_ra()? as i32;
588 let divisor = inputs.try_get_rb()? as i32;
589 let result;
590 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
591 result = 0;
592 } else {
593 result = (dividend % divisor) as u64;
594 }
595 Ok(InstructionOutput {
596 rt: Some(result),
597 ..InstructionOutput::default()
598 })
599 }
600
601 pub fn moduw(inputs: InstructionInput) -> InstructionResult {
602 let dividend = inputs.try_get_ra()? as u32;
603 let divisor = inputs.try_get_rb()? as u32;
604 let result;
605 if divisor == 0 {
606 result = 0;
607 } else {
608 result = (dividend % divisor) as u64;
609 }
610 Ok(InstructionOutput {
611 rt: Some(result),
612 ..InstructionOutput::default()
613 })
614 }
615
616 create_instr_variants_ov_cr!(mullw, mullwo, mullw_, mullwo_, i64);
617
618 pub fn mullwo(inputs: InstructionInput) -> InstructionResult {
619 let ra = inputs.try_get_ra()? as i32 as i64;
620 let rb = inputs.try_get_rb()? as i32 as i64;
621 let result = ra.wrapping_mul(rb) as u64;
622 let overflow = result as i32 as i64 != result as i64;
623 Ok(InstructionOutput {
624 rt: Some(result),
625 overflow: Some(propagate_so(
626 OverflowFlags::from_overflow(overflow),
627 inputs,
628 )?),
629 ..InstructionOutput::default()
630 })
631 }
632
633 create_instr_variants_cr!(mulhw, mulhw_, i32);
634
635 pub fn mulhw(inputs: InstructionInput) -> InstructionResult {
636 let ra = inputs.try_get_ra()? as i32 as i64;
637 let rb = inputs.try_get_rb()? as i32 as i64;
638 let result = (ra * rb) >> 32;
639 let mut result = result as u32 as u64;
640 result |= result << 32;
641 Ok(InstructionOutput {
642 rt: Some(result),
643 ..InstructionOutput::default()
644 })
645 }
646
647 create_instr_variants_cr!(mulhwu, mulhwu_, i32);
648
649 pub fn mulhwu(inputs: InstructionInput) -> InstructionResult {
650 let ra = inputs.try_get_ra()? as u32 as u64;
651 let rb = inputs.try_get_rb()? as u32 as u64;
652 let result = (ra * rb) >> 32;
653 let mut result = result as u32 as u64;
654 result |= result << 32;
655 Ok(InstructionOutput {
656 rt: Some(result),
657 ..InstructionOutput::default()
658 })
659 }
660
661 create_instr_variants_ov_cr!(mulld, mulldo, mulld_, mulldo_, i64);
662
663 pub fn mulldo(inputs: InstructionInput) -> InstructionResult {
664 let ra = inputs.try_get_ra()? as i64;
665 let rb = inputs.try_get_rb()? as i64;
666 let result = ra.wrapping_mul(rb) as u64;
667 let overflow = ra.checked_mul(rb).is_none();
668 Ok(InstructionOutput {
669 rt: Some(result),
670 overflow: Some(propagate_so(
671 OverflowFlags::from_overflow(overflow),
672 inputs,
673 )?),
674 ..InstructionOutput::default()
675 })
676 }
677
678 create_instr_variants_cr!(mulhd, mulhd_, i64);
679
680 pub fn mulhd(inputs: InstructionInput) -> InstructionResult {
681 let ra = inputs.try_get_ra()? as i64 as i128;
682 let rb = inputs.try_get_rb()? as i64 as i128;
683 let result = ((ra * rb) >> 64) as i64;
684 let result = result as u64;
685 Ok(InstructionOutput {
686 rt: Some(result),
687 ..InstructionOutput::default()
688 })
689 }
690
691 create_instr_variants_cr!(mulhdu, mulhdu_, i64);
692
693 pub fn mulhdu(inputs: InstructionInput) -> InstructionResult {
694 let ra = inputs.try_get_ra()? as u128;
695 let rb = inputs.try_get_rb()? as u128;
696 let result = ((ra * rb) >> 64) as u64;
697 Ok(InstructionOutput {
698 rt: Some(result),
699 ..InstructionOutput::default()
700 })
701 }
702
703 pub fn maddhd(inputs: InstructionInput) -> InstructionResult {
704 let ra = inputs.try_get_ra()? as i64 as i128;
705 let rb = inputs.try_get_rb()? as i64 as i128;
706 let rc = inputs.try_get_rc()? as i64 as i128;
707 let result = ((ra * rb + rc) >> 64) as u64;
708 Ok(InstructionOutput {
709 rt: Some(result),
710 ..InstructionOutput::default()
711 })
712 }
713
714 pub fn maddhdu(inputs: InstructionInput) -> InstructionResult {
715 let ra = inputs.try_get_ra()? as u128;
716 let rb = inputs.try_get_rb()? as u128;
717 let rc = inputs.try_get_rc()? as u128;
718 let result = ((ra * rb + rc) >> 64) as u64;
719 Ok(InstructionOutput {
720 rt: Some(result),
721 ..InstructionOutput::default()
722 })
723 }
724
725 pub fn maddld(inputs: InstructionInput) -> InstructionResult {
726 let ra = inputs.try_get_ra()? as i64;
727 let rb = inputs.try_get_rb()? as i64;
728 let rc = inputs.try_get_rc()? as i64;
729 let result = ra.wrapping_mul(rb).wrapping_add(rc) as u64;
730 Ok(InstructionOutput {
731 rt: Some(result),
732 ..InstructionOutput::default()
733 })
734 }