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
29static const char * get_insn_name (sim_cpu *, int);
30
31/* For compatibility */
32SIM_DESC simulator;
33
34
35
36/* v850 interrupt model */
37
38enum 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
51char *interrupt_names[] = {
52  "reset",
53  "nmi",
54  "intov1",
55  "intp10",
56  "intp11",
57  "intp12",
58  "intp13",
59  "intcm4",
60  NULL
61};
62
63static void
64do_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
180static const char *
181get_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
188uint32 OP[4];
189
190
191SIM_DESC
192sim_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    case bfd_mach_v850e1:
281      STATE_CPU (sd, 0)->psw_mask = (PSW_NP | PSW_EP | PSW_ID | PSW_SAT
282				     | PSW_CY | PSW_OV | PSW_S | PSW_Z);
283      break;
284    }
285
286  return sd;
287}
288
289
290void
291sim_close (sd, quitting)
292     SIM_DESC sd;
293     int quitting;
294{
295  sim_module_uninstall (sd);
296}
297
298SIM_RC
299sim_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  return SIM_RC_OK;
309}
310
311int
312sim_fetch_register (sd, rn, memory, length)
313     SIM_DESC sd;
314     int rn;
315     unsigned char *memory;
316     int length;
317{
318  *(unsigned32*)memory = H2T_4 (State.regs[rn]);
319  return -1;
320}
321
322int
323sim_store_register (sd, rn, memory, length)
324     SIM_DESC sd;
325     int rn;
326     unsigned char *memory;
327     int length;
328{
329  State.regs[rn] = T2H_4 (*(unsigned32*)memory);
330  return -1;
331}
332
333void
334sim_do_command (sd, cmd)
335     SIM_DESC sd;
336     char *cmd;
337{
338  char *mm_cmd = "memory-map";
339  char *int_cmd = "interrupt";
340
341  if (sim_args_command (sd, cmd) != SIM_RC_OK)
342    {
343      if (strncmp (cmd, mm_cmd, strlen (mm_cmd) == 0))
344	sim_io_eprintf (sd, "`memory-map' command replaced by `sim memory'\n");
345      else if (strncmp (cmd, int_cmd, strlen (int_cmd)) == 0)
346	sim_io_eprintf (sd, "`interrupt' command replaced by `sim watch'\n");
347      else
348	sim_io_eprintf (sd, "Unknown command `%s'\n", cmd);
349    }
350}
351