target-alpha: Implement do_interrupt for system mode.
[qemu/kevin.git] / target-alpha / helper.c
blob6f890cde4059c7888cdf8d5532ce43fe9dd163aa
1 /*
2 * Alpha emulation cpu helpers for qemu.
4 * Copyright (c) 2007 Jocelyn Mayer
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <stdio.h>
24 #include "cpu.h"
25 #include "exec-all.h"
26 #include "softfloat.h"
28 uint64_t cpu_alpha_load_fpcr (CPUState *env)
30 uint64_t r = 0;
31 uint8_t t;
33 t = env->fpcr_exc_status;
34 if (t) {
35 r = FPCR_SUM;
36 if (t & float_flag_invalid) {
37 r |= FPCR_INV;
39 if (t & float_flag_divbyzero) {
40 r |= FPCR_DZE;
42 if (t & float_flag_overflow) {
43 r |= FPCR_OVF;
45 if (t & float_flag_underflow) {
46 r |= FPCR_UNF;
48 if (t & float_flag_inexact) {
49 r |= FPCR_INE;
53 t = env->fpcr_exc_mask;
54 if (t & float_flag_invalid) {
55 r |= FPCR_INVD;
57 if (t & float_flag_divbyzero) {
58 r |= FPCR_DZED;
60 if (t & float_flag_overflow) {
61 r |= FPCR_OVFD;
63 if (t & float_flag_underflow) {
64 r |= FPCR_UNFD;
66 if (t & float_flag_inexact) {
67 r |= FPCR_INED;
70 switch (env->fpcr_dyn_round) {
71 case float_round_nearest_even:
72 r |= FPCR_DYN_NORMAL;
73 break;
74 case float_round_down:
75 r |= FPCR_DYN_MINUS;
76 break;
77 case float_round_up:
78 r |= FPCR_DYN_PLUS;
79 break;
80 case float_round_to_zero:
81 r |= FPCR_DYN_CHOPPED;
82 break;
85 if (env->fpcr_dnz) {
86 r |= FPCR_DNZ;
88 if (env->fpcr_dnod) {
89 r |= FPCR_DNOD;
91 if (env->fpcr_undz) {
92 r |= FPCR_UNDZ;
95 return r;
98 void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
100 uint8_t t;
102 t = 0;
103 if (val & FPCR_INV) {
104 t |= float_flag_invalid;
106 if (val & FPCR_DZE) {
107 t |= float_flag_divbyzero;
109 if (val & FPCR_OVF) {
110 t |= float_flag_overflow;
112 if (val & FPCR_UNF) {
113 t |= float_flag_underflow;
115 if (val & FPCR_INE) {
116 t |= float_flag_inexact;
118 env->fpcr_exc_status = t;
120 t = 0;
121 if (val & FPCR_INVD) {
122 t |= float_flag_invalid;
124 if (val & FPCR_DZED) {
125 t |= float_flag_divbyzero;
127 if (val & FPCR_OVFD) {
128 t |= float_flag_overflow;
130 if (val & FPCR_UNFD) {
131 t |= float_flag_underflow;
133 if (val & FPCR_INED) {
134 t |= float_flag_inexact;
136 env->fpcr_exc_mask = t;
138 switch (val & FPCR_DYN_MASK) {
139 case FPCR_DYN_CHOPPED:
140 t = float_round_to_zero;
141 break;
142 case FPCR_DYN_MINUS:
143 t = float_round_down;
144 break;
145 case FPCR_DYN_NORMAL:
146 t = float_round_nearest_even;
147 break;
148 case FPCR_DYN_PLUS:
149 t = float_round_up;
150 break;
152 env->fpcr_dyn_round = t;
154 env->fpcr_flush_to_zero
155 = (val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD);
157 env->fpcr_dnz = (val & FPCR_DNZ) != 0;
158 env->fpcr_dnod = (val & FPCR_DNOD) != 0;
159 env->fpcr_undz = (val & FPCR_UNDZ) != 0;
162 #if defined(CONFIG_USER_ONLY)
163 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
164 int mmu_idx, int is_softmmu)
166 env->exception_index = EXCP_MMFAULT;
167 env->trap_arg0 = address;
168 return 1;
170 #else
171 target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
173 return -1;
176 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
177 int mmu_idx, int is_softmmu)
179 return 0;
181 #endif /* USER_ONLY */
183 void do_interrupt (CPUState *env)
185 int i = env->exception_index;
187 if (qemu_loglevel_mask(CPU_LOG_INT)) {
188 static int count;
189 const char *name = "<unknown>";
191 switch (i) {
192 case EXCP_RESET:
193 name = "reset";
194 break;
195 case EXCP_MCHK:
196 name = "mchk";
197 break;
198 case EXCP_SMP_INTERRUPT:
199 name = "smp_interrupt";
200 break;
201 case EXCP_CLK_INTERRUPT:
202 name = "clk_interrupt";
203 break;
204 case EXCP_DEV_INTERRUPT:
205 name = "dev_interrupt";
206 break;
207 case EXCP_MMFAULT:
208 name = "mmfault";
209 break;
210 case EXCP_UNALIGN:
211 name = "unalign";
212 break;
213 case EXCP_OPCDEC:
214 name = "opcdec";
215 break;
216 case EXCP_ARITH:
217 name = "arith";
218 break;
219 case EXCP_FEN:
220 name = "fen";
221 break;
222 case EXCP_CALL_PAL:
223 name = "call_pal";
224 break;
225 case EXCP_STL_C:
226 name = "stl_c";
227 break;
228 case EXCP_STQ_C:
229 name = "stq_c";
230 break;
232 qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
233 ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
236 env->exception_index = -1;
238 #if !defined(CONFIG_USER_ONLY)
239 switch (i) {
240 case EXCP_RESET:
241 i = 0x0000;
242 break;
243 case EXCP_MCHK:
244 i = 0x0080;
245 break;
246 case EXCP_SMP_INTERRUPT:
247 i = 0x0100;
248 break;
249 case EXCP_CLK_INTERRUPT:
250 i = 0x0180;
251 break;
252 case EXCP_DEV_INTERRUPT:
253 i = 0x0200;
254 break;
255 case EXCP_MMFAULT:
256 i = 0x0280;
257 break;
258 case EXCP_UNALIGN:
259 i = 0x0300;
260 break;
261 case EXCP_OPCDEC:
262 i = 0x0380;
263 break;
264 case EXCP_ARITH:
265 i = 0x0400;
266 break;
267 case EXCP_FEN:
268 i = 0x0480;
269 break;
270 case EXCP_CALL_PAL:
271 i = env->error_code;
272 /* There are 64 entry points for both privileged and unprivileged,
273 with bit 0x80 indicating unprivileged. Each entry point gets
274 64 bytes to do its job. */
275 if (i & 0x80) {
276 i = 0x2000 + (i - 0x80) * 64;
277 } else {
278 i = 0x1000 + i * 64;
280 break;
281 default:
282 cpu_abort(env, "Unhandled CPU exception");
285 /* Remember where the exception happened. Emulate real hardware in
286 that the low bit of the PC indicates PALmode. */
287 env->exc_addr = env->pc | env->pal_mode;
289 /* Continue execution at the PALcode entry point. */
290 env->pc = env->palbr + i;
292 /* Switch to PALmode. */
293 env->pal_mode = 1;
294 #endif /* !USER_ONLY */
297 void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
298 int flags)
300 static const char *linux_reg_names[] = {
301 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
302 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
303 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
304 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
306 int i;
308 cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n",
309 env->pc, env->ps);
310 for (i = 0; i < 31; i++) {
311 cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
312 linux_reg_names[i], env->ir[i]);
313 if ((i % 3) == 2)
314 cpu_fprintf(f, "\n");
317 cpu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n",
318 env->lock_addr, env->lock_value);
320 for (i = 0; i < 31; i++) {
321 cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
322 *((uint64_t *)(&env->fir[i])));
323 if ((i % 3) == 2)
324 cpu_fprintf(f, "\n");
326 cpu_fprintf(f, "\n");