Skip to content
Open
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
5 changes: 4 additions & 1 deletion src/cts/src/CtsOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ class CtsOptions : public odb::dbBlockCallBackObj
unsigned getNumMaxLeafSinks() const { return numMaxLeafSinks_; }
void setMaxSlew(unsigned slew) { maxSlew_ = slew; }
unsigned getMaxSlew() const { return maxSlew_; }
void setMaxWl(int wl) { maxWl_ = wl; }
int getMaxWl() const { return maxWl_; }
void setMaxCharSlew(double slew) { maxCharSlew_ = slew; }
double getMaxCharSlew() const { return maxCharSlew_; }
void setMaxCharCap(double cap) { maxCharCap_ = cap; }
Expand Down Expand Up @@ -374,12 +376,13 @@ class CtsOptions : public odb::dbBlockCallBackObj
unsigned numMaxLeafSinks_ = 15;
unsigned maxFanout_ = 0;
unsigned maxSlew_ = 4;
int maxWl_ = 0;
double maxCharSlew_ = 0;
double maxCharCap_ = 0;
double sinkBufferInputCap_ = 0;
int capSteps_ = 20;
int slewSteps_ = 7;
unsigned charWirelengthIterations_ = 4;
double sinkBufferInputCap_ = 0;
unsigned clockTreeMaxDepth_ = 100;
bool enableFakeLutEntries_ = true;
bool forceBuffersOnLeafLevel_ = true;
Expand Down
60 changes: 55 additions & 5 deletions src/cts/src/HTreeBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "Clustering.h"
#include "SinkClustering.h"
#include "TechChar.h"
#include "Util.h"
#include "odb/db.h"
#include "odb/isotropy.h"
Expand Down Expand Up @@ -1407,23 +1408,44 @@ void HTreeBuilder::computeLevelTopology(const unsigned level,
= options_->getVertexBufferDistance() / (techChar_->getLengthUnit() * 2);
int remainingLength
= options_->getBufferDistance() / (techChar_->getLengthUnit());
int currWl = 0;
unsigned inputCap = minInputCap_;
unsigned inputSlew = 1;
if (level > 1) {
const LevelTopology& previousLevel = topologyForEachLevel_[level - 2];
inputCap = previousLevel.getOutputCap();
inputSlew = previousLevel.getOutputSlew();
remainingLength = previousLevel.getRemainingLength();
currWl = previousLevel.getCurrWl();
}

const unsigned SLEW_THRESHOLD = options_->getMaxSlew();
const unsigned INIT_TOLERANCE = 1;
Comment on lines 1422 to 1423
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const unsigned SLEW_THRESHOLD = options_->getMaxSlew();
const unsigned INIT_TOLERANCE = 1;
const unsigned kSlewThreshold = options_->getMaxSlew();
const unsigned kInitTolerance = 1;


int WIRELENGTH_THRESHOLD;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an ordinary variable so use lower case naming.

// If max wirelength is 0, set it as slew threshold * maximum topology
// wirelength. This will behave as if there was no max wirelength threshold.
if (!options_->getMaxWl()) {
WIRELENGTH_THRESHOLD = SLEW_THRESHOLD * techChar_->getMaxSegmentLength();
} else {
WIRELENGTH_THRESHOLD = options_->getMaxWl() / techChar_->getLengthUnit();
}

debugPrint(
logger_, CTS, "tech char", 1, "slew threshold = {}", SLEW_THRESHOLD);
debugPrint(logger_,
CTS,
"tech char",
1,
"wirelength threshold = {}",
WIRELENGTH_THRESHOLD);
unsigned length = 0;
for (int charSegLength = techChar_->getMaxSegmentLength(); charSegLength >= 1;
--charSegLength) {
const unsigned numWires = (segmentLength - length) / charSegLength;

if (numWires >= 1) {
debugPrint(logger_, CTS, "tech char", 1, "curr wl = {}", currWl);
for (int wireCount = 0; wireCount < numWires; ++wireCount) {
unsigned outCap = 0, outSlew = 0;
unsigned key = 0;
Expand Down Expand Up @@ -1474,9 +1496,11 @@ void HTreeBuilder::computeLevelTopology(const unsigned level,
inputSlew,
inputCap,
SLEW_THRESHOLD,
WIRELENGTH_THRESHOLD,
INIT_TOLERANCE,
outSlew,
outCap);
outCap,
currWl);
}

if (key == std::numeric_limits<unsigned>::max()) {
Expand All @@ -1501,6 +1525,7 @@ void HTreeBuilder::computeLevelTopology(const unsigned level,

topology.setOutputSlew(inputSlew);
topology.setOutputCap(inputCap);
topology.setCurrWl(currWl);

computeBranchingPoints(level, topology);
topologyForEachLevel_.push_back(topology);
Expand Down Expand Up @@ -1529,9 +1554,11 @@ unsigned HTreeBuilder::computeMinDelaySegment(const unsigned length,
const unsigned inputSlew,
const unsigned inputCap,
const unsigned slewThreshold,
const int wirelengthThreshold,
const unsigned tolerance,
unsigned& outputSlew,
unsigned& outputCap) const
unsigned& outputCap,
int& currWl) const
{
unsigned minKey = std::numeric_limits<unsigned>::max();
unsigned minDelay = std::numeric_limits<unsigned>::max();
Expand All @@ -1548,6 +1575,17 @@ unsigned HTreeBuilder::computeMinDelaySegment(const unsigned length,
return;
}

if (seg.isBuffered()
&& (currWl + seg.getWl2FisrtBuffer() > wirelengthThreshold)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix the typo in getWl2FisrtBuffer -> getWl2FirstBuffer

return;
}

if (!seg.isBuffered()
&& (currWl + seg.getWl2FisrtBuffer()
> wirelengthThreshold - techChar_->getMinSegmentLength())) {
return;
}
Comment on lines +1578 to +1587
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If options_->getMaxWl() is not set, wirelengthThreshold will be 0. In this case, currWl + seg.getWl2FisrtBuffer() > wirelengthThreshold will likely be true for any segment, causing all segments to be pruned. This would prevent CTS from finding a solution. The wirelength constraint should only be applied when wirelengthThreshold is positive.

            if (wirelengthThreshold > 0) {
              if (seg.isBuffered()
                  && (currWl + seg.getWl2FisrtBuffer() > wirelengthThreshold)) {
                return;
              }

              if (!seg.isBuffered()
                  && (currWl + seg.getWl2FisrtBuffer()
                      > wirelengthThreshold - techChar_->getMinSegmentLength())) {
                return;
              }
            }


if (seg.getDelay() < minDelay) {
minDelay = seg.getDelay();
minKey = key;
Expand All @@ -1567,6 +1605,7 @@ unsigned HTreeBuilder::computeMinDelaySegment(const unsigned length,
const WireSegment& bestBufSegment = techChar_->getWireSegment(minBufKey);
outputSlew = bestBufSegment.getOutputSlew();
outputCap = bestBufSegment.getLoad();
currWl = bestBufSegment.getLastWl();
return minBufKey;
}
if (tolerance < MAX_TOLERANCE) {
Expand All @@ -1575,9 +1614,11 @@ unsigned HTreeBuilder::computeMinDelaySegment(const unsigned length,
inputSlew,
inputCap,
slewThreshold,
wirelengthThreshold,
tolerance + 1,
outputSlew,
outputCap);
outputCap,
currWl);
}
}

Expand All @@ -1590,13 +1631,22 @@ unsigned HTreeBuilder::computeMinDelaySegment(const unsigned length,
inputSlew,
inputCap,
slewThreshold,
wirelengthThreshold,
tolerance + 1,
outputSlew,
outputCap);
outputCap,
currWl);
}

const WireSegment& bestSegment = techChar_->getWireSegment(minKey);
outputSlew = std::max((unsigned) bestSegment.getOutputSlew(), inputSlew + 1);
if (bestSegment.isBuffered()) {
outputSlew = bestSegment.getOutputSlew();
currWl = bestSegment.getLastWl();
} else {
outputSlew
= std::max((unsigned) bestSegment.getOutputSlew(), inputSlew + 1);
currWl += bestSegment.getLastWl();
}
outputCap = bestSegment.getLoad();

return minKey;
Expand Down
7 changes: 6 additions & 1 deletion src/cts/src/HTreeBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,15 @@ class HTreeBuilder : public TreeBuilder
unsigned getOutputCap() const { return outputCap_; }
void setRemainingLength(unsigned length) { remainingLength_ = length; }
unsigned getRemainingLength() const { return remainingLength_; }
void setCurrWl(int wl) { curr_Wl_ = wl; }
int getCurrWl() const { return curr_Wl_; }

private:
double length_;
unsigned outputSlew_ = 0;
unsigned outputCap_ = 0;
unsigned remainingLength_ = 0;
int curr_Wl_ = 0;
std::vector<unsigned> wireSegments_;
std::vector<Point<double>> branchPointLoc_;
std::vector<unsigned> parents_;
Expand Down Expand Up @@ -270,9 +273,11 @@ class HTreeBuilder : public TreeBuilder
unsigned inputSlew,
unsigned inputCap,
unsigned slewThreshold,
int wirelengthThreshold,
unsigned tolerance,
unsigned& outputSlew,
unsigned& outputCap) const;
unsigned& outputCap,
int& currWl) const;

