X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=sim%2Ffrv%2Ffrv.c;h=2640b1c29c692c47daea0aeceb1e5f96349838c4;hb=c7a48b9ac9215f67421a769c2986b6eb2a69780b;hp=bd3220dcacf3ae6d52ced6eda4d4f12956022c48;hpb=f9e18f5a11abe959220c570da56b09cc0fd6fd62;p=deliverable%2Fbinutils-gdb.git diff --git a/sim/frv/frv.c b/sim/frv/frv.c index bd3220dcac..2640b1c29c 100644 --- a/sim/frv/frv.c +++ b/sim/frv/frv.c @@ -1,5 +1,6 @@ /* frv simulator support code - Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004 Free Software + Foundation, Inc. Contributed by Red Hat. This file is part of the GNU simulators. @@ -27,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cgen-engine.h" #include "cgen-par.h" #include "bfd.h" +#include "gdb/sim-frv.h" #include /* Maintain a flag in order to know when to write the address of the next @@ -38,18 +40,48 @@ int frvbf_write_next_vliw_addr_to_LR; int frvbf_fetch_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len) { - if (rn <= GR_REGNUM_MAX) - SETTSI (buf, GET_H_GR (rn)); - else if (rn <= FR_REGNUM_MAX) - SETTSI (buf, GET_H_FR (rn - GR_REGNUM_MAX - 1)); - else if (rn == PC_REGNUM) + if (SIM_FRV_GR0_REGNUM <= rn && rn <= SIM_FRV_GR63_REGNUM) + { + int hi_available, lo_available; + int grn = rn - SIM_FRV_GR0_REGNUM; + + frv_gr_registers_available (current_cpu, &hi_available, &lo_available); + + if ((grn < 32 && !lo_available) || (grn >= 32 && !hi_available)) + return 0; + else + SETTSI (buf, GET_H_GR (grn)); + } + else if (SIM_FRV_FR0_REGNUM <= rn && rn <= SIM_FRV_FR63_REGNUM) + { + int hi_available, lo_available; + int frn = rn - SIM_FRV_FR0_REGNUM; + + frv_fr_registers_available (current_cpu, &hi_available, &lo_available); + + if ((frn < 32 && !lo_available) || (frn >= 32 && !hi_available)) + return 0; + else + SETTSI (buf, GET_H_FR (frn)); + } + else if (rn == SIM_FRV_PC_REGNUM) SETTSI (buf, GET_H_PC ()); - else if (rn == LR_REGNUM) - SETTSI (buf, GET_H_SPR (H_SPR_LR)); + else if (SIM_FRV_SPR0_REGNUM <= rn && rn <= SIM_FRV_SPR4095_REGNUM) + { + /* Make sure the register is implemented. */ + FRV_REGISTER_CONTROL *control = CPU_REGISTER_CONTROL (current_cpu); + int spr = rn - SIM_FRV_SPR0_REGNUM; + if (! control->spr[spr].implemented) + return 0; + SETTSI (buf, GET_H_SPR (spr)); + } else - SETTSI (buf, 0xdeadbeef); + { + SETTSI (buf, 0xdeadbeef); + return 0; + } - return -1; + return len; } /* The contents of BUF are in target byte order. */ @@ -57,16 +89,45 @@ frvbf_fetch_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len) int frvbf_store_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len) { - if (rn <= GR_REGNUM_MAX) - SET_H_GR (rn, GETTSI (buf)); - else if (rn <= FR_REGNUM_MAX) - SET_H_FR (rn - GR_REGNUM_MAX - 1, GETTSI (buf)); - else if (rn == PC_REGNUM) + if (SIM_FRV_GR0_REGNUM <= rn && rn <= SIM_FRV_GR63_REGNUM) + { + int hi_available, lo_available; + int grn = rn - SIM_FRV_GR0_REGNUM; + + frv_gr_registers_available (current_cpu, &hi_available, &lo_available); + + if ((grn < 32 && !lo_available) || (grn >= 32 && !hi_available)) + return 0; + else + SET_H_GR (grn, GETTSI (buf)); + } + else if (SIM_FRV_FR0_REGNUM <= rn && rn <= SIM_FRV_FR63_REGNUM) + { + int hi_available, lo_available; + int frn = rn - SIM_FRV_FR0_REGNUM; + + frv_fr_registers_available (current_cpu, &hi_available, &lo_available); + + if ((frn < 32 && !lo_available) || (frn >= 32 && !hi_available)) + return 0; + else + SET_H_FR (frn, GETTSI (buf)); + } + else if (rn == SIM_FRV_PC_REGNUM) SET_H_PC (GETTSI (buf)); - else if (rn == LR_REGNUM) - SET_H_SPR (H_SPR_LR, GETTSI (buf)); + else if (SIM_FRV_SPR0_REGNUM <= rn && rn <= SIM_FRV_SPR4095_REGNUM) + { + /* Make sure the register is implemented. */ + FRV_REGISTER_CONTROL *control = CPU_REGISTER_CONTROL (current_cpu); + int spr = rn - SIM_FRV_SPR0_REGNUM; + if (! control->spr[spr].implemented) + return 0; + SET_H_SPR (spr, GETTSI (buf)); + } + else + return 0; - return -1; + return len; } /* Cover fns to access the general registers. */ @@ -113,6 +174,7 @@ check_register_alignment (SIM_CPU *current_cpu, UINT reg, int align_mask) switch (STATE_ARCHITECTURE (sd)->mach) { case bfd_mach_fr400: + case bfd_mach_fr550: frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); break; case bfd_mach_frvtomcat: @@ -140,6 +202,7 @@ check_fr_register_alignment (SIM_CPU *current_cpu, UINT reg, int align_mask) switch (STATE_ARCHITECTURE (sd)->mach) { case bfd_mach_fr400: + case bfd_mach_fr550: frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); break; case bfd_mach_frvtomcat: @@ -431,6 +494,9 @@ frvbf_h_spr_set_handler (SIM_CPU *current_cpu, UINT spr, USI newval) case H_SPR_SR3: spr_sr_set_handler (current_cpu, spr, newval); break; + case H_SPR_IHSR8: + frv_cache_reconfigure (current_cpu, CPU_INSN_CACHE (current_cpu)); + break; default: CPU (h_spr[spr]) = newval; break; @@ -926,9 +992,13 @@ frvbf_clear_accumulators (SIM_CPU *current_cpu, SI acc_ix, int A) SIM_DESC sd = CPU_STATE (current_cpu); int acc_num = (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr500) ? 8 : + (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) ? 8 : (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400) ? 4 : 63; + FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (current_cpu); + ps->mclracc_acc = acc_ix; + ps->mclracc_A = A; if (A == 0 || acc_ix != 0) /* Clear 1 accumuator? */ { /* This instruction is a nop if the referenced accumulator is not @@ -1027,6 +1097,93 @@ frvbf_media_cut_ss (SIM_CPU *current_cpu, DI acc, SI cut_point) return frvbf_media_cut (current_cpu, acc, cut_point); } +/* Compute the result of int accumulator cut (SCUTSS). */ +SI +frvbf_iacc_cut (SIM_CPU *current_cpu, DI acc, SI cut_point) +{ + DI lower, upper; + + /* The cut point is the lower 7 bits (signed) of what we are passed. */ + cut_point = cut_point << 25 >> 25; + + /* Conceptually, the operation is on a 128-bit sign-extension of ACC. + The top bit of the return value corresponds to bit (63 - CUT_POINT) + of this 128-bit value. + + Since we can't deal with 128-bit values very easily, convert the + operation into an equivalent 64-bit one. */ + if (cut_point < 0) + { + /* Avoid an undefined shift operation. */ + if (cut_point == -64) + acc >>= 63; + else + acc >>= -cut_point; + cut_point = 0; + } + + /* Get the shifted but unsaturated result. Set LOWER to the lowest + 32 bits of the result and UPPER to the result >> 31. */ + if (cut_point < 32) + { + /* The cut loses the (32 - CUT_POINT) least significant bits. + Round the result up if the most significant of these lost bits + is 1. */ + lower = acc >> (32 - cut_point); + if (lower < 0x7fffffff) + if (acc & LSBIT64 (32 - cut_point - 1)) + lower++; + upper = lower >> 31; + } + else + { + lower = acc << (cut_point - 32); + upper = acc >> (63 - cut_point); + } + + /* Saturate the result. */ + if (upper < -1) + return ~0x7fffffff; + else if (upper > 0) + return 0x7fffffff; + else + return lower; +} + +/* Compute the result of shift-left-arithmetic-with-saturation (SLASS). */ +SI +frvbf_shift_left_arith_saturate (SIM_CPU *current_cpu, SI arg1, SI arg2) +{ + int neg_arg1; + + /* FIXME: what to do with negative shift amt? */ + if (arg2 <= 0) + return arg1; + + if (arg1 == 0) + return 0; + + /* Signed shift by 31 or greater saturates by definition. */ + if (arg2 >= 31) + if (arg1 > 0) + return (SI) 0x7fffffff; + else + return (SI) 0x80000000; + + /* OK, arg2 is between 1 and 31. */ + neg_arg1 = (arg1 < 0); + do { + arg1 <<= 1; + /* Check for sign bit change (saturation). */ + if (neg_arg1 && (arg1 >= 0)) + return (SI) 0x80000000; + else if (!neg_arg1 && (arg1 < 0)) + return (SI) 0x7fffffff; + } while (--arg2 > 0); + + return arg1; +} + /* Simulate the media custom insns. */ void frvbf_media_cop (SIM_CPU *current_cpu, int cop_num) @@ -1051,12 +1208,13 @@ do_media_average (SIM_CPU *current_cpu, HI arg1, HI arg2) HI result = sum >> 1; int rounding_value; - /* On fr400, check the rounding mode. On other machines rounding is always + /* On fr400 and fr550, check the rounding mode. On other machines rounding is always toward negative infinity and the result is already correctly rounded. */ switch (STATE_ARCHITECTURE (sd)->mach) { /* Need to check rounding mode. */ case bfd_mach_fr400: + case bfd_mach_fr550: /* Check whether rounding will be required. Rounding will be required if the sum is an odd number. */ rounding_value = sum & 1;