Previous - Up - Next

7.2   Example of a new command

This is an example on how to add a command in Python, as it would appear in the commands.py file of a module's source code subdirectory:

# this line imports definitions needed below
from cli import *

# this is my Python function that will be called when the
# command is invoked from the Simics prompt.
def my_command_fun(int_arg, str_arg, flag_arg):
    print "My integer: %d" % int_arg
    print "My string: %s" % str_arg
    print "Flag is",
    if flag_arg:
        print "given"
    else:
        print "not given"
    return int_arg

# register our new command
new_command("my-command", my_command_fun,
            args  = [arg(int_t, "arg", "?", 10), arg(str_t, "name"),
                     arg(flag_t, "-f")],
            alias = "mc",
            type  = "my-module-commands",
            short = "my command does it",
            doc_items = [("NOTE", "This command is best")],
            see_also = ["my_other_command"],
            doc = """
<b>my-command</b> is best.
This is its documentation. <i>arg</i>
is the first argument...""")

The code above will define a command called my-command. When the command is invoked from the Simics command line interface, the function my_command_fun() will be called. The function must take exactly as many arguments as the command; in this case 3: an integer, a string, and a flag. The first command argument is called "arg" and is optional, indicated by "?". If omitted by the user, the command function will be called with the default value, 10. The second argument is called "name" and is required (since there is no "?", there is no default value). The last argument is a flag and will have a value of 1 if the flag is given, otherwise 0. Flags are thus always optional.

If the command function returns a value (a string or an integer) Simics will print this value on the terminal or pass it on to other commands as input arguments, e.g., print -x (my-command 15 foo).

Writing help my-command at the Simics prompt will display:

NAME
   my-command - my command does it
SYNOPSIS
   my-command [arg] name [-f]
ALIAS
   mc
DESCRIPTION
   my-command is best. This is its documentation. arg is the first argument.
NOTE
   This command is best
SEE ALSO
   my_other_command

The command can be invoked in different ways, here are some examples:

simics> my-command 2 foo -f
My integer: 2
My string: foo
Flag is given
2
simics> my-command bar
My integer: 10
My string: bar
Flag is not given
10
simics> my-command 20 -f
Argument error: argument number 2 is missing in 'my-command', string expected.
SYNOPSIS: my-command [arg] name [-f]
simics> print -x (mc -f name="hello there!" arg = 23)
My integer: 23
My string: hello there!
Flag is given
0x17

In the last case the alias is used and the command is passed to the print command that outputs the value in hexadecimal notation.

All the parameters of the new_command() function will be explained bellow. After the parameter name follows the type of the parameter and if the argument is required, recommended, or optional:

name — string (required)
First argument (no need to write name =) and the name of the command. May include digits and underscores as well as dashes. Must begin with a letter.
fun — function (required)
The command handler function that will be called when the command is executed. The number of arguments must match the args-list(see below). Since new_command is executed when the commands.py file is loaded into Python the function must be defined before the new_command call, as in the example.
args — list of argument specifiers (required)
This is a list of the arguments given to the command, and must match the arguments of the function described above. An argument specifier is created by calling the function arg(). This function takes as arguments a type (this is in fact also a function), that is called to handle the argument. Examples of available types are int_t, str_t, addr_t, filename_t(), and flag_t. See the next section for a discussion of these.

To create an argument list of an integer and a string, use:

..., args = [arg(int_t), arg(str_t)], ...

It is, however, recommended that names for the parameters are specified. This is done as a second argument for arg():

..., args = [arg(int_t, "value"), arg(str_t, "file")], ...

This way the documentation of the argument list (help command) will use these names and also makes it possible to enter the argument in any order at the command line, e.g.,

command file = "/tmp/bar" value = 17

The flag type requires the name to be specified and the name must begin with a hyphen, e.g., "–all". The corresponding value passed to the command handler function will be 1 if the flag is given on the command line or 0 otherwise.

The addr type can be used for addresses. It understands argument of the form p:0xcf00 (physical address), v:0xff00 (virtual address), or 0xffdc at the command line. The command handler function will receive a tuple of the prefix and the address, e.g., ("v", 0xcff0). If only the address is given, "v" will be used.

Sometimes it is convenient to have other arguments than flags optional. To indicate this, add "?" as the third argument to arg(), and the default value as the fourth; e.g.,