private:
void initSinkRegion();
Expand Down
48 changes: 32 additions & 16 deletions src/cts/src/TechChar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,16 @@ void TechChar::compileLut(const std::vector<TechChar::ResultData>& lutSols)
if (!(lutLine.isPureWire)) {
// Goes through the topology of the wiresegment and defines the buffer
// locations and masters.
int wl2FirstBuffer
= std::round(std::stod(lutLine.topology[0]) * (double) length);
int lastWl = 0;
int maxIndex = 0;
if (lutLine.topology.size() % 2 == 0) {
maxIndex = lutLine.topology.size();
} else {
maxIndex = lutLine.topology.size() - 1;
lastWl = std::round(std::stod(lutLine.topology[maxIndex])
* (double) length);
}
for (int topologyIndex = 0; topologyIndex < maxIndex; topologyIndex++) {
const std::string topologyS = lutLine.topology[topologyIndex];
Expand All @@ -115,6 +120,12 @@ void TechChar::compileLut(const std::vector<TechChar::ResultData>& lutSols)
segment.addBufferMaster(topologyS);
}
}
segment.setLastWl(lastWl);
segment.setWl2FirstBuffer(wl2FirstBuffer);
} else {
int wl = std::round(std::stod(lutLine.topology[0]) * (double) length);
segment.setLastWl(wl);
segment.setWl2FirstBuffer(wl);
}
}

