From a761b772c8294858590c4abced272d04bd58aad3 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 2 Aug 2018 18:10:01 +0200 Subject: Make worker generic --- gui/ice40/mainwindow.cc | 73 ++++++---------- gui/ice40/mainwindow.h | 5 +- gui/ice40/worker.cc | 221 ------------------------------------------------ gui/ice40/worker.h | 110 ------------------------ gui/worker.cc | 175 ++++++++++++++++++++++++++++++++++++++ gui/worker.h | 98 +++++++++++++++++++++ ice40/main.cc | 6 +- 7 files changed, 304 insertions(+), 384 deletions(-) delete mode 100644 gui/ice40/worker.cc delete mode 100644 gui/ice40/worker.h create mode 100644 gui/worker.cc create mode 100644 gui/worker.h diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index f06971b6..bc790296 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -47,9 +47,6 @@ MainWindow::MainWindow(std::unique_ptr context, ArchArgs args, QWidget 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))); @@ -238,19 +235,34 @@ void MainWindow::new_proj() } } -void MainWindow::load_json(std::string filename, std::string pcf) +void MainWindow::load_json(std::string filename) { disableActions(); currentJson = filename; - currentPCF = pcf; - Q_EMIT task->loadfile(filename); + std::ifstream f(filename); + if (parse_json_file(f, filename, ctx.get())) { + log("Loading design successful.\n"); + actionLoadPCF->setEnabled(true); + actionPack->setEnabled(true); + Q_EMIT updateTreeView(); + } else { + actionLoadJSON->setEnabled(true); + log("Loading design failed.\n"); + } } 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,7 +343,9 @@ 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) { } } @@ -341,7 +355,7 @@ void MainWindow::open_json() { QString fileName = QFileDialog::getOpenFileName(this, QString("Open JSON"), QString(), QString("*.json")); if (!fileName.isEmpty()) { - load_json(fileName.toStdString(), ""); + load_json(fileName.toStdString()); } } @@ -389,7 +403,9 @@ void MainWindow::save_asc() if (!fileName.isEmpty()) { std::string fn = fileName.toStdString(); disableActions(); - Q_EMIT task->saveasc(fn); + std::ofstream f(fn); + write_asc(ctx.get(), f); + log("Saving ASC successful.\n"); } } @@ -412,43 +428,6 @@ void MainWindow::disableActions() 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) { - log("Saving ASC successful.\n"); - } else { - log("Saving ASC failed.\n"); - } -} - void MainWindow::pack_finished(bool status) { disableActions(); diff --git a/gui/ice40/mainwindow.h b/gui/ice40/mainwindow.h index 4600d1da..b71af162 100644 --- a/gui/ice40/mainwindow.h +++ b/gui/ice40/mainwindow.h @@ -35,7 +35,7 @@ class MainWindow : public BaseMainWindow public: void createMenu(); - void load_json(std::string filename, std::string pcf); + void load_json(std::string filename); void load_pcf(std::string filename); protected Q_SLOTS: virtual void new_proj(); @@ -48,9 +48,6 @@ class MainWindow : public BaseMainWindow 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); diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc deleted file mode 100644 index 09093ec8..00000000 --- a/gui/ice40/worker.cc +++ /dev/null @@ -1,221 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2018 Miodrag Milanovic - * - * 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 -#include "bitstream.h" -#include "design_utils.h" -#include "jsonparse.h" -#include "log.h" -#include "pcf.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::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(); - 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::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); - connect(this, &TaskManager::route, worker, &Worker::route); - - 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); - 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 diff --git a/gui/ice40/worker.h b/gui/ice40/worker.h deleted file mode 100644 index f4369535..00000000 --- a/gui/ice40/worker.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2018 Miodrag Milanovic - * - * 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. - * - */ - -#ifndef WORKER_H -#define WORKER_H - -#include -#include -#include "nextpnr.h" - -NEXTPNR_NAMESPACE_BEGIN - -class TaskManager; - -class Worker : public QObject -{ - Q_OBJECT - public: - 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); - void route_finished(bool status); - void taskCanceled(); - void taskStarted(); - void taskPaused(); - - private: - Context *ctx; -}; - -class TaskManager : public QObject -{ - Q_OBJECT - QThread workerThread; - - public: - explicit TaskManager(); - ~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 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); - void route(); - - // 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); - void route_finished(bool status); - void taskCanceled(); - void taskStarted(); - void taskPaused(); - - private: - QMutex mutex; - bool toTerminate; - bool toPause; -}; - -NEXTPNR_NAMESPACE_END - -#endif // WORKER_H 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 + * + * 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 +#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 diff --git a/gui/worker.h b/gui/worker.h new file mode 100644 index 00000000..12a11977 --- /dev/null +++ b/gui/worker.h @@ -0,0 +1,98 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Miodrag Milanovic + * + * 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. + * + */ + +#ifndef WORKER_H +#define WORKER_H + +#include +#include +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +class TaskManager; + +class Worker : public QObject +{ + Q_OBJECT + public: + explicit Worker(TaskManager *parent); + public Q_SLOTS: + void newContext(Context *); + void pack(); + void budget(double freq); + void place(bool timing_driven); + void route(); + Q_SIGNALS: + void log(const std::string &text); + 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(); + + private: + Context *ctx; +}; + +class TaskManager : public QObject +{ + Q_OBJECT + QThread workerThread; + + public: + explicit TaskManager(); + ~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 contextChanged(Context *ctx); + void terminate(); + void pack(); + void budget(double freq); + void place(bool timing_driven); + void route(); + + // redirected signals + void log(const std::string &text); + 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(); + + private: + QMutex mutex; + bool toTerminate; + bool toPause; +}; + +NEXTPNR_NAMESPACE_END + +#endif // WORKER_H diff --git a/ice40/main.cc b/ice40/main.cc index 358b46ba..4a2e9532 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -406,9 +406,11 @@ int main(int argc, char *argv[]) if (vm.count("json")) { std::string filename = vm["json"].as(); std::string pcf = ""; - if (vm.count("pcf")) + w.load_json(filename); + if (vm.count("pcf")) { pcf = vm["pcf"].as(); - w.load_json(filename, pcf); + w.load_pcf(pcf); + } } w.show(); -- cgit v1.2.3