def test_cap(): mydir = pathlib.Path(__file__).resolve() pdk_path = mydir.parent.parent.parent / "pdks" / "FinFET14nm_Mock_PDK" config_path = mydir.parent.parent / "files" test_path = mydir.parent.parent / "files" / "test_circuits" / "test_cap.sp" gen_const_path = mydir.parent / "Results" / "TEST_CAP.verilog.json" gold_const_path = (mydir.parent.parent / "files" / "test_results" / "test_cap.const.json") updated_ckt = compiler_input(test_path, "test_cap", pdk_path, config_path) assert updated_ckt.find("TEST_CAP") primitives, generators = call_primitive_generator(updated_ckt, pdk_path, True) verilog_tbl = constraint_generator(updated_ckt, generators) compiler_output( updated_ckt, "TEST_CAP", verilog_tbl, pathlib.Path(__file__).parent / "Results", ) assert "CAP_30f" in primitives.keys() with open(gen_const_path, "r") as const_fp: gen_const = next(x for x in json.load(const_fp)["modules"] if x["name"] == "TEST_CAP")["constraints"] gen_const.sort(key=lambda item: item.get("constraint")) with open(gold_const_path, "r") as const_fp: gold_const = json.load(const_fp) gold_const.sort(key=lambda item: item.get("constraint")) assert gold_const == gen_const
def test_multi_param_remove_dummy(): name = f'ckt_{get_test_id()}'.upper() netlist = multi_param_ckt(name) constraints = [{ "constraint": "PowerPorts", "ports": ["D"] }, { "constraint": "GroundPorts", "ports": ["S"] }] example = build_example(name, netlist, constraints) ckt_library = compiler_input(example, name, pdk_path, config_path) all_modules = set([name]) available_modules = set([ module.name for module in ckt_library if isinstance(module, SubCircuit) ]) assert available_modules == all_modules, f"{available_modules}" ckt = ckt_library.find(name) assert ckt assert ckt.get_element( "MI1"), f"all instances{[ele.name for ele in ckt.elements]}" assert ckt.get_element("MI1").parameters["NFIN"] == "16" assert ckt.get_element("MI2") assert ckt.get_element("MI2").parameters["NFIN"] == "24" assert ckt.get_element("MI3") assert ckt.get_element("MI3").parameters["NFIN"] == "24" assert ckt.get_element("MI4") assert ckt.get_element("MI4").parameters["NFIN"] == "64" clean_data(name)
def test_array_gen_ro_f(): name = f'ckt_{get_test_id()}' netlist = ring_oscillator_flat(name) constraints = [{ "constraint": "DoNotUseLib", "libraries": ["STAGE2_INV", "INV", "DP_PMOS", "DP_NMOS"] }] example = build_example(name, netlist, constraints) ckt_library = compiler_input(example, name, pdk_path, config_path) ckt = ckt_library.find(name) assert ckt, f"No ckt {name} found in library" array_cl = process_arrays(ckt, dict()) array1 = array_cl.find_array('VCCX', ['VSSX']) assert array1 == [['MP0', 'MN0'], ['MP1', 'MN1'], ['MP2', 'MN2'], ['MP3', 'MN3'], ['MP4', 'MN4']] array_cl.add_align_block_const() array_cl.add_new_array_hier() assert ckt.get_element("X_ARRAY_HIER_VCCX") assert ckt_library.find("ARRAY_HIER_VCCX") assert ckt_library.find( "ARRAY_TEMPLATE" ), f"{set([inst.name for inst in ckt_library.find('ARRAY_TEMPLATE').elements])}" assert set([ inst.name for inst in ckt_library.find("ARRAY_TEMPLATE").elements ]) == {'MP0', 'MN0'} array_insts = [ 'X_ARRAY_TEMPLATE', 'X_ARRAY_TEMPLATE1', 'X_ARRAY_TEMPLATE2', 'X_ARRAY_TEMPLATE3', 'X_ARRAY_TEMPLATE4' ] assert [ inst.name for inst in ckt_library.find("ARRAY_HIER_VCCX").elements ] == array_insts clean_data(name)
def test_preprocessing_SD(): name = f'ckt_{get_test_id()}'.upper() netlist = nested_swap_SD(name) constraints = constraints = [{ "constraint": "PowerPorts", "ports": ["D"] }, { "constraint": "GroundPorts", "ports": ["S"] }, { "constraint": "KeepDummyHierarchies", "isTrue": True }] example = build_example(name, netlist, constraints) ckt_library = compiler_input(example, name, pdk_path, config_path) all_modules = set([name, "PARAM_MOS", "P_MOS"]) available_modules = set([ module.name for module in ckt_library if isinstance(module, SubCircuit) ]) assert available_modules == all_modules, f"{available_modules}" assert ckt_library.find("P_MOS").get_element( "MN1").parameters["NFIN"] == "12" assert ckt_library.find("P_MOS").get_element("MN1").pins == { "D": "D", "G": "G", "S": "S", "B": "B", } clean_data(name)
def test_symm_net(): name = f'ckt_{get_test_id()}' netlist = ota_six(name) constraints = [ {"constraint": "IsDigital", "isTrue": True} ] example = build_example(name, netlist, constraints) ckt_library = compiler_input(example, name, pdk_path, config_path) ckt = ckt_library.find(name) G = Graph(ckt) pairs, pinsA, pinsB = symmnet_device_pairs(G, 'VIN', 'VIP', list(), None, True) assert pairs == {'VIN': 'VIP', 'MN4': 'MN3'} assert pinsA == ['MN4/G', 'VIN'] assert pinsB == ['MN3/G', 'VIP'] pairs, pinsA, pinsB = symmnet_device_pairs(G, 'VIN', 'VIP', [{'MN3', 'MN4'}], None) assert pairs == {'VIN': 'VIP', 'MN4': 'MN3'} pairs, pinsA, pinsB = symmnet_device_pairs(G, 'VIN', 'VIP', ['MN3'], None) assert pairs is None pairs, pinsA, pinsB = symmnet_device_pairs(G, "VIN", "VIP", ["MN4"], None) assert pairs is None pairs, pinsA, pinsB = symmnet_device_pairs(G, "VIN", "VIP", list(), ["MN4"]) assert pairs is None pairs, pinsA, pinsB = symmnet_device_pairs(G, "VIN", "VIP", list(), ["MN3"]) assert pairs is None pairs, pinsA, pinsB = symmnet_device_pairs(G, "IBIAS", "TAIL", list(), ["MN3"]) assert pairs is None pairs, pinsA, pinsB = symmnet_device_pairs(G, "VON", "VOP", list(), ["MN3"]) assert pairs is None pairs, pinsA, pinsB = symmnet_device_pairs(G, "VIN", "VON", list(), ["MN3"]) assert pairs is None clean_data(name)
def test_multi_param_skip(): name = f'ckt_{get_test_id()}'.upper() netlist = multi_param_ckt_with_existing_name(name) constraints = [{ "constraint": "PowerPorts", "ports": ["D"] }, { "constraint": "GroundPorts", "ports": ["S"] }, { "constraint": "KeepDummyHierarchies", "isTrue": True }] example = build_example(name, netlist, constraints) ckt_library = compiler_input(example, name, pdk_path, config_path) all_modules = set([name, "PARAM_MOS", "PARAM_MOS_1", "PARAM_MOS_2"]) available_modules = set([ module.name for module in ckt_library if isinstance(module, SubCircuit) ]) assert available_modules == all_modules, f"{available_modules}" assert ckt_library.find("PARAM_MOS").parameters["TF"] == "16" assert ckt_library.find("PARAM_MOS_1").parameters["TF"] == "32" assert ckt_library.find("PARAM_MOS_2").parameters["TF"] == "24" assert ckt_library.find("PARAM_MOS").get_element( "MN1").parameters["NFIN"] == "16" assert ckt_library.find("PARAM_MOS_1").get_element( "MN2").parameters["NFIN"] == "32" assert ckt_library.find("PARAM_MOS_2").get_element( "MN1").parameters["NFIN"] == "24" clean_data(name)
def test_add_symmetry_const(): name = f'ckt_{get_test_id()}' netlist = ota_six(name) constraints = [ {"constraint": "IsDigital", "isTrue": True} ] example = build_example(name, netlist, constraints) ckt_library = compiler_input(example, name, pdk_path, config_path) ckt = ckt_library.find(name) with set_context(ckt.constraints): x = constraint.SymmetricBlocks(direction="V", pairs=[["MN4", "MN3"]]) const_pairs = {"MN4": "MN3"} # skip dictionary element with pytest.raises(KeyError): add_or_revert_const(const_pairs, ckt.constraints, list()) assert len(ckt.constraints) == 1 const_pairs = [["MN4", "MN3"]] add_or_revert_const(const_pairs, ckt.constraints, list()) assert len(ckt.constraints) == 2 assert ckt.constraints[1] == x const_pairs = [["MN4", "MN5"]] # Skip unequal size add_or_revert_const(const_pairs, ckt.constraints, list()) assert len(ckt.constraints) == 2 const_pairs = [["VIN", "VIP"]] # Skip net add_or_revert_const(const_pairs, ckt.constraints, list()) assert len(ckt.constraints) == 2 clean_data(name)
def ckt(cn): mydir = pathlib.Path(__file__).resolve() pdk_path = mydir.parent.parent.parent / "pdks" / "FinFET14nm_Mock_PDK" config_path = mydir.parent.parent / "files" test_path = mydir.parent.parent / "files" / "test_circuits" / (cn + ".sp") ckt_library = compiler_input(test_path, cn, pdk_path, config_path) assert ckt_library.find(cn) return ckt_library.find(cn)
def test_constraint_checking(dir_name): circuit_name = "high_speed_comparator" test_path = ( pathlib.Path(__file__).resolve().parent.parent / "files" / "test_circuits" / dir_name / (circuit_name + ".sp") ) with pytest.raises(SolutionNotFoundError): updated_cktlib = compiler_input(test_path, circuit_name, pdk_dir, config_path)
def test_compiler(): test_home = pathlib.Path(__file__).resolve().parent.parent test_path = test_home / "files" / "test_circuits" / "ota" / "ota.sp" pdk_dir = test_home.parent / "pdks" / "FinFET14nm_Mock_PDK" config_path = pathlib.Path(__file__).resolve().parent.parent / "files" updated_ckt = compiler_input(test_path, "ota", pdk_dir, config_path) assert updated_ckt.find("CMC_PMOS") assert updated_ckt.find("SCM_NMOS") assert updated_ckt.find("CMC_S_NMOS_B") assert updated_ckt.find("DP_NMOS_B") assert updated_ckt.find("OTA") return updated_ckt
def test_array_gen_ro(): name = f'ckt_{get_test_id()}' netlist = ring_oscillator(name) constraints = [] example = build_example(name, netlist, constraints) ckt_library = compiler_input(example, name, pdk_path, config_path) ckt = ckt_library.find(name) assert ckt, f"No ckt {name} found in library" array_cl = process_arrays(ckt, dict()) array1 = array_cl.find_array('VCCX', ['VSSX']) assert array1 == ['XI0', 'XI1', 'XI2', 'XI3', 'XI4'] array_cl.add_align_block_const() with set_context(ckt.constraints): x = constraint.Align(line="h_center", instances=array1) assert ckt.constraints == [x] clean_data(name)
def test_array_gen_ro_fh(): name = f'ckt_{get_test_id()}' netlist = ring_oscillator_flat(name) constraints = [{"constraint": "DoNotUseLib", "libraries": ["STAGE2_INV"]}] example = build_example(name, netlist, constraints) ckt_library = compiler_input(example, name, pdk_path, config_path) ckt = ckt_library.find(name) assert ckt, f"No ckt {name} found in library" array_cl = process_arrays(ckt, dict()) array1 = array_cl.find_array('VCCX', ['VSSX']) assert array1 == [ 'X_INV_MN0_MP0', 'X_INV_MN1_MP1', 'X_INV_MN2_MP2', 'X_INV_MN3_MP3', 'X_INV_MN4_MP4' ] array_cl.add_align_block_const() with set_context(ckt.constraints): x = constraint.Align(line="h_center", instances=array1) assert ckt.constraints[-1] == x clean_data(name)
def test_ota_six(): name = f'ckt_{get_test_id()}'.upper() netlist = ota_six(name) constraints = [{ "constraint": "PowerPorts", "ports": ["VCCX"] }, { "constraint": "GroundPorts", "ports": ["VSSX"] }] example = build_example(name, netlist, constraints) ckt_library = compiler_input(example, name, pdk_path, config_path) all_modules = set([name, "SCM_NMOS", "SCM_PMOS", "DP_NMOS_B"]) available_modules = set([ module.name for module in ckt_library if isinstance(module, SubCircuit) ]) assert available_modules == all_modules, f"{available_modules}" clean_data(name)
def test_array_vga_equal(): name = f'ckt_{get_test_id()}' netlist = variable_gain_amplifier_equal(name) constraints = list() example = build_example(name, netlist, constraints) ckt_library = compiler_input(example, name, pdk_path, config_path) ckt = ckt_library.find(name) assert ckt, f"No ckt {name} found in library" FindConst(ckt) all_arrays = [ module.name for module in ckt_library if isinstance(module, SubCircuit) and 'ARRAY' in module.name ] ARRAY_HIER = ckt_library.find("ARRAY_HIER_VOUT_VGA1") assert ARRAY_HIER, f"ARRAY_HIER_VOUT_VGA1 not found in {all_arrays}" TEMPLATE = ckt_library.find("ARRAY_TEMPLATE") assert TEMPLATE, f"TEMPLATE not found in {all_arrays}" insts = [inst.name for inst in TEMPLATE.elements] assert set(insts) == {'X_DP_NMOS_B_M00_M01', 'MSW0'} clean_data(name)
def test_group_block_hsc(dir_name): circuit_name = "high_speed_comparator" test_path = ( pathlib.Path(__file__).resolve().parent.parent / "files" / "test_circuits" / dir_name / (circuit_name + ".sp") ) updated_cktlib = compiler_input(test_path, circuit_name, pdk_dir, config_path) assert updated_cktlib.find("DP") assert updated_cktlib.find("CCN") assert updated_cktlib.find("CCP") assert updated_cktlib.find("INV_P") assert updated_cktlib.find("INV_N") assert updated_cktlib.find("DP_NMOS_B") assert updated_cktlib.find("CCP_S_NMOS_B") assert updated_cktlib.find("CCP_PMOS") assert updated_cktlib.find("INV") result_path = out_path / dir_name if result_path.exists() and result_path.is_dir(): shutil.rmtree(result_path) result_path.mkdir(parents=True, exist_ok=False) verilog_tbl = constraint_generator(updated_cktlib, dict()) gen_const_path = result_path / "HIGH_SPEED_COMPARATOR.const.json" for module in verilog_tbl["modules"]: if module["name"] == "HIGH_SPEED_COMPARATOR": gen_const = module["constraints"] gen_const.sort(key=lambda item: item.get("constraint")) with (gen_const_path).open("wt") as fp: json.dump(gen_const, fp=fp, indent=2) gold_const_path = ( pathlib.Path(__file__).resolve().parent.parent / "files" / "test_results" / (dir_name + ".const.json") ) with open(gold_const_path, "r") as const_fp: gold_const = json.load(const_fp) gold_const.sort(key=lambda item: item.get("constraint")) assert gold_const == gen_const
def test_top_param(): name = f'ckt_{get_test_id()}'.upper() netlist = mos_ckt(name) constraints = [{ "constraint": "PowerPorts", "ports": ["D"] }, { "constraint": "GroundPorts", "ports": ["S"] }] example = build_example(name, netlist, constraints) ckt_library = compiler_input(example, name, pdk_path, config_path) all_modules = set([name]) available_modules = set([ module.name for module in ckt_library if isinstance(module, SubCircuit) ]) assert available_modules == all_modules, f"{available_modules}" assert ckt_library.find(name).get_element("MN1") assert ckt_library.find(name).get_element("MN1").parameters["NFIN"] == "12" clean_data(name)
def test_ota_dont_swap(): # check drain gate swap name = f'ckt_{get_test_id()}'.upper() netlist = ota_six_flip(name) constraints = [{ "constraint": "PowerPorts", "ports": ["VCCX"] }, { "constraint": "GroundPorts", "ports": ["VSSX"] }, { "constraint": "FixSourceDrain", "isTrue": False }] example = build_example(name, netlist, constraints) ckt_library = compiler_input(example, name, pdk_path, config_path) all_modules = set([name, 'SCM_NMOS', 'SCM_PMOS']) available_modules = set([ module.name for module in ckt_library if isinstance(module, SubCircuit) ]) assert available_modules == all_modules, f"{available_modules}" clean_data(name)
def test_scf(): mydir = pathlib.Path(__file__).resolve() test_path = ( mydir.parent.parent / "files" / "test_circuits" / "switched_capacitor_filter" / "switched_capacitor_filter.sp" ) gold_const_path = ( mydir.parent.parent / "files" / "test_results" / "switched_capacitor_filter.const.json" ) updated_cktlib = compiler_input( test_path, "SWITCHED_CAPACITOR_FILTER", pdk_dir, config_path ) assert updated_cktlib.find("SWITCHED_CAPACITOR_FILTER") verilog_tbl = constraint_generator(updated_cktlib, dict()) for module in verilog_tbl["modules"]: if module["name"] == "SWITCHED_CAPACITOR_FILTER": gen_const = module["constraints"] gen_const.sort(key=lambda item: item.get("constraint")) gold_const_path = ( pathlib.Path(__file__).resolve().parent.parent / "files" / "test_results" / "switched_capacitor_filter.const.json" ) with open(gold_const_path, "r") as const_fp: gold_const = json.load(const_fp) gold_const.sort(key=lambda item: item.get("constraint")) assert gold_const == gen_const
def test_simple_circuit(): test_home = pathlib.Path(__file__).resolve().parent.parent test_path = test_home / "files"/ "test_circuits"/ "test2.sp" pdk_dir = test_home.parent / "pdks"/ "FinFET14nm_Mock_PDK" config_path = pathlib.Path(__file__).resolve().parent.parent / "files" lib = compiler_input(test_path, "test2", pdk_dir, config_path) circuit = lib.find("TEST2") assert len(circuit.elements) == 9 assert len(circuit.nets) == 10 assert circuit.name == "TEST2" assert len(circuit.pins) == 3 assert ( circuit.elements[0].name == "MM0" ) # can we directly use instance name instead of index? assert circuit.elements[0].model == "NMOS_RVT" model = lib.find(circuit.elements[0].model) assert model.base == "NMOS" assert circuit.elements[0].pins == { "B": "GND!", "D": "VOUT", "G": "NET5", "S": "GND!", } assert model.pins == ["D", "G", "S", "B"] assert model.parameters == { "L": "1", "M": "1", "NF": "1", "NFIN": "1", "W": "1", "PARALLEL": "1", "STACK": "1", } # TBF: Document base model assert model.prefix == "M" assert circuit.elements[0].parameters == { "W": "2.7E-08", "L": "2E-08", "NFIN": "1", "NF": "1", "M": "1", "PARALLEL": "1", "STACK": "1", } assert circuit.elements[1].name == "MM2" assert circuit.elements[1].model == "N" assert circuit.elements[1].pins == { "D": "VOUT", "G": "NET2", "S": "NET3", "B": "GND!", } assert circuit.elements[1].parameters == { "W": "2.7E-08", "L": "2E-08", "NFIN": "1", "NF": "1", "M": "1", "PARALLEL": "1", "STACK": "1", } assert circuit.elements[2].name == "MM3" assert circuit.elements[2].model == "NFET" assert circuit.elements[2].pins == { "D": "VOUT", "G": "NET3", "S": "NET4", "B": "GND!", } assert circuit.elements[2].parameters == { "W": "2.7E-08", "L": "2E-08", "NFIN": "1", "NF": "1", "M": "1", "PARALLEL": "1", "STACK": "1", } assert circuit.elements[3].name == "RR0" assert circuit.elements[3].model == "RES" model = lib.find(circuit.elements[3].model) assert model.base == None # Using base model assert model.pins == ["PLUS", "MINUS"] assert model.parameters == {"VALUE": "0"} assert model.prefix == "R" assert circuit.elements[3].pins == {"PLUS": "VBIAS", "MINUS": "NET5"} assert circuit.elements[3].parameters == {"VALUE": "5000"} assert circuit.elements[4].name == "CC0" model = lib.find(circuit.elements[4].model) assert circuit.elements[4].model == "CAP" assert model.base == None assert circuit.elements[4].pins == {"PLUS": "VIN", "MINUS": "NET5"} assert circuit.elements[4].parameters == { "VALUE": "1.0000000000000002E-14" } # TBF: remove multiple zeros assert circuit.elements[5].name == "LL0" assert circuit.elements[5].model == "IND" model = lib.find(circuit.elements[5].model) assert model.base == None assert circuit.elements[5].pins == {"PLUS": "VDD!", "MINUS": "VOUT"} assert circuit.elements[5].parameters == { "VALUE": "0.002" } # TBF: change to scientific nomenclature? assert circuit.elements[6].name == "RR1" assert circuit.elements[6].model == "RESISTOR" model = lib.find(circuit.elements[6].model) assert model.name == "RESISTOR" assert model.pins == ["PLUS", "MINUS"] assert model.parameters == {"R": "1", "VALUE": "0"} assert circuit.elements[6].pins == {"PLUS": "VBIAS", "MINUS": "NET6"} assert circuit.elements[6].parameters == {"R": "5000", "VALUE": "0"} assert circuit.elements[7].name == "CC1" assert circuit.elements[7].model == "CAPACITOR" model = lib.find(circuit.elements[7].model) assert model.name == "CAPACITOR" assert model.pins == ["PLUS", "MINUS"] assert model.parameters == {"C": "1", "VALUE": "0"} assert circuit.elements[7].pins == {"PLUS": "VIN", "MINUS": "NET6"} assert circuit.elements[7].parameters == { "C": "1.0000000000000002E-14", "VALUE": "0", } assert circuit.elements[8].name == "LL1" assert circuit.elements[8].model == "INDUCTOR" model = lib.find(circuit.elements[8].model) assert model.name == "INDUCTOR" assert model.pins == ["PLUS", "MINUS"] assert model.parameters == {"IND": "1", "VALUE": "0"} assert circuit.elements[8].pins == {"PLUS": "VDD!", "MINUS": "NET6"} assert circuit.elements[8].parameters == {"IND": "0.002", "VALUE": "0"}