add add[o][.]
[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, overflow) = ra.overflowing_add(rb);
47 let result = result as u64;
48 InstructionResult {
49 rt: Some(result),
50 overflow: Some(OverflowFlags::from_overflow(overflow)),
51 ..InstructionResult::default()
52 }
53 }
54
55 create_instr_variants_ov_cr!(divde, divdeo, divde_, divdeo_, i64);
56
57 pub fn divdeo(inputs: InstructionInput) -> InstructionResult {
58 let dividend = i128::from(inputs.ra as i64) << 64;
59 let divisor = i128::from(inputs.rb as i64);
60 let overflow;
61 let result;
62 if divisor == 0 || (divisor == -1 && dividend == i128::min_value()) {
63 result = 0;
64 overflow = true;
65 } else {
66 let result128 = dividend / divisor;
67 if result128 as i64 as i128 != result128 {
68 result = 0;
69 overflow = true;
70 } else {
71 result = result128 as u64;
72 overflow = false;
73 }
74 }
75 InstructionResult {
76 rt: Some(result),
77 overflow: Some(OverflowFlags::from_overflow(overflow)),
78 ..InstructionResult::default()
79 }
80 }
81
82 create_instr_variants_ov_cr!(divdeu, divdeuo, divdeu_, divdeuo_, i64);
83
84 pub fn divdeuo(inputs: InstructionInput) -> InstructionResult {
85 let dividend = u128::from(inputs.ra) << 64;
86 let divisor = u128::from(inputs.rb);
87 let overflow;
88 let result;
89 if divisor == 0 {
90 result = 0;
91 overflow = true;
92 } else {
93 let resultu128 = dividend / divisor;
94 if resultu128 > u128::from(u64::max_value()) {
95 result = 0;
96 overflow = true;
97 } else {
98 result = resultu128 as u64;
99 overflow = false;
100 }
101 }
102 InstructionResult {
103 rt: Some(result),
104 overflow: Some(OverflowFlags::from_overflow(overflow)),
105 ..InstructionResult::default()
106 }
107 }
108
109 create_instr_variants_ov_cr!(divd, divdo, divd_, divdo_, i64);
110
111 pub fn divdo(inputs: InstructionInput) -> InstructionResult {
112 let dividend = inputs.ra as i64;
113 let divisor = inputs.rb as i64;
114 let overflow;
115 let result;
116 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
117 result = 0;
118 overflow = true;
119 } else {
120 result = (dividend / divisor) as u64;
121 overflow = false;
122 }
123 InstructionResult {
124 rt: Some(result),
125 overflow: Some(OverflowFlags::from_overflow(overflow)),
126 ..InstructionResult::default()
127 }
128 }
129
130 create_instr_variants_ov_cr!(divdu, divduo, divdu_, divduo_, i64);
131
132 pub fn divduo(inputs: InstructionInput) -> InstructionResult {
133 let dividend: u64 = inputs.ra;
134 let divisor: u64 = inputs.rb;
135 let overflow;
136 let result;
137 if divisor == 0 {
138 result = 0;
139 overflow = true;
140 } else {
141 result = dividend / divisor;
142 overflow = false;
143 }
144 InstructionResult {
145 rt: Some(result),
146 overflow: Some(OverflowFlags::from_overflow(overflow)),
147 ..InstructionResult::default()
148 }
149 }
150
151 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
152 create_instr_variants_ov_cr!(divwe, divweo, divwe_, divweo_, i64);
153
154 pub fn divweo(inputs: InstructionInput) -> InstructionResult {
155 let dividend = i64::from(inputs.ra as i32) << 32;
156 let divisor = i64::from(inputs.rb as i32);
157 let overflow;
158 let result;
159 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
160 result = 0;
161 overflow = true;
162 } else {
163 let result64 = dividend / divisor;
164 if result64 as i32 as i64 != result64 {
165 result = 0;
166 overflow = true;
167 } else {
168 result = result64 as u32 as u64;
169 overflow = false;
170 }
171 }
172 InstructionResult {
173 rt: Some(result),
174 overflow: Some(OverflowFlags::from_overflow(overflow)),
175 ..InstructionResult::default()
176 }
177 }
178
179 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
180 create_instr_variants_ov_cr!(divweu, divweuo, divweu_, divweuo_, i64);
181
182 pub fn divweuo(inputs: InstructionInput) -> InstructionResult {
183 let dividend = u64::from(inputs.ra as u32) << 32;
184 let divisor = u64::from(inputs.rb as u32);
185 let overflow;
186 let result;
187 if divisor == 0 {
188 result = 0;
189 overflow = true;
190 } else {
191 let resultu64 = dividend / divisor;
192 if resultu64 > u64::from(u32::max_value()) {
193 result = 0;
194 overflow = true;
195 } else {
196 result = resultu64 as u32 as u64;
197 overflow = false;
198 }
199 }
200 InstructionResult {
201 rt: Some(result),
202 overflow: Some(OverflowFlags::from_overflow(overflow)),
203 ..InstructionResult::default()
204 }
205 }
206
207 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
208 create_instr_variants_ov_cr!(divw, divwo, divw_, divwo_, i64);
209
210 pub fn divwo(inputs: InstructionInput) -> InstructionResult {
211 let dividend = inputs.ra as i32;
212 let divisor = inputs.rb as i32;
213 let overflow;
214 let result;
215 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
216 result = 0;
217 overflow = true;
218 } else {
219 result = (dividend / divisor) as u32 as u64;
220 overflow = false;
221 }
222 InstructionResult {
223 rt: Some(result),
224 overflow: Some(OverflowFlags::from_overflow(overflow)),
225 ..InstructionResult::default()
226 }
227 }
228
229 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
230 create_instr_variants_ov_cr!(divwu, divwuo, divwu_, divwuo_, i64);
231
232 pub fn divwuo(inputs: InstructionInput) -> InstructionResult {
233 let dividend = inputs.ra as u32;
234 let divisor = inputs.rb as u32;
235 let overflow;
236 let result;
237 if divisor == 0 {
238 result = 0;
239 overflow = true;
240 } else {
241 result = (dividend / divisor) as u64;
242 overflow = false;
243 }
244 InstructionResult {
245 rt: Some(result),
246 overflow: Some(OverflowFlags::from_overflow(overflow)),
247 ..InstructionResult::default()
248 }
249 }
250
251 pub fn modsd(inputs: InstructionInput) -> InstructionResult {
252 let dividend = inputs.ra as i64;
253 let divisor = inputs.rb as i64;
254 let result;
255 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
256 result = 0;
257 } else {
258 result = (dividend % divisor) as u64;
259 }
260 InstructionResult {
261 rt: Some(result),
262 ..InstructionResult::default()
263 }
264 }
265
266 pub fn modud(inputs: InstructionInput) -> InstructionResult {
267 let dividend: u64 = inputs.ra;
268 let divisor: u64 = inputs.rb;
269 let result;
270 if divisor == 0 {
271 result = 0;
272 } else {
273 result = dividend % divisor;
274 }
275 InstructionResult {
276 rt: Some(result),
277 ..InstructionResult::default()
278 }
279 }
280
281 pub fn modsw(inputs: InstructionInput) -> InstructionResult {
282 let dividend = inputs.ra as i32;
283 let divisor = inputs.rb as i32;
284 let result;
285 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
286 result = 0;
287 } else {
288 result = (dividend % divisor) as u64;
289 }
290 InstructionResult {
291 rt: Some(result),
292 ..InstructionResult::default()
293 }
294 }
295
296 pub fn moduw(inputs: InstructionInput) -> InstructionResult {
297 let dividend = inputs.ra as u32;
298 let divisor = inputs.rb as u32;
299 let result;
300 if divisor == 0 {
301 result = 0;
302 } else {
303 result = (dividend % divisor) as u64;
304 }
305 InstructionResult {
306 rt: Some(result),
307 ..InstructionResult::default()
308 }
309 }
310
311 create_instr_variants_ov_cr!(mullw, mullwo, mullw_, mullwo_, i64);
312
313 pub fn mullwo(inputs: InstructionInput) -> InstructionResult {
314 let ra = inputs.ra as i32 as i64;
315 let rb = inputs.rb as i32 as i64;
316 let result = ra.wrapping_mul(rb) as u64;
317 let overflow = result as i32 as i64 != result as i64;
318 InstructionResult {
319 rt: Some(result),
320 overflow: Some(OverflowFlags::from_overflow(overflow)),
321 ..InstructionResult::default()
322 }
323 }
324
325 create_instr_variants_cr!(mulhw, mulhw_, i32);
326
327 pub fn mulhw(inputs: InstructionInput) -> InstructionResult {
328 let ra = inputs.ra as i32 as i64;
329 let rb = inputs.rb as i32 as i64;
330 let result = (ra * rb) >> 32;
331 let mut result = result as u32 as u64;
332 result |= result << 32;
333 InstructionResult {
334 rt: Some(result),
335 ..InstructionResult::default()
336 }
337 }
338
339 create_instr_variants_cr!(mulhwu, mulhwu_, i32);
340
341 pub fn mulhwu(inputs: InstructionInput) -> InstructionResult {
342 let ra = inputs.ra as u32 as u64;
343 let rb = inputs.rb as u32 as u64;
344 let result = (ra * rb) >> 32;
345 let mut result = result as u32 as u64;
346 result |= result << 32;
347 InstructionResult {
348 rt: Some(result),
349 ..InstructionResult::default()
350 }
351 }
352
353 create_instr_variants_ov_cr!(mulld, mulldo, mulld_, mulldo_, i64);
354
355 pub fn mulldo(inputs: InstructionInput) -> InstructionResult {
356 let ra = inputs.ra as i64;
357 let rb = inputs.rb as i64;
358 let result = ra.wrapping_mul(rb) as u64;
359 let overflow = ra.checked_mul(rb).is_none();
360 InstructionResult {
361 rt: Some(result),
362 overflow: Some(OverflowFlags::from_overflow(overflow)),
363 ..InstructionResult::default()
364 }
365 }
366
367 create_instr_variants_cr!(mulhd, mulhd_, i64);
368
369 pub fn mulhd(inputs: InstructionInput) -> InstructionResult {
370 let ra = inputs.ra as i64 as i128;
371 let rb = inputs.rb as i64 as i128;
372 let result = ((ra * rb) >> 64) as i64;
373 let result = result as u64;
374 InstructionResult {
375 rt: Some(result),
376 ..InstructionResult::default()
377 }
378 }
379
380 create_instr_variants_cr!(mulhdu, mulhdu_, i64);
381
382 pub fn mulhdu(inputs: InstructionInput) -> InstructionResult {
383 let ra = inputs.ra as u128;
384 let rb = inputs.rb as u128;
385 let result = ((ra * rb) >> 64) as u64;
386 InstructionResult {
387 rt: Some(result),
388 ..InstructionResult::default()
389 }
390 }
391
392 pub fn maddhd(inputs: InstructionInput) -> InstructionResult {
393 let ra = inputs.ra as i64 as i128;
394 let rb = inputs.rb as i64 as i128;
395 let rc = inputs.rc as i64 as i128;
396 let result = ((ra * rb + rc) >> 64) as u64;
397 InstructionResult {
398 rt: Some(result),
399 ..InstructionResult::default()
400 }
401 }
402
403 pub fn maddhdu(inputs: InstructionInput) -> InstructionResult {
404 let ra = inputs.ra as u128;
405 let rb = inputs.rb as u128;
406 let rc = inputs.rc as u128;
407 let result = ((ra * rb + rc) >> 64) as u64;
408 InstructionResult {
409 rt: Some(result),
410 ..InstructionResult::default()
411 }
412 }
413
414 pub fn maddld(inputs: InstructionInput) -> InstructionResult {
415 let ra = inputs.ra as i64;
416 let rb = inputs.rb as i64;
417 let rc = inputs.rc as i64;
418 let result = ra.wrapping_mul(rb).wrapping_add(rc) as u64;
419 InstructionResult {
420 rt: Some(result),
421 ..InstructionResult::default()
422 }
423 }