From 61bce47f3cb7b4adf1d5292b3c431ca4048ad038 Mon Sep 17 00:00:00 2001
From: Miodrag Milanovic <mmicko@gmail.com>
Date: Wed, 8 Aug 2018 20:14:18 +0200
Subject: Use settings for json and pcf

---
 common/project.cc       | 62 ++++++++++++++++++++++++++++++++++++++-----------
 common/project.h        |  5 +++-
 ecp5/project.cc         |  2 +-
 generic/project.cc      |  2 +-
 gui/ecp5/mainwindow.h   |  1 -
 gui/ice40/mainwindow.cc |  2 +-
 ice40/main.cc           |  5 ++--
 ice40/pcf.cc            |  3 ++-
 ice40/pcf.h             |  2 +-
 ice40/project.cc        | 10 ++++----
 json/jsonparse.cc       |  1 +
 11 files changed, 68 insertions(+), 27 deletions(-)

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/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/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc
index 35ad5768..bf6e4b4c 100644
--- a/gui/ice40/mainwindow.cc
+++ b/gui/ice40/mainwindow.cc
@@ -150,7 +150,7 @@ 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 {
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;
-- 
cgit v1.2.3