RandomWOW/doc/isa.md
tevador 2756bcdcfe Added magic division to JIT compiler
New B operand selection rules
2019-01-11 16:53:52 +01:00

182 lines
5.9 KiB
Markdown

# RandomX instruction encoding
The instruction set was designed in such way that any random 16-byte word is a valid instruction and any sequence of valid instructions is a valid program. There are no syntax rules.
The encoding of each 128-bit instruction word is following:
![Imgur](https://i.imgur.com/xi8zuAZ.png)
## opcode
There are 256 opcodes, which are distributed between 3 groups of instructions. There are 31 distinct operations (each operation can be encoded using multiple opcodes - for example opcodes `0x00` to `0x0d` correspond to integer addition).
**Table 1: Instruction groups**
|group|# operations|# opcodes||
|---------|-----------------|----|-|
|integer (IA)|22|144|56.3%|
|floating point (FP)|5|76|29.7%|
|control (CL)|4|36|14.0%
||**31**|**256**|**100%**
Full description of all instructions: [isa-ops.md](isa-ops.md).
## A.LOC
**Table 2: `A.LOC` encoding**
|bits|description|
|----|--------|
|0-1|`A.LOC.W` flag|
|2-5|Reserved|
|6-7|`A.LOC.X` flag|
The `A.LOC.W` flag determines the address width when reading operand A from the scratchpad:
**Table 3: Operand A read address width**
|`A.LOC.W`|address width (W)|
|---------|-|
|0|15 bits (256 KiB)|
|1-3|11 bits (16 KiB)|
If the `A.LOC.W` flag is zero, the address space covers the whole 256 KiB scratchpad. Otherwise, just the first 16 KiB of the scratchpad are addressed.
If the `A.LOC.X` flag is zero, the instruction mixes the scratchpad read address into the `mx` register using XOR. This mixing happens before the address is truncated to W bits (see pseudocode below).
## A.REG
**Table 4: `A.REG` encoding**
|bits|description|
|----|--------|
|0-2|`A.REG.R` flag|
|3-7|Reserved|
The `A.REG.R` flag encodes "readAddressRegister", which is an integer register `r0`-`r7` to be used for scratchpad read address generation. Read address is generated as follows (pseudocode):
```python
readAddressRegister = IntegerRegister(A.REG.R)
readAddressRegister = readAddressRegister XOR SignExtend(A.mask32)
readAddress = readAddressRegister[31:0]
# dataset is read if the ic register is divisible by 64
IF ic mod 64 == 0:
DatasetRead(readAddress)
# optional mixing into the mx register
IF A.LOC.X == 0:
mx = mx XOR readAddress
# truncate to W bits
W = GetAddressWidth(A.LOC.W)
readAddress = readAddress[W-1:0]
```
Note that the value of the read address register is modified during address generation.
## B.LOC
**Table 5: `B.LOC` encoding**
|bits|description|
|----|--------|
|0-1|`B.LOC.L` flag|
|0-2|`B.LOC.C` flag|
|3-7|Reserved|
The `B.LOC.L` flag determines the B operand. It can be either a register or immediate value.
**Table 6: Operand B**
|`B.LOC.L`|IA/DIV|IA/SHIFT|IA/MATH|FP|CL|
|----|--------|----|------|----|---|
|0|register|`imm8`|`imm32`|register|register|
|1|`imm32`|register|register|register|register|
|2|`imm32`|`imm8`|register|register|register|
|3|`imm32`|register|register|register|register|
Integer instructions are split into 3 classes: integer division (IA/DIV), shift and rotate (IA/SHIFT) and other (IA/MATH). Floating point (FP) and control (CL) instructions always use a register operand.
Register to be used as operand B is encoded in the `B.REG.R` flag (see below).
The `B.LOC.C` flag determines the condition for the JUMP and CALL instructions. The flag partially overlaps with the `B.LOC.L` flag.
## B.REG
**Table 7: `B.REG` encoding**
|bits|description|
|----|--------|
|0-2|`B.REG.R` flag|
|3-7|Reserved|
Register encoded by the `B.REG.R` depends on the instruction group:
**Table 8: Register operands by group**
|group|registers|
|----|--------|
|IA|`r0`-`r7`|
|FP|`f0`-`f7`|
|CL|`r0`-`r7`|
## C.LOC
**Table 9: `C.LOC` encoding**
|bits|description|
|----|--------|
|0-1|`C.LOC.W` flag|
|2|`C.LOC.R` flag|
|3-6|Reserved|
|7|`C.LOC.H` flag|
The `C.LOC.W` flag determines the address width when writing operand C to the scratchpad:
**Table 10: Operand C write address width**
|`C.LOC.W`|address width (W)|
|---------|-|
|0|15 bits (256 KiB)|
|1-3|11 bits (16 KiB)|
If the `C.LOC.W` flag is zero, the address space covers the whole 256 KiB scratchpad. Otherwise, just the first 16 KiB of the scratchpad are addressed.
The `C.LOC.R` determines the destination where operand C is written:
**Table 11: Operand C destination**
|`C.LOC.R`|groups IA, CL|group FP
|---------|-|-|
|0|scratchpad|register
|1|register|register + scratchpad
Integer and control instructions (groups IA and CL) write either to the scratchpad or to a register. Floating point instructions always write to a register and can also write to the scratchpad. In that case, flag `C.LOC.H` determines if the low or high half of the register is written:
**Table 12: Floating point register write**
|`C.LOC.H`|write bits|
|---------|----------|
|0|0-63|
|1|64-127|
## C.REG
**Table 13: `C.REG` encoding**
|bits|description|
|----|--------|
|0-2|`C.REG.R` flag|
|3-7|Reserved|
The destination register encoded in the `C.REG.R` flag encodes both the write address register (if writing to the scratchpad) and the destination register (if writing to a register). The destination register depends on the instruction group (see Table 8). Write address is always generated from an integer register:
```python
writeAddressRegister = IntegerRegister(C.REG.R)
writeAddress = writeAddressRegister[31:0] XOR C.mask32
# truncate to W bits
W = GetAddressWidth(C.LOC.W)
writeAddress = writeAddress [W-1:0]
```
## imm8
`imm8` is an 8-bit immediate value that is used as the B operand by IA/SHIFT instructions (see Table 6). Additionally, it's used by some control instructions.
## A.mask32
`A.mask32` is a 32-bit address mask that is used to calculate the read address for the A operand. It's sign-extended to 64 bits before use.
## imm32
`imm32` is a 32-bit immediate value which is used for integer instructions from groups IA/DIV and IA/OTHER (see Table 6). The immediate value is sign-extended for instructions that expect 64-bit operands.
## C.mask32
`C.mask32` is a 32-bit address mask that is used to calculate the write address for the C operand. `C.mask32` is equal to `imm32`.