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