[top]

Documentation for HMMM
(Harvey Mudd Miniature Machine)

Last update: 2024

Quick reference: Table of Hmmm Instructions


Instruction    Description Aliases
System instructions
halt Stop! None
read rX Place user input in register rX None
write rX Print contents of register rX None
nop Do nothing None
Setting register data
setn rX N Set register rX equal to the integer N (-128 to +127) None
addn rX N Add integer N (-128 to 127) to register rX None
copy rX rY Set rX = rY mov
Arithmetic
add rX rY rZ Set rX = rY + rZ None
sub rX rY rZ Set rX = rY - rZ None
neg rX rY Set rX = -rY None
mul rX rY rZ Set rX = rY * rZ None
div rX rY rZ Set rX = rY // rZ (integer division; rounds down; no remainder) None
mod rX rY rZ Set rX = rY % rZ (returns the remainder of integer division) None
Jumps!
jumpn N Set program counter to address N None
jumpr rX Set program counter to address in rX jump
jeqzn rX N If rX == 0, then jump to line N jeqz
jnezn rX N If rX != 0, then jump to line N jnez
jgtzn rX N If rX > 0, then jump to line N jgtz
jltzn rX N If rX < 0, then jump to line N jltz
calln rX N Copy addr. of next instr. into rX and then jump to mem. addr. N call
Interacting with memory (RAM)
pushr rX rY Store contents of register rX onto stack pointed to by reg. rY None
popr rX rY Load contents of register rX from stack pointed to by reg. rY None
loadn rX N Load register rX with the contents of memory address N None
storen rX N Store contents of register rX into memory address N None
loadr rX rY Load register rX with data from the address location held in reg. rY loadi, load
storer rX rY Store contents of register rX into memory address held in reg. rY storei, store


Table of Contents

Introduction

Hmmm the (Harvey Mudd Miniature Machine) is a 16-bit, 26-instruction simulated assembly language with 28 = 256 16-bit words of memory. Hmmm is written in Python, and it is intended as an introduction to assembly coding in general. Programs written in Hmmm consist of numbered lines with one instruction per line, and comments.

Hmmm is implemented as a single program written in Python. By default, hmmm will assemble and run a file written in the Hmmm assembly language. There are options that to assemble a program without executing it, to run a previously assembled program, and to invoke a built-in debugger.

Installing Hmmm

Hmmm is available online in the form of source code from the HMC CS5 website at http://www.cs.hmc.edu/twiki/bin/view/CS5/Resources. If you plan on installing it on your own machine, you will need a working version of Python 3 but nothing more. Download the hmmm file and put it in a directory where you will also write your Hmmm programs.

Using Hmmm

Please refer to your lecture notes and the current Hmmm assignment for an introduction to using Hmmm.

The Basics

