From f6bcefefe817b20b493081511cdeb8f87052bd41 Mon Sep 17 00:00:00 2001 From: Hans-Peter Nilsson Date: Fri, 28 Jan 2005 04:29:00 +0000 Subject: * cris: New directory, simulator for Axis Communications CRIS including CRIS v32, CGEN-based. * configure.ac: Add corresponding configury. * configure: Regenerate. --- sim/cris/crisv32f.c | 558 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 558 insertions(+) create mode 100644 sim/cris/crisv32f.c (limited to 'sim/cris/crisv32f.c') diff --git a/sim/cris/crisv32f.c b/sim/cris/crisv32f.c new file mode 100644 index 0000000..d1d5fc9 --- /dev/null +++ b/sim/cris/crisv32f.c @@ -0,0 +1,558 @@ +/* CRIS v32 simulator support code + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Contributed by Axis Communications. + +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. + +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. */ + +/* The infrastructure is based on that of i960.c. */ + +#define WANT_CPU_CRISV32F + +#define SPECIFIC_U_EXEC_FN +#define SPECIFIC_U_SKIP4_FN +#define SPECIFIC_U_CONST16_FN +#define SPECIFIC_U_CONST32_FN +#define SPECIFIC_U_MEM_FN +#define SPECIFIC_U_MOVEM_FN +#define BASENUM 32 +#include "cris-tmpl.c" + +#if WITH_PROFILE_MODEL_P + +/* Re-use the bit position for the BZ register, since there are no stall + cycles for reading or writing it. */ +#define CRIS_BZ_REGNO 16 +#define CRIS_MODF_JUMP_MASK (1 << CRIS_BZ_REGNO) +/* Likewise for the WZ register, marking memory writes. */ +#define CRIS_WZ_REGNO 20 +#define CRIS_MODF_MEM_WRITE_MASK (1 << CRIS_WZ_REGNO) +#define CRIS_MOF_REGNO (16 + 7) +#define CRIS_ALWAYS_CONDITION 14 + +/* This macro must only be used in context where there's only one + dynamic cause for a penalty, except in the u-exec unit. */ + +#define PENALIZE1(CNT) \ + do \ + { \ + CPU_CRIS_MISC_PROFILE (current_cpu)->CNT++; \ + model_data->prev_prev_prev_modf_regs \ + = model_data->prev_prev_modf_regs; \ + model_data->prev_prev_modf_regs \ + = model_data->prev_modf_regs; \ + model_data->prev_modf_regs = 0; \ + model_data->prev_prev_prev_movem_dest_regs \ + = model_data->prev_prev_movem_dest_regs; \ + model_data->prev_prev_movem_dest_regs \ + = model_data->prev_movem_dest_regs; \ + model_data->prev_movem_dest_regs = 0; \ + } \ + while (0) + + +/* Model function for u-skip4 unit. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM, + _u_skip4)) (SIM_CPU *current_cpu, + const IDESC *idesc ATTRIBUTE_UNUSED, + int unit_num ATTRIBUTE_UNUSED, + int referenced ATTRIBUTE_UNUSED) +{ + /* Handle PC not being updated with pbb. FIXME: What if not pbb? */ + CPU (h_pc) += 4; + return 0; +} + +/* Model function for u-exec unit. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM, + _u_exec)) (SIM_CPU *current_cpu, + const IDESC *idesc ATTRIBUTE_UNUSED, + int unit_num ATTRIBUTE_UNUSED, + int referenced ATTRIBUTE_UNUSED, + INT destreg_in, + INT srcreg, + INT destreg_out) +{ + MODEL_CRISV32_DATA *model_data + = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu); + UINT modf_regs + = ((destreg_out == -1 ? 0 : (1 << destreg_out)) + | model_data->modf_regs); + + if (srcreg != -1) + { + if (model_data->prev_movem_dest_regs & (1 << srcreg)) + { + PENALIZE1 (movemdst_stall_count); + PENALIZE1 (movemdst_stall_count); + PENALIZE1 (movemdst_stall_count); + } + else if (model_data->prev_prev_movem_dest_regs & (1 << srcreg)) + { + PENALIZE1 (movemdst_stall_count); + PENALIZE1 (movemdst_stall_count); + } + else if (model_data->prev_prev_prev_movem_dest_regs & (1 << srcreg)) + PENALIZE1 (movemdst_stall_count); + } + + if (destreg_in != -1) + { + if (model_data->prev_movem_dest_regs & (1 << destreg_in)) + { + PENALIZE1 (movemdst_stall_count); + PENALIZE1 (movemdst_stall_count); + PENALIZE1 (movemdst_stall_count); + } + else if (model_data->prev_prev_movem_dest_regs & (1 << destreg_in)) + { + PENALIZE1 (movemdst_stall_count); + PENALIZE1 (movemdst_stall_count); + } + else if (model_data->prev_prev_prev_movem_dest_regs & (1 << destreg_in)) + PENALIZE1 (movemdst_stall_count); + } + + model_data->prev_prev_prev_modf_regs + = model_data->prev_prev_modf_regs; + model_data->prev_prev_modf_regs = model_data->prev_modf_regs; + model_data->prev_modf_regs = modf_regs; + model_data->modf_regs = 0; + + model_data->prev_prev_prev_movem_dest_regs + = model_data->prev_prev_movem_dest_regs; + model_data->prev_prev_movem_dest_regs = model_data->prev_movem_dest_regs; + model_data->prev_movem_dest_regs = model_data->movem_dest_regs; + model_data->movem_dest_regs = 0; + + /* Handle PC not being updated with pbb. FIXME: What if not pbb? */ + CPU (h_pc) += 2; + return 1; +} + +/* Special case used when the destination is a special register. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM, + _u_exec_to_sr)) (SIM_CPU *current_cpu, + const IDESC *idesc ATTRIBUTE_UNUSED, + int unit_num ATTRIBUTE_UNUSED, + int referenced ATTRIBUTE_UNUSED, + INT srcreg, + INT specreg) +{ + int specdest; + + if (specreg != -1) + specdest = specreg + 16; + else + abort (); + + return MY (XCONCAT3 (f_model_crisv,BASENUM,_u_exec)) + (current_cpu, NULL, 0, 0, -1, srcreg, + /* The positions for constant-zero registers BZ and WZ are recycled + for jump and memory-write markers. We must take precautions + here not to add false markers for them. It might be that the + hardware inserts stall cycles for instructions that actually try + and write those registers, but we'll burn that bridge when we + get to it; we'd have to find other free bits or make new + model_data variables. However, it's doubtful that there will + ever be a need to be cycle-correct for useless code, at least in + this particular simulator, mainly used for GCC testing. */ + specdest == CRIS_BZ_REGNO || specdest == CRIS_WZ_REGNO + ? -1 : specdest); +} + + +/* Special case for movem. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM, + _u_exec_movem)) (SIM_CPU *current_cpu, + const IDESC *idesc ATTRIBUTE_UNUSED, + int unit_num ATTRIBUTE_UNUSED, + int referenced ATTRIBUTE_UNUSED, + INT srcreg, + INT destreg_out) +{ + return MY (XCONCAT3 (f_model_crisv,BASENUM,_u_exec)) + (current_cpu, NULL, 0, 0, -1, srcreg, destreg_out); +} + +/* Model function for u-const16 unit. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM, + _u_const16)) (SIM_CPU *current_cpu, + const IDESC *idesc ATTRIBUTE_UNUSED, + int unit_num ATTRIBUTE_UNUSED, + int referenced ATTRIBUTE_UNUSED) +{ + MODEL_CRISV32_DATA *model_data + = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu); + + /* If the previous insn was a jump of some sort and this insn + straddles a cache-line, there's a one-cycle penalty. + FIXME: Test-cases for normal const16 and others, like branch. */ + if ((model_data->prev_modf_regs & CRIS_MODF_JUMP_MASK) + && (CPU (h_pc) & 0x1e) == 0x1e) + PENALIZE1 (jumptarget_stall_count); + + /* Handle PC not being updated with pbb. FIXME: What if not pbb? */ + CPU (h_pc) += 2; + + return 0; +} + +/* Model function for u-const32 unit. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM, + _u_const32)) (SIM_CPU *current_cpu, + const IDESC *idesc ATTRIBUTE_UNUSED, + int unit_num ATTRIBUTE_UNUSED, + int referenced ATTRIBUTE_UNUSED) +{ + MODEL_CRISV32_DATA *model_data + = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu); + + /* If the previous insn was a jump of some sort and this insn + straddles a cache-line, there's a one-cycle penalty. */ + if ((model_data->prev_modf_regs & CRIS_MODF_JUMP_MASK) + && (CPU (h_pc) & 0x1e) == 0x1c) + PENALIZE1 (jumptarget_stall_count); + + /* Handle PC not being updated with pbb. FIXME: What if not pbb? */ + CPU (h_pc) += 4; + + return 0; +} + +/* Model function for u-mem unit. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM, + _u_mem)) (SIM_CPU *current_cpu, + const IDESC *idesc ATTRIBUTE_UNUSED, + int unit_num ATTRIBUTE_UNUSED, + int referenced ATTRIBUTE_UNUSED, + INT srcreg) +{ + MODEL_CRISV32_DATA *model_data + = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu); + + if (srcreg == -1) + abort (); + + /* If srcreg references a register modified in the previous cycle + through other than autoincrement, then there's a penalty: one + cycle. */ + if (model_data->prev_modf_regs & (1 << srcreg)) + PENALIZE1 (memsrc_stall_count); + + return 0; +} + +/* Model function for u-mem-r unit. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM, + _u_mem_r)) (SIM_CPU *current_cpu, + const IDESC *idesc ATTRIBUTE_UNUSED, + int unit_num ATTRIBUTE_UNUSED, + int referenced ATTRIBUTE_UNUSED) +{ + MODEL_CRISV32_DATA *model_data + = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu); + + /* There's a two-cycle penalty for read after a memory write in any of + the two previous cycles, known as a cache read-after-write hazard. + + This model function (the model_data member access) depends on being + executed before the u-exec unit. */ + if ((model_data->prev_modf_regs & CRIS_MODF_MEM_WRITE_MASK) + || (model_data->prev_prev_modf_regs & CRIS_MODF_MEM_WRITE_MASK)) + { + PENALIZE1 (memraw_stall_count); + PENALIZE1 (memraw_stall_count); + } + + return 0; +} + +/* Model function for u-mem-w unit. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM, + _u_mem_w)) (SIM_CPU *current_cpu, + const IDESC *idesc ATTRIBUTE_UNUSED, + int unit_num ATTRIBUTE_UNUSED, + int referenced ATTRIBUTE_UNUSED) +{ + MODEL_CRISV32_DATA *model_data + = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu); + + /* Mark that memory has been written. This model function (the + model_data member access) depends on being executed after the + u-exec unit. */ + model_data->prev_modf_regs |= CRIS_MODF_MEM_WRITE_MASK; + + return 0; +} + +/* Model function for u-movem-rtom unit. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM, + _u_movem_rtom)) (SIM_CPU *current_cpu, + const IDESC *idesc ATTRIBUTE_UNUSED, + int unit_num ATTRIBUTE_UNUSED, + int referenced ATTRIBUTE_UNUSED, + /* Deliberate order. */ + INT addrreg, INT limreg) +{ + USI addr; + MODEL_CRISV32_DATA *model_data + = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu); + + if (limreg == -1 || addrreg == -1) + abort (); + + addr = GET_H_GR (addrreg); + + /* The movem-to-memory instruction must not move a register modified + in one of the previous two cycles. Enforce by adding penalty + cycles. */ + if (model_data->prev_modf_regs & ((1 << (limreg + 1)) - 1)) + { + PENALIZE1 (movemsrc_stall_count); + PENALIZE1 (movemsrc_stall_count); + } + else if (model_data->prev_prev_modf_regs & ((1 << (limreg + 1)) - 1)) + PENALIZE1 (movemsrc_stall_count); + + /* One-cycle penalty for each cache-line straddled. Use the + documented expressions. Unfortunately no penalty cycles are + eliminated by any penalty cycles above. We file these numbers + separately, since they aren't schedulable for all cases. */ + if ((addr >> 5) == (((addr + 4 * (limreg + 1)) - 1) >> 5)) + ; + else if ((addr >> 5) == (((addr + 4 * (limreg + 1)) - 1) >> 5) - 1) + PENALIZE1 (movemaddr_stall_count); + else if ((addr >> 5) == (((addr + 4 * (limreg + 1)) - 1) >> 5) - 2) + { + PENALIZE1 (movemaddr_stall_count); + PENALIZE1 (movemaddr_stall_count); + } + else + abort (); + + return 0; +} + +/* Model function for u-movem-mtor unit. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM, + _u_movem_mtor)) (SIM_CPU *current_cpu, + const IDESC *idesc ATTRIBUTE_UNUSED, + int unit_num ATTRIBUTE_UNUSED, + int referenced ATTRIBUTE_UNUSED, + /* Deliberate order. */ + INT addrreg, INT limreg) +{ + USI addr; + int nregs = limreg + 1; + MODEL_CRISV32_DATA *model_data + = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu); + + if (limreg == -1 || addrreg == -1) + abort (); + + addr = GET_H_GR (addrreg); + + /* One-cycle penalty for each cache-line straddled. Use the + documented expressions. One cycle is the norm; more cycles are + counted as penalties. Unfortunately no penalty cycles here + eliminate penalty cycles indicated in ->movem_dest_regs. */ + if ((addr >> 5) == (((addr + 4 * nregs) - 1) >> 5) - 1) + PENALIZE1 (movemaddr_stall_count); + else if ((addr >> 5) == (((addr + 4 * nregs) - 1) >> 5) - 2) + { + PENALIZE1 (movemaddr_stall_count); + PENALIZE1 (movemaddr_stall_count); + } + + model_data->modf_regs |= ((1 << nregs) - 1); + model_data->movem_dest_regs |= ((1 << nregs) - 1); + return 0; +} + + +/* Model function for u-branch unit. + FIXME: newpc and cc are always wrong. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM,_u_branch)) (SIM_CPU *current_cpu, + const IDESC *idesc, + int unit_num, int referenced) +{ + CRIS_MISC_PROFILE *profp = CPU_CRIS_MISC_PROFILE (current_cpu); + USI pc = profp->old_pc; + MODEL_CRISV32_DATA *model_data + = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu); + int taken = profp->branch_taken; + int branch_index = (pc & (N_CRISV32_BRANCH_PREDICTORS - 1)) >> 1; + int pred_taken = (profp->branch_predictors[branch_index] & 2) != 0; + + if (taken != pred_taken) + { + PENALIZE1 (branch_stall_count); + PENALIZE1 (branch_stall_count); + } + + if (taken) + { + if (profp->branch_predictors[branch_index] < 3) + profp->branch_predictors[branch_index]++; + + return MY (XCONCAT3 (f_model_crisv,BASENUM,_u_jump)) + (current_cpu, idesc, unit_num, referenced, -1); + } + + if (profp->branch_predictors[branch_index] != 0) + profp->branch_predictors[branch_index]--; + + return 0; +} + +/* Model function for u-jump-r unit. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM, + _u_jump_r)) (SIM_CPU *current_cpu, + const IDESC *idesc ATTRIBUTE_UNUSED, + int unit_num ATTRIBUTE_UNUSED, + int referenced ATTRIBUTE_UNUSED, + int regno) +{ + MODEL_CRISV32_DATA *model_data + = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu); + + if (regno == -1) + abort (); + + /* For jump-to-register, the register must not have been modified the + last two cycles. Penalty: two cycles from the modifying insn. */ + if ((1 << regno) & model_data->prev_modf_regs) + { + PENALIZE1 (jumpsrc_stall_count); + PENALIZE1 (jumpsrc_stall_count); + } + else if ((1 << regno) & model_data->prev_prev_modf_regs) + PENALIZE1 (jumpsrc_stall_count); + + return 0; +} + +/* Model function for u-jump-sr unit. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM,_u_jump_sr)) (SIM_CPU *current_cpu, + const IDESC *idesc, + int unit_num, int referenced, + int sr_regno) +{ + int regno; + + MODEL_CRISV32_DATA *model_data + = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu); + + if (sr_regno == -1) + abort (); + + regno = sr_regno + 16; + + /* For jump-to-register, the register must not have been modified the + last two cycles. Penalty: two cycles from the modifying insn. */ + if ((1 << regno) & model_data->prev_modf_regs) + { + PENALIZE1 (jumpsrc_stall_count); + PENALIZE1 (jumpsrc_stall_count); + } + else if ((1 << regno) & model_data->prev_prev_modf_regs) + PENALIZE1 (jumpsrc_stall_count); + + return + MY (XCONCAT3 (f_model_crisv,BASENUM,_u_jump)) (current_cpu, idesc, + unit_num, referenced, -1); +} + +/* Model function for u-jump unit. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM, + _u_jump)) (SIM_CPU *current_cpu, + const IDESC *idesc ATTRIBUTE_UNUSED, + int unit_num ATTRIBUTE_UNUSED, + int referenced ATTRIBUTE_UNUSED, + int out_sr_regno) +{ + MODEL_CRISV32_DATA *model_data + = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu); + + /* Mark that we made a jump. */ + model_data->modf_regs + |= (CRIS_MODF_JUMP_MASK + | (out_sr_regno == -1 || out_sr_regno == CRIS_BZ_REGNO + ? 0 : (1 << (out_sr_regno + 16)))); + return 0; +} + +/* Model function for u-multiply unit. */ + +int +MY (XCONCAT3 (f_model_crisv,BASENUM, + _u_multiply)) (SIM_CPU *current_cpu, + const IDESC *idesc ATTRIBUTE_UNUSED, + int unit_num ATTRIBUTE_UNUSED, + int referenced ATTRIBUTE_UNUSED, + int srcreg, int destreg) +{ + MODEL_CRISV32_DATA *model_data + = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu); + + /* Sanity-check for cases that should never happen. */ + if (srcreg == -1 || destreg == -1) + abort (); + + /* This takes extra cycles when one of the inputs has been modified + through other than autoincrement in the previous cycle. Penalty: + one cycle. */ + if (((1 << srcreg) | (1 << destreg)) & model_data->prev_modf_regs) + PENALIZE1 (mulsrc_stall_count); + + /* We modified the multiplication destination (marked in u-exec) and + the MOF register. */ + model_data->modf_regs |= (1 << CRIS_MOF_REGNO); + return 0; +} + +#endif /* WITH_PROFILE_MODEL_P */ -- cgit v1.1