add subf[o][.] instructions
[power-instruction-analyzer.git] / src / instr_models.rs
1 use crate::{ConditionRegister, InstructionInput, InstructionResult, OverflowFlags};
2
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 {
6 InstructionResult {
7 overflow: None,
8 ..$fno(inputs)
9 }
10 }
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");
14 cr0.so = false;
15 retval.overflow = None;
16 retval
17 }
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);
24 retval
25 }
26 };
27 }
28
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);
36 retval
37 }
38 };
39 }
40
41 create_instr_variants_ov_cr!(add, addo, add_, addo_, i64);
42
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;
49 InstructionResult {
50 rt: Some(result),
51 overflow: Some(OverflowFlags { so: ov, ov, ov32 }),
52 ..InstructionResult::default()
53 }
54 }
55
56 create_instr_variants_ov_cr!(subf, subfo, subf_, subfo_, i64);
57
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;
64 InstructionResult {
65 rt: Some(result),
66 overflow: Some(OverflowFlags { so: ov, ov, ov32 }),
67 ..InstructionResult::default()
68 }
69 }
70
71 create_instr_variants_ov_cr!(divde, divdeo, divde_, divdeo_, i64);
72
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);
76 let overflow;
77 let result;
78 if divisor == 0 || (divisor == -1 && dividend == i128::min_value()) {
79 result = 0;
80 overflow = true;
81 } else {
82 let result128 = dividend / divisor;
83 if result128 as i64 as i128 != result128 {
84 result = 0;
85 overflow = true;
86 } else {
87 result = result128 as u64;
88 overflow = false;
89 }
90 }
91 InstructionResult {
92 rt: Some(result),
93 overflow: Some(OverflowFlags::from_overflow(overflow)),
94 ..InstructionResult::default()
95 }
96 }
97
98 create_instr_variants_ov_cr!(divdeu, divdeuo, divdeu_, divdeuo_, i64);
99
100 pub fn divdeuo(inputs: InstructionInput) -> InstructionResult {
101 let dividend = u128::from(inputs.ra) << 64;
102 let divisor = u128::from(inputs.rb);
103 let overflow;
104 let result;
105 if divisor == 0 {
106 result = 0;
107 overflow = true;
108 } else {
109 let resultu128 = dividend / divisor;
110 if resultu128 > u128::from(u64::max_value()) {
111 result = 0;
112 overflow = true;
113 } else {
114 result = resultu128 as u64;
115 overflow = false;
116 }
117 }
118 InstructionResult {
119 rt: Some(result),
120 overflow: Some(OverflowFlags::from_overflow(overflow)),
121 ..InstructionResult::default()
122 }
123 }
124
125 create_instr_variants_ov_cr!(divd, divdo, divd_, divdo_, i64);
126
127 pub fn divdo(inputs: InstructionInput) -> InstructionResult {
128 let dividend = inputs.ra as i64;
129 let divisor = inputs.rb as i64;
130 let overflow;
131 let result;
132 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
133 result = 0;
134 overflow = true;
135 } else {
136 result = (dividend / divisor) as u64;
137 overflow = false;
138 }
139 InstructionResult {
140 rt: Some(result),
141 overflow: Some(OverflowFlags::from_overflow(overflow)),
142 ..InstructionResult::default()
143 }
144 }
145
146 create_instr_variants_ov_cr!(divdu, divduo, divdu_, divduo_, i64);
147
148 pub fn divduo(inputs: InstructionInput) -> InstructionResult {
149 let dividend: u64 = inputs.ra;
150 let divisor: u64 = inputs.rb;
151 let overflow;
152 let result;
153 if divisor == 0 {
154 result = 0;
155 overflow = true;
156 } else {
157 result = dividend / divisor;
158 overflow = false;
159 }
160 InstructionResult {
161 rt: Some(result),
162 overflow: Some(OverflowFlags::from_overflow(overflow)),
163 ..InstructionResult::default()
164 }
165 }
166
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);
169
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);
173 let overflow;
174 let result;
175 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
176 result = 0;
177 overflow = true;
178 } else {
179 let result64 = dividend / divisor;
180 if result64 as i32 as i64 != result64 {
181 result = 0;
182 overflow = true;
183 } else {
184 result = result64 as u32 as u64;
185 overflow = false;
186 }
187 }
188 InstructionResult {
189 rt: Some(result),
190 overflow: Some(OverflowFlags::from_overflow(overflow)),
191 ..InstructionResult::default()
192 }
193 }
194
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);
197
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);
201 let overflow;
202 let result;
203 if divisor == 0 {
204 result = 0;
205 overflow = true;
206 } else {
207 let resultu64 = dividend / divisor;
208 if resultu64 > u64::from(u32::max_value()) {
209 result = 0;
210 overflow = true;
211 } else {
212 result = resultu64 as u32 as u64;
213 overflow = false;
214 }
215 }
216 InstructionResult {
217 rt: Some(result),
218 overflow: Some(OverflowFlags::from_overflow(overflow)),
219 ..InstructionResult::default()
220 }
221 }
222
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);
225
226 pub fn divwo(inputs: InstructionInput) -> InstructionResult {
227 let dividend = inputs.ra as i32;
228 let divisor = inputs.rb as i32;
229 let overflow;
230 let result;
231 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
232 result = 0;
233 overflow = true;
234 } else {
235 result = (dividend / divisor) as u32 as u64;
236 overflow = false;
237 }
238 InstructionResult {
239 rt: Some(result),
240 overflow: Some(OverflowFlags::from_overflow(overflow)),
241 ..InstructionResult::default()
242 }
243 }
244
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);
247
248 pub fn divwuo(inputs: InstructionInput) -> InstructionResult {
249 let dividend = inputs.ra as u32;
250 let divisor = inputs.rb as u32;
251 let overflow;
252 let result;
253 if divisor == 0 {
254 result = 0;
255 overflow = true;
256 } else {
257 result = (dividend / divisor) as u64;
258 overflow = false;
259 }
260 InstructionResult {
261 rt: Some(result),
262 overflow: Some(OverflowFlags::from_overflow(overflow)),
263 ..InstructionResult::default()
264 }
265 }
266
267 pub fn modsd(inputs: InstructionInput) -> InstructionResult {
268 let dividend = inputs.ra as i64;
269 let divisor = inputs.rb as i64;
270 let result;
271 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
272 result = 0;
273 } else {
274 result = (dividend % divisor) as u64;
275 }
276 InstructionResult {
277 rt: Some(result),
278 ..InstructionResult::default()
279 }
280 }
281
282 pub fn modud(inputs: InstructionInput) -> InstructionResult {
283 let dividend: u64 = inputs.ra;
284 let divisor: u64 = inputs.rb;
285 let result;
286 if divisor == 0 {
287 result = 0;
288 } else {
289 result = dividend % divisor;
290 }
291 InstructionResult {
292 rt: Some(result),
293 ..InstructionResult::default()
294 }
295 }
296
297 pub fn modsw(inputs: InstructionInput) -> InstructionResult {
298 let dividend = inputs.ra as i32;
299 let divisor = inputs.rb as i32;
300 let result;
301 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
302 result = 0;
303 } else {
304 result = (dividend % divisor) as u64;
305 }
306 InstructionResult {
307 rt: Some(result),
308 ..InstructionResult::default()
309 }
310 }
311
312 pub fn moduw(inputs: InstructionInput) -> InstructionResult {
313 let dividend = inputs.ra as u32;
314 let divisor = inputs.rb as u32;
315 let result;
316 if divisor == 0 {
317 result = 0;
318 } else {
319 result = (dividend % divisor) as u64;
320 }
321 InstructionResult {
322 rt: Some(result),
323 ..InstructionResult::default()
324 }
325 }
326
327 create_instr_variants_ov_cr!(mullw, mullwo, mullw_, mullwo_, i64);
328
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;
334 InstructionResult {
335 rt: Some(result),
336 overflow: Some(OverflowFlags::from_overflow(overflow)),
337 ..InstructionResult::default()
338 }
339 }
340
341 create_instr_variants_cr!(mulhw, mulhw_, i32);
342
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;
349 InstructionResult {
350 rt: Some(result),
351 ..InstructionResult::default()
352 }
353 }
354
355 create_instr_variants_cr!(mulhwu, mulhwu_, i32);
356
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;
363 InstructionResult {
364 rt: Some(result),
365 ..InstructionResult::default()
366 }
367 }
368
369 create_instr_variants_ov_cr!(mulld, mulldo, mulld_, mulldo_, i64);
370
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();
376 InstructionResult {
377 rt: Some(result),
378 overflow: Some(OverflowFlags::from_overflow(overflow)),
379 ..InstructionResult::default()
380 }
381 }
382
383 create_instr_variants_cr!(mulhd, mulhd_, i64);
384
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;
390 InstructionResult {
391 rt: Some(result),
392 ..InstructionResult::default()
393 }
394 }
395
396 create_instr_variants_cr!(mulhdu, mulhdu_, i64);
397
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;
402 InstructionResult {
403 rt: Some(result),
404 ..InstructionResult::default()
405 }
406 }
407
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;
413 InstructionResult {
414 rt: Some(result),
415 ..InstructionResult::default()
416 }
417 }
418
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;
424 InstructionResult {
425 rt: Some(result),
426 ..InstructionResult::default()
427 }
428 }
429
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;
435 InstructionResult {
436 rt: Some(result),
437 ..InstructionResult::default()
438 }
439 }