-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathOpcodeMap.v3
104 lines (97 loc) · 3.36 KB
/
OpcodeMap.v3
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
// Copyright 2022 Ben L. Titzer. All rights reserved.
// See LICENSE for details of Apache 2.0 license.
// Efficiently maps opcodes to a value of type {T}.
class OpcodeMap<T> {
private def main_table = OpcodeMapTable<T>.new(0, Opcodes.page_00.opcodes);
private def fb_table = OpcodeMapTable<T>.new(0xFB, Opcodes.page_FB.opcodes);
private def fc_table = OpcodeMapTable<T>.new(0xFC, Opcodes.page_FC.opcodes);
private def fd_table = OpcodeMapTable<T>.new(0xFD, Opcodes.page_FD.opcodes);
private def fe_table = OpcodeMapTable<T>.new(0xFE, Opcodes.page_FE.opcodes);
private def d: T;
private def NONE = (Opcode.INVALID, d);
// Look up the value for the opcode obtained by decoding the bytes in {decoder}, not
// including immediates.
def decode(decoder: Decoder) -> (Opcode, T) {
if (decoder.pos >= decoder.limit) return NONE;
var code = decoder.read1();
match (code) {
0xFB => return fb_table.get(decoder.read_uleb32());
0xFC => return fc_table.get(decoder.read_uleb32());
0xFD => return fd_table.get(decoder.read_uleb32());
0xFE => return fe_table.get(decoder.read_uleb32());
_ => return main_table.get(code);
}
}
// Look up the value for a given opcode {op}.
def get(op: Opcode) -> T {
if (op.prefix == 0) return main_table.vals[op.code];
else return get2(op.prefix, op.code).1;
}
// Look up the value for a given 1-byte opcode {code}.
def get1(code: byte) -> (Opcode, T) {
return main_table.get(code);
}
// Look up the value for a given prefixed opcode {prefix, code}.
def get2(prefix: byte, code: u32) -> (Opcode, T) {
match (prefix) {
0x00 => return main_table.get(code);
0xFB => return fb_table.get(code);
0xFC => return fc_table.get(code);
0xFD => return fd_table.get(code);
0xFE => return fe_table.get(code);
}
return NONE;
}
// Set the value for the given opcode {op} to be {v}.
def set(op: Opcode, v: T) {
match (op.prefix) {
0x00 => main_table.vals[op.code] = v;
0xFB => fb_table.vals[op.code] = v;
0xFC => fc_table.vals[op.code] = v;
0xFD => fd_table.vals[op.code] = v;
0xFE => fe_table.vals[op.code] = v;
}
}
// Set the value for the given 1-byte opcode {code} to be {v}.
def set1(code: byte, v: T) {
main_table.vals[code] = v;
}
// Set the value for the given prefixed opcode {prefix, code} to be {v}.
def set2(prefix: byte, code: u32, v: T) {
match (prefix) {
0x00 => main_table.vals[code] = v;
0xFB => fb_table.vals[code] = v;
0xFC => fc_table.vals[code] = v;
0xFD => fd_table.vals[code] = v;
0xFE => fe_table.vals[code] = v;
}
}
}
// implementation detail of OpcodeMap.
private class OpcodeMapTable<T>(prefix: byte, globalOpTable: Array<Opcode>) {
def vals = Array<T>.new(256);
def get(code: u32) -> (Opcode, T) {
if (code > vals.length) {
var d: T;
return (Opcode.INVALID, d);
}
return (globalOpTable[code], vals[code]);
}
}
def globalOpTable_00 = Array<Opcode>.new(256);
def globalOpTable_FB = Array<Opcode>.new(256);
def globalOpTable_FC = Array<Opcode>.new(256);
def globalOpTable_FD = Array<Opcode>.new(256);
def globalOpTable_FE = Array<Opcode>.new(256);
def X_ = initGlobalOpTable();
def initGlobalOpTable() {
for (op in Opcode) {
match (op.prefix) {
0x00 => globalOpTable_00[op.code] = op;
0xFB => globalOpTable_FB[op.code] = op;
0xFC => globalOpTable_FC[op.code] = op;
0xFD => globalOpTable_FD[op.code] = op;
0xFE => globalOpTable_FE[op.code] = op;
}
}
}