14e98e3e1Schristos /* main.c --- main function for stand-alone RX simulator. 24e98e3e1Schristos 3*1f4e7eb9Schristos Copyright (C) 2005-2024 Free Software Foundation, Inc. 44e98e3e1Schristos Contributed by Red Hat, Inc. 54e98e3e1Schristos 64e98e3e1Schristos This file is part of the GNU simulators. 74e98e3e1Schristos 84e98e3e1Schristos This program is free software; you can redistribute it and/or modify 94e98e3e1Schristos it under the terms of the GNU General Public License as published by 104e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 114e98e3e1Schristos (at your option) any later version. 124e98e3e1Schristos 134e98e3e1Schristos This program is distributed in the hope that it will be useful, 144e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 154e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 164e98e3e1Schristos GNU General Public License for more details. 174e98e3e1Schristos 184e98e3e1Schristos You should have received a copy of the GNU General Public License 194e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 204e98e3e1Schristos 214b169a6bSchristos /* This must come before any other includes. */ 224b169a6bSchristos #include "defs.h" 234e98e3e1Schristos 244e98e3e1Schristos #include <stdio.h> 254e98e3e1Schristos #include <string.h> 264e98e3e1Schristos #include <stdlib.h> 274e98e3e1Schristos #include <unistd.h> 284e98e3e1Schristos #include <assert.h> 294e98e3e1Schristos #include <setjmp.h> 304e98e3e1Schristos #include <signal.h> 314e98e3e1Schristos #include <getopt.h> 324e98e3e1Schristos 334e98e3e1Schristos #include "bfd.h" 344e98e3e1Schristos 354e98e3e1Schristos #include "cpu.h" 364e98e3e1Schristos #include "mem.h" 374e98e3e1Schristos #include "misc.h" 384e98e3e1Schristos #include "load.h" 394e98e3e1Schristos #include "trace.h" 404e98e3e1Schristos #include "err.h" 414e98e3e1Schristos 424e98e3e1Schristos static int disassemble = 0; 434e98e3e1Schristos 444e98e3e1Schristos /* This must be higher than any other option index. */ 454e98e3e1Schristos #define OPT_ACT 400 464e98e3e1Schristos 474e98e3e1Schristos #define ACT(E,A) (OPT_ACT + SIM_ERR_##E * SIM_ERRACTION_NUM_ACTIONS + SIM_ERRACTION_##A) 484e98e3e1Schristos 494e98e3e1Schristos static struct option sim_options[] = 504e98e3e1Schristos { 514e98e3e1Schristos { "end-sim-args", 0, NULL, 'E' }, 524e98e3e1Schristos { "exit-null-deref", 0, NULL, ACT(NULL_POINTER_DEREFERENCE,EXIT) }, 534e98e3e1Schristos { "warn-null-deref", 0, NULL, ACT(NULL_POINTER_DEREFERENCE,WARN) }, 544e98e3e1Schristos { "ignore-null-deref", 0, NULL, ACT(NULL_POINTER_DEREFERENCE,IGNORE) }, 554e98e3e1Schristos { "exit-unwritten-pages", 0, NULL, ACT(READ_UNWRITTEN_PAGES,EXIT) }, 564e98e3e1Schristos { "warn-unwritten-pages", 0, NULL, ACT(READ_UNWRITTEN_PAGES,WARN) }, 574e98e3e1Schristos { "ignore-unwritten-pages", 0, NULL, ACT(READ_UNWRITTEN_PAGES,IGNORE) }, 584e98e3e1Schristos { "exit-unwritten-bytes", 0, NULL, ACT(READ_UNWRITTEN_BYTES,EXIT) }, 594e98e3e1Schristos { "warn-unwritten-bytes", 0, NULL, ACT(READ_UNWRITTEN_BYTES,WARN) }, 604e98e3e1Schristos { "ignore-unwritten-bytes", 0, NULL, ACT(READ_UNWRITTEN_BYTES,IGNORE) }, 614e98e3e1Schristos { "exit-corrupt-stack", 0, NULL, ACT(CORRUPT_STACK,EXIT) }, 624e98e3e1Schristos { "warn-corrupt-stack", 0, NULL, ACT(CORRUPT_STACK,WARN) }, 634e98e3e1Schristos { "ignore-corrupt-stack", 0, NULL, ACT(CORRUPT_STACK,IGNORE) }, 644e98e3e1Schristos { 0, 0, 0, 0 } 654e98e3e1Schristos }; 664e98e3e1Schristos 674e98e3e1Schristos static void 684e98e3e1Schristos done (int exit_code) 694e98e3e1Schristos { 704e98e3e1Schristos if (verbose) 714e98e3e1Schristos { 724e98e3e1Schristos stack_heap_stats (); 734e98e3e1Schristos mem_usage_stats (); 744e98e3e1Schristos /* Only use comma separated numbers when being very verbose. 754e98e3e1Schristos Comma separated numbers are hard to parse in awk scripts. */ 764e98e3e1Schristos if (verbose > 1) 774e98e3e1Schristos printf ("insns: %14s\n", comma (rx_cycles)); 784e98e3e1Schristos else 794e98e3e1Schristos printf ("insns: %u\n", rx_cycles); 804e98e3e1Schristos 814e98e3e1Schristos pipeline_stats (); 824e98e3e1Schristos } 834e98e3e1Schristos exit (exit_code); 844e98e3e1Schristos } 854e98e3e1Schristos 864e98e3e1Schristos int 874e98e3e1Schristos main (int argc, char **argv) 884e98e3e1Schristos { 894e98e3e1Schristos int o; 904e98e3e1Schristos int save_trace; 914e98e3e1Schristos bfd *prog; 924e98e3e1Schristos int rc; 934e98e3e1Schristos 944e98e3e1Schristos /* By default, we exit when an execution error occurs. */ 954e98e3e1Schristos execution_error_init_standalone (); 964e98e3e1Schristos 974e98e3e1Schristos while ((o = getopt_long (argc, argv, "tvdeEwi", sim_options, NULL)) != -1) 984e98e3e1Schristos { 994e98e3e1Schristos if (o == 'E') 1004e98e3e1Schristos /* Stop processing the command line. This is so that any remaining 1014e98e3e1Schristos words on the command line that look like arguments will be passed 1024e98e3e1Schristos on to the program being simulated. */ 1034e98e3e1Schristos break; 1044e98e3e1Schristos 1054e98e3e1Schristos if (o >= OPT_ACT) 1064e98e3e1Schristos { 1074e98e3e1Schristos int e, a; 1084e98e3e1Schristos 1094e98e3e1Schristos o -= OPT_ACT; 1104e98e3e1Schristos e = o / SIM_ERRACTION_NUM_ACTIONS; 1114e98e3e1Schristos a = o % SIM_ERRACTION_NUM_ACTIONS; 1124e98e3e1Schristos execution_error_set_action (e, a); 1134e98e3e1Schristos } 1144e98e3e1Schristos else switch (o) 1154e98e3e1Schristos { 1164e98e3e1Schristos case 't': 1174e98e3e1Schristos trace++; 1184e98e3e1Schristos break; 1194e98e3e1Schristos case 'v': 1204e98e3e1Schristos verbose++; 1214e98e3e1Schristos break; 1224e98e3e1Schristos case 'd': 1234e98e3e1Schristos disassemble++; 1244e98e3e1Schristos break; 1254e98e3e1Schristos case 'e': 1264e98e3e1Schristos execution_error_init_standalone (); 1274e98e3e1Schristos break; 1284e98e3e1Schristos case 'w': 1294e98e3e1Schristos execution_error_warn_all (); 1304e98e3e1Schristos break; 1314e98e3e1Schristos case 'i': 1324e98e3e1Schristos execution_error_ignore_all (); 1334e98e3e1Schristos break; 1344e98e3e1Schristos case '?': 1354e98e3e1Schristos { 1364e98e3e1Schristos int i; 1374e98e3e1Schristos fprintf (stderr, 1384e98e3e1Schristos "usage: run [options] program [arguments]\n"); 1394e98e3e1Schristos fprintf (stderr, 1404e98e3e1Schristos "\t-v\t- increase verbosity.\n" 1414e98e3e1Schristos "\t-t\t- trace.\n" 1424e98e3e1Schristos "\t-d\t- disassemble.\n" 1434e98e3e1Schristos "\t-E\t- stop processing sim args\n" 1444e98e3e1Schristos "\t-e\t- exit on all execution errors.\n" 1454e98e3e1Schristos "\t-w\t- warn (do not exit) on all execution errors.\n" 1464e98e3e1Schristos "\t-i\t- ignore all execution errors.\n"); 1474e98e3e1Schristos for (i=0; sim_options[i].name; i++) 1484e98e3e1Schristos fprintf (stderr, "\t--%s\n", sim_options[i].name); 1494e98e3e1Schristos exit (1); 1504e98e3e1Schristos } 1514e98e3e1Schristos } 1524e98e3e1Schristos } 1534e98e3e1Schristos 1544e98e3e1Schristos prog = bfd_openr (argv[optind], 0); 1554e98e3e1Schristos if (!prog) 1564e98e3e1Schristos { 1574e98e3e1Schristos fprintf (stderr, "Can't read %s\n", argv[optind]); 1584e98e3e1Schristos exit (1); 1594e98e3e1Schristos } 1604e98e3e1Schristos 1614e98e3e1Schristos if (!bfd_check_format (prog, bfd_object)) 1624e98e3e1Schristos { 1634e98e3e1Schristos fprintf (stderr, "%s not a rx program\n", argv[optind]); 1644e98e3e1Schristos exit (1); 1654e98e3e1Schristos } 1664e98e3e1Schristos 1674e98e3e1Schristos init_regs (); 1684e98e3e1Schristos 1694e98e3e1Schristos rx_in_gdb = 0; 1704e98e3e1Schristos save_trace = trace; 1714e98e3e1Schristos trace = 0; 172a2e2270fSchristos rx_load (prog, NULL); 1734e98e3e1Schristos trace = save_trace; 1744e98e3e1Schristos 1754e98e3e1Schristos sim_disasm_init (prog); 1764e98e3e1Schristos 1774e98e3e1Schristos enable_counting = verbose; 1784e98e3e1Schristos 1794e98e3e1Schristos rc = setjmp (decode_jmp_buf); 1804e98e3e1Schristos 1814e98e3e1Schristos if (rc == 0) 1824e98e3e1Schristos { 1834e98e3e1Schristos if (!trace && !disassemble) 1844e98e3e1Schristos { 1854e98e3e1Schristos /* This will longjmp to the above if an exception 1864e98e3e1Schristos happens. */ 1874e98e3e1Schristos for (;;) 1884e98e3e1Schristos decode_opcode (); 1894e98e3e1Schristos } 1904e98e3e1Schristos else 1914e98e3e1Schristos while (1) 1924e98e3e1Schristos { 1934e98e3e1Schristos 1944e98e3e1Schristos if (trace) 1954e98e3e1Schristos printf ("\n"); 1964e98e3e1Schristos 1974e98e3e1Schristos if (disassemble) 1984e98e3e1Schristos { 1994e98e3e1Schristos enable_counting = 0; 2004e98e3e1Schristos sim_disasm_one (); 2014e98e3e1Schristos enable_counting = verbose; 2024e98e3e1Schristos } 2034e98e3e1Schristos 2044e98e3e1Schristos rc = decode_opcode (); 2054e98e3e1Schristos 2064e98e3e1Schristos if (trace) 2074e98e3e1Schristos trace_register_changes (); 2084e98e3e1Schristos } 2094e98e3e1Schristos } 2104e98e3e1Schristos 2114e98e3e1Schristos if (RX_HIT_BREAK (rc)) 2124e98e3e1Schristos done (1); 2134e98e3e1Schristos else if (RX_EXITED (rc)) 2144e98e3e1Schristos done (RX_EXIT_STATUS (rc)); 2154e98e3e1Schristos else if (RX_STOPPED (rc)) 2164e98e3e1Schristos { 2174e98e3e1Schristos if (verbose) 2184e98e3e1Schristos printf("Stopped on signal %d\n", RX_STOP_SIG (rc)); 2194e98e3e1Schristos exit(1); 2204e98e3e1Schristos } 2214e98e3e1Schristos done (0); 2224e98e3e1Schristos exit (0); 2234e98e3e1Schristos } 224