diff options
Diffstat (limited to 'gui/worker.cc')
-rw-r--r-- | gui/worker.cc | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/gui/worker.cc b/gui/worker.cc new file mode 100644 index 00000000..b009ecd3 --- /dev/null +++ b/gui/worker.cc @@ -0,0 +1,175 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "worker.h" +#include <fstream> +#include "design_utils.h" +#include "log.h" +#include "timing.h" + +NEXTPNR_NAMESPACE_BEGIN + +struct WorkerInterruptionRequested +{ +}; + +Worker::Worker(TaskManager *parent) : ctx(nullptr) +{ + log_write_function = [this, parent](std::string text) { + Q_EMIT log(text); + if (parent->shouldTerminate()) { + parent->clearTerminate(); + throw WorkerInterruptionRequested(); + } + if (parent->isPaused()) { + Q_EMIT taskPaused(); + } + while (parent->isPaused()) { + if (parent->shouldTerminate()) { + parent->clearTerminate(); + throw WorkerInterruptionRequested(); + } + QThread::sleep(1); + } + }; +} + +void Worker::newContext(Context *ctx_) { ctx = ctx_; } + +void Worker::pack() +{ + Q_EMIT taskStarted(); + try { + bool res = ctx->pack(); + print_utilisation(ctx); + Q_EMIT pack_finished(res); + } catch (WorkerInterruptionRequested) { + Q_EMIT taskCanceled(); + } +} + +void Worker::budget(double freq) +{ + Q_EMIT taskStarted(); + try { + ctx->target_freq = freq; + assign_budget(ctx); + Q_EMIT budget_finish(true); + } catch (WorkerInterruptionRequested) { + Q_EMIT taskCanceled(); + } +} + +void Worker::place(bool timing_driven) +{ + Q_EMIT taskStarted(); + try { + ctx->timing_driven = timing_driven; + Q_EMIT place_finished(ctx->place()); + } catch (WorkerInterruptionRequested) { + Q_EMIT taskCanceled(); + } +} + +void Worker::route() +{ + Q_EMIT taskStarted(); + try { + Q_EMIT route_finished(ctx->route()); + } catch (WorkerInterruptionRequested) { + Q_EMIT taskCanceled(); + } +} + +TaskManager::TaskManager() : toTerminate(false), toPause(false) +{ + Worker *worker = new Worker(this); + worker->moveToThread(&workerThread); + + connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); + + connect(this, &TaskManager::pack, worker, &Worker::pack); + connect(this, &TaskManager::budget, worker, &Worker::budget); + connect(this, &TaskManager::place, worker, &Worker::place); + connect(this, &TaskManager::route, worker, &Worker::route); + + connect(this, &TaskManager::contextChanged, worker, &Worker::newContext); + + connect(worker, &Worker::log, this, &TaskManager::info); + 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); + connect(worker, &Worker::route_finished, this, &TaskManager::route_finished); + + connect(worker, &Worker::taskCanceled, this, &TaskManager::taskCanceled); + connect(worker, &Worker::taskStarted, this, &TaskManager::taskStarted); + connect(worker, &Worker::taskPaused, this, &TaskManager::taskPaused); + + 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); + toPause = false; + 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; + Q_EMIT taskStarted(); +} + +bool TaskManager::isPaused() +{ + QMutexLocker locker(&mutex); + return toPause; +} + +NEXTPNR_NAMESPACE_END |