Example #1
0
 def __init__(self, db):
     self.netlist_ = Netlist()
     self.upstream_db_ = db
     self.cell_id_ = None
     self.bsf_ = None
     self.bsf_weak_ = None
     self.bsf_unified_ = None
     self.bsf_weak_unified_ = None
Example #2
0
 def test_create_netlist(self):
     netlist = Netlist()
     str_netlist = "M0001 N0002 IN001 N0001 GND NMOS\n"\
                   "M0002 VDD N0001 N0002 GND NMOS\n" \
                   "M0003 N0001 IN001 IN002 VDD PMOS\n" \
                   "M0004 OUT01 N0001 IN002 VDD PMOS\n"
     netlist.set_netlist(str_netlist)
     self.assertEqual(str_netlist, str(netlist))
Example #3
0
 def __init__(self):
     self.netlist_ = Netlist()
     self.strategy_ = None
     self.bsf_same_cnt_ = 0
     self.bsf_diff_cnt_ = 0
     self.bsf_weak_same_cnt_ = 0
     self.bsf_weak_diff_cnt_ = 0
     self.golden_bsf_ = None
     self.golden_bsf_weak_ = None
Example #4
0
 def test_equ_netlist_swap_diff(self):
     netlist = Netlist()
     str_netlist = "M0001 VDD IN001 IN002 GND NMOS\n"
     netlist.set_netlist(str_netlist)
     equ_netlists = [
         "M0001 VDD IN001 IN002 GND NMOS\n",
         "M0001 IN002 IN001 VDD GND NMOS\n",
         "M0001 VDD IN002 IN001 GND NMOS\n",
         "M0001 IN001 IN002 VDD GND NMOS\n"
     ]
     self.assertCountEqual(equ_netlists, netlist.get_equ_netlists())
    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_)
Example #6
0
 def test_get_max_cnt(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.assertEqual(2, netlist.get_max_cnt_for_dict('internal'))
     self.assertEqual(2, netlist.get_max_cnt_for_dict('in'))
Example #7
0
 def test_update_transistors(self):
     netlist = Netlist()
     str_netlist = "M0003 N0002 IN001 N0001 GND NMOS\n" \
                   "M0008 VDD N0001 N0002 GND NMOS\n" \
                   "M0001 N0001 IN001 IN002 VDD PMOS\n" \
                   "M0003 OUT01 N0001 IN002 VDD PMOS\n"
     netlist.set_netlist(str_netlist)
     netlist.update_transistor_names()
     cnt = 1
     for transistor in netlist.get_transistors():
         self.assertEqual(int(transistor.get_name()[1:]), cnt)
         cnt += 1
Example #8
0
 def test_short_transistor_with_auto_node_removal(self):
     netlist = Netlist()
     str_netlist = "M0001 OUT01 N0001 IN002 VDD PMOS\n"
     netlist.set_netlist(str_netlist)
     self.assertEqual(
         len(netlist.node_dicts_[netlist.get_set_name_for_node('N0001')]),
         1)
     old_gate_name = netlist.turn_on_transistor('M0001')
     self.assertEqual(old_gate_name, 'N0001')
     self.assertEqual(
         len(netlist.node_dicts_[netlist.get_set_name_for_node('N0001')]),
         0)
Example #9
0
 def test_shift_node_cnt(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)
     netlist.shift_node_cnt_for_dict('internal', 3)
     str_netlist = "M0001 VDD VDD N0005 GND NMOS\n" \
                   "M0002 N0004 IN002 IN002 VDD PMOS\n" \
                   "M0003 OUT01 N0004 IN002 VDD PMOS\n"
     self.assertEqual(str_netlist, netlist.get_netlist_string())
     self.assertCountEqual(['N0004', 'N0005'],
                           netlist.node_dicts_['internal'].keys())
Example #10
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())
Example #11
0
 def test_remove_transistor_with_dup(self):
     netlist = Netlist()
     str_netlist = "M0003 N0002 IN001 N0001 GND NMOS\n" \
                   "M0008 VDD N0001 N0002 GND NMOS\n" \
                   "M0001 N0001 IN001 IN002 VDD PMOS\n" \
                   "M0003 OUT01 N0001 IN002 VDD PMOS\n"
     netlist.set_netlist(str_netlist)
     netlist.remove_transistor("M0003", True)
     str_netlist = "M0001 VDD N0001 N0002 GND NMOS\n" \
                   "M0002 N0001 IN001 IN002 VDD PMOS\n" \
                   "M0003 OUT01 N0001 IN002 VDD PMOS\n"
     self.assertEqual(str_netlist, netlist.get_netlist_string())
     self.assertEqual(len(netlist.p_transistors_), 2)
     self.assertEqual(len(netlist.n_transistors_), 1)
