From 245cca5a2d742cbbea9636c8d0f4455ab8a237f6 Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Tue, 24 Dec 2024 19:00:28 +0200 Subject: [PATCH] dft: per-chain enables, user-configurable name patterns This changeset makes the DFT module a bit more flexible. The highlights are new ports don't have to be punched- you can connect to any existing ITerm or BTerm and new ports are only punched as a fallback. Additionally, the scan chain order can be written in a JSON format so it may be consumed by other utilities. --- * dft::Dft::insertDft: Add capability for per-chain enable, ability to provide runtime format strings for scan enable/in/out patterns * dft::ScanStitch: * if a name pattern includes an un-escaped forward slash (/), steps are to attempt to find an existing ITerm instead of creating a new BTerm * else, if a BTerm already exists, the BTerm is reused. * finally, a new BTerm is created. * dft::Dft: create writeScanChains, which writes the scan chains (currently just names and ordering of flip-flops) in JSON format. Allows data to be passed to other DFT utilities. * dft: create ResetDomain, which encapsulates reset domains similar to how dft::ClockDomain encapsulates clock domains. currently unused --- There is one breaking change, which is that scan_enable_{}/scan_in_{}/ etc are numbered starting from 0 instead of 1. The rationale is the chains themselves are numbered starting from 0 and there appears to be no good justification to start them from 1. Otherwise, tests will (hopefully) show this PR as fully backwards-compatible. Signed-off-by: Mohamed Gaber --- .gitignore | 1 + src/dft/CMakeLists.txt | 2 + src/dft/README.md | 42 +++- src/dft/include/dft/Dft.hh | 10 +- src/dft/src/Dft.cpp | 52 ++++- src/dft/src/architect/ScanChain.cpp | 5 + src/dft/src/architect/ScanChain.hh | 3 + src/dft/src/cells/ScanCell.hh | 9 +- src/dft/src/dft.i | 56 ++++- src/dft/src/dft.tcl | 39 +++- src/dft/src/replace/ScanReplace.cpp | 15 +- src/dft/src/reset_domain/CMakeLists.txt | 15 ++ src/dft/src/reset_domain/ResetDomain.cpp | 80 +++++++ src/dft/src/reset_domain/ResetDomain.hh | 70 ++++++ src/dft/src/stitch/ScanStitch.cpp | 189 ++++++++++++---- src/dft/src/stitch/ScanStitch.hh | 68 +++--- src/dft/src/utils/Utils.cpp | 38 ++++ src/dft/src/utils/Utils.hh | 10 + src/dft/test/max_chain_count_sky130.vok | 30 +-- src/dft/test/one_cell_sky130.ok | 4 +- src/dft/test/one_cell_sky130.vok | 12 +- src/dft/test/place_sort_sky130.vok | 30 +-- .../test/scan_architect_clock_mix_sky130.vok | 64 +++--- src/dft/test/scan_architect_no_mix_sky130.vok | 58 ++--- ...tect_register_bank_no_clock_mix_sky130.vok | 206 +++++++++--------- src/dft/test/sub_modules_sky130.vok | 20 +- 26 files changed, 825 insertions(+), 303 deletions(-) create mode 100644 src/dft/src/reset_domain/CMakeLists.txt create mode 100644 src/dft/src/reset_domain/ResetDomain.cpp create mode 100644 src/dft/src/reset_domain/ResetDomain.hh diff --git a/.gitignore b/.gitignore index 631e4d0862f..1d6b7d1c547 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ TAGS .cache Makefile __pycache__ +venv/ include/ord/Version.hh diff --git a/src/dft/CMakeLists.txt b/src/dft/CMakeLists.txt index f2c1b524dfb..f4e712026bb 100644 --- a/src/dft/CMakeLists.txt +++ b/src/dft/CMakeLists.txt @@ -70,6 +70,7 @@ target_link_libraries(dft dft_config_lib dft_replace_lib dft_clock_domain_lib + dft_reset_domain_lib dft_utils_lib dft_stitch_lib ) @@ -105,6 +106,7 @@ add_subdirectory(src/cells) add_subdirectory(src/clock_domain) add_subdirectory(src/config) add_subdirectory(src/replace) +add_subdirectory(src/reset_domain) add_subdirectory(src/stitch) add_subdirectory(src/utils) if(ENABLE_TESTS) diff --git a/src/dft/README.md b/src/dft/README.md index e25ed0a6641..6d08e51ffac 100644 --- a/src/dft/README.md +++ b/src/dft/README.md @@ -77,13 +77,51 @@ preview_dft ### Insert DFT -Architect scan chains and connect them up in a way that minimises wirelength. As a result, this -should be run after placement, and after `scan_replace`. +Architect scan chains and connect them up in a way that minimises wirelength. As +a result, this should be run after placement, and after `scan_replace`. ```tcl insert_dft + [-per_chain_enable] + [-scan_enable_name_pattern ] + [-scan_in_name_pattern ] + [-scan_out_name_pattern ] ``` +#### Options + +| Switch Name | Description | +| ---- | ---- | +| `-per_chain_enable` | Creates one enable signal per chain instead of reusing the same one for every chain. | +| `-scan_enable_name_pattern` | A format pattern with exactly one set of braces (`{}`) to use to find or create scan enable drivers. The braces will be replaced with the chain's ordinal number (starting at `0`) if `-per_chain_enable` is defined, otherwise, all will share `0`. If an un-escaped forward slash (`/`) is found, instead of searching for and/or creating a top-level port, an instance's pin will be searched for instead where the part of the string preceding the `/` is interpreted as the instance name and part succeeding it will be interpreted as the pin's name. | +| `-scan_in_name_pattern` | A format pattern with exactly one set of braces (`{}`) to use to find or create scan in drivers. The braces will be replaced with the chain's ordinal number (starting at `0`). If an un-escaped forward slash (`/`) is found, instead of searching for and/or creating a top-level port, an instance's pin will be searched for instead where the part of the string preceding the `/` is interpreted as the instance name and part succeeding it will be interpreted as the pin's name. | +| `-scan_out_name_pattern` | A format pattern with exactly one set of braces (`{}`) to use to find or create scan in loads. The braces will be replaced with the chain's ordinal number (starting at `0`). If an un-escaped forward slash (`/`) is found, instead of searching for and/or creating a top-level port, an instance's pin will be searched for instead where the part of the string preceding the `/` is interpreted as the instance name and part succeeding it will be interpreted as the pin's name. | + +### Write Scan Chains + +Writes a JSON file containing metadata about the current architected scan chain. + +The JSON file is currently in this format: + +```jsonc +{ + "chain_0": { + "cells": [ + "scanflop_0", + "scanflop_1", + "scanflop_2" + ] + }, + /* … other chains … */ +} +``` + +…where the order of `.chain_name.cells` corresponds to the order of the elements +in the scan-chain. + +```tcl +write_scan_chains +``` ## Example scripts diff --git a/src/dft/include/dft/Dft.hh b/src/dft/include/dft/Dft.hh index cfa70cc08c3..23725933fb3 100644 --- a/src/dft/include/dft/Dft.hh +++ b/src/dft/include/dft/Dft.hh @@ -31,6 +31,8 @@ // POSSIBILITY OF SUCH DAMAGE. #pragma once +#include "ClockDomain.hh" +#include "ResetDomain.hh" #include "db_sta/dbSta.hh" #include "odb/db.h" #include "utl/Logger.h" @@ -95,7 +97,10 @@ class Dft // void scanReplace(); - void insertDft(); + void insertDft(bool per_chain_enable, + const std::string& scan_enable_name_pattern, + const std::string& scan_in_name_pattern, + const std::string& scan_out_name_pattern); // Returns a mutable version of DftConfig DftConfig* getMutableDftConfig(); @@ -106,6 +111,9 @@ class Dft // Prints to stdout void reportDftConfig() const; + // Writes scan chains in a JSON format + void writeScanChains(const std::string& filename); + private: // If we need to run pre_dft to create the internal state bool need_to_run_pre_dft_; diff --git a/src/dft/src/Dft.cpp b/src/dft/src/Dft.cpp index a6512f989c7..d316db5a40f 100644 --- a/src/dft/src/Dft.cpp +++ b/src/dft/src/Dft.cpp @@ -32,6 +32,8 @@ #include "dft/Dft.hh" +#include +#include #include #include "ClockDomain.hh" @@ -104,15 +106,59 @@ void Dft::scanReplace() scan_replace_->scanReplace(); } -void Dft::insertDft() +void Dft::writeScanChains(const std::string& filename) +{ + using boost::property_tree::ptree; + if (need_to_run_pre_dft_) { + pre_dft(); + } + + std::ofstream json_file(filename); + if (!json_file.is_open()) { + logger_->error( + utl::DFT, 13, "Failed to open file {} for writing.", filename); + } + try { + ptree root; + + std::vector> scan_chains = scanArchitect(); + + for (auto& chain : scan_chains) { + ptree current_chain; + ptree cells; + auto& scan_cells = chain->getScanCells(); + for (auto& cell : scan_cells) { + ptree name; + name.put("", cell->getName()); + cells.push_back(std::make_pair("", name)); + } + current_chain.add_child("cells", cells); + root.add_child(chain->getName(), current_chain); + } + + boost::property_tree::write_json(json_file, root); + } catch (std::exception& ex) { + logger_->error( + utl::DFT, 14, "Failed to write JSON report. Exception: {}", ex.what()); + } +} + +void Dft::insertDft(bool per_chain_enable, + const std::string& scan_enable_name_pattern, + const std::string& scan_in_name_pattern, + const std::string& scan_out_name_pattern) { if (need_to_run_pre_dft_) { pre_dft(); } std::vector> scan_chains = scanArchitect(); - ScanStitch stitch(db_); - stitch.Stitch(scan_chains); + ScanStitch stitch(db_, + per_chain_enable, + scan_enable_name_pattern, + scan_in_name_pattern, + scan_out_name_pattern); + stitch.Stitch(scan_chains, logger_); } DftConfig* Dft::getMutableDftConfig() diff --git a/src/dft/src/architect/ScanChain.cpp b/src/dft/src/architect/ScanChain.cpp index ecb1693efcb..77ca99034e4 100644 --- a/src/dft/src/architect/ScanChain.cpp +++ b/src/dft/src/architect/ScanChain.cpp @@ -119,4 +119,9 @@ const std::string& ScanChain::getName() const return name_; } +void ScanChain::rename(std::string& new_name) +{ + name_ = new_name; +} + } // namespace dft diff --git a/src/dft/src/architect/ScanChain.hh b/src/dft/src/architect/ScanChain.hh index ec8d896c394..2087e872706 100644 --- a/src/dft/src/architect/ScanChain.hh +++ b/src/dft/src/architect/ScanChain.hh @@ -85,6 +85,9 @@ class ScanChain // Returns the name of the scan chain const std::string& getName() const; + // Changes the name of the scan chain + void rename(std::string& new_name); + private: std::string name_; std::vector> rising_edge_scan_cells_; diff --git a/src/dft/src/cells/ScanCell.hh b/src/dft/src/cells/ScanCell.hh index 1f5f160b5be..5789da2a510 100644 --- a/src/dft/src/cells/ScanCell.hh +++ b/src/dft/src/cells/ScanCell.hh @@ -127,8 +127,15 @@ class ScanCell odb::dbNet* driver_net = driver->getNet(); if (!driver_net) { - driver_net = odb::dbNet::create(driver->getBlock(), GetTermName(driver)); + driver_net = odb::dbNet::create(driver->getBlock(), driver->getName().c_str()); + if (!driver_net) { + logger_->error(utl::DFT, + 30, + "Failed to create driver net named '{}'", + driver->getName()); + } driver_net->setSigType(odb::dbSigType::SCAN); + driver->connect(driver_net); } debugPrint(logger_, utl::DFT, diff --git a/src/dft/src/dft.i b/src/dft/src/dft.i index f0af5a88915..9c40a517c5c 100644 --- a/src/dft/src/dft.i +++ b/src/dft/src/dft.i @@ -38,6 +38,8 @@ #include "DftConfig.hh" #include "ord/OpenRoad.hh" #include "ScanArchitect.hh" +#include "ClockDomain.hh" +#include "ResetDomain.hh" dft::Dft * getDft() { @@ -51,6 +53,48 @@ utl::Logger* getLogger() %} +%include "../../Exception.i" + +%typemap(typecheck) dft::ResetActiveEdge { + char *str = Tcl_GetStringFromObj($input, 0); + if (strcasecmp(str, "LOW") == 0) { + $1 = 1; + } else if (strcasecmp(str, "HIGH") == 0) { + $1 = 1; + } else { + $1 = 0; + } +} + +%typemap(in) dft::ResetActiveEdge { + char *str = Tcl_GetStringFromObj($input, 0); + if (strcasecmp(str, "LOW") == 0) { + $1 = dft::ResetActiveEdge::Low; + } else /* other values eliminated in typecheck */ { + $1 = dft::ResetActiveEdge::High; + }; +} + +%typemap(typecheck) dft::ClockEdge { + char *str = Tcl_GetStringFromObj($input, 0); + if (strcasecmp(str, "RISING") == 0) { + $1 = 1; + } else if (strcasecmp(str, "FALLING") == 0) { + $1 = 1; + } else { + $1 = 0; + } +} + +%typemap(in) dft::ClockEdge { + char *str = Tcl_GetStringFromObj($input, 0); + if (strcasecmp(str, "FALLING") == 0) { + $1 = dft::ClockEdge::Falling; + } else /* other values eliminated in typecheck */ { + $1 = dft::ClockEdge::Rising; + }; +} + %inline %{ @@ -64,10 +108,18 @@ void scan_replace() getDft()->scanReplace(); } +void insert_dft(bool per_chain_enable, + const char* scan_enable_name_pattern, + const char* scan_in_name_pattern, + const char* scan_out_name_pattern) +{ + getDft()->insertDft(per_chain_enable, scan_enable_name_pattern, scan_in_name_pattern, scan_out_name_pattern); +} -void insert_dft() +void write_scan_chains(const char* filename_p) { - getDft()->insertDft(); + std::string filename(filename_p); + getDft()->writeScanChains(filename); } void set_dft_config_max_length(int max_length) diff --git a/src/dft/src/dft.tcl b/src/dft/src/dft.tcl index fbe5892d766..4d3f88cad14 100644 --- a/src/dft/src/dft.tcl +++ b/src/dft/src/dft.tcl @@ -29,7 +29,7 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -sta::define_cmd_args "preview_dft" { [-verbose]} +sta::define_cmd_args "preview_dft" {[-verbose]} proc preview_dft { args } { sta::parse_key_args "preview_dft" args \ @@ -58,15 +58,46 @@ proc scan_replace { args } { dft::scan_replace } -sta::define_cmd_args "insert_dft" { } +sta::define_cmd_args "write_scan_chains" {[json_file_out]} +proc write_scan_chains { args } { + sta::parse_key_args "write_scan_chains" args \ + keys {} flags {} + + if { [ord::get_db_block] == "NULL" } { + utl::error DFT 15 "No design block found." + } + + dft::write_scan_chains [lindex $args 0] +} + +sta::define_cmd_args "insert_dft" { + [-per_chain_enable] + [-scan_enable_name_pattern scan_enable_name_pattern] + [-scan_in_name_pattern scan_in_name_pattern] + [-scan_out_name_pattern scan_out_name_pattern] +} proc insert_dft { args } { sta::parse_key_args "insert_dft" args \ - keys {} flags {} + keys {-scan_enable_name_pattern -scan_in_name_pattern -scan_out_name_pattern} \ + flags {-per_chain_enable} if { [ord::get_db_block] == "NULL" } { utl::error DFT 9 "No design block found." } - dft::insert_dft + + foreach {flag default} { + -scan_enable_name_pattern "scan_enable_{}" + -scan_in_name_pattern "scan_in_{}" + -scan_out_name_pattern "scan_out_{}" + } { + if { ![info exists keys($flag)] } { + set keys($flag) $default + } + } + dft::insert_dft [info exists flags(-per_chain_enable)] \ + $keys(-scan_enable_name_pattern) \ + $keys(-scan_in_name_pattern) \ + $keys(-scan_out_name_pattern) } sta::define_cmd_args "set_dft_config" { [-max_length max_length] \ diff --git a/src/dft/src/replace/ScanReplace.cpp b/src/dft/src/replace/ScanReplace.cpp index a658e57df60..709b736c89b 100644 --- a/src/dft/src/replace/ScanReplace.cpp +++ b/src/dft/src/replace/ScanReplace.cpp @@ -45,19 +45,6 @@ namespace dft { namespace { - -// Checks if the given LibertyCell is really a Scan Cell with a Scan In and a -// Scan Enable -bool IsScanCell(const sta::LibertyCell* libertyCell) -{ - const sta::TestCell* test_cell = libertyCell->testCell(); - if (test_cell) { - return getLibertyScanIn(test_cell) != nullptr - && getLibertyScanEnable(test_cell) != nullptr; - } - return false; -} - // Checks the ports sta::LibertyPort* FindEquivalentPortInScanCell( const sta::LibertyPort* non_scan_cell_port, @@ -309,7 +296,7 @@ void ScanReplace::collectScanCellAvailable() continue; } - if (IsScanCell(liberty_cell)) { + if (utils::IsScanCell(liberty_cell)) { available_scan_lib_cells_.insert(liberty_cell); } else { non_scan_cells.push_back(liberty_cell); diff --git a/src/dft/src/reset_domain/CMakeLists.txt b/src/dft/src/reset_domain/CMakeLists.txt new file mode 100644 index 00000000000..3225c608439 --- /dev/null +++ b/src/dft/src/reset_domain/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(dft_reset_domain_lib + # Keep sorted + ResetDomain.cpp +) + +target_include_directories(dft_reset_domain_lib + PUBLIC + ${CMAKE_CURRENT_LIST_DIR} +) + +target_link_libraries(dft_reset_domain_lib + PRIVATE + odb + utl_lib +) diff --git a/src/dft/src/reset_domain/ResetDomain.cpp b/src/dft/src/reset_domain/ResetDomain.cpp new file mode 100644 index 00000000000..6e6f34c1cb9 --- /dev/null +++ b/src/dft/src/reset_domain/ResetDomain.cpp @@ -0,0 +1,80 @@ +/////////////////////////////////////////////////////////////////////////////// +// BSD 3-Clause License +// +// Copyright (c) 2023, Google LLC +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#include "ResetDomain.hh" + +namespace dft { + +std::function GetResetDomainHashFn() +{ + return [](const ResetDomain& reset_domain) { + return std::hash{}(reset_domain.getResetName()) + ^ std::hash{}(reset_domain.getResetActiveEdge()); + }; +} + +ResetDomain::ResetDomain(const std::string& reset_name, + ResetActiveEdge reset_edge) + : reset_name_(reset_name), reset_edge_(reset_edge) +{ +} + +std::string_view ResetDomain::getResetName() const +{ + return reset_name_; +} + +ResetActiveEdge ResetDomain::getResetActiveEdge() const +{ + return reset_edge_; +} + +std::string_view ResetDomain::getResetActiveEdgeName() const +{ + switch (reset_edge_) { + case ResetActiveEdge::High: + return "high"; + break; + case ResetActiveEdge::Low: + return "low"; + break; + } + // TODO replace with std::unreachable() once we reach c++23 + return "Unknown reset active edge"; +} + +size_t ResetDomain::getResetDomainId() const +{ + return std::hash{}(reset_name_) + ^ std::hash{}(reset_edge_); +} + +} // namespace dft diff --git a/src/dft/src/reset_domain/ResetDomain.hh b/src/dft/src/reset_domain/ResetDomain.hh new file mode 100644 index 00000000000..f8b274d9729 --- /dev/null +++ b/src/dft/src/reset_domain/ResetDomain.hh @@ -0,0 +1,70 @@ +/////////////////////////////////////////////////////////////////////////////// +// BSD 3-Clause License +// +// Copyright (c) 2023, Google LLC +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +#pragma once + +#include +#include +#include +#include + +namespace dft { + +// Reset domains can be active high or active low. +enum class ResetActiveEdge +{ + Low = 0, // active low + High = 1, // active high +}; + +class ResetDomain +{ + public: + ResetDomain(const std::string& reset_name, ResetActiveEdge reset_edge); + // Allow move, copy is implicitly deleted + ResetDomain(ResetDomain&& other) = default; + ResetDomain& operator=(ResetDomain&& other) = default; + + std::string_view getResetName() const; + ResetActiveEdge getResetActiveEdge() const; + std::string_view getResetActiveEdgeName() const; + + // Returns a unique id that can be used to identify a particular reset domain + size_t getResetDomainId() const; + + private: + std::string reset_name_; + ResetActiveEdge reset_edge_; +}; + +std::function GetResetDomainHashFn(); + +} // namespace dft diff --git a/src/dft/src/stitch/ScanStitch.cpp b/src/dft/src/stitch/ScanStitch.cpp index b148a8b379a..c171214d6ba 100644 --- a/src/dft/src/stitch/ScanStitch.cpp +++ b/src/dft/src/stitch/ScanStitch.cpp @@ -1,50 +1,58 @@ #include "ScanStitch.hh" +#include #include #include -namespace { - -constexpr std::string_view kScanEnableNamePattern = "scan_enable_{}"; -constexpr std::string_view kScanInNamePattern = "scan_in_{}"; -constexpr std::string_view kScanOutNamePattern = "scan_out_{}"; - -} // namespace - namespace dft { -ScanStitch::ScanStitch(odb::dbDatabase* db) : db_(db) +ScanStitch::ScanStitch(odb::dbDatabase* db, + bool per_chain_enable, + std::string scan_enable_name_pattern, + std::string scan_in_name_pattern, + std::string scan_out_name_pattern) + : db_(db), + per_chain_enable_(per_chain_enable), + scan_enable_name_pattern_(scan_enable_name_pattern), + scan_in_name_pattern_(scan_in_name_pattern), + scan_out_name_pattern_(scan_out_name_pattern) { odb::dbChip* chip = db_->getChip(); top_block_ = chip->getBlock(); } void ScanStitch::Stitch( - const std::vector>& scan_chains) + const std::vector>& scan_chains, + utl::Logger* logger) { - // TODO: For now, we only use one scan enable for all the chains. We may - // support in the future multiple test modes if (scan_chains.empty()) { return; } - ScanDriver scan_enable = FindOrCreateScanEnable(top_block_); - odb::dbChip* chip = db_->getChip(); - odb::dbBlock* block = chip->getBlock(); - + size_t enable_ordinal = 0; + size_t ordinal = 0; for (const std::unique_ptr& scan_chain : scan_chains) { - Stitch(block, *scan_chain, scan_enable); + Stitch(top_block_, *scan_chain, logger, ordinal, enable_ordinal); + ordinal += 1; + if (per_chain_enable_) { + enable_ordinal += 1; + } } } void ScanStitch::Stitch(odb::dbBlock* block, const ScanChain& scan_chain, - const ScanDriver& scan_enable) + utl::Logger* logger, + size_t ordinal, + size_t enable_ordinal) { - // Let's create the scan in and scan out of the chain - // TODO: Suport user defined scan signals + auto scan_enable_name + = fmt::format(FMT_RUNTIME(scan_enable_name_pattern_), enable_ordinal); + auto scan_enable = FindOrCreateScanEnable(block, scan_enable_name, logger); - ScanDriver scan_in_port = FindOrCreateScanIn(block); + // Let's create the scan in and scan out of the chain + auto scan_in_name = fmt::format(FMT_RUNTIME(scan_in_name_pattern_), ordinal); + ScanDriver scan_in_driver = FindOrCreateScanIn(block, scan_in_name, logger); // We need fast pop for front and back std::deque>> @@ -83,7 +91,7 @@ void ScanStitch::Stitch(odb::dbBlock* block, // Let's connect the first cell first_scan_cell->connectScanEnable(scan_enable); - first_scan_cell->connectScanIn(scan_in_port); + first_scan_cell->connectScanIn(scan_in_driver); if (!scan_cells.empty()) { scan_cells.begin()->get()->connectScanIn(first_scan_cell->getScanOut()); @@ -95,30 +103,137 @@ void ScanStitch::Stitch(odb::dbBlock* block, } // Let's connect the last cell - ScanLoad scan_out_port - = FindOrCreateScanOut(block, last_scan_cell->getScanOut()); - last_scan_cell->connectScanOut(scan_out_port); + auto scan_out_name + = fmt::format(FMT_RUNTIME(scan_out_name_pattern_), ordinal); + ScanLoad scan_out_load = FindOrCreateScanOut( + block, last_scan_cell->getScanOut(), scan_out_name, logger); + last_scan_cell->connectScanOut(scan_out_load); } -ScanDriver ScanStitch::FindOrCreateScanEnable(odb::dbBlock* block) +static std::pair> split_term_identifier( + const std::string& input, + const char* kind, + utl::Logger* logger) { - // TODO: For now we will create a new scan_enable pin at the top level. We - // need to support defining DFT signals for scan_enable - return CreateNewPort(block, kScanEnableNamePattern); + size_t tracker = 0; + size_t slash_position; + while ((slash_position = input.find('/', tracker)) != std::string::npos) { + if (slash_position != 0 && input[slash_position - 1] == '\\') { + tracker = slash_position + 1; + continue; + } + return {input.substr(0, slash_position), input.substr(slash_position + 1)}; + } + return {input, std::nullopt}; } -ScanDriver ScanStitch::FindOrCreateScanIn(odb::dbBlock* block) +ScanDriver ScanStitch::FindOrCreateDriver(const char* kind, + odb::dbBlock* block, + const std::string& with_name, + utl::Logger* logger) { - // TODO: For now we will create a new scan_in pin at the top level. We - // need to support defining DFT signals for scan_in - return CreateNewPort(block, kScanInNamePattern); + auto term_info = split_term_identifier(with_name, kind, logger); + + if (term_info.second.has_value()) { // Instance/ITerm + auto inst = block->findInst(term_info.first.c_str()); + if (inst == nullptr) { + logger->error(utl::DFT, + 34, + "Instance {} not found for {} port", + term_info.first, + kind); + } + auto iterm = inst->findITerm(term_info.second.value().c_str()); + if (iterm == nullptr) { + logger->error(utl::DFT, + 35, + "ITerm {}/{} not found for {} port", + term_info.first, + term_info.second.value(), + kind); + } + if (iterm->getIoType() != odb::dbIoType::OUTPUT) { + logger->error(utl::DFT, + 36, + "ITerm {}/{} for {} port is a {}", + term_info.first, + term_info.second.value(), + kind, + iterm->getIoType().getString()); + } + return ScanDriver(iterm); + } else { // BTerm + auto bterm = block->findBTerm(with_name.data()); + if (bterm != nullptr) { + // We don't actually care if it's an output, that works here too. + return ScanDriver(bterm); + } + return CreateNewPort(block, with_name, logger); + } +} + +ScanDriver ScanStitch::FindOrCreateScanEnable(odb::dbBlock* block, + const std::string& with_name, + utl::Logger* logger) +{ + return FindOrCreateDriver("scan-enable", block, with_name, logger); +} + +ScanDriver ScanStitch::FindOrCreateScanIn(odb::dbBlock* block, + const std::string& with_name, + utl::Logger* logger) +{ + return FindOrCreateDriver("scan-in", block, with_name, logger); } ScanLoad ScanStitch::FindOrCreateScanOut(odb::dbBlock* block, - const ScanDriver& cell_scan_out) + const ScanDriver& cell_scan_out, + const std::string& with_name, + utl::Logger* logger) { - // TODO: For now we will create a new scan_out pin at the top level if we need - // one. We need to support defining DFT signals for scan_out + const char* kind = "scan-out"; + auto term_info = split_term_identifier(with_name, kind, logger); + + if (term_info.second.has_value()) { // Instance/ITerm + auto inst = block->findInst(term_info.first.c_str()); + if (inst == nullptr) { + logger->error(utl::DFT, + 37, + "Instance {} not found for {} port", + term_info.first, + kind); + } + auto iterm = inst->findITerm(term_info.second.value().c_str()); + if (iterm == nullptr) { + logger->error(utl::DFT, + 38, + "ITerm {}/{} not found for {} port", + term_info.first, + term_info.second.value(), + kind); + } + if (iterm->getIoType() != odb::dbIoType::INPUT) { + logger->error(utl::DFT, + 39, + "ITerm {}/{} for {} port is a {}", + term_info.first, + term_info.second.value(), + kind, + iterm->getIoType().getString()); + } + return ScanLoad(iterm); + } + auto bterm = block->findBTerm(with_name.data()); + if (bterm != nullptr) { + if (bterm->getIoType() != odb::dbIoType::OUTPUT) { + logger->error(utl::DFT, + 40, + "Top-level pin '{}' specified as {} is not an output port", + term_info.first, + kind); + } + return ScanLoad(bterm); + } // TODO: Trace forward the scan out net so we can see if it is connected to a // top port or to functional logic @@ -134,7 +249,7 @@ ScanLoad ScanStitch::FindOrCreateScanOut(odb::dbBlock* block, } } - return CreateNewPort(block, kScanOutNamePattern); + return CreateNewPort(block, with_name, logger); } } // namespace dft diff --git a/src/dft/src/stitch/ScanStitch.hh b/src/dft/src/stitch/ScanStitch.hh index 41b03ff2c73..73fbdb8b134 100644 --- a/src/dft/src/stitch/ScanStitch.hh +++ b/src/dft/src/stitch/ScanStitch.hh @@ -36,6 +36,7 @@ #include #include "ScanChain.hh" +#include "Utils.hh" #include "odb/db.h" namespace dft { @@ -49,50 +50,63 @@ inline constexpr bool always_false_v = false; class ScanStitch { public: - explicit ScanStitch(odb::dbDatabase* db); + explicit ScanStitch(odb::dbDatabase* db, + bool per_chain_enable, + std::string scan_enable_name_pattern = "scan_enable_{}", + std::string scan_in_name_pattern = "scan_in_{}", + std::string scan_out_name_pattern = "scan_out_{}"); // Stitch all the cells inside each one of the scan chains together. - void Stitch(const std::vector>& scan_chains); + void Stitch(const std::vector>& scan_chains, + utl::Logger* logger); void Stitch(odb::dbBlock* block, const ScanChain& scan_chain, - const ScanDriver& scan_enable); + utl::Logger* logger, + size_t ordinal = 1, + size_t enable_ordinal = 1); private: - ScanDriver FindOrCreateScanEnable(odb::dbBlock* block); - ScanDriver FindOrCreateScanIn(odb::dbBlock* block); + ScanDriver FindOrCreateDriver(const char* kind, + odb::dbBlock* block, + const std::string& with_name, + utl::Logger* logger); + ScanDriver FindOrCreateScanEnable(odb::dbBlock* block, + const std::string& with_name, + utl::Logger* logger); + ScanDriver FindOrCreateScanIn(odb::dbBlock* block, + const std::string& with_name, + utl::Logger* logger); ScanLoad FindOrCreateScanOut(odb::dbBlock* block, - const ScanDriver& cell_scan_out); + const ScanDriver& cell_scan_out, + const std::string& with_name, + utl::Logger* logger); // Typesafe function to create Ports for the scan chains. template - Port CreateNewPort(odb::dbBlock* block, std::string_view name_pattern) + inline Port CreateNewPort(odb::dbBlock* block, + const std::string& port_name, + utl::Logger* logger, + odb::dbNet* net = nullptr) { - for (int port_number = 1;; ++port_number) { - std::string port_name - = fmt::format(FMT_RUNTIME(name_pattern), port_number); - odb::dbBTerm* port = block->findBTerm(port_name.c_str()); - if (!port) { - odb::dbNet* net = odb::dbNet::create(block, port_name.c_str()); - net->setSigType(odb::dbSigType::SCAN); - port = odb::dbBTerm::create(net, port_name.c_str()); - port->setSigType(odb::dbSigType::SCAN); + auto port = dft::utils::CreateNewPort(block, port_name, logger, net); - if constexpr (std::is_same_v) { - port->setIoType(odb::dbIoType::OUTPUT); - } else if constexpr (std::is_same_v) { - port->setIoType(odb::dbIoType::INPUT); - } else { - static_assert(always_false_v, - "Non-exhaustive cases for Port Type"); - } - - return Port(port); - } + if constexpr (std::is_same_v) { + port->setIoType(odb::dbIoType::OUTPUT); + } else if constexpr (std::is_same_v) { + port->setIoType(odb::dbIoType::INPUT); + } else { + static_assert(always_false_v, "Non-exhaustive cases for Port Type"); } + + return Port(port); } odb::dbDatabase* db_; odb::dbBlock* top_block_; + bool per_chain_enable_; + std::string scan_enable_name_pattern_; + std::string scan_in_name_pattern_; + std::string scan_out_name_pattern_; }; } // namespace dft diff --git a/src/dft/src/utils/Utils.cpp b/src/dft/src/utils/Utils.cpp index d8bbf237f77..23c310bd212 100644 --- a/src/dft/src/utils/Utils.cpp +++ b/src/dft/src/utils/Utils.cpp @@ -126,4 +126,42 @@ std::optional GetClock(sta::dbSta* sta, odb::dbITerm* iterm) return std::nullopt; } +bool IsScanCell(const sta::LibertyCell* libertyCell) +{ + const sta::TestCell* test_cell = libertyCell->testCell(); + if (test_cell) { + return getLibertyScanIn(test_cell) != nullptr + && getLibertyScanEnable(test_cell) != nullptr; + } + return false; +} + +odb::dbBTerm* CreateNewPort(odb::dbBlock* block, + const std::string& port_name, + utl::Logger* logger, + odb::dbNet* net) +{ + if (!net) { + net = odb::dbNet::create(block, port_name.c_str()); + if (!net) { + logger->error(utl::DFT, + 31, + "Error while attempting to create new port {}: an " + "unrelated net with the same name already exists", + port_name); + } + net->setSigType(odb::dbSigType::SCAN); + } + auto port = odb::dbBTerm::create(net, port_name.c_str()); + if (port == nullptr) { + logger->error(utl::DFT, + 18, + "Failed to create port: a port named '{}' already exists", + port_name); + } + port->setSigType(odb::dbSigType::SCAN); + + return port; +} + } // namespace dft::utils diff --git a/src/dft/src/utils/Utils.hh b/src/dft/src/utils/Utils.hh index 1c7fb4f7116..f15cc380529 100644 --- a/src/dft/src/utils/Utils.hh +++ b/src/dft/src/utils/Utils.hh @@ -61,4 +61,14 @@ std::vector GetClockPin(odb::dbInst* inst); // Returns a sta::Clock of the given iterm std::optional GetClock(sta::dbSta* sta, odb::dbITerm* iterm); +// Checks if the given LibertyCell is really a Scan Cell with a Scan In and a +// Scan Enable +bool IsScanCell(const sta::LibertyCell* libertyCell); + +// Convenience method to create a new port +odb::dbBTerm* CreateNewPort(odb::dbBlock* block, + const std::string& port_name, + utl::Logger* logger, + odb::dbNet* net = nullptr); + } // namespace dft::utils diff --git a/src/dft/test/max_chain_count_sky130.vok b/src/dft/test/max_chain_count_sky130.vok index 74a83c0746c..259d722f5b6 100644 --- a/src/dft/test/max_chain_count_sky130.vok +++ b/src/dft/test/max_chain_count_sky130.vok @@ -11,8 +11,8 @@ module max_chain_count (clock, output9, port1, set_b, - scan_enable_1, - scan_in_1); + scan_enable_0, + scan_in_0); input clock; output output1; output output10; @@ -26,68 +26,68 @@ module max_chain_count (clock, output output9; input port1; input set_b; - input scan_enable_1; - input scan_in_1; + input scan_enable_0; + input scan_in_0; sky130_fd_sc_hd__sdfsbp_1 ff1_clk1_rising (.D(port1), .Q(output1), .SCD(output2), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff2_clk1_rising (.D(port1), .Q(output2), .SCD(output3), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff3_clk1_rising (.D(port1), .Q(output3), .SCD(output4), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff4_clk1_rising (.D(port1), .Q(output4), .SCD(output5), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff5_clk1_rising (.D(port1), .Q(output5), .SCD(output6), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff6_clk1_rising (.D(port1), .Q(output6), .SCD(output7), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff7_clk1_rising (.D(port1), .Q(output7), .SCD(output8), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff8_clk1_rising (.D(port1), .Q(output8), .SCD(output9), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff9_clk1_rising (.D(port1), .Q(output9), - .SCD(scan_in_1), - .SCE(scan_enable_1), + .SCD(scan_in_0), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff10_clk1_rising (.D(port1), .Q(output10), .SCD(output1), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); endmodule diff --git a/src/dft/test/one_cell_sky130.ok b/src/dft/test/one_cell_sky130.ok index ab785342e9b..a44975ad6a8 100644 --- a/src/dft/test/one_cell_sky130.ok +++ b/src/dft/test/one_cell_sky130.ok @@ -53,8 +53,8 @@ Instance ff1 Path cells: sky130_fd_sc_hd__sdfsbp_1 Input pins: D input port1 - SCD input scan_in_1 - SCE input scan_enable_1 + SCD input scan_in_0 + SCE input scan_enable_0 SET_B input set_b CLK input clock Output pins: diff --git a/src/dft/test/one_cell_sky130.vok b/src/dft/test/one_cell_sky130.vok index a8a47cf04b8..8f31233ec66 100644 --- a/src/dft/test/one_cell_sky130.vok +++ b/src/dft/test/one_cell_sky130.vok @@ -2,20 +2,20 @@ module one_cell (clock, output1, port1, set_b, - scan_enable_1, - scan_in_1); + scan_enable_0, + scan_in_0); input clock; output output1; input port1; input set_b; - input scan_enable_1; - input scan_in_1; + input scan_enable_0; + input scan_in_0; sky130_fd_sc_hd__sdfsbp_1 ff1 (.D(port1), .Q(output1), - .SCD(scan_in_1), - .SCE(scan_enable_1), + .SCD(scan_in_0), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); endmodule diff --git a/src/dft/test/place_sort_sky130.vok b/src/dft/test/place_sort_sky130.vok index b531c40d2fa..4d7217ec703 100644 --- a/src/dft/test/place_sort_sky130.vok +++ b/src/dft/test/place_sort_sky130.vok @@ -11,8 +11,8 @@ module place_sort (clock, output9, port1, set_b, - scan_enable_1, - scan_in_1); + scan_enable_0, + scan_in_0); input clock; output output1; output output10; @@ -26,68 +26,68 @@ module place_sort (clock, output output9; input port1; input set_b; - input scan_enable_1; - input scan_in_1; + input scan_enable_0; + input scan_in_0; sky130_fd_sc_hd__sdfsbp_1 ff1_clk1_rising (.D(port1), .Q(output1), .SCD(output5), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff2_clk1_rising (.D(port1), .Q(output2), .SCD(output8), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff3_clk1_rising (.D(port1), .Q(output3), .SCD(output4), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff4_clk1_rising (.D(port1), .Q(output4), .SCD(output9), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff5_clk1_rising (.D(port1), .Q(output5), - .SCD(scan_in_1), - .SCE(scan_enable_1), + .SCD(scan_in_0), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff6_clk1_rising (.D(port1), .Q(output6), .SCD(output2), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff7_clk1_rising (.D(port1), .Q(output7), .SCD(output6), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff8_clk1_rising (.D(port1), .Q(output8), .SCD(output10), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff9_clk1_rising (.D(port1), .Q(output9), .SCD(output7), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 ff10_clk1_rising (.D(port1), .Q(output10), .SCD(output1), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock)); endmodule diff --git a/src/dft/test/scan_architect_clock_mix_sky130.vok b/src/dft/test/scan_architect_clock_mix_sky130.vok index b308bc10ee6..84827e7deb2 100644 --- a/src/dft/test/scan_architect_clock_mix_sky130.vok +++ b/src/dft/test/scan_architect_clock_mix_sky130.vok @@ -22,14 +22,14 @@ module scan_architect (clock1, output9, port1, set_b, - scan_enable_1, + scan_enable_0, + scan_in_0, scan_in_1, scan_in_2, scan_in_3, scan_in_4, scan_in_5, - scan_in_6, - scan_in_7); + scan_in_6); input clock1; input clock2; output output1; @@ -54,134 +54,134 @@ module scan_architect (clock1, output output9; input port1; input set_b; - input scan_enable_1; + input scan_enable_0; + input scan_in_0; input scan_in_1; input scan_in_2; input scan_in_3; input scan_in_4; input scan_in_5; input scan_in_6; - input scan_in_7; sky130_fd_sc_hd__sdfsbp_1 ff10_clk2_rising (.D(port1), .Q(output10), .SCD(output14), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock2)); sky130_fd_sc_hd__sdfbbn_1 ff1_clk1_falling (.D(port1), .Q(output11), - .SCD(scan_in_4), - .SCE(scan_enable_1), + .SCD(scan_in_3), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock1)); sky130_fd_sc_hd__sdfsbp_1 ff1_clk1_rising (.D(port1), .Q(output1), - .SCD(scan_in_7), - .SCE(scan_enable_1), + .SCD(scan_in_6), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock1)); sky130_fd_sc_hd__sdfbbn_1 ff2_clk2_falling (.D(port1), .Q(output12), .SCD(output18), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock2)); sky130_fd_sc_hd__sdfsbp_1 ff2_clk2_rising (.D(port1), .Q(output2), .SCD(output8), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock2)); sky130_fd_sc_hd__sdfbbn_1 ff3_clk1_falling (.D(port1), .Q(output13), .SCD(output11), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock1)); sky130_fd_sc_hd__sdfsbp_1 ff3_clk1_rising (.D(port1), .Q(output3), - .SCD(scan_in_6), - .SCE(scan_enable_1), + .SCD(scan_in_5), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock1)); sky130_fd_sc_hd__sdfbbn_1 ff4_clk2_falling (.D(port1), .Q(output14), .SCD(output20), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock2)); sky130_fd_sc_hd__sdfsbp_1 ff4_clk2_rising (.D(port1), .Q(output4), .SCD(output13), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock2)); sky130_fd_sc_hd__sdfbbn_1 ff5_clk1_falling (.D(port1), .Q(output15), .SCD(output19), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock1)); sky130_fd_sc_hd__sdfsbp_1 ff5_clk1_rising (.D(port1), .Q(output5), .SCD(output3), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock1)); sky130_fd_sc_hd__sdfbbn_1 ff6_clk2_falling (.D(port1), .Q(output16), .SCD(output12), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock2)); sky130_fd_sc_hd__sdfsbp_1 ff6_clk2_rising (.D(port1), .Q(output6), .SCD(output2), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock2)); sky130_fd_sc_hd__sdfbbn_1 ff7_clk1_falling (.D(port1), .Q(output17), - .SCD(scan_in_5), - .SCE(scan_enable_1), + .SCD(scan_in_4), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock1)); sky130_fd_sc_hd__sdfsbp_1 ff7_clk1_rising (.D(port1), .Q(output7), .SCD(output5), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock1)); sky130_fd_sc_hd__sdfbbn_1 ff8_clk2_falling (.D(port1), .Q(output18), - .SCD(scan_in_1), - .SCE(scan_enable_1), + .SCD(scan_in_0), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock2)); sky130_fd_sc_hd__sdfsbp_1 ff8_clk2_rising (.D(port1), .Q(output8), - .SCD(scan_in_3), - .SCE(scan_enable_1), + .SCD(scan_in_2), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock2)); sky130_fd_sc_hd__sdfbbn_1 ff9_clk1_falling (.D(port1), .Q(output19), .SCD(output17), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock1)); sky130_fd_sc_hd__sdfsbp_1 ff9_clk1_rising (.D(port1), .Q(output9), .SCD(output1), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock1)); sky130_fd_sc_hd__sdfbbn_1 ff10_clk2_falling (.D(port1), .Q(output20), - .SCD(scan_in_2), - .SCE(scan_enable_1), + .SCD(scan_in_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock2)); endmodule diff --git a/src/dft/test/scan_architect_no_mix_sky130.vok b/src/dft/test/scan_architect_no_mix_sky130.vok index 6242ff0352b..f8098892812 100644 --- a/src/dft/test/scan_architect_no_mix_sky130.vok +++ b/src/dft/test/scan_architect_no_mix_sky130.vok @@ -22,11 +22,11 @@ module scan_architect (clock1, output9, port1, set_b, - scan_enable_1, + scan_enable_0, + scan_in_0, scan_in_1, scan_in_2, - scan_in_3, - scan_in_4); + scan_in_3); input clock1; input clock2; output output1; @@ -51,131 +51,131 @@ module scan_architect (clock1, output output9; input port1; input set_b; - input scan_enable_1; + input scan_enable_0; + input scan_in_0; input scan_in_1; input scan_in_2; input scan_in_3; - input scan_in_4; sky130_fd_sc_hd__sdfsbp_1 ff10_clk2_rising (.D(port1), .Q(output10), .SCD(output2), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock2)); sky130_fd_sc_hd__sdfbbn_1 ff1_clk1_falling (.D(port1), .Q(output11), .SCD(output13), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock1)); sky130_fd_sc_hd__sdfsbp_1 ff1_clk1_rising (.D(port1), .Q(output1), .SCD(output3), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock1)); sky130_fd_sc_hd__sdfbbn_1 ff2_clk2_falling (.D(port1), .Q(output12), .SCD(output14), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock2)); sky130_fd_sc_hd__sdfsbp_1 ff2_clk2_rising (.D(port1), .Q(output2), .SCD(output4), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock2)); sky130_fd_sc_hd__sdfbbn_1 ff3_clk1_falling (.D(port1), .Q(output13), .SCD(output15), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock1)); sky130_fd_sc_hd__sdfsbp_1 ff3_clk1_rising (.D(port1), .Q(output3), .SCD(output5), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock1)); sky130_fd_sc_hd__sdfbbn_1 ff4_clk2_falling (.D(port1), .Q(output14), .SCD(output16), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock2)); sky130_fd_sc_hd__sdfsbp_1 ff4_clk2_rising (.D(port1), .Q(output4), .SCD(output6), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock2)); sky130_fd_sc_hd__sdfbbn_1 ff5_clk1_falling (.D(port1), .Q(output15), .SCD(output17), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock1)); sky130_fd_sc_hd__sdfsbp_1 ff5_clk1_rising (.D(port1), .Q(output5), .SCD(output7), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock1)); sky130_fd_sc_hd__sdfbbn_1 ff6_clk2_falling (.D(port1), .Q(output16), .SCD(output18), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock2)); sky130_fd_sc_hd__sdfsbp_1 ff6_clk2_rising (.D(port1), .Q(output6), .SCD(output8), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock2)); sky130_fd_sc_hd__sdfbbn_1 ff7_clk1_falling (.D(port1), .Q(output17), .SCD(output19), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock1)); sky130_fd_sc_hd__sdfsbp_1 ff7_clk1_rising (.D(port1), .Q(output7), .SCD(output9), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock1)); sky130_fd_sc_hd__sdfbbn_1 ff8_clk2_falling (.D(port1), .Q(output18), - .SCD(scan_in_3), - .SCE(scan_enable_1), + .SCD(scan_in_2), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock2)); sky130_fd_sc_hd__sdfsbp_1 ff8_clk2_rising (.D(port1), .Q(output8), - .SCD(scan_in_4), - .SCE(scan_enable_1), + .SCD(scan_in_3), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock2)); sky130_fd_sc_hd__sdfbbn_1 ff9_clk1_falling (.D(port1), .Q(output19), - .SCD(scan_in_1), - .SCE(scan_enable_1), + .SCD(scan_in_0), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock1)); sky130_fd_sc_hd__sdfsbp_1 ff9_clk1_rising (.D(port1), .Q(output9), - .SCD(scan_in_2), - .SCE(scan_enable_1), + .SCD(scan_in_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK(clock1)); sky130_fd_sc_hd__sdfbbn_1 ff10_clk2_falling (.D(port1), .Q(output20), .SCD(output12), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(set_b), .CLK_N(clock2)); endmodule diff --git a/src/dft/test/scan_architect_register_bank_no_clock_mix_sky130.vok b/src/dft/test/scan_architect_register_bank_no_clock_mix_sky130.vok index 2ea254a39f6..6b05bc54579 100644 --- a/src/dft/test/scan_architect_register_bank_no_clock_mix_sky130.vok +++ b/src/dft/test/scan_architect_register_bank_no_clock_mix_sky130.vok @@ -6,9 +6,9 @@ module top (clk1, inputs_64, outputs_32, outputs_64, - scan_enable_1, - scan_in_1, - scan_in_2); + scan_enable_0, + scan_in_0, + scan_in_1); input clk1; input clk2; input enable; @@ -17,9 +17,9 @@ module top (clk1, input [63:0] inputs_64; output [31:0] outputs_32; output [63:0] outputs_64; - input scan_enable_1; + input scan_enable_0; + input scan_in_0; input scan_in_1; - input scan_in_2; wire \bank1/_000_ ; wire \bank1/_001_ ; @@ -409,194 +409,194 @@ module top (clk1, sky130_fd_sc_hd__sdfrbp_1 \bank1/_129_ (.D(\bank1/_033_ ), .Q(outputs_32[1]), .RESET_B(\bank1/_001_ ), - .SCD(scan_in_2), - .SCE(scan_enable_1), + .SCD(scan_in_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_130_ (.D(\bank1/_034_ ), .Q(outputs_32[2]), .RESET_B(\bank1/_002_ ), .SCD(outputs_32[1]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_131_ (.D(\bank1/_035_ ), .Q(outputs_32[3]), .RESET_B(\bank1/_003_ ), .SCD(outputs_32[2]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_132_ (.D(\bank1/_036_ ), .Q(outputs_32[4]), .RESET_B(\bank1/_004_ ), .SCD(outputs_32[3]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_133_ (.D(\bank1/_037_ ), .Q(outputs_32[5]), .RESET_B(\bank1/_005_ ), .SCD(outputs_32[4]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_134_ (.D(\bank1/_038_ ), .Q(outputs_32[6]), .RESET_B(\bank1/_006_ ), .SCD(outputs_32[5]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_135_ (.D(\bank1/_039_ ), .Q(outputs_32[7]), .RESET_B(\bank1/_007_ ), .SCD(outputs_32[6]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_136_ (.D(\bank1/_040_ ), .Q(outputs_32[8]), .RESET_B(\bank1/_008_ ), .SCD(outputs_32[7]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_137_ (.D(\bank1/_041_ ), .Q(outputs_32[9]), .RESET_B(\bank1/_009_ ), .SCD(outputs_32[8]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_138_ (.D(\bank1/_042_ ), .Q(outputs_32[10]), .RESET_B(\bank1/_010_ ), .SCD(outputs_32[9]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_139_ (.D(\bank1/_043_ ), .Q(outputs_32[11]), .RESET_B(\bank1/_011_ ), .SCD(outputs_32[10]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_140_ (.D(\bank1/_044_ ), .Q(outputs_32[12]), .RESET_B(\bank1/_012_ ), .SCD(outputs_32[11]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_141_ (.D(\bank1/_045_ ), .Q(outputs_32[13]), .RESET_B(\bank1/_013_ ), .SCD(outputs_32[12]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_142_ (.D(\bank1/_046_ ), .Q(outputs_32[14]), .RESET_B(\bank1/_014_ ), .SCD(outputs_32[13]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_143_ (.D(\bank1/_047_ ), .Q(outputs_32[15]), .RESET_B(\bank1/_015_ ), .SCD(outputs_32[14]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_144_ (.D(\bank1/_048_ ), .Q(outputs_32[16]), .RESET_B(\bank1/_016_ ), .SCD(outputs_32[31]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_145_ (.D(\bank1/_049_ ), .Q(outputs_32[17]), .RESET_B(\bank1/_017_ ), .SCD(outputs_32[0]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_146_ (.D(\bank1/_050_ ), .Q(outputs_32[18]), .RESET_B(\bank1/_018_ ), .SCD(outputs_32[17]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_147_ (.D(\bank1/_051_ ), .Q(outputs_32[19]), .RESET_B(\bank1/_019_ ), .SCD(outputs_32[18]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_148_ (.D(\bank1/_052_ ), .Q(outputs_32[20]), .RESET_B(\bank1/_020_ ), .SCD(outputs_32[19]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_149_ (.D(\bank1/_053_ ), .Q(outputs_32[21]), .RESET_B(\bank1/_021_ ), .SCD(outputs_32[20]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_150_ (.D(\bank1/_054_ ), .Q(outputs_32[22]), .RESET_B(\bank1/_022_ ), .SCD(outputs_32[21]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_151_ (.D(\bank1/_055_ ), .Q(outputs_32[23]), .RESET_B(\bank1/_023_ ), .SCD(outputs_32[22]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_152_ (.D(\bank1/_056_ ), .Q(outputs_32[24]), .RESET_B(\bank1/_024_ ), .SCD(outputs_32[23]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_153_ (.D(\bank1/_057_ ), .Q(outputs_32[25]), .RESET_B(\bank1/_025_ ), .SCD(outputs_32[24]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_154_ (.D(\bank1/_058_ ), .Q(outputs_32[26]), .RESET_B(\bank1/_026_ ), .SCD(outputs_32[25]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_155_ (.D(\bank1/_059_ ), .Q(outputs_32[27]), .RESET_B(\bank1/_027_ ), .SCD(outputs_32[26]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_156_ (.D(\bank1/_060_ ), .Q(outputs_32[28]), .RESET_B(\bank1/_028_ ), .SCD(outputs_32[27]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_157_ (.D(\bank1/_061_ ), .Q(outputs_32[29]), .RESET_B(\bank1/_029_ ), .SCD(outputs_32[28]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_158_ (.D(\bank1/_062_ ), .Q(outputs_32[30]), .RESET_B(\bank1/_030_ ), .SCD(outputs_32[29]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_159_ (.D(\bank1/_063_ ), .Q(outputs_32[31]), .RESET_B(\bank1/_031_ ), .SCD(outputs_32[30]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_256_ (.D(\bank2/_064_ ), .Q(outputs_64[11]), .RESET_B(\bank2/_000_ ), .SCD(outputs_64[28]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__clkinv_1 \bank2/_128_ (.A(reset), .Y(\bank2/_000_ )); @@ -986,384 +986,384 @@ module top (clk1, .Q(outputs_64[12]), .RESET_B(\bank2/_001_ ), .SCD(outputs_64[13]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_258_ (.D(\bank2/_066_ ), .Q(outputs_64[13]), .RESET_B(\bank2/_002_ ), .SCD(outputs_64[14]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_259_ (.D(\bank2/_067_ ), .Q(outputs_64[14]), .RESET_B(\bank2/_003_ ), .SCD(outputs_64[15]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_260_ (.D(\bank2/_068_ ), .Q(outputs_64[15]), .RESET_B(\bank2/_004_ ), .SCD(outputs_64[16]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_261_ (.D(\bank2/_069_ ), .Q(outputs_64[16]), .RESET_B(\bank2/_005_ ), .SCD(outputs_64[17]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_262_ (.D(\bank2/_070_ ), .Q(outputs_64[17]), .RESET_B(\bank2/_006_ ), .SCD(outputs_64[18]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_263_ (.D(\bank2/_071_ ), .Q(outputs_64[18]), .RESET_B(\bank2/_007_ ), .SCD(outputs_64[19]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_264_ (.D(\bank2/_072_ ), .Q(outputs_64[19]), .RESET_B(\bank2/_008_ ), .SCD(outputs_64[20]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_265_ (.D(\bank2/_073_ ), .Q(outputs_64[20]), .RESET_B(\bank2/_009_ ), .SCD(outputs_64[21]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_266_ (.D(\bank2/_074_ ), .Q(outputs_64[21]), .RESET_B(\bank2/_010_ ), .SCD(outputs_64[22]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_267_ (.D(\bank2/_075_ ), .Q(outputs_64[22]), .RESET_B(\bank2/_011_ ), .SCD(outputs_64[23]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_268_ (.D(\bank2/_076_ ), .Q(outputs_64[23]), .RESET_B(\bank2/_012_ ), .SCD(outputs_64[24]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_269_ (.D(\bank2/_077_ ), .Q(outputs_64[24]), .RESET_B(\bank2/_013_ ), .SCD(outputs_64[25]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_270_ (.D(\bank2/_078_ ), .Q(outputs_64[25]), .RESET_B(\bank2/_014_ ), .SCD(outputs_64[26]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_271_ (.D(\bank2/_079_ ), .Q(outputs_64[26]), .RESET_B(\bank2/_015_ ), .SCD(outputs_64[11]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_272_ (.D(\bank2/_080_ ), .Q(outputs_64[27]), .RESET_B(\bank2/_016_ ), .SCD(outputs_64[12]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_273_ (.D(\bank2/_081_ ), .Q(outputs_64[28]), .RESET_B(\bank2/_017_ ), .SCD(outputs_64[29]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_274_ (.D(\bank2/_082_ ), .Q(outputs_64[29]), .RESET_B(\bank2/_018_ ), .SCD(outputs_64[30]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_275_ (.D(\bank2/_083_ ), .Q(outputs_64[30]), .RESET_B(\bank2/_019_ ), .SCD(outputs_64[31]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_276_ (.D(\bank2/_084_ ), .Q(outputs_64[31]), .RESET_B(\bank2/_020_ ), .SCD(outputs_64[32]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_277_ (.D(\bank2/_085_ ), .Q(outputs_64[32]), .RESET_B(\bank2/_021_ ), .SCD(outputs_64[33]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_278_ (.D(\bank2/_086_ ), .Q(outputs_64[33]), .RESET_B(\bank2/_022_ ), .SCD(outputs_64[34]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_279_ (.D(\bank2/_087_ ), .Q(outputs_64[34]), .RESET_B(\bank2/_023_ ), .SCD(outputs_64[35]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_280_ (.D(\bank2/_088_ ), .Q(outputs_64[35]), .RESET_B(\bank2/_024_ ), .SCD(outputs_64[36]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_281_ (.D(\bank2/_089_ ), .Q(outputs_64[36]), .RESET_B(\bank2/_025_ ), .SCD(outputs_64[37]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_282_ (.D(\bank2/_090_ ), .Q(outputs_64[37]), .RESET_B(\bank2/_026_ ), .SCD(outputs_64[38]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_283_ (.D(\bank2/_091_ ), .Q(outputs_64[38]), .RESET_B(\bank2/_027_ ), .SCD(outputs_64[39]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_284_ (.D(\bank2/_092_ ), .Q(outputs_64[39]), .RESET_B(\bank2/_028_ ), .SCD(outputs_64[40]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_285_ (.D(\bank2/_093_ ), .Q(outputs_64[40]), .RESET_B(\bank2/_029_ ), .SCD(outputs_64[41]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_286_ (.D(\bank2/_094_ ), .Q(outputs_64[41]), .RESET_B(\bank2/_030_ ), .SCD(outputs_64[42]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_287_ (.D(\bank2/_095_ ), .Q(outputs_64[42]), .RESET_B(\bank2/_031_ ), - .SCD(scan_in_1), - .SCE(scan_enable_1), + .SCD(scan_in_0), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_288_ (.D(\bank2/_096_ ), .Q(outputs_64[43]), .RESET_B(\bank2/_032_ ), .SCD(outputs_64[60]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_289_ (.D(\bank2/_097_ ), .Q(outputs_64[44]), .RESET_B(\bank2/_033_ ), .SCD(outputs_64[45]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_290_ (.D(\bank2/_098_ ), .Q(outputs_64[45]), .RESET_B(\bank2/_034_ ), .SCD(outputs_64[46]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_291_ (.D(\bank2/_099_ ), .Q(outputs_64[46]), .RESET_B(\bank2/_035_ ), .SCD(outputs_64[47]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_292_ (.D(\bank2/_100_ ), .Q(outputs_64[47]), .RESET_B(\bank2/_036_ ), .SCD(outputs_64[48]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_293_ (.D(\bank2/_101_ ), .Q(outputs_64[48]), .RESET_B(\bank2/_037_ ), .SCD(outputs_64[49]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_294_ (.D(\bank2/_102_ ), .Q(outputs_64[49]), .RESET_B(\bank2/_038_ ), .SCD(outputs_64[50]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_295_ (.D(\bank2/_103_ ), .Q(outputs_64[50]), .RESET_B(\bank2/_039_ ), .SCD(outputs_64[51]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_296_ (.D(\bank2/_104_ ), .Q(outputs_64[51]), .RESET_B(\bank2/_040_ ), .SCD(outputs_64[52]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_297_ (.D(\bank2/_105_ ), .Q(outputs_64[52]), .RESET_B(\bank2/_041_ ), .SCD(outputs_64[53]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_298_ (.D(\bank2/_106_ ), .Q(outputs_64[53]), .RESET_B(\bank2/_042_ ), .SCD(outputs_64[54]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_299_ (.D(\bank2/_107_ ), .Q(outputs_64[54]), .RESET_B(\bank2/_043_ ), .SCD(outputs_64[55]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_300_ (.D(\bank2/_108_ ), .Q(outputs_64[55]), .RESET_B(\bank2/_044_ ), .SCD(outputs_64[56]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_301_ (.D(\bank2/_109_ ), .Q(outputs_64[56]), .RESET_B(\bank2/_045_ ), .SCD(outputs_64[57]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_302_ (.D(\bank2/_110_ ), .Q(outputs_64[57]), .RESET_B(\bank2/_046_ ), .SCD(outputs_64[58]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_303_ (.D(\bank2/_111_ ), .Q(outputs_64[58]), .RESET_B(\bank2/_047_ ), .SCD(outputs_64[43]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_304_ (.D(\bank2/_112_ ), .Q(outputs_64[59]), .RESET_B(\bank2/_048_ ), .SCD(outputs_64[44]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_305_ (.D(\bank2/_113_ ), .Q(outputs_64[60]), .RESET_B(\bank2/_049_ ), .SCD(outputs_64[61]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_306_ (.D(\bank2/_114_ ), .Q(outputs_64[61]), .RESET_B(\bank2/_050_ ), .SCD(outputs_64[62]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_307_ (.D(\bank2/_115_ ), .Q(outputs_64[62]), .RESET_B(\bank2/_051_ ), .SCD(outputs_64[63]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_308_ (.D(\bank2/_116_ ), .Q(outputs_64[63]), .RESET_B(\bank2/_052_ ), .SCD(outputs_64[0]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_309_ (.D(\bank2/_117_ ), .Q(outputs_64[0]), .RESET_B(\bank2/_053_ ), .SCD(outputs_64[1]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_310_ (.D(\bank2/_118_ ), .Q(outputs_64[1]), .RESET_B(\bank2/_054_ ), .SCD(outputs_64[2]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_311_ (.D(\bank2/_119_ ), .Q(outputs_64[2]), .RESET_B(\bank2/_055_ ), .SCD(outputs_64[3]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_312_ (.D(\bank2/_120_ ), .Q(outputs_64[3]), .RESET_B(\bank2/_056_ ), .SCD(outputs_64[4]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_313_ (.D(\bank2/_121_ ), .Q(outputs_64[4]), .RESET_B(\bank2/_057_ ), .SCD(outputs_64[5]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_314_ (.D(\bank2/_122_ ), .Q(outputs_64[5]), .RESET_B(\bank2/_058_ ), .SCD(outputs_64[6]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_315_ (.D(\bank2/_123_ ), .Q(outputs_64[6]), .RESET_B(\bank2/_059_ ), .SCD(outputs_64[7]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_316_ (.D(\bank2/_124_ ), .Q(outputs_64[7]), .RESET_B(\bank2/_060_ ), .SCD(outputs_64[8]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_317_ (.D(\bank2/_125_ ), .Q(outputs_64[8]), .RESET_B(\bank2/_061_ ), .SCD(outputs_64[9]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_318_ (.D(\bank2/_126_ ), .Q(outputs_64[9]), .RESET_B(\bank2/_062_ ), .SCD(outputs_64[10]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank2/_319_ (.D(\bank2/_127_ ), .Q(outputs_64[10]), .RESET_B(\bank2/_063_ ), .SCD(outputs_64[27]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk2)); sky130_fd_sc_hd__sdfrbp_1 \bank1/_128_ (.D(\bank1/_032_ ), .Q(outputs_32[0]), .RESET_B(\bank1/_000_ ), .SCD(outputs_32[15]), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .CLK(clk1)); endmodule diff --git a/src/dft/test/sub_modules_sky130.vok b/src/dft/test/sub_modules_sky130.vok index b67b4459c5c..3df669648c6 100644 --- a/src/dft/test/sub_modules_sky130.vok +++ b/src/dft/test/sub_modules_sky130.vok @@ -2,31 +2,31 @@ module sub_modules (clock, output1, port1, set_b, - scan_enable_1, - scan_in_1, - scan_out_1); + scan_enable_0, + scan_in_0, + scan_out_0); input clock; output output1; input port1; input set_b; - input scan_enable_1; - input scan_in_1; - output scan_out_1; + input scan_enable_0; + input scan_in_0; + output scan_out_0; wire \my_shift_register/net1 ; wire \my_shift_register/set_b ; sky130_fd_sc_hd__sdfsbp_1 \my_shift_register/ff2 (.D(\my_shift_register/net1 ), .Q(output1), - .SCD(scan_in_1), - .SCE(scan_enable_1), + .SCD(scan_in_0), + .SCE(scan_enable_0), .SET_B(\my_shift_register/set_b ), .CLK(clock)); sky130_fd_sc_hd__sdfsbp_1 \my_shift_register/ff1 (.D(port1), .Q(\my_shift_register/net1 ), .SCD(output1), - .SCE(scan_enable_1), + .SCE(scan_enable_0), .SET_B(\my_shift_register/set_b ), .CLK(clock)); - assign scan_out_1 = \my_shift_register/net1 ; + assign scan_out_0 = \my_shift_register/net1 ; endmodule