diff options
Diffstat (limited to 'gui/ice40')
-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 |
8 files changed, 286 insertions, 0 deletions
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 |