GDB copyright headers update after running GDB's copyright.py script.
[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 static int v850_reg_fetch (SIM_CPU *, int, unsigned char *, int);
192 static int v850_reg_store (SIM_CPU *, int, unsigned char *, int);
193
194 SIM_DESC
195 sim_open (SIM_OPEN_KIND    kind,
196           host_callback *  cb,
197           struct bfd *     abfd,
198           char **          argv)
199 {
200   int i;
201   SIM_DESC sd = sim_state_alloc (kind, cb);
202   int mach;
203
204   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
205
206   /* The cpu data is kept in a separately allocated chunk of memory.  */
207   if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK)
208     return 0;
209
210   /* for compatibility */
211   simulator = sd;
212
213   /* FIXME: should be better way of setting up interrupts */
214   STATE_WATCHPOINTS (sd)->pc = &(PC);
215   STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PC);
216   STATE_WATCHPOINTS (sd)->interrupt_handler = do_interrupt;
217   STATE_WATCHPOINTS (sd)->interrupt_names = interrupt_names;
218
219   /* Initialize the mechanism for doing insn profiling.  */
220   CPU_INSN_NAME (STATE_CPU (sd, 0)) = get_insn_name;
221   CPU_MAX_INSNS (STATE_CPU (sd, 0)) = nr_itable_entries;
222
223   if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
224     return 0;
225
226   /* Allocate core managed memory */
227
228   /* "Mirror" the ROM addresses below 1MB. */
229   sim_do_commandf (sd, "memory region 0,0x100000,0x%lx", V850_ROM_SIZE);
230   /* Chunk of ram adjacent to rom */
231   sim_do_commandf (sd, "memory region 0x100000,0x%lx", V850_LOW_END-0x100000);
232   /* peripheral I/O region - mirror 1K across 4k (0x1000) */
233   sim_do_command (sd, "memory region 0xfff000,0x1000,1024");
234   /* similarly if in the internal RAM region */
235   sim_do_command (sd, "memory region 0xffe000,0x1000,1024");
236
237   /* getopt will print the error message so we just have to exit if this fails.
238      FIXME: Hmmm...  in the case of gdb we need getopt to call
239      print_filtered.  */
240   if (sim_parse_args (sd, argv) != SIM_RC_OK)
241     {
242       /* Uninstall the modules to avoid memory leaks,
243          file descriptor leaks, etc.  */
244       sim_module_uninstall (sd);
245       return 0;
246     }
247
248   /* check for/establish the a reference program image */
249   if (sim_analyze_program (sd,
250                            (STATE_PROG_ARGV (sd) != NULL
251                             ? *STATE_PROG_ARGV (sd)
252                             : NULL),
253                            abfd) != SIM_RC_OK)
254     {
255       sim_module_uninstall (sd);
256       return 0;
257     }
258
259   /* establish any remaining configuration options */
260   if (sim_config (sd) != SIM_RC_OK)
261     {
262       sim_module_uninstall (sd);
263       return 0;
264     }
265
266   if (sim_post_argv_init (sd) != SIM_RC_OK)
267     {
268       /* Uninstall the modules to avoid memory leaks,
269          file descriptor leaks, etc.  */
270       sim_module_uninstall (sd);
271       return 0;
272     }
273
274
275   /* determine the machine type */
276   if (STATE_ARCHITECTURE (sd) != NULL
277       && (STATE_ARCHITECTURE (sd)->arch == bfd_arch_v850
278           || STATE_ARCHITECTURE (sd)->arch == bfd_arch_v850_rh850))
279     mach = STATE_ARCHITECTURE (sd)->mach;
280   else
281     mach = bfd_mach_v850; /* default */
282
283   /* set machine specific configuration */
284   switch (mach)
285     {
286     case bfd_mach_v850:
287     case bfd_mach_v850e:
288     case bfd_mach_v850e1:
289     case bfd_mach_v850e2:
290     case bfd_mach_v850e2v3:
291     case bfd_mach_v850e3v5:
292       STATE_CPU (sd, 0)->psw_mask = (PSW_NP | PSW_EP | PSW_ID | PSW_SAT
293                                      | PSW_CY | PSW_OV | PSW_S | PSW_Z);
294       break;
295     }
296
297   /* CPU specific initialization.  */
298   for (i = 0; i < MAX_NR_PROCESSORS; ++i)
299     {
300       SIM_CPU *cpu = STATE_CPU (sd, i);
301
302       CPU_REG_FETCH (cpu) = v850_reg_fetch;
303       CPU_REG_STORE (cpu) = v850_reg_store;
304       CPU_PC_FETCH (cpu) = v850_pc_get;
305       CPU_PC_STORE (cpu) = v850_pc_set;
306     }
307
308   return sd;
309 }
310
311 SIM_RC
312 sim_create_inferior (SIM_DESC      sd,
313                      struct bfd *  prog_bfd,
314                      char **       argv,
315                      char **       env)
316 {
317   memset (&State, 0, sizeof (State));
318   if (prog_bfd != NULL)
319     PC = bfd_get_start_address (prog_bfd);
320   return SIM_RC_OK;
321 }
322
323 static int
324 v850_reg_fetch (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
325 {
326   *(unsigned32*)memory = H2T_4 (State.regs[rn]);
327   return -1;
328 }
329
330 static int
331 v850_reg_store (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
332 {
333   State.regs[rn] = T2H_4 (*(unsigned32 *) memory);
334   return length;
335 }