OpenSTA/liberty/LibertyBuilder.cc

699 lines
22 KiB
C++
Raw Normal View History

2018-09-28 17:54:21 +02:00
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
2018-09-28 17:54:21 +02:00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2018-09-28 17:54:21 +02:00
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2018-09-28 17:54:21 +02:00
#include "LibertyBuilder.hh"
2020-04-05 23:53:44 +02:00
#include "PortDirection.hh"
#include "TimingRole.hh"
#include "FuncExpr.hh"
#include "TimingArc.hh"
#include "InternalPower.hh"
#include "LeakagePower.hh"
#include "Sequential.hh"
#include "Liberty.hh"
2020-04-05 20:35:51 +02:00
2018-09-28 17:54:21 +02:00
namespace sta {
void
LibertyBuilder::init(Debug *debug,
Report *report)
{
debug_ = debug;
report_ = report;
}
2018-09-28 17:54:21 +02:00
LibertyCell *
LibertyBuilder::makeCell(LibertyLibrary *library,
const char *name,
const char *filename)
{
LibertyCell *cell = new LibertyCell(library, name, filename);
library->addCell(cell);
return cell;
}
LibertyPort *
LibertyBuilder::makePort(LibertyCell *cell,
const char *port_name)
2018-09-28 17:54:21 +02:00
{
rm tmp string uses commit 2d0a4f8e9a8b46faa2ba91e1be636c3c3ad95a7f Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 21:25:37 2023 -0700 leaks Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 5514910a91707d615bac0bbed3a29f579eca8de2 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 18:21:54 2023 -0700 foo Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 076a51d5816444e883232933c2ded7309291d0bc Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 16:38:42 2023 -0700 parse bus string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 2b80e563cbbb6563a6b716431f391bbb6639f816 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 15:57:05 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 9e4f2308658232d0b1ee9efcd948bb19ae5dd30f Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 14:37:35 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit ebad3afd49b08e7194452dd082c3c7c05767f875 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 10:59:11 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 69647913932312a04ca06e7a04cca17ed50d4daf Author: James Cherry <cherry@parallaxsw.com> Date: Fri Mar 24 21:02:20 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 55e67996a7b0651dbb5ee06cb89fe0410648c3c1 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 10:42:43 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 73cee43925c0d32940989c616440b4da18640121 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 09:55:17 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit eba6d1413b8d87a64a90141e5263a56eede1df51 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 09:40:16 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 95d6ed78144512a37fd7c1d3d8a62fc4c8965818 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 08:18:46 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit faf82464d7be7fd6c958a21d401fa48ece4ac341 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 07:49:11 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit cfc9064496cb6f46ec562b104bc7fff2fbc1b32e Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 07:37:12 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 057933a6ac356a7541883aa64b5109c7a0e8b8d1 Author: James Cherry <cherry@parallaxsw.com> Date: Fri Mar 24 21:02:20 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit fdeb6436a72413356a627dd1de1d8cec7fca4c4a Author: James Cherry <cherry@parallaxsw.com> Date: Fri Mar 24 19:53:44 2023 -0700 rm TmpString uses Signed-off-by: James Cherry <cherry@parallaxsw.com> Signed-off-by: James Cherry <cherry@parallaxsw.com>
2023-03-26 15:34:36 +02:00
string sta_name = portLibertyToSta(port_name);
LibertyPort *port = new LibertyPort(cell, sta_name.c_str(), false, nullptr,
-1, -1, false, nullptr);
2018-09-28 17:54:21 +02:00
cell->addPort(port);
return port;
}
LibertyPort *
LibertyBuilder::makeBusPort(LibertyCell *cell,
const char *bus_name,
int from_index,
int to_index,
BusDcl *bus_dcl)
2018-09-28 17:54:21 +02:00
{
string sta_name = portLibertyToSta(bus_name);
LibertyPort *port = new LibertyPort(cell, sta_name.c_str(), true, bus_dcl,
from_index, to_index,
2018-09-28 17:54:21 +02:00
false, new ConcretePortSeq);
cell->addPort(port);
makeBusPortBits(cell->library(), cell, port, sta_name.c_str(), from_index, to_index);
2018-09-28 17:54:21 +02:00
return port;
}
void
LibertyBuilder::makeBusPortBits(ConcreteLibrary *library,
LibertyCell *cell,
ConcretePort *bus_port,
const char *bus_name,
2018-09-28 17:54:21 +02:00
int from_index,
int to_index)
{
if (from_index < to_index) {
for (int index = from_index; index <= to_index; index++)
makeBusPortBit(library, cell, bus_port, bus_name, index);
2018-09-28 17:54:21 +02:00
}
else {
for (int index = from_index; index >= to_index; index--)
makeBusPortBit(library, cell, bus_port, bus_name, index);
2018-09-28 17:54:21 +02:00
}
}
void
LibertyBuilder::makeBusPortBit(ConcreteLibrary *library,
LibertyCell *cell,
ConcretePort *bus_port,
const char *bus_name,
int bit_index)
{
rm tmp string uses commit 2d0a4f8e9a8b46faa2ba91e1be636c3c3ad95a7f Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 21:25:37 2023 -0700 leaks Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 5514910a91707d615bac0bbed3a29f579eca8de2 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 18:21:54 2023 -0700 foo Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 076a51d5816444e883232933c2ded7309291d0bc Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 16:38:42 2023 -0700 parse bus string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 2b80e563cbbb6563a6b716431f391bbb6639f816 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 15:57:05 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 9e4f2308658232d0b1ee9efcd948bb19ae5dd30f Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 14:37:35 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit ebad3afd49b08e7194452dd082c3c7c05767f875 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 10:59:11 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 69647913932312a04ca06e7a04cca17ed50d4daf Author: James Cherry <cherry@parallaxsw.com> Date: Fri Mar 24 21:02:20 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 55e67996a7b0651dbb5ee06cb89fe0410648c3c1 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 10:42:43 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 73cee43925c0d32940989c616440b4da18640121 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 09:55:17 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit eba6d1413b8d87a64a90141e5263a56eede1df51 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 09:40:16 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 95d6ed78144512a37fd7c1d3d8a62fc4c8965818 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 08:18:46 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit faf82464d7be7fd6c958a21d401fa48ece4ac341 Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 07:49:11 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit cfc9064496cb6f46ec562b104bc7fff2fbc1b32e Author: James Cherry <cherry@parallaxsw.com> Date: Sat Mar 25 07:37:12 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit 057933a6ac356a7541883aa64b5109c7a0e8b8d1 Author: James Cherry <cherry@parallaxsw.com> Date: Fri Mar 24 21:02:20 2023 -0700 rm tmp string Signed-off-by: James Cherry <cherry@parallaxsw.com> commit fdeb6436a72413356a627dd1de1d8cec7fca4c4a Author: James Cherry <cherry@parallaxsw.com> Date: Fri Mar 24 19:53:44 2023 -0700 rm TmpString uses Signed-off-by: James Cherry <cherry@parallaxsw.com> Signed-off-by: James Cherry <cherry@parallaxsw.com>
2023-03-26 15:34:36 +02:00
string bit_name;
stringPrint(bit_name, "%s%c%d%c",
bus_name,
library->busBrktLeft(),
bit_index,
library->busBrktRight());
LibertyPort *port = makePort(cell, bit_name.c_str(), bit_index);
2018-09-28 17:54:21 +02:00
bus_port->addPortBit(port);
cell->addPortBit(port);
}
2021-02-08 01:33:53 +01:00
LibertyPort *
2018-09-28 17:54:21 +02:00
LibertyBuilder::makePort(LibertyCell *cell,
const char *bit_name,
int bit_index)
{
LibertyPort *port = new LibertyPort(cell, bit_name, false, nullptr,
2021-02-08 01:33:53 +01:00
bit_index, bit_index, false, nullptr);
2018-09-28 17:54:21 +02:00
return port;
}
LibertyPort *
LibertyBuilder::makeBundlePort(LibertyCell *cell,
const char *name,
ConcretePortSeq *members)
{
LibertyPort *port = new LibertyPort(cell, name, false, nullptr, -1, -1, true, members);
2018-09-28 17:54:21 +02:00
cell->addPort(port);
return port;
}
////////////////////////////////////////////////////////////////
TimingArcSet *
LibertyBuilder::makeTimingArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
TimingArcAttrsPtr attrs,
int /* line */)
2018-09-28 17:54:21 +02:00
{
FuncExpr *to_func = to_port->function();
Sequential *seq = (to_func && to_func->port())
? cell->outputPortSequential(to_func->port())
: nullptr;
TimingType timing_type = attrs->timingType();
// Register/latch timing group missing timing_type.
if (attrs->timingType() == TimingType::combinational
&& seq) {
if (seq->clock() && seq->clock()->hasPort(from_port)) {
switch (seq->clock()->portTimingSense(from_port)) {
case TimingSense::positive_unate:
timing_type = TimingType::rising_edge;
break;
case TimingSense::negative_unate:
timing_type = TimingType::rising_edge;
break;
default:
break;
}
}
else if (seq->clear() && seq->clear()->hasPort(from_port)) {
timing_type = TimingType::clear;
if (attrs->timingSense() == TimingSense::unknown) {
// Missing timing_sense also.
TimingSense timing_sense = seq->clear()->portTimingSense(from_port);
attrs->setTimingSense(timing_sense);
}
}
else if (seq->preset() && seq->preset()->hasPort(from_port)) {
timing_type = TimingType::preset;
if (attrs->timingSense() == TimingSense::unknown) {
// Missing timing_sense also.
TimingSense timing_sense = seq->preset()->portTimingSense(from_port);
attrs->setTimingSense(timing_sense);
}
}
}
switch (timing_type) {
2019-03-13 01:25:53 +01:00
case TimingType::combinational:
if (seq
&& seq->isLatch()
&& seq->data()->hasPort(from_port))
// Latch D->Q timing arcs.
return makeLatchDtoQArcs(cell, from_port, to_port,
seq->data()->portTimingSense(from_port),
related_out, attrs);
2018-09-28 17:54:21 +02:00
else
return makeCombinationalArcs(cell, from_port, to_port, related_out,
true, true, attrs);
2019-03-13 01:25:53 +01:00
case TimingType::combinational_fall:
2018-09-28 17:54:21 +02:00
return makeCombinationalArcs(cell, from_port, to_port, related_out,
false, true, attrs);
2019-03-13 01:25:53 +01:00
case TimingType::combinational_rise:
2018-09-28 17:54:21 +02:00
return makeCombinationalArcs(cell, from_port, to_port, related_out,
true, false, attrs);
2019-03-13 01:25:53 +01:00
case TimingType::setup_rising:
2018-09-28 17:54:21 +02:00
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::rise(), TimingRole::setup(),
2018-09-28 17:54:21 +02:00
attrs);
2019-03-13 01:25:53 +01:00
case TimingType::setup_falling:
2018-09-28 17:54:21 +02:00
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::fall(), TimingRole::setup(),
2018-09-28 17:54:21 +02:00
attrs);
2019-03-13 01:25:53 +01:00
case TimingType::hold_rising:
2018-09-28 17:54:21 +02:00
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::rise(), TimingRole::hold(),
2018-09-28 17:54:21 +02:00
attrs);
2019-03-13 01:25:53 +01:00
case TimingType::hold_falling:
2018-09-28 17:54:21 +02:00
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::fall(), TimingRole::hold(),
2018-09-28 17:54:21 +02:00
attrs);
2019-03-13 01:25:53 +01:00
case TimingType::rising_edge:
2018-09-28 17:54:21 +02:00
return makeRegLatchArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::rise(), attrs);
2019-03-13 01:25:53 +01:00
case TimingType::falling_edge:
2018-09-28 17:54:21 +02:00
return makeRegLatchArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::fall(), attrs);
2019-03-13 01:25:53 +01:00
case TimingType::preset:
2018-09-28 17:54:21 +02:00
return makePresetClrArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::rise(), attrs);
2019-03-13 01:25:53 +01:00
case TimingType::clear:
2018-09-28 17:54:21 +02:00
return makePresetClrArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::fall(), attrs);
2019-03-13 01:25:53 +01:00
case TimingType::recovery_rising:
2018-09-28 17:54:21 +02:00
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::rise(),TimingRole::recovery(),
2018-09-28 17:54:21 +02:00
attrs);
2019-03-13 01:25:53 +01:00
case TimingType::recovery_falling:
2018-09-28 17:54:21 +02:00
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::fall(),TimingRole::recovery(),
2018-09-28 17:54:21 +02:00
attrs);
2019-03-13 01:25:53 +01:00
case TimingType::removal_rising:
2018-09-28 17:54:21 +02:00
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::rise(), TimingRole::removal(),
2018-09-28 17:54:21 +02:00
attrs);
2019-03-13 01:25:53 +01:00
case TimingType::removal_falling:
2018-09-28 17:54:21 +02:00
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::fall(), TimingRole::removal(),
2018-09-28 17:54:21 +02:00
attrs);
2019-03-13 01:25:53 +01:00
case TimingType::three_state_disable:
2018-09-28 17:54:21 +02:00
return makeTristateDisableArcs(cell, from_port, to_port, related_out,
true, true, attrs);
2019-03-13 01:25:53 +01:00
case TimingType::three_state_disable_fall:
2018-09-28 17:54:21 +02:00
return makeTristateDisableArcs(cell, from_port, to_port, related_out,
false, true, attrs);
2019-03-13 01:25:53 +01:00
case TimingType::three_state_disable_rise:
2018-09-28 17:54:21 +02:00
return makeTristateDisableArcs(cell, from_port, to_port, related_out,
true, false, attrs);
2019-03-13 01:25:53 +01:00
case TimingType::three_state_enable:
2018-09-28 17:54:21 +02:00
return makeTristateEnableArcs(cell, from_port, to_port, related_out,
true, true, attrs);
2019-03-13 01:25:53 +01:00
case TimingType::three_state_enable_fall:
2018-09-28 17:54:21 +02:00
return makeTristateEnableArcs(cell, from_port, to_port, related_out,
false, true, attrs);
2019-03-13 01:25:53 +01:00
case TimingType::three_state_enable_rise:
2018-09-28 17:54:21 +02:00
return makeTristateEnableArcs(cell, from_port, to_port, related_out,
true, false, attrs);
2019-03-13 01:25:53 +01:00
case TimingType::skew_falling:
2018-09-28 17:54:21 +02:00
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::fall(), TimingRole::skew(),
2018-09-28 17:54:21 +02:00
attrs);
2019-03-13 01:25:53 +01:00
case TimingType::skew_rising:
2018-09-28 17:54:21 +02:00
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::rise(), TimingRole::skew(),
2018-09-28 17:54:21 +02:00
attrs);
2019-03-13 01:25:53 +01:00
case TimingType::non_seq_setup_rising:
2018-09-28 17:54:21 +02:00
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::rise(),
2018-09-28 17:54:21 +02:00
TimingRole::nonSeqSetup(), attrs);
2019-03-13 01:25:53 +01:00
case TimingType::non_seq_setup_falling:
2018-09-28 17:54:21 +02:00
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::fall(),
2018-09-28 17:54:21 +02:00
TimingRole::nonSeqSetup(), attrs);
2019-03-13 01:25:53 +01:00
case TimingType::non_seq_hold_rising:
2018-09-28 17:54:21 +02:00
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::rise(),
2018-09-28 17:54:21 +02:00
TimingRole::nonSeqHold(),
attrs);
2019-03-13 01:25:53 +01:00
case TimingType::non_seq_hold_falling:
2018-09-28 17:54:21 +02:00
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
RiseFall::fall(),
2018-09-28 17:54:21 +02:00
TimingRole::nonSeqHold(),
attrs);
2019-03-13 01:25:53 +01:00
case TimingType::min_pulse_width:
case TimingType::minimum_period:
case TimingType::nochange_high_high:
case TimingType::nochange_high_low:
case TimingType::nochange_low_high:
case TimingType::nochange_low_low:
case TimingType::retaining_time:
case TimingType::unknown:
case TimingType::min_clock_tree_path:
case TimingType::max_clock_tree_path:
return nullptr;
2018-09-28 17:54:21 +02:00
}
// Prevent warnings from lame compilers.
2019-03-13 01:25:53 +01:00
return nullptr;
2018-09-28 17:54:21 +02:00
}
TimingArcSet *
LibertyBuilder::makeCombinationalArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrsPtr attrs)
2018-09-28 17:54:21 +02:00
{
FuncExpr *func = to_port->function();
FuncExpr *enable = to_port->tristateEnable();
2018-09-28 17:54:21 +02:00
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, related_out,
TimingRole::combinational(), attrs);
TimingSense sense = attrs->timingSense();
if (sense == TimingSense::unknown) {
2018-09-28 17:54:21 +02:00
// Timing sense not specified - find it from function.
if (func && func->hasPort(from_port))
sense = func->portTimingSense(from_port);
// Check tristate enable.
else if (to_port->direction()->isAnyTristate()
&& enable
&& enable->hasPort(from_port))
sense = TimingSense::non_unate;
// Don't warn for functions that reference ff/latch/lut internal ports.
//else if (func->port() && !func->port()->direction()->isInternal())
// report_->fileWarn(172, cell->filename(), line,
// "timing sense cannot be inferred because pin function does not reference related pin %s.",
// from_port->name());
2018-09-28 17:54:21 +02:00
}
2018-09-28 17:54:21 +02:00
TimingModel *model;
2019-11-11 23:30:19 +01:00
RiseFall *to_rf;
2018-09-28 17:54:21 +02:00
switch (sense) {
2019-03-13 01:25:53 +01:00
case TimingSense::positive_unate:
2018-09-28 17:54:21 +02:00
if (to_rise) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::rise();
model = attrs->model(to_rf);
2018-12-05 23:18:41 +01:00
if (model)
2019-11-11 23:30:19 +01:00
makeTimingArc(arc_set, RiseFall::rise(), to_rf, model);
2018-09-28 17:54:21 +02:00
}
if (to_fall) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::fall();
model = attrs->model(to_rf);
2018-12-05 23:18:41 +01:00
if (model)
2019-11-11 23:30:19 +01:00
makeTimingArc(arc_set, RiseFall::fall(), to_rf, model);
2018-09-28 17:54:21 +02:00
}
break;
2019-03-13 01:25:53 +01:00
case TimingSense::negative_unate:
2018-09-28 17:54:21 +02:00
if (to_fall) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::fall();
model = attrs->model(to_rf);
2018-12-05 23:18:41 +01:00
if (model)
2019-11-11 23:30:19 +01:00
makeTimingArc(arc_set, RiseFall::rise(), to_rf, model);
2018-09-28 17:54:21 +02:00
}
if (to_rise) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::rise();
model = attrs->model(to_rf);
2018-12-05 23:18:41 +01:00
if (model)
2019-11-11 23:30:19 +01:00
makeTimingArc(arc_set, RiseFall::fall(), to_rf, model);
2018-09-28 17:54:21 +02:00
}
break;
2019-03-13 01:25:53 +01:00
case TimingSense::non_unate:
case TimingSense::unknown:
case TimingSense::none:
2018-09-28 17:54:21 +02:00
if (to_fall) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::fall();
model = attrs->model(to_rf);
2018-09-28 17:54:21 +02:00
if (model) {
2019-11-11 23:30:19 +01:00
makeTimingArc(arc_set, RiseFall::fall(), to_rf, model);
makeTimingArc(arc_set, RiseFall::rise(), to_rf, model);
2018-09-28 17:54:21 +02:00
}
}
if (to_rise) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::rise();
model = attrs->model(to_rf);
2018-09-28 17:54:21 +02:00
if (model) {
2019-11-11 23:30:19 +01:00
makeTimingArc(arc_set, RiseFall::rise(), to_rf, model);
makeTimingArc(arc_set, RiseFall::fall(), to_rf, model);
2018-09-28 17:54:21 +02:00
}
}
break;
}
return arc_set;
}
TimingArcSet *
LibertyBuilder::makeLatchDtoQArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
TimingSense sense,
2018-09-28 17:54:21 +02:00
LibertyPort *related_out,
TimingArcAttrsPtr attrs)
2018-09-28 17:54:21 +02:00
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
related_out,
TimingRole::latchDtoQ(), attrs);
TimingModel *model;
2019-11-11 23:30:19 +01:00
RiseFall *to_rf = RiseFall::rise();
model = attrs->model(to_rf);
2018-09-28 17:54:21 +02:00
if (model) {
2019-11-11 23:30:19 +01:00
RiseFall *from_rf = (sense == TimingSense::negative_unate) ?
to_rf->opposite() : to_rf;
makeTimingArc(arc_set, from_rf, to_rf, model);
2018-09-28 17:54:21 +02:00
}
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::fall();
model = attrs->model(to_rf);
2018-09-28 17:54:21 +02:00
if (model) {
2019-11-11 23:30:19 +01:00
RiseFall *from_rf = (sense == TimingSense::negative_unate) ?
to_rf->opposite() : to_rf;
makeTimingArc(arc_set, from_rf, to_rf, model);
2018-09-28 17:54:21 +02:00
}
return arc_set;
}
TimingArcSet *
LibertyBuilder::makeRegLatchArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
2019-11-11 23:30:19 +01:00
RiseFall *from_rf,
TimingArcAttrsPtr attrs)
2018-09-28 17:54:21 +02:00
{
FuncExpr *to_func = to_port->function();
FuncExprPortIterator port_iter(to_func);
while (port_iter.hasNext()) {
LibertyPort *func_port = port_iter.next();
Sequential *seq = cell->outputPortSequential(func_port);
if (seq) {
if (seq->clock() && seq->clock()->hasPort(from_port)) {
TimingRole *role = seq->isRegister() ?
TimingRole::regClkToQ() : TimingRole::latchEnToQ();
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
from_rf, role, attrs);
2018-09-28 17:54:21 +02:00
}
else if (seq->isLatch()
&& seq->data()
&& seq->data()->hasPort(from_port))
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
from_rf, TimingRole::latchDtoQ(), attrs);
2018-09-28 17:54:21 +02:00
else if ((seq->clear() && seq->clear()->hasPort(from_port))
|| (seq->preset() && seq->preset()->hasPort(from_port)))
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
from_rf, TimingRole::regSetClr(), attrs);
2018-09-28 17:54:21 +02:00
}
}
// No associated ff/latch - assume register clk->q.
cell->setHasInferedRegTimingArcs(true);
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
2019-11-11 23:30:19 +01:00
from_rf, TimingRole::regClkToQ(), attrs);
2018-09-28 17:54:21 +02:00
}
TimingArcSet *
LibertyBuilder::makeFromTransitionArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
2019-11-11 23:30:19 +01:00
RiseFall *from_rf,
2018-09-28 17:54:21 +02:00
TimingRole *role,
TimingArcAttrsPtr attrs)
2018-09-28 17:54:21 +02:00
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
related_out, role, attrs);
for (auto to_rf : RiseFall::range()) {
TimingModel *model = attrs->model(to_rf);
if (model)
makeTimingArc(arc_set, from_rf, to_rf, model);
}
2018-09-28 17:54:21 +02:00
return arc_set;
}
TimingArcSet *
LibertyBuilder::makePresetClrArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
2019-11-11 23:30:19 +01:00
RiseFall *to_rf,
TimingArcAttrsPtr attrs)
2018-09-28 17:54:21 +02:00
{
2019-03-13 01:25:53 +01:00
TimingArcSet *arc_set = nullptr;
2019-11-11 23:30:19 +01:00
TimingModel *model = attrs->model(to_rf);
2018-09-28 17:54:21 +02:00
if (model) {
arc_set = makeTimingArcSet(cell, from_port, to_port, related_out,
TimingRole::regSetClr(), attrs);
2019-11-11 23:30:19 +01:00
RiseFall *opp_rf = to_rf->opposite();
2018-09-28 17:54:21 +02:00
switch (attrs->timingSense()) {
2019-03-13 01:25:53 +01:00
case TimingSense::positive_unate:
2019-11-11 23:30:19 +01:00
makeTimingArc(arc_set, to_rf, to_rf, model);
2018-09-28 17:54:21 +02:00
break;
2019-03-13 01:25:53 +01:00
case TimingSense::negative_unate:
2019-11-11 23:30:19 +01:00
makeTimingArc(arc_set, opp_rf, to_rf, model);
2018-09-28 17:54:21 +02:00
break;
2019-03-13 01:25:53 +01:00
case TimingSense::non_unate:
case TimingSense::unknown:
2019-11-11 23:30:19 +01:00
makeTimingArc(arc_set, to_rf, to_rf, model);
makeTimingArc(arc_set, opp_rf, to_rf, model);
2018-09-28 17:54:21 +02:00
break;
2019-03-13 01:25:53 +01:00
case TimingSense::none:
2018-09-28 17:54:21 +02:00
break;
}
}
return arc_set;
}
// To rise/fall for Z transitions is as follows:
// 0Z, Z1 rise
// 1Z, Z0 fall
TimingArcSet *
LibertyBuilder::makeTristateEnableArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrsPtr attrs)
2018-09-28 17:54:21 +02:00
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, related_out,
TimingRole::tristateEnable(), attrs);
2018-09-28 17:54:21 +02:00
FuncExpr *tristate_enable = to_port->tristateEnable();
TimingSense sense = attrs->timingSense();
2019-03-13 01:25:53 +01:00
if (sense == TimingSense::unknown && tristate_enable)
2018-09-28 17:54:21 +02:00
sense = tristate_enable->portTimingSense(from_port);
TimingModel *model;
2019-11-11 23:30:19 +01:00
RiseFall *to_rf;
2018-09-28 17:54:21 +02:00
switch (sense) {
2019-03-13 01:25:53 +01:00
case TimingSense::positive_unate:
2018-09-28 17:54:21 +02:00
if (to_rise) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::rise();
model = attrs->model(to_rf);
2018-12-05 23:18:41 +01:00
if (model)
2018-09-28 17:54:21 +02:00
makeTimingArc(arc_set, Transition::rise(), Transition::trZ1(), model);
}
if (to_fall) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::fall();
model = attrs->model(to_rf);
2018-12-05 23:18:41 +01:00
if (model)
2018-09-28 17:54:21 +02:00
makeTimingArc(arc_set, Transition::rise(), Transition::trZ0(), model);
}
break;
2019-03-13 01:25:53 +01:00
case TimingSense::negative_unate:
2018-09-28 17:54:21 +02:00
if (to_rise) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::rise();
model = attrs->model(to_rf);
2018-12-05 23:18:41 +01:00
if (model)
2018-09-28 17:54:21 +02:00
makeTimingArc(arc_set, Transition::fall(), Transition::trZ1(), model);
}
if (to_fall) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::fall();
model = attrs->model(to_rf);
2018-12-05 23:18:41 +01:00
if (model)
2018-09-28 17:54:21 +02:00
makeTimingArc(arc_set, Transition::fall(), Transition::trZ0(), model);
}
break;
2019-03-13 01:25:53 +01:00
case TimingSense::non_unate:
case TimingSense::unknown:
2018-09-28 17:54:21 +02:00
if (to_rise) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::rise();
model = attrs->model(to_rf);
2018-09-28 17:54:21 +02:00
if (model) {
makeTimingArc(arc_set, Transition::rise(), Transition::trZ1(), model);
makeTimingArc(arc_set, Transition::fall(), Transition::trZ1(), model);
}
}
if (to_fall) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::fall();
model = attrs->model(to_rf);
2018-09-28 17:54:21 +02:00
if (model) {
makeTimingArc(arc_set, Transition::rise(), Transition::trZ0(), model);
makeTimingArc(arc_set, Transition::fall(), Transition::trZ0(), model);
}
}
break;
2019-03-13 01:25:53 +01:00
case TimingSense::none:
2018-09-28 17:54:21 +02:00
break;
}
return arc_set;
}
TimingArcSet *
LibertyBuilder::makeTristateDisableArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrsPtr attrs)
2018-09-28 17:54:21 +02:00
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
related_out,
TimingRole::tristateDisable(),
attrs);
TimingSense sense = attrs->timingSense();
FuncExpr *tristate_enable = to_port->tristateEnable();
2019-03-13 01:25:53 +01:00
if (sense == TimingSense::unknown && tristate_enable)
2018-09-28 17:54:21 +02:00
sense = timingSenseOpposite(tristate_enable->portTimingSense(from_port));
TimingModel *model;
2019-11-11 23:30:19 +01:00
RiseFall *to_rf;
2018-09-28 17:54:21 +02:00
switch (sense) {
2019-03-13 01:25:53 +01:00
case TimingSense::positive_unate:
2018-09-28 17:54:21 +02:00
if (to_rise) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::rise();
model = attrs->model(to_rf);
2018-12-05 23:18:41 +01:00
if (model)
2018-09-28 17:54:21 +02:00
makeTimingArc(arc_set, Transition::rise(), Transition::tr0Z(), model);
}
if (to_fall) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::fall();
model = attrs->model(to_rf);
2018-12-05 23:18:41 +01:00
if (model)
2018-09-28 17:54:21 +02:00
makeTimingArc(arc_set, Transition::rise(), Transition::tr1Z(), model);
}
break;
2019-03-13 01:25:53 +01:00
case TimingSense::negative_unate:
2018-09-28 17:54:21 +02:00
if (to_rise) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::rise();
model = attrs->model(to_rf);
2018-12-05 23:18:41 +01:00
if (model)
2018-09-28 17:54:21 +02:00
makeTimingArc(arc_set, Transition::fall(), Transition::tr0Z(), model);
}
if (to_fall) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::fall();
model = attrs->model(to_rf);
2018-12-05 23:18:41 +01:00
if (model)
2018-09-28 17:54:21 +02:00
makeTimingArc(arc_set, Transition::fall(), Transition::tr1Z(), model);
}
break;
2019-03-13 01:25:53 +01:00
case TimingSense::non_unate:
case TimingSense::unknown:
2018-09-28 17:54:21 +02:00
if (to_rise) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::rise();
model = attrs->model(to_rf);
2018-09-28 17:54:21 +02:00
if (model) {
makeTimingArc(arc_set, Transition::fall(), Transition::tr0Z(), model);
makeTimingArc(arc_set, Transition::rise(), Transition::tr0Z(), model);
}
}
if (to_fall) {
2019-11-11 23:30:19 +01:00
to_rf = RiseFall::fall();
model = attrs->model(to_rf);
2018-09-28 17:54:21 +02:00
if (model) {
makeTimingArc(arc_set, Transition::fall(), Transition::tr1Z(), model);
makeTimingArc(arc_set, Transition::rise(), Transition::tr1Z(), model);
}
}
break;
2019-03-13 01:25:53 +01:00
case TimingSense::none:
2018-09-28 17:54:21 +02:00
break;
}
return arc_set;
}
TimingArcSet *
LibertyBuilder::makeTimingArcSet(LibertyCell *cell,
LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out,
TimingRole *role,
TimingArcAttrsPtr attrs)
2018-09-28 17:54:21 +02:00
{
return new TimingArcSet(cell, from, to, related_out, role, attrs);
}
TimingArc *
LibertyBuilder::makeTimingArc(TimingArcSet *set,
2019-11-11 23:30:19 +01:00
RiseFall *from_rf,
RiseFall *to_rf,
2018-09-28 17:54:21 +02:00
TimingModel *model)
{
2019-11-11 23:30:19 +01:00
return new TimingArc(set, from_rf->asTransition(),
to_rf->asTransition(), model);
2018-09-28 17:54:21 +02:00
}
TimingArc *
LibertyBuilder::makeTimingArc(TimingArcSet *set,
2019-11-11 23:30:19 +01:00
Transition *from_rf,
Transition *to_rf,
2018-09-28 17:54:21 +02:00
TimingModel *model)
{
2019-11-11 23:30:19 +01:00
return new TimingArc(set, from_rf, to_rf, model);
2018-09-28 17:54:21 +02:00
}
////////////////////////////////////////////////////////////////
InternalPower *
LibertyBuilder::makeInternalPower(LibertyCell *cell,
LibertyPort *port,
LibertyPort *related_port,
InternalPowerAttrs *attrs)
{
return new InternalPower(cell, port, related_port, attrs);
}
LeakagePower *
LibertyBuilder::makeLeakagePower(LibertyCell *cell,
LeakagePowerAttrs *attrs)
{
return new LeakagePower(cell, attrs);
}
} // namespace