Commit 599bc5e8 authored by Aleksandar Markovic's avatar Aleksandar Markovic Committed by Leon Alrae
Browse files

target-mips: Implement FCR31's R/W bitmask and related functionalities



This patch implements read and write access rules for Mips floating
point control and status register (FCR31). The change can be divided
into following parts:

- Add fields that will keep FCR31's R/W bitmask in procesor
  definitions and processor float_status structure.

- Add appropriate value for FCR31's R/W bitmask for each supported
  processor.

- Add function for setting snan_bit_is_one, and integrate it in
  appropriate places.

- Modify handling of CTC1 (case 31) instruction to use FCR31's R/W
  bitmask.

- Modify handling user mode executables for Mips, in relation to the
  bit EF_MIPS_NAN2008 from ELF header, that is in turn related to
  reading and writing to FCR31.

- Modify gdb behavior in relation to FCR31.

Signed-off-by: default avatarThomas Schwinge <thomas@codesourcery.com>
Signed-off-by: default avatarMaciej W. Rozycki <macro@codesourcery.com>
Signed-off-by: default avatarAleksandar Markovic <aleksandar.markovic@imgtec.com>
Reviewed-by: default avatarLeon Alrae <leon.alrae@imgtec.com>
Signed-off-by: default avatarLeon Alrae <leon.alrae@imgtec.com>
parent 87552089
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -4687,6 +4687,20 @@ int main(int argc, char **argv, char **envp)
        if (regs->cp0_epc & 1) {
            env->hflags |= MIPS_HFLAG_M16;
        }
        if (((info->elf_flags & EF_MIPS_NAN2008) != 0) !=
            ((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) != 0)) {
            if ((env->active_fpu.fcr31_rw_bitmask &
                  (1 << FCR31_NAN2008)) == 0) {
                fprintf(stderr, "ELF binary's NaN mode not supported by CPU\n");
                exit(1);
            }
            if ((info->elf_flags & EF_MIPS_NAN2008) != 0) {
                env->active_fpu.fcr31 |= (1 << FCR31_NAN2008);
            } else {
                env->active_fpu.fcr31 &= ~(1 << FCR31_NAN2008);
            }
            restore_snan_bit_mode(env);
        }
    }
#elif defined(TARGET_OPENRISC)
    {
+8 −0
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ struct CPUMIPSFPUContext {
#define FCR0_PRID 8
#define FCR0_REV 0
    /* fcsr */
    uint32_t fcr31_rw_bitmask;
    uint32_t fcr31;
#define FCR31_ABS2008 19
#define FCR31_NAN2008 18
@@ -853,10 +854,17 @@ static inline void restore_flush_mode(CPUMIPSState *env)
                      &env->active_fpu.fp_status);
}

static inline void restore_snan_bit_mode(CPUMIPSState *env)
{
    set_snan_bit_is_one((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) == 0,
                        &env->active_fpu.fp_status);
}

static inline void restore_fp_status(CPUMIPSState *env)
{
    restore_rounding_mode(env);
    restore_flush_mode(env);
    restore_snan_bit_mode(env);
}

static inline void restore_msa_fp_status(CPUMIPSState *env)
+3 −5
Original line number Diff line number Diff line
@@ -90,11 +90,9 @@ int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
    if (env->CP0_Config1 & (1 << CP0C1_FP) && n >= 38 && n < 72) {
        switch (n) {
        case 70:
            env->active_fpu.fcr31 = tmp & 0xFF83FFFF;
            /* set rounding mode */
            restore_rounding_mode(env);
            /* set flush-to-zero mode */
            restore_flush_mode(env);
            env->active_fpu.fcr31 = (tmp & env->active_fpu.fcr31_rw_bitmask) |
                  (env->active_fpu.fcr31 & ~(env->active_fpu.fcr31_rw_bitmask));
            restore_fp_status(env);
            break;
        case 71:
            /* FIR is read-only.  Ignore writes.  */
+3 −11
Original line number Diff line number Diff line
@@ -2575,21 +2575,13 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
                     ((arg1 & 0x4) << 22);
        break;
    case 31:
        if (env->insn_flags & ISA_MIPS32R6) {
            uint32_t mask = 0xfefc0000;
            env->active_fpu.fcr31 = (arg1 & ~mask) |
                (env->active_fpu.fcr31 & mask);
        } else if (!(arg1 & 0x007c0000)) {
            env->active_fpu.fcr31 = arg1;
        }
        env->active_fpu.fcr31 = (arg1 & env->active_fpu.fcr31_rw_bitmask) |
               (env->active_fpu.fcr31 & ~(env->active_fpu.fcr31_rw_bitmask));
        break;
    default:
        return;
    }
    /* set rounding mode */
    restore_rounding_mode(env);
    /* set flush-to-zero mode */
    restore_flush_mode(env);
    restore_fp_status(env);
    set_float_exception_flags(0, &env->active_fpu.fp_status);
    if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
        do_raise_exception(env, EXCP_FPE, GETPC());
+2 −3
Original line number Diff line number Diff line
@@ -20241,8 +20241,8 @@ void cpu_state_reset(CPUMIPSState *env)
    env->CP0_PageGrain_rw_bitmask = env->cpu_model->CP0_PageGrain_rw_bitmask;
    env->CP0_PageGrain = env->cpu_model->CP0_PageGrain;
    env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0;
    env->active_fpu.fcr31_rw_bitmask = env->cpu_model->CP1_fcr31_rw_bitmask;
    env->active_fpu.fcr31 = env->cpu_model->CP1_fcr31;
    set_snan_bit_is_one(1, &env->active_fpu.fp_status);
    env->msair = env->cpu_model->MSAIR;
    env->insn_flags = env->cpu_model->insn_flags;
@@ -20352,8 +20352,7 @@ void cpu_state_reset(CPUMIPSState *env)
    }
    compute_hflags(env);
    restore_rounding_mode(env);
    restore_flush_mode(env);
    restore_fp_status(env);
    restore_pamask(env);
    cs->exception_index = EXCP_NONE;
Loading