Commit | Line | Data |
---|---|---|
f6bcefef | 1 | /* CRIS base simulator support code |
8d516ebc | 2 | Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. |
f6bcefef HPN |
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 2, or (at your option) | |
10 | 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 along | |
18 | with this program; if not, write to the Free Software Foundation, Inc., | |
19 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
20 | ||
21 | /* The infrastructure is based on that of i960.c. */ | |
22 | ||
23 | #define WANT_CPU | |
24 | ||
25 | #include "sim-main.h" | |
26 | #include "cgen-mem.h" | |
27 | #include "cgen-ops.h" | |
28 | ||
29 | #define MY(f) XCONCAT3(crisv,BASENUM,f) | |
30 | ||
31 | /* Dispatcher for break insn. */ | |
32 | ||
33 | USI | |
34 | MY (f_break_handler) (SIM_CPU *cpu, USI breaknum, USI pc) | |
35 | { | |
36 | SIM_DESC sd = CPU_STATE (cpu); | |
37 | USI ret = pc + 2; | |
38 | ||
39 | MY (f_h_pc_set) (cpu, ret); | |
40 | ||
41 | /* FIXME: Error out if IBR or ERP set. */ | |
42 | switch (breaknum) | |
43 | { | |
44 | case 13: | |
45 | MY (f_h_gr_set (cpu, 10, | |
46 | cris_break_13_handler (cpu, | |
47 | MY (f_h_gr_get (cpu, 9)), | |
48 | MY (f_h_gr_get (cpu, 10)), | |
49 | MY (f_h_gr_get (cpu, 11)), | |
50 | MY (f_h_gr_get (cpu, 12)), | |
51 | MY (f_h_gr_get (cpu, 13)), | |
52 | MY (f_h_sr_get (cpu, 7)), | |
53 | MY (f_h_sr_get (cpu, 11)), | |
54 | pc))); | |
55 | break; | |
56 | ||
57 | case 14: | |
58 | sim_io_printf (sd, "%x\n", MY (f_h_gr_get (cpu, 3))); | |
59 | break; | |
60 | ||
61 | case 15: | |
62 | /* Re-use the Linux exit call. */ | |
63 | cris_break_13_handler (cpu, /* TARGET_SYS_exit */ 1, 0, | |
64 | 0, 0, 0, 0, 0, pc); | |
65 | ||
66 | default: | |
67 | abort (); | |
68 | } | |
69 | ||
70 | return MY (f_h_pc_get) (cpu); | |
71 | } | |
72 | ||
73 | /* Accessor function for simulator internal use. | |
74 | Note the contents of BUF are in target byte order. */ | |
75 | ||
76 | int | |
77 | MY (f_fetch_register) (SIM_CPU *current_cpu, int rn, | |
78 | unsigned char *buf, int len ATTRIBUTE_UNUSED) | |
79 | { | |
80 | SETTSI (buf, XCONCAT3(crisv,BASENUM,f_h_gr_get) (current_cpu, rn)); | |
81 | return -1; | |
82 | } | |
83 | ||
84 | /* Accessor function for simulator internal use. | |
85 | Note the contents of BUF are in target byte order. */ | |
86 | ||
87 | int | |
88 | MY (f_store_register) (SIM_CPU *current_cpu, int rn, | |
89 | unsigned char *buf, int len ATTRIBUTE_UNUSED) | |
90 | { | |
91 | XCONCAT3(crisv,BASENUM,f_h_gr_set) (current_cpu, rn, GETTSI (buf)); | |
92 | return -1; | |
93 | } | |
94 | \f | |
95 | #if WITH_PROFILE_MODEL_P | |
96 | ||
97 | /* FIXME: Some of these should be inline or macros. Later. */ | |
98 | ||
99 | /* Initialize cycle counting for an insn. | |
100 | FIRST_P is non-zero if this is the first insn in a set of parallel | |
101 | insns. */ | |
102 | ||
103 | void | |
104 | MY (f_model_insn_before) (SIM_CPU *current_cpu, int first_p ATTRIBUTE_UNUSED) | |
105 | { | |
106 | /* To give the impression that we actually know what PC is, we have to | |
107 | dump register contents *before* the *next* insn, not after the | |
108 | *previous* insn. Uhh... */ | |
109 | ||
110 | /* FIXME: Move this to separate, overridable function. */ | |
111 | if ((CPU_CRIS_MISC_PROFILE (current_cpu)->flags | |
112 | & FLAG_CRIS_MISC_PROFILE_XSIM_TRACE) | |
113 | #ifdef GET_H_INSN_PREFIXED_P | |
114 | /* For versions with prefixed insns, trace the combination as | |
115 | one insn. */ | |
116 | && !GET_H_INSN_PREFIXED_P () | |
117 | #endif | |
118 | && 1) | |
119 | { | |
120 | int i; | |
121 | char flags[7]; | |
4fc9958a HPN |
122 | unsigned64 cycle_count; |
123 | ||
f6bcefef HPN |
124 | SIM_DESC sd = CPU_STATE (current_cpu); |
125 | ||
ae81c235 HPN |
126 | cris_trace_printf (sd, current_cpu, "%lx ", |
127 | 0xffffffffUL & (unsigned long) (CPU (h_pc))); | |
f6bcefef HPN |
128 | |
129 | for (i = 0; i < 15; i++) | |
130 | cris_trace_printf (sd, current_cpu, "%lx ", | |
ae81c235 HPN |
131 | 0xffffffffUL |
132 | & (unsigned long) (XCONCAT3(crisv,BASENUM, | |
133 | f_h_gr_get) (current_cpu, | |
134 | i))); | |
f6bcefef HPN |
135 | flags[0] = GET_H_IBIT () != 0 ? 'I' : 'i'; |
136 | flags[1] = GET_H_XBIT () != 0 ? 'X' : 'x'; | |
137 | flags[2] = GET_H_NBIT () != 0 ? 'N' : 'n'; | |
138 | flags[3] = GET_H_ZBIT () != 0 ? 'Z' : 'z'; | |
139 | flags[4] = GET_H_VBIT () != 0 ? 'V' : 'v'; | |
140 | flags[5] = GET_H_CBIT () != 0 ? 'C' : 'c'; | |
141 | flags[6] = 0; | |
142 | ||
4fc9958a HPN |
143 | /* For anything else than basic tracing we'd add stall cycles for |
144 | e.g. unaligned accesses. FIXME: add --cris-trace=x options to | |
145 | match --cris-cycles=x. */ | |
146 | cycle_count | |
147 | = (CPU_CRIS_MISC_PROFILE (current_cpu)->basic_cycle_count | |
148 | - CPU_CRIS_PREV_MISC_PROFILE (current_cpu)->basic_cycle_count); | |
149 | ||
f6bcefef HPN |
150 | /* Emit ACR after flags and cycle count for this insn. */ |
151 | if (BASENUM == 32) | |
152 | cris_trace_printf (sd, current_cpu, "%s %d %lx\n", flags, | |
4fc9958a | 153 | (int) cycle_count, |
ae81c235 HPN |
154 | 0xffffffffUL |
155 | & (unsigned long) (XCONCAT3(crisv,BASENUM, | |
156 | f_h_gr_get) (current_cpu, | |
157 | 15))); | |
f6bcefef HPN |
158 | else |
159 | cris_trace_printf (sd, current_cpu, "%s %d\n", flags, | |
4fc9958a | 160 | (int) cycle_count); |
f6bcefef HPN |
161 | |
162 | CPU_CRIS_PREV_MISC_PROFILE (current_cpu)[0] | |
163 | = CPU_CRIS_MISC_PROFILE (current_cpu)[0]; | |
164 | } | |
165 | } | |
166 | ||
167 | /* Record the cycles computed for an insn. | |
168 | LAST_P is non-zero if this is the last insn in a set of parallel insns, | |
169 | and we update the total cycle count. | |
170 | CYCLES is the cycle count of the insn. */ | |
171 | ||
172 | void | |
173 | MY (f_model_insn_after) (SIM_CPU *current_cpu, int last_p ATTRIBUTE_UNUSED, | |
174 | int cycles) | |
175 | { | |
176 | PROFILE_DATA *p = CPU_PROFILE_DATA (current_cpu); | |
177 | ||
178 | PROFILE_MODEL_TOTAL_CYCLES (p) += cycles; | |
179 | CPU_CRIS_MISC_PROFILE (current_cpu)->basic_cycle_count += cycles; | |
180 | PROFILE_MODEL_CUR_INSN_CYCLES (p) = cycles; | |
181 | } | |
182 | ||
183 | /* Initialize cycle counting for an insn. | |
184 | FIRST_P is non-zero if this is the first insn in a set of parallel | |
185 | insns. */ | |
186 | ||
187 | void | |
188 | MY (f_model_init_insn_cycles) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, | |
189 | int first_p ATTRIBUTE_UNUSED) | |
190 | { | |
191 | abort (); | |
192 | } | |
193 | ||
194 | /* Record the cycles computed for an insn. | |
195 | LAST_P is non-zero if this is the last insn in a set of parallel insns, | |
196 | and we update the total cycle count. */ | |
197 | ||
198 | void | |
199 | MY (f_model_update_insn_cycles) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, | |
200 | int last_p ATTRIBUTE_UNUSED) | |
201 | { | |
202 | abort (); | |
203 | } | |
204 | ||
205 | #if 0 | |
206 | void | |
207 | MY (f_model_record_cycles) (SIM_CPU *current_cpu, unsigned long cycles) | |
208 | { | |
209 | abort (); | |
210 | } | |
211 | ||
212 | void | |
213 | MY (f_model_mark_get_h_gr) (SIM_CPU *current_cpu, ARGBUF *abuf) | |
214 | { | |
215 | abort (); | |
216 | } | |
217 | ||
218 | void | |
219 | MY (f_model_mark_set_h_gr) (SIM_CPU *current_cpu, ARGBUF *abuf) | |
220 | { | |
221 | abort (); | |
222 | } | |
223 | #endif | |
224 | \f | |
225 | /* Create the context for a thread. */ | |
226 | ||
227 | void * | |
228 | MY (make_thread_cpu_data) (SIM_CPU *current_cpu, void *context) | |
229 | { | |
230 | void *info = xmalloc (current_cpu->thread_cpu_data_size); | |
231 | ||
232 | if (context != NULL) | |
233 | memcpy (info, | |
234 | context, | |
235 | current_cpu->thread_cpu_data_size); | |
236 | else | |
237 | memset (info, 0, current_cpu->thread_cpu_data_size),abort(); | |
238 | return info; | |
239 | } | |
240 | ||
241 | /* Hook function for per-cpu simulator initialization. */ | |
242 | ||
243 | void | |
244 | MY (f_specific_init) (SIM_CPU *current_cpu) | |
245 | { | |
246 | current_cpu->make_thread_cpu_data = MY (make_thread_cpu_data); | |
247 | current_cpu->thread_cpu_data_size = sizeof (current_cpu->cpu_data); | |
248 | } | |
249 | \f | |
250 | /* Model function for arbitrary single stall cycles. */ | |
251 | ||
252 | int | |
253 | MY (XCONCAT3 (f_model_crisv,BASENUM, | |
254 | _u_stall)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, | |
255 | const IDESC *idesc, | |
256 | int unit_num, | |
257 | int referenced ATTRIBUTE_UNUSED) | |
258 | { | |
259 | return idesc->timing->units[unit_num].done; | |
260 | } | |
261 | ||
262 | #ifndef SPECIFIC_U_SKIP4_FN | |
263 | ||
264 | /* Model function for u-skip4 unit. */ | |
265 | ||
266 | int | |
267 | MY (XCONCAT3 (f_model_crisv,BASENUM, | |
268 | _u_skip4)) (SIM_CPU *current_cpu, | |
269 | const IDESC *idesc, | |
270 | int unit_num, | |
271 | int referenced ATTRIBUTE_UNUSED) | |
272 | { | |
273 | /* Handle PC not being updated with pbb. FIXME: What if not pbb? */ | |
274 | CPU (h_pc) += 4; | |
275 | return idesc->timing->units[unit_num].done; | |
276 | } | |
277 | ||
278 | #endif | |
279 | ||
280 | #ifndef SPECIFIC_U_EXEC_FN | |
281 | ||
282 | /* Model function for u-exec unit. */ | |
283 | ||
284 | int | |
285 | MY (XCONCAT3 (f_model_crisv,BASENUM, | |
286 | _u_exec)) (SIM_CPU *current_cpu, | |
287 | const IDESC *idesc, | |
288 | int unit_num, int referenced ATTRIBUTE_UNUSED) | |
289 | { | |
290 | /* Handle PC not being updated with pbb. FIXME: What if not pbb? */ | |
291 | CPU (h_pc) += 2; | |
292 | return idesc->timing->units[unit_num].done; | |
293 | } | |
294 | #endif | |
295 | ||
296 | #ifndef SPECIFIC_U_MEM_FN | |
297 | ||
298 | /* Model function for u-mem unit. */ | |
299 | ||
300 | int | |
301 | MY (XCONCAT3 (f_model_crisv,BASENUM, | |
302 | _u_mem)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, | |
303 | const IDESC *idesc, | |
304 | int unit_num, | |
305 | int referenced ATTRIBUTE_UNUSED) | |
306 | { | |
307 | return idesc->timing->units[unit_num].done; | |
308 | } | |
309 | #endif | |
310 | ||
311 | #ifndef SPECIFIC_U_CONST16_FN | |
312 | ||
313 | /* Model function for u-const16 unit. */ | |
314 | ||
315 | int | |
316 | MY (XCONCAT3 (f_model_crisv,BASENUM, | |
317 | _u_const16)) (SIM_CPU *current_cpu, | |
318 | const IDESC *idesc, | |
319 | int unit_num, | |
320 | int referenced ATTRIBUTE_UNUSED) | |
321 | { | |
322 | CPU (h_pc) += 2; | |
323 | return idesc->timing->units[unit_num].done; | |
324 | } | |
325 | #endif /* SPECIFIC_U_CONST16_FN */ | |
326 | ||
327 | #ifndef SPECIFIC_U_CONST32_FN | |
328 | ||
329 | /* This will be incorrect for early models, where a dword always take | |
330 | two cycles. */ | |
331 | #define CRIS_MODEL_MASK_PC_STALL 2 | |
332 | ||
333 | /* Model function for u-const32 unit. */ | |
334 | ||
335 | int | |
336 | MY (XCONCAT3 (f_model_crisv,BASENUM, | |
337 | _u_const32)) (SIM_CPU *current_cpu, | |
338 | const IDESC *idesc, | |
339 | int unit_num, | |
340 | int referenced ATTRIBUTE_UNUSED) | |
341 | { | |
342 | int unaligned_extra | |
343 | = (((CPU (h_pc) + 2) & CRIS_MODEL_MASK_PC_STALL) | |
344 | == CRIS_MODEL_MASK_PC_STALL); | |
345 | ||
346 | /* Handle PC not being updated with pbb. FIXME: What if not pbb? */ | |
347 | CPU_CRIS_MISC_PROFILE (current_cpu)->unaligned_mem_dword_count | |
348 | += unaligned_extra; | |
349 | ||
350 | CPU (h_pc) += 4; | |
351 | return idesc->timing->units[unit_num].done; | |
352 | } | |
353 | #endif /* SPECIFIC_U_CONST32_FN */ | |
354 | ||
355 | #ifndef SPECIFIC_U_MOVEM_FN | |
356 | ||
357 | /* Model function for u-movem unit. */ | |
358 | ||
359 | int | |
360 | MY (XCONCAT3 (f_model_crisv,BASENUM, | |
361 | _u_movem)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, | |
362 | const IDESC *idesc ATTRIBUTE_UNUSED, | |
363 | int unit_num ATTRIBUTE_UNUSED, | |
364 | int referenced ATTRIBUTE_UNUSED, | |
365 | INT limreg) | |
366 | { | |
367 | /* FIXME: Add cycles for misalignment. */ | |
368 | ||
369 | if (limreg == -1) | |
370 | abort (); | |
371 | ||
372 | /* We don't record movem move cycles in movemsrc_stall_count since | |
373 | those cycles have historically been handled as ordinary cycles. */ | |
374 | return limreg + 1; | |
375 | } | |
376 | #endif /* SPECIFIC_U_MOVEM_FN */ | |
377 | ||
378 | #endif /* WITH_PROFILE_MODEL_P */ |