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
21static const char * get_insn_name (sim_cpu *, int);
22
23/* For compatibility.  */
24SIM_DESC simulator;
25
26/* V850 interrupt model.  */
27
28enum 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
41const char *interrupt_names[] =
42{
43  "reset",
44  "nmi",
45  "intov1",
46  "intp10",
47  "intp11",
48  "intp12",
49  "intp13",
50  "intcm4",
51  NULL
52};
53
54static void
55do_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
169static const char *
170get_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
177uint32 OP[4];
178
179static sim_cia
180v850_pc_get (sim_cpu *cpu)
181{
182  return PC;
183}
184
185static void
186v850_pc_set (sim_cpu *cpu, sim_cia pc)
187{
188  PC = pc;
189}
190
191static int v850_reg_fetch (SIM_CPU *, int, unsigned char *, int);
192static int v850_reg_store (SIM_CPU *, int, unsigned char *, int);
193
194SIM_DESC
195sim_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
309SIM_RC
310sim_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
321static int
322v850_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
328static int
329v850_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}
334