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  | 
