|
1 /* |
|
2 * Alpha emulation cpu helpers for qemu. |
|
3 * |
|
4 * Copyright (c) 2007 Jocelyn Mayer |
|
5 * |
|
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. |
|
10 * |
|
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. |
|
15 * |
|
16 * You should have received a copy of the GNU Lesser General Public |
|
17 * License along with this library; if not, write to the Free Software |
|
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
19 */ |
|
20 |
|
21 #include <stdint.h> |
|
22 #include <stdlib.h> |
|
23 #include <stdio.h> |
|
24 |
|
25 #include "cpu.h" |
|
26 #include "exec-all.h" |
|
27 |
|
28 #if defined(CONFIG_USER_ONLY) |
|
29 |
|
30 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
|
31 int mmu_idx, int is_softmmu) |
|
32 { |
|
33 if (rw == 2) |
|
34 env->exception_index = EXCP_ITB_MISS; |
|
35 else |
|
36 env->exception_index = EXCP_DFAULT; |
|
37 env->ipr[IPR_EXC_ADDR] = address; |
|
38 |
|
39 return 1; |
|
40 } |
|
41 |
|
42 target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr) |
|
43 { |
|
44 return addr; |
|
45 } |
|
46 |
|
47 void do_interrupt (CPUState *env) |
|
48 { |
|
49 env->exception_index = -1; |
|
50 } |
|
51 |
|
52 #else |
|
53 |
|
54 target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr) |
|
55 { |
|
56 return -1; |
|
57 } |
|
58 |
|
59 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
|
60 int mmu_idx, int is_softmmu) |
|
61 { |
|
62 uint32_t opc; |
|
63 |
|
64 if (rw == 2) { |
|
65 /* Instruction translation buffer miss */ |
|
66 env->exception_index = EXCP_ITB_MISS; |
|
67 } else { |
|
68 if (env->ipr[IPR_EXC_ADDR] & 1) |
|
69 env->exception_index = EXCP_DTB_MISS_PAL; |
|
70 else |
|
71 env->exception_index = EXCP_DTB_MISS_NATIVE; |
|
72 opc = (ldl_code(env->pc) >> 21) << 4; |
|
73 if (rw) { |
|
74 opc |= 0x9; |
|
75 } else { |
|
76 opc |= 0x4; |
|
77 } |
|
78 env->ipr[IPR_MM_STAT] = opc; |
|
79 } |
|
80 |
|
81 return 1; |
|
82 } |
|
83 |
|
84 int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp) |
|
85 { |
|
86 uint64_t hwpcb; |
|
87 int ret = 0; |
|
88 |
|
89 hwpcb = env->ipr[IPR_PCBB]; |
|
90 switch (iprn) { |
|
91 case IPR_ASN: |
|
92 if (env->features & FEATURE_ASN) |
|
93 *valp = env->ipr[IPR_ASN]; |
|
94 else |
|
95 *valp = 0; |
|
96 break; |
|
97 case IPR_ASTEN: |
|
98 *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60; |
|
99 break; |
|
100 case IPR_ASTSR: |
|
101 *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60; |
|
102 break; |
|
103 case IPR_DATFX: |
|
104 /* Write only */ |
|
105 ret = -1; |
|
106 break; |
|
107 case IPR_ESP: |
|
108 if (env->features & FEATURE_SPS) |
|
109 *valp = env->ipr[IPR_ESP]; |
|
110 else |
|
111 *valp = ldq_raw(hwpcb + 8); |
|
112 break; |
|
113 case IPR_FEN: |
|
114 *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63; |
|
115 break; |
|
116 case IPR_IPIR: |
|
117 /* Write-only */ |
|
118 ret = -1; |
|
119 break; |
|
120 case IPR_IPL: |
|
121 *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59; |
|
122 break; |
|
123 case IPR_KSP: |
|
124 if (!(env->ipr[IPR_EXC_ADDR] & 1)) { |
|
125 ret = -1; |
|
126 } else { |
|
127 if (env->features & FEATURE_SPS) |
|
128 *valp = env->ipr[IPR_KSP]; |
|
129 else |
|
130 *valp = ldq_raw(hwpcb + 0); |
|
131 } |
|
132 break; |
|
133 case IPR_MCES: |
|
134 *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59; |
|
135 break; |
|
136 case IPR_PERFMON: |
|
137 /* Implementation specific */ |
|
138 *valp = 0; |
|
139 break; |
|
140 case IPR_PCBB: |
|
141 *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16; |
|
142 break; |
|
143 case IPR_PRBR: |
|
144 *valp = env->ipr[IPR_PRBR]; |
|
145 break; |
|
146 case IPR_PTBR: |
|
147 *valp = env->ipr[IPR_PTBR]; |
|
148 break; |
|
149 case IPR_SCBB: |
|
150 *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]); |
|
151 break; |
|
152 case IPR_SIRR: |
|
153 /* Write-only */ |
|
154 ret = -1; |
|
155 break; |
|
156 case IPR_SISR: |
|
157 *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]); |
|
158 case IPR_SSP: |
|
159 if (env->features & FEATURE_SPS) |
|
160 *valp = env->ipr[IPR_SSP]; |
|
161 else |
|
162 *valp = ldq_raw(hwpcb + 16); |
|
163 break; |
|
164 case IPR_SYSPTBR: |
|
165 if (env->features & FEATURE_VIRBND) |
|
166 *valp = env->ipr[IPR_SYSPTBR]; |
|
167 else |
|
168 ret = -1; |
|
169 break; |
|
170 case IPR_TBCHK: |
|
171 if ((env->features & FEATURE_TBCHK)) { |
|
172 /* XXX: TODO */ |
|
173 *valp = 0; |
|
174 ret = -1; |
|
175 } else { |
|
176 ret = -1; |
|
177 } |
|
178 break; |
|
179 case IPR_TBIA: |
|
180 /* Write-only */ |
|
181 ret = -1; |
|
182 break; |
|
183 case IPR_TBIAP: |
|
184 /* Write-only */ |
|
185 ret = -1; |
|
186 break; |
|
187 case IPR_TBIS: |
|
188 /* Write-only */ |
|
189 ret = -1; |
|
190 break; |
|
191 case IPR_TBISD: |
|
192 /* Write-only */ |
|
193 ret = -1; |
|
194 break; |
|
195 case IPR_TBISI: |
|
196 /* Write-only */ |
|
197 ret = -1; |
|
198 break; |
|
199 case IPR_USP: |
|
200 if (env->features & FEATURE_SPS) |
|
201 *valp = env->ipr[IPR_USP]; |
|
202 else |
|
203 *valp = ldq_raw(hwpcb + 24); |
|
204 break; |
|
205 case IPR_VIRBND: |
|
206 if (env->features & FEATURE_VIRBND) |
|
207 *valp = env->ipr[IPR_VIRBND]; |
|
208 else |
|
209 ret = -1; |
|
210 break; |
|
211 case IPR_VPTB: |
|
212 *valp = env->ipr[IPR_VPTB]; |
|
213 break; |
|
214 case IPR_WHAMI: |
|
215 *valp = env->ipr[IPR_WHAMI]; |
|
216 break; |
|
217 default: |
|
218 /* Invalid */ |
|
219 ret = -1; |
|
220 break; |
|
221 } |
|
222 |
|
223 return ret; |
|
224 } |
|
225 |
|
226 int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp) |
|
227 { |
|
228 uint64_t hwpcb, tmp64; |
|
229 uint8_t tmp8; |
|
230 int ret = 0; |
|
231 |
|
232 hwpcb = env->ipr[IPR_PCBB]; |
|
233 switch (iprn) { |
|
234 case IPR_ASN: |
|
235 /* Read-only */ |
|
236 ret = -1; |
|
237 break; |
|
238 case IPR_ASTEN: |
|
239 tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4; |
|
240 *oldvalp = tmp8; |
|
241 tmp8 &= val & 0xF; |
|
242 tmp8 |= (val >> 4) & 0xF; |
|
243 env->ipr[IPR_ASTEN] &= ~0xF; |
|
244 env->ipr[IPR_ASTEN] |= tmp8; |
|
245 ret = 1; |
|
246 break; |
|
247 case IPR_ASTSR: |
|
248 tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4; |
|
249 *oldvalp = tmp8; |
|
250 tmp8 &= val & 0xF; |
|
251 tmp8 |= (val >> 4) & 0xF; |
|
252 env->ipr[IPR_ASTSR] &= ~0xF; |
|
253 env->ipr[IPR_ASTSR] |= tmp8; |
|
254 ret = 1; |
|
255 case IPR_DATFX: |
|
256 env->ipr[IPR_DATFX] &= ~0x1; |
|
257 env->ipr[IPR_DATFX] |= val & 1; |
|
258 tmp64 = ldq_raw(hwpcb + 56); |
|
259 tmp64 &= ~0x8000000000000000ULL; |
|
260 tmp64 |= (val & 1) << 63; |
|
261 stq_raw(hwpcb + 56, tmp64); |
|
262 break; |
|
263 case IPR_ESP: |
|
264 if (env->features & FEATURE_SPS) |
|
265 env->ipr[IPR_ESP] = val; |
|
266 else |
|
267 stq_raw(hwpcb + 8, val); |
|
268 break; |
|
269 case IPR_FEN: |
|
270 env->ipr[IPR_FEN] = val & 1; |
|
271 tmp64 = ldq_raw(hwpcb + 56); |
|
272 tmp64 &= ~1; |
|
273 tmp64 |= val & 1; |
|
274 stq_raw(hwpcb + 56, tmp64); |
|
275 break; |
|
276 case IPR_IPIR: |
|
277 /* XXX: TODO: Send IRQ to CPU #ir[16] */ |
|
278 break; |
|
279 case IPR_IPL: |
|
280 *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59; |
|
281 env->ipr[IPR_IPL] &= ~0x1F; |
|
282 env->ipr[IPR_IPL] |= val & 0x1F; |
|
283 /* XXX: may issue an interrupt or ASR _now_ */ |
|
284 ret = 1; |
|
285 break; |
|
286 case IPR_KSP: |
|
287 if (!(env->ipr[IPR_EXC_ADDR] & 1)) { |
|
288 ret = -1; |
|
289 } else { |
|
290 if (env->features & FEATURE_SPS) |
|
291 env->ipr[IPR_KSP] = val; |
|
292 else |
|
293 stq_raw(hwpcb + 0, val); |
|
294 } |
|
295 break; |
|
296 case IPR_MCES: |
|
297 env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18); |
|
298 env->ipr[IPR_MCES] |= val & 0x18; |
|
299 break; |
|
300 case IPR_PERFMON: |
|
301 /* Implementation specific */ |
|
302 *oldvalp = 0; |
|
303 ret = 1; |
|
304 break; |
|
305 case IPR_PCBB: |
|
306 /* Read-only */ |
|
307 ret = -1; |
|
308 break; |
|
309 case IPR_PRBR: |
|
310 env->ipr[IPR_PRBR] = val; |
|
311 break; |
|
312 case IPR_PTBR: |
|
313 /* Read-only */ |
|
314 ret = -1; |
|
315 break; |
|
316 case IPR_SCBB: |
|
317 env->ipr[IPR_SCBB] = (uint32_t)val; |
|
318 break; |
|
319 case IPR_SIRR: |
|
320 if (val & 0xF) { |
|
321 env->ipr[IPR_SISR] |= 1 << (val & 0xF); |
|
322 /* XXX: request a software interrupt _now_ */ |
|
323 } |
|
324 break; |
|
325 case IPR_SISR: |
|
326 /* Read-only */ |
|
327 ret = -1; |
|
328 break; |
|
329 case IPR_SSP: |
|
330 if (env->features & FEATURE_SPS) |
|
331 env->ipr[IPR_SSP] = val; |
|
332 else |
|
333 stq_raw(hwpcb + 16, val); |
|
334 break; |
|
335 case IPR_SYSPTBR: |
|
336 if (env->features & FEATURE_VIRBND) |
|
337 env->ipr[IPR_SYSPTBR] = val; |
|
338 else |
|
339 ret = -1; |
|
340 case IPR_TBCHK: |
|
341 /* Read-only */ |
|
342 ret = -1; |
|
343 break; |
|
344 case IPR_TBIA: |
|
345 tlb_flush(env, 1); |
|
346 break; |
|
347 case IPR_TBIAP: |
|
348 tlb_flush(env, 1); |
|
349 break; |
|
350 case IPR_TBIS: |
|
351 tlb_flush_page(env, val); |
|
352 break; |
|
353 case IPR_TBISD: |
|
354 tlb_flush_page(env, val); |
|
355 break; |
|
356 case IPR_TBISI: |
|
357 tlb_flush_page(env, val); |
|
358 break; |
|
359 case IPR_USP: |
|
360 if (env->features & FEATURE_SPS) |
|
361 env->ipr[IPR_USP] = val; |
|
362 else |
|
363 stq_raw(hwpcb + 24, val); |
|
364 break; |
|
365 case IPR_VIRBND: |
|
366 if (env->features & FEATURE_VIRBND) |
|
367 env->ipr[IPR_VIRBND] = val; |
|
368 else |
|
369 ret = -1; |
|
370 break; |
|
371 case IPR_VPTB: |
|
372 env->ipr[IPR_VPTB] = val; |
|
373 break; |
|
374 case IPR_WHAMI: |
|
375 /* Read-only */ |
|
376 ret = -1; |
|
377 break; |
|
378 default: |
|
379 /* Invalid */ |
|
380 ret = -1; |
|
381 break; |
|
382 } |
|
383 |
|
384 return ret; |
|
385 } |
|
386 |
|
387 void do_interrupt (CPUState *env) |
|
388 { |
|
389 int excp; |
|
390 |
|
391 env->ipr[IPR_EXC_ADDR] = env->pc | 1; |
|
392 excp = env->exception_index; |
|
393 env->exception_index = 0; |
|
394 env->error_code = 0; |
|
395 /* XXX: disable interrupts and memory mapping */ |
|
396 if (env->ipr[IPR_PAL_BASE] != -1ULL) { |
|
397 /* We use native PALcode */ |
|
398 env->pc = env->ipr[IPR_PAL_BASE] + excp; |
|
399 } else { |
|
400 /* We use emulated PALcode */ |
|
401 call_pal(env); |
|
402 /* Emulate REI */ |
|
403 env->pc = env->ipr[IPR_EXC_ADDR] & ~7; |
|
404 env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1; |
|
405 /* XXX: re-enable interrupts and memory mapping */ |
|
406 } |
|
407 } |
|
408 #endif |
|
409 |
|
410 void cpu_dump_state (CPUState *env, FILE *f, |
|
411 int (*cpu_fprintf)(FILE *f, const char *fmt, ...), |
|
412 int flags) |
|
413 { |
|
414 static const char *linux_reg_names[] = { |
|
415 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ", |
|
416 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ", |
|
417 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ", |
|
418 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero", |
|
419 }; |
|
420 int i; |
|
421 |
|
422 cpu_fprintf(f, " PC " TARGET_FMT_lx " PS " TARGET_FMT_lx "\n", |
|
423 env->pc, env->ps); |
|
424 for (i = 0; i < 31; i++) { |
|
425 cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i, |
|
426 linux_reg_names[i], env->ir[i]); |
|
427 if ((i % 3) == 2) |
|
428 cpu_fprintf(f, "\n"); |
|
429 } |
|
430 cpu_fprintf(f, "\n"); |
|
431 for (i = 0; i < 31; i++) { |
|
432 cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i, |
|
433 *((uint64_t *)(&env->fir[i]))); |
|
434 if ((i % 3) == 2) |
|
435 cpu_fprintf(f, "\n"); |
|
436 } |
|
437 cpu_fprintf(f, "\nlock " TARGET_FMT_lx "\n", env->lock); |
|
438 } |