mixvm, the MIX computer simulator
*********************************

This chapter describes mixvm, the MIX computer simulator. mixvm is a command line interface programme which simulates the MIX computer (see The MIX computer). It is able to run MIXAL programs (see MIXAL) previously compiled with the MIX assembler (see mixasm). The simulator allows inspection of the MIX computer components (registers, memory cells, comparison flag and overflow toggle), step by step execution of MIX programmes, and breakpoint setting to aid you in debugging your code. For a tutorial description of mixvm usage, see Running the program.

Invoking mixvm
==============

mixvm can be invoked with the following command line options (note that, following GNU's conventions, we provide a long option name for each available single letter switch):

     mixvm [-vhurdtq] [--version] [--help] [--usage] [--run] [--dump]
           [--time] [--noinit]  [FILE[.mix]]

The meaning of these options is as follows:

 -- User Option: -v
 -- User Option: --version
     Prints version and copyleft information and exits.

 -- User Option: -h
 -- User Option: --help
 -- User Option: -u
 -- User Option: --usage
     Prints a summary of available options and exits.

 -- User Option: -r
 -- User Option: --run
     Loads the specified FILE and executes it. After the program execution, mixvm exits. FILE must be the name of a binary .mix program compiled with mixasm. If your program does not produce any output, use the -d flag (see below) to peek at the virtual machine's state after execution.

 -- User Option: -d
 -- User Option: --dump
     This option must be used in conjunction with -r, and tells mixvm to print the value of the virtual machine's registers, comparison flag and overflow toggle after executing the program named FILE. See Non-interactive mode, for sample usage.

 -- User Option: -t
 -- User Option: --time
     This option must be used in conjunction with -r, and tells mixvm to print virtual time statistics for the program's execution.

When run without the -r flag, mixvm enters its interactive mode, showing you a prompt like this one:

     MIX >

and waiting for your commands (see Commands). If the optional FILE argument is given, the file FILE.mix will be loaded into the virtual machine memory before entering the interactive mode.

The first time mixvm is invoked, a directory named .mdk is created in your home directory. It contains the mixvm configuration file, the command history file and (by default) the block devices files (see Devices). Before showing you the command prompt, mixvm looks in the ~/.mdk directory for a file named mixguile.scm; if it exists, it is read and evaluated by the embedded Guile interpreter (see Defining new functions). You can use the -q command line option to skip this file loading:

 -- User Option: -q
 -- User Option: --noinit
     Do not load the Guile initialisation file ~/.mdk/mixguile.scm at startup.

Interactive commands
====================

You can enter the interactive mode of the MIX virtual machine by simply invoking mixvm without arguments. You will then be greeted by a shell prompt (The default command prompt, MIX > , can be changed using the prompt command (see Configuration commands))

     MIX >

which indicates that a new virtual machine has been initialised and is ready to execute your commands. As we have already mentioned, this command prompt offers you command line editing facilities which are described in the Readline user's manual (chances are that you are already familiar with these command line editing capabilities, as they are present in many GNU utilities, e.g. the bash shell) (The readline functionality will be available if you have compiled MDK with readline support, i.e., if GNU readline is installed in your system. This is often the case in GNU/Linux and BSD systems). In a nutshell, readline provides command completion using the TAB key and command history using the cursor keys. A history file containing the last commands typed in previous sessions is stored in the MDK configuration directory (~/.mdk).

As a beginner, your best friend will be the help command, which shows you a summary of all available MIX commands and their usage; its syntax is as follows:

 -- mixvm command: help [command]
     Prints a short description of the given COMMAND and its usage. If COMMAND is omitted, help prints the short description for all available commands.

File commands
-------------

You have at your disposal a series of commands that let you load and execute MIX executable files, as well as manipulate MIXAL source files:

 -- file command: load file[.mix]
     This command loads a binary file, FILE.MIX into the virtual machine memory, and positions the program counter at the beginning of the loaded program. This address is indicated in the MIXAL source file as the operand of the END pseudoinstruction. Thus, if your sample.mixal source file contains the line:

               END 3000

     and you compile it with mixasm to produce the binary file sample.mix, you will load it into the virtual machine as follows:

          MIX > load sample
          Program loaded. Start address: 3000
          MIX >

 -- file command: run [file[.mix]]
     When executed without argument, this command initiates or resumes execution of instructions from the current program counter address. Therefore, issuing this command after a successful load, will run the loaded program until either a HLT instruction or a breakpoint is found. If you provide a MIX filename as argument, the given file will be loaded (as with load FILE) and executed. If run is invoked again after program execution completion (i.e., after the HLT instruction has been found in a previous run), the program counter is repositioned and execution starts again from the beginning (as a matter of fact, a load command preserving the currently set breakpoints is issued before resuming execution).

 -- file command: edit [file[.mixal]]
     The source file FILE.MIXAL is edited using the editor defined in the environment variable MDK_EDITOR. If this variable is not set, the following ones are tried out in order: X_EDITOR, EDITOR and VISUAL. If invoked without argument, the source file for the currently loaded MIX file is edited. The command used to edit source files can also be configured using the sedit command (see Configuration commands).

 -- file command: compile file[.mixal]
     The source file FILE.MIXAL is compiled (with debug information enabled) using mixasm. If invoked without argument, the source file for the currently loaded MIX file is recompiled. The compilation command can be set using the sasm command (see Configuration commands).

 -- file command: pprog
 -- file command: psrc
     Print the path of the currently loaded MIX program and its source file:

          MIX > load ../samples/primes
          Program loaded. Start address: 3000
          MIX > pprog
          ../samples/primes.mix
          MIX > psrc
          /home/jao/projects/mdk/gnu/samples/primes.mixal
          MIx>

Finally, you can use the quit command to exit mixvm:

 -- file command: quit
     Exit mixvm, saving the current configuration parameters in ~/.mdk/mixvm.config.

Debug commands
--------------

Sequential execution of loaded programs can be interrupted using the following debug commands:

 -- debug command: next [ins_number]
     This command causes the virtual machine to fetch and execute  up to INS_NUMBER instructions, beginning from the current program counter position. Execution is interrupted either when the specified number of instructions have been fetched or a breakpoint is found, whatever happens first. If run without arguments, one instruction is executed. If next is invoked again after program execution completion (i.e., after the HLT instruction has been found in a previous run), the program counter is repositioned and execution starts again from the beginning (as a matter of fact, a load command preserving the currently set breakpoints is issued before resuming execution).

 -- debug command: sbp line_number
 -- debug command: cbp line_no
     Sets a breakpoint at the specified source file line number. If the line specified corresponds to a command or to a MIXAL pseudoinstruction which does not produce a MIX instruction in the binary file (such as ORIG or EQU) the breakpoint is set at the first source code line giving rise to a MIX instruction after the specified one. Thus, for our sample hello.mixal file:

          *                                                        (1)
          * hello.mixal: say 'hello world' in MIXAL                (2)
          *                                                        (3)
          * label ins    operand     comment                       (4)
          TERM    EQU    19          the MIX console device number (5)
                  ORIG   1000        start address                 (6)
          START   OUT    MSG(TERM)   output data at address MSG    (7)
          ...

     trying to set a breakpoint at line 5, will produce the following result:

          MIX > sbp 5
          Breakpoint set at line 7
          MIX >

     since line 7 is the first one compiled into a MIX instruction (at address 3000).

     The command cbp clears a (previously set) breakpoint at the given source file line.

 -- debug command: spba address
 -- debug command: cbpa address
     Sets a breakpoint at the given memory ADDRESS. The argument must be a valid MIX memory address, i.e., it must belong into the range [0-3999]. Note that no check is performed to verify that the specified address is reachable during program execution. No debug information is needed to set a breakpoint by address with sbpa. The command cbpa clears a (previously set) breakpoint at the given memory address.

 -- debug command: sbpr A | X | J | Ii
 -- debug command: cbpr A | X | J | Ii
     Sets a conditional breakpoint on the specified register change. For instance,

          sbpr I1

     will cause an interruption during program execution whenever the contents of register I1 changes. A previously set breakpoint is cleared using the cbpr command.

 -- debug command: sbpm address
 -- debug command: cbpm address
     Sets a conditional breakpoint on the specified memory cell change. The argument must be a valid MIX memory address, i.e., it must belong into the range [0-3999]. For instance,

          sbpm 1000

     will cause an interruption during program execution whenever the contents of the memory cell number 1000 changes. A previously set breakpoint is cleared using the cbpm command.

 -- debug command: sbpo
 -- debug command: cbpo
     Sets/clears a conditional breakpoint on overflow toggle change.

 -- debug command: sbpc
 -- debug command: cbpc
     Sets/clears a conditional breakpoint on comparison flag change.

 -- debug command: cabp
     Clears all currently set breakpoints.

 -- debug command: psym [symbol_name]
     MIXAL programs can define symbolic constants, using either the EQU pseudoinstruction or a label at the beginning of a line. Thus, in the program fragment

          VAR     EQU  2168
                  ORIG 4000
          START   LDA  VAR

     the symbol VAR stands for the value 2168, while START is assigned the value 4000. The symbol table can be consulted from the mixvm command line using psym followed by the name of the symbol whose contents you are interested in. When run without arguments, psym will print all defined symbols and their values.

The virtual machine can also show you the instructions it is executing, using the following commands:

 -- debug command: strace [on|off]
     strace on enables instruction tracing. When tracing is enabled, each time the virtual machine executes an instruction (due to your issuing a run or next command), it is printed in its canonical form (that is, with all expressions evaluated to their numerical values) and, if the program was compiled with debug information, as it was originally typed in the MIXAL source file. Instruction tracing is disabled with strace off command. A typical tracing session could be like this:

          MIX > strace on
          MIX > next
          3000: [OUT	3002,0(2:3)]	START	OUT	MSG(TERM)
          MIXAL HELLO WORLD
          Elapsed time: 1 /Total program time: 1 (Total uptime: 1)
          MIX > next
          3001: [HLT	0,0]		HLT
          End of program reached at address 3002
          Elapsed time: 10 /Total program time: 11 (Total uptime: 11)
          MIX > strace off
          MIX >

     The executed instruction, as it was translated, is shown between square brackets after the memory address, and, following it, you can see the actual MIXAL code that was compiled into the executed instruction. The tracing behaviour is stored as a configuration parameter in ~/.mdk.

 -- debug command: pline [LINE_NUMBER]
     Prints the requested source line (or the current one if LINE_NUMBER is omitted:

          MIX > load ../samples/hello
          Program loaded. Start address: 3000
          MIX > pline
          Line 5: START       OUT   MSG(TERM)
          MIX > pline 6
          Line 6:             HLT
          MIX >

 -- debug command: sbt [NUMBER]
     This command changes the limit for the backtrace of executed instructions. If the number is omitted, the command prints the current limit.  If you use a 0, backtraces are turned off. This can improve performance. If you wish for all the instructions to be logged, a -1 will enable that. The amount of memory required for unlimited backtraces can be substantial for long-running programs.

 -- debug command: pbt [INS_NUMBER]
     This command prints a backtrace of executed instructions. Its optional argument INS_NUMBER is the number of instructions to print. If it is omitted or equals zero, all executed instructions are printed. For instance, if you compile and load the following program (bt.mixal):

              ORIG 0
          BEG JMP *+1
              JMP *+1
          FOO JMP BAR
          BAR HLT
              END BEG

     you could get the following traces:

          MIX > load bt
          Program loaded. Start address: 0
          MIX > next
          MIX > pbt
          #0      BEG     in bt.mixal:2
          MIX > next
          MIX > pbt
          #0      1       in bt.mixal:3
          #1      BEG     in bt.mixal:2
          MIX > run
          Running ...
          ... done
          MIX > pbt 3
          #0      BAR     in bt.mixal:5
          #1      FOO     in bt.mixal:4
          #2      1       in bt.mixal:3
          MIX > pbt
          #0      BAR     in bt.mixal:5
          #1      FOO     in bt.mixal:4
          #2      1       in bt.mixal:3
          #3      BEG     in bt.mixal:2
          MIX >

     Note that the executed instruction trace gives you the label of the executed line or, if it has no label, its address.

As you have probably observed, mixvm prints timing statistics when running programs. This behaviour can be controlled using the stime command (see Configuration commands).

mixvm is also able of evaluating w-expressions (see W-expressions) using the following command:

 -- debug command: weval WEXP
     Evaluates the given w-expression, WEXP. The w-expression can contain any currently defined symbol. For instance:

          MIX > psym START
          + 00 00 00 46 56 (0000003000)
          MIX > weval START(0:1),START(3:4)
          + 56 00 46 56 00 (0939716096)
          MIX >

New symbols can be defined using the ssym command:

 -- debug command: ssym SYM WEXP
     Defines the symbol named SYM with the value resulting from evaluating WEXP, a w-expression. The newly defined symbol can be used in subsequent weval commands, as part of the expression to be evaluated. E.g.,

          MIX > ssym S 2+23*START
          + 00 00 18 19 56 (0000075000)
          MIX > psym S
          + 00 00 18 19 56 (0000075000)
          MIX > weval S(3:4)
          + 00 00 19 56 00 (0000081408)
          MIX >

Finally, if you want to discover which is the decimal value of a MIX word expressed as five bytes plus sign, you can use

 -- debug command: w2d WORD
     Computes the decimal value of the given word. WORD must be expressed as a sign (+/-) followed by five space-delimited, two-digit decimal values representing the five bytes composing the word. The reverse operation (showing the word representation of a decimal value) can be accomplished with weval. For instance:

          MIX > w2d - 01 00 00 02 02
          -16777346
          MIX > weval -16777346
          - 01 00 00 02 02 (0016777346)
          MIX >

State commands
--------------

Inspection and modification of the virtual machine state (memory, registers, overflow toggle and comparison flag contents) is accomplished using the following commands:

 -- state command: pstat
     This commands prints the current virtual machine state, which can be one of the following:

       - No program loaded

       - Program successfully loaded

       - Execution stopped (next executed)

       - Execution stopped: breakpoint encountered

       - Execution stopped: conditional breakpoint encountered

       - Program successfully terminated

 -- state command: pc
     Prints the current value of the program counter, which stores the address of the next instruction to be executed in a non-halted program.

 -- state command: sreg A | X | J | I[1-6] value
 -- state command: preg [A | X | J | I[1-6]]
 -- state command: pall
     preg prints the contents of a given MIX register. For instance, preg A will print the contents of the A-register. When invoked without arguments, all registers shall be printed:

          MIX > preg
          rA: - 00 00 00 00 35 (0000000035)
          rX: + 00 00 00 15 40 (0000001000)
          rJ: + 00 00 (0000)
          rI1: + 00 00 (0000)	rI2: + 00 00 (0000)
          rI3: + 00 00 (0000)	rI4: + 00 00 (0000)
          rI5: + 00 00 (0000)	rI6: + 00 00 (0000)
          MIX >

     As you can see in the above sample, the contents are printed as the sign plus the values of the MIX bytes stored in the register and, between parenthesis, the decimal representation of its module.

     pall prints the contents of all registers plus the comparison flag and overflow toggle.

     Finally, sreg Sets the contents of the given register to VALUE, expressed as a decimal constant. If VALUE exceeds the maximum value storable in the given register, VALUE mod MAXIMUM_VALUE is stored, e.g.

          MIX > sreg I1 1000
          MIX > preg I1
          rI1: + 15 40 (1000)
          MIX > sreg I1 1000000
          MIX > preg I1
          rI1: + 09 00 (0576)
          MIX >

 -- state command: pflags
 -- state command: scmp E | G | L
 -- state command: sover F | T
     pflags prints the value of the comparison flag and overflow toggle of the virtual machine, e.g.

          MIX > pflags
          Overflow: F
          Cmp: E
          MIX >

     The values of the overflow toggle are either F (false) or T (true), and, for the comparison flag, E, G, L (equal, greater, lesser). scmp and sover are setters of the comparison flag and overflow toggle values.

 -- state command: pmem from[-to]
 -- state command: smem address value
     pmem prints the contents of memory cells in the address range [FROM-TO]. If the upper limit TO is omitted, only the contents of the memory cell with address FROM is printed, as in

          MIX > pmem 3000
          3000: + 46 58 00 19 37 (0786957541)
          MIX >

     The memory contents are displayed both as the set of five MIX bytes plus sign composing the stored MIX word and, between parenthesis, the decimal representation of the module of the stored value.

     smem sets the content of the memory cell with address ADDRESS to VALUE, expressed as a decimal constant.

Configuration commands
----------------------

This section describes commands that allow you to configure the virtual machine behaviour. This configuration is stored in the MDK directory ~/.mdk.

As you can see in their description, some commands print, as a side effect, informational messages to the standard output (e.g. load prints a message telling you the loaded program's start address): these messages can be enabled/disabled using slog:

 -- config command: slog on|off
     Turns on/off the logging of informational messages. Note that error messages are always displayed, as well as state messages required using commands prefixed with p (preg, pmem and the like).

 -- config command: stime on|off
 -- config command: ptime
     The stime command (un)sets the printing of timing statistics, and ptime prints their current value:

          MIX > ptime
          Elapsed time: 10 /Total program time: 11 (Total uptime: 11)
          MIX >

 -- config command: sedit TEMPLATE
 -- config command: pedit
     sedit sets the command to be used to edit MIXAL source files with the edit command. TEMPLATE must contain the control characters %s to mark the place where the source's file name will be inserted. For instance, if you type

          MIX > sedit emacsclient %s
          MIX >

     issuing the mixvm command edit foo.mixal will invoke the operating system command emacsclient foo.mixal.

     pedit prints the current value of the edit command template.

 -- config command: sasm TEMPLATE
 -- config command: pasm
     sasm sets the command to be used to compile MIXAL source files with the compile command. TEMPLATE must contain the control characters %s to mark the place where the source's file name will be inserted. For instance, if you type

          MIX > sasm mixasm -l %s
          MIX >

     issuing the mixvm command compile foo.mixal will invoke the operating system command mixasm -l foo.mixal.

     pasm prints the current value of the compile command template.

 -- config command: sddir DIRNAME
 -- config command: pddir
     MIX devices (see Devices) are implemented as regular files stored, by default, inside ~/.mdk. The sddir command lets you specify an alternative location for storing these device files, while pddir prints the current device directory.

Finally, you can change the default command prompt, MIX > , using the prompt command:

 -- config command: prompt PROMPT
     Changes the command prompt to PROMPT. If you want to include white space(s) at the end of the new prompt, bracket PROMPT using double quotes (e.g., prompt ">> ").

Scheme commands
---------------

If you have compiled MDK with libguile support (see Special configure flags), mixvm will start and initialise an embedded Guile Scheme interpreter when it is invoked. That means that you have at your disposal, at mixvm's command prompt, all the Scheme primitives described in Using mixguile and mixguile, as well as any other function or hook that you have defined in the initialisation file ~/.mdk/mixguile.scm. To evaluate a Scheme function, simply type it at the mixvm command prompt (see Using Scheme in mixvm and gmixvm for a sample). Compared to the mixguile program, this has only one limitation: the expressions used in mixvm cannot span more than one line. You can get over this inconvenience writing your multiline Scheme expressions in a file and loading it using the scmf command:

 -- scheme command: scmf FILE_NAME
     Loads the given Scheme file and evaluates it using the embedded Guile interpreter.

MIX block devices
=================

The MIX computer comes equipped with a set of block devices for input-output operations (see Input-output operators). mixvm implements these block devices as disk files, with the exception of block device no. 19 (typewriter terminal) which is redirected to standard input/output. When you request an output operation on any other (output) device, a file named according to the following table will be created, and the specified MIX words will be written to the file in binary form (for binary devices) or in ASCII (for char devices). Files corresponding to input block devices should be created and filled beforehand to be used by the MIX virtual machine (for input-output devices this creation can be accomplished by a MIXAL program writing to the device the required data, or, if you prefer, with your favourite editor). The device files are stored, by default, in the directory ~/.mdk; this location can be changed using the mixvm command devdir (see Configuration commands).

Device    No.   filename   type and block size
Tape   0-7   tape[0-7].dev   bin i/o - 100 words
Disks   8-15   disk[0-7].dev   bin i/o - 100 words
Card reader   16   cardrd.dev   char in - 16 words
Card writer   17   cardwr.dev   char out - 16 words
Line printer   18   printer.dev   char out - 24 words
Terminal   19   stdin/stdout   char i/o - 14 words
Paper tape   20   paper.dev   char in - 14 words

Devices of type char are stored as ASCII files, using one line per block. For instance, since the card reader has blocks of size 16, that is, 80 characters, it will be emulated by an ASCII file consisting of lines with length 80. If the reader finds a line with less than the required number of characters, it pads the memory with zeroes (MIX character 'space') to complete the block size.

Note that the virtual machine automatically converts between the MIX and ASCII character encodings, so that you can manipulate char device files with any ASCII editor. In addition, the reader is not case-sensitive, i.e., it automatically converts lowercase letters to their uppercase counterparts (since the MIX character set does not include the former).

The typewriter (device no. 19) lets you use the standard input and output in your MIXAL programs. For instance, here is a simple 'echo' program:

     * simple echo program
     TERM    EQU     19          the typewriter device
     BUF     EQU     500         input buffer
             ORIG    1000
     START   IN      BUF(TERM)   read a block (70 chars)
             OUT     BUF(TERM)   write the read chars
             HLT
             END     START

Input lines longer than 70 characters (14 words) are trimmed. On the other hand, if you type less than a block of characters, whitespace (MIX character zero) is used as padding.