diff options
author | Sergiusz Bazanski <q3k@q3k.org> | 2018-06-22 14:29:28 +0100 |
---|---|---|
committer | Sergiusz Bazanski <q3k@q3k.org> | 2018-06-22 14:29:28 +0100 |
commit | 858acc5c1c0ee4bbdfb8d2012b80cda656ca39db (patch) | |
tree | 7cc94b94e40c05c5a7baae61c9d0db4f23a31b60 /gui | |
parent | 98b1f0c041b01d07f64e8e04503f8eccb05a93de (diff) | |
parent | f86a0d6c8c8792c36c87cf345665ce7c9fbcc60f (diff) | |
download | nextpnr-858acc5c1c0ee4bbdfb8d2012b80cda656ca39db.tar.gz nextpnr-858acc5c1c0ee4bbdfb8d2012b80cda656ca39db.tar.bz2 nextpnr-858acc5c1c0ee4bbdfb8d2012b80cda656ca39db.zip |
Merge branch 'master' of gitlab.com:SymbioticEDA/nextpnr into q3k/gl
Diffstat (limited to 'gui')
-rw-r--r-- | gui/CMakeLists.txt | 5 | ||||
-rw-r--r-- | gui/base.qrc (renamed from gui/nextpnr.qrc) | 0 | ||||
-rw-r--r-- | gui/basewindow.cc (renamed from gui/mainwindow.cc) | 67 | ||||
-rw-r--r-- | gui/basewindow.h | 49 | ||||
-rw-r--r-- | gui/designwidget.cc | 4 | ||||
-rw-r--r-- | gui/designwidget.h | 5 | ||||
-rw-r--r-- | gui/dummy/mainwindow.cc | 30 | ||||
-rw-r--r-- | gui/dummy/mainwindow.h | 26 | ||||
-rw-r--r-- | gui/dummy/nextpnr.qrc | 2 | ||||
-rw-r--r-- | gui/emb.cc | 138 | ||||
-rw-r--r-- | gui/emb.h | 20 | ||||
-rw-r--r-- | gui/fpgaviewwidget.cc | 4 | ||||
-rw-r--r-- | gui/ice40/mainwindow.cc | 82 | ||||
-rw-r--r-- | gui/ice40/mainwindow.h | 30 | ||||
-rw-r--r-- | gui/ice40/nextpnr.qrc | 7 | ||||
-rw-r--r-- | gui/ice40/resources/control_pause.png | bin | 0 -> 598 bytes | |||
-rw-r--r-- | gui/ice40/resources/control_play.png | bin | 0 -> 592 bytes | |||
-rw-r--r-- | gui/ice40/resources/control_stop.png | bin | 0 -> 403 bytes | |||
-rw-r--r-- | gui/ice40/worker.cc | 112 | ||||
-rw-r--r-- | gui/ice40/worker.h | 55 | ||||
-rw-r--r-- | gui/infotab.cc | 4 | ||||
-rw-r--r-- | gui/infotab.h | 5 | ||||
-rw-r--r-- | gui/line_editor.cc | 7 | ||||
-rw-r--r-- | gui/line_editor.h | 5 | ||||
-rw-r--r-- | gui/mainwindow.h | 36 | ||||
-rw-r--r-- | gui/pythontab.cc | 6 | ||||
-rw-r--r-- | gui/pythontab.h | 5 |
27 files changed, 452 insertions, 252 deletions
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 5db86a9b..f19d2d20 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -2,7 +2,8 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) aux_source_directory(. GUI_SOURCE_FILES) -set(_RESOURCES nextpnr.qrc) +aux_source_directory(${family}/ GUI_SOURCE_FILES) +set(_RESOURCES base.qrc ${family}/nextpnr.qrc) qt5_add_resources(GUI_RESOURCE_FILES ${_RESOURCES}) @@ -10,6 +11,6 @@ set(GUI_LIBRARY_FILES_${ufamily} Qt5::Widgets Qt5::OpenGL ${OPENGL_LIBRARIES} Qt add_library(gui_${family} STATIC ${GUI_SOURCE_FILES} ${GUI_RESOURCE_FILES}) -target_include_directories(gui_${family} PRIVATE ../${family}/) +target_include_directories(gui_${family} PRIVATE ../${family} ${family} ../3rdparty/QtPropertyBrowser/src) target_compile_definitions(gui_${family} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family} ARCH_${ufamily} ARCHNAME=${family} QT_NO_KEYWORDS) target_link_libraries(gui_${family} Qt5::Widgets) diff --git a/gui/nextpnr.qrc b/gui/base.qrc index b9e2f237..b9e2f237 100644 --- a/gui/nextpnr.qrc +++ b/gui/base.qrc diff --git a/gui/mainwindow.cc b/gui/basewindow.cc index 91232390..f16b205d 100644 --- a/gui/mainwindow.cc +++ b/gui/basewindow.cc @@ -1,39 +1,29 @@ -#include "mainwindow.h"
#include <QAction>
#include <QFileDialog>
#include <QGridLayout>
#include <QIcon>
-#include <QMenu>
-#include <QMenuBar>
#include <QSplitter>
-#include <QStatusBar>
-#include <QToolBar>
-#include <fstream>
#include "designwidget.h"
#include "fpgaviewwidget.h"
#include "jsonparse.h"
#include "log.h"
+#include "mainwindow.h"
#include "pythontab.h"
-//#include "pack.h"
-//#include "pcf.h"
-#include "place_sa.h"
-#include "pybindings.h"
-#include "route.h"
-//#include "bitstream.h"
-#include "design_utils.h"
-
-MainWindow::MainWindow(Context *_ctx, QWidget *parent)
+
+static void initBasenameResource() { Q_INIT_RESOURCE(base); }
+
+NEXTPNR_NAMESPACE_BEGIN
+
+BaseMainWindow::BaseMainWindow(Context *_ctx, QWidget *parent)
: QMainWindow(parent), ctx(_ctx)
{
- Q_INIT_RESOURCE(nextpnr);
+ initBasenameResource();
+ qRegisterMetaType<std::string>();
log_files.clear();
log_streams.clear();
- log_write_function = [this](std::string text) { info->info(text); };
- std::string title = "nextpnr-ice40 - " + ctx->getChipName();
- setWindowTitle(title.c_str());
- setObjectName(QStringLiteral("MainWindow"));
+ setObjectName(QStringLiteral("BaseMainWindow"));
resize(1024, 768);
createMenusAndBars();
@@ -64,15 +54,19 @@ MainWindow::MainWindow(Context *_ctx, QWidget *parent) tabWidget->addTab(new PythonTab(), "Python");
info = new InfoTab();
tabWidget->addTab(info, "Info");
- splitter_v->addWidget(new FPGAViewWidget());
+
+ centralTabWidget = new QTabWidget();
+ centralTabWidget->addTab(new FPGAViewWidget(), "Graphics");
+
+ splitter_v->addWidget(centralTabWidget);
splitter_v->addWidget(tabWidget);
}
-MainWindow::~MainWindow() {}
+BaseMainWindow::~BaseMainWindow() {}
-void MainWindow::writeInfo(std::string text) { info->info(text); }
+void BaseMainWindow::writeInfo(std::string text) { info->info(text); }
-void MainWindow::createMenusAndBars()
+void BaseMainWindow::createMenusAndBars()
{
QAction *actionOpen = new QAction("Open", this);
QIcon icon1;
@@ -101,7 +95,7 @@ void MainWindow::createMenusAndBars() QAction *actionAbout = new QAction("About", this);
- QMenuBar *menuBar = new QMenuBar();
+ menuBar = new QMenuBar();
menuBar->setGeometry(QRect(0, 0, 1024, 27));
QMenu *menu_File = new QMenu("&File", menuBar);
QMenu *menu_Help = new QMenu("&Help", menuBar);
@@ -109,10 +103,10 @@ void MainWindow::createMenusAndBars() menuBar->addAction(menu_Help->menuAction());
setMenuBar(menuBar);
- QToolBar *mainToolBar = new QToolBar();
+ mainToolBar = new QToolBar();
addToolBar(Qt::TopToolBarArea, mainToolBar);
- QStatusBar *statusBar = new QStatusBar();
+ statusBar = new QStatusBar();
setStatusBar(statusBar);
menu_File->addAction(actionOpen);
@@ -125,21 +119,4 @@ void MainWindow::createMenusAndBars() mainToolBar->addAction(actionSave);
}
-void MainWindow::open()
-{
- QString fileName = QFileDialog::getOpenFileName(this, QString(), QString(),
- QString("*.json"));
- if (!fileName.isEmpty()) {
- tabWidget->setCurrentWidget(info);
-
- std::string fn = fileName.toStdString();
- std::istream *f = new std::ifstream(fn);
-
- parse_json_file(f, fn, ctx);
-
- // pack_design(ctx);
- print_utilisation(ctx);
- }
-}
-
-bool MainWindow::save() { return false; }
+NEXTPNR_NAMESPACE_END
diff --git a/gui/basewindow.h b/gui/basewindow.h new file mode 100644 index 00000000..55e4affc --- /dev/null +++ b/gui/basewindow.h @@ -0,0 +1,49 @@ +#ifndef BASEMAINWINDOW_H
+#define BASEMAINWINDOW_H
+
+#include "infotab.h"
+#include "nextpnr.h"
+
+#include <QMainWindow>
+#include <QMenu>
+#include <QMenuBar>
+#include <QStatusBar>
+#include <QTabWidget>
+#include <QToolBar>
+
+Q_DECLARE_METATYPE(std::string)
+
+NEXTPNR_NAMESPACE_BEGIN
+
+class BaseMainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+ public:
+ explicit BaseMainWindow(Context *ctx, QWidget *parent = 0);
+ virtual ~BaseMainWindow();
+ Context *getContext() { return ctx; }
+
+ protected:
+ void createMenusAndBars();
+
+ protected Q_SLOTS:
+ void writeInfo(std::string text);
+
+ virtual void open() = 0;
+ virtual bool save() = 0;
+
+ protected:
+ Context *ctx;
+ QTabWidget *tabWidget;
+ QTabWidget *centralTabWidget;
+ InfoTab *info;
+
+ QMenuBar *menuBar;
+ QToolBar *mainToolBar;
+ QStatusBar *statusBar;
+};
+
+NEXTPNR_NAMESPACE_END
+
+#endif // BASEMAINWINDOW_H
diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 40e69403..7532653d 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -7,6 +7,8 @@ #include "fpgaviewwidget.h"
#include "pybindings.h"
+NEXTPNR_NAMESPACE_BEGIN
+
enum class ElementType
{
BEL,
@@ -234,3 +236,5 @@ void DesignWidget::selectObject() {
Q_EMIT info("selected " + itemContextMenu->text(0).toStdString() + "\n");
}
+
+NEXTPNR_NAMESPACE_END
diff --git a/gui/designwidget.h b/gui/designwidget.h index 9682726c..5bd12d4d 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -7,8 +7,7 @@ #include "qttreepropertybrowser.h"
#include "qtvariantproperty.h"
-// FIXME
-USING_NEXTPNR_NAMESPACE
+NEXTPNR_NAMESPACE_BEGIN
class DesignWidget : public QWidget
{
@@ -45,4 +44,6 @@ class DesignWidget : public QWidget QMap<QString, QtVariantProperty *> idToProperty;
};
+NEXTPNR_NAMESPACE_END
+
#endif // DESIGNWIDGET_H
diff --git a/gui/dummy/mainwindow.cc b/gui/dummy/mainwindow.cc new file mode 100644 index 00000000..da162dd0 --- /dev/null +++ b/gui/dummy/mainwindow.cc @@ -0,0 +1,30 @@ +#include "mainwindow.h"
+
+static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
+
+NEXTPNR_NAMESPACE_BEGIN
+
+MainWindow::MainWindow(Context *_ctx, QWidget *parent)
+ : BaseMainWindow(_ctx, parent)
+{
+ initMainResource();
+
+ std::string title = "nextpnr-dummy - " + ctx->getChipName();
+ setWindowTitle(title.c_str());
+
+ createMenu();
+}
+
+MainWindow::~MainWindow() {}
+
+void MainWindow::createMenu()
+{
+ QMenu *menu_Custom = new QMenu("&Dummy", menuBar);
+ menuBar->addAction(menu_Custom->menuAction());
+}
+
+void MainWindow::open() {}
+
+bool MainWindow::save() { return false; }
+
+NEXTPNR_NAMESPACE_END
diff --git a/gui/dummy/mainwindow.h b/gui/dummy/mainwindow.h new file mode 100644 index 00000000..c2786906 --- /dev/null +++ b/gui/dummy/mainwindow.h @@ -0,0 +1,26 @@ +#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include "../basewindow.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+class MainWindow : public BaseMainWindow
+{
+ Q_OBJECT
+
+ public:
+ explicit MainWindow(Context *ctx, QWidget *parent = 0);
+ virtual ~MainWindow();
+
+ public:
+ void createMenu();
+
+ protected Q_SLOTS:
+ virtual void open();
+ virtual bool save();
+};
+
+NEXTPNR_NAMESPACE_END
+
+#endif // MAINWINDOW_H
diff --git a/gui/dummy/nextpnr.qrc b/gui/dummy/nextpnr.qrc new file mode 100644 index 00000000..03585ec0 --- /dev/null +++ b/gui/dummy/nextpnr.qrc @@ -0,0 +1,2 @@ +<RCC> +</RCC> diff --git a/gui/emb.cc b/gui/emb.cc deleted file mode 100644 index 2e3379d5..00000000 --- a/gui/emb.cc +++ /dev/null @@ -1,138 +0,0 @@ -// -// Copyright (C) 2011 Mateusz Loskot <mateusz@loskot.net> -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// Blog article: http://mateusz.loskot.net/?p=2819 - -#include "emb.h" -#include <Python.h> -#include <functional> -#include <iostream> -#include <string> - -namespace emb { -struct Stdout -{ - PyObject_HEAD stdout_write_type write; -}; - -PyObject *Stdout_write(PyObject *self, PyObject *args) -{ - std::size_t written(0); - Stdout *selfimpl = reinterpret_cast<Stdout *>(self); - if (selfimpl->write) { - char *data; - if (!PyArg_ParseTuple(args, "s", &data)) - return 0; - - std::string str(data); - selfimpl->write(str); - written = str.size(); - } - return PyLong_FromSize_t(written); -} - -PyObject *Stdout_flush(PyObject *self, PyObject *args) -{ - // no-op - return Py_BuildValue(""); -} - -PyMethodDef Stdout_methods[] = { - {"write", Stdout_write, METH_VARARGS, "sys.stdout.write"}, - {"flush", Stdout_flush, METH_VARARGS, "sys.stdout.write"}, - {0, 0, 0, 0} // sentinel -}; - -PyTypeObject StdoutType = { - PyVarObject_HEAD_INIT(0, 0) "emb.StdoutType", /* tp_name */ - sizeof(Stdout), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - "emb.Stdout objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Stdout_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; - -PyModuleDef embmodule = { - PyModuleDef_HEAD_INIT, "emb", 0, -1, 0, -}; - -// Internal state -PyObject *g_stdout; -PyObject *g_stdout_saved; - -PyMODINIT_FUNC PyInit_emb(void) -{ - g_stdout = 0; - g_stdout_saved = 0; - - StdoutType.tp_new = PyType_GenericNew; - if (PyType_Ready(&StdoutType) < 0) - return 0; - - PyObject *m = PyModule_Create(&embmodule); - if (m) { - Py_INCREF(&StdoutType); - PyModule_AddObject(m, "Stdout", - reinterpret_cast<PyObject *>(&StdoutType)); - } - return m; -} - -void set_stdout(stdout_write_type write) -{ - if (!g_stdout) { - g_stdout_saved = PySys_GetObject("stdout"); // borrowed - g_stdout = StdoutType.tp_new(&StdoutType, 0, 0); - } - - Stdout *impl = reinterpret_cast<Stdout *>(g_stdout); - impl->write = write; - PySys_SetObject("stdout", g_stdout); -} - -void reset_stdout() -{ - if (g_stdout_saved) - PySys_SetObject("stdout", g_stdout_saved); - - Py_XDECREF(g_stdout); - g_stdout = 0; -} - -void append_inittab() { PyImport_AppendInittab("emb", emb::PyInit_emb); } - -} // namespace emb diff --git a/gui/emb.h b/gui/emb.h deleted file mode 100644 index 3daa7ca3..00000000 --- a/gui/emb.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (C) 2011 Mateusz Loskot <mateusz@loskot.net> -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// Blog article: http://mateusz.loskot.net/?p=2819 - -#include <functional> -#include <iostream> -#include <string> - -namespace emb { -typedef std::function<void(std::string)> stdout_write_type; - -void set_stdout(stdout_write_type write); -void reset_stdout(); - -void append_inittab(); -} // namespace emb diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 4e60c56b..5dbc8952 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -217,14 +217,14 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), moveX_(0), moveY_(0), zoom_(10.0f), lineShader_(this) { - ctx = qobject_cast<MainWindow *>(getMainWindow())->getContext(); + ctx = qobject_cast<BaseMainWindow *>(getMainWindow())->getContext(); } QMainWindow *FPGAViewWidget::getMainWindow() { QWidgetList widgets = qApp->topLevelWidgets(); for (QWidgetList::iterator i = widgets.begin(); i != widgets.end(); ++i) - if ((*i)->objectName() == "MainWindow") + if ((*i)->objectName() == "BaseMainWindow") return (QMainWindow *)(*i); return NULL; } diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc new file mode 100644 index 00000000..4c7bc18f --- /dev/null +++ b/gui/ice40/mainwindow.cc @@ -0,0 +1,82 @@ +#include "mainwindow.h"
+#include <QAction>
+#include <QFileDialog>
+#include <QIcon>
+#include "bitstream.h"
+#include "design_utils.h"
+#include "jsonparse.h"
+#include "log.h"
+#include "pack.h"
+#include "pcf.h"
+#include "place_sa.h"
+#include "route.h"
+
+static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
+
+NEXTPNR_NAMESPACE_BEGIN
+
+MainWindow::MainWindow(Context *_ctx, QWidget *parent)
+ : BaseMainWindow(_ctx, parent)
+{
+ initMainResource();
+
+ std::string title = "nextpnr-ice40 - " + ctx->getChipName();
+ setWindowTitle(title.c_str());
+
+ task = new TaskManager(_ctx);
+ connect(task, SIGNAL(log(std::string)), this, SLOT(writeInfo(std::string)));
+
+ createMenu();
+}
+
+MainWindow::~MainWindow() { delete task; }
+
+void MainWindow::createMenu()
+{
+ QMenu *menu_Custom = new QMenu("&ICE 40", menuBar);
+ menuBar->addAction(menu_Custom->menuAction());
+
+ QAction *actionPlay = new QAction("Play", this);
+ QIcon icon1;
+ icon1.addFile(QStringLiteral(":/icons/resources/control_play.png"));
+ actionPlay->setIcon(icon1);
+ actionPlay->setStatusTip("Continue running task");
+ connect(actionPlay, SIGNAL(triggered()), task, SLOT(continue_thread()));
+
+ QAction *actionPause = new QAction("Pause", this);
+ QIcon icon2;
+ icon2.addFile(QStringLiteral(":/icons/resources/control_pause.png"));
+ actionPause->setIcon(icon2);
+ actionPause->setStatusTip("Pause running task");
+ connect(actionPause, SIGNAL(triggered()), task, SLOT(pause_thread()));
+
+ QAction *actionStop = new QAction("Stop", this);
+ QIcon icon3;
+ icon3.addFile(QStringLiteral(":/icons/resources/control_stop.png"));
+ actionStop->setIcon(icon3);
+ actionStop->setStatusTip("Stop running task");
+ 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);
+}
+
+void MainWindow::open()
+{
+ QString fileName = QFileDialog::getOpenFileName(this, QString(), QString(),
+ QString("*.json"));
+ if (!fileName.isEmpty()) {
+ tabWidget->setCurrentWidget(info);
+
+ std::string fn = fileName.toStdString();
+ Q_EMIT task->parsejson(fn);
+ }
+}
+
+bool MainWindow::save() { return false; }
+
+NEXTPNR_NAMESPACE_END
\ No newline at end of file diff --git a/gui/ice40/mainwindow.h b/gui/ice40/mainwindow.h new file mode 100644 index 00000000..712f341a --- /dev/null +++ b/gui/ice40/mainwindow.h @@ -0,0 +1,30 @@ +#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include "../basewindow.h"
+#include "worker.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+class MainWindow : public BaseMainWindow
+{
+ Q_OBJECT
+
+ public:
+ explicit MainWindow(Context *ctx, QWidget *parent = 0);
+ virtual ~MainWindow();
+
+ public:
+ void createMenu();
+
+ protected Q_SLOTS:
+ virtual void open();
+ virtual bool save();
+
+ private:
+ TaskManager *task;
+};
+
+NEXTPNR_NAMESPACE_END
+
+#endif // MAINWINDOW_H
diff --git a/gui/ice40/nextpnr.qrc b/gui/ice40/nextpnr.qrc new file mode 100644 index 00000000..cbdb8b26 --- /dev/null +++ b/gui/ice40/nextpnr.qrc @@ -0,0 +1,7 @@ +<RCC> + <qresource prefix="/icons"> + <file>resources/control_play.png</file> + <file>resources/control_pause.png</file> + <file>resources/control_stop.png</file> + </qresource> +</RCC> diff --git a/gui/ice40/resources/control_pause.png b/gui/ice40/resources/control_pause.png Binary files differnew file mode 100644 index 00000000..2d9ce9c4 --- /dev/null +++ b/gui/ice40/resources/control_pause.png diff --git a/gui/ice40/resources/control_play.png b/gui/ice40/resources/control_play.png Binary files differnew file mode 100644 index 00000000..0846555d --- /dev/null +++ b/gui/ice40/resources/control_play.png diff --git a/gui/ice40/resources/control_stop.png b/gui/ice40/resources/control_stop.png Binary files differnew file mode 100644 index 00000000..893bb60e --- /dev/null +++ b/gui/ice40/resources/control_stop.png diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc new file mode 100644 index 00000000..9549f659 --- /dev/null +++ b/gui/ice40/worker.cc @@ -0,0 +1,112 @@ +#include "worker.h" +#include <fstream> +#include "bitstream.h" +#include "design_utils.h" +#include "jsonparse.h" +#include "log.h" +#include "pack.h" +#include "pcf.h" +#include "place_sa.h" +#include "route.h" +#include "timing.h" + +NEXTPNR_NAMESPACE_BEGIN + +struct WorkerInterruptionRequested +{ +}; + +Worker::Worker(Context *_ctx, TaskManager *parent) : ctx(_ctx) +{ + log_write_function = [this, parent](std::string text) { + Q_EMIT log(text); + if (parent->shouldTerminate()) { + parent->clearTerminate(); + throw WorkerInterruptionRequested(); + } + while (parent->isPaused()) { + QThread::sleep(1); + } + }; +} + +void Worker::parsejson(const std::string &filename) +{ + std::string fn = filename; + std::ifstream f(fn); + try { + if (!parse_json_file(f, fn, ctx)) + log_error("Loading design failed.\n"); + if (!pack_design(ctx)) + log_error("Packing design failed.\n"); + double freq = 50e6; + assign_budget(ctx, freq); + print_utilisation(ctx); + + if (!place_design_sa(ctx)) + log_error("Placing design failed.\n"); + if (!route_design(ctx)) + log_error("Routing design failed.\n"); + Q_EMIT log("DONE\n"); + } catch (log_execution_error_exception) { + } catch (WorkerInterruptionRequested) { + Q_EMIT log("CANCELED\n"); + } +} + +TaskManager::TaskManager(Context *ctx) : toTerminate(false), toPause(false) +{ + Worker *worker = new Worker(ctx, this); + worker->moveToThread(&workerThread); + connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); + connect(this, &TaskManager::parsejson, worker, &Worker::parsejson); + connect(worker, &Worker::log, this, &TaskManager::info); + workerThread.start(); +} + +TaskManager::~TaskManager() +{ + if (workerThread.isRunning()) + terminate_thread(); + workerThread.quit(); + workerThread.wait(); +} + +void TaskManager::info(const std::string &result) { Q_EMIT log(result); } + +void TaskManager::terminate_thread() +{ + QMutexLocker locker(&mutex); + toTerminate = true; +} + +bool TaskManager::shouldTerminate() +{ + QMutexLocker locker(&mutex); + return toTerminate; +} + +void TaskManager::clearTerminate() +{ + QMutexLocker locker(&mutex); + toTerminate = false; +} + +void TaskManager::pause_thread() +{ + QMutexLocker locker(&mutex); + toPause = true; +} + +void TaskManager::continue_thread() +{ + QMutexLocker locker(&mutex); + toPause = false; +} +bool TaskManager::isPaused() +{ + QMutexLocker locker(&mutex); + return toPause; +} + +NEXTPNR_NAMESPACE_END diff --git a/gui/ice40/worker.h b/gui/ice40/worker.h new file mode 100644 index 00000000..181fafa3 --- /dev/null +++ b/gui/ice40/worker.h @@ -0,0 +1,55 @@ +#ifndef WORKER_H +#define WORKER_H + +#include <QMutex> +#include <QThread> +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +class TaskManager; + +class Worker : public QObject +{ + Q_OBJECT + public: + Worker(Context *ctx, TaskManager *parent); + public Q_SLOTS: + void parsejson(const std::string &filename); + Q_SIGNALS: + void log(const std::string &text); + + private: + Context *ctx; +}; + +class TaskManager : public QObject +{ + Q_OBJECT + QThread workerThread; + + public: + TaskManager(Context *ctx); + ~TaskManager(); + bool shouldTerminate(); + void clearTerminate(); + bool isPaused(); + public Q_SLOTS: + void info(const std::string &text); + void terminate_thread(); + void pause_thread(); + void continue_thread(); + Q_SIGNALS: + void terminate(); + void parsejson(const std::string &); + void log(const std::string &text); + + private: + QMutex mutex; + bool toTerminate; + bool toPause; +}; + +NEXTPNR_NAMESPACE_END + +#endif // WORKER_H diff --git a/gui/infotab.cc b/gui/infotab.cc index 7690b83c..29d557d2 100644 --- a/gui/infotab.cc +++ b/gui/infotab.cc @@ -1,6 +1,8 @@ #include "infotab.h"
#include <QGridLayout>
+NEXTPNR_NAMESPACE_BEGIN
+
InfoTab::InfoTab(QWidget *parent) : QWidget(parent)
{
plainTextEdit = new QPlainTextEdit();
@@ -37,3 +39,5 @@ void InfoTab::showContextMenu(const QPoint &pt) }
void InfoTab::clearBuffer() { plainTextEdit->clear(); }
+
+NEXTPNR_NAMESPACE_END
diff --git a/gui/infotab.h b/gui/infotab.h index d7f1408c..3e0220c4 100644 --- a/gui/infotab.h +++ b/gui/infotab.h @@ -5,8 +5,7 @@ #include <QPlainTextEdit>
#include "nextpnr.h"
-// FIXME
-USING_NEXTPNR_NAMESPACE
+NEXTPNR_NAMESPACE_BEGIN
class InfoTab : public QWidget
{
@@ -24,4 +23,6 @@ class InfoTab : public QWidget QMenu *contextMenu;
};
+NEXTPNR_NAMESPACE_END
+
#endif // INFOTAB_H
diff --git a/gui/line_editor.cc b/gui/line_editor.cc index b5ed955f..6299c9cc 100644 --- a/gui/line_editor.cc +++ b/gui/line_editor.cc @@ -1,7 +1,8 @@ #include "line_editor.h" - #include <QKeyEvent> +NEXTPNR_NAMESPACE_BEGIN + LineEditor::LineEditor(QWidget *parent) : QLineEdit(parent), index(0) { setContextMenuPolicy(Qt::CustomContextMenu); @@ -64,4 +65,6 @@ void LineEditor::clearHistory() lines.clear(); index = 0; clear(); -}
\ No newline at end of file +} + +NEXTPNR_NAMESPACE_END
\ No newline at end of file diff --git a/gui/line_editor.h b/gui/line_editor.h index 15b675f9..5f27e502 100644 --- a/gui/line_editor.h +++ b/gui/line_editor.h @@ -3,6 +3,9 @@ #include <QLineEdit> #include <QMenu> +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN class LineEditor : public QLineEdit { @@ -28,4 +31,6 @@ class LineEditor : public QLineEdit QMenu *contextMenu; }; +NEXTPNR_NAMESPACE_END + #endif // LINE_EDITOR_H diff --git a/gui/mainwindow.h b/gui/mainwindow.h deleted file mode 100644 index 35d917d9..00000000 --- a/gui/mainwindow.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MAINWINDOW_H
-#define MAINWINDOW_H
-
-#include "infotab.h"
-#include "nextpnr.h"
-
-#include <QMainWindow>
-#include <QTabWidget>
-
-// FIXME
-USING_NEXTPNR_NAMESPACE
-
-class MainWindow : public QMainWindow
-{
- Q_OBJECT
-
- public:
- explicit MainWindow(Context *ctx, QWidget *parent = 0);
- ~MainWindow();
- Context *getContext() { return ctx; }
-
- private:
- void createMenusAndBars();
-
- private Q_SLOTS:
- void writeInfo(std::string text);
- void open();
- bool save();
-
- private:
- Context *ctx;
- QTabWidget *tabWidget;
- InfoTab *info;
-};
-
-#endif // MAINWINDOW_H
diff --git a/gui/pythontab.cc b/gui/pythontab.cc index 96a6c4b9..19aa0162 100644 --- a/gui/pythontab.cc +++ b/gui/pythontab.cc @@ -3,6 +3,8 @@ #include "emb.h"
#include "pybindings.h"
+NEXTPNR_NAMESPACE_BEGIN
+
PythonTab::PythonTab(QWidget *parent) : QWidget(parent)
{
PyImport_ImportModule("emb");
@@ -114,4 +116,6 @@ void PythonTab::showContextMenu(const QPoint &pt) contextMenu->exec(mapToGlobal(pt));
}
-void PythonTab::clearBuffer() { plainTextEdit->clear(); }
\ No newline at end of file +void PythonTab::clearBuffer() { plainTextEdit->clear(); }
+
+NEXTPNR_NAMESPACE_END
diff --git a/gui/pythontab.h b/gui/pythontab.h index 5aed8b0b..52a8ff8d 100644 --- a/gui/pythontab.h +++ b/gui/pythontab.h @@ -8,8 +8,7 @@ #include "line_editor.h"
#include "nextpnr.h"
-// FIXME
-USING_NEXTPNR_NAMESPACE
+NEXTPNR_NAMESPACE_BEGIN
class PythonTab : public QWidget
{
@@ -33,4 +32,6 @@ class PythonTab : public QWidget emb::stdout_write_type write;
};
+NEXTPNR_NAMESPACE_END
+
#endif // PYTHONTAB_H
|