Registers
r0 - r12
The above registers are general purpose registers; Meaning that you can set them to integers, read from them and use them in commands.
acc
The Accumulator has two roles.
-
Acts as a general purpose register
-
Stores the result of the logic operators (teq, tne, …)
Special Operators
#
Syntax: #[number]
The above operator is used to define tell the compiler that the number following it is a constant.
+
Syntax: + [cmd]
The above operator is a prefix. Commands prefixed with this execute only if the value stored in the accumulator is not equal to 0.
Example: + mov r0 #100
In the above example, the value of r0 will be set to 100, only if the value stored in the accumulator is not equal to 0.
labels
Syntax: [name]:
Labels are used to define subroutines. You need to write the name of the subroutine and add a colon to define a label. All the instructions following it have to be indented.
Example:
start: mov r0 #100 end: mov r7 #1 swi
General Commands
mov
Syntax: mov [register] [constant]
This sets the value of the specified register to the specified constant
Example: mov r10 #23
In the above example, the value of r10 is set to 23
Syntax: print [register | constant]
This prints the value stored in the specified register, or the constant to the console
Example: print r4
| print #10
In the first example, the value of r4 is printed. In the second example, 10 is printed.
swi
Syntax: swi
This checks the value in r7 and performs actions. As of right now, it defaults to exit the program no matter which value is stored in r7.
Arithmetic
add
Syntax: add [register to store the result] [register | constant] [register | constant]
This adds the values of the first two arguments and stores it in the register specified by the first argument.
Example: add r0 r1 r2
sub
Syntax: sub [register to store the result] [register | constant] [register | constant]
This subtracts the value of the second argument by the value of the third argument and stores it in the register specified by the first argument.
Example: sub r0 r0 #100
mul
Syntax: sub [register to store the result] [register | constant] [register | constant]
This multiplies the value of the first argument by the value of the second argument and stores it in the register specified by the first argument.
Example: mul r0 #1233333 #100000
div
Syntax: div [register to store the result] [register | constant] [register | constant]
This divides the value of the first argument by the value of the second argument and stores it in the register specified by the first argument.
Example: div r0 r4 #78
Logic
teq
Syntax: teq [register | constant] [register | constant]
This tests whether the value of the first argument is equal to the value of the second argument and stores the result as a 1 (True) or 0 (False) in the 'acc' register.
Example: teq r0 #100
tne
Syntax: tne [register | constant] [register | constant]
This tests whether the value of the first argument is not equal to the value of the second argument and stores the result as a 1 (True) or 0 (False) in the 'acc' register.
Example: tne #10 #20
tgt
Syntax: tgt [register | constant] [register | constant]
This tests whether the value of the first argument is greater than the value of the second argument and stores the result as a 1 (True) or 0 (False) in the 'acc' register.
Example: tgt r8 r12
tgte
Syntax: tgte [register | constant] [register | constant]
This tests whether the value of the first argument is greater than or equal to the value of the second argument and stores the result as a 1 (True) or 0 (False) in the 'acc' register.
Example: tgte #100 r1
tlt
Syntax: tlt [register | constant] [register | constant]
This tests whether the value of the first argument is lesser than the value of the second argument and stores the result as a 1 (True) or 0 (False) in the 'acc' register.
Example: tlt r0 r2
tlte
Syntax: tlte [register | constant] [register | constant]
This tests whether the value of the first argument is lesser than or equal to the value of the second argument and stores the result as a 1 (True) or 0 (False) in the 'acc' register.
Example: tlte r0 #100
Subroutines
jmp
Syntax: jmp [label]
This pushes the current page to the stack and executes the instructions of the specified subroutine.
Example: jmp add_loop
In the above example, the program will jump to the 'add_loop' subroutine and execute its instructions.
return
Syntax: return
This ends the current subroutine and returns to the subroutine that called it.
Structure
Similar to public static void main(String[] args)
in Java and func main()
in Go, the subroutine _start
is where the main code goes to.
_start: ....
While you could most definitely write all your code in the _start
subroutine, you could create other subroutines to help out as well, as you will see below.
Example Project
Let’s build an example project. This project will add the number 23 to r0, fifteen times. Here’s how it would look.
_start: mov r0 #0 mov r1 #0 jmp add_loop jmp end add_loop: add r0 r0 #23 add r1 r1 #1 tne r1 #15 + jmp add_loop return end: print r1 print r0 mov r7 #1 swi
In _start
, we set the value of r0 (The main result) to 0 and the value of r1 (The counter) to 0. We then jump to the add_loop
subroutine. Once it returns, we jump to the end
subroutine.
In add_loop
, we add 23 to the value stored in r0, and increment r1 by 1. We then check if the value stored in r1 is not equal to 15, which will lead to calling the same subroutine again. This is done until the value of r1 is equal to 15, where we return to the calling subroutine by using the return
keyword (Though it does have to fall through quite a few pages).
In end
, we print the value of r1 (The counter) and r0 (The value) and end the program. You could run it for yourself and see if the output is correct.