Automatic date update in version.in
[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 * const *   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   /* The parser will print an error message for us, so we silently return.  */
238   if (sim_parse_args (sd, argv) != SIM_RC_OK)
239     {
240       /* Uninstall the modules to avoid memory leaks,
241          file descriptor leaks, etc.  */
242       sim_module_uninstall (sd);
243       return 0;
244     }
245
246   /* check for/establish the a reference program image */
247   if (sim_analyze_program (sd,
248                            (STATE_PROG_ARGV (sd) != NULL
249                             ? *STATE_PROG_ARGV (sd)
250                             : NULL),
251                            abfd) != SIM_RC_OK)
252     {
253       sim_module_uninstall (sd);
254       return 0;
255     }
256
257   /* establish any remaining configuration options */
258   if (sim_config (sd) != SIM_RC_OK)
259     {
260       sim_module_uninstall (sd);
261       return 0;
262     }
263
264   if (sim_post_argv_init (sd) != SIM_RC_OK)
265     {
266       /* Uninstall the modules to avoid memory leaks,
267          file descriptor leaks, etc.  */
268       sim_module_uninstall (sd);
269       return 0;
270     }
271
272
273   /* determine the machine type */
274   if (STATE_ARCHITECTURE (sd) != NULL
275       && (STATE_ARCHITECTURE (sd)->arch == bfd_arch_v850
276           || STATE_ARCHITECTURE (sd)->arch == bfd_arch_v850_rh850))
277     mach = STATE_ARCHITECTURE (sd)->mach;
278   else
279     mach = bfd_mach_v850; /* default */
280
281   /* set machine specific configuration */
282   switch (mach)
283     {
284     case bfd_mach_v850:
285     case bfd_mach_v850e:
286     case bfd_mach_v850e1:
287     case bfd_mach_v850e2:
288     case bfd_mach_v850e2v3:
289     case bfd_mach_v850e3v5:
290       STATE_CPU (sd, 0)->psw_mask = (PSW_NP | PSW_EP | PSW_ID | PSW_SAT
291                                      | PSW_CY | PSW_OV | PSW_S | PSW_Z);
292       break;
293     }
294
295   /* CPU specific initialization.  */
296   for (i = 0; i < MAX_NR_PROCESSORS; ++i)
297     {
298       SIM_CPU *cpu = STATE_CPU (sd, i);
299
300       CPU_REG_FETCH (cpu) = v850_reg_fetch;
301       CPU_REG_STORE (cpu) = v850_reg_store;
302       CPU_PC_FETCH (cpu) = v850_pc_get;
303       CPU_PC_STORE (cpu) = v850_pc_set;
304     }
305
306   return sd;
307 }
308
309 SIM_RC
310 sim_create_inferior (SIM_DESC      sd,
311                      struct bfd *  prog_bfd,
312                      char * const *argv,
313                      char * const *env)
314 {
315   memset (&State, 0, sizeof (State));
316   if (prog_bfd != NULL)
317     PC = bfd_get_start_address (prog_bfd);
318   return SIM_RC_OK;
319 }
320
321 static int
322 v850_reg_fetch (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
323 {
324   *(unsigned32*)memory = H2T_4 (State.regs[rn]);
325   return -1;
326 }
327
328 static int
329 v850_reg_store (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
330 {
331   State.regs[rn] = T2H_4 (*(unsigned32 *) memory);
332   return length;
333 }