1/*  This file is part of the program psim.
2
3    Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, see <http://www.gnu.org/licenses/>.
17
18    */
19
20/* This must come before any other includes.  */
21#include "defs.h"
22
23#include <stdarg.h>
24#include <stdio.h>
25#include <fcntl.h>
26
27#include <signal.h>
28
29#include "psim.h"
30#include "options.h"
31#include "device.h" /* FIXME: psim should provide the interface */
32#include "events.h" /* FIXME: psim should provide the interface */
33
34#include "bfd.h"
35#include "sim/callback.h"
36#include "sim/sim.h"
37
38#include <stdlib.h>
39#ifdef HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42#include <string.h>
43#include <errno.h>
44
45#include "environ.h"
46
47#if !defined(O_NONBLOCK) || !defined(F_GETFL) || !defined(F_SETFL)
48#undef WITH_STDIO
49#define WITH_STDIO DO_USE_STDIO
50#endif
51
52
53static psim *simulation = NULL;
54
55
56void
57sim_io_poll_quit (void)
58{
59  /* nothing to do */
60}
61
62void
63sim_io_printf_filtered(const char *msg, ...)
64{
65  va_list ap;
66  va_start(ap, msg);
67  vprintf(msg, ap);
68  va_end(ap);
69}
70
71void
72error (const char *msg, ...)
73{
74  va_list ap;
75  va_start(ap, msg);
76  vprintf(msg, ap);
77  printf("\n");
78  va_end(ap);
79
80  /* any final clean up */
81  if (ppc_trace[trace_print_info] && simulation != NULL)
82    psim_print_info (simulation, ppc_trace[trace_print_info]);
83
84  exit (1);
85}
86
87int
88sim_io_write_stdout(const char *buf,
89		    int sizeof_buf)
90{
91  switch (CURRENT_STDIO) {
92  case DO_USE_STDIO:
93    {
94      int i;
95      for (i = 0; i < sizeof_buf; i++) {
96	putchar(buf[i]);
97      }
98      return i;
99    }
100    break;
101  case DONT_USE_STDIO:
102    return write(1, buf, sizeof_buf);
103    break;
104  default:
105    error("sim_io_write_stdout: invalid switch\n");
106  }
107  return 0;
108}
109
110int
111sim_io_write_stderr(const char *buf,
112		    int sizeof_buf)
113{
114  switch (CURRENT_STDIO) {
115  case DO_USE_STDIO:
116    {
117      int i;
118      for (i = 0; i < sizeof_buf; i++) {
119	fputc(buf[i], stderr);
120      }
121      return i;
122    }
123    break;
124  case DONT_USE_STDIO:
125    return write(2, buf, sizeof_buf);
126    break;
127  default:
128    error("sim_io_write_stdout: invalid switch\n");
129  }
130  return 0;
131}
132
133int
134sim_io_read_stdin(char *buf,
135		  int sizeof_buf)
136{
137  switch (CURRENT_STDIO) {
138  case DO_USE_STDIO:
139    if (sizeof_buf > 1) {
140      if (fgets(buf, sizeof_buf, stdin) != NULL)
141	return strlen(buf);
142    }
143    else if (sizeof_buf == 1) {
144      char b[2];
145      if (fgets(b, sizeof(b), stdin) != NULL) {
146	memcpy(buf, b, strlen(b));
147	return strlen(b);
148      }
149    }
150    else if (sizeof_buf == 0)
151      return 0;
152    return sim_io_eof;
153    break;
154  case DONT_USE_STDIO:
155#if defined(O_NONBLOCK) && defined(F_GETFL) && defined(F_SETFL)
156    {
157      /* check for input */
158      int flags;
159      int status;
160      int nr_read;
161      int result;
162      /* get the old status */
163      flags = fcntl(0, F_GETFL, 0);
164      if (flags == -1) {
165	perror("sim_io_read_stdin");
166	return sim_io_eof;
167      }
168      /* temp, disable blocking IO */
169      status = fcntl(0, F_SETFL, flags | O_NONBLOCK);
170      if (status == -1) {
171	perror("sim_io_read_stdin");
172	return sim_io_eof;
173      }
174      /* try for input */
175      nr_read = read(0, buf, sizeof_buf);
176      if (nr_read > 0
177	  || (nr_read == 0 && sizeof_buf == 0))
178	result = nr_read;
179      else if (nr_read == 0)
180	result = sim_io_eof;
181      else { /* nr_read < 0 */
182	if (errno == EAGAIN)
183	  result = sim_io_not_ready;
184	else
185	  result = sim_io_eof;
186      }
187      /* return to regular vewing */
188      status = fcntl(0, F_SETFL, flags);
189      if (status == -1) {
190	perror("sim_io_read_stdin");
191	return sim_io_eof;
192      }
193      return result;
194    }
195    break;
196#endif
197  default:
198    error("sim_io_read_stdin: invalid switch\n");
199    break;
200  }
201  return 0;
202}
203
204void
205sim_io_flush_stdoutput(void)
206{
207  switch (CURRENT_STDIO) {
208  case DO_USE_STDIO:
209    fflush (stdout);
210    break;
211  case DONT_USE_STDIO:
212    break;
213  default:
214    error("sim_io_flush_stdoutput: invalid switch\n");
215    break;
216  }
217}
218
219/* Glue to use sim-fpu module.  */
220
221void
222sim_io_error (SIM_DESC sd, const char *msg, ...)
223{
224  va_list ap;
225  va_start(ap, msg);
226  vprintf(msg, ap);
227  printf("\n");
228  va_end(ap);
229
230  /* any final clean up */
231  if (ppc_trace[trace_print_info] && simulation != NULL)
232    psim_print_info (simulation, ppc_trace[trace_print_info]);
233
234  exit (1);
235}
236
237
238void *
239zalloc(long size)
240{
241  void *memory = malloc(size);
242  if (memory == NULL)
243    error("zalloc failed\n");
244  memset(memory, 0, size);
245  return memory;
246}
247
248/* When a CNTRL-C occures, queue an event to shut down the simulation */
249
250static RETSIGTYPE
251cntrl_c(int sig)
252{
253  psim_stop (simulation);
254}
255
256
257int
258main(int argc, char * const *argv)
259{
260  const char *name_of_file;
261  char *arg_;
262  psim_status status;
263  device *root = psim_tree();
264
265  /* parse the arguments */
266  argv = psim_options (root, argv + 1, SIM_OPEN_STANDALONE);
267  if (argv[0] == NULL) {
268    if (ppc_trace[trace_opts]) {
269      print_options ();
270      return 0;
271    } else {
272      psim_usage (0, 0, SIM_OPEN_STANDALONE);
273    }
274  }
275  name_of_file = argv[0];
276
277  if (ppc_trace[trace_opts])
278    print_options ();
279
280  /* create the simulator */
281  simulation = psim_create(name_of_file, root);
282
283  /* fudge the environment so that _=prog-name */
284  arg_ = (char*)zalloc(strlen(argv[0]) + strlen("_=") + 1);
285  strcpy(arg_, "_=");
286  strcat(arg_, argv[0]);
287  putenv(arg_);
288
289  /* initialize it */
290  psim_init(simulation);
291  psim_stack(simulation, argv, environ);
292
293  {
294    RETSIGTYPE (*prev) ();
295    prev = signal(SIGINT, cntrl_c);
296    psim_run(simulation);
297    signal(SIGINT, prev);
298  }
299
300  /* any final clean up */
301  if (ppc_trace[trace_print_info])
302    psim_print_info (simulation, ppc_trace[trace_print_info]);
303
304  /* why did we stop */
305  status = psim_get_status(simulation);
306  switch (status.reason) {
307  case was_continuing:
308    error("psim: continuing while stopped!\n");
309    return 0;
310  case was_trap:
311    error("psim: no trap insn\n");
312    return 0;
313  case was_exited:
314    return status.signal;
315  case was_signalled:
316    printf ("%s: Caught signal %d at address 0x%lx\n",
317 	    name_of_file, (int)status.signal,
318 	    (long)status.program_counter);
319    return status.signal;
320  default:
321    error("unknown halt condition\n");
322    return 0;
323  }
324}
325