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