x86: Fix x86 instruction decoder selftest to check only .text
[pandora-kernel.git] / arch / x86 / tools / gen-insn-attr-x86.awk
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
7 BEGIN {
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
64 function semantic_error(msg) {
65         print "Semantic error at " NR ": " msg > "/dev/stderr"
66         exit 1
67 }
68
69 function debug(msg) {
70         print "DEBUG: " msg
71 }
72
73 function 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
107 function 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
173 function 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.
183 function 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
295 END {
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 }