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 |
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.
python hmmm program.hmmm -o program.hb python hmmm -d program.hbIn 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.
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.
Assembly | Binary | Description |
---|---|---|
halt | 0000 0000 0000 0000 | Halt program |
nop | 0110 0000 0000 0000 | Do nothing |
read rX | 0000 XXXX 0000 0001 | Stop
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 rX | 0000 XXXX 0000 0010 | Print 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, rY | 0100 XXXX YYYY 0000 | Load register rX from memory word addressed by rY: rX = memory[rY] |
storer rX, rY | 0100 XXXX YYYY 0001 | Store contents of register rX into memory word addressed by rY: memory[rY] = rX |
popr rX rY | 0100 XXXX YYYY 0010 | Load contents of register rX from stack pointed to by register rY: rY -= 1; rX = memory[rY] |
pushr rX rY | 0100 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, rY | 0110 XXXX YYYY 0000 | Set rX = rY |
neg rX, rY | 0111 XXXX 0000 YYYY | Set rX = -rY |
add rX, rY, rZ | 0110 XXXX YYYY ZZZZ | Set rX = rY + rZ |
sub rX, rY, rZ | 0111 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 rX | 0000 XXXX 0000 0011 | Set program counter to address in rX |
jumpn n | 1011 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 # |
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'.
Command | Effect |
---|---|
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. |
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. |
# 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 haltThis 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
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 haltThis 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
# 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 numberHere 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.