MMIX Style Guide
Style Guide for MMIX Assembler ProgrammingThis is an evolving collection of hints how to write readable programs in MMIX assembly language.
CommentsAll subroutines should start with a short comment explaining the code to follow. After that, use comments only if the comment adds information, that is not yet obvious from the code. It is better to have readable code without comments than unreadable code with comments.
The Stack FrameA subroutine starts with setting up its stack frame. The stack frame contains parameters and local variables. For most subroutines, it is sufficient to name the appropriate registers.
Therefore, the code should start naming the parameters and local register variables.
Often you need a temporary variable, just to move data from one instruction to the next. One temporary variable is almost always enough. If you need more than one, think about naming them appropriately. It is good practice to make the temporary variable the last of the local variables (see Nested Subroutines below).
You may use $0 just before a POP 1,0 to receive the function return value. For example:
% converting a number to an ASCII digit d IS $0 parameter ToAscii ADD $0,d,'0' POP 1,0or
% computing the sum of an array a of n tetras a IS $0 parameters n IS $1 s IS $2 local variables tmp IS $3 Sum SET s,0 JMP 2F 1H LDT tmp,a,0 ADD s,s,tmp ADD a,a,4 SUB n,n,1 2H BP n,1B SET $0,s POP 1,0
Local NamespaceIf you use multiple subroutines, name conflicts will be inevitable, unless you use the PREFIX pseudo instruction. In most cases you have a separate namespace for each subroutine. It can have the same name as the subroutine itself. The entry point of the subroutine is usually the only "global" name defined by a subroutine.
PREFIX :Sum: % computing the sum of an array a of n tetras a IS $0 parameters n IS $1 s IS $2 local variables tmp IS $3 :Sum SET s,0 JMP 2F 1H LDT tmp,a,0 ADD s,s,tmp ADD a,a,4 SUB n,n,1 2H BP n,1B SET $0,s POP 1,0In the example above, the subroutine is referenced in the rest of the program by :Sum.
Calling SubroutinesThe most convenient way to pass parameters to a subroutine is the following:
LDA tmp+1,my_array SET tmp+2,my_size PUSHJ tmp,:SumNote that assigning a different register number to tmp will automatically renumber the corresponding registers for the argument values. Further, all local variables and parameters (having local register numbers smaller than tmp) will keep their values during the subroutine call.
Nested SubroutinesIf one subroutine calls another subroutine, this is called nested subroutines. Two things need to be done: saving the return address and passing parameters.
The most common error when doing so is not saving and restoring the rJ register, which contains the return address for the POP instruction. There are two preferred places to save and restore rJ
Example: Using the above function :Sum, we can write the function :Average.
PREFIX :Average: % compute the average of an array a of n tetras a IS $0 parameters n IS $1 return IS $2 local variables tmp IS $3 :Sum GET return,:rJ SET tmp+1,a SET tmp+2,n PUSHJ tmp,:Sum FLOT tmp,tmp FLOT n,n FDIV $0,tmp,n PUT :rJ,return POP 1,0or
PREFIX :Average: % compute the average of an array a of n tetras a IS $0 parameters n IS $1 return IS $2 local variables tmp IS $3 :Sum SET tmp+1,a SET tmp+2,n GET return,:rJ PUSHJ tmp,:Sum PUT :rJ,return FLOT tmp,tmp FLOT n,n FDIV $0,tmp,n POP 1,0
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