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