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 | #include "fpa11.h" |
12 | #include "fpopcode.h" |
13 | |
14 | #include "fpmodule.h" |
15 | #include "fpmodule.inl" |
16 | |
17 | #include <linux/compiler.h> |
18 | #include <linux/string.h> |
19 | |
20 | /* Reset the FPA11 chip. Called to initialize and reset the emulator. */ |
21 | static void resetFPA11(void) |
22 | { |
23 | int i; |
24 | FPA11 *fpa11 = GET_FPA11(); |
25 | |
26 | /* initialize the register type array */ |
27 | for (i = 0; i <= 7; i++) { |
28 | fpa11->fType[i] = typeNone; |
29 | } |
30 | |
31 | /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ |
32 | fpa11->fpsr = FP_EMULATOR | BIT_AC; |
33 | } |
34 | |
35 | int8 SetRoundingMode(const unsigned int opcode) |
36 | { |
37 | switch (opcode & MASK_ROUNDING_MODE) { |
38 | default: |
39 | case ROUND_TO_NEAREST: |
40 | return float_round_nearest_even; |
41 | |
42 | case ROUND_TO_PLUS_INFINITY: |
43 | return float_round_up; |
44 | |
45 | case ROUND_TO_MINUS_INFINITY: |
46 | return float_round_down; |
47 | |
48 | case ROUND_TO_ZERO: |
49 | return float_round_to_zero; |
50 | } |
51 | } |
52 | |
53 | int8 SetRoundingPrecision(const unsigned int opcode) |
54 | { |
55 | #ifdef CONFIG_FPE_NWFPE_XP |
56 | switch (opcode & MASK_ROUNDING_PRECISION) { |
57 | case ROUND_SINGLE: |
58 | return 32; |
59 | |
60 | case ROUND_DOUBLE: |
61 | return 64; |
62 | |
63 | case ROUND_EXTENDED: |
64 | return 80; |
65 | |
66 | default: |
67 | return 80; |
68 | } |
69 | #endif |
70 | return 80; |
71 | } |
72 | |
73 | void nwfpe_init_fpa(union fp_state *fp) |
74 | { |
75 | FPA11 *fpa11 = (FPA11 *)fp; |
76 | #ifdef NWFPE_DEBUG |
77 | printk("NWFPE: setting up state.\n" ); |
78 | #endif |
79 | memset(fpa11, 0, sizeof(FPA11)); |
80 | resetFPA11(); |
81 | fpa11->initflag = 1; |
82 | } |
83 | |
84 | /* Emulate the instruction in the opcode. */ |
85 | unsigned int EmulateAll(unsigned int opcode) |
86 | { |
87 | unsigned int code; |
88 | |
89 | #ifdef NWFPE_DEBUG |
90 | printk("NWFPE: emulating opcode %08x\n" , opcode); |
91 | #endif |
92 | code = opcode & 0x00000f00; |
93 | if (code == 0x00000100 || code == 0x00000200) { |
94 | /* For coprocessor 1 or 2 (FPA11) */ |
95 | code = opcode & 0x0e000000; |
96 | if (code == 0x0e000000) { |
97 | if (opcode & 0x00000010) { |
98 | /* Emulate conversion opcodes. */ |
99 | /* Emulate register transfer opcodes. */ |
100 | /* Emulate comparison opcodes. */ |
101 | return EmulateCPRT(opcode); |
102 | } else { |
103 | /* Emulate monadic arithmetic opcodes. */ |
104 | /* Emulate dyadic arithmetic opcodes. */ |
105 | return EmulateCPDO(opcode); |
106 | } |
107 | } else if (code == 0x0c000000) { |
108 | /* Emulate load/store opcodes. */ |
109 | /* Emulate load/store multiple opcodes. */ |
110 | return EmulateCPDT(opcode); |
111 | } |
112 | } |
113 | |
114 | /* Invalid instruction detected. Return FALSE. */ |
115 | return 0; |
116 | } |
117 | |