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 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))
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 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_)
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'))
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
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)
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())
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())
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)
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())
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)
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})
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())