From f5b5090be16b00ff0503fa831eeed72e82be55c8 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 4 Apr 2020 00:05:48 -0700 Subject: [PATCH] util: Pull most code out of m5.c. By pulling the code out, this code can be tested by unit tests. Change-Id: I2d0510995d3e97d721f1de3024120f0c90b7a5ba Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/27547 Tested-by: kokoro Reviewed-by: Gabe Black Reviewed-by: Daniel Carvalho Maintainer: Gabe Black --- util/m5/src/SConscript | 8 +- util/m5/src/addr_call_type.c | 17 +- util/m5/src/addr_call_type.h | 3 +- util/m5/src/args.c | 24 +-- util/m5/src/args.h | 20 ++- util/m5/src/call_type.c | 64 +++++++ util/m5/src/call_type.h | 14 +- util/m5/src/commands.c | 257 +++++++++++++++++++++++++++ util/m5/src/commands.h | 52 ++++++ util/m5/src/inst_call_type.c | 7 +- util/m5/src/inst_call_type.h | 3 +- util/m5/src/m5.c | 325 ++--------------------------------- util/m5/src/semi_call_type.c | 7 +- util/m5/src/semi_call_type.h | 3 +- util/m5/src/usage.c | 88 ++++++++++ util/m5/src/usage.h | 48 ++++++ 16 files changed, 581 insertions(+), 359 deletions(-) create mode 100644 util/m5/src/call_type.c create mode 100644 util/m5/src/commands.c create mode 100644 util/m5/src/commands.h create mode 100644 util/m5/src/usage.c create mode 100644 util/m5/src/usage.h diff --git a/util/m5/src/SConscript b/util/m5/src/SConscript index 1bf781c8b..6e5cd6cda 100644 --- a/util/m5/src/SConscript +++ b/util/m5/src/SConscript @@ -28,9 +28,13 @@ import os Import('*') # Raw source files. -m5_mmap = 'm5_mmap.c' args = 'args.c' +call_type = 'call_type.c' +commands = 'commands.c' m5 = 'm5.c' +m5_mmap = 'm5_mmap.c' +usage = 'usage.c' + jni = 'jni_gem5Op.c' lua = 'lua_gem5Op.c' @@ -65,7 +69,7 @@ libm5 = static_env.StaticLibrary('out/m5', [ m5_mmap ] + m5ops) # ct_support = list([ File('%s_call_type.c' % ct.name) for ct in call_types ]) m5_bin = static_env.Program('out/m5', - ct_support + [ args, m5, m5_mmap, libm5 ]) + ct_support + [ args, call_type, commands, m5, m5_mmap, libm5, usage ]) # The shared version of the m5 op call sights, used by mutliple targets below. diff --git a/util/m5/src/addr_call_type.c b/util/m5/src/addr_call_type.c index 0b3d1fcf4..6c6ebe22c 100644 --- a/util/m5/src/addr_call_type.c +++ b/util/m5/src/addr_call_type.c @@ -42,17 +42,15 @@ M5OP_FOREACH }; int -addr_call_type_detect(int *argc, char **argv[]) +addr_call_type_detect(Args *args) { static const char *prefix = "--addr"; const size_t prefix_len = strlen(prefix); uint64_t addr_override; // If the first argument starts with --addr... - if (*argc > 0 && memcmp((*argv)[0], prefix, prefix_len) == 0) { - char *argv0 = (*argv)[0]; - (*argc)--; - (*argv)++; + if (args->argc && memcmp(args->argv[0], prefix, prefix_len) == 0) { + const char *argv0 = pop_arg(args); // If there's more text in this argument... if (strlen(argv0) != prefix_len) { @@ -60,8 +58,9 @@ addr_call_type_detect(int *argc, char **argv[]) if (argv0[prefix_len] != '=') return -1; // Attempt to extract an address after the '='. - char *temp_argv[] = { &argv0[prefix_len + 1] }; - if (!parse_int_args(1, temp_argv, &addr_override, 1)) + const char *temp_argv[] = { &argv0[prefix_len + 1] }; + Args temp_args = { 1, temp_argv }; + if (!parse_int_args(&temp_args, &addr_override, 1)) return -1; // If we found an address, use it to override m5op_addr. m5op_addr = addr_override; @@ -69,10 +68,8 @@ addr_call_type_detect(int *argc, char **argv[]) } // If an address override wasn't part of the first argument, check if // it's the second argument. If not, then there's no override. - if (*argc > 0 && parse_int_args(1, *argv, &addr_override, 1)) { + if (args->argc && parse_int_args(args, &addr_override, 1)) { m5op_addr = addr_override; - (*argc)--; - (*argv)++; return 1; } // If the default address was zero, an override is required. diff --git a/util/m5/src/addr_call_type.h b/util/m5/src/addr_call_type.h index 6dcdb5bdb..33fdf02b3 100644 --- a/util/m5/src/addr_call_type.h +++ b/util/m5/src/addr_call_type.h @@ -28,10 +28,11 @@ #ifndef __ADDR_CALL_TYPE_H__ #define __ADDR_CALL_TYPE_H__ +#include "args.h" #include "dispatch_table.h" // Returns 0 if not detected, 1 if detected successfully, and -1 on error. -int addr_call_type_detect(int *argc, char **argv[]); +int addr_call_type_detect(Args *args); DispatchTable *addr_call_type_init(); #endif // __ADDR_CALL_TYPE_H__ diff --git a/util/m5/src/args.c b/util/m5/src/args.c index f1896c80c..68753e9f7 100644 --- a/util/m5/src/args.c +++ b/util/m5/src/args.c @@ -42,10 +42,12 @@ #include #include +#include "args.h" + int -parse_int_args(int argc, char *argv[], uint64_t ints[], int len) +parse_int_args(Args *args, uint64_t ints[], int len) { - if (argc > len) + if (args->argc > len) return 0; // On 32 bit platforms we need to use strtoull to do the conversion @@ -54,31 +56,33 @@ parse_int_args(int argc, char *argv[], uint64_t ints[], int len) #else #define strto64 strtoull #endif - int i; - for (i = 0; i < len; ++i) - ints[i] = (i < argc) ? strto64(argv[i], NULL, 0) : 0; + for (int i = 0; i < len; ++i) { + const char *arg = pop_arg(args); + ints[i] = arg ? strto64(arg, NULL, 0) : 0; + } #undef strto64 return 1; } int -pack_str_into_regs(const char *str, uint64_t regs[], int num_regs) +pack_arg_into_regs(Args *args, uint64_t regs[], int num_regs) { const size_t RegSize = sizeof(regs[0]); const size_t MaxLen = num_regs * RegSize; + const char *arg = pop_arg(args); + + memset(regs, 0, MaxLen); - size_t len = strlen(str); + size_t len = arg ? strlen(arg) : 0; if (len > MaxLen) return 0; - memset(regs, 0, MaxLen); - while (len) { for (int offset = 0; offset < RegSize && len; offset++, len--) { int shift = offset * 8; - *regs |= (uint64_t)(uint8_t)*str++ << shift; + *regs |= (uint64_t)(uint8_t)*arg++ << shift; } regs++; } diff --git a/util/m5/src/args.h b/util/m5/src/args.h index 530462e5c..911db7786 100644 --- a/util/m5/src/args.h +++ b/util/m5/src/args.h @@ -41,9 +41,25 @@ #ifndef __ARGS_H__ #define __ARGS_H__ +#include #include -int parse_int_args(int argc, char *argv[], uint64_t ints[], int len); -int pack_str_into_regs(const char *str, uint64_t regs[], int num_regs); +typedef struct Args +{ + int argc; + const char **argv; +} Args; + +static inline const char * +pop_arg(Args *args) +{ + if (!args->argc) + return NULL; + args->argc--; + return (args->argv++)[0]; +} + +int parse_int_args(Args *args, uint64_t ints[], int len); +int pack_arg_into_regs(Args *args, uint64_t regs[], int num_regs); #endif // __ARGS_H__ diff --git a/util/m5/src/call_type.c b/util/m5/src/call_type.c new file mode 100644 index 000000000..5792f07a0 --- /dev/null +++ b/util/m5/src/call_type.c @@ -0,0 +1,64 @@ +/* + * Copyright 2020 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "args.h" +#include "call_type.h" +#include "usage.h" + +#if ENABLE_CT_addr +#include "addr_call_type.h" +#endif +#if ENABLE_CT_inst +#include "inst_call_type.h" +#endif +#if ENABLE_CT_semi +#include "semi_call_type.h" +#endif + +#define default_call_type_init() \ + M5OP_MERGE_TOKENS(DEFAULT_CALL_TYPE, _call_type_init()) + +DispatchTable * +init_call_type(Args *args) +{ +# if ENABLE_CT_inst + if (inst_call_type_detect(args)) + return inst_call_type_init(); +# endif +# if ENABLE_CT_addr + int detect = addr_call_type_detect(args); + if (detect < 0) + usage(); + if (detect > 0) + return addr_call_type_init(); +# endif +# if ENABLE_CT_semi + if (semi_call_type_detect(args)) + return semi_call_type_init(); +# endif + return default_call_type_init(); +} diff --git a/util/m5/src/call_type.h b/util/m5/src/call_type.h index 17b1165bc..7166670d3 100644 --- a/util/m5/src/call_type.h +++ b/util/m5/src/call_type.h @@ -28,19 +28,9 @@ #ifndef __CALL_TYPE_H__ #define __CALL_TYPE_H__ +#include "args.h" #include "dispatch_table.h" -#if ENABLE_CT_addr -#include "addr_call_type.h" -#endif -#if ENABLE_CT_inst -#include "inst_call_type.h" -#endif -#if ENABLE_CT_semi -#include "semi_call_type.h" -#endif - -#define default_call_type_init() \ - M5OP_MERGE_TOKENS(DEFAULT_CALL_TYPE, _call_type_init()) +DispatchTable *init_call_type(Args *args); #endif // __CALL_TYPE_H__ diff --git a/util/m5/src/commands.c b/util/m5/src/commands.c new file mode 100644 index 000000000..8dd459c29 --- /dev/null +++ b/util/m5/src/commands.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "args.h" +#include "commands.h" +#include "usage.h" + +static int +read_file(DispatchTable *dt, int dest_fid) +{ + uint8_t buf[256*1024]; + int offset = 0; + int len, ret; + + // Touch all buffer pages to ensure they are mapped in the + // page table. This is required in the case of X86_FS, where + // Linux does demand paging. + memset(buf, 0, sizeof(buf)); + + while ((len = (*dt->m5_read_file)(buf, sizeof(buf), offset)) > 0) { + uint8_t *base = buf; + offset += len; + do { + ret = write(dest_fid, base, len); + if (ret < 0) { + perror("Failed to write file"); + exit(2); + } else if (ret == 0) { + fprintf(stderr, "Failed to write file: " + "Unhandled short write\n"); + exit(2); + } + + base += ret; + len -= ret; + } while (len); + } + + return offset; +} + +static void +write_file(DispatchTable *dt, const char *filename, const char *host_filename) +{ + fprintf(stderr, "opening %s\n", filename); + int src_fid = open(filename, O_RDONLY); + + if (src_fid < 0) { + fprintf(stderr, "error opening %s\n", filename); + return; + } + + char buf[256*1024]; + int offset = 0; + int len; + int bytes = 0; + + memset(buf, 0, sizeof(buf)); + + while ((len = read(src_fid, buf, sizeof(buf))) > 0) { + bytes += (*dt->m5_write_file)(buf, len, offset, host_filename); + offset += len; + } + fprintf(stderr, "written %d bytes\n", bytes); + + close(src_fid); +} + +static void +do_exit(DispatchTable *dt, Args *args) +{ + if (args->argc > 1) + usage(); + + uint64_t ints[1]; + if (!parse_int_args(args, ints, 1)) + usage(); + (*dt->m5_exit)(ints[0]); +} + +static void +do_fail(DispatchTable *dt, Args *args) +{ + if (args->argc < 1 || args->argc > 2) + usage(); + + uint64_t ints[2] = { 0, 0 }; + if (!parse_int_args(args, ints, args->argc)) + usage(); + (*dt->m5_fail)(ints[1], ints[0]); +} + +static void +do_reset_stats(DispatchTable *dt, Args *args) +{ + uint64_t ints[2]; + if (!parse_int_args(args, ints, 2)) + usage(); + (*dt->m5_reset_stats)(ints[0], ints[1]); +} + +static void +do_dump_stats(DispatchTable *dt, Args *args) +{ + uint64_t ints[2]; + if (!parse_int_args(args, ints, 2)) + usage(); + (*dt->m5_dump_stats)(ints[0], ints[1]); +} + +static void +do_dump_reset_stats(DispatchTable *dt, Args *args) +{ + uint64_t ints[2]; + if (!parse_int_args(args, ints, 2)) + usage(); + (*dt->m5_dump_reset_stats)(ints[0], ints[1]); +} + +static void +do_read_file(DispatchTable *dt, Args *args) +{ + if (args->argc > 0) + usage(); + + read_file(dt, STDOUT_FILENO); +} + +static void +do_write_file(DispatchTable *dt, Args *args) +{ + if (args->argc != 1 && args->argc != 2) + usage(); + + const char *filename = pop_arg(args); + const char *host_filename = pop_arg(args); + if (!host_filename) + host_filename = filename; + + write_file(dt, filename, host_filename); +} + +static void +do_checkpoint(DispatchTable *dt, Args *args) +{ + uint64_t ints[2]; + if (!parse_int_args(args, ints, 2)) + usage(); + (*dt->m5_checkpoint)(ints[0], ints[1]); +} + +static void +do_addsymbol(DispatchTable *dt, Args *args) +{ + if (args->argc != 2) + usage(); + + uint64_t addr = strtoul(pop_arg(args), NULL, 0); + const char *symbol = pop_arg(args); + (*dt->m5_add_symbol)(addr, symbol); +} + + +static void +do_loadsymbol(DispatchTable *dt, Args *args) +{ + if (args->argc > 0) + usage(); + + (*dt->m5_load_symbol)(); +} + +static void +do_initparam(DispatchTable *dt, Args *args) +{ + if (args->argc > 1) + usage(); + + uint64_t key_str[2]; + if (!pack_arg_into_regs(args, key_str, 2)) + usage(); + uint64_t val = (*dt->m5_init_param)(key_str[0], key_str[1]); + printf("%"PRIu64, val); +} + +struct CommandInfo command_table[] = { + { "addsymbol", do_addsymbol, "
// Adds a " + "symbol with address \"address\" " + "to gem5's symbol table" }, + { "checkpoint", do_checkpoint, "[delay [period]] // After " + "delay (default 0) take a " + "checkpoint, and then optionally " + "every period after" }, + { "dumpresetstats", do_dump_reset_stats, "[delay [period]] // After " + "delay (default 0) dump and " + "reset the stats, and then " + "optionally every period after" }, + { "dumpstats", do_dump_stats, "[delay [period]] // After " + "delay (default 0) dump the " + "stats, and then optionally " + "every period after" }, + { "exit", do_exit, "[delay] // Exit after delay, " + "or immediately" }, + { "fail", do_fail, " [delay] // Exit with " + "failure code code after delay, " + "or immediately" }, + { "initparam", do_initparam, "[key] // optional key may be at " + "most 16 characters long" }, + { "loadsymbol", do_loadsymbol, "load a preselected symbol file " + "into gem5's symbol table" }, + { "readfile", do_read_file, "read a preselected file from " + "the host and write it to " + "stdout" }, + { "resetstats", do_reset_stats, "[delay [period]] // After " + "delay (default 0) reset the " + "stats, and then optionally " + "every period after" }, + { "writefile", do_write_file, " [host filename] // " + "Write a file to the host, " + "optionally with a different " + "name" }, +}; + +int num_commands = sizeof(command_table) / sizeof(CommandInfo); diff --git a/util/m5/src/commands.h b/util/m5/src/commands.h new file mode 100644 index 000000000..5d489ba81 --- /dev/null +++ b/util/m5/src/commands.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __COMMANDS_H__ +#define __COMMANDS_H__ + +#include "args.h" +#include "dispatch_table.h" + +typedef struct CommandInfo +{ + // The name of the command. + char *name; + // A function which processes command line arguments and passes them to + // the underlying function through the dispatch table. + void (*func)(DispatchTable *dt, Args *args); + // Help text for this command. + char *usage; +} CommandInfo; + +// The commands themselves. +extern CommandInfo command_table[]; + +// The number of commands. +extern int num_commands; + +#endif // __COMMANDS_H__ diff --git a/util/m5/src/inst_call_type.c b/util/m5/src/inst_call_type.c index f4821fca6..98c1db271 100644 --- a/util/m5/src/inst_call_type.c +++ b/util/m5/src/inst_call_type.c @@ -36,11 +36,10 @@ M5OP_FOREACH }; int -inst_call_type_detect(int *argc, char **argv[]) +inst_call_type_detect(Args *args) { - if (*argc > 0 && strcmp((*argv)[0], "--inst") == 0) { - (*argc)--; - (*argv)++; + if (args->argc && strcmp(args->argv[0], "--inst") == 0) { + pop_arg(args); return 1; } return 0; diff --git a/util/m5/src/inst_call_type.h b/util/m5/src/inst_call_type.h index a20aee5de..549a3dcd8 100644 --- a/util/m5/src/inst_call_type.h +++ b/util/m5/src/inst_call_type.h @@ -28,9 +28,10 @@ #ifndef __INST_CALL_TYPE_H__ #define __INST_CALL_TYPE_H__ +#include "args.h" #include "dispatch_table.h" -int inst_call_type_detect(int *argc, char **argv[]); +int inst_call_type_detect(Args *args); DispatchTable *inst_call_type_init(); #endif // __INST_CALL_TYPE_H__ diff --git a/util/m5/src/m5.c b/util/m5/src/m5.c index 644acd033..e4b187f5a 100644 --- a/util/m5/src/m5.c +++ b/util/m5/src/m5.c @@ -38,337 +38,38 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include -#include -#include #include #include -#include -#include -#include -#include - -#include -#include #include "args.h" #include "call_type.h" -#include "dispatch_table.h" -#include "m5_mmap.h" - -char *progname; -char *command = "unspecified"; -void usage(); +#include "commands.h" +#include "usage.h" int -read_file(DispatchTable *dt, int dest_fid) -{ - uint8_t buf[256*1024]; - int offset = 0; - int len, ret; - - // Touch all buffer pages to ensure they are mapped in the - // page table. This is required in the case of X86_FS, where - // Linux does demand paging. - memset(buf, 0, sizeof(buf)); - - while ((len = (*dt->m5_read_file)(buf, sizeof(buf), offset)) > 0) { - uint8_t *base = buf; - offset += len; - do { - ret = write(dest_fid, base, len); - if (ret < 0) { - perror("Failed to write file"); - exit(2); - } else if (ret == 0) { - fprintf(stderr, "Failed to write file: " - "Unhandled short write\n"); - exit(2); - } - - base += ret; - len -= ret; - } while (len); - } - - return offset; -} - -void -write_file(DispatchTable *dt, const char *filename, const char *host_filename) -{ - fprintf(stderr, "opening %s\n", filename); - int src_fid = open(filename, O_RDONLY); - - if (src_fid < 0) { - fprintf(stderr, "error opening %s\n", filename); - return; - } - - char buf[256*1024]; - int offset = 0; - int len; - int bytes = 0; - - memset(buf, 0, sizeof(buf)); - - while ((len = read(src_fid, buf, sizeof(buf))) > 0) { - bytes += (*dt->m5_write_file)(buf, len, offset, host_filename); - offset += len; - } - fprintf(stderr, "written %d bytes\n", bytes); - - close(src_fid); -} - -void -do_exit(DispatchTable *dt, int argc, char *argv[]) -{ - if (argc > 1) - usage(); - - uint64_t ints[1]; - if (!parse_int_args(argc, argv, ints, 1)) - usage(); - (*dt->m5_exit)(ints[0]); -} - -void -do_fail(DispatchTable *dt, int argc, char *argv[]) -{ - if (argc < 1 || argc > 2) - usage(); - - uint64_t ints[2] = {0,0}; - if (!parse_int_args(argc, argv, ints, argc)) - usage(); - (*dt->m5_fail)(ints[1], ints[0]); -} - -void -do_reset_stats(DispatchTable *dt, int argc, char *argv[]) -{ - uint64_t ints[2]; - if (!parse_int_args(argc, argv, ints, 2)) - usage(); - (*dt->m5_reset_stats)(ints[0], ints[1]); -} - -void -do_dump_stats(DispatchTable *dt, int argc, char *argv[]) -{ - uint64_t ints[2]; - if (!parse_int_args(argc, argv, ints, 2)) - usage(); - (*dt->m5_dump_stats)(ints[0], ints[1]); -} - -void -do_dump_reset_stats(DispatchTable *dt, int argc, char *argv[]) -{ - uint64_t ints[2]; - if (!parse_int_args(argc, argv, ints, 2)) - usage(); - (*dt->m5_dump_reset_stats)(ints[0], ints[1]); -} - -void -do_read_file(DispatchTable *dt, int argc, char *argv[]) -{ - if (argc > 0) - usage(); - - read_file(dt, STDOUT_FILENO); -} - -void -do_write_file(DispatchTable *dt, int argc, char *argv[]) -{ - if (argc != 1 && argc != 2) - usage(); - - const char *filename = argv[0]; - const char *host_filename = (argc == 2) ? argv[1] : argv[0]; - - write_file(dt, filename, host_filename); -} - -void -do_checkpoint(DispatchTable *dt, int argc, char *argv[]) +main(int argc, const char *argv[]) { - uint64_t ints[2]; - if (!parse_int_args(argc, argv, ints, 2)) - usage(); - (*dt->m5_checkpoint)(ints[0], ints[1]); -} + Args args = { argc, argv }; -void -do_addsymbol(DispatchTable *dt, int argc, char *argv[]) -{ - if (argc != 2) + if (!args.argc) usage(); - uint64_t addr = strtoul(argv[0], NULL, 0); - char *symbol = argv[1]; - (*dt->m5_add_symbol)(addr, symbol); -} + progname = pop_arg(&args); + DispatchTable *dt = init_call_type(&args); -void -do_loadsymbol(DispatchTable *dt, int argc, char *argv[]) -{ - if (argc > 0) - usage(); - - (*dt->m5_load_symbol)(); -} + const char *command = pop_arg(&args); -void -do_initparam(DispatchTable *dt, int argc, char *argv[]) -{ - if (argc > 1) + if (!command) usage(); - uint64_t key_str[2]; - if (!pack_str_into_regs(argc == 0 ? "" : argv[0], key_str, 2)) - usage(); - uint64_t val = (*dt->m5_init_param)(key_str[0], key_str[1]); - printf("%"PRIu64, val); -} - -struct MainFunc -{ - char *name; - void (*func)(DispatchTable *dt, int argc, char *argv[]); - char *usage; -}; - -struct MainFunc mainfuncs[] = { - { "addsymbol", do_addsymbol, "
// Adds a " - "symbol with address \"address\" " - "to gem5's symbol table" }, - { "checkpoint", do_checkpoint, "[delay [period]] // After " - "delay (default 0) take a " - "checkpoint, and then optionally " - "every period after" }, - { "dumpresetstats", do_dump_reset_stats, "[delay [period]] // After " - "delay (default 0) dump and " - "reset the stats, and then " - "optionally every period after" }, - { "dumpstats", do_dump_stats, "[delay [period]] // After " - "delay (default 0) dump the " - "stats, and then optionally " - "every period after" }, - { "exit", do_exit, "[delay] // Exit after delay, " - "or immediately" }, - { "fail", do_fail, " [delay] // Exit with " - "failure code code after delay, " - "or immediately" }, - { "initparam", do_initparam, "[key] // optional key may be at " - "most 16 characters long" }, - { "loadsymbol", do_loadsymbol, "load a preselected symbol file " - "into gem5's symbol table" }, - { "readfile", do_read_file, "read a preselected file from " - "the host and write it to " - "stdout" }, - { "resetstats", do_reset_stats, "[delay [period]] // After " - "delay (default 0) reset the " - "stats, and then optionally " - "every period after" }, - { "writefile", do_write_file, " [host filename] // " - "Write a file to the host, " - "optionally with a different " - "name" }, -}; -int numfuncs = sizeof(mainfuncs) / sizeof(mainfuncs[0]); - -void -usage() -{ - fprintf(stderr, "Usage: %s [call type] [arguments]\n", progname); - fprintf(stderr, "\n"); - fprintf(stderr, "Call types:\n"); -# if ENABLE_CT_addr - fprintf(stderr, " --addr %s%s\n", -# if defined(M5OP_ADDR) - "[address override]", -# else - "
", -# endif - DEFAULT_CT_addr ? " (default)" : ""); - fprintf(stderr, " Use the address based invocation method.\n"); -# if defined(M5OP_ADDR) - fprintf(stderr, " The default address is %#"PRIx64".\n", - (uint64_t)M5OP_ADDR); -# endif -# endif -# if ENABLE_CT_inst - fprintf(stderr, " --inst%s\n", DEFAULT_CT_inst ? " (default)" : ""); - fprintf(stderr, " Use the instruction based invocation method.\n"); -# endif -# if ENABLE_CT_semi - fprintf(stderr, " --semi%s\n", DEFAULT_CT_semi ? " (default)" : ""); - fprintf(stderr, " Use the semi-hosting based invocation method.\n"); -# endif - fprintf(stderr, "\n"); - fprintf(stderr, "Commands:\n"); - for (int i = 0; i < numfuncs; ++i) - fprintf(stderr, " %s %s\n", mainfuncs[i].name, mainfuncs[i].usage); - fprintf(stderr, "\n"); - fprintf(stderr, "All times in nanoseconds!\n"); - - exit(1); -} - -int -main(int argc, char *argv[]) -{ - progname = argv[0]; - - argv++; - argc--; - - DispatchTable *dt = NULL; - -# if ENABLE_CT_inst - if (!dt && inst_call_type_detect(&argc, &argv)) { - dt = inst_call_type_init(); - } -# endif -# if ENABLE_CT_addr - if (!dt) { - int detect = addr_call_type_detect(&argc, &argv); - if (detect < 0) - usage(); - if (detect > 0) - dt = addr_call_type_init(); - } -# endif -# if ENABLE_CT_semi - if (!dt && semi_call_type_detect(&argc, &argv)) { - dt = semi_call_type_init(); - } -# endif - if (!dt) - dt = default_call_type_init(); - - if (!argc) - usage(1); - - command = argv[0]; - - argv++; - argc--; - - int i; - for (i = 0; i < numfuncs; ++i) { - if (strcmp(command, mainfuncs[i].name) != 0) + for (int i = 0; i < num_commands; ++i) { + if (strcmp(command, command_table[i].name) != 0) continue; - mainfuncs[i].func(dt, argc, argv); + command_table[i].func(dt, &args); exit(0); } - usage(1); + usage(); } diff --git a/util/m5/src/semi_call_type.c b/util/m5/src/semi_call_type.c index f3d563083..d57e34805 100644 --- a/util/m5/src/semi_call_type.c +++ b/util/m5/src/semi_call_type.c @@ -40,11 +40,10 @@ M5OP_FOREACH }; int -semi_call_type_detect(int *argc, char **argv[]) +semi_call_type_detect(Args *args) { - if (*argc > 0 && strcmp((*argv)[0], "--semi") == 0) { - (*argc)--; - (*argv)++; + if (args->argc && strcmp(args->argv[0], "--semi") == 0) { + pop_arg(args); return 1; } return 0; diff --git a/util/m5/src/semi_call_type.h b/util/m5/src/semi_call_type.h index 2f8f9c8ba..111ae218c 100644 --- a/util/m5/src/semi_call_type.h +++ b/util/m5/src/semi_call_type.h @@ -28,9 +28,10 @@ #ifndef __SEMI_CALL_TYPE_H__ #define __SEMI_CALL_TYPE_H__ +#include "args.h" #include "dispatch_table.h" -int semi_call_type_detect(int *argc, char **argv[]); +int semi_call_type_detect(Args *args); DispatchTable *semi_call_type_init(); #endif // __SEMI_CALL_TYPE_H__ diff --git a/util/m5/src/usage.c b/util/m5/src/usage.c new file mode 100644 index 000000000..822d9f0a7 --- /dev/null +++ b/util/m5/src/usage.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011, 2017 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "commands.h" +#include "usage.h" + +const char *progname = "{progname}"; + +void +usage() +{ + fprintf(stderr, "Usage: %s [call type] [arguments]\n", progname); + fprintf(stderr, "\n"); + fprintf(stderr, "Call types:\n"); +# if ENABLE_CT_addr + fprintf(stderr, " --addr %s%s\n", +# if defined(M5OP_ADDR) + "[address override]", +# else + "
", +# endif + DEFAULT_CT_addr ? " (default)" : ""); + fprintf(stderr, " Use the address based invocation method.\n"); +# if defined(M5OP_ADDR) + fprintf(stderr, " The default address is %#"PRIx64".\n", + (uint64_t)M5OP_ADDR); +# endif +# endif +# if ENABLE_CT_inst + fprintf(stderr, " --inst%s\n", DEFAULT_CT_inst ? " (default)" : ""); + fprintf(stderr, " Use the instruction based invocation method.\n"); +# endif +# if ENABLE_CT_semi + fprintf(stderr, " --semi%s\n", DEFAULT_CT_semi ? " (default)" : ""); + fprintf(stderr, " Use the semi-hosting based invocation method.\n"); +# endif + fprintf(stderr, "\n"); + fprintf(stderr, "Commands:\n"); + for (int i = 0; i < num_commands; ++i) { + fprintf(stderr, " %s %s\n", + command_table[i].name, command_table[i].usage); + } + fprintf(stderr, "\n"); + fprintf(stderr, "All times in nanoseconds!\n"); + + exit(1); +} diff --git a/util/m5/src/usage.h b/util/m5/src/usage.h new file mode 100644 index 000000000..d1e148d83 --- /dev/null +++ b/util/m5/src/usage.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011, 2017 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __USAGE_H__ +#define __USAGE_H__ + +extern const char *progname; + +void usage(); + +#endif // __USAGE_H__ -- 2.30.2