1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
2 | /* |
3 | NetWinder Floating Point Emulator |
4 | (c) Rebel.COM, 1998,1999 |
5 | (c) Philip Blundell, 2001 |
6 | |
7 | Direct questions, comments to Scott Bambrough <scottb@netwinder.org> |
8 | |
9 | */ |
10 | |
11 | #ifndef __FPOPCODE_H__ |
12 | #define __FPOPCODE_H__ |
13 | |
14 | |
15 | /* |
16 | ARM Floating Point Instruction Classes |
17 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
18 | |c o n d|1 1 0 P|U|u|W|L| Rn |v| Fd |0|0|0|1| o f f s e t | CPDT |
19 | |c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|1|0| o f f s e t | CPDT (copro 2) |
20 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
21 | |c o n d|1 1 1 0|a|b|c|d|e| Fn |j| Fd |0|0|0|1|f|g|h|0|i| Fm | CPDO |
22 | |c o n d|1 1 1 0|a|b|c|L|e| Fn | Rd |0|0|0|1|f|g|h|1|i| Fm | CPRT |
23 | |c o n d|1 1 1 0|a|b|c|1|e| Fn |1|1|1|1|0|0|0|1|f|g|h|1|i| Fm | comparisons |
24 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
25 | |
26 | CPDT data transfer instructions |
27 | LDF, STF, LFM (copro 2), SFM (copro 2) |
28 | |
29 | CPDO dyadic arithmetic instructions |
30 | ADF, MUF, SUF, RSF, DVF, RDF, |
31 | POW, RPW, RMF, FML, FDV, FRD, POL |
32 | |
33 | CPDO monadic arithmetic instructions |
34 | MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP, |
35 | SIN, COS, TAN, ASN, ACS, ATN, URD, NRM |
36 | |
37 | CPRT joint arithmetic/data transfer instructions |
38 | FIX (arithmetic followed by load/store) |
39 | FLT (load/store followed by arithmetic) |
40 | CMF, CNF CMFE, CNFE (comparisons) |
41 | WFS, RFS (write/read floating point status register) |
42 | WFC, RFC (write/read floating point control register) |
43 | |
44 | cond condition codes |
45 | P pre/post index bit: 0 = postindex, 1 = preindex |
46 | U up/down bit: 0 = stack grows down, 1 = stack grows up |
47 | W write back bit: 1 = update base register (Rn) |
48 | L load/store bit: 0 = store, 1 = load |
49 | Rn base register |
50 | Rd destination/source register |
51 | Fd floating point destination register |
52 | Fn floating point source register |
53 | Fm floating point source register or floating point constant |
54 | |
55 | uv transfer length (TABLE 1) |
56 | wx register count (TABLE 2) |
57 | abcd arithmetic opcode (TABLES 3 & 4) |
58 | ef destination size (rounding precision) (TABLE 5) |
59 | gh rounding mode (TABLE 6) |
60 | j dyadic/monadic bit: 0 = dyadic, 1 = monadic |
61 | i constant bit: 1 = constant (TABLE 6) |
62 | */ |
63 | |
64 | /* |
65 | TABLE 1 |
66 | +-------------------------+---+---+---------+---------+ |
67 | | Precision | u | v | FPSR.EP | length | |
68 | +-------------------------+---+---+---------+---------+ |
69 | | Single | 0 | 0 | x | 1 words | |
70 | | Double | 1 | 1 | x | 2 words | |
71 | | Extended | 1 | 1 | x | 3 words | |
72 | | Packed decimal | 1 | 1 | 0 | 3 words | |
73 | | Expanded packed decimal | 1 | 1 | 1 | 4 words | |
74 | +-------------------------+---+---+---------+---------+ |
75 | Note: x = don't care |
76 | */ |
77 | |
78 | /* |
79 | TABLE 2 |
80 | +---+---+---------------------------------+ |
81 | | w | x | Number of registers to transfer | |
82 | +---+---+---------------------------------+ |
83 | | 0 | 1 | 1 | |
84 | | 1 | 0 | 2 | |
85 | | 1 | 1 | 3 | |
86 | | 0 | 0 | 4 | |
87 | +---+---+---------------------------------+ |
88 | */ |
89 | |
90 | /* |
91 | TABLE 3: Dyadic Floating Point Opcodes |
92 | +---+---+---+---+----------+-----------------------+-----------------------+ |
93 | | a | b | c | d | Mnemonic | Description | Operation | |
94 | +---+---+---+---+----------+-----------------------+-----------------------+ |
95 | | 0 | 0 | 0 | 0 | ADF | Add | Fd := Fn + Fm | |
96 | | 0 | 0 | 0 | 1 | MUF | Multiply | Fd := Fn * Fm | |
97 | | 0 | 0 | 1 | 0 | SUF | Subtract | Fd := Fn - Fm | |
98 | | 0 | 0 | 1 | 1 | RSF | Reverse subtract | Fd := Fm - Fn | |
99 | | 0 | 1 | 0 | 0 | DVF | Divide | Fd := Fn / Fm | |
100 | | 0 | 1 | 0 | 1 | RDF | Reverse divide | Fd := Fm / Fn | |
101 | | 0 | 1 | 1 | 0 | POW | Power | Fd := Fn ^ Fm | |
102 | | 0 | 1 | 1 | 1 | RPW | Reverse power | Fd := Fm ^ Fn | |
103 | | 1 | 0 | 0 | 0 | RMF | Remainder | Fd := IEEE rem(Fn/Fm) | |
104 | | 1 | 0 | 0 | 1 | FML | Fast Multiply | Fd := Fn * Fm | |
105 | | 1 | 0 | 1 | 0 | FDV | Fast Divide | Fd := Fn / Fm | |
106 | | 1 | 0 | 1 | 1 | FRD | Fast reverse divide | Fd := Fm / Fn | |
107 | | 1 | 1 | 0 | 0 | POL | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm) | |
108 | | 1 | 1 | 0 | 1 | | undefined instruction | trap | |
109 | | 1 | 1 | 1 | 0 | | undefined instruction | trap | |
110 | | 1 | 1 | 1 | 1 | | undefined instruction | trap | |
111 | +---+---+---+---+----------+-----------------------+-----------------------+ |
112 | Note: POW, RPW, POL are deprecated, and are available for backwards |
113 | compatibility only. |
114 | */ |
115 | |
116 | /* |
117 | TABLE 4: Monadic Floating Point Opcodes |
118 | +---+---+---+---+----------+-----------------------+-----------------------+ |
119 | | a | b | c | d | Mnemonic | Description | Operation | |
120 | +---+---+---+---+----------+-----------------------+-----------------------+ |
121 | | 0 | 0 | 0 | 0 | MVF | Move | Fd := Fm | |
122 | | 0 | 0 | 0 | 1 | MNF | Move negated | Fd := - Fm | |
123 | | 0 | 0 | 1 | 0 | ABS | Absolute value | Fd := abs(Fm) | |
124 | | 0 | 0 | 1 | 1 | RND | Round to integer | Fd := int(Fm) | |
125 | | 0 | 1 | 0 | 0 | SQT | Square root | Fd := sqrt(Fm) | |
126 | | 0 | 1 | 0 | 1 | LOG | Log base 10 | Fd := log10(Fm) | |
127 | | 0 | 1 | 1 | 0 | LGN | Log base e | Fd := ln(Fm) | |
128 | | 0 | 1 | 1 | 1 | EXP | Exponent | Fd := e ^ Fm | |
129 | | 1 | 0 | 0 | 0 | SIN | Sine | Fd := sin(Fm) | |
130 | | 1 | 0 | 0 | 1 | COS | Cosine | Fd := cos(Fm) | |
131 | | 1 | 0 | 1 | 0 | TAN | Tangent | Fd := tan(Fm) | |
132 | | 1 | 0 | 1 | 1 | ASN | Arc Sine | Fd := arcsin(Fm) | |
133 | | 1 | 1 | 0 | 0 | ACS | Arc Cosine | Fd := arccos(Fm) | |
134 | | 1 | 1 | 0 | 1 | ATN | Arc Tangent | Fd := arctan(Fm) | |
135 | | 1 | 1 | 1 | 0 | URD | Unnormalized round | Fd := int(Fm) | |
136 | | 1 | 1 | 1 | 1 | NRM | Normalize | Fd := norm(Fm) | |
137 | +---+---+---+---+----------+-----------------------+-----------------------+ |
138 | Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are |
139 | available for backwards compatibility only. |
140 | */ |
141 | |
142 | /* |
143 | TABLE 5 |
144 | +-------------------------+---+---+ |
145 | | Rounding Precision | e | f | |
146 | +-------------------------+---+---+ |
147 | | IEEE Single precision | 0 | 0 | |
148 | | IEEE Double precision | 0 | 1 | |
149 | | IEEE Extended precision | 1 | 0 | |
150 | | undefined (trap) | 1 | 1 | |
151 | +-------------------------+---+---+ |
152 | */ |
153 | |
154 | /* |
155 | TABLE 5 |
156 | +---------------------------------+---+---+ |
157 | | Rounding Mode | g | h | |
158 | +---------------------------------+---+---+ |
159 | | Round to nearest (default) | 0 | 0 | |
160 | | Round toward plus infinity | 0 | 1 | |
161 | | Round toward negative infinity | 1 | 0 | |
162 | | Round toward zero | 1 | 1 | |
163 | +---------------------------------+---+---+ |
164 | */ |
165 | |
166 | /* |
167 | === |
168 | === Definitions for load and store instructions |
169 | === |
170 | */ |
171 | |
172 | /* bit masks */ |
173 | #define BIT_PREINDEX 0x01000000 |
174 | #define BIT_UP 0x00800000 |
175 | #define BIT_WRITE_BACK 0x00200000 |
176 | #define BIT_LOAD 0x00100000 |
177 | |
178 | /* masks for load/store */ |
179 | #define MASK_CPDT 0x0c000000 /* data processing opcode */ |
180 | #define MASK_OFFSET 0x000000ff |
181 | #define MASK_TRANSFER_LENGTH 0x00408000 |
182 | #define MASK_REGISTER_COUNT MASK_TRANSFER_LENGTH |
183 | #define MASK_COPROCESSOR 0x00000f00 |
184 | |
185 | /* Tests for transfer length */ |
186 | #define TRANSFER_SINGLE 0x00000000 |
187 | #define TRANSFER_DOUBLE 0x00008000 |
188 | #define TRANSFER_EXTENDED 0x00400000 |
189 | #define TRANSFER_PACKED MASK_TRANSFER_LENGTH |
190 | |
191 | /* Get the coprocessor number from the opcode. */ |
192 | #define getCoprocessorNumber(opcode) ((opcode & MASK_COPROCESSOR) >> 8) |
193 | |
194 | /* Get the offset from the opcode. */ |
195 | #define getOffset(opcode) (opcode & MASK_OFFSET) |
196 | |
197 | /* Tests for specific data transfer load/store opcodes. */ |
198 | #define TEST_OPCODE(opcode,mask) (((opcode) & (mask)) == (mask)) |
199 | |
200 | #define LOAD_OP(opcode) TEST_OPCODE((opcode),MASK_CPDT | BIT_LOAD) |
201 | #define STORE_OP(opcode) ((opcode & (MASK_CPDT | BIT_LOAD)) == MASK_CPDT) |
202 | |
203 | #define LDF_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) |
204 | #define LFM_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) |
205 | #define STF_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) |
206 | #define SFM_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) |
207 | |
208 | #define PREINDEXED(opcode) ((opcode & BIT_PREINDEX) != 0) |
209 | #define POSTINDEXED(opcode) ((opcode & BIT_PREINDEX) == 0) |
210 | #define BIT_UP_SET(opcode) ((opcode & BIT_UP) != 0) |
211 | #define BIT_UP_CLEAR(opcode) ((opcode & BIT_DOWN) == 0) |
212 | #define WRITE_BACK(opcode) ((opcode & BIT_WRITE_BACK) != 0) |
213 | #define LOAD(opcode) ((opcode & BIT_LOAD) != 0) |
214 | #define STORE(opcode) ((opcode & BIT_LOAD) == 0) |
215 | |
216 | /* |
217 | === |
218 | === Definitions for arithmetic instructions |
219 | === |
220 | */ |
221 | /* bit masks */ |
222 | #define BIT_MONADIC 0x00008000 |
223 | #define BIT_CONSTANT 0x00000008 |
224 | |
225 | #define CONSTANT_FM(opcode) ((opcode & BIT_CONSTANT) != 0) |
226 | #define MONADIC_INSTRUCTION(opcode) ((opcode & BIT_MONADIC) != 0) |
227 | |
228 | /* instruction identification masks */ |
229 | #define MASK_CPDO 0x0e000000 /* arithmetic opcode */ |
230 | #define MASK_ARITHMETIC_OPCODE 0x00f08000 |
231 | #define MASK_DESTINATION_SIZE 0x00080080 |
232 | |
233 | /* dyadic arithmetic opcodes. */ |
234 | #define ADF_CODE 0x00000000 |
235 | #define MUF_CODE 0x00100000 |
236 | #define SUF_CODE 0x00200000 |
237 | #define RSF_CODE 0x00300000 |
238 | #define DVF_CODE 0x00400000 |
239 | #define RDF_CODE 0x00500000 |
240 | #define POW_CODE 0x00600000 |
241 | #define RPW_CODE 0x00700000 |
242 | #define RMF_CODE 0x00800000 |
243 | #define FML_CODE 0x00900000 |
244 | #define FDV_CODE 0x00a00000 |
245 | #define FRD_CODE 0x00b00000 |
246 | #define POL_CODE 0x00c00000 |
247 | /* 0x00d00000 is an invalid dyadic arithmetic opcode */ |
248 | /* 0x00e00000 is an invalid dyadic arithmetic opcode */ |
249 | /* 0x00f00000 is an invalid dyadic arithmetic opcode */ |
250 | |
251 | /* monadic arithmetic opcodes. */ |
252 | #define MVF_CODE 0x00008000 |
253 | #define MNF_CODE 0x00108000 |
254 | #define ABS_CODE 0x00208000 |
255 | #define RND_CODE 0x00308000 |
256 | #define SQT_CODE 0x00408000 |
257 | #define LOG_CODE 0x00508000 |
258 | #define LGN_CODE 0x00608000 |
259 | #define EXP_CODE 0x00708000 |
260 | #define SIN_CODE 0x00808000 |
261 | #define COS_CODE 0x00908000 |
262 | #define TAN_CODE 0x00a08000 |
263 | #define ASN_CODE 0x00b08000 |
264 | #define ACS_CODE 0x00c08000 |
265 | #define ATN_CODE 0x00d08000 |
266 | #define URD_CODE 0x00e08000 |
267 | #define NRM_CODE 0x00f08000 |
268 | |
269 | /* |
270 | === |
271 | === Definitions for register transfer and comparison instructions |
272 | === |
273 | */ |
274 | |
275 | #define MASK_CPRT 0x0e000010 /* register transfer opcode */ |
276 | #define MASK_CPRT_CODE 0x00f00000 |
277 | #define FLT_CODE 0x00000000 |
278 | #define FIX_CODE 0x00100000 |
279 | #define WFS_CODE 0x00200000 |
280 | #define RFS_CODE 0x00300000 |
281 | #define WFC_CODE 0x00400000 |
282 | #define RFC_CODE 0x00500000 |
283 | #define CMF_CODE 0x00900000 |
284 | #define CNF_CODE 0x00b00000 |
285 | #define CMFE_CODE 0x00d00000 |
286 | #define CNFE_CODE 0x00f00000 |
287 | |
288 | /* |
289 | === |
290 | === Common definitions |
291 | === |
292 | */ |
293 | |
294 | /* register masks */ |
295 | #define MASK_Rd 0x0000f000 |
296 | #define MASK_Rn 0x000f0000 |
297 | #define MASK_Fd 0x00007000 |
298 | #define MASK_Fm 0x00000007 |
299 | #define MASK_Fn 0x00070000 |
300 | |
301 | /* condition code masks */ |
302 | #define CC_MASK 0xf0000000 |
303 | #define CC_NEGATIVE 0x80000000 |
304 | #define CC_ZERO 0x40000000 |
305 | #define CC_CARRY 0x20000000 |
306 | #define CC_OVERFLOW 0x10000000 |
307 | #define CC_EQ 0x00000000 |
308 | #define CC_NE 0x10000000 |
309 | #define CC_CS 0x20000000 |
310 | #define CC_HS CC_CS |
311 | #define CC_CC 0x30000000 |
312 | #define CC_LO CC_CC |
313 | #define CC_MI 0x40000000 |
314 | #define CC_PL 0x50000000 |
315 | #define CC_VS 0x60000000 |
316 | #define CC_VC 0x70000000 |
317 | #define CC_HI 0x80000000 |
318 | #define CC_LS 0x90000000 |
319 | #define CC_GE 0xa0000000 |
320 | #define CC_LT 0xb0000000 |
321 | #define CC_GT 0xc0000000 |
322 | #define CC_LE 0xd0000000 |
323 | #define CC_AL 0xe0000000 |
324 | #define CC_NV 0xf0000000 |
325 | |
326 | /* rounding masks/values */ |
327 | #define MASK_ROUNDING_MODE 0x00000060 |
328 | #define ROUND_TO_NEAREST 0x00000000 |
329 | #define ROUND_TO_PLUS_INFINITY 0x00000020 |
330 | #define ROUND_TO_MINUS_INFINITY 0x00000040 |
331 | #define ROUND_TO_ZERO 0x00000060 |
332 | |
333 | #define MASK_ROUNDING_PRECISION 0x00080080 |
334 | #define ROUND_SINGLE 0x00000000 |
335 | #define ROUND_DOUBLE 0x00000080 |
336 | #define ROUND_EXTENDED 0x00080000 |
337 | |
338 | /* Get the condition code from the opcode. */ |
339 | #define getCondition(opcode) (opcode >> 28) |
340 | |
341 | /* Get the source register from the opcode. */ |
342 | #define getRn(opcode) ((opcode & MASK_Rn) >> 16) |
343 | |
344 | /* Get the destination floating point register from the opcode. */ |
345 | #define getFd(opcode) ((opcode & MASK_Fd) >> 12) |
346 | |
347 | /* Get the first source floating point register from the opcode. */ |
348 | #define getFn(opcode) ((opcode & MASK_Fn) >> 16) |
349 | |
350 | /* Get the second source floating point register from the opcode. */ |
351 | #define getFm(opcode) (opcode & MASK_Fm) |
352 | |
353 | /* Get the destination register from the opcode. */ |
354 | #define getRd(opcode) ((opcode & MASK_Rd) >> 12) |
355 | |
356 | /* Get the rounding mode from the opcode. */ |
357 | #define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5) |
358 | |
359 | #ifdef CONFIG_FPE_NWFPE_XP |
360 | static inline floatx80 __pure getExtendedConstant(const unsigned int nIndex) |
361 | { |
362 | extern const floatx80 floatx80Constant[]; |
363 | return floatx80Constant[nIndex]; |
364 | } |
365 | #endif |
366 | |
367 | static inline float64 __pure getDoubleConstant(const unsigned int nIndex) |
368 | { |
369 | extern const float64 float64Constant[]; |
370 | return float64Constant[nIndex]; |
371 | } |
372 | |
373 | static inline float32 __pure getSingleConstant(const unsigned int nIndex) |
374 | { |
375 | extern const float32 float32Constant[]; |
376 | return float32Constant[nIndex]; |
377 | } |
378 | |
379 | static inline unsigned int getTransferLength(const unsigned int opcode) |
380 | { |
381 | unsigned int nRc; |
382 | |
383 | switch (opcode & MASK_TRANSFER_LENGTH) { |
384 | case 0x00000000: |
385 | nRc = 1; |
386 | break; /* single precision */ |
387 | case 0x00008000: |
388 | nRc = 2; |
389 | break; /* double precision */ |
390 | case 0x00400000: |
391 | nRc = 3; |
392 | break; /* extended precision */ |
393 | default: |
394 | nRc = 0; |
395 | } |
396 | |
397 | return (nRc); |
398 | } |
399 | |
400 | static inline unsigned int getRegisterCount(const unsigned int opcode) |
401 | { |
402 | unsigned int nRc; |
403 | |
404 | switch (opcode & MASK_REGISTER_COUNT) { |
405 | case 0x00000000: |
406 | nRc = 4; |
407 | break; |
408 | case 0x00008000: |
409 | nRc = 1; |
410 | break; |
411 | case 0x00400000: |
412 | nRc = 2; |
413 | break; |
414 | case 0x00408000: |
415 | nRc = 3; |
416 | break; |
417 | default: |
418 | nRc = 0; |
419 | } |
420 | |
421 | return (nRc); |
422 | } |
423 | |
424 | static inline unsigned int getRoundingPrecision(const unsigned int opcode) |
425 | { |
426 | unsigned int nRc; |
427 | |
428 | switch (opcode & MASK_ROUNDING_PRECISION) { |
429 | case 0x00000000: |
430 | nRc = 1; |
431 | break; |
432 | case 0x00000080: |
433 | nRc = 2; |
434 | break; |
435 | case 0x00080000: |
436 | nRc = 3; |
437 | break; |
438 | default: |
439 | nRc = 0; |
440 | } |
441 | |
442 | return (nRc); |
443 | } |
444 | |
445 | static inline unsigned int getDestinationSize(const unsigned int opcode) |
446 | { |
447 | unsigned int nRc; |
448 | |
449 | switch (opcode & MASK_DESTINATION_SIZE) { |
450 | case 0x00000000: |
451 | nRc = typeSingle; |
452 | break; |
453 | case 0x00000080: |
454 | nRc = typeDouble; |
455 | break; |
456 | case 0x00080000: |
457 | nRc = typeExtended; |
458 | break; |
459 | default: |
460 | nRc = typeNone; |
461 | } |
462 | |
463 | return (nRc); |
464 | } |
465 | |
466 | extern const float64 float64Constant[]; |
467 | extern const float32 float32Constant[]; |
468 | |
469 | #endif |
470 | |