Home | History | Annotate | Line # | Download | only in cris
crisv32f.c revision 1.1.1.4
      1 /* CRIS v32 simulator support code
      2    Copyright (C) 2004-2015 Free Software Foundation, Inc.
      3    Contributed by Axis Communications.
      4 
      5 This file is part of the GNU simulators.
      6 
      7 This program is free software; you can redistribute it and/or modify
      8 it under the terms of the GNU General Public License as published by
      9 the Free Software Foundation; either version 3 of the License, or
     10 (at your option) any later version.
     11 
     12 This program is distributed in the hope that it will be useful,
     13 but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 /* The infrastructure is based on that of i960.c.  */
     21 
     22 #define WANT_CPU_CRISV32F
     23 
     24 #define SPECIFIC_U_EXEC_FN
     25 #define SPECIFIC_U_SKIP4_FN
     26 #define SPECIFIC_U_CONST16_FN
     27 #define SPECIFIC_U_CONST32_FN
     28 #define SPECIFIC_U_MEM_FN
     29 #define SPECIFIC_U_MOVEM_FN
     30 #define BASENUM 32
     31 #define CRIS_TLS_REGISTER 2
     32 #include "cris-tmpl.c"
     33 
     34 #if WITH_PROFILE_MODEL_P
     35 
     36 /* Re-use the bit position for the BZ register, since there are no stall
     37    cycles for reading or writing it.  */
     38 #define CRIS_BZ_REGNO 16
     39 #define CRIS_MODF_JUMP_MASK (1 << CRIS_BZ_REGNO)
     40 /* Likewise for the WZ register, marking memory writes.  */
     41 #define CRIS_WZ_REGNO 20
     42 #define CRIS_MODF_MEM_WRITE_MASK (1 << CRIS_WZ_REGNO)
     43 #define CRIS_MOF_REGNO (16 + 7)
     44 #define CRIS_ALWAYS_CONDITION 14
     45 
     46 /* This macro must only be used in context where there's only one
     47    dynamic cause for a penalty, except in the u-exec unit.  */
     48 
     49 #define PENALIZE1(CNT)					\
     50   do							\
     51     {							\
     52       CPU_CRIS_MISC_PROFILE (current_cpu)->CNT++;	\
     53       model_data->prev_prev_prev_modf_regs		\
     54 	= model_data->prev_prev_modf_regs;		\
     55       model_data->prev_prev_modf_regs			\
     56 	= model_data->prev_modf_regs;			\
     57       model_data->prev_modf_regs = 0;			\
     58       model_data->prev_prev_prev_movem_dest_regs	\
     59 	= model_data->prev_prev_movem_dest_regs;	\
     60       model_data->prev_prev_movem_dest_regs		\
     61 	= model_data->prev_movem_dest_regs;		\
     62       model_data->prev_movem_dest_regs = 0;		\
     63     }							\
     64   while (0)
     65 
     66 
     67 /* Model function for u-skip4 unit.  */
     68 
     69 int
     70 MY (XCONCAT3 (f_model_crisv,BASENUM,
     71 	      _u_skip4)) (SIM_CPU *current_cpu,
     72 			  const IDESC *idesc ATTRIBUTE_UNUSED,
     73 			  int unit_num ATTRIBUTE_UNUSED,
     74 			  int referenced ATTRIBUTE_UNUSED)
     75 {
     76   /* Handle PC not being updated with pbb.  FIXME: What if not pbb?  */
     77   CPU (h_pc) += 4;
     78   return 0;
     79 }
     80 
     81 /* Model function for u-exec unit.  */
     82 
     83 int
     84 MY (XCONCAT3 (f_model_crisv,BASENUM,
     85 	      _u_exec)) (SIM_CPU *current_cpu,
     86 			 const IDESC *idesc ATTRIBUTE_UNUSED,
     87 			 int unit_num ATTRIBUTE_UNUSED,
     88 			 int referenced ATTRIBUTE_UNUSED,
     89 			 INT destreg_in,
     90 			 INT srcreg,
     91 			 INT destreg_out)
     92 {
     93   MODEL_CRISV32_DATA *model_data
     94     = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
     95   UINT modf_regs
     96     = ((destreg_out == -1 ? 0 : (1 << destreg_out))
     97        | model_data->modf_regs);
     98 
     99   if (srcreg != -1)
    100     {
    101       if (model_data->prev_movem_dest_regs & (1 << srcreg))
    102 	{
    103 	  PENALIZE1 (movemdst_stall_count);
    104 	  PENALIZE1 (movemdst_stall_count);
    105 	  PENALIZE1 (movemdst_stall_count);
    106 	}
    107       else if (model_data->prev_prev_movem_dest_regs & (1 << srcreg))
    108 	{
    109 	  PENALIZE1 (movemdst_stall_count);
    110 	  PENALIZE1 (movemdst_stall_count);
    111 	}
    112       else if (model_data->prev_prev_prev_movem_dest_regs & (1 << srcreg))
    113 	PENALIZE1 (movemdst_stall_count);
    114     }
    115 
    116   if (destreg_in != -1)
    117     {
    118       if (model_data->prev_movem_dest_regs & (1 << destreg_in))
    119 	{
    120 	  PENALIZE1 (movemdst_stall_count);
    121 	  PENALIZE1 (movemdst_stall_count);
    122 	  PENALIZE1 (movemdst_stall_count);
    123 	}
    124       else if (model_data->prev_prev_movem_dest_regs & (1 << destreg_in))
    125 	{
    126 	  PENALIZE1 (movemdst_stall_count);
    127 	  PENALIZE1 (movemdst_stall_count);
    128 	}
    129       else if (model_data->prev_prev_prev_movem_dest_regs & (1 << destreg_in))
    130 	PENALIZE1 (movemdst_stall_count);
    131     }
    132 
    133   model_data->prev_prev_prev_modf_regs
    134     = model_data->prev_prev_modf_regs;
    135   model_data->prev_prev_modf_regs = model_data->prev_modf_regs;
    136   model_data->prev_modf_regs = modf_regs;
    137   model_data->modf_regs = 0;
    138 
    139   model_data->prev_prev_prev_movem_dest_regs
    140     = model_data->prev_prev_movem_dest_regs;
    141   model_data->prev_prev_movem_dest_regs = model_data->prev_movem_dest_regs;
    142   model_data->prev_movem_dest_regs = model_data->movem_dest_regs;
    143   model_data->movem_dest_regs = 0;
    144 
    145   /* Handle PC not being updated with pbb.  FIXME: What if not pbb?  */
    146   CPU (h_pc) += 2;
    147   return 1;
    148 }
    149 
    150 /* Special case used when the destination is a special register.  */
    151 
    152 int
    153 MY (XCONCAT3 (f_model_crisv,BASENUM,
    154 	      _u_exec_to_sr)) (SIM_CPU *current_cpu,
    155 			       const IDESC *idesc ATTRIBUTE_UNUSED,
    156 			       int unit_num ATTRIBUTE_UNUSED,
    157 			       int referenced ATTRIBUTE_UNUSED,
    158 			       INT srcreg,
    159 			       INT specreg)
    160 {
    161   int specdest;
    162 
    163   if (specreg != -1)
    164     specdest = specreg + 16;
    165   else
    166     abort ();
    167 
    168   return MY (XCONCAT3 (f_model_crisv,BASENUM,_u_exec))
    169     (current_cpu, NULL, 0, 0, -1, srcreg,
    170      /* The positions for constant-zero registers BZ and WZ are recycled
    171 	for jump and memory-write markers.  We must take precautions
    172 	here not to add false markers for them.  It might be that the
    173 	hardware inserts stall cycles for instructions that actually try
    174 	and write those registers, but we'll burn that bridge when we
    175 	get to it; we'd have to find other free bits or make new
    176 	model_data variables.  However, it's doubtful that there will
    177 	ever be a need to be cycle-correct for useless code, at least in
    178 	this particular simulator, mainly used for GCC testing.  */
    179      specdest == CRIS_BZ_REGNO || specdest == CRIS_WZ_REGNO
    180      ? -1 : specdest);
    181 }
    182 
    183 
    184 /* Special case for movem.  */
    185 
    186 int
    187 MY (XCONCAT3 (f_model_crisv,BASENUM,
    188 	      _u_exec_movem)) (SIM_CPU *current_cpu,
    189 			       const IDESC *idesc ATTRIBUTE_UNUSED,
    190 			       int unit_num ATTRIBUTE_UNUSED,
    191 			       int referenced ATTRIBUTE_UNUSED,
    192 			       INT srcreg,
    193 			       INT destreg_out)
    194 {
    195   return MY (XCONCAT3 (f_model_crisv,BASENUM,_u_exec))
    196     (current_cpu, NULL, 0, 0, -1, srcreg, destreg_out);
    197 }
    198 
    199 /* Model function for u-const16 unit.  */
    200 
    201 int
    202 MY (XCONCAT3 (f_model_crisv,BASENUM,
    203 	      _u_const16)) (SIM_CPU *current_cpu,
    204 			    const IDESC *idesc ATTRIBUTE_UNUSED,
    205 			    int unit_num ATTRIBUTE_UNUSED,
    206 			    int referenced ATTRIBUTE_UNUSED)
    207 {
    208   MODEL_CRISV32_DATA *model_data
    209     = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
    210 
    211   /* If the previous insn was a jump of some sort and this insn
    212      straddles a cache-line, there's a one-cycle penalty.
    213      FIXME: Test-cases for normal const16 and others, like branch.  */
    214   if ((model_data->prev_modf_regs & CRIS_MODF_JUMP_MASK)
    215       && (CPU (h_pc) & 0x1e) == 0x1e)
    216     PENALIZE1 (jumptarget_stall_count);
    217 
    218   /* Handle PC not being updated with pbb.  FIXME: What if not pbb?  */
    219   CPU (h_pc) += 2;
    220 
    221   return 0;
    222 }
    223 
    224 /* Model function for u-const32 unit.  */
    225 
    226 int
    227 MY (XCONCAT3 (f_model_crisv,BASENUM,
    228 	      _u_const32)) (SIM_CPU *current_cpu,
    229 			    const IDESC *idesc ATTRIBUTE_UNUSED,
    230 			    int unit_num ATTRIBUTE_UNUSED,
    231 			    int referenced ATTRIBUTE_UNUSED)
    232 {
    233   MODEL_CRISV32_DATA *model_data
    234     = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
    235 
    236   /* If the previous insn was a jump of some sort and this insn
    237      straddles a cache-line, there's a one-cycle penalty.  */
    238   if ((model_data->prev_modf_regs & CRIS_MODF_JUMP_MASK)
    239       && (CPU (h_pc) & 0x1e) == 0x1c)
    240     PENALIZE1 (jumptarget_stall_count);
    241 
    242   /* Handle PC not being updated with pbb.  FIXME: What if not pbb?  */
    243   CPU (h_pc) += 4;
    244 
    245   return 0;
    246 }
    247 
    248 /* Model function for u-mem unit.  */
    249 
    250 int
    251 MY (XCONCAT3 (f_model_crisv,BASENUM,
    252 	      _u_mem)) (SIM_CPU *current_cpu,
    253 			const IDESC *idesc ATTRIBUTE_UNUSED,
    254 			int unit_num ATTRIBUTE_UNUSED,
    255 			int referenced ATTRIBUTE_UNUSED,
    256 			INT srcreg)
    257 {
    258   MODEL_CRISV32_DATA *model_data
    259     = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
    260 
    261   if (srcreg == -1)
    262     abort ();
    263 
    264   /* If srcreg references a register modified in the previous cycle
    265      through other than autoincrement, then there's a penalty: one
    266      cycle.  */
    267   if (model_data->prev_modf_regs & (1 << srcreg))
    268     PENALIZE1 (memsrc_stall_count);
    269 
    270   return 0;
    271 }
    272 
    273 /* Model function for u-mem-r unit.  */
    274 
    275 int
    276 MY (XCONCAT3 (f_model_crisv,BASENUM,
    277 	      _u_mem_r)) (SIM_CPU *current_cpu,
    278 			  const IDESC *idesc ATTRIBUTE_UNUSED,
    279 			  int unit_num ATTRIBUTE_UNUSED,
    280 			  int referenced ATTRIBUTE_UNUSED)
    281 {
    282   MODEL_CRISV32_DATA *model_data
    283     = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
    284 
    285   /* There's a two-cycle penalty for read after a memory write in any of
    286      the two previous cycles, known as a cache read-after-write hazard.
    287 
    288      This model function (the model_data member access) depends on being
    289      executed before the u-exec unit.  */
    290   if ((model_data->prev_modf_regs & CRIS_MODF_MEM_WRITE_MASK)
    291       || (model_data->prev_prev_modf_regs & CRIS_MODF_MEM_WRITE_MASK))
    292     {
    293       PENALIZE1 (memraw_stall_count);
    294       PENALIZE1 (memraw_stall_count);
    295     }
    296 
    297   return 0;
    298 }
    299 
    300 /* Model function for u-mem-w unit.  */
    301 
    302 int
    303 MY (XCONCAT3 (f_model_crisv,BASENUM,
    304 	      _u_mem_w)) (SIM_CPU *current_cpu,
    305 			  const IDESC *idesc ATTRIBUTE_UNUSED,
    306 			  int unit_num ATTRIBUTE_UNUSED,
    307 			  int referenced ATTRIBUTE_UNUSED)
    308 {
    309   MODEL_CRISV32_DATA *model_data
    310     = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
    311 
    312   /* Mark that memory has been written.  This model function (the
    313      model_data member access) depends on being executed after the
    314      u-exec unit.  */
    315   model_data->prev_modf_regs |= CRIS_MODF_MEM_WRITE_MASK;
    316 
    317   return 0;
    318 }
    319 
    320 /* Model function for u-movem-rtom unit.  */
    321 
    322 int
    323 MY (XCONCAT3 (f_model_crisv,BASENUM,
    324 	      _u_movem_rtom)) (SIM_CPU *current_cpu,
    325 			       const IDESC *idesc ATTRIBUTE_UNUSED,
    326 			       int unit_num ATTRIBUTE_UNUSED,
    327 			       int referenced ATTRIBUTE_UNUSED,
    328 			       /* Deliberate order.  */
    329 			       INT addrreg, INT limreg)
    330 {
    331   USI addr;
    332   MODEL_CRISV32_DATA *model_data
    333     = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
    334 
    335   if (limreg == -1 || addrreg == -1)
    336     abort ();
    337 
    338   addr = GET_H_GR (addrreg);
    339 
    340   /* The movem-to-memory instruction must not move a register modified
    341      in one of the previous two cycles.  Enforce by adding penalty
    342      cycles.  */
    343   if (model_data->prev_modf_regs & ((1 << (limreg + 1)) - 1))
    344     {
    345       PENALIZE1 (movemsrc_stall_count);
    346       PENALIZE1 (movemsrc_stall_count);
    347     }
    348   else if (model_data->prev_prev_modf_regs & ((1 << (limreg + 1)) - 1))
    349     PENALIZE1 (movemsrc_stall_count);
    350 
    351   /* One-cycle penalty for each cache-line straddled.  Use the
    352      documented expressions.  Unfortunately no penalty cycles are
    353      eliminated by any penalty cycles above.  We file these numbers
    354      separately, since they aren't schedulable for all cases.  */
    355   if ((addr >> 5) == (((addr + 4 * (limreg + 1)) - 1) >> 5))
    356     ;
    357   else if ((addr >> 5) == (((addr + 4 * (limreg + 1)) - 1) >> 5) - 1)
    358     PENALIZE1 (movemaddr_stall_count);
    359   else if ((addr >> 5) == (((addr + 4 * (limreg + 1)) - 1) >> 5) - 2)
    360     {
    361       PENALIZE1 (movemaddr_stall_count);
    362       PENALIZE1 (movemaddr_stall_count);
    363     }
    364   else
    365     abort ();
    366 
    367   return 0;
    368 }
    369 
    370 /* Model function for u-movem-mtor unit.  */
    371 
    372 int
    373 MY (XCONCAT3 (f_model_crisv,BASENUM,
    374 	      _u_movem_mtor)) (SIM_CPU *current_cpu,
    375 			       const IDESC *idesc ATTRIBUTE_UNUSED,
    376 			       int unit_num ATTRIBUTE_UNUSED,
    377 			       int referenced ATTRIBUTE_UNUSED,
    378 			       /* Deliberate order.  */
    379 			       INT addrreg, INT limreg)
    380 {
    381   USI addr;
    382   int nregs = limreg + 1;
    383   MODEL_CRISV32_DATA *model_data
    384     = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
    385 
    386   if (limreg == -1 || addrreg == -1)
    387     abort ();
    388 
    389   addr = GET_H_GR (addrreg);
    390 
    391   /* One-cycle penalty for each cache-line straddled.  Use the
    392      documented expressions.  One cycle is the norm; more cycles are
    393      counted as penalties.  Unfortunately no penalty cycles here
    394      eliminate penalty cycles indicated in ->movem_dest_regs.  */
    395   if ((addr >> 5) == (((addr + 4 * nregs) - 1) >> 5) - 1)
    396     PENALIZE1 (movemaddr_stall_count);
    397   else if ((addr >> 5) == (((addr + 4 * nregs) - 1) >> 5) - 2)
    398     {
    399       PENALIZE1 (movemaddr_stall_count);
    400       PENALIZE1 (movemaddr_stall_count);
    401     }
    402 
    403   model_data->modf_regs |= ((1 << nregs) - 1);
    404   model_data->movem_dest_regs  |= ((1 << nregs) - 1);
    405   return 0;
    406 }
    407 
    408 
    409 /* Model function for u-branch unit.
    410    FIXME: newpc and cc are always wrong.  */
    411 
    412 int
    413 MY (XCONCAT3 (f_model_crisv,BASENUM,_u_branch)) (SIM_CPU *current_cpu,
    414 						 const IDESC *idesc,
    415 						 int unit_num, int referenced)
    416 {
    417   CRIS_MISC_PROFILE *profp = CPU_CRIS_MISC_PROFILE (current_cpu);
    418   USI pc = profp->old_pc;
    419   MODEL_CRISV32_DATA *model_data
    420     = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
    421   int taken = profp->branch_taken;
    422   int branch_index = (pc & (N_CRISV32_BRANCH_PREDICTORS - 1)) >> 1;
    423   int pred_taken = (profp->branch_predictors[branch_index] & 2) != 0;
    424 
    425   if (taken != pred_taken)
    426     {
    427       PENALIZE1 (branch_stall_count);
    428       PENALIZE1 (branch_stall_count);
    429     }
    430 
    431   if (taken)
    432     {
    433       if (profp->branch_predictors[branch_index] < 3)
    434 	profp->branch_predictors[branch_index]++;
    435 
    436       return MY (XCONCAT3 (f_model_crisv,BASENUM,_u_jump))
    437 	(current_cpu, idesc, unit_num, referenced, -1);
    438     }
    439 
    440   if (profp->branch_predictors[branch_index] != 0)
    441     profp->branch_predictors[branch_index]--;
    442 
    443   return 0;
    444 }
    445 
    446 /* Model function for u-jump-r unit.  */
    447 
    448 int
    449 MY (XCONCAT3 (f_model_crisv,BASENUM,
    450 	      _u_jump_r)) (SIM_CPU *current_cpu,
    451 			   const IDESC *idesc ATTRIBUTE_UNUSED,
    452 			   int unit_num ATTRIBUTE_UNUSED,
    453 			   int referenced ATTRIBUTE_UNUSED,
    454 			   int regno)
    455 {
    456   MODEL_CRISV32_DATA *model_data
    457     = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
    458 
    459   if (regno == -1)
    460     abort ();
    461 
    462   /* For jump-to-register, the register must not have been modified the
    463      last two cycles.  Penalty: two cycles from the modifying insn.  */
    464   if ((1 << regno) & model_data->prev_modf_regs)
    465     {
    466       PENALIZE1 (jumpsrc_stall_count);
    467       PENALIZE1 (jumpsrc_stall_count);
    468     }
    469   else if ((1 << regno) & model_data->prev_prev_modf_regs)
    470     PENALIZE1 (jumpsrc_stall_count);
    471 
    472   return 0;
    473 }
    474 
    475 /* Model function for u-jump-sr unit.  */
    476 
    477 int
    478 MY (XCONCAT3 (f_model_crisv,BASENUM,_u_jump_sr)) (SIM_CPU *current_cpu,
    479 						  const IDESC *idesc,
    480 						  int unit_num, int referenced,
    481 						  int sr_regno)
    482 {
    483   int regno;
    484 
    485   MODEL_CRISV32_DATA *model_data
    486     = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
    487 
    488   if (sr_regno == -1)
    489     abort ();
    490 
    491   regno = sr_regno + 16;
    492 
    493   /* For jump-to-register, the register must not have been modified the
    494      last two cycles.  Penalty: two cycles from the modifying insn.  */
    495   if ((1 << regno) & model_data->prev_modf_regs)
    496     {
    497       PENALIZE1 (jumpsrc_stall_count);
    498       PENALIZE1 (jumpsrc_stall_count);
    499     }
    500   else if ((1 << regno) & model_data->prev_prev_modf_regs)
    501     PENALIZE1 (jumpsrc_stall_count);
    502 
    503   return
    504     MY (XCONCAT3 (f_model_crisv,BASENUM,_u_jump)) (current_cpu, idesc,
    505 						   unit_num, referenced, -1);
    506 }
    507 
    508 /* Model function for u-jump unit.  */
    509 
    510 int
    511 MY (XCONCAT3 (f_model_crisv,BASENUM,
    512 	      _u_jump)) (SIM_CPU *current_cpu,
    513 			 const IDESC *idesc ATTRIBUTE_UNUSED,
    514 			 int unit_num ATTRIBUTE_UNUSED,
    515 			 int referenced ATTRIBUTE_UNUSED,
    516 			 int out_sr_regno)
    517 {
    518   MODEL_CRISV32_DATA *model_data
    519     = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
    520 
    521   /* Mark that we made a jump.  */
    522   model_data->modf_regs
    523     |= (CRIS_MODF_JUMP_MASK
    524 	| (out_sr_regno == -1 || out_sr_regno == CRIS_BZ_REGNO
    525 	   ? 0 : (1 << (out_sr_regno + 16))));
    526   return 0;
    527 }
    528 
    529 /* Model function for u-multiply unit.  */
    530 
    531 int
    532 MY (XCONCAT3 (f_model_crisv,BASENUM,
    533 	      _u_multiply)) (SIM_CPU *current_cpu,
    534 			     const IDESC *idesc ATTRIBUTE_UNUSED,
    535 			     int unit_num ATTRIBUTE_UNUSED,
    536 			     int referenced ATTRIBUTE_UNUSED,
    537 			     int srcreg, int destreg)
    538 {
    539   MODEL_CRISV32_DATA *model_data
    540     = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
    541 
    542   /* Sanity-check for cases that should never happen.  */
    543   if (srcreg == -1 || destreg == -1)
    544     abort ();
    545 
    546   /* This takes extra cycles when one of the inputs has been modified
    547      through other than autoincrement in the previous cycle.  Penalty:
    548      one cycle.  */
    549   if (((1 << srcreg) | (1 << destreg)) & model_data->prev_modf_regs)
    550     PENALIZE1 (mulsrc_stall_count);
    551 
    552   /* We modified the multiplication destination (marked in u-exec) and
    553      the MOF register.  */
    554   model_data->modf_regs |= (1 << CRIS_MOF_REGNO);
    555   return 0;
    556 }
    557 
    558 #endif /* WITH_PROFILE_MODEL_P */
    559 
    560 int
    561 MY (deliver_interrupt) (SIM_CPU *current_cpu,
    562 			enum cris_interrupt_type type,
    563 			unsigned int vec)
    564 {
    565   unsigned32 old_ccs, shifted_ccs, new_ccs;
    566   unsigned char entryaddr_le[4];
    567   int was_user;
    568   SIM_DESC sd = CPU_STATE (current_cpu);
    569   unsigned32 entryaddr;
    570 
    571   /* We haven't implemented other interrupt-types yet.  */
    572   if (type != CRIS_INT_INT)
    573     abort ();
    574 
    575   /* We're called outside of branch delay slots etc, so we don't check
    576      for that.  */
    577   if (!GET_H_IBIT_V32 ())
    578     return 0;
    579 
    580   old_ccs = GET_H_SR_V32 (H_SR_CCS);
    581   shifted_ccs = (old_ccs << 10) & ((1 << 30) - 1);
    582 
    583   /* The M bit is handled by code below and the M bit setter function, but
    584      we need to preserve the Q bit.  */
    585   new_ccs = shifted_ccs | (old_ccs & (unsigned32) 0x80000000UL);
    586   was_user = GET_H_UBIT_V32 ();
    587 
    588   /* We need to force kernel mode since the setter method doesn't allow
    589      it.  Then we can use setter methods at will, since they then
    590      recognize that we're in kernel mode.  */
    591   CPU (h_ubit_v32) = 0;
    592 
    593   SET_H_SR (H_SR_CCS, new_ccs);
    594 
    595   if (was_user)
    596     {
    597       /* These methods require that user mode is unset.  */
    598       SET_H_SR (H_SR_USP, GET_H_GR (H_GR_SP));
    599       SET_H_GR (H_GR_SP, GET_H_KERNEL_SP ());
    600     }
    601 
    602   /* ERP setting is simplified by not taking interrupts in delay-slots
    603      or when halting.  */
    604   /* For all other exceptions than guru and NMI, store the return
    605      address in ERP and set EXS and EXD here.  */
    606   SET_H_SR (H_SR_ERP, GET_H_PC ());
    607 
    608   /* Simplified by not having exception types (fault indications).  */
    609   SET_H_SR_V32 (H_SR_EXS, (vec * 256));
    610   SET_H_SR_V32 (H_SR_EDA, 0);
    611 
    612   if (sim_core_read_buffer (sd,
    613 			    current_cpu,
    614 			    read_map, entryaddr_le,
    615 			    GET_H_SR (H_SR_EBP) + vec * 4, 4) == 0)
    616     {
    617       /* Nothing to do actually; either abort or send a signal.  */
    618       sim_core_signal (sd, current_cpu, CIA_GET (current_cpu), 0, 4,
    619 		       GET_H_SR (H_SR_EBP) + vec * 4,
    620 		       read_transfer, sim_core_unmapped_signal);
    621       return 0;
    622     }
    623 
    624   entryaddr = bfd_getl32 (entryaddr_le);
    625   SET_H_PC (entryaddr);
    626 
    627   return 1;
    628 }
    629