@ -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
|
||||
|
@ -14,5 +14,13 @@
|
||||
<file>resources/zoom_out.png</file>
|
||||
<file>resources/shape_handles.png</file>
|
||||
<file>resources/shape_square.png</file>
|
||||
<file>resources/control_play.png</file>
|
||||
<file>resources/control_pause.png</file>
|
||||
<file>resources/control_stop.png</file>
|
||||
<file>resources/pack.png</file>
|
||||
<file>resources/place.png</file>
|
||||
<file>resources/route.png</file>
|
||||
<file>resources/time_add.png</file>
|
||||
<file>resources/open_json.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -23,9 +23,12 @@
|
||||
#include <QFileDialog>
|
||||
#include <QGridLayout>
|
||||
#include <QIcon>
|
||||
#include <QInputDialog>
|
||||
#include <QSplitter>
|
||||
#include <fstream>
|
||||
#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> context, QWidget *parent)
|
||||
: QMainWindow(parent), ctx(std::move(context))
|
||||
: QMainWindow(parent), ctx(std::move(context)), timing_driven(false)
|
||||
{
|
||||
initBasenameResource();
|
||||
qRegisterMetaType<std::string>();
|
||||
@ -46,10 +49,10 @@ BaseMainWindow::BaseMainWindow(std::unique_ptr<Context> 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> 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<DecalXY>, bool)), fpgaView,
|
||||
SLOT(onSelectedArchItem(std::vector<DecalXY>, 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<DecalXY>, int)), fpgaView,
|
||||
SLOT(onHighlightGroupChanged(std::vector<DecalXY>, 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
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define BASEMAINWINDOW_H
|
||||
|
||||
#include "nextpnr.h"
|
||||
#include "worker.h"
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QMenu>
|
||||
@ -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<Context> 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
|
||||
|
@ -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<TreeModel::Item*> item;
|
||||
boost::optional<TreeModel::Item *> item;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock_ui(ctx->ui_mutex);
|
||||
std::lock_guard<std::mutex> lock(ctx->mutex);
|
||||
@ -334,7 +333,7 @@ void DesignWidget::onClickedBel(BelId bel, bool keep)
|
||||
|
||||
void DesignWidget::onClickedWire(WireId wire, bool keep)
|
||||
{
|
||||
boost::optional<TreeModel::Item*> item;
|
||||
boost::optional<TreeModel::Item *> item;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock_ui(ctx->ui_mutex);
|
||||
std::lock_guard<std::mutex> lock(ctx->mutex);
|
||||
@ -351,7 +350,7 @@ void DesignWidget::onClickedWire(WireId wire, bool keep)
|
||||
|
||||
void DesignWidget::onClickedPip(PipId pip, bool keep)
|
||||
{
|
||||
boost::optional<TreeModel::Item*> item;
|
||||
boost::optional<TreeModel::Item *> item;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock_ui(ctx->ui_mutex);
|
||||
std::lock_guard<std::mutex> lock(ctx->mutex);
|
||||
|
@ -53,7 +53,6 @@ class DesignWidget : public QWidget
|
||||
std::vector<DecalXY> getDecals(ElementType type, IdString value);
|
||||
void updateHighlightGroup(QList<TreeModel::Item *> item, int group);
|
||||
Q_SIGNALS:
|
||||
void info(std::string text);
|
||||
void selected(std::vector<DecalXY> decal, bool keep);
|
||||
void highlight(std::vector<DecalXY> decal, int group);
|
||||
void zoomSelected();
|
||||
|
@ -36,13 +36,7 @@ MainWindow::MainWindow(std::unique_ptr<Context> 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() {}
|
||||
|
||||
|
@ -36,13 +36,7 @@ MainWindow::MainWindow(std::unique_ptr<Context> 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() {}
|
||||
|
||||
|
@ -37,130 +37,45 @@ static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
MainWindow::MainWindow(std::unique_ptr<Context> 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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -1,14 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/icons">
|
||||
<file>resources/control_play.png</file>
|
||||
<file>resources/control_pause.png</file>
|
||||
<file>resources/control_stop.png</file>
|
||||
<file>resources/pack.png</file>
|
||||
<file>resources/place.png</file>
|
||||
<file>resources/route.png</file>
|
||||
<file>resources/time_add.png</file>
|
||||
<file>resources/open_pcf.png</file>
|
||||
<file>resources/save_asc.png</file>
|
||||
<file>resources/open_json.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 721 B |
Before Width: | Height: | Size: 717 B After Width: | Height: | Size: 717 B |
Before Width: | Height: | Size: 695 B After Width: | Height: | Size: 695 B |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 853 B After Width: | Height: | Size: 853 B |
Before Width: | Height: | Size: 825 B After Width: | Height: | Size: 825 B |
Before Width: | Height: | Size: 683 B After Width: | Height: | Size: 683 B |
Before Width: | Height: | Size: 827 B After Width: | Height: | Size: 827 B |
@ -19,11 +19,8 @@
|
||||
|
||||
#include "worker.h"
|
||||
#include <fstream>
|
||||
#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);
|
@ -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);
|
@ -406,9 +406,11 @@ int main(int argc, char *argv[])
|
||||
if (vm.count("json")) {
|
||||
std::string filename = vm["json"].as<std::string>();
|
||||
std::string pcf = "";
|
||||
if (vm.count("pcf"))
|
||||
w.load_json(filename);
|
||||
if (vm.count("pcf")) {
|
||||
pcf = vm["pcf"].as<std::string>();
|
||||
w.load_json(filename, pcf);
|
||||
w.load_pcf(pcf);
|
||||
}
|
||||
}
|
||||
w.show();
|
||||
|
||||
|