-
Notifications
You must be signed in to change notification settings - Fork 90
Instruction Set
The instruction table and instructions are sorted alphabetically.
Current opcodes in use
0
1, 2, 3, 4, 5, 6, 7, 8 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49 50
63
Current opcodes unsused
51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
61, 62
| Instruction mnemonic | Operands | Opcode | C Z S O B |
|---|---|---|---|
| ADD destination, source | mem/reg, mem/reg/imm | 0x02 | X X X X - |
| AND destination, source | mem/reg, mem/reg/imm | 0x04 | 0 X X 0 - |
| BRK | None | 0x00 | - - - - 1 |
| CALL target | mem/reg/imm | 0x15 | - - - - - |
| CMP destination, source | mem/reg, mem/reg/imm | 0x0C | X X X X - |
| DEC destination | mem/reg | 0x2B | - X X X - |
| DIV source | mem/reg/imm | 0x18 | - - - - - |
| HWI source | mem/reg/imm | 0x09 | - - - - - |
| HWQ source | mem/reg/imm | 0x1C | - - - - - |
| INC destination | mem/reg | 0x2A | - X X X - |
| INT | imm (0-255) | 0x30 | - - - - - |
| INTO | None | 0x08 | - - - - - |
| IRET | None | 0x31 | - - - - - |
| JA target | mem/reg/imm | 0x2E | - - - - - |
| JAE target | mem/reg/imm | 0x22 | - - - - - |
| JC target | mem/reg/imm | 0x21 | - - - - - |
| JG target | mem/reg/imm | 0x0F | - - - - - |
| JGE target | mem/reg/imm | 0x10 | - - - - - |
| JL target | mem/reg/imm | 0x11 | - - - - - |
| JLE target | mem/reg/imm | 0x12 | - - - - - |
| JMP target | mem/reg/imm | 0x0A | - - - - - |
| JNA target | mem/reg/imm | 0x2F | - - - - - |
| JNC target | mem/reg/imm | 0x22 | - - - - - |
| JNO target | mem/reg/imm | 0x25 | - - - - - |
| JNS target | mem/reg/imm | 0x1B | - - - - - |
| JNZ target | mem/reg/imm | 0x0D | - - - - - |
| JO target | mem/reg/imm | 0x24 | - - - - - |
| JS target | mem/reg/imm | 0x1A | - - - - - |
| JZ target | mem/reg/imm | 0x0E | - - - - - |
| MOV destination, source | mem/reg, mem/reg/imm | 0x01 | - - - - - |
| MUL source | mem/reg/imm | 0x17 | X - - X - |
| NEG destination | mem/reg | 0x19 |
X X X X -* |
| NOP | None | 0x3F | - - - - - |
| NOT destination | mem/reg | 0x1D | - - - - - |
| OR destination, source | mem/reg, mem/reg/imm | 0x05 | 0 X X 0 - |
| POP destination | mem/reg | 0x14 | - - - - - |
| POPF | None | 0x2C | X X X X - |
| PUSH source | mem/reg/imm | 0x13 | - - - - - |
| PUSHF | None | 0x2D | - - - - - |
| RCL destination, count | mem/reg, mem/reg/imm | 0x27 | X - - X - |
| RCR destination, count | mem/reg, mem/reg/imm | 0x28 | X - - X - |
| RET optional-pop-value | imm/None | 0x16 | - - - - - |
| ROL destination, count | mem/reg, mem/reg/imm | 0x23 | X - - X - |
| ROR destination, count | mem/reg, mem/reg/imm | 0x20 | X - - X - |
| SAL destination, count | mem/reg, mem/reg/imm | 0x06 | X - - X - |
| SAR destination, count | mem/reg, mem/reg/imm | 0x29 | X - - X - |
| SETcc destination | mem/reg | 0x32 | - - - - - |
| SETA destination | mem/reg | 0x32 | - - - - - |
| SETAE destination | mem/reg | 0x32 | - - - - - |
| SETB destination | mem/reg | 0x32 | - - - - - |
| SETBE destination | mem/reg | 0x32 | - - - - - |
| SETC destination | mem/reg | 0x32 | - - - - - |
| SETE destination | mem/reg | 0x32 | - - - - - |
| SETG destination | mem/reg | 0x32 | - - - - - |
| SETGE destination | mem/reg | 0x32 | - - - - - |
| SETL destination | mem/reg | 0x32 | - - - - - |
| SETLE destination | mem/reg | 0x32 | - - - - - |
| SETS destination | mem/reg | 0x32 | - - - - - |
| SETO destination | mem/reg | 0x32 | - - - - - |
| SETZ destination | mem/reg | 0x32 | - - - - - |
| SETNA destination | mem/reg | 0x32 | - - - - - |
| SETNAE destination | mem/reg | 0x32 | - - - - - |
| SETNB destination | mem/reg | 0x32 | - - - - - |
| SETNBE destination | mem/reg | 0x32 | - - - - - |
| SETNC destination | mem/reg | 0x32 | - - - - - |
| SETNE destination | mem/reg | 0x32 | - - - - - |
| SETNG destination | mem/reg | 0x32 | - - - - - |
| SETNGE destination | mem/reg | 0x32 | - - - - - |
| SETNL destination | mem/reg | 0x32 | - - - - - |
| SETNLE destination | mem/reg | 0x32 | - - - - - |
| SETNO destination | mem/reg | 0x32 | - - - - - |
| SETNS destination | mem/reg | 0x32 | - - - - - |
| SETNZ destination | mem/reg | 0x32 | - - - - - |
| SHL destination, count | mem/reg, mem/reg/imm | 0x06 | X - - X - |
| SHR destination, count | mem/reg, mem/reg/imm | 0x07 | X - - X - |
| SUB destination, source | mem/reg, mem/reg/imm | 0x03 | X X X X - |
| TEST destination, source | mem/reg, mem/reg/imm | 0x0B | 0 X X 0 - |
| XCHG destination, source | mem/reg, mem/reg | 0x1F | - - - - - |
| XOR destination, source | mem/reg, mem/reg/imm | 0x26 | 0 X X 0 - |
This is an effort to specify the specific MAR Assembly Instruction Set and its behavior. The instruction set is a subset of the 8086 instruction set. A more detailed specification of the 8086 Instruction Set can be found here. Note that the MAR Instruction Set can differ from the 8086 Instruction Set.
This manual tries to describe how to use the instructions and show any side effects they might have.
Each instruction has a Mnemonic or syntax. This is the way the instruction is written in human readable format. This exists of the instruction name and its operands (if any).
MOV A, 0x20This human readable format is parsed by the assembler which will output the actual binary opcodes and operands.
Instructions are 1-3 words long and are fully defined by the first word.
In a basic instruction, the lower 6 bits of the first word of the instruction
are the opcode, and the remaining 10 bits are split into a 5 bit destination operand
and a 5 bit source operand.
In bits, a basic instruction has the format: sssssdddddoooooo
Operand value:
| Description | Value |
|---|---|
| Invalid or none | 00000 |
| Immediate value at IP+1 | 11111 |
| [Immediate value at IP+1] | 11110 |
| Register |
00001-01000
|
| [Register] |
01001-10000
|
| Register + Immediate value at IP+1 |
10001-11000
|
Some instructions will change certain flags based on their result. These are in a special non read-write register. These flags are used for the family of jump instructions. You can also use the PUSHF and POPF instructions to query and manipulate the flags
for more information check the docs NOTE: The table below was copied from the link above. There is more info available, if you have trouble understanding the flags we strongly suggest you read the section in the link.
| Flag | Description |
|---|---|
| CF (Carry flag) | Relevant for unsigned operations. Indicates that there was a carry out of the most significant (leftmost) bit |
| ZF (Zero flag) | Indicates that the result of an operation is 0 |
| SF (Sign flag) | Indicates that the most significant (leftmost) bit of the result of an operation is set |
| OF (Overflow flag) | Relevant for signed operations. Indicates that the sign of the result of an signed operation is wrong (See examples below) |
| BF (Break flag) | Tells the CPU to stop the execution. This flag is set with the BRK instruction. |
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
ADD destination, source |
0x02 |
destination : reg / mem
|
X |
X |
X |
X |
- |
source : reg / mem / imm
|
ADD replaces the destination operand with the sum of the source and destination operands. It sets the carry flag if there is an overflow.
destination = destination + source| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
AND destination, source |
0x04 |
destination : reg / mem
|
0 |
X |
X |
0 |
- |
source : reg / mem / imm
|
AND performs a bit-by-bit logical AND operation on its operands
and stores the result in destination. AND sets each bit of the
result to one if both of the corresponding bits of the operands
are one.
destination = destination & source| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
BRK |
0x00 |
- |
- |
- |
- |
1 |
BRK sets the break flag. This will halt execution until the next game 'tick', where it will be cleared and execution resumes from the start of the .text label.
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
CALL target |
0x15 |
target : reg / mem / imm
|
- |
- |
- |
- |
- |
CALL pushes the current instruction pointer on to the stack and then performs a jump to the target address
SP = SP - 1
memory[SP] = IP
IP = target| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
CMP destination, source |
0x0C |
destination : reg / mem
|
X |
X |
X |
X |
- |
source : reg / mem / imm
|
CMP compares two numbers by subtracting the source from the
destination and updates the flags. None of the operands are
changed.
destination - source # flags will be set| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
DEC destination |
0x2B |
destination : mem / reg
|
- |
X |
X |
X |
- |
DEC subtracts one from the value of destination, replacing the previous value. Unlike SUB the carry flag is not modified. If you wish the carry flag to be modified then use sub dest, 1 instead
destination = destination - 1| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
DIV source |
0x18 |
source : mem / reg / imm
|
- |
- |
- |
- |
X |
DIV performs unsigned division on Y:A with source as divisor and stores the result into A and the remainder in Y.
Division by zero triggers a INT 0
NOTE:
DIVoperates on a 32 bit integer composed ofY:A. So multipleDIVinstructions without setting Y to what you want will result into unexpected results
This is a somewhat complicated instruction, see the source if needed
if source == 0:
ERROR_FLAG = 1
BREAK_FLAG = 1
# temp is a 32-bit integer
temp = (Y << 16) | A
A = temp / source # result is floored
Y = temp % source| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
HWI source |
0x09 |
source : reg / mem / imm
|
- |
- |
- |
- |
- |
HWI triggers a Hardware Interrupt. source should be the address of the hardware device. This is different from the RAM memory addresses. See the documentation of the hardware devices to see what an HWI does for each device.
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
HWQ source |
0x1C |
source : mem / reg / imm
|
- |
- |
- |
- |
- |
HWQ queries the hardware id of the hardware at the hardware address specified by source
if hardware_memory[source] != None:
B = get_hardware_id(
hardware_memory[source]
)
else:
B = 0| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
INC destination |
0x2A |
destination : mem / reg
|
- |
X |
X |
X |
- |
INC adds one to the value of destination, replacing the previous value. Unlike ADD the carry flag is not modified. If you wish the carry flag to be modified then use add dest, 1 instead
destination = destination + 1| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
JA target |
0x2E |
target : mem / reg / imm
|
- |
- |
- |
- |
- |
JA jumps to the target if the carry flag and the zero flag are NOT set.
if CARRY_FLAG == 0 and ZERO_FLAG == 0:
IP = targetJAE is an alias for the JNC instruction
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
JC target |
0x21 |
target : mem / reg / imm
|
- |
- |
- |
- |
- |
JC jumps to the target if the carry flag IS set.
if CARRY_FLAG == 1:
IP = target| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
JG target |
0x0F |
target : reg / mem / imm
|
- |
- |
- |
- |
- |
JG performs a jump if the sign flag IS EQUAL to the overflow flag AND the zero flag IS NOT set.
if SIGN_FLAG == OVERFLOW_FLAG and ZERO_FLAG == 0:
IP = target| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
JGE target |
0x10 |
target : reg / mem / imm
|
- |
- |
- |
- |
- |
JGE performs a jump if the sign flag IS EQUAL to the overflow flag
if SIGN_FLAG == OVERFLOW_FLAG:
IP = target| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
JL target |
0x11 |
target : reg / mem / imm
|
- |
- |
- |
- |
- |
JL performs a jump if the sign flag IS NOT EQUAL to the overflow flag
if SIGN_FLAG != OVERFLOW_FLAG:
IP = target| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
JLE target |
0x12 |
target : reg / mem / imm
|
- |
- |
- |
- |
- |
JLE performs a jump if the sign flag IS NOT EQUAL to the overflow flag OR the zero flag IS set
if SIGN_FLAG != OVERFLOW_FLAG or ZERO_FLAG == 1:
IP = target| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
JMP target |
0x0A |
target : reg / mem / imm
|
- |
- |
- |
- |
- |
JMP performs an unconditional jump to the target memory address and will resume execution there.
IP = target| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
JNC target |
0x22 |
target : mem / reg / imm
|
- |
- |
- |
- |
- |
JNC jumps to the target if the carry flag IS NOT set.
if CARRY_FLAG == 0:
IP = target| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
JNO target |
0x25 |
target : mem / reg / imm
|
- |
- |
- |
- |
- |
JNO jumps to the target if the overflow flag IS NOT set.
if OVERFLOW_FLAG == 0:
IP = target| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
JNS target |
0x1B |
target : mem / reg / imm
|
- |
- |
- |
- |
- |
JNS jumps to the target if the sign flag IS NOT set.
if SIGN_FLAG == 0:
IP = target| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
JNZ target |
0x0D |
target : reg / mem / imm
|
- |
- |
- |
- |
- |
JNZ performs a jump if the zero flag IS NOT set.
if ZERO_FLAG == 0:
IP = target| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
JO target |
0x24 |
target : mem / reg / imm
|
- |
- |
- |
- |
- |
JO jumps to the target if the overflow flag IS set.
if OVERFLOW_FLAG == 1:
IP = target| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
JS target |
0x1A |
target : mem / reg / imm
|
- |
- |
- |
- |
- |
JS jumps to the target if the sign flag IS set.
if SIGN_FLAG == 1:
IP = target| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
JZ target |
0x0E |
target : reg / mem / imm
|
- |
- |
- |
- |
- |
JZ performs a jump if the the zero flag IS set.
if ZERO_FLAG == 1:
IP = target| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
MOV destination, source |
0x01 |
destination : reg / mem
|
- |
- |
- |
- |
- |
source : reg / mem / imm
|
MOV transfers (copies) a word from the source operand to the destination operand.
destination = source| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
MUL source |
0x17 |
source : mem / reg / imm
|
X |
- |
- |
X |
- |
MUL performs unsigned multiplication with A and source and stores the result into Y:A.
The result of the multiplication is stored into Y:A where the higher order bits are stored in Y and the lower order bits are stored in A
The carry and overflow flags are set to 1 if the high-order of the result is bigger than 0; otherwise, CF and OF are reset to 0.
This is a somewhat complicated instruction, see the source if needed
# result is a 32-bit integer
result = A * source
# get the 16 most significant bits of result
higher_order_word = (result & 0xff00)
if higher_order_word != 0:
OVERFLOW_FLAG = 1
CARRY_FLAG = 1
Y = higher_order_word
else:
OVERFLOW_FLAG = 0
CARRY_FLAG = 0
A = (result & 0x00ff)
# result is stored in Y:A
# you can check if you need Y by check the flags| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
NEG destination |
0x19 |
destination : mem / reg
|
X |
X |
X |
X |
- |
NEG subtracts the destination operand from 0 and returns the result in the destination. This effectively produces the two's complement of the operand.
If the operand is zero, the carry flag is cleared; in all other cases, the carry flag is set.
Attempting to negate a word containing -32,768 causes no change to the operand and sets the Overflow Flag.
if destination == 0:
CARRY_FLAG = 0
ZERO_FLAG = 1
else:
CARRY_FLAG = 1
if destination == -32768:
OVERFLOW_FLAG = 1
else
destination = 0 - destination # or destination = destination + (-dest)| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
NOP |
0x3F |
- |
- |
- |
- |
- |
NOP is an instruction that performs no operation. Often used for timing purposes, as a placeholder or for aligning purposes.
# do nothing| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
NOT destination |
0x1D |
source : mem / reg
|
- |
- |
- |
- |
- |
NOT inverts each bit in its operand, i.e. forms the one's complement.
dest = ~dest| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
OR destination, source |
0x05 |
destination : reg / mem
|
0 |
X |
X |
0 |
- |
source : reg / mem / imm
|
OR performs a bit-by-bit logical inclusive OR operation on its
operands and returns the result to destination. OR sets each bit
of the result to one if either or both of the corresponding bits
of the operands are one.
destination = destination | source| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
POP destination |
0x14 |
destination : reg / mem
|
- |
- |
- |
- |
- |
POP copies the value of the memory address specified in the stack pointer to the destination and increments the stack pointer.
The stack grows downwards from 0xFFFF -> 0x0000 So incrementing will 'shrink' the stack
destination = memory[SP]
SP = SP + 1| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
POPF |
0x2C |
X |
X |
X |
X |
- |
Pops a word of the top of the stack and uses the 4 lowest bits of the result to set the CPU flags. In the order sign, zero, carry and overflow also represented by the following bit pattern xxxx xxxx xxxx SZCO.
All flags will be according to the corresponding bit values of given word. To only set on flag a PUSHF to query the flags and a bitmask with the desired flag to manipulate should be used.
flags = memory[SP]
SIGN_FLAG = flags & (1 << 3)
ZERO_FLAG = flags & (1 << 2)
CARRY_FLAG = flags & (1 << 1)
OVERFLOW_FLAG = flags & 1
SP = SP + 1| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
PUSH source |
0x13 |
source : reg / mem / imm
|
- |
- |
- |
- |
- |
PUSH decrements the stack pointer by one and then copies source to the address the stack pointer is pointing to.
The stack grows downwards from 0xFFFF -> 0x0000 So decrementing will 'grow' the stack
SP = SP - 1
memory[SP] = source| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
PUSHF |
0x2D |
- |
- |
- |
- |
- |
Pushes the current flags on top of the stack. The flags are present in the 4 lowest bits of the result on the stack. In the order sign, zero, carry and overflow also represented by the following bit pattern xxxx xxxx xxxx SZCO.
To get the state of a single flag you can use a bit mask.
example: the operation flags & 0100 will give a result of 1 if the zero flag was set and a result of 0 if it was unset
# 0000 0000 0000 SZCO
flags = (SIGN_FLAG << 3) | (ZERO_FLAG << 2) | (CARRY_FLAG << 1) | (OVERFLOW_FLAG)
SP = SP - 1
memory[SP] = flags| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
RCL destination, count |
0x27 |
destination : mem / reg
|
X |
- |
- |
X |
- |
count : mem / reg, imm
|
RCL shifts the bits of the destination operand to the left by the
number of bit positions specified in the count operand. A bit
shifted out of the left (high-order) end of the destination enters
the carry flag (CF), and the displaced carry flag rotates around
to enter the vacated right-most bit position of the destination.
Another way of looking at this is to consider the carry flag as
the highest order bit of the word being rotated.
if count is bigger than 16 it will be the remainder of a division by 17.
The shift is repeated the number of times indicated by the count operand
if count equals 1 then the overflow flag will be set if the sign bit of destination has changed
count = count % 17
# TODO: less implementation more pseudo code
if (destination & 0x8000) > 0:
old_sign_bit = 1
else
old_sign_bit = 0
destination = # ... RCL magic
# carry flag might be set
if (destination & 0x8000) > 0:
new_sign_bit = 1
else:
new_sign_bit = 0
if count == 1:
OVERFLOW_FLAG = (old_sign_bit != new_sign_bit)| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
RCR destination, count |
0x28 |
destination : mem / reg
|
X |
- |
- |
X |
- |
count : mem / reg / imm
|
RCR shifts the bits of the destination operand to the right by the
number of bit positions specified in the count operand. A bit
shifted out of the right (low-order) end of the destination enters
the carry flag (CF), and the displaced carry flag rotates around
to enter the vacated left-most bit position of the destination.
Another way of looking at this is to consider the carry flag as
the lowest order bit of the word being rotated.
if count is bigger than 16 it will be the remainder of a division by 17.
The shift is repeated the number of times indicated by the count operand
if count equals 1 then the overflow flag will be set if the sign bit of destination has changed
count = count % 17
# TODO: less implementation more pseudo code
if (destination & 0x8000) > 0:
old_sign_bit = 1
else
old_sign_bit = 0
destination = # ... RCR magic
# carry flag might be set
if (destination & 0x8000) > 0:
new_sign_bit = 1
else:
new_sign_bit = 0
if count == 1:
OVERFLOW_FLAG = (old_sign_bit != new_sign_bit)| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
RET [amount] |
0x16 |
amount : imm / None
|
- |
- |
- |
- |
- |
RET jumps to the address stored at the stack pointer and then increments (pops) that address of the stack.
When amount is given increment the stack pointer the number of times given in amount.
IP = memory[SP]
if amount == None:
amount = 0
SP = SP + 1 + amount| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
ROL destination, count |
0x23 |
destination : mem / reg
|
X |
- |
- |
X |
- |
count : mem / reg, imm
|
ROL shifts the bits of destination operand to the left by the number of bit positions specified by count.
if count is greater than 15 it will be the remainder of a division by 16.
as bits are transferred out the left (high-order) end of the destination, they re-enter on the right (low-order) end. The carry flag (CF) is updated to match the last bit shifted out of the left end.
if count equals 1 then the overflow flag will be set if the sign bit of destination has changed
count = count % 16
# TODO: less implementation more pseudo code
if (destination & 0x8000) > 0: # check if sign bit was set
old_sign_bit = 1
else
old_sign_bit = 0
destination = #... ROL magic
# carry flag might be set
if (destination & 0x8000) > 0: # check if sign bit was set
new_sign_bit = 1
else
new_sign_bit = 0
if count == 1:
OVERFLOW_FLAG = (old_signbit != new_signbit) # check if sign bit changed
# TODO: less implementation more pseudo code
if (destination & 0x01) == 1:
CARRY_FLAG = 1
else:
CARRY_FLAG = 0| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
ROR destination, count |
0x20 |
destination : mem / reg
|
X |
- |
- |
X |
- |
count : mem / reg, imm
|
ROR shifts the bits of destination operand to the right by the number of bit positions specified by count.
if count is greater than 15 it will be the remainder of a division by 16.
as bits are transferred out the right (low-order) end of the destination, they re-enter on the left (high-order) end. The carry flag (CF) is updated to match the last bit shifted out of the right end.
if count equals 1 then the overflow flag will be set if the sign bit of destination has changed
count = count % 16
# TODO: less implementation more pseudo code
if (destination & 0x8000) > 0: # check if sign bit was set
old_sign_bit = 1
else
old_sign_bit = 0
destination = #... ROR magic
if (destination & 0x8000) > 0: # check if sign bit was set
new_sign_bit = 1
else
new_sign_bit = 0
if count == 1:
OVERFLOW_FLAG = (old_signbit != new_signbit) # check if sign bit changed
if new_sign_bit == 1:
CARRY_FLAG = 1
else:
CARRY_FLAG = 0SAL is an alias for the SHL instruction
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
SAR destination, count |
0x29 |
destination : mem / reg
|
X |
X |
X |
X |
- |
count : mem / reg/ imm
|
The SAR (Shift Arithmetic Right) instruction shifts the bits of the destination operand downward (toward the least significant bit) by the number of bit positions specified in the second operand (count).
As bits are transferred out of the right (low-order) end of the destination, bits equal to the original sign bit are shifted into the left (high-order) end, thereby preserving the sign bit. The carry flag (CF) is set equal to the last bit shifted out of the right end.
If the count operand is not an immediate 1, the overflow flag (OF) is undefined; otherwise SAR resets OF to zero.
TODO: Not sure if this part is implemented, should check source code
TODO: Plain english? (now copy pasta from the manual)
destination = destination <<< count
#NOTE: be aware of the difference between a logical and an arithmetic shift| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
SHL destination, count |
0x06 |
destination : reg / mem
|
X |
X |
X |
X |
- |
count : reg / mem / imm
|
SHL (Shift Logical Left) shifts the bits of the destination operand upward (toward the
most significant bit) by the number of bit positions specified in
the second operand (count). As bits are transferred out of the
left (high-order) end of the destination, zero bits are shifted
into the right (low-order) end.
The carry flag (CF) is set equal to the last bit shifted out of the left end.
destination = destination << count
#NOTE: be aware of the difference between a logical and an arithmetic shift| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
SHR destination, count |
0x07 |
destination : reg / mem
|
X |
- |
- |
X |
- |
count : reg / mem / imm
|
SHR (Shift Logical Right) shifts the bits of the destination operand downward (toward
the least significant bit) by the number of bit positions
specified in the second operand (count). As bits are transferred
out of the right (low-order) end of the destination, zero bits are
shifted into the left (high-order) end.
destination = destination >> count
#NOTE: be aware of the difference between a logical and an arithmetic shift| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
SUB destination, source |
0x03 |
destination : reg / mem
|
X |
X |
X |
X |
- |
source : reg / mem / imm
|
SUB subtracts the source operand from the destination operand and stores the result in destination.
destination = destination - source| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
TEST destination, source |
0x0B |
destination : reg / mem
|
0 |
X |
X |
0 |
- |
source : reg / mem / imm
|
TEST performs a bitwise AND operation on its two operands and
updates the flags. None of the operands are changed.
destination & source # flags will be set| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
XCHG destination, source |
0x1F |
destination : mem / reg
|
- |
- |
- |
- |
- |
source : mem / reg
|
XCHG switches the contents of two operands.
temp = destination
destination = source
source = temp| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
|---|---|---|---|---|---|---|---|
XOR destination, source |
0x26 |
destination : reg / mem
|
0 |
X |
X |
0 |
- |
source : reg / mem / imm
|
XOR performs a bit-by-bit "exclusive or" on its two operands, and returns the result in the destination operand. XOR sets each bit of the result to one if only one of the corresponding bits is set to one.
destination = destination ^ source