diff options
| -rw-r--r-- | 3rdparty/python-console/modified/pyinterpreter.cc | 22 | ||||
| -rw-r--r-- | 3rdparty/python-console/modified/pyinterpreter.h | 1 | ||||
| -rw-r--r-- | common/timing.cc | 29 | ||||
| -rw-r--r-- | gui/base.qrc | 1 | ||||
| -rw-r--r-- | gui/basewindow.cc | 18 | ||||
| -rw-r--r-- | gui/basewindow.h | 5 | ||||
| -rw-r--r-- | gui/pyconsole.cc | 17 | ||||
| -rw-r--r-- | gui/pyconsole.h | 1 | ||||
| -rw-r--r-- | gui/pythontab.cc | 2 | ||||
| -rw-r--r-- | gui/pythontab.h | 1 | ||||
| -rw-r--r-- | gui/resources/py.png | bin | 0 -> 2277 bytes | |||
| -rw-r--r-- | json/jsonparse.cc | 40 | 
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.pngBinary files differ new file mode 100644 index 00000000..9cc6e522 --- /dev/null +++ b/gui/resources/py.png 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); | 
