MMIX Hello World - Using the GNU Tool Chain

Table of Content


MMIX Hello World - Using the GNU Tool Chain

In this example, we see

  • first how we can replace the mmix assembler mmixal by the gnu assembler mmix-as to produce mmo files.
  • second how to use the GNU C Compiler to produce mmo files,
  • and last how to use the GNU debugger to run and debug binary files in the standard ELF format.

Using the MMIX GNU Assembler and Linker

The GNU assembler is part of a whole collection of programs and libraries, the GNU binutils,, that should be installed as a complete package (see next section). The assembler is, however, such a simple program, that you can also run it as a single program without the package. So you can download mmix-as (Win32, Linux) and run it on the file hello.mms, that we used already in the previous two Hello world examples (Basic Hello World Example, Hello World Example with VMB) using the following command line:

mmix-as hello.mms -o hello.o

The -o Option specifies the name of the output file. The extension here is not .mmo, since the assembler does not produce .mmo files, it produces ELF object files. This is a very flexible standard format for object files, that can contain also debug information as we will see. Tho make the final executable file (whether mmo or elf) a second step is required: Linkage.

The GNU linker/loader for MMIX is called mmix-ld (Win32, Linux) and we invoke it with the command-line:

mmix-ld.exe --oformat mmo hello.o -o hello.mmo

this produces the file hello.mmo. The mmo file format is currently the default format for the linker, so the option -oformat mmo can be omitted.

You can run the obtained file hello.mmo on either the regular mmix simulator or the VMB mmix simulator, or any other MMIX simulator that is compatible with the original.

You might want to use the GNU assembler instead of the simple mmixal assembler, for several reasons:

  • The GNU assembler is a powerful macro assembler that has all the features you expect from an assembler.
  • Using the GNU linker, you can build a program from multiple souorcefiles, that are independently assembled before linking.
  • The main reason however to use the GNU assembler is its integration with the other GNU binutils which allows you to produce files in ELF format, with debug information, that integrate nicely with files produced by the GNU Compiler Collection. We look at this use in the next section.

Installing and Using the MMIX GNU Binutils and Compiler Collection GCC

If you want to install the GNU Binutils and Compiler Collection from sources, you can follow the Installation instructions for GCC & Co. MMIX tools by Hans-Peter Nilson (not containing the GNU debugger for MMIX, which is not yet part) of the standard GNU distribution. The easier way is the download of ready to use binaries which are available here.

Download and extract it into a convenient location. This could be C:\Programs\ or your home directory, or c:\opt in UNIX style.

Extracting the zip file creates the folder mmix and in it a folder bin containing the executables belonging to the GNU binutils, the GNU C compiler and the GNU debugger. Next you should put the mmix\bin directory on your search path following these instructions.

Download optmmix-date-.tgz and extract it into a convenient location. This could be your home directory, or more typically the /opt directory.

Extracting the tgz file (using tar -xzvf filename) creates the folder mmix and in it a folder bin containing the executables belonging to the GNU binutils, the GNU C compiler and the GNU debugger. Next you should put the mmix/bin directory on your search path (e.g. PATH=$PATH;/opt/mmix/bin).

Now we are ready to use the C compiler to produce a hello.mmo program from the file hello.c with the command line:

mmix-gcc hello.c -o hello.mmo

You run this file using the MMIX simulator as usual:

mmix -i hello.mmo 

When the program stops, it has executed 1718 instructions, 310 mems, and 2058 oops, which is quite a difference to our simple hello.mms program. Using the -O3 option (optimization) or -mabi=mmixware to use the register stack to pass variables you can reduce this overhead considerable. But that is a different topic. What we explain next is the use of a high level debugger using the GNU compatible version of mmix called mmixgdb (Win32, Linux).

Using the GNU debugger gdb with MMIX

The GNU debugger will work especially nice, if it finds debug information in the executable. So we start by producing an executable file containing debug information. We do this with the command line
mmix-gcc -g -melf hello.c -o hello.elf

The GNU debugger comes in two forms: a simple command line version and a version with a sophisticated GUI, called insight. Both need to communicate with the program under inspection, so to use either of them, you need a version of MMIX that understands the gdb remote protocol. mmixgdb, which is part of the Virtual Motherboard collection of programs, is such a program.

As explained in the Hello World Example with VMB to simulate a computer, the Virtual Motherboard Architecture uses a collection of simulators for different devices, that work together, very much like real hardware, to simulate a complex system.

For this example, we need to following components: The motherboard (Win32, Linux), RAM (Win32, Linux) to hold the application program, ROM (Win32, Linux) and a ROM Image bios.img to contain the BIOS implementing the operating system, and a screen (Win32, Linux) to display output. Since our example does not use Input, a keyboard (Win32, Linux) is not strictly necessary, we add it, however, to make the system complete and who knows, may be you want to experiment with the system and use input. Finally we need a version of the MMIX CPU (Win32, Linux) that knows how to work with the Virtual Motherboard and GDB.

