Instructions
Instruction listings
The BELLE-ISA has 16 instructions. Below is a description, definition, use case, and example of every instruction.
Please refer to the encoding document for more information about the specifics on how certain arguments are encoded, particularly the meaning of “determinant bits” and the different encodings that each instruction can use. This document omits such information for brevity’s sake, as it is already quite long.
Note: The BELLE-ISA uses 16 bit long memory addresses.
Rounding: For instructions that will round a number, the number will simply have its decimal points cut off. It will not be rounded to the nearest integer, it will simply have the decimal places removed. (e.g. 4.5 becomes 4)
HLT - Halt
HLT
will halt BELLE when it is encountered. The program will stop and gracefully exit, and no other instructions will be executed.
In binary, it is simply 16 consecutive zeros, thus making it possible to call a halt instruction by simply loading a zero into a memory address and performing a jump to the address.
HLT
takes no arguments, and is not compatible with any argument types.
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
HLT | None | Halt BELLE | Halting once the overflow flag is set. | hlt ; Stop the program |
Flags affected: running
state.
Binary encoding
Instruction: hlt
Opcode | Rest of instruction |
---|---|
[0000] | [000000000000] |
Pseudocode representation
ADD - Addition
ADD
will perform arithmetic addition, taking the second operand (right-hand side), and adding it to the first operand (left-hand side), storing the result in the first operand. ADD
will always take 2 arguments, and can also perform subtraction if the value in RHS is negative.
ADD
will perform floating point arithmetic as the 6th and 7th registers are floating-point, however the values will be cast to integers if the destination is an integer register.
ADD
can only perform floating-point-to-floating-point addition if the two floating-point registers are passed as arguments. Literal values cannot be floating point.
Compatible LHS argument types: Register
Compatible RHS argument types: Register, literal, register pointer, memory address pointer, can be signed and unsigned
Flags affected: None
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
ADD | 2 | ADD two values | Adding values in a Fibonacci sequence | add r0, 3 ; add 3 to r0 |
Binary encoding
Instruction: add r4, &r3
Opcode | LHS | DTBs | RHS |
---|---|---|---|
[0001] | [100] | [0010] | [00011] |
Pseudocode representation
JO and JZ - Conditional jump
JO - Jump if the overflow flag is set, JZ - Jump if the zero flag is set
JO
and JZ
perform conditional jumps, which set the CPU’s program counter to the destination specified.
JO
will only jump if the overflow flag on the CPU is set. This flag becomes set if an arithmetic operation (e.g. add
, mul
) overflows the destination register.
JZ
will only jump if the zero flag is set. This flag becomes set if a compare instruction (cmp
) has two operands that are of the same value.
When JO
or JZ
are performed, the memory address that it is performed at is “push
ed” onto the call stack. This memory address is known as a return address and is retrieved if the jump is to be returned from. Thus, if a value is to be retrieved off the stack after JO
or JZ
, the return address must first be removed, or the stack and base pointers must be adjusted.
Note: The value it pushes onto the stack may overflow a memory address, as memory address values are signed but the addresses themselves are not. Thus, if the program is very large or starts at a very high memory address, it may not be feasible to retrieve a jumped address as it may have overflowed. This is unlikely unless the assembly program is above 27,000 lines of source code.
The overflow flag can be set unconditionally with int 21
, unset with int 22
, and inverted with int 23
.
The zero flag can be set unconditionally with int 11
, unset with int 12
, and inverted with int 13
.
As subroutines and labels in assembly resolve to memory addresses, JO
and JZ
will always jump to a memory address if the jump location is a subroutine, granted the destination is small enough to fit within 11
bits.
JO
and JZ
can also take a register pointer argument, meaning that the value in a register is interpreted as a memory address for the destination of a jump. This must be set manually, as the assembler will not do this.
Using a register as the destination can be beneficial, as r4
and r5
are unsigned 16 bit integers, being able to address all memory addresses. It is also possible to pass r6
or r7
- the floating point registers - to this instruction.
If the condition is not met, the jump will simply be skipped, and the next instruction will be executed accordingly.
Note: Any jump instruction can overflow the stack if it is full
Compatible DEST types: Register pointer, memory address
Flags affected: Affected by overflow flag and zero flag. Cannot change any flags.
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
JO | 1 | Jump if overflow flag is true | Leaving a loop when a register overflows | jo [3] ; jump to address 3 if overflow flag is set |
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
JZ | 1 | Jump if zero flag is true | Jumping somewhere after a cmp | jz [42] ; jump to address 42 if zero flag is set |
Binary encoding
Instruction: jo &r3
Opcode | DTB | DEST |
---|---|---|
[0010] | [1] | [00000000011] |
Binary encoding
Instruction: jz [1]
Opcode | DTB | DEST |
---|---|---|
[1001] | [0] | [00000000001] |
Pseudocode representation
POP - Pop off the stack
POP
reads the stack pointer, and then “pop
s” the value contained at the stack pointer into a destination. The destination can only be a register, and POP
will only ever take one argument. The value at the top of the call stack - which is referenced with the stack pointer - will be cleared, and the stack pointer will be adjusted depending on the direction the call stack is “going”.
If a POP
instruction is called whilst the stack pointer does not point to a value, the CPU will report a stack underflow - a type of segmentation fault - where the call stack does not have enough data to satisfy a POP
instruction.
As the memory is composed of signed 16 bit integers, the values “pop
ped” off it will always be 16 bit signed integers. Thus, it is typically unnecessary to pop
into a floating point register or an unsigned 16-bit register.
Compatible DEST argument types: Register
Flags affected: None
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
POP | 1 | Take a value off the stack | Retrieving a memory address from a JMP | pop %r4 ; pop a value off the stack into register 4 |
Binary encoding
Instruction: pop r2
Opcode | DEST |
---|---|
[0011] | [000000000010] |
Pseudocode representation
DIV - Division
DIV
divides LHS by RHS, storing the result in LHS.
DIV
will perform arithmetic division between the two arguments passed to it, and the result will be cast to an integer if the destination is not a register capable of storing floating point values (any register that is not register 6 or 7).
If DIV
results in a value with a remainder, the remainder flag
will be set.
Compatible LHS argument types: Register
Compatible RHS argument types: Register, literal, register pointer, memory address pointer, can be signed and unsigned
Flags affected: Remainder flag
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
DIV | 2 | DIVide two values | Floating-point math | div r4, 3 ; divide value in r4 by 3 |
Binary encoding
Instruction: div r1, &2
Opcode | LHS | DTBs | RHS |
---|---|---|---|
[0100] | [001] | [0100] | [00010] |
Pseudocode representation
RET - Return
RET
will read the value that the memory address that the stack pointer points to holds. The program counter will then be set to this address, and the memory address will be cleared. This instruction is similar to the POP
instruction, however, it doesn’t load the value into a register.
RET
takes no arguments.
RET
can be used after a jump instruction is called to return to where the jump instruction was called from if the return address is still on the top of the call stack. If not, it is possible to create a return address on the call stack by saving the return address after a jump, then pushing it back on before RET
is called.
Example:
Compatible argument types: None
Flags affected: None
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
RET | None | Return | Returning from a jump | ret |
Binary encoding
Instruction: ret
Opcode | Rest of instruction |
---|---|
[0101] | [000000000000] |
Pseudocode representation
LD - Load direct
LD
will read the memory address provided by the RHS, and retrieve the value at the memory address specified. Then, the value will be loaded into the register provided by the LHS of the instruction. If no value is found, a segmentation fault will occur, and the emulator will halt.
Compatible LHS argument types: Register
Compatible RHS argument types: Memory address
Flags affected: None
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
LD | 2 | Load from address to register | Loading to registers | ld r0, [40] ; load value at address 40 into r0 |
Binary encoding
Instruction: ld r5, [42]
Opcode | LHS | RHS |
---|---|---|
[0110] | [101] | [000101010] |
Pseudocode representation
ST - Store direct and indirect
ST
takes two arguments, and retrieves the value in the RHS register and stores it into the LHS. LHS can be either a register pointer, or a direct memory address. This allows the ST
instruction to addresses all addresses if used indirectly via a register pointer. ST
will overwrite any data at the destination address, and it can also overwrite program memory if the destination address is also part of program memory. Using ST
in conjunction with LD
or with the call stack can allow for full usage of the memory of the BELLE-ISA.
If a given register pointer is negative, the value will simply be stored at address 0.
Compatible LHS argument types: Register pointer, memory address
Compatible RHS argument types: Register
Flags affected: None
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
ST | 2 | Store into an address | <--- | st [4], r1 ; store r1 into addr 4 |
Binary encoding
Instruction: st &r3, r4
Opcode | DTB | LHS | RHS |
---|---|---|---|
[0111] | [1] | [011] | [00000100] |
Pseudocode representation
JMP - Unconditional jump
JMP
performs an unconditional jump, which sets the CPU’s program counter to the destination specified.
When JMP
is performed, the memory address that it is performed at is “push
ed” onto the call stack. This memory address is known as a return address and is retrieved if the jump is to be returned from. Thus, if a value is to be retrieved off the stack after JMP
, the return address must first be removed, or the stack and base pointers must be adjusted.
Note: The value it pushes onto the stack may overflow a memory address, as memory address values are signed but the addresses themselves are not. Thus, if the program is very large or starts at a very high memory address, it may not be feasible to retrieve a jumped address as it may have overflowed. This is unlikely unless the assembly program is above 27,000 lines of source code.
As subroutines and labels in assembly resolve to memory addresses, JMP
will always jump to a memory address if the jump location is a subroutine, granted the destination is small enough to fit within 11
bits.
JMP
can also take a register pointer argument, meaning that the value in a register is interpreted as a memory address for the destination of a jump. This must be set manually, as the assembler will not do this.
Using a register as the destination can be beneficial, as r4
and r5
are unsigned 16 bit integers, being able to address all memory addresses. It is also possible to pass r6
or r7
- the floating point registers - to this instruction.
Note: Any jump instruction can overflow the stack if it is full
Compatible DEST types: Register pointer, memory address
Flags affected: None
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
JMP | 1 | Jump | Recursion | jmp [31] ; jump to address 31 |
Binary encoding
Instruction: jmp [50]
Opcode | DTB | DEST |
---|---|---|
[1000] | [0] | [00000110010] |
Pseudocode representation
CMP - Compare two operands
CMP
Takes two arguments and compares their values, setting flags accordingly. The zero and sign flags are affected with this instruction, with the sign flag being set if the compared values result in a negative result, and the zero flag being set if they are equal. CMP
requires two arguments.
The CMP
instruction can take registers, literals, register pointers, and memory address pointers on the RHS, and it can only take a register on the LHS.
CMP
will set the sign flag if the LHS is less than the RHS (if the result is negative), and it will be unset if the LHS is greater than the RHS.
CMP
can be used along with JZ
to perform a conditional jump out of a loop after recursion occurs enough times in a loop.
Compatible LHS argument types: Register
Compatible RHS argument types: Register, literal, register pointer, memory address pointer, can be signed and unsigned
Flags affected: Zero flag, sign flag
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
CMP | 2 | Compare RHS and LHS | Exiting loops | cmp r3, 4 ; compare value in r3 to literal 4 |
Binary encoding
Instruction: cmp r4, 1
Opcode | LHS | DTBs | RHS |
---|---|---|---|
[1010] | [0100] | [1000] | [0001] |
Pseudocode representation
MUL - Multiplication
MUL
will perform arithmetic signed floating point multiplication (as there are floating point registers), and will cast the value to an integer if the destination is an integer register.
MUL
can also be used for division if the RHS is a decimal value less than one. In particular, if it is a floating point register containing a decimal value less than one.
MUL
, in conjunction with ADD
and MOV
can be used to change register values to very large numbers, thus allowing large memor y addresses to be addressed with indirect loading and storing via ST
and MOV
.
Similar to the other arithmetic instructions, MUL
does not take floating point literal values.
Compatible LHS argument types: Register
Compatible RHS argument types: Register, literal, register pointer, memory address pointer, can be signed and unsigned
Flags affected: None
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
MUL | 2 | Multiply two values | Achieving large numbers in registers | mul r4, 3 ; multiply r4 by 3 |
Binary encoding
Instruction: mul r2, 42
Opcode | LHS | DTBs | RHS |
---|---|---|---|
[1011] | [010] | [1] | [00101010] |
Pseudocode representation
PUSH - Push a value onto the stack
PUSH
will take either a register or literal value, increment or decrement the stack pointer depending on the direction of the call stack, then assign the memory address in the stack pointer to the value passed to the instruction.
PUSH
can be used in conjunction with POP
to easily manipulate values on the stack, and understanding both instructions can allow for efficient utilization of the call stack, reducing the need to directly use memory addresses.
PUSH
will take one argument.
If the stack pointer will become negative if it is decremented or go above the unsigned 16 bit integer limit if it is incremented (depending on the direction of the call stack), the PUSH
instruction will result in a stack overflow, where the stack will have ran out of space to continue to add values onto it.
When a jump instruction is called, PUSH
is also called internally to push a return address onto the call stack.
Compatible SRC argument types: Register, literal
Flags affected: None
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
PUSH | 1 | Push onto the stack | Pushing a return address | push 4 ; push literal 4 onto stack |
Binary encoding
Instruction: push 55
Opcode | Padding | DTBs | RHS |
---|---|---|---|
[1100] | [000] | [1] | [00110111] |
Pseudocode representation
INT - Pseudo-instruction/“interrupt”
INT
is a “pseudo-instruction”. In other architectures, INT
is the “interrupt” instruction, which generates a system interrupt to stop the program momentarily to perform an action, such as reading from the standard input, writing to the standard output, or waiting for an event to finish.
In the BELLE-ISA, however, INT
also has further functionality beyond a simple interrupt. INT
is the pseudo-instruction instruction, being able to perform tasks such as setting, unsetting, and inverting flags. INT
exists to keep the size of the ISA small, as implementing separate instructions to perform these tasks would greatly increase the number of instructions in the ISA.
INT
was chosen as the name as some functionalities are modeled after system interrupts, however, it is not primarily an interrupt instruction, and can be utilized to alter CPU flags or generate an “interrupt”.
INT
takes one literal argument, and depending on the literal argument passed, it will perform a different action.
Compatible SRC argument types: Literal
Below is a table for interrupt codes and their functions.
| Code | Action |
|:------|:----------------------------------------------------------------------------------------------------|
| 0-7 | Print the value at the register specified by code
to stdout as their numeric values |
| 8 | Print values from memory indexed by r0
to r1
as characters |
| 9 | Read a single byte from stdin and store it in r0
|
| 10 | Pause the CPU for 1 second |
| 11 | Set the zero flag |
| 12 | Unset the zero flag |
| 13 | Invert the zero flag |
| 20 | Set the maximum clock cycles to the value in r0
|
| 21 | Set the overflow flag |
| 22 | Unset the overflow flag |
| 23 | Invert the overflow flag |
| 31 | Set the remainder flag |
| 32 | Unset the remainder flag |
| 33 | Invert the remainder flag |
| 41 | Set the sign flag |
| 42 | Unset the sign flag |
| 43 | Invert the sign flag |
| 51 | Make the CPU halt on overflow |
| 52 | Make the CPU not halt on overflow |
| 53 | Invert the CPU’s halt on overflow property |
| 60 | Set the stack pointer to the value in r4
|
| 61 | Set the base pointer to the value in r4
|
Flags affected: All
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
INT | 1 | Pseudo-instruction | Printing to stdout | int 52 ; don't halt on overflow |
Binary encoding
Instruction: int #42
Opcode | SRC |
---|---|
[1101] | [000000101010] |
MOV - Move
MOV
will move a value from a source to a destination, keeping the source intact. MOV
takes two arguments, and the RHS can be a literal, register pointer, memory address pointer, register, and can be both signed and unsigned. Similar to other instructions, MOV
uses floating point reassignments to reassign values of registers, and if the destination is an integer register, casts it as an integer.
MOV
can accept floating point values to move around if the source is a floating point register. Otherwise, it will only accept an integer.
The destination, or the LHS of MOV
must always be a register. To change memory address values, please refer to ST.
The source, or RHS of MOV
cannot be a memory address. Refer to LD for loading from memory addresses.
Unlike LD
, however, MOV
allows register indirects - otherwise known as register pointers - to be passed as the RHS of the instruction. This allows for MOV
to load from very large memory addresses that wouldn’t fit into a simple LD
instruction. Thus, MOV
is also the indirect load instruction (in other architectures).
Compatible LHS argument types: Register
Compatible RHS argument types: Register, literal, register pointer, memory address pointer, can be signed and unsigned
Flags affected: None
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
MOV | 2 | Copy a value | Any program ever | mov r0, 22 ; mov 22 into r0 |
Binary encoding
Instruction: mov r4, &r3
Opcode | LHS | DTBs | RHS |
---|---|---|---|
[1110] | [100] | [0010] | [00011] |
Pseudocode representation
NOP - No operation
NOP
is an instruction that does absolutely nothing - or as close to nothing as possible - and continues the program.
In BELLE, the emulated NOP
instruction calls a real NOP
instruction via inline assembly.
Flags affected: None
Name | Arguments | Description | Use case | Example |
---|---|---|---|---|
NOP | 0 | NO-OP | Timing alignments | nop ; do nothing |
Binary encoding
Instruction: nop
Opcode | Rest of instruction |
---|---|
[1111] | [000000000000] |