aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/command.cc10
-rw-r--r--common/project.cc62
-rw-r--r--common/project.h5
-rw-r--r--ecp5/project.cc2
-rw-r--r--generic/project.cc2
-rw-r--r--gui/basewindow.cc34
-rw-r--r--gui/basewindow.h5
-rw-r--r--gui/ecp5/mainwindow.cc2
-rw-r--r--gui/ecp5/mainwindow.h1
-rw-r--r--gui/generic/mainwindow.cc1
-rw-r--r--gui/ice40/mainwindow.cc14
-rw-r--r--gui/ice40/mainwindow.h2
-rw-r--r--ice40/delay.cc2
-rw-r--r--ice40/main.cc5
-rw-r--r--ice40/pcf.cc3
-rw-r--r--ice40/pcf.h2
-rw-r--r--ice40/project.cc10
-rw-r--r--json/jsonparse.cc1
18 files changed, 105 insertions, 58 deletions
diff --git a/common/command.cc b/common/command.cc
index 736f6201..54111130 100644
--- a/common/command.cc
+++ b/common/command.cc
@@ -168,12 +168,16 @@ int CommandHandler::executeMain(std::unique_ptr<Context> ctx)
if (vm.count("json")) {
std::string filename = vm["json"].as<std::string>();
std::ifstream f(filename);
+ w.notifyChangeContext();
if (!parse_json_file(f, filename, w.getContext()))
log_error("Loading design failed.\n");
customAfterLoad(w.getContext());
- w.updateJsonLoaded();
- }
+ w.updateLoaded();
+ } else if (vm.count("load")) {
+ w.projectLoad(vm["load"].as<std::string>());
+ } else
+ w.notifyChangeContext();
} catch (log_execution_error_exception) {
// show error is handled by gui itself
}
@@ -247,7 +251,7 @@ int CommandHandler::exec()
return 0;
std::unique_ptr<Context> ctx;
- if (vm.count("load")) {
+ if (vm.count("load") && vm.count("gui") == 0) {
ctx = project.load(vm["load"].as<std::string>());
} else {
ctx = createContext();
diff --git a/common/project.cc b/common/project.cc
index 244ca761..949f6878 100644
--- a/common/project.cc
+++ b/common/project.cc
@@ -26,19 +26,53 @@
NEXTPNR_NAMESPACE_BEGIN
+boost::filesystem::path make_relative(boost::filesystem::path child, boost::filesystem::path parent)
+{
+ boost::filesystem::path::const_iterator parentIter = parent.begin();
+ boost::filesystem::path::const_iterator childIter = child.begin();
+
+ while (parentIter != parent.end() && childIter != child.end() && (*childIter) == (*parentIter)) {
+ ++childIter;
+ ++parentIter;
+ }
+
+ boost::filesystem::path finalPath;
+ while (parentIter != parent.end()) {
+ finalPath /= "..";
+ ++parentIter;
+ }
+
+ while (childIter != child.end()) {
+ finalPath /= *childIter;
+ ++childIter;
+ }
+
+ return finalPath;
+}
+
void ProjectHandler::save(Context *ctx, std::string filename)
{
- std::ofstream f(filename);
- pt::ptree root;
- root.put("project.version", 1);
- root.put("project.name", boost::filesystem::basename(filename));
- root.put("project.arch.name", ctx->archId().c_str(ctx));
- root.put("project.arch.type", ctx->archArgsToId(ctx->archArgs()).c_str(ctx));
- /* root.put("project.input.json", );*/
- root.put("project.params.freq", int(ctx->target_freq / 1e6));
- root.put("project.params.seed", ctx->rngstate);
- saveArch(ctx, root);
- pt::write_json(f, root);
+ try {
+ boost::filesystem::path proj(filename);
+ std::ofstream f(filename);
+ pt::ptree root;
+
+ log_info("Saving project %s...\n", filename.c_str());
+ log_break();
+
+ root.put("project.version", 1);
+ root.put("project.name", boost::filesystem::basename(filename));
+ root.put("project.arch.name", ctx->archId().c_str(ctx));
+ root.put("project.arch.type", ctx->archArgsToId(ctx->archArgs()).c_str(ctx));
+ std::string fn = ctx->settings[ctx->id("project/input/json")];
+ root.put("project.input.json", make_relative(fn, proj.parent_path()).string());
+ root.put("project.params.freq", int(ctx->target_freq / 1e6));
+ root.put("project.params.seed", ctx->rngstate);
+ saveArch(ctx, root, proj.parent_path().string());
+ pt::write_json(f, root);
+ } catch (...) {
+ log_error("Error saving project file.\n");
+ }
}
std::unique_ptr<Context> ProjectHandler::load(std::string filename)
@@ -63,10 +97,10 @@ std::unique_ptr<Context> ProjectHandler::load(std::string filename)
auto project = root.get_child("project");
auto input = project.get_child("input");
- std::string filename = input.get<std::string>("json");
- boost::filesystem::path json = proj.parent_path() / filename;
+ std::string fn = input.get<std::string>("json");
+ boost::filesystem::path json = proj.parent_path() / fn;
std::ifstream f(json.string());
- if (!parse_json_file(f, filename, ctx.get()))
+ if (!parse_json_file(f, fn, ctx.get()))
log_error("Loading design failed.\n");
if (project.count("params")) {
diff --git a/common/project.h b/common/project.h
index 14f03ecd..03b4b7b5 100644
--- a/common/project.h
+++ b/common/project.h
@@ -20,6 +20,7 @@
#ifndef PROJECT_H
#define PROJECT_H
+#include <boost/filesystem/convenience.hpp>
#include <boost/property_tree/ptree.hpp>
#include "nextpnr.h"
@@ -32,11 +33,13 @@ struct ProjectHandler
void save(Context *ctx, std::string filename);
std::unique_ptr<Context> load(std::string filename);
// implemented per arch
- void saveArch(Context *ctx, pt::ptree &root);
+ void saveArch(Context *ctx, pt::ptree &root, std::string path);
std::unique_ptr<Context> createContext(pt::ptree &root);
void loadArch(Context *ctx, pt::ptree &root, std::string path);
};
+boost::filesystem::path make_relative(boost::filesystem::path child, boost::filesystem::path parent);
+
NEXTPNR_NAMESPACE_END
#endif // PROJECT_H
diff --git a/ecp5/project.cc b/ecp5/project.cc
index 6c1f6a94..bca21643 100644
--- a/ecp5/project.cc
+++ b/ecp5/project.cc
@@ -25,7 +25,7 @@
NEXTPNR_NAMESPACE_BEGIN
-void ProjectHandler::saveArch(Context *ctx, pt::ptree &root)
+void ProjectHandler::saveArch(Context *ctx, pt::ptree &root, std::string path)
{
root.put("project.arch.package", ctx->archArgs().package);
root.put("project.arch.speed", ctx->archArgs().speed);
diff --git a/generic/project.cc b/generic/project.cc
index 8103e91f..342fcac3 100644
--- a/generic/project.cc
+++ b/generic/project.cc
@@ -24,7 +24,7 @@
NEXTPNR_NAMESPACE_BEGIN
-void ProjectHandler::saveArch(Context *ctx, pt::ptree &root) {}
+void ProjectHandler::saveArch(Context *ctx, pt::ptree &root, std::string path) {}
std::unique_ptr<Context> ProjectHandler::createContext(pt::ptree &root)
{
diff --git a/gui/basewindow.cc b/gui/basewindow.cc
index 857919ea..66df3ca4 100644
--- a/gui/basewindow.cc
+++ b/gui/basewindow.cc
@@ -298,12 +298,11 @@ void BaseMainWindow::createMenusAndBars()
void BaseMainWindow::load_json(std::string filename)
{
disableActions();
- currentJson = filename;
std::ifstream f(filename);
if (parse_json_file(f, filename, ctx.get())) {
log("Loading design successful.\n");
Q_EMIT updateTreeView();
- updateJsonLoaded();
+ updateLoaded();
} else {
actionLoadJSON->setEnabled(true);
log("Loading design failed.\n");
@@ -420,35 +419,42 @@ void BaseMainWindow::disableActions()
actionNew->setEnabled(true);
actionOpen->setEnabled(true);
- actionSave->setEnabled(!currentJson.empty());
+
+ if (ctx->settings.find(ctx->id("project/input/json")) != ctx->settings.end())
+ actionSave->setEnabled(true);
+ else
+ actionSave->setEnabled(false);
onDisableActions();
}
-void BaseMainWindow::updateJsonLoaded()
+void BaseMainWindow::updateLoaded()
{
disableActions();
actionPack->setEnabled(true);
onJsonLoaded();
+ onProjectLoaded();
+}
+
+void BaseMainWindow::projectLoad(std::string filename)
+{
+ ProjectHandler proj;
+ disableActions();
+ ctx = proj.load(filename);
+ Q_EMIT contextChanged(ctx.get());
+ log_info("Loaded project %s...\n", filename.c_str());
+ updateLoaded();
}
void BaseMainWindow::open_proj()
{
QString fileName = QFileDialog::getOpenFileName(this, QString("Open Project"), QString(), QString("*.proj"));
if (!fileName.isEmpty()) {
- try {
- ProjectHandler proj;
- disableActions();
- ctx = proj.load(fileName.toStdString());
- Q_EMIT contextChanged(ctx.get());
- log_info("Loaded project %s...\n", fileName.toStdString().c_str());
- updateJsonLoaded();
- onProjectLoaded();
- } catch (log_execution_error_exception) {
- }
+ projectLoad(fileName.toStdString());
}
}
+void BaseMainWindow::notifyChangeContext() { Q_EMIT contextChanged(ctx.get()); }
void BaseMainWindow::save_proj()
{
if (currentProj.empty()) {
diff --git a/gui/basewindow.h b/gui/basewindow.h
index 6e8f8587..eb32033a 100644
--- a/gui/basewindow.h
+++ b/gui/basewindow.h
@@ -48,7 +48,9 @@ class BaseMainWindow : public QMainWindow
explicit BaseMainWindow(std::unique_ptr<Context> context, ArchArgs args, QWidget *parent = 0);
virtual ~BaseMainWindow();
Context *getContext() { return ctx.get(); }
- void updateJsonLoaded();
+ void updateLoaded();
+ void projectLoad(std::string filename);
+ void notifyChangeContext();
protected:
void createMenusAndBars();
@@ -95,7 +97,6 @@ class BaseMainWindow : public QMainWindow
std::unique_ptr<Context> ctx;
TaskManager *task;
bool timing_driven;
- std::string currentJson;
std::string currentProj;
// main widgets
diff --git a/gui/ecp5/mainwindow.cc b/gui/ecp5/mainwindow.cc
index 4fc8be16..b3c53849 100644
--- a/gui/ecp5/mainwindow.cc
+++ b/gui/ecp5/mainwindow.cc
@@ -40,7 +40,6 @@ MainWindow::MainWindow(std::unique_ptr<Context> context, ArchArgs args, QWidget
connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext);
createMenu();
- Q_EMIT contextChanged(ctx.get());
}
MainWindow::~MainWindow() {}
@@ -115,7 +114,6 @@ void MainWindow::new_proj()
if (ok && !item.isEmpty()) {
currentProj = "";
- currentJson = "";
disableActions();
chipArgs.package = package.toStdString().c_str();
ctx = std::unique_ptr<Context>(new Context(chipArgs));
diff --git a/gui/ecp5/mainwindow.h b/gui/ecp5/mainwindow.h
index aa1af17b..f85c2abc 100644
--- a/gui/ecp5/mainwindow.h
+++ b/gui/ecp5/mainwindow.h
@@ -52,7 +52,6 @@ class MainWindow : public BaseMainWindow
ArchArgs chipArgs;
- std::string currentProj;
std::string currentBaseConfig;
};
diff --git a/gui/generic/mainwindow.cc b/gui/generic/mainwindow.cc
index 76837ed4..12912cc9 100644
--- a/gui/generic/mainwindow.cc
+++ b/gui/generic/mainwindow.cc
@@ -34,7 +34,6 @@ MainWindow::MainWindow(std::unique_ptr<Context> context, ArchArgs args, QWidget
connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext);
createMenu();
- Q_EMIT contextChanged(ctx.get());
}
MainWindow::~MainWindow() {}
diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc
index 35ad5768..9fe80717 100644
--- a/gui/ice40/mainwindow.cc
+++ b/gui/ice40/mainwindow.cc
@@ -46,8 +46,6 @@ MainWindow::MainWindow(std::unique_ptr<Context> context, ArchArgs args, QWidget
connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext);
createMenu();
-
- Q_EMIT contextChanged(ctx.get());
}
MainWindow::~MainWindow() {}
@@ -133,8 +131,6 @@ void MainWindow::new_proj()
if (ok && !item.isEmpty()) {
currentProj = "";
- currentJson = "";
- currentPCF = "";
disableActions();
chipArgs.package = package.toStdString().c_str();
ctx = std::unique_ptr<Context>(new Context(chipArgs));
@@ -148,9 +144,8 @@ void MainWindow::new_proj()
void MainWindow::load_pcf(std::string filename)
{
disableActions();
- currentPCF = filename;
std::ifstream f(filename);
- if (apply_pcf(ctx.get(), f)) {
+ if (apply_pcf(ctx.get(), filename, f)) {
log("Loading PCF successful.\n");
actionPack->setEnabled(true);
} else {
@@ -193,6 +188,11 @@ void MainWindow::onDisableActions()
void MainWindow::onJsonLoaded() { actionLoadPCF->setEnabled(true); }
void MainWindow::onRouteFinished() { actionSaveAsc->setEnabled(true); }
-void MainWindow::onProjectLoaded() { actionLoadPCF->setEnabled(false); }
+
+void MainWindow::onProjectLoaded()
+{
+ if (ctx->settings.find(ctx->id("project/input/pcf")) != ctx->settings.end())
+ actionLoadPCF->setEnabled(false);
+}
NEXTPNR_NAMESPACE_END
diff --git a/gui/ice40/mainwindow.h b/gui/ice40/mainwindow.h
index 201bf1b1..bb8ed75f 100644
--- a/gui/ice40/mainwindow.h
+++ b/gui/ice40/mainwindow.h
@@ -54,8 +54,6 @@ class MainWindow : public BaseMainWindow
private:
QAction *actionLoadPCF;
QAction *actionSaveAsc;
-
- std::string currentPCF;
};
NEXTPNR_NAMESPACE_END
diff --git a/ice40/delay.cc b/ice40/delay.cc
index dd2a4969..d76aaefb 100644
--- a/ice40/delay.cc
+++ b/ice40/delay.cc
@@ -121,7 +121,7 @@ struct model_params_t
int delta_sp4;
int delta_sp12;
- static const model_params_t &get(ArchArgs args)
+ static const model_params_t &get(const ArchArgs& args)
{
static const model_params_t model_hx8k = {588, 129253, 8658, 118333, 23915, -73105, 57696,
-86797, 89, 3706, -316, -575, -158, -296};
diff --git a/ice40/main.cc b/ice40/main.cc
index 2818a3ad..8bab360d 100644
--- a/ice40/main.cc
+++ b/ice40/main.cc
@@ -79,8 +79,9 @@ void Ice40CommandHandler::validate()
void Ice40CommandHandler::customAfterLoad(Context *ctx)
{
if (vm.count("pcf")) {
- std::ifstream pcf(vm["pcf"].as<std::string>());
- if (!apply_pcf(ctx, pcf))
+ std::string filename = vm["pcf"].as<std::string>();
+ std::ifstream pcf(filename);
+ if (!apply_pcf(ctx, filename, pcf))
log_error("Loading PCF failed.\n");
}
}
diff --git a/ice40/pcf.cc b/ice40/pcf.cc
index 410fa1c9..d9fc4e68 100644
--- a/ice40/pcf.cc
+++ b/ice40/pcf.cc
@@ -27,7 +27,7 @@ NEXTPNR_NAMESPACE_BEGIN
// Read a w
// Apply PCF constraints to a pre-packing design
-bool apply_pcf(Context *ctx, std::istream &in)
+bool apply_pcf(Context *ctx, std::string filename, std::istream &in)
{
try {
if (!in)
@@ -66,6 +66,7 @@ bool apply_pcf(Context *ctx, std::istream &in)
log_error("unsupported pcf command '%s'\n", cmd.c_str());
}
}
+ ctx->settings.emplace(ctx->id("project/input/pcf"), filename);
return true;
} catch (log_execution_error_exception) {
return false;
diff --git a/ice40/pcf.h b/ice40/pcf.h
index 315f6270..ecc81e59 100644
--- a/ice40/pcf.h
+++ b/ice40/pcf.h
@@ -27,7 +27,7 @@
NEXTPNR_NAMESPACE_BEGIN
// Apply PCF constraints to a pre-packing design
-bool apply_pcf(Context *ctx, std::istream &in);
+bool apply_pcf(Context *ctx, std::string filename, std::istream &in);
NEXTPNR_NAMESPACE_END
diff --git a/ice40/project.cc b/ice40/project.cc
index d1f1674a..8ca10e36 100644
--- a/ice40/project.cc
+++ b/ice40/project.cc
@@ -25,11 +25,13 @@
NEXTPNR_NAMESPACE_BEGIN
-void ProjectHandler::saveArch(Context *ctx, pt::ptree &root)
+void ProjectHandler::saveArch(Context *ctx, pt::ptree &root, std::string path)
{
root.put("project.arch.package", ctx->archArgs().package);
- // if(!pcfFilename.empty())
- // root.put("project.input.pcf", pcfFilename);
+ if (ctx->settings.find(ctx->id("project/input/pcf")) != ctx->settings.end()) {
+ std::string fn = ctx->settings[ctx->id("project/input/pcf")];
+ root.put("project.input.pcf", make_relative(fn, path).string());
+ }
}
std::unique_ptr<Context> ProjectHandler::createContext(pt::ptree &root)
@@ -64,7 +66,7 @@ void ProjectHandler::loadArch(Context *ctx, pt::ptree &root, std::string path)
auto input = root.get_child("project").get_child("input");
boost::filesystem::path pcf = boost::filesystem::path(path) / input.get<std::string>("pcf");
std::ifstream f(pcf.string());
- if (!apply_pcf(ctx, f))
+ if (!apply_pcf(ctx, input.get<std::string>("pcf"), f))
log_error("Loading PCF failed.\n");
}
diff --git a/json/jsonparse.cc b/json/jsonparse.cc
index 89c2b8d9..9e86f93e 100644
--- a/json/jsonparse.cc
+++ b/json/jsonparse.cc
@@ -754,6 +754,7 @@ bool parse_json_file(std::istream &f, std::string &filename, Context *ctx)
log_info("Checksum: 0x%08x\n", ctx->checksum());
log_break();
+ ctx->settings.emplace(ctx->id("project/input/json"), filename);
return true;
} catch (log_execution_error_exception) {
return false;