diff --git a/ecp5/arch.h b/ecp5/arch.h index cd103b12..6daf543d 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -384,7 +384,7 @@ struct PipRange struct ArchArgs { - enum + enum ArchArgsTypes { NONE, LFE5U_25F, diff --git a/ecp5/main.cc b/ecp5/main.cc index dac7a635..dde3ffed 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -148,7 +148,7 @@ int main(int argc, char *argv[]) #ifndef NO_GUI if (vm.count("gui")) { Application a(argc, argv); - MainWindow w(std::move(ctx)); + MainWindow w(std::move(ctx),args); w.show(); return a.exec(); diff --git a/generic/arch.cc b/generic/arch.cc index f9133f9e..7c0828e0 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -175,7 +175,7 @@ void Arch::setGroupDecal(GroupId group, DecalXY decalxy) // --------------------------------------------------------------- -Arch::Arch(ArchArgs) {} +Arch::Arch(ArchArgs) : chipName("generic") {} void IdString::initialize_arch(const BaseCtx *ctx) {} diff --git a/generic/main.cc b/generic/main.cc index 3b8b3fe6..8653da01 100644 --- a/generic/main.cc +++ b/generic/main.cc @@ -90,7 +90,8 @@ int main(int argc, char *argv[]) return 1; } - std::unique_ptr ctx = std::unique_ptr(new Context(ArchArgs{})); + ArchArgs chipArgs{}; + std::unique_ptr ctx = std::unique_ptr(new Context(chipArgs)); if (vm.count("verbose")) { ctx->verbose = true; @@ -107,7 +108,7 @@ int main(int argc, char *argv[]) #ifndef NO_GUI if (vm.count("gui")) { Application a(argc, argv); - MainWindow w(std::move(ctx)); + MainWindow w(std::move(ctx), chipArgs); w.show(); return a.exec(); diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 37141fd6..53720156 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -37,8 +37,8 @@ static void initBasenameResource() { Q_INIT_RESOURCE(base); } NEXTPNR_NAMESPACE_BEGIN -BaseMainWindow::BaseMainWindow(std::unique_ptr context, QWidget *parent) - : QMainWindow(parent), ctx(std::move(context)), timing_driven(false) +BaseMainWindow::BaseMainWindow(std::unique_ptr context, ArchArgs args, QWidget *parent) + : QMainWindow(parent), chipArgs(args), ctx(std::move(context)), timing_driven(false) { initBasenameResource(); qRegisterMetaType(); diff --git a/gui/basewindow.h b/gui/basewindow.h index 5cec24c5..341cc8e2 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -45,7 +45,7 @@ class BaseMainWindow : public QMainWindow Q_OBJECT public: - explicit BaseMainWindow(std::unique_ptr context, QWidget *parent = 0); + explicit BaseMainWindow(std::unique_ptr context, ArchArgs args, QWidget *parent = 0); virtual ~BaseMainWindow(); Context *getContext() { return ctx.get(); } @@ -88,6 +88,7 @@ class BaseMainWindow : public QMainWindow protected: // state variables + ArchArgs chipArgs; std::unique_ptr ctx; TaskManager *task; bool timing_driven; diff --git a/gui/ecp5/mainwindow.cc b/gui/ecp5/mainwindow.cc index 935daefd..efaad364 100644 --- a/gui/ecp5/mainwindow.cc +++ b/gui/ecp5/mainwindow.cc @@ -18,30 +18,148 @@ */ #include "mainwindow.h" +#include "bitstream.h" +#include "log.h" + +#include +#include +#include static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } NEXTPNR_NAMESPACE_BEGIN -MainWindow::MainWindow(std::unique_ptr context, QWidget *parent) : BaseMainWindow(std::move(context), parent) +MainWindow::MainWindow(std::unique_ptr context, ArchArgs args, QWidget *parent) : BaseMainWindow(std::move(context), args, parent) { initMainResource(); std::string title = "nextpnr-ecp5 - [EMPTY]"; setWindowTitle(title.c_str()); + connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext); + createMenu(); Q_EMIT contextChanged(ctx.get()); } MainWindow::~MainWindow() {} -void MainWindow::createMenu() {} +void MainWindow::newContext(Context *ctx) +{ + std::string title = "nextpnr-generic - " + ctx->getChipName() + " ( " + chipArgs.package + " )"; + setWindowTitle(title.c_str()); +} -void MainWindow::new_proj() {} +void MainWindow::createMenu() { + // Add arch specific actions + actionLoadBase = new QAction("Open Base Config", this); + actionLoadBase->setIcon(QIcon(":/icons/resources/open_base.png")); + actionLoadBase->setStatusTip("Open Base Config file"); + actionLoadBase->setEnabled(false); + connect(actionLoadBase, &QAction::triggered, this, &MainWindow::open_base); + + actionSaveConfig = new QAction("Save Bitstream", this); + actionSaveConfig->setIcon(QIcon(":/icons/resources/save_config.png")); + actionSaveConfig->setStatusTip("Save Bitstream config file"); + actionSaveConfig->setEnabled(false); + connect(actionSaveConfig, &QAction::triggered, this, &MainWindow::save_config); + + // Add actions in menus + mainActionBar->addSeparator(); + mainActionBar->addAction(actionLoadBase); + mainActionBar->addAction(actionSaveConfig); + + menuDesign->addSeparator(); + menuDesign->addAction(actionLoadBase); + menuDesign->addAction(actionSaveConfig); +} + +static const ChipInfoPOD *get_chip_info(const RelPtr *ptr) { return ptr->get(); } + +static QStringList getSupportedPackages(ArchArgs::ArchArgsTypes chip) +{ + QStringList packages; + const ChipInfoPOD *chip_info; + if (chip == ArchArgs::LFE5U_25F) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_25k)); + } else if (chip == ArchArgs::LFE5U_45F) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_45k)); + } else if (chip == ArchArgs::LFE5U_85F) { + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_85k)); + } else { + log_error("Unsupported ECP5 chip type.\n"); + } + + for (int i = 0; i < chip_info->num_packages; i++) { + packages << chip_info->package_info[i].name.get(); + } + return packages; +} + + +void MainWindow::new_proj() { + QMap arch; + arch.insert("Lattice ECP5 25K", ArchArgs::LFE5U_25F); + arch.insert("Lattice ECP5 45K", ArchArgs::LFE5U_45F); + arch.insert("Lattice ECP5 85K", ArchArgs::LFE5U_85F); + bool ok; + QString item = QInputDialog::getItem(this, "Select new context", "Chip:", arch.keys(), 0, false, &ok); + if (ok && !item.isEmpty()) { + + chipArgs.type = (ArchArgs::ArchArgsTypes)arch.value(item); + + QString package = QInputDialog::getItem(this, "Select package", "Package:", getSupportedPackages(chipArgs.type), + 0, false, &ok); + + if (ok && !item.isEmpty()) { + currentProj = ""; + currentJson = ""; + disableActions(); + chipArgs.package = package.toStdString().c_str(); + ctx = std::unique_ptr(new Context(chipArgs)); + actionLoadJSON->setEnabled(true); + + Q_EMIT contextChanged(ctx.get()); + } + } +} void MainWindow::open_proj() {} bool MainWindow::save_proj() { return false; } +void MainWindow::load_base_config(std::string filename) +{ + disableActions(); + currentBaseConfig = filename; + actionSaveConfig->setEnabled(true); +} + +void MainWindow::open_base() +{ + QString fileName = QFileDialog::getOpenFileName(this, QString("Open Base Config"), QString(), QString("*.config")); + if (!fileName.isEmpty()) { + load_base_config(fileName.toStdString()); + } +} + +void MainWindow::save_config() +{ + QString fileName = QFileDialog::getSaveFileName(this, QString("Save Bitstream"), QString(), QString("*.config")); + if (!fileName.isEmpty()) { + std::string fn = fileName.toStdString(); + disableActions(); + write_bitstream(ctx.get(), currentBaseConfig, fileName.toStdString()); + log("Saving Bitstream successful.\n"); + } +} + +void MainWindow::onDisableActions() +{ + actionLoadBase->setEnabled(false); + actionSaveConfig->setEnabled(false); +} + +void MainWindow::onRouteFinished() { actionLoadBase->setEnabled(true); } + NEXTPNR_NAMESPACE_END diff --git a/gui/ecp5/mainwindow.h b/gui/ecp5/mainwindow.h index e97bb4e7..d1d5a5a2 100644 --- a/gui/ecp5/mainwindow.h +++ b/gui/ecp5/mainwindow.h @@ -29,16 +29,32 @@ class MainWindow : public BaseMainWindow Q_OBJECT public: - explicit MainWindow(std::unique_ptr context, QWidget *parent = 0); + explicit MainWindow(std::unique_ptr context, ArchArgs args, QWidget *parent = 0); virtual ~MainWindow(); public: void createMenu(); + void load_base_config(std::string filename); + + protected: + void onDisableActions() override; + void onRouteFinished() override; protected Q_SLOTS: virtual void new_proj(); virtual void open_proj(); virtual bool save_proj(); + void newContext(Context *ctx); + void open_base(); + void save_config(); + private: + QAction *actionLoadBase; + QAction *actionSaveConfig; + + ArchArgs chipArgs; + + std::string currentProj; + std::string currentBaseConfig; }; NEXTPNR_NAMESPACE_END diff --git a/gui/ecp5/nextpnr.qrc b/gui/ecp5/nextpnr.qrc index 03585ec0..09f96d74 100644 --- a/gui/ecp5/nextpnr.qrc +++ b/gui/ecp5/nextpnr.qrc @@ -1,2 +1,6 @@ + + resources/open_base.png + resources/save_config.png + diff --git a/gui/ecp5/resources/open_base.png b/gui/ecp5/resources/open_base.png new file mode 100644 index 00000000..d58d226c Binary files /dev/null and b/gui/ecp5/resources/open_base.png differ diff --git a/gui/ecp5/resources/save_config.png b/gui/ecp5/resources/save_config.png new file mode 100644 index 00000000..2ade7128 Binary files /dev/null and b/gui/ecp5/resources/save_config.png differ diff --git a/gui/generic/mainwindow.cc b/gui/generic/mainwindow.cc index 70ee600d..050c0fb8 100644 --- a/gui/generic/mainwindow.cc +++ b/gui/generic/mainwindow.cc @@ -23,19 +23,27 @@ static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } NEXTPNR_NAMESPACE_BEGIN -MainWindow::MainWindow(std::unique_ptr context, QWidget *parent) : BaseMainWindow(std::move(context), parent) +MainWindow::MainWindow(std::unique_ptr context, ArchArgs args, QWidget *parent) : BaseMainWindow(std::move(context), args, parent) { initMainResource(); std::string title = "nextpnr-generic - [EMPTY]"; setWindowTitle(title.c_str()); + connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext); + createMenu(); Q_EMIT contextChanged(ctx.get()); } MainWindow::~MainWindow() {} +void MainWindow::newContext(Context *ctx) +{ + std::string title = "nextpnr-generic - " + ctx->getChipName(); + setWindowTitle(title.c_str()); +} + void MainWindow::createMenu() {} void MainWindow::new_proj() {} diff --git a/gui/generic/mainwindow.h b/gui/generic/mainwindow.h index e97bb4e7..375436b6 100644 --- a/gui/generic/mainwindow.h +++ b/gui/generic/mainwindow.h @@ -29,7 +29,7 @@ class MainWindow : public BaseMainWindow Q_OBJECT public: - explicit MainWindow(std::unique_ptr context, QWidget *parent = 0); + explicit MainWindow(std::unique_ptr context, ArchArgs args, QWidget *parent = 0); virtual ~MainWindow(); public: @@ -39,6 +39,7 @@ class MainWindow : public BaseMainWindow virtual void new_proj(); virtual void open_proj(); virtual bool save_proj(); + void newContext(Context *ctx); }; NEXTPNR_NAMESPACE_END diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index 2fa2e561..40b863e9 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -37,7 +37,7 @@ static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } NEXTPNR_NAMESPACE_BEGIN MainWindow::MainWindow(std::unique_ptr context, ArchArgs args, QWidget *parent) - : BaseMainWindow(std::move(context), parent), chipArgs(args) + : BaseMainWindow(std::move(context), args, parent) { initMainResource(); @@ -78,18 +78,11 @@ void MainWindow::createMenu() menuDesign->addAction(actionSaveAsc); } -#if defined(_MSC_VER) -void load_chipdb(); -#endif - static const ChipInfoPOD *get_chip_info(const RelPtr *ptr) { return ptr->get(); } -QStringList getSupportedPackages(ArchArgs::ArchArgsTypes chip) +static QStringList getSupportedPackages(ArchArgs::ArchArgsTypes chip) { QStringList packages; -#if defined(_MSC_VER) - load_chipdb(); -#endif const ChipInfoPOD *chip_info; #ifdef ICE40_HX1K_ONLY if (chip == ArchArgs::HX1K) { diff --git a/gui/ice40/mainwindow.h b/gui/ice40/mainwindow.h index 230ccc4e..829375e2 100644 --- a/gui/ice40/mainwindow.h +++ b/gui/ice40/mainwindow.h @@ -55,8 +55,6 @@ class MainWindow : public BaseMainWindow QAction *actionLoadPCF; QAction *actionSaveAsc; - ArchArgs chipArgs; - std::string currentProj; std::string currentPCF; };