def print_to_results(gate_config_file, required_gates, results_file, prefix): gates = read_gate_config(gate_config_file, None) generate_all = required_gates is None or required_gates == "" or "ALL" in required_gates t_p_list = [] t_p_percent_list = [] t_p_mode_list = [] name_list = [] channel_type_list = [] channel_location_list = [] n_up_list = [] n_do_list = [] x_1_up_list = [] x_1_do_list = [] tau1_up_list = [] tau1_do_list = [] tau2_up_list = [] tau2_do_list = [] for name in sorted(gates.keys()): gate = gates[name] if not generate_all and name not in required_gates: my_print("Ignoring: " + name) continue # we do not want to generate all gates, if not necessary for the circuit t_p_list.append(gate.T_P) t_p_percent_list.append(gate.T_P_percent) t_p_mode_list.append(gate.T_P_mode) name_list.append(gate.entity_name) channel_type_list.append(gate.channel_type) channel_location_list.append(gate.channel_location) append_channel_parameter(n_up_list, gate, "N_UP") append_channel_parameter(n_do_list, gate, "N_DO") append_channel_parameter(x_1_up_list, gate, "X_1_UP") append_channel_parameter(x_1_do_list, gate, "X_1_DO") append_channel_parameter(tau1_up_list, gate, "TAU_1_UP") append_channel_parameter(tau1_do_list, gate, "TAU_1_DO") append_channel_parameter(tau2_up_list, gate, "TAU_2_UP") append_channel_parameter(tau2_do_list, gate, "TAU_2_DO") # Now extend the results dictionary results = dict() append_to_result_dict(results, prefix + 'T_P', t_p_list) append_to_result_dict(results, prefix + 'T_P_Percent', t_p_percent_list) append_to_result_dict(results, prefix + 'T_P_Mode', t_p_mode_list) append_to_result_dict(results, prefix + 'name', name_list) append_to_result_dict(results, prefix + 'channel_type', channel_type_list) append_to_result_dict(results, prefix + 'channel_location', channel_location_list) append_to_result_dict(results, prefix + 'n_up', n_up_list) append_to_result_dict(results, prefix + 'n_do', n_do_list) append_to_result_dict(results, prefix + 'x_1_up', x_1_up_list) append_to_result_dict(results, prefix + 'x_1_do', x_1_do_list) append_to_result_dict(results, prefix + 'tau_1_up', tau1_up_list) append_to_result_dict(results, prefix + 'tau_1_do', tau1_do_list) append_to_result_dict(results, prefix + 'tau_2_up', tau2_up_list) append_to_result_dict(results, prefix + 'tau_2_do', tau2_do_list) extend_results(results_file, results)
def combine_gates(default_config_file, circuit_config_file, target_config_file): gates = read_gate_config(default_config_file, circuit_config_file) with open(target_config_file, "w") as gate_cfg_file: gate_cfg_file.write( json.dumps(gates, cls=ObjectEncoder, indent=2, sort_keys=True))
def prepate_gates(default_config_file, circuit_config_file, template_gate_config_file, output_file, required_gates): gates = read_gate_config(default_config_file, circuit_config_file) gate_config_template = "" with open(template_gate_config_file, 'r') as tempfile: gate_config_template = tempfile.read() generate_all = required_gates is None or "ALL" in required_gates file_content = "" # now that we have all the gates we want to create --> create them for name, gate in gates.items(): if not generate_all and name not in required_gates: my_print("Ignoring: " + name) continue # we do not want to generate all gates, if not necessary for the circuit channel_parameters = "" for param_key, param_value in gate.channel_parameters.items(): channel_parameters += replace_special_chars( str(param_key)) + ": " + replace_special_chars( str(param_value)) + "\\\\" if channel_parameters != "": channel_parameters = "Additional channel parameters: \\\\\n" + channel_parameters file_content = gate_config_template.replace( "%##ENTITY_NAME##%", replace_special_chars(gate.entity_name)).replace( "%##CHANNEL_TYPE##%", replace_special_chars(str(gate.channel_type))).replace( "%##EXP_CHANNEL_LOCATION##%", replace_special_chars(str(gate.channel_location))).replace( "%##CHANNEL_LOCATION##%", str(gate.channel_location)).replace( "%##T_P##%", str(gate.T_P)).replace( "%##FUNCTION##%", gate.function).replace( "%##INPUTS##%", ", ".join(gate.inputs)).replace( "%##OUTPUTS##%", ", ".join(gate.outputs)).replace( "%##CHANNEL_PARAMETERS##%", channel_parameters) with open(output_file, 'w') as outfile: outfile.write(file_content)
def generate_gates(default_config_file, circuit_config_file, gate_dir, gate_template_file, gate_input_process_template_file, use_gidm, structure_file, tt_file_path, generate_gate_per_instance, vectors_dir_file_path, required_gates): gates = read_gate_config(default_config_file, circuit_config_file) use_gidm = to_bool(use_gidm) generate_gate_per_instance = to_bool(generate_gate_per_instance) # read template for gate gate_template = "" with open(gate_template_file, 'r') as template_file: gate_template = template_file.read() # read template for gate input process gate_input_process_template = "" with open(gate_input_process_template_file, 'r') as template_file: gate_input_process_template = template_file.read() generate_all = required_gates is None or "ALL" in required_gates structure = CircuitStructure() if use_gidm or generate_gate_per_instance: # now we need to read the structure.json file and generate structure = read_circuit_structure(structure_file) else: # This case is obsolete, we do not want to maintain this option any more. # Simply switch to GIDM or to generate_gate_per_instance # There is no function reduction, only a little performance sacrifice my_print("Gate generation configuration not supported any more!", EscCodes.FAIL) # now that we have all the gates we want to create --> create them for name, gate in gates.items(): if not check_gate_creation(generate_all, name, required_gates, gate): continue output = gate.outputs[0] function, function_input_list, delay_channel_list, signal_list = build_function( use_gidm, gate, output) entity_generic = build_entity_generic(gate) channel, d_up, d_down = build_channel_parameters( delay_channel_list, gate, output, use_gidm) arch_name = build_arch_name(use_gidm, gate) # Replace stuff that is independent of GIDM / IDM, and the ImplementationType content = gate_template.replace("##ARCH_NAME##", arch_name).replace( "##ARCH_FUNCTION##", function).replace("##ENTITY_GENERIC##", entity_generic).replace( "##GATE_SPECIFIC_PARAMETERS##", "") if use_gidm: generate_gate_gidm(gate, content, structure, name, channel, gate_dir, gate_input_process_template, tt_file_path, function_input_list, output, vectors_dir_file_path) else: generate_gate_idm(gate, content, structure, name, channel, gate_dir, d_up, d_down, signal_list, generate_all, required_gates)
def prepare_testbench(circuit_file_in, circuit_file_out, process_template_file, input_names, vector_names, default_gate_config_file, circuit_gate_config_file, circuit_configuration_file): my_print("prepare_testbench") gates = read_gate_config(default_gate_config_file, circuit_gate_config_file) circuit_content = "" with open(circuit_file_in, 'r') as tempfile: circuit_content = tempfile.read() process_template = "" with open(process_template_file, 'r') as tempfile: process_template = tempfile.read() circuit_configuration = "" if circuit_configuration_file and os.path.isfile( circuit_configuration_file): with open(circuit_configuration_file, 'r') as tempfile: circuit_configuration = tempfile.read() input_list = input_names.split(" ") vector_list = vector_names.split(" ") input_list = [x.strip(" \r\t\n") for x in input_list if x.strip(" \r\n\t")] vector_list = [ x.strip(" \r\t\n") for x in vector_list if x.strip(" \r\n\t") ] if len(input_list) != len(vector_list): my_print( "input_names and vector_names have a different length, this should not happen!", EscCode.FAIL) return input_process_content = "" for x in range(0, len(input_list)): my_print("Signal: " + input_list[x]) input_process_content += process_template.replace( "##SIGNALNAME##", input_list[x]).replace("##VECTORNAME##", vector_list[x]) input_process_content += "\n\n\n" for name, gate in gates.items(): additional_generics = "" for key, value in gate.channel_parameters.items(): additional_generics = ",\n\t\t\t" + str(key) + " => " + str(value) circuit_configuration = circuit_configuration.replace( "##GATE_ARCHITECTURE_" + name + "##", str(gate.channel_type) + "_" + str(gate.channel_location)).replace( "##T_P_" + name + "##", str(gate.T_P) + " ps").replace( "##CHANNEL_SPECIFIC_GENERICS_" + name + "##", additional_generics) input_process_content = """ init_proc : PROCESS BEGIN init_wrapper; initialized <= '1'; WAIT; END PROCESS; """.format() + input_process_content all_inputs_done = " AND ".join( ["{input}_done = '1'".format(input=input) for input in input_list]) input_process_content = input_process_content + """ clean_process : PROCESS BEGIN WAIT UNTIL {all_done}; WAIT for 10 sec; -- This is to ensure that clean_wrapper is definitely called after all transitions have been handled clean_wrapper; WAIT; END PROCESS; """.format(all_done=all_inputs_done) content_to_write = circuit_content.replace("##INPUT_PROCESS##", input_process_content).replace( "##CIRCUIT_CONFIGURATION##", circuit_configuration) with open(circuit_file_out, 'w') as outfile: outfile.write(content_to_write)
def generate_cell_initialization(circuit_folder, characterization_conf_file_path, structure_file_path, default_gate_config_file_path, circuit_gate_config_file_path, start_value): characterization_conf_file_path = os.path.join(circuit_folder, characterization_conf_file_path) structure_file_path = os.path.join(circuit_folder, structure_file_path) default_gate_config_file_path = os.path.join(circuit_folder, default_gate_config_file_path) circuit_gate_config_file_path = os.path.join(circuit_folder, circuit_gate_config_file_path) start_value = str(start_value) init_mapping = dict() # Need to read the characterization file char_conf = None with open(characterization_conf_file_path) as json_file: char_conf = json.load(json_file) # Need to read structure file structure = read_circuit_structure(structure_file_path) # Need to read the gate config file, to check which gate type we have gate_config = read_gate_config(default_gate_config_file_path, circuit_gate_config_file_path) # Traverse over the dependeny tree and fill out init mapping importer = DictImporter() dependency_tree = importer.import_(char_conf['dependency_tree']) for node in PreOrderIter(dependency_tree): if node.name == 'Top': continue cellname = get_cellname(char_conf, node.name) # Now use the cellname to find the cell_type in the structure.json file found_cell = find_cell_in_structure(structure, cellname) assert(found_cell) # Now we use the cell_type and find the function in the gate config gate = gate_config[found_cell.cell_type] # print(node.name, cellname, found_cell, gate, gate.function) assert(gate.function == "not" or gate.function == "") input_found_cell = gate.inputs assert(len(input_found_cell) == 1) input_found_cell = input_found_cell[0] # We need to find the predecessor and get the output value of the predecessor pred = find_pred_interconnect(structure, found_cell, input_found_cell) print(pred, cell) # Get the value of the predecessor from the dict in_value = None if pred.from_instance in init_mapping: in_value = init_mapping[pred.from_instance] else: in_value = start_value in_value = to_bool(in_value) logic_function = None if gate.function == "not": logic_function = my_not elif gate.funtion == "": logic_function = my_id else: assert(False) init_mapping[cell.instance] = bool_to_logic(logic_function(in_value)) # Write the init mapping to the structure file and save it structure.init = init_mapping save_circuit_structure(structure_file_path, structure)
def multi_exec_sim(config_file): temp_folder_name = 'temp' if not os.path.exists(temp_folder_name): os.makedirs(temp_folder_name) waveform_file_name = 'generate.json' waveform_generation = read_generate_cfg( os.path.join(os.environ["WAVEFORM_GENERATION_CONFIG_DIR"], waveform_file_name)) with open(os.path.join(temp_folder_name, waveform_file_name), "w") as waveform_cfg_file: waveform_cfg_file.write( json.dumps(waveform_generation, cls=ObjectEncoder, indent=2, sort_keys=True)) os.environ["WAVEFORM_GENERATION_CONFIG_DIR"] = os.path.join( os.getcwd(), temp_folder_name) # Read the multi_exec config file multi_exec = MultiExec() with open(config_file, "r") as cfg_file: jsonobject = json.load(cfg_file) for key, value in jsonobject.items(): if key.lower() == "waveform_generation": for elem in value: cfg = copy.deepcopy( waveform_generation ) # Required, because we want the default values from the default config file cfg.__dict__.update(elem) multi_exec.waveform_generation.append(cfg) elif key.lower() == "gate_generation": multi_exec.gate_generation.__dict__.update(value) else: multi_exec.__dict__[key] = value if get_print_level() > PrintLevel.INFORMATION: os.environ["MAKEFILE_PRINT_INFO"] = "False" # innermost loops (keep waveform!) must have lower numbers than than properties where a new waveform has to be created KEY_WAVEFORM = 8 KEY_SPICE_PROPERTIES = 7 # we can keep the waveform, but need to re-execute the Spice Simulation for these properties KEY_CROSSING_PROPERTIES = 6 KEY_DIGSIM_PROPERTIES = 5 # no need to re-execute SPICE, but we need to re-run our digital (ModelSim) simulation. ==> For example if only the sdf / spef File is changed KEY_INVOLUTION_PROPERTIES = 4 # we need to reexectue make sim_involution, since for example the SDF has changed (only allowed if we use a different SDF file for (G)IDM and Standard Delay Model, or if USE_GIDM flag is changed) KEY_CHANNEL_LOCATION = 3 KEY_CHANNEL_TYPE = 2 KEY_T_P = 1 # Prepare a dictionary with the properties to change and a index to the current element property_dict = dict() total_sim_num = 1 if len(multi_exec.waveform_generation) > 0: property_dict[KEY_WAVEFORM] = 0 total_sim_num = total_sim_num * len(multi_exec.waveform_generation) if len(multi_exec.gate_generation.t_p_list) > 0: property_dict[KEY_T_P] = 0 total_sim_num = total_sim_num * len( multi_exec.gate_generation.t_p_list) if len(multi_exec.gate_generation.channel_location_list) > 0: property_dict[KEY_CHANNEL_LOCATION] = 0 total_sim_num = total_sim_num * len( multi_exec.gate_generation.channel_location_list) if len(multi_exec.gate_generation.channel_type_list) > 0: property_dict[KEY_CHANNEL_TYPE] = 0 total_sim_num = total_sim_num * len( multi_exec.gate_generation.channel_type_list) if len(multi_exec.spice_properties) > 0: property_dict[KEY_SPICE_PROPERTIES] = 0 total_sim_num = total_sim_num * len(multi_exec.spice_properties) if len(multi_exec.crossing_properties) > 0: property_dict[KEY_CROSSING_PROPERTIES] = 0 total_sim_num = total_sim_num * len(multi_exec.crossing_properties) if len(multi_exec.digsim_properties) > 0: property_dict[KEY_DIGSIM_PROPERTIES] = 0 total_sim_num = total_sim_num * len(multi_exec.digsim_properties) if len(multi_exec.involution_properties) > 0: property_dict[KEY_INVOLUTION_PROPERTIES] = 0 total_sim_num = total_sim_num * len(multi_exec.involution_properties) last_key_to_keep_waveform = KEY_SPICE_PROPERTIES last_key_to_keep_crossings = KEY_DIGSIM_PROPERTIES last_key_to_keep_spice = KEY_CROSSING_PROPERTIES last_key_to_keep_stddigsim = KEY_INVOLUTION_PROPERTIES last_key_to_keep_group_count = KEY_T_P last_key_to_keep_reference_count = KEY_SPICE_PROPERTIES length_dict = dict() length_dict[KEY_WAVEFORM] = len(multi_exec.waveform_generation) length_dict[KEY_SPICE_PROPERTIES] = len(multi_exec.spice_properties) length_dict[KEY_CROSSING_PROPERTIES] = len(multi_exec.crossing_properties) length_dict[KEY_DIGSIM_PROPERTIES] = len(multi_exec.digsim_properties) length_dict[KEY_INVOLUTION_PROPERTIES] = len( multi_exec.involution_properties) length_dict[KEY_CHANNEL_LOCATION] = len( multi_exec.gate_generation.channel_location_list) length_dict[KEY_CHANNEL_TYPE] = len( multi_exec.gate_generation.channel_type_list) length_dict[KEY_T_P] = len(multi_exec.gate_generation.t_p_list) # 4. simulate my_print("Keep waveform: " + str(multi_exec.keep_waveform), EscCodes.OKBLUE, override_print_env_flag) # If keep_waveform is false, we just re-execute the complete toolchain fpr each configuration (do not keep SPICE, STD DIGISIM if possible) for iteraterion in range(multi_exec.N): my_print("Iteration: " + str(iteraterion + 1), EscCodes.OKBLUE, override_print_env_flag) keep_waveform_local = False # we ALWAYS want a new waveform in a new iteration keep_std_digsim = False keep_spice = False keep_crossings = False curr_sim_num = 1 config_num = 0 # Reset ME_reference_group and ME_group, these are "counters" which are later used for reporting os.environ[ "ME_reference_group"] = "0" # The ME_reference_group is incremented when the waveform config changes os.environ[ "ME_group"] = "0" # The ME_group is incremented when a channel property changes prev_param_mode = None me_group_param_mode_dict = dict() # reset property_dict indices (value is a pointer to the current setting for each key) for key in property_dict.keys(): property_dict[key] = 0 while True: if not keep_waveform_local: my_print("New waveform should be generated!", EscCodes.OKBLUE, override_print_env_flag) waveform_file = "multi_exec_" + time.strftime( "%Y%m%d_%H%M%S") + ".json" os.environ["INPUT_WAVEFORM"] = waveform_file my_print( "Iteration: " + str(iteraterion + 1) + " / " + str(multi_exec.N) + ", Simulation: " + str(curr_sim_num) + " / " + str(total_sim_num), EscCodes.OKBLUE, override_print_env_flag) # set the current spice_properties (if we have some). Note that these properties need to be checked with ifndef PROP_NAME before they are exported in the default *.cfg files set_config_property_list(multi_exec.spice_properties, property_dict, KEY_SPICE_PROPERTIES) set_config_property_list(multi_exec.crossing_properties, property_dict, KEY_CROSSING_PROPERTIES) set_config_property_list(multi_exec.digsim_properties, property_dict, KEY_DIGSIM_PROPERTIES) set_config_property_list(multi_exec.involution_properties, property_dict, KEY_INVOLUTION_PROPERTIES) # "Copy" the config files which will be adapted to the temp folder gate_config_name = 'gate_config.json' gate_default_config_file = os.environ["GENERAL_GATE_CONFIG"] gate_circuit_config_file = os.environ["CIRCUIT_GATE_CONFIG"] gates = read_gate_config(gate_default_config_file, gate_circuit_config_file) with open(os.path.join(temp_folder_name, gate_config_name), "w") as gate_cfg_file: gate_cfg_file.write( json.dumps(gates, cls=ObjectEncoder, indent=2, sort_keys=True)) # update the environment variables to the new generated config files (valid for this process and all child process) os.environ["GENERAL_GATE_CONFIG"] = os.path.join( os.getcwd(), temp_folder_name, gate_config_name) os.environ["CIRCUIT_GATE_CONFIG"] = os.path.join( os.getcwd(), temp_folder_name, gate_config_name) # Deepcopy required if we set one property in the previous simulation, but not in th current one # --> we want to have the value of the default config file new_gates = copy.deepcopy(gates) new_waveform_generation = copy.deepcopy(waveform_generation) config_num = config_num + 1 # iterate over all properties to set for key, value in property_dict.items(): if key == KEY_WAVEFORM: new_waveform_generation = multi_exec.waveform_generation[ value] elif key == KEY_T_P: for gate in new_gates.values(): # Make distinction between ABSOLUTE and PERCENT if isinstance( multi_exec.gate_generation.t_p_list[value], list): mode = multi_exec.gate_generation.t_p_list[value][ 1] gate.T_P_mode = mode if mode == ParameterMode.ABSOLUTE: gate.T_P = multi_exec.gate_generation.t_p_list[ value][0] elif mode == ParameterMode.PERCENT: gate.T_P_percent = multi_exec.gate_generation.t_p_list[ value][0] else: my_print("Error: Unknown T_P_mode: " + mode, EscCodes.FAIL, override_print_env_flag) else: # Default behaviour (ABSOLUTE) gate.T_P = multi_exec.gate_generation.t_p_list[ value] gate.T_P_mode = ParameterMode.ABSOLUTE # Handle ME_group counter (must be different between ABSOLUTE and percent if prev_param_mode is None: prev_param_mode = gate.T_P_mode me_group_param_mode_dict[prev_param_mode] = int( os.environ["ME_group"]) elif prev_param_mode != gate.T_P_mode: # check the dict if we already have a group id for this T_P if gate.T_P_mode in me_group_param_mode_dict: # go back to the already used group id os.environ["ME_group"] = str( me_group_param_mode_dict[gate.T_P_mode]) else: # Create new group id me_group_param_mode_dict[gate.T_P_mode] = max( me_group_param_mode_dict.values()) + 1 # and use this id os.environ["ME_group"] = str( me_group_param_mode_dict[gate.T_P_mode]) prev_param_mode = gate.T_P_mode elif key == KEY_CHANNEL_LOCATION: for gate in new_gates.values(): gate.channel_location = multi_exec.gate_generation.channel_location_list[ value] elif key == KEY_CHANNEL_TYPE: gate_config_dict = multi_exec.gate_generation.channel_type_list[ value] for gate_key, gate_value in new_gates.items(): gate_key_for_copy = "ALL" # use the default configuration for this gate if gate_key in gate_config_dict: gate_key_for_copy = gate_key # we found a more specific configuration for this gate => use it if "channel_type" in gate_config_dict[ gate_key_for_copy].keys(): gate_value.channel_type = gate_config_dict[ gate_key_for_copy]["channel_type"] if "channel_parameters" in gate_config_dict[ gate_key_for_copy].keys(): gate_value.channel_parameters = gate_config_dict[ gate_key_for_copy]["channel_parameters"] elif key == KEY_SPICE_PROPERTIES: # nothing to do? pass elif key == KEY_CROSSING_PROPERTIES: # nothing to do? pass elif key == KEY_DIGSIM_PROPERTIES: # nothing to do? pass elif key == KEY_INVOLUTION_PROPERTIES: # nothing to do? pass else: my_print("Error: Undefined key", EscCodes.FAIL, override_print_env_flag) # write the files after setting all the properties with open(os.path.join(temp_folder_name, gate_config_name), "w") as gate_cfg_file: gate_cfg_file.write( json.dumps(new_gates, cls=ObjectEncoder, indent=2, sort_keys=True)) with open(os.path.join(temp_folder_name, waveform_file_name), "w") as waveform_cfg_file: waveform_cfg_file.write( json.dumps(new_waveform_generation, cls=ObjectEncoder, indent=2, sort_keys=True)) # TODO: Remove, just for debugging reasons: with open( os.path.join(temp_folder_name, gate_config_name + str(config_num)), "w") as gate_cfg_file: gate_cfg_file.write( json.dumps(new_gates, cls=ObjectEncoder, indent=2, sort_keys=True)) with open( os.path.join(temp_folder_name, waveform_file_name + str(config_num)), "w") as waveform_cfg_file: waveform_cfg_file.write( json.dumps(new_waveform_generation, cls=ObjectEncoder, indent=2, sort_keys=True)) # set the path for the (single-)report os.environ["TARGET_FOLDER"] = os.path.join( os.environ["RESULT_OUTPUT_DIR"], os.environ["ME_REPORT_FOLDER"], time.strftime("%Y%m%d_%H%M%S")) my_print("target folder: " + str(os.environ["TARGET_FOLDER"])) # always check for the keep_waveform setting from the json file ==> If disabled, we always rerun the complete simulation if multi_exec.keep_waveform and keep_std_digsim: my_print("Keep DIGSIM!", EscCodes.OKBLUE, override_print_env_flag) execute_make_cmd("make me_involution") elif multi_exec.keep_waveform and keep_crossings: my_print("Keep CROSSINGS!", EscCodes.OKBLUE, override_print_env_flag) execute_make_cmd("make me_digsim") elif multi_exec.keep_waveform and keep_spice: my_print("Keep SPICE!", EscCodes.OKBLUE, override_print_env_flag) execute_make_cmd("make me_crossings") elif multi_exec.keep_waveform and keep_waveform_local: my_print("Keep Waveform!", EscCodes.OKBLUE, override_print_env_flag) execute_make_cmd("make clean") execute_make_cmd( "make all" ) # Careful, altough we clean up, we still want to keep the waveform else: my_print("Complete run!", EscCodes.OKBLUE, override_print_env_flag) # Clean up after previous simulation execute_make_cmd("make clean") # Now execute the simulation execute_make_cmd("make all") # Add a file with the "configuration id" - required for reporting if not (os.getenv('SKIP_SIMULATION', None)): with open( os.path.join(os.environ["TARGET_FOLDER"], "config_id"), "w") as cfg_id_file: cfg_id_file.write(str(config_num)) #increment all the counters in the dict (needs to be done in a sorted way) # sorted is also required, because properties where the waveform can be kept have to be in the innermost loop overflow = False for key in sorted(property_dict): overflow = False property_dict[key] += 1 if property_dict[key] == length_dict[key]: overflow = True #print "Overflow at: " + key + "" property_dict[key] = 0 # We had an overflow. Now check if we can keep the waveform (true as long this is not the last parameter that keeps the waveform) keep_std_digsim = calc_keep_property( key, last_key_to_keep_stddigsim, True) keep_crossings = calc_keep_property( key, last_key_to_keep_crossings, True) keep_spice = calc_keep_property(key, last_key_to_keep_spice, True) keep_waveform_local = calc_keep_property( key, last_key_to_keep_waveform, True) keep_group_count = calc_keep_property( key, last_key_to_keep_group_count, True) keep_reference_group_count = calc_keep_property( key, last_key_to_keep_reference_count, True) else: keep_std_digsim = calc_keep_property( key, last_key_to_keep_stddigsim, False) keep_crossings = calc_keep_property( key, last_key_to_keep_crossings, False) keep_spice = calc_keep_property(key, last_key_to_keep_spice, False) keep_waveform_local = calc_keep_property( key, last_key_to_keep_waveform, False) keep_group_count = calc_keep_property( key, last_key_to_keep_group_count, False) keep_reference_group_count = calc_keep_property( key, last_key_to_keep_reference_count, False) break # no need to increment the other properties if len(property_dict) == 0: # if we just want to execute the standard configuration multiple times, we have an overflow after each simulation run: overflow = True if not keep_group_count: # we need to get the maximum value from the dict (because we could configure ABSOLUTE, PERCENT, ABSOLUTE) new_group_id = int(os.environ["ME_group"]) + 1 if not me_group_param_mode_dict: if len(me_group_param_mode_dict.values()) == 0: new_group_id = 0 else: new_group_id = max( me_group_param_mode_dict.values()) + 1 os.environ["ME_group"] = str(new_group_id) # Reset our datastructures me_group_param_mode_dict = dict() prev_param_mode = None if not keep_reference_group_count: os.environ["ME_reference_group"] = str( int(os.environ["ME_reference_group"]) + 1) # "first" property has "overflowed", we are done if overflow: #print "Iterated over all configurations" break curr_sim_num = curr_sim_num + 1
def causality_checker(circuit_folder, default_gate_config_file_path, circuit_gate_config_file_path, structure_file_path, characterization_conf_file_path, sdf_file_path, instance_mapping_file_path): # structure file structure_file_path = os.path.join(circuit_folder, structure_file_path) structure = read_circuit_structure(structure_file_path) # sdf file sdf_file_path = os.path.join(circuit_folder, sdf_file_path) dinf_dict = read_sdf_file(sdf_file_path) # instance_mapping instance_mapping_file_path = os.path.join(circuit_folder, instance_mapping_file_path) instance_mapping = dict() if os.path.exists(instance_mapping_file_path): with open(instance_mapping_file_path) as f: instance_mapping = json.load(f) # gate config files (general and circuit specific files) default_gate_config_file_path = os.path.join( circuit_folder, default_gate_config_file_path) circuit_gate_config_file_path = os.path.join( circuit_folder, circuit_gate_config_file_path) gate_config = read_gate_config(default_gate_config_file_path, circuit_gate_config_file_path) # Characterization config file (the tree) characterization_conf_file_path = os.path.join( circuit_folder, characterization_conf_file_path) char_conf = None with open(characterization_conf_file_path) as json_file: char_conf = json.load(json_file) # Algorithm: Go over the tree in preorder importer = DictImporter() dependency_tree = importer.import_(char_conf['dependency_tree']) node_cnt = 0 for node in PreOrderIter(dependency_tree): if node.name == 'Top': continue print("-----------", node_cnt) node_cnt = node_cnt + 1 cellname = get_cellname(char_conf, node.name) # Find the cell with cellname curr_cell = find_cell_in_structure(structure, cellname) if not curr_cell: print("Did not find a cell for {}".format(cellname)) continue assert (curr_cell.instance in instance_mapping) sdf_instance_name = instance_mapping[curr_cell.instance] (d_inf_up, d_inf_do) = dinf_dict[sdf_instance_name] curr_gate = gate_config[curr_cell.cell_type] # now we need to check causality from this cell to all successor cells for succ in node.children: succ_cellname = get_cellname(char_conf, succ.name) succ_cell = find_cell_in_structure(structure, succ_cellname) print(curr_cell, succ_cell) if succ_cell: succ_gate = gate_config[succ_cell.cell_type] assert (succ_gate.function.lower() == "not" or succ_gate.function == "") succ_cell_inverting = succ_gate.function.lower() == "not" if succ_cell_inverting: succ_pure_delay_up = extract_delay_from_structure( succ_cell.pure_delay_down) succ_pure_delay_do = extract_delay_from_structure( succ_cell.pure_delay_up) else: succ_pure_delay_up = extract_delay_from_structure( succ_cell.pure_delay_up) succ_pure_delay_do = extract_delay_from_structure( succ_cell.pure_delay_down) succ_pure_delay = extract_delay_from_structure( succ_cell.pure_delay) succ_delta_plus = succ_pure_delay_up - succ_pure_delay succ_delta_minus = succ_pure_delay_do - succ_pure_delay curr_pure_delay = extract_delay_from_structure( curr_cell.pure_delay) curr_pure_delay_up = extract_delay_from_structure( curr_cell.pure_delay_up) curr_pure_delay_do = extract_delay_from_structure( curr_cell.pure_delay_down) curr_delta_plus = curr_pure_delay_up - curr_pure_delay curr_delta_minus = curr_pure_delay_do - curr_pure_delay # If none of them is > 0, we are definitely acausal assert (succ_delta_plus >= 0 or succ_delta_minus >= 0) # One must be <= 0, the other one >= 0 assert ((succ_delta_plus >= 0 and succ_delta_minus <= 0) or (succ_delta_plus <= 0 and succ_delta_minus >= 0)) assert (d_inf_up > 0) assert (d_inf_do > 0) assert (curr_pure_delay < d_inf_up) assert (curr_pure_delay < d_inf_do) # No algorithm yet implemented to automatically fix acausality, this is currently done manually # But of course, the simplest solution would be a binary search on the negative delta value and stop once we have two subsequent iteration # where the previous one was causal and the current acausal, and the difference between the two delta values is less than 1 fs (this is the highest possible precision of Questa) # TODO: Not sure anymore if this simple approach would be sufficient (causal_up, causal_do) = check_causality( curr_gate, curr_cell, d_inf_up, d_inf_do, curr_pure_delay, succ_delta_plus, succ_delta_minus, curr_delta_plus, curr_delta_minus) # plot_involution(curr_gate, curr_cell, d_inf_up, d_inf_do, curr_pure_delay, succ_delta_plus, succ_delta_minus, curr_delta_plus, curr_delta_minus) print(succ_cell_inverting, cellname, succ_cellname, "d_inf_up: ", d_inf_up, "d_inf_do: ", d_inf_do, "curr_pure_delay: ", curr_pure_delay, "curr_delta_plus: ", curr_delta_plus, "curr_delta_minus:", curr_delta_minus, "succ_delta_plus: ", succ_delta_plus, "succ_delta_minus: ", succ_delta_minus, "causal_up: ", causal_up, "causal_do: ", causal_do) # We need at least 1 fs, otherwise we are potentially due to rounding at 0, which is not strictly causal any more assert (causal_up >= 0 and causal_do >= 0) else: # Only the current dmin needs to be > 0 curr_pure_delay = extract_delay_from_structure( curr_cell.pure_delay) assert (curr_pure_delay > 0)