📄 frv.c
字号:
/* Compute the result of the cut insns. */SIfrvbf_media_cut (SIM_CPU *current_cpu, DI acc, SI cut_point){ /* The cut point is the lower 6 bits (signed) of what we are passed. */ cut_point = cut_point << 26 >> 26; /* The cut_point is relative to bit 40 of 64 bits. */ if (cut_point >= 0) return (acc << (cut_point + 24)) >> 32; /* Extend the sign bit (bit 40) for negative cuts. */ if (cut_point == -32) return (acc << 24) >> 63; /* Special case for full shiftout. */ return (acc << 24) >> (32 + -cut_point);}/* Compute the result of the cut insns. */SIfrvbf_media_cut_ss (SIM_CPU *current_cpu, DI acc, SI cut_point){ /* The cut point is the lower 6 bits (signed) of what we are passed. */ cut_point = cut_point << 26 >> 26; if (cut_point >= 0) { /* The cut_point is relative to bit 40 of 64 bits. */ DI shifted = acc << (cut_point + 24); DI unshifted = shifted >> (cut_point + 24); /* The result will be saturated if significant bits are shifted out. */ if (unshifted != acc) { if (acc < 0) return 0x80000000; return 0x7fffffff; } } /* The result will not be saturated, so use the code for the normal cut. */ return frvbf_media_cut (current_cpu, acc, cut_point);}/* Compute the result of int accumulator cut (SCUTSS). */SIfrvbf_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). */SIfrvbf_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. */voidfrvbf_media_cop (SIM_CPU *current_cpu, int cop_num){ /* The semantics of the insn are a nop, since it is implementation defined. We do need to check whether it's implemented and set up for MTRAP if it's not. */ USI msr0 = GET_MSR (0); if (GET_MSR_EMCI (msr0) == 0) { /* no interrupt queued at this time. */ frv_set_mp_exception_registers (current_cpu, MTT_UNIMPLEMENTED_MPOP, 0); }}/* Simulate the media average (MAVEH) insn. */static HIdo_media_average (SIM_CPU *current_cpu, HI arg1, HI arg2){ SIM_DESC sd = CPU_STATE (current_cpu); SI sum = (arg1 + arg2); HI result = sum >> 1; int rounding_value; /* 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; if (rounding_value) { USI msr0 = GET_MSR (0); /* Check MSR0.SRDAV to determine which bits control the rounding. */ if (GET_MSR_SRDAV (msr0)) { /* MSR0.RD controls rounding. */ switch (GET_MSR_RD (msr0)) { case 0: /* Round to nearest. */ if (result >= 0) ++result; break; case 1: /* Round toward 0. */ if (result < 0) ++result; break; case 2: /* Round toward positive infinity. */ ++result; break; case 3: /* Round toward negative infinity. The result is already correctly rounded. */ break; default: abort (); break; } } else { /* MSR0.RDAV controls rounding. If set, round toward positive infinity. Otherwise the result is already rounded correctly toward negative infinity. */ if (GET_MSR_RDAV (msr0)) ++result; } } break; default: break; } return result;}SIfrvbf_media_average (SIM_CPU *current_cpu, SI reg1, SI reg2){ SI result; result = do_media_average (current_cpu, reg1 & 0xffff, reg2 & 0xffff); result &= 0xffff; result |= do_media_average (current_cpu, (reg1 >> 16) & 0xffff, (reg2 >> 16) & 0xffff) << 16; return result;}/* Maintain a flag in order to know when to write the address of the next VLIW instruction into the LR register. Used by JMPL. JMPIL, and CALL. */voidfrvbf_set_write_next_vliw_addr_to_LR (SIM_CPU *current_cpu, int value){ frvbf_write_next_vliw_addr_to_LR = value;}voidfrvbf_set_ne_index (SIM_CPU *current_cpu, int index){ USI NE_flags[2]; /* Save the target register so interrupt processing can set its NE flag in the event of an exception. */ frv_interrupt_state.ne_index = index; /* Clear the NE flag of the target register. It will be reset if necessary in the event of an exception. */ GET_NE_FLAGS (NE_flags, H_SPR_FNER0); CLEAR_NE_FLAG (NE_flags, index); SET_NE_FLAGS (H_SPR_FNER0, NE_flags);}voidfrvbf_force_update (SIM_CPU *current_cpu){ CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (current_cpu); int ix = CGEN_WRITE_QUEUE_INDEX (q); if (ix > 0) { CGEN_WRITE_QUEUE_ELEMENT *item = CGEN_WRITE_QUEUE_ELEMENT (q, ix - 1); item->flags |= FRV_WRITE_QUEUE_FORCE_WRITE; }}/* Condition code logic. */enum cr_ops { andcr, orcr, xorcr, nandcr, norcr, andncr, orncr, nandncr, norncr, num_cr_ops};enum cr_result {cr_undefined, cr_undefined1, cr_false, cr_true};static enum cr_resultcr_logic[num_cr_ops][4][4] = { /* andcr */ { /* undefined undefined false true */ /* undefined */ {cr_undefined, cr_undefined, cr_undefined, cr_undefined}, /* undefined */ {cr_undefined, cr_undefined, cr_undefined, cr_undefined}, /* false */ {cr_undefined, cr_undefined, cr_undefined, cr_undefined}, /* true */ {cr_undefined, cr_undefined, cr_false, cr_true } }, /* orcr */ { /* undefined undefined false true */ /* undefined */ {cr_undefined, cr_undefined, cr_false, cr_true }, /* undefined */ {cr_undefined, cr_undefined, cr_false, cr_true }, /* false */ {cr_false, cr_false, cr_false, cr_true }, /* true */ {cr_true, cr_true, cr_true, cr_true } }, /* xorcr */ { /* undefined undefined false true */ /* undefined */ {cr_undefined, cr_undefined, cr_undefined, cr_undefined}, /* undefined */ {cr_undefined, cr_undefined, cr_undefined, cr_undefined}, /* false */ {cr_undefined, cr_undefined, cr_false, cr_true }, /* true */ {cr_true, cr_true, cr_true, cr_false } }, /* nandcr */ { /* undefined undefined false true */ /* undefined */ {cr_undefined, cr_undefined, cr_undefined, cr_undefined}, /* undefined */ {cr_undefined, cr_undefined, cr_undefined, cr_undefined}, /* false */ {cr_undefined, cr_undefined, cr_undefined, cr_undefined}, /* true */ {cr_undefined, cr_undefined, cr_true, cr_false } }, /* norcr */ { /* undefined undefined false true */ /* undefined */ {cr_undefined, cr_undefined, cr_true, cr_false }, /* undefined */ {cr_undefined, cr_undefined, cr_true, cr_false }, /* false */ {cr_true, cr_true, cr_true, cr_false }, /* true */ {cr_false, cr_false, cr_false, cr_false } }, /* andncr */ { /* undefined undefined false true */ /* undefined */ {cr_undefined, cr_undefined, cr_undefined, cr_undefined}, /* undefined */ {cr_undefined, cr_undefined, cr_undefined, cr_undefined}, /* false */ {cr_undefined, cr_undefined, cr_false, cr_true }, /* true */ {cr_undefined, cr_undefined, cr_undefined, cr_undefined} }, /* orncr */ { /* undefined undefined false true */ /* undefined */ {cr_undefined, cr_undefined, cr_false, cr_true }, /* undefined */ {cr_undefined, cr_undefined, cr_false, cr_true }, /* false */ {cr_true, cr_true, cr_true, cr_true }, /* true */ {cr_false, cr_false, cr_false, cr_true } }, /* nandncr */ { /* undefined undefined false true */ /* undefined */ {cr_undefined, cr_undefined, cr_undefined, cr_undefined}, /* undefined */ {cr_undefined, cr_undefined, cr_undefined, cr_undefined}, /* false */ {cr_undefined, cr_undefined, cr_true, cr_false }, /* true */ {cr_undefined, cr_undefined, cr_undefined, cr_undefined} }, /* norncr */ { /* undefined undefined false true */ /* undefined */ {cr_undefined, cr_undefined, cr_true, cr_false }, /* undefined */ {cr_undefined, cr_undefined, cr_true, cr_false }, /* false */ {cr_false, cr_false, cr_false, cr_false }, /* true */ {cr_true, cr_true, cr_true, cr_false } }};UQIfrvbf_cr_logic (SIM_CPU *current_cpu, SI operation, UQI arg1, UQI arg2){ return cr_logic[operation][arg1][arg2];}/* Cache Manipulation. */voidfrvbf_insn_cache_preload (SIM_CPU *current_cpu, SI address, USI length, int lock){ /* If we need to count cycles, then the cache operation will be initiated from the model profiling functions. See frvbf_model_.... */ int hsr0 = GET_HSR0 (); if (GET_HSR0_ICE (hsr0)) { if (model_insn) { CPU_LOAD_ADDRESS (current_cpu) = address; CPU_LOAD_LENGTH (current_cpu) = length; CPU_LOAD_LOCK (current_cpu) = lock; } else { FRV_CACHE *cache = CPU_INSN_CACHE (current_cpu); frv_cache_preload (cache, address, length, lock); } }}voidfrvbf_data_cache_preload (SIM_CPU *current_cpu, SI address, USI length, int lock){ /* If we need to count cycles, then the cache operation will be initiated from the model profiling functions. See frvbf_model_.... */ int hsr0 = GET_HSR0 (); if (GET_HSR0_DCE (hsr0)) { if (model_insn) { CPU_LOAD_ADDRESS (current_cpu) = address; CPU_LOAD_LENGTH (current_cpu) = length; CPU_LOAD_LOCK (current_cpu) = lock; } else { FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); frv_cache_preload (cache, address, length, lock); } }}voidfrvbf_insn_cache_unlock (SIM_CPU *current_cpu, SI address){ /* If we need to count cycles, then the cache operation will be initiated from the model profiling functions. See frvbf_model_.... */ int hsr0 = GET_HSR0 (); if (GET_HSR0_ICE (hsr0)) { if (model_insn) CPU_LOAD_ADDRESS (current_cpu) = address; else { FRV_CACHE *cache = CPU_INSN_CACHE (current_cpu); frv_cache_unlock (cache, address); } }}voidfrvbf_data_cache_unlock (SIM_CPU *current_cpu, SI address){ /* If we need to count cycles, then the cache operation will be initiated from the model profiling functions. See frvbf_model_.... */ int hsr0 = GET_HSR0 (); if (GET_HSR0_DCE (hsr0)) { if (model_insn) CPU_LOAD_ADDRESS (current_cpu) = address; else { FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); frv_cache_unlock (cache, address); } }}voidfrvbf_insn_cache_invalidate (SIM_CPU *current_cpu, SI address, int all){ /* Make sure the insn was specified properly. -1 will be passed for ALL for a icei with A=0. */ if (all == -1) { frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); return; } /* If we need to count cycles, then the cache operation will be initiated from the model profiling functions. See frvbf_model_.... */ if (model_insn) { /* Record the all-entries flag for use in profiling. */ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (current_cpu); ps->all_cache_entries = all; CPU_LOAD_ADDRESS (current_cpu) = address; } else { FRV_CACHE *cache = CPU_INSN_CACHE (current_cpu); if (all) frv_cache_invalidate_all (cache, 0/* flush? */); else frv_cache_invalidate (cache, address, 0/* flush? */); }}voidfrvbf_data_cache_invalidate (SIM_CPU *current_cpu, SI address, int all){ /* Make sure the insn was specified properly. -1 will be passed for ALL for a dcei with A=0. */ if (all == -1) { frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); return; } /* If we need to count cycles, then the cache operation will be initiated from the model profiling functions. See frvbf_model_.... */ if (model_insn) { /* Record the all-entries flag for use in profiling. */ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (current_cpu); ps->all_cache_entries = all; CPU_LOAD_ADDRESS (current_cpu) = address; } else { FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); if (all) frv_cache_invalidate_all (cache, 0/* flush? */); else frv_cache_invalidate (cache, address, 0/* flush? */); }}voidfrvbf_data_cache_flush (SIM_CPU *current_cpu, SI address, int all){ /* Make sure the insn was specified properly. -1 will be passed for ALL for a dcef with A=0. */ if (all == -1) { frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); return; } /* If we need to count cycles, then the cache operation will be initiated from the model profiling functions. See frvbf_model_.... */ if (model_insn) { /* Record the all-entries flag for use in profiling. */ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (current_cpu); ps->all_cache_entries = all; CPU_LOAD_ADDRESS (current_cpu) = address; } else { FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); if (all) frv_cache_invalidate_all (cache, 1/* flush? */); else frv_cache_invalidate (cache, address, 1/* flush? */); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -