Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dft: stitch configuration, stitched scan chains in odb #6412

Merged
merged 9 commits into from
Jan 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ TAGS
.cache
Makefile
__pycache__
venv/

include/ord/Version.hh

Expand Down
11 changes: 8 additions & 3 deletions src/dft/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ set_dft_config
[-max_length <int>]
[-max_chains <int>]
[-clock_mixing <string>]
[-scan_enable_name_pattern <string>]
[-scan_in_name_pattern <string>]
[-scan_out_name_pattern <string>]
```

#### Options
Expand All @@ -38,6 +41,9 @@ 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_name_pattern` | A format pattern with one or less set of braces (`{}`) to use to find or create scan enable drivers during scan chain stitching. The braces, if found, will be set to `0` as DFT architectures typically use a single shift-enable for all scan chains. 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 one or less 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 one or less 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

Expand Down Expand Up @@ -77,14 +83,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
Expand Down
1 change: 1 addition & 0 deletions src/dft/include/dft/Dft.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
49 changes: 48 additions & 1 deletion src/dft/src/Dft.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@

#include "dft/Dft.hh"

#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <iostream>

#include "ClockDomain.hh"
Expand All @@ -44,6 +46,10 @@
#include "odb/db.h"
#include "utl/Logger.h"

namespace {
constexpr char kDefaultPartition[] = "default";
} // namespace

namespace dft {

Dft::Dft() : dft_config_(std::make_unique<DftConfig>())
Expand Down Expand Up @@ -111,8 +117,49 @@ void Dft::insertDft()
}
std::vector<std::unique_ptr<ScanChain>> 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 (const 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 (const 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});
}

std::optional<ScanDriver> sc_enable_driver = chain->getScanEnable();
std::optional<ScanDriver> sc_in_driver = chain->getScanIn();
std::optional<ScanLoad> sc_out_load = chain->getScanOut();

if (sc_enable_driver.has_value()) {
std::visit(
[&](auto&& sc_enable_term) { db_sc->setScanEnable(sc_enable_term); },
sc_enable_driver.value().getValue());
}
if (sc_in_driver.has_value()) {
std::visit([&](auto&& sc_in_term) { db_sc->setScanIn(sc_in_term); },
sc_in_driver.value().getValue());
}
if (sc_out_load.has_value()) {
std::visit([&](auto&& sc_out_term) { db_sc->setScanOut(sc_out_term); },
sc_out_load.value().getValue());
}
}
}

DftConfig* Dft::getMutableDftConfig()
Expand Down
26 changes: 26 additions & 0 deletions src/dft/src/architect/ScanChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,30 @@ const std::string& ScanChain::getName() const
return name_;
}

std::optional<ScanDriver> ScanChain::getScanIn() const
{
return scan_in_;
}
std::optional<ScanDriver> ScanChain::getScanEnable() const
{
return scan_enable_;
}
std::optional<ScanLoad> ScanChain::getScanOut() const
{
return scan_out_;
}

void ScanChain::setScanIn(const std::optional<ScanDriver>& signal)
{
scan_in_ = signal;
}
void ScanChain::setScanEnable(const std::optional<ScanDriver>& signal)
{
scan_enable_ = signal;
}
void ScanChain::setScanOut(const std::optional<ScanLoad>& signal)
{
scan_out_ = signal;
}

} // namespace dft
14 changes: 14 additions & 0 deletions src/dft/src/architect/ScanChain.hh
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ class ScanChain
// Returns the name of the scan chain
const std::string& getName() const;

// For stitchers
std::optional<ScanDriver> getScanIn() const;
std::optional<ScanDriver> getScanEnable() const;
std::optional<ScanLoad> getScanOut() const;

void setScanIn(const std::optional<ScanDriver>& signal);
void setScanEnable(const std::optional<ScanDriver>& signal);
void setScanOut(const std::optional<ScanLoad>& signal);

private:
std::string name_;
std::vector<std::unique_ptr<ScanCell>> rising_edge_scan_cells_;
Expand All @@ -95,6 +104,11 @@ 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::optional<ScanDriver> scan_in_;
std::optional<ScanLoad> scan_out_;
std::optional<ScanDriver> scan_enable_;
};

} // namespace dft
5 changes: 5 additions & 0 deletions src/dft/src/cells/OneBitScanCell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/dft/src/cells/OneBitScanCell.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 10 additions & 1 deletion src/dft/src/cells/ScanCell.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/dft/src/config/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ add_library(dft_config_lib
# Keep sorted
DftConfig.cpp
ScanArchitectConfig.cpp
ScanStitchConfig.cpp
)

target_include_directories(dft_config_lib
Expand Down
11 changes: 11 additions & 0 deletions src/dft/src/config/DftConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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("***************************");
}

Expand Down
5 changes: 5 additions & 0 deletions src/dft/src/config/DftConfig.hh
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#pragma once

#include "ScanArchitectConfig.hh"
#include "ScanStitchConfig.hh"
#include "utl/Logger.h"

namespace dft {
Expand All @@ -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
75 changes: 75 additions & 0 deletions src/dft/src/config/ScanStitchConfig.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
///////////////////////////////////////////////////////////////////////////////
// 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::report(utl::Logger* logger) const
{
logger->report("Scan Stitch Config:");
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
Loading
Loading