Papyrus Opcodes¶
All 50 opcodes with operand layouts.
Conventions:
dest= destination identifier (always aPexValue.Identifier)src,lhs,rhs= source operands (anyPexValuetype)VarArgs= N fixed operands + one int count + count more operands (all flattened in reader)- Jump offsets are relative to current instruction (target = i + offset)
Common Opcodes (v3.1+)¶
| ID | Name | Operands |
|---|---|---|
| 0 | Nop | — |
| 1 | IAdd | [dest, lhs, rhs] |
| 2 | FAdd | [dest, lhs, rhs] |
| 3 | ISub | [dest, lhs, rhs] |
| 4 | FSub | [dest, lhs, rhs] |
| 5 | IMul | [dest, lhs, rhs] |
| 6 | FMul | [dest, lhs, rhs] |
| 7 | IDiv | [dest, lhs, rhs] |
| 8 | FDiv | [dest, lhs, rhs] |
| 9 | IMod | [dest, lhs, rhs] |
| 10 | Not | [dest, src] |
| 11 | INeg | [dest, src] |
| 12 | FNeg | [dest, src] |
| 13 | Assign | [dest, src] |
| 14 | Cast | [dest, src] |
| 15 | CmpEq | [dest, lhs, rhs] |
| 16 | CmpLt | [dest, lhs, rhs] |
| 17 | CmpLte | [dest, lhs, rhs] |
| 18 | CmpGt | [dest, lhs, rhs] |
| 19 | CmpGte | [dest, lhs, rhs] |
| 20 | Jmp | [offset] |
| 21 | JmpT | [cond, offset] |
| 22 | JmpF | [cond, offset] |
| 23 | CallMethod | [method, self, dest, argCount, args...] |
| 24 | CallParent | [method, dest, argCount, args...] |
| 25 | CallStatic | [script, method, dest, argCount, args...] |
| 26 | Return | [value] |
| 27 | StrCat | [dest, lhs, rhs] |
| 28 | PropGet | [propName, receiver, dest] |
| 29 | PropSet | [propName, receiver, value] |
| 30 | ArrayCreate | [dest, size] |
| 31 | ArrayLength | [dest, array] |
| 32 | ArrayGetElement | [dest, array, index] |
| 33 | ArraySetElement | [array, index, value] |
| 34 | ArrayFindElement | [array, dest, value, startIdx] |
| 35 | ArrayRFindElement | [array, dest, value, startIdx] |
FO4 / Papyrus 3.9 Additions¶
| ID | Name | Operands |
|---|---|---|
| 36 | Is | [dest, value, typeName] |
| 37 | StructCreate | [dest] |
| 38 | StructGet | [dest, struct, memberName] |
| 39 | StructSet | [struct, memberName, value] |
| 40 | ArrayFindStruct | [array, dest, member, value, startIdx] |
| 41 | ArrayRFindStruct | [array, dest, member, value, startIdx] |
| 42 | ArrayAdd | [array, value, count] |
| 43 | ArrayInsert | [array, value, index] |
| 44 | ArrayRemoveLast | [array] |
| 45 | ArrayRemove | [array, index, count] |
| 46 | ArrayClear | [array] |
FO4 Guard / Coroutine Opcodes¶
| ID | Name | Operands |
|---|---|---|
| 47 | LockGuards | [argCount, guards...] |
| 48 | UnlockGuards | [argCount, guards...] |
| 49 | TryLockGuards | [dest, argCount, guards...] |
Notes¶
IDiv / IMod (integer semantics)¶
Papyrus uses C-style truncation toward zero for integer division and modulo. This means (-7) / 2 evaluates to -3 (not -4), and (-7) % 2 evaluates to -1 (not 1). Implementations targeting languages with floor-division semantics must account for this.
Array indexing¶
Papyrus arrays are 0-based. ArrayFindElement and ArrayFindStruct return 0-based indices, or -1 when the element is not found.
Void call results¶
Papyrus void call results go to the special identifier ::NoneVar (case-insensitive). When a call instruction writes to ::NoneVar, the return value is discarded.
Cast¶
The destination variable's declared type is looked up from the function's parameter/local table and passed as the type name string.
Control flow labels¶
Jump targets are absolute instruction indices computed as current_index + signed_offset. Past-end targets (target >= instruction count) indicate function exit. Only instructions that are jump targets need labels in a disassembly.