A cheatsheet for Hack's virtual machine language




About

This cheatsheet assumes that you are using this compiler. However, most of the information is also applicable to compilers that follow the specifications of TECS

Use the navigation bar to jump to a section of interest



General

Case sensitive

File extension is .vm



Comments

Single line comments start with //



Valid Names

A valid name must begin with a letter or underscore. The remaining characters can be digits, letters, or underscores



Operations

Unary

Operates on most recent stack value

Arithemtic

neg Negate

Bitwise

not Not

For example:


push constant 6
neg              // yields -6

Binary

Operates on the two most recent stack values

Arithemtic

add Add

sub Subtract

mul Multiply*

div Divide*

Comparison

eq Equal to

ne Not equal to

lt Less than

gt Greater than

lte Less than or equal

gte Greater than or equal

Bitwise

and And

or Or

xor Xor*

lsl Logical shift left*

lsr Logical shift right*

For example:


push constant 5
push constant 3
sub              // yields 2

push constant 3
neg              // yields -3
push constant 2
gte              // yields false  ( is -3 gte 2, false )

Notes

The mul, div, xor, lsl, and lsr operations assume that the Hack computer's ALU can perform them. Though not present in the official TECS architecture, I am in the process of adding them to my version of the ALU



"Segments"

A look at Hack's memory layout diagram might be helpful

temp

Memory segment

Holds arbitrary temporary variables

static

Memory segment

Holds the static variables of the classes used by the running program

local

Pseudo memory segment in stack

Holds the local (var type) variables declared by the current subroutine

arg

Pseudo memory segment in stack

Holds the arguments passed to the current subroutine

this

Pointer

Set to point to the base address of the current class instance

Used to access the instance's field variables. For example this 0 points to field 0

For example:


//	method void setZ ( int zNew ) {
//
//		z = zNew;
//	}

method Point.setZ 2   // two arguments: pointer to instance, zNew

	push argument 0
	pop  pointer  0   // Memory[ THIS ] = argument 0 (pointer to instance)

	push argument 1   // zNew
	pop  this     2   // z = zNew
	                  // Memory[ Memory[ THIS ] + 2 ] = zNew
	                  // In this example, Point class has 3 field variables (x, y, z)

	push constant 0   // return 0
	return

that

Pointer

Typically used to access the contents of an array

This is accomplished by setting that to the array's base address + desired index

For example:


//	function void foo ( Array a, int b, int c ) {
// 
//		a[ b ] = c;
//	}

function className.foo 0

	push argument 1   // b
	push argument 0   // a (base address)
	add
	pop  pointer  1   // Memory[ THAT ] = a + b

	push argument 2   // c
	pop  that     0   // Memory[ Memory[ THAT ] + 0 ] = c
	                  // Memory[ a + b ] = c

	push constant 0   // return 0
	return

pointer

Pseudo memory segment. It is not allocated space in memory

Used to access the values of the THIS and THAT pointers:

pointer 0 accesses the THIS pointer

pointer 1 accesses the THAT pointer

Generates assembly code equivalent to:


// -- Retrieve value of THIS pointer and place it in stack --

// push pointer 0
@THIS
D = M;   // top of stack = Memory[ THIS ]


// -- Set value of THIS pointer to most recent stack value --

// pop pointer 0
@THIS
M = D;   // Memory[ THIS ] = top of stack

constant

Pseudo memory segment. It is not allocated space in memory

Used to push positive integers onto the stack



Stack Actions

Move data into and out of the stack

push

push segmentName index

Copy the value in the specified location (segmentName index), and place it in the stack

pop

pop segmentName index

Remove the most recent value from the stack, and place it in the specified location (segmentName index)

See "segments"

Where index is an integer in the range 0 to 32767 (inclusive)



Jump Actions

Jump to a location in the program code

goto

goto labelName

Jumps immediately to labelName

if-goto

if-goto labelName

If some condition is true, jumps immediately to labelName

Assumes that the result (True or False) of evaluating the condition is the most recent value on the stack

For example:


push argument 0
push constant 78
gt                 // result of gt comparison is placed on stack
if-goto SOMEWHERE  // program counter jumps to SOMEWHERE if the result is true

call

call subroutineName numberOfArguments

Assumes that the arguments intended for the subroutine have already been pushed to the stack

First saves the caller's return address and state (values for the LCL, ARG, THIS, and THAT pointers)1

Then jumps to subroutineName

return

return

Returns to the current subroutine's caller

First restores the caller's state (values for the LCL, ARG, THIS, and THAT pointers)1

Then jumps to the saved return address

Note:

1The save and restore code is generated by the VM compiler



Targets

Specific locations in the program

label

label labelName

Marks a point in the program

Used in conjunction with goto labelName and if-goto labelName

For example:


//	function void countdown ( int n ) {
//
//		while ( n > 0 ) {
//
//			n -= 1;
//		}
//
//		GFX.printChar( '!' );
//	}

function Point.countdown 0

	label WHILE_COND

		push argument 0
		push constant 0
		gt
		if-goto WHILE_BODY    // if n > 0, goto WHILE_BODY
		goto WHILE_END        // else, goto WHILE_END

	label WHILE_BODY

		push argument 0
		push constant 1
		sub
		pop argument 0        // n = n - 1
		goto WHILE_COND

	label WHILE_END

		push constant 33      // '!'
		call GFX.printChar 1
		pop temp 0

	push constant 0           // return 0
	return

function

function subroutineName numberOfLocalVariables

Block of code

Expects zero or more arguments, uses zero or more local variables, and returns a value

First sets the THIS pointer to:

The value returned by a call to DataMemory.alloc( numberOfFieldVariables ) if the subroutine is a constructor

argument 0 if the subroutine is a method

For example:


//	constructor Point new ( int ax, int ay ) {
//
//		x = ax;
//		y = ay;
//
//		return this;
//	}

function Point.new 0

	push constant 2           // In this example, Point class has 2 field variables (x, y)
	call DataMemory.alloc 1   // DataMemory.alloc( 2 )
	pop  pointer  0           // Memory[ THIS ] = DataMemory.alloc( 2 )

	push argument 0           // ax
	pop  this     0           // x = ax
	push argument 1           // ay
	pop  this     1           // y = ay  

	push pointer  0           // return Memory[ THIS ]
	return

//	method int subt ( int x2 ) {
//
//		var int s;
//
//		s = x - x2;
//
//		return s;
//	}

function Point.subt 2         // two arguments: pointer to instance, x2

	push argument 0
	pop  pointer  0           // Memory[ THIS ] = argument 0

	push this     0           // x
	push argument 1           // x2
	sub
	pop  local    0           // s = x - x2

	push local    0           // return s
	return

See valid names