Repository navigation
Expand file tree
/
Copy pathopcodes.zig
More file actions
136 lines (128 loc) · 12.2 KB
/
Copy pathopcodes.zig
File metadata and controls
136 lines (128 loc) · 12.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//! The mission script VM's instruction set.
//!
//! Generated by `src/tools/tablegen` from the payload executable's dispatch table at
//! 0x004F6350, which holds 86 entries. Do not edit by hand; run `make vm-opcodes`.
const assert = @import("std").debug.assert;
const dte = @import("../../formats/dte.zig");
/// What an instruction does to the instruction pointer.
pub const Form = enum {
/// Execution continues at the instruction after the operands.
sequential,
/// The operand bytes hold a displacement, relative to their own position, to where
/// execution resumes. The instruction itself still ends after them.
branch,
/// The one operand byte is a total length, covering itself: `length - 1` bytes of
/// inline data follow it, and execution resumes after them.
inline_data,
/// Control passes somewhere a linear decoder cannot follow.
transfer,
};
pub const Info = struct {
/// The opcode, by its name (`dte.Opcode`).
opcode: dte.Opcode,
/// Operand bytes between the opcode and the next instruction. For `inline_data` this
/// counts only the length byte.
operands: u8,
form: Form,
/// Whether execution can continue at the instruction after the operands. Where it
/// cannot, the bytes that follow are reached only by a branch, so a linear sweep
/// would decode whatever happens to sit there.
falls_through: bool,
/// Whether the instruction starts a statement, which a step of the editor link stops before
/// (`vm_starts_statement`, 0x004575C0).
starts_statement: bool,
/// Address of the handler in the payload executable.
handler: u32,
};
/// Every opcode the VM implements, in order.
pub const table = [_]Info{
.{ .opcode = .equal, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BAD0 },
.{ .opcode = .not_equal, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BB00 },
.{ .opcode = .greater, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BB30 },
.{ .opcode = .greater_equal, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BB60 },
.{ .opcode = .less, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BB90 },
.{ .opcode = .less_equal, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BBC0 },
.{ .opcode = .in_flight_group, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BBF0 },
.{ .opcode = .not_in_flight_group, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BC30 },
.{ .opcode = .assign, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = true, .handler = 0x0045BC70 },
.{ .opcode = .add_assign, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = true, .handler = 0x0045BCA0 },
.{ .opcode = .sub_assign, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = true, .handler = 0x0045BCD0 },
.{ .opcode = .mul_assign, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = true, .handler = 0x0045BD00 },
.{ .opcode = .div_assign, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = true, .handler = 0x0045BD30 },
.{ .opcode = .add, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BD60 },
.{ .opcode = .sub, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BD90 },
.{ .opcode = .mul, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BDC0 },
.{ .opcode = .div, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BDF0 },
.{ .opcode = .logical_and, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BE20 },
.{ .opcode = .logical_or, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BE60 },
.{ .opcode = .command, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = true, .handler = 0x0045BEA0 },
.{ .opcode = .call_part, .operands = 1, .form = .transfer, .falls_through = true, .starts_statement = true, .handler = 0x0045BFA0 },
.{ .opcode = .branch_if_zero, .operands = 2, .form = .branch, .falls_through = true, .starts_statement = true, .handler = 0x0045C270 },
.{ .opcode = .branch_if_zero_alt, .operands = 2, .form = .branch, .falls_through = true, .starts_statement = true, .handler = 0x0045C270 },
.{ .opcode = .return_alt, .operands = 0, .form = .transfer, .falls_through = true, .starts_statement = true, .handler = 0x0045C6E0 },
.{ .opcode = .push_array, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C2D0 },
.{ .opcode = .push_global, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C300 },
.{ .opcode = .push_constant, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C340 },
.{ .opcode = .push_constant_wide, .operands = 2, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C370 },
.{ .opcode = .push_string, .operands = 1, .form = .inline_data, .falls_through = true, .starts_statement = false, .handler = 0x0045C3B0 },
.{ .opcode = .push_string_alt, .operands = 1, .form = .inline_data, .falls_through = true, .starts_statement = false, .handler = 0x0045C3B0 },
.{ .opcode = .push_ship, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C3E0 },
.{ .opcode = .push_flight_group, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C560 },
.{ .opcode = .push_byte_alt, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C6B0 },
.{ .opcode = .push_percent, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045DA50 },
.{ .opcode = .push_local, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C5A0 },
.{ .opcode = .push_argument, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C680 },
.{ .opcode = .push_byte, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C6B0 },
.{ .opcode = .greater_f, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045DAB0 },
.{ .opcode = .greater_equal_f, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045DB10 },
.{ .opcode = .less_f, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045DB70 },
.{ .opcode = .less_equal_f, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045DBD0 },
.{ .opcode = .add_assign_f, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = true, .handler = 0x0045DC30 },
.{ .opcode = .sub_assign_f, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = true, .handler = 0x0045DC70 },
.{ .opcode = .mul_assign_f, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = true, .handler = 0x0045DCB0 },
.{ .opcode = .div_assign_f, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = true, .handler = 0x0045DCF0 },
.{ .opcode = .add_f, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045DD30 },
.{ .opcode = .sub_f, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045DD80 },
.{ .opcode = .mul_f, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045DDD0 },
.{ .opcode = .div_f, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045DE20 },
.{ .opcode = .select_array, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C790 },
.{ .opcode = .select_global, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C7D0 },
.{ .opcode = .select_argument, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C810 },
.{ .opcode = .jump, .operands = 2, .form = .branch, .falls_through = false, .starts_statement = false, .handler = 0x0045C2B0 },
.{ .opcode = .@"return", .operands = 0, .form = .transfer, .falls_through = true, .starts_statement = false, .handler = 0x0045C6E0 },
.{ .opcode = .push_squad, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C850 },
.{ .opcode = .in_squad, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C890 },
.{ .opcode = .not_in_squad, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C8D0 },
.{ .opcode = .push_component, .operands = 2, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C460 },
.{ .opcode = .push_null, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C4B0 },
.{ .opcode = .push_curve, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C4D0 },
.{ .opcode = .call_part_b, .operands = 1, .form = .transfer, .falls_through = false, .starts_statement = true, .handler = 0x0045C110 },
.{ .opcode = .push_event_value, .operands = 3, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C5E0 },
.{ .opcode = .push_result, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C650 },
.{ .opcode = .spawn_part, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = true, .handler = 0x0045C070 },
.{ .opcode = .spawn_part_b, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = true, .handler = 0x0045C1E0 },
.{ .opcode = .command_b, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045BF20 },
.{ .opcode = .random_branch, .operands = 0, .form = .transfer, .falls_through = false, .starts_statement = false, .handler = 0x0045C910 },
.{ .opcode = .push_ship_wide, .operands = 2, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C420 },
.{ .opcode = .nop, .operands = 0, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C510 },
.{ .opcode = .push_section_19, .operands = 1, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C520 },
.{ .opcode = .push_component_alt, .operands = 2, .form = .sequential, .falls_through = true, .starts_statement = false, .handler = 0x0045C460 },
};
comptime {
// `find` relies on the order.
for (table[1..], table[0 .. table.len - 1]) |next, previous| assert(@backingInt(next.opcode) > @backingInt(previous.opcode));
}
/// Looks up `opcode`, or null when the VM has no handler for it.
pub fn find(opcode: dte.Opcode) ?Info {
// The table is sorted, and short enough that a scan beats anything cleverer.
for (table) |info| {
if (info.opcode == opcode) return info;
if (@backingInt(info.opcode) > @backingInt(opcode)) break;
}
return null;
}
test find {
const std = @import("std");
try std.testing.expect(find(table[0].opcode) != null);
try std.testing.expect(find(@fromBackingInt(0x00)) == null);
}