latch en=1 tags
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
d8c0e9285b
commit
12c811a492
|
|
@ -323,6 +323,10 @@ Latches::latchOutArrival(const Path *data_path,
|
||||||
ArcDelay &arc_delay,
|
ArcDelay &arc_delay,
|
||||||
Arrival &q_arrival)
|
Arrival &q_arrival)
|
||||||
{
|
{
|
||||||
|
q_tag = nullptr;
|
||||||
|
arc_delay = 0.0;
|
||||||
|
q_arrival = 0.0;
|
||||||
|
|
||||||
Scene *scene = data_path->scene(this);
|
Scene *scene = data_path->scene(this);
|
||||||
Sdc *sdc = scene->sdc();
|
Sdc *sdc = scene->sdc();
|
||||||
const Mode *mode = scene->mode();
|
const Mode *mode = scene->mode();
|
||||||
|
|
@ -337,83 +341,110 @@ Latches::latchOutArrival(const Path *data_path,
|
||||||
// Latch enable may be missing if library is malformed.
|
// Latch enable may be missing if library is malformed.
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case LatchEnableState::closed:
|
case LatchEnableState::closed:
|
||||||
// Latch is disabled by constant enable.
|
// Latch is always closed because enable is constant.
|
||||||
break;
|
break;
|
||||||
case LatchEnableState::open: {
|
case LatchEnableState::open: {
|
||||||
|
// Latch is always open because enable is constant.
|
||||||
ExceptionPath *excpt = exceptionTo(data_path, nullptr);
|
ExceptionPath *excpt = exceptionTo(data_path, nullptr);
|
||||||
if (!(excpt && excpt->isFalse())) {
|
if (!(excpt && excpt->isFalse())) {
|
||||||
arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge,
|
arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge,
|
||||||
false, min_max, dcalc_ap, sdc);
|
false, min_max, dcalc_ap, sdc);
|
||||||
q_arrival = data_path->arrival() + arc_delay;
|
q_arrival = data_path->arrival() + arc_delay;
|
||||||
q_tag = data_path->tag(this);
|
// Copy the data tag but remove the drprClkPath.
|
||||||
|
// Levelization does not traverse latch D->Q edges, so in some cases
|
||||||
|
// level(Q) < level(D)
|
||||||
|
// Note that
|
||||||
|
// level(crprClkPath(data)) < level(D)
|
||||||
|
// The danger is that
|
||||||
|
// level(crprClkPath(data)) == level(Q)
|
||||||
|
// or some other downstream vertex.
|
||||||
|
// This can lead to data races when finding arrivals at the same level
|
||||||
|
// use multiple threads.
|
||||||
|
// Kill the crprClklPath to be safe.
|
||||||
|
const ClkInfo *data_clk_info = data_path->clkInfo(this);
|
||||||
|
const ClkInfo *q_clk_info =
|
||||||
|
search_->findClkInfo(scene,
|
||||||
|
data_clk_info->clkEdge(),
|
||||||
|
data_clk_info->clkSrc(),
|
||||||
|
data_clk_info->isPropagated(),
|
||||||
|
data_clk_info->genClkSrc(),
|
||||||
|
data_clk_info->isGenClkSrcPath(),
|
||||||
|
data_clk_info->pulseClkSense(),
|
||||||
|
data_clk_info->insertion(),
|
||||||
|
data_clk_info->latency(),
|
||||||
|
data_clk_info->uncertainties(),
|
||||||
|
min_max, nullptr);
|
||||||
|
q_tag = search_->findTag(scene, d_q_arc->toEdge()->asRiseFall(),
|
||||||
|
min_max, q_clk_info, false,
|
||||||
|
nullptr, false, data_path->tag(this)->states(),
|
||||||
|
false, nullptr);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case LatchEnableState::enabled: {
|
case LatchEnableState::enabled: {
|
||||||
const MinMax *tgt_min_max = data_path->tgtClkMinMax(this);
|
const MinMax *tgt_min_max = data_path->tgtClkMinMax(this);
|
||||||
VertexPathIterator enable_iter(enable_vertex, scene, tgt_min_max,
|
VertexPathIterator enable_iter(enable_vertex, scene, tgt_min_max,
|
||||||
enable_rf, this);
|
enable_rf, this);
|
||||||
while (enable_iter.hasNext()) {
|
while (enable_iter.hasNext()) {
|
||||||
Path *enable_path = enable_iter.next();
|
Path *enable_path = enable_iter.next();
|
||||||
const ClkInfo *en_clk_info = enable_path->clkInfo(this);
|
const ClkInfo *en_clk_info = enable_path->clkInfo(this);
|
||||||
const ClockEdge *en_clk_edge = en_clk_info->clkEdge();
|
const ClockEdge *en_clk_edge = en_clk_info->clkEdge();
|
||||||
if (enable_path->isClock(this)) {
|
if (enable_path->isClock(this)) {
|
||||||
ExceptionPath *excpt = exceptionTo(data_path, en_clk_edge);
|
ExceptionPath *excpt = exceptionTo(data_path, en_clk_edge);
|
||||||
// D->Q is disabled when if there is a path delay -to D or EN clk.
|
// D->Q is disabled when if there is a path delay -to D or EN clk.
|
||||||
if (!(excpt && (excpt->isFalse()
|
if (!(excpt && (excpt->isFalse()
|
||||||
|| excpt->isPathDelay()))) {
|
|| excpt->isPathDelay()))) {
|
||||||
Path *disable_path = latchEnableOtherPath(enable_path);
|
Path *disable_path = latchEnableOtherPath(enable_path);
|
||||||
Delay borrow, time_given_to_startpoint;
|
Delay borrow, time_given_to_startpoint;
|
||||||
Arrival adjusted_data_arrival;
|
Arrival adjusted_data_arrival;
|
||||||
Required required;
|
Required required;
|
||||||
latchRequired(data_path, enable_path, disable_path,
|
latchRequired(data_path, enable_path, disable_path,
|
||||||
required, borrow, adjusted_data_arrival,
|
required, borrow, adjusted_data_arrival,
|
||||||
time_given_to_startpoint);
|
time_given_to_startpoint);
|
||||||
if (delayGreater(borrow, 0.0, this)) {
|
if (delayGreater(borrow, 0.0, this)) {
|
||||||
// Latch is transparent when data arrives.
|
// Latch is transparent when data arrives.
|
||||||
arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge,
|
arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge,
|
||||||
false, min_max, dcalc_ap, sdc);
|
false, min_max, dcalc_ap, sdc);
|
||||||
q_arrival = adjusted_data_arrival + arc_delay;
|
q_arrival = adjusted_data_arrival + arc_delay;
|
||||||
// Tag switcheroo - data passing thru gets latch enable tag.
|
// Tag switcheroo - data passing thru gets latch enable tag.
|
||||||
// States and path ap come from Q, everything else from enable.
|
// States and path ap come from Q, everything else from enable.
|
||||||
Path *crpr_clk_path = crprActive(mode) ? enable_path : nullptr;
|
Path *crpr_clk_path = crprActive(mode) ? enable_path : nullptr;
|
||||||
const ClkInfo *q_clk_info =
|
const ClkInfo *q_clk_info =
|
||||||
search_->findClkInfo(en_clk_info->scene(),
|
search_->findClkInfo(scene,
|
||||||
en_clk_edge,
|
en_clk_edge,
|
||||||
en_clk_info->clkSrc(),
|
en_clk_info->clkSrc(),
|
||||||
en_clk_info->isPropagated(),
|
en_clk_info->isPropagated(),
|
||||||
en_clk_info->genClkSrc(),
|
en_clk_info->genClkSrc(),
|
||||||
en_clk_info->isGenClkSrcPath(),
|
en_clk_info->isGenClkSrcPath(),
|
||||||
en_clk_info->pulseClkSense(),
|
en_clk_info->pulseClkSense(),
|
||||||
en_clk_info->insertion(),
|
en_clk_info->insertion(),
|
||||||
en_clk_info->latency(),
|
en_clk_info->latency(),
|
||||||
en_clk_info->uncertainties(),
|
en_clk_info->uncertainties(),
|
||||||
min_max, crpr_clk_path);
|
min_max, crpr_clk_path);
|
||||||
const RiseFall *q_rf = d_q_arc->toEdge()->asRiseFall();
|
ExceptionStateSet *states = nullptr;
|
||||||
ExceptionStateSet *states = nullptr;
|
// Latch data pin is a valid exception -from pin.
|
||||||
// Latch data pin is a valid exception -from pin.
|
if (sdc->exceptionFromStates(data_path->pin(this),
|
||||||
if (sdc->exceptionFromStates(data_path->pin(this),
|
data_path->transition(this),
|
||||||
data_path->transition(this),
|
nullptr, nullptr, // clk below
|
||||||
nullptr, nullptr, // clk below
|
MinMax::max(), states)
|
||||||
MinMax::max(), states)
|
// -from enable non-filter exceptions apply.
|
||||||
// -from enable non-filter exceptions apply.
|
&& sdc->exceptionFromStates(enable_vertex->pin(),
|
||||||
&& sdc->exceptionFromStates(enable_vertex->pin(),
|
enable_rf,
|
||||||
enable_rf,
|
en_clk_edge->clock(),
|
||||||
en_clk_edge->clock(),
|
en_clk_edge->transition(),
|
||||||
en_clk_edge->transition(),
|
MinMax::max(), false, states))
|
||||||
MinMax::max(), false, states))
|
q_tag = search_->findTag(scene, d_q_arc->toEdge()->asRiseFall(),
|
||||||
q_tag = search_->findTag(enable_path->tag(this)->scene(),
|
MinMax::max(), q_clk_info, false,
|
||||||
q_rf, MinMax::max(), q_clk_info, false,
|
nullptr, false, states, true, nullptr);
|
||||||
nullptr, false, states, true, nullptr);
|
}
|
||||||
}
|
return;
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// No enable path found.
|
// No enable path found.
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExceptionPath *
|
ExceptionPath *
|
||||||
|
|
|
||||||
|
|
@ -3654,7 +3654,7 @@ RequiredVisitor::visitFromToPath(const Pin *,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
// Don't propagate required times through latch D->Q edges.
|
// Don't propagate required times through latch D->Q edges.
|
||||||
if (edge->role() != TimingRole::latchDtoQ()) {
|
if (!edge->role()->isLatchDtoQ()) {
|
||||||
debugPrint(debug_, "search", 3, " %s -> %s %s",
|
debugPrint(debug_, "search", 3, " %s -> %s %s",
|
||||||
from_rf->shortName(),
|
from_rf->shortName(),
|
||||||
to_rf->shortName(),
|
to_rf->shortName(),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue