Added first draft of instructions up to 0x1D

Kevin Ramharak 2017-12-30 00:53:41 +01:00
parent 53571e7e73
commit 804af72104

@ -63,3 +63,534 @@ Operand value:
| Register | `00001`-`01000` | | Register | `00001`-`01000` |
| [Register] | `01001`-`10000` | | [Register] | `01001`-`10000` |
| Register + Immediate value at IP+1 | `10001`-`11000` | | Register + Immediate value at IP+1 | `10001`-`11000` |
***
> NOTE: Work In Progress
# Instruction Set
## Introduction
This is an effort to specify the specific MAR Assembly Instruction Set and its behaviour. The instruction set is a subset of the 8086 instruction set. A more detailed specification if the 8086 Instruction Set can be found [here](http://www.ousob.com/ng/iapx86/ng2e5.php). 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).
```s
MOV A, 0x20
```
This human readable format is parsed by the assembler which will output the actual binary opcodes and operands. More about the encoding can be read [below](#Encoding).
## Instructions
### BRK
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `BRK` | `0x00` | | `-` | `-` | `-` | `-` | `1` |
#### Description
`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.
### MOV
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `MOV destination, source` | `0x01` | `destination` : `reg` / `mem` | `-` | `-` | `-` | `-` | `-` |
| | | `source` : `reg` / `mem` / `imm` |
#### Description
`MOV` transfers (copies) a word from the source operand to the destination operand.
#### Pseudo code
```py
destination = source
```
### ADD
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `ADD destination, source` | `0x02` | `destination` : `reg` / `mem` | `X` | `X` | `X` | `X` | `-` |
| | | `source` : `reg` / `mem` / `imm` |
#### Description
`ADD` replaces the destination operand with the sum of the source and destination operands. It sets the carry flag if there is an overflow.
### Pseudo code
```py
destination = destination + source
```
### SUB
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `SUB destination, source` | `0x03` | `destination` : `reg` / `mem` | `X` | `X` | `X` | `X` | `-` |
| | | `source` : `reg` / `mem` / `imm` |
#### Description
`SUB` subtracts the source operand from the destination operand and stores the result in destination.
> ? TODO: is this implemented?
> When an immediate byte value is subtracted from a word operand, the immediate value is first sign-extended to the size of the destination operand.
#### Pseudo code
```py
destination = destination - source
```
### AND
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `AND destination, source` | `0x04` | `destination` : `reg` / `mem` | `0` | `X` | `X` | `0` | `-` |
| | | `source` : `reg` / `mem` / `imm` |
#### Description
`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.
#### Pseudo code
```py
destination = destination & source
```
### OR
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `OR destination, source` | `0x05` | `destination` : `reg` / `mem` | `0` | `X` | `X` | `0` | `-` |
| | | `source` : `reg` / `mem` / `imm` |
#### Description
`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.
#### Pseudo code
```py
destination = destination | source
```
### SHL (Shift Logical Left)
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `SHL destination, count` | `0x06` | `destination` : `reg` / `mem` | `X` | `-` | `-` | `X` | `-` |
| | | `count` : `reg` / `mem` / `imm` |
#### Description
`SHL` 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.
> ? TODO: is this implemented?
> The carry flag (CF) is set equal
to the last bit shifted out of the left end.
#### Pseudo code
```py
destination = destination << count
```
### SHR (Shift Logical Right)
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `SHR destination, count` | `0x07` | `destination` : `reg` / `mem` | `X` | `-` | `-` | `X` | `-` |
| | | `count` : `reg` / `mem` / `imm` |
#### Description
SHR 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.
> ? TODO: is this implemented?
> The carry flag (CF) is set
equal to the last bit shifted out of the right end.
#### Pseudo code
```py
destination = destination >> count
```
### HWI (Hardware Interrupt)
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `HWI source` | `0x09` | `source` : `reg` / `mem` / `imm` | `-` | `-` | `-` | `-` | `-` |
#### Description
`HWI` triggers an [Hardware Interrupt](https://github.com/simon987/Much-Assembly-Required/wiki/Hardware). `source` should be the address of the harware device. This is differnt from the RAM memory addresses. See the documentation of the hardware devices to see what an `HWI` does for each device.
### JMP
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `JMP target` | `0x0A` | `target` : `reg` / `mem` / `imm` | `-` | `-` | `-` | `-` | `-` |
#### Description
`JMP` performs an unconditional jump to the target memory address and will resume execution there.
#### Pseudo code
```py
IP = target
```
### TEST
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `TEST destination, source` | `0x0B` | `destination` : `reg` / `mem` | `0` | `X` | `X` | `0` | `-` |
| | | `source` : `reg` / `mem` / `imm` |
#### Description
`TEST` performs a logical AND operation on its two operands and
updates the flags. None of the operands are changed.
#### Pseudo code
```py
destination & source # flags will be set
```
### CMP
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `CMP destination, source` | `0x0C` | `destination` : `reg` / `mem` | `X` | `X` | `X` | `X` | `-` |
| | | `source` : `reg` / `mem` / `imm` |
#### Description
`CMP` compares two numbers by subtracting the source from the
destination and updates the flags. None of the operands are
changed.
#### Pseudo code
```py
destination - source # flags will be set
```
### JNZ
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `JNZ target` | `0x0D` | `target` : `reg` / `mem` / `imm` | `-` | `-` | `-` | `-` | `-` |
#### Description
`JNZ` performs a jump if the zero flag **IS NOT** set.
#### Pseudo code
```py
if ZERO_FLAG == 0:
IP = target
```
### JZ
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `JZ target` | `0x0E` | `target` : `reg` / `mem` / `imm` | `-` | `-` | `-` | `-` | `-` |
#### Description
`JZ` performs a jump if the the zero flag **IS** set.
#### Pseudo code
```py
if ZERO_FLAG == 1:
IP = target
```
### JG
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `JG target` | `0x0F` | `target` : `reg` / `mem` / `imm` | `-` | `-` | `-` | `-` | `-` |
#### Description
`JG` performs a jump if the sign flag **IS EQUAL** to the overflow flag **AND** the zero flag **IS NOT** set.
#### Pseudo code
```py
if SIGN_FLAG == OVERFLOW_FLAG and ZERO_FLAG == 0:
IP = target
```
### JGE
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `JGE target` | `0x10` | `target` : `reg` / `mem` / `imm` | `-` | `-` | `-` | `-` | `-` |
#### Description
`JGE` performs a jump if the sign flag **IS EQUAL** to the overflow flag
#### Pseudo code
```py
if SIGN_FLAG == OVERFLOW_FLAG:
IP = target
```
### JL
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `JL target` | `0x11` | `target` : `reg` / `mem` / `imm` | `-` | `-` | `-` | `-` | `-` |
#### Description
`JL` performs a jump if the sign flag **IS NOT EQUAL** to the overflow flag
#### Pseudo code
```py
if SIGN_FLAG != OVERFLOW_FLAG:
IP = target
```
### JLE
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `JLE target` | `0x12` | `target` : `reg` / `mem` / `imm` | `-` | `-` | `-` | `-` | `-` |
#### Description
`JLE` performs a jump if the sign flag **IS NOT EQUAL** to the overflow flag **OR** the zero flag **IS** set
#### Pseudo code
```py
if SIGN_FLAG != OVERFLOW_FLAG or ZERO_FLAG == 1:
IP = target
```
### PUSH
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `PUSH source` | `0x13` | `source` : `reg` / `mem` / `imm` | `-` | `-` | `-` | `-` | `-` |
#### Description
`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
#### Pseudo code
```py
SP = SP - 1
memory[SP] = source
```
### POP
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `POP destintation` | `0x14` | `destination` : `reg` / `mem` | `-` | `-` | `-` | `-` | `-` |
#### Description
`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
#### Pseudo code
```py
destination = memory[SP]
SP = SP + 1
```
### CALL
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `CALL target` | `0x15` | `target` : `reg` / `mem` / `imm` | `-` | `-` | `-` | `-` | `-` |
#### Description
`CALL` pushes the current instruction pointer on to the stack and then performs a jump to the `target` address
#### Pseudo code
```py
SP = SP - 1
memory[SP] = IP
IP = target
```
### RET
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `RET [amount]` | `0x16` | `amount` : `imm` / `None` | `-` | `-` | `-` | `-` | `-` |
#### Description
`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.
#### Pseudo code
```py
IP = memory[SP]
if amount == None:
amount = 0
SP = SP + 1 + amount
```
### MUL
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `MUL source` | `0x17` | `source` : `mem` / `reg` / `imm` | `X` | `-` | `-` | `X` | `-` |
#### Description
`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](https://github.com/simon987/Much-Assembly-Required/blob/master/Server/source/main/java/net/simon987/server/assembly/instruction/MulInstruction.java) if needed
#### Pseudo code
```py
# 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
```
### DIV
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `DIV source` | `0x18` | `source` : `mem` / `reg` / `imm` | `-` | `-` | `-` | `-` | `X` |
#### Description
`DIV` performs unsigned division on `A` with `source` as divisor and stores the result into `A` and the remainder in `Y`.
Note that a division by 0 will set the (undocumented) error flag and the break flag. This will halt execution.
> This is a somewhat complicated instruction
> See the [source](https://github.com/simon987/Much-Assembly-Required/blob/master/Server/source/main/java/net/simon987/server/assembly/instruction/DivInstruction.java) if needed
#### Pseudo code
```py
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
```
### NEG
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `NEG destintation` | `0x19` | `destination` : `mem` / `reg` | `X` | `X` | `X` | `X` | `-` |
#### Description
`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.
#### Pseudo code
```py
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)
```
### JS
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `JS target` | `0x1A` | `target` : `mem` / `reg` / `imm` | `-` | `-` | `-` | `-` | `-` |
#### Description
`JS` jumps to the target if the sign flag **IS** set.
#### Pseudo code
```py
if SIGN_FLAG == 1:
IP = target
```
### JNS
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `JNS target` | `0x1B` | `target` : `mem` / `reg` / `imm` | `-` | `-` | `-` | `-` | `-` |
#### Description
`JNS` jumps to the target if the sign flag **IS NOT** set.
#### Pseudo code
```py
if SIGN_FLAG == 0:
IP = target
```
### HWQ
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `HWQ source` | `0x1C` | `source` : `mem` / `reg` / `imm` | `-` | `-` | `-` | `-` | `-` |
#### Description
`HWQ` queries the hardware id of the hardware at the hardware address specified by `source`
#### Pseudo code
```py
if hardware_memory[source] != None:
B = get_hardware_id(hardware_memory[source]) # not sure how to (pseudo) code this
else:
B = 0
```
### NOT
#### Details
| mnemonic | opcode | operands | carry | zero | sign | overflow | break |
| -------- | ------ | -------- | ----- | ---- | ---- | -------- | ----- |
| `NOT destintation` | `0x1D` | `source` : `mem` / `reg` | `-` | `-` | `-` | `-` | `-` |
#### Description
`NOT` inverts each bit in its operand, i.e. forms the one's complement.
#### Pseudo code
```py
dest = ~dest
```
## Encoding