1/* main.c --- main function for stand-alone RX simulator.
2
3Copyright (C) 2005-2023 Free Software Foundation, Inc.
4Contributed by Red Hat, Inc.
5
6This file is part of the GNU simulators.
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 3 of the License, or
11(at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21/* This must come before any other includes.  */
22#include "defs.h"
23
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27#ifdef HAVE_UNISTD_H
28#include <unistd.h>
29#endif
30#include <assert.h>
31#include <setjmp.h>
32#include <signal.h>
33#include <getopt.h>
34
35#include "bfd.h"
36
37#include "cpu.h"
38#include "mem.h"
39#include "misc.h"
40#include "load.h"
41#include "trace.h"
42#include "err.h"
43
44static int disassemble = 0;
45
46/* This must be higher than any other option index.  */
47#define OPT_ACT 400
48
49#define ACT(E,A) (OPT_ACT + SIM_ERR_##E * SIM_ERRACTION_NUM_ACTIONS + SIM_ERRACTION_##A)
50
51static struct option sim_options[] =
52{
53  { "end-sim-args", 0, NULL, 'E' },
54  { "exit-null-deref", 0, NULL, ACT(NULL_POINTER_DEREFERENCE,EXIT) },
55  { "warn-null-deref", 0, NULL, ACT(NULL_POINTER_DEREFERENCE,WARN) },
56  { "ignore-null-deref", 0, NULL, ACT(NULL_POINTER_DEREFERENCE,IGNORE) },
57  { "exit-unwritten-pages", 0, NULL, ACT(READ_UNWRITTEN_PAGES,EXIT) },
58  { "warn-unwritten-pages", 0, NULL, ACT(READ_UNWRITTEN_PAGES,WARN) },
59  { "ignore-unwritten-pages", 0, NULL, ACT(READ_UNWRITTEN_PAGES,IGNORE) },
60  { "exit-unwritten-bytes", 0, NULL, ACT(READ_UNWRITTEN_BYTES,EXIT) },
61  { "warn-unwritten-bytes", 0, NULL, ACT(READ_UNWRITTEN_BYTES,WARN) },
62  { "ignore-unwritten-bytes", 0, NULL, ACT(READ_UNWRITTEN_BYTES,IGNORE) },
63  { "exit-corrupt-stack", 0, NULL, ACT(CORRUPT_STACK,EXIT) },
64  { "warn-corrupt-stack", 0, NULL, ACT(CORRUPT_STACK,WARN) },
65  { "ignore-corrupt-stack", 0, NULL, ACT(CORRUPT_STACK,IGNORE) },
66  { 0, 0, 0, 0 }
67};
68
69static void
70done (int exit_code)
71{
72  if (verbose)
73    {
74      stack_heap_stats ();
75      mem_usage_stats ();
76      /* Only use comma separated numbers when being very verbose.
77	 Comma separated numbers are hard to parse in awk scripts.  */
78      if (verbose > 1)
79	printf ("insns: %14s\n", comma (rx_cycles));
80      else
81	printf ("insns: %u\n", rx_cycles);
82
83      pipeline_stats ();
84    }
85  exit (exit_code);
86}
87
88int
89main (int argc, char **argv)
90{
91  int o;
92  int save_trace;
93  bfd *prog;
94  int rc;
95
96  /* By default, we exit when an execution error occurs.  */
97  execution_error_init_standalone ();
98
99  while ((o = getopt_long (argc, argv, "tvdeEwi", sim_options, NULL)) != -1)
100    {
101      if (o == 'E')
102	/* Stop processing the command line. This is so that any remaining
103	   words on the command line that look like arguments will be passed
104	   on to the program being simulated.  */
105	break;
106
107      if (o >= OPT_ACT)
108	{
109	  int e, a;
110
111	  o -= OPT_ACT;
112	  e = o / SIM_ERRACTION_NUM_ACTIONS;
113	  a = o % SIM_ERRACTION_NUM_ACTIONS;
114	  execution_error_set_action (e, a);
115	}
116      else switch (o)
117	{
118	case 't':
119	  trace++;
120	  break;
121	case 'v':
122	  verbose++;
123	  break;
124	case 'd':
125	  disassemble++;
126	  break;
127	case 'e':
128	  execution_error_init_standalone ();
129	  break;
130	case 'w':
131	  execution_error_warn_all ();
132	  break;
133	case 'i':
134	  execution_error_ignore_all ();
135	  break;
136	case '?':
137	  {
138	    int i;
139	    fprintf (stderr,
140		     "usage: run [options] program [arguments]\n");
141	    fprintf (stderr,
142		     "\t-v\t- increase verbosity.\n"
143		     "\t-t\t- trace.\n"
144		     "\t-d\t- disassemble.\n"
145		     "\t-E\t- stop processing sim args\n"
146		     "\t-e\t- exit on all execution errors.\n"
147		     "\t-w\t- warn (do not exit) on all execution errors.\n"
148		     "\t-i\t- ignore all execution errors.\n");
149	    for (i=0; sim_options[i].name; i++)
150	      fprintf (stderr, "\t--%s\n", sim_options[i].name);
151	    exit (1);
152	  }
153	}
154    }
155
156  prog = bfd_openr (argv[optind], 0);
157  if (!prog)
158    {
159      fprintf (stderr, "Can't read %s\n", argv[optind]);
160      exit (1);
161    }
162
163  if (!bfd_check_format (prog, bfd_object))
164    {
165      fprintf (stderr, "%s not a rx program\n", argv[optind]);
166      exit (1);
167    }
168
169  init_regs ();
170
171  rx_in_gdb = 0;
172  save_trace = trace;
173  trace = 0;
174  rx_load (prog, NULL);
175  trace = save_trace;
176
177  sim_disasm_init (prog);
178
179  enable_counting = verbose;
180
181  rc = setjmp (decode_jmp_buf);
182
183  if (rc == 0)
184    {
185      if (!trace && !disassemble)
186	{
187	  /* This will longjmp to the above if an exception
188	     happens.  */
189	  for (;;)
190	    decode_opcode ();
191	}
192      else
193	while (1)
194	  {
195
196	    if (trace)
197	      printf ("\n");
198
199	    if (disassemble)
200	      {
201		enable_counting = 0;
202		sim_disasm_one ();
203		enable_counting = verbose;
204	      }
205
206	    rc = decode_opcode ();
207
208	    if (trace)
209	      trace_register_changes ();
210	  }
211    }
212
213  if (RX_HIT_BREAK (rc))
214    done (1);
215  else if (RX_EXITED (rc))
216    done (RX_EXIT_STATUS (rc));
217  else if (RX_STOPPED (rc))
218    {
219      if (verbose)
220	printf("Stopped on signal %d\n", RX_STOP_SIG (rc));
221      exit(1);
222    }
223  done (0);
224  exit (0);
225}
226