diff --git a/.github/workflows/basic_reg_test.sh b/.github/workflows/basic_reg_test.sh index 02d5da8db..1dbf7705c 100755 --- a/.github/workflows/basic_reg_test.sh +++ b/.github/workflows/basic_reg_test.sh @@ -14,6 +14,7 @@ python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/config python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/configuration_chain_use_set --debug --show_thread_logs python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/configuration_chain_use_setb --debug --show_thread_logs python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/configuration_chain_use_set_reset --debug --show_thread_logs +python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/configuration_chain_config_enable_scff --debug --show_thread_logs python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/multi_region_configuration_chain --debug --show_thread_logs python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/fast_configuration_chain --debug --show_thread_logs python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/fast_configuration_chain_use_set --debug --show_thread_logs @@ -108,3 +109,6 @@ python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/tile_organization/til echo -e "Testing global port definition from tiles"; python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/global_tile_ports/global_tile_clock --debug --show_thread_logs python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/global_tile_ports/global_tile_reset --debug --show_thread_logs + +echo -e "Testing yosys flow using custom ys script for running quicklogic device"; +python3 openfpga_flow/scripts/run_fpga_task.py quicklogic_tests/flow_test --debug --show_thread_logs diff --git a/.github/workflows/fpga_verilog_reg_test.sh b/.github/workflows/fpga_verilog_reg_test.sh index a866b7bfc..4e01c1a0a 100755 --- a/.github/workflows/fpga_verilog_reg_test.sh +++ b/.github/workflows/fpga_verilog_reg_test.sh @@ -49,6 +49,9 @@ python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/io/embedded_io --deb echo -e "Testing Verilog generation with SoC I/Os for an FPGA "; python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/io/soc_io --debug --show_thread_logs +echo -e "Testing Verilog generation with registerable I/Os for an FPGA "; +python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/io/registerable_io --debug --show_thread_logs + echo -e "Testing Verilog generation with adder chain across an FPGA"; python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/fabric_chain/adder_chain --debug --show_thread_logs diff --git a/docs/source/manual/arch_lang/annotate_vpr_arch.rst b/docs/source/manual/arch_lang/annotate_vpr_arch.rst index b5d8a93e5..14581f327 100644 --- a/docs/source/manual/arch_lang/annotate_vpr_arch.rst +++ b/docs/source/manual/arch_lang/annotate_vpr_arch.rst @@ -60,21 +60,14 @@ Here is an example: .. code-block:: xml - + + + ... + - ``name=""`` is the port name to appear in the top-level FPGA fabric. -- ``tile_port=""`` is the port name of a physical tile, e.g., ``tile_port="clb.clk"``. - -.. note:: The port of physical tile must be a valid port of the physical definition in VPR architecture! - -.. note:: The linked port of physical tile must meet the following requirements: - - - If the ``global_port`` is set as clock through ``is_clock="true"``, the port of the physical tile must also be a clock port. - - If not a clock, the port of the physical tile must be defined as non-clock global - - The port of the physical tile should have zero connectivity (``Fc=0``) in VPR architecture - - ``is_clock=""`` define if the global port is a clock port at the top-level FPGA fabric. An operating clock port will be driven by proper signals in auto-generated testbenches. - ``is_reset=""`` define if the global port is a reset port at the top-level FPGA fabric. An operating reset port will be driven by proper signals in testbenches. @@ -87,6 +80,26 @@ Here is an example: - ``default_val=""`` define if the default value for the global port when initialized in testbenches. Valid values are either ``0`` or ``1``. For example, the default value of an active-high reset pin is ``0``, while an active-low reset pin is ``1``. +.. note:: A global port could be connected from different tiles by defining multiple lines under a global port!!! + +.. option:: + +- ``name=""`` is the name of a physical tile, e.g., ``name="clb"``. + +- ``port=""`` is the port name of a physical tile, e.g., ``port="clk[0:3]"``. + +- ``x=""`` is the x coordinate of a physical tile, e.g., ``x="1"``. If the x coordinate is set to ``-1``, it means all the valid x coordinates of the selected physical tile in the FPGA device will be considered. + +- ``y=""`` is the y coordinate of a physical tile, e.g., ``y="1"``. If the y coordinate is set to ``-1``, it means all the valid y coordinates of the selected physical tile in the FPGA device will be considered. + +.. note:: The port of physical tile must be a valid port of the physical definition in VPR architecture! If you define a multi-bit port, it must be explicitly defined in the port, e.g., clk[0:3], which must be in the range of the port definition in physical tiles of VPR architecture files!!! + +.. note:: The linked port of physical tile must meet the following requirements: + + - If the ``global_port`` is set as clock through ``is_clock="true"``, the port of the physical tile must also be a clock port. + - If not a clock, the port of the physical tile must be defined as non-clock global + - The port of the physical tile should have zero connectivity (``Fc=0``) in VPR architecture + A more illustrative example: :numref:`fig_global_tile_ports` illustrates the difference between the global ports defined through ``circuit_model`` and ``tile_annotation``. @@ -114,7 +127,9 @@ When a global port, e.g., ``clk``, is defined in ``tile_annotation`` using the f .. code-block:: xml - + + + Clock port ``clk`` of each ``clb`` tile will be connected to a common clock port of the top module, while local clock network is customizable through VPR's architecture description language. For instance, the local clock network can be a programmable clock network. diff --git a/docs/source/manual/arch_lang/circuit_model_examples.rst b/docs/source/manual/arch_lang/circuit_model_examples.rst index 48b7fdf2f..1f4c0c1d3 100644 --- a/docs/source/manual/arch_lang/circuit_model_examples.rst +++ b/docs/source/manual/arch_lang/circuit_model_examples.rst @@ -979,18 +979,18 @@ This example shows: .. _circuit_model_ccff_example: -Configuration-chain Flip-flop -````````````````````````````` +Regular Configuration-chain Flip-flop +````````````````````````````````````` -:numref:`fig_ccff` illustrates an example of scan-chain flop-flop used to build a configuration chain. +:numref:`fig_ccff_config_chain` illustrates an example of standard flip-flops used to build a configuration chain. -.. _fig_ccff: +.. _fig_ccff_config_chain: -.. figure:: ./figures/scff.png +.. figure:: ./figures/config_chain.svg :scale: 50% :alt: SCFF symbol - An example of a Scan-Chain Flip-Flop. + An example of a Flip-Flop organized in a chain. The code describing this FF is: @@ -999,14 +999,94 @@ The code describing this FF is: - - + + This example shows: - A configuration-chain flip-flop which is defined in a Verilog netlist ``ccff.v`` and a SPICE netlist ``ccff.sp`` - The flip-flop has a global clock port, ``CK``, which will be wired a global programming clock +.. note:: + The output ports of the configuration flip-flop must follow a fixed sequence in definition: + - The first output port **MUST** be the data output port, e.g., ``Q``. + - The second output port **MUST** be the **inverted** data output port, e.g., ``QN``. + +Configuration-chain Flip-flop with Configure Enable Signals +``````````````````````````````````````````````````````````` + +Configuration chain could be built with flip-flops with outputs that are enabled by specific signals. +Consider the example in :numref:`fig_ccff_config_chain_config_enable`, the flip-flop has + +- a configure enable signal ``CFG_EN`` to release the data output ``Q`` and ``QN`` +- a pair of data outputs ``Q`` and ``QN`` which are controlled by the configure enable signal ``CFG_EN`` +- a regular data output ``SCAN_Q`` which outputs registered data + +.. _fig_ccff_config_chain_config_enable: + +.. figure:: ./figures/config_chain_config_enable.svg + :scale: 50% + :alt: SCFF symbol + + An example of a Flip-Flop with config enable feature organized in a chain. + +The code describing this FF is: + +.. code-block:: xml + + + + + + + + + + +.. note:: + The output ports of the configuration flip-flop must follow a fixed sequence in definition: + - The first output port **MUST** be the regular data output port, e.g., ``SCAN_Q``. + - The second output port **MUST** be the **inverted** data output port which is activated by the configure enable signal, e.g., ``QN``. + - The second output port **MUST** be the data output port which is activated by the configure enable signal, e.g., ``Q``. + +Configuration-chain Flip-flop with Scan Input +````````````````````````````````````````````` + +Configuration chain could be built with flip-flops with a scan chain input . +Consider the example in :numref:`fig_ccff_config_chain_scan_capable`, the flip-flop has + +- an additional input ``SI`` to enable scan-chain capabaility +- a configure enable signal ``CFG_EN`` to release the data output ``Q`` and ``QN`` +- a pair of data outputs ``Q`` and ``QN`` which are controlled by the configure enable signal ``CFG_EN`` +- a regular data output ``SCAN_Q`` which outputs registered data + +.. _fig_ccff_config_chain_scan_capable: + +.. figure:: ./figures/config_chain_scan_capable.svg + :scale: 50% + :alt: SCFF symbol + + An example of a Flip-Flop with scan input organized in a chain. + +The code describing this FF is: + +.. code-block:: xml + + + + + + + + + + + +.. note:: + The input ports of the configuration flip-flop must follow a fixed sequence in definition: + - The first input port **MUST** be the regular data input port, e.g., ``D``. + - The second input port **MUST** be the scan input port, e.g., ``SI``. + Hard Logics ~~~~~~~~~~~ diff --git a/docs/source/manual/arch_lang/figures/config_chain.svg b/docs/source/manual/arch_lang/figures/config_chain.svg new file mode 100644 index 000000000..d7e1ad8fc --- /dev/null +++ b/docs/source/manual/arch_lang/figures/config_chain.svg @@ -0,0 +1,375 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Produced by OmniGraffle 7.18.1\n2021-01-05 01:03:21 +0000 + + regular + + Layer 1 + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + + + + Q + + + + + QN + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + + + + Q + + + + + QN + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + + + + Q + + + + + QN + + + + + + + + + + + + + + + + + + + + + CLK + + + + + CCFF_HEAD + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + + + + Q + + + + + QN + + + + + + + + + + + + + + + + + + + + + CCFF_TAIL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mem_out[0] + + + + + mem_outb[0] + + + + + mem_out[1] + + + + + mem_outb[1] + + + + + mem_out[2] + + + + + mem_outb[2] + + + + + mem_out[n] + + + + + mem_outb[n] + + + + + + + + Configurable Circuits + + + + + Configuration Chain + + + + + diff --git a/docs/source/manual/arch_lang/figures/config_chain_config_enable.svg b/docs/source/manual/arch_lang/figures/config_chain_config_enable.svg new file mode 100644 index 000000000..4df2c7854 --- /dev/null +++ b/docs/source/manual/arch_lang/figures/config_chain_config_enable.svg @@ -0,0 +1,411 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Produced by OmniGraffle 7.18.1\n2021-01-05 01:03:21 +0000 + + config_enable + + Layer 1 + + + + + + + + + CLK + + + + + CCFF_HEAD + + + + + + + + + + + + + + + + + + + + + + CCFF_TAIL + + + + + + + + + + + mem_out[0] + + + + + mem_outb[0] + + + + + mem_out[1] + + + + + mem_outb[1] + + + + + mem_out[2] + + + + + mem_outb[2] + + + + + mem_out[n] + + + + + mem_outb[n] + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CONFIG_EN + + + + + CFG_EN + + + + + CONFIG_EN + + + + + + + + + + + CONFIG_EN + + + + + + + + CONFIG_EN + + + + + + + + + + + + + + + + + + + + + + + + + + Configurable Circuits + + + + + Configuration Chain + + + + + diff --git a/docs/source/manual/arch_lang/figures/config_chain_scan_capable.svg b/docs/source/manual/arch_lang/figures/config_chain_scan_capable.svg new file mode 100644 index 000000000..68a30d37d --- /dev/null +++ b/docs/source/manual/arch_lang/figures/config_chain_scan_capable.svg @@ -0,0 +1,462 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Produced by OmniGraffle 7.18.1\n2021-01-05 01:03:21 +0000 + + scan_capable + + Layer 1 + + + + + + + + + CLK + + + + + CCFF_HEAD + + + + + + + + + + + + + + + + + + + + + + CCFF_TAIL + + + + + + + + + + + mem_out[0] + + + + + mem_outb[0] + + + + + mem_out[1] + + + + + mem_outb[1] + + + + + mem_out[2] + + + + + mem_outb[2] + + + + + mem_out[n] + + + + + mem_outb[n] + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CONFIG_EN + + + + + CFG_EN + + + + + CONFIG_EN + + + + + + + + + + + CONFIG_EN + + + + + + + + CONFIG_EN + + + + + + + + + + + + + + + + + + + + + + + + + + Configurable Circuits + + + + + Configuration Chain + + + + + SI + + + + + + + + + + + + + + + SI + + + + + + + + + + + + SI + + + + + + + + + + + + SI + + + + + + + + + + + + diff --git a/docs/source/manual/arch_lang/figures/scff.png b/docs/source/manual/arch_lang/figures/scff.png deleted file mode 100644 index db0bf66dd..000000000 Binary files a/docs/source/manual/arch_lang/figures/scff.png and /dev/null differ diff --git a/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp b/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp index d7b19f41a..689d1af6f 100644 --- a/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp +++ b/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp @@ -290,17 +290,35 @@ size_t check_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib, VTR_ASSERT(CIRCUIT_MODEL_CCFF == circuit_lib.model_type(circuit_model)); /* Check if we have D, Set and Reset */ + /* We can have either 1 input which is D or 2 inputs which are D and scan input */ + size_t num_input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true).size(); + if ((1 != num_input_ports) && (2 != num_input_ports)) { + VTR_LOG_ERROR("Configuration flip-flop '%s' must have either 1 or 2 %s ports!\n\tAmong which:\n\t\tthe first input is a regular input (e.g., D)\n\t\tand the other could be scan-chain input (e.g., SI)\n", + circuit_lib.model_name(circuit_model).c_str(), + CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(CIRCUIT_MODEL_PORT_INPUT)]); + num_err++; + } + num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_INPUT, - 1, 1, false); + num_input_ports, 1, false); /* Check if we have a clock */ num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_CLOCK, 1, 1, true); - /* Check if we have 1 or 2 outputs */ + /* Check if we have 1 or 2 or 3 outputs */ size_t num_output_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, true).size(); + if ((1 != num_output_ports) + && (2 != num_output_ports) + && (3 != num_output_ports)) { + VTR_LOG_ERROR("Configuration flip-flop '%s' must have either 1 or 2 or 3 %s ports!\n\tAmong which:\n\t\tthe first port is the manadatory regular data output (e.g., Q) and \n\t\tthe second port could be the inverted data output which can optionally be enabled by configure-enable signal (e.g., QN or cgf_en_QN) and \n\t\tthe third port could be the data output which can optionally be enabled by configure-enable signal (e.g., cgf_en_Q)\n", + circuit_lib.model_name(circuit_model).c_str(), + CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(CIRCUIT_MODEL_PORT_OUTPUT)]); + num_err++; + } + num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, num_output_ports, 1, false); diff --git a/libopenfpga/libarchopenfpga/src/read_xml_tile_annotation.cpp b/libopenfpga/libarchopenfpga/src/read_xml_tile_annotation.cpp index 28d2a6ab8..4f1a42745 100644 --- a/libopenfpga/libarchopenfpga/src/read_xml_tile_annotation.cpp +++ b/libopenfpga/libarchopenfpga/src/read_xml_tile_annotation.cpp @@ -30,25 +30,12 @@ static void read_xml_tile_global_port_annotation(pugi::xml_node& xml_tile, const pugiutil::loc_data& loc_data, openfpga::TileAnnotation& tile_annotation) { - /* We have two mandatory XML attributes - * 1. name of the port - * 2. name of the tile and ports in the format of . + /* We have mandatory XML attributes: + * - name of the port */ const std::string& name_attr = get_attribute(xml_tile, "name", loc_data).as_string(); - const std::string& tile_port_name_attr = get_attribute(xml_tile, "tile_port", loc_data).as_string(); - /* Extract the tile name */ - openfpga::StringToken tokenizer(tile_port_name_attr); - std::vector tile_port_tokens = tokenizer.split('.'); - if (2 != tile_port_tokens.size()) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tile), - "Invalid tile_port attribute '%s'! Valid format is .\n", - tile_port_name_attr.c_str()); - } - /* Extract the tile port information */ - openfpga::PortParser tile_port_parser(tile_port_tokens[1]); - - TileGlobalPortId tile_global_port_id = tile_annotation.create_global_port(name_attr, tile_port_tokens[0], tile_port_parser.port()); + TileGlobalPortId tile_global_port_id = tile_annotation.create_global_port(name_attr); /* Report any duplicated port names */ if (TileGlobalPortId::INVALID() == tile_global_port_id) { @@ -57,6 +44,39 @@ void read_xml_tile_global_port_annotation(pugi::xml_node& xml_tile, name_attr.c_str()); } + /* Iterate over the children under this node, + * each child should be named after + */ + for (pugi::xml_node xml_tile_port : xml_tile.children()) { + /* Error out if the XML child has an invalid name! */ + if (xml_tile_port.name() != std::string("tile")) { + bad_tag(xml_tile_port, loc_data, xml_tile, {"tile"}); + } + /* Parse the name of the tiles and ports */ + const std::string& tile_name_attr = get_attribute(xml_tile_port, "name", loc_data).as_string(); + const std::string& port_name_attr = get_attribute(xml_tile_port, "port", loc_data).as_string(); + + /* Extract the tile port information */ + openfpga::PortParser tile_port_parser(port_name_attr); + + /* Parse tile coordinates */ + vtr::Point tile_coord(get_attribute(xml_tile_port, "x", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(-1), + get_attribute(xml_tile_port, "y", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(-1)); + + /* Add tile port information */ + tile_annotation.add_global_port_tile_information(tile_global_port_id, + tile_name_attr, + tile_port_parser.port(), + tile_coord); + } + + /* Check: Must have at least one global port tile information */ + if (true == tile_annotation.global_port_tile_names(tile_global_port_id).empty()) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tile), + "Invalid tile annotation for global port '%s'! At least 1 tile port definition is expected!\n", + name_attr.c_str()); + } + /* Get is_clock attributes */ tile_annotation.set_global_port_is_clock(tile_global_port_id, get_attribute(xml_tile, "is_clock", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false)); @@ -81,7 +101,7 @@ void read_xml_tile_global_port_annotation(pugi::xml_node& xml_tile, * Top function to parse XML description about tile annotation *******************************************************************/ openfpga::TileAnnotation read_xml_tile_annotations(pugi::xml_node& Node, - const pugiutil::loc_data& loc_data) { + const pugiutil::loc_data& loc_data) { openfpga::TileAnnotation tile_annotations; /* Parse configuration protocol root node */ diff --git a/libopenfpga/libarchopenfpga/src/tile_annotation.cpp b/libopenfpga/libarchopenfpga/src/tile_annotation.cpp index 5bef68a31..a1268aefa 100644 --- a/libopenfpga/libarchopenfpga/src/tile_annotation.cpp +++ b/libopenfpga/libarchopenfpga/src/tile_annotation.cpp @@ -30,16 +30,21 @@ std::string TileAnnotation::global_port_name(const TileGlobalPortId& global_port return global_port_names_[global_port_id]; } -std::string TileAnnotation::global_port_tile_name(const TileGlobalPortId& global_port_id) const { +std::vector TileAnnotation::global_port_tile_names(const TileGlobalPortId& global_port_id) const { VTR_ASSERT(valid_global_port_id(global_port_id)); return global_port_tile_names_[global_port_id]; } -BasicPort TileAnnotation::global_port_tile_port(const TileGlobalPortId& global_port_id) const { +std::vector TileAnnotation::global_port_tile_ports(const TileGlobalPortId& global_port_id) const { VTR_ASSERT(valid_global_port_id(global_port_id)); return global_port_tile_ports_[global_port_id]; } +std::vector> TileAnnotation::global_port_tile_coordinates(const TileGlobalPortId& global_port_id) const { + VTR_ASSERT(valid_global_port_id(global_port_id)); + return global_port_tile_coordinates_[global_port_id]; +} + bool TileAnnotation::global_port_is_clock(const TileGlobalPortId& global_port_id) const { VTR_ASSERT(valid_global_port_id(global_port_id)); return global_port_is_clock_[global_port_id]; @@ -63,9 +68,7 @@ size_t TileAnnotation::global_port_default_value(const TileGlobalPortId& global_ /************************************************************************ * Public Mutators ***********************************************************************/ -TileGlobalPortId TileAnnotation::create_global_port(const std::string& port_name, - const std::string& tile_name, - const BasicPort& tile_port) { +TileGlobalPortId TileAnnotation::create_global_port(const std::string& port_name) { /* Ensure that the name is unique */ std::map::iterator it = global_port_name2ids_.find(port_name); if (it != global_port_name2ids_.end()) { @@ -76,8 +79,9 @@ TileGlobalPortId TileAnnotation::create_global_port(const std::string& port_name TileGlobalPortId port_id = TileGlobalPortId(global_port_ids_.size()); global_port_ids_.push_back(port_id); global_port_names_.push_back(port_name); - global_port_tile_names_.push_back(tile_name); - global_port_tile_ports_.push_back(tile_port); + global_port_tile_names_.emplace_back(); + global_port_tile_ports_.emplace_back(); + global_port_tile_coordinates_.emplace_back(); global_port_is_clock_.push_back(false); global_port_is_set_.push_back(false); global_port_is_reset_.push_back(false); @@ -89,6 +93,16 @@ TileGlobalPortId TileAnnotation::create_global_port(const std::string& port_name return port_id; } +void TileAnnotation::add_global_port_tile_information(const TileGlobalPortId& global_port_id, + const std::string& tile_name, + const BasicPort& tile_port, + const vtr::Point& tile_coord) { + VTR_ASSERT(valid_global_port_id(global_port_id)); + global_port_tile_names_[global_port_id].push_back(tile_name); + global_port_tile_ports_[global_port_id].push_back(tile_port); + global_port_tile_coordinates_[global_port_id].push_back(tile_coord); +} + void TileAnnotation::set_global_port_is_clock(const TileGlobalPortId& global_port_id, const bool& is_clock) { VTR_ASSERT(valid_global_port_id(global_port_id)); diff --git a/libopenfpga/libarchopenfpga/src/tile_annotation.h b/libopenfpga/libarchopenfpga/src/tile_annotation.h index b87ceb74a..1f863d1ac 100644 --- a/libopenfpga/libarchopenfpga/src/tile_annotation.h +++ b/libopenfpga/libarchopenfpga/src/tile_annotation.h @@ -9,6 +9,7 @@ #include #include "vtr_vector.h" +#include "vtr_geometry.h" #include "openfpga_port.h" @@ -39,8 +40,9 @@ class TileAnnotation { global_port_range global_ports() const; public: /* Public accessors */ std::string global_port_name(const TileGlobalPortId& global_port_id) const; - std::string global_port_tile_name(const TileGlobalPortId& global_port_id) const; - BasicPort global_port_tile_port(const TileGlobalPortId& global_port_id) const; + std::vector global_port_tile_names(const TileGlobalPortId& global_port_id) const; + std::vector global_port_tile_ports(const TileGlobalPortId& global_port_id) const; + std::vector> global_port_tile_coordinates(const TileGlobalPortId& global_port_id) const; bool global_port_is_clock(const TileGlobalPortId& global_port_id) const; bool global_port_is_set(const TileGlobalPortId& global_port_id) const; bool global_port_is_reset(const TileGlobalPortId& global_port_id) const; @@ -49,9 +51,12 @@ class TileAnnotation { /* By default, we do not set it as a clock. * Users should set it through the set_global_port_is_clock() function */ - TileGlobalPortId create_global_port(const std::string& port_name, - const std::string& tile_name, - const BasicPort& tile_port); + TileGlobalPortId create_global_port(const std::string& port_name); + /* Add tile port information */ + void add_global_port_tile_information(const TileGlobalPortId& global_port_id, + const std::string& tile_name, + const BasicPort& tile_port, + const vtr::Point& tile_coord); void set_global_port_is_clock(const TileGlobalPortId& global_port_id, const bool& is_clock); void set_global_port_is_set(const TileGlobalPortId& global_port_id, @@ -70,8 +75,9 @@ class TileAnnotation { /* Global port information for tiles */ vtr::vector global_port_ids_; vtr::vector global_port_names_; - vtr::vector global_port_tile_names_; - vtr::vector global_port_tile_ports_; + vtr::vector> global_port_tile_names_; + vtr::vector>> global_port_tile_coordinates_; + vtr::vector> global_port_tile_ports_; vtr::vector global_port_is_clock_; vtr::vector global_port_is_reset_; vtr::vector global_port_is_set_; diff --git a/libopenfpga/libarchopenfpga/src/write_xml_tile_annotation.cpp b/libopenfpga/libarchopenfpga/src/write_xml_tile_annotation.cpp index a3214d4df..69a568fc5 100644 --- a/libopenfpga/libarchopenfpga/src/write_xml_tile_annotation.cpp +++ b/libopenfpga/libarchopenfpga/src/write_xml_tile_annotation.cpp @@ -51,11 +51,6 @@ void write_xml_tile_annotation_global_port(std::fstream& fp, write_xml_attribute(fp, "name", tile_annotation.global_port_name(global_port_id).c_str()); - std::string tile_port_attr = tile_annotation.global_port_tile_name(global_port_id) - + "." - + generate_tile_port_name(tile_annotation.global_port_tile_port(global_port_id)); - write_xml_attribute(fp, "tile_port", tile_port_attr.c_str()); - write_xml_attribute(fp, "is_clock", tile_annotation.global_port_is_clock(global_port_id)); write_xml_attribute(fp, "is_set", tile_annotation.global_port_is_set(global_port_id)); @@ -64,7 +59,18 @@ void write_xml_tile_annotation_global_port(std::fstream& fp, write_xml_attribute(fp, "default_value", tile_annotation.global_port_default_value(global_port_id)); - fp << "/>" << "\n"; + fp << ">" << "\n"; + + for (size_t tile_info_id = 0; tile_info_id < tile_annotation.global_port_tile_names(global_port_id).size(); ++tile_info_id) { + fp << "\t\t\t" << ""; + } + + fp << "\t\t" << ""; } /******************************************************************** diff --git a/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h b/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h index 3f27c6966..2f9bae817 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h +++ b/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h @@ -13,7 +13,10 @@ namespace openfpga { /* Top-level module name */ constexpr char* FPGA_TOP_MODULE_NAME = "fpga_top"; +constexpr char* CONFIGURABLE_MEMORY_CHAIN_IN_NAME = "ccff_head"; +constexpr char* CONFIGURABLE_MEMORY_CHAIN_OUT_NAME = "ccff_tail"; constexpr char* CONFIGURABLE_MEMORY_DATA_OUT_NAME = "mem_out"; +constexpr char* CONFIGURABLE_MEMORY_INVERTED_DATA_OUT_NAME = "mem_outb"; /* IO PORT */ /* Prefix of global input, output and inout ports of FPGA fabric */ diff --git a/openfpga/src/base/openfpga_naming.cpp b/openfpga/src/base/openfpga_naming.cpp index d2e41f549..192015ddf 100644 --- a/openfpga/src/base/openfpga_naming.cpp +++ b/openfpga/src/base/openfpga_naming.cpp @@ -708,7 +708,7 @@ std::string generate_formal_verification_sram_port_name(const CircuitLibrary& ci * TODO: This could be replaced as a constexpr string *********************************************************************/ std::string generate_configuration_chain_head_name() { - return std::string("ccff_head"); + return std::string(CONFIGURABLE_MEMORY_CHAIN_IN_NAME); } /********************************************************************* @@ -716,7 +716,7 @@ std::string generate_configuration_chain_head_name() { * TODO: This could be replaced as a constexpr string *********************************************************************/ std::string generate_configuration_chain_tail_name() { - return std::string("ccff_tail"); + return std::string(CONFIGURABLE_MEMORY_CHAIN_OUT_NAME); } /********************************************************************* @@ -732,7 +732,7 @@ std::string generate_configurable_memory_data_out_name() { * TODO: This could be replaced as a constexpr string *********************************************************************/ std::string generate_configurable_memory_inverted_data_out_name() { - return std::string("mem_outb"); + return std::string(CONFIGURABLE_MEMORY_INVERTED_DATA_OUT_NAME); } /********************************************************************* diff --git a/openfpga/src/fabric/build_memory_modules.cpp b/openfpga/src/fabric/build_memory_modules.cpp index 32d1c93b2..970ef8a95 100644 --- a/openfpga/src/fabric/build_memory_modules.cpp +++ b/openfpga/src/fabric/build_memory_modules.cpp @@ -77,8 +77,6 @@ void add_module_input_nets_to_mem_modules(ModuleManager& module_manager, * j-th pin of output port of the i-th child module is wired to the j + i*W -th * pin of output port of the memory module, where W is the size of port * 3. It assumes fixed port name for output ports - * - * We cache the module nets that have been created because they will be used later ********************************************************************/ static std::vector add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager, @@ -165,15 +163,11 @@ void add_module_output_nets_to_mem_modules(ModuleManager& module_manager, * add_module_nets_cmos_memory_chain_config_bus() !!! *********************************************************************/ static -void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager, - const ModuleId& parent_module, - const std::vector& output_nets, - const CircuitLibrary& circuit_lib, - const CircuitPortId& model_input_port, - const CircuitPortId& model_output_port) { - /* Counter for the nets */ - size_t net_counter = 0; - +void add_module_nets_to_cmos_memory_config_chain_module(ModuleManager& module_manager, + const ModuleId& parent_module, + const CircuitLibrary& circuit_lib, + const CircuitPortId& model_input_port, + const CircuitPortId& model_output_port) { for (size_t mem_index = 0; mem_index < module_manager.configurable_children(parent_module).size(); ++mem_index) { ModuleId net_src_module_id; size_t net_src_instance_id; @@ -219,21 +213,9 @@ void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager, /* Create a net for each pin */ for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) { /* Create a net and add source and sink to it */ - ModuleNetId net; - if (0 == mem_index) { - net = module_manager.create_module_net(parent_module); - } else { - net = output_nets[net_counter]; - } - /* Add net source */ - module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]); + ModuleNetId net = create_module_source_pin_net(module_manager, parent_module, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]); /* Add net sink */ module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]); - - /* Update net counter */ - if (0 < mem_index) { - net_counter++; - } } } @@ -263,17 +245,90 @@ void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager, /* Create a net for each pin */ for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) { /* Create a net and add source and sink to it */ - ModuleNetId net = output_nets[net_counter]; - /* Add net source */ - module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]); + ModuleNetId net = create_module_source_pin_net(module_manager, parent_module, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]); /* Add net sink */ module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]); - - /* Update net counter */ - net_counter++; } +} - VTR_ASSERT(net_counter == output_nets.size()); +/******************************************************************** + * Connect the scan input of all the memory modules + * under the parent module in a chain + * + * +--------+ +--------+ +--------+ + * ccff_head --->| Memory |--->| Memory |--->... --->| Memory | + * | Module | | Module | | Module | + * | [0] | | [1] | | [N-1] | + * +--------+ +--------+ +--------+ + * For the 1st memory module: + * net source is the configuration chain head of the primitive module + * net sink is the scan input of the next memory module + * + * For the rest of memory modules: + * net source is the configuration chain tail of the previous memory module + * net sink is the scan input of the next memory module + * + * Note that: + * This function is designed for memory modules ONLY! + * Do not use it to replace the + * add_module_nets_cmos_memory_chain_config_bus() !!! + *********************************************************************/ +static +void add_module_nets_to_cmos_memory_scan_chain_module(ModuleManager& module_manager, + const ModuleId& parent_module, + const CircuitLibrary& circuit_lib, + const CircuitPortId& model_input_port, + const CircuitPortId& model_output_port) { + for (size_t mem_index = 0; mem_index < module_manager.configurable_children(parent_module).size(); ++mem_index) { + ModuleId net_src_module_id; + size_t net_src_instance_id; + ModulePortId net_src_port_id; + + ModuleId net_sink_module_id; + size_t net_sink_instance_id; + ModulePortId net_sink_port_id; + + if (0 == mem_index) { + /* Find the port name of configuration chain head */ + std::string src_port_name = generate_configuration_chain_head_name(); + net_src_module_id = parent_module; + net_src_instance_id = 0; + net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name); + + /* Find the port name of next memory module */ + std::string sink_port_name = circuit_lib.port_prefix(model_input_port); + net_sink_module_id = module_manager.configurable_children(parent_module)[mem_index]; + net_sink_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index]; + net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name); + } else { + /* Find the port name of previous memory module */ + std::string src_port_name = circuit_lib.port_prefix(model_output_port); + net_src_module_id = module_manager.configurable_children(parent_module)[mem_index - 1]; + net_src_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index - 1]; + net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name); + + /* Find the port name of next memory module */ + std::string sink_port_name = circuit_lib.port_prefix(model_input_port); + net_sink_module_id = module_manager.configurable_children(parent_module)[mem_index]; + net_sink_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index]; + net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name); + } + + /* Get the pin id for source port */ + BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id); + /* Get the pin id for sink port */ + BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id); + /* Port sizes of source and sink should match */ + VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width()); + + /* Create a net for each pin */ + for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) { + /* Create a net and add source and sink to it */ + ModuleNetId net = create_module_source_pin_net(module_manager, parent_module, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]); + /* Add net sink */ + module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]); + } + } } /********************************************************************* @@ -382,7 +437,7 @@ void build_memory_flatten_module(ModuleManager& module_manager, * scan-chain--->| CCFF |--->| CCFF |--->... --->| CCFF |---->scan-chain * input&clock | [0] | | [1] | | [N-1] | output * +-------+ +-------+ +-------+ - * | | ... | + * | | ... | config-memory output * v v v * +-----------------------------------------+ * | Multiplexer Configuration port | @@ -397,12 +452,15 @@ void build_memory_chain_module(ModuleManager& module_manager, /* Get the input ports from the SRAM */ std::vector sram_input_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_INPUT, true); - /* Should have only 1 input port */ - VTR_ASSERT( 1 == sram_input_ports.size() ); + /* Should have only 1 or 2 input port */ + VTR_ASSERT( (1 == sram_input_ports.size()) + || (2 == sram_input_ports.size()) ); /* Get the output ports from the SRAM */ std::vector sram_output_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_OUTPUT, true); - /* Should have only 1 or 2 output port */ - VTR_ASSERT( (1 == sram_output_ports.size()) || ( 2 == sram_output_ports.size()) ); + /* Should have only 1 or 2 or 3 output port */ + VTR_ASSERT( (1 == sram_output_ports.size()) + || (2 == sram_output_ports.size()) + || (3 == sram_output_ports.size()) ); /* Create a module and add to the module manager */ ModuleId mem_module = module_manager.add_module(module_name); @@ -428,13 +486,27 @@ void build_memory_chain_module(ModuleManager& module_manager, circuit_lib.port_size(sram_output_ports[0])); module_manager.add_port(mem_module, chain_tail_port, ModuleManager::MODULE_OUTPUT_PORT); - /* Add each output port: port width should match the number of memories */ - for (size_t iport = 0; iport < sram_output_ports.size(); ++iport) { + /* There could be 3 conditions w.r.t. the number of output ports: + * - Only one output port is defined. In this case, the 1st port is the Q + * In such case, only Q will be considered as data output ports + * - Two output port is defined. In this case, the 1st port is the Q while the 2nd port is the QN + * In such case, both Q and QN will be considered as data output ports + * - Three output port is defined. + * In this case: + * - the 1st port is the Q (the chain output) + * - the 2nd port is the QN (the inverted data output) + * - the 3nd port is the configure-enabled Q + * In such case, configure-enabled Q and QN will be considered as data output ports + */ + size_t num_data_output_ports = sram_output_ports.size(); + if (3 == sram_output_ports.size()) { + num_data_output_ports = 2; + } + for (size_t iport = 0; iport < num_data_output_ports; ++iport) { std::string port_name; if (0 == iport) { port_name = generate_configurable_memory_data_out_name(); - } else { - VTR_ASSERT( 1 == iport); + } else if (1 == iport) { port_name = generate_configurable_memory_inverted_data_out_name(); } BasicPort output_port(port_name, num_mems); @@ -444,9 +516,6 @@ void build_memory_chain_module(ModuleManager& module_manager, /* Find the sram module in the module manager */ ModuleId sram_mem_module = module_manager.find_module(circuit_lib.model_name(sram_model)); - /* Cache the output nets for non-inverted data output */ - std::vector mem_output_nets; - /* Instanciate each submodule */ for (size_t i = 0; i < num_mems; ++i) { size_t sram_mem_instance = module_manager.num_instance(mem_module, sram_mem_module); @@ -454,7 +523,7 @@ void build_memory_chain_module(ModuleManager& module_manager, module_manager.add_configurable_child(mem_module, sram_mem_module, sram_mem_instance); /* Build module nets to wire outputs of sram modules to outputs of memory module */ - for (size_t iport = 0; iport < sram_output_ports.size(); ++iport) { + for (size_t iport = 0; iport < num_data_output_ports; ++iport) { std::string port_name; if (0 == iport) { port_name = generate_configurable_memory_data_out_name(); @@ -462,20 +531,32 @@ void build_memory_chain_module(ModuleManager& module_manager, VTR_ASSERT( 1 == iport); port_name = generate_configurable_memory_inverted_data_out_name(); } + /* Find the proper data output port + * The exception is when there are 3 output ports defined + * The 3rd port is the regular data output port to be used + */ + CircuitPortId data_output_port_to_connect = sram_output_ports[iport]; + if ((3 == sram_output_ports.size()) && (0 == iport)) { + data_output_port_to_connect = sram_output_ports.back(); + } + std::vector output_nets = add_module_output_nets_to_chain_mem_modules(module_manager, mem_module, - port_name, circuit_lib, sram_output_ports[iport], + port_name, circuit_lib, data_output_port_to_connect, sram_mem_module, i, sram_mem_instance); - /* Cache only for regular data outputs */ - if (0 == iport) { - mem_output_nets.insert(mem_output_nets.end(), output_nets.begin(), output_nets.end()); - } } } /* Build module nets to wire the configuration chain */ - add_module_nets_to_cmos_memory_chain_module(module_manager, mem_module, mem_output_nets, - circuit_lib, sram_input_ports[0], sram_output_ports[0]); + add_module_nets_to_cmos_memory_config_chain_module(module_manager, mem_module, + circuit_lib, sram_input_ports[0], sram_output_ports[0]); + /* If there is a second input defined, + * add nets to short wire the 2nd inputs to the first inputs + */ + if (2 == sram_input_ports.size()) { + add_module_nets_to_cmos_memory_scan_chain_module(module_manager, mem_module, + circuit_lib, sram_input_ports[1], sram_output_ports[0]); + } /* Add global ports to the pb_module: * This is a much easier job after adding sub modules (instances), diff --git a/openfpga/src/fabric/build_top_module_connection.cpp b/openfpga/src/fabric/build_top_module_connection.cpp index 8843f5210..354e785a2 100644 --- a/openfpga/src/fabric/build_top_module_connection.cpp +++ b/openfpga/src/fabric/build_top_module_connection.cpp @@ -695,33 +695,42 @@ void add_top_module_nets_connect_grids_and_gsbs(ModuleManager& module_manager, * that are defined as global in tile annotation *******************************************************************/ static -void build_top_module_global_net_for_given_grid_module(ModuleManager& module_manager, - const ModuleId& top_module, - const ModulePortId& top_module_port, - const TileAnnotation& tile_annotation, - const TileGlobalPortId& tile_global_port, - const DeviceGrid& grids, - const vtr::Point& grid_coordinate, - const e_side& border_side, - const vtr::Matrix& grid_instance_ids) { +int build_top_module_global_net_for_given_grid_module(ModuleManager& module_manager, + const ModuleId& top_module, + const ModulePortId& top_module_port, + const TileAnnotation& tile_annotation, + const TileGlobalPortId& tile_global_port, + const BasicPort& tile_port_to_connect, + const DeviceGrid& grids, + const vtr::Point& grid_coordinate, + const e_side& border_side, + const vtr::Matrix& grid_instance_ids) { t_physical_tile_type_ptr physical_tile = grids[grid_coordinate.x()][grid_coordinate.y()].type; - /* Ensure physical tile matches the global port definition */ - VTR_ASSERT(std::string(physical_tile->name) == tile_annotation.global_port_tile_name(tile_global_port)); /* Find the port of the grid module according to the tile annotation */ - int grid_pin_index = physical_tile->num_pins; + int grid_pin_start_index = physical_tile->num_pins; for (const t_physical_tile_port& tile_port : physical_tile->ports) { - if (std::string(tile_port.name) == tile_annotation.global_port_tile_port(tile_global_port).get_name()) { + if (std::string(tile_port.name) == tile_port_to_connect.get_name()) { + BasicPort ref_tile_port(tile_port.name, tile_port.num_pins); /* Port size must match!!! */ - VTR_ASSERT(size_t(tile_port.num_pins) == tile_annotation.global_port_tile_port(tile_global_port).get_width()); - /* TODO: Should check there is only port matching!!! */ - grid_pin_index = tile_port.absolute_first_pin_index; + if (false == ref_tile_port.contained(tile_port_to_connect)) { + VTR_LOG_ERROR("Tile annotation '%s' port '%s[%lu:%lu]' is out of the range of physical tile port '%s[%lu:%lu]'!", + tile_annotation.global_port_name(tile_global_port).c_str(), + tile_port_to_connect.get_name().c_str(), + tile_port_to_connect.get_lsb(), + tile_port_to_connect.get_msb(), + ref_tile_port.get_name().c_str(), + ref_tile_port.get_lsb(), + ref_tile_port.get_msb()); + return CMD_EXEC_FATAL_ERROR; + } + grid_pin_start_index = tile_port.absolute_first_pin_index; break; } } /* Ensure the pin index is valid */ - VTR_ASSERT(grid_pin_index < physical_tile->num_pins); + VTR_ASSERT(grid_pin_start_index < physical_tile->num_pins); /* Find the module name for this type of grid */ std::string grid_module_name_prefix(GRID_MODULE_NAME_PREFIX); @@ -730,23 +739,39 @@ void build_top_module_global_net_for_given_grid_module(ModuleManager& module_man VTR_ASSERT(true == module_manager.valid_module_id(grid_module)); size_t grid_instance = grid_instance_ids[grid_coordinate.x()][grid_coordinate.y()]; - /* Find the module pin */ - size_t grid_pin_width = physical_tile->pin_width_offset[grid_pin_index]; - size_t grid_pin_height = physical_tile->pin_height_offset[grid_pin_index]; - std::vector pin_sides = find_physical_tile_pin_side(physical_tile, grid_pin_index, border_side); - for (const e_side& pin_side : pin_sides) { - std::string grid_port_name = generate_grid_port_name(grid_coordinate, - grid_pin_width, grid_pin_height, - pin_side, - grid_pin_index, false); - ModulePortId grid_port_id = module_manager.find_module_port(grid_module, grid_port_name); - VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_port_id)); + VTR_ASSERT(1 == physical_tile->equivalent_sites.size()); - /* Build nets */ - add_module_bus_nets(module_manager, top_module, - top_module, 0, top_module_port, - grid_module, grid_instance, grid_port_id); + /* A tile may consist of multiple subtile, connect to all the pins from sub tiles */ + for (int iz = 0; iz < physical_tile->capacity; ++iz) { + /* TODO: This should be replaced by using a pin mapping data structure from physical tile! */ + int grid_pin_index = grid_pin_start_index + iz * physical_tile->equivalent_sites[0]->pb_type->num_pins; + /* Find the module pin */ + size_t grid_pin_width = physical_tile->pin_width_offset[grid_pin_index]; + size_t grid_pin_height = physical_tile->pin_height_offset[grid_pin_index]; + std::vector pin_sides = find_physical_tile_pin_side(physical_tile, grid_pin_index, border_side); + for (const e_side& pin_side : pin_sides) { + std::string grid_port_name = generate_grid_port_name(grid_coordinate, + grid_pin_width, grid_pin_height, + pin_side, + grid_pin_index, false); + ModulePortId grid_port_id = module_manager.find_module_port(grid_module, grid_port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_port_id)); + + /* Build nets */ + BasicPort src_port = module_manager.module_port(top_module, top_module_port); + for (size_t pin_id = 0; pin_id < tile_port_to_connect.pins().size(); ++pin_id) { + ModuleNetId net = create_module_source_pin_net(module_manager, top_module, + top_module, 0, + top_module_port, src_port.pins()[pin_id]); + VTR_ASSERT(ModuleNetId::INVALID() != net); + + /* Configure the net sink */ + module_manager.add_module_net_sink(top_module, net, grid_module, grid_instance, grid_port_id, tile_port_to_connect.pins()[pin_id]); + } + } } + + return CMD_EXEC_SUCCESS; } /******************************************************************** @@ -757,17 +782,23 @@ int add_top_module_global_ports_from_grid_modules(ModuleManager& module_manager, const TileAnnotation& tile_annotation, const DeviceGrid& grids, const vtr::Matrix& grid_instance_ids) { + int status = CMD_EXEC_SUCCESS; - /* Add the global ports which are yet added to the top-level module + /* Add the global ports which are NOT yet added to the top-level module * (in different names than the global ports defined in circuit library */ std::vector global_ports_to_add; for (const TileGlobalPortId& tile_global_port : tile_annotation.global_ports()) { ModulePortId module_port = module_manager.find_module_port(top_module, tile_annotation.global_port_name(tile_global_port)); + /* The global port size is derived from the maximum port size among all the tile port defintion */ if (ModulePortId::INVALID() == module_port) { BasicPort global_port_to_add; global_port_to_add.set_name(tile_annotation.global_port_name(tile_global_port)); - global_port_to_add.set_width(tile_annotation.global_port_tile_port(tile_global_port).get_width()); + size_t max_port_size = 0; + for (const BasicPort& tile_port : tile_annotation.global_port_tile_ports(tile_global_port)) { + max_port_size = std::max(tile_port.get_width(), max_port_size); + } + global_port_to_add.set_width(max_port_size); global_ports_to_add.push_back(global_port_to_add); } } @@ -784,72 +815,130 @@ int add_top_module_global_ports_from_grid_modules(ModuleManager& module_manager, ModulePortId top_module_port = module_manager.find_module_port(top_module, tile_annotation.global_port_name(tile_global_port)); VTR_ASSERT(ModulePortId::INVALID() != top_module_port); - /* Spot the port from child modules from core grids */ - for (size_t ix = 1; ix < grids.width() - 1; ++ix) { - for (size_t iy = 1; iy < grids.height() - 1; ++iy) { - /* Bypass EMPTY tiles */ - if (true == is_empty_type(grids[ix][iy].type)) { - continue; - } - /* Skip width or height > 1 tiles (mostly heterogeneous blocks) */ - if ( (0 < grids[ix][iy].width_offset) - || (0 < grids[ix][iy].height_offset)) { - continue; - } + for (size_t tile_info_id = 0; tile_info_id < tile_annotation.global_port_tile_names(tile_global_port).size(); ++tile_info_id) { + std::string tile_name = tile_annotation.global_port_tile_names(tile_global_port)[tile_info_id]; + BasicPort tile_port = tile_annotation.global_port_tile_ports(tile_global_port)[tile_info_id]; + /* Find the coordinates for the wanted tiles */ + vtr::Point start_coord(1, 1); + vtr::Point end_coord(grids.width() - 1, grids.height() - 1); + vtr::Point range = tile_annotation.global_port_tile_coordinates(tile_global_port)[tile_info_id]; + bool out_of_range = false; - /* Bypass the tiles whose names do not match */ - if (std::string(grids[ix][iy].type->name) != tile_annotation.global_port_tile_name(tile_global_port)) { - continue; + /* -1 means all the x should be considered */ + if (size_t(-1) != range.x()) { + if ((range.x() < start_coord.x()) || (range.x() > end_coord.x())) { + out_of_range = true; + } else { + /* Set the range */ + start_coord.set_x(range.x()); + end_coord.set_x(range.x()); } - - /* Create nets and finish connection build-up */ - build_top_module_global_net_for_given_grid_module(module_manager, - top_module, - top_module_port, - tile_annotation, - tile_global_port, - grids, - vtr::Point(ix, iy), - NUM_SIDES, - grid_instance_ids); - } - } - /* Walk through all the grids on the perimeter, which are I/O grids */ - for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) { - for (const vtr::Point& io_coordinate : io_coordinates[io_side]) { - /* Bypass EMPTY grid */ - if (true == is_empty_type(grids[io_coordinate.x()][io_coordinate.y()].type)) { - continue; - } + /* -1 means all the y should be considered */ + if (size_t(-1) != range.y()) { + if ((range.y() < start_coord.y()) || (range.y() > end_coord.y())) { + out_of_range = true; + } else { + /* Set the range */ + start_coord.set_y(range.y()); + end_coord.set_y(range.y()); + } + } + + /* Error out immediately if the coordinate is not valid! */ + if (true == out_of_range) { + VTR_LOG_ERROR("Coordinate (%lu, %lu) in tile annotation for tile '%s' is out of range (%lu:%lu, %lu:%lu)!", + range.x(), range.y(), tile_name.c_str(), + start_coord.x(), end_coord.x(), start_coord.y(), end_coord.y()); + return CMD_EXEC_FATAL_ERROR; + } + + /* Spot the port from child modules from core grids */ + for (size_t ix = start_coord.x(); ix < end_coord.x(); ++ix) { + for (size_t iy = start_coord.y(); iy < end_coord.y(); ++iy) { + /* Bypass EMPTY tiles */ + if (true == is_empty_type(grids[ix][iy].type)) { + continue; + } + /* Skip width or height > 1 tiles (mostly heterogeneous blocks) */ + if ( (0 < grids[ix][iy].width_offset) + || (0 < grids[ix][iy].height_offset)) { + continue; + } + + /* Bypass the tiles whose names do not match */ + if (std::string(grids[ix][iy].type->name) != tile_name) { + continue; + } + + /* Create nets and finish connection build-up */ + status = build_top_module_global_net_for_given_grid_module(module_manager, + top_module, + top_module_port, + tile_annotation, + tile_global_port, + tile_port, + grids, + vtr::Point(ix, iy), + NUM_SIDES, + grid_instance_ids); + if (CMD_EXEC_FATAL_ERROR == status) { + return status; + } + } + } + + /* Walk through all the grids on the perimeter, which are I/O grids */ + for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) { + for (const vtr::Point& io_coordinate : io_coordinates[io_side]) { + /* Bypass EMPTY grid */ + if (true == is_empty_type(grids[io_coordinate.x()][io_coordinate.y()].type)) { + continue; + } - /* Skip width or height > 1 tiles (mostly heterogeneous blocks) */ - if ( (0 < grids[io_coordinate.x()][io_coordinate.y()].width_offset) - || (0 < grids[io_coordinate.x()][io_coordinate.y()].height_offset)) { - continue; - } + /* Skip width or height > 1 tiles (mostly heterogeneous blocks) */ + if ( (0 < grids[io_coordinate.x()][io_coordinate.y()].width_offset) + || (0 < grids[io_coordinate.x()][io_coordinate.y()].height_offset)) { + continue; + } - /* Bypass the tiles whose names do not match */ - if (std::string(grids[io_coordinate.x()][io_coordinate.y()].type->name) != tile_annotation.global_port_tile_name(tile_global_port)) { - continue; - } + /* Bypass the tiles whose names do not match */ + if (std::string(grids[io_coordinate.x()][io_coordinate.y()].type->name) != tile_name) { + continue; + } - /* Create nets and finish connection build-up */ - build_top_module_global_net_for_given_grid_module(module_manager, - top_module, - top_module_port, - tile_annotation, - tile_global_port, - grids, - io_coordinate, - io_side, - grid_instance_ids); + /* Check if the coordinate satisfy the tile coordinate defintion + * - Bypass if the x is a specific number (!= -1), and io_coordinate is different + * - Bypass if the y is a specific number (!= -1), and io_coordinate is different + */ + if ((size_t(-1) != range.x()) && (range.x() != io_coordinate.x())) { + continue; + } + if ((size_t(-1) != range.y()) && (range.y() != io_coordinate.y())) { + continue; + } + + /* Create nets and finish connection build-up */ + status = build_top_module_global_net_for_given_grid_module(module_manager, + top_module, + top_module_port, + tile_annotation, + tile_global_port, + tile_port, + grids, + io_coordinate, + io_side, + grid_instance_ids); + if (CMD_EXEC_FATAL_ERROR == status) { + return status; + } + } } } } - return CMD_EXEC_SUCCESS; + return status; } } /* end namespace openfpga */ diff --git a/openfpga/src/fpga_bitstream/fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/fabric_bitstream.cpp index 6ea5c8168..785327661 100644 --- a/openfpga/src/fpga_bitstream/fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/fabric_bitstream.cpp @@ -21,6 +21,9 @@ FabricBitstream::FabricBitstream() { num_regions_ = 0; invalid_region_ids_.clear(); + + use_address_ = false; + use_wl_address_ = false; } /************************************************** diff --git a/openfpga/src/utils/check_tile_annotation.cpp b/openfpga/src/utils/check_tile_annotation.cpp index 75d1eeaf5..df209644d 100644 --- a/openfpga/src/utils/check_tile_annotation.cpp +++ b/openfpga/src/utils/check_tile_annotation.cpp @@ -102,107 +102,125 @@ int check_tile_annotation_conflicts_with_physical_tile(const TileAnnotation& til int num_err = 0; for (const TileGlobalPortId& tile_global_port : tile_annotation.global_ports()) { - /* Must find a valid physical tile in the same name */ - size_t found_matched_physical_tile = 0; - size_t found_matched_physical_tile_port = 0; - for (const t_physical_tile_type& physical_tile : physical_tile_types) { - if (std::string(physical_tile.name) != tile_annotation.global_port_tile_name(tile_global_port)) { - continue; - } + for (size_t tile_info_id = 0; tile_info_id < tile_annotation.global_port_tile_names(tile_global_port).size(); ++tile_info_id) { + /* Must find a valid physical tile in the same name */ + size_t found_matched_physical_tile = 0; + size_t found_matched_physical_tile_port = 0; - /* Found a match, increment the counter */ - found_matched_physical_tile++; + std::string required_tile_name = tile_annotation.global_port_tile_names(tile_global_port)[tile_info_id]; + BasicPort required_tile_port = tile_annotation.global_port_tile_ports(tile_global_port)[tile_info_id]; - /* Must found a valid port where both port name and port size must match!!! */ - for (const t_physical_tile_port& tile_port : physical_tile.ports) { - if (std::string(tile_port.name) != tile_annotation.global_port_tile_port(tile_global_port).get_name()) { + for (const t_physical_tile_type& physical_tile : physical_tile_types) { + if (std::string(physical_tile.name) != required_tile_name) { continue; } - if (size_t(tile_port.num_pins) != tile_annotation.global_port_tile_port(tile_global_port).get_width()) { - continue; + + /* Found a match, increment the counter */ + found_matched_physical_tile++; + + /* Must found a valid port where both port name and port size must match!!! */ + for (const t_physical_tile_port& tile_port : physical_tile.ports) { + if (std::string(tile_port.name) != required_tile_port.get_name()) { + continue; + } + + BasicPort ref_tile_port(tile_port.name, tile_port.num_pins); + /* Port size must be in range!!! */ + if (false == ref_tile_port.contained(required_tile_port)) { + VTR_LOG_ERROR("Tile annotation port '%s[%lu:%lu]' is out of the range of physical tile port '%s[%lu:%lu]'!", + required_tile_port.get_name().c_str(), + required_tile_port.get_lsb(), + required_tile_port.get_msb(), + ref_tile_port.get_name().c_str(), + ref_tile_port.get_lsb(), + ref_tile_port.get_msb()); + num_err++; + continue; + } + + + /* Check if port property matches */ + int grid_pin_index = tile_port.absolute_first_pin_index; + + if (tile_port.is_clock != tile_annotation.global_port_is_clock(tile_global_port)) { + VTR_LOGF_ERROR(__FILE__, __LINE__, + "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' does not match physical tile port %s.%s in clock property (one is defined as clock while the other is not)!\n", + required_tile_name.c_str(), + required_tile_port.get_name().c_str(), + required_tile_port.get_lsb(), + required_tile_port.get_msb(), + tile_annotation.global_port_name(tile_global_port).c_str(), + physical_tile.name, tile_port.name); + num_err++; + } + + if ((false == tile_port.is_clock) + && (false == tile_port.is_non_clock_global)) { + VTR_LOGF_ERROR(__FILE__, __LINE__, + "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match physical tile port %s.%s but is not defined as a non-clock global port!\n", + required_tile_name.c_str(), + required_tile_port.get_name().c_str(), + required_tile_port.get_lsb(), + required_tile_port.get_msb(), + tile_annotation.global_port_name(tile_global_port).c_str(), + physical_tile.name, tile_port.name); + num_err++; + } + + float pin_Fc = find_physical_tile_pin_Fc(&physical_tile, grid_pin_index); + if (0. != pin_Fc) { + VTR_LOGF_ERROR(__FILE__, __LINE__, + "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match physical tile port %s.%s but its Fc is not zero '%g' !\n", + required_tile_name.c_str(), + required_tile_port.get_name().c_str(), + required_tile_port.get_lsb(), + required_tile_port.get_msb(), + tile_annotation.global_port_name(tile_global_port).c_str(), + physical_tile.name, tile_port.name, pin_Fc); + + } + + found_matched_physical_tile_port++; } - - /* Check if port property matches */ - int grid_pin_index = tile_port.absolute_first_pin_index; - - if (tile_port.is_clock != tile_annotation.global_port_is_clock(tile_global_port)) { - VTR_LOGF_ERROR(__FILE__, __LINE__, - "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' does not match physical tile port %s.%s in clock property (one is defined as clock while the other is not)!\n", - tile_annotation.global_port_tile_name(tile_global_port).c_str(), - tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(), - tile_annotation.global_port_tile_port(tile_global_port).get_lsb(), - tile_annotation.global_port_tile_port(tile_global_port).get_msb(), - tile_annotation.global_port_name(tile_global_port).c_str(), - physical_tile.name, tile_port.name); - num_err++; - } - - if ((false == tile_port.is_clock) - && (false == tile_port.is_non_clock_global)) { - VTR_LOGF_ERROR(__FILE__, __LINE__, - "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match physical tile port %s.%s but is not defined as a non-clock global port!\n", - tile_annotation.global_port_tile_name(tile_global_port).c_str(), - tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(), - tile_annotation.global_port_tile_port(tile_global_port).get_lsb(), - tile_annotation.global_port_tile_port(tile_global_port).get_msb(), - tile_annotation.global_port_name(tile_global_port).c_str(), - physical_tile.name, tile_port.name); - num_err++; - } - - float pin_Fc = find_physical_tile_pin_Fc(&physical_tile, grid_pin_index); - if (0. != pin_Fc) { - VTR_LOGF_ERROR(__FILE__, __LINE__, - "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match physical tile port %s.%s but its Fc is not zero '%g' !\n", - tile_annotation.global_port_tile_name(tile_global_port).c_str(), - tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(), - tile_annotation.global_port_tile_port(tile_global_port).get_lsb(), - tile_annotation.global_port_tile_port(tile_global_port).get_msb(), - tile_annotation.global_port_name(tile_global_port).c_str(), - physical_tile.name, tile_port.name, pin_Fc); - - } - - found_matched_physical_tile_port++; } - } - /* If we found no match, error out */ - if (0 == found_matched_physical_tile) { - VTR_LOGF_ERROR(__FILE__, __LINE__, - "Tile name '%s' in tile annotation '%s' does not match any physical tile!\n", - tile_annotation.global_port_tile_name(tile_global_port).c_str(), - tile_annotation.global_port_name(tile_global_port).c_str()); - num_err++; - } - if (0 == found_matched_physical_tile_port) { - VTR_LOGF_ERROR(__FILE__, __LINE__, - "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' does not match any physical tile port!\n", - tile_annotation.global_port_tile_name(tile_global_port).c_str(), - tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(), - tile_annotation.global_port_tile_port(tile_global_port).get_lsb(), - tile_annotation.global_port_tile_port(tile_global_port).get_msb(), - tile_annotation.global_port_name(tile_global_port).c_str()); - num_err++; - } + /* If we found no match, error out */ + if (0 == found_matched_physical_tile) { + VTR_LOGF_ERROR(__FILE__, __LINE__, + "Tile name '%s' in tile annotation '%s' does not match any physical tile!\n", + required_tile_name.c_str(), + tile_annotation.global_port_name(tile_global_port).c_str()); + num_err++; + } + if (0 == found_matched_physical_tile_port) { + VTR_LOGF_ERROR(__FILE__, __LINE__, + "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' does not match any physical tile port!\n", + required_tile_name.c_str(), + required_tile_port.get_name().c_str(), + required_tile_port.get_lsb(), + required_tile_port.get_msb(), + tile_annotation.global_port_name(tile_global_port).c_str()); + num_err++; + } - /* If we found more than 1 match, error out */ - if (1 < found_matched_physical_tile) { - VTR_LOGF_ERROR(__FILE__, __LINE__, - "Tile name '%s' in tile annotation '%s' match more than 1 physical tile!\n", - tile_annotation.global_port_tile_name(tile_global_port).c_str(), - tile_annotation.global_port_name(tile_global_port).c_str()); - num_err++; - } - if (1 < found_matched_physical_tile_port) { - VTR_LOGF_ERROR(__FILE__, __LINE__, - "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match more than 1physical tile port!\n", - tile_annotation.global_port_tile_name(tile_global_port).c_str(), - tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(), - tile_annotation.global_port_tile_port(tile_global_port).get_lsb(), - tile_annotation.global_port_tile_port(tile_global_port).get_msb(), - tile_annotation.global_port_name(tile_global_port).c_str()); - num_err++; + /* If we found more than 1 match, error out */ + if (1 < found_matched_physical_tile) { + VTR_LOGF_ERROR(__FILE__, __LINE__, + "Tile name '%s' in tile annotation '%s' match more than 1 physical tile!\n", + required_tile_name.c_str(), + tile_annotation.global_port_name(tile_global_port).c_str()); + num_err++; + } + if (1 < found_matched_physical_tile_port) { + VTR_LOGF_ERROR(__FILE__, __LINE__, + "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match more than 1 physical tile port!\n", + required_tile_name.c_str(), + required_tile_port.get_name().c_str(), + required_tile_port.get_lsb(), + required_tile_port.get_msb(), + tile_annotation.global_port_name(tile_global_port).c_str()); + num_err++; + } } } diff --git a/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.act b/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.act new file mode 100644 index 000000000..8f1ec666a --- /dev/null +++ b/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.act @@ -0,0 +1,9 @@ +clk 0.500000 2.000000 +a 0.502000 0.197200 +b 0.485400 0.202800 +c 0.248000 0.176800 +a_reg 0.502000 0.197200 +b_reg 0.485400 0.202800 +n10 0.248000 0.043259 +n13 0.502000 0.098994 +n17 0.485400 0.098439 diff --git a/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.blif b/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.blif new file mode 100644 index 000000000..19207fd81 --- /dev/null +++ b/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.blif @@ -0,0 +1,16 @@ +# Benchmark "and2_pipelined" written by ABC on Sun Jan 10 10:26:01 2021 +.model and2_pipelined +.inputs clk a b +.outputs c + +.latch n10 c 2 +.latch n13 a_reg 2 +.latch n17 b_reg 2 + +.names a_reg b_reg n10 +11 1 +.names a n13 +1 1 +.names b n17 +1 1 +.end diff --git a/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.v b/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.v new file mode 100644 index 000000000..1efccbba0 --- /dev/null +++ b/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.v @@ -0,0 +1,34 @@ +///////////////////////////////////////// +// Functionality: a pipelined 2-input AND +// where inputs and outputs are registered +// Author: Xifan Tang +//////////////////////////////////////// +`timescale 1ns / 1ps + +module and2_pipelined( + clk, + a, + b, + c); + +input wire clk; +input wire a; +input wire b; +output wire c; + +reg a_reg; +reg b_reg; +reg c_reg; + +always @(posedge clk) begin + a_reg <= a; + b_reg <= b; +end + +always @(posedge clk) begin + c_reg <= a_reg & b_reg; +end + +assign c = c_reg; + +endmodule diff --git a/openfpga_flow/misc/quicklogic_yosys_flow_ap3.ys b/openfpga_flow/misc/quicklogic_yosys_flow_ap3.ys new file mode 100644 index 000000000..cccd220b9 --- /dev/null +++ b/openfpga_flow/misc/quicklogic_yosys_flow_ap3.ys @@ -0,0 +1,6 @@ +# Yosys synthesis script for ${TOP_MODULE} +# Read verilog files +${READ_VERILOG_FILE} + +synth_quicklogic -blif ${OUTPUT_BLIF} -openfpga -top ${TOP_MODULE} + diff --git a/openfpga_flow/openfpga_arch/README.md b/openfpga_flow/openfpga_arch/README.md index ba6e307ca..5d1e8cafa 100644 --- a/openfpga_flow/openfpga_arch/README.md +++ b/openfpga_flow/openfpga_arch/README.md @@ -21,6 +21,7 @@ Note that an OpenFPGA architecture can be applied to multiple VPR architecture f - behavioral: If behavioral Verilog modeling is specified - local\_encoder: If local encoders are used in routing multiplexer design - spyio/spypad: If spy I/Os are used +- registerable\_io: If I/Os are registerable (can be either combinational or sequential) - stdcell: If circuit designs are built with standard cells only - tree\_mux: If routing multiplexers are built with a tree-like structure - : The technology node which the delay numbers are extracted from. diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_cc_openfpga.xml index d3f4baf4b..ed9abccff 100644 --- a/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_cc_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_cc_openfpga.xml @@ -169,7 +169,9 @@ - + + + diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_registerable_io_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_registerable_io_cc_openfpga.xml new file mode 100644 index 000000000..1e5412069 --- /dev/null +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_registerable_io_cc_openfpga.xml @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + + + + + 10e-12 5e-12 5e-12 + + + 10e-12 5e-12 5e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_cc_cfgscff_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_cc_cfgscff_openfpga.xml new file mode 100644 index 000000000..e0fd1f9bb --- /dev/null +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_cc_cfgscff_openfpga.xml @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + + + + + 10e-12 5e-12 5e-12 + + + 10e-12 5e-12 5e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/openfpga_arch/k4_frac_N8_reset_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N8_reset_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml index 0ad0bd1a6..69654611a 100644 --- a/openfpga_flow/openfpga_arch/k4_frac_N8_reset_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_frac_N8_reset_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml @@ -217,8 +217,12 @@ - - + + + + + + diff --git a/openfpga_flow/openfpga_cell_library/verilog/dff.v b/openfpga_flow/openfpga_cell_library/verilog/dff.v index e54950827..a0548c54c 100644 --- a/openfpga_flow/openfpga_cell_library/verilog/dff.v +++ b/openfpga_flow/openfpga_cell_library/verilog/dff.v @@ -397,3 +397,50 @@ end assign Q = q_reg; endmodule //End Of Module + +//----------------------------------------------------- +// Function : D-type flip-flop with +// - asynchronous active high reset +// - scan-chain input +// - a scan-chain enable +// - a configure enable, when enabled the registered output will +// be released to the Q +//----------------------------------------------------- +module CFGSDFFR ( + input RST, // Reset input + input CK, // Clock Input + input SE, // Scan-chain Enable + input D, // Data Input + input SI, // Scan-chain input + input CFGE, // Configure enable + output Q, // Regular Q output + output CFGQ, // Data Q output which is released when configure enable is activated + output CFGQN // Data Qb output which is released when configure enable is activated +); +//------------Internal Variables-------- +reg q_reg; +wire QN; + +//-------------Code Starts Here--------- +always @ ( posedge CK or posedge RST) +if (RST) begin + q_reg <= 1'b0; +end else if (SE) begin + q_reg <= SI; +end else begin + q_reg <= D; +end + +assign CFGQ = CFGE ? Q : 1'b0; +assign CFGQN = CFGE ? QN : 1'b1; + +`ifndef ENABLE_FORMAL_VERIFICATION +// Wire q_reg to Q + assign Q = q_reg; + assign QN = !Q; +`else + assign Q = 1'bZ; + assign QN = !Q; +`endif + +endmodule //End Of Module diff --git a/openfpga_flow/openfpga_shell_scripts/fix_device_global_tile_clock_example_script.openfpga b/openfpga_flow/openfpga_shell_scripts/fix_device_global_tile_clock_example_script.openfpga new file mode 100644 index 000000000..b5fd710b6 --- /dev/null +++ b/openfpga_flow/openfpga_shell_scripts/fix_device_global_tile_clock_example_script.openfpga @@ -0,0 +1,76 @@ +# Run VPR for the 'and' design +# When the global clock is defined as a port of a tile, clock routing in VPR should be skipped +# This is due to the Fc_in of clock port is set to 0 for global wiring +#--write_rr_graph example_rr_graph.xml +vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --device ${OPENFPGA_VPR_DEVICE_LAYOUT} + +# Read OpenFPGA architecture definition +read_openfpga_arch -f ${OPENFPGA_ARCH_FILE} + +# Read OpenFPGA simulation settings +read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE} + +# Annotate the OpenFPGA architecture to VPR data base +# to debug use --verbose options +link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges + +# Check and correct any naming conflicts in the BLIF netlist +check_netlist_naming_conflict --fix --report ./netlist_renaming.xml + +# Apply fix-up to clustering nets based on routing results +pb_pin_fixup --verbose + +# Apply fix-up to Look-Up Table truth tables based on packing results +lut_truth_table_fixup + +# Build the module graph +# - Enabled compression on routing architecture modules +# - Enable pin duplication on grid modules +build_fabric --compress_routing #--verbose + +# Write the fabric hierarchy of module graph to a file +# This is used by hierarchical PnR flows +write_fabric_hierarchy --file ./fabric_hierarchy.txt + +# Repack the netlist to physical pbs +# This must be done before bitstream generator and testbench generation +# Strongly recommend it is done after all the fix-up have been applied +repack #--verbose + +# Build the bitstream +# - Output the fabric-independent bitstream to a file +build_architecture_bitstream --verbose --write_file fabric_independent_bitstream.xml + +# Build fabric-dependent bitstream +build_fabric_bitstream --verbose + +# Write fabric-dependent bitstream +write_fabric_bitstream --file fabric_bitstream.xml --format xml + +# Write the Verilog netlist for FPGA fabric +# - Enable the use of explicit port mapping in Verilog netlist +write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --print_user_defined_template --verbose + +# Write the Verilog testbench for FPGA fabric +# - We suggest the use of same output directory as fabric Verilog netlists +# - Must specify the reference benchmark file if you want to output any testbenches +# - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA +# - Enable pre-configured top-level testbench which is a fast verification skipping programming phase +# - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts +write_verilog_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --print_top_testbench --print_preconfig_top_testbench --print_simulation_ini ./SimulationDeck/simulation_deck.ini --include_signal_init --support_icarus_simulator --explicit_port_mapping + +# Write the SDC files for PnR backend +# - Turn on every options here +write_pnr_sdc --file ./SDC + +# Write SDC to disable timing for configure ports +write_sdc_disable_timing_configure_ports --file ./SDC/disable_configure_ports.sdc + +# Write the SDC to run timing analysis for a mapped FPGA fabric +write_analysis_sdc --file ./SDC_analysis + +# Finish and exit OpenFPGA +exit + +# Note : +# To run verification at the end of the flow maintain source in ./SRC directory diff --git a/openfpga_flow/openfpga_shell_scripts/quicklogic_flow_example_script.openfpga b/openfpga_flow/openfpga_shell_scripts/quicklogic_flow_example_script.openfpga new file mode 100644 index 000000000..5adab1c51 --- /dev/null +++ b/openfpga_flow/openfpga_shell_scripts/quicklogic_flow_example_script.openfpga @@ -0,0 +1,77 @@ +# Run VPR for the 'and' design +#--write_rr_graph example_rr_graph.xml +vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling route + +# Read OpenFPGA architecture definition +read_openfpga_arch -f ${OPENFPGA_ARCH_FILE} + +# Read OpenFPGA simulation settings +read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE} + +# Annotate the OpenFPGA architecture to VPR data base +# to debug use --verbose options +link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges + +# Check and correct any naming conflicts in the BLIF netlist +check_netlist_naming_conflict --fix --report ./netlist_renaming.xml + +# Apply fix-up to clustering nets based on routing results +pb_pin_fixup --verbose + +# Apply fix-up to Look-Up Table truth tables based on packing results +lut_truth_table_fixup + +# Build the module graph +# - Enabled compression on routing architecture modules +# - Enable pin duplication on grid modules +build_fabric --compress_routing #--verbose + +# Write the fabric hierarchy of module graph to a file +# This is used by hierarchical PnR flows +write_fabric_hierarchy --file ./fabric_hierarchy.txt + +# Repack the netlist to physical pbs +# This must be done before bitstream generator and testbench generation +# Strongly recommend it is done after all the fix-up have been applied +repack #--verbose + +# Build the bitstream +# - Output the fabric-independent bitstream to a file +build_architecture_bitstream --verbose --write_file fabric_independent_bitstream.xml + +# Build fabric-dependent bitstream +build_fabric_bitstream --verbose + +# Write fabric-dependent bitstream +write_fabric_bitstream --file fabric_bitstream.xml --format xml + +# Write the Verilog netlist for FPGA fabric +# - Enable the use of explicit port mapping in Verilog netlist +write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --print_user_defined_template --verbose + +# Write the Verilog testbench for FPGA fabric +# - We suggest the use of same output directory as fabric Verilog netlists +# - Must specify the reference benchmark file if you want to output any testbenches +# - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA +# - Enable pre-configured top-level testbench which is a fast verification skipping programming phase +# - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts +write_verilog_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --print_top_testbench --print_preconfig_top_testbench --print_simulation_ini ./SimulationDeck/simulation_deck.ini --include_signal_init --support_icarus_simulator + +# Write the SDC files for PnR backend +# - Turn on every options here +write_pnr_sdc --file ./SDC + +# Write SDC to constrain timing of configuration chain +write_configuration_chain_sdc --file ./SDC/ccff_timing.sdc --time_unit ns --max_delay 5 --min_delay 2.5 + +# Write SDC to disable timing for configure ports +write_sdc_disable_timing_configure_ports --file ./SDC/disable_configure_ports.sdc + +# Write the SDC to run timing analysis for a mapped FPGA fabric +write_analysis_sdc --file ./SDC_analysis + +# Finish and exit OpenFPGA +exit + +# Note : +# To run verification at the end of the flow maintain source in ./SRC directory diff --git a/openfpga_flow/tasks/basic_tests/full_testbench/configuration_chain_config_enable_scff/config/task.conf b/openfpga_flow/tasks/basic_tests/full_testbench/configuration_chain_config_enable_scff/config/task.conf new file mode 100644 index 000000000..8fd922fd9 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/full_testbench/configuration_chain_config_enable_scff/config/task.conf @@ -0,0 +1,42 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = true +spice_output=false +verilog_output=true +timeout_each_job = 1*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/configuration_chain_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_cc_cfgscff_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v +bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v +bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v + +[SYNTHESIS_PARAM] +bench0_top = and2 +bench0_chan_width = 300 + +bench1_top = or2 +bench1_chan_width = 300 + +bench2_top = and2_latch +bench2_chan_width = 300 + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= diff --git a/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock/config/task.conf b/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock/config/task.conf index fd95b7ca9..abc1be003 100644 --- a/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock/config/task.conf +++ b/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock/config/task.conf @@ -26,6 +26,7 @@ arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTileClk_ [BENCHMARKS] bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v +bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.v [SYNTHESIS_PARAM] bench0_top = and2 @@ -34,5 +35,8 @@ bench0_chan_width = 300 bench1_top = and2_latch bench1_chan_width = 300 +bench2_top = and2_pipelined +bench2_chan_width = 300 + [SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] end_flow_with_test= diff --git a/openfpga_flow/tasks/fpga_verilog/io/registerable_io/config/task.conf b/openfpga_flow/tasks/fpga_verilog/io/registerable_io/config/task.conf new file mode 100644 index 000000000..700f8e3c7 --- /dev/null +++ b/openfpga_flow/tasks/fpga_verilog/io/registerable_io/config/task.conf @@ -0,0 +1,35 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = true +spice_output=false +verilog_output=true +timeout_each_job = 20*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/fix_device_global_tile_clock_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_registerable_io_cc_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml +openfpga_vpr_device_layout=2x2 + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTileClk_registerable_io_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.v + +[SYNTHESIS_PARAM] +bench0_top = and2_pipelined +bench0_chan_width = 300 + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= diff --git a/openfpga_flow/tasks/quicklogic_tests/flow_test/config/task.conf b/openfpga_flow/tasks/quicklogic_tests/flow_test/config/task.conf new file mode 100644 index 000000000..67d074bd0 --- /dev/null +++ b/openfpga_flow/tasks/quicklogic_tests/flow_test/config/task.conf @@ -0,0 +1,36 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = true +spice_output=false +verilog_output=true +timeout_each_job = 20*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/quicklogic_flow_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_cc_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counter/counter.v + +[SYNTHESIS_PARAM] +bench0_top = counter +bench0_chan_width = 100 +bench0_yosys=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/quicklogic_yosys_flow_ap3.ys + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist= diff --git a/openfpga_flow/vpr_arch/README.md b/openfpga_flow/vpr_arch/README.md index 4ab3a92e4..87723c7e3 100644 --- a/openfpga_flow/vpr_arch/README.md +++ b/openfpga_flow/vpr_arch/README.md @@ -15,6 +15,7 @@ Please reveal the following architecture features in the names to help quickly s - aib: If the Advanced Interface Bus (AIB) is used in place of some I/Os. - multi\_io\_capacity: If I/O capacity is different on each side of FPGAs. - reduced\_io: If I/Os only appear a certain or multiple sides of FPGAs +- registerable\_io: If I/Os are registerable (can be either combinational or sequential) - : The technology node which the delay numbers are extracted from. - TileOrgz: How tile is organized. * Top-left (Tl): the pins of a tile are placed on the top side and left side only diff --git a/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTileClk_registerable_io_40nm.xml b/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTileClk_registerable_io_40nm.xml new file mode 100644 index 000000000..c3c68f421 --- /dev/null +++ b/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTileClk_registerable_io_40nm.xml @@ -0,0 +1,329 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + io.outpad io.inpad io.clk + io.outpad io.inpad io.clk + io.outpad io.inpad io.clk + io.outpad io.inpad io.clk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 1 1 1 1 + 1 1 1 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 261e-12 + 261e-12 + 261e-12 + 261e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/vpr_arch/k4_frac_N8_tileable_reset_softadder_register_scan_chain_nonLR_caravel_io_skywater130nm.xml b/openfpga_flow/vpr_arch/k4_frac_N8_tileable_reset_softadder_register_scan_chain_nonLR_caravel_io_skywater130nm.xml new file mode 100644 index 000000000..07c6ba848 --- /dev/null +++ b/openfpga_flow/vpr_arch/k4_frac_N8_tileable_reset_softadder_register_scan_chain_nonLR_caravel_io_skywater130nm.xml @@ -0,0 +1,737 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + io_top.outpad io_top.inpad + + + + + + + + + + + + io_right.outpad io_right.inpad + + + + + + + + + + + + io_bottom.outpad io_bottom.inpad + + + + + + + + + + + + io_left.outpad io_left.inpad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + clb.clk clb.reset + clb.reg_in clb.sc_in clb.cin clb.O[7:0] clb.I0 clb.I0i clb.I1 clb.I1i clb.I2 clb.I2i clb.I3 clb.I3i + clb.O[15:8] clb.I4 clb.I4i clb.I5 clb.I5i clb.I6 clb.I6i clb.I7 clb.I7i + clb.reg_out clb.sc_out clb.cout + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 1 + 1 + + + + 1 1 1 + 1 1 + + + + 1 1 1 1 1 + 1 1 1 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 235e-12 + 235e-12 + 235e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 261e-12 + 261e-12 + 261e-12 + 261e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/yosys b/yosys index aec2c4144..a0606e09f 160000 --- a/yosys +++ b/yosys @@ -1 +1 @@ -Subproject commit aec2c41441bffa981092095d25655e80dae6ef06 +Subproject commit a0606e09f57df456ba9bcfc6a7cf7b64d814b8e4