OR 4732 Liberty support for positive/negative clock_tree_path
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
b4e58d5b74
commit
1740c894b4
|
|
@ -796,10 +796,16 @@ public:
|
|||
void setDriverWaveform(DriverWaveform *driver_waveform,
|
||||
const RiseFall *rf);
|
||||
void setClkTreeDelay(const TableModel *model,
|
||||
const RiseFall *rf,
|
||||
const RiseFall *from_rf,
|
||||
const RiseFall *to_rf,
|
||||
const MinMax *min_max);
|
||||
// Should be deprecated.
|
||||
float clkTreeDelay(float in_slew,
|
||||
const RiseFall *rf,
|
||||
const RiseFall *from_rf,
|
||||
const MinMax *min_max) const;
|
||||
float clkTreeDelay(float in_slew,
|
||||
const RiseFall *from_rf,
|
||||
const RiseFall *to_rf,
|
||||
const MinMax *min_max) const;
|
||||
// Assumes input slew of 0.0.
|
||||
RiseFallMinMax clkTreeDelays() const;
|
||||
|
|
@ -846,7 +852,7 @@ protected:
|
|||
ReceiverModelPtr receiver_model_;
|
||||
DriverWaveform *driver_waveform_[RiseFall::index_count];
|
||||
// Redundant with clock_tree_path_delay timing arcs but faster to access.
|
||||
const TableModel *clk_tree_delay_[RiseFall::index_count][MinMax::index_count];
|
||||
const TableModel *clk_tree_delay_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count];
|
||||
|
||||
unsigned int min_pulse_width_exists_:RiseFall::index_count;
|
||||
bool min_period_exists_:1;
|
||||
|
|
|
|||
|
|
@ -2001,9 +2001,11 @@ LibertyPort::LibertyPort(LibertyCell *cell,
|
|||
liberty_port_ = this;
|
||||
min_pulse_width_[RiseFall::riseIndex()] = 0.0;
|
||||
min_pulse_width_[RiseFall::fallIndex()] = 0.0;
|
||||
for (auto rf_index : RiseFall::rangeIndex()) {
|
||||
for (auto mm_index : MinMax::rangeIndex())
|
||||
clk_tree_delay_[rf_index][mm_index] = nullptr;
|
||||
for (auto from_rf_index : RiseFall::rangeIndex()) {
|
||||
for (auto to_rf_index : RiseFall::rangeIndex()) {
|
||||
for (auto mm_index : MinMax::rangeIndex())
|
||||
clk_tree_delay_[from_rf_index][to_rf_index][mm_index] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2607,12 +2609,15 @@ RiseFallMinMax
|
|||
LibertyPort::clkTreeDelays() const
|
||||
{
|
||||
RiseFallMinMax delays;
|
||||
for (const RiseFall *rf : RiseFall::range()) {
|
||||
for (const MinMax *min_max : MinMax::range()) {
|
||||
const TableModel *model = clk_tree_delay_[rf->index()][min_max->index()];
|
||||
if (model) {
|
||||
float delay = model->findValue(0.0, 0.0, 0.0);
|
||||
delays.setValue(rf, min_max, delay);
|
||||
for (const RiseFall *from_rf : RiseFall::range()) {
|
||||
for (const RiseFall *to_rf : RiseFall::range()) {
|
||||
for (const MinMax *min_max : MinMax::range()) {
|
||||
const TableModel *model =
|
||||
clk_tree_delay_[from_rf->index()][to_rf->index()][min_max->index()];
|
||||
if (model) {
|
||||
float delay = model->findValue(0.0, 0.0, 0.0);
|
||||
delays.setValue(from_rf, min_max, delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2624,7 +2629,21 @@ LibertyPort::clkTreeDelay(float in_slew,
|
|||
const RiseFall *rf,
|
||||
const MinMax *min_max) const
|
||||
{
|
||||
const TableModel *model = clk_tree_delay_[rf->index()][min_max->index()];
|
||||
const TableModel *model = clk_tree_delay_[rf->index()][rf->index()][min_max->index()];
|
||||
if (model)
|
||||
return model->findValue(in_slew, 0.0, 0.0);
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
float
|
||||
LibertyPort::clkTreeDelay(float in_slew,
|
||||
const RiseFall *from_rf,
|
||||
const RiseFall *to_rf,
|
||||
const MinMax *min_max) const
|
||||
{
|
||||
const TableModel *model =
|
||||
clk_tree_delay_[from_rf->index()][to_rf->index()][min_max->index()];
|
||||
if (model)
|
||||
return model->findValue(in_slew, 0.0, 0.0);
|
||||
else
|
||||
|
|
@ -2633,10 +2652,11 @@ LibertyPort::clkTreeDelay(float in_slew,
|
|||
|
||||
void
|
||||
LibertyPort::setClkTreeDelay(const TableModel *model,
|
||||
const RiseFall *rf,
|
||||
const RiseFall *from_rf,
|
||||
const RiseFall *to_rf,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
clk_tree_delay_[rf->index()][min_max->index()] = model;
|
||||
clk_tree_delay_[from_rf->index()][to_rf->index()][min_max->index()] = model;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -642,9 +642,27 @@ LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell,
|
|||
for (auto to_rf : RiseFall::range()) {
|
||||
TimingModel *model = attrs->model(to_rf);
|
||||
if (model) {
|
||||
makeTimingArc(arc_set, nullptr, to_rf->asTransition(), model);
|
||||
const GateTableModel *gate_model = dynamic_cast<GateTableModel *>(model);
|
||||
to_port->setClkTreeDelay(gate_model->delayModel(), to_rf, min_max);
|
||||
RiseFall *opp_rf = to_rf->opposite();
|
||||
switch (attrs->timingSense()) {
|
||||
case TimingSense::positive_unate:
|
||||
makeTimingArc(arc_set, to_rf, to_rf, model);
|
||||
to_port->setClkTreeDelay(gate_model->delayModel(), to_rf, to_rf, min_max);
|
||||
break;
|
||||
case TimingSense::negative_unate:
|
||||
makeTimingArc(arc_set, opp_rf, to_rf, model);
|
||||
to_port->setClkTreeDelay(gate_model->delayModel(), opp_rf, to_rf, min_max);
|
||||
break;
|
||||
case TimingSense::non_unate:
|
||||
case TimingSense::unknown:
|
||||
makeTimingArc(arc_set, to_rf, to_rf, model);
|
||||
makeTimingArc(arc_set, opp_rf, to_rf, model);
|
||||
to_port->setClkTreeDelay(gate_model->delayModel(), to_rf, to_rf, min_max);
|
||||
to_port->setClkTreeDelay(gate_model->delayModel(), opp_rf, to_rf, min_max);
|
||||
break;
|
||||
case TimingSense::none:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return arc_set;
|
||||
|
|
|
|||
|
|
@ -36,13 +36,13 @@ public:
|
|||
float &lib_clk_delay,
|
||||
float &latency,
|
||||
PathVertex &path,
|
||||
bool &exists);
|
||||
bool &exists) const;
|
||||
void latency(const RiseFall *src_rf,
|
||||
const RiseFall *end_rf,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &delay,
|
||||
bool &exists);
|
||||
bool &exists) const;
|
||||
static float latency(PathVertex *clk_path,
|
||||
StaState *sta);
|
||||
void setLatency(const RiseFall *src_rf,
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ ClkDelays::delay(const RiseFall *src_rf,
|
|||
float &lib_clk_delay,
|
||||
float &latency,
|
||||
PathVertex &path,
|
||||
bool &exists)
|
||||
bool &exists) const
|
||||
{
|
||||
int src_rf_index = src_rf->index();
|
||||
int end_rf_index = end_rf->index();
|
||||
|
|
@ -213,7 +213,7 @@ ClkDelays::latency(const RiseFall *src_rf,
|
|||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &latency,
|
||||
bool &exists)
|
||||
bool &exists) const
|
||||
{
|
||||
int src_rf_index = src_rf->index();
|
||||
int end_rf_index = end_rf->index();
|
||||
|
|
|
|||
|
|
@ -544,30 +544,8 @@ MakeTimingModel::findClkInsertionDelays()
|
|||
for (const Clock *clk : *clks) {
|
||||
ClkDelays delays = sta_->findClkDelays(clk);
|
||||
for (const MinMax *min_max : MinMax::range()) {
|
||||
TimingArcAttrsPtr attrs = nullptr;
|
||||
for (const RiseFall *clk_rf : RiseFall::range()) {
|
||||
float delay = min_max->initValue();
|
||||
for (const RiseFall *end_rf : RiseFall::range()) {
|
||||
PathVertex clk_path;
|
||||
float insertion, delay1, lib_clk_delay, latency;
|
||||
bool exists;
|
||||
delays.delay(clk_rf, end_rf, min_max, insertion, delay1,
|
||||
lib_clk_delay, latency, clk_path, exists);
|
||||
if (exists)
|
||||
delay = min_max->minMax(delay, delayAsFloat(delay1));
|
||||
}
|
||||
TimingModel *model = makeGateModelScalar(delay, clk_rf);
|
||||
if (attrs == nullptr)
|
||||
attrs = std::make_shared<TimingArcAttrs>();
|
||||
attrs->setModel(clk_rf, model);
|
||||
}
|
||||
if (attrs)
|
||||
attrs->setTimingSense(TimingSense::positive_unate);
|
||||
TimingRole *role = (min_max == MinMax::min())
|
||||
? TimingRole::clockTreePathMin()
|
||||
: TimingRole::clockTreePathMax();
|
||||
lib_builder_->makeClockTreePathArcs(cell_, lib_port, role,
|
||||
min_max, attrs);
|
||||
makeClkTreePaths(lib_port, min_max, TimingSense::positive_unate, delays);
|
||||
makeClkTreePaths(lib_port, min_max, TimingSense::negative_unate, delays);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -577,6 +555,38 @@ MakeTimingModel::findClkInsertionDelays()
|
|||
delete port_iter;
|
||||
}
|
||||
|
||||
void
|
||||
MakeTimingModel::makeClkTreePaths(LibertyPort *lib_port,
|
||||
const MinMax *min_max,
|
||||
TimingSense sense,
|
||||
const ClkDelays &delays)
|
||||
{
|
||||
TimingArcAttrsPtr attrs = nullptr;
|
||||
for (const RiseFall *clk_rf : RiseFall::range()) {
|
||||
const RiseFall *end_rf = (sense == TimingSense::positive_unate)
|
||||
? clk_rf
|
||||
: clk_rf->opposite();
|
||||
PathVertex clk_path;
|
||||
float insertion, delay, lib_clk_delay, latency;
|
||||
bool exists;
|
||||
delays.delay(clk_rf, end_rf, min_max, insertion, delay,
|
||||
lib_clk_delay, latency, clk_path, exists);
|
||||
if (exists) {
|
||||
TimingModel *model = makeGateModelScalar(delay, end_rf);
|
||||
if (attrs == nullptr)
|
||||
attrs = std::make_shared<TimingArcAttrs>();
|
||||
attrs->setModel(end_rf, model);
|
||||
}
|
||||
}
|
||||
if (attrs) {
|
||||
attrs->setTimingSense(sense);
|
||||
TimingRole *role = (min_max == MinMax::min())
|
||||
? TimingRole::clockTreePathMin()
|
||||
: TimingRole::clockTreePathMax();
|
||||
lib_builder_->makeClockTreePathArcs(cell_, lib_port, role, min_max, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
LibertyPort *
|
||||
|
|
|
|||
|
|
@ -64,6 +64,10 @@ private:
|
|||
void findTimingFromInput(Port *input_port);
|
||||
void findClkedOutputPaths();
|
||||
void findClkInsertionDelays();
|
||||
void makeClkTreePaths(LibertyPort *lib_port,
|
||||
const MinMax *min_max,
|
||||
TimingSense sense,
|
||||
const ClkDelays &delays);
|
||||
void findOutputDelays(const RiseFall *input_rf,
|
||||
OutputPinDelays &output_pin_delays);
|
||||
void makeSetupHoldTimingArcs(const Pin *input_pin,
|
||||
|
|
|
|||
Loading…
Reference in New Issue