The complete system is started by the motherboard (using a common configuration file default.vmb) .So double click on the mother board (Win32), or type mother in a terminal window (Linux), and you will find the system starting. Press the Power button (Win32) or type the command on (Linux) to get it running. You will then see the line Connecting to gdb... in the MMIX CPU window. So next we start the debugger with the command-line:

mmix-gdb hello.elf

and get the output

GNU gdb
Copyright 2005 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General 
Public License, and you are welcome to change it 
and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  
Type "show warranty" for details.
This GDB was configured as "--host=i386-pc-mingw32 --target=mmix"...

To connect the debugger to the running CPU we type

(gdb) target remote :2331

Next, we load the file we had given on the command line as an argument to gdb into the simulator using the command:

(gdb) load

It produces output like this:

Loading section .init, size 0x78 lma 0x100
Loading section .text, size 0xeb14 lma 0x178
Loading section .fini, size 0x3c lma 0xec8c
Loading section .rodata, size 0x5f4 lma 0xecc8
Loading section .eh_frame, size 0x4 lma 0x2000000000000000
Loading section .ctors, size 0x10 lma 0x2000000000000008
Loading section .dtors, size 0x10 lma 0x2000000000000018
Loading section .jcr, size 0x8 lma 0x2000000000000028
Loading section .data, size 0x101c lma 0x2000000000000030
Start address 0x180

Next, we set a breakpoint at the begin of the main program with the command

(gdb) break main
Breakpoint 1 at 0x2c0: file hello.c, line 4.

Using the continue command (short c) we start the program and see it stop when it hits the breakpoint at main. At that point it displays information about source file and line number, and you can print the content of variables, and use all other features of gdb.

(gdb) c
Breakpoint 1, main (argc=0, argv=0x0) at hello.c:4
4       { printf("Hello world!\n");
(gdb) n
5         return 0;
Much of this can be automated by putting these command in the gdb initialization file. So make a file .gdbinit (note the leading dot) and put in it the lines
target remote :2331
break main

Next time you start gdb or insight, these commands will be executed on startup automatically. To start insight, the GUI version of gdb, start the simulator as before and switch on power, then type the command:

mmix-insight --args hello.elf

The debugger will start connect to the simulator load the hello.elf file into the simulator and set a break point at main. The simulator has not yet booted. It is at the begin of the BIOS, where it can not yet display the source. Just hit the Continue key and the debugger will stop right at the first line of the main program and display the source file. If you want to see the BIOS also in the debugger - read the next section.

Making the BIOS using the GNU Binutils

To make the BIOS using the GNU binutils, we use the following commands:

mmix-as -g bios.mms -o bios.o
mmix-ld --entry=0x8000000000000000 --oformat elf64-mmix bios.o -o bios.elf
mmix-objcopy -O binary bios.elf bios.img

The first line just assembles the mmix source file, the second links it into an elf binary specifying the address of the entry point to be 0x8000000000000000 (that is the address where MMIX starts booting), and the last line uses the object copy program (Win32, Linux),to convert the format into binary data to obtain an image file. That's it.

Start gdb again. But, surprise, it will still not know the debug information for the BIOS. Sure, how could it! The bios.img file after all was not loaded by the debugger, but directly mapped into memory through the ROM device, and second, the image file does not contain debug information. It is just the binary. You can however tell gdb where it finds additional symbol information with this command:

(gdb) add-symbol-file bios.elf

The debugger will read the elf file and immediately know where it is. Now you can step through the bios code, set breakpoints etc... If you start to do development with the BIOS, it is probably a good idea to add this command to the .gdbinit file as well.

Further Examples

Now that you have worked your way to the end of this example, the fun-part is ready to start. There are some more examples waiting for you that illustrate different techniques and/or devices.

The Stopwatch example implements - trust its name - a Stopwatch using a sevensegment display, three buttons and a timer. It is programmed entirely in ROM. So there is no RAM, no user program, just a specialized BIOS. This is a good example to look at if you want to program BIOS routines that handle interrupts.

The Minesweeper example features an implementation of the well known Windows program. It uses a frame buffer device with GPU for graphics output and a mouse for input. There is no character oriented screen device and no keyboard. It is an extended program written in MMIX Assembler.

The MMIX on MMIX example has a BIOS that can handle a FAT32 filesystem on a simulated hard drive. The Filesystem code is written in C, compiled and linked together with the rest of the BIOS. The Application is MMIX itself. The simulator code is translated from its original form as a cweb file to a c file, then compiled to MMIX code and runs on the MMIX simulating the MMIX (you can take that idea to any level). The example illustrates a fairly complex BIOS running a fairly complex program.

A very different approach to operating systems is TinyOS, and the Blink example runs the Blink program from the TinyOS tutorials on the MMIX under TinyOS. Using the GNU Tool chain, both the BIOS and the Application are build from nesc Code. TinyOS is an operating system developed for wireless sensor networks and stresses efficiency. It's interesting to see how the requirements of such an OS can be mapped to the MMIX architecture.

The Linux example is still under construction. It boots an MMIX under Linux ...

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