1 /* CRIS v32 simulator support code
2 Copyright (C) 2004-2018 Free Software Foundation, Inc.
3 Contributed by Axis Communications.
5 This file is part of the GNU simulators.
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.
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.
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/>. */
20 /* The infrastructure is based on that of i960.c. */
22 #define WANT_CPU_CRISV32F
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
31 #define CRIS_TLS_REGISTER 2
32 #include "cris-tmpl.c"
34 #if WITH_PROFILE_MODEL_P
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
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. */
49 #define PENALIZE1(CNT) \
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; \
67 /* Model function for u-skip4 unit. */
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)
76 /* Handle PC not being updated with pbb. FIXME: What if not pbb? */
81 /* Model function for u-exec unit. */
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,
93 MODEL_CRISV32_DATA *model_data
94 = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
96 = ((destreg_out == -1 ? 0 : (1 << destreg_out))
97 | model_data->modf_regs);
101 if (model_data->prev_movem_dest_regs & (1 << srcreg))
103 PENALIZE1 (movemdst_stall_count);
104 PENALIZE1 (movemdst_stall_count);
105 PENALIZE1 (movemdst_stall_count);
107 else if (model_data->prev_prev_movem_dest_regs & (1 << srcreg))
109 PENALIZE1 (movemdst_stall_count);
110 PENALIZE1 (movemdst_stall_count);
112 else if (model_data->prev_prev_prev_movem_dest_regs & (1 << srcreg))
113 PENALIZE1 (movemdst_stall_count);
116 if (destreg_in != -1)
118 if (model_data->prev_movem_dest_regs & (1 << destreg_in))
120 PENALIZE1 (movemdst_stall_count);
121 PENALIZE1 (movemdst_stall_count);
122 PENALIZE1 (movemdst_stall_count);
124 else if (model_data->prev_prev_movem_dest_regs & (1 << destreg_in))
126 PENALIZE1 (movemdst_stall_count);
127 PENALIZE1 (movemdst_stall_count);
129 else if (model_data->prev_prev_prev_movem_dest_regs & (1 << destreg_in))
130 PENALIZE1 (movemdst_stall_count);
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;
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;
145 /* Handle PC not being updated with pbb. FIXME: What if not pbb? */
150 /* Special case used when the destination is a special register. */
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,
164 specdest = specreg + 16;
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
184 /* Special case for movem. */
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,
195 return MY (XCONCAT3 (f_model_crisv,BASENUM,_u_exec))
196 (current_cpu, NULL, 0, 0, -1, srcreg, destreg_out);
199 /* Model function for u-const16 unit. */
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)
208 MODEL_CRISV32_DATA *model_data
209 = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
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);
218 /* Handle PC not being updated with pbb. FIXME: What if not pbb? */
224 /* Model function for u-const32 unit. */
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)
233 MODEL_CRISV32_DATA *model_data
234 = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
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);
242 /* Handle PC not being updated with pbb. FIXME: What if not pbb? */
248 /* Model function for u-mem unit. */
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,
258 MODEL_CRISV32_DATA *model_data
259 = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
264 /* If srcreg references a register modified in the previous cycle
265 through other than autoincrement, then there's a penalty: one
267 if (model_data->prev_modf_regs & (1 << srcreg))
268 PENALIZE1 (memsrc_stall_count);
273 /* Model function for u-mem-r unit. */
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)
282 MODEL_CRISV32_DATA *model_data
283 = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
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.
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))
293 PENALIZE1 (memraw_stall_count);
294 PENALIZE1 (memraw_stall_count);
300 /* Model function for u-mem-w unit. */
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)
309 MODEL_CRISV32_DATA *model_data
310 = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
312 /* Mark that memory has been written. This model function (the
313 model_data member access) depends on being executed after the
315 model_data->prev_modf_regs |= CRIS_MODF_MEM_WRITE_MASK;
320 /* Model function for u-movem-rtom unit. */
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)
332 MODEL_CRISV32_DATA *model_data
333 = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
335 if (limreg == -1 || addrreg == -1)
338 addr = GET_H_GR (addrreg);
340 /* The movem-to-memory instruction must not move a register modified
341 in one of the previous two cycles. Enforce by adding penalty
343 if (model_data->prev_modf_regs & ((1 << (limreg + 1)) - 1))
345 PENALIZE1 (movemsrc_stall_count);
346 PENALIZE1 (movemsrc_stall_count);
348 else if (model_data->prev_prev_modf_regs & ((1 << (limreg + 1)) - 1))
349 PENALIZE1 (movemsrc_stall_count);
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))
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)
361 PENALIZE1 (movemaddr_stall_count);
362 PENALIZE1 (movemaddr_stall_count);
370 /* Model function for u-movem-mtor unit. */
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)
382 int nregs = limreg + 1;
383 MODEL_CRISV32_DATA *model_data
384 = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
386 if (limreg == -1 || addrreg == -1)
389 addr = GET_H_GR (addrreg);
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)
399 PENALIZE1 (movemaddr_stall_count);
400 PENALIZE1 (movemaddr_stall_count);
403 model_data->modf_regs |= ((1 << nregs) - 1);
404 model_data->movem_dest_regs |= ((1 << nregs) - 1);
409 /* Model function for u-branch unit.
410 FIXME: newpc and cc are always wrong. */
413 MY (XCONCAT3 (f_model_crisv,BASENUM,_u_branch)) (SIM_CPU *current_cpu,
415 int unit_num, int referenced)
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;
425 if (taken != pred_taken)
427 PENALIZE1 (branch_stall_count);
428 PENALIZE1 (branch_stall_count);
433 if (profp->branch_predictors[branch_index] < 3)
434 profp->branch_predictors[branch_index]++;
436 return MY (XCONCAT3 (f_model_crisv,BASENUM,_u_jump))
437 (current_cpu, idesc, unit_num, referenced, -1);
440 if (profp->branch_predictors[branch_index] != 0)
441 profp->branch_predictors[branch_index]--;
446 /* Model function for u-jump-r unit. */
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,
456 MODEL_CRISV32_DATA *model_data
457 = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
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)
466 PENALIZE1 (jumpsrc_stall_count);
467 PENALIZE1 (jumpsrc_stall_count);
469 else if ((1 << regno) & model_data->prev_prev_modf_regs)
470 PENALIZE1 (jumpsrc_stall_count);
475 /* Model function for u-jump-sr unit. */
478 MY (XCONCAT3 (f_model_crisv,BASENUM,_u_jump_sr)) (SIM_CPU *current_cpu,
480 int unit_num, int referenced,
485 MODEL_CRISV32_DATA *model_data
486 = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
491 regno = sr_regno + 16;
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)
497 PENALIZE1 (jumpsrc_stall_count);
498 PENALIZE1 (jumpsrc_stall_count);
500 else if ((1 << regno) & model_data->prev_prev_modf_regs)
501 PENALIZE1 (jumpsrc_stall_count);
504 MY (XCONCAT3 (f_model_crisv,BASENUM,_u_jump)) (current_cpu, idesc,
505 unit_num, referenced, -1);
508 /* Model function for u-jump unit. */
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,
518 MODEL_CRISV32_DATA *model_data
519 = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
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))));
529 /* Model function for u-multiply unit. */
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)
539 MODEL_CRISV32_DATA *model_data
540 = (MODEL_CRISV32_DATA *) CPU_MODEL_DATA (current_cpu);
542 /* Sanity-check for cases that should never happen. */
543 if (srcreg == -1 || destreg == -1)
546 /* This takes extra cycles when one of the inputs has been modified
547 through other than autoincrement in the previous cycle. Penalty:
549 if (((1 << srcreg) | (1 << destreg)) & model_data->prev_modf_regs)
550 PENALIZE1 (mulsrc_stall_count);
552 /* We modified the multiplication destination (marked in u-exec) and
554 model_data->modf_regs |= (1 << CRIS_MOF_REGNO);
558 #endif /* WITH_PROFILE_MODEL_P */
561 MY (deliver_interrupt) (SIM_CPU *current_cpu,
562 enum cris_interrupt_type type,
565 unsigned32 old_ccs, shifted_ccs, new_ccs;
566 unsigned char entryaddr_le[4];
568 SIM_DESC sd = CPU_STATE (current_cpu);
569 unsigned32 entryaddr;
571 /* We haven't implemented other interrupt-types yet. */
572 if (type != CRIS_INT_INT)
575 /* We're called outside of branch delay slots etc, so we don't check
577 if (!GET_H_IBIT_V32 ())
580 old_ccs = GET_H_SR_V32 (H_SR_CCS);
581 shifted_ccs = (old_ccs << 10) & ((1 << 30) - 1);
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 ();
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;
593 SET_H_SR (H_SR_CCS, new_ccs);
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 ());
602 /* ERP setting is simplified by not taking interrupts in delay-slots
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 ());
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);
612 if (sim_core_read_buffer (sd,
614 read_map, entryaddr_le,
615 GET_H_SR (H_SR_EBP) + vec * 4, 4) == 0)
617 /* Nothing to do actually; either abort or send a signal. */
618 sim_core_signal (sd, current_cpu, CPU_PC_GET (current_cpu), 0, 4,
619 GET_H_SR (H_SR_EBP) + vec * 4,
620 read_transfer, sim_core_unmapped_signal);
624 entryaddr = bfd_getl32 (entryaddr_le);
625 SET_H_PC (entryaddr);