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