Пример #1
0
    def __init__(self, fl, line_num, uid, props, params=None):
        self._fl = fl
        self._line_num = line_num
        self._uid = uid
        self._lazy_statements = {}
        self._amb_types = {}
        self._inline_comment = None
        self._st_language = None

        if isinstance(props, str):
            self._props = OrderedDict()
            self._props[Types.name] = props
        elif isinstance(props, dict):
            self._props = OrderedDict(props)
        elif props is None:
            self._props = OrderedDict()
        else:
            raise InvalidTypeException('props must be a dict or str')

        if isinstance(params, str):
            self._params = OrderedDict()
            self._params[Types.name] = params
        elif isinstance(params, dict):
            self._params = OrderedDict(params)
        elif params is None:
            self._params = OrderedDict()
        else:
            raise InvalidTypeException('params must be a dict or str')
Пример #2
0
    def add_device(self, st, case_insensitive=False):
        """

        Adds a statement to the scope tree.

        If LAZY_STATEMENT was added:

        Takes in a statement and finds its LAZY_OBJECT equivilent, and
        updates the scope tree (remove LAZY_OBJECT and add to current scope).
        It also calls bind() on the LAZY_OBJECT so all referencing Statements
        can be updated to reference to the correct object.

        Args:
           st (Statement): Statement to add to scoping
           case_insensitive

        Throws:
           NameConflictException if the name conflicts with another name within the scope
        """
        if isinstance(st, Device):
            st.set_prop(Types.statementType, "__DEVICE__")
            self._add_statement(st, True, case_insensitive)
            self._name_to_statement[st.get_prop(Types.name)] = st
        else:
            raise InvalidTypeException(st.name + " is not of type Device")
Пример #3
0
    def add(self, st, case_insensitive=False):
        """
        Generic add function.  This takes in ModelDef, Device, ENODE, and str.
        If the object is a str, then it will assume this is a lazy object (type
        is not yet known).

        Args:
           st (ModelDef, Device, ENODE, or str): Object to add to index
           case_insensitive

        Throws:
           InvalidTypeException. Raised if st is of an unknown type
        """
        if isinstance(st, ModelDef):
            self.add_model(st, case_insensitive=case_insensitive)
        elif isinstance(st, Device):
            self.add_device(st, case_insensitive=case_insensitive)
        elif isinstance(st, ENODE):
            self.add_enode(st, case_insensitive=case_insensitive)
        elif isinstance(st, Ref):
            self.add_ref(st)
        elif isinstance(st, LAZY_STATEMENT):
            self.add_lazy_statement(st)
        elif isinstance(st, Command):
            st.set_prop(Types.statementType, "__COMMAND__")
            self._add_statement(st)
        #        elif isinstance(st, SUBCKT):
        #            st.set_prop(Types.statementType, "__SUBCKT__")
        #            self._add_statement(st, case_insensitive=case_insensitive)
        else:
            raise InvalidTypeException(
                st + ' must be of type ModelDef, Device, ENODE, or str')
Пример #4
0
    def add(self, ws):
        """
        Adds a Statement to the index

        Args:
           ws (Statement): Statement to be indexed

        """
        if not isinstance(ws, self._t):
            raise InvalidTypeException(ws.__class__.__name__ +
                                       " is not instance of " +
                                       self._t.__name__)

        # get the files name
        nm = self._f(ws)

        # if first entry, then create array
        if nm not in self._file_dict:
            self._file_dict[nm] = []
            self._file_dict_keys[nm] = []

        if self._s is not None:
            # get the line number
            key = self._s(ws)

            # find the position in the list that the statement
            # belongs in, then insert both the key and the statement
            # at that position
            key_pos = bisect_left(self._file_dict_keys[nm], key)
            self._file_dict_keys[nm].insert(key_pos, key)
            self._file_dict[nm].insert(key_pos, ws)
        else:
            self._file_dict[nm].append(ws)
