Skip to content

Commit

Permalink
dft: store stitched scan chains in odb
Browse files Browse the repository at this point in the history
* dft::Dft::insertDft: stitched scan chains now committed into odb, so it can be stored in the def and accessed using the relevant APIs
* dft::ScanChain: add setters and getters for scan in/out/enable drivers and loads
* dft::ScanCell: add getter for scan in terminal
* dft::ScanStitch: Now stores the scan in/out/enable drivers and loads in the scan chain via new setters
* dft::ScanPin: Accept a sum type in the constructor, reorder sum type to match that of db.h for easier exporting
* removed dft::Dft::writeScanChains: functionality can now be achieved using an Odb script of some kind

Signed-off-by: Mohamed Gaber <[email protected]>
  • Loading branch information
donn committed Jan 6, 2025
1 parent 2fd8a2e commit 1a1e4bd
Show file tree
Hide file tree
Showing 18 changed files with 129 additions and 114 deletions.
26 changes: 0 additions & 26 deletions src/dft/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,32 +92,6 @@ a result, this should be run after placement, and after `scan_replace`.
insert_dft
```

### Write Scan Chains

Writes a JSON file containing metadata about the current architected scan chain.

The JSON file is currently in this format:

```jsonc
{
"chain_0": {
"cells": [
"scanflop_0",
"scanflop_1",
"scanflop_2"
]
},
/* … other chains … */
}
```

…where the order of `.chain_name.cells` corresponds to the order of the elements
in the scan-chain.

```tcl
write_scan_chains
```

## Example scripts

This example will create scan chains with a max length of 10 bits mixing all the
Expand Down
3 changes: 0 additions & 3 deletions src/dft/include/dft/Dft.hh
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,6 @@ class Dft
// Prints to stdout
void reportDftConfig() const;

// Writes scan chains in a JSON format
void writeScanChains(const std::string& filename);

private:
// If we need to run pre_dft to create the internal state
bool need_to_run_pre_dft_;
Expand Down
74 changes: 37 additions & 37 deletions src/dft/src/Dft.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
#include "odb/db.h"
#include "utl/Logger.h"

constexpr char kDefaultPartition[] = "default";

namespace dft {

Dft::Dft() : dft_config_(std::make_unique<DftConfig>())
Expand Down Expand Up @@ -106,43 +108,6 @@ void Dft::scanReplace()
scan_replace_->scanReplace();
}

void Dft::writeScanChains(const std::string& filename)
{
using boost::property_tree::ptree;
if (need_to_run_pre_dft_) {
pre_dft();
}

std::ofstream json_file(filename);
if (!json_file.is_open()) {
logger_->error(
utl::DFT, 13, "Failed to open file {} for writing.", filename);
}
try {
ptree root;

std::vector<std::unique_ptr<ScanChain>> scan_chains = scanArchitect();

for (auto& chain : scan_chains) {
ptree current_chain;
ptree cells;
auto& scan_cells = chain->getScanCells();
for (auto& cell : scan_cells) {
ptree name;
name.put("", cell->getName());
cells.push_back(std::make_pair("", name));
}
current_chain.add_child("cells", cells);
root.add_child(chain->getName(), current_chain);
}

boost::property_tree::write_json(json_file, root);
} catch (std::exception& ex) {
logger_->error(
utl::DFT, 14, "Failed to write JSON report. Exception: {}", ex.what());
}
}

void Dft::insertDft()
{
if (need_to_run_pre_dft_) {
Expand All @@ -152,6 +117,41 @@ void Dft::insertDft()

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()
Expand Down
27 changes: 27 additions & 0 deletions src/dft/src/architect/ScanChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,31 @@ 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
16 changes: 16 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
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<std::unique_ptr<ScanCell>> rising_edge_scan_cells_;
Expand All @@ -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<odb::dbBTerm*, odb::dbITerm*> scan_in_ = (odb::dbBTerm*) nullptr;
std::variant<odb::dbBTerm*, odb::dbITerm*> scan_out_
= (odb::dbBTerm*) nullptr;
std::variant<odb::dbBTerm*, odb::dbITerm*> scan_enable_
= (odb::dbBTerm*) nullptr;
};

} // 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
1 change: 1 addition & 0 deletions 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
6 changes: 0 additions & 6 deletions src/dft/src/dft.i
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,6 @@ void insert_dft()
getDft()->insertDft();
}

void write_scan_chains(const char* filename_p)
{
std::string filename(filename_p);
getDft()->writeScanChains(filename);
}

void set_dft_config_max_length(int max_length)
{
getDft()->getMutableDftConfig()->getMutableScanArchitectConfig()->setMaxLength(max_length);
Expand Down
12 changes: 0 additions & 12 deletions src/dft/src/dft.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,6 @@ proc scan_replace { args } {
dft::scan_replace
}

sta::define_cmd_args "write_scan_chains" {[json_file_out]}
proc write_scan_chains { args } {
sta::parse_key_args "write_scan_chains" args \
keys {} flags {}

if { [ord::get_db_block] == "NULL" } {
utl::error DFT 15 "No design block found."
}

dft::write_scan_chains [lindex $args 0]
}

sta::define_cmd_args "insert_dft" {}
proc insert_dft { args } {
sta::parse_key_args "insert_dft" args \
Expand Down
13 changes: 8 additions & 5 deletions src/dft/src/stitch/ScanStitch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,21 @@ void ScanStitch::Stitch(
}

void ScanStitch::Stitch(odb::dbBlock* block,
const ScanChain& scan_chain,
ScanChain& scan_chain,
size_t ordinal,
size_t enable_ordinal)
{
auto scan_enable_name = fmt::format(
FMT_RUNTIME(config_.getEnableNamePattern()), enable_ordinal);
auto scan_enable = FindOrCreateScanEnable(block, scan_enable_name);
auto scan_enable_driver = FindOrCreateScanEnable(block, scan_enable_name);

// Let's create the scan in and scan out of the chain
auto scan_in_name
= fmt::format(FMT_RUNTIME(config_.getInNamePattern()), ordinal);
ScanDriver scan_in_driver = FindOrCreateScanIn(block, scan_in_name);

scan_chain.setScanIn(scan_in_driver);
scan_chain.setScanEnable(scan_enable_driver);

// We need fast pop for front and back
std::deque<std::reference_wrapper<const std::unique_ptr<ScanCell>>>
scan_cells;
Expand All @@ -96,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<ScanCell>& scan_cell : scan_cells) {
scan_cell->connectScanEnable(scan_enable);
scan_cell->connectScanEnable(scan_enable_driver);
}

// Lets get the first and last cell
Expand All @@ -119,7 +121,7 @@ void ScanStitch::Stitch(odb::dbBlock* block,
}

// Let's connect the first cell
first_scan_cell->connectScanEnable(scan_enable);
first_scan_cell->connectScanEnable(scan_enable_driver);
first_scan_cell->connectScanIn(scan_in_driver);

if (!scan_cells.empty()) {
Expand All @@ -137,6 +139,7 @@ void ScanStitch::Stitch(odb::dbBlock* block,
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 {
Expand Down
2 changes: 1 addition & 1 deletion src/dft/src/stitch/ScanStitch.hh
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class ScanStitch
// - 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,
ScanChain& scan_chain,
size_t ordinal = 0,
size_t enable_ordinal = 0);

Expand Down
22 changes: 6 additions & 16 deletions src/dft/src/utils/ScanPin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@

namespace dft {

ScanPin::ScanPin(odb::dbITerm* iterm) : value_(iterm)
{
}

ScanPin::ScanPin(odb::dbBTerm* bterm) : value_(bterm)
ScanPin::ScanPin(std::variant<odb::dbBTerm*, odb::dbITerm*> term) : value_(term)
{
}

Expand All @@ -27,24 +23,18 @@ std::string_view ScanPin::getName() const
value_);
}

const std::variant<odb::dbITerm*, odb::dbBTerm*>& ScanPin::getValue() const
const std::variant<odb::dbBTerm*, odb::dbITerm*>& 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<odb::dbBTerm*, odb::dbITerm*> term)
: ScanPin(term)
{
}

ScanDriver::ScanDriver(odb::dbBTerm* bterm) : ScanPin(bterm)
ScanDriver::ScanDriver(std::variant<odb::dbBTerm*, odb::dbITerm*> term)
: ScanPin(term)
{
}

Expand Down
Loading

0 comments on commit 1a1e4bd

Please sign in to comment.