class RegParser(object): """ Parses the XML file, loading up the register database. """ def __init__(self, dbase): self.__db = dbase self.__reg = None self.__field = None self.__in_ports = False self.__current_val = 0 self.__current_token = '' self.__reset_type = 0 self.__reset_parameter = "" self.__token_list = [] self.save_id = None def parse(self, input_file): """ Parses the specified input file. """ parser = xml.parsers.expat.ParserCreate() parser.StartElementHandler = self.start_element parser.EndElementHandler = self.end_element parser.CharacterDataHandler = self.characters parser.ParseFile(input_file) def start_element(self, tag, attrs): """ Called every time an XML element begins """ self.__token_list = [] mname = 'start_' + tag if hasattr(self, mname): method = getattr(self, mname) method(attrs) def end_element(self, tag): """ Called every time an XML element end """ text = ''.join(self.__token_list) mname = 'end_' + tag if hasattr(self, mname): method = getattr(self, mname) method(text) def characters(self, data): """ Called with segments of the character data. This is not predictable in how it is called, so we must collect the information for assembly later. """ self.__token_list.append(data) def start_module(self, attrs): """ Called when the module tag is first encounterd. Pulls off the ID tag if it exists, and pulls out the description """ self.__db.module_name = attrs['name'] if 'owner' in attrs: self.__db.owner = attrs['owner'] if 'id' in attrs: self.save_id = cnv_str(attrs, 'id').upper() self.__db.descriptive_title = cnv_str(attrs, 'title') def start_base(self, attrs): """ Called when the base tag is encountered. Attributes are: offset (optional) addr_width data_width """ self.__db.address_bus_width = cnv_int(attrs, 'addr_width', 32) self.__db.data_bus_width = cnv_int(attrs, 'data_width', 32) def start_signal(self, attrs): """ Called when the signal tag is encountered. Attributes are: enb static side_effect type """ self.__field.use_output_enable = cnv_bool(attrs, 'enb') self.__field.output_is_static = cnv_bool(attrs, 'static') self.__field.output_has_side_effect = cnv_bool(attrs, 'side_effect') self.__field.volatile = cnv_bool(attrs, 'volatile') if attrs.get('type'): t = cnv_int(attrs, 'type') oneshot = cnv_int(attrs, 'oneshot') if t == BitField.READ_ONLY: self.__field.field_type = BitField.TYPE_READ_ONLY elif t == BitField.READ_WRITE: if oneshot == BitField.ONE_SHOT_ANY: self.__field.field_type = BitField.TYPE_READ_WRITE_1S elif oneshot == BitField.ONE_SHOT_ONE: self.__field.field_type = BitField.TYPE_READ_WRITE_1S_1 else: self.__field.field_type = BitField.TYPE_READ_WRITE elif t == BitField.WRITE_1_TO_CLEAR: if oneshot == BitField.ONE_SHOT_ANY: self.__field.field_type = BitField.TYPE_WRITE_1_TO_CLEAR_SET_1S elif oneshot == BitField.ONE_SHOT_ONE: self.__field.field_type = BitField.TYPE_WRITE_1_TO_CLEAR_SET_1S_1 else: self.__field.field_type = BitField.TYPE_WRITE_1_TO_CLEAR_SET elif t == BitField.WRITE_1_TO_SET: self.__field.field_type = BitField.TYPE_WRITE_1_TO_SET else: self.__field.field_type = BitField.TYPE_WRITE_ONLY else: self.__field.field_type = ID_TO_TYPE[attrs.get('field_type', 'RO')] def start_input(self, attrs): """ Called when the input tag is encountered. Attributes are; function load """ if attrs.get('function'): old_type = self.__field.field_type func = cnv_int(attrs, 'function', BitField.FUNC_ASSIGNMENT) if old_type == BitField.TYPE_READ_ONLY: if func == BitField.FUNC_PARALLEL: self.__field.field_type = BitField.TYPE_READ_ONLY_LOAD elif func == BitField.FUNC_SET_BITS: self.__field.field_type = BitField.TYPE_READ_ONLY_VALUE elif old_type == BitField.TYPE_READ_WRITE: if func == BitField.FUNC_SET_BITS: self.__field.field_type = BitField.TYPE_READ_WRITE_SET elif func == BitField.FUNC_CLEAR_BITS: self.__field.field_type = BitField.TYPE_READ_WRITE_CLR elif func == BitField.FUNC_PARALLEL: self.__field.field_type = BitField.TYPE_READ_WRITE_LOAD elif old_type == BitField.TYPE_READ_WRITE_1S: if func == BitField.FUNC_SET_BITS: self.__field.field_type = BitField.TYPE_READ_WRITE_SET_1S elif func == BitField.FUNC_CLEAR_BITS: self.__field.field_type = BitField.TYPE_READ_WRITE_CLR_1S elif func == BitField.FUNC_PARALLEL: self.__field.field_type = BitField.TYPE_READ_WRITE_LOAD_1S elif old_type == BitField.TYPE_READ_WRITE_1S_1: if func == BitField.FUNC_SET_BITS: self.__field.field_type = BitField.TYPE_READ_WRITE_SET_1S_1 elif func == BitField.FUNC_CLEAR_BITS: self.__field.field_type = BitField.TYPE_READ_WRITE_CLR_1S_1 elif func == BitField.FUNC_PARALLEL: self.__field.field_type = BitField.TYPE_READ_WRITE_LOAD_1S_1 elif old_type == BitField.TYPE_WRITE_1_TO_CLEAR_SET: if func == BitField.FUNC_PARALLEL: self.__field.field_type = BitField.TYPE_WRITE_1_TO_CLEAR_LOAD elif old_type == BitField.TYPE_WRITE_1_TO_CLEAR_SET_1S: if func == BitField.FUNC_PARALLEL: self.__field.field_type = BitField.TYPE_WRITE_1_TO_CLEAR_LOAD_1S elif old_type == BitField.TYPE_WRITE_1_TO_CLEAR_SET_1S_1: if func == BitField.FUNC_PARALLEL: self.__field.field_type = BitField.TYPE_WRITE_1_TO_CLEAR_LOAD_1S_1 self.__field.control_signal = cnv_str(attrs, 'load') def start_register(self, attrs): """ Called when the register tag is encountered. Attributes are: nocode dont_test hide """ self.__reg = Register() self.__reg.do_not_generate_code = cnv_bool(attrs, 'nocode') self.__reg.do_not_test = cnv_bool(attrs, 'dont_test') self.__reg.hide = cnv_bool(attrs, 'hide') def start_ports(self, attrs): """ Called when the ports tag is encountered. """ self.__in_ports = True def start_value(self, attrs): """ Called when the value tag is encountered. Attributes are: val token """ self.__current_val = attrs['val'] self.__current_token = attrs.get('token', '') def start_range(self, attrs): """ Called when the range tag is encountered. Attributes are: start stop """ self.__field = BitField(cnv_int(attrs, 'stop'), cnv_int(attrs, 'start')) self.__reg.add_bit_field(self.__field) def start_be(self, attrs): """ Called when the be tag is encountered. Attributes are: active """ self.__db.be_level = cnv_int(attrs, 'active') def start_reset(self, attrs): """ Called with the reset tag is encountered. If it is a ports definition, then it refers to a global reset, and the attributes are: active If not, then it refers to the reset value of a bit field, in which case the attribute is: type if type is not specified, the it is assumed to be RESET_NUMERIC """ if self.__in_ports: self.__db.reset_active_level = cnv_int(attrs, 'active') else: try: self.__reset_type = int(attrs.get('type', "0")) self.__reset_parameter = attrs.get('parameter', '') except ValueError: self.__reset_type = BitField.RESET_NUMERIC def end_register(self, text): """ Called when the register tag is terminated. """ self.__reg = None def end_ports(self, text): """ Called when the ports tag is terminated. """ self.__in_ports = False def end_range(self, text): """ Called when the range tag is terminated. """ self.__field = None def end_reset(self, text): """ Called when the register tag is terminated. If we are in a port definition, then the text contains the reset signal name. """ if self.__in_ports: self.__db.reset_name = text elif self.__reset_type == 1: self.__field.reset_input = text.strip() self.__field.reset_type = BitField.RESET_INPUT elif self.__reset_type == 2: self.__field.reset_parameter = self.__reset_parameter self.__field.reset_value = int(text, 16) self.__field.reset_type = BitField.RESET_PARAMETER else: self.__field.reset_value = int(text, 16) self.__field.reset_type = BitField.RESET_NUMERIC def end_token(self, text): """ Called when the token tag is terminated. The text is the register token value. """ self.__reg.token = text def end_ram_size(self, text): """ Called when the token tag is terminated. The text is the register token value. """ self.__reg.ram_size = int(text) def end_mneumonic(self, text): """ Called when the token tag is terminated. The text is the register token value. """ self.__reg.token = text def end_address(self, text): """ Called when the register tag is terminated. The address is the text value (base 10). At this point, the register can be added to the database, since the address is used as the key. """ self.__reg.address = int(text) self.__db.add_register(self.__reg) def end_signal(self, text): """ Called when the signal tag is terminated. The text value is assigned to the field's output signal """ self.__field.output_signal = text def end_value(self, text): """ Called when the value tag is terminated. The value, token and text value are added to the field's value list. """ self.__field.values.append((self.__current_val, self.__current_token, text)) def end_input(self, text): """ Called when the input tag is terminated. The text value is assigned to the field's input signal """ self.__field.input_signal = text def end_width(self, text): """ Called when the width tag is terminated. The text value is assigned as the register's width. This is assumed to be base 10. """ self.__reg.width = int(text) def end_name(self, text): """ Called when the name tag is terminated. If a field is active, then the text value is assigned to the field. Otherwise, it is assigned to the register. """ if self.__field: self.__field.field_name = text else: self.__reg.register_name = text def end_description(self, text): """ Called when the description tag is terminated. If a field is active, then the text value is assigned to the field. Otherwise, it is assigned to the register. """ if self.__field: self.__field.description = text else: self.__reg.description = text def end_overview(self, text): """ Called when the overview tag is terminated. The text value is assigned to the database's overview_text """ self.__db.overview_text = text def end_addr(self, text): """ Called when the addr tag is terminated. The text value is assigned to the database's address_bus_name """ self.__db.address_bus_name = text def end_data_in(self, text): """ Called when the data_in tag is terminated. The text value is assigned to the database's write_data_name """ self.__db.write_data_name = text def end_data_out(self, text): """ Called when the data_out tag is terminated. The text value is assigned to the database's read_data_name """ self.__db.read_data_name = text def end_be(self, text): """ Called when the be tag is terminated. The text value is assigned to the database's byte_strobe_name """ self.__db.byte_strobe_name = text def end_wr(self, text): """ Called when the wr tag is terminated. The text value is assigned to the database's write_strobe_name """ self.__db.write_strobe_name = text def end_ack(self, text): """ Called when the ack tag is terminated. The text value is assigned to the database's acknowledge_name """ self.__db.acknowledge_name = text def end_rd(self, text): """ Called when the rd tag is terminated. The text value is assigned to the database's read_strobe_name """ self.__db.read_strobe_name = text def end_clk(self, text): """ Called when the clk tag is terminated. The text value is assigned to the database's clock_name """ self.__db.clock_name = text