util: Pull most code out of m5.c.
authorGabe Black <gabeblack@google.com>
Sat, 4 Apr 2020 07:05:48 +0000 (00:05 -0700)
committerGabe Black <gabeblack@google.com>
Fri, 26 Jun 2020 02:36:48 +0000 (02:36 +0000)
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 <noreply+kokoro@google.com>
Reviewed-by: Gabe Black <gabeblack@google.com>
Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br>
Maintainer: Gabe Black <gabeblack@google.com>

16 files changed:
util/m5/src/SConscript
util/m5/src/addr_call_type.c
util/m5/src/addr_call_type.h
util/m5/src/args.c
util/m5/src/args.h
util/m5/src/call_type.c [new file with mode: 0644]
util/m5/src/call_type.h
util/m5/src/commands.c [new file with mode: 0644]
util/m5/src/commands.h [new file with mode: 0644]
util/m5/src/inst_call_type.c
util/m5/src/inst_call_type.h
util/m5/src/m5.c
util/m5/src/semi_call_type.c
util/m5/src/semi_call_type.h
util/m5/src/usage.c [new file with mode: 0644]
util/m5/src/usage.h [new file with mode: 0644]

index 1bf781c8b60c2dcf9f9aa8aec99d33feca5fedae..6e5cd6cda2328b8bbe42cc66b17ce0501679a9f6 100644 (file)
@@ -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.
index 0b3d1fcf43b65ca1d035bdfc72f4a0d46945c82b..6c6ebe22c95a718b056688344ea963db5711c081 100644 (file)
@@ -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.
index 6dcdb5bdbcad3ee863b6118093b46fed34edc878..33fdf02b3dae6be933b72873edfd5d1b7e99dbe8 100644 (file)
 #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__
index f1896c80c0ada92a91dbdb0f1bccacb5cda3241f..68753e9f78bbd782076511d77be0688a20d06fc9 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+#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++;
     }
index 530462e5cd48a46689d562548e52166e3c0a5e12..911db778629a1a4683bc928c6982fef2ad4d1039 100644 (file)
 #ifndef __ARGS_H__
 #define __ARGS_H__
 
+#include <stddef.h>
 #include <stdint.h>
 
-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 (file)
index 0000000..5792f07
--- /dev/null
@@ -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();
+}
index 17b1165bcddc85c054ad05e71d4f5eca76a9627e..7166670d39355dfaedeccff98f4561dc5df307ea 100644 (file)
 #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 (file)
index 0000000..8dd459c
--- /dev/null
@@ -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 <err.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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,        "<address> <symbol> // 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,             "<code> [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,       "<filename> [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 (file)
index 0000000..5d489ba
--- /dev/null
@@ -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__
index f4821fca61cf87c6532a177a35fa2b38f89a9889..98c1db2715cf1d1bcbe08ab617f6db47792497ef 100644 (file)
@@ -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;
index a20aee5ded49a42d2d52801c9b4bd43568fc962e..549a3dcd82ffb24c8444179d3ccd901e070a0495 100644 (file)
 #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__
index 644acd03378ed6384da30f904268e6b0fb4870ef..e4b187f5a50c5a67e0277cd1db8d9171066f9f83 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <err.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <gem5/asm/generic/m5ops.h>
-#include <gem5/m5ops.h>
 
 #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,        "<address> <symbol> // 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,             "<code> [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,       "<filename> [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] <command> [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
-            "<address override>",
-#   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();
 }
index f3d563083cd99db8e2ecbc921b49a9e4978d6505..d57e34805fa88a57e8d83e1669d6a818b66d8ff2 100644 (file)
@@ -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;
index 2f8f9c8ba727759a5e92dde94670371e010846c2..111ae218c1571672a3887ce920b837fbbcbc31dd 100644 (file)
 #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 (file)
index 0000000..822d9f0
--- /dev/null
@@ -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 <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "commands.h"
+#include "usage.h"
+
+const char *progname = "{progname}";
+
+void
+usage()
+{
+    fprintf(stderr, "Usage: %s [call type] <command> [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
+            "<address override>",
+#   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 (file)
index 0000000..d1e148d
--- /dev/null
@@ -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__