From 804af72104a338d8d319a4573f6dea0a04d60fb5 Mon Sep 17 00:00:00 2001 From: Kevin Ramharak Date: Sat, 30 Dec 2017 00:53:41 +0100 Subject: [PATCH] Added first draft of instructions up to `0x1D` --- Instruction-Set.md | 533 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 532 insertions(+), 1 deletion(-) diff --git a/Instruction-Set.md b/Instruction-Set.md index df113e5..847595d 100644 --- a/Instruction-Set.md +++ b/Instruction-Set.md @@ -62,4 +62,535 @@ Operand value: | [Immediate value at IP+1] | `11110` | | Register | `00001`-`01000` | | [Register] | `01001`-`10000` | -| Register + Immediate value at IP+1 | `10001`-`11000` | \ No newline at end of file +| 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 +