/* This file is part of the program psim.
- Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
+ Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney
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 2 of the License, or
+ 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,
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, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "tree.h"
+#include <signal.h>
+
#include <stdio.h>
#include <ctype.h>
#include "bfd.h"
-
+#include "libiberty.h"
+#include "gdb/signals.h"
/* system structure, actual size of processor array determined at
runtime */
INLINE_PSIM\
(void)
-psim_usage(int verbose)
+psim_usage (int verbose, int help, SIM_OPEN_KIND kind)
{
printf_filtered("Usage:\n");
printf_filtered("\n");
printf_filtered("\t chirp - OEA + a few OpenBoot calls\n");
printf_filtered("\n"); }
+ printf_filtered("\t-E <endian> Specify the endianness of the target\n");
+ if (verbose) {
+ printf_filtered("\t Can be any of the following:\n");
+ printf_filtered("\t big - big endian target\n");
+ printf_filtered("\t little - little endian target\n");
+ printf_filtered("\n"); }
+
printf_filtered("\t-f <file> Merge <file> into the device tree\n");
if (verbose) { printf_filtered("\n"); }
printf_filtered("\n");
print_options();
}
- error("");
+
+ if (kind == SIM_OPEN_STANDALONE)
+ {
+ if (REPORT_BUGS_TO[0])
+ printf ("Report bugs to %s\n", REPORT_BUGS_TO);
+ exit (help ? 0 : 1);
+ }
+}
+
+/* Test "string" for containing a string of digits that form a number
+between "min" and "max". The return value is the number or "err". */
+static
+int is_num( char *string, int min, int max, int err)
+{
+ int result = 0;
+
+ for ( ; *string; ++string)
+ {
+ if (!isdigit(*string))
+ {
+ result = err;
+ break;
+ }
+ result = result * 10 + (*string - '0');
+ }
+ if (result < min || result > max)
+ result = err;
+
+ return result;
}
INLINE_PSIM\
(char **)
psim_options(device *root,
- char **argv)
+ char **argv,
+ SIM_OPEN_KIND kind)
{
device *current = root;
int argp;
while (*p != '\0') {
switch (*p) {
default:
- psim_usage(0);
- error ("");
- break;
+ printf_filtered ("Invalid Option: %s\n", argv[argp]);
+ psim_usage (0, 0, kind);
+ return NULL;
case 'c':
param = find_arg("Missing <count> option for -c (max-iterations)\n", &argp, argv);
tree_parse(root, "/openprom/options/max-iterations %s", param);
param = find_arg("Missing <emul> option for -e (os-emul)\n", &argp, argv);
tree_parse(root, "/openprom/options/os-emul %s", param);
break;
+ case 'E':
+ /* endian spec, ignored for now */
+ param = find_arg("Missing <endian> option for -E (target-endian)\n", &argp, argv);
+ if (strcmp (param, "big") == 0)
+ tree_parse (root, "/options/little-endian? false");
+ else if (strcmp (param, "little") == 0)
+ tree_parse (root, "/options/little-endian? true");
+ else
+ {
+ printf_filtered ("Invalid <endian> option for -E (target-endian)\n");
+ psim_usage (0, 0, kind);
+ return NULL;
+ }
+ break;
case 'f':
param = find_arg("Missing <file> option for -f\n", &argp, argv);
psim_merge_device_file(root, param);
break;
case 'h':
case '?':
- psim_usage(1);
- break;
+ psim_usage (1, 1, kind);
+ return NULL;
case 'H':
- psim_usage(2);
- break;
+ psim_usage (2, 1, kind);
+ return NULL;
case 'i':
if (isdigit(p[1])) {
tree_parse(root, "/openprom/trace/print-info %c", p[1]);
break;
case 'o':
param = find_arg("Missing <dev-spec> option for -o\n", &argp, argv);
- current = tree_parse(current, "%s", param);
+ if (memcmp(param, "mpc860c0", 8) == 0)
+ {
+ if (param[8] == '\0')
+ tree_parse(root, "/options/mpc860c0 5");
+ else if (param[8] == '=' && is_num(param+9, 1, 10, 0))
+ {
+ tree_parse(root, "/options/mpc860c0 %s", param+9);
+ }
+ else error("Invalid mpc860c0 option for -o\n");
+ }
+ else
+ current = tree_parse(current, "%s", param);
break;
case 'r':
param = find_arg("Missing <ram-size> option for -r (oea-memory-size)\n", &argp, argv);
else
tree_parse(root, "/openprom/trace/%s 1", param);
break;
- case 'E':
- /* endian spec, ignored for now */
- ++p;
+ case '-':
+ /* it's a long option of the form --optionname=optionvalue.
+ Such options can be passed through if we are invoked by
+ gdb. */
+ if (strstr(argv[argp], "architecture") != NULL) {
+ /* we must consume the argument here, so that we get out
+ of the loop. */
+ p = argv[argp] + strlen(argv[argp]) - 1;
+ printf_filtered("Warning - architecture parameter ignored\n");
+ }
+ else if (strcmp (argv[argp], "--help") == 0)
+ {
+ psim_usage (0, 1, kind);
+ return NULL;
+ }
+ else if (strncmp (argv[argp], "--sysroot=",
+ sizeof ("--sysroot=") - 1) == 0)
+ /* Ignore this option. */
+ p = argv[argp] + strlen(argv[argp]) - 1;
+ else if (strcmp (argv[argp], "--version") == 0)
+ {
+ extern const char version[];
+ printf ("GNU simulator %s%s\n", PKGVERSION, version);
+ if (kind == SIM_OPEN_STANDALONE)
+ exit (0);
+ else
+ return NULL;
+ }
+ else
+ {
+ printf_filtered ("Invalid option: %s\n", argv[argp]);
+ psim_usage (0, 0, kind);
+ return NULL;
+ }
break;
}
p += 1;
NULL, 0,
device_ioctl_set_trace);
+ {
+ void semantic_init(device* root);
+ semantic_init(root);
+ }
+
/* return where the options end */
return argv + argp;
}
}
+static void
+cntrl_c_simulation(void *data)
+{
+ psim *system = data;
+ psim_halt(system,
+ psim_nr_cpus(system),
+ was_continuing,
+ GDB_SIGNAL_INT);
+}
+
+INLINE_PSIM\
+(void)
+psim_stop(psim *system)
+{
+ event_queue_schedule_after_signal(psim_event_queue(system),
+ 0 /*NOW*/,
+ cntrl_c_simulation,
+ system);
+}
+
INLINE_PSIM\
(void)
psim_halt(psim *system,
"/openprom/init/stack");
if (stack_device != (device*)0) {
unsigned_word stack_pointer;
- psim_read_register(system, 0, &stack_pointer, "sp", cooked_transfer);
+ ASSERT (psim_read_register(system, 0, &stack_pointer, "sp",
+ cooked_transfer) > 0);
device_ioctl(stack_device,
NULL, /*cpu*/
0, /*cia*/
system->events, system->processors, system->nr_cpus);
}
-INLINE_PSIM\
-(void)
-psim_run_until_stop(psim *system,
- volatile int *keep_running)
-{
- idecode_run_until_stop(system, keep_running,
- system->events, system->processors, system->nr_cpus);
-}
-
-
/* storage manipulation functions */
INLINE_PSIM\
-(void)
+(int)
psim_read_register(psim *system,
int which_cpu,
void *buf,
transfer_mode mode)
{
register_descriptions description;
- char cooked_buf[sizeof(unsigned_8)];
+ char *cooked_buf;
cpu *processor;
/* find our processor */
/* find the register description */
description = register_description(reg);
if (description.type == reg_invalid)
- error("psim_read_register() invalid register name `%s'\n", reg);
+ return 0;
+ cooked_buf = alloca (description.size);
/* get the cooked value */
switch (description.type) {
*(msreg*)cooked_buf = cpu_registers(processor)->msr;
break;
+ case reg_fpscr:
+ *(fpscreg*)cooked_buf = cpu_registers(processor)->fpscr;
+ break;
+
case reg_insns:
*(unsigned_word*)cooked_buf = mon_get_number_of_insns(system->monitor,
which_cpu);
*(unsigned_word*)cooked_buf = model_get_number_of_cycles(cpu_model(processor));
break;
+#ifdef WITH_ALTIVEC
+ case reg_vr:
+ *(vreg*)cooked_buf = cpu_registers(processor)->altivec.vr[description.index];
+ break;
+
+ case reg_vscr:
+ *(vscreg*)cooked_buf = cpu_registers(processor)->altivec.vscr;
+ break;
+#endif
+
+#ifdef WITH_E500
+ case reg_gprh:
+ *(gpreg*)cooked_buf = cpu_registers(processor)->e500.gprh[description.index];
+ break;
+
+ case reg_evr:
+ *(unsigned64*)cooked_buf = EVR(description.index);
+ break;
+
+ case reg_acc:
+ *(accreg*)cooked_buf = cpu_registers(processor)->e500.acc;
+ break;
+#endif
+
default:
printf_filtered("psim_read_register(processor=0x%lx,buf=0x%lx,reg=%s) %s\n",
(unsigned long)processor, (unsigned long)buf, reg,
case 8:
*(unsigned_8*)buf = H2T_8(*(unsigned_8*)cooked_buf);
break;
+#ifdef WITH_ALTIVEC
+ case 16:
+ if (CURRENT_HOST_BYTE_ORDER != CURRENT_TARGET_BYTE_ORDER)
+ {
+ union { vreg v; unsigned_8 d[2]; } h, t;
+ memcpy(&h.v/*dest*/, cooked_buf/*src*/, description.size);
+ { _SWAP_8(t.d[0] =, h.d[1]); }
+ { _SWAP_8(t.d[1] =, h.d[0]); }
+ memcpy(buf/*dest*/, &t/*src*/, description.size);
+ break;
+ }
+ else
+ memcpy(buf/*dest*/, cooked_buf/*src*/, description.size);
+ break;
+#endif
}
}
else {
memcpy(buf/*dest*/, cooked_buf/*src*/, description.size);
}
+ return description.size;
}
INLINE_PSIM\
-(void)
+(int)
psim_write_register(psim *system,
int which_cpu,
const void *buf,
{
cpu *processor;
register_descriptions description;
- char cooked_buf[sizeof(unsigned_8)];
+ char *cooked_buf;
/* find our processor */
if (which_cpu == MAX_NR_PROCESSORS) {
else
which_cpu = system->last_cpu;
}
+
+ /* find the description of the register */
+ description = register_description(reg);
+ if (description.type == reg_invalid)
+ return 0;
+ cooked_buf = alloca (description.size);
+
if (which_cpu == -1) {
int i;
for (i = 0; i < system->nr_cpus; i++)
psim_write_register(system, i, buf, reg, mode);
- return;
+ return description.size;
}
ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus);
processor = system->processors[which_cpu];
- /* find the description of the register */
- description = register_description(reg);
- if (description.type == reg_invalid)
- error("psim_write_register() invalid register name %s\n", reg);
-
/* If the data is comming in raw (target order), need to cook it
into host order before putting it into PSIM's internal structures */
if (mode == raw_transfer) {
case 8:
*(unsigned_8*)cooked_buf = T2H_8(*(unsigned_8*)buf);
break;
+#ifdef WITH_ALTIVEC
+ case 16:
+ if (CURRENT_HOST_BYTE_ORDER != CURRENT_TARGET_BYTE_ORDER)
+ {
+ union { vreg v; unsigned_8 d[2]; } h, t;
+ memcpy(&t.v/*dest*/, buf/*src*/, description.size);
+ { _SWAP_8(h.d[0] =, t.d[1]); }
+ { _SWAP_8(h.d[1] =, t.d[0]); }
+ memcpy(cooked_buf/*dest*/, &h/*src*/, description.size);
+ break;
+ }
+ else
+ memcpy(cooked_buf/*dest*/, buf/*src*/, description.size);
+#endif
}
}
else {
cpu_registers(processor)->msr = *(msreg*)cooked_buf;
break;
+ case reg_fpscr:
+ cpu_registers(processor)->fpscr = *(fpscreg*)cooked_buf;
+ break;
+
+#ifdef WITH_E500
+ case reg_gprh:
+ cpu_registers(processor)->e500.gprh[description.index] = *(gpreg*)cooked_buf;
+ break;
+
+ case reg_evr:
+ {
+ unsigned64 v;
+ v = *(unsigned64*)cooked_buf;
+ cpu_registers(processor)->e500.gprh[description.index] = v >> 32;
+ cpu_registers(processor)->gpr[description.index] = v;
+ break;
+ }
+
+ case reg_acc:
+ cpu_registers(processor)->e500.acc = *(accreg*)cooked_buf;
+ break;
+#endif
+
+#ifdef WITH_ALTIVEC
+ case reg_vr:
+ cpu_registers(processor)->altivec.vr[description.index] = *(vreg*)cooked_buf;
+ break;
+
+ case reg_vscr:
+ cpu_registers(processor)->altivec.vscr = *(vscreg*)cooked_buf;
+ break;
+#endif
+
default:
printf_filtered("psim_write_register(processor=0x%lx,cooked_buf=0x%lx,reg=%s) %s\n",
(unsigned long)processor, (unsigned long)cooked_buf, reg,
}
+ return description.size;
}