Chromium Code Reviews| Index: src/trusted/validator_arm/dgen_decoder_output.py |
| =================================================================== |
| --- src/trusted/validator_arm/dgen_decoder_output.py (revision 0) |
| +++ src/trusted/validator_arm/dgen_decoder_output.py (revision 0) |
| @@ -0,0 +1,273 @@ |
| +#!/usr/bin/python |
| +# |
| +# Copyright (c) 2012 The Native Client Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| +# |
| + |
| +""" |
| +Responsible for generating the decoder based on parsed |
| +table representations. |
| +""" |
| + |
| + |
| +import dgen_opt |
| +import dgen_output |
| + |
| +# This file generates the class decoder Decoder as defined by the |
| +# decoder tables. The code is specifically written to minize the |
|
sehr (please use chromium)
2012/04/19 21:54:46
minimize
Karl
2012/04/24 19:58:27
Done.
|
| +# number of decoder classes needed to parse valid ARM |
| +# instructions. Many rows in the table use the same decoder class. In |
| +# addition, we optimize tables by merging, so long as the same decoder |
| +# class is built. |
| +# |
| +# The following files are generated: |
| +# |
| +# decoder.h |
| +# decoder.cc |
| +# |
| +# decoder.h declares the generated decoder parser class while |
| +# decoder.cc contains the implementation of that decoder class. |
| +# |
| +# For testing purposes (see dgen_test_output.py) different rules are |
| +# applied. Note: It may be worth reading dgen_test_output.py preamble |
| +# to get a better understanding of decoder actions, and why we need |
| +# the "action_filter" methods. |
| + |
| +# Defines the header for decoder.h |
| +H_HEADER=""" |
| +%(FILE_HEADER)s |
| + |
| +#ifndef %(IFDEF_NAME)s |
| +#define %(IFDEF_NAME)s |
| + |
| +#include "native_client/src/trusted/validator_arm/decode.h" |
| +#include "native_client/src/trusted/validator_arm/inst_classes.h" |
| + |
| +namespace nacl_arm_dec { |
| +""" |
| + |
| +DECODER_DECLARE_HEADER=""" |
| +// Defines a decoder class selector for instructions. |
| +class %(decoder_name)s : DecoderState { |
| + public: |
| + explicit %(decoder_name)s(); |
| + virtual ~%(decoder_name)s(); |
| + |
| + // Parses the given instruction, returning the decoder to use. |
| + virtual const ClassDecoder& decode(const Instruction) const; |
| + |
| + private: |
| +""" |
| + |
| +DECODER_DECLARE_METHOD_COMMENTS=""" |
| + // The following list of methods correspond to each decoder table, |
| + // and implements the pattern matching of the corresponding bit |
| + // patterns. After matching the corresponding bit patterns, they |
| + // either call other methods in this list (corresponding to another |
| + // decoder table), or they return the instance field that implements |
| + // the class decoder that should be used to decode the particular |
| + // instruction. |
| +""" |
| + |
| +DECODER_DECLARE_METHOD=""" |
| + inline const ClassDecoder& decode_%(table_name)s( |
| + const Instruction insn) const; |
| +""" |
| + |
| +DECODER_DECLARE_FIELD_COMMENTS=""" |
| + // The following fields define the set of class decoders |
| + // that can be returned by the API function "decode". They |
| + // are created once as instance fields, and then returned |
| + // by the table methods above. This speeds up the code since |
| + // the class decoders need to only be built once (and reused |
| + // for each call to "decode"). |
| +""" |
| + |
| +DECODER_DECLARE_FIELD=""" |
| + const %(decoder)s %(decoder)s_instance_; |
| +""" |
| + |
| +DECODER_DECLARE_FOOTER=""" |
| +}; |
| +""" |
| + |
| +H_FOOTER=""" |
| +} // namespace nacl_arm_dec |
| +#endif // %(IFDEF_NAME)s |
| +""" |
| + |
| +def generate_h(decoder, decoder_name, filename, out): |
| + """Entry point to the decoder for .h file. |
| + |
| + Args: |
| + decoder: The decoder defined by the list of Table objects to process. |
| + decoder_name: The name of the decoder state to build. |
| + filename: The (localized) name for the .h file. |
| + named_decoders: If true, generate a decoder state with named instances. |
| + out: a COutput object to write to. |
| + """ |
| + if not decoder.primary: raise Exception('No tables provided.') |
| + |
| + # Before starting, remove all testing information from the parsed tables. |
| + decoder = decoder.action_filter(['name']) |
| + |
| + values = { |
| + 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, |
| + 'IFDEF_NAME': dgen_output.ifdef_name(filename), |
| + 'decoder_name': decoder_name, |
| + } |
| + out.write(H_HEADER % values) |
| + out.write(DECODER_DECLARE_HEADER % values) |
| + out.write(DECODER_DECLARE_METHOD_COMMENTS) |
| + for table in decoder.tables(): |
| + values['table_name'] = table.name |
| + out.write(DECODER_DECLARE_METHOD % values) |
| + out.write(DECODER_DECLARE_FIELD_COMMENTS) |
| + for action in decoder.decoders(): |
| + values['decoder'] = action.name; |
| + out.write(DECODER_DECLARE_FIELD % values) |
| + out.write(DECODER_DECLARE_FOOTER % values) |
| + out.write(H_FOOTER % values) |
| + |
| +# Defines the header for DECODER.h |
| +CC_HEADER=""" |
| +%(FILE_HEADER)s |
| + |
| +#include "%(header_filename)s" |
| + |
| +#include <stdio.h> |
| + |
| +namespace nacl_arm_dec { |
| + |
| +""" |
| + |
| +CONSTRUCTOR_HEADER=""" |
| +%(decoder_name)s::%(decoder_name)s() : DecoderState() |
| +""" |
| + |
| +CONSTRUCTOR_FIELD_INIT=""" |
| + , %(decoder)s_instance_() |
| +""" |
| + |
| +CONSTRUCTOR_FOOTER=""" |
| +{} |
| + |
| +%(decoder_name)s::~%(decoder_name)s() {} |
| +""" |
| + |
| +METHOD_HEADER=""" |
| +// Implementation of table: %(table_name)s. |
| +// Specified by: %(citation)s |
| +const ClassDecoder& %(decoder_name)s::decode_%(table_name)s( |
| + const Instruction insn) const |
| +{ |
| +""" |
| + |
| +METHOD_DISPATCH=""" |
| + if (%(tests)s) |
| +""" |
| + |
| +METHOD_DISPATCH_CLASS_DECODER=""" |
| + return %(decoder)s_instance_; |
| +""" |
| + |
| +METHOD_DISPATCH_SUBMETHOD=""" |
| + return decode_%(subtable_name)s(insn); |
| +""" |
| + |
| +METHOD_FOOTER=""" |
| + // Catch any attempt to fall though ... |
| + fprintf(stderr, "TABLE IS INCOMPLETE: %(table_name)s could not parse %%08X", |
| + insn.bits(31, 0)); |
| + return Forbidden_instance_; |
| +} |
| +""" |
| + |
| +DECODER_METHOD=""" |
| +const ClassDecoder& %(decoder_name)s::decode(const Instruction insn) const { |
| + return decode_%(entry_table_name)s(insn); |
| +} |
| +""" |
| + |
| +CC_FOOTER=""" |
| +} // namespace nacl_arm_dec |
| +""" |
| + |
| +def generate_cc(decoder, decoder_name, filename, out): |
| + """Implementation of the decoder in .cc file |
| + |
| + Args: |
| + decoder: The decoder defined by the list of Table objects to process. |
| + decoder_name: The name of the decoder state to build. |
| + filename: The (localized) name for the .h file. |
| + named_decoders: If true, generate a decoder state with named instances. |
| + out: a COutput object to write to. |
| + """ |
| + if not decoder.primary: raise Exception('No tables provided.') |
| + assert filename.endswith('.cc') |
| + |
| + # Before starting, remove all testing information from the parsed tables. |
| + decoder = decoder.action_filter(['name']) |
| + values = { |
| + 'FILE_HEADER': dgen_output.HEADER_BOILERPLATE, |
| + 'header_filename': filename[:-2] + 'h', |
| + 'decoder_name': decoder_name, |
| + 'entry_table_name': decoder.primary.name, |
| + } |
| + out.write(CC_HEADER % values) |
| + _generate_constructors(decoder, values, out) |
| + _generate_methods(decoder, values, out) |
| + out.write(DECODER_METHOD % values) |
| + out.write(CC_FOOTER % values) |
| + |
| +def _generate_constructors(decoder, values, out): |
| + out.write(CONSTRUCTOR_HEADER % values) |
| + for decoder in decoder.decoders(): |
| + values['decoder'] = decoder.name |
| + out.write(CONSTRUCTOR_FIELD_INIT % values) |
| + out.write(CONSTRUCTOR_FOOTER % values) |
| + |
| +def _generate_methods(decoder, values, out): |
| + for table in decoder.tables(): |
| + opt_rows = sorted(dgen_opt.optimize_rows(table.rows)) |
| + print ("Table %s: %d rows minimized to %d" |
| + % (table.name, len(table.rows), len(opt_rows))) |
| + |
| + values['table_name'] = table.name |
| + values['citation'] = table.citation |
| + out.write(METHOD_HEADER % values) |
| + |
| + # Add message to stop compilation warnings if this table |
| + # doesn't require subtables to select a class decoder. |
| + if not [r for r in opt_rows |
| + if r.action.__class__.__name__ == 'DecoderMethod']: |
| + out.write(" UNREFERENCED_PARAMETER(insn);") |
| + |
| + for row in opt_rows: |
| + # Each row consists of a set of bit patterns defining if the row |
| + # is applicable. Convert this into a sequence of anded C test |
| + # expressions. For example, convert the following pair of bit |
| + # patterns: |
| + # |
| + # xxxx1010xxxxxxxxxxxxxxxxxxxxxxxx |
| + # xxxxxxxxxxxxxxxxxxxxxxxxxxxx0101 |
| + # |
| + # Each instruction is masked to get the the bits, and then |
| + # tested against the corresponding expected bits. Hence, the |
| + # above example is converted to: |
| + # |
| + # ((insn & 0x0F000000) != 0x0C000000) && |
| + # ((insn & 0x0000000F) != 0x00000005) |
| + values['tests'] = ' && '.join(["(%s)" % p.to_c_expr('insn') |
| + for p in row.patterns]) |
| + out.write(METHOD_DISPATCH % values) |
| + if row.action.__class__.__name__ == 'DecoderAction': |
| + values['decoder'] = row.action.name |
| + out.write(METHOD_DISPATCH_CLASS_DECODER % values) |
| + elif row.action.__class__.__name__ == 'DecoderMethod': |
| + values['subtable_name'] = row.action.name |
| + out.write(METHOD_DISPATCH_SUBMETHOD % values) |
| + else: |
| + raise Exception('Bad table action: %s' % repr(row.action)) |
| + out.write(METHOD_FOOTER % values) |
| Property changes on: src/trusted/validator_arm/dgen_decoder_output.py |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |