| /* This file is part of the program psim. |
| |
| Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, see <http://www.gnu.org/licenses/>. |
| |
| */ |
| |
| /* This must come before any other includes. */ |
| #include "defs.h" |
| |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <fcntl.h> |
| |
| #include <signal.h> |
| |
| #include "psim.h" |
| #include "options.h" |
| #include "device.h" /* FIXME: psim should provide the interface */ |
| #include "events.h" /* FIXME: psim should provide the interface */ |
| |
| #include "bfd.h" |
| #include "sim/callback.h" |
| #include "sim/sim.h" |
| |
| #include <stdlib.h> |
| #ifdef HAVE_UNISTD_H |
| #include <unistd.h> |
| #endif |
| #include <string.h> |
| #include <errno.h> |
| |
| #if !defined(O_NONBLOCK) || !defined(F_GETFL) || !defined(F_SETFL) |
| #undef WITH_STDIO |
| #define WITH_STDIO DO_USE_STDIO |
| #endif |
| |
| |
| extern char **environ; |
| |
| static psim *simulation = NULL; |
| |
| |
| void |
| sim_io_poll_quit (void) |
| { |
| /* nothing to do */ |
| } |
| |
| void |
| sim_io_printf_filtered(const char *msg, ...) |
| { |
| va_list ap; |
| va_start(ap, msg); |
| vprintf(msg, ap); |
| va_end(ap); |
| } |
| |
| void |
| error (const char *msg, ...) |
| { |
| va_list ap; |
| va_start(ap, msg); |
| vprintf(msg, ap); |
| printf("\n"); |
| va_end(ap); |
| |
| /* any final clean up */ |
| if (ppc_trace[trace_print_info] && simulation != NULL) |
| psim_print_info (simulation, ppc_trace[trace_print_info]); |
| |
| exit (1); |
| } |
| |
| int |
| sim_io_write_stdout(const char *buf, |
| int sizeof_buf) |
| { |
| switch (CURRENT_STDIO) { |
| case DO_USE_STDIO: |
| { |
| int i; |
| for (i = 0; i < sizeof_buf; i++) { |
| putchar(buf[i]); |
| } |
| return i; |
| } |
| break; |
| case DONT_USE_STDIO: |
| return write(1, buf, sizeof_buf); |
| break; |
| default: |
| error("sim_io_write_stdout: invalid switch\n"); |
| } |
| return 0; |
| } |
| |
| int |
| sim_io_write_stderr(const char *buf, |
| int sizeof_buf) |
| { |
| switch (CURRENT_STDIO) { |
| case DO_USE_STDIO: |
| { |
| int i; |
| for (i = 0; i < sizeof_buf; i++) { |
| fputc(buf[i], stderr); |
| } |
| return i; |
| } |
| break; |
| case DONT_USE_STDIO: |
| return write(2, buf, sizeof_buf); |
| break; |
| default: |
| error("sim_io_write_stdout: invalid switch\n"); |
| } |
| return 0; |
| } |
| |
| int |
| sim_io_read_stdin(char *buf, |
| int sizeof_buf) |
| { |
| switch (CURRENT_STDIO) { |
| case DO_USE_STDIO: |
| if (sizeof_buf > 1) { |
| if (fgets(buf, sizeof_buf, stdin) != NULL) |
| return strlen(buf); |
| } |
| else if (sizeof_buf == 1) { |
| char b[2]; |
| if (fgets(b, sizeof(b), stdin) != NULL) { |
| memcpy(buf, b, strlen(b)); |
| return strlen(b); |
| } |
| } |
| else if (sizeof_buf == 0) |
| return 0; |
| return sim_io_eof; |
| break; |
| case DONT_USE_STDIO: |
| #if defined(O_NONBLOCK) && defined(F_GETFL) && defined(F_SETFL) |
| { |
| /* check for input */ |
| int flags; |
| int status; |
| int nr_read; |
| int result; |
| /* get the old status */ |
| flags = fcntl(0, F_GETFL, 0); |
| if (flags == -1) { |
| perror("sim_io_read_stdin"); |
| return sim_io_eof; |
| } |
| /* temp, disable blocking IO */ |
| status = fcntl(0, F_SETFL, flags | O_NONBLOCK); |
| if (status == -1) { |
| perror("sim_io_read_stdin"); |
| return sim_io_eof; |
| } |
| /* try for input */ |
| nr_read = read(0, buf, sizeof_buf); |
| if (nr_read > 0 |
| || (nr_read == 0 && sizeof_buf == 0)) |
| result = nr_read; |
| else if (nr_read == 0) |
| result = sim_io_eof; |
| else { /* nr_read < 0 */ |
| if (errno == EAGAIN) |
| result = sim_io_not_ready; |
| else |
| result = sim_io_eof; |
| } |
| /* return to regular vewing */ |
| status = fcntl(0, F_SETFL, flags); |
| if (status == -1) { |
| perror("sim_io_read_stdin"); |
| return sim_io_eof; |
| } |
| return result; |
| } |
| break; |
| #endif |
| default: |
| error("sim_io_read_stdin: invalid switch\n"); |
| break; |
| } |
| return 0; |
| } |
| |
| void |
| sim_io_flush_stdoutput(void) |
| { |
| switch (CURRENT_STDIO) { |
| case DO_USE_STDIO: |
| fflush (stdout); |
| break; |
| case DONT_USE_STDIO: |
| break; |
| default: |
| error("sim_io_flush_stdoutput: invalid switch\n"); |
| break; |
| } |
| } |
| |
| /* Glue to use sim-fpu module. */ |
| |
| void |
| sim_io_error (SIM_DESC sd, const char *msg, ...) |
| { |
| va_list ap; |
| va_start(ap, msg); |
| vprintf(msg, ap); |
| printf("\n"); |
| va_end(ap); |
| |
| /* any final clean up */ |
| if (ppc_trace[trace_print_info] && simulation != NULL) |
| psim_print_info (simulation, ppc_trace[trace_print_info]); |
| |
| exit (1); |
| } |
| |
| |
| void * |
| zalloc(long size) |
| { |
| void *memory = malloc(size); |
| if (memory == NULL) |
| error("zalloc failed\n"); |
| memset(memory, 0, size); |
| return memory; |
| } |
| |
| /* When a CNTRL-C occures, queue an event to shut down the simulation */ |
| |
| static RETSIGTYPE |
| cntrl_c(int sig) |
| { |
| psim_stop (simulation); |
| } |
| |
| |
| int |
| main(int argc, char * const *argv) |
| { |
| const char *name_of_file; |
| char *arg_; |
| psim_status status; |
| device *root = psim_tree(); |
| |
| /* parse the arguments */ |
| argv = psim_options (root, argv + 1, SIM_OPEN_STANDALONE); |
| if (argv[0] == NULL) { |
| if (ppc_trace[trace_opts]) { |
| print_options (); |
| return 0; |
| } else { |
| psim_usage (0, 0, SIM_OPEN_STANDALONE); |
| } |
| } |
| name_of_file = argv[0]; |
| |
| if (ppc_trace[trace_opts]) |
| print_options (); |
| |
| /* create the simulator */ |
| simulation = psim_create(name_of_file, root); |
| |
| /* fudge the environment so that _=prog-name */ |
| arg_ = (char*)zalloc(strlen(argv[0]) + strlen("_=") + 1); |
| strcpy(arg_, "_="); |
| strcat(arg_, argv[0]); |
| putenv(arg_); |
| |
| /* initialize it */ |
| psim_init(simulation); |
| psim_stack(simulation, argv, environ); |
| |
| { |
| RETSIGTYPE (*prev) (); |
| prev = signal(SIGINT, cntrl_c); |
| psim_run(simulation); |
| signal(SIGINT, prev); |
| } |
| |
| /* any final clean up */ |
| if (ppc_trace[trace_print_info]) |
| psim_print_info (simulation, ppc_trace[trace_print_info]); |
| |
| /* why did we stop */ |
| status = psim_get_status(simulation); |
| switch (status.reason) { |
| case was_continuing: |
| error("psim: continuing while stopped!\n"); |
| return 0; |
| case was_trap: |
| error("psim: no trap insn\n"); |
| return 0; |
| case was_exited: |
| return status.signal; |
| case was_signalled: |
| printf ("%s: Caught signal %d at address 0x%lx\n", |
| name_of_file, (int)status.signal, |
| (long)status.program_counter); |
| return status.signal; |
| default: |
| error("unknown halt condition\n"); |
| return 0; |
| } |
| } |