aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--3rdparty/python-console/modified/pyinterpreter.cc22
-rw-r--r--3rdparty/python-console/modified/pyinterpreter.h1
-rw-r--r--common/timing.cc29
-rw-r--r--gui/base.qrc1
-rw-r--r--gui/basewindow.cc18
-rw-r--r--gui/basewindow.h5
-rw-r--r--gui/pyconsole.cc17
-rw-r--r--gui/pyconsole.h1
-rw-r--r--gui/pythontab.cc2
-rw-r--r--gui/pythontab.h1
-rw-r--r--gui/resources/py.pngbin0 -> 2277 bytes
-rw-r--r--json/jsonparse.cc40
12 files changed, 119 insertions, 18 deletions
diff --git a/3rdparty/python-console/modified/pyinterpreter.cc b/3rdparty/python-console/modified/pyinterpreter.cc
index f53207ad..89c9b88c 100644
--- a/3rdparty/python-console/modified/pyinterpreter.cc
+++ b/3rdparty/python-console/modified/pyinterpreter.cc
@@ -153,3 +153,25 @@ void pyinterpreter_release()
{
PyEval_ReleaseThread(m_threadState);
}
+
+std::string pyinterpreter_execute_file(const char *python_file, int *errorCode)
+{
+ PyEval_AcquireThread(m_threadState);
+ *errorCode = 0;
+ std::string res;
+ FILE *fp = fopen(python_file, "r");
+ if (fp == NULL) {
+ *errorCode = 1;
+ res = "Fatal error: file not found " + std::string(python_file) + "\n";
+ return res;
+ }
+
+ if (PyRun_SimpleFile(fp, python_file)==-1) {
+ *errorCode = 1;
+ PyErr_Print();
+ }
+ res = redirector_take_output(m_threadState);
+
+ PyEval_ReleaseThread(m_threadState);
+ return res;
+}
diff --git a/3rdparty/python-console/modified/pyinterpreter.h b/3rdparty/python-console/modified/pyinterpreter.h
index 1a85c1fb..48512507 100644
--- a/3rdparty/python-console/modified/pyinterpreter.h
+++ b/3rdparty/python-console/modified/pyinterpreter.h
@@ -33,4 +33,5 @@ void pyinterpreter_initialize();
void pyinterpreter_finalize();
void pyinterpreter_aquire();
void pyinterpreter_release();
+std::string pyinterpreter_execute_file(const char *python_file, int *errorCode);
#endif // PYINTERPRETER_H
diff --git a/common/timing.cc b/common/timing.cc
index b15327fb..b27dd56e 100644
--- a/common/timing.cc
+++ b/common/timing.cc
@@ -414,7 +414,6 @@ struct Timing
while (crit_net) {
const PortInfo *crit_ipin = nullptr;
delay_t max_arrival = std::numeric_limits<delay_t>::min();
-
// Look at all input ports on its driving cell
for (const auto &port : crit_net->driver.cell->ports) {
if (port.second.type != PORT_IN || !port.second.net)
@@ -428,14 +427,21 @@ struct Timing
int port_clocks;
TimingPortClass portClass =
ctx->getPortTimingClass(crit_net->driver.cell, port.first, port_clocks);
- if (portClass == TMG_REGISTER_INPUT || portClass == TMG_CLOCK_INPUT ||
- portClass == TMG_ENDPOINT || portClass == TMG_IGNORE)
+ if (portClass == TMG_CLOCK_INPUT || portClass == TMG_ENDPOINT || portClass == TMG_IGNORE ||
+ portClass == TMG_REGISTER_INPUT)
continue;
-
// And find the fanin net with the latest arrival time
if (net_data.count(port.second.net) &&
net_data.at(port.second.net).count(crit_pair.first.start)) {
- const auto net_arrival = net_data.at(port.second.net).at(crit_pair.first.start).max_arrival;
+ auto net_arrival = net_data.at(port.second.net).at(crit_pair.first.start).max_arrival;
+ if (net_delays) {
+ for (auto &user : port.second.net->users)
+ if (user.port == port.first && user.cell == crit_net->driver.cell) {
+ net_arrival += ctx->getNetinfoRouteDelay(port.second.net, user);
+ break;
+ }
+ }
+ net_arrival += comb_delay.maxDelay();
if (net_arrival > max_arrival) {
max_arrival = net_arrival;
crit_ipin = &port.second;
@@ -445,7 +451,6 @@ struct Timing
if (!crit_ipin)
break;
-
// Now convert PortInfo* into a PortRef*
for (auto &usr : crit_ipin->net->users) {
if (usr.cell->name == crit_net->driver.cell->name && usr.port == crit_ipin->name) {
@@ -779,6 +784,7 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
int port_clocks;
auto portClass = ctx->getPortTimingClass(front_driver.cell, front_driver.port, port_clocks);
IdString last_port = front_driver.port;
+ int clock_start = -1;
if (portClass == TMG_REGISTER_OUTPUT) {
for (int i = 0; i < port_clocks; i++) {
TimingClockingInfo clockInfo = ctx->getPortClockingInfo(front_driver.cell, front_driver.port, i);
@@ -786,8 +792,7 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
if (clknet != nullptr && clknet->name == clocks.start.clock &&
clockInfo.edge == clocks.start.edge) {
last_port = clockInfo.clock_port;
- total += clockInfo.clockToQ.maxDelay();
- logic_total += clockInfo.clockToQ.maxDelay();
+ clock_start = i;
break;
}
}
@@ -801,11 +806,15 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p
auto &driver = net->driver;
auto driver_cell = driver.cell;
DelayInfo comb_delay;
- if (last_port == driver.port) {
+ if (clock_start != -1) {
+ auto clockInfo = ctx->getPortClockingInfo(driver_cell, driver.port, clock_start);
+ comb_delay = clockInfo.clockToQ;
+ clock_start = -1;
+ } else if (last_port == driver.port) {
// Case where we start with a STARTPOINT etc
comb_delay = ctx->getDelayFromNS(0);
} else {
- ctx->getCellDelay(sink_cell, last_port, driver.port, comb_delay);
+ ctx->getCellDelay(driver_cell, last_port, driver.port, comb_delay);
}
total += comb_delay.maxDelay();
logic_total += comb_delay.maxDelay();
diff --git a/gui/base.qrc b/gui/base.qrc
index 8f58f585..644b16a6 100644
--- a/gui/base.qrc
+++ b/gui/base.qrc
@@ -22,5 +22,6 @@
<file>resources/route.png</file>
<file>resources/time_add.png</file>
<file>resources/open_json.png</file>
+ <file>resources/py.png</file>
</qresource>
</RCC>
diff --git a/gui/basewindow.cc b/gui/basewindow.cc
index 49c2d8d5..346efb88 100644
--- a/gui/basewindow.cc
+++ b/gui/basewindow.cc
@@ -189,6 +189,12 @@ void BaseMainWindow::createMenusAndBars()
actionRoute->setEnabled(false);
connect(actionRoute, &QAction::triggered, task, &TaskManager::route);
+ actionExecutePy = new QAction("Execute Python", this);
+ actionExecutePy->setIcon(QIcon(":/icons/resources/py.png"));
+ actionExecutePy->setStatusTip("Execute Python script");
+ actionExecutePy->setEnabled(true);
+ connect(actionExecutePy, &QAction::triggered, this, &BaseMainWindow::execute_python);
+
// Worker control toolbar actions
actionPlay = new QAction("Play", this);
actionPlay->setIcon(QIcon(":/icons/resources/control_play.png"));
@@ -249,6 +255,8 @@ void BaseMainWindow::createMenusAndBars()
menuDesign->addAction(actionAssignBudget);
menuDesign->addAction(actionPlace);
menuDesign->addAction(actionRoute);
+ menuDesign->addSeparator();
+ menuDesign->addAction(actionExecutePy);
// Add Help menu actions
menuHelp->addAction(actionAbout);
@@ -268,6 +276,7 @@ void BaseMainWindow::createMenusAndBars()
mainActionBar->addAction(actionAssignBudget);
mainActionBar->addAction(actionPlace);
mainActionBar->addAction(actionRoute);
+ mainActionBar->addAction(actionExecutePy);
// Add worker control toolbar
QToolBar *workerControlToolBar = new QToolBar("Worker");
@@ -412,6 +421,7 @@ void BaseMainWindow::disableActions()
actionAssignBudget->setEnabled(false);
actionPlace->setEnabled(false);
actionRoute->setEnabled(false);
+ actionExecutePy->setEnabled(true);
actionPlay->setEnabled(false);
actionPause->setEnabled(false);
@@ -454,6 +464,14 @@ void BaseMainWindow::open_proj()
}
}
+void BaseMainWindow::execute_python()
+{
+ QString fileName = QFileDialog::getOpenFileName(this, QString("Execute Python"), QString(), QString("*.py"));
+ if (!fileName.isEmpty()) {
+ console->execute_python(fileName.toStdString());
+ }
+}
+
void BaseMainWindow::notifyChangeContext() { Q_EMIT contextChanged(ctx.get()); }
void BaseMainWindow::save_proj()
{
diff --git a/gui/basewindow.h b/gui/basewindow.h
index eb32033a..0b2d3fbc 100644
--- a/gui/basewindow.h
+++ b/gui/basewindow.h
@@ -78,6 +78,8 @@ class BaseMainWindow : public QMainWindow
void budget();
void place();
+ void execute_python();
+
void pack_finished(bool status);
void budget_finish(bool status);
void place_finished(bool status);
@@ -122,6 +124,9 @@ class BaseMainWindow : public QMainWindow
QAction *actionAssignBudget;
QAction *actionPlace;
QAction *actionRoute;
+
+ QAction *actionExecutePy;
+
QAction *actionPlay;
QAction *actionPause;
QAction *actionStop;
diff --git a/gui/pyconsole.cc b/gui/pyconsole.cc
index 0ee393ce..d015aea2 100644
--- a/gui/pyconsole.cc
+++ b/gui/pyconsole.cc
@@ -76,4 +76,21 @@ void PythonConsole::moveCursorToEnd()
setTextCursor(cursor);
}
+void PythonConsole::execute_python(std::string filename)
+{
+ int errorCode = 0;
+ std::string res;
+ res = pyinterpreter_execute_file(filename.c_str(), &errorCode);
+ if (res.size()) {
+ if (errorCode) {
+ setTextColor(ERROR_COLOR);
+ } else {
+ setTextColor(OUTPUT_COLOR);
+ }
+ append(res.c_str());
+ setTextColor(NORMAL_COLOR);
+ moveCursorToEnd();
+ }
+}
+
NEXTPNR_NAMESPACE_END
diff --git a/gui/pyconsole.h b/gui/pyconsole.h
index 9dbd3b95..977242f3 100644
--- a/gui/pyconsole.h
+++ b/gui/pyconsole.h
@@ -43,6 +43,7 @@ class PythonConsole : public QTextEdit, public ParseListener
void displayString(QString text);
void moveCursorToEnd();
virtual void parseEvent(const ParseMessage &message);
+ void execute_python(std::string filename);
protected:
static const QColor NORMAL_COLOR;
diff --git a/gui/pythontab.cc b/gui/pythontab.cc
index 80d731e9..827f1907 100644
--- a/gui/pythontab.cc
+++ b/gui/pythontab.cc
@@ -114,4 +114,6 @@ void PythonTab::clearBuffer() { console->clear(); }
void PythonTab::info(std::string str) { console->displayString(str.c_str()); }
+void PythonTab::execute_python(std::string filename) { console->execute_python(filename); }
+
NEXTPNR_NAMESPACE_END
diff --git a/gui/pythontab.h b/gui/pythontab.h
index 134874b6..860bf1c3 100644
--- a/gui/pythontab.h
+++ b/gui/pythontab.h
@@ -45,6 +45,7 @@ class PythonTab : public QWidget
void newContext(Context *ctx);
void info(std::string str);
void clearBuffer();
+ void execute_python(std::string filename);
private:
PythonConsole *console;
diff --git a/gui/resources/py.png b/gui/resources/py.png
new file mode 100644
index 00000000..9cc6e522
--- /dev/null
+++ b/gui/resources/py.png
Binary files differ
diff --git a/json/jsonparse.cc b/json/jsonparse.cc
index c4ef5584..5f4df0a2 100644
--- a/json/jsonparse.cc
+++ b/json/jsonparse.cc
@@ -692,8 +692,28 @@ void json_import(Context *ctx, string modname, JsonNode *node)
log_info("Importing module %s\n", modname.c_str());
+ // Multiple labels might refer to the same net. For now we resolve conflicts thus:
+ // - names with fewer $ are always prefered
+ // - between equal $ counts, fewer .s are prefered
+ // - ties are resolved alphabetically
+ auto prefer_netlabel = [](const std::string &a, const std::string &b) {
+ if (b.empty())
+ return true;
+ long a_dollars = std::count(a.begin(), a.end(), '$'), b_dollars = std::count(b.begin(), b.end(), '$');
+ if (a_dollars < b_dollars)
+ return true;
+ else if (a_dollars > b_dollars)
+ return false;
+ long a_dots = std::count(a.begin(), a.end(), '.'), b_dots = std::count(b.begin(), b.end(), '.');
+ if (a_dots < b_dots)
+ return true;
+ else if (a_dots > b_dots)
+ return false;
+ return a < b;
+ };
+
// Import netnames
- std::vector<IdString> netnames;
+ std::vector<std::string> netlabels;
if (node->data_dict.count("netnames")) {
JsonNode *cell_parent = node->data_dict.at("netnames");
for (int nnid = 0; nnid < GetSize(cell_parent->data_dict_keys); nnid++) {
@@ -707,15 +727,19 @@ void json_import(Context *ctx, string modname, JsonNode *node)
size_t num_bits = bits->data_array.size();
for (size_t i = 0; i < num_bits; i++) {
int netid = bits->data_array.at(i)->data_number;
- if (netid >= int(netnames.size()))
- netnames.resize(netid + 1);
- netnames.at(netid) = ctx->id(
- basename + (num_bits == 1 ? "" : std::string("[") + std::to_string(i) + std::string("]")));
+ if (netid >= int(netlabels.size()))
+ netlabels.resize(netid + 1);
+ std::string name =
+ basename + (num_bits == 1 ? "" : std::string("[") + std::to_string(i) + std::string("]"));
+ if (prefer_netlabel(name, netlabels.at(netid)))
+ netlabels.at(netid) = name;
}
}
}
}
-
+ std::vector<IdString> netids;
+ std::transform(netlabels.begin(), netlabels.end(), std::back_inserter(netids),
+ [ctx](const std::string &s) { return ctx->id(s); });
if (node->data_dict.count("cells")) {
JsonNode *cell_parent = node->data_dict.at("cells");
//
@@ -725,7 +749,7 @@ void json_import(Context *ctx, string modname, JsonNode *node)
//
for (int cellid = 0; cellid < GetSize(cell_parent->data_dict_keys); cellid++) {
JsonNode *here = cell_parent->data_dict.at(cell_parent->data_dict_keys[cellid]);
- json_import_cell(ctx, modname, netnames, here, cell_parent->data_dict_keys[cellid]);
+ json_import_cell(ctx, modname, netids, here, cell_parent->data_dict_keys[cellid]);
}
}
@@ -739,7 +763,7 @@ void json_import(Context *ctx, string modname, JsonNode *node)
JsonNode *here;
here = ports_parent->data_dict.at(ports_parent->data_dict_keys[portid]);
- json_import_toplevel_port(ctx, modname, netnames, ports_parent->data_dict_keys[portid], here);
+ json_import_toplevel_port(ctx, modname, netids, ports_parent->data_dict_keys[portid], here);
}
}
check_all_nets_driven(ctx);