MMIX Hello World - Basic Example

Table of Content


MMIX Hello World - Basic Example

This is the most basic example of running MMIX using Donald Knuth's MMIXware.

The file hello.mms contains the following assembly code:

	LOC	Data_Segment
Text	BYTE	"Hello world!",10,0

	LOC	#100
Main	LDA	$255,Text
	TRAP	0,Fputs,StdOut
	TRAP	0,Halt,0

May be some words of explanation are in order unless you want to read the introduction given in mmix-doc.pdf which is by far more detailed.

An assembly program basically specifies the memory content at the start of the simulator. The LOC Data_Segment places the next items, the byte sequence "Hello world!" with a trailing newline (ASCII code 10) and a terminating 0 character into the data segment (starting at address #2000 0000 0000 0000) . (You will find an explanation of the mysterious GREG @ below, where the program trace is explained.)

The LOC #100 places the following three instructions into the text segment (containing executable code) starting at address #100. The first instruction loads the address of the byte sequence, represented by the label Text into register $255. This register is used by convention to transmit parameters to operating system calls. In this case, the following TRAP instructions calls the Function Fputs with the additional parameter StdOut. After return from this call to the operating system, the next operating system call follows immediately, asking the operating system to Halt the program.

For a short summary of the most common MMIX Instructions get a printout of the MMIX Quick Reference Card.

The MMIX source file is assembled, using the MMIX Assembler mmixal (Win32, Linux, OS X) like this:

mmixal hello.mms

It produces an MMIX object file hello.mmo which then can be executed using the MMIX instruction level simulator mmix (Win32, Linux, OS X) with the command:

mmix -i hello.mmo

The -i stands for "interactive". It is one of many command line options for the simulator. You get a complete summary by running the mmix simulator with the -h option (h for help!).

Running the simulator interactively presents you with the mmix prompt mmix> waiting for input. The simplest input is just the return key, which executes the program stepwise, one instruction at a time. Doing this, you get the following output:

      (00000000000000fc: fb0000ff (UNSAVE)) #6000000000000088: rG=254, ..., rL=2
  0 instructions, 0 mems, 0 oops; 0 good guesses, 0 bad
  (now at location #0000000000000100)
    1. 0000000000000100: 23fffe00 (ADDUI) $255=g[255] = 2305843009213693952 = #2000000000000000
  1 instruction, 0 mems, 1 oop; 0 good guesses, 0 bad
  (now at location #0000000000000104)
Hello world!
    1. 0000000000000104: 00000701 (TRAP) $255 = Fputs(StdOut,#2000000000000000) = 13
  2 instructions, 0 mems, 6 oops; 0 good guesses, 0 bad
  (now at location #0000000000000108)
    1. 0000000000000108: 00000000 (TRAP) Halt(0)
  3 instructions, 0 mems, 11 oops; 0 good guesses, 0 bad
  (halted at location #0000000000000108)

The instruction trace shown above gives detailed information on each instruction executed.

The first instruction you see is somewhat special. It is the UNSAVE instruction used by the operating system to initialize the process environment from the stack.

Preceding the name of the instruction UNSAVE, you see the in hexadecimal notation the four-byte instruction word stored in memory (fb0000ff). The first byte (fb) is the instructions opcode and the last byte (ff) is the Z parameter containing the register number 255. Preceding the instruction word, you find the address of the instruction (00000000000000fc). This format is common to all the instructions found in the trace. The shown address of the UNSAVE instruction is just one instruction before the first "real" instruction of the program (labeled Main in the source file) which gets executed next.

The first proper instruction of the program is LDA (Load Address). It has been assembled into an ADDUI (Add Unsigned Immediate) Instruction adding a base address (#2000 0000 0000 0000 in register $254) and an immediate offset (0) to obtain the desired address. This is the MMIX way of loading 64 Bit addresses into registers. The register $254, by the way, got its value during the UNSAVE instruction, and the assembly program gave the assembler a hint to do so using the GREG @ instruction.

The next two instruction execute the two calls to the operating system using the TRAP instruction. You see the output of the Fputs call immediately preceding the trace information about having executed the TRAP.

There is some statistics that is printed with the trace:

  • the number of instructions executed,
  • the number of cycles used (oops),
  • the number of memory accesses (mems),
  • the number of correctly predicted branches (good guesses), and
  • the number of incorrectly predicted branches (bad).
These statistics exclude the system time spend in the operating system. One reason for this is: there is actually no operating system. The simulator takes a shortcut, by simulating not the TRAP instruction but simulating the effect that a TRAP 0,Fputs,StdOut, including the complete operating system, would have for the application program - that is: it will output the string to the standard output. So the output is done by the simulator on the host machine not by MMIX on the simulated machine. If you need a simulator that really simulates TRAP instructions, so that you can program you own implementation of Fputs, you have to use the Virtual Motherboard based MMIX simulator for instance. This is described in the next Hello World Example using VMB.

Alternatively you might be interested in seeing how to use the GNU toolchain. This is explained in the Hello World Example using the GNU Toolchain.

Please help to keep this site up to date! If you want to point out important material or projects that are not listed here, if you find errors or want to suggest improvements, please send email to email