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/README.md b/src/dft/README.md index e25ed0a6641..eb0c3f1a47a 100644 --- a/src/dft/README.md +++ b/src/dft/README.md @@ -28,6 +28,10 @@ set_dft_config [-max_length ] [-max_chains ] [-clock_mixing ] + [-scan_enable_mode ] + [-scan_enable_name_pattern ] + [-scan_in_name_pattern ] + [-scan_out_name_pattern ] ``` #### Options @@ -38,6 +42,10 @@ set_dft_config | `-max_chains` | The maximum number of scan chains that will be generated. This takes priority over `max_length`, in `no_mix` clock mode it specifies a maximum number of chains per clock-edge pair. | | `-clock_mixing` | How architect will mix the scan flops based on the clock driver. `no_mix`: Creates scan chains with only one type of clock and edge. This may create unbalanced chains. `clock_mix`: Creates scan chains mixing clocks and edges. Falling edge flops are going to be stitched before rising edge. | +| `-scan_enable_mode` | Experimental: how the scan chain enable signals will be created/assigned by the scan chain stitcher. `global`: All scan chains use the same enable signal. `per_chain`: Each scan chain gets assigned or created its own scan enanle. The default is `global`. | +| `-scan_enable_name_pattern` | A format pattern with exactly one set of braces (`{}`) to use to find or create scan enable drivers during scan chain stitching. The braces will be replaced with the chain's ordinal number (starting at `0`) if `-scan_enable_mode` is set to `per_chain`, 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 during scan chain stitching. 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 during scan chain stitching. 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. | ### Report DFT Config @@ -77,14 +85,13 @@ 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 ``` - ## Example scripts This example will create scan chains with a max length of 10 bits mixing all the diff --git a/src/dft/include/dft/Dft.hh b/src/dft/include/dft/Dft.hh index cfa70cc08c3..12e3d8c623a 100644 --- a/src/dft/include/dft/Dft.hh +++ b/src/dft/include/dft/Dft.hh @@ -31,6 +31,7 @@ // POSSIBILITY OF SUCH DAMAGE. #pragma once +#include "ClockDomain.hh" #include "db_sta/dbSta.hh" #include "odb/db.h" #include "utl/Logger.h" diff --git a/src/dft/src/Dft.cpp b/src/dft/src/Dft.cpp index a6512f989c7..541ce949bea 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" @@ -44,6 +46,8 @@ #include "odb/db.h" #include "utl/Logger.h" +constexpr char kDefaultPartition[] = "default"; + namespace dft { Dft::Dft() : dft_config_(std::make_unique()) @@ -111,8 +115,43 @@ void Dft::insertDft() } std::vector> scan_chains = scanArchitect(); - ScanStitch stitch(db_); + ScanStitch stitch(db_, logger_, dft_config_->getScanStitchConfig()); stitch.Stitch(scan_chains); + + // Write scan chains to odb + odb::dbBlock* db_block = db_->getChip()->getBlock(); + odb::dbDft* db_dft = db_block->getDft(); + + for (auto& chain : scan_chains) { + odb::dbScanChain* db_sc = odb::dbScanChain::create(db_dft); + db_sc->setName(chain->getName()); + odb::dbScanPartition* db_part = odb::dbScanPartition::create(db_sc); + db_part->setName(kDefaultPartition); + odb::dbScanList* db_scanlist = odb::dbScanList::create(db_part); + + for (auto& scan_cell : chain->getScanCells()) { + std::string inst_name(scan_cell->getName()); + odb::dbInst* db_inst = db_block->findInst(inst_name.c_str()); + odb::dbScanInst* db_scaninst = db_scanlist->add(db_inst); + db_scaninst->setBits(scan_cell->getBits()); + auto scan_in_term = scan_cell->getScanIn().getValue(); + auto scan_out_term = scan_cell->getScanOut().getValue(); + db_scaninst->setAccessPins( + {.scan_in = scan_in_term, .scan_out = scan_out_term}); + } + + ScanDriver sc_enable_driver = chain->getScanEnable(); + ScanDriver sc_in_driver = chain->getScanIn(); + ScanLoad sc_out_load = chain->getScanOut(); + + std::visit( + [&](auto&& sc_enable_term) { db_sc->setScanEnable(sc_enable_term); }, + sc_enable_driver.getValue()); + std::visit([&](auto&& sc_in_term) { db_sc->setScanIn(sc_in_term); }, + sc_in_driver.getValue()); + std::visit([&](auto&& sc_out_term) { db_sc->setScanOut(sc_out_term); }, + sc_out_load.getValue()); + } } DftConfig* Dft::getMutableDftConfig() diff --git a/src/dft/src/architect/ScanChain.cpp b/src/dft/src/architect/ScanChain.cpp index ecb1693efcb..7786d05638c 100644 --- a/src/dft/src/architect/ScanChain.cpp +++ b/src/dft/src/architect/ScanChain.cpp @@ -119,4 +119,30 @@ const std::string& ScanChain::getName() const return name_; } +ScanDriver ScanChain::getScanIn() const +{ + return ScanDriver(scan_in_); +} +ScanDriver ScanChain::getScanEnable() const +{ + return ScanDriver(scan_enable_); +} +ScanLoad ScanChain::getScanOut() const +{ + return ScanLoad(scan_out_); +} + +void ScanChain::setScanIn(const ScanDriver& signal) +{ + scan_in_ = signal.getValue(); +} +void ScanChain::setScanEnable(const ScanDriver& signal) +{ + scan_enable_ = signal.getValue(); +} +void ScanChain::setScanOut(const ScanLoad& signal) +{ + scan_out_ = signal.getValue(); +} + } // namespace dft diff --git a/src/dft/src/architect/ScanChain.hh b/src/dft/src/architect/ScanChain.hh index ec8d896c394..840e3effb9f 100644 --- a/src/dft/src/architect/ScanChain.hh +++ b/src/dft/src/architect/ScanChain.hh @@ -85,6 +85,15 @@ class ScanChain // Returns the name of the scan chain const std::string& getName() const; + // For stitchers + ScanDriver getScanIn() const; + ScanDriver getScanEnable() const; + ScanLoad getScanOut() const; + + void setScanIn(const ScanDriver& signal); + void setScanEnable(const ScanDriver& signal); + void setScanOut(const ScanLoad& signal); + private: std::string name_; std::vector> rising_edge_scan_cells_; @@ -95,6 +104,13 @@ class ScanChain // The total bits in this scan chain. Scan cells can contain more than one // bit, that's why this is different from the number of cells. uint64_t bits_; + + // After stitching: store input/output bterms/iterms + std::variant scan_in_ = (odb::dbBTerm*) nullptr; + std::variant scan_out_ + = (odb::dbBTerm*) nullptr; + std::variant scan_enable_ + = (odb::dbBTerm*) nullptr; }; } // namespace dft diff --git a/src/dft/src/cells/OneBitScanCell.cpp b/src/dft/src/cells/OneBitScanCell.cpp index 97ed6abc65b..80cbac1c94a 100644 --- a/src/dft/src/cells/OneBitScanCell.cpp +++ b/src/dft/src/cells/OneBitScanCell.cpp @@ -83,6 +83,11 @@ ScanDriver OneBitScanCell::getScanOut() const return ScanDriver(findITerm(getLibertyScanOut(test_cell_))); } +ScanLoad OneBitScanCell::getScanIn() const +{ + return ScanLoad(findITerm(getLibertyScanIn(test_cell_))); +} + odb::dbITerm* OneBitScanCell::findITerm(sta::LibertyPort* liberty_port) const { odb::dbMTerm* mterm = db_network_->staToDb(liberty_port); diff --git a/src/dft/src/cells/OneBitScanCell.hh b/src/dft/src/cells/OneBitScanCell.hh index 6420f3fe50f..8e95e9862ac 100644 --- a/src/dft/src/cells/OneBitScanCell.hh +++ b/src/dft/src/cells/OneBitScanCell.hh @@ -57,6 +57,7 @@ class OneBitScanCell : public ScanCell void connectScanEnable(const ScanDriver& driver) const override; void connectScanIn(const ScanDriver& driver) const override; void connectScanOut(const ScanLoad& load) const override; + ScanLoad getScanIn() const override; ScanDriver getScanOut() const override; odb::Point getOrigin() const override; diff --git a/src/dft/src/cells/ScanCell.hh b/src/dft/src/cells/ScanCell.hh index 1f5f160b5be..5386c428e11 100644 --- a/src/dft/src/cells/ScanCell.hh +++ b/src/dft/src/cells/ScanCell.hh @@ -64,6 +64,7 @@ class ScanCell virtual void connectScanEnable(const ScanDriver& driver) const = 0; virtual void connectScanIn(const ScanDriver& driver) const = 0; virtual void connectScanOut(const ScanLoad& load) const = 0; + virtual ScanLoad getScanIn() const = 0; virtual ScanDriver getScanOut() const = 0; const ClockDomain& getClockDomain() const; @@ -127,8 +128,16 @@ 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/config/CMakeLists.txt b/src/dft/src/config/CMakeLists.txt index eac4849c0b9..1429690a205 100644 --- a/src/dft/src/config/CMakeLists.txt +++ b/src/dft/src/config/CMakeLists.txt @@ -2,6 +2,7 @@ add_library(dft_config_lib # Keep sorted DftConfig.cpp ScanArchitectConfig.cpp + ScanStitchConfig.cpp ) target_include_directories(dft_config_lib diff --git a/src/dft/src/config/DftConfig.cpp b/src/dft/src/config/DftConfig.cpp index 50e08015dd2..57a0942bcad 100644 --- a/src/dft/src/config/DftConfig.cpp +++ b/src/dft/src/config/DftConfig.cpp @@ -44,11 +44,22 @@ const ScanArchitectConfig& DftConfig::getScanArchitectConfig() const return scan_architect_config_; } +ScanStitchConfig* DftConfig::getMutableScanStitchConfig() +{ + return &scan_stitch_config_; +} + +const ScanStitchConfig& DftConfig::getScanStitchConfig() const +{ + return scan_stitch_config_; +} + void DftConfig::report(utl::Logger* logger) const { logger->report("***************************"); logger->report("DFT Config Report:\n"); scan_architect_config_.report(logger); + scan_stitch_config_.report(logger); logger->report("***************************"); } diff --git a/src/dft/src/config/DftConfig.hh b/src/dft/src/config/DftConfig.hh index 541cf1b910c..574db8bc8c8 100644 --- a/src/dft/src/config/DftConfig.hh +++ b/src/dft/src/config/DftConfig.hh @@ -32,6 +32,7 @@ #pragma once #include "ScanArchitectConfig.hh" +#include "ScanStitchConfig.hh" #include "utl/Logger.h" namespace dft { @@ -49,11 +50,15 @@ class DftConfig ScanArchitectConfig* getMutableScanArchitectConfig(); const ScanArchitectConfig& getScanArchitectConfig() const; + ScanStitchConfig* getMutableScanStitchConfig(); + const ScanStitchConfig& getScanStitchConfig() const; + // Prints the information currently being used by DFT for config void report(utl::Logger* logger) const; private: ScanArchitectConfig scan_architect_config_; + ScanStitchConfig scan_stitch_config_; }; } // namespace dft diff --git a/src/dft/src/config/ScanStitchConfig.cpp b/src/dft/src/config/ScanStitchConfig.cpp new file mode 100644 index 00000000000..348e5afed74 --- /dev/null +++ b/src/dft/src/config/ScanStitchConfig.cpp @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////////// +// BSD 3-Clause License +// +// Copyright (c) 2024, Efabless Corporation +// 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 "ScanStitchConfig.hh" + +#include "Formatting.hh" + +namespace dft { + +void ScanStitchConfig::setEnableNamePattern( + std::string_view& enable_name_pattern) +{ + enable_name_pattern_ = enable_name_pattern; +} +std::string_view ScanStitchConfig::getEnableNamePattern() const +{ + return enable_name_pattern_; +}; + +void ScanStitchConfig::setInNamePattern(std::string_view& in_name_pattern) +{ + in_name_pattern_ = in_name_pattern; +}; +std::string_view ScanStitchConfig::getInNamePattern() const +{ + return in_name_pattern_; +}; + +void ScanStitchConfig::setOutNamePattern(std::string_view& out_name_pattern) +{ + out_name_pattern_ = out_name_pattern; +}; +std::string_view ScanStitchConfig::getOutNamePattern() const +{ + return out_name_pattern_; +}; + +void ScanStitchConfig::setEnableMode(ScanStitchConfig::EnableMode enable_mode) +{ + enable_mode_ = enable_mode; +} +ScanStitchConfig::EnableMode ScanStitchConfig::getEnableMode() const +{ + return enable_mode_; +} + +std::string_view ScanStitchConfig::EnableModeName( + ScanStitchConfig::EnableMode enable_mode) +{ + switch (enable_mode) { + case ScanStitchConfig::EnableMode::Global: + return "Global"; + case ScanStitchConfig::EnableMode::PerChain: + return "Per-Chain"; + default: + return "ScanStitchConfig::EnableMode missing case"; + } +} + +void ScanStitchConfig::report(utl::Logger* logger) const +{ + logger->report("Scan Stitch Config:"); + logger->report("- Enable Mode: '{}'", EnableModeName(enable_mode_)); + logger->report("- Scan Enable Name Pattern: '{}'", enable_name_pattern_); + logger->report("- Scan In Name Pattern: '{}'", in_name_pattern_); + logger->report("- Scan Out Name Pattern: '{}'", out_name_pattern_); +} + +} // namespace dft diff --git a/src/dft/src/config/ScanStitchConfig.hh b/src/dft/src/config/ScanStitchConfig.hh new file mode 100644 index 00000000000..e316554b593 --- /dev/null +++ b/src/dft/src/config/ScanStitchConfig.hh @@ -0,0 +1,71 @@ +/////////////////////////////////////////////////////////////////////////////// +// BSD 3-Clause License +// +// Copyright (c) 2024, Efabless Corporation +// 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 "utl/Logger.h" + +namespace dft { + +class ScanStitchConfig +{ + public: + enum class EnableMode + { + Global = 0, + PerChain + }; + + static std::string_view EnableModeName(EnableMode enable_mode); + + void setEnableNamePattern(std::string_view& enable_name_pattern); + std::string_view getEnableNamePattern() const; + + void setInNamePattern(std::string_view& in_name_pattern); + std::string_view getInNamePattern() const; + + void setOutNamePattern(std::string_view& out_name_pattern); + std::string_view getOutNamePattern() const; + + void setEnableMode(EnableMode enable_mode); + EnableMode getEnableMode() const; + + // Prints using logger->report the config used by Scan Stitch + void report(utl::Logger* logger) const; + + private: + std::string enable_name_pattern_ = "scan_enable_{}"; + std::string in_name_pattern_ = "scan_in_{}"; + std::string out_name_pattern_ = "scan_out_{}"; + EnableMode enable_mode_ = EnableMode::Global; +}; + +} // namespace dft diff --git a/src/dft/src/dft.i b/src/dft/src/dft.i index f0af5a88915..b106a842905 100644 --- a/src/dft/src/dft.i +++ b/src/dft/src/dft.i @@ -38,6 +38,7 @@ #include "DftConfig.hh" #include "ord/OpenRoad.hh" #include "ScanArchitect.hh" +#include "ClockDomain.hh" dft::Dft * getDft() { @@ -51,6 +52,92 @@ utl::Logger* getLogger() %} +%include "../../Exception.i" + +// Enum: dft::ResetActiveEdge +%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; + }; +} + +// Enum: dft::ClockEdge +%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; + }; +} + +// Enum: dft::ScanArchitectConfig::ClockMixing +%typemap(typecheck) dft::ScanArchitectConfig::ClockMixing { + char *str = Tcl_GetStringFromObj($input, 0); + if (strcasecmp(str, "NO_MIX") == 0) { + $1 = 1; + } else if (strcasecmp(str, "CLOCK_MIX") == 0) { + $1 = 1; + } else { + $1 = 0; + } +} + +%typemap(in) dft::ScanArchitectConfig::ClockMixing { + char *str = Tcl_GetStringFromObj($input, 0); + if (strcasecmp(str, "NO_MIX") == 0) { + $1 = dft::ScanArchitectConfig::ClockMixing::NoMix; + } else /* other values eliminated in typecheck */ { + $1 = dft::ScanArchitectConfig::ClockMixing::ClockMix; + }; +} + +// Enum: dft::EnableMode +%typemap(typecheck) dft::ScanStitchConfig::EnableMode { + char *str = Tcl_GetStringFromObj($input, 0); + if (strcasecmp(str, "GLOBAL") == 0) { + $1 = 1; + } else if (strcasecmp(str, "PER_CHAIN") == 0) { + $1 = 1; + } else { + $1 = 0; + } +} + +%typemap(in) dft::ScanStitchConfig::EnableMode { + char *str = Tcl_GetStringFromObj($input, 0); + if (strcasecmp(str, "GLOBAL") == 0) { + $1 = dft::ScanStitchConfig::EnableMode::Global; + } else /* other values eliminated in typecheck */ { + $1 = dft::ScanStitchConfig::EnableMode::PerChain; + }; +} + %inline %{ @@ -64,7 +151,6 @@ void scan_replace() getDft()->scanReplace(); } - void insert_dft() { getDft()->insertDft(); @@ -80,15 +166,28 @@ void set_dft_config_max_chains(int max_chains) getDft()->getMutableDftConfig()->getMutableScanArchitectConfig()->setMaxChains(max_chains); } -void set_dft_config_clock_mixing(const char* clock_mixing_ptr) +void set_dft_config_clock_mixing(dft::ScanArchitectConfig::ClockMixing clock_mixing) { - std::string_view clock_mixing(clock_mixing_ptr); - if (clock_mixing == "no_mix") { - getDft()->getMutableDftConfig()->getMutableScanArchitectConfig()->setClockMixing(dft::ScanArchitectConfig::ClockMixing::NoMix); - } else if (clock_mixing == "clock_mix") { - getDft()->getMutableDftConfig()->getMutableScanArchitectConfig()->setClockMixing(dft::ScanArchitectConfig::ClockMixing::ClockMix); + getDft()->getMutableDftConfig()->getMutableScanArchitectConfig()->setClockMixing(clock_mixing); +} + +void set_dft_config_scan_enable_mode(dft::ScanStitchConfig::EnableMode enable_mode) +{ + getDft()->getMutableDftConfig()->getMutableScanStitchConfig()->setEnableMode(enable_mode); +} + +void set_dft_config_scan_signal_name_pattern(const char* signal_ptr, const char* pattern_ptr) { + auto config = getDft()->getMutableDftConfig()->getMutableScanStitchConfig(); + std::string_view signal(signal_ptr), pattern(pattern_ptr); + + if (signal == "scan_in") { + config->setInNamePattern(pattern); + } else if (signal == "scan_enable") { + config->setEnableNamePattern(pattern); + } else if (signal == "scan_out") { + config->setOutNamePattern(pattern); } else { - getLogger()->error(utl::DFT, 6, "Requested clock mixing config not valid"); + getLogger()->error(utl::DFT, 6, "Internal error: unrecognized signal '{}' to set a pattern for", signal); } } diff --git a/src/dft/src/dft.tcl b/src/dft/src/dft.tcl index fbe5892d766..ea0c1f58898 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,10 +58,11 @@ proc scan_replace { args } { dft::scan_replace } -sta::define_cmd_args "insert_dft" { } +sta::define_cmd_args "insert_dft" {} proc insert_dft { args } { sta::parse_key_args "insert_dft" args \ - keys {} flags {} + keys {} \ + flags {} if { [ord::get_db_block] == "NULL" } { utl::error DFT 9 "No design block found." @@ -69,12 +70,25 @@ proc insert_dft { args } { dft::insert_dft } -sta::define_cmd_args "set_dft_config" { [-max_length max_length] \ - [-max_chains max_chains] \ - [-clock_mixing clock_mixing]} +sta::define_cmd_args "set_dft_config" { [-max_length max_length] + [-max_chains max_chains] + [-clock_mixing clock_mixing] + [-scan_enable_mode mode] + [-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 set_dft_config { args } { sta::parse_key_args "set_dft_config" args \ - keys {-max_length -max_chains -clock_mixing} \ + keys { + -max_length + -max_chains + -clock_mixing + -scan_enable_mode + -scan_enable_name_pattern + -scan_in_name_pattern + -scan_out_name_pattern + } \ flags {} sta::check_argc_eq0 "set_dft_config" $args @@ -93,9 +107,22 @@ proc set_dft_config { args } { if { [info exists keys(-clock_mixing)] } { set clock_mixing $keys(-clock_mixing) - puts $clock_mixing dft::set_dft_config_clock_mixing $clock_mixing } + + if { [info exists keys(-scan_enable_mode)] } { + dft::set_dft_config_scan_enable_mode $keys(-scan_enable_mode) + } + + foreach {flag signal} { + -scan_enable_name_pattern "scan_enable" + -scan_in_name_pattern "scan_in" + -scan_out_name_pattern "scan_out" + } { + if { [info exists keys($flag)] } { + dft::set_dft_config_scan_signal_name_pattern $signal $keys($flag) + } + } } sta::define_cmd_args "report_dft_config" { } diff --git a/src/dft/src/replace/ScanReplace.cpp b/src/dft/src/replace/ScanReplace.cpp index af0379c5179..37e4a1c6976 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/stitch/CMakeLists.txt b/src/dft/src/stitch/CMakeLists.txt index 48045d9030e..2f688a63ea0 100644 --- a/src/dft/src/stitch/CMakeLists.txt +++ b/src/dft/src/stitch/CMakeLists.txt @@ -17,4 +17,5 @@ target_link_libraries(dft_stitch_lib dft_cells_lib dft_architect_lib dft_utils_lib + dft_config_lib ) diff --git a/src/dft/src/stitch/ScanStitch.cpp b/src/dft/src/stitch/ScanStitch.cpp index b148a8b379a..e8a408cae9c 100644 --- a/src/dft/src/stitch/ScanStitch.cpp +++ b/src/dft/src/stitch/ScanStitch.cpp @@ -1,19 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////// +// 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 "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 +constexpr std::string_view kScanEnable = "scan-enable"; +constexpr std::string_view kScanIn = "scan-in"; +constexpr std::string_view kScanOut = "scan-out"; namespace dft { -ScanStitch::ScanStitch(odb::dbDatabase* db) : db_(db) +ScanStitch::ScanStitch(odb::dbDatabase* db, + utl::Logger* logger, + const ScanStitchConfig& config) + : config_(config), db_(db), logger_(logger) { odb::dbChip* chip = db_->getChip(); top_block_ = chip->getBlock(); @@ -22,29 +53,37 @@ ScanStitch::ScanStitch(odb::dbDatabase* db) : db_(db) void ScanStitch::Stitch( const std::vector>& scan_chains) { - // 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, ordinal, enable_ordinal); + ordinal += 1; + + // If a unique enable signal is ever needed per-chain, simply increment + // enable_ordinal as follows: + // enable_ordinal += 1; } } void ScanStitch::Stitch(odb::dbBlock* block, - const ScanChain& scan_chain, - const ScanDriver& scan_enable) + ScanChain& scan_chain, + 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(config_.getEnableNamePattern()), enable_ordinal); + auto scan_enable_driver = FindOrCreateScanEnable(block, scan_enable_name); + + auto scan_in_name + = fmt::format(FMT_RUNTIME(config_.getInNamePattern()), ordinal); + ScanDriver scan_in_driver = FindOrCreateScanIn(block, scan_in_name); - ScanDriver scan_in_port = FindOrCreateScanIn(block); + scan_chain.setScanIn(scan_in_driver); + scan_chain.setScanEnable(scan_enable_driver); // We need fast pop for front and back std::deque>> @@ -59,7 +98,7 @@ void ScanStitch::Stitch(odb::dbBlock* block, // All the cells in the scan chain are controlled by the same scan enable for (const std::unique_ptr& scan_cell : scan_cells) { - scan_cell->connectScanEnable(scan_enable); + scan_cell->connectScanEnable(scan_enable_driver); } // Lets get the first and last cell @@ -82,8 +121,8 @@ 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->connectScanEnable(scan_enable_driver); + first_scan_cell->connectScanIn(scan_in_driver); if (!scan_cells.empty()) { scan_cells.begin()->get()->connectScanIn(first_scan_cell->getScanOut()); @@ -95,30 +134,134 @@ 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(config_.getOutNamePattern()), ordinal); + ScanLoad scan_out_load + = FindOrCreateScanOut(block, last_scan_cell->getScanOut(), scan_out_name); + last_scan_cell->connectScanOut(scan_out_load); + scan_chain.setScanOut(scan_out_load); +} + +namespace { +static std::pair> SplitTermIdentifier( + const std::string& input) +{ + 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}; +} +} // namespace + +ScanDriver ScanStitch::FindOrCreateDriver(const std::string_view& kind, + odb::dbBlock* block, + const std::string& with_name) +{ + auto term_info = SplitTermIdentifier(with_name); + + 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); + } + + // 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); } -ScanDriver ScanStitch::FindOrCreateScanEnable(odb::dbBlock* block) +ScanDriver ScanStitch::FindOrCreateScanEnable(odb::dbBlock* block, + const std::string& with_name) { - // 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); + return FindOrCreateDriver(kScanEnable, block, with_name); } -ScanDriver ScanStitch::FindOrCreateScanIn(odb::dbBlock* block) +ScanDriver ScanStitch::FindOrCreateScanIn(odb::dbBlock* block, + const std::string& with_name) { - // 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); + return FindOrCreateDriver(kScanIn, block, with_name); } ScanLoad ScanStitch::FindOrCreateScanOut(odb::dbBlock* block, - const ScanDriver& cell_scan_out) + const ScanDriver& cell_scan_out, + const std::string& with_name) { - // 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 + auto term_info = SplitTermIdentifier(with_name); + + 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, + kScanOut); + } + 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(), + kScanOut); + } + if (iterm->getIoType() != odb::dbIoType::INPUT) { + logger_->error(utl::DFT, + 39, + "ITerm {}/{} for {} port is a {}", + term_info.first, + term_info.second.value(), + kScanOut, + 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, + kScanEnable); + } + 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 +277,7 @@ ScanLoad ScanStitch::FindOrCreateScanOut(odb::dbBlock* block, } } - return CreateNewPort(block, kScanOutNamePattern); + return CreateNewPort(block, with_name); } } // namespace dft diff --git a/src/dft/src/stitch/ScanStitch.hh b/src/dft/src/stitch/ScanStitch.hh index 41b03ff2c73..2bd92a91a27 100644 --- a/src/dft/src/stitch/ScanStitch.hh +++ b/src/dft/src/stitch/ScanStitch.hh @@ -36,6 +36,8 @@ #include #include "ScanChain.hh" +#include "ScanStitchConfig.hh" +#include "Utils.hh" #include "odb/db.h" namespace dft { @@ -49,49 +51,56 @@ inline constexpr bool always_false_v = false; class ScanStitch { public: - explicit ScanStitch(odb::dbDatabase* db); + explicit ScanStitch(odb::dbDatabase* db, + utl::Logger* logger, + const ScanStitchConfig& config); - // Stitch all the cells inside each one of the scan chains together. + // Stitch one or more scan chains. void Stitch(const std::vector>& scan_chains); + + // Stitch all the cells inside each one of the scan chains together. + // - Ordinals are used with scan in/out/enable name patterns to produce the + // - final name for the signal(s) in question. Enable ordinal is different + // - to account for whether you're using global or per-chain enable. void Stitch(odb::dbBlock* block, - const ScanChain& scan_chain, - const ScanDriver& scan_enable); + ScanChain& scan_chain, + size_t ordinal = 0, + size_t enable_ordinal = 0); private: - ScanDriver FindOrCreateScanEnable(odb::dbBlock* block); - ScanDriver FindOrCreateScanIn(odb::dbBlock* block); + ScanDriver FindOrCreateDriver(const std::string_view& kind, + odb::dbBlock* block, + const std::string& with_name); + ScanDriver FindOrCreateScanEnable(odb::dbBlock* block, + const std::string& with_name); + ScanDriver FindOrCreateScanIn(odb::dbBlock* block, + const std::string& with_name); ScanLoad FindOrCreateScanOut(odb::dbBlock* block, - const ScanDriver& cell_scan_out); + const ScanDriver& cell_scan_out, + const std::string& with_name); // 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, + 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); } + const ScanStitchConfig& config_; odb::dbDatabase* db_; + utl::Logger* logger_; odb::dbBlock* top_block_; }; diff --git a/src/dft/src/utils/ScanPin.cpp b/src/dft/src/utils/ScanPin.cpp index bfe97af531f..4828cc49ace 100644 --- a/src/dft/src/utils/ScanPin.cpp +++ b/src/dft/src/utils/ScanPin.cpp @@ -2,11 +2,7 @@ namespace dft { -ScanPin::ScanPin(odb::dbITerm* iterm) : value_(iterm) -{ -} - -ScanPin::ScanPin(odb::dbBTerm* bterm) : value_(bterm) +ScanPin::ScanPin(std::variant term) : value_(term) { } @@ -27,24 +23,18 @@ std::string_view ScanPin::getName() const value_); } -const std::variant& ScanPin::getValue() const +const std::variant& ScanPin::getValue() const { return value_; } -ScanLoad::ScanLoad(odb::dbITerm* iterm) : ScanPin(iterm) -{ -} - -ScanLoad::ScanLoad(odb::dbBTerm* bterm) : ScanPin(bterm) -{ -} - -ScanDriver::ScanDriver(odb::dbITerm* iterm) : ScanPin(iterm) +ScanLoad::ScanLoad(std::variant term) + : ScanPin(term) { } -ScanDriver::ScanDriver(odb::dbBTerm* bterm) : ScanPin(bterm) +ScanDriver::ScanDriver(std::variant term) + : ScanPin(term) { } diff --git a/src/dft/src/utils/ScanPin.hh b/src/dft/src/utils/ScanPin.hh index 7bfbac78585..0b5ed7176db 100644 --- a/src/dft/src/utils/ScanPin.hh +++ b/src/dft/src/utils/ScanPin.hh @@ -51,24 +51,22 @@ overloaded(Ts...) -> overloaded; class ScanPin { public: - explicit ScanPin(odb::dbITerm* iterm); - explicit ScanPin(odb::dbBTerm* bterm); + explicit ScanPin(std::variant term); ScanPin(const ScanPin&) = delete; // no copy odb::dbNet* getNet() const; std::string_view getName() const; - const std::variant& getValue() const; + const std::variant& getValue() const; protected: - std::variant value_; + std::variant value_; }; // Typesafe wrapper for load pins class ScanLoad : public ScanPin { public: - explicit ScanLoad(odb::dbITerm* iterm); - explicit ScanLoad(odb::dbBTerm* bterm); + explicit ScanLoad(std::variant term); ScanLoad(const ScanLoad&) = delete; // no copy }; @@ -76,8 +74,7 @@ class ScanLoad : public ScanPin class ScanDriver : public ScanPin { public: - explicit ScanDriver(odb::dbITerm* iterm); - explicit ScanDriver(odb::dbBTerm* bterm); + explicit ScanDriver(std::variant term); ScanDriver(const ScanDriver&) = delete; // no copy }; diff --git a/src/dft/src/utils/Utils.cpp b/src/dft/src/utils/Utils.cpp index 24f89617464..c77cd33ce67 100644 --- a/src/dft/src/utils/Utils.cpp +++ b/src/dft/src/utils/Utils.cpp @@ -147,4 +147,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/cpp/ScanCellMock.cpp b/src/dft/test/cpp/ScanCellMock.cpp index a287371464d..7a55486c3f5 100644 --- a/src/dft/test/cpp/ScanCellMock.cpp +++ b/src/dft/test/cpp/ScanCellMock.cpp @@ -29,6 +29,11 @@ void ScanCellMock::connectScanOut(const ScanLoad& pin) const { } +ScanLoad ScanCellMock::getScanIn() const +{ + return ScanLoad(static_cast(nullptr)); +} + ScanDriver ScanCellMock::getScanOut() const { return ScanDriver(static_cast(nullptr)); diff --git a/src/dft/test/cpp/ScanCellMock.hh b/src/dft/test/cpp/ScanCellMock.hh index a716809f3c8..5ac6a6c26b1 100644 --- a/src/dft/test/cpp/ScanCellMock.hh +++ b/src/dft/test/cpp/ScanCellMock.hh @@ -16,6 +16,7 @@ class ScanCellMock : public ScanCell void connectScanEnable(const ScanDriver& pin) const override; void connectScanIn(const ScanDriver& pin) const override; void connectScanOut(const ScanLoad& pin) const override; + ScanLoad getScanIn() const override; ScanDriver getScanOut() const override; odb::Point getOrigin() const override; bool isPlaced() const override; 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.defok b/src/dft/test/one_cell_sky130.defok index b9944f9e2fb..083d1ae8b80 100644 --- a/src/dft/test/one_cell_sky130.defok +++ b/src/dft/test/one_cell_sky130.defok @@ -13,19 +13,31 @@ PINS 6 ; - clock + NET clock + DIRECTION INPUT + USE SIGNAL ; - output1 + NET output1 + DIRECTION OUTPUT + USE SIGNAL ; - port1 + NET port1 + DIRECTION INPUT + USE SIGNAL ; - - scan_enable_1 + NET scan_enable_1 + DIRECTION INPUT + USE SCAN ; - - scan_in_1 + NET scan_in_1 + DIRECTION INPUT + USE SCAN ; + - scan_enable_0 + NET scan_enable_0 + DIRECTION INPUT + USE SCAN ; + - scan_in_0 + NET scan_in_0 + DIRECTION INPUT + USE SCAN ; - set_b + NET set_b + DIRECTION INPUT + USE SIGNAL ; END PINS NETS 6 ; - clock ( PIN clock ) ( ff1 CLK ) + USE SIGNAL ; - output1 ( PIN output1 ) ( ff1 Q ) + USE SIGNAL ; - port1 ( PIN port1 ) ( ff1 D ) + USE SIGNAL ; - - scan_enable_1 ( PIN scan_enable_1 ) ( ff1 SCE ) + USE SCAN ; - - scan_in_1 ( PIN scan_in_1 ) ( ff1 SCD ) + USE SCAN ; + - scan_enable_0 ( PIN scan_enable_0 ) ( ff1 SCE ) + USE SCAN ; + - scan_in_0 ( PIN scan_in_0 ) ( ff1 SCD ) + USE SCAN ; - set_b ( PIN set_b ) ( ff1 SET_B ) + USE SIGNAL ; END NETS GROUPS 1 ; - group ff1 + REGION region ; END GROUPS + +SCANCHAINS 1 ; + +- chain_0 ++ START PIN scan_in_0 ++ FLOATING + ff1 ( IN SCD ) ( OUT Q ) ++ PARTITION default ++ STOP PIN output1 ; + +END SCANCHAINS + END DESIGN diff --git a/src/dft/test/one_cell_sky130.ok b/src/dft/test/one_cell_sky130.ok index 40eaa9eb698..155058c8112 100644 --- a/src/dft/test/one_cell_sky130.ok +++ b/src/dft/test/one_cell_sky130.ok @@ -57,8 +57,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.ok b/src/dft/test/scan_architect_clock_mix_sky130.ok index a77dc2e2206..d1eabfbb5a1 100644 --- a/src/dft/test/scan_architect_clock_mix_sky130.ok +++ b/src/dft/test/scan_architect_clock_mix_sky130.ok @@ -1,6 +1,5 @@ [INFO ODB-0227] LEF file: sky130hd/sky130hd.tlef, created 13 layers, 25 vias [INFO ODB-0227] LEF file: sky130hd/sky130_fd_sc_hd_merged.lef, created 437 library cells -clock_mix *************************** Preview DFT Report Number of chains: 7 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.ok b/src/dft/test/scan_architect_register_bank_no_clock_mix_sky130.ok index 7d474dc5a5e..fe8774ca0c9 100644 --- a/src/dft/test/scan_architect_register_bank_no_clock_mix_sky130.ok +++ b/src/dft/test/scan_architect_register_bank_no_clock_mix_sky130.ok @@ -1,6 +1,5 @@ [INFO ODB-0227] LEF file: sky130hd/sky130hd.tlef, created 13 layers, 25 vias [INFO ODB-0227] LEF file: sky130hd/sky130_fd_sc_hd_merged.lef, created 437 library cells -no_mix *************************** Preview DFT Report Number of chains: 2 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 diff --git a/src/odb/src/swig/common/containers.i b/src/odb/src/swig/common/containers.i index 30494ad8dba..cf1c9e4972c 100644 --- a/src/odb/src/swig/common/containers.i +++ b/src/odb/src/swig/common/containers.i @@ -68,3 +68,7 @@ WRAP_DB_CONTAINER(odb::dbNetTrack) WRAP_DB_CONTAINER(odb::dbLevelShifter) WRAP_DB_CONTAINER(odb::dbMarker) WRAP_DB_CONTAINER(odb::dbMarkerCategory) +WRAP_DB_CONTAINER(odb::dbScanChain) +WRAP_DB_CONTAINER(odb::dbScanPartition) +WRAP_DB_CONTAINER(odb::dbScanList) +WRAP_DB_CONTAINER(odb::dbScanInst)