1 /* CRIS v32 simulator support code
2 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009
3 Free Software Foundation, Inc.
4 Contributed by Axis Communications.
6 This file is part of the GNU simulators.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 /* The infrastructure is based on that of i960.c. */
23 #define WANT_CPU_CRISV32F
25 #define SPECIFIC_U_EXEC_FN
26 #define SPECIFIC_U_SKIP4_FN
27 #define SPECIFIC_U_CONST16_FN
28 #define SPECIFIC_U_CONST32_FN
29 #define SPECIFIC_U_MEM_FN
30 #define SPECIFIC_U_MOVEM_FN
32 #define CRIS_TLS_REGISTER 2
33 #include "cris-tmpl.c"
35 #if WITH_PROFILE_MODEL_P
37 /* Re-use the bit position for the BZ register, since there are no stall
38 cycles for reading or writing it. */
39 #define CRIS_BZ_REGNO 16
40 #define CRIS_MODF_JUMP_MASK (1 << CRIS_BZ_REGNO)
41 /* Likewise for the WZ register, marking memory writes. */
42 #define CRIS_WZ_REGNO 20
43 #define CRIS_MODF_MEM_WRITE_MASK (1 << CRIS_WZ_REGNO)
44 #define CRIS_MOF_REGNO (16 + 7)
45 #define CRIS_ALWAYS_CONDITION 14
47 /* This macro must only be used in context where there's only one
48 dynamic cause for a penalty, except in the u-exec unit. */
50 #define PENALIZE1(CNT) \
53 CPU_CRIS_MISC_PROFILE (current_cpu)->CNT++; \
54 model_data->prev_prev_prev_modf_regs \
55 = model_data->prev_prev_modf_regs; \
56 model_data->prev_prev_modf_regs \
57 = model_data->prev_modf_regs; \
58 model_data->prev_modf_regs = 0; \
59 model_data->prev_prev_prev_movem_dest_regs \
60 = model_data->prev_prev_movem_dest_regs; \
61 model_data->prev_prev_movem_dest_regs \
62 = model_data->prev_movem_dest_regs; \
63 model_data->prev_movem_dest_regs = 0; \
68 /* Model function for u-skip4 unit. */
71 MY (XCONCAT3 (f_model_crisv
,BASENUM
,
72 _u_skip4
)) (SIM_CPU
*current_cpu
,
73 const IDESC
*idesc ATTRIBUTE_UNUSED
,
74 int unit_num ATTRIBUTE_UNUSED
,
75 int referenced ATTRIBUTE_UNUSED
)
77 /* Handle PC not being updated with pbb. FIXME: What if not pbb? */
82 /* Model function for u-exec unit. */
85 MY (XCONCAT3 (f_model_crisv
,BASENUM
,
86 _u_exec
)) (SIM_CPU
*current_cpu
,
87 const IDESC
*idesc ATTRIBUTE_UNUSED
,
88 int unit_num ATTRIBUTE_UNUSED
,
89 int referenced ATTRIBUTE_UNUSED
,
94 MODEL_CRISV32_DATA
*model_data
95 = (MODEL_CRISV32_DATA
*) CPU_MODEL_DATA (current_cpu
);
97 = ((destreg_out
== -1 ? 0 : (1 << destreg_out
))
98 | model_data
->modf_regs
);
102 if (model_data
->prev_movem_dest_regs
& (1 << srcreg
))
104 PENALIZE1 (movemdst_stall_count
);
105 PENALIZE1 (movemdst_stall_count
);
106 PENALIZE1 (movemdst_stall_count
);
108 else if (model_data
->prev_prev_movem_dest_regs
& (1 << srcreg
))
110 PENALIZE1 (movemdst_stall_count
);
111 PENALIZE1 (movemdst_stall_count
);
113 else if (model_data
->prev_prev_prev_movem_dest_regs
& (1 << srcreg
))
114 PENALIZE1 (movemdst_stall_count
);
117 if (destreg_in
!= -1)
119 if (model_data
->prev_movem_dest_regs
& (1 << destreg_in
))
121 PENALIZE1 (movemdst_stall_count
);
122 PENALIZE1 (movemdst_stall_count
);
123 PENALIZE1 (movemdst_stall_count
);
125 else if (model_data
->prev_prev_movem_dest_regs
& (1 << destreg_in
))
127 PENALIZE1 (movemdst_stall_count
);
128 PENALIZE1 (movemdst_stall_count
);
130 else if (model_data
->prev_prev_prev_movem_dest_regs
& (1 << destreg_in
))
131 PENALIZE1 (movemdst_stall_count
);
134 model_data
->prev_prev_prev_modf_regs
135 = model_data
->prev_prev_modf_regs
;
136 model_data
->prev_prev_modf_regs
= model_data
->prev_modf_regs
;
137 model_data
->prev_modf_regs
= modf_regs
;
138 model_data
->modf_regs
= 0;
140 model_data
->prev_prev_prev_movem_dest_regs
141 = model_data
->prev_prev_movem_dest_regs
;
142 model_data
->prev_prev_movem_dest_regs
= model_data
->prev_movem_dest_regs
;
143 model_data
->prev_movem_dest_regs
= model_data
->movem_dest_regs
;
144 model_data
->movem_dest_regs
= 0;
146 /* Handle PC not being updated with pbb. FIXME: What if not pbb? */
151 /* Special case used when the destination is a special register. */
154 MY (XCONCAT3 (f_model_crisv
,BASENUM
,
155 _u_exec_to_sr
)) (SIM_CPU
*current_cpu
,
156 const IDESC
*idesc ATTRIBUTE_UNUSED
,
157 int unit_num ATTRIBUTE_UNUSED
,
158 int referenced ATTRIBUTE_UNUSED
,
165 specdest
= specreg
+ 16;
169 return MY (XCONCAT3 (f_model_crisv
,BASENUM
,_u_exec
))
170 (current_cpu
, NULL
, 0, 0, -1, srcreg
,
171 /* The positions for constant-zero registers BZ and WZ are recycled
172 for jump and memory-write markers. We must take precautions
173 here not to add false markers for them. It might be that the
174 hardware inserts stall cycles for instructions that actually try
175 and write those registers, but we'll burn that bridge when we
176 get to it; we'd have to find other free bits or make new
177 model_data variables. However, it's doubtful that there will
178 ever be a need to be cycle-correct for useless code, at least in
179 this particular simulator, mainly used for GCC testing. */
180 specdest
== CRIS_BZ_REGNO
|| specdest
== CRIS_WZ_REGNO
185 /* Special case for movem. */
188 MY (XCONCAT3 (f_model_crisv
,BASENUM
,
189 _u_exec_movem
)) (SIM_CPU
*current_cpu
,
190 const IDESC
*idesc ATTRIBUTE_UNUSED
,
191 int unit_num ATTRIBUTE_UNUSED
,
192 int referenced ATTRIBUTE_UNUSED
,
196 return MY (XCONCAT3 (f_model_crisv
,BASENUM
,_u_exec
))
197 (current_cpu
, NULL
, 0, 0, -1, srcreg
, destreg_out
);
200 /* Model function for u-const16 unit. */
203 MY (XCONCAT3 (f_model_crisv
,BASENUM
,
204 _u_const16
)) (SIM_CPU
*current_cpu
,
205 const IDESC
*idesc ATTRIBUTE_UNUSED
,
206 int unit_num ATTRIBUTE_UNUSED
,
207 int referenced ATTRIBUTE_UNUSED
)
209 MODEL_CRISV32_DATA
*model_data
210 = (MODEL_CRISV32_DATA
*) CPU_MODEL_DATA (current_cpu
);
212 /* If the previous insn was a jump of some sort and this insn
213 straddles a cache-line, there's a one-cycle penalty.
214 FIXME: Test-cases for normal const16 and others, like branch. */
215 if ((model_data
->prev_modf_regs
& CRIS_MODF_JUMP_MASK
)
216 && (CPU (h_pc
) & 0x1e) == 0x1e)
217 PENALIZE1 (jumptarget_stall_count
);
219 /* Handle PC not being updated with pbb. FIXME: What if not pbb? */
225 /* Model function for u-const32 unit. */
228 MY (XCONCAT3 (f_model_crisv
,BASENUM
,
229 _u_const32
)) (SIM_CPU
*current_cpu
,
230 const IDESC
*idesc ATTRIBUTE_UNUSED
,
231 int unit_num ATTRIBUTE_UNUSED
,
232 int referenced ATTRIBUTE_UNUSED
)
234 MODEL_CRISV32_DATA
*model_data
235 = (MODEL_CRISV32_DATA
*) CPU_MODEL_DATA (current_cpu
);
237 /* If the previous insn was a jump of some sort and this insn
238 straddles a cache-line, there's a one-cycle penalty. */
239 if ((model_data
->prev_modf_regs
& CRIS_MODF_JUMP_MASK
)
240 && (CPU (h_pc
) & 0x1e) == 0x1c)
241 PENALIZE1 (jumptarget_stall_count
);
243 /* Handle PC not being updated with pbb. FIXME: What if not pbb? */
249 /* Model function for u-mem unit. */
252 MY (XCONCAT3 (f_model_crisv
,BASENUM
,
253 _u_mem
)) (SIM_CPU
*current_cpu
,
254 const IDESC
*idesc ATTRIBUTE_UNUSED
,
255 int unit_num ATTRIBUTE_UNUSED
,
256 int referenced ATTRIBUTE_UNUSED
,
259 MODEL_CRISV32_DATA
*model_data
260 = (MODEL_CRISV32_DATA
*) CPU_MODEL_DATA (current_cpu
);
265 /* If srcreg references a register modified in the previous cycle
266 through other than autoincrement, then there's a penalty: one
268 if (model_data
->prev_modf_regs
& (1 << srcreg
))
269 PENALIZE1 (memsrc_stall_count
);
274 /* Model function for u-mem-r unit. */
277 MY (XCONCAT3 (f_model_crisv
,BASENUM
,
278 _u_mem_r
)) (SIM_CPU
*current_cpu
,
279 const IDESC
*idesc ATTRIBUTE_UNUSED
,
280 int unit_num ATTRIBUTE_UNUSED
,
281 int referenced ATTRIBUTE_UNUSED
)
283 MODEL_CRISV32_DATA
*model_data
284 = (MODEL_CRISV32_DATA
*) CPU_MODEL_DATA (current_cpu
);
286 /* There's a two-cycle penalty for read after a memory write in any of
287 the two previous cycles, known as a cache read-after-write hazard.
289 This model function (the model_data member access) depends on being
290 executed before the u-exec unit. */
291 if ((model_data
->prev_modf_regs
& CRIS_MODF_MEM_WRITE_MASK
)
292 || (model_data
->prev_prev_modf_regs
& CRIS_MODF_MEM_WRITE_MASK
))
294 PENALIZE1 (memraw_stall_count
);
295 PENALIZE1 (memraw_stall_count
);
301 /* Model function for u-mem-w unit. */
304 MY (XCONCAT3 (f_model_crisv
,BASENUM
,
305 _u_mem_w
)) (SIM_CPU
*current_cpu
,
306 const IDESC
*idesc ATTRIBUTE_UNUSED
,
307 int unit_num ATTRIBUTE_UNUSED
,
308 int referenced ATTRIBUTE_UNUSED
)
310 MODEL_CRISV32_DATA
*model_data
311 = (MODEL_CRISV32_DATA
*) CPU_MODEL_DATA (current_cpu
);
313 /* Mark that memory has been written. This model function (the
314 model_data member access) depends on being executed after the
316 model_data
->prev_modf_regs
|= CRIS_MODF_MEM_WRITE_MASK
;
321 /* Model function for u-movem-rtom unit. */
324 MY (XCONCAT3 (f_model_crisv
,BASENUM
,
325 _u_movem_rtom
)) (SIM_CPU
*current_cpu
,
326 const IDESC
*idesc ATTRIBUTE_UNUSED
,
327 int unit_num ATTRIBUTE_UNUSED
,
328 int referenced ATTRIBUTE_UNUSED
,
329 /* Deliberate order. */
330 INT addrreg
, INT limreg
)
333 MODEL_CRISV32_DATA
*model_data
334 = (MODEL_CRISV32_DATA
*) CPU_MODEL_DATA (current_cpu
);
336 if (limreg
== -1 || addrreg
== -1)
339 addr
= GET_H_GR (addrreg
);
341 /* The movem-to-memory instruction must not move a register modified
342 in one of the previous two cycles. Enforce by adding penalty
344 if (model_data
->prev_modf_regs
& ((1 << (limreg
+ 1)) - 1))
346 PENALIZE1 (movemsrc_stall_count
);
347 PENALIZE1 (movemsrc_stall_count
);
349 else if (model_data
->prev_prev_modf_regs
& ((1 << (limreg
+ 1)) - 1))
350 PENALIZE1 (movemsrc_stall_count
);
352 /* One-cycle penalty for each cache-line straddled. Use the
353 documented expressions. Unfortunately no penalty cycles are
354 eliminated by any penalty cycles above. We file these numbers
355 separately, since they aren't schedulable for all cases. */
356 if ((addr
>> 5) == (((addr
+ 4 * (limreg
+ 1)) - 1) >> 5))
358 else if ((addr
>> 5) == (((addr
+ 4 * (limreg
+ 1)) - 1) >> 5) - 1)
359 PENALIZE1 (movemaddr_stall_count
);
360 else if ((addr
>> 5) == (((addr
+ 4 * (limreg
+ 1)) - 1) >> 5) - 2)
362 PENALIZE1 (movemaddr_stall_count
);
363 PENALIZE1 (movemaddr_stall_count
);
371 /* Model function for u-movem-mtor unit. */
374 MY (XCONCAT3 (f_model_crisv
,BASENUM
,
375 _u_movem_mtor
)) (SIM_CPU
*current_cpu
,
376 const IDESC
*idesc ATTRIBUTE_UNUSED
,
377 int unit_num ATTRIBUTE_UNUSED
,
378 int referenced ATTRIBUTE_UNUSED
,
379 /* Deliberate order. */
380 INT addrreg
, INT limreg
)
383 int nregs
= limreg
+ 1;
384 MODEL_CRISV32_DATA
*model_data
385 = (MODEL_CRISV32_DATA
*) CPU_MODEL_DATA (current_cpu
);
387 if (limreg
== -1 || addrreg
== -1)
390 addr
= GET_H_GR (addrreg
);
392 /* One-cycle penalty for each cache-line straddled. Use the
393 documented expressions. One cycle is the norm; more cycles are
394 counted as penalties. Unfortunately no penalty cycles here
395 eliminate penalty cycles indicated in ->movem_dest_regs. */
396 if ((addr
>> 5) == (((addr
+ 4 * nregs
) - 1) >> 5) - 1)
397 PENALIZE1 (movemaddr_stall_count
);
398 else if ((addr
>> 5) == (((addr
+ 4 * nregs
) - 1) >> 5) - 2)
400 PENALIZE1 (movemaddr_stall_count
);
401 PENALIZE1 (movemaddr_stall_count
);
404 model_data
->modf_regs
|= ((1 << nregs
) - 1);
405 model_data
->movem_dest_regs
|= ((1 << nregs
) - 1);
410 /* Model function for u-branch unit.
411 FIXME: newpc and cc are always wrong. */
414 MY (XCONCAT3 (f_model_crisv
,BASENUM
,_u_branch
)) (SIM_CPU
*current_cpu
,
416 int unit_num
, int referenced
)
418 CRIS_MISC_PROFILE
*profp
= CPU_CRIS_MISC_PROFILE (current_cpu
);
419 USI pc
= profp
->old_pc
;
420 MODEL_CRISV32_DATA
*model_data
421 = (MODEL_CRISV32_DATA
*) CPU_MODEL_DATA (current_cpu
);
422 int taken
= profp
->branch_taken
;
423 int branch_index
= (pc
& (N_CRISV32_BRANCH_PREDICTORS
- 1)) >> 1;
424 int pred_taken
= (profp
->branch_predictors
[branch_index
] & 2) != 0;
426 if (taken
!= pred_taken
)
428 PENALIZE1 (branch_stall_count
);
429 PENALIZE1 (branch_stall_count
);
434 if (profp
->branch_predictors
[branch_index
] < 3)
435 profp
->branch_predictors
[branch_index
]++;
437 return MY (XCONCAT3 (f_model_crisv
,BASENUM
,_u_jump
))
438 (current_cpu
, idesc
, unit_num
, referenced
, -1);
441 if (profp
->branch_predictors
[branch_index
] != 0)
442 profp
->branch_predictors
[branch_index
]--;
447 /* Model function for u-jump-r unit. */
450 MY (XCONCAT3 (f_model_crisv
,BASENUM
,
451 _u_jump_r
)) (SIM_CPU
*current_cpu
,
452 const IDESC
*idesc ATTRIBUTE_UNUSED
,
453 int unit_num ATTRIBUTE_UNUSED
,
454 int referenced ATTRIBUTE_UNUSED
,
457 MODEL_CRISV32_DATA
*model_data
458 = (MODEL_CRISV32_DATA
*) CPU_MODEL_DATA (current_cpu
);
463 /* For jump-to-register, the register must not have been modified the
464 last two cycles. Penalty: two cycles from the modifying insn. */
465 if ((1 << regno
) & model_data
->prev_modf_regs
)
467 PENALIZE1 (jumpsrc_stall_count
);
468 PENALIZE1 (jumpsrc_stall_count
);
470 else if ((1 << regno
) & model_data
->prev_prev_modf_regs
)
471 PENALIZE1 (jumpsrc_stall_count
);
476 /* Model function for u-jump-sr unit. */
479 MY (XCONCAT3 (f_model_crisv
,BASENUM
,_u_jump_sr
)) (SIM_CPU
*current_cpu
,
481 int unit_num
, int referenced
,
486 MODEL_CRISV32_DATA
*model_data
487 = (MODEL_CRISV32_DATA
*) CPU_MODEL_DATA (current_cpu
);
492 regno
= sr_regno
+ 16;
494 /* For jump-to-register, the register must not have been modified the
495 last two cycles. Penalty: two cycles from the modifying insn. */
496 if ((1 << regno
) & model_data
->prev_modf_regs
)
498 PENALIZE1 (jumpsrc_stall_count
);
499 PENALIZE1 (jumpsrc_stall_count
);
501 else if ((1 << regno
) & model_data
->prev_prev_modf_regs
)
502 PENALIZE1 (jumpsrc_stall_count
);
505 MY (XCONCAT3 (f_model_crisv
,BASENUM
,_u_jump
)) (current_cpu
, idesc
,
506 unit_num
, referenced
, -1);
509 /* Model function for u-jump unit. */
512 MY (XCONCAT3 (f_model_crisv
,BASENUM
,
513 _u_jump
)) (SIM_CPU
*current_cpu
,
514 const IDESC
*idesc ATTRIBUTE_UNUSED
,
515 int unit_num ATTRIBUTE_UNUSED
,
516 int referenced ATTRIBUTE_UNUSED
,
519 MODEL_CRISV32_DATA
*model_data
520 = (MODEL_CRISV32_DATA
*) CPU_MODEL_DATA (current_cpu
);
522 /* Mark that we made a jump. */
523 model_data
->modf_regs
524 |= (CRIS_MODF_JUMP_MASK
525 | (out_sr_regno
== -1 || out_sr_regno
== CRIS_BZ_REGNO
526 ? 0 : (1 << (out_sr_regno
+ 16))));
530 /* Model function for u-multiply unit. */
533 MY (XCONCAT3 (f_model_crisv
,BASENUM
,
534 _u_multiply
)) (SIM_CPU
*current_cpu
,
535 const IDESC
*idesc ATTRIBUTE_UNUSED
,
536 int unit_num ATTRIBUTE_UNUSED
,
537 int referenced ATTRIBUTE_UNUSED
,
538 int srcreg
, int destreg
)
540 MODEL_CRISV32_DATA
*model_data
541 = (MODEL_CRISV32_DATA
*) CPU_MODEL_DATA (current_cpu
);
543 /* Sanity-check for cases that should never happen. */
544 if (srcreg
== -1 || destreg
== -1)
547 /* This takes extra cycles when one of the inputs has been modified
548 through other than autoincrement in the previous cycle. Penalty:
550 if (((1 << srcreg
) | (1 << destreg
)) & model_data
->prev_modf_regs
)
551 PENALIZE1 (mulsrc_stall_count
);
553 /* We modified the multiplication destination (marked in u-exec) and
555 model_data
->modf_regs
|= (1 << CRIS_MOF_REGNO
);
559 #endif /* WITH_PROFILE_MODEL_P */
562 MY (deliver_interrupt
) (SIM_CPU
*current_cpu
,
563 enum cris_interrupt_type type
,
566 unsigned32 old_ccs
, shifted_ccs
, new_ccs
;
567 unsigned char entryaddr_le
[4];
569 SIM_DESC sd
= CPU_STATE (current_cpu
);
570 unsigned32 entryaddr
;
572 /* We haven't implemented other interrupt-types yet. */
573 if (type
!= CRIS_INT_INT
)
576 /* We're called outside of branch delay slots etc, so we don't check
578 if (!GET_H_IBIT_V32 ())
581 old_ccs
= GET_H_SR_V32 (H_SR_CCS
);
582 shifted_ccs
= (old_ccs
<< 10) & ((1 << 30) - 1);
584 /* The M bit is handled by code below and the M bit setter function, but
585 we need to preserve the Q bit. */
586 new_ccs
= shifted_ccs
| (old_ccs
& (unsigned32
) 0x80000000UL
);
587 was_user
= GET_H_UBIT_V32 ();
589 /* We need to force kernel mode since the setter method doesn't allow
590 it. Then we can use setter methods at will, since they then
591 recognize that we're in kernel mode. */
592 CPU (h_ubit_v32
) = 0;
594 SET_H_SR (H_SR_CCS
, new_ccs
);
598 /* These methods require that user mode is unset. */
599 SET_H_SR (H_SR_USP
, GET_H_GR (H_GR_SP
));
600 SET_H_GR (H_GR_SP
, GET_H_KERNEL_SP ());
603 /* ERP setting is simplified by not taking interrupts in delay-slots
605 /* For all other exceptions than guru and NMI, store the return
606 address in ERP and set EXS and EXD here. */
607 SET_H_SR (H_SR_ERP
, GET_H_PC ());
609 /* Simplified by not having exception types (fault indications). */
610 SET_H_SR_V32 (H_SR_EXS
, (vec
* 256));
611 SET_H_SR_V32 (H_SR_EDA
, 0);
613 if (sim_core_read_buffer (sd
,
615 read_map
, entryaddr_le
,
616 GET_H_SR (H_SR_EBP
) + vec
* 4, 4) == 0)
618 /* Nothing to do actually; either abort or send a signal. */
619 sim_core_signal (sd
, current_cpu
, CIA_GET (current_cpu
), 0, 4,
620 GET_H_SR (H_SR_EBP
) + vec
* 4,
621 read_transfer
, sim_core_unmapped_signal
);
625 entryaddr
= bfd_getl32 (entryaddr_le
);
626 SET_H_PC (entryaddr
);