root / target-m68k / helper.c @ 6e473128
History | View | Annotate | Download (7.2 kB)
1 | e6e5906b | pbrook | /*
|
---|---|---|---|
2 | e6e5906b | pbrook | * m68k op helpers
|
3 | e6e5906b | pbrook | *
|
4 | 0633879f | pbrook | * Copyright (c) 2006-2007 CodeSourcery
|
5 | e6e5906b | pbrook | * Written by Paul Brook
|
6 | e6e5906b | pbrook | *
|
7 | e6e5906b | pbrook | * This library is free software; you can redistribute it and/or
|
8 | e6e5906b | pbrook | * modify it under the terms of the GNU Lesser General Public
|
9 | e6e5906b | pbrook | * License as published by the Free Software Foundation; either
|
10 | e6e5906b | pbrook | * version 2 of the License, or (at your option) any later version.
|
11 | e6e5906b | pbrook | *
|
12 | e6e5906b | pbrook | * This library is distributed in the hope that it will be useful,
|
13 | e6e5906b | pbrook | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 | e6e5906b | pbrook | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15 | e6e5906b | pbrook | * General Public License for more details.
|
16 | e6e5906b | pbrook | *
|
17 | e6e5906b | pbrook | * You should have received a copy of the GNU Lesser General Public
|
18 | e6e5906b | pbrook | * License along with this library; if not, write to the Free Software
|
19 | e6e5906b | pbrook | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
20 | e6e5906b | pbrook | */
|
21 | e6e5906b | pbrook | |
22 | e6e5906b | pbrook | #include <stdio.h> |
23 | 0402f767 | pbrook | #include <string.h> |
24 | e6e5906b | pbrook | |
25 | e6e5906b | pbrook | #include "config.h" |
26 | e6e5906b | pbrook | #include "cpu.h" |
27 | e6e5906b | pbrook | #include "exec-all.h" |
28 | e6e5906b | pbrook | |
29 | 0402f767 | pbrook | enum m68k_cpuid {
|
30 | 0402f767 | pbrook | M68K_CPUID_M5206, |
31 | 0402f767 | pbrook | M68K_CPUID_CFV4E, |
32 | 0402f767 | pbrook | M68K_CPUID_ANY, |
33 | 0402f767 | pbrook | }; |
34 | 0402f767 | pbrook | |
35 | 0402f767 | pbrook | struct m68k_def_t {
|
36 | 0402f767 | pbrook | const char * name; |
37 | 0402f767 | pbrook | enum m68k_cpuid id;
|
38 | 0402f767 | pbrook | }; |
39 | 0402f767 | pbrook | |
40 | 0402f767 | pbrook | static m68k_def_t m68k_cpu_defs[] = {
|
41 | 0402f767 | pbrook | {"m5206", M68K_CPUID_M5206},
|
42 | 0402f767 | pbrook | {"cfv4e", M68K_CPUID_CFV4E},
|
43 | 0402f767 | pbrook | {"any", M68K_CPUID_ANY},
|
44 | 0402f767 | pbrook | {NULL, 0}, |
45 | 0402f767 | pbrook | }; |
46 | 0402f767 | pbrook | |
47 | 0402f767 | pbrook | static void m68k_set_feature(CPUM68KState *env, int feature) |
48 | 0402f767 | pbrook | { |
49 | 0402f767 | pbrook | env->features |= (1u << feature);
|
50 | 0402f767 | pbrook | } |
51 | 0402f767 | pbrook | |
52 | 0402f767 | pbrook | int cpu_m68k_set_model(CPUM68KState *env, const char * name) |
53 | 0402f767 | pbrook | { |
54 | 0402f767 | pbrook | m68k_def_t *def; |
55 | 0402f767 | pbrook | |
56 | 0402f767 | pbrook | for (def = m68k_cpu_defs; def->name; def++) {
|
57 | 0402f767 | pbrook | if (strcmp(def->name, name) == 0) |
58 | 0402f767 | pbrook | break;
|
59 | 0402f767 | pbrook | } |
60 | 0402f767 | pbrook | if (!def->name)
|
61 | 0402f767 | pbrook | return 1; |
62 | 0402f767 | pbrook | |
63 | 0402f767 | pbrook | switch (def->id) {
|
64 | 0402f767 | pbrook | case M68K_CPUID_M5206:
|
65 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); |
66 | 0402f767 | pbrook | break;
|
67 | 0402f767 | pbrook | case M68K_CPUID_CFV4E:
|
68 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); |
69 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); |
70 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); |
71 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_FPU); |
72 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_MAC); |
73 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_EMAC); |
74 | 0402f767 | pbrook | break;
|
75 | 0402f767 | pbrook | case M68K_CPUID_ANY:
|
76 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); |
77 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); |
78 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); |
79 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_FPU); |
80 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_MAC); |
81 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_EMAC); |
82 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_EXT_FULL); |
83 | 0402f767 | pbrook | break;
|
84 | 0402f767 | pbrook | } |
85 | 0402f767 | pbrook | |
86 | 0402f767 | pbrook | register_m68k_insns(env); |
87 | 0402f767 | pbrook | |
88 | 0402f767 | pbrook | return 0; |
89 | 0402f767 | pbrook | } |
90 | 0402f767 | pbrook | |
91 | e6e5906b | pbrook | void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) |
92 | e6e5906b | pbrook | { |
93 | e6e5906b | pbrook | int flags;
|
94 | e6e5906b | pbrook | uint32_t src; |
95 | e6e5906b | pbrook | uint32_t dest; |
96 | e6e5906b | pbrook | uint32_t tmp; |
97 | e6e5906b | pbrook | |
98 | e6e5906b | pbrook | #define HIGHBIT 0x80000000u |
99 | e6e5906b | pbrook | |
100 | e6e5906b | pbrook | #define SET_NZ(x) do { \ |
101 | e6e5906b | pbrook | if ((x) == 0) \ |
102 | e6e5906b | pbrook | flags |= CCF_Z; \ |
103 | e6e5906b | pbrook | else if ((int32_t)(x) < 0) \ |
104 | e6e5906b | pbrook | flags |= CCF_N; \ |
105 | e6e5906b | pbrook | } while (0) |
106 | e6e5906b | pbrook | |
107 | e6e5906b | pbrook | #define SET_FLAGS_SUB(type, utype) do { \ |
108 | e6e5906b | pbrook | SET_NZ((type)dest); \ |
109 | e6e5906b | pbrook | tmp = dest + src; \ |
110 | e6e5906b | pbrook | if ((utype) tmp < (utype) src) \
|
111 | e6e5906b | pbrook | flags |= CCF_C; \ |
112 | e6e5906b | pbrook | if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \ |
113 | e6e5906b | pbrook | flags |= CCF_V; \ |
114 | e6e5906b | pbrook | } while (0) |
115 | e6e5906b | pbrook | |
116 | e6e5906b | pbrook | flags = 0;
|
117 | e6e5906b | pbrook | src = env->cc_src; |
118 | e6e5906b | pbrook | dest = env->cc_dest; |
119 | e6e5906b | pbrook | switch (cc_op) {
|
120 | e6e5906b | pbrook | case CC_OP_FLAGS:
|
121 | e6e5906b | pbrook | flags = dest; |
122 | e6e5906b | pbrook | break;
|
123 | e6e5906b | pbrook | case CC_OP_LOGIC:
|
124 | e6e5906b | pbrook | SET_NZ(dest); |
125 | e6e5906b | pbrook | break;
|
126 | e6e5906b | pbrook | case CC_OP_ADD:
|
127 | e6e5906b | pbrook | SET_NZ(dest); |
128 | e6e5906b | pbrook | if (dest < src)
|
129 | e6e5906b | pbrook | flags |= CCF_C; |
130 | e6e5906b | pbrook | tmp = dest - src; |
131 | e6e5906b | pbrook | if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
|
132 | e6e5906b | pbrook | flags |= CCF_V; |
133 | e6e5906b | pbrook | break;
|
134 | e6e5906b | pbrook | case CC_OP_SUB:
|
135 | e6e5906b | pbrook | SET_FLAGS_SUB(int32_t, uint32_t); |
136 | e6e5906b | pbrook | break;
|
137 | e6e5906b | pbrook | case CC_OP_CMPB:
|
138 | e6e5906b | pbrook | SET_FLAGS_SUB(int8_t, uint8_t); |
139 | e6e5906b | pbrook | break;
|
140 | e6e5906b | pbrook | case CC_OP_CMPW:
|
141 | e6e5906b | pbrook | SET_FLAGS_SUB(int16_t, uint16_t); |
142 | e6e5906b | pbrook | break;
|
143 | e6e5906b | pbrook | case CC_OP_ADDX:
|
144 | e6e5906b | pbrook | SET_NZ(dest); |
145 | e6e5906b | pbrook | if (dest <= src)
|
146 | e6e5906b | pbrook | flags |= CCF_C; |
147 | e6e5906b | pbrook | tmp = dest - src - 1;
|
148 | e6e5906b | pbrook | if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
|
149 | e6e5906b | pbrook | flags |= CCF_V; |
150 | e6e5906b | pbrook | break;
|
151 | e6e5906b | pbrook | case CC_OP_SUBX:
|
152 | e6e5906b | pbrook | SET_NZ(dest); |
153 | e6e5906b | pbrook | tmp = dest + src + 1;
|
154 | e6e5906b | pbrook | if (tmp <= src)
|
155 | e6e5906b | pbrook | flags |= CCF_C; |
156 | e6e5906b | pbrook | if (HIGHBIT & (tmp ^ dest) & (tmp ^ src))
|
157 | e6e5906b | pbrook | flags |= CCF_V; |
158 | e6e5906b | pbrook | break;
|
159 | e6e5906b | pbrook | case CC_OP_SHL:
|
160 | e6e5906b | pbrook | if (src >= 32) { |
161 | e6e5906b | pbrook | SET_NZ(0);
|
162 | e6e5906b | pbrook | } else {
|
163 | e6e5906b | pbrook | tmp = dest << src; |
164 | e6e5906b | pbrook | SET_NZ(tmp); |
165 | e6e5906b | pbrook | } |
166 | e6e5906b | pbrook | if (src && src <= 32 && (dest & (1 << (32 - src)))) |
167 | e6e5906b | pbrook | flags |= CCF_C; |
168 | e6e5906b | pbrook | break;
|
169 | e6e5906b | pbrook | case CC_OP_SHR:
|
170 | e6e5906b | pbrook | if (src >= 32) { |
171 | e6e5906b | pbrook | SET_NZ(0);
|
172 | e6e5906b | pbrook | } else {
|
173 | e6e5906b | pbrook | tmp = dest >> src; |
174 | e6e5906b | pbrook | SET_NZ(tmp); |
175 | e6e5906b | pbrook | } |
176 | e6e5906b | pbrook | if (src && src <= 32 && ((dest >> (src - 1)) & 1)) |
177 | e6e5906b | pbrook | flags |= CCF_C; |
178 | e6e5906b | pbrook | break;
|
179 | e6e5906b | pbrook | case CC_OP_SAR:
|
180 | e6e5906b | pbrook | if (src >= 32) { |
181 | e6e5906b | pbrook | SET_NZ(-1);
|
182 | e6e5906b | pbrook | } else {
|
183 | e6e5906b | pbrook | tmp = (int32_t)dest >> src; |
184 | e6e5906b | pbrook | SET_NZ(tmp); |
185 | e6e5906b | pbrook | } |
186 | e6e5906b | pbrook | if (src && src <= 32 && (((int32_t)dest >> (src - 1)) & 1)) |
187 | e6e5906b | pbrook | flags |= CCF_C; |
188 | e6e5906b | pbrook | break;
|
189 | e6e5906b | pbrook | default:
|
190 | e6e5906b | pbrook | cpu_abort(env, "Bad CC_OP %d", cc_op);
|
191 | e6e5906b | pbrook | } |
192 | e6e5906b | pbrook | env->cc_op = CC_OP_FLAGS; |
193 | e6e5906b | pbrook | env->cc_dest = flags; |
194 | e6e5906b | pbrook | } |
195 | e6e5906b | pbrook | |
196 | e6e5906b | pbrook | float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1) |
197 | e6e5906b | pbrook | { |
198 | e6e5906b | pbrook | /* ??? This may incorrectly raise exceptions. */
|
199 | e6e5906b | pbrook | /* ??? Should flush denormals to zero. */
|
200 | e6e5906b | pbrook | float64 res; |
201 | e6e5906b | pbrook | res = float64_sub(src0, src1, &env->fp_status); |
202 | e6e5906b | pbrook | if (float64_is_nan(res)) {
|
203 | e6e5906b | pbrook | /* +/-inf compares equal against itself, but sub returns nan. */
|
204 | e6e5906b | pbrook | if (!float64_is_nan(src0)
|
205 | e6e5906b | pbrook | && !float64_is_nan(src1)) { |
206 | e6e5906b | pbrook | res = 0;
|
207 | e6e5906b | pbrook | if (float64_lt_quiet(src0, res, &env->fp_status))
|
208 | e6e5906b | pbrook | res = float64_chs(res); |
209 | e6e5906b | pbrook | } |
210 | e6e5906b | pbrook | } |
211 | e6e5906b | pbrook | return res;
|
212 | e6e5906b | pbrook | } |
213 | 0633879f | pbrook | |
214 | 0633879f | pbrook | void helper_movec(CPUM68KState *env, int reg, uint32_t val) |
215 | 0633879f | pbrook | { |
216 | 0633879f | pbrook | switch (reg) {
|
217 | 0633879f | pbrook | case 0x02: /* CACR */ |
218 | 0633879f | pbrook | /* Ignored. */
|
219 | 0633879f | pbrook | break;
|
220 | 0633879f | pbrook | case 0x801: /* VBR */ |
221 | 0633879f | pbrook | env->vbr = val; |
222 | 0633879f | pbrook | break;
|
223 | 0633879f | pbrook | /* TODO: Implement control registers. */
|
224 | 0633879f | pbrook | default:
|
225 | 0633879f | pbrook | cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n",
|
226 | 0633879f | pbrook | reg, val); |
227 | 0633879f | pbrook | } |
228 | 0633879f | pbrook | } |
229 | 0633879f | pbrook | |
230 | 0633879f | pbrook | /* MMU */
|
231 | 0633879f | pbrook | |
232 | 0633879f | pbrook | /* TODO: This will need fixing once the MMU is implemented. */
|
233 | 0633879f | pbrook | target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
234 | 0633879f | pbrook | { |
235 | 0633879f | pbrook | return addr;
|
236 | 0633879f | pbrook | } |
237 | 0633879f | pbrook | |
238 | 0633879f | pbrook | #if defined(CONFIG_USER_ONLY)
|
239 | 0633879f | pbrook | |
240 | 0633879f | pbrook | int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
241 | 0633879f | pbrook | int is_user, int is_softmmu) |
242 | 0633879f | pbrook | { |
243 | 0633879f | pbrook | env->exception_index = EXCP_ACCESS; |
244 | 0633879f | pbrook | env->mmu.ar = address; |
245 | 0633879f | pbrook | return 1; |
246 | 0633879f | pbrook | } |
247 | 0633879f | pbrook | |
248 | 0633879f | pbrook | #else
|
249 | 0633879f | pbrook | |
250 | 0633879f | pbrook | int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
251 | 0633879f | pbrook | int is_user, int is_softmmu) |
252 | 0633879f | pbrook | { |
253 | 0633879f | pbrook | int prot;
|
254 | 0633879f | pbrook | |
255 | 0633879f | pbrook | address &= TARGET_PAGE_MASK; |
256 | 0633879f | pbrook | prot = PAGE_READ | PAGE_WRITE; |
257 | 0633879f | pbrook | return tlb_set_page(env, address, address, prot, is_user, is_softmmu);
|
258 | 0633879f | pbrook | } |
259 | 0633879f | pbrook | |
260 | 0633879f | pbrook | /* Notify CPU of a pending interrupt. Prioritization and vectoring should
|
261 | 0633879f | pbrook | be handled by the interrupt controller. Real hardware only requests
|
262 | 0633879f | pbrook | the vector when the interrupt is acknowledged by the CPU. For
|
263 | 0633879f | pbrook | simplicitly we calculate it when the interrupt is signalled. */
|
264 | 0633879f | pbrook | void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector) |
265 | 0633879f | pbrook | { |
266 | 0633879f | pbrook | env->pending_level = level; |
267 | 0633879f | pbrook | env->pending_vector = vector; |
268 | 0633879f | pbrook | if (level)
|
269 | 0633879f | pbrook | cpu_interrupt(env, CPU_INTERRUPT_HARD); |
270 | 0633879f | pbrook | else
|
271 | 0633879f | pbrook | cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); |
272 | 0633879f | pbrook | } |
273 | 0633879f | pbrook | |
274 | 0633879f | pbrook | #endif |