diff options
Diffstat (limited to 'sim/common/sim-memopt.c')
-rw-r--r-- | sim/common/sim-memopt.c | 471 |
1 files changed, 471 insertions, 0 deletions
diff --git a/sim/common/sim-memopt.c b/sim/common/sim-memopt.c new file mode 100644 index 0000000..be52a66 --- /dev/null +++ b/sim/common/sim-memopt.c @@ -0,0 +1,471 @@ +/* Simulator memory option handling. + Copyright (C) 1996-1999 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +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. */ + +#include "sim-main.h" +#include "sim-assert.h" +#include "sim-options.h" + +#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 + +/* Memory fill byte */ +static unsigned8 fill_byte_value; +static int fill_byte_flag = 0; + +/* Memory command line options. */ + +enum { + OPTION_MEMORY_DELETE = OPTION_START, + OPTION_MEMORY_REGION, + OPTION_MEMORY_SIZE, + OPTION_MEMORY_INFO, + OPTION_MEMORY_ALIAS, + OPTION_MEMORY_CLEAR, + OPTION_MEMORY_FILL +}; + +static DECLARE_OPTION_HANDLER (memory_option_handler); + +static const OPTION memory_options[] = +{ + { {"memory-delete", required_argument, NULL, OPTION_MEMORY_DELETE }, + '\0', "ADDRESS|all", "Delete memory at ADDRESS (all addresses)", + memory_option_handler }, + { {"delete-memory", required_argument, NULL, OPTION_MEMORY_DELETE }, + '\0', "ADDRESS", NULL, + memory_option_handler }, + + { {"memory-region", required_argument, NULL, OPTION_MEMORY_REGION }, + '\0', "ADDRESS,SIZE[,MODULO]", "Add a memory region", + memory_option_handler }, + + { {"memory-alias", required_argument, NULL, OPTION_MEMORY_ALIAS }, + '\0', "ADDRESS,SIZE{,ADDRESS}", "Add memory shadow", + memory_option_handler }, + + { {"memory-size", required_argument, NULL, OPTION_MEMORY_SIZE }, + '\0', "SIZE", "Add memory at address zero", + memory_option_handler }, + + { {"memory-fill", required_argument, NULL, OPTION_MEMORY_FILL }, + '\0', "VALUE", "Fill subsequently added memory regions", + memory_option_handler }, + + { {"memory-clear", no_argument, NULL, OPTION_MEMORY_CLEAR }, + '\0', NULL, "Clear subsequently added memory regions", + memory_option_handler }, + + { {"memory-info", no_argument, NULL, OPTION_MEMORY_INFO }, + '\0', NULL, "List configurable memory regions", + memory_option_handler }, + { {"info-memory", no_argument, NULL, OPTION_MEMORY_INFO }, + '\0', NULL, NULL, + memory_option_handler }, + + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } +}; + + +static sim_memopt * +do_memopt_add (SIM_DESC sd, + int level, + int space, + address_word addr, + address_word nr_bytes, + unsigned modulo, + sim_memopt **entry, + void *buffer) +{ + void *fill_buffer; + unsigned fill_length; + void *free_buffer; + + if (buffer != NULL) + { + /* Buffer already given. sim_memory_uninstall will free it. */ + sim_core_attach (sd, NULL, + level, access_read_write_exec, space, + addr, nr_bytes, modulo, NULL, buffer); + + free_buffer = buffer; + fill_buffer = buffer; + fill_length = (modulo == 0) ? nr_bytes : modulo; + } + else + { + /* Allocate new well-aligned buffer, just as sim_core_attach(). */ + void *aligned_buffer; + int padding = (addr % sizeof (unsigned64)); + unsigned long bytes = (modulo == 0 ? nr_bytes : modulo) + padding; + + /* If filling with non-zero value, do not use clearing allocator. */ + + if (fill_byte_flag && fill_byte_value != 0) + free_buffer = xmalloc (bytes); /* don't clear */ + else + free_buffer = zalloc (bytes); /* clear */ + + aligned_buffer = (char*) free_buffer + padding; + + sim_core_attach (sd, NULL, + level, access_read_write_exec, space, + addr, nr_bytes, modulo, NULL, aligned_buffer); + + fill_buffer = aligned_buffer; + fill_length = (modulo == 0) ? nr_bytes : modulo; + + /* If we just used a clearing allocator, and are about to fill with + zero, truncate the redundant fill operation. */ + + if (fill_byte_flag && fill_byte_value == 0) + fill_length = 1; /* avoid boundary length=0 case */ + } + + if (fill_byte_flag) + { + ASSERT (fill_buffer != 0); + memset ((char*) fill_buffer, fill_byte_value, fill_length); + } + + while ((*entry) != NULL) + entry = &(*entry)->next; + (*entry) = ZALLOC (sim_memopt); + (*entry)->level = level; + (*entry)->space = space; + (*entry)->addr = addr; + (*entry)->nr_bytes = nr_bytes; + (*entry)->modulo = modulo; + (*entry)->buffer = free_buffer; + + return (*entry); +} + +static SIM_RC +do_memopt_delete (SIM_DESC sd, + int level, + int space, + address_word addr) +{ + sim_memopt **entry = &STATE_MEMOPT (sd); + sim_memopt *alias; + while ((*entry) != NULL + && ((*entry)->level != level + || (*entry)->space != space + || (*entry)->addr != addr)) + entry = &(*entry)->next; + if ((*entry) == NULL) + { + sim_io_eprintf (sd, "Memory at 0x%lx not found, not deleted\n", + (long) addr); + return SIM_RC_FAIL; + } + /* delete any buffer */ + if ((*entry)->buffer != NULL) + zfree ((*entry)->buffer); + /* delete it and its aliases */ + alias = *entry; + *entry = (*entry)->next; + while (alias != NULL) + { + sim_memopt *dead = alias; + alias = alias->alias; + sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr); + zfree (dead); + } + return SIM_RC_OK; +} + + +static char * +parse_size (char *chp, + address_word *nr_bytes, + unsigned *modulo) +{ + /* <nr_bytes> [ "%" <modulo> ] */ + *nr_bytes = strtoul (chp, &chp, 0); + if (*chp == '%') + { + *modulo = strtoul (chp + 1, &chp, 0); + } + return chp; +} + +static char * +parse_ulong_value (char *chp, + unsigned long *value) +{ + *value = strtoul (chp, &chp, 0); + return chp; +} + +static char * +parse_addr (char *chp, + int *level, + int *space, + address_word *addr) +{ + /* [ <space> ": " ] <addr> [ "@" <level> ] */ + *addr = (unsigned long) strtoul (chp, &chp, 0); + if (*chp == ':') + { + *space = *addr; + *addr = (unsigned long) strtoul (chp + 1, &chp, 0); + } + if (*chp == '@') + { + *level = strtoul (chp + 1, &chp, 0); + } + return chp; +} + + +static SIM_RC +memory_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, + char *arg, int is_command) +{ + switch (opt) + { + + case OPTION_MEMORY_DELETE: + if (strcasecmp (arg, "all") == 0) + { + while (STATE_MEMOPT (sd) != NULL) + do_memopt_delete (sd, + STATE_MEMOPT (sd)->level, + STATE_MEMOPT (sd)->space, + STATE_MEMOPT (sd)->addr); + return SIM_RC_OK; + } + else + { + int level = 0; + int space = 0; + address_word addr = 0; + parse_addr (arg, &level, &space, &addr); + return do_memopt_delete (sd, level, space, addr); + } + + case OPTION_MEMORY_REGION: + { + char *chp = arg; + int level = 0; + int space = 0; + address_word addr = 0; + address_word nr_bytes = 0; + unsigned modulo = 0; + /* parse the arguments */ + chp = parse_addr (chp, &level, &space, &addr); + if (*chp != ',') + { + sim_io_eprintf (sd, "Missing size for memory-region\n"); + return SIM_RC_FAIL; + } + chp = parse_size (chp + 1, &nr_bytes, &modulo); + /* old style */ + if (*chp == ',') + modulo = strtoul (chp + 1, &chp, 0); + /* try to attach/insert it */ + do_memopt_add (sd, level, space, addr, nr_bytes, modulo, + &STATE_MEMOPT (sd), NULL); + return SIM_RC_OK; + } + + case OPTION_MEMORY_ALIAS: + { + char *chp = arg; + int level = 0; + int space = 0; + address_word addr = 0; + address_word nr_bytes = 0; + unsigned modulo = 0; + sim_memopt *entry; + /* parse the arguments */ + chp = parse_addr (chp, &level, &space, &addr); + if (*chp != ',') + { + sim_io_eprintf (sd, "Missing size for memory-region\n"); + return SIM_RC_FAIL; + } + chp = parse_size (chp + 1, &nr_bytes, &modulo); + /* try to attach/insert the main record */ + entry = do_memopt_add (sd, level, space, addr, nr_bytes, modulo, + &STATE_MEMOPT (sd), + NULL); + /* now attach all the aliases */ + while (*chp == ',') + { + int a_level = level; + int a_space = space; + address_word a_addr = addr; + chp = parse_addr (chp + 1, &a_level, &a_space, &a_addr); + do_memopt_add (sd, a_level, a_space, a_addr, nr_bytes, modulo, + &entry->alias, entry->buffer); + } + return SIM_RC_OK; + } + + case OPTION_MEMORY_SIZE: + { + int level = 0; + int space = 0; + address_word addr = 0; + address_word nr_bytes = 0; + unsigned modulo = 0; + /* parse the arguments */ + parse_size (arg, &nr_bytes, &modulo); + /* try to attach/insert it */ + do_memopt_add (sd, level, space, addr, nr_bytes, modulo, + &STATE_MEMOPT (sd), NULL); + return SIM_RC_OK; + } + + case OPTION_MEMORY_CLEAR: + { + fill_byte_value = (unsigned8) 0; + fill_byte_flag = 1; + return SIM_RC_OK; + break; + } + + case OPTION_MEMORY_FILL: + { + unsigned long fill_value; + parse_ulong_value (arg, &fill_value); + if (fill_value > 255) + { + sim_io_eprintf (sd, "Missing fill value between 0 and 255\n"); + return SIM_RC_FAIL; + } + fill_byte_value = (unsigned8) fill_value; + fill_byte_flag = 1; + return SIM_RC_OK; + break; + } + + case OPTION_MEMORY_INFO: + { + sim_memopt *entry; + sim_io_printf (sd, "Memory maps:\n"); + for (entry = STATE_MEMOPT (sd); entry != NULL; entry = entry->next) + { + sim_memopt *alias; + sim_io_printf (sd, " memory"); + if (entry->alias == NULL) + sim_io_printf (sd, " region "); + else + sim_io_printf (sd, " alias "); + if (entry->space != 0) + sim_io_printf (sd, "0x%lx:", (long) entry->space); + sim_io_printf (sd, "0x%08lx", (long) entry->addr); + if (entry->level != 0) + sim_io_printf (sd, "@0x%lx", (long) entry->level); + sim_io_printf (sd, ",0x%lx", + (long) entry->nr_bytes); + if (entry->modulo != 0) + sim_io_printf (sd, "%%0x%lx", (long) entry->modulo); + for (alias = entry->alias; + alias != NULL; + alias = alias->next) + { + if (alias->space != 0) + sim_io_printf (sd, "0x%lx:", (long) alias->space); + sim_io_printf (sd, ",0x%08lx", (long) alias->addr); + if (alias->level != 0) + sim_io_printf (sd, "@0x%lx", (long) alias->level); + } + sim_io_printf (sd, "\n"); + } + return SIM_RC_OK; + break; + } + + default: + sim_io_eprintf (sd, "Unknown memory option %d\n", opt); + return SIM_RC_FAIL; + + } + + return SIM_RC_FAIL; +} + + +/* "memory" module install handler. + + This is called via sim_module_install to install the "memory" subsystem + into the simulator. */ + +static MODULE_INIT_FN sim_memory_init; +static MODULE_UNINSTALL_FN sim_memory_uninstall; + +SIM_RC +sim_memopt_install (SIM_DESC sd) +{ + SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); + sim_add_option_table (sd, NULL, memory_options); + sim_module_add_uninstall_fn (sd, sim_memory_uninstall); + sim_module_add_init_fn (sd, sim_memory_init); + return SIM_RC_OK; +} + + +/* Uninstall the "memory" subsystem from the simulator. */ + +static void +sim_memory_uninstall (SIM_DESC sd) +{ + sim_memopt **entry = &STATE_MEMOPT (sd); + sim_memopt *alias; + + while ((*entry) != NULL) + { + /* delete any buffer */ + if ((*entry)->buffer != NULL) + zfree ((*entry)->buffer); + + /* delete it and its aliases */ + alias = *entry; + while (alias != NULL) + { + sim_memopt *dead = alias; + alias = alias->alias; + sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr); + zfree (dead); + } + + /* next victim */ + *entry = (*entry)->next; + } +} + + +static SIM_RC +sim_memory_init (SIM_DESC sd) +{ + /* FIXME: anything needed? */ + return SIM_RC_OK; +} |