root / target-m68k / helper.c @ ce62e5ba
History | View | Annotate | Download (9.3 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 | 20dcee94 | pbrook | M68K_CPUID_M5208, |
32 | 0402f767 | pbrook | M68K_CPUID_CFV4E, |
33 | 0402f767 | pbrook | M68K_CPUID_ANY, |
34 | 0402f767 | pbrook | }; |
35 | 0402f767 | pbrook | |
36 | 0402f767 | pbrook | struct m68k_def_t {
|
37 | 0402f767 | pbrook | const char * name; |
38 | 0402f767 | pbrook | enum m68k_cpuid id;
|
39 | 0402f767 | pbrook | }; |
40 | 0402f767 | pbrook | |
41 | 0402f767 | pbrook | static m68k_def_t m68k_cpu_defs[] = {
|
42 | 0402f767 | pbrook | {"m5206", M68K_CPUID_M5206},
|
43 | 20dcee94 | pbrook | {"m5208", M68K_CPUID_M5208},
|
44 | 0402f767 | pbrook | {"cfv4e", M68K_CPUID_CFV4E},
|
45 | 0402f767 | pbrook | {"any", M68K_CPUID_ANY},
|
46 | 0402f767 | pbrook | {NULL, 0}, |
47 | 0402f767 | pbrook | }; |
48 | 0402f767 | pbrook | |
49 | 0402f767 | pbrook | static void m68k_set_feature(CPUM68KState *env, int feature) |
50 | 0402f767 | pbrook | { |
51 | 0402f767 | pbrook | env->features |= (1u << feature);
|
52 | 0402f767 | pbrook | } |
53 | 0402f767 | pbrook | |
54 | 0402f767 | pbrook | int cpu_m68k_set_model(CPUM68KState *env, const char * name) |
55 | 0402f767 | pbrook | { |
56 | 0402f767 | pbrook | m68k_def_t *def; |
57 | 0402f767 | pbrook | |
58 | 0402f767 | pbrook | for (def = m68k_cpu_defs; def->name; def++) {
|
59 | 0402f767 | pbrook | if (strcmp(def->name, name) == 0) |
60 | 0402f767 | pbrook | break;
|
61 | 0402f767 | pbrook | } |
62 | 0402f767 | pbrook | if (!def->name)
|
63 | 0402f767 | pbrook | return 1; |
64 | 0402f767 | pbrook | |
65 | 0402f767 | pbrook | switch (def->id) {
|
66 | 0402f767 | pbrook | case M68K_CPUID_M5206:
|
67 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); |
68 | 0402f767 | pbrook | break;
|
69 | 20dcee94 | pbrook | case M68K_CPUID_M5208:
|
70 | 20dcee94 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); |
71 | d315c888 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC); |
72 | d315c888 | pbrook | m68k_set_feature(env, M68K_FEATURE_BRAL); |
73 | 20dcee94 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_EMAC); |
74 | 20dcee94 | pbrook | m68k_set_feature(env, M68K_FEATURE_USP); |
75 | 20dcee94 | pbrook | break;
|
76 | 0402f767 | pbrook | case M68K_CPUID_CFV4E:
|
77 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); |
78 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); |
79 | d315c888 | pbrook | m68k_set_feature(env, M68K_FEATURE_BRAL); |
80 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_FPU); |
81 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_EMAC); |
82 | 20dcee94 | pbrook | m68k_set_feature(env, M68K_FEATURE_USP); |
83 | 0402f767 | pbrook | break;
|
84 | 0402f767 | pbrook | case M68K_CPUID_ANY:
|
85 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); |
86 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); |
87 | d315c888 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC); |
88 | d315c888 | pbrook | m68k_set_feature(env, M68K_FEATURE_BRAL); |
89 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_FPU); |
90 | acf930aa | pbrook | /* MAC and EMAC are mututally exclusive, so pick EMAC.
|
91 | acf930aa | pbrook | It's mostly backwards compatible. */
|
92 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_EMAC); |
93 | d315c888 | pbrook | m68k_set_feature(env, M68K_FEATURE_CF_EMAC_B); |
94 | 20dcee94 | pbrook | m68k_set_feature(env, M68K_FEATURE_USP); |
95 | 0402f767 | pbrook | m68k_set_feature(env, M68K_FEATURE_EXT_FULL); |
96 | d315c888 | pbrook | m68k_set_feature(env, M68K_FEATURE_WORD_INDEX); |
97 | 0402f767 | pbrook | break;
|
98 | 0402f767 | pbrook | } |
99 | 0402f767 | pbrook | |
100 | 0402f767 | pbrook | register_m68k_insns(env); |
101 | 0402f767 | pbrook | |
102 | 0402f767 | pbrook | return 0; |
103 | 0402f767 | pbrook | } |
104 | 0402f767 | pbrook | |
105 | e6e5906b | pbrook | void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) |
106 | e6e5906b | pbrook | { |
107 | e6e5906b | pbrook | int flags;
|
108 | e6e5906b | pbrook | uint32_t src; |
109 | e6e5906b | pbrook | uint32_t dest; |
110 | e6e5906b | pbrook | uint32_t tmp; |
111 | e6e5906b | pbrook | |
112 | e6e5906b | pbrook | #define HIGHBIT 0x80000000u |
113 | e6e5906b | pbrook | |
114 | e6e5906b | pbrook | #define SET_NZ(x) do { \ |
115 | e6e5906b | pbrook | if ((x) == 0) \ |
116 | e6e5906b | pbrook | flags |= CCF_Z; \ |
117 | e6e5906b | pbrook | else if ((int32_t)(x) < 0) \ |
118 | e6e5906b | pbrook | flags |= CCF_N; \ |
119 | e6e5906b | pbrook | } while (0) |
120 | e6e5906b | pbrook | |
121 | e6e5906b | pbrook | #define SET_FLAGS_SUB(type, utype) do { \ |
122 | e6e5906b | pbrook | SET_NZ((type)dest); \ |
123 | e6e5906b | pbrook | tmp = dest + src; \ |
124 | e6e5906b | pbrook | if ((utype) tmp < (utype) src) \
|
125 | e6e5906b | pbrook | flags |= CCF_C; \ |
126 | e6e5906b | pbrook | if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \ |
127 | e6e5906b | pbrook | flags |= CCF_V; \ |
128 | e6e5906b | pbrook | } while (0) |
129 | e6e5906b | pbrook | |
130 | e6e5906b | pbrook | flags = 0;
|
131 | e6e5906b | pbrook | src = env->cc_src; |
132 | e6e5906b | pbrook | dest = env->cc_dest; |
133 | e6e5906b | pbrook | switch (cc_op) {
|
134 | e6e5906b | pbrook | case CC_OP_FLAGS:
|
135 | e6e5906b | pbrook | flags = dest; |
136 | e6e5906b | pbrook | break;
|
137 | e6e5906b | pbrook | case CC_OP_LOGIC:
|
138 | e6e5906b | pbrook | SET_NZ(dest); |
139 | e6e5906b | pbrook | break;
|
140 | e6e5906b | pbrook | case CC_OP_ADD:
|
141 | e6e5906b | pbrook | SET_NZ(dest); |
142 | e6e5906b | pbrook | if (dest < src)
|
143 | e6e5906b | pbrook | flags |= CCF_C; |
144 | e6e5906b | pbrook | tmp = dest - src; |
145 | e6e5906b | pbrook | if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
|
146 | e6e5906b | pbrook | flags |= CCF_V; |
147 | e6e5906b | pbrook | break;
|
148 | e6e5906b | pbrook | case CC_OP_SUB:
|
149 | e6e5906b | pbrook | SET_FLAGS_SUB(int32_t, uint32_t); |
150 | e6e5906b | pbrook | break;
|
151 | e6e5906b | pbrook | case CC_OP_CMPB:
|
152 | e6e5906b | pbrook | SET_FLAGS_SUB(int8_t, uint8_t); |
153 | e6e5906b | pbrook | break;
|
154 | e6e5906b | pbrook | case CC_OP_CMPW:
|
155 | e6e5906b | pbrook | SET_FLAGS_SUB(int16_t, uint16_t); |
156 | e6e5906b | pbrook | break;
|
157 | e6e5906b | pbrook | case CC_OP_ADDX:
|
158 | e6e5906b | pbrook | SET_NZ(dest); |
159 | e6e5906b | pbrook | if (dest <= src)
|
160 | e6e5906b | pbrook | flags |= CCF_C; |
161 | e6e5906b | pbrook | tmp = dest - src - 1;
|
162 | e6e5906b | pbrook | if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
|
163 | e6e5906b | pbrook | flags |= CCF_V; |
164 | e6e5906b | pbrook | break;
|
165 | e6e5906b | pbrook | case CC_OP_SUBX:
|
166 | e6e5906b | pbrook | SET_NZ(dest); |
167 | e6e5906b | pbrook | tmp = dest + src + 1;
|
168 | e6e5906b | pbrook | if (tmp <= src)
|
169 | e6e5906b | pbrook | flags |= CCF_C; |
170 | e6e5906b | pbrook | if (HIGHBIT & (tmp ^ dest) & (tmp ^ src))
|
171 | e6e5906b | pbrook | flags |= CCF_V; |
172 | e6e5906b | pbrook | break;
|
173 | e6e5906b | pbrook | case CC_OP_SHL:
|
174 | e6e5906b | pbrook | if (src >= 32) { |
175 | e6e5906b | pbrook | SET_NZ(0);
|
176 | e6e5906b | pbrook | } else {
|
177 | e6e5906b | pbrook | tmp = dest << src; |
178 | e6e5906b | pbrook | SET_NZ(tmp); |
179 | e6e5906b | pbrook | } |
180 | e6e5906b | pbrook | if (src && src <= 32 && (dest & (1 << (32 - src)))) |
181 | e6e5906b | pbrook | flags |= CCF_C; |
182 | e6e5906b | pbrook | break;
|
183 | e6e5906b | pbrook | case CC_OP_SHR:
|
184 | e6e5906b | pbrook | if (src >= 32) { |
185 | e6e5906b | pbrook | SET_NZ(0);
|
186 | e6e5906b | pbrook | } else {
|
187 | e6e5906b | pbrook | tmp = dest >> src; |
188 | e6e5906b | pbrook | SET_NZ(tmp); |
189 | e6e5906b | pbrook | } |
190 | e6e5906b | pbrook | if (src && src <= 32 && ((dest >> (src - 1)) & 1)) |
191 | e6e5906b | pbrook | flags |= CCF_C; |
192 | e6e5906b | pbrook | break;
|
193 | e6e5906b | pbrook | case CC_OP_SAR:
|
194 | e6e5906b | pbrook | if (src >= 32) { |
195 | e6e5906b | pbrook | SET_NZ(-1);
|
196 | e6e5906b | pbrook | } else {
|
197 | e6e5906b | pbrook | tmp = (int32_t)dest >> src; |
198 | e6e5906b | pbrook | SET_NZ(tmp); |
199 | e6e5906b | pbrook | } |
200 | e6e5906b | pbrook | if (src && src <= 32 && (((int32_t)dest >> (src - 1)) & 1)) |
201 | e6e5906b | pbrook | flags |= CCF_C; |
202 | e6e5906b | pbrook | break;
|
203 | e6e5906b | pbrook | default:
|
204 | e6e5906b | pbrook | cpu_abort(env, "Bad CC_OP %d", cc_op);
|
205 | e6e5906b | pbrook | } |
206 | e6e5906b | pbrook | env->cc_op = CC_OP_FLAGS; |
207 | e6e5906b | pbrook | env->cc_dest = flags; |
208 | e6e5906b | pbrook | } |
209 | e6e5906b | pbrook | |
210 | e6e5906b | pbrook | float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1) |
211 | e6e5906b | pbrook | { |
212 | e6e5906b | pbrook | /* ??? This may incorrectly raise exceptions. */
|
213 | e6e5906b | pbrook | /* ??? Should flush denormals to zero. */
|
214 | e6e5906b | pbrook | float64 res; |
215 | e6e5906b | pbrook | res = float64_sub(src0, src1, &env->fp_status); |
216 | e6e5906b | pbrook | if (float64_is_nan(res)) {
|
217 | e6e5906b | pbrook | /* +/-inf compares equal against itself, but sub returns nan. */
|
218 | e6e5906b | pbrook | if (!float64_is_nan(src0)
|
219 | e6e5906b | pbrook | && !float64_is_nan(src1)) { |
220 | e6e5906b | pbrook | res = 0;
|
221 | e6e5906b | pbrook | if (float64_lt_quiet(src0, res, &env->fp_status))
|
222 | e6e5906b | pbrook | res = float64_chs(res); |
223 | e6e5906b | pbrook | } |
224 | e6e5906b | pbrook | } |
225 | e6e5906b | pbrook | return res;
|
226 | e6e5906b | pbrook | } |
227 | 0633879f | pbrook | |
228 | 0633879f | pbrook | void helper_movec(CPUM68KState *env, int reg, uint32_t val) |
229 | 0633879f | pbrook | { |
230 | 0633879f | pbrook | switch (reg) {
|
231 | 0633879f | pbrook | case 0x02: /* CACR */ |
232 | 20dcee94 | pbrook | env->cacr = val; |
233 | 20dcee94 | pbrook | m68k_switch_sp(env); |
234 | 20dcee94 | pbrook | break;
|
235 | 20dcee94 | pbrook | case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */ |
236 | 20dcee94 | pbrook | /* TODO: Implement Access Control Registers. */
|
237 | 0633879f | pbrook | break;
|
238 | 0633879f | pbrook | case 0x801: /* VBR */ |
239 | 0633879f | pbrook | env->vbr = val; |
240 | 0633879f | pbrook | break;
|
241 | 0633879f | pbrook | /* TODO: Implement control registers. */
|
242 | 0633879f | pbrook | default:
|
243 | 0633879f | pbrook | cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n",
|
244 | 0633879f | pbrook | reg, val); |
245 | 0633879f | pbrook | } |
246 | 0633879f | pbrook | } |
247 | 0633879f | pbrook | |
248 | acf930aa | pbrook | void m68k_set_macsr(CPUM68KState *env, uint32_t val)
|
249 | acf930aa | pbrook | { |
250 | acf930aa | pbrook | uint32_t acc; |
251 | acf930aa | pbrook | int8_t exthigh; |
252 | acf930aa | pbrook | uint8_t extlow; |
253 | acf930aa | pbrook | uint64_t regval; |
254 | acf930aa | pbrook | int i;
|
255 | acf930aa | pbrook | if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
|
256 | acf930aa | pbrook | for (i = 0; i < 4; i++) { |
257 | acf930aa | pbrook | regval = env->macc[i]; |
258 | acf930aa | pbrook | exthigh = regval >> 40;
|
259 | acf930aa | pbrook | if (env->macsr & MACSR_FI) {
|
260 | acf930aa | pbrook | acc = regval >> 8;
|
261 | acf930aa | pbrook | extlow = regval; |
262 | acf930aa | pbrook | } else {
|
263 | acf930aa | pbrook | acc = regval; |
264 | acf930aa | pbrook | extlow = regval >> 32;
|
265 | acf930aa | pbrook | } |
266 | acf930aa | pbrook | if (env->macsr & MACSR_FI) {
|
267 | acf930aa | pbrook | regval = (((uint64_t)acc) << 8) | extlow;
|
268 | acf930aa | pbrook | regval |= ((int64_t)exthigh) << 40;
|
269 | acf930aa | pbrook | } else if (env->macsr & MACSR_SU) { |
270 | acf930aa | pbrook | regval = acc | (((int64_t)extlow) << 32);
|
271 | acf930aa | pbrook | regval |= ((int64_t)exthigh) << 40;
|
272 | acf930aa | pbrook | } else {
|
273 | acf930aa | pbrook | regval = acc | (((uint64_t)extlow) << 32);
|
274 | acf930aa | pbrook | regval |= ((uint64_t)(uint8_t)exthigh) << 40;
|
275 | acf930aa | pbrook | } |
276 | acf930aa | pbrook | env->macc[i] = regval; |
277 | acf930aa | pbrook | } |
278 | acf930aa | pbrook | } |
279 | acf930aa | pbrook | env->macsr = val; |
280 | acf930aa | pbrook | } |
281 | acf930aa | pbrook | |
282 | 20dcee94 | pbrook | void m68k_switch_sp(CPUM68KState *env)
|
283 | 20dcee94 | pbrook | { |
284 | 20dcee94 | pbrook | int new_sp;
|
285 | 20dcee94 | pbrook | |
286 | 20dcee94 | pbrook | env->sp[env->current_sp] = env->aregs[7];
|
287 | 20dcee94 | pbrook | new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP) |
288 | 20dcee94 | pbrook | ? M68K_SSP : M68K_USP; |
289 | 20dcee94 | pbrook | env->aregs[7] = env->sp[new_sp];
|
290 | 20dcee94 | pbrook | env->current_sp = new_sp; |
291 | 20dcee94 | pbrook | } |
292 | 20dcee94 | pbrook | |
293 | 0633879f | pbrook | /* MMU */
|
294 | 0633879f | pbrook | |
295 | 0633879f | pbrook | /* TODO: This will need fixing once the MMU is implemented. */
|
296 | 0633879f | pbrook | target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
297 | 0633879f | pbrook | { |
298 | 0633879f | pbrook | return addr;
|
299 | 0633879f | pbrook | } |
300 | 0633879f | pbrook | |
301 | 0633879f | pbrook | #if defined(CONFIG_USER_ONLY)
|
302 | 0633879f | pbrook | |
303 | 0633879f | pbrook | int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
304 | 0633879f | pbrook | int is_user, int is_softmmu) |
305 | 0633879f | pbrook | { |
306 | 0633879f | pbrook | env->exception_index = EXCP_ACCESS; |
307 | 0633879f | pbrook | env->mmu.ar = address; |
308 | 0633879f | pbrook | return 1; |
309 | 0633879f | pbrook | } |
310 | 0633879f | pbrook | |
311 | 0633879f | pbrook | #else
|
312 | 0633879f | pbrook | |
313 | 0633879f | pbrook | int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
314 | 0633879f | pbrook | int is_user, int is_softmmu) |
315 | 0633879f | pbrook | { |
316 | 0633879f | pbrook | int prot;
|
317 | 0633879f | pbrook | |
318 | 0633879f | pbrook | address &= TARGET_PAGE_MASK; |
319 | 0633879f | pbrook | prot = PAGE_READ | PAGE_WRITE; |
320 | 0633879f | pbrook | return tlb_set_page(env, address, address, prot, is_user, is_softmmu);
|
321 | 0633879f | pbrook | } |
322 | 0633879f | pbrook | |
323 | 0633879f | pbrook | /* Notify CPU of a pending interrupt. Prioritization and vectoring should
|
324 | 0633879f | pbrook | be handled by the interrupt controller. Real hardware only requests
|
325 | 0633879f | pbrook | the vector when the interrupt is acknowledged by the CPU. For
|
326 | 0633879f | pbrook | simplicitly we calculate it when the interrupt is signalled. */
|
327 | 0633879f | pbrook | void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector) |
328 | 0633879f | pbrook | { |
329 | 0633879f | pbrook | env->pending_level = level; |
330 | 0633879f | pbrook | env->pending_vector = vector; |
331 | 0633879f | pbrook | if (level)
|
332 | 0633879f | pbrook | cpu_interrupt(env, CPU_INTERRUPT_HARD); |
333 | 0633879f | pbrook | else
|
334 | 0633879f | pbrook | cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); |
335 | 0633879f | pbrook | } |
336 | 0633879f | pbrook | |
337 | 0633879f | pbrook | #endif |