Revision 1a2fb1c0 target-sparc/op_helper.c
b/target-sparc/op_helper.c | ||
---|---|---|
1 | 1 |
#include "exec.h" |
2 | 2 |
#include "host-utils.h" |
3 |
#include "helper.h" |
|
3 | 4 |
|
4 | 5 |
//#define DEBUG_PCALL |
5 | 6 |
//#define DEBUG_MMU |
... | ... | |
35 | 36 |
cpu_loop_exit(); |
36 | 37 |
} |
37 | 38 |
|
38 |
void check_ieee_exceptions()
|
|
39 |
void helper_trap(target_ulong nb_trap)
|
|
39 | 40 |
{ |
40 |
T0 = get_float_exception_flags(&env->fp_status); |
|
41 |
if (T0) |
|
42 |
{ |
|
41 |
env->exception_index = TT_TRAP + (nb_trap & 0x7f); |
|
42 |
cpu_loop_exit(); |
|
43 |
} |
|
44 |
|
|
45 |
void helper_trapcc(target_ulong nb_trap, target_ulong do_trap) |
|
46 |
{ |
|
47 |
if (do_trap) { |
|
48 |
env->exception_index = TT_TRAP + (nb_trap & 0x7f); |
|
49 |
cpu_loop_exit(); |
|
50 |
} |
|
51 |
} |
|
52 |
|
|
53 |
void check_ieee_exceptions(void) |
|
54 |
{ |
|
55 |
target_ulong status; |
|
56 |
|
|
57 |
status = get_float_exception_flags(&env->fp_status); |
|
58 |
if (status) { |
|
43 | 59 |
/* Copy IEEE 754 flags into FSR */ |
44 |
if (T0 & float_flag_invalid)
|
|
60 |
if (status & float_flag_invalid)
|
|
45 | 61 |
env->fsr |= FSR_NVC; |
46 |
if (T0 & float_flag_overflow)
|
|
62 |
if (status & float_flag_overflow)
|
|
47 | 63 |
env->fsr |= FSR_OFC; |
48 |
if (T0 & float_flag_underflow)
|
|
64 |
if (status & float_flag_underflow)
|
|
49 | 65 |
env->fsr |= FSR_UFC; |
50 |
if (T0 & float_flag_divbyzero)
|
|
66 |
if (status & float_flag_divbyzero)
|
|
51 | 67 |
env->fsr |= FSR_DZC; |
52 |
if (T0 & float_flag_inexact)
|
|
68 |
if (status & float_flag_inexact)
|
|
53 | 69 |
env->fsr |= FSR_NXC; |
54 | 70 |
|
55 |
if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) |
|
56 |
{ |
|
71 |
if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) { |
|
57 | 72 |
/* Unmasked exception, generate a trap */ |
58 | 73 |
env->fsr |= FSR_FTT_IEEE_EXCP; |
59 | 74 |
raise_exception(TT_FP_EXCP); |
60 |
} |
|
61 |
else |
|
62 |
{ |
|
75 |
} else { |
|
63 | 76 |
/* Accumulate exceptions */ |
64 | 77 |
env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5; |
65 | 78 |
} |
66 |
}
|
|
79 |
} |
|
67 | 80 |
} |
68 | 81 |
|
69 | 82 |
#ifdef USE_INT_TO_FLOAT_HELPERS |
... | ... | |
157 | 170 |
#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \ |
158 | 171 |
void glue(do_, name) (void) \ |
159 | 172 |
{ \ |
173 |
target_ulong new_fsr; \ |
|
174 |
\ |
|
160 | 175 |
env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ |
161 | 176 |
switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \ |
162 | 177 |
case float_relation_unordered: \ |
163 |
T0 = (FSR_FCC1 | FSR_FCC0) << FS; \
|
|
178 |
new_fsr = (FSR_FCC1 | FSR_FCC0) << FS; \
|
|
164 | 179 |
if ((env->fsr & FSR_NVM) || TRAP) { \ |
165 |
env->fsr |= T0; \
|
|
180 |
env->fsr |= new_fsr; \
|
|
166 | 181 |
env->fsr |= FSR_NVC; \ |
167 | 182 |
env->fsr |= FSR_FTT_IEEE_EXCP; \ |
168 | 183 |
raise_exception(TT_FP_EXCP); \ |
... | ... | |
171 | 186 |
} \ |
172 | 187 |
break; \ |
173 | 188 |
case float_relation_less: \ |
174 |
T0 = FSR_FCC0 << FS; \
|
|
189 |
new_fsr = FSR_FCC0 << FS; \
|
|
175 | 190 |
break; \ |
176 | 191 |
case float_relation_greater: \ |
177 |
T0 = FSR_FCC1 << FS; \
|
|
192 |
new_fsr = FSR_FCC1 << FS; \
|
|
178 | 193 |
break; \ |
179 | 194 |
default: \ |
180 |
T0 = 0; \
|
|
195 |
new_fsr = 0; \
|
|
181 | 196 |
break; \ |
182 | 197 |
} \ |
183 |
env->fsr |= T0; \
|
|
198 |
env->fsr |= new_fsr; \
|
|
184 | 199 |
} |
185 | 200 |
|
186 | 201 |
GEN_FCMP(fcmps, float32, FT0, FT1, 0, 0); |
... | ... | |
222 | 237 |
#endif |
223 | 238 |
#endif |
224 | 239 |
|
225 |
#ifndef TARGET_SPARC64 |
|
226 |
#ifndef CONFIG_USER_ONLY |
|
227 |
|
|
228 |
#ifdef DEBUG_MXCC |
|
240 |
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && defined(DEBUG_MXCC) |
|
229 | 241 |
static void dump_mxcc(CPUState *env) |
230 | 242 |
{ |
231 | 243 |
printf("mxccdata: %016llx %016llx %016llx %016llx\n", |
... | ... | |
237 | 249 |
} |
238 | 250 |
#endif |
239 | 251 |
|
240 |
#ifdef DEBUG_ASI |
|
241 |
static void dump_asi(const char * txt, uint32_t addr, int asi, int size, |
|
242 |
uint32_t r1, uint32_t r2) |
|
252 |
#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \ |
|
253 |
&& defined(DEBUG_ASI) |
|
254 |
static void dump_asi(const char *txt, target_ulong addr, int asi, int size, |
|
255 |
uint64_t r1) |
|
243 | 256 |
{ |
244 | 257 |
switch (size) |
245 | 258 |
{ |
246 | 259 |
case 1: |
247 |
DPRINTF_ASI("%s %08x asi 0x%02x = %02x\n", txt, addr, asi, r1 & 0xff); |
|
260 |
DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt, |
|
261 |
addr, asi, r1 & 0xff); |
|
248 | 262 |
break; |
249 | 263 |
case 2: |
250 |
DPRINTF_ASI("%s %08x asi 0x%02x = %04x\n", txt, addr, asi, r1 & 0xffff); |
|
264 |
DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt, |
|
265 |
addr, asi, r1 & 0xffff); |
|
251 | 266 |
break; |
252 | 267 |
case 4: |
253 |
DPRINTF_ASI("%s %08x asi 0x%02x = %08x\n", txt, addr, asi, r1); |
|
268 |
DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt, |
|
269 |
addr, asi, r1 & 0xffffffff); |
|
254 | 270 |
break; |
255 | 271 |
case 8: |
256 |
DPRINTF_ASI("%s %08x asi 0x%02x = %016llx\n", txt, addr, asi,
|
|
257 |
r2 | ((uint64_t)r1 << 32));
|
|
272 |
DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt,
|
|
273 |
addr, asi, r1);
|
|
258 | 274 |
break; |
259 | 275 |
} |
260 | 276 |
} |
261 | 277 |
#endif |
262 | 278 |
|
263 |
void helper_ld_asi(int asi, int size, int sign) |
|
279 |
#ifndef TARGET_SPARC64 |
|
280 |
#ifndef CONFIG_USER_ONLY |
|
281 |
uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) |
|
264 | 282 |
{ |
265 |
uint32_t ret = 0; |
|
266 |
uint64_t tmp; |
|
283 |
uint64_t ret = 0; |
|
267 | 284 |
#if defined(DEBUG_MXCC) || defined(DEBUG_ASI) |
268 |
uint32_t last_T0 = T0;
|
|
285 |
uint32_t last_addr = addr;
|
|
269 | 286 |
#endif |
270 | 287 |
|
271 | 288 |
switch (asi) { |
272 | 289 |
case 2: /* SuperSparc MXCC registers */ |
273 |
switch (T0) {
|
|
290 |
switch (addr) {
|
|
274 | 291 |
case 0x01c00a00: /* MXCC control register */ |
275 |
if (size == 8) { |
|
276 |
ret = env->mxccregs[3] >> 32; |
|
277 |
T0 = env->mxccregs[3]; |
|
278 |
} else |
|
279 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); |
|
292 |
if (size == 8) |
|
293 |
ret = env->mxccregs[3]; |
|
294 |
else |
|
295 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, size); |
|
280 | 296 |
break; |
281 | 297 |
case 0x01c00a04: /* MXCC control register */ |
282 | 298 |
if (size == 4) |
283 | 299 |
ret = env->mxccregs[3]; |
284 | 300 |
else |
285 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
|
|
301 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, size);
|
|
286 | 302 |
break; |
287 | 303 |
case 0x01c00c00: /* Module reset register */ |
288 | 304 |
if (size == 8) { |
289 |
ret = env->mxccregs[5] >> 32; |
|
290 |
T0 = env->mxccregs[5]; |
|
305 |
ret = env->mxccregs[5]; |
|
291 | 306 |
// should we do something here? |
292 | 307 |
} else |
293 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
|
|
308 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, size);
|
|
294 | 309 |
break; |
295 | 310 |
case 0x01c00f00: /* MBus port address register */ |
296 |
if (size == 8) { |
|
297 |
ret = env->mxccregs[7] >> 32; |
|
298 |
T0 = env->mxccregs[7]; |
|
299 |
} else |
|
300 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size); |
|
311 |
if (size == 8) |
|
312 |
ret = env->mxccregs[7]; |
|
313 |
else |
|
314 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, size); |
|
301 | 315 |
break; |
302 | 316 |
default: |
303 |
DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", T0, size);
|
|
317 |
DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr, size);
|
|
304 | 318 |
break; |
305 | 319 |
} |
306 |
DPRINTF_MXCC("asi = %d, size = %d, sign = %d, T0 = %08x -> ret = %08x,"
|
|
307 |
"T0 = %08x\n", asi, size, sign, last_T0, ret, T0);
|
|
320 |
DPRINTF_MXCC("asi = %d, size = %d, sign = %d, addr = %08x -> ret = %08x,"
|
|
321 |
"addr = %08x\n", asi, size, sign, last_addr, ret, addr);
|
|
308 | 322 |
#ifdef DEBUG_MXCC |
309 | 323 |
dump_mxcc(env); |
310 | 324 |
#endif |
... | ... | |
313 | 327 |
{ |
314 | 328 |
int mmulev; |
315 | 329 |
|
316 |
mmulev = (T0 >> 8) & 15;
|
|
330 |
mmulev = (addr >> 8) & 15;
|
|
317 | 331 |
if (mmulev > 4) |
318 | 332 |
ret = 0; |
319 |
else { |
|
320 |
ret = mmu_probe(env, T0, mmulev); |
|
321 |
//bswap32s(&ret); |
|
322 |
} |
|
323 |
DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret); |
|
333 |
else |
|
334 |
ret = mmu_probe(env, addr, mmulev); |
|
335 |
DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n", |
|
336 |
addr, mmulev, ret); |
|
324 | 337 |
} |
325 | 338 |
break; |
326 | 339 |
case 4: /* read MMU regs */ |
327 | 340 |
{ |
328 |
int reg = (T0 >> 8) & 0x1f;
|
|
341 |
int reg = (addr >> 8) & 0x1f;
|
|
329 | 342 |
|
330 | 343 |
ret = env->mmuregs[reg]; |
331 | 344 |
if (reg == 3) /* Fault status cleared on read */ |
... | ... | |
334 | 347 |
ret = env->mmuregs[3]; |
335 | 348 |
else if (reg == 0x14) /* Fault address read */ |
336 | 349 |
ret = env->mmuregs[4]; |
337 |
DPRINTF_MMU("mmu_read: reg[%d] = 0x%08x\n", reg, ret);
|
|
350 |
DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret);
|
|
338 | 351 |
} |
339 | 352 |
break; |
340 | 353 |
case 5: // Turbosparc ITLB Diagnostic |
... | ... | |
344 | 357 |
case 9: /* Supervisor code access */ |
345 | 358 |
switch(size) { |
346 | 359 |
case 1: |
347 |
ret = ldub_code(T0);
|
|
360 |
ret = ldub_code(addr);
|
|
348 | 361 |
break; |
349 | 362 |
case 2: |
350 |
ret = lduw_code(T0 & ~1);
|
|
363 |
ret = lduw_code(addr & ~1);
|
|
351 | 364 |
break; |
352 | 365 |
default: |
353 | 366 |
case 4: |
354 |
ret = ldl_code(T0 & ~3);
|
|
367 |
ret = ldl_code(addr & ~3);
|
|
355 | 368 |
break; |
356 | 369 |
case 8: |
357 |
tmp = ldq_code(T0 & ~7); |
|
358 |
ret = tmp >> 32; |
|
359 |
T0 = tmp; |
|
370 |
ret = ldq_code(addr & ~7); |
|
360 | 371 |
break; |
361 | 372 |
} |
362 | 373 |
break; |
363 | 374 |
case 0xa: /* User data access */ |
364 | 375 |
switch(size) { |
365 | 376 |
case 1: |
366 |
ret = ldub_user(T0);
|
|
377 |
ret = ldub_user(addr);
|
|
367 | 378 |
break; |
368 | 379 |
case 2: |
369 |
ret = lduw_user(T0 & ~1);
|
|
380 |
ret = lduw_user(addr & ~1);
|
|
370 | 381 |
break; |
371 | 382 |
default: |
372 | 383 |
case 4: |
373 |
ret = ldl_user(T0 & ~3);
|
|
384 |
ret = ldl_user(addr & ~3);
|
|
374 | 385 |
break; |
375 | 386 |
case 8: |
376 |
tmp = ldq_user(T0 & ~7); |
|
377 |
ret = tmp >> 32; |
|
378 |
T0 = tmp; |
|
387 |
ret = ldq_user(addr & ~7); |
|
379 | 388 |
break; |
380 | 389 |
} |
381 | 390 |
break; |
382 | 391 |
case 0xb: /* Supervisor data access */ |
383 | 392 |
switch(size) { |
384 | 393 |
case 1: |
385 |
ret = ldub_kernel(T0);
|
|
394 |
ret = ldub_kernel(addr);
|
|
386 | 395 |
break; |
387 | 396 |
case 2: |
388 |
ret = lduw_kernel(T0 & ~1);
|
|
397 |
ret = lduw_kernel(addr & ~1);
|
|
389 | 398 |
break; |
390 | 399 |
default: |
391 | 400 |
case 4: |
392 |
ret = ldl_kernel(T0 & ~3);
|
|
401 |
ret = ldl_kernel(addr & ~3);
|
|
393 | 402 |
break; |
394 | 403 |
case 8: |
395 |
tmp = ldq_kernel(T0 & ~7); |
|
396 |
ret = tmp >> 32; |
|
397 |
T0 = tmp; |
|
404 |
ret = ldq_kernel(addr & ~7); |
|
398 | 405 |
break; |
399 | 406 |
} |
400 | 407 |
break; |
... | ... | |
406 | 413 |
case 0x20: /* MMU passthrough */ |
407 | 414 |
switch(size) { |
408 | 415 |
case 1: |
409 |
ret = ldub_phys(T0);
|
|
416 |
ret = ldub_phys(addr);
|
|
410 | 417 |
break; |
411 | 418 |
case 2: |
412 |
ret = lduw_phys(T0 & ~1);
|
|
419 |
ret = lduw_phys(addr & ~1);
|
|
413 | 420 |
break; |
414 | 421 |
default: |
415 | 422 |
case 4: |
416 |
ret = ldl_phys(T0 & ~3);
|
|
423 |
ret = ldl_phys(addr & ~3);
|
|
417 | 424 |
break; |
418 | 425 |
case 8: |
419 |
tmp = ldq_phys(T0 & ~7); |
|
420 |
ret = tmp >> 32; |
|
421 |
T0 = tmp; |
|
426 |
ret = ldq_phys(addr & ~7); |
|
422 | 427 |
break; |
423 | 428 |
} |
424 | 429 |
break; |
425 | 430 |
case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */ |
426 | 431 |
switch(size) { |
427 | 432 |
case 1: |
428 |
ret = ldub_phys((target_phys_addr_t)T0
|
|
433 |
ret = ldub_phys((target_phys_addr_t)addr
|
|
429 | 434 |
| ((target_phys_addr_t)(asi & 0xf) << 32)); |
430 | 435 |
break; |
431 | 436 |
case 2: |
432 |
ret = lduw_phys((target_phys_addr_t)(T0 & ~1)
|
|
437 |
ret = lduw_phys((target_phys_addr_t)(addr & ~1)
|
|
433 | 438 |
| ((target_phys_addr_t)(asi & 0xf) << 32)); |
434 | 439 |
break; |
435 | 440 |
default: |
436 | 441 |
case 4: |
437 |
ret = ldl_phys((target_phys_addr_t)(T0 & ~3)
|
|
442 |
ret = ldl_phys((target_phys_addr_t)(addr & ~3)
|
|
438 | 443 |
| ((target_phys_addr_t)(asi & 0xf) << 32)); |
439 | 444 |
break; |
440 | 445 |
case 8: |
441 |
tmp = ldq_phys((target_phys_addr_t)(T0 & ~7)
|
|
446 |
ret = ldq_phys((target_phys_addr_t)(addr & ~7)
|
|
442 | 447 |
| ((target_phys_addr_t)(asi & 0xf) << 32)); |
443 |
ret = tmp >> 32; |
|
444 |
T0 = tmp; |
|
445 | 448 |
break; |
446 | 449 |
} |
447 | 450 |
break; |
... | ... | |
453 | 456 |
break; |
454 | 457 |
case 8: /* User code access, XXX */ |
455 | 458 |
default: |
456 |
do_unassigned_access(T0, 0, 0, asi);
|
|
459 |
do_unassigned_access(addr, 0, 0, asi);
|
|
457 | 460 |
ret = 0; |
458 | 461 |
break; |
459 | 462 |
} |
460 | 463 |
if (sign) { |
461 | 464 |
switch(size) { |
462 | 465 |
case 1: |
463 |
T1 = (int8_t) ret;
|
|
466 |
ret = (int8_t) ret;
|
|
464 | 467 |
break; |
465 | 468 |
case 2: |
466 |
T1 = (int16_t) ret; |
|
469 |
ret = (int16_t) ret; |
|
470 |
break; |
|
471 |
case 4: |
|
472 |
ret = (int32_t) ret; |
|
467 | 473 |
break; |
468 | 474 |
default: |
469 |
T1 = ret; |
|
470 | 475 |
break; |
471 | 476 |
} |
472 | 477 |
} |
473 |
else |
|
474 |
T1 = ret; |
|
475 | 478 |
#ifdef DEBUG_ASI |
476 |
dump_asi("read ", last_T0, asi, size, T1, T0);
|
|
479 |
dump_asi("read ", last_addr, asi, size, ret);
|
|
477 | 480 |
#endif |
481 |
return ret; |
|
478 | 482 |
} |
479 | 483 |
|
480 |
void helper_st_asi(int asi, int size) |
|
484 |
void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
|
|
481 | 485 |
{ |
482 | 486 |
switch(asi) { |
483 | 487 |
case 2: /* SuperSparc MXCC registers */ |
484 |
switch (T0) {
|
|
488 |
switch (addr) {
|
|
485 | 489 |
case 0x01c00000: /* MXCC stream data register 0 */ |
486 | 490 |
if (size == 8) |
487 |
env->mxccdata[0] = ((uint64_t)T1 << 32) | T2;
|
|
491 |
env->mxccdata[0] = val;
|
|
488 | 492 |
else |
489 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
|
|
493 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, size);
|
|
490 | 494 |
break; |
491 | 495 |
case 0x01c00008: /* MXCC stream data register 1 */ |
492 | 496 |
if (size == 8) |
493 |
env->mxccdata[1] = ((uint64_t)T1 << 32) | T2;
|
|
497 |
env->mxccdata[1] = val;
|
|
494 | 498 |
else |
495 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
|
|
499 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, size);
|
|
496 | 500 |
break; |
497 | 501 |
case 0x01c00010: /* MXCC stream data register 2 */ |
498 | 502 |
if (size == 8) |
499 |
env->mxccdata[2] = ((uint64_t)T1 << 32) | T2;
|
|
503 |
env->mxccdata[2] = val;
|
|
500 | 504 |
else |
501 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
|
|
505 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, size);
|
|
502 | 506 |
break; |
503 | 507 |
case 0x01c00018: /* MXCC stream data register 3 */ |
504 | 508 |
if (size == 8) |
505 |
env->mxccdata[3] = ((uint64_t)T1 << 32) | T2;
|
|
509 |
env->mxccdata[3] = val;
|
|
506 | 510 |
else |
507 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
|
|
511 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, size);
|
|
508 | 512 |
break; |
509 | 513 |
case 0x01c00100: /* MXCC stream source */ |
510 | 514 |
if (size == 8) |
511 |
env->mxccregs[0] = ((uint64_t)T1 << 32) | T2;
|
|
515 |
env->mxccregs[0] = val;
|
|
512 | 516 |
else |
513 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
|
|
517 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, size);
|
|
514 | 518 |
env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 0); |
515 | 519 |
env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 8); |
516 | 520 |
env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + 16); |
... | ... | |
518 | 522 |
break; |
519 | 523 |
case 0x01c00200: /* MXCC stream destination */ |
520 | 524 |
if (size == 8) |
521 |
env->mxccregs[1] = ((uint64_t)T1 << 32) | T2;
|
|
525 |
env->mxccregs[1] = val;
|
|
522 | 526 |
else |
523 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
|
|
527 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, size);
|
|
524 | 528 |
stq_phys((env->mxccregs[1] & 0xffffffffULL) + 0, env->mxccdata[0]); |
525 | 529 |
stq_phys((env->mxccregs[1] & 0xffffffffULL) + 8, env->mxccdata[1]); |
526 | 530 |
stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16, env->mxccdata[2]); |
... | ... | |
528 | 532 |
break; |
529 | 533 |
case 0x01c00a00: /* MXCC control register */ |
530 | 534 |
if (size == 8) |
531 |
env->mxccregs[3] = ((uint64_t)T1 << 32) | T2;
|
|
535 |
env->mxccregs[3] = val;
|
|
532 | 536 |
else |
533 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
|
|
537 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, size);
|
|
534 | 538 |
break; |
535 | 539 |
case 0x01c00a04: /* MXCC control register */ |
536 | 540 |
if (size == 4) |
537 |
env->mxccregs[3] = (env->mxccregs[0xa] & 0xffffffff00000000ULL) | T1;
|
|
541 |
env->mxccregs[3] = (env->mxccregs[0xa] & 0xffffffff00000000ULL) | val;
|
|
538 | 542 |
else |
539 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
|
|
543 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, size);
|
|
540 | 544 |
break; |
541 | 545 |
case 0x01c00e00: /* MXCC error register */ |
542 | 546 |
// writing a 1 bit clears the error |
543 | 547 |
if (size == 8) |
544 |
env->mxccregs[6] &= ~(((uint64_t)T1 << 32) | T2);
|
|
548 |
env->mxccregs[6] &= ~val;
|
|
545 | 549 |
else |
546 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
|
|
550 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, size);
|
|
547 | 551 |
break; |
548 | 552 |
case 0x01c00f00: /* MBus port address register */ |
549 | 553 |
if (size == 8) |
550 |
env->mxccregs[7] = ((uint64_t)T1 << 32) | T2;
|
|
554 |
env->mxccregs[7] = val;
|
|
551 | 555 |
else |
552 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", T0, size);
|
|
556 |
DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, size);
|
|
553 | 557 |
break; |
554 | 558 |
default: |
555 |
DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", T0, size);
|
|
559 |
DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr, size);
|
|
556 | 560 |
break; |
557 | 561 |
} |
558 |
DPRINTF_MXCC("asi = %d, size = %d, T0 = %08x, T1 = %08x\n", asi, size, T0, T1);
|
|
562 |
DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %08x\n", asi, size, addr, val);
|
|
559 | 563 |
#ifdef DEBUG_MXCC |
560 | 564 |
dump_mxcc(env); |
561 | 565 |
#endif |
... | ... | |
564 | 568 |
{ |
565 | 569 |
int mmulev; |
566 | 570 |
|
567 |
mmulev = (T0 >> 8) & 15;
|
|
571 |
mmulev = (addr >> 8) & 15;
|
|
568 | 572 |
DPRINTF_MMU("mmu flush level %d\n", mmulev); |
569 | 573 |
switch (mmulev) { |
570 | 574 |
case 0: // flush page |
571 |
tlb_flush_page(env, T0 & 0xfffff000);
|
|
575 |
tlb_flush_page(env, addr & 0xfffff000);
|
|
572 | 576 |
break; |
573 | 577 |
case 1: // flush segment (256k) |
574 | 578 |
case 2: // flush region (16M) |
... | ... | |
586 | 590 |
break; |
587 | 591 |
case 4: /* write MMU regs */ |
588 | 592 |
{ |
589 |
int reg = (T0 >> 8) & 0x1f;
|
|
593 |
int reg = (addr >> 8) & 0x1f;
|
|
590 | 594 |
uint32_t oldreg; |
591 | 595 |
|
592 | 596 |
oldreg = env->mmuregs[reg]; |
593 | 597 |
switch(reg) { |
594 | 598 |
case 0: // Control Register |
595 | 599 |
env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) | |
596 |
(T1 & 0x00ffffff);
|
|
600 |
(val & 0x00ffffff);
|
|
597 | 601 |
// Mappings generated during no-fault mode or MMU |
598 | 602 |
// disabled mode are invalid in normal mode |
599 | 603 |
if ((oldreg & (MMU_E | MMU_NF | env->mmu_bm)) != |
... | ... | |
601 | 605 |
tlb_flush(env, 1); |
602 | 606 |
break; |
603 | 607 |
case 1: // Context Table Pointer Register |
604 |
env->mmuregs[reg] = T1 & env->mmu_ctpr_mask;
|
|
608 |
env->mmuregs[reg] = val & env->mmu_ctpr_mask;
|
|
605 | 609 |
break; |
606 | 610 |
case 2: // Context Register |
607 |
env->mmuregs[reg] = T1 & env->mmu_cxr_mask;
|
|
611 |
env->mmuregs[reg] = val & env->mmu_cxr_mask;
|
|
608 | 612 |
if (oldreg != env->mmuregs[reg]) { |
609 | 613 |
/* we flush when the MMU context changes because |
610 | 614 |
QEMU has no MMU context support */ |
... | ... | |
615 | 619 |
case 4: // Synchronous Fault Address Register |
616 | 620 |
break; |
617 | 621 |
case 0x10: // TLB Replacement Control Register |
618 |
env->mmuregs[reg] = T1 & env->mmu_trcr_mask;
|
|
622 |
env->mmuregs[reg] = val & env->mmu_trcr_mask;
|
|
619 | 623 |
break; |
620 | 624 |
case 0x13: // Synchronous Fault Status Register with Read and Clear |
621 |
env->mmuregs[3] = T1 & env->mmu_sfsr_mask;
|
|
625 |
env->mmuregs[3] = val & env->mmu_sfsr_mask;
|
|
622 | 626 |
break; |
623 | 627 |
case 0x14: // Synchronous Fault Address Register |
624 |
env->mmuregs[4] = T1;
|
|
628 |
env->mmuregs[4] = val;
|
|
625 | 629 |
break; |
626 | 630 |
default: |
627 |
env->mmuregs[reg] = T1;
|
|
631 |
env->mmuregs[reg] = val;
|
|
628 | 632 |
break; |
629 | 633 |
} |
630 | 634 |
if (oldreg != env->mmuregs[reg]) { |
... | ... | |
642 | 646 |
case 0xa: /* User data access */ |
643 | 647 |
switch(size) { |
644 | 648 |
case 1: |
645 |
stb_user(T0, T1);
|
|
649 |
stb_user(addr, val);
|
|
646 | 650 |
break; |
647 | 651 |
case 2: |
648 |
stw_user(T0 & ~1, T1);
|
|
652 |
stw_user(addr & ~1, val);
|
|
649 | 653 |
break; |
650 | 654 |
default: |
651 | 655 |
case 4: |
652 |
stl_user(T0 & ~3, T1);
|
|
656 |
stl_user(addr & ~3, val);
|
|
653 | 657 |
break; |
654 | 658 |
case 8: |
655 |
stq_user(T0 & ~7, ((uint64_t)T1 << 32) | T2);
|
|
659 |
stq_user(addr & ~7, val);
|
|
656 | 660 |
break; |
657 | 661 |
} |
658 | 662 |
break; |
659 | 663 |
case 0xb: /* Supervisor data access */ |
660 | 664 |
switch(size) { |
661 | 665 |
case 1: |
662 |
stb_kernel(T0, T1);
|
|
666 |
stb_kernel(addr, val);
|
|
663 | 667 |
break; |
664 | 668 |
case 2: |
665 |
stw_kernel(T0 & ~1, T1);
|
|
669 |
stw_kernel(addr & ~1, val);
|
|
666 | 670 |
break; |
667 | 671 |
default: |
668 | 672 |
case 4: |
669 |
stl_kernel(T0 & ~3, T1);
|
|
673 |
stl_kernel(addr & ~3, val);
|
|
670 | 674 |
break; |
671 | 675 |
case 8: |
672 |
stq_kernel(T0 & ~7, ((uint64_t)T1 << 32) | T2);
|
|
676 |
stq_kernel(addr & ~7, val);
|
|
673 | 677 |
break; |
674 | 678 |
} |
675 | 679 |
break; |
... | ... | |
685 | 689 |
break; |
686 | 690 |
case 0x17: /* Block copy, sta access */ |
687 | 691 |
{ |
688 |
// value (T1) = src
|
|
689 |
// address (T0) = dst
|
|
692 |
// val = src |
|
693 |
// addr = dst |
|
690 | 694 |
// copy 32 bytes |
691 | 695 |
unsigned int i; |
692 |
uint32_t src = T1 & ~3, dst = T0 & ~3, temp;
|
|
696 |
uint32_t src = val & ~3, dst = addr & ~3, temp;
|
|
693 | 697 |
|
694 | 698 |
for (i = 0; i < 32; i += 4, src += 4, dst += 4) { |
695 | 699 |
temp = ldl_kernel(src); |
... | ... | |
699 | 703 |
break; |
700 | 704 |
case 0x1f: /* Block fill, stda access */ |
701 | 705 |
{ |
702 |
// value (T1, T2) |
|
703 |
// address (T0) = dst |
|
704 |
// fill 32 bytes |
|
706 |
// addr = dst |
|
707 |
// fill 32 bytes with val |
|
705 | 708 |
unsigned int i; |
706 |
uint32_t dst = T0 & 7; |
|
707 |
uint64_t val; |
|
708 |
|
|
709 |
val = (((uint64_t)T1) << 32) | T2; |
|
709 |
uint32_t dst = addr & 7; |
|
710 | 710 |
|
711 | 711 |
for (i = 0; i < 32; i += 8, dst += 8) |
712 | 712 |
stq_kernel(dst, val); |
... | ... | |
716 | 716 |
{ |
717 | 717 |
switch(size) { |
718 | 718 |
case 1: |
719 |
stb_phys(T0, T1);
|
|
719 |
stb_phys(addr, val);
|
|
720 | 720 |
break; |
721 | 721 |
case 2: |
722 |
stw_phys(T0 & ~1, T1);
|
|
722 |
stw_phys(addr & ~1, val);
|
|
723 | 723 |
break; |
724 | 724 |
case 4: |
725 | 725 |
default: |
726 |
stl_phys(T0 & ~3, T1);
|
|
726 |
stl_phys(addr & ~3, val);
|
|
727 | 727 |
break; |
728 | 728 |
case 8: |
729 |
stq_phys(T0 & ~7, ((uint64_t)T1 << 32) | T2);
|
|
729 |
stq_phys(addr & ~7, val);
|
|
730 | 730 |
break; |
731 | 731 |
} |
732 | 732 |
} |
... | ... | |
735 | 735 |
{ |
736 | 736 |
switch(size) { |
737 | 737 |
case 1: |
738 |
stb_phys((target_phys_addr_t)T0
|
|
739 |
| ((target_phys_addr_t)(asi & 0xf) << 32), T1);
|
|
738 |
stb_phys((target_phys_addr_t)addr
|
|
739 |
| ((target_phys_addr_t)(asi & 0xf) << 32), val);
|
|
740 | 740 |
break; |
741 | 741 |
case 2: |
742 |
stw_phys((target_phys_addr_t)(T0 & ~1)
|
|
743 |
| ((target_phys_addr_t)(asi & 0xf) << 32), T1);
|
|
742 |
stw_phys((target_phys_addr_t)(addr & ~1)
|
|
743 |
| ((target_phys_addr_t)(asi & 0xf) << 32), val);
|
|
744 | 744 |
break; |
745 | 745 |
case 4: |
746 | 746 |
default: |
747 |
stl_phys((target_phys_addr_t)(T0 & ~3)
|
|
748 |
| ((target_phys_addr_t)(asi & 0xf) << 32), T1);
|
|
747 |
stl_phys((target_phys_addr_t)(addr & ~3)
|
|
748 |
| ((target_phys_addr_t)(asi & 0xf) << 32), val);
|
|
749 | 749 |
break; |
750 | 750 |
case 8: |
751 |
stq_phys((target_phys_addr_t)(T0 & ~7) |
|
752 |
| ((target_phys_addr_t)(asi & 0xf) << 32), |
|
753 |
((uint64_t)T1 << 32) | T2); |
|
751 |
stq_phys((target_phys_addr_t)(addr & ~7) |
|
752 |
| ((target_phys_addr_t)(asi & 0xf) << 32), val); |
|
754 | 753 |
break; |
755 | 754 |
} |
756 | 755 |
} |
... | ... | |
767 | 766 |
case 8: /* User code access, XXX */ |
768 | 767 |
case 9: /* Supervisor code access, XXX */ |
769 | 768 |
default: |
770 |
do_unassigned_access(T0, 1, 0, asi);
|
|
769 |
do_unassigned_access(addr, 1, 0, asi);
|
|
771 | 770 |
break; |
772 | 771 |
} |
773 | 772 |
#ifdef DEBUG_ASI |
774 |
dump_asi("write", T0, asi, size, T1, T2);
|
|
773 |
dump_asi("write", addr, asi, size, val);
|
|
775 | 774 |
#endif |
776 | 775 |
} |
777 | 776 |
|
... | ... | |
779 | 778 |
#else /* TARGET_SPARC64 */ |
780 | 779 |
|
781 | 780 |
#ifdef CONFIG_USER_ONLY |
782 |
void helper_ld_asi(int asi, int size, int sign)
|
|
781 |
uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
|
|
783 | 782 |
{ |
784 | 783 |
uint64_t ret = 0; |
784 |
#if defined(DEBUG_ASI) |
|
785 |
target_ulong last_addr = addr; |
|
786 |
#endif |
|
785 | 787 |
|
786 | 788 |
if (asi < 0x80) |
787 | 789 |
raise_exception(TT_PRIV_ACT); |
... | ... | |
794 | 796 |
{ |
795 | 797 |
switch(size) { |
796 | 798 |
case 1: |
797 |
ret = ldub_raw(T0);
|
|
799 |
ret = ldub_raw(addr);
|
|
798 | 800 |
break; |
799 | 801 |
case 2: |
800 |
ret = lduw_raw(T0 & ~1);
|
|
802 |
ret = lduw_raw(addr & ~1);
|
|
801 | 803 |
break; |
802 | 804 |
case 4: |
803 |
ret = ldl_raw(T0 & ~3);
|
|
805 |
ret = ldl_raw(addr & ~3);
|
|
804 | 806 |
break; |
805 | 807 |
default: |
806 | 808 |
case 8: |
807 |
ret = ldq_raw(T0 & ~7);
|
|
809 |
ret = ldq_raw(addr & ~7);
|
|
808 | 810 |
break; |
809 | 811 |
} |
810 | 812 |
} |
... | ... | |
858 | 860 |
break; |
859 | 861 |
} |
860 | 862 |
} |
861 |
T1 = ret; |
|
863 |
#ifdef DEBUG_ASI |
|
864 |
dump_asi("read ", last_addr, asi, size, ret); |
|
865 |
#endif |
|
866 |
return ret; |
|
862 | 867 |
} |
863 | 868 |
|
864 |
void helper_st_asi(int asi, int size) |
|
869 |
void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
|
|
865 | 870 |
{ |
871 |
#ifdef DEBUG_ASI |
|
872 |
dump_asi("write", addr, asi, size, val); |
|
873 |
#endif |
|
866 | 874 |
if (asi < 0x80) |
867 | 875 |
raise_exception(TT_PRIV_ACT); |
868 | 876 |
|
... | ... | |
872 | 880 |
case 0x89: // Secondary LE |
873 | 881 |
switch(size) { |
874 | 882 |
case 2: |
875 |
T0 = bswap16(T0);
|
|
883 |
addr = bswap16(addr);
|
|
876 | 884 |
break; |
877 | 885 |
case 4: |
878 |
T0 = bswap32(T0);
|
|
886 |
addr = bswap32(addr);
|
|
879 | 887 |
break; |
880 | 888 |
case 8: |
881 |
T0 = bswap64(T0);
|
|
889 |
addr = bswap64(addr);
|
|
882 | 890 |
break; |
883 | 891 |
default: |
884 | 892 |
break; |
... | ... | |
893 | 901 |
{ |
894 | 902 |
switch(size) { |
895 | 903 |
case 1: |
896 |
stb_raw(T0, T1);
|
|
904 |
stb_raw(addr, val);
|
|
897 | 905 |
break; |
898 | 906 |
case 2: |
899 |
stw_raw(T0 & ~1, T1);
|
|
907 |
stw_raw(addr & ~1, val);
|
|
900 | 908 |
break; |
901 | 909 |
case 4: |
902 |
stl_raw(T0 & ~3, T1);
|
|
910 |
stl_raw(addr & ~3, val);
|
|
903 | 911 |
break; |
904 | 912 |
case 8: |
905 | 913 |
default: |
906 |
stq_raw(T0 & ~7, T1);
|
|
914 |
stq_raw(addr & ~7, val);
|
|
907 | 915 |
break; |
908 | 916 |
} |
909 | 917 |
} |
... | ... | |
918 | 926 |
case 0x8a: // Primary no-fault LE, RO |
919 | 927 |
case 0x8b: // Secondary no-fault LE, RO |
920 | 928 |
default: |
921 |
do_unassigned_access(T0, 1, 0, 1);
|
|
929 |
do_unassigned_access(addr, 1, 0, 1);
|
|
922 | 930 |
return; |
923 | 931 |
} |
924 | 932 |
} |
925 | 933 |
|
926 | 934 |
#else /* CONFIG_USER_ONLY */ |
927 | 935 |
|
928 |
void helper_ld_asi(int asi, int size, int sign)
|
|
936 |
uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
|
|
929 | 937 |
{ |
930 | 938 |
uint64_t ret = 0; |
939 |
#if defined(DEBUG_ASI) |
|
940 |
target_ulong last_addr = addr; |
|
941 |
#endif |
|
931 | 942 |
|
932 | 943 |
if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) |
933 | 944 |
|| (asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV))) |
... | ... | |
944 | 955 |
if (env->hpstate & HS_PRIV) { |
945 | 956 |
switch(size) { |
946 | 957 |
case 1: |
947 |
ret = ldub_hypv(T0);
|
|
958 |
ret = ldub_hypv(addr);
|
|
948 | 959 |
break; |
949 | 960 |
case 2: |
950 |
ret = lduw_hypv(T0 & ~1);
|
|
961 |
ret = lduw_hypv(addr & ~1);
|
|
951 | 962 |
break; |
952 | 963 |
case 4: |
953 |
ret = ldl_hypv(T0 & ~3);
|
|
964 |
ret = ldl_hypv(addr & ~3);
|
|
954 | 965 |
break; |
955 | 966 |
default: |
956 | 967 |
case 8: |
957 |
ret = ldq_hypv(T0 & ~7);
|
|
968 |
ret = ldq_hypv(addr & ~7);
|
|
958 | 969 |
break; |
959 | 970 |
} |
960 | 971 |
} else { |
961 | 972 |
switch(size) { |
962 | 973 |
case 1: |
963 |
ret = ldub_kernel(T0);
|
|
974 |
ret = ldub_kernel(addr);
|
|
964 | 975 |
break; |
965 | 976 |
case 2: |
966 |
ret = lduw_kernel(T0 & ~1);
|
|
977 |
ret = lduw_kernel(addr & ~1);
|
|
967 | 978 |
break; |
968 | 979 |
case 4: |
969 |
ret = ldl_kernel(T0 & ~3);
|
|
980 |
ret = ldl_kernel(addr & ~3);
|
|
970 | 981 |
break; |
971 | 982 |
default: |
972 | 983 |
case 8: |
973 |
ret = ldq_kernel(T0 & ~7);
|
|
984 |
ret = ldq_kernel(addr & ~7);
|
|
974 | 985 |
break; |
975 | 986 |
} |
976 | 987 |
} |
977 | 988 |
} else { |
978 | 989 |
switch(size) { |
979 | 990 |
case 1: |
980 |
ret = ldub_user(T0);
|
|
991 |
ret = ldub_user(addr);
|
|
981 | 992 |
break; |
982 | 993 |
case 2: |
983 |
ret = lduw_user(T0 & ~1);
|
|
994 |
ret = lduw_user(addr & ~1);
|
|
984 | 995 |
break; |
985 | 996 |
case 4: |
986 |
ret = ldl_user(T0 & ~3);
|
|
997 |
ret = ldl_user(addr & ~3);
|
|
987 | 998 |
break; |
988 | 999 |
default: |
989 | 1000 |
case 8: |
990 |
ret = ldq_user(T0 & ~7);
|
|
1001 |
ret = ldq_user(addr & ~7);
|
|
991 | 1002 |
break; |
992 | 1003 |
} |
993 | 1004 |
} |
... | ... | |
999 | 1010 |
{ |
1000 | 1011 |
switch(size) { |
1001 | 1012 |
case 1: |
1002 |
ret = ldub_phys(T0);
|
|
1013 |
ret = ldub_phys(addr);
|
|
1003 | 1014 |
break; |
1004 | 1015 |
case 2: |
1005 |
ret = lduw_phys(T0 & ~1);
|
|
1016 |
ret = lduw_phys(addr & ~1);
|
|
1006 | 1017 |
break; |
1007 | 1018 |
case 4: |
1008 |
ret = ldl_phys(T0 & ~3);
|
|
1019 |
ret = ldl_phys(addr & ~3);
|
|
1009 | 1020 |
break; |
1010 | 1021 |
default: |
1011 | 1022 |
case 8: |
1012 |
ret = ldq_phys(T0 & ~7);
|
|
1023 |
ret = ldq_phys(addr & ~7);
|
|
1013 | 1024 |
break; |
1014 | 1025 |
} |
1015 | 1026 |
break; |
... | ... | |
1032 | 1043 |
break; |
1033 | 1044 |
case 0x50: // I-MMU regs |
1034 | 1045 |
{ |
1035 |
int reg = (T0 >> 3) & 0xf;
|
|
1046 |
int reg = (addr >> 3) & 0xf;
|
|
1036 | 1047 |
|
1037 | 1048 |
ret = env->immuregs[reg]; |
1038 | 1049 |
break; |
... | ... | |
1049 | 1060 |
for (i = 0; i < 64; i++) { |
1050 | 1061 |
// Valid, ctx match, vaddr match |
1051 | 1062 |
if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 && |
1052 |
env->itlb_tag[i] == T0) {
|
|
1063 |
env->itlb_tag[i] == addr) {
|
|
1053 | 1064 |
ret = env->itlb_tag[i]; |
1054 | 1065 |
break; |
1055 | 1066 |
} |
... | ... | |
1058 | 1069 |
} |
1059 | 1070 |
case 0x58: // D-MMU regs |
1060 | 1071 |
{ |
1061 |
int reg = (T0 >> 3) & 0xf;
|
|
1072 |
int reg = (addr >> 3) & 0xf;
|
|
1062 | 1073 |
|
1063 | 1074 |
ret = env->dmmuregs[reg]; |
1064 | 1075 |
break; |
... | ... | |
1070 | 1081 |
for (i = 0; i < 64; i++) { |
1071 | 1082 |
// Valid, ctx match, vaddr match |
1072 | 1083 |
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 && |
1073 |
env->dtlb_tag[i] == T0) {
|
|
1084 |
env->dtlb_tag[i] == addr) {
|
|
1074 | 1085 |
ret = env->dtlb_tag[i]; |
1075 | 1086 |
break; |
1076 | 1087 |
} |
... | ... | |
1092 | 1103 |
case 0x5f: // D-MMU demap, WO |
1093 | 1104 |
case 0x77: // Interrupt vector, WO |
1094 | 1105 |
default: |
1095 |
do_unassigned_access(T0, 0, 0, 1);
|
|
1106 |
do_unassigned_access(addr, 0, 0, 1);
|
|
1096 | 1107 |
ret = 0; |
1097 | 1108 |
break; |
1098 | 1109 |
} |
... | ... | |
1141 | 1152 |
break; |
1142 | 1153 |
} |
1143 | 1154 |
} |
1144 |
T1 = ret; |
|
1155 |
#ifdef DEBUG_ASI |
|
1156 |
dump_asi("read ", last_addr, asi, size, ret); |
|
1157 |
#endif |
|
1158 |
return ret; |
|
1145 | 1159 |
} |
1146 | 1160 |
|
1147 |
void helper_st_asi(int asi, int size) |
|
1161 |
void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
|
|
1148 | 1162 |
{ |
1163 |
#ifdef DEBUG_ASI |
|
1164 |
dump_asi("write", addr, asi, size, val); |
|
1165 |
#endif |
|
1149 | 1166 |
if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) |
1150 | 1167 |
|| (asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV))) |
1151 | 1168 |
raise_exception(TT_PRIV_ACT); |
... | ... | |
1161 | 1178 |
case 0x89: // Secondary LE |
1162 | 1179 |
switch(size) { |
1163 | 1180 |
case 2: |
1164 |
T0 = bswap16(T0);
|
|
1181 |
addr = bswap16(addr);
|
|
1165 | 1182 |
break; |
1166 | 1183 |
case 4: |
1167 |
T0 = bswap32(T0);
|
|
1184 |
addr = bswap32(addr);
|
|
1168 | 1185 |
break; |
1169 | 1186 |
case 8: |
1170 |
T0 = bswap64(T0);
|
|
1187 |
addr = bswap64(addr);
|
|
1171 | 1188 |
break; |
1172 | 1189 |
default: |
1173 | 1190 |
break; |
... | ... | |
1185 | 1202 |
if (env->hpstate & HS_PRIV) { |
1186 | 1203 |
switch(size) { |
1187 | 1204 |
case 1: |
1188 |
stb_hypv(T0, T1);
|
|
1205 |
stb_hypv(addr, val);
|
|
1189 | 1206 |
break; |
1190 | 1207 |
case 2: |
1191 |
stw_hypv(T0 & ~1, T1);
|
|
1208 |
stw_hypv(addr & ~1, val);
|
|
1192 | 1209 |
break; |
1193 | 1210 |
case 4: |
1194 |
stl_hypv(T0 & ~3, T1);
|
|
1211 |
stl_hypv(addr & ~3, val);
|
|
1195 | 1212 |
break; |
1196 | 1213 |
case 8: |
1197 | 1214 |
default: |
1198 |
stq_hypv(T0 & ~7, T1);
|
|
1215 |
stq_hypv(addr & ~7, val);
|
|
1199 | 1216 |
break; |
1200 | 1217 |
} |
1201 | 1218 |
} else { |
1202 | 1219 |
switch(size) { |
1203 | 1220 |
case 1: |
1204 |
stb_kernel(T0, T1);
|
|
1221 |
stb_kernel(addr, val);
|
|
1205 | 1222 |
break; |
1206 | 1223 |
case 2: |
1207 |
stw_kernel(T0 & ~1, T1);
|
|
1224 |
stw_kernel(addr & ~1, val);
|
|
1208 | 1225 |
break; |
1209 | 1226 |
case 4: |
1210 |
stl_kernel(T0 & ~3, T1);
|
|
1227 |
stl_kernel(addr & ~3, val);
|
|
1211 | 1228 |
break; |
1212 | 1229 |
case 8: |
1213 | 1230 |
default: |
1214 |
stq_kernel(T0 & ~7, T1);
|
|
1231 |
stq_kernel(addr & ~7, val);
|
|
1215 | 1232 |
break; |
1216 | 1233 |
} |
1217 | 1234 |
} |
1218 | 1235 |
} else { |
1219 | 1236 |
switch(size) { |
1220 | 1237 |
case 1: |
1221 |
stb_user(T0, T1);
|
|
1238 |
stb_user(addr, val);
|
|
1222 | 1239 |
break; |
1223 | 1240 |
case 2: |
1224 |
stw_user(T0 & ~1, T1);
|
|
1241 |
stw_user(addr & ~1, val);
|
|
1225 | 1242 |
break; |
1226 | 1243 |
case 4: |
1227 |
stl_user(T0 & ~3, T1);
|
|
1244 |
stl_user(addr & ~3, val);
|
|
1228 | 1245 |
break; |
1229 | 1246 |
case 8: |
1230 | 1247 |
default: |
1231 |
stq_user(T0 & ~7, T1);
|
|
1248 |
stq_user(addr & ~7, val);
|
|
1232 | 1249 |
break; |
1233 | 1250 |
} |
1234 | 1251 |
} |
... | ... | |
1240 | 1257 |
{ |
1241 | 1258 |
switch(size) { |
1242 | 1259 |
case 1: |
1243 |
stb_phys(T0, T1);
|
|
1260 |
stb_phys(addr, val);
|
|
1244 | 1261 |
break; |
1245 | 1262 |
case 2: |
1246 |
stw_phys(T0 & ~1, T1);
|
|
1263 |
stw_phys(addr & ~1, val);
|
|
1247 | 1264 |
break; |
1248 | 1265 |
case 4: |
1249 |
stl_phys(T0 & ~3, T1);
|
|
1266 |
stl_phys(addr & ~3, val);
|
|
1250 | 1267 |
break; |
1251 | 1268 |
case 8: |
1252 | 1269 |
default: |
1253 |
stq_phys(T0 & ~7, T1);
|
|
1270 |
stq_phys(addr & ~7, val);
|
|
1254 | 1271 |
break; |
1255 | 1272 |
} |
1256 | 1273 |
} |
... | ... | |
1271 | 1288 |
uint64_t oldreg; |
1272 | 1289 |
|
1273 | 1290 |
oldreg = env->lsu; |
1274 |
env->lsu = T1 & (DMMU_E | IMMU_E);
|
|
1291 |
env->lsu = val & (DMMU_E | IMMU_E);
|
|
1275 | 1292 |
// Mappings generated during D/I MMU disabled mode are |
1276 | 1293 |
// invalid in normal mode |
1277 | 1294 |
if (oldreg != env->lsu) { |
... | ... | |
1285 | 1302 |
} |
1286 | 1303 |
case 0x50: // I-MMU regs |
1287 | 1304 |
{ |
1288 |
int reg = (T0 >> 3) & 0xf;
|
|
1305 |
int reg = (addr >> 3) & 0xf;
|
|
1289 | 1306 |
uint64_t oldreg; |
1290 | 1307 |
|
1291 | 1308 |
oldreg = env->immuregs[reg]; |
... | ... | |
1299 | 1316 |
case 8: |
1300 | 1317 |
return; |
1301 | 1318 |
case 3: // SFSR |
1302 |
if ((T1 & 1) == 0)
|
|
1303 |
T1 = 0; // Clear SFSR
|
|
1319 |
if ((val & 1) == 0)
|
|
1320 |
val = 0; // Clear SFSR
|
|
1304 | 1321 |
break; |
1305 | 1322 |
case 5: // TSB access |
1306 | 1323 |
case 6: // Tag access |
1307 | 1324 |
default: |
1308 | 1325 |
break; |
1309 | 1326 |
} |
1310 |
env->immuregs[reg] = T1;
|
|
1327 |
env->immuregs[reg] = val;
|
|
1311 | 1328 |
if (oldreg != env->immuregs[reg]) { |
1312 | 1329 |
DPRINTF_MMU("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->immuregs[reg]); |
1313 | 1330 |
} |
... | ... | |
1324 | 1341 |
for (i = 0; i < 64; i++) { |
1325 | 1342 |
if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) { |
1326 | 1343 |
env->itlb_tag[i] = env->immuregs[6]; |
1327 |
env->itlb_tte[i] = T1;
|
|
1344 |
env->itlb_tte[i] = val;
|
|
1328 | 1345 |
return; |
1329 | 1346 |
} |
1330 | 1347 |
} |
... | ... | |
1332 | 1349 |
for (i = 0; i < 64; i++) { |
1333 | 1350 |
if ((env->itlb_tte[i] & 0x40) == 0) { |
1334 | 1351 |
env->itlb_tag[i] = env->immuregs[6]; |
1335 |
env->itlb_tte[i] = T1;
|
|
1352 |
env->itlb_tte[i] = val;
|
|
1336 | 1353 |
return; |
1337 | 1354 |
} |
1338 | 1355 |
} |
... | ... | |
1341 | 1358 |
} |
1342 | 1359 |
case 0x55: // I-MMU data access |
1343 | 1360 |
{ |
1344 |
unsigned int i = (T0 >> 3) & 0x3f;
|
|
1361 |
unsigned int i = (addr >> 3) & 0x3f;
|
|
1345 | 1362 |
|
1346 | 1363 |
env->itlb_tag[i] = env->immuregs[6]; |
1347 |
env->itlb_tte[i] = T1;
|
|
1364 |
env->itlb_tte[i] = val;
|
|
1348 | 1365 |
return; |
1349 | 1366 |
} |
1350 | 1367 |
case 0x57: // I-MMU demap |
... | ... | |
1352 | 1369 |
return; |
1353 | 1370 |
case 0x58: // D-MMU regs |
1354 | 1371 |
{ |
1355 |
int reg = (T0 >> 3) & 0xf;
|
|
1372 |
int reg = (addr >> 3) & 0xf;
|
|
1356 | 1373 |
uint64_t oldreg; |
1357 | 1374 |
|
1358 | 1375 |
oldreg = env->dmmuregs[reg]; |
... | ... | |
1361 | 1378 |
case 4: |
1362 | 1379 |
return; |
1363 | 1380 |
case 3: // SFSR |
1364 |
if ((T1 & 1) == 0) {
|
|
1365 |
T1 = 0; // Clear SFSR, Fault address
|
|
1381 |
if ((val & 1) == 0) {
|
|
1382 |
val = 0; // Clear SFSR, Fault address
|
|
1366 | 1383 |
env->dmmuregs[4] = 0; |
1367 | 1384 |
} |
1368 |
env->dmmuregs[reg] = T1;
|
|
1385 |
env->dmmuregs[reg] = val;
|
|
1369 | 1386 |
break; |
1370 | 1387 |
case 1: // Primary context |
1371 | 1388 |
case 2: // Secondary context |
... | ... | |
1376 | 1393 |
default: |
1377 | 1394 |
break; |
1378 | 1395 |
} |
1379 |
env->dmmuregs[reg] = T1;
|
|
1396 |
env->dmmuregs[reg] = val;
|
|
1380 | 1397 |
if (oldreg != env->dmmuregs[reg]) { |
1381 | 1398 |
DPRINTF_MMU("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); |
1382 | 1399 |
} |
... | ... | |
1393 | 1410 |
for (i = 0; i < 64; i++) { |
1394 | 1411 |
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) { |
1395 | 1412 |
env->dtlb_tag[i] = env->dmmuregs[6]; |
1396 |
env->dtlb_tte[i] = T1;
|
|
1413 |
env->dtlb_tte[i] = val;
|
|
1397 | 1414 |
return; |
1398 | 1415 |
} |
1399 | 1416 |
} |
... | ... | |
1401 | 1418 |
for (i = 0; i < 64; i++) { |
1402 | 1419 |
if ((env->dtlb_tte[i] & 0x40) == 0) { |
1403 | 1420 |
env->dtlb_tag[i] = env->dmmuregs[6]; |
1404 |
env->dtlb_tte[i] = T1;
|
|
1421 |
env->dtlb_tte[i] = val;
|
|
1405 | 1422 |
return; |
1406 | 1423 |
} |
1407 | 1424 |
} |
... | ... | |
1410 | 1427 |
} |
1411 | 1428 |
case 0x5d: // D-MMU data access |
1412 | 1429 |
{ |
1413 |
unsigned int i = (T0 >> 3) & 0x3f;
|
|
1430 |
unsigned int i = (addr >> 3) & 0x3f;
|
|
1414 | 1431 |
|
1415 | 1432 |
env->dtlb_tag[i] = env->dmmuregs[6]; |
1416 |
env->dtlb_tte[i] = T1;
|
|
1433 |
env->dtlb_tte[i] = val;
|
|
1417 | 1434 |
return; |
1418 | 1435 |
} |
1419 | 1436 |
case 0x5f: // D-MMU demap |
... | ... | |
1434 | 1451 |
case 0x8a: // Primary no-fault LE, RO |
1435 | 1452 |
case 0x8b: // Secondary no-fault LE, RO |
1436 | 1453 |
default: |
1437 |
do_unassigned_access(T0, 1, 0, 1);
|
|
1454 |
do_unassigned_access(addr, 1, 0, 1);
|
|
1438 | 1455 |
return; |
1439 | 1456 |
} |
1440 | 1457 |
} |
1441 | 1458 |
#endif /* CONFIG_USER_ONLY */ |
1442 | 1459 |
|
1443 |
void helper_ldf_asi(int asi, int size, int rd) |
|
1460 |
void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
|
|
1444 | 1461 |
{ |
1445 |
target_ulong tmp_T0 = T0, tmp_T1 = T1; |
|
1446 | 1462 |
unsigned int i; |
1463 |
target_ulong val; |
|
1447 | 1464 |
|
1448 | 1465 |
switch (asi) { |
1449 | 1466 |
case 0xf0: // Block load primary |
... | ... | |
1454 | 1471 |
raise_exception(TT_ILL_INSN); |
1455 | 1472 |
return; |
1456 | 1473 |
} |
1457 |
if (T0 & 0x3f) {
|
|
1474 |
if (addr & 0x3f) {
|
|
1458 | 1475 |
raise_exception(TT_UNALIGNED); |
1459 | 1476 |
return; |
1460 | 1477 |
} |
1461 | 1478 |
for (i = 0; i < 16; i++) { |
1462 |
helper_ld_asi(asi & 0x8f, 4, 0); |
|
1463 |
*(uint32_t *)&env->fpr[rd++] = T1; |
|
1464 |
T0 += 4; |
|
1479 |
*(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4, 0); |
|
1480 |
addr += 4; |
|
1465 | 1481 |
} |
1466 |
T0 = tmp_T0; |
|
1467 |
T1 = tmp_T1; |
|
1468 | 1482 |
|
1469 | 1483 |
return; |
1470 | 1484 |
default: |
1471 | 1485 |
break; |
1472 | 1486 |
} |
1473 | 1487 |
|
1474 |
helper_ld_asi(asi, size, 0);
|
|
1488 |
val = helper_ld_asi(addr, asi, size, 0);
|
|
1475 | 1489 |
switch(size) { |
1476 | 1490 |
default: |
1477 | 1491 |
case 4: |
1478 |
*((uint32_t *)&FT0) = T1;
|
|
1492 |
*((uint32_t *)&FT0) = val;
|
|
1479 | 1493 |
break; |
1480 | 1494 |
case 8: |
1481 |
*((int64_t *)&DT0) = T1;
|
|
1495 |
*((int64_t *)&DT0) = val;
|
|
1482 | 1496 |
break; |
1483 | 1497 |
#if defined(CONFIG_USER_ONLY) |
1484 | 1498 |
case 16: |
... | ... | |
1486 | 1500 |
break; |
1487 | 1501 |
#endif |
1488 | 1502 |
} |
1489 |
T1 = tmp_T1; |
|
1490 | 1503 |
} |
1491 | 1504 |
|
1492 |
void helper_stf_asi(int asi, int size, int rd) |
|
1505 |
void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
|
|
1493 | 1506 |
{ |
1494 |
target_ulong tmp_T0 = T0, tmp_T1 = T1; |
|
1495 | 1507 |
unsigned int i; |
1508 |
target_ulong val = 0; |
|
1496 | 1509 |
|
1497 | 1510 |
switch (asi) { |
1498 | 1511 |
case 0xf0: // Block store primary |
... | ... | |
1503 | 1516 |
raise_exception(TT_ILL_INSN); |
1504 | 1517 |
return; |
1505 | 1518 |
} |
1506 |
if (T0 & 0x3f) {
|
|
1519 |
if (addr & 0x3f) {
|
|
1507 | 1520 |
raise_exception(TT_UNALIGNED); |
1508 | 1521 |
return; |
1509 | 1522 |
} |
1510 | 1523 |
for (i = 0; i < 16; i++) { |
1511 |
T1 = *(uint32_t *)&env->fpr[rd++];
|
|
1512 |
helper_st_asi(asi & 0x8f, 4); |
|
1513 |
T0 += 4;
|
|
1524 |
val = *(uint32_t *)&env->fpr[rd++];
|
|
1525 |
helper_st_asi(addr, val, asi & 0x8f, 4);
|
|
1526 |
addr += 4;
|
|
1514 | 1527 |
} |
1515 |
T0 = tmp_T0; |
|
1516 |
T1 = tmp_T1; |
|
1517 | 1528 |
|
1518 | 1529 |
return; |
1519 | 1530 |
default: |
... | ... | |
1523 | 1534 |
switch(size) { |
1524 | 1535 |
default: |
1525 | 1536 |
case 4: |
1526 |
T1 = *((uint32_t *)&FT0);
|
|
1537 |
val = *((uint32_t *)&FT0);
|
|
1527 | 1538 |
break; |
1528 | 1539 |
case 8: |
1529 |
T1 = *((int64_t *)&DT0);
|
|
1540 |
val = *((int64_t *)&DT0);
|
|
1530 | 1541 |
break; |
1531 | 1542 |
#if defined(CONFIG_USER_ONLY) |
1532 | 1543 |
case 16: |
... | ... | |
1534 | 1545 |
break; |
1535 | 1546 |
#endif |
1536 | 1547 |
} |
1537 |
helper_st_asi(asi, size); |
|
1538 |
T1 = tmp_T1; |
|
1548 |
helper_st_asi(addr, val, asi, size); |
|
1539 | 1549 |
} |
1540 | 1550 |
|
1551 |
target_ulong helper_cas_asi(target_ulong addr, target_ulong val1, |
|
1552 |
target_ulong val2, uint32_t asi) |
|
1553 |
{ |
|
1554 |
target_ulong ret; |
|
1555 |
|
|
1556 |
val1 &= 0xffffffffUL; |
|
1557 |
ret = helper_ld_asi(addr, asi, 4, 0); |
|
1558 |
ret &= 0xffffffffUL; |
|
1559 |
if (val1 == ret) |
|
1560 |
helper_st_asi(addr, val2 & 0xffffffffUL, asi, 4); |
|
1561 |
return ret; |
|
1562 |
} |
|
1563 |
|
|
1564 |
target_ulong helper_casx_asi(target_ulong addr, target_ulong val1, |
|
1565 |
target_ulong val2, uint32_t asi) |
|
1566 |
{ |
|
1567 |
target_ulong ret; |
|
1568 |
|
|
1569 |
ret = helper_ld_asi(addr, asi, 8, 0); |
|
1570 |
if (val1 == ret) |
|
1571 |
helper_st_asi(addr, val2, asi, 8); |
|
1572 |
return ret; |
|
1573 |
} |
|
1541 | 1574 |
#endif /* TARGET_SPARC64 */ |
1542 | 1575 |
|
1543 | 1576 |
#ifndef TARGET_SPARC64 |
1544 |
void helper_rett() |
|
1577 |
void helper_rett(void)
|
|
1545 | 1578 |
{ |
1546 | 1579 |
unsigned int cwp; |
1547 | 1580 |
|
... | ... | |
1558 | 1591 |
} |
1559 | 1592 |
#endif |
1560 | 1593 |
|
1594 |
uint64_t helper_pack64(target_ulong high, target_ulong low) |
|
1595 |
{ |
|
1596 |
return ((uint64_t)high << 32) | (uint64_t)(low & 0xffffffff); |
|
1597 |
} |
|
1598 |
|
|
1561 | 1599 |
void helper_ldfsr(void) |
1562 | 1600 |
{ |
1563 | 1601 |
int rnd_mode; |
... | ... | |
1586 | 1624 |
} |
1587 | 1625 |
|
1588 | 1626 |
#ifndef TARGET_SPARC64 |
1589 |
void do_wrpsr()
|
|
1627 |
void helper_wrpsr(target_ulong new_psr)
|
|
1590 | 1628 |
{ |
1591 |
if ((T0 & PSR_CWP) >= NWINDOWS)
|
|
1629 |
if ((new_psr & PSR_CWP) >= NWINDOWS)
|
|
1592 | 1630 |
raise_exception(TT_ILL_INSN); |
1593 | 1631 |
else |
1594 |
PUT_PSR(env, T0);
|
|
1632 |
PUT_PSR(env, new_psr);
|
|
1595 | 1633 |
} |
1596 | 1634 |
|
1597 |
void do_rdpsr()
|
|
1635 |
target_ulong helper_rdpsr(void)
|
|
1598 | 1636 |
{ |
1599 |
T0 = GET_PSR(env);
|
|
1637 |
return GET_PSR(env);
|
|
1600 | 1638 |
} |
1601 | 1639 |
|
1602 | 1640 |
#else |
1603 | 1641 |
|
1604 |
void do_popc()
|
|
1642 |
target_ulong helper_popc(target_ulong val)
|
|
1605 | 1643 |
{ |
1606 |
T0 = ctpop64(T1);
|
|
1644 |
return ctpop64(val);
|
|
1607 | 1645 |
} |
1608 | 1646 |
|
1609 | 1647 |
static inline uint64_t *get_gregset(uint64_t pstate) |
... | ... | |
1638 | 1676 |
env->pstate = new_pstate; |
1639 | 1677 |
} |
1640 | 1678 |
|
1641 |
void do_wrpstate(void)
|
|
1679 |
void helper_wrpstate(target_ulong new_state)
|
|
1642 | 1680 |
{ |
1643 |
change_pstate(T0 & 0xf3f);
|
|
1681 |
change_pstate(new_state & 0xf3f);
|
|
1644 | 1682 |
} |
1645 | 1683 |
|
1646 |
void do_done(void)
|
|
1684 |
void helper_done(void)
|
|
1647 | 1685 |
{ |
1648 | 1686 |
env->tl--; |
1649 | 1687 |
env->pc = env->tnpc[env->tl]; |
... | ... | |
1654 | 1692 |
PUT_CWP64(env, env->tstate[env->tl] & 0xff); |
1655 | 1693 |
} |
1656 | 1694 |
|
1657 |
void do_retry(void)
|
|
1695 |
void helper_retry(void)
|
|
1658 | 1696 |
{ |
1659 | 1697 |
env->tl--; |
1660 | 1698 |
env->pc = env->tpc[env->tl]; |
Also available in: Unified diff