updating instruction models
[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 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
138 create_instr_variants_ov_cr!(divwe, divweo, divwe_, divweo_, i64);
139
140 pub fn divweo(inputs: InstructionInput) -> InstructionResult {
141 let dividend = i64::from(inputs.ra as i32) << 32;
142 let divisor = i64::from(inputs.rb as i32);
143 let overflow;
144 let result;
145 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
146 result = 0;
147 overflow = true;
148 } else {
149 let result64 = dividend / divisor;
150 if result64 as i32 as i64 != result64 {
151 result = 0;
152 overflow = true;
153 } else {
154 result = result64 as u32 as u64;
155 overflow = false;
156 }
157 }
158 InstructionResult {
159 rt: Some(result),
160 overflow: Some(OverflowFlags::from_overflow(overflow)),
161 ..InstructionResult::default()
162 }
163 }
164
165 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
166 create_instr_variants_ov_cr!(divweu, divweuo, divweu_, divweuo_, i64);
167
168 pub fn divweuo(inputs: InstructionInput) -> InstructionResult {
169 let dividend = u64::from(inputs.ra as u32) << 32;
170 let divisor = u64::from(inputs.rb as u32);
171 let overflow;
172 let result;
173 if divisor == 0 {
174 result = 0;
175 overflow = true;
176 } else {
177 let resultu64 = dividend / divisor;
178 if resultu64 > u64::from(u32::max_value()) {
179 result = 0;
180 overflow = true;
181 } else {
182 result = resultu64 as u32 as u64;
183 overflow = false;
184 }
185 }
186 InstructionResult {
187 rt: Some(result),
188 overflow: Some(OverflowFlags::from_overflow(overflow)),
189 ..InstructionResult::default()
190 }
191 }
192
193 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
194 create_instr_variants_ov_cr!(divw, divwo, divw_, divwo_, i64);
195
196 pub fn divwo(inputs: InstructionInput) -> InstructionResult {
197 let dividend = inputs.ra as i32;
198 let divisor = inputs.rb as i32;
199 let overflow;
200 let result;
201 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
202 result = 0;
203 overflow = true;
204 } else {
205 result = (dividend / divisor) as u32 as u64;
206 overflow = false;
207 }
208 InstructionResult {
209 rt: Some(result),
210 overflow: Some(OverflowFlags::from_overflow(overflow)),
211 ..InstructionResult::default()
212 }
213 }
214
215 // ISA doesn't define compare results -- POWER9 apparently uses i64 instead of i32
216 create_instr_variants_ov_cr!(divwu, divwuo, divwu_, divwuo_, i64);
217
218 pub fn divwuo(inputs: InstructionInput) -> InstructionResult {
219 let dividend = inputs.ra as u32;
220 let divisor = inputs.rb as u32;
221 let overflow;
222 let result;
223 if divisor == 0 {
224 result = 0;
225 overflow = true;
226 } else {
227 result = (dividend / divisor) as u64;
228 overflow = false;
229 }
230 InstructionResult {
231 rt: Some(result),
232 overflow: Some(OverflowFlags::from_overflow(overflow)),
233 ..InstructionResult::default()
234 }
235 }
236
237 pub fn modsd(inputs: InstructionInput) -> InstructionResult {
238 let dividend = inputs.ra as i64;
239 let divisor = inputs.rb as i64;
240 let result;
241 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
242 result = 0;
243 } else {
244 result = (dividend % divisor) as u64;
245 }
246 InstructionResult {
247 rt: Some(result),
248 ..InstructionResult::default()
249 }
250 }
251
252 pub fn modud(inputs: InstructionInput) -> InstructionResult {
253 let dividend: u64 = inputs.ra;
254 let divisor: u64 = inputs.rb;
255 let result;
256 if divisor == 0 {
257 result = 0;
258 } else {
259 result = dividend % divisor;
260 }
261 InstructionResult {
262 rt: Some(result),
263 ..InstructionResult::default()
264 }
265 }
266
267 pub fn modsw(inputs: InstructionInput) -> InstructionResult {
268 let dividend = inputs.ra as i32;
269 let divisor = inputs.rb as i32;
270 let result;
271 if divisor == 0 || (divisor == -1 && dividend == i32::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 moduw(inputs: InstructionInput) -> InstructionResult {
283 let dividend = inputs.ra as u32;
284 let divisor = inputs.rb as u32;
285 let result;
286 if divisor == 0 {
287 result = 0;
288 } else {
289 result = (dividend % divisor) as u64;
290 }
291 InstructionResult {
292 rt: Some(result),
293 ..InstructionResult::default()
294 }
295 }
296
297 create_instr_variants_ov_cr!(mullw, mullwo, mullw_, mullwo_, i32);
298
299 pub fn mullwo(inputs: InstructionInput) -> InstructionResult {
300 let ra = inputs.ra as i32 as i64;
301 let rb = inputs.rb as i32 as i64;
302 let result = ra.wrapping_mul(rb) as u64;
303 let overflow = result as i32 as i64 != result as i64;
304 InstructionResult {
305 rt: Some(result),
306 overflow: Some(OverflowFlags::from_overflow(overflow)),
307 ..InstructionResult::default()
308 }
309 }
310
311 create_instr_variants_cr!(mulhw, mulhw_, i32);
312
313 pub fn mulhw(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 * rb) >> 32) as i32;
317 let result = result as u64;
318 InstructionResult {
319 rt: Some(result),
320 ..InstructionResult::default()
321 }
322 }
323
324 create_instr_variants_cr!(mulhwu, mulhwu_, i32);
325
326 pub fn mulhwu(inputs: InstructionInput) -> InstructionResult {
327 let ra = inputs.ra as u32 as u64;
328 let rb = inputs.rb as u32 as u64;
329 let result = ((ra * rb) >> 32) as u32;
330 let result = result as u64;
331 InstructionResult {
332 rt: Some(result),
333 ..InstructionResult::default()
334 }
335 }
336
337 create_instr_variants_ov_cr!(mulld, mulldo, mulld_, mulldo_, i64);
338
339 pub fn mulldo(inputs: InstructionInput) -> InstructionResult {
340 let ra = inputs.ra as i64;
341 let rb = inputs.rb as i64;
342 let result = ra.wrapping_mul(rb) as u64;
343 let overflow = ra.checked_mul(rb).is_none();
344 InstructionResult {
345 rt: Some(result),
346 overflow: Some(OverflowFlags::from_overflow(overflow)),
347 ..InstructionResult::default()
348 }
349 }
350
351 create_instr_variants_cr!(mulhd, mulhd_, i64);
352
353 pub fn mulhd(inputs: InstructionInput) -> InstructionResult {
354 let ra = inputs.ra as i64 as i128;
355 let rb = inputs.rb as i64 as i128;
356 let result = ((ra * rb) >> 64) as i64;
357 let result = result as u64;
358 InstructionResult {
359 rt: Some(result),
360 ..InstructionResult::default()
361 }
362 }
363
364 create_instr_variants_cr!(mulhdu, mulhdu_, i64);
365
366 pub fn mulhdu(inputs: InstructionInput) -> InstructionResult {
367 let ra = inputs.ra as u128;
368 let rb = inputs.rb as u128;
369 let result = ((ra * rb) >> 64) as u64;
370 InstructionResult {
371 rt: Some(result),
372 ..InstructionResult::default()
373 }
374 }
375
376 pub fn maddhd(inputs: InstructionInput) -> InstructionResult {
377 let ra = inputs.ra as i64 as i128;
378 let rb = inputs.rb as i64 as i128;
379 let rc = inputs.rc as i64 as i128;
380 let result = ((ra * rb + rc) >> 64) as u64;
381 InstructionResult {
382 rt: Some(result),
383 ..InstructionResult::default()
384 }
385 }
386
387 pub fn maddhdu(inputs: InstructionInput) -> InstructionResult {
388 let ra = inputs.ra as u128;
389 let rb = inputs.rb as u128;
390 let rc = inputs.rc as u128;
391 let result = ((ra * rb + rc) >> 64) as u64;
392 InstructionResult {
393 rt: Some(result),
394 ..InstructionResult::default()
395 }
396 }
397
398 pub fn maddld(inputs: InstructionInput) -> InstructionResult {
399 let ra = inputs.ra as i64;
400 let rb = inputs.rb as i64;
401 let rc = inputs.rc as i64;
402 let result = ra.wrapping_mul(rb).wrapping_add(rc) as u64;
403 InstructionResult {
404 rt: Some(result),
405 ..InstructionResult::default()
406 }
407 }