Merge remote-tracking branch 'upstream/master' into sta_latest_0609
This commit is contained in:
commit
7aeca8c193
|
|
@ -1,15 +1,22 @@
|
|||
---
|
||||
description: C++ coding standards and formatting for OpenSTA
|
||||
globs: ["**/*.cc", "**/*.hh", "**/*.h"]
|
||||
alwaysApply: false
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# C++ Coding Standards
|
||||
|
||||
## File-internal helpers (translation-unit local)
|
||||
|
||||
- For helpers used only in one `.cc` file, put them in the **same namespace** as the rest of the implementation (e.g. `namespace sta { ... }`).
|
||||
- Mark them **`static`** at namespace scope so they have internal linkage.
|
||||
- **Do not** wrap them in an **anonymous namespace** in this project (no `namespace { ... }` file-static helpers). The user preference is `static` inside the real namespace, not a nested anonymous namespace inside `sta` or at file scope before `sta`.
|
||||
|
||||
## Line Width
|
||||
|
||||
- **Keep lines under 90 characters** to match `.clang-format` (ColumnLimit: 90).
|
||||
- Break long lines at logical points: after commas, before operators, after opening parens.
|
||||
- Only break a line when it would exceed 90 characters. Do not introduce unnecessary line breaks when the expression fits on one line.
|
||||
- When a break is needed, break at logical points: after commas, before operators. Keep the first argument on the same line as the opening paren (do not break immediately after an opening paren).
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
FROM ubuntu:24.04
|
||||
LABEL author="James Cherry"
|
||||
LABEL maintainer="James Cherry <cherry@parallaxsw.com>"
|
||||
|
||||
# Install basics
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && \
|
||||
apt-get install -y \
|
||||
git \
|
||||
wget \
|
||||
cmake \
|
||||
gcc \
|
||||
gdb \
|
||||
tcl-dev \
|
||||
tcl-tclreadline \
|
||||
swig \
|
||||
bison \
|
||||
flex \
|
||||
automake \
|
||||
autotools-dev \
|
||||
libeigen3-dev \
|
||||
libfmt-dev
|
||||
|
||||
# Download CUDD
|
||||
RUN wget https://raw.githubusercontent.com/davidkebo/cudd/main/cudd_versions/cudd-3.0.0.tar.gz && \
|
||||
tar -xvf cudd-3.0.0.tar.gz && \
|
||||
rm cudd-3.0.0.tar.gz
|
||||
|
||||
# Build CUDD
|
||||
RUN cd cudd-3.0.0 && \
|
||||
mkdir ../cudd && \
|
||||
./configure && \
|
||||
make -j`nproc`
|
||||
|
||||
# Copy files and install OpenSTA
|
||||
RUN mkdir OpenSTA
|
||||
COPY . OpenSTA
|
||||
RUN cd OpenSTA && \
|
||||
rm -rf build && \
|
||||
mkdir build && \
|
||||
cd build && \
|
||||
cmake -DCUDD_DIR=../cudd-3.0.0 .. && \
|
||||
make -j`nproc`
|
||||
|
||||
# Run sta on entry
|
||||
ENTRYPOINT ["OpenSTA/build/sta"]
|
||||
|
|
@ -194,7 +194,7 @@ following command builds a Docker image.
|
|||
|
||||
```
|
||||
cd OpenSTA
|
||||
docker build --file Dockerfile.ubuntu22.04 --tag opensta_ubuntu22.04 .
|
||||
docker build --file Dockerfile.ubuntu24.04 --tag opensta_ubuntu24.04 .
|
||||
or
|
||||
docker build --file Dockerfile.centos7 --tag opensta_centos7 .
|
||||
```
|
||||
|
|
|
|||
|
|
@ -29,14 +29,14 @@ set(TCL_POSSIBLE_NAMES
|
|||
tcl85 tcl8.5
|
||||
)
|
||||
|
||||
# tcl lib path guesses.
|
||||
# TCL lib path guesses.
|
||||
if (NOT TCL_LIB_PATHS)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
file(GLOB tcl_homebrew_libs
|
||||
/opt/homebrew/Cellar/tcl-tk@8/*/lib
|
||||
)
|
||||
set(TCL_LIB_PATHS
|
||||
#/opt/homebrew/Cellar/tcl-tk/9.0.3/lib
|
||||
/opt/homebrew/Cellar/tcl-tk@8/8.6.18/lib
|
||||
/opt/homebrew/Cellar/tcl-tk@8/8.6.17/lib
|
||||
/opt/homebrew/Cellar/tcl-tk@8/8.6.16/lib
|
||||
${tcl_homebrew_libs}
|
||||
/opt/homebrew/opt/tcl-tk/lib /usr/local/lib)
|
||||
set(TCL_NO_DEFAULT_PATH TRUE)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
// Author Phillip Johnston
|
||||
// Original Author: Phillip Johnston
|
||||
// Licensed under CC0 1.0 Universal
|
||||
// https://github.com/embeddedartistry/embedded-resources/blob/master/examples/cpp/dispatch.cpp
|
||||
// https://embeddedartistry.com/blog/2017/2/1/dispatch-queues?rq=dispatch
|
||||
// Original source: https://github.com/embeddedartistry/embedded-resources/blob/master/examples/cpp/dispatch.cpp
|
||||
// Original article: https://embeddedartistry.com/blog/2017/2/1/dispatch-queues?rq=dispatch
|
||||
//
|
||||
// Modified for OpenSTA to use C++20 non-spinning DynamicLatch for synchronization.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <condition_variable>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
|
@ -16,6 +19,49 @@
|
|||
|
||||
namespace sta {
|
||||
|
||||
class DynamicLatch
|
||||
{
|
||||
public:
|
||||
explicit DynamicLatch(std::ptrdiff_t initial_count = 0) :
|
||||
count_(initial_count)
|
||||
{
|
||||
}
|
||||
|
||||
// Delete copy/move constructors to prevent accidental slicing/copying of atomics
|
||||
DynamicLatch(const DynamicLatch&) = delete;
|
||||
DynamicLatch& operator=(const DynamicLatch&) = delete;
|
||||
|
||||
// Increases the latch count (used when a new task is dispatched)
|
||||
void
|
||||
countUp()
|
||||
{
|
||||
count_.fetch_add(1, std::memory_order_release);
|
||||
}
|
||||
|
||||
// Decreases the latch count and wakes waiting threads if it hits zero
|
||||
void
|
||||
countDown(std::ptrdiff_t n = 1)
|
||||
{
|
||||
if (count_.fetch_sub(n, std::memory_order_release) == n) {
|
||||
count_.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
// Blocks until the count reaches zero
|
||||
void
|
||||
wait() const
|
||||
{
|
||||
std::ptrdiff_t current = count_.load(std::memory_order_acquire);
|
||||
while (current != 0) {
|
||||
count_.wait(current, std::memory_order_acquire);
|
||||
current = count_.load(std::memory_order_acquire);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::atomic<std::ptrdiff_t> count_{0};
|
||||
};
|
||||
|
||||
class DispatchQueue
|
||||
{
|
||||
using fp_t = std::function<void(int thread)>;
|
||||
|
|
@ -45,7 +91,7 @@ private:
|
|||
std::vector<std::thread> threads_;
|
||||
std::queue<fp_t> q_;
|
||||
std::condition_variable cv_;
|
||||
std::atomic<size_t> pending_task_count_;
|
||||
DynamicLatch pending_task_count_latch_;
|
||||
bool quit_ = false;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -502,6 +502,8 @@ class NetworkEdit : public Network
|
|||
public:
|
||||
NetworkEdit() = default;
|
||||
bool isEditable() const override { return true; }
|
||||
virtual Port *makePort(Cell *cell,
|
||||
std::string_view name) = 0;
|
||||
virtual Instance *makeInstance(LibertyCell *cell,
|
||||
std::string_view name,
|
||||
Instance *parent) = 0;
|
||||
|
|
@ -556,8 +558,6 @@ public:
|
|||
virtual void setAttribute(Instance *instance,
|
||||
std::string_view key,
|
||||
std::string_view value) = 0;
|
||||
virtual Port *makePort(Cell *cell,
|
||||
std::string_view name) = 0;
|
||||
virtual Port *makeBusPort(Cell *cell,
|
||||
std::string_view name,
|
||||
int from_index,
|
||||
|
|
|
|||
|
|
@ -94,11 +94,12 @@ parseBusName(std::string_view name,
|
|||
int &to,
|
||||
bool &subscript_wild);
|
||||
|
||||
// Insert escapes before ch1 and ch2 in token.
|
||||
// Insert escapes before ch1, ch2 or ch3 in token.
|
||||
std::string
|
||||
escapeChars(std::string_view token,
|
||||
char ch1,
|
||||
char ch2,
|
||||
char ch3,
|
||||
char escape);
|
||||
|
||||
} // namespace sta
|
||||
|
|
|
|||
|
|
@ -146,8 +146,9 @@ public:
|
|||
PathGroup *findPathGroup(const Clock *clock,
|
||||
const MinMax *min_max) const;
|
||||
PathGroupSeq pathGroups(const PathEnd *path_end) const;
|
||||
static StringSeq pathGroupNames(const PathEnd *path_end,
|
||||
const StaState *sta);
|
||||
static bool inPathGroupNamed(const PathEnd *path_end,
|
||||
std::string_view path_group_name,
|
||||
const StaState *sta);
|
||||
static std::string_view asyncPathGroupName() { return async_group_name_; }
|
||||
static std::string_view pathDelayGroupName() { return path_delay_group_name_; }
|
||||
static std::string_view gatedClkGroupName() { return gated_clk_group_name_; }
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ public:
|
|||
int index) const override;
|
||||
PortMemberIterator *memberIterator(const Port *port) const override;
|
||||
bool hasMembers(const Port *port) const override;
|
||||
Port *makePort(Cell *cell,
|
||||
std::string_view name) override;
|
||||
|
||||
ObjectId id(const Instance *instance) const override;
|
||||
std::string getAttribute(const Instance *inst,
|
||||
|
|
@ -146,6 +148,7 @@ public:
|
|||
char pathEscape() const override;
|
||||
void setPathEscape(char escape) override;
|
||||
|
||||
// NetworkEdit
|
||||
bool isEditable() const override;
|
||||
LibertyLibrary *makeLibertyLibrary(std::string_view name,
|
||||
std::string_view filename) override;
|
||||
|
|
@ -202,6 +205,8 @@ public:
|
|||
const PatternMatch *pattern) const override;
|
||||
std::string name(const Port *port) const override;
|
||||
std::string busName(const Port *port) const override;
|
||||
Port *makePort(Cell *cell,
|
||||
std::string_view name) override;
|
||||
|
||||
std::string name(const Instance *instance) const override;
|
||||
std::string pathName(const Instance *instance) const override;
|
||||
|
|
@ -289,5 +294,8 @@ escapeDividers(std::string_view name,
|
|||
std::string
|
||||
escapeBrackets(std::string_view name,
|
||||
const Network *network);
|
||||
std::string
|
||||
escapeDividerBrackets(std::string_view name,
|
||||
const Network *network);
|
||||
|
||||
} // namespace sta
|
||||
|
|
|
|||
|
|
@ -363,7 +363,8 @@ public:
|
|||
TagGroup *tagGroup(const Vertex *vertex) const;
|
||||
TagGroup *tagGroup(TagGroupIndex index) const;
|
||||
void reportArrivals(Vertex *vertex,
|
||||
bool report_tag_index) const;
|
||||
bool report_tag_index,
|
||||
int digits) const;
|
||||
Slack wnsSlack(Vertex *vertex,
|
||||
PathAPIndex path_ap_index);
|
||||
void levelsChangedBefore();
|
||||
|
|
|
|||
|
|
@ -3081,7 +3081,8 @@ libertyReaderFindPort(const LibertyCell *cell,
|
|||
char brkt_right = library->busBrktRight();
|
||||
const char escape = '\\';
|
||||
// Pins at top level with bus names have escaped brackets.
|
||||
std::string escaped_port_name = escapeChars(port_name, brkt_left, brkt_right, escape);
|
||||
std::string escaped_port_name = escapeChars(port_name, brkt_left, brkt_right,
|
||||
'\0', escape);
|
||||
port = cell->findLibertyPort(escaped_port_name);
|
||||
}
|
||||
return port;
|
||||
|
|
|
|||
|
|
@ -167,9 +167,10 @@ parseBusName(std::string_view name,
|
|||
|
||||
std::string
|
||||
escapeChars(std::string_view token,
|
||||
const char ch1,
|
||||
const char ch2,
|
||||
const char escape)
|
||||
char ch1,
|
||||
char ch2,
|
||||
char ch3,
|
||||
char escape)
|
||||
{
|
||||
std::string escaped;
|
||||
escaped.reserve(token.size());
|
||||
|
|
@ -184,7 +185,7 @@ escapeChars(std::string_view token,
|
|||
else
|
||||
escaped += ch;
|
||||
}
|
||||
else if (ch == ch1 || ch == ch2) {
|
||||
else if (ch == ch1 || ch == ch2 || ch == ch3) {
|
||||
escaped += escape;
|
||||
escaped += ch;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -330,6 +330,13 @@ NetworkNameAdapter::memberIterator(const Port *port) const
|
|||
return network_->memberIterator(port);
|
||||
}
|
||||
|
||||
Port *
|
||||
NetworkNameAdapter::makePort(Cell *cell,
|
||||
std::string_view name)
|
||||
{
|
||||
return network_edit_->makePort(cell, name);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
ObjectId
|
||||
|
|
@ -736,6 +743,14 @@ SdcNetwork::busName(const Port *port) const
|
|||
return staToSdc(network_->busName(port));
|
||||
}
|
||||
|
||||
Port *
|
||||
SdcNetwork::makePort(Cell *cell,
|
||||
std::string_view name)
|
||||
{
|
||||
std::string escaped_name = escapeDividerBrackets(name, network_edit_);
|
||||
return network_edit_->makePort(cell, escaped_name);
|
||||
}
|
||||
|
||||
std::string
|
||||
SdcNetwork::name(const Instance *instance) const
|
||||
{
|
||||
|
|
@ -1073,7 +1088,7 @@ SdcNetwork::makeInstance(LibertyCell *cell,
|
|||
std::string_view name,
|
||||
Instance *parent)
|
||||
{
|
||||
std::string escaped_name = escapeDividers(std::string(name), this);
|
||||
std::string escaped_name = escapeDividerBrackets(name, this);
|
||||
return network_edit_->makeInstance(cell, escaped_name, parent);
|
||||
}
|
||||
|
||||
|
|
@ -1081,7 +1096,7 @@ Net *
|
|||
SdcNetwork::makeNet(std::string_view name,
|
||||
Instance *parent)
|
||||
{
|
||||
std::string escaped_name = escapeDividers(std::string(name), this);
|
||||
std::string escaped_name = escapeDividerBrackets(name, this);
|
||||
return network_edit_->makeNet(escaped_name, parent);
|
||||
}
|
||||
|
||||
|
|
@ -1254,11 +1269,19 @@ SdcNetwork::visitMatches(const Instance *parent,
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string
|
||||
escapeDividerBrackets(std::string_view name,
|
||||
const Network *network)
|
||||
{
|
||||
return escapeChars(name, network->pathDivider(), '[', ']',
|
||||
network->pathEscape());
|
||||
}
|
||||
|
||||
std::string
|
||||
escapeDividers(std::string_view name,
|
||||
const Network *network)
|
||||
{
|
||||
return escapeChars(name, network->pathDivider(), '\0',
|
||||
return escapeChars(name, network->pathDivider(), '\0', '\0',
|
||||
network->pathEscape());
|
||||
}
|
||||
|
||||
|
|
@ -1266,7 +1289,7 @@ std::string
|
|||
escapeBrackets(std::string_view name,
|
||||
const Network *network)
|
||||
{
|
||||
return escapeChars(name, '[', ']', network->pathEscape());
|
||||
return escapeChars(name, '[', ']', '\0', network->pathEscape());
|
||||
}
|
||||
|
||||
} // namespace sta
|
||||
|
|
|
|||
|
|
@ -474,23 +474,23 @@ PathGroups::pathGroups(const PathEnd *path_end) const
|
|||
}
|
||||
|
||||
// Mirrors PathGroups::pathGroup.
|
||||
StringSeq
|
||||
PathGroups::pathGroupNames(const PathEnd *path_end,
|
||||
const StaState *sta)
|
||||
bool
|
||||
PathGroups::inPathGroupNamed(const PathEnd *path_end,
|
||||
std::string_view path_group_name,
|
||||
const StaState *sta)
|
||||
{
|
||||
StringSeq group_names;
|
||||
std::string group_name;
|
||||
const Search *search = sta->search();
|
||||
ExceptionPathSeq group_paths = search->groupPathsTo(path_end);
|
||||
if (path_end->isUnconstrained())
|
||||
group_name = unconstrained_group_name_;
|
||||
return path_group_name == unconstrained_group_name_;
|
||||
else if (!group_paths.empty()) {
|
||||
// GroupPaths have precedence.
|
||||
for (ExceptionPath *group_path : group_paths) {
|
||||
if (group_path->isDefault())
|
||||
group_names.emplace_back(path_delay_group_name_);
|
||||
else
|
||||
group_names.emplace_back(group_path->name());
|
||||
std::string_view group_name = group_path->isDefault()
|
||||
? path_delay_group_name_
|
||||
: group_path->name();
|
||||
if (path_group_name == group_name)
|
||||
return true;;
|
||||
}
|
||||
}
|
||||
else if (path_end->isCheck() || path_end->isLatchCheck()) {
|
||||
|
|
@ -498,18 +498,18 @@ PathGroups::pathGroupNames(const PathEnd *path_end,
|
|||
const Clock *tgt_clk = path_end->targetClk(sta);
|
||||
if (check_role == TimingRole::removal()
|
||||
|| check_role == TimingRole::recovery())
|
||||
group_name = async_group_name_;
|
||||
return path_group_name == async_group_name_;
|
||||
else
|
||||
group_name = tgt_clk->name();
|
||||
return path_group_name == tgt_clk->name();
|
||||
}
|
||||
else if (path_end->isOutputDelay()
|
||||
|| path_end->isDataCheck()) {
|
||||
const Clock *tgt_clk = path_end->targetClk(sta);
|
||||
if (tgt_clk)
|
||||
group_name = tgt_clk->name();
|
||||
return path_group_name == tgt_clk->name();
|
||||
}
|
||||
else if (path_end->isGatedClock())
|
||||
group_name = gated_clk_group_name_;
|
||||
return path_group_name == gated_clk_group_name_;
|
||||
else if (path_end->isPathDelay()) {
|
||||
// Path delays that end at timing checks are part of the target clk group
|
||||
// unless -ignore_clock_latency is true.
|
||||
|
|
@ -517,13 +517,11 @@ PathGroups::pathGroupNames(const PathEnd *path_end,
|
|||
const Clock *tgt_clk = path_end->targetClk(sta);
|
||||
if (tgt_clk
|
||||
&& !path_delay->ignoreClkLatency())
|
||||
group_name = tgt_clk->name();
|
||||
return path_group_name == tgt_clk->name();
|
||||
else
|
||||
group_name = path_delay_group_name_;
|
||||
return path_group_name == path_delay_group_name_;
|
||||
}
|
||||
if (!group_name.empty())
|
||||
group_names.push_back(group_name);
|
||||
return group_names;
|
||||
return false;
|
||||
}
|
||||
|
||||
GroupPath *
|
||||
|
|
|
|||
|
|
@ -2770,7 +2770,8 @@ ReportPathLess::operator()(const Path *path1,
|
|||
|
||||
void
|
||||
Search::reportArrivals(Vertex *vertex,
|
||||
bool report_tag_index) const
|
||||
bool report_tag_index,
|
||||
int digits) const
|
||||
{
|
||||
report_->report("Vertex {}", vertex->to_string(this));
|
||||
TagGroup *tag_group = tagGroup(vertex);
|
||||
|
|
@ -2787,7 +2788,6 @@ Search::reportArrivals(Vertex *vertex,
|
|||
for (const Path *path : paths) {
|
||||
const Tag *tag = path->tag(this);
|
||||
const RiseFall *rf = tag->transition();
|
||||
std::string req = delayAsString(path->required(), this);
|
||||
bool report_prev = false;
|
||||
std::string prev_str;
|
||||
if (report_prev) {
|
||||
|
|
@ -2807,7 +2807,8 @@ Search::reportArrivals(Vertex *vertex,
|
|||
}
|
||||
report_->report(" {} {} {} / {} {}{}", rf->shortName(),
|
||||
path->minMax(this)->to_string(),
|
||||
delayAsString(path->arrival(), this), req,
|
||||
delayAsString(path->arrival(), digits, this),
|
||||
delayAsString(path->required(), digits, this),
|
||||
tag->to_string(report_tag_index, false, this), prev_str);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -294,9 +294,10 @@ report_tag_groups()
|
|||
|
||||
void
|
||||
report_tag_arrivals_cmd(Vertex *vertex,
|
||||
bool report_tag_index)
|
||||
bool report_tag_index,
|
||||
int digits)
|
||||
{
|
||||
Sta::sta()->search()->reportArrivals(vertex, report_tag_index);
|
||||
Sta::sta()->search()->reportArrivals(vertex, report_tag_index, digits);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -805,10 +805,19 @@ proc report_slack { args } {
|
|||
################################################################
|
||||
|
||||
# Internal debugging command.
|
||||
proc report_tag_arrivals { pin } {
|
||||
set pin [get_port_pin_error "pin" $pin]
|
||||
proc report_tag_arrivals { args } {
|
||||
global sta_report_default_digits
|
||||
|
||||
parse_key_args "report_tag_arrivals" args keys {-digits} flags {}
|
||||
set pin [get_port_pin_error "pin" [lindex $args 0]]
|
||||
if [info exists keys(-digits)] {
|
||||
set digits $keys(-digits)
|
||||
check_positive_integer "-digits" $digits
|
||||
} else {
|
||||
set digits $sta_report_default_digits
|
||||
}
|
||||
foreach vertex [$pin vertices] {
|
||||
report_tag_arrivals_cmd $vertex 1
|
||||
report_tag_arrivals_cmd $vertex 1 $digits
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3304,15 +3304,11 @@ EndpointPathEndVisitor::copy() const
|
|||
void
|
||||
EndpointPathEndVisitor::visit(PathEnd *path_end)
|
||||
{
|
||||
if (path_end->minMax(sta_) == min_max_) {
|
||||
StringSeq group_names = PathGroups::pathGroupNames(path_end, sta_);
|
||||
for (std::string &group_name : group_names) {
|
||||
if (group_name == path_group_name_) {
|
||||
Slack end_slack = path_end->slack(sta_);
|
||||
if (delayLess(end_slack, slack_, sta_))
|
||||
slack_ = end_slack;
|
||||
}
|
||||
}
|
||||
if (path_end->minMax(sta_) == min_max_
|
||||
&& PathGroups::inPathGroupNamed(path_end, path_group_name_, sta_)) {
|
||||
Slack end_slack = path_end->slack(sta_);
|
||||
if (delayLess(end_slack, slack_, sta_))
|
||||
slack_ = end_slack;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4437,7 +4433,8 @@ Sta::makeNet(const char *name,
|
|||
Instance *parent)
|
||||
{
|
||||
NetworkEdit *network = networkCmdEdit();
|
||||
Net *net = network->makeNet(name, parent);
|
||||
std::string escaped = escapeBrackets(name, network);
|
||||
Net *net = network->makeNet(escaped, parent);
|
||||
// Sta notification unnecessary.
|
||||
return net;
|
||||
}
|
||||
|
|
@ -4485,8 +4482,9 @@ Sta::makePortPin(const char *port_name,
|
|||
ensureLinked();
|
||||
NetworkReader *network = dynamic_cast<NetworkReader *>(network_);
|
||||
Instance *top_inst = network->topInstance();
|
||||
std::string escaped = escapeBrackets(port_name, network);
|
||||
Cell *top_cell = network->cell(top_inst);
|
||||
Port *port = network->makePort(top_cell, port_name);
|
||||
Port *port = network->makePort(top_cell, escaped);
|
||||
network->setDirection(port, dir);
|
||||
Pin *pin = network->makePin(top_inst, port, nullptr);
|
||||
makePortPinAfter(pin);
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
// Author Phillip Johnston
|
||||
// Original Author: Phillip Johnston
|
||||
// Licensed under CC0 1.0 Universal
|
||||
// https://github.com/embeddedartistry/embedded-resources/blob/master/examples/cpp/dispatch.cpp
|
||||
// https://embeddedartistry.com/blog/2017/2/1/dispatch-queues?rq=dispatch
|
||||
// Original source: https://github.com/embeddedartistry/embedded-resources/blob/master/examples/cpp/dispatch.cpp
|
||||
// Original article: https://embeddedartistry.com/blog/2017/2/1/dispatch-queues?rq=dispatch
|
||||
//
|
||||
// Modified for OpenSTA to use C++20 non-spinning DynamicLatch for synchronization.
|
||||
|
||||
#include "DispatchQueue.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
DispatchQueue::DispatchQueue(size_t thread_count) :
|
||||
threads_(thread_count),
|
||||
pending_task_count_(0)
|
||||
threads_(thread_count)
|
||||
{
|
||||
for(size_t i = 0; i < thread_count; i++)
|
||||
threads_[i] = std::thread(&DispatchQueue::dispatch_thread_handler, this, i);
|
||||
|
|
@ -58,8 +59,7 @@ DispatchQueue::getThreadCount() const
|
|||
void
|
||||
DispatchQueue::finishTasks()
|
||||
{
|
||||
while (pending_task_count_.load(std::memory_order_acquire) != 0)
|
||||
std::this_thread::yield();
|
||||
pending_task_count_latch_.wait();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -67,7 +67,7 @@ DispatchQueue::dispatch(const fp_t& op)
|
|||
{
|
||||
std::unique_lock<std::mutex> lock(lock_);
|
||||
q_.push(op);
|
||||
pending_task_count_++;
|
||||
pending_task_count_latch_.countUp();
|
||||
|
||||
// Manual unlocking is done before notifying, to avoid waking up
|
||||
// the waiting thread only to block again (see notify_one for details)
|
||||
|
|
@ -80,7 +80,7 @@ DispatchQueue::dispatch(fp_t&& op)
|
|||
{
|
||||
std::unique_lock<std::mutex> lock(lock_);
|
||||
q_.push(std::move(op));
|
||||
pending_task_count_++;
|
||||
pending_task_count_latch_.countUp();
|
||||
|
||||
// Manual unlocking is done before notifying, to avoid waking up
|
||||
// the waiting thread only to block again (see notify_one for details)
|
||||
|
|
@ -106,7 +106,7 @@ DispatchQueue::dispatch_thread_handler(size_t i)
|
|||
|
||||
op(i);
|
||||
|
||||
pending_task_count_--;
|
||||
pending_task_count_latch_.countDown();
|
||||
lock.lock();
|
||||
}
|
||||
} while (!quit_);
|
||||
|
|
|
|||
|
|
@ -242,13 +242,8 @@ stmt_seq:
|
|||
continuous_assign
|
||||
;
|
||||
|
||||
/* specify blocks are used by some comercial tools to convey macro timing
|
||||
* and other metadata.
|
||||
* Their presence is not forbidden in structural verilog, this is a placeholder
|
||||
* that just ignores them and allows verilog processing to proceed
|
||||
* <<TODO>> if someone in the future wants implement support for timing info
|
||||
* via specify blocks, implement proper parsing here
|
||||
*/
|
||||
// Specify blocks are used by some comercial tools to convey macro timing
|
||||
// and other metadata.
|
||||
specify_block:
|
||||
SPECIFY specify_stmts ENDSPECIFY
|
||||
{ $$ = nullptr; }
|
||||
|
|
|
|||
Loading…
Reference in New Issue