Пример #5
0
 def add_device_type(self, device_type):
     if isinstance(device_type, XmlDeviceType):
         if not self._device_types.get(device_type.name):
             self._device_types[device_type.name] = []
         self._device_types[device_type.name].append(device_type)
     else:
         raise InvalidTypeException(device_type +
                                    " is not of type DeviceType")
Пример #6
0
    def add_ref(self, st):
        """

        Adds a Ref to the scope tree.

        Args:
           st (Statement): Statement to add to scoping
        """
        if isinstance(st, Ref):
            st.set_prop(Types.statementType, "__REF__")
            self._add_statement(st)
        else:
            raise InvalidTypeException(st.name + " is not of type Ref")
Пример #7
0
    def add_index(self, idx):
        """
        Adds an index  to the data model.

        Args:
           idx (StatementIndex): Statement index to add

        Throws:
           InvalidTypeException. If the user passes in idx that is of an incorrect type
        """
        if isinstance(idx, StatementIndex):
            self._indexes.append((idx.type, idx))
        else:
            raise InvalidTypeException(idx + " is not of type StatementIndex")
Пример #8
0
    def add_enode(self, e, case_insensitive=False):
        """

        Adds a ENODE to the scope tree.

        ENODES will not bind to LAZY_STATEMENTs and attempts to add an ENODE that
        conflicts with a LAZY_STATEMENT will get a NameConflictException

        Args:
           e (Statement): Statement to add to scoping
           case_insensitive

        Throws:
           NameConflictException if the name conflicts with another name within the scope
        """
        if isinstance(e, ENODE):
            e.set_prop(Types.statementType, "__ENODE__")
            self._add_statement(e, case_insensitive)
        else:
            raise InvalidTypeException(e.name + " is not of type ENODE")
Пример #9
0
    def set_lazy_statement(self, o, types):
        """
        Sets a lazy object to a device.  This is used when o has not been properly
        defined when the current line is parsed.  The parser should know a list of
        possibilities and this is passed in as well.  When the object is defined,
        it will call bind causing this object to properly set references to o.

        Args:
           o (LAZY_STATEMENT): Object who has not yet been defined
           types (list<__class__>): List of all possible classes that o could be.

        Throws:
           InvalidTypeException. if o is not of type LAZY_STATEMENT
        """

        if 'add_listener' not in o.__class__.__dict__:
            raise InvalidTypeException(
                str(o) + " (" + str(o.__class__) +
                ") is not of type LAZY_STATEMENT")

        self._lazy_statements[o.name] = types
        o.add_listener(self)
Пример #10
0
 def __init__(self, trans_type):
     if trans_type.upper() not in transient_value_map.keys():
         raise InvalidTypeException(trans_type + " is not a valid type of transient")
     self._transType = trans_type.upper()
     self._transParams = OrderedDict()
Пример #11
0
 def add_directive_type(self, directive_type):
     if isinstance(directive_type, XmlDirectiveType):
         self._directive_types[directive_type.identity()] = directive_type
     else:
         raise InvalidTypeException(directive_type +
                                    " is not of type DirectiveType")
