x86: Fix x86 instruction decoder selftest to check only .text
[linux-2.6-block.git] / arch / x86 / tools / gen-insn-attr-x86.awk
CommitLineData
eb13296c
MH
1#!/bin/awk -f
2# gen-insn-attr-x86.awk: Instruction attribute table generator
3# Written by Masami Hiramatsu <mhiramat@redhat.com>
4#
5# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c
6
7BEGIN {
8 print "/* x86 opcode map generated from x86-opcode-map.txt */"
9 print "/* Do not change this code. */"
10 ggid = 1
11 geid = 1
12
13 opnd_expr = "^[[:alpha:]]"
14 ext_expr = "^\\("
15 sep_expr = "^\\|$"
16 group_expr = "^Grp[[:alnum:]]+"
17
18 imm_expr = "^[IJAO][[:lower:]]"
19 imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
20 imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
21 imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)"
22 imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)"
23 imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)"
24 imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)"
25 imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
26 imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
27 imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)"
28 imm_flag["Ob"] = "INAT_MOFFSET"
29 imm_flag["Ov"] = "INAT_MOFFSET"
30
31 modrm_expr = "^([CDEGMNPQRSUVW][[:lower:]]+|NTA|T[012])"
32 force64_expr = "\\([df]64\\)"
33 rex_expr = "^REX(\\.[XRWB]+)*"
34 fpu_expr = "^ESC" # TODO
35
36 lprefix1_expr = "\\(66\\)"
37 delete lptable1
38 lprefix2_expr = "\\(F2\\)"
39 delete lptable2
40 lprefix3_expr = "\\(F3\\)"
41 delete lptable3
42 max_lprefix = 4
43
44 prefix_expr = "\\(Prefix\\)"
45 prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
46 prefix_num["REPNE"] = "INAT_PFX_REPNE"
47 prefix_num["REP/REPE"] = "INAT_PFX_REPE"
48 prefix_num["LOCK"] = "INAT_PFX_LOCK"
49 prefix_num["SEG=CS"] = "INAT_PFX_CS"
50 prefix_num["SEG=DS"] = "INAT_PFX_DS"
51 prefix_num["SEG=ES"] = "INAT_PFX_ES"
52 prefix_num["SEG=FS"] = "INAT_PFX_FS"
53 prefix_num["SEG=GS"] = "INAT_PFX_GS"
54 prefix_num["SEG=SS"] = "INAT_PFX_SS"
55 prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
56
57 delete table
58 delete etable
59 delete gtable
60 eid = -1
61 gid = -1
62}
63
64function semantic_error(msg) {
65 print "Semantic error at " NR ": " msg > "/dev/stderr"
66 exit 1
67}
68
69function debug(msg) {
70 print "DEBUG: " msg
71}
72
73function array_size(arr, i,c) {
74 c = 0
75 for (i in arr)
76 c++
77 return c
78}
79
80/^Table:/ {
81 print "/* " $0 " */"
82}
83
84/^Referrer:/ {
85 if (NF == 1) {
86 # primary opcode table
87 tname = "inat_primary_table"
88 eid = -1
89 } else {
90 # escape opcode table
91 ref = ""
92 for (i = 2; i <= NF; i++)
93 ref = ref $i
94 eid = escape[ref]
95 tname = sprintf("inat_escape_table_%d", eid)
96 }
97}
98
99/^GrpTable:/ {
100 print "/* " $0 " */"
101 if (!($2 in group))
102 semantic_error("No group: " $2 )
103 gid = group[$2]
104 tname = "inat_group_table_" gid
105}
106
107function print_table(tbl,name,fmt,n)
108{
109 print "const insn_attr_t " name " = {"
110 for (i = 0; i < n; i++) {
111 id = sprintf(fmt, i)
112 if (tbl[id])
113 print " [" id "] = " tbl[id] ","
114 }
115 print "};"
116}
117
118/^EndTable/ {
119 if (gid != -1) {
120 # print group tables
121 if (array_size(table) != 0) {
122 print_table(table, tname "[INAT_GROUP_TABLE_SIZE]",
123 "0x%x", 8)
124 gtable[gid,0] = tname
125 }
126 if (array_size(lptable1) != 0) {
127 print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]",
128 "0x%x", 8)
129 gtable[gid,1] = tname "_1"
130 }
131 if (array_size(lptable2) != 0) {
132 print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]",
133 "0x%x", 8)
134 gtable[gid,2] = tname "_2"
135 }
136 if (array_size(lptable3) != 0) {
137 print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]",
138 "0x%x", 8)
139 gtable[gid,3] = tname "_3"
140 }
141 } else {
142 # print primary/escaped tables
143 if (array_size(table) != 0) {
144 print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]",
145 "0x%02x", 256)
146 etable[eid,0] = tname
147 }
148 if (array_size(lptable1) != 0) {
149 print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]",
150 "0x%02x", 256)
151 etable[eid,1] = tname "_1"
152 }
153 if (array_size(lptable2) != 0) {
154 print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]",
155 "0x%02x", 256)
156 etable[eid,2] = tname "_2"
157 }
158 if (array_size(lptable3) != 0) {
159 print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]",
160 "0x%02x", 256)
161 etable[eid,3] = tname "_3"
162 }
163 }
164 print ""
165 delete table
166 delete lptable1
167 delete lptable2
168 delete lptable3
169 gid = -1
170 eid = -1
171}
172
173function add_flags(old,new) {
174 if (old && new)
175 return old " | " new
176 else if (old)
177 return old
178 else
179 return new
180}
181
182# convert operands to flags.
183function convert_operands(opnd, i,imm,mod)
184{
185 imm = null
186 mod = null
187 for (i in opnd) {
188 i = opnd[i]
189 if (match(i, imm_expr) == 1) {
190 if (!imm_flag[i])
191 semantic_error("Unknown imm opnd: " i)
192 if (imm) {
193 if (i != "Ib")
194 semantic_error("Second IMM error")
195 imm = add_flags(imm, "INAT_SCNDIMM")
196 } else
197 imm = imm_flag[i]
198 } else if (match(i, modrm_expr))
199 mod = "INAT_MODRM"
200 }
201 return add_flags(imm, mod)
202}
203
204/^[0-9a-f]+\:/ {
205 if (NR == 1)
206 next
207 # get index
208 idx = "0x" substr($1, 1, index($1,":") - 1)
209 if (idx in table)
210 semantic_error("Redefine " idx " in " tname)
211
212 # check if escaped opcode
213 if ("escape" == $2) {
214 if ($3 != "#")
215 semantic_error("No escaped name")
216 ref = ""
217 for (i = 4; i <= NF; i++)
218 ref = ref $i
219 if (ref in escape)
220 semantic_error("Redefine escape (" ref ")")
221 escape[ref] = geid
222 geid++
223 table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")"
224 next
225 }
226
227 variant = null
228 # converts
229 i = 2
230 while (i <= NF) {
231 opcode = $(i++)
232 delete opnds
233 ext = null
234 flags = null
235 opnd = null
236 # parse one opcode
237 if (match($i, opnd_expr)) {
238 opnd = $i
239 split($(i++), opnds, ",")
240 flags = convert_operands(opnds)
241 }
242 if (match($i, ext_expr))
243 ext = $(i++)
244 if (match($i, sep_expr))
245 i++
246 else if (i < NF)
247 semantic_error($i " is not a separator")
248
249 # check if group opcode
250 if (match(opcode, group_expr)) {
251 if (!(opcode in group)) {
252 group[opcode] = ggid
253 ggid++
254 }
255 flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")")
256 }
257 # check force(or default) 64bit
258 if (match(ext, force64_expr))
259 flags = add_flags(flags, "INAT_FORCE64")
260
261 # check REX prefix
262 if (match(opcode, rex_expr))
263 flags = add_flags(flags, "INAT_REXPFX")
264
265 # check coprocessor escape : TODO
266 if (match(opcode, fpu_expr))
267 flags = add_flags(flags, "INAT_MODRM")
268
269 # check prefixes
270 if (match(ext, prefix_expr)) {
271 if (!prefix_num[opcode])
272 semantic_error("Unknown prefix: " opcode)
273 flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")")
274 }
275 if (length(flags) == 0)
276 continue
277 # check if last prefix
278 if (match(ext, lprefix1_expr)) {
279 lptable1[idx] = add_flags(lptable1[idx],flags)
280 variant = "INAT_VARIANT"
281 } else if (match(ext, lprefix2_expr)) {
282 lptable2[idx] = add_flags(lptable2[idx],flags)
283 variant = "INAT_VARIANT"
284 } else if (match(ext, lprefix3_expr)) {
285 lptable3[idx] = add_flags(lptable3[idx],flags)
286 variant = "INAT_VARIANT"
287 } else {
288 table[idx] = add_flags(table[idx],flags)
289 }
290 }
291 if (variant)
292 table[idx] = add_flags(table[idx],variant)
293}
294
295END {
296 # print escape opcode map's array
297 print "/* Escape opcode map array */"
298 print "const insn_attr_t const *inat_escape_tables[INAT_ESC_MAX + 1]" \
299 "[INAT_LPREFIX_MAX + 1] = {"
300 for (i = 0; i < geid; i++)
301 for (j = 0; j < max_lprefix; j++)
302 if (etable[i,j])
303 print " ["i"]["j"] = "etable[i,j]","
304 print "};\n"
305 # print group opcode map's array
306 print "/* Group opcode map array */"
307 print "const insn_attr_t const *inat_group_tables[INAT_GRP_MAX + 1]"\
308 "[INAT_LPREFIX_MAX + 1] = {"
309 for (i = 0; i < ggid; i++)
310 for (j = 0; j < max_lprefix; j++)
311 if (gtable[i,j])
312 print " ["i"]["j"] = "gtable[i,j]","
313 print "};"
314}