Example #12
0
    def test_equ_netlist_complete_test_1(self):
        netlist = Netlist()
        str_netlist = "M0001 N0002 IN001 N0001 GND NMOS\n"
        netlist.set_netlist(str_netlist)
        equ_netlists = []

        script_dir = os.path.dirname(os.path.realpath(__file__)) + '/'
        with open(script_dir + 'complete_test_results_1.txt') as results:
            temp_netlist = ''
            for line in results:
                if line == "\n":
                    equ_netlists.append(temp_netlist)
                    temp_netlist = ''
                    continue
                temp_netlist += line
        self.assertEqual(len(equ_netlists),
                         len(list(netlist.get_equ_netlists())))
        self.assertCountEqual(equ_netlists, netlist.get_equ_netlists())
Example #13
0
class StructuralHypoChecker:
    def __init__(self):
        self.netlist_ = Netlist()
        self.strategy_ = None
        self.bsf_same_cnt_ = 0
        self.bsf_diff_cnt_ = 0
        self.bsf_weak_same_cnt_ = 0
        self.bsf_weak_diff_cnt_ = 0
        self.golden_bsf_ = None
        self.golden_bsf_weak_ = None

    def set_strategy(self, strategy):
        self.strategy_ = strategy

    def set_netlist(self, str_netlist):
        self.netlist_.set_netlist(str_netlist)
        self.golden_bsf_, self.golden_bsf_weak_ = csim(str_netlist)

    def check(self):
        self.bsf_same_cnt_ = 0
        self.bsf_weak_same_cnt_ = 0
        self.bsf_diff_cnt_ = 0
        self.bsf_weak_diff_cnt_ = 0
        for str_netlist in self.strategy_.get_str_netlists(self.netlist_):
            bsf, bsf_weak = csim(str_netlist)
            if bsf == self.golden_bsf_:
                self.bsf_same_cnt_ += 1
            else:
                self.bsf_diff_cnt_ += 1
            if bsf_weak == self.golden_bsf_weak_:
                self.bsf_weak_same_cnt_ += 1
            else:
                self.bsf_weak_diff_cnt_ += 1

    def is_all_bsf_same(self):
        return self.bsf_diff_cnt_ == 0

    def is_all_bsf_weak_same(self):
        return self.bsf_weak_diff_cnt_ == 0

    def is_all_bsf_diff(self):
        return self.bsf_same_cnt_ == 0

    def is_all_bsf_weak_diff(self):
        return self.bsf_weak_same_cnt_ == 0

    def get_bsf_same_cnt(self):
        return self.bsf_same_cnt_

    def get_bsf_weak_same_cnt(self):
        return self.bsf_weak_same_cnt_

    def print_report_summary(self):
        print('--- summary ---')
        if self.bsf_diff_cnt_ == 0:
            # print(f'{Fore.GREEN}[OK]{Style.RESET_ALL} bsf all the same')
            print('[OK] bsf all the same')
        else:
            print('[--] bsf not the same')
        if self.bsf_weak_diff_cnt_ == 0:
            print('[OK] weak bsf all the same')
        else:
            print('[--] weak bsf not the same')

        print('--- detail ---')
        print(f'Total instances: {self.bsf_same_cnt_+self.bsf_diff_cnt_}')
        print(f'Same bsf instances: {self.bsf_same_cnt_}')
        print(f'Diff bsf instances: {self.bsf_diff_cnt_}')
        print(f'Same weak instances: {self.bsf_weak_same_cnt_}')
        print(f'Diff weak instances: {self.bsf_weak_diff_cnt_}')
        print('--- end ---')
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)
Example #15
0
class Cell:
    def __init__(self, db):
        self.netlist_ = Netlist()
        self.upstream_db_ = db
        self.cell_id_ = None
        self.bsf_ = None
        self.bsf_weak_ = None
        self.bsf_unified_ = None
        self.bsf_weak_unified_ = None

    def init_based_on_id(self, id_cell):
        self.cell_id_ = id_cell
        self.bsf_ = None
        self.bsf_weak_ = None
        self.bsf_unified_ = None
        self.bsf_weak_unified_ = None
        row = self.upstream_db_.get_query_row(
            'SELECT CELL_BSF, CELL_BSF_UNIFIED, CELL_BSF_weak, '
            'CELL_BSF_weak_UNIFIED, CELL_NETLIST '
            f'FROM {self.upstream_db_.table_} WHERE idCELL=%s', [id_cell])
        if row is None:
            raise ValueError(
                f'Cell #{id_cell} not found in {self.upstream_db_.table_}')
        self.netlist_.set_netlist(row['CELL_NETLIST'])
        self.bsf_ = row['CELL_BSF'].decode("utf-8")
        self.bsf_weak_ = row['CELL_BSF_weak'].decode("utf-8")
        self.bsf_unified_ = row['CELL_BSF_UNIFIED'].decode("utf-8")
        self.bsf_weak_unified_ = row['CELL_BSF_weak_UNIFIED'].decode("utf-8")

    def init_based_on_netlist(self, netlist):
        self.cell_id_ = None
        self.bsf_ = None
        self.bsf_weak_ = None
        self.bsf_unified_ = None
        self.bsf_weak_unified_ = None
        self.netlist_.set_netlist(netlist)

    def cal_bsf(self):
        self.bsf_, self.bsf_weak_ = csim(self.netlist_.get_netlist_string())

        self.bsf_unified_, bsf_list = gen_equ_bsf(self.bsf_)
        self.bsf_weak_unified_, bsf_list = gen_equ_bsf(self.bsf_weak_)

    def get_upstream_db(self):
        return self.upstream_db_

    def set_upstream_db(self, db_):
        self.upstream_db_ = db_

    def get_bsf(self):
        if not self.bsf_:
            self.cal_bsf()
        return self.bsf_

    def get_bsf_unified(self):
        if not self.bsf_unified_:
            self.cal_bsf()
        return self.bsf_unified_

    def get_bsf_weak(self):
        if not self.bsf_weak_:
            self.cal_bsf()
        return self.bsf_weak_

    def fetch_ids(self):
        query = f'SELECT Q.ID FROM ' \
                f'(SELECT idCELL AS ID, CELL_NETLIST AS Netlist ' \
                f'FROM {self.upstream_db_.get_table()} WHERE CELL_BSF_UNIFIED=%s)' \
                f' AS Q WHERE Q.Netlist IN ('
        temp = "', '".join(self.netlist_.get_equ_netlists())
        temp = "'" + temp + "'"
        query += temp
        query += ')'

        id_list = list()
        for row in self.upstream_db_.run_query(query,
                                               [self.get_bsf_unified()]):
            id_list.append(int(row['ID']))

        return id_list

    def get_id(self):
        if self.cell_id_ is None:
            id_list = self.fetch_ids()
            if id_list:
                self.cell_id_ = id_list[0]
            else:
                self.cell_id_ = 0
        return self.cell_id_

    def get_family(self):
        id_cell = self.get_id()
        cell_family = self.upstream_db_.get_query_value(
            'CELL_FAMILY',
            f'SELECT CELL_FAMILY FROM {self.upstream_db_.get_table()} '
            'WHERE idCELL=%s', [id_cell])
        return cell_family

    def clear_family(self):
        id_cell = self.get_id()
        self.upstream_db_.run_sql(
            f'UPDATE {self.upstream_db_.get_table()} SET CELL_FAMILY=NULL WHERE '
            f'idCELL={id_cell}')

    def add_to_family(self, family_name):
        id_cell = self.get_id()
        if id_cell == 0:
            return
        cell_family = self.get_family()
        if not cell_family:
            cell_family = family_name
        elif family_name not in cell_family:
            cell_family += ',' + family_name
        else:
            # cell already belongs to this family
            return
        self.upstream_db_.update(id_cell, 'idCELL',
                                 {'CELL_FAMILY': cell_family})
Example #16
0
    def test_unshort_transistor(self):
        netlist = Netlist()
        str_netlist = "M0001 OUT01 N0001 IN002 VDD PMOS\n"
        netlist.set_netlist(str_netlist)
        self.assertEqual(
            len(netlist.node_dicts_[netlist.get_set_name_for_node('N0001')]),
            1)
        old_gate_name = netlist.turn_on_transistor('M0001')
        self.assertEqual(old_gate_name, 'N0001')
        self.assertEqual(
            len(netlist.node_dicts_[netlist.get_set_name_for_node('N0001')]),
            0)

        netlist.replace_transistor_gate('M0001', old_gate_name)
        self.assertEqual(
            len(netlist.node_dicts_[netlist.get_set_name_for_node('N0001')]),
            1)
        self.assertEqual(str_netlist, netlist.get_netlist_string())