OLD | NEW |
| (Empty) |
1 #!/usr/bin/python | |
2 # | |
3 # Copyright (c) 2012 The Native Client Authors. All rights reserved. | |
4 # Use of this source code is governed by a BSD-style license that can be | |
5 # found in the LICENSE file. | |
6 # | |
7 | |
8 """ | |
9 Responsible for generating the decoder based on parsed | |
10 table representations. | |
11 """ | |
12 | |
13 | |
14 import dgen_opt | |
15 import dgen_output | |
16 | |
17 # This file generates the class decoder Decoder as defined by the | |
18 # decoder tables. The code is specifically written to minimize the | |
19 # number of decoder classes needed to parse valid ARM | |
20 # instructions. Many rows in the table use the same decoder class. In | |
21 # addition, we optimize tables by merging, so long as the same decoder | |
22 # class is built. | |
23 # | |
24 # The following files are generated: | |
25 # | |
26 # decoder.h | |
27 # decoder.cc | |
28 # | |
29 # decoder.h declares the generated decoder parser class while | |
30 # decoder.cc contains the implementation of that decoder class. | |
31 # | |
32 # For testing purposes (see dgen_test_output.py) different rules are | |
33 # applied. Note: It may be worth reading dgen_test_output.py preamble | |
34 # to get a better understanding of decoder actions, and why we need | |
35 # the "action_filter" methods. | |
36 | |
37 # Defines the header for decoder.h | |
38 H_HEADER=""" | |
39 %(FILE_HEADER)s | |
40 | |
41 #ifndef %(IFDEF_NAME)s | |
42 #define %(IFDEF_NAME)s | |
43 | |
44 #include "native_client/src/trusted/validator_arm/decode.h" | |
45 #include "native_client/src/trusted/validator_arm/inst_classes.h" | |
46 | |
47 namespace nacl_arm_dec { | |
48 """ | |
49 | |
50 DECODER_DECLARE_HEADER=""" | |
51 // Defines a decoder class selector for instructions. | |
52 class %(decoder_name)s : DecoderState { | |
53 public: | |
54 explicit %(decoder_name)s(); | |
55 virtual ~%(decoder_name)s(); | |
56 | |
57 // Parses the given instruction, returning the decoder to use. | |
58 virtual const ClassDecoder& decode(const Instruction) const; | |
59 | |
60 private: | |
61 """ | |
62 | |
63 DECODER_DECLARE_METHOD_COMMENTS=""" | |
64 // The following list of methods correspond to each decoder table, | |
65 // and implements the pattern matching of the corresponding bit | |
66 // patterns. After matching the corresponding bit patterns, they | |
67 // either call other methods in this list (corresponding to another | |
68 // decoder table), or they return the instance field that implements | |
69 // the class decoder that should be used to decode the particular | |
70 // instruction. | |
71 """ | |
72 | |
73 DECODER_DECLARE_METHOD=""" | |
74 inline const ClassDecoder& decode_%(table_name)s( | |
75 const Instruction insn) const; | |
76 """ | |
77 | |
78 DECODER_DECLARE_FIELD_COMMENTS=""" | |
79 // The following fields define the set of class decoders | |
80 // that can be returned by the API function "decode". They | |
81 // are created once as instance fields, and then returned | |
82 // by the table methods above. This speeds up the code since | |
83 // the class decoders need to only be built once (and reused | |
84 // for each call to "decode"). | |
85 """ | |
86 | |
87 DECODER_DECLARE_FIELD=""" | |
88 const %(decoder)s %(decoder)s_instance_; | |
89 """ | |
90 | |
91 DECODER_DECLARE_FOOTER=""" | |
92 }; | |
93 """ | |
94 | |
95 H_FOOTER=""" | |
96 } // namespace nacl_arm_dec | |
97 #endif // %(IFDEF_NAME)s | |
98 """ | |
99 | |
100 def generate_h(decoder, decoder_name, filename, out): | |
101 """Entry point to the decoder for .h file. | |
102 | |
103 Args: | |
104 decoder: The decoder defined by the list of Table objects to process. | |
105 decoder_name: The name of the decoder state to build. | |
106 filename: The (localized) name for the .h file. | |
107 named_decoders: If true, generate a decoder state with named instances. | |
108 out: a COutput object to write to. | |
109 """ | |
110 if not decoder.primary: raise Exception('No tables provided.') | |
111 | |
112 # Before starting, remove all testing information from the parsed tables. | |
113 decoder = decoder.action_filter(['name']) | |
114 | |
115 values = { | |
116 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, | |
117 'IFDEF_NAME': dgen_output.ifdef_name(filename), | |
118 'decoder_name': decoder_name, | |
119 } | |
120 out.write(H_HEADER % values) | |
121 out.write(DECODER_DECLARE_HEADER % values) | |
122 out.write(DECODER_DECLARE_METHOD_COMMENTS) | |
123 for table in decoder.tables(): | |
124 values['table_name'] = table.name | |
125 out.write(DECODER_DECLARE_METHOD % values) | |
126 out.write(DECODER_DECLARE_FIELD_COMMENTS) | |
127 for action in decoder.decoders(): | |
128 values['decoder'] = action.name; | |
129 out.write(DECODER_DECLARE_FIELD % values) | |
130 out.write(DECODER_DECLARE_FOOTER % values) | |
131 out.write(H_FOOTER % values) | |
132 | |
133 # Defines the header for DECODER.h | |
134 CC_HEADER=""" | |
135 %(FILE_HEADER)s | |
136 | |
137 #include "%(header_filename)s" | |
138 | |
139 #include <stdio.h> | |
140 | |
141 namespace nacl_arm_dec { | |
142 | |
143 """ | |
144 | |
145 CONSTRUCTOR_HEADER=""" | |
146 %(decoder_name)s::%(decoder_name)s() : DecoderState() | |
147 """ | |
148 | |
149 CONSTRUCTOR_FIELD_INIT=""" | |
150 , %(decoder)s_instance_() | |
151 """ | |
152 | |
153 CONSTRUCTOR_FOOTER=""" | |
154 {} | |
155 | |
156 %(decoder_name)s::~%(decoder_name)s() {} | |
157 """ | |
158 | |
159 METHOD_HEADER=""" | |
160 // Implementation of table: %(table_name)s. | |
161 // Specified by: %(citation)s | |
162 const ClassDecoder& %(decoder_name)s::decode_%(table_name)s( | |
163 const Instruction insn) const | |
164 { | |
165 """ | |
166 | |
167 METHOD_DISPATCH=""" | |
168 if (%(tests)s) | |
169 """ | |
170 | |
171 METHOD_DISPATCH_CLASS_DECODER=""" | |
172 return %(decoder)s_instance_; | |
173 """ | |
174 | |
175 METHOD_DISPATCH_SUBMETHOD=""" | |
176 return decode_%(subtable_name)s(insn); | |
177 """ | |
178 | |
179 METHOD_FOOTER=""" | |
180 // Catch any attempt to fall though ... | |
181 fprintf(stderr, "TABLE IS INCOMPLETE: %(table_name)s could not parse %%08X", | |
182 insn.bits(31, 0)); | |
183 return Forbidden_instance_; | |
184 } | |
185 """ | |
186 | |
187 DECODER_METHOD=""" | |
188 const ClassDecoder& %(decoder_name)s::decode(const Instruction insn) const { | |
189 return decode_%(entry_table_name)s(insn); | |
190 } | |
191 """ | |
192 | |
193 CC_FOOTER=""" | |
194 } // namespace nacl_arm_dec | |
195 """ | |
196 | |
197 def generate_cc(decoder, decoder_name, filename, out): | |
198 """Implementation of the decoder in .cc file | |
199 | |
200 Args: | |
201 decoder: The decoder defined by the list of Table objects to process. | |
202 decoder_name: The name of the decoder state to build. | |
203 filename: The (localized) name for the .h file. | |
204 named_decoders: If true, generate a decoder state with named instances. | |
205 out: a COutput object to write to. | |
206 """ | |
207 if not decoder.primary: raise Exception('No tables provided.') | |
208 assert filename.endswith('.cc') | |
209 | |
210 # Before starting, remove all testing information from the parsed tables. | |
211 decoder = decoder.action_filter(['name']) | |
212 values = { | |
213 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, | |
214 'header_filename': filename[:-2] + 'h', | |
215 'decoder_name': decoder_name, | |
216 'entry_table_name': decoder.primary.name, | |
217 } | |
218 out.write(CC_HEADER % values) | |
219 _generate_constructors(decoder, values, out) | |
220 _generate_methods(decoder, values, out) | |
221 out.write(DECODER_METHOD % values) | |
222 out.write(CC_FOOTER % values) | |
223 | |
224 def _generate_constructors(decoder, values, out): | |
225 out.write(CONSTRUCTOR_HEADER % values) | |
226 for decoder in decoder.decoders(): | |
227 values['decoder'] = decoder.name | |
228 out.write(CONSTRUCTOR_FIELD_INIT % values) | |
229 out.write(CONSTRUCTOR_FOOTER % values) | |
230 | |
231 def _generate_methods(decoder, values, out): | |
232 for table in decoder.tables(): | |
233 opt_rows = sorted(dgen_opt.optimize_rows(table.rows)) | |
234 print ("Table %s: %d rows minimized to %d" | |
235 % (table.name, len(table.rows), len(opt_rows))) | |
236 | |
237 values['table_name'] = table.name | |
238 values['citation'] = table.citation | |
239 out.write(METHOD_HEADER % values) | |
240 | |
241 # Add message to stop compilation warnings if this table | |
242 # doesn't require subtables to select a class decoder. | |
243 if not [r for r in opt_rows | |
244 if r.action.__class__.__name__ == 'DecoderMethod']: | |
245 out.write(" UNREFERENCED_PARAMETER(insn);") | |
246 | |
247 for row in opt_rows: | |
248 # Each row consists of a set of bit patterns defining if the row | |
249 # is applicable. Convert this into a sequence of anded C test | |
250 # expressions. For example, convert the following pair of bit | |
251 # patterns: | |
252 # | |
253 # xxxx1010xxxxxxxxxxxxxxxxxxxxxxxx | |
254 # xxxxxxxxxxxxxxxxxxxxxxxxxxxx0101 | |
255 # | |
256 # Each instruction is masked to get the the bits, and then | |
257 # tested against the corresponding expected bits. Hence, the | |
258 # above example is converted to: | |
259 # | |
260 # ((insn & 0x0F000000) != 0x0C000000) && | |
261 # ((insn & 0x0000000F) != 0x00000005) | |
262 values['tests'] = ' && '.join(["(%s)" % p.to_c_expr('insn') | |
263 for p in row.patterns]) | |
264 out.write(METHOD_DISPATCH % values) | |
265 if row.action.__class__.__name__ == 'DecoderAction': | |
266 values['decoder'] = row.action.name | |
267 out.write(METHOD_DISPATCH_CLASS_DECODER % values) | |
268 elif row.action.__class__.__name__ == 'DecoderMethod': | |
269 values['subtable_name'] = row.action.name | |
270 out.write(METHOD_DISPATCH_SUBMETHOD % values) | |
271 else: | |
272 raise Exception('Bad table action: %s' % repr(row.action)) | |
273 out.write(METHOD_FOOTER % values) | |
OLD | NEW |