..., args = [arg(int_t, "value", "?", 1),
             arg(str_t, "file")], ...
makes value an optional argument with 1 as its default value.

The arg function takes more parameters than those already mentioned:

..., args = [arg(str_t, "cpu",
             expander = exp_fun,
             is_a = test_fun)], ...

will connect an argument completion (expander) function for the cpu arg, i.e., the function exp_fun() will be called when the user presses the TAB key while entering the argument value. The expander function takes an argument representing the text the user has written for the argument. For example, if the user presses TAB after typing command cpu = ultr, the exp_fun() will be passed "ultr" and should return a list of strings completing "ultr". Here is an example of an expander function:

def exp_fun(comp):
    return get_completions(comp, ["ultraI", "ultraII",
                                  "ultraIII", "pentium"])

When called with "ultr", it will return ["ultraI", "ultraII", "ultraIII"]. The get_completions function filters the list and keep elements with prefix comp. The expander functions only works for the string type for the moment.

The is_a argument takes a function that tests if the argument is valid. It should return 1 for valid values and 0 otherwise. For example the read-reg command has as first argument a CPU (optional) and as second argument a register. If a user types read-reg g7, CLI will incorrectly interpret g7 as a CPU since g7 is a valid string and the command will fail. The is_a function could therefore return 0 for non-CPUs and pass the string to the next argument, which will match since g7 is a register.

Polyvalue

A command argument can be of multiple types as well (polyvalues). For example,

...,
args = [ arg((str_t, int_t, flag_t), ("cpu","value","-all"), "?",
             (int_t, 0, "value"), expander = (exp1, exp2, None)) ],
...

will create an argument that is either a string, an integer, or a flag. The argument passed to the command handler function is a tuple specifying the arg-type, the value, and the name of the argument. E.g., command foo will pass (str_t, "foo", "cpu") to the command handler function. This is why the default value looks the way it does. The corresponding expander function will also be used. command cpu = abc<tab> will use the exp1 expander.

doc — string (required if not doc_with is used)
This is the documentation of the command. Some simple, HTML-like formatting markup can be used, such as <i>, <b> and <br/> for italic, bold and line-break. A blank line separates paragraphs. Italic does not usually work in terminals so underlining will be used instead. Use italics when referring to arguments and bold for command names.
type — string (default is "misc-commands")
This is the command category that the command belongs to. All categories will be listed when the help command is used. help category will list all command in that category. Any whitespace within this string will be replaced with dashes.
short — string (recommended)
A short description of the command used when listing commands (e.g. help –all).
repeat — function (optional)
If such a function is supplied, it will be called when the user enters an empty line (i.e., just presses enter) after this command has been run. The arguments passed to the repeat function will be the same as those of fun (see above). This is used to implement the behavior of commands like disassemble, where pressing enter after having run one disassemble command disassembles the instructions following the last one of the previous command.
namespace — string (optional)
Makes the command a namespace command. Such commands are invoked as a method call of the form object.command, e.g., rec0.playback-start. This means that the command handler function will get the namespace object as first argument (a recorder object) and then the rest of the arguments. The namespace string is either the class name of the object, e.g., "recorder", or the name of a "superclass" of the object, or an interface that the object implements. For instance, the class name "processor" is a superclass of any processor, e.g., "ultrasparc-ii", and "breakpoint" is an interface that a memory-space object implements.

The full name of a namespace command will be <class_or_interface>.command (angle brackets included) and this is what is printed when command are listed, but as stated above the command is invoked with object.command.

Device commands are typically implemented using namespace commands. This is because they usually operate on a single configuration object, e.g., a MMU or cache object.

doc_with — string (optional)
This argument can be specified if a command should be documented together with another one. For example the disable command is documented with the enable command since they are tightly coupled together. So the doc argument is missing for the disable command and all documentation is written in the enable command. Note: doc_with together with a namespace command must be given as "<class_or_interface>.command"
alias — string or list of strings (optional)
Specify aliases for this command. Does not work with namespace commands.
infix — 0,1 (default 0)
Indicates that the command should be an infix command. For example the arithmetic command sets this argument to 1.
pri — integer (default is 0)
Sets the priority for the commands, typically only relevant to infix commands. For example, * has higher priority than + (200 and 100, respectively).
left — 0,1 (default 0)
If the command is left associative or not (right associative).

Previous - Up - Next