diff --git a/ecp5/arch.h b/ecp5/arch.h index d450321d..cd103b12 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -454,6 +454,7 @@ struct Arch : BaseCtx bel_to_cell[bel] = cell; cells[cell]->bel = bel; cells[cell]->belStrength = strength; + refreshUiBel(bel); } void unbindBel(BelId bel) @@ -463,6 +464,7 @@ struct Arch : BaseCtx cells[bel_to_cell[bel]]->bel = BelId(); cells[bel_to_cell[bel]]->belStrength = STRENGTH_NONE; bel_to_cell[bel] = IdString(); + refreshUiBel(bel); } Loc getBelLocation(BelId bel) const diff --git a/gui/base.qrc b/gui/base.qrc index 7b3fa55c..8f58f585 100644 --- a/gui/base.qrc +++ b/gui/base.qrc @@ -14,5 +14,13 @@ resources/zoom_out.png resources/shape_handles.png resources/shape_square.png + resources/control_play.png + resources/control_pause.png + resources/control_stop.png + resources/pack.png + resources/place.png + resources/route.png + resources/time_add.png + resources/open_json.png diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 685a205f..37141fd6 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -23,9 +23,12 @@ #include #include #include +#include #include +#include #include "designwidget.h" #include "fpgaviewwidget.h" +#include "jsonparse.h" #include "log.h" #include "mainwindow.h" #include "pythontab.h" @@ -35,7 +38,7 @@ static void initBasenameResource() { Q_INIT_RESOURCE(base); } NEXTPNR_NAMESPACE_BEGIN BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent) - : QMainWindow(parent), ctx(std::move(context)) + : QMainWindow(parent), ctx(std::move(context)), timing_driven(false) { initBasenameResource(); qRegisterMetaType(); @@ -46,10 +49,10 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent setObjectName("BaseMainWindow"); resize(1024, 768); - createMenusAndBars(); + task = new TaskManager(); + // Create and deploy widgets on main screen QWidget *centralWidget = new QWidget(this); - QGridLayout *gridLayout = new QGridLayout(centralWidget); gridLayout->setSpacing(6); gridLayout->setContentsMargins(11, 11, 11, 11); @@ -70,38 +73,54 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent console = new PythonTab(); tabWidget->addTab(console, "Console"); - connect(this, SIGNAL(contextChanged(Context *)), console, SLOT(newContext(Context *))); centralTabWidget = new QTabWidget(); centralTabWidget->setTabsClosable(true); - connect(centralTabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int))); fpgaView = new FPGAViewWidget(); centralTabWidget->addTab(fpgaView, "Device"); centralTabWidget->tabBar()->setTabButton(0, QTabBar::RightSide, 0); centralTabWidget->tabBar()->setTabButton(0, QTabBar::LeftSide, 0); - connect(this, SIGNAL(contextChanged(Context *)), fpgaView, SLOT(newContext(Context *))); - connect(designview, SIGNAL(selected(std::vector, bool)), fpgaView, - SLOT(onSelectedArchItem(std::vector, bool))); - connect(fpgaView, SIGNAL(clickedBel(BelId, bool)), designview, SLOT(onClickedBel(BelId, bool))); - connect(fpgaView, SIGNAL(clickedWire(WireId, bool)), designview, SLOT(onClickedWire(WireId, bool))); - connect(fpgaView, SIGNAL(clickedPip(PipId, bool)), designview, SLOT(onClickedPip(PipId, bool))); - connect(designview, SIGNAL(zoomSelected()), fpgaView, SLOT(zoomSelected())); - - connect(designview, SIGNAL(highlight(std::vector, int)), fpgaView, - SLOT(onHighlightGroupChanged(std::vector, int))); - - connect(this, SIGNAL(contextChanged(Context *)), designview, SLOT(newContext(Context *))); - connect(this, SIGNAL(updateTreeView()), designview, SLOT(updateTree())); - - connect(designview, SIGNAL(info(std::string)), this, SLOT(writeInfo(std::string))); - splitter_v->addWidget(centralTabWidget); splitter_v->addWidget(tabWidget); + + // Connect Worker + connect(task, &TaskManager::log, this, &BaseMainWindow::writeInfo); + connect(task, &TaskManager::pack_finished, this, &BaseMainWindow::pack_finished); + connect(task, &TaskManager::budget_finish, this, &BaseMainWindow::budget_finish); + connect(task, &TaskManager::place_finished, this, &BaseMainWindow::place_finished); + connect(task, &TaskManager::route_finished, this, &BaseMainWindow::route_finished); + connect(task, &TaskManager::taskCanceled, this, &BaseMainWindow::taskCanceled); + connect(task, &TaskManager::taskStarted, this, &BaseMainWindow::taskStarted); + connect(task, &TaskManager::taskPaused, this, &BaseMainWindow::taskPaused); + + // Events for context change + connect(this, &BaseMainWindow::contextChanged, task, &TaskManager::contextChanged); + connect(this, &BaseMainWindow::contextChanged, console, &PythonTab::newContext); + connect(this, &BaseMainWindow::contextChanged, fpgaView, &FPGAViewWidget::newContext); + connect(this, &BaseMainWindow::contextChanged, designview, &DesignWidget::newContext); + + // Catch close tab events + connect(centralTabWidget, &QTabWidget::tabCloseRequested, this, &BaseMainWindow::closeTab); + + // Propagate events from design view to device view + connect(designview, &DesignWidget::selected, fpgaView, &FPGAViewWidget::onSelectedArchItem); + connect(designview, &DesignWidget::zoomSelected, fpgaView, &FPGAViewWidget::zoomSelected); + connect(designview, &DesignWidget::highlight, fpgaView, &FPGAViewWidget::onHighlightGroupChanged); + + // Click event on device view + connect(fpgaView, &FPGAViewWidget::clickedBel, designview, &DesignWidget::onClickedBel); + connect(fpgaView, &FPGAViewWidget::clickedWire, designview, &DesignWidget::onClickedWire); + connect(fpgaView, &FPGAViewWidget::clickedPip, designview, &DesignWidget::onClickedPip); + + // Update tree event + connect(this, &BaseMainWindow::updateTreeView, designview, &DesignWidget::updateTree); + + createMenusAndBars(); } -BaseMainWindow::~BaseMainWindow() {} +BaseMainWindow::~BaseMainWindow() { delete task; } void BaseMainWindow::closeTab(int index) { delete centralTabWidget->widget(index); } @@ -109,44 +128,162 @@ void BaseMainWindow::writeInfo(std::string text) { console->info(text); } void BaseMainWindow::createMenusAndBars() { + // File menu / project toolbar actions actionNew = new QAction("New", this); actionNew->setIcon(QIcon(":/icons/resources/new.png")); actionNew->setShortcuts(QKeySequence::New); actionNew->setStatusTip("New project file"); - connect(actionNew, SIGNAL(triggered()), this, SLOT(new_proj())); + connect(actionNew, &QAction::triggered, this, &BaseMainWindow::new_proj); actionOpen = new QAction("Open", this); actionOpen->setIcon(QIcon(":/icons/resources/open.png")); actionOpen->setShortcuts(QKeySequence::Open); actionOpen->setStatusTip("Open an existing project file"); - connect(actionOpen, SIGNAL(triggered()), this, SLOT(open_proj())); + connect(actionOpen, &QAction::triggered, this, &BaseMainWindow::open_proj); actionSave = new QAction("Save", this); actionSave->setIcon(QIcon(":/icons/resources/save.png")); actionSave->setShortcuts(QKeySequence::Save); actionSave->setStatusTip("Save existing project to disk"); actionSave->setEnabled(false); - connect(actionSave, SIGNAL(triggered()), this, SLOT(save_proj())); + connect(actionSave, &QAction::triggered, this, &BaseMainWindow::save_proj); QAction *actionExit = new QAction("Exit", this); actionExit->setIcon(QIcon(":/icons/resources/exit.png")); actionExit->setShortcuts(QKeySequence::Quit); actionExit->setStatusTip("Exit the application"); - connect(actionExit, SIGNAL(triggered()), this, SLOT(close())); + connect(actionExit, &QAction::triggered, this, &BaseMainWindow::close); + // Help menu actions QAction *actionAbout = new QAction("About", this); + // Design menu options + actionLoadJSON = new QAction("Open JSON", this); + actionLoadJSON->setIcon(QIcon(":/icons/resources/open_json.png")); + actionLoadJSON->setStatusTip("Open an existing JSON file"); + actionLoadJSON->setEnabled(true); + connect(actionLoadJSON, &QAction::triggered, this, &BaseMainWindow::open_json); + + actionPack = new QAction("Pack", this); + actionPack->setIcon(QIcon(":/icons/resources/pack.png")); + actionPack->setStatusTip("Pack current design"); + actionPack->setEnabled(false); + connect(actionPack, &QAction::triggered, task, &TaskManager::pack); + + actionAssignBudget = new QAction("Assign Budget", this); + actionAssignBudget->setIcon(QIcon(":/icons/resources/time_add.png")); + actionAssignBudget->setStatusTip("Assign time budget for current design"); + actionAssignBudget->setEnabled(false); + connect(actionAssignBudget, &QAction::triggered, this, &BaseMainWindow::budget); + + actionPlace = new QAction("Place", this); + actionPlace->setIcon(QIcon(":/icons/resources/place.png")); + actionPlace->setStatusTip("Place current design"); + actionPlace->setEnabled(false); + connect(actionPlace, &QAction::triggered, this, &BaseMainWindow::place); + + actionRoute = new QAction("Route", this); + actionRoute->setIcon(QIcon(":/icons/resources/route.png")); + actionRoute->setStatusTip("Route current design"); + actionRoute->setEnabled(false); + connect(actionRoute, &QAction::triggered, task, &TaskManager::route); + + // Worker control toolbar actions + actionPlay = new QAction("Play", this); + actionPlay->setIcon(QIcon(":/icons/resources/control_play.png")); + actionPlay->setStatusTip("Continue running task"); + actionPlay->setEnabled(false); + connect(actionPlay, &QAction::triggered, task, &TaskManager::continue_thread); + + actionPause = new QAction("Pause", this); + actionPause->setIcon(QIcon(":/icons/resources/control_pause.png")); + actionPause->setStatusTip("Pause running task"); + actionPause->setEnabled(false); + connect(actionPause, &QAction::triggered, task, &TaskManager::pause_thread); + + actionStop = new QAction("Stop", this); + actionStop->setIcon(QIcon(":/icons/resources/control_stop.png")); + actionStop->setStatusTip("Stop running task"); + actionStop->setEnabled(false); + connect(actionStop, &QAction::triggered, task, &TaskManager::terminate_thread); + + // Device view control toolbar actions + QAction *actionZoomIn = new QAction("Zoom In", this); + actionZoomIn->setIcon(QIcon(":/icons/resources/zoom_in.png")); + connect(actionZoomIn, &QAction::triggered, fpgaView, &FPGAViewWidget::zoomIn); + + QAction *actionZoomOut = new QAction("Zoom Out", this); + actionZoomOut->setIcon(QIcon(":/icons/resources/zoom_out.png")); + connect(actionZoomOut, &QAction::triggered, fpgaView, &FPGAViewWidget::zoomOut); + + QAction *actionZoomSelected = new QAction("Zoom Selected", this); + actionZoomSelected->setIcon(QIcon(":/icons/resources/shape_handles.png")); + connect(actionZoomSelected, &QAction::triggered, fpgaView, &FPGAViewWidget::zoomSelected); + + QAction *actionZoomOutbound = new QAction("Zoom Outbound", this); + actionZoomOutbound->setIcon(QIcon(":/icons/resources/shape_square.png")); + connect(actionZoomOutbound, &QAction::triggered, fpgaView, &FPGAViewWidget::zoomOutbound); + + // Add main menu menuBar = new QMenuBar(); menuBar->setGeometry(QRect(0, 0, 1024, 27)); - QMenu *menu_File = new QMenu("&File", menuBar); - QMenu *menu_Help = new QMenu("&Help", menuBar); - menuBar->addAction(menu_File->menuAction()); - menuBar->addAction(menu_Help->menuAction()); setMenuBar(menuBar); + QMenu *menuFile = new QMenu("&File", menuBar); + QMenu *menuHelp = new QMenu("&Help", menuBar); + menuDesign = new QMenu("&Design", menuBar); + menuBar->addAction(menuFile->menuAction()); + menuBar->addAction(menuDesign->menuAction()); + menuBar->addAction(menuHelp->menuAction()); - mainToolBar = new QToolBar(); - addToolBar(Qt::TopToolBarArea, mainToolBar); + // Add File menu actions + menuFile->addAction(actionNew); + menuFile->addAction(actionOpen); + menuFile->addAction(actionSave); + menuFile->addSeparator(); + menuFile->addAction(actionExit); + // Add Design menu actions + menuDesign->addAction(actionLoadJSON); + menuDesign->addAction(actionPack); + menuDesign->addAction(actionAssignBudget); + menuDesign->addAction(actionPlace); + menuDesign->addAction(actionRoute); + + // Add Help menu actions + menuHelp->addAction(actionAbout); + + // Project toolbar + QToolBar *projectToolBar = new QToolBar("Project"); + addToolBar(Qt::TopToolBarArea, projectToolBar); + projectToolBar->addAction(actionNew); + projectToolBar->addAction(actionOpen); + projectToolBar->addAction(actionSave); + + // Main action bar + mainActionBar = new QToolBar("Main"); + addToolBar(Qt::TopToolBarArea, mainActionBar); + mainActionBar->addAction(actionLoadJSON); + mainActionBar->addAction(actionPack); + mainActionBar->addAction(actionAssignBudget); + mainActionBar->addAction(actionPlace); + mainActionBar->addAction(actionRoute); + + // Add worker control toolbar + QToolBar *workerControlToolBar = new QToolBar("Worker"); + addToolBar(Qt::TopToolBarArea, workerControlToolBar); + workerControlToolBar->addAction(actionPlay); + workerControlToolBar->addAction(actionPause); + workerControlToolBar->addAction(actionStop); + + // Add device view control toolbar + QToolBar *deviceViewToolBar = new QToolBar("Device"); + addToolBar(Qt::TopToolBarArea, deviceViewToolBar); + deviceViewToolBar->addAction(actionZoomIn); + deviceViewToolBar->addAction(actionZoomOut); + deviceViewToolBar->addAction(actionZoomSelected); + deviceViewToolBar->addAction(actionZoomOutbound); + + // Add status bar with progress bar statusBar = new QStatusBar(); progressBar = new QProgressBar(statusBar); progressBar->setAlignment(Qt::AlignRight); @@ -155,43 +292,137 @@ void BaseMainWindow::createMenusAndBars() progressBar->setValue(0); progressBar->setEnabled(false); setStatusBar(statusBar); - - menu_File->addAction(actionNew); - menu_File->addAction(actionOpen); - menu_File->addAction(actionSave); - menu_File->addSeparator(); - menu_File->addAction(actionExit); - menu_Help->addAction(actionAbout); - - mainToolBar->addAction(actionNew); - mainToolBar->addAction(actionOpen); - mainToolBar->addAction(actionSave); } -void BaseMainWindow::createGraphicsBar() +void BaseMainWindow::load_json(std::string filename) { - QAction *actionZoomIn = new QAction("Zoom In", this); - actionZoomIn->setIcon(QIcon(":/icons/resources/zoom_in.png")); - connect(actionZoomIn, SIGNAL(triggered()), fpgaView, SLOT(zoomIn())); + disableActions(); + currentJson = filename; + std::ifstream f(filename); + if (parse_json_file(f, filename, ctx.get())) { + log("Loading design successful.\n"); + Q_EMIT updateTreeView(); + actionPack->setEnabled(true); + onJsonLoaded(); + } else { + actionLoadJSON->setEnabled(true); + log("Loading design failed.\n"); + } +} - QAction *actionZoomOut = new QAction("Zoom Out", this); - actionZoomOut->setIcon(QIcon(":/icons/resources/zoom_out.png")); - connect(actionZoomOut, SIGNAL(triggered()), fpgaView, SLOT(zoomOut())); +void BaseMainWindow::open_json() +{ + QString fileName = QFileDialog::getOpenFileName(this, QString("Open JSON"), QString(), QString("*.json")); + if (!fileName.isEmpty()) { + load_json(fileName.toStdString()); + } +} - QAction *actionZoomSelected = new QAction("Zoom Selected", this); - actionZoomSelected->setIcon(QIcon(":/icons/resources/shape_handles.png")); - connect(actionZoomSelected, SIGNAL(triggered()), fpgaView, SLOT(zoomSelected())); +void BaseMainWindow::pack_finished(bool status) +{ + disableActions(); + if (status) { + log("Packing design successful.\n"); + Q_EMIT updateTreeView(); + actionPlace->setEnabled(true); + actionAssignBudget->setEnabled(true); + onPackFinished(); + } else { + log("Packing design failed.\n"); + } +} - QAction *actionZoomOutbound = new QAction("Zoom Outbound", this); - actionZoomOutbound->setIcon(QIcon(":/icons/resources/shape_square.png")); - connect(actionZoomOutbound, SIGNAL(triggered()), fpgaView, SLOT(zoomOutbound())); +void BaseMainWindow::budget_finish(bool status) +{ + disableActions(); + if (status) { + log("Assigning timing budget successful.\n"); + actionPlace->setEnabled(true); + onBudgetFinished(); + } else { + log("Assigning timing budget failed.\n"); + } +} - graphicsToolBar = new QToolBar(); - addToolBar(Qt::TopToolBarArea, graphicsToolBar); - graphicsToolBar->addAction(actionZoomIn); - graphicsToolBar->addAction(actionZoomOut); - graphicsToolBar->addAction(actionZoomSelected); - graphicsToolBar->addAction(actionZoomOutbound); +void BaseMainWindow::place_finished(bool status) +{ + disableActions(); + if (status) { + log("Placing design successful.\n"); + Q_EMIT updateTreeView(); + actionRoute->setEnabled(true); + onPlaceFinished(); + } else { + log("Placing design failed.\n"); + } +} +void BaseMainWindow::route_finished(bool status) +{ + disableActions(); + if (status) { + log("Routing design successful.\n"); + Q_EMIT updateTreeView(); + onRouteFinished(); + } else + log("Routing design failed.\n"); +} + +void BaseMainWindow::taskCanceled() +{ + log("CANCELED\n"); + disableActions(); +} + +void BaseMainWindow::taskStarted() +{ + disableActions(); + actionPause->setEnabled(true); + actionStop->setEnabled(true); + + actionNew->setEnabled(false); + actionOpen->setEnabled(false); +} + +void BaseMainWindow::taskPaused() +{ + disableActions(); + actionPlay->setEnabled(true); + actionStop->setEnabled(true); + + actionNew->setEnabled(false); + actionOpen->setEnabled(false); +} + +void BaseMainWindow::budget() +{ + bool ok; + double freq = QInputDialog::getDouble(this, "Assign timing budget", "Frequency [MHz]:", 50, 0, 250, 2, &ok); + if (ok) { + freq *= 1e6; + timing_driven = true; + Q_EMIT task->budget(freq); + } +} + +void BaseMainWindow::place() { Q_EMIT task->place(timing_driven); } + +void BaseMainWindow::disableActions() +{ + actionLoadJSON->setEnabled(false); + actionPack->setEnabled(false); + actionAssignBudget->setEnabled(false); + actionPlace->setEnabled(false); + actionRoute->setEnabled(false); + + actionPlay->setEnabled(false); + actionPause->setEnabled(false); + actionStop->setEnabled(false); + + actionNew->setEnabled(true); + actionOpen->setEnabled(true); + actionSave->setEnabled(!currentJson.empty()); + + onDisableActions(); } NEXTPNR_NAMESPACE_END diff --git a/gui/basewindow.h b/gui/basewindow.h index a25a2854..5cec24c5 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -21,6 +21,7 @@ #define BASEMAINWINDOW_H #include "nextpnr.h" +#include "worker.h" #include #include @@ -48,9 +49,17 @@ class BaseMainWindow : public QMainWindow virtual ~BaseMainWindow(); Context *getContext() { return ctx.get(); } + void load_json(std::string filename); + protected: void createMenusAndBars(); - void createGraphicsBar(); + void disableActions(); + virtual void onDisableActions(){}; + virtual void onJsonLoaded(){}; + virtual void onPackFinished(){}; + virtual void onBudgetFinished(){}; + virtual void onPlaceFinished(){}; + virtual void onRouteFinished(){}; protected Q_SLOTS: void writeInfo(std::string text); @@ -60,26 +69,56 @@ class BaseMainWindow : public QMainWindow virtual void open_proj() = 0; virtual bool save_proj() = 0; + void open_json(); + void budget(); + void place(); + + void pack_finished(bool status); + void budget_finish(bool status); + void place_finished(bool status); + void route_finished(bool status); + + void taskCanceled(); + void taskStarted(); + void taskPaused(); + Q_SIGNALS: void contextChanged(Context *ctx); void updateTreeView(); protected: + // state variables std::unique_ptr ctx; + TaskManager *task; + bool timing_driven; + std::string currentJson; + + // main widgets QTabWidget *tabWidget; QTabWidget *centralTabWidget; PythonTab *console; + DesignWidget *designview; + FPGAViewWidget *fpgaView; + // Menus, bars and actions QMenuBar *menuBar; - QToolBar *mainToolBar; - QToolBar *graphicsToolBar; + QMenu *menuDesign; QStatusBar *statusBar; + QToolBar *mainActionBar; + QProgressBar *progressBar; + QAction *actionNew; QAction *actionOpen; QAction *actionSave; - QProgressBar *progressBar; - DesignWidget *designview; - FPGAViewWidget *fpgaView; + + QAction *actionLoadJSON; + QAction *actionPack; + QAction *actionAssignBudget; + QAction *actionPlace; + QAction *actionRoute; + QAction *actionPlay; + QAction *actionPause; + QAction *actionStop; }; NEXTPNR_NAMESPACE_END diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 276b8b20..5a448235 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -55,7 +55,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), sel searchEdit->setClearButtonEnabled(true); searchEdit->addAction(QIcon(":/icons/resources/zoom.png"), QLineEdit::LeadingPosition); searchEdit->setPlaceholderText("Search..."); - connect(searchEdit, SIGNAL(returnPressed()), this, SLOT(onSearchInserted())); + connect(searchEdit, &QLineEdit::returnPressed, this, &DesignWidget::onSearchInserted); actionFirst = new QAction("", this); actionFirst->setIcon(QIcon(":/icons/resources/resultset_first.png")); @@ -162,8 +162,7 @@ DesignWidget::DesignWidget(QWidget *parent) : QWidget(parent), ctx(nullptr), sel connect(treeView, &QTreeView::customContextMenuRequested, this, &DesignWidget::prepareMenuTree); connect(treeView, &QTreeView::doubleClicked, this, &DesignWidget::onDoubleClicked); selectionModel = treeView->selectionModel(); - connect(selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), - SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &))); + connect(selectionModel, &QItemSelectionModel::selectionChanged, this, &DesignWidget::onSelectionChanged); history_index = -1; history_ignore = false; @@ -317,7 +316,7 @@ QtProperty *DesignWidget::addSubGroup(QtProperty *topItem, const QString &name) void DesignWidget::onClickedBel(BelId bel, bool keep) { - boost::optional item; + boost::optional item; { std::lock_guard lock_ui(ctx->ui_mutex); std::lock_guard lock(ctx->mutex); @@ -334,7 +333,7 @@ void DesignWidget::onClickedBel(BelId bel, bool keep) void DesignWidget::onClickedWire(WireId wire, bool keep) { - boost::optional item; + boost::optional item; { std::lock_guard lock_ui(ctx->ui_mutex); std::lock_guard lock(ctx->mutex); @@ -351,7 +350,7 @@ void DesignWidget::onClickedWire(WireId wire, bool keep) void DesignWidget::onClickedPip(PipId pip, bool keep) { - boost::optional item; + boost::optional item; { std::lock_guard lock_ui(ctx->ui_mutex); std::lock_guard lock(ctx->mutex); diff --git a/gui/designwidget.h b/gui/designwidget.h index 628586f4..c78d7232 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -53,7 +53,6 @@ class DesignWidget : public QWidget std::vector getDecals(ElementType type, IdString value); void updateHighlightGroup(QList item, int group); Q_SIGNALS: - void info(std::string text); void selected(std::vector decal, bool keep); void highlight(std::vector decal, int group); void zoomSelected(); diff --git a/gui/ecp5/mainwindow.cc b/gui/ecp5/mainwindow.cc index 4b1c7e3b..935daefd 100644 --- a/gui/ecp5/mainwindow.cc +++ b/gui/ecp5/mainwindow.cc @@ -36,13 +36,7 @@ MainWindow::MainWindow(std::unique_ptr context, QWidget *parent) : Base MainWindow::~MainWindow() {} -void MainWindow::createMenu() -{ - QMenu *menu_Custom = new QMenu("&Generic", menuBar); - menuBar->addAction(menu_Custom->menuAction()); - - createGraphicsBar(); -} +void MainWindow::createMenu() {} void MainWindow::new_proj() {} diff --git a/gui/generic/mainwindow.cc b/gui/generic/mainwindow.cc index 1efc73bb..70ee600d 100644 --- a/gui/generic/mainwindow.cc +++ b/gui/generic/mainwindow.cc @@ -36,13 +36,7 @@ MainWindow::MainWindow(std::unique_ptr context, QWidget *parent) : Base MainWindow::~MainWindow() {} -void MainWindow::createMenu() -{ - QMenu *menu_Custom = new QMenu("&Generic", menuBar); - menuBar->addAction(menu_Custom->menuAction()); - - createGraphicsBar(); -} +void MainWindow::createMenu() {} void MainWindow::new_proj() {} diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index f06971b6..2fa2e561 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -37,130 +37,45 @@ static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } NEXTPNR_NAMESPACE_BEGIN MainWindow::MainWindow(std::unique_ptr context, ArchArgs args, QWidget *parent) - : BaseMainWindow(std::move(context), parent), timing_driven(false), chipArgs(args) + : BaseMainWindow(std::move(context), parent), chipArgs(args) { initMainResource(); std::string title = "nextpnr-ice40 - [EMPTY]"; setWindowTitle(title.c_str()); - task = new TaskManager(); - connect(task, SIGNAL(log(std::string)), this, SLOT(writeInfo(std::string))); - - connect(task, SIGNAL(loadfile_finished(bool)), this, SLOT(loadfile_finished(bool))); - connect(task, SIGNAL(loadpcf_finished(bool)), this, SLOT(loadpcf_finished(bool))); - connect(task, SIGNAL(saveasc_finished(bool)), this, SLOT(saveasc_finished(bool))); - connect(task, SIGNAL(pack_finished(bool)), this, SLOT(pack_finished(bool))); - connect(task, SIGNAL(budget_finish(bool)), this, SLOT(budget_finish(bool))); - connect(task, SIGNAL(place_finished(bool)), this, SLOT(place_finished(bool))); - connect(task, SIGNAL(route_finished(bool)), this, SLOT(route_finished(bool))); - - connect(task, SIGNAL(taskCanceled()), this, SLOT(taskCanceled())); - connect(task, SIGNAL(taskStarted()), this, SLOT(taskStarted())); - connect(task, SIGNAL(taskPaused()), this, SLOT(taskPaused())); - - connect(this, SIGNAL(contextChanged(Context *)), this, SLOT(newContext(Context *))); - connect(this, SIGNAL(contextChanged(Context *)), task, SIGNAL(contextChanged(Context *))); + connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext); createMenu(); Q_EMIT contextChanged(ctx.get()); } -MainWindow::~MainWindow() { delete task; } +MainWindow::~MainWindow() {} void MainWindow::createMenu() { - QMenu *menu_Design = new QMenu("&Design", menuBar); - menuBar->addAction(menu_Design->menuAction()); - - actionLoadJSON = new QAction("Open JSON", this); - actionLoadJSON->setIcon(QIcon(":/icons/resources/open_json.png")); - actionLoadJSON->setStatusTip("Open an existing JSON file"); - actionLoadJSON->setEnabled(true); - connect(actionLoadJSON, SIGNAL(triggered()), this, SLOT(open_json())); - + // Add arch specific actions actionLoadPCF = new QAction("Open PCF", this); actionLoadPCF->setIcon(QIcon(":/icons/resources/open_pcf.png")); actionLoadPCF->setStatusTip("Open PCF file"); actionLoadPCF->setEnabled(false); - connect(actionLoadPCF, SIGNAL(triggered()), this, SLOT(open_pcf())); - - actionPack = new QAction("Pack", this); - actionPack->setIcon(QIcon(":/icons/resources/pack.png")); - actionPack->setStatusTip("Pack current design"); - actionPack->setEnabled(false); - connect(actionPack, SIGNAL(triggered()), task, SIGNAL(pack())); - - actionAssignBudget = new QAction("Assign Budget", this); - actionAssignBudget->setIcon(QIcon(":/icons/resources/time_add.png")); - actionAssignBudget->setStatusTip("Assign time budget for current design"); - actionAssignBudget->setEnabled(false); - connect(actionAssignBudget, SIGNAL(triggered()), this, SLOT(budget())); - - actionPlace = new QAction("Place", this); - actionPlace->setIcon(QIcon(":/icons/resources/place.png")); - actionPlace->setStatusTip("Place current design"); - actionPlace->setEnabled(false); - connect(actionPlace, SIGNAL(triggered()), this, SLOT(place())); - - actionRoute = new QAction("Route", this); - actionRoute->setIcon(QIcon(":/icons/resources/route.png")); - actionRoute->setStatusTip("Route current design"); - actionRoute->setEnabled(false); - connect(actionRoute, SIGNAL(triggered()), task, SIGNAL(route())); + connect(actionLoadPCF, &QAction::triggered, this, &MainWindow::open_pcf); actionSaveAsc = new QAction("Save ASC", this); actionSaveAsc->setIcon(QIcon(":/icons/resources/save_asc.png")); actionSaveAsc->setStatusTip("Save ASC file"); actionSaveAsc->setEnabled(false); - connect(actionSaveAsc, SIGNAL(triggered()), this, SLOT(save_asc())); + connect(actionSaveAsc, &QAction::triggered, this, &MainWindow::save_asc); - QToolBar *taskFPGABar = new QToolBar(); - addToolBar(Qt::TopToolBarArea, taskFPGABar); + // Add actions in menus + mainActionBar->addSeparator(); + mainActionBar->addAction(actionLoadPCF); + mainActionBar->addAction(actionSaveAsc); - taskFPGABar->addAction(actionLoadJSON); - taskFPGABar->addAction(actionLoadPCF); - taskFPGABar->addAction(actionPack); - taskFPGABar->addAction(actionAssignBudget); - taskFPGABar->addAction(actionPlace); - taskFPGABar->addAction(actionRoute); - taskFPGABar->addAction(actionSaveAsc); - - menu_Design->addAction(actionLoadJSON); - menu_Design->addAction(actionLoadPCF); - menu_Design->addAction(actionPack); - menu_Design->addAction(actionAssignBudget); - menu_Design->addAction(actionPlace); - menu_Design->addAction(actionRoute); - menu_Design->addAction(actionSaveAsc); - - actionPlay = new QAction("Play", this); - actionPlay->setIcon(QIcon(":/icons/resources/control_play.png")); - actionPlay->setStatusTip("Continue running task"); - actionPlay->setEnabled(false); - connect(actionPlay, SIGNAL(triggered()), task, SLOT(continue_thread())); - - actionPause = new QAction("Pause", this); - actionPause->setIcon(QIcon(":/icons/resources/control_pause.png")); - actionPause->setStatusTip("Pause running task"); - actionPause->setEnabled(false); - connect(actionPause, SIGNAL(triggered()), task, SLOT(pause_thread())); - - actionStop = new QAction("Stop", this); - actionStop->setIcon(QIcon(":/icons/resources/control_stop.png")); - actionStop->setStatusTip("Stop running task"); - actionStop->setEnabled(false); - connect(actionStop, SIGNAL(triggered()), task, SLOT(terminate_thread())); - - QToolBar *taskToolBar = new QToolBar(); - addToolBar(Qt::TopToolBarArea, taskToolBar); - - taskToolBar->addAction(actionPlay); - taskToolBar->addAction(actionPause); - taskToolBar->addAction(actionStop); - - createGraphicsBar(); + menuDesign->addSeparator(); + menuDesign->addAction(actionLoadPCF); + menuDesign->addAction(actionSaveAsc); } #if defined(_MSC_VER) @@ -238,19 +153,18 @@ void MainWindow::new_proj() } } -void MainWindow::load_json(std::string filename, std::string pcf) -{ - disableActions(); - currentJson = filename; - currentPCF = pcf; - Q_EMIT task->loadfile(filename); -} - void MainWindow::load_pcf(std::string filename) { disableActions(); currentPCF = filename; - Q_EMIT task->loadpcf(filename); + std::ifstream f(filename); + if (apply_pcf(ctx.get(), f)) { + log("Loading PCF successful.\n"); + actionPack->setEnabled(true); + } else { + actionLoadPCF->setEnabled(true); + log("Loading PCF failed.\n"); + } } void MainWindow::newContext(Context *ctx) @@ -331,20 +245,14 @@ void MainWindow::open_proj() } log_info("Loading json: %s...\n", json.c_str()); - load_json(json, pcf); + load_json(json); + if (!pcf.empty()) + load_pcf(json); } catch (log_execution_error_exception) { } } } -void MainWindow::open_json() -{ - QString fileName = QFileDialog::getOpenFileName(this, QString("Open JSON"), QString(), QString("*.json")); - if (!fileName.isEmpty()) { - load_json(fileName.toStdString(), ""); - } -} - void MainWindow::open_pcf() { QString fileName = QFileDialog::getOpenFileName(this, QString("Open PCF"), QString(), QString("*.pcf")); @@ -389,149 +297,19 @@ void MainWindow::save_asc() if (!fileName.isEmpty()) { std::string fn = fileName.toStdString(); disableActions(); - Q_EMIT task->saveasc(fn); - } -} - -void MainWindow::disableActions() -{ - actionLoadJSON->setEnabled(false); - actionLoadPCF->setEnabled(false); - actionPack->setEnabled(false); - actionAssignBudget->setEnabled(false); - actionPlace->setEnabled(false); - actionRoute->setEnabled(false); - actionSaveAsc->setEnabled(false); - - actionPlay->setEnabled(false); - actionPause->setEnabled(false); - actionStop->setEnabled(false); - - actionNew->setEnabled(true); - actionOpen->setEnabled(true); - actionSave->setEnabled(!currentJson.empty()); -} - -void MainWindow::loadfile_finished(bool status) -{ - disableActions(); - if (status) { - log("Loading design successful.\n"); - actionLoadPCF->setEnabled(true); - actionPack->setEnabled(true); - if (!currentPCF.empty()) - load_pcf(currentPCF); - Q_EMIT updateTreeView(); - } else { - log("Loading design failed.\n"); - currentPCF = ""; - } -} - -void MainWindow::loadpcf_finished(bool status) -{ - disableActions(); - if (status) { - log("Loading PCF successful.\n"); - actionPack->setEnabled(true); - } else { - log("Loading PCF failed.\n"); - } -} - -void MainWindow::saveasc_finished(bool status) -{ - disableActions(); - if (status) { + std::ofstream f(fn); + write_asc(ctx.get(), f); log("Saving ASC successful.\n"); - } else { - log("Saving ASC failed.\n"); } } -void MainWindow::pack_finished(bool status) +void MainWindow::onDisableActions() { - disableActions(); - if (status) { - log("Packing design successful.\n"); - Q_EMIT updateTreeView(); - actionPlace->setEnabled(true); - actionAssignBudget->setEnabled(true); - } else { - log("Packing design failed.\n"); - } + actionLoadPCF->setEnabled(false); + actionSaveAsc->setEnabled(false); } -void MainWindow::budget_finish(bool status) -{ - disableActions(); - if (status) { - log("Assigning timing budget successful.\n"); - actionPlace->setEnabled(true); - } else { - log("Assigning timing budget failed.\n"); - } -} - -void MainWindow::place_finished(bool status) -{ - disableActions(); - if (status) { - log("Placing design successful.\n"); - Q_EMIT updateTreeView(); - actionRoute->setEnabled(true); - } else { - log("Placing design failed.\n"); - } -} -void MainWindow::route_finished(bool status) -{ - disableActions(); - if (status) { - log("Routing design successful.\n"); - Q_EMIT updateTreeView(); - actionSaveAsc->setEnabled(true); - } else - log("Routing design failed.\n"); -} - -void MainWindow::taskCanceled() -{ - log("CANCELED\n"); - disableActions(); -} - -void MainWindow::taskStarted() -{ - disableActions(); - actionPause->setEnabled(true); - actionStop->setEnabled(true); - - actionNew->setEnabled(false); - actionOpen->setEnabled(false); -} - -void MainWindow::taskPaused() -{ - disableActions(); - actionPlay->setEnabled(true); - actionStop->setEnabled(true); - - actionNew->setEnabled(false); - actionOpen->setEnabled(false); -} - -void MainWindow::budget() -{ - bool ok; - double freq = QInputDialog::getDouble(this, "Assign timing budget", "Frequency [MHz]:", 50, 0, 250, 2, &ok); - if (ok) { - freq *= 1e6; - timing_driven = true; - Q_EMIT task->budget(freq); - } -} - -void MainWindow::place() { Q_EMIT task->place(timing_driven); } +void MainWindow::onJsonLoaded() { actionLoadPCF->setEnabled(true); } +void MainWindow::onRouteFinished() { actionSaveAsc->setEnabled(true); } NEXTPNR_NAMESPACE_END diff --git a/gui/ice40/mainwindow.h b/gui/ice40/mainwindow.h index 4600d1da..230ccc4e 100644 --- a/gui/ice40/mainwindow.h +++ b/gui/ice40/mainwindow.h @@ -21,7 +21,6 @@ #define MAINWINDOW_H #include "../basewindow.h" -#include "worker.h" NEXTPNR_NAMESPACE_BEGIN @@ -35,53 +34,30 @@ class MainWindow : public BaseMainWindow public: void createMenu(); - void load_json(std::string filename, std::string pcf); void load_pcf(std::string filename); + + protected: + void onDisableActions() override; + void onJsonLoaded() override; + void onRouteFinished() override; + protected Q_SLOTS: virtual void new_proj(); virtual void open_proj(); virtual bool save_proj(); - void open_json(); void open_pcf(); - void budget(); - void place(); void save_asc(); - void loadfile_finished(bool status); - void loadpcf_finished(bool status); - void saveasc_finished(bool status); - void pack_finished(bool status); - void budget_finish(bool status); - void place_finished(bool status); - void route_finished(bool status); - - void taskCanceled(); - void taskStarted(); - void taskPaused(); - void newContext(Context *ctx); private: - void disableActions(); - - TaskManager *task; - QAction *actionLoadJSON; QAction *actionLoadPCF; - QAction *actionPack; - QAction *actionAssignBudget; - QAction *actionPlace; - QAction *actionRoute; QAction *actionSaveAsc; - QAction *actionPlay; - QAction *actionPause; - QAction *actionStop; - bool timing_driven; ArchArgs chipArgs; std::string currentProj; - std::string currentJson; std::string currentPCF; }; diff --git a/gui/ice40/nextpnr.qrc b/gui/ice40/nextpnr.qrc index 3c86057d..8eca1e09 100644 --- a/gui/ice40/nextpnr.qrc +++ b/gui/ice40/nextpnr.qrc @@ -1,14 +1,6 @@ - resources/control_play.png - resources/control_pause.png - resources/control_stop.png - resources/pack.png - resources/place.png - resources/route.png - resources/time_add.png resources/open_pcf.png resources/save_asc.png - resources/open_json.png diff --git a/gui/line_editor.cc b/gui/line_editor.cc index 23415092..b25f4031 100644 --- a/gui/line_editor.cc +++ b/gui/line_editor.cc @@ -32,13 +32,13 @@ LineEditor::LineEditor(ParseHelper *helper, QWidget *parent) : QLineEdit(parent) setContextMenuPolicy(Qt::CustomContextMenu); QAction *clearAction = new QAction("Clear &history", this); clearAction->setStatusTip("Clears line edit history"); - connect(clearAction, SIGNAL(triggered()), this, SLOT(clearHistory())); + connect(clearAction, &QAction::triggered, this, &LineEditor::clearHistory); contextMenu = createStandardContextMenu(); contextMenu->addSeparator(); contextMenu->addAction(clearAction); - connect(this, SIGNAL(returnPressed()), SLOT(textInserted())); - connect(this, SIGNAL(customContextMenuRequested(const QPoint)), this, SLOT(showContextMenu(const QPoint))); + connect(this, &LineEditor::returnPressed, this, &LineEditor::textInserted); + connect(this, &LineEditor::customContextMenuRequested, this, &LineEditor::showContextMenu); } void LineEditor::keyPressEvent(QKeyEvent *ev) diff --git a/gui/pythontab.cc b/gui/pythontab.cc index e761128d..80d731e9 100644 --- a/gui/pythontab.cc +++ b/gui/pythontab.cc @@ -42,18 +42,18 @@ PythonTab::PythonTab(QWidget *parent) : QWidget(parent), initialized(false) console->setContextMenuPolicy(Qt::CustomContextMenu); QAction *clearAction = new QAction("Clear &buffer", this); clearAction->setStatusTip("Clears display buffer"); - connect(clearAction, SIGNAL(triggered()), this, SLOT(clearBuffer())); + connect(clearAction, &QAction::triggered, this, &PythonTab::clearBuffer); contextMenu = console->createStandardContextMenu(); contextMenu->addSeparator(); contextMenu->addAction(clearAction); - connect(console, SIGNAL(customContextMenuRequested(const QPoint)), this, SLOT(showContextMenu(const QPoint))); + connect(console, &PythonConsole::customContextMenuRequested, this, &PythonTab::showContextMenu); lineEdit = new LineEditor(&parseHelper); lineEdit->setMinimumHeight(30); lineEdit->setMaximumHeight(30); lineEdit->setFont(f); lineEdit->setPlaceholderText(PythonTab::PROMPT); - connect(lineEdit, SIGNAL(textLineInserted(QString)), this, SLOT(editLineReturnPressed(QString))); + connect(lineEdit, &LineEditor::textLineInserted, this, &PythonTab::editLineReturnPressed); QGridLayout *mainLayout = new QGridLayout(); mainLayout->addWidget(console, 0, 0); diff --git a/gui/ice40/resources/control_pause.png b/gui/resources/control_pause.png similarity index 100% rename from gui/ice40/resources/control_pause.png rename to gui/resources/control_pause.png diff --git a/gui/ice40/resources/control_play.png b/gui/resources/control_play.png similarity index 100% rename from gui/ice40/resources/control_play.png rename to gui/resources/control_play.png diff --git a/gui/ice40/resources/control_stop.png b/gui/resources/control_stop.png similarity index 100% rename from gui/ice40/resources/control_stop.png rename to gui/resources/control_stop.png diff --git a/gui/ice40/resources/open_json.png b/gui/resources/open_json.png similarity index 100% rename from gui/ice40/resources/open_json.png rename to gui/resources/open_json.png diff --git a/gui/ice40/resources/pack.png b/gui/resources/pack.png similarity index 100% rename from gui/ice40/resources/pack.png rename to gui/resources/pack.png diff --git a/gui/ice40/resources/place.png b/gui/resources/place.png similarity index 100% rename from gui/ice40/resources/place.png rename to gui/resources/place.png diff --git a/gui/ice40/resources/route.png b/gui/resources/route.png similarity index 100% rename from gui/ice40/resources/route.png rename to gui/resources/route.png diff --git a/gui/ice40/resources/time_add.png b/gui/resources/time_add.png similarity index 100% rename from gui/ice40/resources/time_add.png rename to gui/resources/time_add.png diff --git a/gui/ice40/worker.cc b/gui/worker.cc similarity index 77% rename from gui/ice40/worker.cc rename to gui/worker.cc index 09093ec8..b009ecd3 100644 --- a/gui/ice40/worker.cc +++ b/gui/worker.cc @@ -19,11 +19,8 @@ #include "worker.h" #include -#include "bitstream.h" #include "design_utils.h" -#include "jsonparse.h" #include "log.h" -#include "pcf.h" #include "timing.h" NEXTPNR_NAMESPACE_BEGIN @@ -55,43 +52,6 @@ Worker::Worker(TaskManager *parent) : ctx(nullptr) void Worker::newContext(Context *ctx_) { ctx = ctx_; } -void Worker::loadfile(const std::string &filename) -{ - Q_EMIT taskStarted(); - std::string fn = filename; - std::ifstream f(fn); - try { - Q_EMIT loadfile_finished(parse_json_file(f, fn, ctx)); - } catch (WorkerInterruptionRequested) { - Q_EMIT taskCanceled(); - } -} - -void Worker::loadpcf(const std::string &filename) -{ - Q_EMIT taskStarted(); - std::string fn = filename; - std::ifstream f(fn); - try { - Q_EMIT loadpcf_finished(apply_pcf(ctx, f)); - } catch (WorkerInterruptionRequested) { - Q_EMIT taskCanceled(); - } -} - -void Worker::saveasc(const std::string &filename) -{ - Q_EMIT taskStarted(); - std::string fn = filename; - std::ofstream f(fn); - try { - write_asc(ctx, f); - Q_EMIT saveasc_finished(true); - } catch (WorkerInterruptionRequested) { - Q_EMIT taskCanceled(); - } -} - void Worker::pack() { Q_EMIT taskStarted(); @@ -144,9 +104,6 @@ TaskManager::TaskManager() : toTerminate(false), toPause(false) connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); - connect(this, &TaskManager::loadfile, worker, &Worker::loadfile); - connect(this, &TaskManager::loadpcf, worker, &Worker::loadpcf); - connect(this, &TaskManager::saveasc, worker, &Worker::saveasc); connect(this, &TaskManager::pack, worker, &Worker::pack); connect(this, &TaskManager::budget, worker, &Worker::budget); connect(this, &TaskManager::place, worker, &Worker::place); @@ -155,9 +112,6 @@ TaskManager::TaskManager() : toTerminate(false), toPause(false) connect(this, &TaskManager::contextChanged, worker, &Worker::newContext); connect(worker, &Worker::log, this, &TaskManager::info); - connect(worker, &Worker::loadfile_finished, this, &TaskManager::loadfile_finished); - connect(worker, &Worker::loadpcf_finished, this, &TaskManager::loadpcf_finished); - connect(worker, &Worker::saveasc_finished, this, &TaskManager::saveasc_finished); connect(worker, &Worker::pack_finished, this, &TaskManager::pack_finished); connect(worker, &Worker::budget_finish, this, &TaskManager::budget_finish); connect(worker, &Worker::place_finished, this, &TaskManager::place_finished); diff --git a/gui/ice40/worker.h b/gui/worker.h similarity index 83% rename from gui/ice40/worker.h rename to gui/worker.h index f4369535..12a11977 100644 --- a/gui/ice40/worker.h +++ b/gui/worker.h @@ -35,18 +35,12 @@ class Worker : public QObject explicit Worker(TaskManager *parent); public Q_SLOTS: void newContext(Context *); - void loadfile(const std::string &); - void loadpcf(const std::string &); - void saveasc(const std::string &); void pack(); void budget(double freq); void place(bool timing_driven); void route(); Q_SIGNALS: void log(const std::string &text); - void loadfile_finished(bool status); - void loadpcf_finished(bool status); - void saveasc_finished(bool status); void pack_finished(bool status); void budget_finish(bool status); void place_finished(bool status); @@ -78,9 +72,6 @@ class TaskManager : public QObject Q_SIGNALS: void contextChanged(Context *ctx); void terminate(); - void loadfile(const std::string &); - void loadpcf(const std::string &); - void saveasc(const std::string &); void pack(); void budget(double freq); void place(bool timing_driven); @@ -88,9 +79,6 @@ class TaskManager : public QObject // redirected signals void log(const std::string &text); - void loadfile_finished(bool status); - void loadpcf_finished(bool status); - void saveasc_finished(bool status); void pack_finished(bool status); void budget_finish(bool status); void place_finished(bool status); diff --git a/ice40/main.cc b/ice40/main.cc index 358b46ba..4a2e9532 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -406,9 +406,11 @@ int main(int argc, char *argv[]) if (vm.count("json")) { std::string filename = vm["json"].as(); std::string pcf = ""; - if (vm.count("pcf")) + w.load_json(filename); + if (vm.count("pcf")) { pcf = vm["pcf"].as(); - w.load_json(filename, pcf); + w.load_pcf(pcf); + } } w.show();