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