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