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