X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=sim%2Ffrv%2Ffrv.c;h=fb683852d0338fa85adef4a0f453c3e557232ba4;hb=05e682e3be7e3d9d63ec358dcf8943fd200545cb;hp=bd3220dcacf3ae6d52ced6eda4d4f12956022c48;hpb=f9e18f5a11abe959220c570da56b09cc0fd6fd62;p=deliverable%2Fbinutils-gdb.git diff --git a/sim/frv/frv.c b/sim/frv/frv.c index bd3220dcac..fb683852d0 100644 --- a/sim/frv/frv.c +++ b/sim/frv/frv.c @@ -1,22 +1,21 @@ /* frv simulator support code - Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc. + Copyright (C) 1998-2020 Free Software Foundation, Inc. Contributed by Red Hat. This file is part of the GNU simulators. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License +along with this program. If not, see . */ #define WANT_CPU #define WANT_CPU_FRVBF @@ -27,6 +26,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 +38,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 +87,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. */ @@ -112,7 +171,16 @@ check_register_alignment (SIM_CPU *current_cpu, UINT reg, int align_mask) SIM_DESC sd = CPU_STATE (current_cpu); switch (STATE_ARCHITECTURE (sd)->mach) { + /* Note: there is a discrepancy between V2.2 of the FR400 + instruction manual and the various FR4xx LSI specs. + The former claims that unaligned registers cause a + register_exception while the latter say it's an + illegal_instruction. The LSI specs appear to be + correct; in fact, the FR4xx series is not documented + as having a register_exception. */ case bfd_mach_fr400: + case bfd_mach_fr450: + case bfd_mach_fr550: frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); break; case bfd_mach_frvtomcat: @@ -139,7 +207,10 @@ check_fr_register_alignment (SIM_CPU *current_cpu, UINT reg, int align_mask) SIM_DESC sd = CPU_STATE (current_cpu); switch (STATE_ARCHITECTURE (sd)->mach) { + /* See comment in check_register_alignment(). */ case bfd_mach_fr400: + case bfd_mach_fr450: + case bfd_mach_fr550: frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); break; case bfd_mach_frvtomcat: @@ -170,7 +241,9 @@ check_memory_alignment (SIM_CPU *current_cpu, SI address, int align_mask) SIM_DESC sd = CPU_STATE (current_cpu); switch (STATE_ARCHITECTURE (sd)->mach) { + /* See comment in check_register_alignment(). */ case bfd_mach_fr400: + case bfd_mach_fr450: frv_queue_data_access_error_interrupt (current_cpu, address); break; case bfd_mach_frvtomcat: @@ -230,7 +303,7 @@ frvbf_h_fr_double_get_handler (SIM_CPU *current_cpu, UINT fr) /* Check the register alignment. */ fr = check_fr_register_alignment (current_cpu, fr, 1); - if (CURRENT_HOST_BYTE_ORDER == LITTLE_ENDIAN) + if (HOST_BYTE_ORDER == BFD_ENDIAN_LITTLE) { value.as_sf[1] = GET_H_FR (fr); value.as_sf[0] = GET_H_FR (fr + 1); @@ -256,7 +329,7 @@ frvbf_h_fr_double_set_handler (SIM_CPU *current_cpu, UINT fr, DF newval) fr = check_fr_register_alignment (current_cpu, fr, 1); value.as_df = newval; - if (CURRENT_HOST_BYTE_ORDER == LITTLE_ENDIAN) + if (HOST_BYTE_ORDER == BFD_ENDIAN_LITTLE) { SET_H_FR (fr , value.as_sf[1]); SET_H_FR (fr + 1, value.as_sf[0]); @@ -431,6 +504,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; @@ -924,24 +1000,30 @@ void 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_fr400) ? 4 : + int acc_mask = + (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr500) ? 7 : + (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) ? 7 : + (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr450) ? 11 : + (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400) ? 3 : 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 implemented. */ - if (acc_ix < acc_num) + if ((acc_ix & acc_mask) == acc_ix) sim_queue_fn_di_write (current_cpu, frvbf_h_acc40S_set, acc_ix, 0); } else { /* Clear all implemented accumulators. */ int i; - for (i = 0; i < acc_num; ++i) - sim_queue_fn_di_write (current_cpu, frvbf_h_acc40S_set, i, 0); + for (i = 0; i <= acc_mask; ++i) + if ((i & acc_mask) == i) + sim_queue_fn_di_write (current_cpu, frvbf_h_acc40S_set, i, 0); } } @@ -972,6 +1054,7 @@ SI frvbf_cut (SIM_CPU *current_cpu, SI reg1, SI reg2, SI cut_point) { SI result; + cut_point &= 0x3f; if (cut_point < 32) { result = reg1 << cut_point; @@ -1027,6 +1110,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 +1221,15 @@ 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 - toward negative infinity and the result is already correctly rounded. */ + /* On fr4xx 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_fr450: + 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;