diff options
Diffstat (limited to 'doc/mdk_gstart.texi')
-rw-r--r-- | doc/mdk_gstart.texi | 1058 |
1 files changed, 1058 insertions, 0 deletions
diff --git a/doc/mdk_gstart.texi b/doc/mdk_gstart.texi new file mode 100644 index 0000000..9eab3f6 --- /dev/null +++ b/doc/mdk_gstart.texi @@ -0,0 +1,1058 @@ +@c -*-texinfo-*- +@c This is part of the GNU MDK Reference Manual. +@c Copyright (C) 2000, 2001, 2002, 2003, 2004 +@c Free Software Foundation, Inc. +@c See the file mdk.texi for copying conditions. + +@c $Id: mdk_gstart.texi,v 1.17 2004/08/01 21:43:29 jao Exp $ + +@node Getting started, Emacs tools, MIX and MIXAL tutorial, Top +@chapter Getting started +@cindex tutorial + +In this chapter, you will find a sample code-compile-run-debug session +using the @sc{mdk} utilities. Familiarity with the MIX mythical computer +and its assembly language MIXAL (as described in Knuth's TAOCP) is +assumed; for a compact reminder, see @ref{MIX and MIXAL tutorial}. + +@menu +* Writing a source file:: A sample MIXAL source file. +* Compiling:: Using @code{mixasm} to compile source + files into binary format. +* Running the program:: Running and debugging your programs. +* Using mixguile:: Using the Scheme interpreter to run and + debug your programs. +* Using Scheme in mixvm and gmixvm:: +@end menu + +@node Writing a source file, Compiling, Getting started, Getting started +@section Writing a source file +@cindex MIXAL +@cindex source file +@cindex .mixal file + +MIXAL programs can be written as ASCII files with your editor of choice. +Here you have the mandatory @emph{hello world} as written in the MIXAL +assembly language: + +@example +* (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) + HLT halt execution (8) +MSG ALF "MIXAL" (9) + ALF " HELL" (10) + ALF "O WOR" (11) + ALF "LD " (12) + END START end of the program (13) +@end example + +@noindent MIXAL source files should have the extension @file{.mixal} +when used with the @sc{mdk} utilities. As you can see in the above +sample, each line in a MIXAL file can be divided into four fields +separated by an arbitrary amount of whitespace characters (blanks and or +tabs). While in Knuth's definition of MIXAL each field must start at a +fixed pre-defined column number, the @sc{mdk} assembler loosens this +requirement and lets you format the file as you see fit. The only +restrictions retained are for comment lines (like 1-4) which must begin +with an asterisk (*) placed at column 1, and for the label field (see +below) which, if present, must also start at column 1. The four fields +in each non-comment line are: + +@itemize @minus +@item +an optional label, which either refers to the current memory address (as +@code{START} and @code{MSG} in lines 7 and 9) or a defined symbol +(@code{TERM}) (if present, the label must always start at the first +column in its line, for the first whitespace in the line maks the +beginning of the second field), +@item +an operation mnemonic, which can represent either a MIX instruction +(@code{OUT} and @code{HLT} in lines 7 and 8 above), or an assembly +pseudoinstruction (e.g., the @code{ORIG} pseudoinstruction in line +6@footnote{If an @code{ORIG} directive is not used, the program will +be loaded by the virtual machine at address 0. @code{ORIG} allows +allocating the executable code where you see fit.}. +@item +an optional operand for the (pseudo)instruction, and +@item +an optional free text comment. +@end itemize + +@noindent Lines 9-12 of the @file{hello.mixal} file above also show the +second (and last) difference between Knuth's MIXAL definition and ours: +the operand of the @code{ALF} pseudoinstruction (a word of five +characters) must be quoted using ""@footnote{In Knuth's definition, +the operand always starts at a fixed column number, and the use of +quotation is therefore unnecessary. As @code{mixasm} releases this +requirement, marking the beginning and end of the @code{ALF} operand +disambiguates the parser's recognition of this operand when it includes +blanks. Note that double-quotes (") are not part of the MIX character +set, and, therefore, no escape characters are needed within +@code{ALF}'s operands.}. + +The workings of this sample program should be straightforward if you are +familiar with MIXAL. See TAOCP vol. 1 for a thorough definition or +@ref{MIX and MIXAL tutorial}, for a tutorial. + +@node Compiling, Running the program, Writing a source file, Getting started +@section Compiling +@cindex compiling +@cindex binary programs +@cindex virtual machine +@cindex assembler +@cindex @code{mixasm} + +Three simulators of the MIX computer, called @code{mixvm}, @code{gmixvm} +and @code{mixguile}, are included in the @sc{mdk} tools. They are able to +run binary files containing MIX instructions written in their binary +representation. You can translate MIXAL source files into this binary +form using @code{mixasm}, the MIXAL assembler. So, in order to compile +the @file{hello.mixal} file, you can type the following command at your +shell prompt: + +@example +mixasm hello @key{RET} +@end example + +@cindex .mix file + +If the source file contains no errors, this will produce a binary file +called @file{hello.mix} which can be loaded and run by the MIX virtual +machine. Unless the @code{mixasm} option @code{-O} is provided, the +assembler will include debug information in the executable file (for a +complete description of all the compilation options, see +@ref{mixasm}). Now, your are ready to run your first MIX program, as +described in the following section. + + +@node Running the program, Using mixguile, Compiling, Getting started +@section Running the program +@cindex @code{mixvm} +@cindex non-interactive mode +@cindex interactive mode + +MIX is a mythical computer, so it is no use ordering it from your +favorite hardware provider. @sc{mdk} provides three software simulators of +the computer, though. They are + +@itemize @bullet +@item +@code{mixvm}, a command line oriented simulator, +@item +@code{gmixvm}, a GTK based graphical interface to @code{mixvm}, and +@item +@code{mixguile}, a Guile shell with a built-in MIX simulator. +@end itemize + +All three simulators accept the same set of user commands, but offer a +different user interface, as noted above. In this section we shall +describe some of these commands, and show you how to use them from +@code{mixvm}'s command line. You can use them as well at @code{gmixvm}'s +command prompt (@pxref{gmixvm}), or using the built-in Scheme primitives +of @code{mixguile} (@pxref{Using mixguile}). + +Using the MIX simulators, you can run your MIXAL programs, after +compiling them with @code{mixasm} into binary @file{.mix} +files. @code{mixvm} can be used either in @dfn{interactive} or +@dfn{non-interactive} mode. In the second case, @code{mixvm} will load +your program into memory, execute it (producing any output due to +MIXAL @code{OUT} instructions present in the program), and exit when +it encounters a @code{HLT} instruction. In interactive mode, you will +enter a shell prompt which allows you issuing commands to the running +virtual machine. This commands will permit you to load, run and debug +programs, as well as to inspect the MIX computer state (register +contents, memory cells contents and so on). + +@menu +* Non-interactive mode:: Running your programs non-interactively. +* Interactive mode:: Running programs interactively. +* Debugging:: Commands for debugging your programs. +@end menu + +@node Non-interactive mode, Interactive mode, Running the program, Running the program +@comment node-name, next, previous, up +@subsection Non-interactive mode +@cindex non-interactive mode + +To make @code{mixvm} work in non-interactive mode, use the @code{-r} +flag. Thus, to run our @file{hello.mix} program, simply type + +@example +mixvm -r hello @key{RET} +@end example + +@noindent at your command prompt, and you will get the following output: + +@example +MIXAL HELLO WORLD +@end example + +@noindent Since our hello world program uses MIX's device number 19 as +its output device (@pxref{Writing a source file}), the output is +redirected to the shell's standard output. Had you used any other MIX +output devices (disks, drums, line printer, etc.), @code{mixvm} would +have created a file named after the device used (e.g. @file{disk4.dev}) +and written its output there@footnote{The device files are stored, by +default, in a directory called @file{.mdk}, which is created in your +home directory the first time @code{mixvm} is run. You can change this +default directory using the command @code{devdir} when running +@code{mixvm} in interactive mode (@pxref{Configuration commands})}. + +The virtual machine can also report the execution time of the program, +according to the (virtual) time spent in each of the binary instructions +(@pxref{Execution times}). Printing of execution time statistics is +activated with the @code{-t} flag; running + +@example +mixvm -t -r hello @key{RET} +@end example + +@noindent +produces the following output: + +@example +MIXAL HELLO WORLD +** Execution time: 11 +@end example + +Sometimes, you will prefer to store the results of your program in MIX +registers rather than writing them to a device. In such cases, +@code{mixvm}'s @code{-d} flag is your friend: it makes @code{mixvm} to +dump the contents of its registers and flags after executing the loaded +program. For instance, typing the following command at your shell's +prompt + +@example +mixvm -d -r hello +@end example + +@noindent you will obtain the following output: + +@example +MIXAL HELLO WORLD +rA: + 00 00 00 00 00 (0000000000) +rX: + 00 00 00 00 00 (0000000000) +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) +Overflow: F +Cmp: E +@end example + +@noindent which, in addition to the program's outputs and execution +time, gives you the contents of the MIX registers and the values of the +overflow toggle and comparison flag (admittedly, rather uninteresting in +our sample). + +As you can see, running programs non-interactively has many +limitations. You cannot peek the virtual machine's memory contents, not +to mention stepping through your program's instructions or setting +breakpoints@footnote{The @code{mixguile} program allows you to execute +arbitrary combinations of @code{mixvm} commands (using Scheme) +non-interactively. @xref{Scheme scripts}.}. Enter interactive mode. + +@node Interactive mode, Debugging, Non-interactive mode, Running the program +@comment node-name, next, previous, up +@subsection Interactive mode +@cindex interactive mode + +To enter the MIX virtual machine interactive mode, simply type + +@example +mixvm @key{RET} +@end example + +@noindent at your shell command prompt. This command enters the +@code{mixvm} command shell. You will be presented the following command +prompt: + +@example +MIX > +@end example + +@noindent The virtual machine is initialised and ready to accept your +commands. The @code{mixvm} command shell uses GNU's readline, so that +you have at your disposal command completion (using @key{TAB}) and +history functionality, as well as other line editing shortcuts common to +all utilities using this library (for a complete description of +readline's line editing usage, see @ref{Command Line +Editing,,,Readline}.) + +@cindex @code{load} +Usually, the first thing you will want to do is loading a compiled MIX +program into memory. This is acomplished by the @code{load} command, +which takes as an argument the name of the @file{.mix} file to be +loaded. Thus, typing + +@example +MIX > load hello @key{RET} +Program loaded. Start address: 3000 +MIX > +@end example + +@noindent will load @file{hello.mix} into the virtual machine's memory +and set the program counter to the address of the first instruction. You +can obtain the contents of the program counter using the command +@code{pc}: + +@cindex @code{pc} +@example +MIX > pc +Current address: 3000 +MIX > +@end example + +@cindex @code{run} +After loading it, you are ready to run the program, using, as you surely +have guessed, the @code{run} command: + +@example +MIX > run +Running ... +MIXAL HELLO WORLD +... done +Elapsed time: 11 /Total program time: 11 (Total uptime: 11) +MIX > +@end example + +@noindent Note that now the timing statistics are richer. You obtain the +elapsed execution time (i.e., the time spent executing instructions +since the last breakpoint), the total execution time for the program up +to now (which in our case coincides with the elapsed time, since there +were no breakpoints), and the total uptime for the virtual machine (you +can load and run more than one program in the same +session)@footnote{Printing of timing statistics can be disabled using +the command @code{timing} (@pxref{Configuration commands}).}. After +running the program, the program counter will point to the address after +the one containing the @code{HLT} instruction. In our case, asking the +value of the program counter after executing the program will give us + +@example +MIX > pc +Current address: 3002 +MIX > +@end example + +@cindex @code{pmem} +@noindent You can check the contents of a memory cell giving its address +as an argument of the command @code{pmem}, like this + +@example +MIX > pmem 3001 +3001: + 00 00 00 02 05 (0000000133) +MIX > +@end example + +@noindent +and convince yourself that address 3001 contains the binary +representation of the instruction @code{HLT}. An address range of the +form FROM-TO can also be used as the argument of @code{pmem}: + +@example +MIX > pmem 3000-3006 +3000: + 46 58 00 19 37 (0786957541) +3001: + 00 00 00 02 05 (0000000133) +3002: + 14 09 27 01 13 (0237350989) +3003: + 00 08 05 13 13 (0002118477) +3004: + 16 00 26 16 19 (0268542995) +3005: + 13 04 00 00 00 (0219152384) +3006: + 00 00 00 00 00 (0000000000) +MIX > +@end example + +@cindex @code{preg} +@noindent +In a similar manner, you can look at the contents of the MIX registers +and flags. For instance, to ask for the contents of the A register you +can type + +@example +MIX > preg A +rA: + 00 00 00 00 00 (0000000000) +MIX > +@end example + +@cindex @code{help} +@noindent +Use the comand @code{help} to obtain a list of all available commands, +and @code{help COMMAND} for help on a specific command, e.g. + +@example +MIX > help run +run Run loaded or given MIX code file. Usage: run [FILENAME] +MIX > +@end example + +@noindent +For a complete list of commands available at the MIX propmt, +@xref{mixvm}. In the following subsection, you will find a quick tour +over commands useful for debugging your programs. + +@node Debugging, , Interactive mode, Running the program +@comment node-name, next, previous, up +@subsection Debugging commands + +@cindex @code{next} +The interactive mode of @code{mixvm} lets you step by step execution of +programs as well as breakpoint setting. Use @code{next} to step through +the program, running its instructions one by one. To run our +two-instruction @file{hello.mix} sample you can do the following: + +@example +MIX > load hello +Program loaded. Start address: 3000 +MIX > pc +Current address: 3000 +MIX > next +MIXAL HELLO WORLD +Elapsed time: 1 /Total program time: 1 (Total uptime: 1) +MIX > pc +Current address: 3001 +MIX > next +End of program reached at address 3002 +Elapsed time: 10 /Total program time: 11 (Total uptime: 11) +MIX > pc +Current address: 3002 +MIX > next +MIXAL HELLO WORLD +Elapsed time: 1 /Total program time: 1 (Total uptime: 12) +MIX > +MIX > run +Running ... +... done +Elapsed time: 10 /Total program time: 11 (Total uptime: 22) +MIX > +@end example +@noindent +(As an aside, the above sample also shows how the virtual machine +handles cummulative time statistics and automatic program restart). + +@cindex @code{sbpa} +@cindex breakpoints + +You can set a breakpoint at a given address using the command +@code{sbpa} (set breakpoint at address). When a breakpoint is set, +@code{run} will stop before executing the instruction at the given +address. Typing @code{run} again will resume program execution. Coming +back to our hello world example, we would have: + +@example +MIX > sbpa 3001 +Breakpoint set at address 3001 +MIX > run +Running ... +MIXAL HELLO WORLD +... stopped: breakpoint at line 8 (address 3001) +Elapsed time: 1 /Total program time: 1 (Total uptime: 23) +MIX > run +Running ... +... done +Elapsed time: 10 /Total program time: 11 (Total uptime: 33) +MIX > +@end example + +@cindex @code{sbp} +@cindex breakpoints +@noindent +Note that, since we compiled @file{hello.mixal} with debug info +enabled, the virtual machine is able to tell us the line in the +source file corresponding to the breakpoint we are setting. As a +matter of fact, you can directly set breakpoints at source code lines +using the command @code{sbp LINE_NO}, e.g. + +@example +MIX > sbp 4 +Breakpoint set at line 7 +MIX > +@end example + +@noindent +@code{sbp} sets the breakpoint at the first meaningful source code line; +thus, in the above example we have requested a breakpoint at a line +which does not correspond to a MIX instruction and the breakpoint is set +at the first line containing a real instruction after the given one. To +unset breakpoints, use @code{cbpa ADDRESS} and @code{cbp LINE_NO}, or +@code{cabp} to remove all currently set breakpoints. You can also set +conditional breakpoints, i.e., tell @code{mixvm} to interrupt program +execution whenever a register, a memory cell, the comparison flag or the +overflow toggle change using the commands @w{@code{sbp[rmco]}} +(@pxref{Debug commands}). + +@cindex @code{psym} +MIXAL lets you define symbolic constants, either using the @code{EQU} +pseudoinstruction or starting an instruction line with a label (which +assigns to the label the value of the current memory address). Each +MIXAL program has, therefore, an associated symbol table which you can +inspect using the @code{psym} command. For our hello world sample, you +will obtain the following output: + +@example +MIX > psym +START: 3000 +TERM: 19 +MSG: 3002 +MIX > +@end example + +Other useful commands for debugging are @code{strace} (which turns on +tracing of executed intructions), @code{pbt} (which prints a backtrace +of executed instructions) and @code{weval} (which evaluates +w-expressions on the fly). For a complete description of all available +MIX commands, @xref{mixvm}. + +@node Using mixguile, Using Scheme in mixvm and gmixvm, Running the program, Getting started +@section Using @code{mixguile} + +With @code{mixguile} you can run a MIX simulator embedded in a Guile +shell, that is, using Scheme functions and programs. As with +@code{mixvm}, @code{mixguile} can be run both in interactive and +non-interactive modes. The following subsections provide a quick tour on +using this MIX emulator. + +@menu +* The mixguile shell:: Using the Scheme MIX virtual machine. +* Additional functions:: Scheme functions accessing the VM. +* Defining new functions:: Defining your own Scheme functions. +* Hook functions:: Using command and break hook functions. +* Scheme scripts:: +@end menu + +@node The mixguile shell, Additional functions, Using mixguile, Using mixguile +@subsection The @code{mixguile} shell +@cindex Scheme +@cindex @code{mixguile} +@cindex REPL + +If you simply type + +@example +mixguile @key{RET} +@end example +@noindent +at the command prompt, you'll be presented a Guile shell prompt like +this + +@example +guile> +@end example +@noindent +At this point, you have entered a Scheme read-eval-print loop (REPL) +which offers you all the Guile functionality plus a new set of built-in +procedures to execute and debug MIX programs. Each of the @code{mixvm} +commands described in the previous sections (and in @pxref{mixvm}) have +a Scheme function counterpart named after it by prepending the prefix +@code{mix-} to its name. Thus, to load our hello world program, you can +simply enter + +@example +guile> (mix-load "hello") +Program loaded. Start address: 3000 +guile> +@end example +@noindent +and run it using @code{mix-run}: + +@example +guile> (mix-run) +Running ... +MIXAL HELLO WORLD +... done +Elapsed time: 11 /Total program time: 11 (Total uptime: 11) +guile> +@end example +@noindent +In the same way, you can execute it step by step using the Scheme +function @code{mix-next} or set a breakpoint: + +@example +guile> (mix-sbp 4) +Breakpoint set at line 5 +guile> +@end example +@noindent +or, if you one to peek at a register contents: + +@example +guile> (mix-preg 'A) +rA: + 00 00 00 00 00 (0000000000) +guile> +@end example + +You get the idea: you have at your disposal all the @code{mixvm} and +@code{gmixvm} commands by means of @code{mix-} functions. But, in case +you are wondering, this is only the beginning. You also have at your +disposal a whole Scheme interpreter, and you can, for instance, define +new functions combining the @code{mix-} and all other Scheme +primitives. In the next sections, you'll find examples of how to take +advantage of the Guile interpreter. + +@node Additional functions, Defining new functions, The mixguile shell, Using mixguile +@subsection Additional MIX Scheme functions + +The @code{mix-} function counterparts of the @code{mixvm} commands don't +return any value, and are evaluated only for their side-effects +(possibly including informational messages to the standard output and/or +error stream). When writting your own Scheme functions to manipulate the +MIX virtual machine within @code{mixguile} (@pxref{Defining new +functions}), you'll probably need Scheme functions returning the value +of the registers, memory cells and so on. Don't worry: @code{mixguile} +also offers you such functions. For instance, to access the (numerical) +value of a register you can use @code{mix-reg}: + +@example +guile> (mix-reg 'I2) +0 +guile> +@end example +@noindent +Note that, unlike @code{(mix-preg 'I2)}, the expression @code{(mix-reg +'I2)} in the above example evaluates to a Scheme number and does not +produce any side-effect: + +@example +guile> (number? (mix-reg 'I2)) +#t +guile> (number? (mix-preg 'I2)) +rI2: + 00 00 (0000) +#f +guile> +@end example + +In a similar fashion, you can access the memory contents using +@code{(mix-cell)}, or the program counter using @code{(mix-loc)}: + +@example +guile> (mix-cell 3000) +786957541 +guile> (mix-loc) +3002 +guile> +@end example + +Other functions returning the contents of the virtual machine components +are @code{mix-cmp} and @code{mix-over}, which eval to the value of the +comparison flag and the overflow toggle respectively. For a complete +list of these additional functions, @xref{mixguile}. + +In the next section, we'll see a sample of using these functions to +extend @code{mixguile}'s functionality. + +@node Defining new functions, Hook functions, Additional functions, Using mixguile +@subsection Defining new functions +@cindex Scheme functions + +Scheme is a powerful language, and you can use it inside @code{mixguile} +to easily extend the MIX interpreter's capabilities. For example, you +can easily define a function that loads a file, prints its name, +executes it and, finally, shows the registers contents, all in one shot: + +@example +guile> (define my-load-and-run @key{RET} + (lambda (file) @key{RET} + (mix-load file) @key{RET} + (display "File loaded: ") @key{RET} + (mix-pprog) @key{RET} + (mix-run) @key{RET} + (mix-preg))) @key{RET} +guile> +@end example +@noindent +and use it to run your programs: + +@example +guile> (my-load-and-run "hello") +Program loaded. Start address: 3000 +File loaded: hello.mix +Running ... +MIXAL HELLO WORLD +... done +Elapsed time: 11 /Total program time: 11 (Total uptime: 33) +rA: + 00 00 00 00 00 (0000000000) +rX: + 00 00 00 00 00 (0000000000) +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) +guile> +@end example + + +Or, maybe, you want a function which sets a breakpoint at a specified +line number before executing it: + +@example +guile> (define my-load-and-run-with-bp + (lambda (file line) + (mix-load file) + (mix-sbp line) + (mix-run))) +guile> (my-load-and-run-with-bp "samples/primes" 10) +Program loaded. Start address: 3000 +Breakpoint set at line 10 +Running ... +... stopped: breakpoint at line 10 (address 3001) +Elapsed time: 1 /Total program time: 1 (Total uptime: 45) +guile> +@end example + +As a third example, the following function loads a program, runs it and +prints the contents of the memory between the program's start and end +addresses: + +@example +guile> (define my-run + (lambda (file) + (mix-load file) + (let ((start (mix-loc))) + (mix-run) + (mix-pmem start (mix-loc))))) +guile> (my-run "hello") +Program loaded. Start address: 3000 +Running ... +MIXAL HELLO WORLD +... done +Elapsed time: 11 /Total program time: 11 (Total uptime: 11) +3000: + 46 58 00 19 37 (0786957541) +3001: + 00 00 00 02 05 (0000000133) +3002: + 14 09 27 01 13 (0237350989) +guile> +@end example + + +As you can see, the possibilities are virtually unlimited. Of course, +you don't need to type a function definition each time you start +@code{mixguile}. You can write it in a file, and load it using Scheme's +@code{load} function. For instance, you can create a file named, say, +@file{functions.scm} with your definitions (or any Scheme expression) +and load it at the @code{mixguile} prompt: + +@example +guile> (load "functions.scm") +@end example + +Alternatively, you can make @code{mixguile} to load it for you. When +@code{mixguile} starts, it looks for a file named @file{mixguile.scm} in +your MDK configuration directory (@file{~/.mdk}) and, if it exists, +loads it before entering the REPL. Therefore, you can copy your +definitions in that file, or load the @file{functions.scm} file in +@file{mixguile.scm}. + +@node Hook functions, Scheme scripts, Defining new functions, Using mixguile +@subsection Hook functions +@cindex hook function +@cindex pre-hook +@cindex post-hook + +Hooks are functions called before or after a given event occurs. In +@code{mixguile}, you can define command and break hooks, which are +associated, respectively, with command execution and program +interruption events. The following sections give you a tutorial on using +hook functions within @code{mixguile}. + +@menu +* Command hooks:: +* Break hooks:: +@end menu + +@node Command hooks, Break hooks, Hook functions, Hook functions +@subsubsection Command hooks + +In the previous section, we have seen how to extend @code{mixguile}'s +functionality through the use of user defined functions. Frequently, +you'll write new functions that improve in some way the workings of a +built-in @code{mixvm} command, following this pattern: + +@enumerate a +@item +Prepare the command execution +@item +Execute the desired command +@item +Perform post execution operations +@end enumerate + +We call the functions executed in step (a) @dfn{pre-hook}s, and those of +step @dfn{post-hook}s of the given command. @code{mixguile} lets you +specify pre- and post-hooks for any @code{mixvm} command using the +@code{mix-add-pre-hook} and @code{mix-add-post-hook} functions, which +take as arguments a symbol naming the command and a function to be +executed before (resp. after) the command. In other words, +@code{mixguile} will execute for you steps (a) and (c) above whenever +you eval (b). The hook functions must take a single argument, which is a +string list of the command's arguments. As an example, let us define the +following hooks for the @code{next} command: + +@example +(define next-pre-hook + (lambda (arglist) + (mix-slog #f))) + +(define next-post-hook + (lambda (arglist) + (display "Stopped at line ") + (display (mix-src-line-no)) + (display ": ") + (display (mix-src-line)) + (newline) + (mix-slog #t))) +@end example +@noindent +In these functions, we are using the function @code{mix-slog} to turn +off the informational messages produced by the virtual machine, since we +are providing our own ones in the post hook function. To install these +hooks, we would write: + +@example +(mix-add-pre-hook 'next next-pre-hook) +(mix-add-post-hook 'next next-post-hook) +@end example +@noindent +Assuming we have put the above expressions in @code{mixguile}'s +initialisation file, we would obtain the following results when +evaluating @code{mix-next}: + +@example +guile> (mix-next) +MIXAL HELLO WORLD +Stopped at line 6: HLT +guile> +@end example + +As a second, more elaborated, example, let's define hooks which print +the address and contents of a cell being modified using @code{smem}. The +hook functions could be something like this: + +@example +(define smem-pre-hook + (lambda (arglist) + (if (eq? (length arglist) 2) + (begin + (display "Changing address ") + (display (car arglist)) + (newline) + (display "Old contents: ") + (display (mix-cell (string->number (car arglist)))) + (newline)) + (error "Wrong arguments" arglist)))) + +(define smem-post-hook + (lambda (arglist) + (if (eq? (length arglist) 2) + (begin + (display "New contents: ") + (display (mix-cell (string->number (car arglist)))) + (newline))))) +@end example +@noindent +and we can install them using + +@example +(mix-add-pre-hook 'smem smem-pre-hook) +(mix-add-post-hook 'smem smem-post-hook) +@end example +@noindent +Aferwards, a sample execution of @code{mix-smem} would look like this: + +@example +guile> (mix-smem 2000 100) +Changing address 2000 +Old contents: 0 +New contents: 100 +guile> +@end example + +@cindex global hook + +You can add any number of hooks to a given command. They will be +executed in the same order as they are registered. You can also define +global post (pre) hooks, which will be called before (after) any +@code{mixvm} command is executed. Global hook functions must admit two +arguments, namely, a string naming the invoked command and a string list +of its arguments, and they are installed using the Scheme functions +@code{mix-add-global-pre-hook} and @code{mix-add-global-post-hook}. A +simple example of global hook would be: + +@example +guile> (define pre-hook + (lambda (cmd args) + (display cmd) + (display " invoked with arguments ") + (display args) + (newline))) +guile> (mix-add-global-pre-hook pre-hook) +ok +guile> (mix-pmem 120 125) +pmem invoked with arguments (120-125) +0120: + 00 00 00 00 00 (0000000000) +0121: + 00 00 00 00 00 (0000000000) +0122: + 00 00 00 00 00 (0000000000) +0123: + 00 00 00 00 00 (0000000000) +0124: + 00 00 00 00 00 (0000000000) +0125: + 00 00 00 00 00 (0000000000) +guile> +@end example + +Note that if you invoke @code{mixvm} commands within a global hook, its +associated command hooks will be run. Thus, if you have installed both +the @code{next} hooks described earlier and the global hook above, +executing @code{mix-next} will yield the following result: + +@example +guile> (mix-next 5) +next invoked with arguments (5) +slog invoked with arguments (off) +MIXAL HELLO WORLD +Stopped at line 7: MSG ALF "MIXAL" +slog invoked with arguments (on) +guile> +@end example + +Adventurous readers may see the above global hook as the beginning of a +command log utility or a macro recorder that saves your commands for +replay. + +@node Break hooks, , Command hooks, Hook functions +@subsubsection Break hooks + +@cindex break hook + +We have seen in the previous section how to associate hooks to command +execution, but they are not the whole story. You can also associate hook +functions to program interruption, that is, specify functions that +should be called every time the execution of a MIX program is stopped +due to the presence of a breakpoint, either explicit or +conditional. Break hooks take as arguments the line number and memory +address at which the break occurred. A simple hook that logs the line +and address of the breakpoint could be defined as: + +@example +(define break-hook + (lambda (line address) + (display "Breakpoint encountered at line ") + (display line) + (display " and address ") + (display address) + (newline))) +@end example +@noindent +and installed for explicit and conditional breakpoints using + +@example +(mix-add-break-hook break-hook) +(mix-add-cond-break-hook break-hook) +@end example +@noindent +after that, every time the virtual machine encounters a breakpoint, +@code{break-code} shall be evaluated for you@footnote{You may have +noticed that break hooks can be implemented in terms of command hooks +associated to @code{mix-run} and @code{mix-next}. As a matter of fact, +they @emph{are} implemented this way: take a look at the file +@file{@emph{install_dir}/share/mdk/mix-vm-stat.scm} if you are curious.}. + +@node Scheme scripts, , Hook functions, Using mixguile +@subsection Scheme scripts +@cindex Scheme script +@cindex non-interactive + +Another useful way of using @code{mixguile} is writing executable +scripts that perform a set of commands for you. This is done using the +@code{mixguile} switch @code{-s} (being a Guile shell, @code{mixguile} +accepts all the command options of @code{guile}; type @code{mixguile -h} +for a list of all available command options). For instance, if you have +a very useful MIX program @file{foo.mix} which you want to run often, +you don't have to fire a MIX virtual machine, load and run it every +time; you can write a Scheme script instead: + +@example +#! /usr/bin/mixguile -s +!# +;;; runprimes: execute the primes.mix program + +;; load the file you want to run +(mix-load "../samples/primes") +;; execute it +(mix-run) +;; print the contents of registers +(mix-pall) +;; ... +@end example + +Just save the above script to a file named, say, @file{runtest}, make it +executable (@code{chmod +x runtest}), and, well, execute it from the +Unix shell: + +@example +$ ./runtest +Program loaded. Start address: 3000 +Running ... +... done +Elapsed time: 190908 /Total program time: 190908 (Total uptime: 190908) +rA: + 30 30 30 30 30 (0511305630) +rX: + 30 30 32 32 39 (0511313959) +rJ: + 47 18 (3026) +rI1: + 00 00 (0000) rI2: + 55 51 (3571) +rI3: + 00 19 (0019) rI4: + 31 51 (2035) +rI5: + 00 00 (0000) rI6: + 00 00 (0000) +Overflow: F +Cmp: L +$ +@end example + +Note that this is far more flexible that running programs +non-interactively using @code{mixvm} (@pxref{Non-interactive mode}), for +you can execute any combination of commands you want from a Scheme +script (not just running and dumping the registers). For additional +@code{mixguile} command line options, see @ref{Invoking mixguile}. + +@node Using Scheme in mixvm and gmixvm, , Using mixguile, Getting started +@section Using Scheme in @code{mixvm} and @code{gmixvm} +@cindex @code{scmf} + +In the previous section (@pxref{Using mixguile}) we have seen how the +Guile shell @code{mixguile} offers you the possibility of using Scheme +to manipulate a MIx virtual machine and extend the set of commands +offered by @code{mixvm} and @code{gmixvm}. This possibility is not +limited to the @code{mixguile} shell. Actually, both @code{mixvm} and +@code{gmixvm} incorporate an embedded Guile interpreter, and can +evaluate Scheme expressions. To evaluate a single-line expression at the +@code{mixvm} or @code{gmixvm} command prompt, simply write it and press +return (the command parser will recognise it as a Scheme expression +because it is parenthesized, and will pass it to the Guile +interpreter). A sample @code{mixvm} session using Scheme expressions +could be: + +@example +MIX > load hello +Program loaded. Start address: 3000 +MIX > (define a (mix-loc)) +MIX > run +Running ... +MIXAL HELLO WORLD +... done +Elapsed time: 11 /Total program time: 11 (Total uptime: 11) +MIX > (mix-pmem a) +3000: + 46 58 00 19 37 (0786957541) +MIX > (mix-pmem (mix-loc)) +3002: + 14 09 27 01 13 (0237350989) +MIX > +@end example + +You can also load and evaluate a file, using the @code{scmf} +command like this: + +@example +MIX> scmf /path/to/file/file.scm +@end example + +Therefore, you have at your disposal all the @code{mixguile} goodies +described above (new functions, new command definitions, hooks...) +inside @code{mixvm} and @code{gmixvm}. In other words, these programs +are extensible using Scheme. See @ref{Using mixguile} for examples of +how to do it. + |