From 13b36c0111e1c71efec49960e65421c5b7b07873 Mon Sep 17 00:00:00 2001 From: Emmet Murphy Date: Wed, 3 Jun 2026 16:03:54 +0200 Subject: [PATCH 1/9] characterize spec attempt 1 --- .gitignore | 4 + spec-only.json | 13 + .../hdl_manager.py | 84 +++++ .../synth-characterization-spec/main.py | 201 ++++++++++ .../report_parser.py | 52 +++ .../run_synthesis.py | 31 ++ .../unit_characterization.py | 257 +++++++++++++ .../synth-characterization-spec/utils.py | 346 ++++++++++++++++++ 8 files changed, 988 insertions(+) create mode 100644 spec-only.json create mode 100644 tools/backend/synth-characterization-spec/hdl_manager.py create mode 100644 tools/backend/synth-characterization-spec/main.py create mode 100644 tools/backend/synth-characterization-spec/report_parser.py create mode 100644 tools/backend/synth-characterization-spec/run_synthesis.py create mode 100644 tools/backend/synth-characterization-spec/unit_characterization.py create mode 100644 tools/backend/synth-characterization-spec/utils.py diff --git a/.gitignore b/.gitignore index 6cb6d8194e..80996b025d 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,7 @@ metals.sbt # ElasticMiter puts external files in this directory /ext + +# Characterization tool scratch dirs +tools/backend/synth-characterization/tmp/ +tools/backend/synth-characterization-spec/tmp/ diff --git a/spec-only.json b/spec-only.json new file mode 100644 index 0000000000..f6c777de96 --- /dev/null +++ b/spec-only.json @@ -0,0 +1,13 @@ +[ + { "generic": "$DYNAMATIC/data/vhdl/support/types.vhd" }, + { "generic": "$DYNAMATIC/data/vhdl/support/spec_types.vhd" }, + { + "name": "handshake.speculator", + "parameters": [ + { "name": "BITWIDTH", "type": "int" }, + { "name": "FIFO_DEPTH", "type": "unsigned" } + ], + "generator": "python $DYNAMATIC/tools/unit-generators/vhdl/vhdl-unit-generator.py -n $MODULE_NAME -o $OUTPUT_DIR/$MODULE_NAME.vhd -t speculator -p fifo_depth=$FIFO_DEPTH bitwidth=$BITWIDTH extra_signals='{\"spec\":1}'", + "dependencies": ["types", "spec_types"] + } +] diff --git a/tools/backend/synth-characterization-spec/hdl_manager.py b/tools/backend/synth-characterization-spec/hdl_manager.py new file mode 100644 index 0000000000..17b6c69a29 --- /dev/null +++ b/tools/backend/synth-characterization-spec/hdl_manager.py @@ -0,0 +1,84 @@ +# This script is used to move the HDL files in the hdl_out_dir and generate the necessary HDL files for the unit. +import os + + +def copy_dependency_rtl_files(unit_name, dependency_dict, hdl_out_dir, dynamatic_dir): + """ + Copy the RTL files of the dependencies of the given unit to the output directory. + + Args: + unit_name (str): Name of the unit for which dependencies are to be copied. + dependency_dict (dict): Dictionary containing the list of dependencies for all units. + hdl_out_dir (str): Directory where HDL files should be stored. + dynamatic_dir (str): Path to the Dynamatic directory. + """ + # Add dependency RTL files to the output directory + remaining_dependencies = dependency_dict[unit_name]["dependencies"].copy() + while remaining_dependencies: + dependency_unit = remaining_dependencies.pop(0) + # Find the dependecy unit location + assert dependency_unit in dependency_dict, f"Dependency {dependency_unit} not found in dependency list." + dependency_info = dependency_dict[dependency_unit] + dependency_rtl = dependency_info["RTL"] + dependency_rtl = dependency_rtl.replace("$DYNAMATIC", dynamatic_dir) + if "_dataless" in dependency_unit: + # If the dependency is a dataless unit, we copy it with a different name + rtl_filename = dependency_rtl.split( + "/")[-1].replace(".vhd", "_dataless.vhd") + os.system(f"cp {dependency_rtl} {hdl_out_dir}/{rtl_filename}") + else: + os.system(f"cp {dependency_rtl} {hdl_out_dir}") + # Add the dependencies of this dependency to the remaining dependencies + if "dependencies" in dependency_info: + remaining_dependencies.extend(dependency_info["dependencies"]) + + extra_dependencies = [ + ("types", "$DYNAMATIC/data/vhdl/support/types.vhd"), + ("logic", "$DYNAMATIC/data/vhdl/support/logic.vhd"), + ("oehb", "$DYNAMATIC/data/vhdl/handshake/oehb.vhd"), + ("oehb_dataless", "$DYNAMATIC/data/vhdl/handshake/dataless/oehb.vhd"), + ("br_dataless", "$DYNAMATIC/data/vhdl/handshake/dataless/br.vhd"), + ] + for extra_name, extra_rtl in extra_dependencies: + extra_rtl = extra_rtl.replace("$DYNAMATIC", dynamatic_dir) + rtl_filename = extra_rtl.split("/")[-1] + if "_dataless" in extra_name: + os.system( + f"cp {extra_rtl} {hdl_out_dir}/{rtl_filename.replace('.vhd', '_dataless.vhd')}") + else: + os.system(f"cp {extra_rtl} {hdl_out_dir}") + + +def get_hdl_files(unit_name, generic, generator, hdl_out_dir, dynamatic_dir, dependency_dict): + """ + Generate or copy the HDL files for the given unit. + + Args: + unit_name (str): Name of the unit. + generic (str): Generic information for the unit. + generator (str): Generator information for the unit. + hdl_out_dir (str): Directory where HDL files should be stored. + dynamatic_dir (str): Path to the Dynamatic directory. + dependency_dict (dict): Dictionary containing the list of dependencies for all units. + + Returns: + str: Path to the generated or copied HDL file. + """ + # Ensure the output directory exists + if not os.path.exists(hdl_out_dir): + os.makedirs(hdl_out_dir) + # Copy the RTL files of the dependencies to the output directory + copy_dependency_rtl_files( + unit_name, dependency_dict, hdl_out_dir, dynamatic_dir) + # For generic-only units (no generator), copy the RTL file once. + # For generator-driven units, the generator is invoked per parameter combo + # by run_unit_characterization, not here. + if generic: + rtl_file = generic.replace("$DYNAMATIC", dynamatic_dir) + os.system(f"cp {rtl_file} {hdl_out_dir}") + return rtl_file + + assert generator, "Unit must have either a generic RTL file or a generator." + rtl_file = None + + return rtl_file diff --git a/tools/backend/synth-characterization-spec/main.py b/tools/backend/synth-characterization-spec/main.py new file mode 100644 index 0000000000..f19f69cb8f --- /dev/null +++ b/tools/backend/synth-characterization-spec/main.py @@ -0,0 +1,201 @@ +# Script to run characterization of dataflow units +import argparse +import json +import os +from report_parser import extract_rpt_data +from hdl_manager import get_hdl_files +from utils import VhdlInterfaceInfo, parameters_ranges, skipping_units +from unit_characterization import run_unit_characterization + + +def extract_rtl_info(unit_info): + """ + Extract RTL information from the unit_info dictionary. + + Args: + unit_info (dict): Dictionary containing unit information. + + Returns: + tuple: A tuple containing the unit name, list of parameters, generic, generator, and dependencies. + """ + unit_name = unit_info.get("name") + list_params = unit_info.get("parameters", []) + generic = unit_info.get("generic", None) + generator = unit_info.get("generator", None) + dependencies = unit_info.get("dependencies", []) + + return unit_name, list_params, generic, generator, dependencies + +# Extract dependencies from the dataflow units +# This function is essential to move the right RTL files +# Example of a dependency dictionary: +# { +# "unit_name": {"RTL": "path/to/rtl_file.vhd", "dependencies": ["dep1", "dep2"]}, +# "dep1": {"RTL": "path/to/dep1.vhd", "dependencies": []}, +# "dep2": {"RTL": "path/to/dep2.vhd", "dependencies": []}, +# ... +# } +# The dependencies are used to copy the necessary RTL files to the output directory + + +def get_dependency_dict(dataflow_units): + """ + Extract the RTLs of all possible dependencies from the dataflow units. + Args: + dataflow_units (list): List of dataflow unit dictionaries. + Returns: + list: A list of unique dependencies. + """ + dependency_dict = {} + for unit_info in dataflow_units: + if not "name" in unit_info: + rtl_file = unit_info.get("generic") + assert rtl_file, "Unit info must contain a 'generic' field for RTL file." + unit_name = rtl_file.split("/")[-1].split(".")[0] + if "dependencies" in unit_info: + dependencies = unit_info["dependencies"] + else: + dependencies = [] + dependency_dict[unit_name] = { + "RTL": rtl_file, "dependencies": dependencies} + elif "module-name" in unit_info: + unit_name = unit_info["module-name"] + rtl_file = unit_info["generic"] + if "dependencies" in unit_info: + dependencies = unit_info["dependencies"] + else: + dependencies = [] + dependency_dict[unit_name] = { + "RTL": rtl_file, "dependencies": dependencies} + else: + rtl_file = unit_info.get("generic") + if not rtl_file: + rtl_file = unit_info.get("generator") + dependencies = unit_info.get("dependencies", []) + unit_name = unit_info["name"] + dependency_dict[unit_name] = { + "RTL": rtl_file, "dependencies": dependencies} + return dependency_dict + + +def run_characterization(json_input, json_output, dynamatic_dir, synth_tool, clock_period): + """ + Run characterization of dataflow units based on the provided JSON input. + + Args: + json_input (str): Path to the input JSON file containing dataflow unit RTL information. + json_output (str): Path to the output JSON file where characterization results will be saved. + dynamatic_dir (str): Path to the DYNAMATIC home directory. + synth_tool (str): Synthesis tool to use for characterization (e.g., 'vivado'). + """ + # Load the input JSON file + with open(json_input, 'r') as f: + dataflow_units = json.load(f) + + tmp_dir = f"{dynamatic_dir}/tools/backend/synth-characterization-spec/tmp" + # Generate the temporary directory if it does not exist + if not os.path.exists(tmp_dir): + os.makedirs(tmp_dir) + # Generate hdl directory + hdl_dir = f"{tmp_dir}/hdl" + if not os.path.exists(hdl_dir): + os.makedirs(hdl_dir) + # Generate tcl directory + tcl_dir = f"{tmp_dir}/tcl" + if not os.path.exists(tcl_dir): + os.makedirs(tcl_dir) + # Generate report directory + rpt_dir = f"{tmp_dir}/reports" + if not os.path.exists(rpt_dir): + os.makedirs(rpt_dir) + # Generate logs directory + log_dir = f"{tmp_dir}/logs" + if not os.path.exists(log_dir): + os.makedirs(log_dir) + + all_dependencies_dict = get_dependency_dict(dataflow_units) + + map_unit_to_list_unit_chars = {} + + for unit_info in dataflow_units: + # Extract the unit name and its RTL information + unit_name, list_params, generic, generator, dependencies = extract_rtl_info( + unit_info) + if unit_name == None: + print("Skipping unit with no name.") + continue + if unit_name in skipping_units: + print(f"Skipping unit {unit_name} as it is in the skipping list.") + continue + # We assume that units with no unit_name are just for dependencies + if unit_name == None: + continue + # If the unit has a "DATA_TYPE" parameter with data = 0, skip since it's a dataless unit + if len(list_params) > 0: + skip_unit = False + for param in list_params: + if param["name"] == "DATA_TYPE" and "data-eq" in param and param["data-eq"] == 0: + skip_unit = True + break + if skip_unit: + continue + # Clean previous RTL files and tcl files + os.system(f"rm -rf {hdl_dir}/*") + os.system(f"rm -rf {tcl_dir}/*") + # Copy the RTL files or generate them if necessary + print(f"Processing unit: {unit_name}") + top_def_file = get_hdl_files( + unit_name, generic, generator, hdl_dir, dynamatic_dir, all_dependencies_dict) + # After generating the HDL files, we can proceed with characterization + list_unit_chars = run_unit_characterization(unit_name, list_params, hdl_dir, synth_tool, top_def_file, + tcl_dir, rpt_dir, log_dir, clock_period, generator=generator, dynamatic_dir=dynamatic_dir) + # Store the results in the map_unit_to_list_unit_chars dictionary + map_unit_to_list_unit_chars[unit_name] = list_unit_chars + + # Save the results to the output JSON file + extract_rpt_data(map_unit_to_list_unit_chars, json_output) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Run characterization of dataflow units") + parser.add_argument( + "--json-input", + type=str, + default=None, + help="Path to the JSON file containing the dataflow unit RTL information (if unspecified, $DYNAMATIC_DIR/data/rtl-config-vhdl-vivado.json)", + ) + parser.add_argument( + "--json-output", + type=str, + required=True, + help="Path to the output JSON file where the characterization results will be saved", + ) + parser.add_argument( + "--dynamatic-dir", + type=str, + required=True, + help="Path to the DYNAMATIC home directory", + ) + parser.add_argument( + "--synth-tool", + type=str, + default="vivado", + help="Synthesis tool to use for characterization (default: vivado)", + ) + parser.add_argument( + "--clock-period", + type=float, + default=4.0, + help="Clock period in nanoseconds to use for synthesis (default: 4.0 ns)", + ) + args = parser.parse_args() + json_input = args.json_input + json_output = args.json_output + dynamatic_dir = args.dynamatic_dir + synth_tool = args.synth_tool + clock_period = args.clock_period + if not json_input: + json_input = f"{dynamatic_dir}/data/rtl-config-vhdl-vivado.json" + run_characterization(json_input, json_output, + dynamatic_dir, synth_tool, clock_period) diff --git a/tools/backend/synth-characterization-spec/report_parser.py b/tools/backend/synth-characterization-spec/report_parser.py new file mode 100644 index 0000000000..6991ced17e --- /dev/null +++ b/tools/backend/synth-characterization-spec/report_parser.py @@ -0,0 +1,52 @@ +# Extract per-(in_port, out_port) timing data and save as a JSON matrix. +import os +import re +import json + +PATTERN_DELAY_INFO = "Data Path Delay:" + + +def extract_delay(line): + match = re.search(r'Data Path Delay:\s+([\d.]+)ns', line) + assert match, f"Could not find data path delay in line: {line}" + return float(match.group(1)) + + +def extract_single_rpt(rpt_file): + """Return the max Data Path Delay in the report file, or None if absent.""" + if not os.path.exists(rpt_file): + return None + max_delay = None + with open(rpt_file, 'r') as f: + for line in f: + if PATTERN_DELAY_INFO in line: + d = extract_delay(line) + max_delay = d if max_delay is None else max(max_delay, d) + return max_delay + + +def extract_rpt_data(map_unit_to_list_unit_chars, json_output): + """ + Build a nested per-port-pair delay matrix per bitwidth. + + output[unit_name]["delays"][in_port][out_port][bitwidth_str] = delay_ns + """ + output_data = {} + for unit_name, list_unit_chars in map_unit_to_list_unit_chars.items(): + delays = {} + for unit_char in list_unit_chars: + bw = str(unit_char.get_parameter_value("BITWIDTH")) + pair_to_rpt = getattr(unit_char, "map_pair_to_rpt", {}) + if not pair_to_rpt: + print( + "\033[91m" + f"[ERROR] No pair_to_rpt for unit {unit_name} at BITWIDTH={bw}." + "\033[0m") + continue + for (iport, oport), rpt_path in pair_to_rpt.items(): + delay = extract_single_rpt(rpt_path) + if delay is None: + continue + delays.setdefault(iport, {}).setdefault(oport, {})[bw] = delay + output_data[unit_name] = {"delays": delays} + + with open(json_output, 'w') as f: + json.dump(output_data, f, indent=2) diff --git a/tools/backend/synth-characterization-spec/run_synthesis.py b/tools/backend/synth-characterization-spec/run_synthesis.py new file mode 100644 index 0000000000..afeee4bdf9 --- /dev/null +++ b/tools/backend/synth-characterization-spec/run_synthesis.py @@ -0,0 +1,31 @@ +import os +from multiprocessing import Pool +from utils import VhdlInterfaceInfo, NUM_CORES + +def _synth_worker(args): + synth_tool, tcl_file, log_file = args + os.system(f"{synth_tool} -mode batch -source {tcl_file} > {log_file}") + +def run_synthesis(tcl_files, synth_tool, log_file): + """ + Run synthesis for the given TCL files using the specified synthesis tool in parallel (if NUM_CORES > 1). + Args: + tcl_files (list): List of TCL files to run synthesis on. + synth_tool (str): Synthesis tool to use (e.g., 'vivado'). + """ + # Run synthesis in parallel using Vivado + args_list = [(synth_tool, tcl_file, f"{log_file}{i}") for i, tcl_file in enumerate(tcl_files)] + with Pool(processes=NUM_CORES) as pool: + pool.map(_synth_worker, args_list) + +def write_sdc_constraints(sdc_file, period_ns): + """ + Write the SDC constraints file with the specified period. + + Args: + sdc_file (str): Path to the SDC file. + period_ns (float): Period in nanoseconds. + """ + with open(sdc_file, 'w') as f: + f.write(f"create_clock -name clk -period {period_ns} -waveform {{0.000 {period_ns/2}}} [get_ports clk]\n") + f.write("set_property HD.CLK_SRC BUFGCTRL_X0Y0 [get_ports clk]\n") diff --git a/tools/backend/synth-characterization-spec/unit_characterization.py b/tools/backend/synth-characterization-spec/unit_characterization.py new file mode 100644 index 0000000000..b53e620997 --- /dev/null +++ b/tools/backend/synth-characterization-spec/unit_characterization.py @@ -0,0 +1,257 @@ +from run_synthesis import run_synthesis, write_sdc_constraints +import os +import re +from itertools import product +from utils import parameters_ranges, VhdlInterfaceInfo, UnitCharacterization +from typing import List, Tuple + + +def extract_generics_ports(vhdl_code, entity_name): + """ + Extract generics and ports from a VHDL entity block. + Args: + vhdl_code (str): VHDL code as a string. + Returns: + Tuple[List[str], List[str]]: A tuple containing two lists: + - List of generics + - List of ports + """ + + # Remove comments + vhdl_code = re.sub(r'--.*', '', vhdl_code) + + # Match the entity block + entity_match = re.search( + r'entity\s+(\w+)\s+is(.*?)end\s+entity', vhdl_code, re.DOTALL | re.IGNORECASE) + if not entity_match: + raise ValueError("Could not find VHDL entity block.") + + # If there are multiple entities, we remove the one that does not match the entity_name + is_right_entity = entity_match.group(1) in entity_name + while not is_right_entity and entity_match: + entity_to_remove = entity_match.group(1) + # Remove the first entity block that does not match the entity_name + first_entity = re.search( + fr'entity\s+{entity_to_remove}\s+is(.*?)end\s+architecture', vhdl_code, re.DOTALL | re.IGNORECASE) + assert first_entity, f"Could not find VHDL entity block for {entity_to_remove} despite being in the code." + vhdl_code = vhdl_code.replace(first_entity.group(0), "") + entity_match = re.search( + r'entity\s+(\w+)\s+is(.*?)end\s+entity', vhdl_code, re.DOTALL | re.IGNORECASE) + entity_extracted = entity_match.group(1) + # Check if the entity name matches the one we are looking for # Selector is a special case since its handshake name is handshake.select + is_right_entity = entity_extracted in entity_name if entity_extracted != "selector" else True + + assert entity_match, f"Entity {entity_name} not found in the VHDL code." + + entity_name = entity_match.group(1) if entity_match else "unknown_entity" + entity_block = entity_match.group(2) + + # Extract generics and ports + generics_match = re.search( + r'generic\s*\((.*?)\)\s*;', entity_block, re.DOTALL | re.IGNORECASE) + ports_match = re.search( + r'port\s*\(((?:[^()]*|\([^()]*\))*)\)\s*;', entity_block, re.DOTALL | re.IGNORECASE) + + generics_raw = generics_match.group(1).strip() if generics_match else '' + ports_raw = ports_match.group(1).strip() if ports_match else '' + + # Split on semicolon while keeping line breaks (in case of multiple declarations) + def split_definitions(raw: str) -> List[str]: + lines = re.split(r';\s*\n', raw) + return [line.strip() for line in lines if line.strip()] + + generics = split_definitions(generics_raw) + ports = split_definitions(ports_raw) + + return entity_name, VhdlInterfaceInfo(generics, ports) + + +def generate_wrapper_top(entity_name, vhdl_interface_info, param_names): + """ + Generate the wrapper for the top file from the given top definition file. + + Args: + entity_name (str): Name of the top entity. + vhdl_interface_info (VhdlInterfaceInfo): VHDL interface information containing generics and ports. + param_names (List[str]): List of parameter names to be used in the wrapper. + + Returns: + str: The wrapper for the top file. + """ + generics = vhdl_interface_info.get_list_generics() + ports = vhdl_interface_info.get_list_ports() + for _generic in generics: + # Get the generic name before the colon + generic = _generic.split(":")[0].strip() + assert generic in param_names, f"Generic `{generic}` not found in parameter names." + + # Create ports for the top file + tb_ports = [] + for _port in ports: + port = _port + for param in param_names: + port = port.replace(f"{param}", f"{param}_const_value") + tb_ports.append(port) + # Create the wrapper for the top file + wrapper_top = f"""library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.math_real.all; +use work.types.all; +entity tb is +port ( +{';\n'.join(tb_ports)} +); +end entity; +architecture tb_arch of tb is +begin +dut: entity work.{entity_name} +generic map ( +""" + + for param in param_names: + if param != "PREDICATE": + wrapper_top += f"{param} => {param}_const_value,\n" + wrapper_top = wrapper_top.rstrip(",\n") + "\n" \ + ")\n" \ + "port map (\n" + for port in ports: + # Get the port name before the colon + port_name = port.split(":")[0].strip() + wrapper_top += f"{port_name} => {port_name},\n" + wrapper_top = wrapper_top.rstrip(",\n") + "\n" \ + ");\n" \ + "end architecture;\n" + + return wrapper_top, entity_name + + +def generate_wrapper_top_no_generics(entity_name, vhdl_interface_info): + """ + Wrapper used when the unit's VHDL has no generics (modern self-contained generator output). + The tb just wires every dut port to a top-level port of the same name. + """ + ports = vhdl_interface_info.get_list_ports() + tb_ports = list(ports) + + wrapper_top = f"""library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.math_real.all; +use work.types.all; +entity tb is +port ( +{';\n'.join(tb_ports)} +); +end entity; +architecture tb_arch of tb is +begin +dut: entity work.{entity_name} +port map ( +""" + for port in ports: + port_name = port.split(":")[0].strip() + wrapper_top += f"{port_name} => {port_name},\n" + wrapper_top = wrapper_top.rstrip(",\n") + "\n);\nend architecture;\n" + return wrapper_top + + +def run_generator_for_combo(generator, dynamatic_dir, hdl_out_dir, module_name, params_dict): + """ + Substitute $DYNAMATIC / $OUTPUT_DIR / $MODULE_NAME / each $ into the + generator command template and invoke it. Returns the path of the produced .vhd. + """ + cmd = generator + cmd = cmd.replace("$DYNAMATIC", dynamatic_dir) + cmd = cmd.replace("$OUTPUT_DIR", hdl_out_dir) + cmd = cmd.replace("$MODULE_NAME", module_name) + for param_name, param_value in params_dict.items(): + cmd = cmd.replace(f"${param_name}", str(param_value)) + print(f"Running generator command: {cmd}") + rc = os.system(cmd) + rtl_file = f"{hdl_out_dir}/{module_name}.vhd" + assert rc == 0, f"Generator command failed for {module_name}: {cmd}" + assert os.path.exists(rtl_file), f"Generator did not produce {rtl_file}" + return rtl_file + + +def run_unit_characterization(unit_name, list_params, hdl_out_dir, synth_tool, top_def_file, tcl_dir, rpt_dir, log_dir, clock_period, generator=None, dynamatic_dir=None): + """ + Run characterization for a single unit using the specified synthesis tool. + + When `generator` is provided, the generator is re-invoked per parameter + combination with that combo's values substituted into the command, producing + a fresh fully-specialised .vhd for each combo. Otherwise (generic-only + units), the existing top_def_file is used and the legacy VHDL-generic + sweeping path is taken. + """ + support_hdl_files = [f"{hdl_out_dir}/{file}" for file in os.listdir( + hdl_out_dir) if os.path.isfile(os.path.join(hdl_out_dir, file))] + + params_charact = {} + for param in list_params: + param_name = param["name"] + # Only sweep params that the generator command actually references; + # avoids a redundant cartesian product when the JSON declares a param + # the generator does not use (e.g. DATA_TYPE alongside BITWIDTH). + if generator is not None and f"${param_name}" not in generator: + continue + assert param_name in parameters_ranges, f"Parameter {param_name} not found in parameters_ranges." + params_charact[param_name] = parameters_ranges[param_name] + param_combinations = list( + product(*params_charact.values())) if params_charact else [()] + param_names = list(params_charact.keys()) + + sdc_file = f"{tcl_dir}/period.sdc" + write_sdc_constraints(sdc_file, clock_period) + + list_tcls = [] + unit_characterization_list = [] + + if generator is not None: + for id, combination in enumerate(param_combinations): + params_dict = dict(zip(param_names, combination)) + module_name = f"{unit_name.split('.')[-1]}_{id}" + unit_vhd = run_generator_for_combo( + generator, dynamatic_dir, hdl_out_dir, module_name, params_dict) + with open(unit_vhd, 'r') as f: + vhdl_code = f.read() + top_entity_name, vhdl_interface_info = extract_generics_ports( + vhdl_code, module_name) + tb_text = generate_wrapper_top_no_generics( + top_entity_name, vhdl_interface_info) + tb_file = f"{hdl_out_dir}/{module_name}_tb.vhd" + with open(tb_file, 'w') as f: + f.write(tb_text) + hdl_files = [tb_file, unit_vhd] + support_hdl_files + unit_char_obj = UnitCharacterization( + unit_name, top_entity_name, params_dict, hdl_files, vhdl_interface_info, id) + list_tcls.append(unit_char_obj.generate_tcl( + tcl_dir, rpt_dir, sdc_file)) + unit_characterization_list.append(unit_char_obj) + else: + print(f"Extracting generics and ports from {top_def_file}") + with open(top_def_file, 'r') as f: + vhdl_code = f.read() + top_entity_name, vhdl_interface_info = extract_generics_ports( + vhdl_code, unit_name) + wrapper_top, top_entity_name = generate_wrapper_top( + top_entity_name, vhdl_interface_info, param_names) + for id, combination in enumerate(param_combinations): + top_file = f"{hdl_out_dir}/{top_entity_name}_top_{id}.vhd" + wrapper_top_combined = wrapper_top + for param_name, param_value in zip(param_names, combination): + wrapper_top_combined = wrapper_top_combined.replace( + f"{param_name}_const_value", str(param_value)) + with open(top_file, 'w') as f: + f.write(wrapper_top_combined) + unit_char_obj = UnitCharacterization(unit_name, top_entity_name, dict(zip( + param_names, combination)), [top_file] + support_hdl_files, vhdl_interface_info, id) + list_tcls.append(unit_char_obj.generate_tcl( + tcl_dir, rpt_dir, sdc_file)) + unit_characterization_list.append(unit_char_obj) + + log_file = f"{log_dir}/synth_{unit_name}_log.txt" + run_synthesis(list_tcls, synth_tool, log_file) + + return unit_characterization_list diff --git a/tools/backend/synth-characterization-spec/utils.py b/tools/backend/synth-characterization-spec/utils.py new file mode 100644 index 0000000000..ed06a74e20 --- /dev/null +++ b/tools/backend/synth-characterization-spec/utils.py @@ -0,0 +1,346 @@ +import os +import re +from typing import List, Tuple, Dict + +# Constants for the characterization process + +NUM_CORES = 10 # Number of cores to use for parallel synthesis (if applicable) + +# List of units to skip during characterization +# These units are either empty, unused, or characterized by other scripts +skipping_units = [ + # empty units + "handshake.constant", + "handshake.br", + "handshake.source", + "handshake.extsi", + "handshake.extui", + "handshake.trunci", + "handshake.truncf", + "handshake.sink", + "handshake.store", + "handshake.maximumf", + "handshake.minimumf", + "handshake.extf", + "handshake.divsi", + "handshake.divui", + # unused units + "handshake.join", + "handshake.sharing_wrapper", + "handshake.ready_remover", + "handshake.valid_merger", + "handshake.ndwire", + "handshake.mem_controller", + "mem_to_bram", + # units characterized by other scripts + "handshake.fork", + "handshake.lazy_fork", + "handshake.lsq", + "handshake.mulf", + "handshake.negf", + "handshake.buffer", + "handshake.addf", + "handshake.cmpf", + "handshake.divf", + "handshake.subf", + "handshake.not"] + +# List of parameters and their ranges for characterization +# This is used to generate the top files for characterization +parameters_ranges = { + "DATA_TYPE": [1, 2, 4, 8, 16, 32, 64], + "BITWIDTH": [1, 2, 4, 8, 16, 32, 64], + "FIFO_DEPTH": [4], + "SIZE": [2], + "SELECT_TYPE": [2], + "INDEX_TYPE": [2], + "ADDR_TYPE": [64], + "PREDICATE": ["ne"], + "EXTRA_SIGNALS": ["{}"], +} + +# Function to write the TCL file for synthesis + + +def write_tcl_multiport(top_entity_name, hdl_files, tcl_file, sdc_file, pair_to_rpt): + """ + Write a TCL file that synthesises the design and then runs one + `report_timing` per (input_port, output_port) pair, each writing to its own + report file. + + Args: + pair_to_rpt: dict keyed by (in_port, out_port) tuple, value is the + report file path for that pair. + """ + with open(tcl_file, 'w') as f: + for hdl_file in hdl_files: + f.write(f"read_vhdl -vhdl2008 {hdl_file}\n") + f.write(f"read_xdc {sdc_file}\n") + f.write( + "synth_design -top tb -part xc7k160tfbg484-2 -no_iobuf -mode out_of_context\n") + f.write("opt_design\n") + f.write("place_design\n") + f.write("phys_opt_design\n") + f.write("route_design\n") + f.write("phys_opt_design\n") + for (iport, oport), rpt_path in pair_to_rpt.items(): + f.write( + f"report_timing -from [get_ports {iport}] -to [get_ports {oport}] > {rpt_path}\n") + + +# Class to hold VHDL interface information +# This class is used to store the generics and ports of a VHDL entity. +class VhdlInterfaceInfo: + """ + Class to hold VHDL interface information. + This class is used to store the generics and ports of a VHDL entity. + """ + generics: List[str] # List of generics in the VHDL entity + ports: List[str] # List of ports in the VHDL entity + ins_per_type: Dict[str, str] # Dictionary of input ports with their types + # Dictionary of output ports with their types + outs_per_type: Dict[str, str] + + def __init__(self, generics: List[str], ports: List[str]): + self.generics = generics + self.ports = ports + ins, outs = self.extract_ins_outs() + self.ins_per_type = self.categorize_ports(ins) + self.outs_per_type = self.categorize_ports(outs) + + def __repr__(self): + return f"VhdlInterfaceInfo(generics={self.generics}, ports={self.ports})" + + def extract_ins_outs(self) -> Tuple[List[str], List[str]]: + """ + Extract input and output ports from the VHDL interface. + + Skips clk/rst ports since they are not characterized. + + Returns: + Tuple[List[str], List[str]]: A tuple containing two lists: + - List of input ports + - List of output ports + """ + def is_clock_or_reset(port_name: str) -> bool: + n = port_name.strip() + return n in ("clk", "clock", "rst", "reset") or n.startswith(("clk_", "rst_")) + + ins = [port.split(":")[0].strip( + ) for port in self.ports if "in" in port and not "data_array" in port] + ins = [p for p in ins if not is_clock_or_reset(p)] + # Add 2d data_array ports to ins + ins.extend(add_2d_ports(self.ports, "in")) + outs = [port.split(":")[0].strip( + ) for port in self.ports if "out" in port and not "data_array" in port] + outs = [p for p in outs if not is_clock_or_reset(p)] + # Add 2d data_array ports to outs + outs.extend(add_2d_ports(self.ports, "out")) + return ins, outs + + def categorize_ports(self, ports: List[str]) -> Dict[str, str]: + """ + Categorize ports based on their types. + + Args: + ports (List[str]): List of ports to categorize. + + Returns: + Dict[str, str]: Dictionary with port names as keys and their types as values. + """ + categorized_ports = {} + for port in ports: + if "_valid" in port: + categorized_ports[port] = "valid" + elif "_ready" in port: + categorized_ports[port] = "ready" + elif "condition" in port or "index" in port: + categorized_ports[port] = "condition" + elif "lhs" in port or "rhs" in port or "trueValue" in port or "falseValue" in port or "ins" in port or "data" in port or "addrIn" in port: + categorized_ports[port] = "data" + elif "result" in port or "outs" in port or "trueOut" in port or "falseOut" in port or "addrOut" in port or "dataOut" in port: + categorized_ports[port] = "data" + elif "clk" in port or "clock" in port or "rst" in port or "reset" in port: + categorized_ports[port] = "control_signal" + else: + categorized_ports[port] = "other" + return categorized_ports + + def get_input_ports(self) -> List[str]: + """ + Get the input ports of the VHDL interface. + + Returns: + List[str]: List of input ports. + """ + return list(self.ins_per_type.keys()) + + def get_input_ports_by_type(self, port_type: str) -> List[str]: + """ + Get the input ports of a specific type from the VHDL interface. + + Args: + port_type (str): Type of the input ports to retrieve (e.g., "valid", "ready", "data", "condition"). + + Returns: + List[str]: List of input ports of the specified type. + """ + assert port_type in ["valid", "ready", "data", + "condition"], f"Invalid port type: {port_type}. Valid types are 'valid', 'ready', 'data', 'condition'." + # Return ports that match the specified type + return [port for port, ptype in self.ins_per_type.items() if ptype == port_type] + + def get_output_ports_by_type(self, port_type: str) -> List[str]: + """ + Get the output ports of a specific type from the VHDL interface. + + Args: + port_type (str): Type of the output ports to retrieve (e.g., "valid", "ready", "data", "condition"). + + Returns: + List[str]: List of output ports of the specified type. + """ + assert port_type in ["valid", "ready", "data", + "condition"], f"Invalid port type: {port_type}. Valid types are 'valid', 'ready', 'data', 'condition'." + # Return ports that match the specified type + return [port for port, ptype in self.outs_per_type.items() if ptype == port_type] + + def get_output_ports(self) -> List[str]: + """ + Get the output ports of the VHDL interface. + + Returns: + List[str]: List of output ports. + """ + return list(self.outs_per_type.keys()) + + def get_list_ports(self) -> List[str]: + """ + Get the list of all ports (input and output) of the VHDL interface. + + Returns: + List[str]: List of all ports. + """ + return self.ports + + def get_list_generics(self) -> List[str]: + """ + Get the list of generics of the VHDL interface. + + Returns: + List[str]: List of generics. + """ + return self.generics + + +def add_2d_ports(ports, direction): + """ + Add 2D data_array ports to the list of ports based on the direction. + + Args: + ports (list): List of ports to process. + direction (str): Direction of the ports ('in' or 'out'). + Returns: + list: List of 2D data_array ports. + """ + + result = [] + for port in ports: + if direction in port and "data_array" in port: + match = re.search( + r'data_array\((\w+)\s*-\s*1\s*downto\s*0\)', port) + assert match, f"Could not find data_array port {port}." + size_name = match.group(1) + # Get corresponding size # Assuming only one value in parameters allowed + size_value = parameters_ranges[size_name][0] + for i in range(size_value): + result.append(f"{port.split(':')[0].strip()}[{i}]") + return result + +# Class that contains all information for a single unit characterization + + +class UnitCharacterization: + """ + Class to hold the characterization information for a single unit. + This class is used to store the unit name, its VHDL interface information, and the parameters used for characterization. + """ + unit_name: str # Name of the unit being characterized + top_entity_name: str # Name of the top entity for this unit + params: dict # Dictionary of parameters used for characterization + # List to hold HDL files generated or copied for this unit + hdl_files: List[str] + # Dictionary to hold delay reports for each signal + map_signals_type_to_delay_rpt: dict + # VHDL interface information containing generics and ports + vhdl_interface_info: VhdlInterfaceInfo + unique_id: int # Unique identifier for the characterization instance + tcl_file: str # Path to the last generated TCL file for synthesis + + # List of delay types to be characterized + # Each tuple contains the input and output port types to be characterized in this exact order + list_delay_types = [("data", "data"), ("valid", "valid"), ("ready", "ready"), + ("valid", "ready"), ("condition", + "valid"), ("condition", "ready"), + ("valid", "condition"), ("valid", "data")] + + def __init__(self, unit_name: str, top_entity_name: str, params: dict, hdl_files: List[str], vhdl_interface_info: VhdlInterfaceInfo, unique_id: int): + """ + Initialize the UnitCharacterization object. + + Args: + unit_name (str): Name of the unit being characterized. + top_entity_name (str): Name of the top entity for this unit. + params (dict): Dictionary of parameters used for characterization. + """ + self.unit_name = unit_name + self.top_entity_name = top_entity_name + self.params = params + self.hdl_files = hdl_files + self.unique_id = unique_id + self.vhdl_interface_info = vhdl_interface_info + self.map_signals_type_to_delay_rpt = {} + self.tcl_file = None + + def generate_tcl(self, tcl_dir: str, rpt_dir: str, sdc_file: str) -> List[str]: + """ + Generate a TCL file for synthesis. After synthesis, runs one + `report_timing` per (input_port, output_port) pair, each to its own + report file. Stashes the (in, out) -> rpt mapping on the object so the + parser can later read every pair. + """ + tcl_file = f"{tcl_dir}/synth_{self.top_entity_name}_top_{self.unique_id}.tcl" + input_ports = self.vhdl_interface_info.get_input_ports() + output_ports = self.vhdl_interface_info.get_output_ports() + pair_to_rpt = {} + for iport in input_ports: + for oport in output_ports: + rpt_path = f"{rpt_dir}/rpt_{self.top_entity_name}_top_{self.unique_id}__{iport}__{oport}.txt" + pair_to_rpt[(iport, oport)] = rpt_path + self.map_pair_to_rpt = pair_to_rpt + write_tcl_multiport(self.top_entity_name, self.hdl_files, + tcl_file, sdc_file, pair_to_rpt) + self.tcl_file = tcl_file + return tcl_file + + def get_signals_type_to_rpt(self) -> dict: + """ + Get the dictionary mapping signal types to their delays. + + Returns: + dict: Dictionary mapping signal types to their delays. + """ + return self.map_signals_type_to_delay_rpt + + def get_parameter_value(self, param_name: str) -> str: + """ + Get the value of a specific parameter. + + Args: + param_name (str): Name of the parameter to retrieve. + + Returns: + str: Value of the specified parameter. + """ + assert param_name in self.params, f"Parameter {param_name} not found in parameters." + return self.params[param_name] From 0bb9b46e9d2295e469e2ddb8bf9190b27709a085 Mon Sep 17 00:00:00 2001 From: Emmet Murphy Date: Thu, 4 Jun 2026 17:31:36 +0200 Subject: [PATCH 2/9] messy commit of everything but working fpl22 buffering --- data/spec-timing.json | 4222 +++++++++++++++++ include/dynamatic/Support/TimingModels.h | 45 + .../Transforms/BufferPlacement/FPL22Buffers.h | 8 + integration-test/fixed/fixed.c | 2 +- integration-test/if_convert/if_convert.c | 2 +- integration-test/loop_path/loop_path.c | 2 +- integration-test/nested_loop/cf.mlir | 34 - integration-test/nested_loop/nested_loop.c | 2 +- integration-test/single_loop/cf.mlir | 20 - integration-test/single_loop/single_loop.c | 2 +- integration-test/sparse/sparse.c | 2 +- integration-test/subdiag/subdiag.c | 2 +- integration-test/subdiag_fast/subdiag_fast.c | 2 +- lib/Support/TimingModels.cpp | 97 + .../BufferPlacement/FPL22Buffers.cpp | 134 + .../BufferPlacement/HandshakePlaceBuffers.cpp | 6 + .../HandshakeSetBufferingProperties.cpp | 10 +- spec-only.json | 9 + .../synth-characterization-spec/main.py | 23 +- .../report_parser.py | 123 +- .../unit_characterization.py | 43 +- .../synth-characterization-spec/utils.py | 21 +- tools/dynamatic/scripts/compile.sh | 2 +- tools/export-dot/export-dot.cpp | 5 +- tools/integration/TEST_SUITE.cpp | 5 +- tools/integration/util.cpp | 8 +- tools/integration/util.h | 2 + 27 files changed, 4722 insertions(+), 111 deletions(-) create mode 100644 data/spec-timing.json delete mode 100644 integration-test/nested_loop/cf.mlir delete mode 100644 integration-test/single_loop/cf.mlir diff --git a/data/spec-timing.json b/data/spec-timing.json new file mode 100644 index 0000000000..88891dd4ec --- /dev/null +++ b/data/spec-timing.json @@ -0,0 +1,4222 @@ +{ + "handshake.speculator": { + "delays": [ + { + "from": { + "port": "ins", + "signal": "data" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.307 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.343 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.343 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.699 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 3.114 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 3.114 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.327 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "data" + }, + "to": { + "port": "trigger", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.161 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.214 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.432 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.661 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.935 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.935 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.269 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "data" + }, + "to": { + "port": "outs", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.38 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.38 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.38 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 3.109 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 3.696 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 4.26 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 4.523 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "data" + }, + "to": { + "port": "outs", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.281 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.281 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.515 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.82 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 3.375 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 3.375 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.436 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "data" + }, + "to": { + "port": "ctrl_issue", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.397 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.397 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.397 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 3.0 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 3.136 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 3.243 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.577 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "data" + }, + "to": { + "port": "ctrl_history", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.218 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.218 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.485 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.588 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.896 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.935 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.339 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "data" + }, + "to": { + "port": "ctrl_commit", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.788 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.788 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.402 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.551 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.701 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.997 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.081 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.303 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.343 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.527 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.527 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.527 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.527 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.527 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "trigger", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.161 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.214 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.318 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.318 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.318 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.318 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.318 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "outs", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.38 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.38 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.77 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.77 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.978 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 3.178 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.855 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "outs", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.683 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.683 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.696 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.696 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.696 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.696 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.696 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "ctrl_issue", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.911 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.911 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.355 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.355 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.421 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.421 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.421 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "ctrl_issue", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.799 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.799 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.799 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.799 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.799 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.799 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.799 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "ctrl_history", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.898 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.898 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.335 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.335 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.335 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.335 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.335 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "ctrl_history", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.278 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.278 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.28 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.28 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.28 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.28 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.28 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "ctrl_commit", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.788 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.788 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.196 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.196 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.196 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.196 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.196 + } + ] + }, + { + "from": { + "port": "trigger", + "signal": "valid" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.226 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.23 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.525 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.525 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.525 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.525 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.525 + } + ] + }, + { + "from": { + "port": "trigger", + "signal": "valid" + }, + "to": { + "port": "trigger", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.135 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.135 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.316 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.316 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.316 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.316 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.316 + } + ] + }, + { + "from": { + "port": "trigger", + "signal": "valid" + }, + "to": { + "port": "outs", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.304 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.455 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.455 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.461 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.735 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 3.178 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.855 + } + ] + }, + { + "from": { + "port": "trigger", + "signal": "valid" + }, + "to": { + "port": "outs", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.683 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.683 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.683 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.683 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.683 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.683 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.683 + } + ] + }, + { + "from": { + "port": "trigger", + "signal": "valid" + }, + "to": { + "port": "ctrl_issue", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.911 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.911 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.227 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.227 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.229 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.229 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.334 + } + ] + }, + { + "from": { + "port": "trigger", + "signal": "valid" + }, + "to": { + "port": "ctrl_issue", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.799 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.799 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.799 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.799 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.799 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.799 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.799 + } + ] + }, + { + "from": { + "port": "trigger", + "signal": "valid" + }, + "to": { + "port": "ctrl_history", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.894 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.894 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.206 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.206 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.206 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.206 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.206 + } + ] + }, + { + "from": { + "port": "trigger", + "signal": "valid" + }, + "to": { + "port": "ctrl_history", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.278 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.278 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.278 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.278 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.278 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.278 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.278 + } + ] + }, + { + "from": { + "port": "outs", + "signal": "ready" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.013 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.013 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.013 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.077 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.307 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.307 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.307 + } + ] + }, + { + "from": { + "port": "outs", + "signal": "ready" + }, + "to": { + "port": "trigger", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.002 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.002 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.291 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.291 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.316 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.316 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.316 + } + ] + }, + { + "from": { + "port": "outs", + "signal": "ready" + }, + "to": { + "port": "ctrl_issue", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.266 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.266 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.266 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.266 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.625 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.625 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.731 + } + ] + }, + { + "from": { + "port": "outs", + "signal": "ready" + }, + "to": { + "port": "ctrl_issue", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.746 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.746 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.746 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.746 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.746 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.746 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.746 + } + ] + }, + { + "from": { + "port": "outs", + "signal": "ready" + }, + "to": { + "port": "ctrl_history", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.128 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.128 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.128 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.129 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.631 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.631 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.631 + } + ] + }, + { + "from": { + "port": "outs", + "signal": "ready" + }, + "to": { + "port": "ctrl_history", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.683 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.82 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.82 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.887 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.887 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.887 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.887 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "ready" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.013 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.013 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.013 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.077 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.307 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.307 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.307 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "ready" + }, + "to": { + "port": "trigger", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.002 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.002 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.291 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.291 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.316 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.316 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.316 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "ready" + }, + "to": { + "port": "outs", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.639 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.724 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.306 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.306 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.306 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.936 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.358 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "ready" + }, + "to": { + "port": "outs", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.606 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.606 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.29 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.29 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.29 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.29 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.327 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "ready" + }, + "to": { + "port": "ctrl_history", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.128 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.128 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.129 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.129 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.631 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.631 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.631 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "ready" + }, + "to": { + "port": "ctrl_history", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.683 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.816 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.816 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.887 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.887 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.887 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.887 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "ready" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.701 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.842 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.842 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.842 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.118 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.118 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.118 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "ready" + }, + "to": { + "port": "trigger", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.596 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.614 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.921 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.921 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.921 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.921 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.921 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "ready" + }, + "to": { + "port": "outs", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.521 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.717 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.74 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.911 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.241 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.936 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.074 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "ready" + }, + "to": { + "port": "outs", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.606 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.743 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.743 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.743 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.743 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.966 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.327 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "ready" + }, + "to": { + "port": "ctrl_issue", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.123 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.125 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.128 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.128 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.625 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.625 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.731 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "ready" + }, + "to": { + "port": "ctrl_issue", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.633 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.71 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.715 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.715 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.715 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.8 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.8 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "ready" + }, + "to": { + "port": "ctrl_commit", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.514 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.514 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.514 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.514 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.514 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.69 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.69 + } + ] + }, + { + "from": { + "port": "ctrl_commit", + "signal": "ready" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.627 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.627 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.813 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.813 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.118 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.118 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.118 + } + ] + }, + { + "from": { + "port": "ctrl_commit", + "signal": "ready" + }, + "to": { + "port": "ctrl_history", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.538 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.538 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.571 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.571 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.571 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.571 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.607 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "data" + }, + "to": { + "port": "ctrl_issue", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.724 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.724 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.178 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.178 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 3.139 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 3.139 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.255 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "data" + }, + "to": { + "port": "ctrl_history", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.611 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.611 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.335 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.335 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.898 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.898 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.92 + } + ] + } + ] + }, + "handshake.spec_save_commit": { + "delays": [ + { + "from": { + "port": "ins", + "signal": "data" + }, + "to": { + "port": "outs", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 4.052 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 4.052 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 4.052 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 4.052 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 4.052 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 4.052 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 4.052 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "data" + }, + "to": { + "port": "outs", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.949 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.949 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.949 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.949 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.949 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.949 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.949 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "data" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 3.327 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 3.327 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 3.327 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 3.327 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 3.327 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 3.327 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.327 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "outs", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 3.694 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 3.694 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 3.694 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 3.694 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 3.694 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 3.694 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.694 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "outs", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.434 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.434 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.434 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.434 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.434 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.434 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.434 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.32 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.32 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.32 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.32 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.32 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.32 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.32 + } + ] + }, + { + "from": { + "port": "outs", + "signal": "ready" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.631 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.631 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.631 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.631 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.631 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.631 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.631 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "ctrl_issue", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.463 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.463 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.463 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.463 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.463 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.463 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.463 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "ctrl_history", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.555 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.555 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.555 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.555 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.555 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.555 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.555 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "data" + }, + "to": { + "port": "ctrl_issue", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.048 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.048 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.048 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.048 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.048 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.048 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.048 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "data" + }, + "to": { + "port": "ctrl_history", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.14 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.14 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.14 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.14 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.14 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.14 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.14 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "data" + }, + "to": { + "port": "outs", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.638 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "data" + }, + "to": { + "port": "outs", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.019 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.019 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.019 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.019 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.019 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.019 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.019 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "data" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.677 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "valid" + }, + "to": { + "port": "ctrl_issue", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.31 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.31 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.31 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.31 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.31 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.31 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.31 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "valid" + }, + "to": { + "port": "ctrl_history", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.402 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.402 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.402 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.402 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.402 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.402 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.402 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "valid" + }, + "to": { + "port": "outs", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.638 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "valid" + }, + "to": { + "port": "outs", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.281 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.281 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.281 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.281 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.281 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.281 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.281 + } + ] + }, + { + "from": { + "port": "ctrl_issue", + "signal": "valid" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.677 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "data" + }, + "to": { + "port": "ctrl_issue", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.048 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.048 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.048 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.048 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.048 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.048 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.048 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "data" + }, + "to": { + "port": "ctrl_history", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.14 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.14 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.14 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.14 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.14 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.14 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.14 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "data" + }, + "to": { + "port": "outs", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.638 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "data" + }, + "to": { + "port": "outs", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.019 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.019 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.019 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.019 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.019 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.019 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.019 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "data" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.677 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "valid" + }, + "to": { + "port": "ctrl_issue", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.31 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.31 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.31 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.31 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.31 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.31 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.31 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "valid" + }, + "to": { + "port": "ctrl_history", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.402 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.402 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.402 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.402 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.402 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.402 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.402 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "valid" + }, + "to": { + "port": "outs", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 3.638 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 3.638 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "valid" + }, + "to": { + "port": "outs", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 2.281 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 2.281 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 2.281 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 2.281 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 2.281 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 2.281 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 2.281 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "valid" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.677 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.677 + } + ] + }, + { + "from": { + "port": "outs", + "signal": "ready" + }, + "to": { + "port": "ctrl_issue", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.415 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.415 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.415 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.415 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.415 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.415 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.415 + } + ] + }, + { + "from": { + "port": "outs", + "signal": "ready" + }, + "to": { + "port": "ctrl_history", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1 + }, + "delay": 1.126 + }, + { + "params": { + "BITWIDTH": 2 + }, + "delay": 1.126 + }, + { + "params": { + "BITWIDTH": 4 + }, + "delay": 1.126 + }, + { + "params": { + "BITWIDTH": 8 + }, + "delay": 1.126 + }, + { + "params": { + "BITWIDTH": 16 + }, + "delay": 1.126 + }, + { + "params": { + "BITWIDTH": 32 + }, + "delay": 1.126 + }, + { + "params": { + "BITWIDTH": 64 + }, + "delay": 1.126 + } + ] + } + ] + } +} \ No newline at end of file diff --git a/include/dynamatic/Support/TimingModels.h b/include/dynamatic/Support/TimingModels.h index 01f0a0d2b0..f7637ee26d 100644 --- a/include/dynamatic/Support/TimingModels.h +++ b/include/dynamatic/Support/TimingModels.h @@ -291,6 +291,33 @@ bool fromJSON(const llvm::json::Value &jsonValue, TimingModel &model, bool fromJSON(const llvm::json::Value &jsonValue, TimingModel::PortModel &model, llvm::json::Path path); +/// One characterised combinational path between two pins of an op, loaded from +/// the spec-timing JSON. Used for ops whose internal timing cannot be +/// expressed by the named scalars in TimingModel (e.g., handshake.speculator, +/// handshake.spec_save_commit). +struct SpecTimingEdge { + /// Endpoint identified by a port name (matching NamedIOInterface) plus a + /// signal kind ("data", "valid", or "ready"). + struct Endpoint { + std::string port; + std::string signal; + }; + Endpoint from; + Endpoint to; + /// Each sample is a measurement at one combination of sweep parameters + /// (e.g., BITWIDTH=16, FIFO_DEPTH=4). + struct Sample { + llvm::StringMap params; + double delay; + }; + std::vector samples; +}; + +/// Per-op-name set of characterised port-pair edges. +struct SpecTimingModel { + std::vector edges; +}; + /// Holds the timing models for a set of operations (internally identified by /// their unique timing model key), usually parsed from a JSON file. The class /// provides accessor methods to quickly get specific information from the @@ -341,10 +368,28 @@ class TimingDatabase { static LogicalResult readFromJSON(std::string &jsonPath, TimingDatabase &timingDB); + /// Loads the per-port-pair spec timing entries (e.g. for SpeculatorOp and + /// SpecSaveCommitOp) from the JSON file at `jsonPath`. Fails if the file is + /// missing or malformed. + static LogicalResult readSpecTimingFromJSON(std::string &jsonPath, + TimingDatabase &timingDB); + + /// Returns the spec timing model for the given op-name key, or nullptr if + /// none was loaded. + const SpecTimingModel *getSpecModel(StringRef timingModelKey) const; + + /// Convenience overload returning the spec timing model corresponding to + /// the op (looked up by op->getName().getStringRef()). + const SpecTimingModel *getSpecModel(Operation *op) const; + private: /// Maps from an operation's timing key to their timing model. /// Timing keys are generated based on operation name and implementation llvm::StringMap models; + + /// Per-op-name set of per-port-pair edges loaded from spec-timing.json. + /// Sparse: only ops that need port-pair-keyed delays appear here. + llvm::StringMap specModels; }; /// Deserializes a JSON value into a TimingDatabase. See ::llvm::json::Value's diff --git a/include/dynamatic/Transforms/BufferPlacement/FPL22Buffers.h b/include/dynamatic/Transforms/BufferPlacement/FPL22Buffers.h index 1a7cbab027..e9b5834bcc 100644 --- a/include/dynamatic/Transforms/BufferPlacement/FPL22Buffers.h +++ b/include/dynamatic/Transforms/BufferPlacement/FPL22Buffers.h @@ -69,6 +69,14 @@ class FPL22BuffersBase : public BufferPlacementMILP { /// `filter` function. void addUnitMixedPathConstraints(Operation *unit, ChannelFilter filter = nullFilter); + + /// Adds all combinational delay constraints for a unit whose timing comes + /// from a `SpecTimingModel` in the spec-timing JSON (per-port-pair edges). + /// Replaces the per-signal `addUnitTimingConstraints` + mixed-domain + /// `addUnitMixedPathConstraints` calls for that unit. The sample with the + /// closest sweep-parameter match to the unit's instance is used. + void addSpecUnitPathConstraints(Operation *unit, + ChannelFilter filter = nullFilter); }; /// This MILP operates on the channels and units from a single CFDFC union diff --git a/integration-test/fixed/fixed.c b/integration-test/fixed/fixed.c index 42b76c4950..ea4c3b5e6c 100644 --- a/integration-test/fixed/fixed.c +++ b/integration-test/fixed/fixed.c @@ -15,7 +15,7 @@ float fixed(in_float_t y) { c = x0 - x1; x0 = x1; loopAgain = c >= a; - #pragma DYN speculate variable=loopAgain max_predictions=3 style=standard + #pragma DYN speculate variable=loopAgain max_predictions=4 style=standard } while (loopAgain); return x1; } diff --git a/integration-test/if_convert/if_convert.c b/integration-test/if_convert/if_convert.c index 4f7aeca5bf..030568607a 100644 --- a/integration-test/if_convert/if_convert.c +++ b/integration-test/if_convert/if_convert.c @@ -9,7 +9,7 @@ void if_convert(in_int_t a[N], inout_int_t b[N]) { do { int tmp = a[i]; bool ifPred = i * tmp < 10000; - #pragma DYN speculate variable=ifPred max_predictions=7 style=standard + #pragma DYN speculate variable=ifPred max_predictions=8 style=standard if (ifPred) { i++; } diff --git a/integration-test/loop_path/loop_path.c b/integration-test/loop_path/loop_path.c index a563821d93..935cb25b9d 100644 --- a/integration-test/loop_path/loop_path.c +++ b/integration-test/loop_path/loop_path.c @@ -15,7 +15,7 @@ void loop_path(in_int_t a[N], in_int_t b[N], inout_int_t c[N]) { i++; break_flag = (1000 - temp) <= x * temp; loopAgain = !break_flag && i < N; - #pragma DYN speculate variable=loopAgain max_predictions=3 style=standard + #pragma DYN speculate variable=loopAgain max_predictions=4 style=standard } while (loopAgain); } diff --git a/integration-test/nested_loop/cf.mlir b/integration-test/nested_loop/cf.mlir deleted file mode 100644 index d49c02ba82..0000000000 --- a/integration-test/nested_loop/cf.mlir +++ /dev/null @@ -1,34 +0,0 @@ -module { - func.func @nested_loop(%arg0: memref<1000xi32> {handshake.arg_name = "a"}, %arg1: memref<1000xi32> {handshake.arg_name = "b"}, %arg2: memref<1000xi32> {handshake.arg_name = "c"}) { - %c1_i32 = arith.constant {handshake.name = "constant0"} 1 : i32 - %c400_i32 = arith.constant {handshake.name = "constant1"} 400 : i32 - %c1000_i32 = arith.constant {handshake.name = "constant2"} 1000 : i32 - %c0_i32 = arith.constant {handshake.name = "constant3"} 0 : i32 - %c0 = arith.constant {handshake.name = "constant4"} 0 : index - %c2 = arith.constant {handshake.name = "constant5"} 2 : index - %c1 = arith.constant {handshake.name = "constant6"} 1 : index - cf.br ^bb1(%c0 : index) {handshake.name = "br0"} - ^bb1(%0: index): // 2 preds: ^bb0, ^bb4 - %1 = arith.index_cast %0 {handshake.name = "index_cast0"} : index to i32 - %2 = arith.muli %1, %c400_i32 {handshake.name = "muli0"} : i32 - cf.br ^bb2(%c0_i32 : i32) {handshake.name = "br1"} - ^bb2(%3: i32): // 2 preds: ^bb1, ^bb3 - %4 = arith.index_cast %3 {handshake.name = "index_cast1"} : i32 to index - %5 = memref.load %arg0[%4] {handshake.name = "load0"} : memref<1000xi32> - %6 = memref.load %arg1[%4] {handshake.name = "load1"} : memref<1000xi32> - %7 = arith.muli %5, %6 {handshake.name = "muli1"} : i32 - %8 = arith.addi %3, %2 {handshake.name = "addi0"} : i32 - %9 = arith.index_cast %8 {handshake.name = "index_cast2"} : i32 to index - memref.store %7, %arg2[%9] {handshake.deps = #handshake, handshake.name = "store0"} : memref<1000xi32> - %10 = arith.cmpi slt, %7, %c1000_i32 {handshake.name = "cmpi0"} : i32 - %12 = arith.addi %3, %c1_i32 {handshake.name = "addi1"} : i32 - cf.cond_br %10, ^bb2(%12 : i32), ^bb4 {handshake.name = "cond_br0"} - ^bb4: // pred: ^bb2 - %13 = arith.addi %0, %c1 {handshake.name = "addi2"} : index - %14 = arith.cmpi ult, %13, %c2 {handshake.name = "cmpi1"} : index - cf.cond_br %14, ^bb1(%13 : index), ^bb5 {handshake.name = "cond_br1"} - ^bb5: // pred: ^bb4 - return {handshake.name = "return0"} - } -} - diff --git a/integration-test/nested_loop/nested_loop.c b/integration-test/nested_loop/nested_loop.c index 3f7f72edcb..1e2601254a 100644 --- a/integration-test/nested_loop/nested_loop.c +++ b/integration-test/nested_loop/nested_loop.c @@ -15,7 +15,7 @@ void nested_loop(in_int_t a[N], in_int_t b[N], inout_int_t c[N]) { c[i + j * 400] = sum; i++; loopAgain = sum < bound; - #pragma DYN speculate variable=loopAgain max_predictions=6 style=standard + #pragma DYN speculate variable=loopAgain max_predictions=8 style=standard } while (loopAgain); } } diff --git a/integration-test/single_loop/cf.mlir b/integration-test/single_loop/cf.mlir deleted file mode 100644 index 4b7fd6ef91..0000000000 --- a/integration-test/single_loop/cf.mlir +++ /dev/null @@ -1,20 +0,0 @@ -module { - func.func @single_loop(%arg0: memref<1000xi32> {handshake.arg_name = "a"}, %arg1: memref<1000xi32> {handshake.arg_name = "b"}, %arg2: memref<1000xi32> {handshake.arg_name = "c"}) { - %c1000_i32 = arith.constant {handshake.name = "constant0"} 1000 : i32 - %c0_i32 = arith.constant {handshake.name = "constant1"} 0 : i32 - %c1_i32 = arith.constant {handshake.name = "constant2"} 1 : i32 - cf.br ^bb1(%c0_i32 : i32) {handshake.name = "br0"} - ^bb1(%0: i32): // 2 preds: ^bb0, ^bb2 - %1 = arith.index_cast %0 {handshake.name = "index_cast0"} : i32 to index - %2 = memref.load %arg0[%1] {handshake.name = "load0"} : memref<1000xi32> - %3 = memref.load %arg1[%1] {handshake.name = "load1"} : memref<1000xi32> - %4 = arith.muli %2, %3 {handshake.name = "muli0"} : i32 - memref.store %4, %arg2[%1] {handshake.deps = #handshake, handshake.name = "store0"} : memref<1000xi32> - %5 = arith.cmpi slt, %4, %c1000_i32 {handshake.name = "cmpi0"} : i32 - %6 = arith.addi %0, %c1_i32 {handshake.name = "addi0"} : i32 - cf.cond_br %5, ^bb1(%6 : i32), ^bb3 {handshake.name = "cond_br0"} - ^bb3: // pred: ^bb1 - return {handshake.name = "return0"} - } -} - diff --git a/integration-test/single_loop/single_loop.c b/integration-test/single_loop/single_loop.c index 4a4e510e5e..f795142a2e 100644 --- a/integration-test/single_loop/single_loop.c +++ b/integration-test/single_loop/single_loop.c @@ -16,7 +16,7 @@ void single_loop(in_int_t a[N], in_int_t b[N], inout_int_t c[N]) { i++; loopAgain = sum < bound; -#pragma DYN speculate variable = loopAgain max_predictions = 6 style = standard +#pragma DYN speculate variable = loopAgain max_predictions = 7 style = standard } while (loopAgain); } diff --git a/integration-test/sparse/sparse.c b/integration-test/sparse/sparse.c index f712338e91..74fbdcd74e 100644 --- a/integration-test/sparse/sparse.c +++ b/integration-test/sparse/sparse.c @@ -14,7 +14,7 @@ float sparse(in_float_t a[N], in_float_t x[N]) { sum += mul; i++; loopAgain = sum >= 0.0f; - #pragma DYN speculate variable=loopAgain max_predictions=2 style=standard + #pragma DYN speculate variable=loopAgain max_predictions=3 style=standard } while (loopAgain); return sum; } diff --git a/integration-test/subdiag/subdiag.c b/integration-test/subdiag/subdiag.c index 6ad1582973..91a2f12105 100644 --- a/integration-test/subdiag/subdiag.c +++ b/integration-test/subdiag/subdiag.c @@ -14,7 +14,7 @@ int subdiag(in_float_t d[N], in_float_t e[N]) { i++; cond_break = (e[i]) <= x * dd; loop_again = i < N_DEC && !cond_break; - #pragma DYN speculate variable = loop_again max_predictions = 8 style = standard + #pragma DYN speculate variable = loop_again max_predictions = 9 style = standard } while (loop_again); return i; } diff --git a/integration-test/subdiag_fast/subdiag_fast.c b/integration-test/subdiag_fast/subdiag_fast.c index 2c23595732..2df77fed62 100644 --- a/integration-test/subdiag_fast/subdiag_fast.c +++ b/integration-test/subdiag_fast/subdiag_fast.c @@ -14,7 +14,7 @@ int subdiag_fast(in_float_t d1[N], in_float_t d2[N], in_float_t e[N]) { i++; cond_break = (e[i]) <= x * dd; loop_again = !cond_break && i < N_DEC; - #pragma DYN speculate variable=loop_again max_predictions=16 style=standard + #pragma DYN speculate variable=loop_again max_predictions=17 style=standard } while (loop_again); return i; } diff --git a/lib/Support/TimingModels.cpp b/lib/Support/TimingModels.cpp index 5ce4ca2dba..20d1ee0a3c 100644 --- a/lib/Support/TimingModels.cpp +++ b/lib/Support/TimingModels.cpp @@ -282,6 +282,103 @@ LogicalResult TimingDatabase::getTotalDelay(Operation *op, } } +const SpecTimingModel * +TimingDatabase::getSpecModel(StringRef timingModelKey) const { + auto it = specModels.find(timingModelKey); + if (it == specModels.end()) + return nullptr; + return &it->second; +} + +const SpecTimingModel *TimingDatabase::getSpecModel(Operation *op) const { + if (!op) + return nullptr; + return getSpecModel(op->getName().getStringRef()); +} + +LogicalResult TimingDatabase::readSpecTimingFromJSON(std::string &jsonpath, + TimingDatabase &timingDB) { + std::ifstream inputFile(jsonpath); + if (!inputFile.is_open()) { + llvm::errs() << "Failed to open spec timing JSON at \"" << jsonpath + << "\"\n"; + return failure(); + } + + std::string jsonString; + std::string line; + while (std::getline(inputFile, line)) + jsonString += line; + + llvm::Expected value = ljson::parse(jsonString); + if (!value) { + llvm::errs() << "Failed to parse spec timing JSON in \"" << jsonpath + << "\"\n"; + return failure(); + } + + const ljson::Object *root = value->getAsObject(); + if (!root) { + llvm::errs() << "Spec timing JSON root must be an object\n"; + return failure(); + } + + for (const auto &unitEntry : *root) { + StringRef unitKey = unitEntry.first; + const ljson::Object *unitObj = unitEntry.second.getAsObject(); + if (!unitObj) + continue; + const ljson::Array *delaysArr = unitObj->getArray("delays"); + if (!delaysArr) + continue; + + SpecTimingModel model; + for (const ljson::Value &edgeVal : *delaysArr) { + const ljson::Object *edgeObj = edgeVal.getAsObject(); + if (!edgeObj) + continue; + + SpecTimingEdge edge; + for (const auto &which : {std::make_pair("from", &edge.from), + std::make_pair("to", &edge.to)}) { + const ljson::Object *endObj = edgeObj->getObject(which.first); + if (!endObj) + continue; + std::optional p = endObj->getString("port"); + std::optional s = endObj->getString("signal"); + if (p) + which.second->port = p->str(); + if (s) + which.second->signal = s->str(); + } + + const ljson::Array *samplesArr = edgeObj->getArray("samples"); + if (samplesArr) { + for (const ljson::Value &sampleVal : *samplesArr) { + const ljson::Object *sampleObj = sampleVal.getAsObject(); + if (!sampleObj) + continue; + SpecTimingEdge::Sample sample; + if (auto d = sampleObj->getNumber("delay")) + sample.delay = *d; + else + continue; + if (const ljson::Object *paramObj = sampleObj->getObject("params")) { + for (const auto ¶mEntry : *paramObj) { + if (auto pv = paramEntry.second.getAsInteger()) + sample.params[paramEntry.first] = *pv; + } + } + edge.samples.push_back(std::move(sample)); + } + } + model.edges.push_back(std::move(edge)); + } + timingDB.specModels[unitKey] = std::move(model); + } + return success(); +} + LogicalResult TimingDatabase::readFromJSON(std::string &jsonpath, TimingDatabase &timingDB) { // Open the timing database diff --git a/lib/Transforms/BufferPlacement/FPL22Buffers.cpp b/lib/Transforms/BufferPlacement/FPL22Buffers.cpp index 2c4ccc2fdb..0c6eb210ef 100644 --- a/lib/Transforms/BufferPlacement/FPL22Buffers.cpp +++ b/lib/Transforms/BufferPlacement/FPL22Buffers.cpp @@ -20,6 +20,7 @@ #include "dynamatic/Transforms/BufferPlacement/Utils/CFDFC.h" #include "llvm/ADT/TypeSwitch.h" #include +#include #include // NOTE: The code wrapped in LLVM_DEBUG(...) is executed when @@ -301,6 +302,131 @@ void FPL22BuffersBase::addUnitMixedPathConstraints(Operation *unit, } } +void FPL22BuffersBase::addSpecUnitPathConstraints(Operation *unit, + ChannelFilter filter) { + const SpecTimingModel *specModel = timingDB.getSpecModel(unit); + if (!specModel) { + unit->emitError() << "addSpecUnitPathConstraints: no spec timing model " + << "loaded for op '" << unit->getName().getStringRef() + << "'"; + return; + } + + auto namedIO = dyn_cast(unit); + if (!namedIO) { + unit->emitError() << "addSpecUnitPathConstraints: op does not implement " + << "NamedIOInterface"; + return; + } + + // Build the per-instance port-name -> SSA Value map by asking the op for + // each operand/result's name. + llvm::StringMap portToValue; + for (unsigned i = 0, e = unit->getNumOperands(); i < e; ++i) + portToValue[namedIO.getOperandName(i)] = unit->getOperand(i); + for (unsigned i = 0, e = unit->getNumResults(); i < e; ++i) + portToValue[namedIO.getResultName(i)] = unit->getResult(i); + + // Determine the current sweep-parameter targets for this op instance. Each + // op type names its bitwidth-carrying channel differently; dispatch. + Value bitwidthChannel = + llvm::TypeSwitch(unit) + .Case( + [](handshake::SpeculatorOp op) { return op.getDataIn(); }) + .Case( + [](handshake::SpecSaveCommitOp op) { return op.getDataIn(); }) + .Default([&](Operation *op) { + op->emitError() << "addSpecUnitPathConstraints called on op type " + << "with no bitwidth accessor registered"; + return Value(); + }); + if (!bitwidthChannel) + return; + llvm::StringMap currentParams; + if (auto chTy = dyn_cast(bitwidthChannel.getType())) + currentParams["BITWIDTH"] = chTy.getDataBitWidth(); + else + currentParams["BITWIDTH"] = 0; + if (auto fifoAttr = unit->getAttrOfType("fifoDepth")) + currentParams["FIFO_DEPTH"] = fifoAttr.getValue().getZExtValue(); + + auto parseSignal = [](StringRef s) -> std::optional { + if (s == "data") + return SignalType::DATA; + if (s == "valid") + return SignalType::VALID; + if (s == "ready") + return SignalType::READY; + return std::nullopt; + }; + + auto pickClosest = + [&](const std::vector &samples) -> double { + assert(!samples.empty() && "spec timing edge has no samples"); + const SpecTimingEdge::Sample *best = &samples.front(); + int64_t bestDist = std::numeric_limits::max(); + for (const auto &s : samples) { + int64_t dist = 0; + for (const auto &targetKV : currentParams) { + auto it = s.params.find(targetKV.first()); + if (it == s.params.end()) + continue; + int64_t d = it->second - targetKV.second; + dist += d * d; + } + if (dist < bestDist) { + bestDist = dist; + best = &s; + } + } + return best->delay; + }; + + StringRef unitName = getUniqueName(unit); + unsigned idx = 0; + for (const SpecTimingEdge &edge : specModel->edges) { + auto fromIt = portToValue.find(edge.from.port); + auto toIt = portToValue.find(edge.to.port); + if (fromIt == portToValue.end()) { + unit->emitError() << "spec timing edge references unknown port '" + << edge.from.port << "'"; + return; + } + if (toIt == portToValue.end()) { + unit->emitError() << "spec timing edge references unknown port '" + << edge.to.port << "'"; + return; + } + std::optional fromSig = parseSignal(edge.from.signal); + std::optional toSig = parseSignal(edge.to.signal); + if (!fromSig || !toSig) { + unit->emitError() << "spec timing edge has unrecognised signal kind '" + << edge.from.signal << "' or '" << edge.to.signal + << "'"; + return; + } + + Value fromVal = fromIt->second; + Value toVal = toIt->second; + if (!filter(fromVal) || !filter(toVal)) + continue; + if (edge.samples.empty()) { + unit->emitError() << "spec timing edge " << edge.from.port << "." + << edge.from.signal << " -> " << edge.to.port << "." + << edge.to.signal << " has no samples"; + return; + } + + double delay = pickClosest(edge.samples); + + CPVar &tFrom = vars.channelVars[fromVal].signalVars[*fromSig].path.tOut; + CPVar &tTo = vars.channelVars[toVal].signalVars[*toSig].path.tIn; + std::string consName = + "path_spec_" + unitName.str() + "_" + std::to_string(idx++); + model->addConstr(tFrom + delay <= tTo, consName); + } +} + CFDFCUnionBuffers::CFDFCUnionBuffers(CPSolver::SolverKind solverKind, int timeout, FuncInfo &funcInfo, const TimingDatabase &timingDB, @@ -369,6 +495,10 @@ void CFDFCUnionBuffers::setup() { // Add single-domain and mixed-domain path constraints as well as elasticity // constraints over all units in the CFDFC union for (Operation *unit : cfUnion.units) { + if (isa(unit)) { + addSpecUnitPathConstraints(unit, channelFilter); + continue; + } addUnitTimingConstraints(unit, SignalType::DATA, channelFilter); addUnitTimingConstraints(unit, SignalType::VALID, channelFilter); addUnitTimingConstraints(unit, SignalType::READY, channelFilter); @@ -483,6 +613,10 @@ void OutOfCycleBuffers::setup() { if (cfUnion.units.contains(&unit)) continue; + if (isa(&unit)) { + addSpecUnitPathConstraints(&unit, channelFilter); + continue; + } addUnitTimingConstraints(&unit, SignalType::DATA, channelFilter); addUnitTimingConstraints(&unit, SignalType::VALID, channelFilter); addUnitTimingConstraints(&unit, SignalType::READY, channelFilter); diff --git a/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp b/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp index e8230b7cf0..febb91ec6d 100644 --- a/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp +++ b/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp @@ -213,6 +213,12 @@ LogicalResult HandshakePlaceBuffersPass::placeUsingMILP() { TimingDatabase timingDB; if (failed(TimingDatabase::readFromJSON(timingModels, timingDB))) return failure(); + // Optional per-port-pair timing for ops like SpeculatorOp / + // SpecSaveCommitOp; missing file is OK and leaves spec models empty. + std::string specTimingPath = + llvm::sys::path::parent_path(timingModels).str() + "/spec-timing.json"; + if (failed(TimingDatabase::readSpecTimingFromJSON(specTimingPath, timingDB))) + return failure(); auto &cfdfcAnalysis = getAnalysis(); diff --git a/lib/Transforms/BufferPlacement/HandshakeSetBufferingProperties.cpp b/lib/Transforms/BufferPlacement/HandshakeSetBufferingProperties.cpp index 51fc5a7348..f697b42b33 100644 --- a/lib/Transforms/BufferPlacement/HandshakeSetBufferingProperties.cpp +++ b/lib/Transforms/BufferPlacement/HandshakeSetBufferingProperties.cpp @@ -95,13 +95,9 @@ setSpeculatorBufferingProperties(handshake::FuncOp funcOp) { Channel resolveChannel(historyCtrl, true); resolveChannel.props->minTrans = std::max(resolveChannel.props->minTrans, 1U); - // The speculator's KILL_ONLY_DATA state stalls the data input for - // 1 cycle during misspeculation recovery. A transparent buffer on - // the data input absorbs this stall and prevents it from propagating - // upstream and causing throughput loss. - Value dataIn = specOp.getDataIn(); - Channel dataInChannel(dataIn, true); - dataInChannel.props->minTrans = std::max(dataInChannel.props->minTrans, 1U); + Value trigger = specOp.getTrigger(); + Channel triggerChannel(trigger, true); + triggerChannel.props->minTrans = std::max(triggerChannel.props->minTrans, 1U); return success(); } diff --git a/spec-only.json b/spec-only.json index f6c777de96..f5b68c33ab 100644 --- a/spec-only.json +++ b/spec-only.json @@ -9,5 +9,14 @@ ], "generator": "python $DYNAMATIC/tools/unit-generators/vhdl/vhdl-unit-generator.py -n $MODULE_NAME -o $OUTPUT_DIR/$MODULE_NAME.vhd -t speculator -p fifo_depth=$FIFO_DEPTH bitwidth=$BITWIDTH extra_signals='{\"spec\":1}'", "dependencies": ["types", "spec_types"] + }, + { + "name": "handshake.spec_save_commit", + "parameters": [ + { "name": "BITWIDTH", "type": "int" }, + { "name": "FIFO_DEPTH", "type": "unsigned" } + ], + "generator": "python $DYNAMATIC/tools/unit-generators/vhdl/vhdl-unit-generator.py -n $MODULE_NAME -o $OUTPUT_DIR/$MODULE_NAME.vhd -t spec_save_commit -p fifo_depth=$FIFO_DEPTH bitwidth=$BITWIDTH extra_signals='{\"spec\":1}'", + "dependencies": ["types", "spec_types"] } ] diff --git a/tools/backend/synth-characterization-spec/main.py b/tools/backend/synth-characterization-spec/main.py index f19f69cb8f..53ae8f16f4 100644 --- a/tools/backend/synth-characterization-spec/main.py +++ b/tools/backend/synth-characterization-spec/main.py @@ -78,7 +78,7 @@ def get_dependency_dict(dataflow_units): return dependency_dict -def run_characterization(json_input, json_output, dynamatic_dir, synth_tool, clock_period): +def run_characterization(json_input, json_output, dynamatic_dir, synth_tool, clock_period, clean=False): """ Run characterization of dataflow units based on the provided JSON input. @@ -93,9 +93,9 @@ def run_characterization(json_input, json_output, dynamatic_dir, synth_tool, clo dataflow_units = json.load(f) tmp_dir = f"{dynamatic_dir}/tools/backend/synth-characterization-spec/tmp" - # Generate the temporary directory if it does not exist - if not os.path.exists(tmp_dir): - os.makedirs(tmp_dir) + if clean and os.path.exists(tmp_dir): + os.system(f"rm -rf {tmp_dir}") + os.makedirs(tmp_dir, exist_ok=True) # Generate hdl directory hdl_dir = f"{tmp_dir}/hdl" if not os.path.exists(hdl_dir): @@ -139,9 +139,10 @@ def run_characterization(json_input, json_output, dynamatic_dir, synth_tool, clo break if skip_unit: continue - # Clean previous RTL files and tcl files - os.system(f"rm -rf {hdl_dir}/*") - os.system(f"rm -rf {tcl_dir}/*") + # Note: hdl_dir / tcl_dir are no longer wiped between units. With + # incremental mode each combo's files are uniquely named (e.g. + # speculator_0.vhd) so leftover files from prior units don't collide. + # Use --clean to wipe everything from scratch. # Copy the RTL files or generate them if necessary print(f"Processing unit: {unit_name}") top_def_file = get_hdl_files( @@ -189,6 +190,11 @@ def run_characterization(json_input, json_output, dynamatic_dir, synth_tool, clo default=4.0, help="Clock period in nanoseconds to use for synthesis (default: 4.0 ns)", ) + parser.add_argument( + "--clean", + action="store_true", + help="Wipe the tmp directory before running. Default behaviour is incremental: combos whose report files already exist are skipped (re-runs only fill holes).", + ) args = parser.parse_args() json_input = args.json_input json_output = args.json_output @@ -198,4 +204,5 @@ def run_characterization(json_input, json_output, dynamatic_dir, synth_tool, clo if not json_input: json_input = f"{dynamatic_dir}/data/rtl-config-vhdl-vivado.json" run_characterization(json_input, json_output, - dynamatic_dir, synth_tool, clock_period) + dynamatic_dir, synth_tool, clock_period, + clean=args.clean) diff --git a/tools/backend/synth-characterization-spec/report_parser.py b/tools/backend/synth-characterization-spec/report_parser.py index 6991ced17e..98672a5a17 100644 --- a/tools/backend/synth-characterization-spec/report_parser.py +++ b/tools/backend/synth-characterization-spec/report_parser.py @@ -13,40 +13,137 @@ def extract_delay(line): def extract_single_rpt(rpt_file): - """Return the max Data Path Delay in the report file, or None if absent.""" + """ + Returns the max Data Path Delay in ns. If the file is present but contains + no Data Path Delay line (Vivado found no timing path between this in/out + pair), returns 0.0. If the file is missing (synth failed), returns None. + """ if not os.path.exists(rpt_file): return None - max_delay = None + max_delay = 0.0 with open(rpt_file, 'r') as f: for line in f: if PATTERN_DELAY_INFO in line: - d = extract_delay(line) - max_delay = d if max_delay is None else max(max_delay, d) + max_delay = max(max_delay, extract_delay(line)) return max_delay -def extract_rpt_data(map_unit_to_list_unit_chars, json_output): +def render_matrix(unit_name, delays, bw): + """Render the (in_port x out_port) matrix at one bitwidth as a string.""" + in_ports = list(delays.keys()) + out_ports = [] + seen = set() + for ip in in_ports: + for op in delays[ip]: + if op not in seen: + seen.add(op) + out_ports.append(op) + col_w = max((len(p) for p in out_ports), default=4) + 1 + row_w = max((len(p) for p in in_ports), default=4) + lines = [f"=== {unit_name} delay matrix (bw={bw}) [ns] ==="] + lines.append(" " * row_w + " " + "".join(p.rjust(col_w) + for p in out_ports)) + for ip in in_ports: + cells = [] + for op in out_ports: + v = delays[ip].get(op, {}).get(bw) + cells.append("---" if v is None else f"{v:.3f}") + lines.append(ip.rjust(row_w) + " " + "".join(c.rjust(col_w) + for c in cells)) + return "\n".join(lines) + + +def split_physical_port(phys): """ - Build a nested per-port-pair delay matrix per bitwidth. + Split a physical VHDL port name into (logical_port, signal). + Examples: + "dataIn" -> ("dataIn", "data") + "dataIn_valid" -> ("dataIn", "valid") + "dataOut_ready" -> ("dataOut", "ready") + "issueCtrl_valid" -> ("issueCtrl", "valid") + "trigger_valid" -> ("trigger", "valid") + """ + for suffix, sig in (("_valid", "valid"), ("_ready", "ready"), ("_spec", "spec")): + if phys.endswith(suffix): + return phys[: -len(suffix)], sig + return phys, "data" + - output[unit_name]["delays"][in_port][out_port][bitwidth_str] = delay_ns +def extract_rpt_data(map_unit_to_list_unit_chars, json_output): """ - output_data = {} + Produce two artifacts: + 1. JSON (json_output) in the edges-list shape: + output[unit_name]["delays"] = [ + { "from": {"port", "signal"}, + "to": {"port", "signal"}, + "samples": [ {"params": {...}, "delay": ns}, ... ] }, + ... + ] + spec signals and all-zero edges are dropped. + 2. A .matrix.txt next to it: per-bitwidth physical-port matrices for + human inspection. + """ + # Per-unit nested matrix for the human-readable view (keyed by physical port + # names, indexed by bitwidth string). + matrix_by_unit = {} + # Per-unit edge map: (from_port, from_sig, to_port, to_sig) -> list of samples. + edges_by_unit = {} + for unit_name, list_unit_chars in map_unit_to_list_unit_chars.items(): - delays = {} + matrix = {} + edges = {} for unit_char in list_unit_chars: - bw = str(unit_char.get_parameter_value("BITWIDTH")) + sample_params = dict(unit_char.params) + bw = str(sample_params.get("BITWIDTH", "")) pair_to_rpt = getattr(unit_char, "map_pair_to_rpt", {}) if not pair_to_rpt: print( - "\033[91m" + f"[ERROR] No pair_to_rpt for unit {unit_name} at BITWIDTH={bw}." + "\033[0m") + "\033[91m" + f"[ERROR] No pair_to_rpt for unit {unit_name} at params={sample_params}." + "\033[0m") continue for (iport, oport), rpt_path in pair_to_rpt.items(): delay = extract_single_rpt(rpt_path) if delay is None: continue - delays.setdefault(iport, {}).setdefault(oport, {})[bw] = delay - output_data[unit_name] = {"delays": delays} + # Matrix view: keep zeros, key by bitwidth for display. + matrix.setdefault(iport, {}).setdefault(oport, {})[bw] = delay + # Edges view: drop spec endpoints; drop zero samples; pre-split. + from_port, from_sig = split_physical_port(iport) + to_port, to_sig = split_physical_port(oport) + if from_sig == "spec" or to_sig == "spec": + continue + if delay == 0.0: + continue + edge_key = (from_port, from_sig, to_port, to_sig) + edges.setdefault(edge_key, []).append( + {"params": sample_params, "delay": delay}) + + matrix_by_unit[unit_name] = matrix + edges_by_unit[unit_name] = edges + + # Assemble the edges-list output. + output_data = {} + for unit_name, edges in edges_by_unit.items(): + edge_list = [] + for (fp, fs, tp, ts), samples in edges.items(): + edge_list.append({ + "from": {"port": fp, "signal": fs}, + "to": {"port": tp, "signal": ts}, + "samples": samples, + }) + output_data[unit_name] = {"delays": edge_list} + + # Render matrices per unit per bitwidth. + matrix_path = json_output + ".matrix.txt" + chunks = [] + for unit_name, matrix in matrix_by_unit.items(): + bws = sorted( + {bw for ip in matrix for op in matrix[ip] for bw in matrix[ip][op]}, key=int) + for bw in bws: + block = render_matrix(unit_name, matrix, bw) + print("\n" + block) + chunks.append(block) + with open(matrix_path, 'w') as f: + f.write("\n\n".join(chunks) + "\n") with open(json_output, 'w') as f: json.dump(output_data, f, indent=2) diff --git a/tools/backend/synth-characterization-spec/unit_characterization.py b/tools/backend/synth-characterization-spec/unit_characterization.py index b53e620997..5c337e620b 100644 --- a/tools/backend/synth-characterization-spec/unit_characterization.py +++ b/tools/backend/synth-characterization-spec/unit_characterization.py @@ -60,8 +60,25 @@ def split_definitions(raw: str) -> List[str]: lines = re.split(r';\s*\n', raw) return [line.strip() for line in lines if line.strip()] - generics = split_definitions(generics_raw) - ports = split_definitions(ports_raw) + def expand_grouped(defs: List[str]) -> List[str]: + # Expand "clk, rst : in std_logic" into one entry per name so each + # gets its own port_map line. + out = [] + for d in defs: + if ":" not in d: + out.append(d) + continue + lhs, rhs = d.split(":", 1) + names = [n.strip() for n in lhs.split(",") if n.strip()] + if len(names) <= 1: + out.append(d) + continue + for n in names: + out.append(f"{n} :{rhs}") + return out + + generics = expand_grouped(split_definitions(generics_raw)) + ports = expand_grouped(split_definitions(ports_raw)) return entity_name, VhdlInterfaceInfo(generics, ports) @@ -226,9 +243,13 @@ def run_unit_characterization(unit_name, list_params, hdl_out_dir, synth_tool, t hdl_files = [tb_file, unit_vhd] + support_hdl_files unit_char_obj = UnitCharacterization( unit_name, top_entity_name, params_dict, hdl_files, vhdl_interface_info, id) - list_tcls.append(unit_char_obj.generate_tcl( - tcl_dir, rpt_dir, sdc_file)) + tcl_file = unit_char_obj.generate_tcl(tcl_dir, rpt_dir, sdc_file) unit_characterization_list.append(unit_char_obj) + if all(os.path.exists(p) for p in unit_char_obj.map_pair_to_rpt.values()): + print( + f"[skip] {unit_name} combo {id} {params_dict}: reports already present") + continue + list_tcls.append(tcl_file) else: print(f"Extracting generics and ports from {top_def_file}") with open(top_def_file, 'r') as f: @@ -247,11 +268,19 @@ def run_unit_characterization(unit_name, list_params, hdl_out_dir, synth_tool, t f.write(wrapper_top_combined) unit_char_obj = UnitCharacterization(unit_name, top_entity_name, dict(zip( param_names, combination)), [top_file] + support_hdl_files, vhdl_interface_info, id) - list_tcls.append(unit_char_obj.generate_tcl( - tcl_dir, rpt_dir, sdc_file)) + tcl_file = unit_char_obj.generate_tcl(tcl_dir, rpt_dir, sdc_file) unit_characterization_list.append(unit_char_obj) + if all(os.path.exists(p) for p in unit_char_obj.map_pair_to_rpt.values()): + print( + f"[skip] {unit_name} combo {id}: reports already present") + continue + list_tcls.append(tcl_file) log_file = f"{log_dir}/synth_{unit_name}_log.txt" - run_synthesis(list_tcls, synth_tool, log_file) + if list_tcls: + run_synthesis(list_tcls, synth_tool, log_file) + else: + print( + f"[skip] {unit_name}: all combos already characterized; nothing to synth") return unit_characterization_list diff --git a/tools/backend/synth-characterization-spec/utils.py b/tools/backend/synth-characterization-spec/utils.py index ed06a74e20..450605eb87 100644 --- a/tools/backend/synth-characterization-spec/utils.py +++ b/tools/backend/synth-characterization-spec/utils.py @@ -4,7 +4,7 @@ # Constants for the characterization process -NUM_CORES = 10 # Number of cores to use for parallel synthesis (if applicable) +NUM_CORES = 4 # Number of cores to use for parallel synthesis (if applicable) # List of units to skip during characterization # These units are either empty, unused, or characterized by other scripts @@ -50,7 +50,7 @@ parameters_ranges = { "DATA_TYPE": [1, 2, 4, 8, 16, 32, 64], "BITWIDTH": [1, 2, 4, 8, 16, 32, 64], - "FIFO_DEPTH": [4], + "FIFO_DEPTH": [4, 5, 6, 7, 8, 10, 12, 14, 16], "SIZE": [2], "SELECT_TYPE": [2], "INDEX_TYPE": [2], @@ -126,15 +126,20 @@ def is_clock_or_reset(port_name: str) -> bool: n = port_name.strip() return n in ("clk", "clock", "rst", "reset") or n.startswith(("clk_", "rst_")) - ins = [port.split(":")[0].strip( - ) for port in self.ports if "in" in port and not "data_array" in port] + # Match the mode after the colon, not anywhere in the port string — + # otherwise a port like `outs_ready : in std_logic` matches both "in" + # and "out" via its name. + mode_in = re.compile(r":\s*in\b", re.IGNORECASE) + mode_out = re.compile(r":\s*out\b", re.IGNORECASE) + ins = [port.split(":")[0].strip() + for port in self.ports + if mode_in.search(port) and "data_array" not in port] ins = [p for p in ins if not is_clock_or_reset(p)] - # Add 2d data_array ports to ins ins.extend(add_2d_ports(self.ports, "in")) - outs = [port.split(":")[0].strip( - ) for port in self.ports if "out" in port and not "data_array" in port] + outs = [port.split(":")[0].strip() + for port in self.ports + if mode_out.search(port) and "data_array" not in port] outs = [p for p in outs if not is_clock_or_reset(p)] - # Add 2d data_array ports to outs outs.extend(add_2d_ports(self.ports, "out")) return ins, outs diff --git a/tools/dynamatic/scripts/compile.sh b/tools/dynamatic/scripts/compile.sh index 1ec506f265..8f11ca70c1 100755 --- a/tools/dynamatic/scripts/compile.sh +++ b/tools/dynamatic/scripts/compile.sh @@ -109,7 +109,7 @@ export_cfg() { # ============================================================================ # # Reset output directory -rm -rf "$COMP_DIR" && mkdir -p "$COMP_DIR" +rm -rf "$OUTPUT_DIR" && mkdir -p "$COMP_DIR" cp "$F_C_SOURCE" "$F_C_REWRITTEN" exit_on_fail "Failed to copy C source into $COMP_DIR" "Copied C source" diff --git a/tools/export-dot/export-dot.cpp b/tools/export-dot/export-dot.cpp index 86f7cfb176..949e53c597 100644 --- a/tools/export-dot/export-dot.cpp +++ b/tools/export-dot/export-dot.cpp @@ -253,7 +253,10 @@ static StringRef getNodeColor(Operation *op) { .Case( [&](auto) { return "lavender"; }) .Case([&](auto) { return "cyan"; }) - .Case([&](auto) { return "palegreen"; }) + .Case( + [&](handshake::BufferOp bufferOp) -> StringRef { + return bufferOp.isBypassDV() ? "palegreen" : "mediumseagreen"; + }) .Case([&](auto) { return "gold"; }) .Case( [&](auto) { return "gainsboro"; }) diff --git a/tools/integration/TEST_SUITE.cpp b/tools/integration/TEST_SUITE.cpp index bcc4b49c81..9cdf9593e0 100644 --- a/tools/integration/TEST_SUITE.cpp +++ b/tools/integration/TEST_SUITE.cpp @@ -225,8 +225,9 @@ TEST_P(SpecFixture, spec) { .useSharing = false, .useSpeculation = true, .milpSolver = "gurobi", - .bufferAlgorithm = "fpga20", - .clockPeriod = 7, + .bufferAlgorithm = "fpl22", + .clockPeriod = 20, + .simTimeoutNs = 500000, .simTime = -1 // clang-format on }; diff --git a/tools/integration/util.cpp b/tools/integration/util.cpp index 1a0853ede4..958afee82d 100644 --- a/tools/integration/util.cpp +++ b/tools/integration/util.cpp @@ -54,17 +54,21 @@ int runIntegrationTest(IntegrationTestData &config) { scriptFile << "verify-invariants" << std::endl; } + std::string timeout; + if (config.simTimeoutNs > 0) + timeout = " --timeout " + std::to_string(config.simTimeoutNs); + // Verify Verilog works correctly if (config.testVerilog) { scriptFile << "write-hdl --hdl verilog" << std::endl - << "simulate" << std::endl; + << "simulate" << timeout << std::endl; } // Verify VHDL works correctly if (config.testVHDL) { // By default, the report containing the simulation time is re-written // during the second simulation (i.e., the VHDL simulation). scriptFile << "write-hdl --hdl vhdl" << std::endl - << "simulate" << std::endl; + << "simulate" << timeout << std::endl; } scriptFile << "exit" << std::endl; diff --git a/tools/integration/util.h b/tools/integration/util.h index f8fecb0826..c99caf6915 100644 --- a/tools/integration/util.h +++ b/tools/integration/util.h @@ -39,6 +39,8 @@ struct IntegrationTestData { std::string milpSolver = "gurobi"; std::string bufferAlgorithm = "fpga20"; unsigned clockPeriod = 5; + // Hard cap on simulation length in nanoseconds. 0 = no timeout. + unsigned simTimeoutNs = 0; // Results int simTime; From 826db66e8d0e6d1efebb8e6d1ce355450d61f54a Mon Sep 17 00:00:00 2001 From: Emmet Murphy Date: Tue, 9 Jun 2026 10:49:35 +0200 Subject: [PATCH 3/9] sweep worked --- data/spec-timing.json | 4413 ++++++++++++----- include/dynamatic/Support/MILP.h | 26 +- include/dynamatic/Support/TimingModels.h | 21 +- .../BufferPlacement/FPGA20Buffers.h | 2 + .../Utils/BufferPlacementMILP.h | 6 + include/dynamatic/Transforms/Passes.td | 4 + lib/Support/TimingModels.cpp | 111 +- .../BufferPlacement/FPGA20Buffers.cpp | 163 + .../BufferPlacement/FPL22Buffers.cpp | 62 +- .../BufferPlacement/HandshakePlaceBuffers.cpp | 23 +- .../Utils/BufferPlacementMILP.cpp | 41 + .../report_parser.py | 54 +- .../unit_characterization.py | 17 +- .../synth-characterization-spec/utils.py | 54 +- tools/dynamatic/scripts/compile.sh | 2 +- tools/integration/TEST_SUITE.cpp | 2 +- 16 files changed, 3640 insertions(+), 1361 deletions(-) diff --git a/data/spec-timing.json b/data/spec-timing.json index 88891dd4ec..28c147d91b 100644 --- a/data/spec-timing.json +++ b/data/spec-timing.json @@ -1,6 +1,6 @@ { "handshake.speculator": { - "delays": [ + "pin2pin": [ { "from": { "port": "ins", @@ -13,45 +13,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.307 + "delay": 2.338 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.343 + "delay": 2.338 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.343 + "delay": 2.338 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.699 + "delay": 2.338 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 3.114 + "delay": 2.622 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 3.114 + "delay": 3.216 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.327 + "delay": 3.216 } ] }, @@ -67,45 +74,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.161 + "delay": 1.79 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.214 + "delay": 1.79 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.432 + "delay": 1.79 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.661 + "delay": 1.918 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.935 + "delay": 2.297 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.935 + "delay": 2.531 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.269 + "delay": 2.609 } ] }, @@ -121,45 +135,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.38 + "delay": 1.688 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.38 + "delay": 1.688 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.38 + "delay": 2.307 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 3.109 + "delay": 2.858 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 3.696 + "delay": 2.961 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 4.26 + "delay": 4.168 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 4.523 + "delay": 4.168 } ] }, @@ -175,45 +196,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 1.686 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 1.968 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.515 + "delay": 2.199 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.82 + "delay": 2.497 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 3.375 + "delay": 2.747 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 3.375 + "delay": 3.301 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.436 + "delay": 3.301 } ] }, @@ -229,45 +257,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.397 + "delay": 1.847 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.397 + "delay": 1.97 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.397 + "delay": 1.996 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 3.0 + "delay": 2.289 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 3.136 + "delay": 2.289 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 3.243 + "delay": 3.152 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.577 + "delay": 3.152 } ] }, @@ -283,45 +318,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.218 + "delay": 2.413 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.218 + "delay": 2.413 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.485 + "delay": 2.413 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.588 + "delay": 2.413 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.896 + "delay": 2.417 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.935 + "delay": 2.704 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.339 + "delay": 2.704 } ] }, @@ -337,45 +379,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.788 + "delay": 1.117 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.788 + "delay": 1.407 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 1.952 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.551 + "delay": 1.952 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.701 + "delay": 2.604 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.997 + "delay": 2.73 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.081 + "delay": 2.908 } ] }, @@ -391,45 +440,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.303 + "delay": 2.377 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.343 + "delay": 2.377 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.527 + "delay": 2.377 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.527 + "delay": 2.377 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.527 + "delay": 2.377 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.527 + "delay": 2.377 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.527 + "delay": 2.377 } ] }, @@ -445,45 +501,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.161 + "delay": 1.861 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.214 + "delay": 1.906 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.318 + "delay": 2.231 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.318 + "delay": 2.231 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.318 + "delay": 2.231 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.318 + "delay": 2.231 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.318 + "delay": 2.231 } ] }, @@ -499,45 +562,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.38 + "delay": 2.046 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.38 + "delay": 2.046 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.77 + "delay": 2.307 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.77 + "delay": 2.357 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.978 + "delay": 2.514 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 3.178 + "delay": 3.418 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.855 + "delay": 3.418 } ] }, @@ -553,45 +623,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.683 + "delay": 2.044 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.683 + "delay": 2.166 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.696 + "delay": 2.199 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.696 + "delay": 2.199 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.696 + "delay": 2.299 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.696 + "delay": 2.551 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.696 + "delay": 2.603 } ] }, @@ -607,45 +684,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.911 + "delay": 1.633 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.911 + "delay": 1.633 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.355 + "delay": 2.25 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.355 + "delay": 2.25 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.421 + "delay": 2.25 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.421 + "delay": 2.25 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.421 + "delay": 2.25 } ] }, @@ -661,45 +745,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.799 + "delay": 2.205 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.799 + "delay": 2.205 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.799 + "delay": 2.205 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.799 + "delay": 2.205 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.799 + "delay": 2.205 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.799 + "delay": 2.403 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.799 + "delay": 2.403 } ] }, @@ -715,45 +806,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.898 + "delay": 1.844 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.898 + "delay": 1.844 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.335 + "delay": 2.117 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.335 + "delay": 2.117 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.335 + "delay": 2.117 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.335 + "delay": 2.123 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.335 + "delay": 2.123 } ] }, @@ -769,45 +867,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.278 + "delay": 2.451 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.278 + "delay": 2.451 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.28 + "delay": 2.451 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.28 + "delay": 2.451 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.28 + "delay": 2.451 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.28 + "delay": 2.451 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.28 + "delay": 2.451 } ] }, @@ -823,45 +928,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.788 + "delay": 1.117 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.788 + "delay": 1.407 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.196 + "delay": 1.54 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.196 + "delay": 1.54 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.196 + "delay": 1.54 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.196 + "delay": 1.97 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.196 + "delay": 1.97 } ] }, @@ -877,45 +989,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.226 + "delay": 2.374 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.23 + "delay": 2.374 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.525 + "delay": 2.374 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.525 + "delay": 2.374 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.525 + "delay": 2.374 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.525 + "delay": 2.374 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.525 + "delay": 2.374 } ] }, @@ -931,45 +1050,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.135 + "delay": 1.877 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.135 + "delay": 1.906 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.316 + "delay": 2.231 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.316 + "delay": 2.231 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.316 + "delay": 2.231 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.316 + "delay": 2.231 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.316 + "delay": 2.231 } ] }, @@ -985,45 +1111,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.304 + "delay": 2.043 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.455 + "delay": 2.043 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.455 + "delay": 2.185 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.461 + "delay": 2.304 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.735 + "delay": 2.514 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 3.178 + "delay": 3.009 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.855 + "delay": 3.009 } ] }, @@ -1039,45 +1172,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.683 + "delay": 2.041 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.683 + "delay": 2.166 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.683 + "delay": 2.166 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.683 + "delay": 2.166 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.683 + "delay": 2.299 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.683 + "delay": 2.299 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.683 + "delay": 2.398 } ] }, @@ -1093,45 +1233,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.911 + "delay": 1.63 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.911 + "delay": 1.63 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.227 + "delay": 2.047 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.227 + "delay": 2.047 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.229 + "delay": 2.047 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.229 + "delay": 2.047 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.334 + "delay": 2.047 } ] }, @@ -1147,45 +1294,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.799 + "delay": 2.202 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.799 + "delay": 2.202 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.799 + "delay": 2.202 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.799 + "delay": 2.202 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.799 + "delay": 2.202 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.799 + "delay": 2.202 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.799 + "delay": 2.202 } ] }, @@ -1201,45 +1355,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.894 + "delay": 1.841 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.894 + "delay": 1.841 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.206 + "delay": 1.913 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.206 + "delay": 1.913 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.206 + "delay": 1.913 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.206 + "delay": 1.968 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.206 + "delay": 1.968 } ] }, @@ -1255,45 +1416,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.278 + "delay": 2.448 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.278 + "delay": 2.448 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.278 + "delay": 2.448 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.278 + "delay": 2.448 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.278 + "delay": 2.448 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.278 + "delay": 2.448 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.278 + "delay": 2.448 } ] }, @@ -1309,45 +1477,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.013 + "delay": 1.661 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.013 + "delay": 1.661 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.013 + "delay": 1.71 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.077 + "delay": 1.71 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.307 + "delay": 2.002 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.307 + "delay": 2.002 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.307 + "delay": 2.285 } ] }, @@ -1363,45 +1538,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.002 + "delay": 1.706 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.002 + "delay": 1.706 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.291 + "delay": 2.199 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.291 + "delay": 2.199 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.316 + "delay": 2.199 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.316 + "delay": 2.199 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.316 + "delay": 2.199 } ] }, @@ -1417,45 +1599,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.266 + "delay": 1.117 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.266 + "delay": 1.117 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.266 + "delay": 1.121 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.266 + "delay": 1.121 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.625 + "delay": 1.121 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.625 + "delay": 1.276 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.731 + "delay": 1.276 } ] }, @@ -1471,45 +1660,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.746 + "delay": 1.117 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.746 + "delay": 1.117 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.746 + "delay": 1.532 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.746 + "delay": 1.532 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.746 + "delay": 1.532 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.746 + "delay": 1.701 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.746 + "delay": 1.701 } ] }, @@ -1525,45 +1721,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.128 + "delay": 1.125 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.128 + "delay": 1.125 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.128 + "delay": 1.125 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.129 + "delay": 1.125 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.631 + "delay": 1.125 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.631 + "delay": 1.53 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.631 + "delay": 1.53 } ] }, @@ -1579,45 +1782,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.683 + "delay": 1.736 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.82 + "delay": 1.736 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.82 + "delay": 1.736 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.887 + "delay": 1.736 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.887 + "delay": 1.736 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.887 + "delay": 1.736 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.887 + "delay": 1.736 } ] }, @@ -1633,45 +1843,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.013 + "delay": 1.66 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.013 + "delay": 1.66 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.013 + "delay": 1.71 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.077 + "delay": 1.71 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.307 + "delay": 2.002 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.307 + "delay": 2.002 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.307 + "delay": 2.285 } ] }, @@ -1687,45 +1904,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.002 + "delay": 1.706 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.002 + "delay": 1.706 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.291 + "delay": 2.199 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.291 + "delay": 2.199 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.316 + "delay": 2.199 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.316 + "delay": 2.199 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.316 + "delay": 2.199 } ] }, @@ -1741,45 +1965,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.639 + "delay": 1.117 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.724 + "delay": 1.413 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.306 + "delay": 2.185 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.306 + "delay": 2.185 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.306 + "delay": 2.185 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.936 + "delay": 2.707 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.358 + "delay": 2.707 } ] }, @@ -1795,45 +2026,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.606 + "delay": 1.117 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.606 + "delay": 1.117 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.29 + "delay": 2.078 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.29 + "delay": 2.078 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.29 + "delay": 2.078 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.29 + "delay": 2.078 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.327 + "delay": 2.078 } ] }, @@ -1849,45 +2087,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.128 + "delay": 1.125 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.128 + "delay": 1.125 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.129 + "delay": 1.126 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.129 + "delay": 1.126 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.631 + "delay": 1.126 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.631 + "delay": 1.53 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.631 + "delay": 1.53 } ] }, @@ -1903,45 +2148,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.683 + "delay": 1.735 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.816 + "delay": 1.735 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.816 + "delay": 1.735 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.887 + "delay": 1.735 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.887 + "delay": 1.735 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.887 + "delay": 1.735 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.887 + "delay": 1.735 } ] }, @@ -1957,45 +2209,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.701 + "delay": 1.117 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.842 + "delay": 1.482 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.842 + "delay": 1.717 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.842 + "delay": 1.717 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.118 + "delay": 1.717 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.118 + "delay": 2.135 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.118 + "delay": 2.135 } ] }, @@ -2011,45 +2270,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.596 + "delay": 1.392 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.614 + "delay": 1.485 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.921 + "delay": 1.604 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.921 + "delay": 1.61 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.921 + "delay": 1.61 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.921 + "delay": 1.61 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.921 + "delay": 1.61 } ] }, @@ -2065,45 +2331,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.521 + "delay": 1.62 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.717 + "delay": 1.62 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.74 + "delay": 1.62 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.911 + "delay": 1.799 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.241 + "delay": 1.945 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.936 + "delay": 2.711 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.074 + "delay": 2.711 } ] }, @@ -2119,45 +2392,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.606 + "delay": 1.622 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.743 + "delay": 1.622 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.743 + "delay": 1.622 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.743 + "delay": 1.622 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.743 + "delay": 1.622 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.966 + "delay": 1.622 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.327 + "delay": 1.622 } ] }, @@ -2173,45 +2453,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.123 + "delay": 1.117 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.125 + "delay": 1.117 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.128 + "delay": 1.125 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.128 + "delay": 1.125 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.625 + "delay": 1.125 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.625 + "delay": 1.276 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.731 + "delay": 1.276 } ] }, @@ -2227,45 +2514,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.633 + "delay": 1.621 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.71 + "delay": 1.621 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.715 + "delay": 1.621 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.715 + "delay": 1.626 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.715 + "delay": 1.769 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.8 + "delay": 1.769 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.8 + "delay": 1.769 } ] }, @@ -2281,45 +2575,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.514 + "delay": 1.427 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.514 + "delay": 1.427 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.514 + "delay": 1.427 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.514 + "delay": 1.427 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.514 + "delay": 1.427 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.69 + "delay": 1.427 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.69 + "delay": 1.427 } ] }, @@ -2335,45 +2636,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.627 + "delay": 1.66 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.627 + "delay": 1.66 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.813 + "delay": 1.717 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.813 + "delay": 1.717 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.118 + "delay": 1.717 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.118 + "delay": 2.135 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.118 + "delay": 2.135 } ] }, @@ -2389,45 +2697,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.538 + "delay": 1.735 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.538 + "delay": 1.735 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.571 + "delay": 1.735 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.571 + "delay": 1.735 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.571 + "delay": 1.735 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.571 + "delay": 1.735 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.607 + "delay": 1.735 } ] }, @@ -2443,45 +2758,52 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.724 + "delay": 2.202 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.724 + "delay": 2.202 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.178 + "delay": 2.202 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.178 + "delay": 2.202 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 3.139 + "delay": 2.202 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 3.139 + "delay": 2.727 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.255 + "delay": 2.727 } ] }, @@ -2497,1081 +2819,1306 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.611 + "delay": 2.069 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.611 + "delay": 2.069 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.335 + "delay": 2.069 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.335 + "delay": 2.069 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.898 + "delay": 2.069 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.898 + "delay": 2.873 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.92 + "delay": 2.873 } ] } - ] - }, - "handshake.spec_save_commit": { - "delays": [ + ], + "pin2reg": [ { - "from": { - "port": "ins", - "signal": "data" - }, - "to": { - "port": "outs", - "signal": "data" - }, + "port": "ins", + "signal": "data", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 4.052 + "delay": 1.832 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 4.052 + "delay": 1.832 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 4.052 + "delay": 1.832 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 4.052 + "delay": 1.855 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 4.052 + "delay": 1.932 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 4.052 + "delay": 2.478 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 4.052 + "delay": 2.478 } ] }, { - "from": { - "port": "ins", - "signal": "data" - }, - "to": { - "port": "outs", - "signal": "valid" - }, + "port": "ins", + "signal": "valid", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.949 + "delay": 1.882 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.949 + "delay": 1.882 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.949 + "delay": 1.932 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.949 + "delay": 1.932 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.949 + "delay": 1.932 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.949 + "delay": 1.932 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.949 + "delay": 1.932 } ] }, { - "from": { - "port": "ins", - "signal": "data" - }, - "to": { - "port": "ins", - "signal": "ready" - }, + "port": "trigger", + "signal": "valid", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 3.327 + "delay": 1.879 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 3.327 + "delay": 1.879 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 3.327 + "delay": 1.879 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 3.327 + "delay": 1.879 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 3.327 + "delay": 1.879 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 3.327 + "delay": 1.879 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.327 + "delay": 1.913 } ] }, { - "from": { - "port": "ins", - "signal": "valid" - }, - "to": { - "port": "outs", - "signal": "data" - }, + "port": "outs", + "signal": "ready", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 3.694 + "delay": 1.724 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 3.694 + "delay": 1.724 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 3.694 + "delay": 1.773 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 3.694 + "delay": 1.773 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 3.694 + "delay": 1.773 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 3.694 + "delay": 1.773 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.694 + "delay": 1.984 } ] }, { - "from": { - "port": "ins", - "signal": "valid" - }, - "to": { - "port": "outs", - "signal": "valid" - }, + "port": "ctrl_issue", + "signal": "ready", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.434 + "delay": 1.724 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.434 + "delay": 1.724 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.434 + "delay": 1.773 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.434 + "delay": 1.773 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.434 + "delay": 1.773 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.434 + "delay": 1.773 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.434 + "delay": 1.984 } ] }, { - "from": { - "port": "ins", - "signal": "valid" - }, - "to": { - "port": "ins", - "signal": "ready" - }, + "port": "ctrl_history", + "signal": "ready", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.32 + "delay": 0.997 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.32 + "delay": 0.997 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.32 + "delay": 1.243 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.32 + "delay": 1.243 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.32 + "delay": 1.243 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.32 + "delay": 1.397 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.32 + "delay": 1.397 } ] }, { - "from": { - "port": "outs", - "signal": "ready" - }, - "to": { - "port": "ins", - "signal": "ready" - }, + "port": "ctrl_commit", + "signal": "ready", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.631 + "delay": 1.09 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.631 + "delay": 1.09 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.631 + "delay": 1.353 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.631 + "delay": 1.353 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.631 + "delay": 1.353 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.631 + "delay": 1.397 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.631 + "delay": 1.397 } ] - }, + } + ], + "reg2pin": [ { - "from": { - "port": "ins", - "signal": "valid" - }, - "to": { - "port": "ctrl_issue", - "signal": "ready" - }, + "port": "ins", + "signal": "ready", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.463 + "delay": 3.029 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.463 + "delay": 3.029 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.463 + "delay": 3.232 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.463 + "delay": 3.232 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.463 + "delay": 3.688 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.463 + "delay": 4.123 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.463 + "delay": 4.123 } ] }, { - "from": { - "port": "ins", - "signal": "valid" - }, - "to": { - "port": "ctrl_history", - "signal": "ready" - }, + "port": "trigger", + "signal": "ready", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.555 + "delay": 2.582 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.555 + "delay": 2.582 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.555 + "delay": 2.611 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.555 + "delay": 2.706 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.555 + "delay": 3.437 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.555 + "delay": 3.539 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.555 + "delay": 3.634 } ] }, { - "from": { - "port": "ctrl_issue", - "signal": "data" - }, - "to": { - "port": "ctrl_issue", - "signal": "ready" - }, + "port": "outs", + "signal": "data", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.048 + "delay": 2.382 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.048 + "delay": 2.382 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.048 + "delay": 3.205 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.048 + "delay": 3.646 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.048 + "delay": 4.101 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.048 + "delay": 5.176 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.048 + "delay": 5.176 } ] }, { - "from": { - "port": "ctrl_issue", - "signal": "data" - }, - "to": { - "port": "ctrl_history", - "signal": "ready" - }, + "port": "outs", + "signal": "valid", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.14 + "delay": 2.38 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.14 + "delay": 2.742 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.14 + "delay": 3.098 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.14 + "delay": 3.286 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.14 + "delay": 3.887 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.14 + "delay": 4.309 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.14 + "delay": 4.309 } ] }, { - "from": { - "port": "ctrl_issue", - "signal": "data" - }, - "to": { - "port": "outs", - "signal": "data" - }, + "port": "ctrl_issue", + "signal": "data", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 1.783 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 1.783 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 3.136 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 3.136 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 3.136 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 3.735 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 3.735 } ] }, { - "from": { - "port": "ctrl_issue", - "signal": "data" - }, - "to": { - "port": "outs", - "signal": "valid" - }, + "port": "ctrl_issue", + "signal": "valid", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.019 + "delay": 2.541 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.019 + "delay": 2.744 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.019 + "delay": 2.93 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.019 + "delay": 3.078 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.019 + "delay": 3.422 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.019 + "delay": 4.16 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.019 + "delay": 4.16 } ] }, { - "from": { - "port": "ctrl_issue", - "signal": "data" - }, - "to": { - "port": "ins", - "signal": "ready" - }, + "port": "ctrl_history", + "signal": "data", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.994 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.994 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 3.003 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 3.003 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 3.003 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 3.881 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 3.881 } ] }, { - "from": { - "port": "ctrl_issue", - "signal": "valid" - }, - "to": { - "port": "ctrl_issue", - "signal": "ready" - }, + "port": "ctrl_history", + "signal": "valid", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.31 + "delay": 3.103 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.31 + "delay": 3.103 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.31 + "delay": 3.103 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.31 + "delay": 3.103 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.31 + "delay": 3.483 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.31 + "delay": 3.712 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.31 + "delay": 3.712 } ] }, { - "from": { - "port": "ctrl_issue", - "signal": "valid" - }, - "to": { - "port": "ctrl_history", - "signal": "ready" - }, + "port": "ctrl_commit", + "signal": "data", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 1.533 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 1.533 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 1.533 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 1.533 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 1.533 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 1.533 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 1.533 } ] }, { - "from": { - "port": "ctrl_issue", - "signal": "valid" - }, - "to": { - "port": "outs", - "signal": "data" - }, + "port": "ctrl_commit", + "signal": "valid", "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 1.83 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 2.184 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 2.886 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 2.886 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 3.67 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 3.727 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 3.922 } ] - }, + } + ] + }, + "handshake.spec_save_commit": { + "pin2pin": [ { "from": { - "port": "ctrl_issue", - "signal": "valid" + "port": "ins", + "signal": "data" }, "to": { "port": "outs", - "signal": "valid" + "signal": "data" }, "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 1.259 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 1.614 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 1.597 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 1.31 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 1.117 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 1.31 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 1.117 } ] }, { "from": { - "port": "ctrl_issue", + "port": "ins", "signal": "valid" }, "to": { - "port": "ins", + "port": "ctrl_issue", "signal": "ready" }, "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 2.045 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 2.294 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 2.036 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 2.349 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 2.082 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 2.566 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.875 } ] }, { "from": { - "port": "ctrl_history", + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "ctrl_history", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 2.224 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.092 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 2.33 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.813 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 1.586 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 2.036 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 1.723 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "outs", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.638 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.113 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 2.185 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 2.558 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 2.667 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 3.36 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 3.348 + } + ] + }, + { + "from": { + "port": "ins", + "signal": "valid" + }, + "to": { + "port": "outs", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 2.172 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.3 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 1.7 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 2.361 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 1.57 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 2.624 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 1.514 + } + ] + }, + { + "from": { + "port": "ctrl_issue", "signal": "data" }, "to": { @@ -3581,51 +4128,58 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.048 + "delay": 2.045 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.048 + "delay": 2.294 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.048 + "delay": 2.036 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.048 + "delay": 2.349 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.048 + "delay": 2.277 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.048 + "delay": 2.41 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.048 + "delay": 2.219 } ] }, { "from": { - "port": "ctrl_history", + "port": "ctrl_issue", "signal": "data" }, "to": { @@ -3635,51 +4189,58 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.14 + "delay": 1.876 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.14 + "delay": 1.982 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.14 + "delay": 2.289 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.14 + "delay": 1.875 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.14 + "delay": 2.219 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.14 + "delay": 1.975 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.14 + "delay": 2.232 } ] }, { "from": { - "port": "ctrl_history", + "port": "ctrl_issue", "signal": "data" }, "to": { @@ -3689,51 +4250,58 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 1.584 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 2.296 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 2.185 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 2.518 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 2.668 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 3.098 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 3.436 } ] }, { "from": { - "port": "ctrl_history", + "port": "ctrl_issue", "signal": "data" }, "to": { @@ -3743,51 +4311,58 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.019 + "delay": 2.172 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.019 + "delay": 2.3 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.019 + "delay": 2.169 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.019 + "delay": 2.361 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.019 + "delay": 1.896 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.019 + "delay": 2.361 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.019 + "delay": 1.995 } ] }, { "from": { - "port": "ctrl_history", + "port": "ctrl_issue", "signal": "data" }, "to": { @@ -3797,51 +4372,58 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.56 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.702 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.546 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.322 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.626 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.487 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.613 } ] }, { "from": { - "port": "ctrl_history", + "port": "ctrl_issue", "signal": "valid" }, "to": { @@ -3851,51 +4433,58 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.31 + "delay": 2.045 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.31 + "delay": 2.294 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.31 + "delay": 2.036 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.31 + "delay": 2.349 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.31 + "delay": 2.277 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.31 + "delay": 2.566 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.31 + "delay": 2.032 } ] }, { "from": { - "port": "ctrl_history", + "port": "ctrl_issue", "signal": "valid" }, "to": { @@ -3905,51 +4494,58 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 1.876 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 1.982 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 2.289 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 1.875 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 1.804 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 2.036 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.402 + "delay": 1.973 } ] }, { "from": { - "port": "ctrl_history", + "port": "ctrl_issue", "signal": "valid" }, "to": { @@ -3959,51 +4555,58 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 1.713 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 2.296 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 2.185 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 2.518 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 2.383 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 3.36 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 3.638 + "delay": 3.435 } ] }, { "from": { - "port": "ctrl_history", + "port": "ctrl_issue", "signal": "valid" }, "to": { @@ -4013,51 +4616,58 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 2.172 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 2.3 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 2.169 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 2.361 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 1.485 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 2.624 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 2.281 + "delay": 1.995 } ] }, { "from": { - "port": "ctrl_history", + "port": "ctrl_issue", "signal": "valid" }, "to": { @@ -4067,52 +4677,59 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.56 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.702 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.546 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.322 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.117 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.487 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.677 + "delay": 1.613 } ] }, { "from": { - "port": "outs", - "signal": "ready" + "port": "ctrl_history", + "signal": "data" }, "to": { "port": "ctrl_issue", @@ -4121,52 +4738,59 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.415 + "delay": 1.661 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.415 + "delay": 2.094 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.415 + "delay": 1.997 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.415 + "delay": 1.617 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.415 + "delay": 2.186 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.415 + "delay": 2.303 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.415 + "delay": 2.463 } ] }, { "from": { - "port": "outs", - "signal": "ready" + "port": "ctrl_history", + "signal": "data" }, "to": { "port": "ctrl_history", @@ -4175,45 +4799,1326 @@ "samples": [ { "params": { - "BITWIDTH": 1 + "BITWIDTH": 1, + "FIFO_DEPTH": 4 }, - "delay": 1.126 + "delay": 2.113 }, { "params": { - "BITWIDTH": 2 + "BITWIDTH": 2, + "FIFO_DEPTH": 4 }, - "delay": 1.126 + "delay": 2.092 }, { "params": { - "BITWIDTH": 4 + "BITWIDTH": 4, + "FIFO_DEPTH": 4 }, - "delay": 1.126 + "delay": 2.289 }, { "params": { - "BITWIDTH": 8 + "BITWIDTH": 8, + "FIFO_DEPTH": 4 }, - "delay": 1.126 + "delay": 1.875 }, { "params": { - "BITWIDTH": 16 + "BITWIDTH": 16, + "FIFO_DEPTH": 4 }, - "delay": 1.126 + "delay": 1.504 }, { "params": { - "BITWIDTH": 32 + "BITWIDTH": 32, + "FIFO_DEPTH": 4 }, - "delay": 1.126 + "delay": 1.975 }, { "params": { - "BITWIDTH": 64 + "BITWIDTH": 64, + "FIFO_DEPTH": 4 }, - "delay": 1.126 + "delay": 2.404 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "data" + }, + "to": { + "port": "outs", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.316 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.296 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 2.137 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 2.518 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 2.711 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 3.098 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 3.348 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "data" + }, + "to": { + "port": "outs", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.704 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.1 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 2.169 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.615 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 1.896 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 2.361 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 1.995 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "data" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.56 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 1.702 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 1.546 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.322 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 2.117 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 1.487 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 1.117 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "valid" + }, + "to": { + "port": "ctrl_issue", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.819 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.094 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 1.997 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.754 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 2.183 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 2.303 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 2.463 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "valid" + }, + "to": { + "port": "ctrl_history", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 2.113 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.092 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 2.289 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.875 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 1.504 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 1.975 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 2.404 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "valid" + }, + "to": { + "port": "outs", + "signal": "data" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.713 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.296 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 2.137 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 2.518 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 2.711 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 3.098 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 3.348 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "valid" + }, + "to": { + "port": "outs", + "signal": "valid" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 2.102 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.1 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 2.169 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.758 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 1.896 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 2.361 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 1.995 + } + ] + }, + { + "from": { + "port": "ctrl_history", + "signal": "valid" + }, + "to": { + "port": "ins", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.56 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 1.702 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 1.546 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.322 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 2.117 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 1.487 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 1.117 + } + ] + }, + { + "from": { + "port": "outs", + "signal": "ready" + }, + "to": { + "port": "ctrl_issue", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.117 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 1.117 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 1.117 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.117 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 2.277 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 1.633 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 2.032 + } + ] + }, + { + "from": { + "port": "outs", + "signal": "ready" + }, + "to": { + "port": "ctrl_history", + "signal": "ready" + }, + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.639 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 1.52 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 1.737 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.416 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 1.805 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 1.614 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 1.973 + } + ] + } + ], + "pin2reg": [ + { + "port": "ins", + "signal": "data", + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 0.537 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 0.537 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 0.537 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 0.537 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 0.537 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 0.537 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 0.537 + } + ] + }, + { + "port": "ins", + "signal": "valid", + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.676 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 1.55 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 1.597 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.592 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 1.573 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 1.82 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 1.533 + } + ] + }, + { + "port": "ctrl_issue", + "signal": "data", + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.748 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.052 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 1.894 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.744 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 1.992 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 1.942 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 2.106 + } + ] + }, + { + "port": "ctrl_issue", + "signal": "valid", + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.748 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.052 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 1.894 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.744 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 1.769 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 1.942 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 2.051 + } + ] + }, + { + "port": "ctrl_history", + "signal": "data", + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.748 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.052 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 1.894 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.744 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 2.216 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 1.942 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 1.959 + } + ] + }, + { + "port": "ctrl_history", + "signal": "valid", + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.748 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.052 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 1.894 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.744 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 2.216 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 1.942 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 1.959 + } + ] + }, + { + "port": "outs", + "signal": "ready", + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.092 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 1.248 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 1.172 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.167 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 1.769 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 1.184 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 1.618 + } + ] + } + ], + "reg2pin": [ + { + "port": "ctrl_issue", + "signal": "ready", + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 2.276 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.401 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 2.08 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 2.78 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 2.349 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 2.773 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 1.973 + } + ] + }, + { + "port": "ctrl_history", + "signal": "ready", + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 2.509 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.195 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 2.551 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.936 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 1.57 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 2.243 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 1.915 + } + ] + }, + { + "port": "outs", + "signal": "data", + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.998 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.616 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 2.672 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 2.837 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 2.965 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 3.567 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 3.684 + } + ] + }, + { + "port": "outs", + "signal": "valid", + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 2.403 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 2.407 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 1.906 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 2.792 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 1.66 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 2.831 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 2.2 + } + ] + }, + { + "port": "ins", + "signal": "ready", + "samples": [ + { + "params": { + "BITWIDTH": 1, + "FIFO_DEPTH": 4 + }, + "delay": 1.308 + }, + { + "params": { + "BITWIDTH": 2, + "FIFO_DEPTH": 4 + }, + "delay": 1.208 + }, + { + "params": { + "BITWIDTH": 4, + "FIFO_DEPTH": 4 + }, + "delay": 1.257 + }, + { + "params": { + "BITWIDTH": 8, + "FIFO_DEPTH": 4 + }, + "delay": 1.628 + }, + { + "params": { + "BITWIDTH": 16, + "FIFO_DEPTH": 4 + }, + "delay": 1.296 + }, + { + "params": { + "BITWIDTH": 32, + "FIFO_DEPTH": 4 + }, + "delay": 1.316 + }, + { + "params": { + "BITWIDTH": 64, + "FIFO_DEPTH": 4 + }, + "delay": 1.831 } ] } diff --git a/include/dynamatic/Support/MILP.h b/include/dynamatic/Support/MILP.h index 39b376ea17..524c90dba9 100644 --- a/include/dynamatic/Support/MILP.h +++ b/include/dynamatic/Support/MILP.h @@ -158,6 +158,11 @@ class MILP { /// Marks the MILP as initial state. void resetMILPState() { state = State::FAILED_TO_SETUP; } + /// Optional second-pass polish hook. Default is a no-op; subclasses can + /// override to e.g. pin solution variables, change the objective, and + /// re-optimize. Called by `solveMILP` when its `polish` argument is true. + virtual LogicalResult polishArrivalTimes() { return success(); } + /// Determines whether the MILP is in a valid state to be optimized. If this /// returns true, `MILP::optimize` can be called to solve the MILP. /// Conversely, if this returns false then a call to optimize will necessarily @@ -179,6 +184,11 @@ class MILP { /// Gurobi model holding the MILP's state. std::unique_ptr model; + /// Path to a file at which to store the MILP's model and its solution after + /// optimization. Empty disables logging. Available to overrides such as + /// `polishArrivalTimes()` that want to dump a second-pass sol log. + std::string writeTo; + /// Fills in the argument with the desired results extract from the MILP's /// solution. Called by `MILP::getResult` after checking that the underlying /// MILP model was optimized successfully. This cannot fail. @@ -199,11 +209,6 @@ class MILP { /// MILP's state, which changes during the object's lifetime. State state = State::FAILED_TO_SETUP; - /// Path to a file at which to store the MILP's model and its solution after - /// optimization. The model will be stored under `writeTo`_model.lp and the - /// solution under `writeTo`_solution.json. Nothing will be stored if the - /// string is empty. - std::string writeTo; /// Returns a description of the MILP's current state. StringRef getStateMessage() { @@ -226,11 +231,16 @@ class MILP { /// Creates, optimizes, and extract results from an MILP in one go. Fails and /// displays an error message to stderr if any step along the process fails. /// Otherwise succeeds and stores the MILP's results in the first function -/// argument. +/// argument. If `polish` is true, runs `polishArrivalTimes()` between optimize +/// and result extraction (a no-op for MILP classes that don't override it). template -LogicalResult solveMILP(MILPRes &milpResult, Args &&...args) { +LogicalResult solveMILP(MILPRes &milpResult, bool polish, Args &&...args) { MILP milp = MILP(std::forward(args)...); - if (failed(milp.optimize()) || failed(milp.getResult(milpResult))) + if (failed(milp.optimize())) + return failure(); + if (polish && failed(milp.polishArrivalTimes())) + return failure(); + if (failed(milp.getResult(milpResult))) return failure(); return success(); } diff --git a/include/dynamatic/Support/TimingModels.h b/include/dynamatic/Support/TimingModels.h index f7637ee26d..f08738550a 100644 --- a/include/dynamatic/Support/TimingModels.h +++ b/include/dynamatic/Support/TimingModels.h @@ -270,15 +270,9 @@ struct TimingModel { /// delay. LogicalResult getTotalDataDelay(unsigned bitwidth, double &delay) const; - /// Returns the total valid delay (input + internal + output delays). - double getTotalValidDelay() const { - return inputModel.validDelay + validDelay + outputModel.validDelay; - }; + double getTotalValidDelay() const { return validDelay; }; - /// Returns the total ready delay (input + internal + output delays). - double getTotalReadyDelay() const { - return inputModel.readyDelay + readyDelay + outputModel.readyDelay; - }; + double getTotalReadyDelay() const { return readyDelay; }; }; /// Deserializes a JSON value into a TimingModel. See ::llvm::json::Value's @@ -313,9 +307,16 @@ struct SpecTimingEdge { std::vector samples; }; -/// Per-op-name set of characterised port-pair edges. +/// Per-port boundary delay (input pin -> register or register -> output pin). +struct SpecTimingPortDelay { + SpecTimingEdge::Endpoint port; + std::vector samples; +}; + struct SpecTimingModel { - std::vector edges; + std::vector pin2pin; + std::vector pin2reg; + std::vector reg2pin; }; /// Holds the timing models for a set of operations (internally identified by diff --git a/include/dynamatic/Transforms/BufferPlacement/FPGA20Buffers.h b/include/dynamatic/Transforms/BufferPlacement/FPGA20Buffers.h index 201f11043f..58bb248ac4 100644 --- a/include/dynamatic/Transforms/BufferPlacement/FPGA20Buffers.h +++ b/include/dynamatic/Transforms/BufferPlacement/FPGA20Buffers.h @@ -68,6 +68,8 @@ class FPGA20Buffers : public BufferPlacementMILP { /// the system's objective. Called by the constructor in the absence of prior /// failures, after which the MILP is ready to be optimized. void setup(); + + void addSpecUnitDataPathConstraints(Operation *unit); }; } // namespace fpga20 diff --git a/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h b/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h index 2d725b0d67..943b0c0544 100644 --- a/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h +++ b/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h @@ -156,6 +156,12 @@ class BufferPlacementMILP : public MILP { FuncInfo &funcInfo, const TimingDatabase &timingDB, double targetPeriod, llvm::StringRef writeTo = ""); + /// Pins all buffer-decision variables to their currently-solved values, + /// replaces the objective with `min Σ(t_*)`, re-optimises, and rewrites the + /// sol log. Lets the dumped values reflect the true min-feasible arrival on + /// each channel signal instead of being packed to the period bound. + LogicalResult polishArrivalTimes() override; + protected: /// Represents a list of signals that are buffered together by a single /// buffer type, which is denoted by its (potentially null) timing model. diff --git a/include/dynamatic/Transforms/Passes.td b/include/dynamatic/Transforms/Passes.td index 9da4ca4229..14c18189fb 100644 --- a/include/dynamatic/Transforms/Passes.td +++ b/include/dynamatic/Transforms/Passes.td @@ -280,6 +280,10 @@ def HandshakePlaceBuffers : Pass<"handshake-place-buffers"> { "Timeout (in seconds) for the buffer placement MILP (0 for no timeout)">, Option<"dumpMILPModels", "dump-milp-models", "bool", "false", "If true, dump MILP models into a directory named 'buffer-placement'.">, + Option<"polishPaths", "polish-paths", "bool", "false", + "If true, after the throughput-maximising solve, fix buffer decisions and " + "re-solve minimising path arrival times. Lets the dumped sol log show the " + "true min-feasible arrival on each channel signal.">, Option<"blifFiles", "blif-files", "std::string", "", "Path to AND-Inverter Graphs of dataflow components in Berkeley " "Logic Interchange Format (BLIF).">, diff --git a/lib/Support/TimingModels.cpp b/lib/Support/TimingModels.cpp index 20d1ee0a3c..34ec9b2b60 100644 --- a/lib/Support/TimingModels.cpp +++ b/lib/Support/TimingModels.cpp @@ -90,19 +90,7 @@ LogicalResult TimingModel::getTotalDataDelay(unsigned bitwidth, auto unitDelayOrFail = dataDelay.select(bitwidth); if (failed(unitDelayOrFail)) return failure(); - double unitDelay = unitDelayOrFail->get(); - - auto inPortDelayOrFail = inputModel.dataDelay.select(bitwidth); - if (failed(inPortDelayOrFail)) - return failure(); - double inPortDelay = inPortDelayOrFail->get(); - - auto outPortDelayOrFail = outputModel.dataDelay.select(bitwidth); - if (failed(outPortDelayOrFail)) - return failure(); - double outPortDelay = outPortDelayOrFail->get(); - - delay = unitDelay + inPortDelay + outPortDelay; + delay = unitDelayOrFail->get(); return success(); } @@ -328,52 +316,73 @@ LogicalResult TimingDatabase::readSpecTimingFromJSON(std::string &jsonpath, const ljson::Object *unitObj = unitEntry.second.getAsObject(); if (!unitObj) continue; - const ljson::Array *delaysArr = unitObj->getArray("delays"); - if (!delaysArr) - continue; - SpecTimingModel model; - for (const ljson::Value &edgeVal : *delaysArr) { - const ljson::Object *edgeObj = edgeVal.getAsObject(); - if (!edgeObj) - continue; - - SpecTimingEdge edge; - for (const auto &which : {std::make_pair("from", &edge.from), - std::make_pair("to", &edge.to)}) { - const ljson::Object *endObj = edgeObj->getObject(which.first); - if (!endObj) + + auto parseSamples = [](const ljson::Array *samplesArr, + std::vector &out) { + if (!samplesArr) + return; + for (const ljson::Value &sampleVal : *samplesArr) { + const ljson::Object *sampleObj = sampleVal.getAsObject(); + if (!sampleObj) + continue; + SpecTimingEdge::Sample sample; + if (auto d = sampleObj->getNumber("delay")) + sample.delay = *d; + else continue; - std::optional p = endObj->getString("port"); - std::optional s = endObj->getString("signal"); - if (p) - which.second->port = p->str(); - if (s) - which.second->signal = s->str(); + if (const ljson::Object *paramObj = sampleObj->getObject("params")) { + for (const auto ¶mEntry : *paramObj) { + if (auto pv = paramEntry.second.getAsInteger()) + sample.params[paramEntry.first] = *pv; + } + } + out.push_back(std::move(sample)); } + }; - const ljson::Array *samplesArr = edgeObj->getArray("samples"); - if (samplesArr) { - for (const ljson::Value &sampleVal : *samplesArr) { - const ljson::Object *sampleObj = sampleVal.getAsObject(); - if (!sampleObj) - continue; - SpecTimingEdge::Sample sample; - if (auto d = sampleObj->getNumber("delay")) - sample.delay = *d; - else + if (const ljson::Array *pin2pinArr = unitObj->getArray("pin2pin")) { + for (const ljson::Value &edgeVal : *pin2pinArr) { + const ljson::Object *edgeObj = edgeVal.getAsObject(); + if (!edgeObj) + continue; + SpecTimingEdge edge; + for (const auto &which : {std::make_pair("from", &edge.from), + std::make_pair("to", &edge.to)}) { + const ljson::Object *endObj = edgeObj->getObject(which.first); + if (!endObj) continue; - if (const ljson::Object *paramObj = sampleObj->getObject("params")) { - for (const auto ¶mEntry : *paramObj) { - if (auto pv = paramEntry.second.getAsInteger()) - sample.params[paramEntry.first] = *pv; - } - } - edge.samples.push_back(std::move(sample)); + if (auto p = endObj->getString("port")) + which.second->port = p->str(); + if (auto s = endObj->getString("signal")) + which.second->signal = s->str(); } + parseSamples(edgeObj->getArray("samples"), edge.samples); + model.pin2pin.push_back(std::move(edge)); } - model.edges.push_back(std::move(edge)); } + + auto parsePortDelayArr = [&](const char *key, + std::vector &out) { + const ljson::Array *arr = unitObj->getArray(key); + if (!arr) + return; + for (const ljson::Value &v : *arr) { + const ljson::Object *o = v.getAsObject(); + if (!o) + continue; + SpecTimingPortDelay pd; + if (auto p = o->getString("port")) + pd.port.port = p->str(); + if (auto s = o->getString("signal")) + pd.port.signal = s->str(); + parseSamples(o->getArray("samples"), pd.samples); + out.push_back(std::move(pd)); + } + }; + parsePortDelayArr("pin2reg", model.pin2reg); + parsePortDelayArr("reg2pin", model.reg2pin); + timingDB.specModels[unitKey] = std::move(model); } return success(); diff --git a/lib/Transforms/BufferPlacement/FPGA20Buffers.cpp b/lib/Transforms/BufferPlacement/FPGA20Buffers.cpp index 8dadc3d5b4..975e2935be 100644 --- a/lib/Transforms/BufferPlacement/FPGA20Buffers.cpp +++ b/lib/Transforms/BufferPlacement/FPGA20Buffers.cpp @@ -17,6 +17,8 @@ #include "dynamatic/Support/TimingModels.h" #include "dynamatic/Transforms/BufferPlacement/Utils/BufferingSupport.h" #include "mlir/IR/Value.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/TypeSwitch.h" // NOTE: The code wrapped in LLVM_DEBUG(...) is executed when // - Dynamatic is built in debug mode @@ -38,6 +40,163 @@ FPGA20Buffers::FPGA20Buffers(CPSolver::SolverKind solverKind, int timeout, setup(); } +void FPGA20Buffers::addSpecUnitDataPathConstraints(Operation *unit) { + const SpecTimingModel *specModel = timingDB.getSpecModel(unit); + if (!specModel) { + unit->emitError() << "addSpecUnitDataPathConstraints: no spec timing model " + << "loaded for op '" << unit->getName().getStringRef() + << "'"; + return; + } + + auto namedIO = dyn_cast(unit); + if (!namedIO) { + unit->emitError() << "addSpecUnitDataPathConstraints: op does not " + << "implement NamedIOInterface"; + return; + } + + llvm::StringMap portToValue; + for (unsigned i = 0, e = unit->getNumOperands(); i < e; ++i) + portToValue[namedIO.getOperandName(i)] = unit->getOperand(i); + for (unsigned i = 0, e = unit->getNumResults(); i < e; ++i) + portToValue[namedIO.getResultName(i)] = unit->getResult(i); + + Value bitwidthChannel = + llvm::TypeSwitch(unit) + .Case( + [](handshake::SpeculatorOp op) { return op.getDataIn(); }) + .Case( + [](handshake::SpecSaveCommitOp op) { return op.getDataIn(); }) + .Default([&](Operation *op) { + op->emitError() << "addSpecUnitDataPathConstraints called on op " + << "type with no bitwidth accessor registered"; + return Value(); + }); + if (!bitwidthChannel) + return; + + llvm::StringMap currentParams; + if (auto chTy = dyn_cast(bitwidthChannel.getType())) + currentParams["BITWIDTH"] = chTy.getDataBitWidth(); + else + currentParams["BITWIDTH"] = 0; + + auto pickClosest = + [&](const std::vector &samples) -> double { + assert(!samples.empty() && "spec timing edge has no samples"); + const SpecTimingEdge::Sample *best = &samples.front(); + int64_t bestDist = std::numeric_limits::max(); + for (const auto &s : samples) { + int64_t dist = 0; + for (const auto &targetKV : currentParams) { + auto it = s.params.find(targetKV.first()); + if (it == s.params.end()) + continue; + int64_t d = it->second - targetKV.second; + dist += d * d; + } + if (dist < bestDist) { + bestDist = dist; + best = &s; + } + } + return best->delay; + }; + + StringRef unitName = getUniqueName(unit); + unsigned idx = 0; + for (const SpecTimingEdge &edge : specModel->pin2pin) { + if (edge.from.signal != "data" || edge.to.signal != "data") + continue; + auto fromIt = portToValue.find(edge.from.port); + auto toIt = portToValue.find(edge.to.port); + if (fromIt == portToValue.end()) { + unit->emitError() << "spec timing edge references unknown port '" + << edge.from.port << "'"; + return; + } + if (toIt == portToValue.end()) { + unit->emitError() << "spec timing edge references unknown port '" + << edge.to.port << "'"; + return; + } + Value fromVal = fromIt->second; + Value toVal = toIt->second; + if (vars.channelVars.find(fromVal) == vars.channelVars.end() || + vars.channelVars.find(toVal) == vars.channelVars.end()) + continue; + if (edge.samples.empty()) { + unit->emitError() << "spec timing edge " << edge.from.port << "." + << edge.from.signal << " -> " << edge.to.port << "." + << edge.to.signal << " has no samples"; + return; + } + double delay = pickClosest(edge.samples); + CPVar &tFrom = + vars.channelVars[fromVal].signalVars[SignalType::DATA].path.tOut; + CPVar &tTo = vars.channelVars[toVal].signalVars[SignalType::DATA].path.tIn; + std::string consName = + "path_spec_p2p_" + unitName.str() + "_" + std::to_string(idx++); + model->addConstr(tFrom + delay <= tTo, consName); + } + + auto unitSideDataVar = [&](Value v) -> CPVar & { + bool unitIsProducer = (v.getDefiningOp() == unit); + if (unitIsProducer) + return vars.channelVars[v].signalVars[SignalType::DATA].path.tIn; + return vars.channelVars[v].signalVars[SignalType::DATA].path.tOut; + }; + + for (const SpecTimingPortDelay &pd : specModel->pin2reg) { + if (pd.port.signal != "data") + continue; + auto it = portToValue.find(pd.port.port); + if (it == portToValue.end()) { + unit->emitError() << "spec pin2reg references unknown port '" + << pd.port.port << "'"; + return; + } + Value v = it->second; + if (vars.channelVars.find(v) == vars.channelVars.end()) + continue; + if (pd.samples.empty()) { + unit->emitError() << "spec pin2reg " << pd.port.port << "." + << pd.port.signal << " has no samples"; + return; + } + double delay = pickClosest(pd.samples); + CPVar &tArr = unitSideDataVar(v); + std::string consName = + "path_spec_p2r_" + unitName.str() + "_" + std::to_string(idx++); + model->addConstr(tArr + delay <= targetPeriod, consName); + } + + for (const SpecTimingPortDelay &pd : specModel->reg2pin) { + if (pd.port.signal != "data") + continue; + auto it = portToValue.find(pd.port.port); + if (it == portToValue.end()) { + unit->emitError() << "spec reg2pin references unknown port '" + << pd.port.port << "'"; + return; + } + Value v = it->second; + if (vars.channelVars.find(v) == vars.channelVars.end()) + continue; + if (pd.samples.empty()) { + unit->emitError() << "spec reg2pin " << pd.port.port << "." + << pd.port.signal << " has no samples"; + return; + } + double delay = pickClosest(pd.samples); + CPVar &tDep = unitSideDataVar(v); + std::string consName = + "path_spec_r2p_" + unitName.str() + "_" + std::to_string(idx++); + model->addConstr(tDep >= delay, consName); + } +} + void FPGA20Buffers::extractResult(BufferPlacement &placement) { // Iterate over all channels in the circuit for (auto &[channel, chVars] : vars.channelVars) { @@ -181,6 +340,10 @@ void FPGA20Buffers::setup() { // Add path and elasticity constraints over all units in the function for (Operation &op : funcInfo.funcOp.getOps()) { + if (isa(&op)) { + addSpecUnitDataPathConstraints(&op); + continue; + } addUnitTimingConstraints(&op, SignalType::DATA); } diff --git a/lib/Transforms/BufferPlacement/FPL22Buffers.cpp b/lib/Transforms/BufferPlacement/FPL22Buffers.cpp index 0c6eb210ef..13d8ad2a2e 100644 --- a/lib/Transforms/BufferPlacement/FPL22Buffers.cpp +++ b/lib/Transforms/BufferPlacement/FPL22Buffers.cpp @@ -347,8 +347,6 @@ void FPL22BuffersBase::addSpecUnitPathConstraints(Operation *unit, currentParams["BITWIDTH"] = chTy.getDataBitWidth(); else currentParams["BITWIDTH"] = 0; - if (auto fifoAttr = unit->getAttrOfType("fifoDepth")) - currentParams["FIFO_DEPTH"] = fifoAttr.getValue().getZExtValue(); auto parseSignal = [](StringRef s) -> std::optional { if (s == "data") @@ -384,7 +382,7 @@ void FPL22BuffersBase::addSpecUnitPathConstraints(Operation *unit, StringRef unitName = getUniqueName(unit); unsigned idx = 0; - for (const SpecTimingEdge &edge : specModel->edges) { + for (const SpecTimingEdge &edge : specModel->pin2pin) { auto fromIt = portToValue.find(edge.from.port); auto toIt = portToValue.find(edge.to.port); if (fromIt == portToValue.end()) { @@ -422,9 +420,65 @@ void FPL22BuffersBase::addSpecUnitPathConstraints(Operation *unit, CPVar &tFrom = vars.channelVars[fromVal].signalVars[*fromSig].path.tOut; CPVar &tTo = vars.channelVars[toVal].signalVars[*toSig].path.tIn; std::string consName = - "path_spec_" + unitName.str() + "_" + std::to_string(idx++); + "path_spec_p2p_" + unitName.str() + "_" + std::to_string(idx++); model->addConstr(tFrom + delay <= tTo, consName); } + + for (const SpecTimingPortDelay &pd : specModel->pin2reg) { + auto it = portToValue.find(pd.port.port); + if (it == portToValue.end()) { + unit->emitError() << "spec pin2reg references unknown port '" + << pd.port.port << "'"; + return; + } + std::optional sig = parseSignal(pd.port.signal); + if (!sig) { + unit->emitError() << "spec pin2reg has unrecognised signal kind '" + << pd.port.signal << "'"; + return; + } + Value v = it->second; + if (!filter(v)) + continue; + if (pd.samples.empty()) { + unit->emitError() << "spec pin2reg " << pd.port.port << "." + << pd.port.signal << " has no samples"; + return; + } + double delay = pickClosest(pd.samples); + std::string consName = + "path_spec_p2r_" + unitName.str() + "_" + std::to_string(idx++); + CPVar &tInPort = vars.channelVars[v].signalVars[*sig].path.tOut; + model->addConstr(tInPort + delay <= targetPeriod, consName); + } + + for (const SpecTimingPortDelay &pd : specModel->reg2pin) { + auto it = portToValue.find(pd.port.port); + if (it == portToValue.end()) { + unit->emitError() << "spec reg2pin references unknown port '" + << pd.port.port << "'"; + return; + } + std::optional sig = parseSignal(pd.port.signal); + if (!sig) { + unit->emitError() << "spec reg2pin has unrecognised signal kind '" + << pd.port.signal << "'"; + return; + } + Value v = it->second; + if (!filter(v)) + continue; + if (pd.samples.empty()) { + unit->emitError() << "spec reg2pin " << pd.port.port << "." + << pd.port.signal << " has no samples"; + return; + } + double delay = pickClosest(pd.samples); + std::string consName = + "path_spec_r2p_" + unitName.str() + "_" + std::to_string(idx++); + CPVar &tOutPort = vars.channelVars[v].signalVars[*sig].path.tIn; + model->addConstr(tOutPort >= delay, consName); + } } CFDFCUnionBuffers::CFDFCUnionBuffers(CPSolver::SolverKind solverKind, diff --git a/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp b/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp index febb91ec6d..1949e940d5 100644 --- a/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp +++ b/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp @@ -505,8 +505,9 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( if (dumpMILPModels) { writeTo = dumpDir + sep + funcName + "-fpga20-buffers"; } - return solveMILP(placement, solverKind, timeout, - info, timingDB, targetCP, writeTo); + return solveMILP(placement, polishPaths, solverKind, + timeout, info, timingDB, targetCP, + writeTo); } if (algorithm == FPL22) { // Create disjoint block unions of all CFDFCs @@ -526,8 +527,8 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( writeTo = dumpDir + sep + funcName + "-cfunion" + std::to_string(idx); } if (failed(solveMILP( - placement, solverKind, timeout, info, timingDB, targetCP, cfUnion, - writeTo))) + placement, polishPaths, solverKind, timeout, info, timingDB, + targetCP, cfUnion, writeTo))) return failure(); } @@ -536,8 +537,9 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( } // Solve last MILP on channels/units that are not part of any CFDFC - return solveMILP( - placement, solverKind, timeout, info, timingDB, targetCP, writeTo); + return solveMILP(placement, polishPaths, + solverKind, timeout, info, + timingDB, targetCP, writeTo); } if (algorithm == FPGA24) { @@ -550,8 +552,9 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( writeTo = dumpDir + sep + funcName + "-cost-aware"; } // Create and solve the MILP - return solveMILP( - placement, solverKind, timeout, info, timingDB, targetCP, writeTo); + return solveMILP(placement, polishPaths, + solverKind, timeout, info, + timingDB, targetCP, writeTo); } if (algorithm == MAPBUF) { @@ -560,8 +563,8 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( } // Create and solve the MILP return solveMILP( - placement, solverKind, timeout, info, timingDB, targetCP, blifFiles, - lutDelay, lutSize, acyclicType, writeTo); + placement, polishPaths, solverKind, timeout, info, timingDB, targetCP, + blifFiles, lutDelay, lutSize, acyclicType, writeTo); } llvm_unreachable("unknown algorithm"); diff --git a/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp b/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp index 7c617b3a96..45a4a02405 100644 --- a/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp +++ b/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp @@ -1663,3 +1663,44 @@ void BufferPlacementMILP::initialize() { auto ops = funcInfo.funcOp.getOps(); largeCst = std::distance(ops.begin(), ops.end()) + 2; } + +LogicalResult BufferPlacementMILP::polishArrivalTimes() { + // Pin all buffer-decision variables to their currently-solved values so the + // re-solve cannot move them. + // Pin only the variables every buffer placement algorithm initialises. + // FPGA24-specific fields (dataLatency, shiftReg, stalled, maxOccupancy) may + // hold uninitialised CPVar handles for fpl22/fpga20 and would crash on + // getValue/addConstr. + auto pinVar = [&](CPVar &v) { + model->addConstr(v == model->getValue(v), "polish_pin"); + }; + for (auto &[channel, chVars] : vars.channelVars) { + pinVar(chVars.bufPresent); + pinVar(chVars.bufNumSlots); + for (auto &[sigType, sigVars] : chVars.signalVars) + pinVar(sigVars.bufPresent); + } + + // Replace objective with minimisation of the sum of path arrival variables + // (Σ tIn + tOut). CPSolver only exposes setMaximizeObjective so we negate. + LinExpr minSum; + for (auto &[channel, chVars] : vars.channelVars) { + for (auto &[sigType, sigVars] : chVars.signalVars) { + minSum += sigVars.path.tIn; + minSum += sigVars.path.tOut; + } + } + model->setMaximizeObjective(-minSum); + + model->optimize(); + if (model->status != CPSolver::OPTIMAL && + model->status != CPSolver::NONOPTIMAL) { + llvm::errs() << "polishArrivalTimes: re-solve failed status=" + << model->status << "\n"; + return failure(); + } + + if (!writeTo.empty()) + model->writeSol(writeTo + "_polished_sol.log"); + return success(); +} diff --git a/tools/backend/synth-characterization-spec/report_parser.py b/tools/backend/synth-characterization-spec/report_parser.py index 98672a5a17..038ffcebd9 100644 --- a/tools/backend/synth-characterization-spec/report_parser.py +++ b/tools/backend/synth-characterization-spec/report_parser.py @@ -83,15 +83,16 @@ def extract_rpt_data(map_unit_to_list_unit_chars, json_output): 2. A .matrix.txt next to it: per-bitwidth physical-port matrices for human inspection. """ - # Per-unit nested matrix for the human-readable view (keyed by physical port - # names, indexed by bitwidth string). matrix_by_unit = {} - # Per-unit edge map: (from_port, from_sig, to_port, to_sig) -> list of samples. edges_by_unit = {} + in_port_by_unit = {} + out_port_by_unit = {} for unit_name, list_unit_chars in map_unit_to_list_unit_chars.items(): matrix = {} edges = {} + in_ports = {} + out_ports = {} for unit_char in list_unit_chars: sample_params = dict(unit_char.params) bw = str(sample_params.get("BITWIDTH", "")) @@ -104,9 +105,7 @@ def extract_rpt_data(map_unit_to_list_unit_chars, json_output): delay = extract_single_rpt(rpt_path) if delay is None: continue - # Matrix view: keep zeros, key by bitwidth for display. matrix.setdefault(iport, {}).setdefault(oport, {})[bw] = delay - # Edges view: drop spec endpoints; drop zero samples; pre-split. from_port, from_sig = split_physical_port(iport) to_port, to_sig = split_physical_port(oport) if from_sig == "spec" or to_sig == "spec": @@ -117,10 +116,37 @@ def extract_rpt_data(map_unit_to_list_unit_chars, json_output): edges.setdefault(edge_key, []).append( {"params": sample_params, "delay": delay}) + in_port_to_rpt = getattr(unit_char, "map_in_port_to_rpt", {}) + for iport, rpt_path in in_port_to_rpt.items(): + delay = extract_single_rpt(rpt_path) + if delay is None: + continue + port, sig = split_physical_port(iport) + if sig == "spec": + continue + if delay == 0.0: + continue + in_ports.setdefault((port, sig), []).append( + {"params": sample_params, "delay": delay}) + + out_port_to_rpt = getattr(unit_char, "map_out_port_to_rpt", {}) + for oport, rpt_path in out_port_to_rpt.items(): + delay = extract_single_rpt(rpt_path) + if delay is None: + continue + port, sig = split_physical_port(oport) + if sig == "spec": + continue + if delay == 0.0: + continue + out_ports.setdefault((port, sig), []).append( + {"params": sample_params, "delay": delay}) + matrix_by_unit[unit_name] = matrix edges_by_unit[unit_name] = edges + in_port_by_unit[unit_name] = in_ports + out_port_by_unit[unit_name] = out_ports - # Assemble the edges-list output. output_data = {} for unit_name, edges in edges_by_unit.items(): edge_list = [] @@ -130,7 +156,21 @@ def extract_rpt_data(map_unit_to_list_unit_chars, json_output): "to": {"port": tp, "signal": ts}, "samples": samples, }) - output_data[unit_name] = {"delays": edge_list} + pin2reg_list = [] + for (port, sig), samples in in_port_by_unit.get(unit_name, {}).items(): + pin2reg_list.append({ + "port": port, "signal": sig, "samples": samples, + }) + reg2pin_list = [] + for (port, sig), samples in out_port_by_unit.get(unit_name, {}).items(): + reg2pin_list.append({ + "port": port, "signal": sig, "samples": samples, + }) + output_data[unit_name] = { + "pin2pin": edge_list, + "pin2reg": pin2reg_list, + "reg2pin": reg2pin_list, + } # Render matrices per unit per bitwidth. matrix_path = json_output + ".matrix.txt" diff --git a/tools/backend/synth-characterization-spec/unit_characterization.py b/tools/backend/synth-characterization-spec/unit_characterization.py index 5c337e620b..9ddf26f0ef 100644 --- a/tools/backend/synth-characterization-spec/unit_characterization.py +++ b/tools/backend/synth-characterization-spec/unit_characterization.py @@ -147,7 +147,10 @@ def generate_wrapper_top_no_generics(entity_name, vhdl_interface_info): """ Wrapper used when the unit's VHDL has no generics (modern self-contained generator output). The tb just wires every dut port to a top-level port of the same name. + Entity is uniquely named (tb_) so multiple combos can coexist + in the same hdl directory without colliding. """ + tb_entity_name = f"tb_{entity_name}" ports = vhdl_interface_info.get_list_ports() tb_ports = list(ports) @@ -156,12 +159,12 @@ def generate_wrapper_top_no_generics(entity_name, vhdl_interface_info): use ieee.numeric_std.all; use ieee.math_real.all; use work.types.all; -entity tb is +entity {tb_entity_name} is port ( {';\n'.join(tb_ports)} ); end entity; -architecture tb_arch of tb is +architecture arch of {tb_entity_name} is begin dut: entity work.{entity_name} port map ( @@ -245,7 +248,10 @@ def run_unit_characterization(unit_name, list_params, hdl_out_dir, synth_tool, t unit_name, top_entity_name, params_dict, hdl_files, vhdl_interface_info, id) tcl_file = unit_char_obj.generate_tcl(tcl_dir, rpt_dir, sdc_file) unit_characterization_list.append(unit_char_obj) - if all(os.path.exists(p) for p in unit_char_obj.map_pair_to_rpt.values()): + all_rpts = list(unit_char_obj.map_pair_to_rpt.values()) + \ + list(unit_char_obj.map_in_port_to_rpt.values()) + \ + list(unit_char_obj.map_out_port_to_rpt.values()) + if all(os.path.exists(p) for p in all_rpts): print( f"[skip] {unit_name} combo {id} {params_dict}: reports already present") continue @@ -270,7 +276,10 @@ def run_unit_characterization(unit_name, list_params, hdl_out_dir, synth_tool, t param_names, combination)), [top_file] + support_hdl_files, vhdl_interface_info, id) tcl_file = unit_char_obj.generate_tcl(tcl_dir, rpt_dir, sdc_file) unit_characterization_list.append(unit_char_obj) - if all(os.path.exists(p) for p in unit_char_obj.map_pair_to_rpt.values()): + all_rpts = list(unit_char_obj.map_pair_to_rpt.values()) + \ + list(unit_char_obj.map_in_port_to_rpt.values()) + \ + list(unit_char_obj.map_out_port_to_rpt.values()) + if all(os.path.exists(p) for p in all_rpts): print( f"[skip] {unit_name} combo {id}: reports already present") continue diff --git a/tools/backend/synth-characterization-spec/utils.py b/tools/backend/synth-characterization-spec/utils.py index 450605eb87..bfaecc400f 100644 --- a/tools/backend/synth-characterization-spec/utils.py +++ b/tools/backend/synth-characterization-spec/utils.py @@ -50,7 +50,7 @@ parameters_ranges = { "DATA_TYPE": [1, 2, 4, 8, 16, 32, 64], "BITWIDTH": [1, 2, 4, 8, 16, 32, 64], - "FIFO_DEPTH": [4, 5, 6, 7, 8, 10, 12, 14, 16], + "FIFO_DEPTH": [4], "SIZE": [2], "SELECT_TYPE": [2], "INDEX_TYPE": [2], @@ -62,30 +62,41 @@ # Function to write the TCL file for synthesis -def write_tcl_multiport(top_entity_name, hdl_files, tcl_file, sdc_file, pair_to_rpt): +def write_tcl_multiport(top_entity_name, hdl_files, tcl_file, sdc_file, + pair_to_rpt, in_port_to_rpt, out_port_to_rpt, + is_vector): """ - Write a TCL file that synthesises the design and then runs one - `report_timing` per (input_port, output_port) pair, each writing to its own - report file. + Synthesise then emit three classes of report_timing: + - per (input_port, output_port) pair: pin-to-pin path delay + - per input_port (no -to): worst path starting at this pin + - per output_port (no -from): worst path ending at this pin - Args: - pair_to_rpt: dict keyed by (in_port, out_port) tuple, value is the - report file path for that pair. + `is_vector` is a callable (port_name) -> bool; chooses between + `[get_ports {name[*]}]` (vector) and `[get_ports name]` (scalar). """ + def _gp(p): + if is_vector(p): + return f"[get_ports {{{p}[*]}}]" + return f"[get_ports {p}]" with open(tcl_file, 'w') as f: for hdl_file in hdl_files: f.write(f"read_vhdl -vhdl2008 {hdl_file}\n") f.write(f"read_xdc {sdc_file}\n") f.write( - "synth_design -top tb -part xc7k160tfbg484-2 -no_iobuf -mode out_of_context\n") + f"synth_design -top tb_{top_entity_name} -part xc7k160tfbg484-2 -no_iobuf -mode out_of_context\n") f.write("opt_design\n") f.write("place_design\n") f.write("phys_opt_design\n") f.write("route_design\n") f.write("phys_opt_design\n") + f.write("puts \"PORTS_AVAILABLE: [get_ports]\"\n") for (iport, oport), rpt_path in pair_to_rpt.items(): f.write( - f"report_timing -from [get_ports {iport}] -to [get_ports {oport}] > {rpt_path}\n") + f"report_timing -from {_gp(iport)} -to {_gp(oport)} > {rpt_path}\n") + for iport, rpt_path in in_port_to_rpt.items(): + f.write(f"report_timing -from {_gp(iport)} > {rpt_path}\n") + for oport, rpt_path in out_port_to_rpt.items(): + f.write(f"report_timing -to {_gp(oport)} > {rpt_path}\n") # Class to hold VHDL interface information @@ -107,6 +118,15 @@ def __init__(self, generics: List[str], ports: List[str]): ins, outs = self.extract_ins_outs() self.ins_per_type = self.categorize_ports(ins) self.outs_per_type = self.categorize_ports(outs) + self.is_vector_map = {} + for raw in ports: + if ":" not in raw: + continue + name = raw.split(":")[0].strip() + self.is_vector_map[name] = "std_logic_vector" in raw + + def is_vector(self, port_name: str) -> bool: + return self.is_vector_map.get(port_name, False) def __repr__(self): return f"VhdlInterfaceInfo(generics={self.generics}, ports={self.ports})" @@ -322,9 +342,21 @@ def generate_tcl(self, tcl_dir: str, rpt_dir: str, sdc_file: str) -> List[str]: for oport in output_ports: rpt_path = f"{rpt_dir}/rpt_{self.top_entity_name}_top_{self.unique_id}__{iport}__{oport}.txt" pair_to_rpt[(iport, oport)] = rpt_path + in_port_to_rpt = {} + for iport in input_ports: + rpt_path = f"{rpt_dir}/rpt_{self.top_entity_name}_top_{self.unique_id}__in__{iport}.txt" + in_port_to_rpt[iport] = rpt_path + out_port_to_rpt = {} + for oport in output_ports: + rpt_path = f"{rpt_dir}/rpt_{self.top_entity_name}_top_{self.unique_id}__out__{oport}.txt" + out_port_to_rpt[oport] = rpt_path self.map_pair_to_rpt = pair_to_rpt + self.map_in_port_to_rpt = in_port_to_rpt + self.map_out_port_to_rpt = out_port_to_rpt write_tcl_multiport(self.top_entity_name, self.hdl_files, - tcl_file, sdc_file, pair_to_rpt) + tcl_file, sdc_file, pair_to_rpt, + in_port_to_rpt, out_port_to_rpt, + self.vhdl_interface_info.is_vector) self.tcl_file = tcl_file return tcl_file diff --git a/tools/dynamatic/scripts/compile.sh b/tools/dynamatic/scripts/compile.sh index 8f11ca70c1..1f671ab135 100755 --- a/tools/dynamatic/scripts/compile.sh +++ b/tools/dynamatic/scripts/compile.sh @@ -360,7 +360,7 @@ else "$DYNAMATIC_OPT_BIN" "$F_HANDSHAKE_TRANSFORMED" \ --handshake-set-unit-impl-attr="target-period=$TARGET_CP timing-models=$DYNAMATIC_DIR/data/components.json impl=$FPUNITS_GEN" \ --handshake-set-buffering-properties="version=fpga20" \ - --handshake-place-buffers="algorithm=$BUFFER_ALGORITHM solver=$MILP_SOLVER frequencies=$F_FREQUENCIES timing-models=$DYNAMATIC_DIR/data/components.json target-period=$TARGET_CP timeout=300 dump-milp-models \ + --handshake-place-buffers="algorithm=$BUFFER_ALGORITHM solver=$MILP_SOLVER frequencies=$F_FREQUENCIES timing-models=$DYNAMATIC_DIR/data/components.json target-period=$TARGET_CP timeout=300 dump-milp-models polish-paths \ blif-files=$DYNAMATIC_DIR/data/aig/ lut-delay=0.55 lut-size=6 acyclic-type" \ ${SHARING_PASS:+"$SHARING_PASS"} \ > "$F_HANDSHAKE_BUFFERED" diff --git a/tools/integration/TEST_SUITE.cpp b/tools/integration/TEST_SUITE.cpp index 9cdf9593e0..de49dc6b7d 100644 --- a/tools/integration/TEST_SUITE.cpp +++ b/tools/integration/TEST_SUITE.cpp @@ -226,7 +226,7 @@ TEST_P(SpecFixture, spec) { .useSpeculation = true, .milpSolver = "gurobi", .bufferAlgorithm = "fpl22", - .clockPeriod = 20, + .clockPeriod = 8, .simTimeoutNs = 500000, .simTime = -1 // clang-format on From b2b1421ce387a0ef066f5261b019e610254ccda6 Mon Sep 17 00:00:00 2001 From: Emmet Murphy Date: Tue, 9 Jun 2026 13:42:43 +0200 Subject: [PATCH 4/9] clean up calculatePathDelays --- include/dynamatic/Support/MILP.h | 26 +++++++++------- .../Transforms/BufferPlacement/FPL22Buffers.h | 2 +- .../Utils/BufferPlacementMILP.h | 11 +++++-- .../BufferPlacement/CostAwareBuffers.cpp | 2 +- .../BufferPlacement/FPGA20Buffers.cpp | 2 +- .../BufferPlacement/FPGA24Buffers.cpp | 8 ++--- .../BufferPlacement/MAPBUFBuffers.cpp | 2 +- .../Utils/BufferPlacementMILP.cpp | 30 ++++++++++++------- 8 files changed, 51 insertions(+), 32 deletions(-) diff --git a/include/dynamatic/Support/MILP.h b/include/dynamatic/Support/MILP.h index 524c90dba9..5dcca33f0f 100644 --- a/include/dynamatic/Support/MILP.h +++ b/include/dynamatic/Support/MILP.h @@ -158,10 +158,13 @@ class MILP { /// Marks the MILP as initial state. void resetMILPState() { state = State::FAILED_TO_SETUP; } - /// Optional second-pass polish hook. Default is a no-op; subclasses can - /// override to e.g. pin solution variables, change the objective, and - /// re-optimize. Called by `solveMILP` when its `polish` argument is true. - virtual LogicalResult polishArrivalTimes() { return success(); } + /// Re-run the MILP with the buffering decisions locked-in, + /// in order to calculate the actual delays the MILP sees + /// from the characterization approach + /// + /// What buffering decisions to fix is algorithm dependent. + /// Currently only implemented for FPGA'20 and FPL'22. + virtual LogicalResult calculatePathDelays() { return success(); } /// Determines whether the MILP is in a valid state to be optimized. If this /// returns true, `MILP::optimize` can be called to solve the MILP. @@ -185,8 +188,7 @@ class MILP { std::unique_ptr model; /// Path to a file at which to store the MILP's model and its solution after - /// optimization. Empty disables logging. Available to overrides such as - /// `polishArrivalTimes()` that want to dump a second-pass sol log. + /// optimization. Empty disables logging. std::string writeTo; /// Fills in the argument with the desired results extract from the MILP's @@ -231,14 +233,18 @@ class MILP { /// Creates, optimizes, and extract results from an MILP in one go. Fails and /// displays an error message to stderr if any step along the process fails. /// Otherwise succeeds and stores the MILP's results in the first function -/// argument. If `polish` is true, runs `polishArrivalTimes()` between optimize -/// and result extraction (a no-op for MILP classes that don't override it). +/// argument. +/// +/// if calculatePathDelays is true, +/// it asks the MILP to lock in the buffering decisions, and re-run to +/// calculate only the path delays. Useful for evaluation of modelling accuracy. template -LogicalResult solveMILP(MILPRes &milpResult, bool polish, Args &&...args) { +LogicalResult solveMILP(MILPRes &milpResult, bool calculatePathDelays, + Args &&...args) { MILP milp = MILP(std::forward(args)...); if (failed(milp.optimize())) return failure(); - if (polish && failed(milp.polishArrivalTimes())) + if (calculatePathDelays && failed(milp.calculatePathDelays())) return failure(); if (failed(milp.getResult(milpResult))) return failure(); diff --git a/include/dynamatic/Transforms/BufferPlacement/FPL22Buffers.h b/include/dynamatic/Transforms/BufferPlacement/FPL22Buffers.h index e9b5834bcc..c4ba897c62 100644 --- a/include/dynamatic/Transforms/BufferPlacement/FPL22Buffers.h +++ b/include/dynamatic/Transforms/BufferPlacement/FPL22Buffers.h @@ -40,7 +40,7 @@ class FPL22BuffersBase : public BufferPlacementMILP { FuncInfo &funcInfo, const TimingDatabase &timingDB, double targetPeriod, StringRef writeTo = "") : BufferPlacementMILP(solverKind, timeout, funcInfo, timingDB, - targetPeriod, writeTo) {}; + targetPeriod, Algorithm::FPL22, writeTo) {}; /// Interprets the MILP solution to derive buffer placement decisions. Since /// the MILP cannot encode the placement of both opaque and transparent slots diff --git a/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h b/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h index 943b0c0544..ae38e43857 100644 --- a/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h +++ b/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h @@ -140,11 +140,15 @@ struct MILPVars { /// some pre/post-processind steps and verification they are likely to need. class BufferPlacementMILP : public MILP { public: + // Enum representation of algorithm class + enum class Algorithm { FPGA20, FPL22, FPGA24, CostAware, MAPBUF }; + /// Contains timing characterizations for dataflow components required to /// create the MILP constraints. const TimingDatabase &timingDB; /// Target clock period. const double targetPeriod; + const Algorithm algorithm; /// Starts setting up a the buffer placement MILP for a Handshake function /// (with its CFDFCs) with specific component timing models. The constructor @@ -154,13 +158,14 @@ class BufferPlacementMILP : public MILP { /// constructor sets the `unsatisfiable` flag to true. BufferPlacementMILP(CPSolver::SolverKind solverKind, int timeout, FuncInfo &funcInfo, const TimingDatabase &timingDB, - double targetPeriod, llvm::StringRef writeTo = ""); + double targetPeriod, Algorithm algorithm, + llvm::StringRef writeTo = ""); - /// Pins all buffer-decision variables to their currently-solved values, + /// Locks all buffer-decision variables to their currently-solved values, /// replaces the objective with `min Σ(t_*)`, re-optimises, and rewrites the /// sol log. Lets the dumped values reflect the true min-feasible arrival on /// each channel signal instead of being packed to the period bound. - LogicalResult polishArrivalTimes() override; + LogicalResult calculatePathDelays() override; protected: /// Represents a list of signals that are buffered together by a single diff --git a/lib/Transforms/BufferPlacement/CostAwareBuffers.cpp b/lib/Transforms/BufferPlacement/CostAwareBuffers.cpp index 70bd283050..f66427cd59 100644 --- a/lib/Transforms/BufferPlacement/CostAwareBuffers.cpp +++ b/lib/Transforms/BufferPlacement/CostAwareBuffers.cpp @@ -34,7 +34,7 @@ CostAwareBuffers::CostAwareBuffers(CPSolver::SolverKind solverKind, int timeout, const TimingDatabase &timingDB, double targetPeriod, StringRef writeTo) : BufferPlacementMILP(solverKind, timeout, funcInfo, timingDB, targetPeriod, - writeTo) { + Algorithm::CostAware, writeTo) { if (!unsatisfiable) setup(); } diff --git a/lib/Transforms/BufferPlacement/FPGA20Buffers.cpp b/lib/Transforms/BufferPlacement/FPGA20Buffers.cpp index 975e2935be..d9cf96c7d6 100644 --- a/lib/Transforms/BufferPlacement/FPGA20Buffers.cpp +++ b/lib/Transforms/BufferPlacement/FPGA20Buffers.cpp @@ -35,7 +35,7 @@ FPGA20Buffers::FPGA20Buffers(CPSolver::SolverKind solverKind, int timeout, FuncInfo &funcInfo, const TimingDatabase &timingDB, double targetPeriod, StringRef writeTo) : BufferPlacementMILP(solverKind, timeout, funcInfo, timingDB, targetPeriod, - writeTo) { + Algorithm::FPGA20, writeTo) { if (!unsatisfiable) setup(); } diff --git a/lib/Transforms/BufferPlacement/FPGA24Buffers.cpp b/lib/Transforms/BufferPlacement/FPGA24Buffers.cpp index fc8fda484b..a6cdfba55f 100644 --- a/lib/Transforms/BufferPlacement/FPGA24Buffers.cpp +++ b/lib/Transforms/BufferPlacement/FPGA24Buffers.cpp @@ -49,8 +49,8 @@ LatencyBalancingMILP::LatencyBalancingMILP( ArrayRef reconvergentPaths, ArrayRef syncCyclePairs, const SynchronizingCyclesFinderGraph &syncGraph, ArrayRef cfdfcs) - : BufferPlacementMILP(solverKind, timeout, funcInfo, timingDB, - targetPeriod), + : BufferPlacementMILP(solverKind, timeout, funcInfo, timingDB, targetPeriod, + Algorithm::FPGA24), reconvergentPaths(reconvergentPaths.begin(), reconvergentPaths.end()), syncCyclePairs(syncCyclePairs.begin(), syncCyclePairs.end()), syncGraph(syncGraph), cfdfcs(cfdfcs.begin(), cfdfcs.end()) { @@ -122,8 +122,8 @@ OccupancyBalancingLP::OccupancyBalancingLP( const LatencyBalancingResult &latencyResult, ArrayRef reconvergentPaths, ArrayRef cfdfcs) - : BufferPlacementMILP(solverKind, timeout, funcInfo, timingDB, - targetPeriod), + : BufferPlacementMILP(solverKind, timeout, funcInfo, timingDB, targetPeriod, + Algorithm::FPGA24), latencyResult(latencyResult), reconvergentPaths(reconvergentPaths.begin(), reconvergentPaths.end()), cfdfcs(cfdfcs.begin(), cfdfcs.end()) { diff --git a/lib/Transforms/BufferPlacement/MAPBUFBuffers.cpp b/lib/Transforms/BufferPlacement/MAPBUFBuffers.cpp index 4e9a5ed12e..504bdbc0f7 100644 --- a/lib/Transforms/BufferPlacement/MAPBUFBuffers.cpp +++ b/lib/Transforms/BufferPlacement/MAPBUFBuffers.cpp @@ -46,7 +46,7 @@ MAPBUFBuffers::MAPBUFBuffers(CPSolver::SolverKind solverKind, int timeout, double lutDelay, int lutSize, bool acyclicType, StringRef writeTo) : BufferPlacementMILP(solverKind, timeout, funcInfo, timingDB, targetPeriod, - writeTo), + Algorithm::MAPBUF, writeTo), acyclicType(acyclicType), lutSize(lutSize), lutDelay(lutDelay), blifFiles(blifFiles) { if (!unsatisfiable) diff --git a/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp b/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp index 45a4a02405..19afbd4550 100644 --- a/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp +++ b/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp @@ -237,9 +237,10 @@ BufferPlacementMILP::BufferPlacementMILP(CPSolver::SolverKind solverKind, int timeout, FuncInfo &funcInfo, const TimingDatabase &timingDB, double targetPeriod, + Algorithm algorithm, llvm::StringRef writeTo) : MILP(solverKind, timeout, writeTo), timingDB(timingDB), - targetPeriod(targetPeriod), funcInfo(funcInfo) { + targetPeriod(targetPeriod), algorithm(algorithm), funcInfo(funcInfo) { initialize(); } @@ -1664,15 +1665,18 @@ void BufferPlacementMILP::initialize() { largeCst = std::distance(ops.begin(), ops.end()) + 2; } -LogicalResult BufferPlacementMILP::polishArrivalTimes() { +LogicalResult BufferPlacementMILP::calculatePathDelays() { + if (algorithm != Algorithm::FPGA20 && algorithm != Algorithm::FPL22) { + llvm::errs() << "BufferPlacementMILP::calculatePathDelays() only supports " + << "FPGA20 and FPL22 buffering algorithms\n"; + return failure(); + } + // Pin all buffer-decision variables to their currently-solved values so the // re-solve cannot move them. - // Pin only the variables every buffer placement algorithm initialises. - // FPGA24-specific fields (dataLatency, shiftReg, stalled, maxOccupancy) may - // hold uninitialised CPVar handles for fpl22/fpga20 and would crash on - // getValue/addConstr. + // Pin only the variables used by FPGA'20 and FPL'22 auto pinVar = [&](CPVar &v) { - model->addConstr(v == model->getValue(v), "polish_pin"); + model->addConstr(v == model->getValue(v), "pin_buffers"); }; for (auto &[channel, chVars] : vars.channelVars) { pinVar(chVars.bufPresent); @@ -1681,8 +1685,9 @@ LogicalResult BufferPlacementMILP::polishArrivalTimes() { pinVar(sigVars.bufPresent); } - // Replace objective with minimisation of the sum of path arrival variables - // (Σ tIn + tOut). CPSolver only exposes setMaximizeObjective so we negate. + // Replace objective with minimizing path delay + // since buffer positions are fixed this is equivalent to + // calculating path delays LinExpr minSum; for (auto &[channel, chVars] : vars.channelVars) { for (auto &[sigType, sigVars] : chVars.signalVars) { @@ -1692,15 +1697,18 @@ LogicalResult BufferPlacementMILP::polishArrivalTimes() { } model->setMaximizeObjective(-minSum); + // actually solve model->optimize(); if (model->status != CPSolver::OPTIMAL && model->status != CPSolver::NONOPTIMAL) { - llvm::errs() << "polishArrivalTimes: re-solve failed status=" + llvm::errs() << "calculatePathDelays: re-solve failed status=" << model->status << "\n"; return failure(); } + // and store the MILP solution but this time + // with accurate path delay numbers if (!writeTo.empty()) - model->writeSol(writeTo + "_polished_sol.log"); + model->writeSol(writeTo + "_accurate_delays.log"); return success(); } From 16cc356ddce23f2f8d2b34fef492d693e5bc9781 Mon Sep 17 00:00:00 2001 From: Emmet Murphy Date: Tue, 9 Jun 2026 13:55:55 +0200 Subject: [PATCH 5/9] clean up spec timing model --- include/dynamatic/Support/TimingModels.h | 64 ++++++++++++------- lib/Support/TimingModels.cpp | 4 +- .../BufferPlacement/FPGA20Buffers.cpp | 4 +- .../BufferPlacement/FPL22Buffers.cpp | 4 +- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/include/dynamatic/Support/TimingModels.h b/include/dynamatic/Support/TimingModels.h index f08738550a..060134352c 100644 --- a/include/dynamatic/Support/TimingModels.h +++ b/include/dynamatic/Support/TimingModels.h @@ -285,34 +285,50 @@ bool fromJSON(const llvm::json::Value &jsonValue, TimingModel &model, bool fromJSON(const llvm::json::Value &jsonValue, TimingModel::PortModel &model, llvm::json::Path path); -/// One characterised combinational path between two pins of an op, loaded from -/// the spec-timing JSON. Used for ops whose internal timing cannot be -/// expressed by the named scalars in TimingModel (e.g., handshake.speculator, -/// handshake.spec_save_commit). +/// Input or output of a unit. +/// signal is stored separately from the rest of the port name +/// since it affects which CPVar the delay applies to +struct SpecTimingEndpoint { + std::string port; + std::string signal; +}; + +/// One measurement of an internal delay at one combination of unit parameters +/// (e.g., BITWIDTH=16, FIFO_DEPTH=4). +struct SpecTimingSample { + llvm::StringMap params; + double delay; +}; + +/// One characterised combinational path between two pins of an op, +/// loaded from the spec-timing JSON. +/// Used for ops whose internal timing requires more expressivity struct SpecTimingEdge { - /// Endpoint identified by a port name (matching NamedIOInterface) plus a - /// signal kind ("data", "valid", or "ready"). - struct Endpoint { - std::string port; - std::string signal; - }; - Endpoint from; - Endpoint to; - /// Each sample is a measurement at one combination of sweep parameters - /// (e.g., BITWIDTH=16, FIFO_DEPTH=4). - struct Sample { - llvm::StringMap params; - double delay; - }; - std::vector samples; + /// input to the unit + SpecTimingEndpoint from; + + /// output of the unit + SpecTimingEndpoint to; + + /// List of sampled parameters + delay + /// present from the JSON file + std::vector samples; }; -/// Per-port boundary delay (input pin -> register or register -> output pin). +/// Per-port boundary delay +/// (input pin -> register or register -> output pin). struct SpecTimingPortDelay { - SpecTimingEdge::Endpoint port; - std::vector samples; + SpecTimingEndpoint port; + + /// List of sampled parameters + delay + /// present from the JSON file + std::vector samples; }; +/// A full timing model for an operation +/// with full expressivity of +/// internal, input, and output delay +/// for parameterized units struct SpecTimingModel { std::vector pin2pin; std::vector pin2reg; @@ -388,8 +404,8 @@ class TimingDatabase { /// Timing keys are generated based on operation name and implementation llvm::StringMap models; - /// Per-op-name set of per-port-pair edges loaded from spec-timing.json. - /// Sparse: only ops that need port-pair-keyed delays appear here. + /// Maps from an operation's timing key to their timing model. + /// for operations which require more expressivity llvm::StringMap specModels; }; diff --git a/lib/Support/TimingModels.cpp b/lib/Support/TimingModels.cpp index 34ec9b2b60..f86fff9bfc 100644 --- a/lib/Support/TimingModels.cpp +++ b/lib/Support/TimingModels.cpp @@ -319,14 +319,14 @@ LogicalResult TimingDatabase::readSpecTimingFromJSON(std::string &jsonpath, SpecTimingModel model; auto parseSamples = [](const ljson::Array *samplesArr, - std::vector &out) { + std::vector &out) { if (!samplesArr) return; for (const ljson::Value &sampleVal : *samplesArr) { const ljson::Object *sampleObj = sampleVal.getAsObject(); if (!sampleObj) continue; - SpecTimingEdge::Sample sample; + SpecTimingSample sample; if (auto d = sampleObj->getNumber("delay")) sample.delay = *d; else diff --git a/lib/Transforms/BufferPlacement/FPGA20Buffers.cpp b/lib/Transforms/BufferPlacement/FPGA20Buffers.cpp index d9cf96c7d6..551294263c 100644 --- a/lib/Transforms/BufferPlacement/FPGA20Buffers.cpp +++ b/lib/Transforms/BufferPlacement/FPGA20Buffers.cpp @@ -83,9 +83,9 @@ void FPGA20Buffers::addSpecUnitDataPathConstraints(Operation *unit) { currentParams["BITWIDTH"] = 0; auto pickClosest = - [&](const std::vector &samples) -> double { + [&](const std::vector &samples) -> double { assert(!samples.empty() && "spec timing edge has no samples"); - const SpecTimingEdge::Sample *best = &samples.front(); + const SpecTimingSample *best = &samples.front(); int64_t bestDist = std::numeric_limits::max(); for (const auto &s : samples) { int64_t dist = 0; diff --git a/lib/Transforms/BufferPlacement/FPL22Buffers.cpp b/lib/Transforms/BufferPlacement/FPL22Buffers.cpp index 13d8ad2a2e..687ba7ccd9 100644 --- a/lib/Transforms/BufferPlacement/FPL22Buffers.cpp +++ b/lib/Transforms/BufferPlacement/FPL22Buffers.cpp @@ -359,9 +359,9 @@ void FPL22BuffersBase::addSpecUnitPathConstraints(Operation *unit, }; auto pickClosest = - [&](const std::vector &samples) -> double { + [&](const std::vector &samples) -> double { assert(!samples.empty() && "spec timing edge has no samples"); - const SpecTimingEdge::Sample *best = &samples.front(); + const SpecTimingSample *best = &samples.front(); int64_t bestDist = std::numeric_limits::max(); for (const auto &s : samples) { int64_t dist = 0; From 3ec22b0629567f33b3291d1f26d6938d1e0de6b8 Mon Sep 17 00:00:00 2001 From: Emmet Murphy Date: Fri, 12 Jun 2026 12:32:16 +0200 Subject: [PATCH 6/9] remove wrong delay getters --- .../CompilerIntrinsics/TimingInformation.md | 8 ++------ include/dynamatic/Support/TimingModels.h | 13 ++++--------- lib/Support/TimingModels.cpp | 4 ++-- .../BufferPlacement/Utils/BufferPlacementMILP.cpp | 4 ++-- tools/integration/TEST_SUITE.cpp | 1 - 5 files changed, 10 insertions(+), 20 deletions(-) diff --git a/docs/DeveloperGuide/CompilerIntrinsics/TimingInformation.md b/docs/DeveloperGuide/CompilerIntrinsics/TimingInformation.md index 3dd16413ab..93cbd5bc56 100644 --- a/docs/DeveloperGuide/CompilerIntrinsics/TimingInformation.md +++ b/docs/DeveloperGuide/CompilerIntrinsics/TimingInformation.md @@ -202,13 +202,9 @@ The TimingModel provides several core methods: 1. **[LogicalResult getTotalDataDelay(unsigned bitwidth, double &delay)]()**: queries the total data delay at a certain bitwidth `bitwidth` and it saves the delay as a double (in nanoseconds) in the `delay` variable. -2. **[double getTotalValidDelay()]()**: returns the total valid delay as a double (in nanoseconds). +2. **[bool fromJSON(const llvm::json::Value &jsonValue, TimingModel &model, llvm::json::Path path)]()**: extracts the TimingModel information from the JSON fragment `jsonValue` located at the specified path `path` relative to the root of the full JSON structure, and stores it in the variable `model`. -3. **[double getTotalReadyDelay()]()**: returns the total ready delay as a double (in nanoseconds). - -4. **[bool fromJSON(const llvm::json::Value &jsonValue, TimingModel &model, llvm::json::Path path)]()**: extracts the TimingModel information from the JSON fragment `jsonValue` located at the specified path `path` relative to the root of the full JSON structure, and stores it in the variable `model`. - -5. **[bool fromJSON(const llvm::json::Value &jsonValue, TimingModel::PortModel &model, llvm::json::Path path)]()**: extracts the PortModel information from the JSON fragment `jsonValue` located at the specified path `path` relative to the root of the full JSON structure, and stores it in the variable `model`. +3. **[bool fromJSON(const llvm::json::Value &jsonValue, TimingModel::PortModel &model, llvm::json::Path path)]()**: extracts the PortModel information from the JSON fragment `jsonValue` located at the specified path `path` relative to the root of the full JSON structure, and stores it in the variable `model`. The LogicalResult or boolean types of these functions represent the successful or unsuccessful execution of the function. diff --git a/include/dynamatic/Support/TimingModels.h b/include/dynamatic/Support/TimingModels.h index 060134352c..a9266328c6 100644 --- a/include/dynamatic/Support/TimingModels.h +++ b/include/dynamatic/Support/TimingModels.h @@ -269,10 +269,6 @@ struct TimingModel { /// bitwidth in the model. On success, sets the last argument to the data /// delay. LogicalResult getTotalDataDelay(unsigned bitwidth, double &delay) const; - - double getTotalValidDelay() const { return validDelay; }; - - double getTotalReadyDelay() const { return readyDelay; }; }; /// Deserializes a JSON value into a TimingModel. See ::llvm::json::Value's @@ -385,14 +381,13 @@ class TimingDatabase { static LogicalResult readFromJSON(std::string &jsonPath, TimingDatabase &timingDB); - /// Loads the per-port-pair spec timing entries (e.g. for SpeculatorOp and - /// SpecSaveCommitOp) from the JSON file at `jsonPath`. Fails if the file is - /// missing or malformed. + /// Parses a JSON file whose path is given as argument and adds all the + /// spec timing models it contains to the passed timing database. static LogicalResult readSpecTimingFromJSON(std::string &jsonPath, TimingDatabase &timingDB); - /// Returns the spec timing model for the given op-name key, or nullptr if - /// none was loaded. + /// Returns the spec timing model for the given op-name, + /// or nullptr if none was loaded. const SpecTimingModel *getSpecModel(StringRef timingModelKey) const; /// Convenience overload returning the spec timing model corresponding to diff --git a/lib/Support/TimingModels.cpp b/lib/Support/TimingModels.cpp index f86fff9bfc..f9cdea21b0 100644 --- a/lib/Support/TimingModels.cpp +++ b/lib/Support/TimingModels.cpp @@ -262,10 +262,10 @@ LogicalResult TimingDatabase::getTotalDelay(Operation *op, case SignalType::DATA: return model->getTotalDataDelay(getOpDatawidth(op), delay); case SignalType::VALID: - delay = model->getTotalValidDelay(); + delay = model->validDelay; return success(); case SignalType::READY: - delay = model->getTotalReadyDelay(); + delay = model->readyDelay; return success(); } } diff --git a/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp b/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp index 19afbd4550..6260fea5e6 100644 --- a/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp +++ b/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp @@ -227,9 +227,9 @@ double BufferPlacementMILP::BufferingGroup::getCombinationalDelay( (void)bufModel->getTotalDataDelay(bitwidth, delay); return delay; case SignalType::VALID: - return bufModel->getTotalValidDelay(); + return bufModel->validDelay; case SignalType::READY: - return bufModel->getTotalReadyDelay(); + return bufModel->readyDelay; } } diff --git a/tools/integration/TEST_SUITE.cpp b/tools/integration/TEST_SUITE.cpp index 4eaa93d08c..89034238c0 100644 --- a/tools/integration/TEST_SUITE.cpp +++ b/tools/integration/TEST_SUITE.cpp @@ -381,7 +381,6 @@ TEST_P(SpecFixture, spec) { .milpSolver = "gurobi", .bufferAlgorithm = "fpl22", .clockPeriod = 8, - .simTimeoutNs = 500000, .simTime = -1 // clang-format on }; From 61abd91e7a3a6d5f9df7bea44508024e3d7fbd85 Mon Sep 17 00:00:00 2001 From: Emmet Murphy Date: Tue, 16 Jun 2026 13:18:43 +0200 Subject: [PATCH 7/9] in the middle of moving the function from milp to buffer milp --- include/dynamatic/Support/MILP.h | 29 ----------- .../Utils/BufferPlacementMILP.h | 12 +++-- .../BufferPlacement/HandshakePlaceBuffers.cpp | 51 +++++++++++++------ 3 files changed, 43 insertions(+), 49 deletions(-) diff --git a/include/dynamatic/Support/MILP.h b/include/dynamatic/Support/MILP.h index 5dcca33f0f..bcee52d131 100644 --- a/include/dynamatic/Support/MILP.h +++ b/include/dynamatic/Support/MILP.h @@ -158,14 +158,6 @@ class MILP { /// Marks the MILP as initial state. void resetMILPState() { state = State::FAILED_TO_SETUP; } - /// Re-run the MILP with the buffering decisions locked-in, - /// in order to calculate the actual delays the MILP sees - /// from the characterization approach - /// - /// What buffering decisions to fix is algorithm dependent. - /// Currently only implemented for FPGA'20 and FPL'22. - virtual LogicalResult calculatePathDelays() { return success(); } - /// Determines whether the MILP is in a valid state to be optimized. If this /// returns true, `MILP::optimize` can be called to solve the MILP. /// Conversely, if this returns false then a call to optimize will necessarily @@ -230,27 +222,6 @@ class MILP { } }; -/// Creates, optimizes, and extract results from an MILP in one go. Fails and -/// displays an error message to stderr if any step along the process fails. -/// Otherwise succeeds and stores the MILP's results in the first function -/// argument. -/// -/// if calculatePathDelays is true, -/// it asks the MILP to lock in the buffering decisions, and re-run to -/// calculate only the path delays. Useful for evaluation of modelling accuracy. -template -LogicalResult solveMILP(MILPRes &milpResult, bool calculatePathDelays, - Args &&...args) { - MILP milp = MILP(std::forward(args)...); - if (failed(milp.optimize())) - return failure(); - if (calculatePathDelays && failed(milp.calculatePathDelays())) - return failure(); - if (failed(milp.getResult(milpResult))) - return failure(); - return success(); -} - } // namespace dynamatic #endif // DYNAMATIC_SUPPORT_MILP_H diff --git a/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h b/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h index ae38e43857..1669fb699c 100644 --- a/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h +++ b/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h @@ -161,11 +161,13 @@ class BufferPlacementMILP : public MILP { double targetPeriod, Algorithm algorithm, llvm::StringRef writeTo = ""); - /// Locks all buffer-decision variables to their currently-solved values, - /// replaces the objective with `min Σ(t_*)`, re-optimises, and rewrites the - /// sol log. Lets the dumped values reflect the true min-feasible arrival on - /// each channel signal instead of being packed to the period bound. - LogicalResult calculatePathDelays() override; + /// Re-run the MILP with the buffering decisions locked-in, + /// in order to calculate the actual delays the MILP sees + /// from the characterization approach + /// + /// What buffering decisions to fix is algorithm dependent. + /// Currently only implemented for FPGA'20 and FPL'22. + LogicalResult calculatePathDelays(); protected: /// Represents a list of signals that are buffered together by a single diff --git a/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp b/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp index 1949e940d5..87ea4772be 100644 --- a/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp +++ b/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp @@ -480,6 +480,26 @@ static void logCFDFCUnions(FuncInfo &info, } } +/// Creates, optimizes, and extract results from an MILP in one go. Fails and +/// displays an error message to stderr if any step along the process fails. +/// Otherwise succeeds and stores the MILP's results in the first function +/// argument. +/// +/// if calculatePathDelays is true, +/// it asks the MILP to lock in the buffering decisions, and re-run to +/// calculate only the path delays. Useful for evaluation of modelling accuracy. +static LogicalResult solveMILP(BufferPlacement &placement, + BufferPlacementMILP &milp, + bool calculatePathDelays) { + if (failed(milp.optimize())) + return failure(); + if (calculatePathDelays && failed(milp.calculatePathDelays())) + return failure(); + if (failed(milp.getResult(placement))) + return failure(); + return success(); +} + LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( FuncInfo &info, TimingDatabase &timingDB, BufferPlacement &placement) { @@ -505,9 +525,9 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( if (dumpMILPModels) { writeTo = dumpDir + sep + funcName + "-fpga20-buffers"; } - return solveMILP(placement, polishPaths, solverKind, - timeout, info, timingDB, targetCP, - writeTo); + fpga20::FPGA20Buffers milp(solverKind, timeout, info, timingDB, targetCP, + writeTo); + return solveMILP(placement, milp, polishPaths); } if (algorithm == FPL22) { // Create disjoint block unions of all CFDFCs @@ -526,9 +546,9 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( if (dumpMILPModels) { writeTo = dumpDir + sep + funcName + "-cfunion" + std::to_string(idx); } - if (failed(solveMILP( - placement, polishPaths, solverKind, timeout, info, timingDB, - targetCP, cfUnion, writeTo))) + fpl22::CFDFCUnionBuffers milp(solverKind, timeout, info, timingDB, + targetCP, cfUnion, writeTo); + if (failed(solveMILP(placement, milp, polishPaths))) return failure(); } @@ -537,9 +557,9 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( } // Solve last MILP on channels/units that are not part of any CFDFC - return solveMILP(placement, polishPaths, - solverKind, timeout, info, - timingDB, targetCP, writeTo); + fpl22::OutOfCycleBuffers milp(solverKind, timeout, info, timingDB, targetCP, + writeTo); + return solveMILP(placement, milp, polishPaths); } if (algorithm == FPGA24) { @@ -552,9 +572,9 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( writeTo = dumpDir + sep + funcName + "-cost-aware"; } // Create and solve the MILP - return solveMILP(placement, polishPaths, - solverKind, timeout, info, - timingDB, targetCP, writeTo); + costaware::CostAwareBuffers milp(solverKind, timeout, info, timingDB, + targetCP, writeTo); + return solveMILP(placement, milp, polishPaths); } if (algorithm == MAPBUF) { @@ -562,9 +582,10 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( writeTo = dumpDir + sep + funcName + "-mapbuf"; } // Create and solve the MILP - return solveMILP( - placement, polishPaths, solverKind, timeout, info, timingDB, targetCP, - blifFiles, lutDelay, lutSize, acyclicType, writeTo); + mapbuf::MAPBUFBuffers milp(solverKind, timeout, info, timingDB, targetCP, + blifFiles, lutDelay, lutSize, acyclicType, + writeTo); + return solveMILP(placement, milp, polishPaths); } llvm_unreachable("unknown algorithm"); From c6e05585ed4191274980bb98c308ab931d15b9e5 Mon Sep 17 00:00:00 2001 From: Emmet Murphy Date: Tue, 16 Jun 2026 14:28:50 +0200 Subject: [PATCH 8/9] calculate path delays refactor --- .../Utils/BufferPlacementMILP.h | 11 +++++++ include/dynamatic/Transforms/Passes.td | 8 ++--- .../BufferPlacement/HandshakePlaceBuffers.cpp | 30 ++++--------------- .../Utils/BufferPlacementMILP.cpp | 11 +++++++ tools/dynamatic/dynamatic.cpp | 10 ++++++- tools/dynamatic/scripts/compile.sh | 8 ++++- 6 files changed, 47 insertions(+), 31 deletions(-) diff --git a/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h b/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h index 1669fb699c..4e190082b6 100644 --- a/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h +++ b/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h @@ -169,6 +169,17 @@ class BufferPlacementMILP : public MILP { /// Currently only implemented for FPGA'20 and FPL'22. LogicalResult calculatePathDelays(); + /// Creates, optimizes, and extract results from an MILP in one go. Fails and + /// displays an error message to stderr if any step along the process fails. + /// Otherwise succeeds and stores the MILP's results in the first function + /// argument. + /// + /// if calculatePathDelays is true, + /// it asks the MILP to lock in the buffering decisions, and re-run to + /// calculate only the path delays. Useful for evaluation of modelling + /// accuracy. + LogicalResult solve(BufferPlacement &placement, bool calculatePathDelays); + protected: /// Represents a list of signals that are buffered together by a single /// buffer type, which is denoted by its (potentially null) timing model. diff --git a/include/dynamatic/Transforms/Passes.td b/include/dynamatic/Transforms/Passes.td index 14c18189fb..7db0101a3a 100644 --- a/include/dynamatic/Transforms/Passes.td +++ b/include/dynamatic/Transforms/Passes.td @@ -280,10 +280,10 @@ def HandshakePlaceBuffers : Pass<"handshake-place-buffers"> { "Timeout (in seconds) for the buffer placement MILP (0 for no timeout)">, Option<"dumpMILPModels", "dump-milp-models", "bool", "false", "If true, dump MILP models into a directory named 'buffer-placement'.">, - Option<"polishPaths", "polish-paths", "bool", "false", - "If true, after the throughput-maximising solve, fix buffer decisions and " - "re-solve minimising path arrival times. Lets the dumped sol log show the " - "true min-feasible arrival on each channel signal.">, + Option<"calculatePathDelays", "calculate-path-delays", "bool", "false", + "After buffer placement, re-run the MILP with the buffering decisions " + "locked in to calculate the path delays the MILP believes are present in " + "the circuit.">, Option<"blifFiles", "blif-files", "std::string", "", "Path to AND-Inverter Graphs of dataflow components in Berkeley " "Logic Interchange Format (BLIF).">, diff --git a/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp b/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp index 87ea4772be..456544c7d7 100644 --- a/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp +++ b/lib/Transforms/BufferPlacement/HandshakePlaceBuffers.cpp @@ -480,26 +480,6 @@ static void logCFDFCUnions(FuncInfo &info, } } -/// Creates, optimizes, and extract results from an MILP in one go. Fails and -/// displays an error message to stderr if any step along the process fails. -/// Otherwise succeeds and stores the MILP's results in the first function -/// argument. -/// -/// if calculatePathDelays is true, -/// it asks the MILP to lock in the buffering decisions, and re-run to -/// calculate only the path delays. Useful for evaluation of modelling accuracy. -static LogicalResult solveMILP(BufferPlacement &placement, - BufferPlacementMILP &milp, - bool calculatePathDelays) { - if (failed(milp.optimize())) - return failure(); - if (calculatePathDelays && failed(milp.calculatePathDelays())) - return failure(); - if (failed(milp.getResult(placement))) - return failure(); - return success(); -} - LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( FuncInfo &info, TimingDatabase &timingDB, BufferPlacement &placement) { @@ -527,7 +507,7 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( } fpga20::FPGA20Buffers milp(solverKind, timeout, info, timingDB, targetCP, writeTo); - return solveMILP(placement, milp, polishPaths); + return milp.solve(placement, calculatePathDelays); } if (algorithm == FPL22) { // Create disjoint block unions of all CFDFCs @@ -548,7 +528,7 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( } fpl22::CFDFCUnionBuffers milp(solverKind, timeout, info, timingDB, targetCP, cfUnion, writeTo); - if (failed(solveMILP(placement, milp, polishPaths))) + if (failed(milp.solve(placement, calculatePathDelays))) return failure(); } @@ -559,7 +539,7 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( // Solve last MILP on channels/units that are not part of any CFDFC fpl22::OutOfCycleBuffers milp(solverKind, timeout, info, timingDB, targetCP, writeTo); - return solveMILP(placement, milp, polishPaths); + return milp.solve(placement, calculatePathDelays); } if (algorithm == FPGA24) { @@ -574,7 +554,7 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( // Create and solve the MILP costaware::CostAwareBuffers milp(solverKind, timeout, info, timingDB, targetCP, writeTo); - return solveMILP(placement, milp, polishPaths); + return milp.solve(placement, calculatePathDelays); } if (algorithm == MAPBUF) { @@ -585,7 +565,7 @@ LogicalResult HandshakePlaceBuffersPass::solveBufferPlacementMILP( mapbuf::MAPBUFBuffers milp(solverKind, timeout, info, timingDB, targetCP, blifFiles, lutDelay, lutSize, acyclicType, writeTo); - return solveMILP(placement, milp, polishPaths); + return milp.solve(placement, calculatePathDelays); } llvm_unreachable("unknown algorithm"); diff --git a/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp b/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp index 6260fea5e6..a256e282cc 100644 --- a/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp +++ b/lib/Transforms/BufferPlacement/Utils/BufferPlacementMILP.cpp @@ -244,6 +244,17 @@ BufferPlacementMILP::BufferPlacementMILP(CPSolver::SolverKind solverKind, initialize(); } +LogicalResult BufferPlacementMILP::solve(BufferPlacement &placement, + bool calculatePathDelays) { + if (failed(optimize())) + return failure(); + if (calculatePathDelays && failed(this->calculatePathDelays())) + return failure(); + if (failed(getResult(placement))) + return failure(); + return success(); +} + void BufferPlacementMILP::addChannelVars(Value channel, ArrayRef signalTypes) { diff --git a/tools/dynamatic/dynamatic.cpp b/tools/dynamatic/dynamatic.cpp index 10ad85486b..254e34223f 100644 --- a/tools/dynamatic/dynamatic.cpp +++ b/tools/dynamatic/dynamatic.cpp @@ -304,6 +304,8 @@ class Compile : public Command { static constexpr llvm::StringLiteral ENABLE_SHORT_CIRCUIT = "enable-short-circuit"; static constexpr llvm::StringLiteral SPECULATION = "speculation"; + static constexpr llvm::StringLiteral CALCULATE_PATH_DELAYS = + "calculate-path-delays"; Compile(FrontendState &state) : Command("compile", @@ -340,6 +342,10 @@ class Compile : public Command { addFlag({SPECULATION, "Enable speculation. Requires a #pragma DYN speculate " "`in the source code file."}); + addFlag({CALCULATE_PATH_DELAYS, + "After buffer placement, re-run the MILP with the buffering " + "decisions locked in to calculate the path delays the MILP " + "believes are present in the circuit."}); } CommandResult execute(CommandArguments &args) override; @@ -782,13 +788,15 @@ CommandResult Compile::execute(CommandArguments &args) { std::string enableShortCircuit = args.flags.contains(ENABLE_SHORT_CIRCUIT) ? "1" : "0"; std::string speculation = args.flags.contains(SPECULATION) ? "1" : "0"; + std::string calculatePathDelays = + args.flags.contains(CALCULATE_PATH_DELAYS) ? "1" : "0"; return execCmd(script, state.dynamaticPath, state.getKernelDir(), state.getOutputDir(), state.getKernelName(), buffers, floatToString(state.targetCP, 3), sharing, state.fpUnitsGenerator, rigidification, kInduction, disableLSQ, fastTokenDelivery, milpSolver, straightToQueue, speculation, - enableShortCircuit); + enableShortCircuit, calculatePathDelays); } CommandResult WriteHDL::execute(CommandArguments &args) { diff --git a/tools/dynamatic/scripts/compile.sh b/tools/dynamatic/scripts/compile.sh index 1f671ab135..27bd8981da 100755 --- a/tools/dynamatic/scripts/compile.sh +++ b/tools/dynamatic/scripts/compile.sh @@ -23,6 +23,7 @@ MILP_SOLVER=${13} STRAIGHT_TO_QUEUE=${14} SPECULATION=${15} ENABLE_SHORT_CIRCUIT=${16} +CALCULATE_PATH_DELAYS=${17} LLVM=$DYNAMATIC_DIR/llvm-project DYNAMATIC_BINS=$DYNAMATIC_DIR/bin @@ -354,13 +355,18 @@ else # Smart buffer placement echo_info "Running smart buffer placement with CP = $TARGET_CP and algorithm = '$BUFFER_ALGORITHM'" cd "$COMP_DIR" + if [[ "$CALCULATE_PATH_DELAYS" == "1" ]]; then + CALC_PD_FLAG="calculate-path-delays" + else + CALC_PD_FLAG="" + fi # To enable debug information, make sure that Dynamatic is built with Debug # mode and add "--debug-only=" to the binary call below. Check # out the value of in the cpp source files. "$DYNAMATIC_OPT_BIN" "$F_HANDSHAKE_TRANSFORMED" \ --handshake-set-unit-impl-attr="target-period=$TARGET_CP timing-models=$DYNAMATIC_DIR/data/components.json impl=$FPUNITS_GEN" \ --handshake-set-buffering-properties="version=fpga20" \ - --handshake-place-buffers="algorithm=$BUFFER_ALGORITHM solver=$MILP_SOLVER frequencies=$F_FREQUENCIES timing-models=$DYNAMATIC_DIR/data/components.json target-period=$TARGET_CP timeout=300 dump-milp-models polish-paths \ + --handshake-place-buffers="algorithm=$BUFFER_ALGORITHM solver=$MILP_SOLVER frequencies=$F_FREQUENCIES timing-models=$DYNAMATIC_DIR/data/components.json target-period=$TARGET_CP timeout=300 dump-milp-models $CALC_PD_FLAG \ blif-files=$DYNAMATIC_DIR/data/aig/ lut-delay=0.55 lut-size=6 acyclic-type" \ ${SHARING_PASS:+"$SHARING_PASS"} \ > "$F_HANDSHAKE_BUFFERED" From 27bd787d0ceb378bca28e8cadd639c0054a0394a Mon Sep 17 00:00:00 2001 From: Emmet Murphy Date: Tue, 16 Jun 2026 14:34:40 +0200 Subject: [PATCH 9/9] make calc path delays private --- .../BufferPlacement/Utils/BufferPlacementMILP.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h b/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h index 4e190082b6..fed996e620 100644 --- a/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h +++ b/include/dynamatic/Transforms/BufferPlacement/Utils/BufferPlacementMILP.h @@ -161,14 +161,6 @@ class BufferPlacementMILP : public MILP { double targetPeriod, Algorithm algorithm, llvm::StringRef writeTo = ""); - /// Re-run the MILP with the buffering decisions locked-in, - /// in order to calculate the actual delays the MILP sees - /// from the characterization approach - /// - /// What buffering decisions to fix is algorithm dependent. - /// Currently only implemented for FPGA'20 and FPL'22. - LogicalResult calculatePathDelays(); - /// Creates, optimizes, and extract results from an MILP in one go. Fails and /// displays an error message to stderr if any step along the process fails. /// Otherwise succeeds and stores the MILP's results in the first function @@ -514,6 +506,14 @@ class BufferPlacementMILP : public MILP { /// properties mapping and defines a large constant used for elasticity /// constraints. void initialize(); + + /// Re-run the MILP with the buffering decisions locked-in, + /// in order to calculate the actual delays the MILP sees + /// from the characterization approach + /// + /// What buffering decisions to fix is algorithm dependent. + /// Currently only implemented for FPGA'20 and FPL'22. + LogicalResult calculatePathDelays(); }; } // namespace buffer