xref: /netbsd-src/external/gpl3/gdb/dist/sim/cris/cris-tmpl.c (revision 9ac63422b666fbe53a067de74d8af2aa4e45a08b)
1 /* CRIS base simulator support code
2    Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
3    Free Software Foundation, Inc.
4    Contributed by Axis Communications.
5 
6 This file is part of the GNU simulators.
7 
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
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 
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];
122     unsigned64 cycle_count;
123 
124     SIM_DESC sd = CPU_STATE (current_cpu);
125 
126     cris_trace_printf (sd, current_cpu, "%lx ",
127 		       0xffffffffUL & (unsigned long) (CPU (h_pc)));
128 
129     for (i = 0; i < 15; i++)
130       cris_trace_printf (sd, current_cpu, "%lx ",
131 			 0xffffffffUL
132 			 & (unsigned long) (XCONCAT3(crisv,BASENUM,
133 						     f_h_gr_get) (current_cpu,
134 								  i)));
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 
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 
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,
153 			 (int) cycle_count,
154 			 0xffffffffUL
155 			 & (unsigned long) (XCONCAT3(crisv,BASENUM,
156 						     f_h_gr_get) (current_cpu,
157 								  15)));
158     else
159       cris_trace_printf (sd, current_cpu, "%s %d\n", flags,
160 			 (int) cycle_count);
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 #if WITH_HW
183   /* For some reason, we don't get to the sim_events_tick call in
184      cgen-run.c:engine_run_1.  Besides, more than one cycle has
185      passed, so we want sim_events_tickn anyway.  The "events we want
186      to process" is usually to initiate an interrupt, but might also
187      be other events.  We can't do the former until the main loop is
188      at point where it accepts changing the PC without internal
189      inconsistency, so just set a flag and wait.  */
190   if (sim_events_tickn (CPU_STATE (current_cpu), cycles))
191     STATE_EVENTS (CPU_STATE (current_cpu))->work_pending = 1;
192 #endif
193 }
194 
195 /* Initialize cycle counting for an insn.
196    FIRST_P is non-zero if this is the first insn in a set of parallel
197    insns.  */
198 
199 void
200 MY (f_model_init_insn_cycles) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
201 			       int first_p ATTRIBUTE_UNUSED)
202 {
203   abort ();
204 }
205 
206 /* Record the cycles computed for an insn.
207    LAST_P is non-zero if this is the last insn in a set of parallel insns,
208    and we update the total cycle count.  */
209 
210 void
211 MY (f_model_update_insn_cycles) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
212 				 int last_p ATTRIBUTE_UNUSED)
213 {
214   abort ();
215 }
216 
217 #if 0
218 void
219 MY (f_model_record_cycles) (SIM_CPU *current_cpu, unsigned long cycles)
220 {
221   abort ();
222 }
223 
224 void
225 MY (f_model_mark_get_h_gr) (SIM_CPU *current_cpu, ARGBUF *abuf)
226 {
227   abort ();
228 }
229 
230 void
231 MY (f_model_mark_set_h_gr) (SIM_CPU *current_cpu, ARGBUF *abuf)
232 {
233   abort ();
234 }
235 #endif
236 
237 /* Set the thread register contents.  */
238 
239 void
240 MY (set_target_thread_data) (SIM_CPU *current_cpu, USI val)
241 {
242   (CPU (XCONCAT2 (h_sr_v, BASENUM) [CRIS_TLS_REGISTER])) = val;
243 }
244 
245 /* Create the context for a thread.  */
246 
247 void *
248 MY (make_thread_cpu_data) (SIM_CPU *current_cpu, void *context)
249 {
250   void *info = xmalloc (current_cpu->thread_cpu_data_size);
251 
252   if (context != NULL)
253     memcpy (info,
254 	    context,
255 	    current_cpu->thread_cpu_data_size);
256   else
257     memset (info, 0, current_cpu->thread_cpu_data_size),abort();
258   return info;
259 }
260 
261 /* Hook function for per-cpu simulator initialization.  */
262 
263 void
264 MY (f_specific_init) (SIM_CPU *current_cpu)
265 {
266   current_cpu->make_thread_cpu_data = MY (make_thread_cpu_data);
267   current_cpu->thread_cpu_data_size = sizeof (current_cpu->cpu_data);
268   current_cpu->set_target_thread_data = MY (set_target_thread_data);
269 #if WITH_HW
270   current_cpu->deliver_interrupt = MY (deliver_interrupt);
271 #endif
272 }
273 
274 /* Model function for arbitrary single stall cycles.  */
275 
276 int
277 MY (XCONCAT3 (f_model_crisv,BASENUM,
278 	      _u_stall)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
279 			  const IDESC *idesc,
280 			  int unit_num,
281 			  int referenced ATTRIBUTE_UNUSED)
282 {
283   return idesc->timing->units[unit_num].done;
284 }
285 
286 #ifndef SPECIFIC_U_SKIP4_FN
287 
288 /* Model function for u-skip4 unit.  */
289 
290 int
291 MY (XCONCAT3 (f_model_crisv,BASENUM,
292 	      _u_skip4)) (SIM_CPU *current_cpu,
293 			  const IDESC *idesc,
294 			  int unit_num,
295 			  int referenced ATTRIBUTE_UNUSED)
296 {
297   /* Handle PC not being updated with pbb.  FIXME: What if not pbb?  */
298   CPU (h_pc) += 4;
299   return idesc->timing->units[unit_num].done;
300 }
301 
302 #endif
303 
304 #ifndef SPECIFIC_U_EXEC_FN
305 
306 /* Model function for u-exec unit.  */
307 
308 int
309 MY (XCONCAT3 (f_model_crisv,BASENUM,
310 	      _u_exec)) (SIM_CPU *current_cpu,
311 			 const IDESC *idesc,
312 			 int unit_num, int referenced ATTRIBUTE_UNUSED)
313 {
314   /* Handle PC not being updated with pbb.  FIXME: What if not pbb?  */
315   CPU (h_pc) += 2;
316   return idesc->timing->units[unit_num].done;
317 }
318 #endif
319 
320 #ifndef SPECIFIC_U_MEM_FN
321 
322 /* Model function for u-mem unit.  */
323 
324 int
325 MY (XCONCAT3 (f_model_crisv,BASENUM,
326 	      _u_mem)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
327 			const IDESC *idesc,
328 			int unit_num,
329 			int referenced ATTRIBUTE_UNUSED)
330 {
331   return idesc->timing->units[unit_num].done;
332 }
333 #endif
334 
335 #ifndef SPECIFIC_U_CONST16_FN
336 
337 /* Model function for u-const16 unit.  */
338 
339 int
340 MY (XCONCAT3 (f_model_crisv,BASENUM,
341 	      _u_const16)) (SIM_CPU *current_cpu,
342 			    const IDESC *idesc,
343 			    int unit_num,
344 			    int referenced ATTRIBUTE_UNUSED)
345 {
346   CPU (h_pc) += 2;
347   return idesc->timing->units[unit_num].done;
348 }
349 #endif /* SPECIFIC_U_CONST16_FN */
350 
351 #ifndef SPECIFIC_U_CONST32_FN
352 
353 /* This will be incorrect for early models, where a dword always take
354    two cycles.  */
355 #define CRIS_MODEL_MASK_PC_STALL 2
356 
357 /* Model function for u-const32 unit.  */
358 
359 int
360 MY (XCONCAT3 (f_model_crisv,BASENUM,
361 	      _u_const32)) (SIM_CPU *current_cpu,
362 			    const IDESC *idesc,
363 			    int unit_num,
364 			    int referenced ATTRIBUTE_UNUSED)
365 {
366   int unaligned_extra
367     = (((CPU (h_pc) + 2) & CRIS_MODEL_MASK_PC_STALL)
368        == CRIS_MODEL_MASK_PC_STALL);
369 
370   /* Handle PC not being updated with pbb.  FIXME: What if not pbb?  */
371   CPU_CRIS_MISC_PROFILE (current_cpu)->unaligned_mem_dword_count
372     += unaligned_extra;
373 
374   CPU (h_pc) += 4;
375   return idesc->timing->units[unit_num].done;
376 }
377 #endif /* SPECIFIC_U_CONST32_FN */
378 
379 #ifndef SPECIFIC_U_MOVEM_FN
380 
381 /* Model function for u-movem unit.  */
382 
383 int
384 MY (XCONCAT3 (f_model_crisv,BASENUM,
385 	      _u_movem)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
386 			  const IDESC *idesc ATTRIBUTE_UNUSED,
387 			  int unit_num ATTRIBUTE_UNUSED,
388 			  int referenced ATTRIBUTE_UNUSED,
389 			  INT limreg)
390 {
391   /* FIXME: Add cycles for misalignment.  */
392 
393   if (limreg == -1)
394     abort ();
395 
396   /* We don't record movem move cycles in movemsrc_stall_count since
397      those cycles have historically been handled as ordinary cycles.  */
398   return limreg + 1;
399 }
400 #endif /* SPECIFIC_U_MOVEM_FN */
401 
402 #endif /* WITH_PROFILE_MODEL_P */
403