Пример #12
0
    def add_model(self, m, case_insensitive=False):
        """
        Adds a model to the scope.  It takes in a ModelDef and either adds it
        to an existing MASTER_MODEL, or creates a new MASTER_MODEL and adds it
        to the scope.  All ModelDefs and MASTER_MODEL must be defined within
        the same scope.

        The ModefDef is also passed to existing indexes to be properly indexed.
        The MASTER_MODEL is passed to existing indexes when it is created.

        Args:
           m (ModelDef): Model added to scope
           case_insensitive

        Returns:
           MASTER_MODEL: parent of ModelDef

        Throws:
           NameConflictException if there is another object with the same name as
           m that is not a corresponding MASTER_MODEL or MASTER_MODEL within
           the same scope.

           InvalidModelException if m is not a ModelDef

        """
        master = None

        # type checking
        if not isinstance(m, ModelDef):
            raise InvalidTypeException(m.name + " is not of type ModeDef")

        # If MASTER_MODEL already exists
        model_name = m.name
        if case_insensitive:
            model_name = m.name.upper()

        if ("__MODELDEF__" + model_name) in self._statements and isinstance(
                self._statements[("__MODELDEF__" + model_name)], MASTER_MODEL):
            master = self._statements[("__MODELDEF__" + model_name)]
        else:
            d = self.get_object("__LAZYSTATEMENT__" + model_name)
            master = MASTER_MODEL(m.name)
            if isinstance(d, LAZY_STATEMENT):
                d.bind(master, case_insensitive)
                self.remove_statement(d)
            if self._lib_command is None:
                if self.scope_contains("__MODELDEF__" + model_name):
                    raise NameConflictException(
                        model_name + " has already been used in this scope")
            else:
                if self.local_scope_contains("__MODELDEF__" + model_name):
                    raise NameConflictException(
                        model_name + " has already been used in this scope")

            self._statements["__MODELDEF__" + model_name] = master
            # Put MASTER_MODEL in indexes (if any care to see it)
            self._add_to_indexes(master)

        m.set_prop(Types.statementType, "__MODELDEF__")
        master.add_model(m)

        # Add ModelDef to indexes
        self._add_to_indexes(m)

        return master
