1 use crate::{ConditionRegister, InstructionInput, InstructionResult, OverflowFlags};
3 macro_rules! create_instr_variants_ov_cr {
4 ($fn:ident, $fno:ident, $fn_:ident, $fno_:ident, $iwidth:ident) => {
5 pub fn $fn(inputs: InstructionInput) -> InstructionResult {
11 pub fn $fn_(inputs: InstructionInput) -> InstructionResult {
12 let mut retval = $fno_(inputs);
13 let mut cr0 = retval.cr0.as_mut().expect("expected cr0 to be set");
15 retval.overflow = None;
18 pub fn $fno_(inputs: InstructionInput) -> InstructionResult {
19 let mut retval = $fno(inputs);
20 let result = retval.rt.expect("expected rt to be set");
21 let so = retval.overflow.expect("expected overflow to be set").so;
22 let cr0 = ConditionRegister::from_signed_int(result as $iwidth, so);
23 retval.cr0 = Some(cr0);
29 macro_rules! create_instr_variants_cr {
30 ($fn:ident, $fn_:ident, $iwidth:ident) => {
31 pub fn $fn_(inputs: InstructionInput) -> InstructionResult {
32 let mut retval = $fn(inputs);
33 let result = retval.rt.expect("expected rt to be set");
34 let cr0 = ConditionRegister::from_signed_int(result as $iwidth, false);
35 retval.cr0 = Some(cr0);
41 create_instr_variants_ov_cr!(add, addo, add_, addo_, i64);
43 pub fn addo(inputs: InstructionInput) -> InstructionResult {
44 let ra = inputs.ra as i64;
45 let rb = inputs.rb as i64;
46 let (result, ov) = ra.overflowing_add(rb);
47 let result = result as u64;
48 let ov32 = (ra as i32).overflowing_add(rb as i32).1;
51 overflow: Some(OverflowFlags { so: ov, ov, ov32 }),
52 ..InstructionResult::default()
56 create_instr_variants_ov_cr!(subf, subfo, subf_, subfo_, i64);
58 pub fn subfo(inputs: InstructionInput) -> InstructionResult {
59 let ra = inputs.ra as i64;
60 let rb = inputs.rb as i64;
61 let (result, ov) = rb.overflowing_sub(ra);
62 let result = result as u64;
63 let ov32 = (rb as i32).overflowing_sub(ra as i32).1;
66 overflow: Some(OverflowFlags { so: ov, ov, ov32 }),
67 ..InstructionResult::default()
71 create_instr_variants_ov_cr!(divde, divdeo, divde_, divdeo_, i64);
73 pub fn divdeo(inputs: InstructionInput) -> InstructionResult {
74 let dividend = i128::from(inputs.ra as i64) << 64;
75 let divisor = i128::from(inputs.rb as i64);
78 if divisor == 0 || (divisor == -1 && dividend == i128::min_value()) {
82 let result128 = dividend / divisor;
83 if result128 as i64 as i128 != result128 {
87 result = result128 as u64;
93 overflow: Some(OverflowFlags::from_overflow(overflow)),
94 ..InstructionResult::default()
98 create_instr_variants_ov_cr!(divdeu, divdeuo, divdeu_, divdeuo_, i64);
100 pub fn divdeuo(inputs: InstructionInput) -> InstructionResult {
101 let dividend = u128::from(inputs.ra) << 64;
102 let divisor = u128::from(inputs.rb);
109 let resultu128 = dividend / divisor;
110 if resultu128 > u128::from(u64::max_value()) {
114 result = resultu128 as u64;
120 overflow: Some(OverflowFlags::from_overflow(overflow)),
121 ..InstructionResult::default()
125 create_instr_variants_ov_cr!(divd, divdo, divd_, divdo_, i64);
127 pub fn divdo(inputs: InstructionInput) -> InstructionResult {
128 let dividend = inputs.ra as i64;
129 let divisor = inputs.rb as i64;
132 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
136 result = (dividend / divisor) as u64;
141 overflow: Some(OverflowFlags::from_overflow(overflow)),
142 ..InstructionResult::default()
146 create_instr_variants_ov_cr!(divdu, divduo, divdu_, divduo_, i64);
148 pub fn divduo(inputs: InstructionInput) -> InstructionResult {
149 let dividend: u64 = inputs.ra;
150 let divisor: u64 = inputs.rb;
157 result = dividend / divisor;
162 overflow: Some(OverflowFlags::from_overflow(overflow)),
163 ..InstructionResult::default()
167 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
168 create_instr_variants_ov_cr!(divwe, divweo, divwe_, divweo_, i64);
170 pub fn divweo(inputs: InstructionInput) -> InstructionResult {
171 let dividend = i64::from(inputs.ra as i32) << 32;
172 let divisor = i64::from(inputs.rb as i32);
175 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
179 let result64 = dividend / divisor;
180 if result64 as i32 as i64 != result64 {
184 result = result64 as u32 as u64;
190 overflow: Some(OverflowFlags::from_overflow(overflow)),
191 ..InstructionResult::default()
195 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
196 create_instr_variants_ov_cr!(divweu, divweuo, divweu_, divweuo_, i64);
198 pub fn divweuo(inputs: InstructionInput) -> InstructionResult {
199 let dividend = u64::from(inputs.ra as u32) << 32;
200 let divisor = u64::from(inputs.rb as u32);
207 let resultu64 = dividend / divisor;
208 if resultu64 > u64::from(u32::max_value()) {
212 result = resultu64 as u32 as u64;
218 overflow: Some(OverflowFlags::from_overflow(overflow)),
219 ..InstructionResult::default()
223 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
224 create_instr_variants_ov_cr!(divw, divwo, divw_, divwo_, i64);
226 pub fn divwo(inputs: InstructionInput) -> InstructionResult {
227 let dividend = inputs.ra as i32;
228 let divisor = inputs.rb as i32;
231 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
235 result = (dividend / divisor) as u32 as u64;
240 overflow: Some(OverflowFlags::from_overflow(overflow)),
241 ..InstructionResult::default()
245 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
246 create_instr_variants_ov_cr!(divwu, divwuo, divwu_, divwuo_, i64);
248 pub fn divwuo(inputs: InstructionInput) -> InstructionResult {
249 let dividend = inputs.ra as u32;
250 let divisor = inputs.rb as u32;
257 result = (dividend / divisor) as u64;
262 overflow: Some(OverflowFlags::from_overflow(overflow)),
263 ..InstructionResult::default()
267 pub fn modsd(inputs: InstructionInput) -> InstructionResult {
268 let dividend = inputs.ra as i64;
269 let divisor = inputs.rb as i64;
271 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
274 result = (dividend % divisor) as u64;
278 ..InstructionResult::default()
282 pub fn modud(inputs: InstructionInput) -> InstructionResult {
283 let dividend: u64 = inputs.ra;
284 let divisor: u64 = inputs.rb;
289 result = dividend % divisor;
293 ..InstructionResult::default()
297 pub fn modsw(inputs: InstructionInput) -> InstructionResult {
298 let dividend = inputs.ra as i32;
299 let divisor = inputs.rb as i32;
301 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
304 result = (dividend % divisor) as u64;
308 ..InstructionResult::default()
312 pub fn moduw(inputs: InstructionInput) -> InstructionResult {
313 let dividend = inputs.ra as u32;
314 let divisor = inputs.rb as u32;
319 result = (dividend % divisor) as u64;
323 ..InstructionResult::default()
327 create_instr_variants_ov_cr!(mullw, mullwo, mullw_, mullwo_, i64);
329 pub fn mullwo(inputs: InstructionInput) -> InstructionResult {
330 let ra = inputs.ra as i32 as i64;
331 let rb = inputs.rb as i32 as i64;
332 let result = ra.wrapping_mul(rb) as u64;
333 let overflow = result as i32 as i64 != result as i64;
336 overflow: Some(OverflowFlags::from_overflow(overflow)),
337 ..InstructionResult::default()
341 create_instr_variants_cr!(mulhw, mulhw_, i32);
343 pub fn mulhw(inputs: InstructionInput) -> InstructionResult {
344 let ra = inputs.ra as i32 as i64;
345 let rb = inputs.rb as i32 as i64;
346 let result = (ra * rb) >> 32;
347 let mut result = result as u32 as u64;
348 result |= result << 32;
351 ..InstructionResult::default()
355 create_instr_variants_cr!(mulhwu, mulhwu_, i32);
357 pub fn mulhwu(inputs: InstructionInput) -> InstructionResult {
358 let ra = inputs.ra as u32 as u64;
359 let rb = inputs.rb as u32 as u64;
360 let result = (ra * rb) >> 32;
361 let mut result = result as u32 as u64;
362 result |= result << 32;
365 ..InstructionResult::default()
369 create_instr_variants_ov_cr!(mulld, mulldo, mulld_, mulldo_, i64);
371 pub fn mulldo(inputs: InstructionInput) -> InstructionResult {
372 let ra = inputs.ra as i64;
373 let rb = inputs.rb as i64;
374 let result = ra.wrapping_mul(rb) as u64;
375 let overflow = ra.checked_mul(rb).is_none();
378 overflow: Some(OverflowFlags::from_overflow(overflow)),
379 ..InstructionResult::default()
383 create_instr_variants_cr!(mulhd, mulhd_, i64);
385 pub fn mulhd(inputs: InstructionInput) -> InstructionResult {
386 let ra = inputs.ra as i64 as i128;
387 let rb = inputs.rb as i64 as i128;
388 let result = ((ra * rb) >> 64) as i64;
389 let result = result as u64;
392 ..InstructionResult::default()
396 create_instr_variants_cr!(mulhdu, mulhdu_, i64);
398 pub fn mulhdu(inputs: InstructionInput) -> InstructionResult {
399 let ra = inputs.ra as u128;
400 let rb = inputs.rb as u128;
401 let result = ((ra * rb) >> 64) as u64;
404 ..InstructionResult::default()
408 pub fn maddhd(inputs: InstructionInput) -> InstructionResult {
409 let ra = inputs.ra as i64 as i128;
410 let rb = inputs.rb as i64 as i128;
411 let rc = inputs.rc as i64 as i128;
412 let result = ((ra * rb + rc) >> 64) as u64;
415 ..InstructionResult::default()
419 pub fn maddhdu(inputs: InstructionInput) -> InstructionResult {
420 let ra = inputs.ra as u128;
421 let rb = inputs.rb as u128;
422 let rc = inputs.rc as u128;
423 let result = ((ra * rb + rc) >> 64) as u64;
426 ..InstructionResult::default()
430 pub fn maddld(inputs: InstructionInput) -> InstructionResult {
431 let ra = inputs.ra as i64;
432 let rb = inputs.rb as i64;
433 let rc = inputs.rc as i64;
434 let result = ra.wrapping_mul(rb).wrapping_add(rc) as u64;
437 ..InstructionResult::default()