xref: /netbsd-src/external/gpl3/gdb/dist/sim/cris/cris-tmpl.c (revision 05d8e8fe083a4bc28647839371f28bad98396c12)
1 /* CRIS base simulator support code
2    Copyright (C) 2004-2024 Free Software Foundation, Inc.
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 3 of the License, or
10 (at your option) 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
18 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 /* The infrastructure is based on that of i960.c.  */
21 
22 /* This must come before any other includes.  */
23 #include "defs.h"
24 
25 #define WANT_CPU
26 
27 #include "sim-main.h"
28 #include "cgen-mem.h"
29 #include "cgen-ops.h"
30 
31 #include <stdlib.h>
32 
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 
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 
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
85 MY (f_fetch_register) (SIM_CPU *current_cpu, int rn, void *buf,
86 		      int len ATTRIBUTE_UNUSED)
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
96 MY (f_store_register) (SIM_CPU *current_cpu, int rn, const void *buf,
97 		      int len ATTRIBUTE_UNUSED)
98 {
99   XCONCAT3(crisv,BASENUM,f_h_gr_set) (current_cpu, rn, GETTSI (buf));
100   return -1;
101 }
102 
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];
130     uint64_t cycle_count;
131 
132     SIM_DESC sd = CPU_STATE (current_cpu);
133 
134     cris_trace_printf (sd, current_cpu, "%lx ",
135 		       0xffffffffUL & (unsigned long) (CPU (h_pc)));
136 
137     for (i = 0; i < 15; i++)
138       cris_trace_printf (sd, current_cpu, "%lx ",
139 			 0xffffffffUL
140 			 & (unsigned long) (XCONCAT3(crisv,BASENUM,
141 						     f_h_gr_get) (current_cpu,
142 								  i)));
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 
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 
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,
161 			 (int) cycle_count,
162 			 0xffffffffUL
163 			 & (unsigned long) (XCONCAT3(crisv,BASENUM,
164 						     f_h_gr_get) (current_cpu,
165 								  15)));
166     else
167       cris_trace_printf (sd, current_cpu, "%s %d\n", flags,
168 			 (int) cycle_count);
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;
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
201 }
202 
203 #if 0
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 
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 
245 /* Set the thread register contents.  */
246 
247 static void
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 
253 /* Create the context for a thread.  */
254 
255 static void *
256 MY (make_thread_cpu_data) (SIM_CPU *current_cpu, void *context)
257 {
258   struct cris_sim_cpu *cris_cpu = CRIS_SIM_CPU (current_cpu);
259   void *info = xmalloc (cris_cpu->thread_cpu_data_size);
260 
261   if (context != NULL)
262     memcpy (info, context, cris_cpu->thread_cpu_data_size);
263   else
264     memset (info, 0, cris_cpu->thread_cpu_data_size),abort();
265   return info;
266 }
267 
268 /* Placate -Wmissing-prototypes when mloop.in isn't used.  */
269 void MY (f_specific_init) (SIM_CPU *current_cpu);
270 
271 /* Hook function for per-cpu simulator initialization.  */
272 
273 void
274 MY (f_specific_init) (SIM_CPU *current_cpu)
275 {
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);
281 #if WITH_HW
282   cris_cpu->deliver_interrupt = MY (deliver_interrupt);
283 #endif
284 }
285 
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 
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 */
422