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