blob: 4c5433daddc8c858b13fa5c6dbe83f1d79aba18e [file] [log] [blame]
/* Main simulator entry points specific to the ARC.
Copyright (C) 1996, 1997, 1998, 1999, 2003, 2004, 2005, 2006, 2007, 2008,
2009 Free Software Foundation, Inc.
This file is part of GDB, the GNU debugger.
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, 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, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/******************************************************************************/
/* */
/* Outline: */
/* This module provides operations to: */
/* */
/* 1) create an "instance" of the ARC simulator */
/* 2) destroy an "instance" of the ARC simulator */
/* 3) create an "inferior" to run on the simulator */
/* 4) execute a simulator-related command */
/* */
/* N.B. there can be only one simulator instance at a time because of the */
/* use of the current_state global variable. */
/* */
/* This module is also responsible for setting up the "command line" */
/* arguments and environment (name/value pairs) to be passed to the */
/* program that is to be debugged. This data is passed on the stack above */
/* the top of stack as it is known to the program. */
/* */
/* E.g. if we are passing 4 arguments to main, we must place the data on */
/* the stack as: */
/* */
/* . */
/* . */
/* stack[top + A3] <== <arg_3> */
/* . */
/* . */
/* stack[top + A2] <== <arg_2> */
/* . */
/* . */
/* stack[top + A1] <== <arg_1> */
/* . */
/* . */
/* stack[top + A0] <== <arg_0> */
/* stack[top + 28] <== 0x0 # ? NULL terminator */
/* stack[top + 24] <== 0x0 # envp NULL terminator */
/* stack[top + 20] <== 0x0 # argv NULL terminator */
/* stack[top + 16] <== TOP + A3 # argv[3] */
/* stack[top + 12] <== TOP + A2 # argv[2] */
/* stack[top + 8] <== TOP + A1 # argv[1] */
/* stack[top + 4] <== TOP + A0 # argv[0] */
/* stack[top ] <== 0x4 # argc */
/* */
/* where TOP = &stack[top] */
/* and A0 .. A3 are the offsets of the stored arguments from the stack */
/* top. */
/* */
/* */
/* Notes: */
/* The interface to this module is somewhat muddled: both sim_open and */
/* sim_create_inferior have a BFD parameter which denotes the executable */
/* file which is to be run; but for sim_open this parameter may be NULL. */
/* */
/* Also, both sim_open and sim_create_inferior have an argv parameter, */
/* but for sim_open *some* of the strings in this array parameter may be */
/* command-line arguments to be passed to the program to be executed, */
/* whilst the others are arguments for the simulator itself; but for */
/* sim_create_inferior, *all* of the strings (if any) in this parameter */
/* are such command-line arguments. */
/* */
/* Finally, sim_create_inferior has an envp parameter which holds a set */
/* of name/value pairs to be passed as the environment of the executed */
/* program, whereas sim_open does not; but this is not (currently) done. */
/* */
/* */
/* This complexity arises from the variety of ways in which a simulator */
/* instance may be created and used: */
/* */
/* a) the instance may be created by gdb before the executable file is */
/* known; e.g. the user may issue the commands */
/* */
/* set endian big | little */
/* target sim */
/* file <executable> */
/* load */
/* run */
/* */
/* and in this case the BFD parameter to sim_open is NULL, and its */
/* argv parameter does not hold the executable's arguments; */
/* */
/* b) the instance may be created by gdb after the executable file is */
/* known; e.g. the user may issue the commands */
/* */
/* file <executable> */
/* target sim */
/* load */
/* run */
/* */
/* and in this case the BFD parameter to sim_open is non-NULL, and */
/* its argv parameter does not hold the executable's arguments; */
/* */
/* c) the instance may be created by a standalone executable; e.g. */
/* known; e.g. the user may issue the command */
/* */
/* run <executable> [ <arg1> .. <argN> ] */
/* */
/* and in this case the BFD parameter to sim_open is non-NULL, and */
/* its argv parameter does hold the executable's arguments. */
/* */
/* Note that in each case, the argv parameter to sim_create_inferior */
/* holds the command-line arguments for the executable (so, there is */
/* apparently no need for them to be passed in the sim_open argv also!). */
/* */
/* The arguments to the executed program may also be specified in several */
/* ways; e.g by use of the gdb 'set args' command, or as arguments to the */
/* gdb 'run' command; or, in the case of a standalone executable, on the */
/* command line. */
/* */
/* Note that the executable program can be run (by gdb) repeatedly with */
/* different argument lists, i.e. there may be multiple calls of */
/* sim_create_inferior after a call of sim_open; and each of these lists */
/* may require a different amount of memory to hold them on the stack. */
/* */
/* */
/* It is necessary to define a memory region with a particular start */
/* address and size in the simulator memory (all accesses outside this */
/* address range by the executed program are erroneous, thus allowing */
/* invalid accesses to be detected); this region must include the program */
/* text, (un)initialized data, heap and stack. This must also include */
/* the argument/environment data which is passed above the top of the */
/* stack. */
/* */
/* If the executable file is known (i.e. we have a non-NULL BFD), */
/* the bounds of the memory region required for the program may be */
/* extracted from the section header information in the file; if the */
/* arguments/environment are known, the space required to hold them on */
/* the stack may be computed. This allows the total space to be computed, */
/* and so a memory region holding it may be defined. */
/* */
/* However, if a subsequent execution of the program should require a */
/* greater total space (because its arguments have changed) it is then */
/* necessary to define an additional memory region to provide the extra */
/* space; it is not possible to redefine the existing region, or a new */
/* region of the new size (as memory regions may not overlap). */
/* */
/******************************************************************************/
/* system header files */
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
/* simulator / binutils header files */
#include "sim-main.h"
#include "sim-options.h"
#include "libiberty.h"
#include "bfd.h"
/* -------------------------------------------------------------------------- */
/* conditional compilation flags */
/* -------------------------------------------------------------------------- */
//#define LOGGING
//#define PUSH_ENVIRONMENT_ONTO_STACK
/* -------------------------------------------------------------------------- */
/* externally visible data */
/* -------------------------------------------------------------------------- */
/* Records simulator descriptor so utilities like arc_dump_regs can be called
from gdb. */
SIM_DESC current_state;
/* -------------------------------------------------------------------------- */
/* local data */
/* -------------------------------------------------------------------------- */
#define DEFAULT_ENVIRONMENT_SPACE 2048
#define TARGET_POINTER_SIZE 4
#define TARGET_INT_SIZE 4
/* -------------------------------------------------------------------------- */
/* local macros */
/* -------------------------------------------------------------------------- */
#define IS_LITTLE_ENDIAN(abfd) (abfd) ? bfd_little_endian (abfd) \
: (CURRENT_TARGET_BYTE_ORDER == LITTLE_ENDIAN)
/* -------------------------------------------------------------------------- */
/* local functions */
/* -------------------------------------------------------------------------- */
/* Cover function of sim_state_free to free the cpu buffers as well. */
static void
free_state (SIM_DESC sd)
{
if (STATE_MODULES (sd) != NULL)
sim_module_uninstall (sd);
sim_cpu_free_all (sd);
sim_state_free (sd);
}
/* PROFILE_CPU_CALLBACK */
static void
print_arc_misc_cpu (SIM_CPU *cpu, int verbose)
{
if (CPU_PROFILE_FLAGS (cpu) [PROFILE_INSN_IDX])
{
SIM_DESC sd = CPU_STATE (cpu);
char buf[20];
sim_io_printf (sd, "Miscellaneous Statistics\n\n");
sim_io_printf (sd, " %-*s %s\n\n",
PROFILE_LABEL_WIDTH, "Fill nops:",
sim_add_commas (buf, sizeof (buf),
CPU_ARC_MISC_PROFILE (cpu)->fillnop_count));
}
}
#ifdef LOGGING
static void
dump (SIM_DESC sd, char** argv, char** envp)
{
char **cpp, **rpp;
char* tag;
int cnt;
for (cpp = argv, tag = "argv", cnt = 2; cnt--; cpp = envp, tag = "env")
{
if (cpp)
{
int i = 0;
for (rpp = cpp; *rpp; rpp++, i++)
sim_io_eprintf(sd, "%s[%d] = %s\n", tag, i, *rpp);
}
}
}
#endif
/* Setup copy arguments / environment to the stack area of SD according
to argv and envp. Either or both of argv and envp may be NULL.
Return 0 on failure, nonzero on success. */
static int
setup_stack (SIM_DESC sd, int little_endian_p, char** argv, char** envp)
{
SIM_CPU* cpu = STATE_CPU (sd, 0);
int wpp = sd->memory.stack_top + TARGET_INT_SIZE;
int cp = sd->memory.argument_data_start;
int count;
char** cpp;
#ifdef LOGGING
sim_io_eprintf(sd, "setup stack (%c/E) %d args\n",
(little_endian_p) ? 'L' : 'B',
sd->memory.num_arguments);
dump(sd, argv, envp);
#endif
if (sd->memory.stack_top <= sd->memory.stack_start)
{
host_callback *callback = STATE_CALLBACK (sd);
(*callback->printf_filtered) (callback, "stack overflow\n");
return 0;
}
/* Can't use sim_core_write_unaligned_4 without everything
initialized when tracing, and then these writes would get into
the trace. */
#define write_dword(addr, data) \
do \
{ \
bfd_byte buf[4]; \
USI data_ = data; \
USI addr_ = addr; \
if (little_endian_p) \
bfd_putl32 (data_, buf); \
else \
bfd_putb32 (data_, buf); \
if (sim_core_write_buffer (sd, cpu, 0, buf, addr_, 4) != 4) \
{ \
sim_io_eprintf(sd, "failed to write word to address 0x%x\n", addr);\
return 0; \
} \
} \
while (0)
/* Push the arguments and environment onto the stack. */
write_dword (sd->memory.stack_top, sd->memory.num_arguments);
for (cpp = argv, count = 2; count--; cpp = envp)
{
if (cpp)
{
char* argument;
char** rpp;
for (rpp = cpp; (argument = *cpp); cpp++)
{
size_t len = strlen(argument) + 1;
#ifdef LOGGING
sim_io_eprintf(sd, "pushing argument '%s' onto program stack at address 0x%x\n", argument, cp);
#endif
if (sim_core_write_buffer (sd, cpu, 0, argument, cp, len) != len)
{
sim_io_eprintf(sd, "could not push argument '%s' onto program stack at address 0x%x\n", argument, cp);
return 0;
}
write_dword (wpp, cp);
cp += len;
wpp += TARGET_POINTER_SIZE;
}
}
write_dword (wpp, 0); // NULL array terminator
wpp += TARGET_POINTER_SIZE;
}
write_dword (wpp, 0); /* uClibc aux_dat NULL terminator. */
/* success */
return 1;
}
/* Find out heap and stack end boundaries, and calculate required memory size;
if this cannot be done, use the default memory size.
ABFD, ARGV and/or ENVP may be NULL.
If this calculation fails, return 0. */
static int
determine_memory_requirements (SIM_DESC sd, struct bfd *abfd, char **argv,
char **envp, struct sim_memory* memory)
{
USI stack_start = 0, stack_top = 0, heap_start = 0, heap_end = 0;
USI program_end = 0;
USI memory_size;
USI data_start;
int argc = 0;
size_t total_argument_length = 0;
int num_pointers = 0;
/* N.B. the *_end variables actually denote the next byte after the end of
the sections to which they refer; however, they are used consistently
in this way, so that is not a problem! */
/* If we have an executable file to look at. */
if (abfd)
{
asection* section;
/* Look at each section in the file. */
for (section = abfd->sections; section; section = section->next)
{
if (strcmp (bfd_get_section_name (abfd, section), ".stack") == 0)
{
stack_start = bfd_get_section_vma (abfd, section);
stack_top = stack_start + bfd_section_size (abfd, section);
stack_top &= -TARGET_POINTER_SIZE;
/* N.B. this assumes that the target memory region to be
created has the range 0 .. stack_top - 1, i.e. that there
is nothing in the program that has to be loaded at
addresses above the stack top. */
memory_size = stack_top;
}
else if (strcmp (bfd_get_section_name (abfd, section), ".heap") == 0)
{
heap_start = bfd_get_section_vma (abfd, section);
heap_end = heap_start + bfd_section_size (abfd, section);
}
else if (bfd_get_section_flags(abfd, section) & SEC_LOAD)
{
USI section_end = bfd_get_section_vma (abfd, section) +
bfd_section_size (abfd, section);
/* Keep track of the end address of whatever else is to be
loaded. */
if (program_end < section_end)
program_end = section_end;
}
}
/* If we know the start of the stack, check for an overlap. */
if (stack_start > 0 && program_end > stack_start)
{
sim_io_eprintf(sd,
"program data overlaps program stack at 0x%x (0x%x)\n",
stack_start, program_end);
return 0;
}
/* No heap section found? */
if (heap_end == 0)
{
/* Assume the heap lies between the program data and the stack. */
heap_start = program_end;
heap_end = stack_start;
}
}
/* If we have arguments or environment variables to pass to the program. */
if (argv)
{
char **rpp;
for (rpp = argv; *rpp; rpp++, num_pointers++)
total_argument_length += strlen (*rpp) + 1;
argc = num_pointers;
}
num_pointers++; /* For NULL terminator. */
if (envp)
{
char** rpp;
for (rpp = envp; *rpp; rpp++, num_pointers++)
total_argument_length += strlen (*rpp) + 1;
}
num_pointers++; /* For NULL terminator. */
num_pointers++; /* For uclibc aux_dat. */
/* If we could not get the stack bounds from the executable file (and hence
do not know the memory size), use the default memory size and take the
top of the stack as being at the end of that memory range (aligned to
the size of a target pointer). */
if (!stack_top)
stack_top = (USI) ((ARC_DEFAULT_MEM_SIZE + 3) & -TARGET_POINTER_SIZE);
data_start = (USI) (stack_top +
TARGET_INT_SIZE + /* For argc. */
num_pointers * TARGET_POINTER_SIZE);
/* We need enough memory to hold the program stack, plus the data to be passed
above the top of the stack. */
memory_size = (USI) (data_start + total_argument_length);
#ifdef PUSH_ENVIRONMENT_ONTO_STACK
if (!envp)
memory_size += DEFAULT_ENVIRONMENT_SPACE;
#endif
/* Round up to multiple of 32: strlen expects memory to come in chunks
that are at least cache-line (32 bytes) sized.
FIXME: is that true? */
memory_size += 31;
memory_size &= -32;
memory->heap_start = heap_start;
memory->heap_end = heap_end;
memory->stack_top = stack_top;
memory->stack_start = stack_start;
memory->total_size = memory_size;
memory->argument_data_start = data_start;
memory->num_arguments = (USI) argc;
#ifdef LOGGING
sim_io_eprintf(sd, "heap start : 0x%x\n", heap_start);
sim_io_eprintf(sd, "heap end : 0x%x\n", heap_end);
sim_io_eprintf(sd, "stack start : 0x%x\n", stack_start);
sim_io_eprintf(sd, "stack top : 0x%x\n", stack_top);
sim_io_eprintf(sd, "memory size : 0x%x\n", memory_size);
sim_io_eprintf(sd, "arg data start: 0x%x\n", data_start);
sim_io_eprintf(sd, "%d args\n", argc);
#endif
/* Success. */
return 1;
}
static void
define_memory_region (SIM_DESC sd, USI start, USI size)
{
/* Allocate core managed memory if none specified by user. */
if (!sd->memory_regions_defined_by_user)
{
#ifdef LOGGING
sim_io_printf (sd, "memory region 0x%x,0x%x\n", start, size);
#endif
sim_do_commandf (sd, "memory region 0x%x,0x%x", start, size);
}
}
/* -------------------------------------------------------------------------- */
/* externally visible functions */
/* -------------------------------------------------------------------------- */
/* Create an instance of the simulator. */
SIM_DESC
sim_open (SIM_OPEN_KIND kind,
host_callback *callback,
struct bfd *abfd, /* May be NULL. */
char **argv)
{
SIM_DESC sd = sim_state_alloc (kind, callback);
int little_endian_p;
char** prog_argv;
char c;
SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
#ifdef LOGGING
sim_io_eprintf (sd, "sim_open: %p\n", abfd);
dump(sd, argv, NULL);
#endif
/* The cpu data is kept in a separately-allocated chunk of memory. */
if (sim_cpu_alloc_all (sd, 1, cgen_cpu_max_extra_bytes ()) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
#if 0 /* FIXME: pc is in mach-specific struct. */
/* FIXME: watchpoints code shouldn't need this. */
{
SIM_CPU *current_cpu = STATE_CPU (sd, 0);
STATE_WATCHPOINTS (sd)->pc = &(PC);
STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PC);
}
#endif
if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
#ifdef HAVE_DV_SOCKSER /* FIXME: was done differently before. */
if (dv_sockser_install (sd) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
#endif
#if 0 /* FIXME: 'twould be nice if we could do this. */
/* These options override any module options.
Obviously ambiguity should be avoided, however the caller may wish to
augment the meaning of an option. */
if (extra_options != NULL)
sim_add_option_table (sd, extra_options);
#endif
/* getopt will print the error message so we just have to exit if this fails.
FIXME: Hmmm... in the case of gdb we need getopt to call
print_filtered. */
if (sim_parse_args (sd, argv) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
#ifdef LOGGING
/* sim_parse_args may set up STATE_PROG_ARGV(sd), in the case that kind == SIM_OPEN_STANDALONE. */
dump(sd, STATE_PROG_ARGV (sd), NULL);
#endif
/* Check for/establish the reference program image, and set arch info. */
if (sim_analyze_program (sd,
(STATE_PROG_ARGV (sd) != NULL
? *STATE_PROG_ARGV (sd)
: NULL),
abfd) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
prog_argv = STATE_PROG_ARGV (sd);
/* If we have not been given an executable file. */
if (!abfd)
{
/* If the test below fails, we will use ARC_DEFAULT_MEM_SIZE. */
if (prog_argv != NULL && *prog_argv != NULL)
{
char* name = *prog_argv;
abfd = bfd_openr (name, 0);
if (abfd == NULL || !bfd_check_format (abfd, bfd_object))
{
free_state (sd);
return 0;
}
}
}
/* Establish any remaining configuration options. */
if (sim_config (sd) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
little_endian_p = IS_LITTLE_ENDIAN(abfd);
/* Check whether core managed memory has been specified by user.
Use address 4 here in case the user wanted address 0 unmapped.
N.B. this is really not a very good check - we want to know whether the
user has explicitly specified the target's memory regions, so that we
don't define a region ourself (which might overlap), and we try to
find that out by seeing if we can read the memory at address 0x4 !!!! */
sd->memory_regions_defined_by_user =
sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) != 0;
/* Calculate the memory size required without actually initializing the stack. */
if (!determine_memory_requirements(sd, abfd, prog_argv, NULL, &sd->memory))
{
free_state (sd);
return 0;
}
define_memory_region (sd, 0, sd->memory.total_size);
/* If the simulator is being used stand-alone, we know that the program
arguments we have been given here are not going to change later on (when
sim_create_inferior is called) - so we can go ahead and set up the stack
with those arguments right now. */
if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
{
/* Now that we do know the memory size, initialize the stack. */
if (!setup_stack (sd, little_endian_p, prog_argv, NULL))
{
free_state (sd);
return 0;
}
}
if (sim_post_argv_init (sd) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
/* Open a copy of the cpu descriptor table. */
{
CGEN_CPU_DESC cd = arc_cgen_cpu_open_1
(STATE_ARCHITECTURE (sd)->printable_name,
(little_endian_p ? CGEN_ENDIAN_LITTLE : CGEN_ENDIAN_BIG));
int i;
for (i = 0; i < MAX_NR_PROCESSORS; ++i)
{
SIM_CPU *cpu = STATE_CPU (sd, i);
CPU_CPU_DESC (cpu) = cd;
CPU_DISASSEMBLER (cpu) = sim_cgen_disassemble_insn;
}
arc_cgen_init_dis (cd);
}
/* Initialize various cgen things not done by common framework.
Must be done after arc_cgen_cpu_open. */
cgen_init (sd);
for (c = 0; c < MAX_NR_PROCESSORS; c++)
{
/* Only needed for profiling, but the structure member is small. */
memset (CPU_ARC_MISC_PROFILE (STATE_CPU (sd, i)), 0,
sizeof (* CPU_ARC_MISC_PROFILE (STATE_CPU (sd, i))));
/* Hook in callback for reporting these stats. */
PROFILE_INFO_CPU_CALLBACK (CPU_PROFILE_DATA (STATE_CPU (sd, i))) =
print_arc_misc_cpu;
}
/* Store in a global so things like arc32_dump_regs can be invoked
from the gdb command line. */
current_state = sd;
return sd;
}
void
sim_close (SIM_DESC sd, int quitting)
{
arc_cgen_cpu_close (CPU_CPU_DESC (STATE_CPU (sd, 0)));
sim_module_uninstall (sd);
}
SIM_RC
sim_create_inferior (SIM_DESC sd, struct bfd *abfd, char **argv, char **envp)
{
SIM_CPU *current_cpu = STATE_CPU (sd, 0);
SIM_ADDR addr;
#ifndef PUSH_ENVIRONMENT_ONTO_STACK
envp = NULL;
#endif
#ifdef LOGGING
sim_io_eprintf (sd, "sim_create_inferior: %p\n", abfd);
dump (sd, argv, envp);
#endif
if (abfd != NULL)
{
int little_endian_p = bfd_little_endian (abfd);
if (little_endian_p)
{
if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN)
{
sim_io_eprintf (sd, "Target is big-endian but executable file %s is little-endian.\n",
bfd_get_filename (abfd));
return SIM_RC_FAIL;
}
}
else
{
if (CURRENT_TARGET_BYTE_ORDER == LITTLE_ENDIAN)
{
sim_io_eprintf (sd, "Target is little-endian but executable file %s is big-endian.\n",
bfd_get_filename(abfd));
return SIM_RC_FAIL;
}
}
addr = bfd_get_start_address (abfd);
}
else
addr = 0;
sim_pc_set (current_cpu, addr);
/* If the simulator is being used stand-alone, we have already set up the
stack (when sim_open was called); but if the simulator is being used by
gdb we must set up the stack each time that sim_create_inferior is
called, in case the program arguments have changed since last time. */
if (STATE_OPEN_KIND(sd) == SIM_OPEN_DEBUG)
{
struct sim_memory memory;
if (determine_memory_requirements (sd, abfd, argv, envp, &memory))
{
USI current_size = sd->memory.total_size;
if (memory.total_size > current_size)
{
#ifdef LOGGING
sim_io_eprintf (sd, "program requires memory size 0x%x bytes"
" but simulator currently has memory size 0x%x bytes\n",
memory.total_size, current_size);
#endif
/* Define another memory region to provide the extra memory
required. */
define_memory_region (sd, current_size,
memory.total_size - current_size);
/* Update all the memory details. */
sd->memory = memory;
}
else
{
/* Update all the memory details *except* the current size. */
sd->memory = memory;
sd->memory.total_size = current_size;
}
if (!setup_stack (sd, IS_LITTLE_ENDIAN (abfd), argv, envp))
return SIM_RC_FAIL;
}
else
return SIM_RC_FAIL;
}
current_cpu->endbrk = sd->memory.heap_start;
/* Set r28 (SP) to the stack top, and set r0/r1 to argc/argv. */
a5f_h_cr_set (current_cpu, 0, sd->memory.num_arguments);
a5f_h_cr_set (current_cpu, 1, sd->memory.stack_top + 4);
a5f_h_cr_set (current_cpu, 28, sd->memory.stack_top);
#ifdef LOGGING
sim_io_eprintf (sd, "R0 = 0x%08X\n", sd->memory.num_arguments);
sim_io_eprintf (sd, "R1 = 0x%08X\n", sd->memory.stack_top + 4);
sim_io_eprintf (sd, "SP = 0x%08X\n", sd->memory.stack_top);
#endif
#if 0
STATE_ARGV (sd) = sim_copy_argv (argv);
STATE_ENVP (sd) = sim_copy_argv (envp);
#endif
return SIM_RC_OK;
}
void
sim_do_command (SIM_DESC sd, char* cmd)
{
char **argv;
if (cmd == NULL)
return;
argv = buildargv (cmd);
/* Is the command 'info reg[ister] <name>' ? */
if (argv[0] != NULL
&& strcasecmp (argv[0], "info") == 0
&& argv[1] != NULL
&& strncasecmp (argv[1], "reg", 3) == 0)
{
SI val;
if (argv[2] == NULL)
sim_io_eprintf (sd, "Missing register in `%s'\n", cmd);
else if (argv[3] != NULL)
sim_io_eprintf (sd, "Too many arguments in `%s'\n", cmd);
/* Should we recognize some/all of the ARC register names here? */
else
sim_io_eprintf (sd, "Printing of register `%s' not supported with `sim info'\n",
argv[2]);
}
else
{
if (sim_args_command (sd, cmd) != SIM_RC_OK)
sim_io_eprintf (sd, "Unknown sim command `%s'\n", cmd);
}
freeargv (argv);
}
/******************************************************************************/