Expand Down Expand Up @@ -312,14 +323,15 @@ void TechChar::printCharacterization() const
logger_->report("wireSegmentUnit = {}", options_->getWireSegmentUnit());

logger_->report(
"\nidx length load outSlew power delay inCap inSlew pureWire bufLoc");
"\n idx length load outSlew power delay inCap inSlew pureWire Wl2Fisrt "
"LastWl bufLoc");
forEachWireSegment([&](unsigned idx, const WireSegment& segment) {
std::string buffer_locations;
for (unsigned idx = 0; idx < segment.getNumBuffers(); ++idx) {
buffer_locations += std::to_string(segment.getBufferLocation(idx)) + " ";
}

logger_->report("{:6} {:2} {:2} {:2} {:.2e} {:4} {:2} {:2} {} {}",
logger_->report("{:6} {:4} {:4} {:4} {:.4e} {:4} {:4} {:4} {} {:4} {:4} {}",
idx,
(unsigned) segment.getLength(),
(unsigned) segment.getLoad(),
Expand All @@ -329,6 +341,8 @@ void TechChar::printCharacterization() const
(unsigned) segment.getInputCap(),
(unsigned) segment.getInputSlew(),
!segment.isBuffered(),
segment.getWl2FisrtBuffer(),
segment.getLastWl(),
buffer_locations);
});
}
Expand Down Expand Up @@ -397,20 +411,22 @@ void TechChar::reportSegment(unsigned key) const
{
const WireSegment& seg = getWireSegment(key);

debugPrint(
logger_,
CTS,
"tech char",
1,
" Key: {} inSlew: {} inCap: {} outSlew: {} load: {} length: {} delay: "
"{}",
key,
seg.getInputSlew(),
seg.getInputCap(),
seg.getOutputSlew(),
seg.getLoad(),
seg.getLength(),
seg.getDelay());
debugPrint(logger_,
CTS,
"tech char",
1,
" Key: {} inSlew: {} inCap: {} outSlew: {} load: {} length: {} "
"wl2fistyBuf: {} lastWL: {} delay: "
"{}",
key,
seg.getInputSlew(),
seg.getInputCap(),
seg.getOutputSlew(),
seg.getLoad(),
seg.getLength(),
seg.getWl2FisrtBuffer(),
seg.getLastWl(),
seg.getDelay());

for (unsigned idx = 0; idx < seg.getNumBuffers(); ++idx) {
debugPrint(logger_,
Expand Down
7 changes: 7 additions & 0 deletions src/cts/src/TechChar.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,18 @@ class WireSegment
bufferMasters_.push_back(name);
}

void setWl2FirstBuffer(int wl) { wl2FisrtBuffer_ = wl; }
void setLastWl(int wl) { lastWl_ = wl; }

double getPower() const { return power_; }
unsigned getDelay() const { return delay_; }
uint8_t getInputCap() const { return inputCap_; }
uint8_t getInputSlew() const { return inputSlew_; }
uint8_t getLength() const { return length_; }
uint8_t getLoad() const { return load_; }
uint8_t getOutputSlew() const { return outputSlew_; }
int getWl2FisrtBuffer() const { return wl2FisrtBuffer_; }
int getLastWl() const { return lastWl_; }
bool isBuffered() const { return !bufferLocations_.empty(); }
unsigned getNumBuffers() const { return bufferLocations_.size(); }
const std::vector<double>& getBufferLocations() { return bufferLocations_; }
Expand Down Expand Up @@ -123,6 +128,8 @@ class WireSegment

std::vector<double> bufferLocations_;
std::vector<std::string> bufferMasters_;
int wl2FisrtBuffer_;
int lastWl_;
};

//-----------------------------------------------------------------------------
Expand Down
14 changes: 8 additions & 6 deletions src/cts/src/TritonCTS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ void TritonCTS::setupCharacterization()
}
}

