1 |
/* |
/* |
2 |
* Copyright (C) 2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2005-2006 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_alpha_instr.c,v 1.2 2005/09/17 17:14:27 debug Exp $ |
* $Id: cpu_alpha_instr.c,v 1.14 2006/08/21 17:02:36 debug Exp $ |
29 |
* |
* |
30 |
* Alpha instructions. |
* Alpha instructions. |
31 |
* |
* |
36 |
*/ |
*/ |
37 |
|
|
38 |
|
|
39 |
|
#include "float_emul.h" |
40 |
|
|
41 |
|
|
42 |
/* |
/* |
43 |
* nop: Do nothing. |
* nop: Do nothing. |
44 |
*/ |
*/ |
65 |
alpha_palcode(cpu, ic->arg[0]); |
alpha_palcode(cpu, ic->arg[0]); |
66 |
|
|
67 |
if (!cpu->running) { |
if (!cpu->running) { |
|
cpu->running_translated = 0; |
|
68 |
cpu->n_translated_instrs --; |
cpu->n_translated_instrs --; |
69 |
cpu->cd.alpha.next_ic = ¬hing_call; |
cpu->cd.alpha.next_ic = ¬hing_call; |
70 |
} else if (cpu->pc != old_pc) { |
} else if (cpu->pc != old_pc) { |
457 |
|
|
458 |
|
|
459 |
/* |
/* |
460 |
|
* cvttq/c: Convert floating point to quad. |
461 |
|
* |
462 |
|
* arg[0] = pointer to rc (destination integer) |
463 |
|
* arg[2] = pointer to rb (source float) |
464 |
|
*/ |
465 |
|
X(cvttq_c) |
466 |
|
{ |
467 |
|
struct ieee_float_value fb; |
468 |
|
ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); |
469 |
|
reg(ic->arg[0]) = fb.nan? 0 : fb.f; |
470 |
|
} |
471 |
|
|
472 |
|
|
473 |
|
/* |
474 |
|
* cvtqt: Convert quad to floating point. |
475 |
|
* |
476 |
|
* arg[0] = pointer to rc (destination float) |
477 |
|
* arg[2] = pointer to rb (source quad integer) |
478 |
|
*/ |
479 |
|
X(cvtqt) |
480 |
|
{ |
481 |
|
reg(ic->arg[0]) = ieee_store_float_value(reg(ic->arg[2]), |
482 |
|
IEEE_FMT_D, 0); |
483 |
|
} |
484 |
|
|
485 |
|
|
486 |
|
/* |
487 |
|
* fabs, fneg: Floating point absolute value, or negation. |
488 |
|
* |
489 |
|
* arg[0] = pointer to rc (destination float) |
490 |
|
* arg[2] = pointer to rb (source quad integer) |
491 |
|
*/ |
492 |
|
X(fabs) |
493 |
|
{ |
494 |
|
reg(ic->arg[0]) = reg(ic->arg[2]) & 0x7fffffffffffffffULL; |
495 |
|
} |
496 |
|
X(fneg) |
497 |
|
{ |
498 |
|
reg(ic->arg[0]) = reg(ic->arg[2]) ^ 0x8000000000000000ULL; |
499 |
|
} |
500 |
|
|
501 |
|
|
502 |
|
/* |
503 |
|
* addt, subt, mult, divt: Floating point arithmetic. |
504 |
|
* |
505 |
|
* arg[0] = pointer to rc (destination) |
506 |
|
* arg[1] = pointer to ra (source) |
507 |
|
* arg[2] = pointer to rb (source) |
508 |
|
*/ |
509 |
|
X(addt) |
510 |
|
{ |
511 |
|
struct ieee_float_value fa, fb; |
512 |
|
double res; |
513 |
|
ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); |
514 |
|
ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); |
515 |
|
if (fa.nan | fb.nan) |
516 |
|
res = 0.0; |
517 |
|
else |
518 |
|
res = fa.f + fb.f; |
519 |
|
reg(ic->arg[0]) = ieee_store_float_value(res, |
520 |
|
IEEE_FMT_D, fa.nan | fb.nan); |
521 |
|
} |
522 |
|
X(subt) |
523 |
|
{ |
524 |
|
struct ieee_float_value fa, fb; |
525 |
|
double res; |
526 |
|
ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); |
527 |
|
ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); |
528 |
|
if (fa.nan | fb.nan) |
529 |
|
res = 0.0; |
530 |
|
else |
531 |
|
res = fa.f - fb.f; |
532 |
|
reg(ic->arg[0]) = ieee_store_float_value(res, |
533 |
|
IEEE_FMT_D, fa.nan | fb.nan); |
534 |
|
} |
535 |
|
X(mult) |
536 |
|
{ |
537 |
|
struct ieee_float_value fa, fb; |
538 |
|
double res; |
539 |
|
ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); |
540 |
|
ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); |
541 |
|
if (fa.nan | fb.nan) |
542 |
|
res = 0.0; |
543 |
|
else |
544 |
|
res = fa.f * fb.f; |
545 |
|
reg(ic->arg[0]) = ieee_store_float_value(res, |
546 |
|
IEEE_FMT_D, fa.nan | fb.nan); |
547 |
|
} |
548 |
|
X(divt) |
549 |
|
{ |
550 |
|
struct ieee_float_value fa, fb; |
551 |
|
double res; |
552 |
|
ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); |
553 |
|
ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); |
554 |
|
if (fa.nan | fb.nan || fb.f == 0) |
555 |
|
res = 0.0; |
556 |
|
else |
557 |
|
res = fa.f / fb.f; |
558 |
|
reg(ic->arg[0]) = ieee_store_float_value(res, |
559 |
|
IEEE_FMT_D, fa.nan | fb.nan || fb.f == 0); |
560 |
|
} |
561 |
|
X(cmpteq) |
562 |
|
{ |
563 |
|
struct ieee_float_value fa, fb; |
564 |
|
int res = 0; |
565 |
|
ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); |
566 |
|
ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); |
567 |
|
if (fa.nan | fb.nan) |
568 |
|
res = 0; |
569 |
|
else |
570 |
|
res = fa.f == fb.f; |
571 |
|
reg(ic->arg[0]) = res; |
572 |
|
} |
573 |
|
X(cmptlt) |
574 |
|
{ |
575 |
|
struct ieee_float_value fa, fb; |
576 |
|
int res = 0; |
577 |
|
ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); |
578 |
|
ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); |
579 |
|
if (fa.nan | fb.nan) |
580 |
|
res = 0; |
581 |
|
else |
582 |
|
res = fa.f < fb.f; |
583 |
|
reg(ic->arg[0]) = res; |
584 |
|
} |
585 |
|
X(cmptle) |
586 |
|
{ |
587 |
|
struct ieee_float_value fa, fb; |
588 |
|
int res = 0; |
589 |
|
ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); |
590 |
|
ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); |
591 |
|
if (fa.nan | fb.nan) |
592 |
|
res = 0; |
593 |
|
else |
594 |
|
res = fa.f <= fb.f; |
595 |
|
reg(ic->arg[0]) = res; |
596 |
|
} |
597 |
|
|
598 |
|
|
599 |
|
/* |
600 |
|
* implver: Return CPU implver value. |
601 |
|
* |
602 |
|
* arg[0] = pointer to destination uint64_t |
603 |
|
*/ |
604 |
|
X(implver) |
605 |
|
{ |
606 |
|
reg(ic->arg[0]) = cpu->cd.alpha.cpu_type.implver; |
607 |
|
} |
608 |
|
|
609 |
|
|
610 |
|
/* |
611 |
* mull: Signed Multiply 32x32 => 32. |
* mull: Signed Multiply 32x32 => 32. |
612 |
* |
* |
613 |
* arg[0] = pointer to destination uint64_t |
* arg[0] = pointer to destination uint64_t |
748 |
|
|
749 |
|
|
750 |
/* |
/* |
|
* alpha_combine_instructions(): |
|
|
* |
|
|
* Combine two or more instructions, if possible, into a single function call. |
|
|
*/ |
|
|
void alpha_combine_instructions(struct cpu *cpu, struct alpha_instr_call *ic, |
|
|
uint64_t addr) |
|
|
{ |
|
|
int n_back; |
|
|
n_back = (addr >> 2) & (ALPHA_IC_ENTRIES_PER_PAGE-1); |
|
|
|
|
|
if (n_back >= 1) { |
|
|
} |
|
|
|
|
|
/* TODO: Combine forward as well */ |
|
|
} |
|
|
|
|
|
|
|
|
/*****************************************************************************/ |
|
|
|
|
|
|
|
|
/* |
|
751 |
* alpha_instr_to_be_translated(): |
* alpha_instr_to_be_translated(): |
752 |
* |
* |
753 |
* Translate an instruction word into an alpha_instr_call. ic is filled in with |
* Translate an instruction word into an alpha_instr_call. ic is filled in with |
759 |
{ |
{ |
760 |
uint64_t addr, low_pc; |
uint64_t addr, low_pc; |
761 |
uint32_t iword; |
uint32_t iword; |
|
struct alpha_vph_page *vph_p; |
|
762 |
unsigned char *page; |
unsigned char *page; |
763 |
unsigned char ib[4]; |
unsigned char ib[4]; |
764 |
void (*samepage_function)(struct cpu *, struct alpha_instr_call *); |
void (*samepage_function)(struct cpu *, struct alpha_instr_call *); |
774 |
cpu->pc = addr; |
cpu->pc = addr; |
775 |
|
|
776 |
/* Read the instruction word from memory: */ |
/* Read the instruction word from memory: */ |
777 |
if ((addr >> ALPHA_TOPSHIFT) == 0) { |
{ |
778 |
vph_p = cpu->cd.alpha.vph_table0[(addr >> |
const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1; |
779 |
ALPHA_LEVEL0_SHIFT) & 8191]; |
const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1; |
780 |
page = vph_p->host_load[(addr >> ALPHA_LEVEL1_SHIFT) & 8191]; |
const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1; |
781 |
} else if ((addr >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) { |
uint32_t x1 = (addr >> (64-DYNTRANS_L1N)) & mask1; |
782 |
vph_p = cpu->cd.alpha.vph_table0_kernel[(addr >> |
uint32_t x2 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; |
783 |
ALPHA_LEVEL0_SHIFT) & 8191]; |
uint32_t x3 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N- |
784 |
page = vph_p->host_load[(addr >> ALPHA_LEVEL1_SHIFT) & 8191]; |
DYNTRANS_L3N)) & mask3; |
785 |
} else |
struct DYNTRANS_L2_64_TABLE *l2 = cpu->cd.alpha.l1_64[x1]; |
786 |
page = NULL; |
struct DYNTRANS_L3_64_TABLE *l3 = l2->l3[x2]; |
787 |
|
page = l3->host_load[x3]; |
788 |
|
} |
789 |
|
|
790 |
if (page != NULL) { |
if (page != NULL) { |
791 |
/* fatal("TRANSLATION HIT!\n"); */ |
/* fatal("TRANSLATION HIT!\n"); */ |
799 |
} |
} |
800 |
} |
} |
801 |
|
|
802 |
#ifdef HOST_LITTLE_ENDIAN |
/* Alpha instruction words are always little-endian. Convert |
803 |
iword = *((uint32_t *)&ib[0]); |
to host order: */ |
804 |
#else |
iword = LE32_TO_HOST( *((uint32_t *)&ib[0]) ); |
|
iword = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24); |
|
|
#endif |
|
|
|
|
|
/* fatal("{ Alpha: translating pc=0x%016llx iword=0x%08x }\n", |
|
|
(long long)addr, (int)iword); */ |
|
805 |
|
|
806 |
|
|
807 |
#define DYNTRANS_TO_BE_TRANSLATED_HEAD |
#define DYNTRANS_TO_BE_TRANSLATED_HEAD |
889 |
} |
} |
890 |
ic->f = alpha_loadstore[ |
ic->f = alpha_loadstore[ |
891 |
loadstore_type + (imm==0? 4 : 0) + 8 * load |
loadstore_type + (imm==0? 4 : 0) + 8 * load |
892 |
+ (cpu->machine->dyntrans_alignment_check? 16:0) |
+ 16 * llsc]; |
|
+ 32 * llsc]; |
|
893 |
/* Load to the zero register is treated as a prefetch |
/* Load to the zero register is treated as a prefetch |
894 |
hint. It is ignored here. */ |
hint. It is ignored here. */ |
895 |
if (load && ra == ALPHA_ZERO) { |
if (load && ra == ALPHA_ZERO) { |
919 |
case 0x02: ic->f = instr(s4addl); break; |
case 0x02: ic->f = instr(s4addl); break; |
920 |
case 0x09: ic->f = instr(subl); break; |
case 0x09: ic->f = instr(subl); break; |
921 |
case 0x0b: ic->f = instr(s4subl); break; |
case 0x0b: ic->f = instr(s4subl); break; |
922 |
|
case 0x0f: ic->f = instr(cmpbge); break; |
923 |
case 0x12: ic->f = instr(s8addl); break; |
case 0x12: ic->f = instr(s8addl); break; |
924 |
case 0x1b: ic->f = instr(s8subl); break; |
case 0x1b: ic->f = instr(s8subl); break; |
925 |
case 0x1d: ic->f = instr(cmpult); break; |
case 0x1d: ic->f = instr(cmpult); break; |
938 |
case 0x82: ic->f = instr(s4addl_imm); break; |
case 0x82: ic->f = instr(s4addl_imm); break; |
939 |
case 0x89: ic->f = instr(subl_imm); break; |
case 0x89: ic->f = instr(subl_imm); break; |
940 |
case 0x8b: ic->f = instr(s4subl_imm); break; |
case 0x8b: ic->f = instr(s4subl_imm); break; |
941 |
|
case 0x8f: ic->f = instr(cmpbge_imm); break; |
942 |
case 0x92: ic->f = instr(s8addl_imm); break; |
case 0x92: ic->f = instr(s8addl_imm); break; |
943 |
case 0x9b: ic->f = instr(s8subl_imm); break; |
case 0x9b: ic->f = instr(s8subl_imm); break; |
944 |
case 0x9d: ic->f = instr(cmpult_imm); break; |
case 0x9d: ic->f = instr(cmpult_imm); break; |
1004 |
case 0xc8: ic->f = instr(xornot_imm); break; |
case 0xc8: ic->f = instr(xornot_imm); break; |
1005 |
case 0xe4: ic->f = instr(cmovle_imm); break; |
case 0xe4: ic->f = instr(cmovle_imm); break; |
1006 |
case 0xe6: ic->f = instr(cmovgt_imm); break; |
case 0xe6: ic->f = instr(cmovgt_imm); break; |
1007 |
|
case 0xec: ic->f = instr(implver); break; |
1008 |
default:fatal("[ Alpha: unimplemented function 0x%03x for" |
default:fatal("[ Alpha: unimplemented function 0x%03x for" |
1009 |
" opcode 0x%02x ]\n", func, opcode); |
" opcode 0x%02x ]\n", func, opcode); |
1010 |
goto bad; |
goto bad; |
1108 |
ic->arg[1] = (size_t) &cpu->cd.alpha.f[ra]; |
ic->arg[1] = (size_t) &cpu->cd.alpha.f[ra]; |
1109 |
ic->arg[2] = (size_t) &cpu->cd.alpha.f[rb]; |
ic->arg[2] = (size_t) &cpu->cd.alpha.f[rb]; |
1110 |
switch (func & 0x7ff) { |
switch (func & 0x7ff) { |
1111 |
|
case 0x02f: ic->f = instr(cvttq_c); break; |
1112 |
|
case 0x0a0: ic->f = instr(addt); break; |
1113 |
|
case 0x0a1: ic->f = instr(subt); break; |
1114 |
|
case 0x0a2: ic->f = instr(mult); break; |
1115 |
|
case 0x0a3: ic->f = instr(divt); break; |
1116 |
|
case 0x0a5: ic->f = instr(cmpteq); break; |
1117 |
|
case 0x0a6: ic->f = instr(cmptlt); break; |
1118 |
|
case 0x0a7: ic->f = instr(cmptle); break; |
1119 |
|
case 0x0be: ic->f = instr(cvtqt); break; |
1120 |
default:fatal("[ Alpha: unimplemented function 0x%03x for" |
default:fatal("[ Alpha: unimplemented function 0x%03x for" |
1121 |
" opcode 0x%02x ]\n", func, opcode); |
" opcode 0x%02x ]\n", func, opcode); |
1122 |
goto bad; |
goto bad; |
1132 |
ic->arg[2] = (size_t) &cpu->cd.alpha.f[rb]; |
ic->arg[2] = (size_t) &cpu->cd.alpha.f[rb]; |
1133 |
switch (func & 0x7ff) { |
switch (func & 0x7ff) { |
1134 |
case 0x020: |
case 0x020: |
1135 |
/* fclr: */ |
/* fabs (or fclr): */ |
1136 |
if (ra == 31 && rb == 31) |
if (ra == 31 && rb == 31) |
1137 |
ic->f = instr(clear); |
ic->f = instr(clear); |
1138 |
else { |
else |
1139 |
/* fabs: */ |
ic->f = instr(fabs); |
1140 |
goto bad; |
break; |
1141 |
} |
case 0x021: |
1142 |
|
ic->f = instr(fneg); |
1143 |
break; |
break; |
1144 |
default:fatal("[ Alpha: unimplemented function 0x%03x for" |
default:fatal("[ Alpha: unimplemented function 0x%03x for" |
1145 |
" opcode 0x%02x ]\n", func, opcode); |
" opcode 0x%02x ]\n", func, opcode); |
1190 |
goto bad; |
goto bad; |
1191 |
} |
} |
1192 |
break; |
break; |
1193 |
case 0x30: /* BR */ |
case 0x30: /* BR */ |
1194 |
case 0x34: /* BSR */ |
case 0x31: /* FBEQ */ |
1195 |
|
case 0x34: /* BSR */ |
1196 |
|
case 0x35: /* FBNE */ |
1197 |
case 0x38: /* BLBC */ |
case 0x38: /* BLBC */ |
1198 |
case 0x39: /* BEQ */ |
case 0x39: /* BEQ */ |
1199 |
case 0x3a: /* BLT */ |
case 0x3a: /* BLT */ |
1200 |
case 0x3b: /* BLE */ |
case 0x3b: /* BLE */ |
1201 |
case 0x3c: /* BLBS */ |
case 0x3c: /* BLBS */ |
1202 |
case 0x3d: /* BNE */ |
case 0x3d: /* BNE */ |
1203 |
case 0x3e: /* BGE */ |
case 0x3e: /* BGE */ |
1204 |
case 0x3f: /* BGT */ |
case 0x3f: /* BGT */ |
1205 |
/* To avoid a GCC warning: */ |
/* To avoid a GCC warning: */ |
1206 |
samepage_function = instr(nop); |
samepage_function = instr(nop); |
1207 |
|
fp = 0; |
1208 |
switch (opcode) { |
switch (opcode) { |
1209 |
case 0x30: |
case 0x30: |
1210 |
case 0x34: |
case 0x34: |
1219 |
ic->f = instr(blbc); |
ic->f = instr(blbc); |
1220 |
samepage_function = instr(blbc_samepage); |
samepage_function = instr(blbc_samepage); |
1221 |
break; |
break; |
1222 |
|
case 0x31: |
1223 |
|
fp = 1; |
1224 |
case 0x39: |
case 0x39: |
1225 |
ic->f = instr(beq); |
ic->f = instr(beq); |
1226 |
samepage_function = instr(beq_samepage); |
samepage_function = instr(beq_samepage); |
1237 |
ic->f = instr(blbs); |
ic->f = instr(blbs); |
1238 |
samepage_function = instr(blbs_samepage); |
samepage_function = instr(blbs_samepage); |
1239 |
break; |
break; |
1240 |
|
case 0x35: |
1241 |
|
fp = 1; |
1242 |
case 0x3d: |
case 0x3d: |
1243 |
ic->f = instr(bne); |
ic->f = instr(bne); |
1244 |
samepage_function = instr(bne_samepage); |
samepage_function = instr(bne_samepage); |
1252 |
samepage_function = instr(bgt_samepage); |
samepage_function = instr(bgt_samepage); |
1253 |
break; |
break; |
1254 |
} |
} |
1255 |
ic->arg[1] = (size_t) &cpu->cd.alpha.r[ra]; |
if (fp) |
1256 |
|
ic->arg[1] = (size_t) &cpu->cd.alpha.f[ra]; |
1257 |
|
else |
1258 |
|
ic->arg[1] = (size_t) &cpu->cd.alpha.r[ra]; |
1259 |
ic->arg[0] = (iword & 0x001fffff) << 2; |
ic->arg[0] = (iword & 0x001fffff) << 2; |
1260 |
/* Sign-extend: */ |
/* Sign-extend: */ |
1261 |
if (ic->arg[0] & 0x00400000) |
if (ic->arg[0] & 0x00400000) |