Project TEST presents
MPC's Custom system language, nicknamed Mach-C (Mindustry Machine Code).
This documentation covers Chapter 7 of the Mach-C language for the MPC project.
The structure of the code is no longer fixed to one single format, but rather multiple formats that are chosen based on the opcode of the instruction.
This was decided so it can be easily adaptible and not constraining in implementation.
- CPU Execution Model
- Architecture & Data Addressing
- Assembly Language Syntax
- Instruction Formats
- Encoding Notes
The MPC processor executes instructions stored in the L2 cache memory. Understanding the execution model is essential for programming the system.
- Starting Point: The processor begins execution at cache address
@0. For multi-core configurations, each processor starts at cache address equal to itsCPUIDregister value (e.g., core 0 starts at@0, core 1 starts at@1, etc.). - Sequential Execution: After executing an instruction, the instruction pointer automatically advances to the next cache address.
- Wrap-Around: When the instruction pointer reaches the end of the cache address space, it wraps around to
@0and continues execution. - Stopping Conditions: Execution pauses when the instruction pointer encounters:
NOP(No Operation) - Skips and continuesHLT(Halt) - Stops execution completely until reset- Invalid opcodes - Triggers exception handling
Each processor core has a unique CPUID register (read-only, address 0x01) that identifies it. This allows:
- Partitioned code execution across cores
- Core-specific branching logic
- Synchronized multi-core operations via shared cache/RAM
The MPC uses separate address spaces for different memory types:
| Address Space | Size | Description |
|---|---|---|
| Registry | 64 locations (6-bit) | Per-processor internal registers |
| Cache | 2^32 locations (32-bit) | Fast L2 cache (Memory Banks) |
| RAM/Unified | 2^32 locations (32-bit) | External memory via RAM module |
Registers are stored within the CPU core using L100 technology. 6-bit addressing supports 64 registers.
| Address | Decimal | Name | Description |
|---|---|---|---|
| 0x00 | 00 | ZERO | Immutable zero constant (always 0) |
| 0x01 | 01 | CPUID | Processor core ID (read-only, used for multi-core startup offset) |
| 0x02 | 02 | PC | Program counter |
| 0x03 | 03 | SP | Stack pointer |
| 0x04 | 04 | RA | Return address (saved by CALL) |
| 0x05 | 05 | FLAGS | Status flags register (see FLAGS structure below) |
| 0x06 | 06 | PI | Constant π (3.14159..., read-only, native Mindustry) |
| 0x07 | 07 | E | Constant e (2.71828..., read-only, native Mindustry) |
| 0x08 | 08 | LINK | Current link count (read-only) |
| 0x09 | 09 | TIME | Game tick counter (read-only) |
| 0x0A | 10 | UNIT | Currently bound unit reference |
| 0x0B | 11 | THIS | Current processor reference (read-only) |
| 0x0C | 12 | IPTR | Instruction pointer (alias for PC) |
| 0x0D | 13 | CNTR | General counter register |
| 0x0E | 14 | ACCM | Accumulator register |
| 0x0F | 15 | - | Reserved for future system use |
| Address | Decimal | Name | Description |
|---|---|---|---|
| 0x10 | 16 | A0 | Argument register 0 |
| 0x11 | 17 | A1 | Argument register 1 |
| 0x12 | 18 | A2 | Argument register 2 |
| 0x13 | 19 | A3 | Argument register 3 |
| 0x14 | 20 | A4 | Argument register 4 |
| 0x15 | 21 | A5 | Argument register 5 |
| 0x16 | 22 | A6 | Argument register 6 |
| 0x17 | 23 | A7 | Argument register 7 |
| 0x18-0x1F | 24-31 | A8-AF | Argument registers 8-15 |
| Address | Decimal | Name | Description |
|---|---|---|---|
| 0x20 | 32 | T0 | Temporary register 0 (caller-saved) |
| 0x21 | 33 | T1 | Temporary register 1 |
| 0x22 | 34 | T2 | Temporary register 2 |
| 0x23 | 35 | T3 | Temporary register 3 |
| 0x24 | 36 | T4 | Temporary register 4 |
| 0x25 | 37 | T5 | Temporary register 5 |
| 0x26 | 38 | T6 | Temporary register 6 |
| 0x27 | 39 | T7 | Temporary register 7 |
| 0x28-0x2F | 40-47 | T8-TF | Temporary registers 8-15 |
| Address | Decimal | Name | Description |
|---|---|---|---|
| 0x30 | 48 | S0 | Saved register 0 (caller-saved) |
| 0x31 | 49 | S1 | Saved register 1 |
| 0x32 | 50 | S2 | Saved register 2 |
| 0x33 | 51 | S3 | Saved register 3 |
| 0x34 | 52 | S4 | Saved register 4 |
| 0x35 | 53 | S5 | Saved register 5 |
| 0x36 | 54 | S6 | Saved register 6 |
| 0x37 | 55 | S7 | Saved register 7 |
| 0x38-0x3F | 56-63 | S8-SF | Saved registers 8-15 |
| Bit | Name | Description |
|---|---|---|
| 0 | ZF | Zero flag (result was zero) |
| 1 | SF | Sign flag (result was negative) |
| 2 | OF | Overflow flag (signed overflow) |
| 3 | CF | Carry flag (unsigned overflow/borrow) |
| 4 | EF | Equal flag (comparison result) |
| 5 | LF | Less-than flag (comparison result) |
| 6 | GF | Greater-than flag (comparison result) |
| 7 | IF | Interrupt enable flag |
| 8 | HF | Halt flag (processor halted) |
| 9 | EXF | Exception flag (exception occurred) |
| 10 | MF | Memory fault flag |
| 11 | UF | Unit bound flag |
| 12-31 | - | Reserved for future use |
L2 cache uses Mindustry Memory Banks placed near the processor. Each memory cell stores a single value—whether negative, positive, decimal, etc., data types are handled natively by Mindustry. Users must process or accommodate specific data types themselves.
Since each memory bank only holds 512 cells, all linked banks are combined into one unified cache address space using a 32-bit address.
When accessing a cache address, the processor calculates:
- Bank ID =
address // 512(integer division) - Cell Index =
address % 512(modulo)
--- L2 CACHE ADDRESS RESOLUTION ---
Address Space: 32-bit (0x00000000 - 0xFFFFFFFF)
Example: Accessing cache address @515 (0x203)
Bank ID = 515 // 512 = 1 → Memory Bank 1
Cell Index = 515 % 512 = 3 → Cell 3 within that bank
Example: Accessing cache address @1030
Bank ID = 1030 // 512 = 2 → Memory Bank 2
Cell Index = 1030 % 512 = 6 → Cell 6 within that bank
1. Load 32-bit address into a register (STR or arithmetic)
2. Issue cache memory operation with address register
3. Processor resolves Bank ID and Cell Index internally
4. Data transferred to/from destination register
Example:
STR #A0 515 ; Store address 515 into register A0
LRC #T0 #A0 ; Load from CACHE[515] (Bank 1, Cell 3) to T0
SRC #T1 #A0 ; Store T1 to CACHE[515]
RAM provides external memory located outside the CPU/processor space. RAM is accessed exclusively through cache-to-RAM operations (F_CM format). Direct register-to-RAM operations are not supported.
Each RAM address points to exactly 8 cells within the RAM module. This block-based addressing enables efficient bulk transfers between cache and RAM.
- Block Address = RAM address (32-bit)
- Block Size = 8 cells per address
- Cell Range =
[address * 8]to[address * 8 + 7]
--- RAM ADDRESS RESOLUTION ---
Address Space: 32-bit (0x00000000 - 0xFFFFFFFF)
Cells per Address: 8
Example: Accessing RAM address $128
Starting Cell = 128 * 8 = 1024 → Cell 1024
Ending Cell = 128 * 8 + 7 = 1031 → Cell 1031
Total Cells = 8 cells (1024-1031)
Example: Accessing RAM address $0
Starting Cell = 0 * 8 = 0 → Cell 0
Ending Cell = 0 * 8 + 7 = 7 → Cell 7
Total Cells = 8 cells (0-7)
RAM can only be accessed through cache operations (F_CM format):
1. Load 32-bit RAM address into a register
2. Issue cache-memory operation (F_CM format)
3. RAM module resolves the 8-cell block
4. Data transferred between cache and RAM block
Example (bulk transfer - 8 cells):
STR #A0 128 ; Store RAM address 128 into register A0
STR #A1 1000 ; Store cache address 1000 into register A1
LCM #A1 #A0 ; Load 8 cells from RAM[128] (cells 1024-1031) to CACHE[1000-1007]
SCM #A1 #A0 ; Store 8 cells from CACHE[1000-1007] to RAM[128]
Example (single cell access):
STR #A0 128 ; Store RAM address 128 into register A0
STR #A1 1000 ; Store cache address 1000 into register A1
STR #A2 3 ; Store cell offset (0-7) into register A2
LCMS #A1 #A0 #A2 ; Load single cell at offset 3 from RAM[128] to CACHE[1000]
Note: RAM operations may take additional cycles compared to cache due to external module communication. Use bulk transfers (LCM/SCM) when possible for efficiency.
The Mach-C compiler accepts human-readable assembly code and compiles it to the 53-bit encoded instruction format. This section documents the text-based syntax.
INSTRUCTION operand1 [operand2] [operand3] [operand4] / comment lines
/ comment lines
- Instructions are case-insensitive (e.g.,
ADD,add,Addall work) - Comments start with
/and extend to end of line - Labels end with
:and define jump targets (e.g.,loop_start:) - Blank lines and comment-only lines are ignored
| Prefix | Type | Description | Example |
|---|---|---|---|
# |
Register | CPU register (0-63) | #16, #T0, #A0 |
@ |
Cache | L2 Cache address | @1000, @0x400 |
$ |
RAM | External RAM module | $8192 |
| (none) | Immediate | Literal numeric value | 42, 100 |
Note: Building and unit references (obtained via
LINKorUBND) can only be stored in registers. They cannot be saved to cache or RAM.
MOV #16 #17 / Move: R16 = R17
SWP #16 #17 / Swap: R16 <=> R17
ADD #16 #17 / Add: R16 = R16 + R17
SUB #32 #33 / Subtract: R32 = R32 - R33
MUL #T0 5 / Multiply: T0 = T0 * 5
SQR #20 / Square root: R20 = sqrt(R20)
SIN #21 / Sine: R21 = sin(R21)
MAX #22 #23 / Maximum: R22 = max(R22, R23)
AND #24 255 / Bitwise AND: R24 = R24 & 255
STR #16 42 / Store immediate: R16 = 42
ADDI #17 10 / Add immediate: R17 = R17 + 10
SUBI #18 5 / Subtract immediate: R18 = R18 - 5
MULI #19 2 / Multiply immediate: R19 = R19 * 2
SHLI #20 3 / Shift left immediate: R20 = R20 << 3
LRC #T0 #A0 / Load from cache: T0 = CACHE[A0]
SRC #T1 #A1 / Store to cache: CACHE[A1] = T1
XCHC #T2 #A2 / Exchange: swap(T2, CACHE[A2])
CCPY #A0 #A1 #A2 / Bulk cache copy: copy A2 values from CACHE[A0] to CACHE[A1]
LCM #A0 #A1 / Load 8 cells from RAM[A1] to CACHE[A0..A0+7]
SCM #A0 #A1 / Store 8 cells from CACHE[A0..A0+7] to RAM[A1]
LCMS #A0 #A1 #A2 / Load single cell at offset A2 from RAM[A1] to CACHE[A0]
SCMS #A0 #A1 #A2 / Store single cell from CACHE[A0] to RAM[A1] at offset A2
CMCPY #A0 #A1 #A2 / Bulk copy: copy A2*8 cells from RAM[A1] to CACHE[A0]
CMSTR #A0 #A1 #A2 / Bulk copy: copy A2*8 cells from CACHE[A0] to RAM[A1]
LINK #S0 0 / Get linked building at index 0 into S0
SENS #T0 #S1 #S2 / Sense property S2 from building S1 (Correction: param1=Building, param2=Property)
CTRL #S0 #A0 #A1 / Control building S0 with params
DRAW #A0 #A1 #A2 / Draw operation
PRNT #T0 / Print value
JMP @100 / Jump to cache address @100
JEQ #16 #17 @200 / Jump to @200 if R16 == R17
JNE #16 #17 @300 / Jump to @300 if R16 != R17
JLT #18 #19 @400 / Jump to @400 if R18 < R19
CALL @1000 / Call subroutine at cache address @1000
RET / Return from subroutine
HLT / Halt execution
Note: All jump/call targets are cache addresses where the instruction pointer will be redirected.
The MPC compiler is a command-line tool that compiles readable Mach-C code into a format that can be processed In-game (as binary).
The compiler is also suited with a decompiler mode that can decompile an already compiled Mach-C binary (represented as decimals) into readable Mach-C code.
Note: The compiler is currently in development and may not be fully accurate.
machc [options]
Options:
-i, --input <file> Input file path
-s, --string <code> Input code as string
-o, --output <file> Output file path
-d, --decompile Decompile mode
-n <threads> Thread count (0=auto)
--benchmark-mode <iter> Run benchmark iterations
-l, --log-level <0-3> Set log level
--max-memory <MB> Max memory limit
--map-file-to-memory Use memory mapping (fast)
-y Skip any confirmation(s)
-h, --help Shows this help message# Compile a file
machc -i program.mach -o output.bin -y
# Compile inline code
machc -s "ADD #16 #17" -y
# Compile with verbose logging
machc -i program.mach -l 3 -yThe following are the formats of instructions that will be decoded based on opcodes.
Bits: [52:46] [45:0]
Desc: OpCode padding
Count: 7b 46b
OpCode = Type of operation to be run. F_0 will only run for OpCodes 0.
padding = Unused bits that serves as padding to keep the size of the instructions consistent. (ignored)
000 : NOP | No operation, skip
Bits: [52:46] [45:40] [39:34] [33:28] [27:22] [21:16] [15:0]
Desc: OpCode out src1 src2 opt1 opt2 padding
Count: 7b 6b 6b 6b 6b 6b 16b
OpCode = Type of operation to be run. F_RR will only run for OpCodes from 1 to 51.
out = The Registry address that the output of this instruction will be pushed to. (usually the same as src1)
src1 = The Registry address of the first value being calculated.
src2 = The Registry address of the second value being calculated. (ignored for some instructions)
opt1 = An optional registry address used for specific instructions, used for input/output registries. (ignored for some instructions)
opt2 = An optional registry address used for specific instructions, used for input/output registries. (ignored for some instructions)
padding = Unused bits that serves as padding to keep the size of the instructions consistent. (ignored)
| OpCode | Mnemonic | Operation | Description |
|---|---|---|---|
| 001 | MOV | src1 => out |
Move value from src1 to out |
| 002 | SWP | src1 <=> src2 |
Swap values between src1 and src2 |
| OpCode | Mnemonic | Operation | Description |
|---|---|---|---|
| 003 | ADD | src1 + src2 => out |
Summation |
| 004 | SUB | src1 - src2 => out |
Subtraction |
| 005 | MUL | src1 * src2 => out |
Multiplication |
| 006 | DIV | src1 / src2 => out |
Regular division |
| 007 | IDV | src1 // src2 => out |
Integer division |
| 008 | MOD | src1 % src2 => out |
Modulo |
| 009 | TMD | src1 %% src2 => out |
True modulo |
| 010 | POW | src1 ^ src2 => out |
Exponentiation by value |
| 011 | LOG | {src2}LOG(src1) => out |
Logarithm of src1 with base src2 |
| 012 | SQR | sqrt(src1) => out |
Square root |
| 013 | MAX | MAX(src1, src2) => out |
Maximum value between both registries |
| 014 | MIN | MIN(src1, src2) => out |
Minimum value between both registries |
| 015 | FLR | FLOOR(src1) => out |
Floor value |
| 016 | CIL | CEIL(src1) => out |
Ceiling value |
| 017 | ABS | ABS(src1) => out |
Absolute value |
| 018 | SIN | SIN(src1) => out |
Sine value in degrees |
| 019 | COS | COS(src1) => out |
Cosine value in degrees |
| 020 | TAN | TAN(src1) => out |
Tangent value in degrees |
| 021 | ASN | ASIN(src1) => out |
Arc-Sine value in degrees |
| 022 | ACS | ACOS(src1) => out |
Arc-Cosine value in degrees |
| 023 | ATN | ATAN(src1) => out |
Arc-Tangent value in degrees |
| 024 | CSC | 1 / SIN(src1) => out |
Cosecant value in degrees |
| 025 | SEC | 1 / COS(src1) => out |
Secant value in degrees |
| 026 | COT | 1 / TAN(src1) => out |
Cotangent value in degrees |
| 027 | ACSC | ASIN(1 / src1) => out |
Arc-Cosecant value in degrees |
| 028 | ASEC | ACOS(1 / src1) => out |
Arc-Secant value in degrees |
| 029 | ACOT | ATAN(1 / src1) => out |
Arc-Cotangent value in degrees |
| OpCode | Mnemonic | Operation | Description |
|---|---|---|---|
| 030 | AND | src1 && src2 => out |
Bitwise and operator |
| 031 | OR | src1 || src2 => out |
Bitwise or operator |
| 032 | XOR | src1 ^^ src2 => out |
Bitwise xor operator |
| 033 | NOT | NOT(src1) => out |
Bitwise flip (flips every bit) |
| 034 | SHL | src1 << src2 => out |
Bit shift left |
| 035 | SHR | src1 >> src2 => out |
Bit shift right |
| 036 | EQ | src1 == src2 => out |
Logical equality |
| 037 | NEQ | src1 != src2 => out |
Logical inequality |
| 038 | STE | src1 === src2 => out |
Strict equality |
| 039 | LAD | src1 & src2 => out |
Logical and operator |
| 040 | LTH | src1 < src2 => out |
Logical less than operator |
| 041 | LTE | src1 <= src2 => out |
Logical less or equal than operator |
| 042 | MTH | src1 > src2 => out |
Logical more than operator |
| 043 | MTE | src1 >= src2 => out |
Logical more or equal than operator |
| OpCode | Mnemonic | Operation | Description |
|---|---|---|---|
| 044 | A2V | ACOS((src1 * src2) / (ABS(src1 * src2))) => out |
Angle of two vectors in degrees |
| 045 | ADV | ABS(src1 - src2) => out |
Absolute distance of two angles in degrees |
| 046 | LOV | ABS(SQRT(src1^2 + src2^2)) => out |
Length of vector |
| 047 | 2DS | NOISE(src1, src2) => out |
2D simplex noise |
| 048 | RDN | RAND(0, src1) => out |
Random number between 0 and src1 |
| 049 | PKC | PACKCOLOR(src1, src2, opt1, opt2) => out |
Color packing (R, G, B, A) to out |
| 050 | UPC | UNPACKCOLOR(src1) => out, src2, opt1, opt2 |
Color unpacking to R, G, B, A |
| 051 | SGN | SIGN(src1) => out |
The positive/negative/zero value of src1 |
Bits: [52:46] [45:40] [39:8] [7:0]
Desc: OpCode out src1 padding
Count: 7b 6b 32b 8b
OpCode = Type of operation to be run. F_RI will only run for OpCodes from 52 to 61.
out = The Registry address that the output of this instruction will be pushed to.
src1 = A 32 bit immediate value to be processed/calculated in this instruction.
padding = Unused bits that serves as padding to keep the size of the instructions consistent. (ignored)
| OpCode | Mnemonic | Operation | Description |
|---|---|---|---|
| 052 | STR | src1 => out |
Store immediate value to registry address out |
| 053 | STRF | src1 => FLAGS |
Store immediate value to FLAGS register |
| 054 | ADDI | out + src1 => out |
Add immediate to register |
| 055 | SUBI | out - src1 => out |
Subtract immediate from register |
| 056 | MULI | out * src1 => out |
Multiply register by immediate |
| 057 | DIVI | out / src1 => out |
Divide register by immediate |
| 058 | ANDI | out && src1 => out |
Bitwise AND with immediate |
| 059 | ORI | out || src1 => out |
Bitwise OR with immediate |
| 060 | XORI | out ^^ src1 => out |
Bitwise XOR with immediate |
| 061 | SHLI | out << src1 => out |
Shift left by immediate |
Bits: [52:46] [45:40] [39:34] [33:28] [27:0]
Desc: OpCode dest addrReg srcReg padding
Count: 7b 6b 6b 6b 28b
OpCode = Type of operation to be run. F_RC will only run for OpCodes from 62 to 66.
dest = Destination registry address for loaded data.
addrReg = Registry containing the cache address.
srcReg = Source registry for stores, or size parameter for copy.
padding = Unused bits for instruction consistency. (ignored)
| OpCode | Mnemonic | Operation | Description |
|---|---|---|---|
| 062 | LRC | CACHE[addrReg] => dest |
Load from cache to register |
| 063 | SRC | srcReg => CACHE[addrReg] |
Store register to cache |
| 064 | XCHC | CACHE[addrReg] <=> srcReg |
Exchange cache and register |
| 065 | CCPY | CACHE[addrReg..addrReg+srcReg] => CACHE[dest] |
Bulk cache copy: copy srcReg values from CACHE[addrReg] to CACHE[dest] |
| 066 | - | (reserved) | Reserved for future use |
Bits: [52:46] [45:40] [39:34] [33:28] [27:0]
Desc: OpCode cacheReg ramReg offsetReg padding
Count: 7b 6b 6b 6b 28b
OpCode = Type of operation to be run. F_CM will only run for OpCodes from 67 to 73.
cacheReg = Registry containing the cache address.
ramReg = Registry containing the RAM address (each RAM address = 8 cells).
offsetReg = Registry containing cell offset (0-7) for single-cell operations, or size for bulk operations.
padding = Unused bits for instruction consistency. (ignored)
Note: Each RAM address points to exactly 8 cells. Bulk operations (LCM/SCM) transfer all 8 cells. Single-cell operations (LCMS/SCMS) use the offset register to select one cell within the 8-cell block.
| OpCode | Mnemonic | Operation | Description |
|---|---|---|---|
| 067 | LCM | RAM[ramReg*8..(ramReg*8)+7] => CACHE[cacheReg..cacheReg+7] |
Load 8 cells from RAM block to cache |
| 068 | SCM | CACHE[cacheReg..cacheReg+7] => RAM[ramReg*8..(ramReg*8)+7] |
Store 8 cells from cache to RAM block |
| 069 | LCMS | RAM[ramReg*8 + offsetReg] => CACHE[cacheReg] |
Load single cell at offset from RAM block to cache |
| 070 | SCMS | CACHE[cacheReg] => RAM[ramReg*8 + offsetReg] |
Store single cell from cache to RAM block at offset |
| 071 | CMCPY | RAM[ramReg*8..ramReg*8+(offsetReg*8)] => CACHE[cacheReg] |
Bulk copy: copy offsetReg blocks (offsetReg*8 cells) from RAM to cache |
| 072 | CMSTR | CACHE[cacheReg..cacheReg+(offsetReg*8)] => RAM[ramReg*8] |
Bulk copy: copy offsetReg blocks (offsetReg*8 cells) from cache to RAM |
| 073 | LEA | ramReg + offsetReg => cacheReg |
Load effective address (address calculation) |
Bits: [52:46] [45:40] [39:34] [33:28] [27:22] [21:0]
Desc: OpCode out param1 param2 param3 padding
Count: 7b 6b 6b 6b 6b 22b
OpCode = Type of operation to be run. F_RW will only run for OpCodes from 74 to 93.
out = The Registry address for the output of this operation.
param1 = Registry address for first parameter (often building reference).
param2 = Registry address for second parameter.
param3 = Registry address for third parameter.
padding = Unused bits for instruction consistency. (ignored)
Note: Building and unit references (from LINK/UBND) can only be stored in registers. They cannot be saved to cache or RAM.
| OpCode | Mnemonic | Operation | Description |
|---|---|---|---|
| 074 | SENS | SENSE(param1, param2) => out |
Sense property from building |
| 075 | CTRL | CONTROL(out, param1, param2) |
Control building with params |
| 076 | RADR | RADAR(param1, param2, param3) => out |
Radar detection from building |
| 077 | LINK | GETLINK(param1) => out |
Get linked building at index |
| 078 | LNKC | @links => out |
Get total link count |
| OpCode | Mnemonic | Operation | Description |
|---|---|---|---|
| 079 | DRAW | DRAW(out, param1, param2) |
Draw operation |
| 080 | DRWF | DRAWFLUSH(out) |
Flush draw buffer to display |
| 081 | DCOL | DRAWCOL(out, param1, param2, param3) |
Set draw color (R,G,B,A) |
| 082 | DSTR | DRAWSTROKE(out) |
Set stroke width |
| OpCode | Mnemonic | Operation | Description |
|---|---|---|---|
| 083 | PRNT | PRINT(out) |
Print value to buffer |
| 084 | PRTF | PRINTFLUSH(out) |
Flush print buffer to message |
| OpCode | Mnemonic | Operation | Description |
|---|---|---|---|
| 085 | UBND | UBIND(out) |
Bind unit by type stored in out |
| 086 | UCTL | UCONTROL(out, param1, param2) |
Control bound unit |
| 087 | URDR | URADAR(out, param1, param2) |
Radar from bound unit |
| 088 | ULOC | ULOCATE(out, param1) |
Locate feature |
| OpCode | Mnemonic | Operation | Description |
|---|---|---|---|
| 089 | WSET | SETPROP(out, param1, param2) |
Set world property |
| 090 | WFLG | SETFLAG(out, param1) |
Set world flag |
| 091 | WRUL | SETRULE(out, param1) |
Set world rule |
| 092 | WFCH | FETCH(out, param1, param2, param3) |
Fetch world object |
| 093 | WEFF | EFFECT(out, param1, param2, param3) |
Create visual effect |
Bits: [52:46] [45:40] [39:34] [33:2] [1:0]
Desc: OpCode cond reg target padding
Count: 7b 6b 6b 32b 2b
OpCode = Type of operation to be run. F_JC will only run for OpCodes from 94 to 103.
cond = Registry address containing the condition value.
reg = Registry address for comparison or return address storage.
target = 32-bit cache address where the instruction pointer will jump to (supports up to 17 billion instructions).
padding = Unused bits for instruction consistency. (ignored)
| OpCode | Mnemonic | Operation | Description |
|---|---|---|---|
| 094 | JMP | goto target |
Unconditional jump to cache address |
| 095 | JEQ | if cond == reg, goto target |
Jump if equal |
| 096 | JNE | if cond != reg, goto target |
Jump if not equal |
| 097 | JLT | if cond < reg, goto target |
Jump if less than |
| 098 | JLE | if cond <= reg, goto target |
Jump if less or equal |
| 099 | JGT | if cond > reg, goto target |
Jump if greater than |
| 100 | JGE | if cond >= reg, goto target |
Jump if greater or equal |
| 101 | CALL | call target; PC => RA |
Subroutine call to cache address (saves return address) |
| 102 | RET | goto RA |
Return from subroutine |
| 103 | HLT | halt |
Halt execution |
Bits: [52:46] [45:40] [39:8] [7:0]
Desc: OpCode errcode handler padding
Count: 7b 6b 32b 8b
OpCode = Always 127 for exception format.
errcode = Error code identifier (see list below).
handler = 32-bit cache address of exception handler routine.
padding = Unused bits for instruction consistency. (ignored)
| Code | Mnemonic | Description |
|---|---|---|
| 0x00 | ERR_UNKNOWN | Unknown/general error |
| 0x01 | ERR_DIVZERO | Division by zero |
| 0x02 | ERR_OVERFLOW | Integer overflow |
| 0x03 | ERR_UNDERFLOW | Integer underflow |
| 0x04 | ERR_BADADDR | Invalid memory address |
| 0x05 | ERR_BADOP | Invalid opcode |
| 0x06 | ERR_STACKOF | Stack overflow |
| 0x07 | ERR_STACKUF | Stack underflow |
| 0x08 | ERR_NOSUB | Subroutine not found |
| 0x09 | ERR_NORET | Missing return statement |
| 0x0A | ERR_NOLNK | No linked building found |
| 0x0B | ERR_NOUNIT | No unit bound |
Negative values in immediate operands are handled by sign extension within the 32-bit immediate field (F_RI format). For register operations, the sign is preserved in the register value itself (native mindustry - IEEE 754 Double).
Building and unit references in F_RW format are stored as numeric IDs. Use LINK to get building references and UBND to get unit references which are then stored in registers for subsequent operations.