--- trunk/src/cpus/cpu_alpha_instr.c 2007/10/08 16:19:23 20 +++ trunk/src/cpus/cpu_alpha_instr.c 2007/10/08 16:20:26 28 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Anders Gavare. All rights reserved. + * Copyright (C) 2005-2006 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_alpha_instr.c,v 1.3 2005/11/06 22:41:11 debug Exp $ + * $Id: cpu_alpha_instr.c,v 1.12 2006/06/30 20:22:53 debug Exp $ * * Alpha instructions. * @@ -36,6 +36,9 @@ */ +#include "float_emul.h" + + /* * nop: Do nothing. */ @@ -455,6 +458,146 @@ /* + * cvttq/c: Convert floating point to quad. + * + * arg[0] = pointer to rc (destination integer) + * arg[2] = pointer to rb (source float) + */ +X(cvttq_c) +{ + struct ieee_float_value fb; + ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); + reg(ic->arg[0]) = fb.nan? 0 : fb.f; +} + + +/* + * cvtqt: Convert quad to floating point. + * + * arg[0] = pointer to rc (destination float) + * arg[2] = pointer to rb (source quad integer) + */ +X(cvtqt) +{ + reg(ic->arg[0]) = ieee_store_float_value(reg(ic->arg[2]), + IEEE_FMT_D, 0); +} + + +/* + * fabs, fneg: Floating point absolute value, or negation. + * + * arg[0] = pointer to rc (destination float) + * arg[2] = pointer to rb (source quad integer) + */ +X(fabs) +{ + reg(ic->arg[0]) = reg(ic->arg[2]) & 0x7fffffffffffffffULL; +} +X(fneg) +{ + reg(ic->arg[0]) = reg(ic->arg[2]) ^ 0x8000000000000000ULL; +} + + +/* + * addt, subt, mult, divt: Floating point arithmetic. + * + * arg[0] = pointer to rc (destination) + * arg[1] = pointer to ra (source) + * arg[2] = pointer to rb (source) + */ +X(addt) +{ + struct ieee_float_value fa, fb; + double res; + ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); + ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); + if (fa.nan | fb.nan) + res = 0.0; + else + res = fa.f + fb.f; + reg(ic->arg[0]) = ieee_store_float_value(res, + IEEE_FMT_D, fa.nan | fb.nan); +} +X(subt) +{ + struct ieee_float_value fa, fb; + double res; + ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); + ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); + if (fa.nan | fb.nan) + res = 0.0; + else + res = fa.f - fb.f; + reg(ic->arg[0]) = ieee_store_float_value(res, + IEEE_FMT_D, fa.nan | fb.nan); +} +X(mult) +{ + struct ieee_float_value fa, fb; + double res; + ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); + ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); + if (fa.nan | fb.nan) + res = 0.0; + else + res = fa.f * fb.f; + reg(ic->arg[0]) = ieee_store_float_value(res, + IEEE_FMT_D, fa.nan | fb.nan); +} +X(divt) +{ + struct ieee_float_value fa, fb; + double res; + ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); + ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); + if (fa.nan | fb.nan || fb.f == 0) + res = 0.0; + else + res = fa.f / fb.f; + reg(ic->arg[0]) = ieee_store_float_value(res, + IEEE_FMT_D, fa.nan | fb.nan || fb.f == 0); +} +X(cmpteq) +{ + struct ieee_float_value fa, fb; + int res = 0; + ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); + ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); + if (fa.nan | fb.nan) + res = 0; + else + res = fa.f == fb.f; + reg(ic->arg[0]) = res; +} +X(cmptlt) +{ + struct ieee_float_value fa, fb; + int res = 0; + ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); + ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); + if (fa.nan | fb.nan) + res = 0; + else + res = fa.f < fb.f; + reg(ic->arg[0]) = res; +} +X(cmptle) +{ + struct ieee_float_value fa, fb; + int res = 0; + ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); + ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); + if (fa.nan | fb.nan) + res = 0; + else + res = fa.f <= fb.f; + reg(ic->arg[0]) = res; +} + + +/* * mull: Signed Multiply 32x32 => 32. * * arg[0] = pointer to destination uint64_t @@ -606,7 +749,6 @@ { uint64_t addr, low_pc; uint32_t iword; - struct alpha_vph_page *vph_p; unsigned char *page; unsigned char ib[4]; void (*samepage_function)(struct cpu *, struct alpha_instr_call *); @@ -622,16 +764,18 @@ cpu->pc = addr; /* Read the instruction word from memory: */ - if ((addr >> ALPHA_TOPSHIFT) == 0) { - vph_p = cpu->cd.alpha.vph_table0[(addr >> - ALPHA_LEVEL0_SHIFT) & 8191]; - page = vph_p->host_load[(addr >> ALPHA_LEVEL1_SHIFT) & 8191]; - } else if ((addr >> ALPHA_TOPSHIFT) == ALPHA_TOP_KERNEL) { - vph_p = cpu->cd.alpha.vph_table0_kernel[(addr >> - ALPHA_LEVEL0_SHIFT) & 8191]; - page = vph_p->host_load[(addr >> ALPHA_LEVEL1_SHIFT) & 8191]; - } else - page = NULL; + { + const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1; + const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1; + const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1; + uint32_t x1 = (addr >> (64-DYNTRANS_L1N)) & mask1; + uint32_t x2 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; + uint32_t x3 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N- + DYNTRANS_L3N)) & mask3; + struct DYNTRANS_L2_64_TABLE *l2 = cpu->cd.alpha.l1_64[x1]; + struct DYNTRANS_L3_64_TABLE *l3 = l2->l3[x2]; + page = l3->host_load[x3]; + } if (page != NULL) { /* fatal("TRANSLATION HIT!\n"); */ @@ -645,14 +789,9 @@ } } -#ifdef HOST_LITTLE_ENDIAN - iword = *((uint32_t *)&ib[0]); -#else - 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); */ + /* Alpha instruction words are always little-endian. Convert + to host order: */ + iword = LE32_TO_HOST( *((uint32_t *)&ib[0]) ); #define DYNTRANS_TO_BE_TRANSLATED_HEAD @@ -740,8 +879,7 @@ } ic->f = alpha_loadstore[ loadstore_type + (imm==0? 4 : 0) + 8 * load - + (cpu->machine->dyntrans_alignment_check? 16:0) - + 32 * llsc]; + + 16 * llsc]; /* Load to the zero register is treated as a prefetch hint. It is ignored here. */ if (load && ra == ALPHA_ZERO) { @@ -771,6 +909,7 @@ case 0x02: ic->f = instr(s4addl); break; case 0x09: ic->f = instr(subl); break; case 0x0b: ic->f = instr(s4subl); break; + case 0x0f: ic->f = instr(cmpbge); break; case 0x12: ic->f = instr(s8addl); break; case 0x1b: ic->f = instr(s8subl); break; case 0x1d: ic->f = instr(cmpult); break; @@ -789,6 +928,7 @@ case 0x82: ic->f = instr(s4addl_imm); break; case 0x89: ic->f = instr(subl_imm); break; case 0x8b: ic->f = instr(s4subl_imm); break; + case 0x8f: ic->f = instr(cmpbge_imm); break; case 0x92: ic->f = instr(s8addl_imm); break; case 0x9b: ic->f = instr(s8subl_imm); break; case 0x9d: ic->f = instr(cmpult_imm); break; @@ -957,6 +1097,15 @@ ic->arg[1] = (size_t) &cpu->cd.alpha.f[ra]; ic->arg[2] = (size_t) &cpu->cd.alpha.f[rb]; switch (func & 0x7ff) { + case 0x02f: ic->f = instr(cvttq_c); break; + case 0x0a0: ic->f = instr(addt); break; + case 0x0a1: ic->f = instr(subt); break; + case 0x0a2: ic->f = instr(mult); break; + case 0x0a3: ic->f = instr(divt); break; + case 0x0a5: ic->f = instr(cmpteq); break; + case 0x0a6: ic->f = instr(cmptlt); break; + case 0x0a7: ic->f = instr(cmptle); break; + case 0x0be: ic->f = instr(cvtqt); break; default:fatal("[ Alpha: unimplemented function 0x%03x for" " opcode 0x%02x ]\n", func, opcode); goto bad; @@ -972,13 +1121,14 @@ ic->arg[2] = (size_t) &cpu->cd.alpha.f[rb]; switch (func & 0x7ff) { case 0x020: - /* fclr: */ + /* fabs (or fclr): */ if (ra == 31 && rb == 31) ic->f = instr(clear); - else { - /* fabs: */ - goto bad; - } + else + ic->f = instr(fabs); + break; + case 0x021: + ic->f = instr(fneg); break; default:fatal("[ Alpha: unimplemented function 0x%03x for" " opcode 0x%02x ]\n", func, opcode); @@ -1029,18 +1179,21 @@ goto bad; } break; - case 0x30: /* BR */ - case 0x34: /* BSR */ + case 0x30: /* BR */ + case 0x31: /* FBEQ */ + case 0x34: /* BSR */ + case 0x35: /* FBNE */ case 0x38: /* BLBC */ - case 0x39: /* BEQ */ - case 0x3a: /* BLT */ - case 0x3b: /* BLE */ + case 0x39: /* BEQ */ + case 0x3a: /* BLT */ + case 0x3b: /* BLE */ case 0x3c: /* BLBS */ - case 0x3d: /* BNE */ - case 0x3e: /* BGE */ - case 0x3f: /* BGT */ + case 0x3d: /* BNE */ + case 0x3e: /* BGE */ + case 0x3f: /* BGT */ /* To avoid a GCC warning: */ samepage_function = instr(nop); + fp = 0; switch (opcode) { case 0x30: case 0x34: @@ -1055,6 +1208,8 @@ ic->f = instr(blbc); samepage_function = instr(blbc_samepage); break; + case 0x31: + fp = 1; case 0x39: ic->f = instr(beq); samepage_function = instr(beq_samepage); @@ -1071,6 +1226,8 @@ ic->f = instr(blbs); samepage_function = instr(blbs_samepage); break; + case 0x35: + fp = 1; case 0x3d: ic->f = instr(bne); samepage_function = instr(bne_samepage); @@ -1084,7 +1241,10 @@ samepage_function = instr(bgt_samepage); break; } - ic->arg[1] = (size_t) &cpu->cd.alpha.r[ra]; + if (fp) + ic->arg[1] = (size_t) &cpu->cd.alpha.f[ra]; + else + ic->arg[1] = (size_t) &cpu->cd.alpha.r[ra]; ic->arg[0] = (iword & 0x001fffff) << 2; /* Sign-extend: */ if (ic->arg[0] & 0x00400000)