To assemble (compile) and run a Hmmm program, simply type "python hmmm" at the command prompt. Hmmm will ask for an input file, assemble it, and if assembly succeeds it will also run it. (On Macs, you may be able to save some effort by typing "./hmmm filename.hmmm" where filename.hmmm is the name of your Hmmm program.

Getting Fancy

Hmmm accepts accepts the -h, --help, -d, and -o options. -h and --help print explanations of all of the options. -d invokes the Hmmm debugger. If -o is given, followed by a file name, the program is assembled and the result is written to the named file; later Hmmm can be run on that file to execute it. For example:

python hmmm program.hmmm -o program.hb
python hmmm -d program.hb
In debug mode, type "h" or "help" at the debug mode prompt for information on debugging commands, or see the diagnostic features section of this document.

File Types

The assembler and the simulator are both file-type independent. Generally, however, files with a 'hmmm' (hmmm assembly) extension are Hmmm code, while files with an 'hb' (hmmm binary) extension are assembled Hmmm binary. (Because Hmmm is only a simulator, the binary files are actually text files and are readable and editable with standard text editors).

Code Format

Each line of Hmmm code consists of a line number, an instruction, and one or more arguments. The line numbers must start at 0 and be consecutive integers, and they must be placed at the beginning of the line with no preceding characters. After the line number, use at least one character of whitespace to separate the instruction. The line number corresponds directly to the memory address of the line. Free (writable) memory begins at the address immediately after the last line of the program.

The instruction consists of a single word; all of the instructions are composed of lowercase alphabetic characters. After the instruction there must be at least one space and then 0 or more arguments, separated by any combination of whitespace and commas. The number of arguments depends on the instruction.

Each argument must be either a register or a number. Registers are denoted by 'r' followed by the number of the register, as in 'r3'. Numbers must fit in 8 bits. (Their decimal value must either be in the range -128 to 127 inclusive, or 0 to 255 inclusive, depending on the particular instruction. This is because numbers are represented using a method called "twos complement".) Each argument must be separated from any preceding arguments by any combination of whitespace and ',' characters, and the line may optionally be ended with some combination of whitespace and comments.

See the examples section for examples of proper and improper syntax.

Comments in Hmmm are identical to comments in Python: a '#' character begins a comment that continues to the end of the line. Comments are allowed both on empty lines and after the arguments on instruction lines. Comments on otherwise empty lines should not have line numbers, and will not be counted towards the line number of any following lines. Completely blank lines are also permitted

Machine Organization

Hmmm simulates a computer that has sixteen 16-bit registers and 256 16-bit words of memory. The program is loaded into memory starting at location 0, so a program 12 lines long has 244 free words of memory starting at location 12 (locations 0 through 11 are occupied by the program's instructions). The program counter starts at location 0 and is incremented by 1 each cycle. It can also be redirected using the various jump commands. Each cycle, the simulator reads the instruction at the memory location pointed to by the program counter and executes it. This continues until it executes a halt instruction.

15 of the 16 registers are interchangeable from a hardware standpoint (although refer to the conventions below). The only special register is r0. When used as a source operand, r0 always provides a zero; when used as a destination it discards the result.

The Hmmm Instruction Set

There are 26 different instructions in Hmmm, each of which accepts between 0 and 3 arguments. Two of the instructions, setn and addn, accept a signed numerical argument between -128 and 127. The load, store, call, and jump instructions accept an unsigned numerical argument between 0 and 255. All other instruction arguments are registers. In the code below, register arguments will be represented by 'rX', 'rY', and 'rZ', while numerical arguments will be represented by '#'. In real code, any of the 16 registers could take the place of 'rX' 'rY' or 'rZ'. The available instructions are:

AssemblyBinaryDescription
halt0000 0000 0000 0000Halt program
nop0110 0000 0000 0000Do nothing
read rX0000 XXXX 0000 0001Stop for user input, which will then be stored in register rX (input is an integer from -32768 to +32767).
Prints "Enter number: " to prompt user for input
write rX0000 XXXX 0000 0010Print the contents of register rX on standard output
setn rX, #0001 XXXX #### ####Load an 8-bit integer # (-128 to +127) into register rX
loadr rX, rY0100 XXXX YYYY 0000 Load register rX from memory word addressed by rY: rX = memory[rY]
storer rX, rY0100 XXXX YYYY 0001 Store contents of register rX into memory word addressed by rY: memory[rY] = rX
popr rX rY0100 XXXX YYYY 0010 Load contents of register rX from stack pointed to by register rY: rY -= 1; rX = memory[rY]
pushr rX rY0100 XXXX YYYY 0011 Store contents of register rX onto stack pointed to by register rY: memory[rY] = rX; rY += 1
loadn rX, #0010 XXXX #### ####Load register rX with memory word at address #
storen rX, #0011 XXXX #### ####Store contents of register rX into memory word at address #
addn rX, #0101 XXXX #### ####Add the 8-bit integer # (-128 to 127) to register rX
copy rX, rY0110 XXXX YYYY 0000 Set rX = rY
neg rX, rY0111 XXXX 0000 YYYY Set rX = -rY
add rX, rY, rZ0110 XXXX YYYY ZZZZ Set rX = rY + rZ
sub rX, rY, rZ0111 XXXX YYYY ZZZZ Set rX = rY - rZ
mul rX, rY, rZ 1000 XXXX YYYY ZZZZ Set rX = rY * rZ
div rX, rY, rZ 1001 XXXX YYYY ZZZZ Set rX = rY // rZ
mod rX, rY, rZ 1010 XXXX YYYY ZZZZ Set rX = rY % rZ
jumpr rX0000 XXXX 0000 0011Set program counter to address in rX
jumpn n1011 0000 #### ####Set program counter to address #
jeqzn rX, #1100 XXXX #### #### If rX = 0 then set program counter to address #
jnezn rX, #1101 XXXX #### #### If rX ≠ 0 then set program counter to address #
jgtzn rX, #1110 XXXX #### #### If rX > 0 then set program counter to address #
jltzn rX, #1111 XXXX #### #### If rX < 0 then set program counter to address #
calln rX, #1011 XXXX #### #### Set rX to (next) program counter, then set program counter to address #

Input and Output

Hmmm supports incredibly simplified I/O in the form of the read and write instructions.

The read instruction prompts the user to enter a number and, after a number is typed, puts it into the given register. If the number is too big or too small, or if it is otherwise bad, read will complain and prompt the user again. As a special convenience, if the user types "q" intead of a number, the program will immediately halt. The write instruction simply writes the given register to the user's console.

Halting The Program

The halt instruction immediately ends the program and stops Hmmm. In addition, at any point during execution, the user can type ctrl-C to stop the program, and entering 'q' at either the debug-mode prompt or the input prompt will stop the program. Typing ctrl-D at any prompt will also stop the program.

Diagnostic Features

The simulator program features a debug mode that is useful for diagnosing errors in the program. It is invoked using either the -d or --debug command-line options.

The debug mode prints information after executing each instruction, showing what instruction was just executed and where that instruction was found in memory (what the program counter was). It also prints the debug prompt. Any unrecognized input at the debug prompt causes the simulator to step one instruction forward. Recognized commands include 'c' or 'continue', 'd' or 'dump', 'h' or 'help', 'p' or 'print', 'q' or 'quit', and 'r' or 'run'.

CommandEffect
continue Causes the debugger to run through the rest of the program without prompting for debugging commands, but continuing to print debugging information.
dump Immediately prints the contents of memory, printing the code lines first (one per line, in binary) followed by the numeric contents of the rest of memory in 6 columns, and then asks for another debugging command.
help Prints a short summary of the debug commands and returns to the prompt.
print Prints the contents of the registers in a single column and returns to the prompt.
quit Causes the program to exit immediately.
run Causes the program to continue running as if it had been invoked with debug mode off: no debugging information is printed and no further prompts are given.

Examples

Good Code:

This is a well-written and -commented program that takes two numbers, echoes the first, and returns the first divided by the second, or 0 if the second is 0.

# program title
# author and date
# descriptive comment
0   read r1     # read dividend from the user
1   write r1    # echo the input
2   read r2     # read divisor from the user
3   jeqzn r2, 7 # jump to 7 if trying to divide by 0

4   div r3, r1, r2 # divide user's parameters
5   write r3    # print the result
6   halt

7   setn r3, 0  # 0 is the result for division by 0
8   write r3    # print the result
9   halt
This is the output from hmmm assembler when the program is run (note that the assembler truncates comments to make the lines fit neatly on your screen):


----------------------
| ASSEMBLY SUCCESSFUL |
----------------------

0: 0000 0001 0000 0001             0   read r1     # read dividend from the us
1: 0000 0001 0000 0010             1   write r1    # echo the input
2: 0000 0010 0000 0001             2   read r2     # read divisor from the use
3: 1100 0010 0000 0111             3   jeqzn r2, 7 # jump to 7 if trying to di
4: 1001 0011 0001 0010             4   div r3, r1, r2 # divide user's paramete
5: 0000 0011 0000 0010             5   write r3    # print the result
6: 0000 0000 0000 0000             6   halt
7: 0001 0011 0000 0000             7   setn r3, 0  # 0 is the result for divis
8: 0000 0011 0000 0010             8   write r3    # print the result
9: 0000 0000 0000 0000             9   halt

Enter number (q to quit): 42
42
Enter number (q to quit): 6
7

Bad Code:

This is the same program, with the same functionality. However, this is very low-quality code.

 0  read r1
1   write r1
2   read  r2 # read r2
3   jeqzn r2, 7
  4 div r3 r1, r2
5   write r3
6   halt        # end
7      setn r3  0
8   write r3
9   halt
This is the assembler output for the above code:


----------------------
| ASSEMBLY SUCCESSFUL |
----------------------

0: 0000 0001 0000 0001             0  read r1
1: 0000 0001 0000 0010             1   write r1
2: 0000 0010 0000 0001             2   read  r2 # read r2
3: 1100 0010 0000 0111             3   jeqzn r2, 7
4: 1001 0011 0001 0010             4 div r3 r1, r2
5: 0000 0011 0000 0010             5   write r3
6: 0000 0000 0000 0000             6   halt        # end
7: 0001 0011 0000 0000             7      setn r3  0
8: 0000 0011 0000 0010             8   write r3
9: 0000 0000 0000 0000             9   halt

Enter number (q to quit): 42
42
Enter number (q to quit): 7
6

Improper Syntax:

This is the same program a third time, this time modified to demonstrate improper syntax. This program will not assemble.

# program title
# program title
# author and date
# descriptive comment
0   read r1,    # trailing characters are not allowed
1   write[r1]   # no grouping symbols allowed
2   read r2, r3 # too many arguments here
3   jeqzn r2, r7 # second argument must be a number
4   div r3, r1r2 # arguments must be separated
5   write 3     # write argument must be a register
5   halt        # line number is incorrect
7   setn r3, 128     # maximum number for setn and addn commands is 127
                # (min is -128)
9   writer3     # instruction must be separated from argument
10halt          # instruction must be separated from line number
Here is the assembly output for this program, demonstrating the error messages for the errors listed above:


ARGUMENT ERROR:
WRONG NUMBER OF ARGUMENTS.
DETECTED 2 ARGUMENTS, EXPECTED 1 ARGUMENTS
read r1,   

SYNTAX ERROR ON LINE 1:
1   write[r1]   # no grouping symbols allowed

ARGUMENT ERROR:
WRONG NUMBER OF ARGUMENTS.
DETECTED 2 ARGUMENTS, EXPECTED 1 ARGUMENTS
read r2, r3

ARGUMENT ERROR:
'r7' IS NOT A VALID NUMBER.

ARGUMENT ERROR:
WRONG NUMBER OF ARGUMENTS.
DETECTED 2 ARGUMENTS, EXPECTED 3 ARGUMENTS
div r3, r1r2

REGISTER ERROR:
'3' IS NOT A VALID REGISTER.

BAD LINE NUMBER AT LINE 6:
LINE NUMBER: 5 EXPECTED 6

ARGUMENT ERROR:
'128' IS OUT OF RANGE FOR THE ARGUMENT.

OPERATION ERROR:
'writer IS NOT A VALID OPERATION.

SYNTAX ERROR ON LINE 9:
10halt          # instruction must be separated from line number

***** ASSEMBLY TERMINATED UNSUCCESSFULLY *****
              ASSEMBLY RESULTS:

0: ***ARGUMENT ERROR HERE***       0   read r1,    # trailing characters are n
1: ***SYNTAX ERROR HERE***         1   write[r1]   # no grouping symbols allow
2: ***ARGUMENT ERROR HERE***       2   read r2, r3 # too many arguments here
3: ***ARGUMENT ERROR HERE***       3   jeqzn r2, r7 # second argument must be 
4: ***ARGUMENT ERROR HERE***       4   div r3, r1r2 # arguments must be separa
5: ***REGISTER ERROR HERE***       5   write 3     # write argument must be a 
6: ***BAD LINE NUMBER HERE***      5   halt        # line number is incorrect
7: ***ARGUMENT ERROR HERE***       7   setn r3, 128     # maximum number for s
8: ***OPERATION ERROR HERE***      9   writer3     # instruction must be separ
9: ***SYNTAX ERROR HERE***         10halt          # instruction must be separ

***** ASSEMBLY FAILED, SEE ABOVE FOR ERRORS *****

Although it may not be obvious from the example above, the assembler will stop trying to assemble each line of code as soon as it finds an error. Thus, if a line of code has multiple errors in it, only one error will be reported. Once that error is fixed, the next error on that line will be reported if it is still there.

Contact Information

If this document is inaccurate or you believe that you have found a bug in hmmm, or if you think that something should be added to it, please contact the CS5 staff at the usual cs5help address.