diff options
-rw-r--r-- | common/command.cc | 10 | ||||
-rw-r--r-- | common/project.cc | 62 | ||||
-rw-r--r-- | common/project.h | 5 | ||||
-rw-r--r-- | ecp5/project.cc | 2 | ||||
-rw-r--r-- | generic/project.cc | 2 | ||||
-rw-r--r-- | gui/basewindow.cc | 34 | ||||
-rw-r--r-- | gui/basewindow.h | 5 | ||||
-rw-r--r-- | gui/ecp5/mainwindow.cc | 2 | ||||
-rw-r--r-- | gui/ecp5/mainwindow.h | 1 | ||||
-rw-r--r-- | gui/generic/mainwindow.cc | 1 | ||||
-rw-r--r-- | gui/ice40/mainwindow.cc | 14 | ||||
-rw-r--r-- | gui/ice40/mainwindow.h | 2 | ||||
-rw-r--r-- | ice40/delay.cc | 2 | ||||
-rw-r--r-- | ice40/main.cc | 5 | ||||
-rw-r--r-- | ice40/pcf.cc | 3 | ||||
-rw-r--r-- | ice40/pcf.h | 2 | ||||
-rw-r--r-- | ice40/project.cc | 10 | ||||
-rw-r--r-- | json/jsonparse.cc | 1 |
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; |