refactor API and add support for more instructions
[power-instruction-analyzer.git] / src / instr_models.rs
1 use crate::{ConditionRegister, InstructionInput, InstructionResult, OverflowFlags};
2
3 macro_rules! create_instr_variants {
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 create_instr_variants!(divde, divdeo, divde_, divdeo_, i64);
30
31 pub fn divdeo(inputs: InstructionInput) -> InstructionResult {
32 let dividend = i128::from(inputs.ra as i64) << 64;
33 let divisor = i128::from(inputs.rb as i64);
34 let overflow;
35 let result;
36 if divisor == 0 || (divisor == -1 && dividend == i128::min_value()) {
37 result = 0;
38 overflow = true;
39 } else {
40 let result128 = dividend / divisor;
41 if result128 as i64 as i128 != result128 {
42 result = 0;
43 overflow = true;
44 } else {
45 result = result128 as u64;
46 overflow = false;
47 }
48 }
49 InstructionResult {
50 rt: Some(result),
51 overflow: Some(OverflowFlags::from_overflow(overflow)),
52 ..InstructionResult::default()
53 }
54 }
55
56 create_instr_variants!(divdeu, divdeuo, divdeu_, divdeuo_, i64);
57
58 pub fn divdeuo(inputs: InstructionInput) -> InstructionResult {
59 let dividend = u128::from(inputs.ra) << 64;
60 let divisor = u128::from(inputs.rb);
61 let overflow;
62 let result;
63 if divisor == 0 {
64 result = 0;
65 overflow = true;
66 } else {
67 let resultu128 = dividend / divisor;
68 if resultu128 > u128::from(u64::max_value()) {
69 result = 0;
70 overflow = true;
71 } else {
72 result = resultu128 as u64;
73 overflow = false;
74 }
75 }
76 InstructionResult {
77 rt: Some(result),
78 overflow: Some(OverflowFlags::from_overflow(overflow)),
79 ..InstructionResult::default()
80 }
81 }
82
83 create_instr_variants!(divd, divdo, divd_, divdo_, i64);
84
85 pub fn divdo(inputs: InstructionInput) -> InstructionResult {
86 let dividend = inputs.ra as i64;
87 let divisor = inputs.rb as i64;
88 let overflow;
89 let result;
90 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
91 result = 0;
92 overflow = true;
93 } else {
94 result = (dividend / divisor) as u64;
95 overflow = false;
96 }
97 InstructionResult {
98 rt: Some(result),
99 overflow: Some(OverflowFlags::from_overflow(overflow)),
100 ..InstructionResult::default()
101 }
102 }
103
104 create_instr_variants!(divdu, divduo, divdu_, divduo_, i64);
105
106 pub fn divduo(inputs: InstructionInput) -> InstructionResult {
107 let dividend: u64 = inputs.ra;
108 let divisor: u64 = inputs.rb;
109 let overflow;
110 let result;
111 if divisor == 0 {
112 result = 0;
113 overflow = true;
114 } else {
115 result = dividend / divisor;
116 overflow = false;
117 }
118 InstructionResult {
119 rt: Some(result),
120 overflow: Some(OverflowFlags::from_overflow(overflow)),
121 ..InstructionResult::default()
122 }
123 }
124
125 create_instr_variants!(divwe, divweo, divwe_, divweo_, i32);
126
127 pub fn divweo(inputs: InstructionInput) -> InstructionResult {
128 let dividend = i64::from(inputs.ra as i32) << 32;
129 let divisor = i64::from(inputs.rb as i32);
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 let result64 = dividend / divisor;
137 if result64 as i32 as i64 != result64 {
138 result = 0;
139 overflow = true;
140 } else {
141 result = result64 as u32 as u64;
142 overflow = false;
143 }
144 }
145 InstructionResult {
146 rt: Some(result),
147 overflow: Some(OverflowFlags::from_overflow(overflow)),
148 ..InstructionResult::default()
149 }
150 }
151
152 create_instr_variants!(divweu, divweuo, divweu_, divweuo_, i32);
153
154 pub fn divweuo(inputs: InstructionInput) -> InstructionResult {
155 let dividend = u64::from(inputs.ra as u32) << 32;
156 let divisor = u64::from(inputs.rb as u32);
157 let overflow;
158 let result;
159 if divisor == 0 {
160 result = 0;
161 overflow = true;
162 } else {
163 let resultu64 = dividend / divisor;
164 if resultu64 > u64::from(u32::max_value()) {
165 result = 0;
166 overflow = true;
167 } else {
168 result = resultu64 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 create_instr_variants!(divw, divwo, divw_, divwo_, i32);
180
181 pub fn divwo(inputs: InstructionInput) -> InstructionResult {
182 let dividend = inputs.ra as i32;
183 let divisor = inputs.rb as i32;
184 let overflow;
185 let result;
186 if divisor == 0 || (divisor == -1 && dividend == i32::min_value()) {
187 result = 0;
188 overflow = true;
189 } else {
190 result = (dividend / divisor) as u32 as u64;
191 overflow = false;
192 }
193 InstructionResult {
194 rt: Some(result),
195 overflow: Some(OverflowFlags::from_overflow(overflow)),
196 ..InstructionResult::default()
197 }
198 }
199
200 create_instr_variants!(divwu, divwuo, divwu_, divwuo_, i32);
201
202 pub fn divwuo(inputs: InstructionInput) -> InstructionResult {
203 let dividend = inputs.ra as u32;
204 let divisor = inputs.rb as u32;
205 let overflow;
206 let result;
207 if divisor == 0 {
208 result = 0;
209 overflow = true;
210 } else {
211 result = (dividend / divisor) as u64;
212 overflow = false;
213 }
214 InstructionResult {
215 rt: Some(result),
216 overflow: Some(OverflowFlags::from_overflow(overflow)),
217 ..InstructionResult::default()
218 }
219 }
220
221 pub fn modsd(inputs: InstructionInput) -> InstructionResult {
222 let dividend = inputs.ra as i64;
223 let divisor = inputs.rb as i64;
224 let result;
225 if divisor == 0 || (divisor == -1 && dividend == i64::min_value()) {
226 result = 0;
227 } else {
228 result = (dividend % divisor) as u64;
229 }
230 InstructionResult {
231 rt: Some(result),
232 ..InstructionResult::default()
233 }
234 }
235
236 pub fn modud(inputs: InstructionInput) -> InstructionResult {
237 let dividend: u64 = inputs.ra;
238 let divisor: u64 = inputs.rb;
239 let result;
240 if divisor == 0 {
241 result = 0;
242 } else {
243 result = dividend % divisor;
244 }
245 InstructionResult {
246 rt: Some(result),
247 ..InstructionResult::default()
248 }
249 }
250
251 pub fn modsw(inputs: InstructionInput) -> InstructionResult {
252 let dividend = inputs.ra as i32;
253 let divisor = inputs.rb as i32;
254 let result;
255 if divisor == 0 || (divisor == -1 && dividend == i32::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 moduw(inputs: InstructionInput) -> InstructionResult {
267 let dividend = inputs.ra as u32;
268 let divisor = inputs.rb as u32;
269 let result;
270 if divisor == 0 {
271 result = 0;
272 } else {
273 result = (dividend % divisor) as u64;
274 }
275 InstructionResult {
276 rt: Some(result),
277 ..InstructionResult::default()
278 }
279 }