Add support for target specific command line switches to old-style simualtors.
[external/binutils.git] / sim / arm / wrapper.c
1 /* run front end support for arm
2    Copyright (C) 1995, 1996, 1997, 2000, 2001, 2002
3    Free Software Foundation, Inc.
4
5    This file is part of ARM SIM.
6
7    GCC is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published
9    by the Free Software Foundation; either version 2, or (at your
10    option) any later version.
11
12    GCC is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See
15    the GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public
18    License along with this program; if not, write to the Free
19    Software Foundation, Inc., 59 Temple Place - Suite 330,
20    Boston, MA 02111-1307, USA.  */
21
22 /* This file provides the interface between the simulator and
23    run.c and gdb (when the simulator is linked with gdb).
24    All simulator interaction should go through this file.  */
25
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include <bfd.h>
30 #include <signal.h>
31 #include "callback.h"
32 #include "remote-sim.h"
33 #include "armdefs.h"
34 #include "armemu.h"
35 #include "dbg_rdi.h"
36 #include "ansidecl.h"
37 #include "sim-utils.h"
38 #include "run-sim.h"
39
40 host_callback *sim_callback;
41
42 static struct ARMul_State *state;
43
44 /* Who is using the simulator.  */
45 static SIM_OPEN_KIND sim_kind;
46
47 /* argv[0] */
48 static char *myname;
49
50 /* Memory size in bytes.  */
51 static int mem_size = (1 << 23);
52
53 /* Non-zero to display start up banner, and maybe other things.  */
54 static int verbosity;
55
56 /* Non-zero to set big endian mode.  */
57 static int big_endian;
58
59 int stop_simulator;
60
61 static void
62 init ()
63 {
64   static int done;
65
66   if (!done)
67     {
68       ARMul_EmulateInit ();
69       state = ARMul_NewState ();
70       state->bigendSig = (big_endian ? HIGH : LOW);
71       ARMul_MemoryInit (state, mem_size);
72       ARMul_OSInit (state);
73       ARMul_CoProInit (state);
74       state->verbose = verbosity;
75       done = 1;
76     }
77 }
78
79 /* Set verbosity level of simulator.
80    This is not intended to produce detailed tracing or debugging information.
81    Just summaries.  */
82 /* FIXME: common/run.c doesn't do this yet.  */
83
84 void
85 sim_set_verbose (v)
86      int v;
87 {
88   verbosity = v;
89 }
90
91 /* Set the memory size to SIZE bytes.
92    Must be called before initializing simulator.  */
93 /* FIXME: Rename to sim_set_mem_size.  */
94
95 void
96 sim_size (size)
97      int size;
98 {
99   mem_size = size;
100 }
101
102 void
103 ARMul_ConsolePrint VPARAMS ((ARMul_State * state,
104                              const char * format,
105                              ...))
106 {
107   va_list ap;
108
109   if (state->verbose)
110     {
111       va_start (ap, format);
112       vprintf (format, ap);
113       va_end (ap);
114     }
115 }
116
117 ARMword
118 ARMul_Debug (state, pc, instr)
119      ARMul_State * state ATTRIBUTE_UNUSED;
120      ARMword       pc    ATTRIBUTE_UNUSED;
121      ARMword       instr ATTRIBUTE_UNUSED;
122 {
123   return 0;
124 }
125
126 int
127 sim_write (sd, addr, buffer, size)
128      SIM_DESC sd ATTRIBUTE_UNUSED;
129      SIM_ADDR addr;
130      unsigned char * buffer;
131      int size;
132 {
133   int i;
134
135   init ();
136
137   for (i = 0; i < size; i++)
138     ARMul_SafeWriteByte (state, addr + i, buffer[i]);
139
140   return size;
141 }
142
143 int
144 sim_read (sd, addr, buffer, size)
145      SIM_DESC sd ATTRIBUTE_UNUSED;
146      SIM_ADDR addr;
147      unsigned char * buffer;
148      int size;
149 {
150   int i;
151
152   init ();
153
154   for (i = 0; i < size; i++)
155     buffer[i] = ARMul_SafeReadByte (state, addr + i);
156
157   return size;
158 }
159
160 int
161 sim_trace (sd)
162      SIM_DESC sd ATTRIBUTE_UNUSED;
163 {  
164   (*sim_callback->printf_filtered)
165     (sim_callback,
166      "This simulator does not support tracing\n");
167   return 1;
168 }
169
170 int
171 sim_stop (sd)
172      SIM_DESC sd ATTRIBUTE_UNUSED;
173 {
174   state->Emulate = STOP;
175   stop_simulator = 1;
176   return 1;
177 }
178
179 void
180 sim_resume (sd, step, siggnal)
181      SIM_DESC sd ATTRIBUTE_UNUSED;
182      int step;
183      int siggnal ATTRIBUTE_UNUSED;
184 {
185   state->EndCondition = 0;
186   stop_simulator = 0;
187
188   if (step)
189     {
190       state->Reg[15] = ARMul_DoInstr (state);
191       if (state->EndCondition == 0)
192         state->EndCondition = RDIError_BreakpointReached;
193     }
194   else
195     {
196       state->NextInstr = RESUME;        /* treat as PC change */
197       state->Reg[15] = ARMul_DoProg (state);
198     }
199
200   FLUSHPIPE;
201 }
202
203 SIM_RC
204 sim_create_inferior (sd, abfd, argv, env)
205      SIM_DESC sd ATTRIBUTE_UNUSED;
206      struct _bfd * abfd;
207      char ** argv;
208      char ** env;
209 {
210   int argvlen = 0;
211   int mach;
212   char **arg;
213
214   if (abfd != NULL)
215     ARMul_SetPC (state, bfd_get_start_address (abfd));
216   else
217     ARMul_SetPC (state, 0);     /* ??? */
218
219   mach = bfd_get_mach (abfd);
220
221   switch (mach)
222     {
223     default:
224       (*sim_callback->printf_filtered)
225         (sim_callback,
226          "Unknown machine type; please update sim_create_inferior.\n");
227       /* fall through */
228
229     case 0:
230       /* We wouldn't set the machine type with earlier toolchains, so we
231          explicitly select a processor capable of supporting all ARMs in
232          32bit mode.  */
233     case bfd_mach_arm_XScale:
234       ARMul_SelectProcessor (state, ARM_v5_Prop | ARM_v5e_Prop | ARM_XScale_Prop);
235       break;
236
237     case bfd_mach_arm_5:
238       if (bfd_family_coff (abfd))
239         {
240           /* This is a special case in order to support COFF based ARM toolchains.
241              The COFF header does not have enough room to store all the different
242              kinds of ARM cpu, so the XScale, v5T and v5TE architectures all default
243              to v5.  (See coff_set_flags() in bdf/coffcode.h).  So if we see a v5
244              machine type here, we assume it could be any of the above architectures
245              and so select the most feature-full.  */
246           ARMul_SelectProcessor (state, ARM_v5_Prop | ARM_v5e_Prop | ARM_XScale_Prop);
247           break;
248         }
249       /* Otherwise drop through.  */
250
251     case bfd_mach_arm_5T:
252       ARMul_SelectProcessor (state, ARM_v5_Prop);
253       break;
254
255     case bfd_mach_arm_5TE:
256       ARMul_SelectProcessor (state, ARM_v5_Prop | ARM_v5e_Prop);
257       break;
258
259     case bfd_mach_arm_4:
260     case bfd_mach_arm_4T:
261       ARMul_SelectProcessor (state, ARM_v4_Prop);
262       break;
263
264     case bfd_mach_arm_3:
265     case bfd_mach_arm_3M:
266       ARMul_SelectProcessor (state, ARM_Lock_Prop);
267       break;
268
269     case bfd_mach_arm_2:
270     case bfd_mach_arm_2a:
271       ARMul_SelectProcessor (state, ARM_Fix26_Prop);
272       break;
273     }
274
275   if (   mach != bfd_mach_arm_3
276       && mach != bfd_mach_arm_3M
277       && mach != bfd_mach_arm_2
278       && mach != bfd_mach_arm_2a)
279     {
280       /* Reset mode to ARM.  A gdb user may rerun a program that had entered
281          THUMB mode from the start and cause the ARM-mode startup code to be
282          executed in THUMB mode.  */
283       ARMul_SetCPSR (state, SVC32MODE);
284     }
285   
286   if (argv != NULL)
287     {
288       /* Set up the command line by laboriously stringing together
289          the environment carefully picked apart by our caller.  */
290
291       /* Free any old stuff.  */
292       if (state->CommandLine != NULL)
293         {
294           free (state->CommandLine);
295           state->CommandLine = NULL;
296         }
297
298       /* See how much we need.  */
299       for (arg = argv; *arg != NULL; arg++)
300         argvlen += strlen (*arg) + 1;
301
302       /* Allocate it.  */
303       state->CommandLine = malloc (argvlen + 1);
304       if (state->CommandLine != NULL)
305         {
306           arg = argv;
307           state->CommandLine[0] = '\0';
308
309           for (arg = argv; *arg != NULL; arg++)
310             {
311               strcat (state->CommandLine, *arg);
312               strcat (state->CommandLine, " ");
313             }
314         }
315     }
316
317   if (env != NULL)
318     {
319       /* Now see if there's a MEMSIZE spec in the environment.  */
320       while (*env)
321         {
322           if (strncmp (*env, "MEMSIZE=", sizeof ("MEMSIZE=") - 1) == 0)
323             {
324               char *end_of_num;
325
326               /* Set up memory limit.  */
327               state->MemSize =
328                 strtoul (*env + sizeof ("MEMSIZE=") - 1, &end_of_num, 0);
329             }
330           env++;
331         }
332     }
333
334   return SIM_RC_OK;
335 }
336
337 void
338 sim_info (sd, verbose)
339      SIM_DESC sd ATTRIBUTE_UNUSED;
340      int verbose ATTRIBUTE_UNUSED;
341 {
342 }
343
344 static int
345 frommem (state, memory)
346      struct ARMul_State *state;
347      unsigned char *memory;
348 {
349   if (state->bigendSig == HIGH)
350     return (memory[0] << 24) | (memory[1] << 16)
351       | (memory[2] << 8) | (memory[3] << 0);
352   else
353     return (memory[3] << 24) | (memory[2] << 16)
354       | (memory[1] << 8) | (memory[0] << 0);
355 }
356
357 static void
358 tomem (state, memory, val)
359      struct ARMul_State *state;
360      unsigned char *memory;
361      int val;
362 {
363   if (state->bigendSig == HIGH)
364     {
365       memory[0] = val >> 24;
366       memory[1] = val >> 16;
367       memory[2] = val >> 8;
368       memory[3] = val >> 0;
369     }
370   else
371     {
372       memory[3] = val >> 24;
373       memory[2] = val >> 16;
374       memory[1] = val >> 8;
375       memory[0] = val >> 0;
376     }
377 }
378
379 int
380 sim_store_register (sd, rn, memory, length)
381      SIM_DESC sd ATTRIBUTE_UNUSED;
382      int rn;
383      unsigned char *memory;
384      int length ATTRIBUTE_UNUSED;
385 {
386   init ();
387
388   if (rn == 25)
389     {
390       state->Cpsr = frommem (state, memory);
391       ARMul_CPSRAltered (state);             
392     }
393   else
394     ARMul_SetReg (state, state->Mode, rn, frommem (state, memory));
395   return -1;
396 }
397
398 int
399 sim_fetch_register (sd, rn, memory, length)
400      SIM_DESC sd ATTRIBUTE_UNUSED;
401      int rn;
402      unsigned char *memory;
403      int length ATTRIBUTE_UNUSED;
404 {
405   ARMword regval;
406
407   init ();
408
409   if (rn < 16)
410     regval = ARMul_GetReg (state, state->Mode, rn);
411   else if (rn == 25)
412     /* FIXME: use PS_REGNUM from gdb/config/arm/tm-arm.h.  */
413     regval = ARMul_GetCPSR (state);
414   else
415     /* FIXME: should report an error.  */
416     regval = 0;
417
418   while (length)
419     {
420       tomem (state, memory, regval);
421
422       length -= 4;
423       memory += 4;
424       regval = 0;
425     }  
426
427   return -1;
428 }
429
430 #ifdef SIM_TARGET_SWITCHES
431
432 static void sim_target_parse_arg_array PARAMS ((char **));
433
434 typedef struct
435 {
436   char *        swi_option;
437   unsigned int  swi_mask;
438 } swi_options;
439
440 #define SWI_SWITCH      "--swi-support"
441
442 static swi_options options[] =
443   {
444     { "none",    0 },
445     { "demon",   SWI_MASK_DEMON },
446     { "angel",   SWI_MASK_ANGEL },
447     { "redboot", SWI_MASK_REDBOOT },
448     { "all",     -1 },
449     { "NONE",    0 },
450     { "DEMON",   SWI_MASK_DEMON },
451     { "ANGEL",   SWI_MASK_ANGEL },
452     { "REDBOOT", SWI_MASK_REDBOOT },
453     { "ALL",     -1 }
454   };
455
456
457 int
458 sim_target_parse_command_line (argc, argv)
459      int argc;
460      char ** argv;
461 {
462   int i;
463
464   for (i = 1; i < argc; i++)
465     {
466       char * ptr = argv[i];
467       int arg;
468
469       if ((ptr == NULL) || (* ptr != '-'))
470         break;
471
472       if (strncmp (ptr, SWI_SWITCH, sizeof SWI_SWITCH - 1) != 0)
473         continue;
474
475       if (ptr[sizeof SWI_SWITCH - 1] == 0)
476         {
477           /* Remove this option from the argv array.  */
478           for (arg = i; arg < argc; arg ++)
479             argv[arg] = argv[arg + 1];
480           argc --;
481           
482           ptr = argv[i];
483         }
484       else
485         ptr += sizeof SWI_SWITCH;
486
487       swi_mask = 0;
488       
489       while (* ptr)
490         {
491           int i;
492
493           for (i = sizeof options / sizeof options[0]; i--;)
494             if (strncmp (ptr, options[i].swi_option,
495                          strlen (options[i].swi_option)) == 0)
496               {
497                 swi_mask |= options[i].swi_mask;
498                 ptr += strlen (options[i].swi_option);
499
500                 if (* ptr == ',')
501                   ++ ptr;
502
503                 break;
504               }
505
506           if (i < 0)
507             break;
508         }
509
510       if (* ptr != 0)
511         fprintf (stderr, "Ignoring swi options: %s\n", ptr);
512       
513       /* Remove this option from the argv array.  */
514       for (arg = i; arg < argc; arg ++)
515         argv[arg] = argv[arg + 1];
516       argc --;
517       i --;
518     }
519   return argc;
520 }
521
522 static void
523 sim_target_parse_arg_array (argv)
524      char ** argv;
525 {
526   int i;
527
528   for (i = 0; argv[i]; i++)
529     ;
530
531   return (void) sim_target_parse_command_line (i, argv);
532 }
533
534 void
535 sim_target_display_usage ()
536 {
537   fprintf (stderr, "%s=<list>  Comma seperated list of SWI protocols to supoport.\n\
538                 This list can contain: NONE, DEMON, ANGEL, REDBOOT and/or ALL.\n",
539            SWI_SWITCH);
540 }
541 #endif
542
543 SIM_DESC
544 sim_open (kind, ptr, abfd, argv)
545      SIM_OPEN_KIND kind;
546      host_callback *ptr;
547      struct _bfd *abfd;
548      char **argv;
549 {
550   sim_kind = kind;
551   if (myname) free (myname);
552   myname = (char *) xstrdup (argv[0]);
553   sim_callback = ptr;
554
555 #ifdef SIM_TARGET_SWITCHES
556   sim_target_parse_arg_array (argv);
557 #endif
558   
559   /* Decide upon the endian-ness of the processor.
560      If we can, get the information from the bfd itself.
561      Otherwise look to see if we have been given a command
562      line switch that tells us.  Otherwise default to little endian.  */
563   if (abfd != NULL)
564     big_endian = bfd_big_endian (abfd);
565   else if (argv[1] != NULL)
566     {
567       int i;
568
569       /* Scan for endian-ness switch.  */
570       for (i = 0; (argv[i] != NULL) && (argv[i][0] != 0); i++)
571         if (argv[i][0] == '-' && argv[i][1] == 'E')
572           {
573             char c;
574
575             if ((c = argv[i][2]) == 0)
576               {
577                 ++i;
578                 c = argv[i][0];
579               }
580
581             switch (c)
582               {
583               case 0:
584                 sim_callback->printf_filtered
585                   (sim_callback, "No argument to -E option provided\n");
586                 break;
587
588               case 'b':
589               case 'B':
590                 big_endian = 1;
591                 break;
592
593               case 'l':
594               case 'L':
595                 big_endian = 0;
596                 break;
597
598               default:
599                 sim_callback->printf_filtered
600                   (sim_callback, "Unrecognised argument to -E option\n");
601                 break;
602               }
603           }
604     }
605
606   return (SIM_DESC) 1;
607 }
608
609 void
610 sim_close (sd, quitting)
611      SIM_DESC sd ATTRIBUTE_UNUSED;
612      int quitting ATTRIBUTE_UNUSED;
613 {
614   if (myname)
615     free (myname);
616   myname = NULL;
617 }
618
619 SIM_RC
620 sim_load (sd, prog, abfd, from_tty)
621      SIM_DESC sd;
622      char *prog;
623      bfd *abfd;
624      int from_tty ATTRIBUTE_UNUSED;
625 {
626   bfd *prog_bfd;
627
628   prog_bfd = sim_load_file (sd, myname, sim_callback, prog, abfd,
629                             sim_kind == SIM_OPEN_DEBUG, 0, sim_write);
630   if (prog_bfd == NULL)
631     return SIM_RC_FAIL;
632   ARMul_SetPC (state, bfd_get_start_address (prog_bfd));
633   if (abfd == NULL)
634     bfd_close (prog_bfd);
635   return SIM_RC_OK;
636 }
637
638 void
639 sim_stop_reason (sd, reason, sigrc)
640      SIM_DESC sd ATTRIBUTE_UNUSED;
641      enum sim_stop *reason;
642      int *sigrc;
643 {
644   if (stop_simulator)
645     {
646       *reason = sim_stopped;
647       *sigrc = SIGINT;
648     }
649   else if (state->EndCondition == 0)
650     {
651       *reason = sim_exited;
652       *sigrc = state->Reg[0] & 255;
653     }
654   else
655     {
656       *reason = sim_stopped;
657       if (state->EndCondition == RDIError_BreakpointReached)
658         *sigrc = SIGTRAP;
659       else
660         *sigrc = 0;
661     }
662 }
663
664 void
665 sim_do_command (sd, cmd)
666      SIM_DESC sd ATTRIBUTE_UNUSED;
667      char *cmd ATTRIBUTE_UNUSED;
668 {  
669   (*sim_callback->printf_filtered)
670     (sim_callback,
671      "This simulator does not accept any commands.\n");
672 }
673
674 void
675 sim_set_callbacks (ptr)
676      host_callback *ptr;
677 {
678   sim_callback = ptr;
679 }