1 /*
2 * nextpnr -- Next Generation Place and Route
3 *
4 * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "mainwindow.h"
21 #include <QAction>
22 #include <QFileDialog>
23 #include <QFileInfo>
24 #include <QIcon>
25 #include <QInputDialog>
26 #include <QLineEdit>
27 #include <fstream>
28 #include "bitstream.h"
29 #include "design_utils.h"
30 #include "log.h"
31 #include "pcf.h"
32
initMainResource()33 static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
34
35 NEXTPNR_NAMESPACE_BEGIN
36
MainWindow(std::unique_ptr<Context> context,CommandHandler * handler,QWidget * parent)37 MainWindow::MainWindow(std::unique_ptr<Context> context, CommandHandler *handler, QWidget *parent)
38 : BaseMainWindow(std::move(context), handler, parent)
39 {
40 initMainResource();
41
42 std::string title = "nextpnr-ice40 - [EMPTY]";
43 setWindowTitle(title.c_str());
44
45 connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext);
46
47 createMenu();
48 }
49
~MainWindow()50 MainWindow::~MainWindow() {}
51
createMenu()52 void MainWindow::createMenu()
53 {
54 // Add arch specific actions
55 actionLoadPCF = new QAction("Open PCF", this);
56 actionLoadPCF->setIcon(QIcon(":/icons/resources/open_pcf.png"));
57 actionLoadPCF->setStatusTip("Open PCF file");
58 actionLoadPCF->setEnabled(false);
59 connect(actionLoadPCF, &QAction::triggered, this, &MainWindow::open_pcf);
60
61 actionSaveAsc = new QAction("Save ASC", this);
62 actionSaveAsc->setIcon(QIcon(":/icons/resources/save_asc.png"));
63 actionSaveAsc->setStatusTip("Save ASC file");
64 actionSaveAsc->setEnabled(false);
65 connect(actionSaveAsc, &QAction::triggered, this, &MainWindow::save_asc);
66
67 // Add actions in menus
68 mainActionBar->addSeparator();
69 mainActionBar->addAction(actionLoadPCF);
70 mainActionBar->addAction(actionSaveAsc);
71
72 menuDesign->addSeparator();
73 menuDesign->addAction(actionLoadPCF);
74 menuDesign->addAction(actionSaveAsc);
75 }
76
new_proj()77 void MainWindow::new_proj()
78 {
79 QMap<QString, int> arch;
80 if (Arch::isAvailable(ArchArgs::LP384))
81 arch.insert("Lattice iCE40LP384", ArchArgs::LP384);
82 if (Arch::isAvailable(ArchArgs::LP1K))
83 arch.insert("Lattice iCE40LP1K", ArchArgs::LP1K);
84 if (Arch::isAvailable(ArchArgs::HX1K))
85 arch.insert("Lattice iCE40HX1K", ArchArgs::HX1K);
86 if (Arch::isAvailable(ArchArgs::U1K))
87 arch.insert("Lattice iCE5LP1K", ArchArgs::U1K);
88 if (Arch::isAvailable(ArchArgs::U2K))
89 arch.insert("Lattice iCE5LP2K", ArchArgs::U2K);
90 if (Arch::isAvailable(ArchArgs::U4K))
91 arch.insert("Lattice iCE5LP4K", ArchArgs::U4K);
92 if (Arch::isAvailable(ArchArgs::UP3K))
93 arch.insert("Lattice iCE40UP3K", ArchArgs::UP3K);
94 if (Arch::isAvailable(ArchArgs::UP5K))
95 arch.insert("Lattice iCE40UP5K", ArchArgs::UP5K);
96 if (Arch::isAvailable(ArchArgs::LP4K))
97 arch.insert("Lattice iCE40LP4K", ArchArgs::LP4K);
98 if (Arch::isAvailable(ArchArgs::LP8K))
99 arch.insert("Lattice iCE40LP8K", ArchArgs::LP8K);
100 if (Arch::isAvailable(ArchArgs::HX4K))
101 arch.insert("Lattice iCE40HX4K", ArchArgs::HX4K);
102 if (Arch::isAvailable(ArchArgs::HX8K))
103 arch.insert("Lattice iCE40HX8K", ArchArgs::HX8K);
104
105 bool ok;
106 QString item = QInputDialog::getItem(this, "Select new context", "Chip:", arch.keys(), 0, false, &ok);
107 if (ok && !item.isEmpty()) {
108 ArchArgs chipArgs;
109 chipArgs.type = (ArchArgs::ArchArgsTypes)arch.value(item);
110
111 QStringList packages;
112 for (auto package : Arch::getSupportedPackages(chipArgs.type))
113 packages.append(QLatin1String(package.data(), package.size()));
114 QString package = QInputDialog::getItem(this, "Select package", "Package:", packages, 0, false, &ok);
115
116 if (ok && !item.isEmpty()) {
117 handler->clear();
118 currentProj = "";
119 disableActions();
120 chipArgs.package = package.toStdString().c_str();
121 ctx = std::unique_ptr<Context>(new Context(chipArgs));
122 actionLoadJSON->setEnabled(true);
123
124 Q_EMIT contextChanged(ctx.get());
125 }
126 }
127 }
128
load_pcf(std::string filename)129 void MainWindow::load_pcf(std::string filename)
130 {
131 disableActions();
132 std::ifstream f(filename);
133 if (apply_pcf(ctx.get(), filename, f)) {
134 log("Loading PCF successful.\n");
135 actionPack->setEnabled(true);
136 } else {
137 actionLoadPCF->setEnabled(true);
138 log("Loading PCF failed.\n");
139 }
140 }
141
newContext(Context * ctx)142 void MainWindow::newContext(Context *ctx)
143 {
144 std::string title = "nextpnr-ice40 - " + ctx->getChipName() + " ( " + ctx->archArgs().package + " )";
145 setWindowTitle(title.c_str());
146 }
147
open_pcf()148 void MainWindow::open_pcf()
149 {
150 QString fileName = QFileDialog::getOpenFileName(this, QString("Open PCF"), QString(), QString("*.pcf"));
151 if (!fileName.isEmpty()) {
152 load_pcf(fileName.toStdString());
153 }
154 }
155
save_asc()156 void MainWindow::save_asc()
157 {
158 QString fileName = QFileDialog::getSaveFileName(this, QString("Save ASC"), QString(), QString("*.asc"));
159 if (!fileName.isEmpty()) {
160 std::string fn = fileName.toStdString();
161 disableActions();
162 std::ofstream f(fn);
163 write_asc(ctx.get(), f);
164 log("Saving ASC successful.\n");
165 }
166 }
167
onDisableActions()168 void MainWindow::onDisableActions()
169 {
170 actionLoadPCF->setEnabled(false);
171 actionSaveAsc->setEnabled(false);
172 }
173
onUpdateActions()174 void MainWindow::onUpdateActions()
175 {
176 if (ctx->settings.find(ctx->id("pack")) == ctx->settings.end())
177 actionLoadPCF->setEnabled(true);
178 if (ctx->settings.find(ctx->id("route")) != ctx->settings.end())
179 actionSaveAsc->setEnabled(true);
180 }
181
182 NEXTPNR_NAMESPACE_END
183