Skip to content

Papyrus Opcodes

All 50 opcodes with operand layouts.

Conventions:

  • dest = destination identifier (always a PexValue.Identifier)
  • src, lhs, rhs = source operands (any PexValue type)
  • 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.