f055149cce6366aaec99c3c2105e8d07fe207749
[external/binutils.git] / sim / v850 / interp.c
1 #include "sim-main.h"
2 #include "sim-options.h"
3 #include "v850_sim.h"
4 #include "sim-assert.h"
5 #include "itable.h"
6
7 #ifdef HAVE_STDLIB_H
8 #include <stdlib.h>
9 #endif
10
11 #ifdef HAVE_STRING_H
12 #include <string.h>
13 #else
14 #ifdef HAVE_STRINGS_H
15 #include <strings.h>
16 #endif
17 #endif
18
19 #include "bfd.h"
20
21 static const char * get_insn_name (sim_cpu *, int);
22
23 /* For compatibility.  */
24 SIM_DESC simulator;
25
26 /* V850 interrupt model.  */
27
28 enum interrupt_type
29 {
30   int_reset,
31   int_nmi,
32   int_intov1,
33   int_intp10,
34   int_intp11,
35   int_intp12,
36   int_intp13,
37   int_intcm4,
38   num_int_types
39 };
40
41 const char *interrupt_names[] =
42 {
43   "reset",
44   "nmi",
45   "intov1",
46   "intp10",
47   "intp11",
48   "intp12",
49   "intp13",
50   "intcm4",
51   NULL
52 };
53
54 static void
55 do_interrupt (SIM_DESC sd, void *data)
56 {
57   const char **interrupt_name = (const char**)data;
58   enum interrupt_type inttype;
59   inttype = (interrupt_name - STATE_WATCHPOINTS (sd)->interrupt_names);
60
61   /* For a hardware reset, drop everything and jump to the start
62      address */
63   if (inttype == int_reset)
64     {
65       PC = 0;
66       PSW = 0x20;
67       ECR = 0;
68       sim_engine_restart (sd, NULL, NULL, NULL_CIA);
69     }
70
71   /* Deliver an NMI when allowed */
72   if (inttype == int_nmi)
73     {
74       if (PSW & PSW_NP)
75         {
76           /* We're already working on an NMI, so this one must wait
77              around until the previous one is done.  The processor
78              ignores subsequent NMIs, so we don't need to count them.
79              Just keep re-scheduling a single NMI until it manages to
80              be delivered */
81           if (STATE_CPU (sd, 0)->pending_nmi != NULL)
82             sim_events_deschedule (sd, STATE_CPU (sd, 0)->pending_nmi);
83           STATE_CPU (sd, 0)->pending_nmi =
84             sim_events_schedule (sd, 1, do_interrupt, data);
85           return;
86         }
87       else
88         {
89           /* NMI can be delivered.  Do not deschedule pending_nmi as
90              that, if still in the event queue, is a second NMI that
91              needs to be delivered later. */
92           FEPC = PC;
93           FEPSW = PSW;
94           /* Set the FECC part of the ECR. */
95           ECR &= 0x0000ffff;
96           ECR |= 0x10;
97           PSW |= PSW_NP;
98           PSW &= ~PSW_EP;
99           PSW |= PSW_ID;
100           PC = 0x10;
101           sim_engine_restart (sd, NULL, NULL, NULL_CIA);
102         }
103     }
104
105   /* deliver maskable interrupt when allowed */
106   if (inttype > int_nmi && inttype < num_int_types)
107     {
108       if ((PSW & PSW_NP) || (PSW & PSW_ID))
109         {
110           /* Can't deliver this interrupt, reschedule it for later */
111           sim_events_schedule (sd, 1, do_interrupt, data);
112           return;
113         }
114       else
115         {
116           /* save context */
117           EIPC = PC;
118           EIPSW = PSW;
119           /* Disable further interrupts.  */
120           PSW |= PSW_ID;
121           /* Indicate that we're doing interrupt not exception processing.  */
122           PSW &= ~PSW_EP;
123           /* Clear the EICC part of the ECR, will set below. */
124           ECR &= 0xffff0000;
125           switch (inttype)
126             {
127             case int_intov1:
128               PC = 0x80;
129               ECR |= 0x80;
130               break;
131             case int_intp10:
132               PC = 0x90;
133               ECR |= 0x90;
134               break;
135             case int_intp11:
136               PC = 0xa0;
137               ECR |= 0xa0;
138               break;
139             case int_intp12:
140               PC = 0xb0;
141               ECR |= 0xb0;
142               break;
143             case int_intp13:
144               PC = 0xc0;
145               ECR |= 0xc0;
146               break;
147             case int_intcm4:
148               PC = 0xd0;
149               ECR |= 0xd0;
150               break;
151             default:
152               /* Should never be possible.  */
153               sim_engine_abort (sd, NULL, NULL_CIA,
154                                 "do_interrupt - internal error - bad switch");
155               break;
156             }
157         }
158       sim_engine_restart (sd, NULL, NULL, NULL_CIA);
159     }
160   
161   /* some other interrupt? */
162   sim_engine_abort (sd, NULL, NULL_CIA,
163                     "do_interrupt - internal error - interrupt %d unknown",
164                     inttype);
165 }
166
167 /* Return name of an insn, used by insn profiling.  */
168
169 static const char *
170 get_insn_name (sim_cpu *cpu, int i)
171 {
172   return itable[i].name;
173 }
174
175 /* These default values correspond to expected usage for the chip.  */
176
177 uint32 OP[4];
178
179 static sim_cia
180 v850_pc_get (sim_cpu *cpu)
181 {
182   return PC;
183 }
184
185 static void
186 v850_pc_set (sim_cpu *cpu, sim_cia pc)
187 {
188   PC = pc;
189 }
190
191 SIM_DESC
192 sim_open (SIM_OPEN_KIND    kind,
193           host_callback *  cb,
194           struct bfd *     abfd,
195           char **          argv)
196 {
197   int i;
198   SIM_DESC sd = sim_state_alloc (kind, cb);
199   int mach;
200
201   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
202
203   /* The cpu data is kept in a separately allocated chunk of memory.  */
204   if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK)
205     return 0;
206
207   /* for compatibility */
208   simulator = sd;
209
210   /* FIXME: should be better way of setting up interrupts */
211   STATE_WATCHPOINTS (sd)->pc = &(PC);
212   STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PC);
213   STATE_WATCHPOINTS (sd)->interrupt_handler = do_interrupt;
214   STATE_WATCHPOINTS (sd)->interrupt_names = interrupt_names;
215
216   /* Initialize the mechanism for doing insn profiling.  */
217   CPU_INSN_NAME (STATE_CPU (sd, 0)) = get_insn_name;
218   CPU_MAX_INSNS (STATE_CPU (sd, 0)) = nr_itable_entries;
219
220   if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
221     return 0;
222
223   /* Allocate core managed memory */
224
225   /* "Mirror" the ROM addresses below 1MB. */
226   sim_do_commandf (sd, "memory region 0,0x100000,0x%lx", V850_ROM_SIZE);
227   /* Chunk of ram adjacent to rom */
228   sim_do_commandf (sd, "memory region 0x100000,0x%lx", V850_LOW_END-0x100000);
229   /* peripheral I/O region - mirror 1K across 4k (0x1000) */
230   sim_do_command (sd, "memory region 0xfff000,0x1000,1024");
231   /* similarly if in the internal RAM region */
232   sim_do_command (sd, "memory region 0xffe000,0x1000,1024");
233
234   /* getopt will print the error message so we just have to exit if this fails.
235      FIXME: Hmmm...  in the case of gdb we need getopt to call
236      print_filtered.  */
237   if (sim_parse_args (sd, argv) != SIM_RC_OK)
238     {
239       /* Uninstall the modules to avoid memory leaks,
240          file descriptor leaks, etc.  */
241       sim_module_uninstall (sd);
242       return 0;
243     }
244
245   /* check for/establish the a reference program image */
246   if (sim_analyze_program (sd,
247                            (STATE_PROG_ARGV (sd) != NULL
248                             ? *STATE_PROG_ARGV (sd)
249                             : NULL),
250                            abfd) != SIM_RC_OK)
251     {
252       sim_module_uninstall (sd);
253       return 0;
254     }
255
256   /* establish any remaining configuration options */
257   if (sim_config (sd) != SIM_RC_OK)
258     {
259       sim_module_uninstall (sd);
260       return 0;
261     }
262
263   if (sim_post_argv_init (sd) != SIM_RC_OK)
264     {
265       /* Uninstall the modules to avoid memory leaks,
266          file descriptor leaks, etc.  */
267       sim_module_uninstall (sd);
268       return 0;
269     }
270
271
272   /* determine the machine type */
273   if (STATE_ARCHITECTURE (sd) != NULL
274       && (STATE_ARCHITECTURE (sd)->arch == bfd_arch_v850
275           || STATE_ARCHITECTURE (sd)->arch == bfd_arch_v850_rh850))
276     mach = STATE_ARCHITECTURE (sd)->mach;
277   else
278     mach = bfd_mach_v850; /* default */
279
280   /* set machine specific configuration */
281   switch (mach)
282     {
283     case bfd_mach_v850:
284     case bfd_mach_v850e:
285     case bfd_mach_v850e1:
286     case bfd_mach_v850e2:
287     case bfd_mach_v850e2v3:
288     case bfd_mach_v850e3v5:
289       STATE_CPU (sd, 0)->psw_mask = (PSW_NP | PSW_EP | PSW_ID | PSW_SAT
290                                      | PSW_CY | PSW_OV | PSW_S | PSW_Z);
291       break;
292     }
293
294   /* CPU specific initialization.  */
295   for (i = 0; i < MAX_NR_PROCESSORS; ++i)
296     {
297       SIM_CPU *cpu = STATE_CPU (sd, i);
298
299       CPU_PC_FETCH (cpu) = v850_pc_get;
300       CPU_PC_STORE (cpu) = v850_pc_set;
301     }
302
303   return sd;
304 }
305
306 SIM_RC
307 sim_create_inferior (SIM_DESC      sd,
308                      struct bfd *  prog_bfd,
309                      char **       argv,
310                      char **       env)
311 {
312   memset (&State, 0, sizeof (State));
313   if (prog_bfd != NULL)
314     PC = bfd_get_start_address (prog_bfd);
315   return SIM_RC_OK;
316 }
317
318 int
319 sim_fetch_register (SIM_DESC         sd,
320                     int              rn,
321                     unsigned char *  memory,
322                     int              length)
323 {
324   *(unsigned32*)memory = H2T_4 (State.regs[rn]);
325   return -1;
326 }
327  
328 int
329 sim_store_register (SIM_DESC        sd,
330                     int             rn,
331                     unsigned char * memory,
332                     int             length)
333 {
334   State.regs[rn] = T2H_4 (*(unsigned32 *) memory);
335   return length;
336 }