Skip to content

Commit

Permalink
Merge pull request #6412 from donn/dft_tweaks
Browse files Browse the repository at this point in the history
dft: stitch configuration, stitched scan chains in odb
  • Loading branch information
maliberty authored Jan 11, 2025
2 parents 2b51c58 + a0843a5 commit 2e35fb1
Show file tree
Hide file tree
Showing 38 changed files with 864 additions and 345 deletions.
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

0 comments on commit 2e35fb1

Please sign in to comment.