block_ = db_->getChip()->getBlock();
options_->setDbUnits(block_->getDbUnitsPerMicron());

openSta_->checkFanoutLimitPreamble();
// Finalize root/sink buffers
std::string rootBuffer = selectRootBuffer(rootBuffers_);
Expand All @@ -226,6 +229,10 @@ void TritonCTS::setupCharacterization()
}
}

double maxWlMicrons
= resizer_->findMaxWireLength(/* don't issue error */ false) * 1e+6;
options_->setMaxWl(block_->micronsToDbu(maxWlMicrons));

// A new characteriztion is always created.
techChar_ = std::make_unique<TechChar>(options_,
db_,
Expand Down Expand Up @@ -913,9 +920,7 @@ void TritonCTS::findLongEdges(
odb::Point driverPt,
std::map<odb::Point, std::vector<odb::dbITerm*>>& point2pin)
{
double maxWlMicrons
= resizer_->findMaxWireLength(/* don't issue error */ false) * 1e+6;
const int threshold = block_->micronsToDbu(maxWlMicrons);
const int threshold = options_->getMaxWl();
debugPrint(
logger_, CTS, "clock gate cloning", 1, "Threshold = {}", threshold);

Expand Down Expand Up @@ -1173,9 +1178,6 @@ void TritonCTS::findLongEdges(

void TritonCTS::populateTritonCTS()
{
block_ = db_->getChip()->getBlock();
options_->setDbUnits(block_->getDbUnitsPerMicron());

clearNumClocks();

// Use dbSta to find all clock nets in the design.
Expand Down