Example #1
0
    def test_transistor_gate_diff_same(self):
        netlist = Netlist()
        str_netlist = "M0001 VDD VDD N0002 GND NMOS\n" \
                      "M0002 N0001 IN002 IN002 VDD PMOS\n" \
                      "M0003 OUT01 N0001 IN002 VDD PMOS\n"
        netlist.set_netlist(str_netlist)

        self.assertTrue(
            netlist.get_transistor('M0001').is_gate_same_as_one_diff())
        self.assertTrue(
            netlist.get_transistor('M0002').is_gate_same_as_one_diff())
        self.assertFalse(
            netlist.get_transistor('M0003').is_gate_same_as_one_diff())
class ResistiveDefect:
    def __init__(self, db):
        self.netlist_ = Netlist()
        self.tg_netlist_ = Netlist()
        self.short_defects_ = list()
        self.open_defects_ = list()
        self.bsf_ = None
        self.bsf_weak_ = None
        self.faulty_bsf_ = None
        self.faulty_bsf_weak_ = None

        self.db_ = db.dup_self()
        self.cell_table_ = db.get_table()
        self.defect_table_ = self.cell_table_ + '_FAULT_LIB'
        if not self.db_.is_table_exist(self.defect_table_):
            self.create_fault_lib()
        self.db_.set_table(self.defect_table_)

    def create_fault_lib(self, is_drop_exist=False):
        table_desc = dict()
        table_desc['table_name'] = self.defect_table_
        table_columns = list()
        table_columns.append({
            'name': 'idFAULT_LIB',
            'type': 'INT',
            'property': 'NOT NULL AUTO_INCREMENT'
        })
        table_columns.append({
            'name': 'idCELL',
            'type': 'INT',
            'property': 'NOT NULL'
        })
        table_columns.append({
            'name': 'FAULT_DESC',
            'type': 'VARCHAR(1000)',
            'property': 'NULL'
        })
        table_columns.append({
            'name': 'FAULTY_NETLIST',
            'type': 'VARCHAR(1000)',
            'property': 'NULL'
        })
        table_columns.append({
            'name':
            'FAULTY_BSF',
            'type':
            'VARCHAR(256)',
            'property':
            "CHARACTER SET 'utf8' COLLATE 'utf8_bin' NULL"
        })
        table_columns.append({
            'name':
            'FAULTY_BSF_weak',
            'type':
            'VARCHAR(256)',
            'property':
            "CHARACTER SET 'utf8' COLLATE 'utf8_bin' NULL"
        })
        table_columns.append({
            'name': 'FAULT_TYPE',
            'type': 'VARCHAR(45)',
            'property': 'NULL'
        })
        table_columns.append({
            'name': 'FAULTY_VEC_CNT',
            'type': 'INT',
            'property': 'NULL'
        })
        table_columns.append({
            'name': 'FAULTY_VEC_CNT_weak',
            'type': 'INT',
            'property': 'NULL'
        })

        table_desc['table_columns'] = table_columns
        table_primary_keys = ['idFAULT_LIB']
        table_desc['table_pks'] = table_primary_keys

        if self.db_.is_table_exist(table_desc['table_name']):
            if is_drop_exist:
                self.db_.run_sql(
                    f"DROP TABLE IF EXISTS {table_desc['table_name']}")
            else:
                return
        self.db_.create_table(table_desc)

    def set_netlist(self, str_netlist):
        self.netlist_.set_netlist(str_netlist)
        self.bsf_, self.bsf_weak_ = csim(str_netlist)
        self.short_defects_.clear()
        self.open_defects_.clear()

    def reset_tg_netlist(self, is_open=False):
        if is_open:
            # constantly off TG
            self.tg_netlist_.set_netlist(
                "M1001 IN101 GND IN102 GND NMOS\nM1002 IN101 VDD IN102 VDD PMOS\n"
            )
        else:
            self.tg_netlist_.set_netlist(
                "M1001 IN101 VDD IN102 GND NMOS\nM1002 IN101 GND IN102 VDD PMOS\n"
            )

    def gen_short_defect_str_netlist(self, short_defect):
        self.reset_tg_netlist()
        self.tg_netlist_.rename_node_only(short_defect[0], 'IN101')
        self.tg_netlist_.rename_node_only(short_defect[1], 'IN102')

        return self.netlist_.get_netlist_string(
        ) + self.tg_netlist_.get_netlist_string()

    def get_faulty_vec_cnts(self):
        faulty_vec_cnt = 0
        faulty_weak_vec_cnt = 0
        for i in range(len(self.bsf_)):
            if self.bsf_[i] != self.faulty_bsf_[i]:
                faulty_vec_cnt += 1
            if self.bsf_weak_[i] != self.faulty_bsf_weak_[i]:
                faulty_weak_vec_cnt += 1
        return faulty_vec_cnt, faulty_weak_vec_cnt

    def get_defect_info_dict(self, defect, defect_type):
        defect_info_dict = dict()
        defect_info_dict['FAULT_TYPE'] = defect_type
        defect_info_dict['FAULT_DESC'] = str(defect)
        if defect_type == 'open':
            defect_info_dict[
                'FAULTY_NETLIST'] = self.gen_open_defect_str_netlist(defect)
        elif defect_type == 'short':
            defect_info_dict[
                'FAULTY_NETLIST'] = self.gen_short_defect_str_netlist(defect)
        else:
            raise ValueError(f'unknown defect type: {defect_type}')

        self.faulty_bsf_, self.faulty_bsf_weak_ = csim(
            defect_info_dict['FAULTY_NETLIST'])
        defect_info_dict['FAULTY_BSF'] = self.faulty_bsf_
        defect_info_dict['FAULTY_BSF_weak'] = self.faulty_bsf_weak_
        defect_info_dict['FAULTY_VEC_CNT'], defect_info_dict[
            'FAULTY_VEC_CNT_weak'] = self.get_faulty_vec_cnts()
        return defect_info_dict

    def get_all_defect_info_dicts(self):
        self.gen_defect_list()
        defects_info_list = list()

        for open_defect in self.open_defects_:
            defects_info_list.append(
                self.get_defect_info_dict(open_defect, 'open'))
        for short_defect in self.short_defects_:
            defects_info_list.append(
                self.get_defect_info_dict(short_defect, 'short'))

        return defects_info_list

    def insert_defect_details_for_id_cell(self, id_cell):
        str_netlist = self.db_.get_query_value(
            'CELL_NETLIST',
            f'SELECT CELL_NETLIST FROM {self.cell_table_} WHERE idCELL=%s',
            [id_cell])
        if str_netlist is None:
            raise ValueError(
                f'Cell # {id_cell} does not exist in {self.cell_table_}')
        self.set_netlist(str_netlist)

        for defect_dict in self.get_all_defect_info_dicts():
            defect_dict['idCELL'] = id_cell
            self.db_.insert_nocommit(defect_dict)

        self.db_.commit()

    def gen_open_defect_str_netlist(self, open_defect):
        defect_node_name = 'N1000'

        self.reset_tg_netlist(True)
        self.tg_netlist_.rename_node_only(open_defect[0], 'IN101')
        self.tg_netlist_.rename_node_only(defect_node_name, 'IN102')

        # insert defect
        for terminal in open_defect[1]:
            defect_transistor = self.netlist_.get_transistor(terminal[:-1])
            defect_terminal = defect_transistor.get_terminal_with_short_type(
                terminal[-1:])
            defect_terminal.set_node(self.netlist_.get_node(defect_node_name))

        # save defect netlist
        defect_str_netlist = self.netlist_.get_netlist_string(
        ) + self.tg_netlist_.get_netlist_string()

        # restore netlist
        for terminal in open_defect[1]:
            defect_transistor = self.netlist_.get_transistor(terminal[:-1])
            defect_terminal = defect_transistor.get_terminal_with_short_type(
                terminal[-1:])
            defect_terminal.set_node(self.netlist_.get_node(open_defect[0]))

        return defect_str_netlist

    def gen_defect_list(self):
        nodes = list(self.netlist_.get_all_nodes())

        # short defects
        # a pair of nets
        # E.g. ('GND', 'N0001')
        for node_pair in combinations(nodes, r=2):
            if node_pair[0].is_supply() and node_pair[1].is_supply():
                continue
            if node_pair[0].is_pi() and node_pair[1].is_supply():
                continue
            if node_pair[0].is_supply() and node_pair[1].is_pi():
                continue
            if node_pair[0].is_pi() and node_pair[1].is_pi():
                continue
            self.short_defects_.append(
                (node_pair[0].get_name(), node_pair[1].get_name()))

        # open defects
        # net name followed by
        # 1) either lists of transistor terminals (if the net is a supply net)
        # E.g. ['GND', ['M0001d', 'M0002d', 'M0003d']] will become:
        #       ['GND', ['M0001d']]
        #       ['GND', ['M0002d']]
        #       ['GND', ['M0003d']]
        #
        # 2) (if the net is an internal net or output net)
        # or the first partition of transistor terminals which should be disconnected from the node
        # E.g.  ['N0001', ['M0002s', 'M0003s'], ['M0001g', 'M0005s']] will become:
        #       ['N0001', ['M0002s', 'M0003s']]
        for node in nodes:
            if node.is_pi() or node.is_supply():
                # each terminal can be disconnected from the source/supply net individually
                for terminal in node.get_terminals():
                    temp_defect = list()
                    temp_defect.append(node.get_name())
                    temp_defect.append([
                        terminal.get_owner_name() + terminal.get_type_short()
                    ])
                    self.open_defects_.append(temp_defect)
            else:
                # partition needed for internal nodes and output node
                num = len(node.get_terminals())
                if num == 1:
                    # this node only has one terminal hence cannot become open
                    continue
                else:
                    for i in range(1, num):
                        for partitions in combinations(node.get_terminals(),
                                                       r=i):
                            partition_a = [
                                x.get_owner_name() + x.get_type_short()
                                for x in node.get_terminals()
                                if x in partitions
                            ]
                            temp_defect = list()
                            temp_defect.append(node.get_name())
                            temp_defect.append(partition_a)
                            self.open_defects_.append(temp_defect)