Пример #13
0
    def read_line(self, parsed_netlist_line, reader_state, top_reader_state, language_definition, control_device_handling_list,
                  inc_files_and_scopes, lib_files):
        """
        Reads a netlist line and calls the appropriate XDMFactory method to insert the statement into the data model.
        """
        if parsed_netlist_line.flag_top_pnl:
            top_reader_state.add_unknown_pnl(parsed_netlist_line)
            
            return parsed_netlist_line.linenum[-1]

        if XDMFactory.is_supported_device(parsed_netlist_line):
            device = XDMFactory.build_device(parsed_netlist_line, reader_state, language_definition)

            if device is None:
                return parsed_netlist_line.linenum[-1]

            # handle case of preprocess directive for xyce
            if parsed_netlist_line.preprocess_keyword_value and "hspice" in language_definition.language:
                # create parsed netlist line object for the preprocess directive
                preprocess_pnl = ParsedNetlistLine(parsed_netlist_line.filename, [0])
                preprocess_pnl.type = ".PREPROCESS"
                preprocess_pnl.local_type = ".PREPROCESS"
                preprocess_pnl.add_known_object(parsed_netlist_line.preprocess_keyword_value[0].split()[0], "PREPROCESS_KEYWORD_VALUE")
                preprocess_pnl.add_value_to_value_list(parsed_netlist_line.preprocess_keyword_value[0].split()[1])

                # check if preprocess directive already in index
                preprocess_uid = -1
                for fl, objs in reader_state.scope_index.source_line_index:
                    for obj in objs:
                        last_uid = obj.uid
                        if isinstance(obj, Command):
                            if obj.command_type == ".PREPROCESS":
                                preprocess_uid = obj.uid

                # if preprocess directive not in index, add in as second index after TITLE object
                if preprocess_uid < 0:
                    XDMFactory.build_directive(preprocess_pnl, reader_state, language_definition, self._lib_sect_list)

            if device.resolve_control_devices:
                control_device_handling_list.append((device, reader_state.scope_index))
            if device.device_type == "X":
                reader_state.add_subcircuit_device(device, reader_state.scope_index)
        elif XDMFactory.is_unknown_device(parsed_netlist_line):
            reader_state.add_unknown_pnl(parsed_netlist_line)
        elif XDMFactory.is_supported_directive(parsed_netlist_line):

            # for case of standalone .PARAM statements with no actual parameters!
            if parsed_netlist_line.type == ".PARAM" and not parsed_netlist_line.params_dict:
                parsed_netlist_line.type = "COMMENT"
                parsed_netlist_line.local_type = ""
                parsed_netlist_line.name = ".PARAM"
                parsed_netlist_line.params_dict["COMMENT"] = ".PARAM"
                XDMFactory.build_comment(parsed_netlist_line, reader_state)

            # BEWARE: hack for Spectre -- takes .PARAM params from inside subckt and moves them to paramsList for subckt
            # UPDATE: 2019-06-20 -- not sure if the hack is actually needed for Spectre translation, but it seems to 
            #                       cause problems with HSPICE translation (possibly PSPICE as well). But to err on the 
            #                       side of caution, will keep code but will check input language being Spectre 
            #                       before moving into the hacked code block
            elif parsed_netlist_line.type == ".PARAM" and not reader_state.scope_index.is_top_parent() and language_definition._language.upper() == "spectre":
                reader_state.scope_index.subckt_command.set_prop(Types.subcircuitParamsList,
                                                                 parsed_netlist_line.params_dict)
            else:
                directive = XDMFactory.build_directive(parsed_netlist_line, reader_state, language_definition, self._lib_sect_list)
                if parsed_netlist_line.type == ".END":
                    reader_state.end_directive = directive
        elif parsed_netlist_line.type == ".MODEL":
            XDMFactory.build_model(parsed_netlist_line, reader_state, language_definition)
        elif parsed_netlist_line.type == ".INC" or parsed_netlist_line.type == ".INCLUDE":
            if not parsed_netlist_line.known_objects[Types.fileNameValue] in self._reader_state.master_inc_list:
                self._reader_state.add_master_inc_list(parsed_netlist_line.known_objects[Types.fileNameValue])
                self._reader_state.add_master_inc_list_scopes(reader_state.scope_index)
                inc_files_and_scopes.append((parsed_netlist_line.known_objects[Types.fileNameValue], reader_state.scope_index))
            elif parsed_netlist_line.known_objects[Types.fileNameValue] in self._reader_state.master_inc_list and reader_state.scope_index.is_top_parent():
                for ind, file_and_scope in enumerate(inc_files_and_scopes):
                    (filename, scope) = file_and_scope
                    if parsed_netlist_line.known_objects[Types.fileNameValue] == filename:
                        inc_files_and_scopes[ind] = (parsed_netlist_line.known_objects[Types.fileNameValue], reader_state.scope_index)

                inc_ind = self._reader_state.master_inc_list.index(parsed_netlist_line.known_objects[Types.fileNameValue])
                self._reader_state.master_inc_list_scopes[inc_ind] = reader_state.scope_index
                # For filenames enclosed in single quotes, ntpath doesn't seem to strip trailing
                # single quote. Therefore, will strip the single quotes before before passing
                # to ntpath.
            parsed_netlist_line.known_objects[Types.fileNameValue] = \
                ntpath.split(parsed_netlist_line.known_objects[Types.fileNameValue].replace("'", "").replace("\"", ""))[1]
            XDMFactory.build_directive(parsed_netlist_line, reader_state, language_definition, self._lib_sect_list)
        elif parsed_netlist_line.type == ".LIB":
            # Prepare lib_file name
            if parsed_netlist_line.known_objects.get(Types.fileNameValue):
                lib_file = parsed_netlist_line.known_objects[Types.fileNameValue].replace("'", '').replace('"', '')

                if not os.path.isfile(lib_file):
                    lib_file = os.path.join(os.path.dirname(self._file), lib_file)

            # Only parse .LIB statements if they are on the parent scope (the scope that 
            # includes the stuff that actually needs to be simulated). Other .LIB sections
            # are unused sections that aren't called by current simulation. This avoids
            # multiple parsing/writing of same files.
            if parsed_netlist_line.known_objects.get(Types.fileNameValue) and reader_state.scope_index.is_top_parent():

                # if .lib command calls a section within the same file, add it to list of sections to parse 
                # for the current file. otherwise, add file/section to list of libraries to be parsed later
                if os.path.normpath(self._file) == os.path.normpath(lib_file):
                    self._lib_sect_list.append(parsed_netlist_line.known_objects[Types.libEntry])
                    child = self._reader_state.scope_index.get_child_scope(parsed_netlist_line.known_objects[Types.libEntry])
                    if not child is None:
                        reader_state.scope_index.retroactive_add_statement(child)

                elif parsed_netlist_line.known_objects.get(Types.libEntry):
                    lib_files.append((parsed_netlist_line.known_objects[Types.fileNameValue],
                                      parsed_netlist_line.known_objects[Types.libEntry]))

                else:
                    lib_files.append((parsed_netlist_line.known_objects[Types.fileNameValue],
                                      parsed_netlist_line.known_objects[Types.fileNameValue]))

                if not lib_file in self._reader_state.lib_files_in_scope:
                    self._reader_state.add_lib_files_in_scope(lib_file)

                if lib_file in self._reader_state.lib_files_not_in_scope:
                    self._reader_state.remove_lib_files_not_in_scope(lib_file)

            elif parsed_netlist_line.known_objects.get(Types.fileNameValue) and not reader_state.scope_index.is_top_parent():
                # for the case of a .lib file that isn't used by the top scope, and in included 
                # by a scope outside of the top scope, the file will need to be translated. 
                # unique files (file cannot be saved more than once) are saved to a tracking list 
                # (self._lib_files_not_in_scope) to be parsed at the very end.

                # in case a library section may be added in to top scope by a .lib statement later in the file. save
                # other .lib sects included, for retroactive processing
                if os.path.normpath(self._file) == os.path.normpath(lib_file):
                    self._reader_state.scope_index.add_child_scope_lib_sects(parsed_netlist_line.known_objects[Types.libEntry])

                # for libraries added in child scope in different files
                elif os.path.normpath(self._file) != os.path.normpath(lib_file):
                    if not lib_file in self._reader_state.lib_files_not_in_scope and not lib_file in self._reader_state.lib_files_in_scope:
                        # only file name needs to be saved - the whole file is outside the top scope,
                        # so the library section doesn't matter
                        self._reader_state.add_lib_files_not_in_scope(lib_file)
             
            if parsed_netlist_line.known_objects.get(Types.fileNameValue):
                parsed_netlist_line.known_objects[Types.fileNameValue] = \
                    ntpath.split(parsed_netlist_line.known_objects[Types.fileNameValue].replace("'", "").replace("\"", ""))[1]
            XDMFactory.build_directive(parsed_netlist_line, reader_state, language_definition, self._lib_sect_list)
        elif parsed_netlist_line.type == "DATA":
            XDMFactory.build_data(parsed_netlist_line, reader_state)
        elif parsed_netlist_line.type == "TITLE":
            XDMFactory.build_title(parsed_netlist_line, reader_state)
        elif parsed_netlist_line.type == "COMMENT":
            XDMFactory.build_comment(parsed_netlist_line, reader_state)
        # spectre simulator command.  defines language type
        elif parsed_netlist_line.type == "simulator":
            lang_type = parsed_netlist_line.params_dict.get('lang')
            # for x in lang_type :
            #    # print (x)
            #    # for y in lang_type[x]:
            #        # print (y, ":", lang_type[x][y])
            # print (lang_type['lang'])
            if 'spice' in lang_type:
                logging.info("Spectre Simulator Command Found.  Switching parse mode to spice.")
                xml_factory = XmlFactory(self._hspice_xml)
                xml_factory.read()
                self._language_definition = xml_factory.language_definition
                self._grammar_type = HSPICENetlistBoostParserInterface
                self._language_changed = True
            elif 'spectre' in lang_type:
                logging.info("Spectre Simulator Command Found.  Switching parse mode to spectre.")
                xml_factory = XmlFactory(self._spectre_xml)
                xml_factory.read()
                self._language_definition = xml_factory.language_definition
                self._grammar_type = SpectreNetlistBoostParserInterface
                self._language_changed = True
        else:
            logging.error("Unable to parse line: " + str(parsed_netlist_line.linenum))
            raise InvalidTypeException()

        return parsed_netlist_line.linenum[-1]