* Makefile.in: Add mips-linux-nat.c, mips-linux-tdep.c,
[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 #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     case bfd_mach_v850ea:
284       PSW |= PSW_US;
285       STATE_CPU (sd, 0)->psw_mask = (PSW_US
286                                      | PSW_NP | PSW_EP | PSW_ID | PSW_SAT
287                                      | PSW_CY | PSW_OV | PSW_S | PSW_Z);
288       break;
289     }
290
291   return sd;
292 }
293
294
295 void
296 sim_close (sd, quitting)
297      SIM_DESC sd;
298      int quitting;
299 {
300   sim_module_uninstall (sd);
301 }
302
303 SIM_RC
304 sim_create_inferior (sd, prog_bfd, argv, env)
305      SIM_DESC sd;
306      struct _bfd *prog_bfd;
307      char **argv;
308      char **env;
309 {
310   memset (&State, 0, sizeof (State));
311   if (prog_bfd != NULL)
312     PC = bfd_get_start_address (prog_bfd);
313   /* For v850ea, set PSW[US] by default */
314   if (STATE_ARCHITECTURE (sd) != NULL
315       && STATE_ARCHITECTURE (sd)->arch == bfd_arch_v850
316       && STATE_ARCHITECTURE (sd)->mach == bfd_mach_v850ea)
317     PSW |= PSW_US;
318   return SIM_RC_OK;
319 }
320
321 int
322 sim_fetch_register (sd, rn, memory, length)
323      SIM_DESC sd;
324      int rn;
325      unsigned char *memory;
326      int length;
327 {
328   *(unsigned32*)memory = H2T_4 (State.regs[rn]);
329   return -1;
330 }
331  
332 int
333 sim_store_register (sd, rn, memory, length)
334      SIM_DESC sd;
335      int rn;
336      unsigned char *memory;
337      int length;
338 {
339   State.regs[rn] = T2H_4 (*(unsigned32*)memory);
340   return -1;
341 }
342
343 void
344 sim_do_command (sd, cmd)
345      SIM_DESC sd;
346      char *cmd;
347 {
348   char *mm_cmd = "memory-map";
349   char *int_cmd = "interrupt";
350
351   if (sim_args_command (sd, cmd) != SIM_RC_OK)
352     {
353       if (strncmp (cmd, mm_cmd, strlen (mm_cmd) == 0))
354         sim_io_eprintf (sd, "`memory-map' command replaced by `sim memory'\n");
355       else if (strncmp (cmd, int_cmd, strlen (int_cmd)) == 0)
356         sim_io_eprintf (sd, "`interrupt' command replaced by `sim watch'\n");
357       else
358         sim_io_eprintf (sd, "Unknown command `%s'\n", cmd);
359     }
360 }