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