Merge remote-tracking branch 'parallax/master'

This commit is contained in:
Matt Liberty 2025-07-09 19:02:06 +00:00
commit 966cdc80fb
18 changed files with 128 additions and 146 deletions

View File

@ -532,7 +532,8 @@ if (TCL_READLINE)
endif()
# common to gcc/clang
set(CXX_FLAGS -Wall -Wextra -pedantic -Wcast-qual -Wredundant-decls -Wformat-security)
set(CXX_FLAGS -Wall -Wextra -pedantic -Wcast-qual -Wredundant-decls
-Wformat-security -Werror=misleading-indentation)
if(ENABLE_TSAN)
message(STATUS "Thread sanitizer: ${ENABLE_TSAN}")

View File

@ -61,7 +61,7 @@ foreach subdir $subdirs {
set files [glob -nocomplain [file join $subdir "*.{cc,hh,yy,ll,i}"]]
set files_c [concat $files_c $files]
}
set warn_regexp_c {(?:(?:criticalError|->warn|->fileWarn|->error|->fileError|libWarn|libError| warn)\(|tclArgError\(interp,\s*)([0-9]+),.*(".+")}
set warn_regexp_c {(?:(?:->critical|->warn|->fileWarn|->error|->fileError|libWarn|libError| warn)\(|tclArgError\(interp,\s*)([0-9]+),.*(".+")}
set files_tcl {}
foreach subdir $subdirs {

View File

@ -999,7 +999,7 @@ Vertex::setObjectIdx(ObjectIdx idx)
string
Vertex::to_string(const StaState *sta) const
{
const Network *network = sta->network();
const Network *network = sta->sdcNetwork();
if (network->direction(pin_)->isBidirect()) {
string str = network->pathName(pin_);
str += ' ';

View File

@ -186,7 +186,7 @@ proc edge_disable_reason { edge } {
}
if { [$edge is_disabled_preset_clear] } {
if { $disables != "" } { append disables ", " }
append disables "timing_enable_preset_clear_arcs"
append disables "sta_preset_clear_arcs_enabled"
}
return $disables
}

View File

@ -57,11 +57,17 @@ protected:
};
// Predicate that is true when the ports, functions, sequentials and
// timing arcs match.
// functions or timing arcs match.
bool
equivCells(const LibertyCell *cell1,
const LibertyCell *cell2);
// Predicate that is true when the ports, functions, sequentials and
// timing arcs match.
bool
equivCellsArcs(const LibertyCell *cell1,
const LibertyCell *cell2);
// Predicate that is true when the ports match.
bool
equivCellPorts(const LibertyCell *cell1,

View File

@ -489,7 +489,6 @@ public:
// timing arcs.
bool hasInferedRegTimingArcs() const { return has_infered_reg_timing_arcs_; }
TestCell *testCell() const { return test_cell_; }
bool isLatchData(LibertyPort *port);
void latchEnable(const TimingArcSet *arc_set,
// Return values.
const LibertyPort *&enable_port,
@ -803,6 +802,10 @@ public:
// Has register/latch rise/fall edges from pin.
bool isRegClk() const { return is_reg_clk_; }
void setIsRegClk(bool is_clk);
bool isRegOutput() const { return is_reg_output_; }
void setIsRegOutput(bool is_reg_out);
bool isLatchData() const { return is_latch_data_; }
void setIsLatchData(bool is_latch_data);
// Is the clock for timing checks.
bool isCheckClk() const { return is_check_clk_; }
void setIsCheckClk(bool is_clk);
@ -899,6 +902,8 @@ protected:
bool min_period_exists_:1;
bool is_clk_:1;
bool is_reg_clk_:1;
bool is_reg_output_:1;
bool is_latch_data_: 1;
bool is_check_clk_:1;
bool is_clk_gate_clk_:1;
bool is_clk_gate_enable_:1;

View File

@ -771,12 +771,13 @@ public:
ClockSet *from_clks,
InstanceSet *from_insts,
const RiseFallBoth *from_rf);
bool isExceptionStartpoint(const Pin *pin) const;
// Make an exception -through specification.
ExceptionThru *makeExceptionThru(PinSet *pins,
NetSet *nets,
InstanceSet *insts,
const RiseFallBoth *rf);
bool exceptionToInvalid(const Pin *pin);
bool isExceptionEndpoint(const Pin *pin);
// Make an exception -to specification.
ExceptionTo *makeExceptionTo(PinSet *pins,
ClockSet *clks,
@ -972,10 +973,11 @@ public:
ExceptionStateSet *&states) const;
// Return hierarchical -thru exceptions that start between
// from_pin and to_pin.
ExceptionStateSet *exceptionThruStates(const Pin *from_pin,
const Pin *to_pin,
const RiseFall *to_rf,
const MinMax *min_max) const;
void exceptionThruStates(const Pin *from_pin,
const Pin *to_pin,
const RiseFall *to_rf,
const MinMax *min_max,
ExceptionStateSet *&states) const;
// Find the highest priority exception with first exception pt at
// pin/clk end.
void exceptionTo(ExceptionPathType type,

View File

@ -118,8 +118,6 @@ public:
Corner *corner,
const MinMaxAll *min_max,
bool infer_latches);
bool setMinLibrary(const char *min_filename,
const char *max_filename);
bool readVerilog(const char *filename);
// Network readers call this to notify the Sta to delete any previously
// linked network.
@ -531,7 +529,6 @@ public:
void checkExceptionFromPins(ExceptionFrom *from,
const char *file,
int line) const;
bool exceptionFromInvalid(const Pin *pin) const;
void deleteExceptionFrom(ExceptionFrom *from);
// Make an exception -through specification.
ExceptionThru *makeExceptionThru(PinSet *pins,

View File

@ -341,6 +341,19 @@ equivCells(const LibertyCell *cell1,
|| equivCellTimingArcSets(cell1, cell2));
}
bool
equivCellsArcs(const LibertyCell *cell1,
const LibertyCell *cell2)
{
return equivCellPorts(cell1, cell2)
&& equivCellFuncs(cell1, cell2)
&& equivCellPgPorts(cell1, cell2)
&& equivCellSequentials(cell1, cell2)
&& equivCellStatetables(cell1, cell2)
// Reqwuire timing arc equivalence if there are no functions.
&& equivCellTimingArcSets(cell1, cell2);
}
static bool
cellHasFuncs(const LibertyCell *cell)
{

View File

@ -1244,10 +1244,13 @@ LibertyCell::addTimingArcSet(TimingArcSet *arc_set)
timing_arc_sets_.push_back(arc_set);
LibertyPort *from = arc_set->from();
LibertyPort *to = arc_set->to();
const TimingRole *role = arc_set->role();
if (role == TimingRole::regClkToQ()
|| role == TimingRole::latchEnToQ())
|| role == TimingRole::latchEnToQ()) {
from->setIsRegClk(true);
to->setIsRegOutput(true);
}
if (role->isTimingCheck())
from->setIsCheckClk(true);
return set_index;
@ -1881,7 +1884,7 @@ LibertyCell::makeLatchEnable(LibertyPort *d,
latch_enables_.push_back(latch_enable);
latch_d_to_q_map_[d_to_q] = latch_enable;
latch_check_map_[setup_check] = latch_enable;
latch_data_ports_.insert(d);
d->setIsLatchData(true);
debugPrint(debug, "liberty_latch", 1,
"latch %s -> %s | %s %s -> %s | %s %s -> %s setup",
d->name(),
@ -1933,12 +1936,6 @@ LibertyCell::inferLatchRoles(Report *report,
}
}
bool
LibertyCell::isLatchData(LibertyPort *port)
{
return latch_data_ports_.hasKey(port);
}
void
LibertyCell::latchEnable(const TimingArcSet *d_to_q_set,
// Return values.
@ -2100,6 +2097,8 @@ LibertyPort::LibertyPort(LibertyCell *cell,
min_period_exists_(false),
is_clk_(false),
is_reg_clk_(false),
is_reg_output_(false),
is_latch_data_(false),
is_check_clk_(false),
is_clk_gate_clk_(false),
is_clk_gate_enable_(false),
@ -2547,6 +2546,18 @@ LibertyPort::setIsRegClk(bool is_clk)
is_reg_clk_ = is_clk;
}
void
LibertyPort::setIsRegOutput(bool is_reg_out)
{
is_reg_output_ = is_reg_out;
}
void
LibertyPort::setIsLatchData(bool is_latch_data)
{
is_latch_data_ = is_latch_data;
}
void
LibertyPort::setIsCheckClk(bool is_clk)
{

View File

@ -655,7 +655,7 @@ Network::isLatchData(const Pin *pin) const
{
LibertyPort *port = libertyPort(pin);
if (port)
return port->libertyCell()->isLatchData(port);
return port->isLatchData();
else
return false;
}

View File

@ -3799,6 +3799,22 @@ Sdc::makeExceptionFrom(PinSet *from_pins,
return nullptr;
}
bool
Sdc::isExceptionStartpoint(const Pin *pin) const
{
Net *net = network_->net(pin);
const LibertyPort *port = network_->libertyPort(pin);
return ((network_->isTopLevelPort(pin)
&& network_->direction(pin)->isAnyInput())
|| (port && port->isRegClk())
|| (port && port->isLatchData()))
// Pins connected to power/ground are invalid.
&& !(net
&& (network_->isPower(net)
|| network_->isGround(net)))
&& !network_->isHierarchical(pin);
}
ExceptionThru *
Sdc::makeExceptionThru(PinSet *pins,
NetSet *nets,
@ -3833,31 +3849,31 @@ Sdc::makeExceptionTo(PinSet *pins,
// Valid endpoints include gated clock enables which are not
// known until clock arrivals are determined.
bool
Sdc::exceptionToInvalid(const Pin *pin)
Sdc::isExceptionEndpoint(const Pin *pin)
{
Net *net = network_->net(pin);
// Floating pins are invalid.
if ((net == nullptr
&& !(network_->isTopLevelPort(pin)
|| network_->direction(pin)->isInternal()))
|| (net
// Pins connected to power/ground are invalid.
&& (network_->isPower(net)
|| network_->isGround(net)))
// Hierarchical pins are invalid.
|| network_->isHierarchical(pin))
return true;
// Register/latch Q pins are invalid.
LibertyPort *port = network_->libertyPort(pin);
bool has_checks = false;
const LibertyPort *port = network_->libertyPort(pin);
if (port) {
// Look for timing checks to the pin witihout using the graph because
// it may not exist.
LibertyCell *cell = port->libertyCell();
for (TimingArcSet *arc_set : cell->timingArcSets(nullptr, port)) {
const TimingRole *role = arc_set->role();
if (role->genericRole() == TimingRole::regClkToQ())
return true;
if (arc_set->role()->isTimingCheck()) {
has_checks = true;
break;
}
}
}
return false;
return ((network_->isTopLevelPort(pin)
&& network_->direction(pin)->isAnyOutput())
|| has_checks
|| (port && port->isLatchData()))
// Pins connected to power/ground are invalid.
&& !(net
&& (network_->isPower(net)
|| network_->isGround(net)))
&& !network_->isHierarchical(pin);
}
void
@ -3914,8 +3930,7 @@ Sdc::recordPathDelayInternalFrom(ExceptionPath *exception)
if (from
&& from->hasPins()) {
for (const Pin *pin : *from->pins()) {
if (!(network_->isRegClkPin(pin)
|| network_->isTopLevelPort(pin))) {
if (!isExceptionStartpoint(pin)) {
path_delay_internal_from_.insert(pin);
if (exception->breakPath())
path_delay_internal_from_break_.insert(pin);
@ -3932,8 +3947,7 @@ Sdc::unrecordPathDelayInternalFrom(ExceptionPath *exception)
&& from->hasPins()
&& !path_delay_internal_from_.empty()) {
for (const Pin *pin : *from->pins()) {
if (!(network_->isRegClkPin(pin)
|| network_->isTopLevelPort(pin))
if (!isExceptionStartpoint(pin)
&& !pathDelayFrom(pin)) {
path_delay_internal_from_.erase(pin);
if (exception->breakPath())
@ -5304,13 +5318,13 @@ Sdc::filterRegQStates(const Pin *to_pin,
}
}
ExceptionStateSet *
void
Sdc::exceptionThruStates(const Pin *from_pin,
const Pin *to_pin,
const RiseFall *to_rf,
const MinMax *min_max) const
const MinMax *min_max,
ExceptionStateSet *&states) const
{
ExceptionStateSet *states = nullptr;
exceptionThruStates(first_thru_pin_exceptions_.findKey(to_pin),
to_rf, min_max, states);
if (!first_thru_edge_exceptions_.empty()) {
@ -5325,7 +5339,6 @@ Sdc::exceptionThruStates(const Pin *from_pin,
exceptionThruStates(first_thru_inst_exceptions_.findKey(to_inst),
to_rf, min_max, states);
}
return states;
}
void

View File

@ -2355,6 +2355,7 @@ proc set_path_delay { cmd args min_max } {
set from [parse_from_arg keys arg_error]
set thrus [parse_thrus_arg args arg_error]
set to [parse_to_arg keys flags arg_error]
check_exception_pins $from $to
if { $arg_error } {
delete_from_thrus_to $from $thrus $to
} else {

View File

@ -1041,33 +1041,6 @@ Genclks::srcPath(const Clock *gclk,
return nullptr;
}
void
Genclks::updateSrcPathPrevs()
{
for (auto const & [clk_pin, src_paths] : genclk_src_paths_) {
for (const Path &src_path : src_paths) {
if (!src_path.isNull()) {
const Path *p = &src_path;
while (p) {
Path *src_vpath = Path::vertexPath(p, this);
if (src_vpath) {
Path *prev_path = p->prevPath();
if (prev_path) {
Path *prev_vpath = Path::vertexPath(prev_path, this);
src_vpath->setPrevPath(prev_vpath);
src_vpath->setPrevEdgeArc(p->prevEdge(this),
p->prevArc(this), this);
}
}
p = p->prevPath();
}
debugPrint(debug_, "genclk", 3, "repaired src path prev %s",
src_path.to_string(this).c_str());
}
}
}
}
Arrival
Genclks::insertionDelay(const Clock *clk,
const Pin *pin,

View File

@ -85,7 +85,6 @@ public:
Level clkPinMaxLevel(const Clock *clk) const;
void copyGenClkSrcPaths(Vertex *vertex,
TagGroupBldr *tag_bldr);
void updateSrcPathPrevs();
private:
void findInsertionDelays();

View File

@ -610,7 +610,6 @@ Search::findFilteredArrivals(bool thru_latches)
int arrival_count = arrival_iter_->visitParallel(max_level,
arrival_visitor_);
deleteTagsPrev();
genclks_->updateSrcPathPrevs();
debugPrint(debug_, "search", 1, "found %d arrivals", arrival_count);
}
arrivals_exist_ = true;
@ -889,7 +888,6 @@ Search::findClkArrivals()
arrival_visitor_->init(false, &search_clk);
arrival_iter_->visitParallel(levelize_->maxLevel(), arrival_visitor_);
deleteTagsPrev();
genclks_->updateSrcPathPrevs();
arrivals_exist_ = true;
stats.report("Find clk arrivals");
}
@ -980,11 +978,9 @@ Search::visitStartpoints(VertexVisitor *visitor)
visitor->visit(vertex);
const PinSet &startpoints = sdc_->pathDelayInternalFrom();
if (!startpoints.empty()) {
for (const Pin *pin : startpoints) {
Vertex *vertex = graph_->pinDrvrVertex(pin);
visitor->visit(vertex);
}
for (const Pin *pin : startpoints) {
Vertex *vertex = graph_->pinDrvrVertex(pin);
visitor->visit(vertex);
}
}
@ -1061,7 +1057,6 @@ Search::findArrivals1(Level level)
Stats stats(debug_, report_);
int arrival_count = arrival_iter_->visitParallel(level, arrival_visitor_);
deleteTagsPrev();
genclks_->updateSrcPathPrevs();
stats.report("Find arrivals");
if (arrival_iter_->empty()
&& invalid_arrivals_->empty()) {
@ -2176,8 +2171,7 @@ PathVisitor::visitFromPath(const Pin *from_pin,
to_tag = search_->thruClkTag(from_path, from_vertex, from_tag, true,
edge, to_rf, arc_delay_min_max_eq,
min_max, path_ap);
if (to_tag)
to_arrival = from_arrival + arc_delay;
to_arrival = from_arrival + arc_delay;
}
}
}
@ -2272,11 +2266,10 @@ PathVisitor::visitFromPath(const Pin *from_pin,
else {
if (!(sdc_->isPathDelayInternalFromBreak(to_pin)
|| sdc_->isPathDelayInternalToBreak(from_pin))) {
to_tag = search_->thruTag(from_tag, edge, to_rf, min_max, path_ap);
arc_delay = search_->deratedDelay(from_vertex, arc, edge, false, path_ap);
if (!delayInf(arc_delay)) {
if (!delayInf(arc_delay))
to_arrival = from_arrival + arc_delay;
to_tag = search_->thruTag(from_tag, edge, to_rf, min_max, path_ap);
}
}
}
if (to_tag)
@ -2643,7 +2636,7 @@ Search::mutateTag(Tag *from_tag,
// Kill path delay tags past the -to pin.
if ((exception->isPathDelay()
&& sdc_->isCompleteTo(state, from_pin, from_rf, min_max))
&& sdc_->isCompleteTo(state, to_pin, to_rf, min_max))
// Kill loop tags at register clock pins.
|| (exception->isLoop()
&& to_is_reg_clk)) {
@ -2653,7 +2646,7 @@ Search::mutateTag(Tag *from_tag,
}
// Get the set of -thru exceptions starting at to_pin/edge.
new_states = sdc_->exceptionThruStates(from_pin, to_pin, to_rf, min_max);
sdc_->exceptionThruStates(from_pin, to_pin, to_rf, min_max, new_states);
if (new_states || state_change) {
// Second pass to apply state changes and add updated existing
// states to new states.
@ -2666,18 +2659,18 @@ Search::mutateTag(Tag *from_tag,
// Found a -thru that we've been waiting for.
state = state->nextState();
// Don't propagate a completed false path -thru unless it is a
// clock. Clocks carry the completed false path to disable
// downstream paths that use the clock as data.
if ((state->isComplete()
&& exception->isFalse()
&& !from_is_clk)
// to_pin/edge completes a loop path.
|| (exception->isLoop()
&& state->isComplete())) {
delete new_states;
return nullptr;
}
// Don't propagate a completed false path -thru unless it is a
// clock. Clocks carry the completed false path to disable
// downstream paths that use the clock as data.
if ((state->isComplete()
&& exception->isFalse()
&& !from_is_clk)
// to_pin/edge completes a loop path.
|| (exception->isLoop()
&& state->isComplete())) {
delete new_states;
return nullptr;
}
// Kill path delay tags past the -to pin.
if (!((exception->isPathDelay()
@ -2691,7 +2684,7 @@ Search::mutateTag(Tag *from_tag,
}
else
// Get the set of -thru exceptions starting at to_pin/edge.
new_states = sdc_->exceptionThruStates(from_pin, to_pin, to_rf, min_max);
sdc_->exceptionThruStates(from_pin, to_pin, to_rf, min_max, new_states);
if (new_states)
return findTag(to_rf, path_ap, to_clk_info, to_is_clk,

View File

@ -735,20 +735,6 @@ Sta::readLibertyAfter(LibertyLibrary *liberty,
network_, report_);
}
bool
Sta::setMinLibrary(const char *min_filename,
const char *max_filename)
{
LibertyLibrary *max_lib = network_->findLibertyFilename(max_filename);
if (max_lib) {
LibertyLibrary *min_lib = readLibertyFile(min_filename, cmd_corner_,
MinMaxAll::min(), false);
return min_lib != nullptr;
}
else
return false;
}
bool
Sta::readVerilog(const char *filename)
{
@ -2027,7 +2013,7 @@ Sta::checkExceptionFromPins(ExceptionFrom *from,
PinSet::ConstIterator pin_iter(from->pins());
while (pin_iter.hasNext()) {
const Pin *pin = pin_iter.next();
if (exceptionFromInvalid(pin)) {
if (!sdc_->isExceptionStartpoint(pin)) {
if (line)
report_->fileWarn(1554, file, line, "'%s' is not a valid start point.",
cmd_network_->pathName(pin));
@ -2039,24 +2025,6 @@ Sta::checkExceptionFromPins(ExceptionFrom *from,
}
}
bool
Sta::exceptionFromInvalid(const Pin *pin) const
{
Net *net = network_->net(pin);
// Floating pins are invalid.
return (net == nullptr
&& !network_->isTopLevelPort(pin))
|| (net
// Pins connected to power/ground are invalid.
&& (network_->isPower(net)
|| network_->isGround(net)))
|| !((network_->isTopLevelPort(pin)
&& network_->direction(pin)->isAnyInput())
|| network_->isRegClkPin(pin)
|| network_->isLatchData(pin)
|| network_->direction(pin)->isInternal());
}
void
Sta::deleteExceptionFrom(ExceptionFrom *from)
{
@ -2103,7 +2071,7 @@ Sta::checkExceptionToPins(ExceptionTo *to,
PinSet::Iterator pin_iter(to->pins());
while (pin_iter.hasNext()) {
const Pin *pin = pin_iter.next();
if (sdc_->exceptionToInvalid(pin)) {
if (!sdc_->isExceptionEndpoint(pin)) {
if (line)
report_->fileWarn(1551, file, line, "'%s' is not a valid endpoint.",
cmd_network_->pathName(pin));
@ -4121,7 +4089,9 @@ Sta::replaceCell(Instance *inst,
{
NetworkEdit *network = networkCmdEdit();
LibertyCell *from_lib_cell = network->libertyCell(inst);
if (sta::equivCells(from_lib_cell, to_lib_cell)) {
if (sta::equivCellsArcs(from_lib_cell, to_lib_cell)) {
// Replace celll optimized for less disruption to graph
// when ports and timing arcs are equivalent.
replaceEquivCellBefore(inst, to_lib_cell);
network->replaceCell(inst, to_cell);
replaceEquivCellAfter(inst);
@ -4258,7 +4228,7 @@ Sta::replaceEquivCellBefore(const Instance *inst,
if (to_set)
edge->setTimingArcSet(to_set);
else
report_->critical(1553, "corresponding timing arc set not found in equiv cells");
report_->critical(1555, "corresponding timing arc set not found in equiv cells");
}
}
}

View File

@ -113,9 +113,8 @@ VisitPathEnds::visitClkedPathEnds(const Pin *pin,
else if (vertex->hasChecks())
visitCheckEnd(pin, vertex, path, end_rf, path_ap, filtered, visitor,
is_constrained);
else if (!sdc_->exceptionToInvalid(pin)
&& (!filtered
|| search_->matchesFilter(path, nullptr))) {
else if (!filtered
|| search_->matchesFilter(path, nullptr)) {
PathDelay *path_delay = pathDelayTo(path, pin, end_rf, path_min_max);
if (path_delay) {
PathEndPathDelay path_end(path_delay, path, this);
@ -231,8 +230,7 @@ VisitPathEnds::visitCheckEnd(const Pin *pin,
}
}
}
if (!check_clked
&& !sdc_->exceptionToInvalid(pin))
if (!check_clked)
visitCheckEndUnclked(pin, vertex, path, end_rf, path_ap, filtered,
visitor, is_constrained);
}