From 1a34d6d33438671c8704388c3911a90bb2184a9b Mon Sep 17 00:00:00 2001
From: David Shah <davey1576@gmail.com>
Date: Wed, 1 Aug 2018 14:39:56 +0200
Subject: ecp5: Memory fixes in packer

Signed-off-by: David Shah <davey1576@gmail.com>
---
 ecp5/pack.cc | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index 11cc2647..786f543e 100644
--- a/ecp5/pack.cc
+++ b/ecp5/pack.cc
@@ -325,19 +325,22 @@ class Ecp5Packer
             lut_to_slice(ctx, lut0, slice.get(), 0);
             lut_to_slice(ctx, lut1, slice.get(), 1);
 
-            auto ff0 = lutffPairs.find(lut0->name), ff1 = lutffPairs.find(lut1->name);
+            auto ff0 = lutffPairs.find(lut0->name);
 
             if (ff0 != lutffPairs.end()) {
                 ff_to_slice(ctx, ctx->cells.at(ff0->second).get(), slice.get(), 0, true);
                 packed_cells.insert(ff0->second);
-                lutffPairs.erase(lut0->name);
                 fflutPairs.erase(ff0->second);
+                lutffPairs.erase(lut0->name);
             }
+
+            auto ff1 = lutffPairs.find(lut1->name);
+
             if (ff1 != lutffPairs.end()) {
                 ff_to_slice(ctx, ctx->cells.at(ff1->second).get(), slice.get(), 1, true);
                 packed_cells.insert(ff1->second);
-                lutffPairs.erase(lut1->name);
                 fflutPairs.erase(ff1->second);
+                lutffPairs.erase(lut1->name);
             }
 
             new_cells.push_back(std::move(slice));
@@ -363,8 +366,8 @@ class Ecp5Packer
                 if (ff != lutffPairs.end()) {
                     ff_to_slice(ctx, ctx->cells.at(ff->second).get(), slice.get(), 0, true);
                     packed_cells.insert(ff->second);
-                    lutffPairs.erase(ci->name);
                     fflutPairs.erase(ff->second);
+                    lutffPairs.erase(ci->name);
                 }
 
                 new_cells.push_back(std::move(slice));
-- 
cgit v1.2.3


From 2743d0fa9d785f994fd1bf7908f5c2824a81938a Mon Sep 17 00:00:00 2001
From: David Shah <davey1576@gmail.com>
Date: Wed, 1 Aug 2018 14:41:36 +0200
Subject: ecp5: Tweak bitstream chip scope

Signed-off-by: David Shah <davey1576@gmail.com>
---
 ecp5/bitstream.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc
index df9b12d5..bf580f44 100644
--- a/ecp5/bitstream.cc
+++ b/ecp5/bitstream.cc
@@ -306,8 +306,8 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
     }
 
     // Configure chip
-    Trellis::Chip cfg_chip = cc.to_chip();
     if (!bitstream_file.empty()) {
+        Trellis::Chip cfg_chip = cc.to_chip();
         Trellis::Bitstream::serialise_chip(cfg_chip).write_bit_py(bitstream_file);
     }
     if (!text_config_file.empty()) {
-- 
cgit v1.2.3


From 305145ffe455e307818bb44aaaf9cf0817367885 Mon Sep 17 00:00:00 2001
From: David Shah <davey1576@gmail.com>
Date: Wed, 1 Aug 2018 15:07:05 +0200
Subject: ecp5: Adding configuration data structures

Signed-off-by: David Shah <davey1576@gmail.com>
---
 ecp5/config.cc | 304 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ecp5/config.h  | 115 ++++++++++++++++++++++
 2 files changed, 419 insertions(+)
 create mode 100644 ecp5/config.cc
 create mode 100644 ecp5/config.h

diff --git a/ecp5/config.cc b/ecp5/config.cc
new file mode 100644
index 00000000..826c16a9
--- /dev/null
+++ b/ecp5/config.cc
@@ -0,0 +1,304 @@
+/*
+ *  nextpnr -- Next Generation Place and Route
+ *
+ *  Copyright (C) 2018  David Shah <david@symbioticeda.com>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "config.h"
+#include <boost/range/adaptor/reversed.hpp>
+#include "log.h"
+NEXTPNR_NAMESPACE_BEGIN
+
+#define fmt(x) (static_cast<const std::ostringstream &>(std::ostringstream() << x).str())
+
+inline std::string to_string(const std::vector<bool> &bv)
+{
+    std::ostringstream os;
+    for (auto bit : boost::adaptors::reverse(bv))
+        os << (bit ? '1' : '0');
+    return os.str();
+}
+
+inline std::istream &operator>>(std::istream &in, std::vector<bool> &bv)
+{
+    bv.clear();
+    std::string s;
+    in >> s;
+    for (auto c : boost::adaptors::reverse(s)) {
+        assert((c == '0') || (c == '1'));
+        bv.push_back((c == '1'));
+    }
+    return in;
+}
+
+struct ConfigBit
+{
+    int frame;
+    int bit;
+    bool inv;
+};
+
+static ConfigBit cbit_from_str(const std::string &s)
+{
+    size_t idx = 0;
+    ConfigBit b;
+    if (s[idx] == '!') {
+        b.inv = true;
+        ++idx;
+    } else {
+        b.inv = false;
+    }
+    NPNR_ASSERT(s[idx] == 'F');
+    ++idx;
+    size_t b_pos = s.find('B');
+    NPNR_ASSERT(b_pos != std::string::npos);
+    b.frame = stoi(s.substr(idx, b_pos - idx));
+    b.bit = stoi(s.substr(b_pos + 1));
+    return b;
+}
+
+inline std::string to_string(ConfigBit b)
+{
+    std::ostringstream ss;
+    if (b.inv)
+        ss << "!";
+    ss << "F" << b.frame;
+    ss << "B" << b.bit;
+    return ss.str();
+}
+
+// Skip whitespace, optionally including newlines
+inline void skip_blank(std::istream &in, bool nl = false)
+{
+    int c = in.peek();
+    while (in && (((c == ' ') || (c == '\t')) || (nl && ((c == '\n') || (c == '\r'))))) {
+        in.get();
+        c = in.peek();
+    }
+}
+// Return true if end of line (or file)
+inline bool skip_check_eol(std::istream &in)
+{
+    skip_blank(in, false);
+    if (!in)
+        return false;
+    int c = in.peek();
+    // Comments count as end of line
+    if (c == '#') {
+        in.get();
+        c = in.peek();
+        while (in && c != EOF && c != '\n') {
+            in.get();
+            c = in.peek();
+        }
+        return true;
+    }
+    return (c == EOF || c == '\n');
+}
+
+// Skip past blank lines and comments
+inline void skip(std::istream &in)
+{
+    skip_blank(in, true);
+    while (in && (in.peek() == '#')) {
+        // Skip comment line
+        skip_check_eol(in);
+        skip_blank(in, true);
+    }
+}
+
+// Return true if at the end of a record (or file)
+inline bool skip_check_eor(std::istream &in)
+{
+    skip(in);
+    int c = in.peek();
+    return (c == EOF || c == '.');
+}
+
+// Return true if at the end of file
+inline bool skip_check_eof(std::istream &in)
+{
+    skip(in);
+    int c = in.peek();
+    return (c == EOF);
+}
+
+std::ostream &operator<<(std::ostream &out, const ConfigArc &arc)
+{
+    out << "arc: " << arc.sink << " " << arc.source << std::endl;
+    return out;
+}
+
+std::istream &operator>>(std::istream &in, ConfigArc &arc)
+{
+    in >> arc.sink;
+    in >> arc.source;
+    return in;
+}
+
+std::ostream &operator<<(std::ostream &out, const ConfigWord &cw)
+{
+    out << "word: " << cw.name << " " << to_string(cw.value) << std::endl;
+    return out;
+}
+
+std::istream &operator>>(std::istream &in, ConfigWord &cw)
+{
+    in >> cw.name;
+    in >> cw.value;
+    return in;
+}
+
+std::ostream &operator<<(std::ostream &out, const ConfigEnum &cw)
+{
+    out << "enum: " << cw.name << " " << cw.value << std::endl;
+    return out;
+}
+
+std::istream &operator>>(std::istream &in, ConfigEnum &ce)
+{
+    in >> ce.name;
+    in >> ce.value;
+    return in;
+}
+
+std::ostream &operator<<(std::ostream &out, const ConfigUnknown &cu)
+{
+    out << "unknown: " << to_string(ConfigBit{cu.frame, cu.bit, false}) << std::endl;
+    return out;
+}
+
+std::istream &operator>>(std::istream &in, ConfigUnknown &cu)
+{
+    std::string s;
+    in >> s;
+    ConfigBit c = cbit_from_str(s);
+    cu.frame = c.frame;
+    cu.bit = c.bit;
+    assert(!c.inv);
+    return in;
+}
+
+std::ostream &operator<<(std::ostream &out, const TileConfig &tc)
+{
+    for (const auto &arc : tc.carcs)
+        out << arc;
+    for (const auto &cword : tc.cwords)
+        out << cword;
+    for (const auto &cenum : tc.cenums)
+        out << cenum;
+    for (const auto &cunk : tc.cunknowns)
+        out << cunk;
+    return out;
+}
+
+std::istream &operator>>(std::istream &in, TileConfig &tc)
+{
+    tc.carcs.clear();
+    tc.cwords.clear();
+    tc.cenums.clear();
+    while (!skip_check_eor(in)) {
+        std::string type;
+        in >> type;
+        if (type == "arc:") {
+            ConfigArc a;
+            in >> a;
+            tc.carcs.push_back(a);
+        } else if (type == "word:") {
+            ConfigWord w;
+            in >> w;
+            tc.cwords.push_back(w);
+        } else if (type == "enum:") {
+            ConfigEnum e;
+            in >> e;
+            tc.cenums.push_back(e);
+        } else if (type == "unknown:") {
+            ConfigUnknown u;
+            in >> u;
+            tc.cunknowns.push_back(u);
+        } else {
+            NPNR_ASSERT_FALSE_STR("unexpected token " + type + " while reading config text");
+        }
+    }
+    return in;
+}
+
+void TileConfig::add_arc(const std::string &sink, const std::string &source) { carcs.push_back({sink, source}); }
+
+void TileConfig::add_word(const std::string &name, const std::vector<bool> &value) { cwords.push_back({name, value}); }
+
+void TileConfig::add_enum(const std::string &name, const std::string &value) { cenums.push_back({name, value}); }
+
+void TileConfig::add_unknown(int frame, int bit) { cunknowns.push_back({frame, bit}); }
+
+std::string TileConfig::to_string() const
+{
+    std::stringstream ss;
+    ss << *this;
+    return ss.str();
+}
+
+TileConfig TileConfig::from_string(const std::string &str)
+{
+    std::stringstream ss(str);
+    TileConfig tc;
+    ss >> tc;
+    return tc;
+}
+
+bool TileConfig::empty() const { return carcs.empty() && cwords.empty() && cenums.empty() && cunknowns.empty(); }
+
+std::ostream &operator<<(std::ostream &out, const ChipConfig &cc)
+{
+    out << ".device " << cc.chip_name << std::endl << std::endl;
+    for (const auto &meta : cc.metadata)
+        out << ".comment " << meta << std::endl;
+    out << std::endl;
+    for (const auto &tile : cc.tiles) {
+        if (!tile.second.empty()) {
+            out << ".tile " << tile.first << std::endl;
+            out << tile.second;
+            out << std::endl;
+        }
+    }
+    return out;
+}
+
+std::istream &operator>>(std::istream &in, ChipConfig &cc)
+{
+    while (!skip_check_eof(in)) {
+        std::string verb;
+        in >> verb;
+        if (verb == ".device") {
+            in >> cc.chip_name;
+        } else if (verb == ".comment") {
+            std::string line;
+            getline(in, line);
+            cc.metadata.push_back(line);
+        } else if (verb == ".tile") {
+            std::string tilename;
+            in >> tilename;
+            TileConfig tc;
+            in >> tc;
+            cc.tiles[tilename] = tc;
+        } else {
+            log_error("unrecognised config entry %s\n", verb.c_str());
+        }
+    }
+    return in;
+}
+
+NEXTPNR_NAMESPACE_END
diff --git a/ecp5/config.h b/ecp5/config.h
new file mode 100644
index 00000000..637069e9
--- /dev/null
+++ b/ecp5/config.h
@@ -0,0 +1,115 @@
+/*
+ *  nextpnr -- Next Generation Place and Route
+ *
+ *  Copyright (C) 2018  David Shah <david@symbioticeda.com>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef ECP5_CONFIG_H
+#define ECP5_CONFIG_H
+
+#include "nextpnr.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+// This represents configuration at "FASM" level, in terms of routing arcs and non-routing configuration settings -
+// either words or enums.
+
+// A connection in a tile
+struct ConfigArc
+{
+    std::string sink;
+    std::string source;
+    inline bool operator==(const ConfigArc &other) const { return other.source == source && other.sink == sink; }
+};
+
+std::ostream &operator<<(std::ostream &out, const ConfigArc &arc);
+
+std::istream &operator>>(std::istream &in, ConfigArc &arc);
+
+// A configuration setting in a tile that takes one or more bits (such as LUT init)
+struct ConfigWord
+{
+    std::string name;
+    std::vector<bool> value;
+    inline bool operator==(const ConfigWord &other) const { return other.name == name && other.value == value; }
+};
+
+std::ostream &operator<<(std::ostream &out, const ConfigWord &cw);
+
+std::istream &operator>>(std::istream &in, ConfigWord &cw);
+
+// A configuration setting in a tile that takes an enumeration value (such as IO type)
+struct ConfigEnum
+{
+    std::string name;
+    std::string value;
+    inline bool operator==(const ConfigEnum &other) const { return other.name == name && other.value == value; }
+};
+
+std::ostream &operator<<(std::ostream &out, const ConfigEnum &ce);
+
+std::istream &operator>>(std::istream &in, ConfigEnum &ce);
+
+// An unknown bit, specified by position only
+struct ConfigUnknown
+{
+    int frame, bit;
+    inline bool operator==(const ConfigUnknown &other) const { return other.frame == frame && other.bit == bit; }
+};
+
+std::ostream &operator<<(std::ostream &out, const ConfigUnknown &tc);
+
+std::istream &operator>>(std::istream &in, ConfigUnknown &ce);
+
+struct TileConfig
+{
+    std::vector<ConfigArc> carcs;
+    std::vector<ConfigWord> cwords;
+    std::vector<ConfigEnum> cenums;
+    std::vector<ConfigUnknown> cunknowns;
+    int total_known_bits = 0;
+
+    void add_arc(const std::string &sink, const std::string &source);
+    void add_word(const std::string &name, const std::vector<bool> &value);
+    void add_enum(const std::string &name, const std::string &value);
+    void add_unknown(int frame, int bit);
+
+    std::string to_string() const;
+    static TileConfig from_string(const std::string &str);
+
+    bool empty() const;
+};
+
+std::ostream &operator<<(std::ostream &out, const TileConfig &tc);
+
+std::istream &operator>>(std::istream &in, TileConfig &ce);
+
+// This represents the configuration of a chip at a high level
+class ChipConfig
+{
+  public:
+    std::string chip_name;
+    std::vector<std::string> metadata;
+    std::map<std::string, TileConfig> tiles;
+};
+
+std::ostream &operator<<(std::ostream &out, const ChipConfig &cc);
+
+std::istream &operator>>(std::istream &in, ChipConfig &cc);
+
+NEXTPNR_NAMESPACE_END
+
+#endif
-- 
cgit v1.2.3


From bcdcba66a69fbad707866299772a17a4ba0972ee Mon Sep 17 00:00:00 2001
From: David Shah <davey1576@gmail.com>
Date: Wed, 1 Aug 2018 15:23:27 +0200
Subject: ecp5: Add tilemap to chip database

Signed-off-by: David Shah <davey1576@gmail.com>
---
 ecp5/arch.h            | 12 ++++++++++++
 ecp5/trellis_import.py | 19 +++++++++++++++++--
 2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/ecp5/arch.h b/ecp5/arch.h
index 2e54276b..0685042c 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -117,6 +117,17 @@ NPNR_PACKED_STRUCT(struct PackageInfoPOD {
     RelPtr<PackagePinPOD> pin_data;
 });
 
+NPNR_PACKED_STRUCT(struct TileNamePOD {
+    RelPtr<char> name;
+    int16_t type_idx;
+    int16_t padding;
+});
+
+NPNR_PACKED_STRUCT(struct TileInfoPOD {
+    int32_t num_tiles;
+    RelPtr<TileNamePOD> tile_names;
+});
+
 enum TapDirection : int8_t
 {
     TAP_DIR_LEFT = 0,
@@ -148,6 +159,7 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD {
     RelPtr<RelPtr<char>> tiletype_names;
     RelPtr<PackageInfoPOD> package_info;
     RelPtr<PIOInfoPOD> pio_info;
+    RelPtr<TileInfoPOD> tile_info;
 });
 
 #if defined(_MSC_VER)
diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py
index 9a4f30ab..d60ab6f4 100755
--- a/ecp5/trellis_import.py
+++ b/ecp5/trellis_import.py
@@ -136,7 +136,7 @@ def process_loc_globals(chip):
             tapdrv = chip.global_data.get_tap_driver(y, x)
             global_data[x, y] = (quadrants.index(quad), int(tapdrv.dir), tapdrv.col)
 
-def write_database(dev_name, ddrg, endianness):
+def write_database(dev_name, chip, ddrg, endianness):
     def write_loc(loc, sym_name):
         bba.u16(loc.x, "%s.x" % sym_name)
         bba.u16(loc.y, "%s.y" % sym_name)
@@ -221,6 +221,20 @@ def write_database(dev_name, ddrg, endianness):
         bba.r("loc%d_wires" % idx if len(loctype.wires) > 0 else None, "wire_data")
         bba.r("loc%d_pips" % idx if len(loctype.arcs) > 0 else None, "pips_data")
 
+    for y in range(0, max_row+1):
+        for x in range(0, max_col+1):
+            bba.l("tile_info_%d_%d" % (x, y), "TileNamePOD")
+            for tile in chip.get_tiles_by_position(y, x):
+                bba.s(tile.info.name, "name")
+                bba.u16(get_tiletype_index(tile.info.type), "type_idx")
+                bba.u16(0, "padding")
+
+    bba.l("tiles_info", "TileInfoPOD")
+    for y in range(0, max_row+1):
+        for x in range(0, max_col+1):
+            bba.u32(len(chip.get_tiles_by_position(y, x)), "num_tiles")
+            bba.r("tile_info_%d_%d" % (x, y), "tile_names")
+
     bba.l("location_types", "int32_t")
     for y in range(0, max_row+1):
         for x in range(0, max_col+1):
@@ -278,6 +292,7 @@ def write_database(dev_name, ddrg, endianness):
     bba.r("tiletype_names", "tiletype_names")
     bba.r("package_data", "package_info")
     bba.r("pio_info", "pio_info")
+    bba.r("tiles_info", "tile_info")
 
     bba.pop()
     return bba
@@ -311,7 +326,7 @@ def main():
     process_pio_db(ddrg, args.device)
     process_loc_globals(chip)
     # print("{} unique location types".format(len(ddrg.locationTypes)))
-    bba = write_database(args.device, ddrg, "le")
+    bba = write_database(args.device, chip, ddrg, "le")
 
 
 
-- 
cgit v1.2.3


From 534465d3ad5a2d42766088418eb37f88b029b195 Mon Sep 17 00:00:00 2001
From: David Shah <davey1576@gmail.com>
Date: Wed, 1 Aug 2018 15:30:28 +0200
Subject: ecp5: Adding tilegrid helper functions to Arch

Signed-off-by: David Shah <davey1576@gmail.com>
---
 ecp5/arch.h | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/ecp5/arch.h b/ecp5/arch.h
index 0685042c..002d69c2 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -759,6 +759,27 @@ struct Arch : BaseCtx
         return range;
     }
 
+    std::string getTileByTypeAndLocation(int row, int col, std::string type) const
+    {
+        auto &tileloc = chip_info->tile_info[row * chip_info->width + col];
+        for (int i = 0; i < tileloc.num_tiles; i++) {
+            if (chip_info->tiletype_names[tileloc.tile_names[i].type_idx].get() == type)
+                return tileloc.tile_names[i].name.get();
+        }
+        NPNR_ASSERT_FALSE_STR("no tile at (" + std::to_string(col) + ", " + std::to_string(row) + ") with type " +
+                              type);
+    }
+
+    std::string getPipTilename(PipId pip) const
+    {
+        auto &tileloc = chip_info->tile_info[pip.location.y * chip_info->width + pip.location.x];
+        for (int i = 0; i < tileloc.num_tiles; i++) {
+            if (tileloc.tile_names[i].type_idx == locInfo(pip)->pip_data[pip.index].tile_type)
+                return tileloc.tile_names[i].name.get();
+        }
+        NPNR_ASSERT_FALSE("failed to find Pip tile");
+    }
+
     std::string getPipTiletype(PipId pip) const
     {
         return chip_info->tiletype_names[locInfo(pip)->pip_data[pip.index].tile_type].get();
-- 
cgit v1.2.3


From ff9b20991436aa588292de53010423998125b54d Mon Sep 17 00:00:00 2001
From: Sergiusz Bazanski <q3k@q3k.org>
Date: Wed, 1 Aug 2018 14:45:09 +0100
Subject: Add COPYING file

---
 COPYING | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 COPYING

diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..6df840be
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,18 @@
+Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
+Copyright (C) 2018 David Shah <david@symbioticeda.com>
+Copyright (C) 2018 Dan Gisselquist <dan@symbioticeda.com>
+Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
+Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com>
+Copyright (C) 2018 Eddie Hung <eddieh@ece.ubc.ca>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-- 
cgit v1.2.3


From 0658759495d25fe5d1ffa8d58f86214ccd0e98d9 Mon Sep 17 00:00:00 2001
From: David Shah <davey1576@gmail.com>
Date: Wed, 1 Aug 2018 15:58:38 +0200
Subject: ecp5: Remove libtrellis link for bitstream gen

Signed-off-by: David Shah <davey1576@gmail.com>
---
 README.md             |  4 +--
 ecp5/arch.cc          | 11 ++++++
 ecp5/arch.h           | 33 +++++++++++------
 ecp5/bitstream.cc     | 98 +++++++++++++++++++++++----------------------------
 ecp5/bitstream.h      |  3 +-
 ecp5/family.cmake     |  8 -----
 ecp5/main.cc          | 13 +------
 ecp5/synth/.gitignore |  2 ++
 8 files changed, 83 insertions(+), 89 deletions(-)

diff --git a/README.md b/README.md
index f9658677..e9f197cd 100644
--- a/README.md
+++ b/README.md
@@ -90,9 +90,9 @@ sudo make install
 ```
 
  - For an ECP5 blinky on the 45k ULX3S board, first synthesise using `yosys blinky.ys` in `ecp5/synth`.
-  - Then run ECP5 place-and route using `./nextpnr-ecp5 --json ecp5/synth/blinky.json --basecfg ecp5/synth/ulx3s_empty.config --bit ecp5/synth/ulx3s.bit`
+  - Then run ECP5 place-and route using `./nextpnr-ecp5 --json ecp5/synth/blinky.json --basecfg ecp5/synth/ulx3s_empty.config --textcfg ecp5/synth/ulx3s_out.config`
+  - Create a bitstream using `ecppack ulx3s_out.config ulx3s.bit`
   - Note that `ulx3s_empty.config` contains fixed/unknown bits to be copied to the output bitstream
-  - You can also use `--textcfg out.config` to write a text file describing the bitstream for debugging
 
  - More examples of the ECP5 flow for a range of boards can be found in the [Project Trellis Examples](https://github.com/SymbiFlow/prjtrellis/tree/master/examples).
 
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index 6c3714cc..bf05c15d 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -496,4 +496,15 @@ IdString Arch::getPortClock(const CellInfo *cell, IdString port) const { return
 
 bool Arch::isClockPort(const CellInfo *cell, IdString port) const { return false; }
 
+std::vector<std::pair<std::string, std::string>> Arch::getTilesAtLocation(int row, int col)
+{
+    std::vector<std::pair<std::string, std::string>> ret;
+    auto &tileloc = chip_info->tile_info[row * chip_info->width + col];
+    for (int i = 0; i < tileloc.num_tiles; i++) {
+        ret.push_back(std::make_pair(tileloc.tile_names[i].name.get(),
+                                     chip_info->tiletype_names[tileloc.tile_names[i].type_idx].get()));
+    }
+    return ret;
+}
+
 NEXTPNR_NAMESPACE_END
diff --git a/ecp5/arch.h b/ecp5/arch.h
index 002d69c2..1ddc4003 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -759,17 +759,6 @@ struct Arch : BaseCtx
         return range;
     }
 
-    std::string getTileByTypeAndLocation(int row, int col, std::string type) const
-    {
-        auto &tileloc = chip_info->tile_info[row * chip_info->width + col];
-        for (int i = 0; i < tileloc.num_tiles; i++) {
-            if (chip_info->tiletype_names[tileloc.tile_names[i].type_idx].get() == type)
-                return tileloc.tile_names[i].name.get();
-        }
-        NPNR_ASSERT_FALSE_STR("no tile at (" + std::to_string(col) + ", " + std::to_string(row) + ") with type " +
-                              type);
-    }
-
     std::string getPipTilename(PipId pip) const
     {
         auto &tileloc = chip_info->tile_info[pip.location.y * chip_info->width + pip.location.x];
@@ -851,6 +840,28 @@ struct Arch : BaseCtx
     // Helper function for above
     bool slicesCompatible(const std::vector<const CellInfo *> &cells) const;
 
+    std::vector<std::pair<std::string, std::string>> getTilesAtLocation(int row, int col);
+    std::string getTileByTypeAndLocation(int row, int col, std::string type) const
+    {
+        auto &tileloc = chip_info->tile_info[row * chip_info->width + col];
+        for (int i = 0; i < tileloc.num_tiles; i++) {
+            if (chip_info->tiletype_names[tileloc.tile_names[i].type_idx].get() == type)
+                return tileloc.tile_names[i].name.get();
+        }
+        NPNR_ASSERT_FALSE_STR("no tile at (" + std::to_string(col) + ", " + std::to_string(row) + ") with type " +
+                              type);
+    }
+
+    std::string getTileByTypeAndLocation(int row, int col, const std::set<std::string> &type) const
+    {
+        auto &tileloc = chip_info->tile_info[row * chip_info->width + col];
+        for (int i = 0; i < tileloc.num_tiles; i++) {
+            if (type.count(chip_info->tiletype_names[tileloc.tile_names[i].type_idx].get()))
+                return tileloc.tile_names[i].name.get();
+        }
+        NPNR_ASSERT_FALSE_STR("no tile at (" + std::to_string(col) + ", " + std::to_string(row) + ") with type in set");
+    }
+
     IdString id_trellis_slice;
     IdString id_clk, id_lsr;
     IdString id_clkmux, id_lsrmux;
diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc
index bf580f44..f12e09b2 100644
--- a/ecp5/bitstream.cc
+++ b/ecp5/bitstream.cc
@@ -19,17 +19,10 @@
 
 #include "bitstream.h"
 
-// From Project Trellis
-#include "BitDatabase.hpp"
-#include "Bitstream.hpp"
-#include "Chip.hpp"
-#include "ChipConfig.hpp"
-#include "Tile.hpp"
-#include "TileConfig.hpp"
-
 #include <fstream>
 #include <streambuf>
 
+#include "config.h"
 #include "io.h"
 #include "log.h"
 #include "util.h"
@@ -49,13 +42,13 @@ static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire)
         return basename;
     std::string rel_prefix;
     if (wire.location.y < loc.y)
-        rel_prefix += "N" + to_string(loc.y - wire.location.y);
+        rel_prefix += "N" + std::to_string(loc.y - wire.location.y);
     if (wire.location.y > loc.y)
-        rel_prefix += "S" + to_string(wire.location.y - loc.y);
+        rel_prefix += "S" + std::to_string(wire.location.y - loc.y);
     if (wire.location.x > loc.x)
-        rel_prefix += "E" + to_string(wire.location.x - loc.x);
+        rel_prefix += "E" + std::to_string(wire.location.x - loc.x);
     if (wire.location.x < loc.x)
-        rel_prefix += "W" + to_string(loc.x - wire.location.x);
+        rel_prefix += "W" + std::to_string(loc.x - wire.location.x);
     return rel_prefix + "_" + basename;
 }
 
@@ -69,7 +62,7 @@ static std::vector<bool> int_to_bitvector(int val, int size)
 }
 
 // Get the PIO tile corresponding to a PIO bel
-static std::string get_pio_tile(Context *ctx, Trellis::Chip &chip, BelId bel)
+static std::string get_pio_tile(Context *ctx, BelId bel)
 {
     static const std::set<std::string> pioabcd_l = {"PICL1", "PICL1_DQS0", "PICL1_DQS3"};
     static const std::set<std::string> pioabcd_r = {"PICR1", "PICR1_DQS0", "PICR1_DQS3"};
@@ -79,31 +72,31 @@ static std::string get_pio_tile(Context *ctx, Trellis::Chip &chip, BelId bel)
     std::string pio_name = ctx->locInfo(bel)->bel_data[bel.index].name.get();
     if (bel.location.y == 0) {
         if (pio_name == "PIOA") {
-            return chip.get_tile_by_position_and_type(0, bel.location.x, "PIOT0");
+            return ctx->getTileByTypeAndLocation(0, bel.location.x, "PIOT0");
         } else if (pio_name == "PIOB") {
-            return chip.get_tile_by_position_and_type(0, bel.location.x + 1, "PIOT1");
+            return ctx->getTileByTypeAndLocation(0, bel.location.x + 1, "PIOT1");
         } else {
             NPNR_ASSERT_FALSE("bad PIO location");
         }
     } else if (bel.location.y == ctx->chip_info->height - 1) {
         if (pio_name == "PIOA") {
-            return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, pioa_b);
+            return ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x, pioa_b);
         } else if (pio_name == "PIOB") {
-            return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x + 1, piob_b);
+            return ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x + 1, piob_b);
         } else {
             NPNR_ASSERT_FALSE("bad PIO location");
         }
     } else if (bel.location.x == 0) {
-        return chip.get_tile_by_position_and_type(bel.location.y + 1, bel.location.x, pioabcd_l);
+        return ctx->getTileByTypeAndLocation(bel.location.y + 1, bel.location.x, pioabcd_l);
     } else if (bel.location.x == ctx->chip_info->width - 1) {
-        return chip.get_tile_by_position_and_type(bel.location.y + 1, bel.location.x, pioabcd_r);
+        return ctx->getTileByTypeAndLocation(bel.location.y + 1, bel.location.x, pioabcd_r);
     } else {
         NPNR_ASSERT_FALSE("bad PIO location");
     }
 }
 
 // Get the PIC tile corresponding to a PIO bel
-static std::string get_pic_tile(Context *ctx, Trellis::Chip &chip, BelId bel)
+static std::string get_pic_tile(Context *ctx, BelId bel)
 {
     static const std::set<std::string> picab_l = {"PICL0", "PICL0_DQS2"};
     static const std::set<std::string> piccd_l = {"PICL2", "PICL2_DQS1", "MIB_CIB_LR"};
@@ -116,33 +109,33 @@ static std::string get_pic_tile(Context *ctx, Trellis::Chip &chip, BelId bel)
     std::string pio_name = ctx->locInfo(bel)->bel_data[bel.index].name.get();
     if (bel.location.y == 0) {
         if (pio_name == "PIOA") {
-            return chip.get_tile_by_position_and_type(1, bel.location.x, "PICT0");
+            return ctx->getTileByTypeAndLocation(1, bel.location.x, "PICT0");
         } else if (pio_name == "PIOB") {
-            return chip.get_tile_by_position_and_type(1, bel.location.x + 1, "PICT1");
+            return ctx->getTileByTypeAndLocation(1, bel.location.x + 1, "PICT1");
         } else {
             NPNR_ASSERT_FALSE("bad PIO location");
         }
     } else if (bel.location.y == ctx->chip_info->height - 1) {
         if (pio_name == "PIOA") {
-            return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, pica_b);
+            return ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x, pica_b);
         } else if (pio_name == "PIOB") {
-            return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x + 1, picb_b);
+            return ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x + 1, picb_b);
         } else {
             NPNR_ASSERT_FALSE("bad PIO location");
         }
     } else if (bel.location.x == 0) {
         if (pio_name == "PIOA" || pio_name == "PIOB") {
-            return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, picab_l);
+            return ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x, picab_l);
         } else if (pio_name == "PIOC" || pio_name == "PIOD") {
-            return chip.get_tile_by_position_and_type(bel.location.y + 2, bel.location.x, piccd_l);
+            return ctx->getTileByTypeAndLocation(bel.location.y + 2, bel.location.x, piccd_l);
         } else {
             NPNR_ASSERT_FALSE("bad PIO location");
         }
     } else if (bel.location.x == ctx->chip_info->width - 1) {
         if (pio_name == "PIOA" || pio_name == "PIOB") {
-            return chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, picab_r);
+            return ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x, picab_r);
         } else if (pio_name == "PIOC" || pio_name == "PIOD") {
-            return chip.get_tile_by_position_and_type(bel.location.y + 2, bel.location.x, piccd_r);
+            return ctx->getTileByTypeAndLocation(bel.location.y + 2, bel.location.x, piccd_r);
         } else {
             NPNR_ASSERT_FALSE("bad PIO location");
         }
@@ -151,11 +144,9 @@ static std::string get_pic_tile(Context *ctx, Trellis::Chip &chip, BelId bel)
     }
 }
 
-void write_bitstream(Context *ctx, std::string base_config_file, std::string text_config_file,
-                     std::string bitstream_file)
+void write_bitstream(Context *ctx, std::string base_config_file, std::string text_config_file)
 {
-    Trellis::Chip empty_chip(ctx->getChipName());
-    Trellis::ChipConfig cc;
+    ChipConfig cc;
 
     std::set<std::string> cib_tiles = {"CIB", "CIB_LR", "CIB_LR_S", "CIB_EFB0", "CIB_EFB1"};
 
@@ -164,8 +155,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
         if (!config_file) {
             log_error("failed to open base config file '%s'\n", base_config_file.c_str());
         }
-        std::string str((std::istreambuf_iterator<char>(config_file)), std::istreambuf_iterator<char>());
-        cc = Trellis::ChipConfig::from_string(str);
+        config_file >> cc;
     } else {
         cc.chip_name = ctx->getChipName();
         // TODO: .bit metadata
@@ -175,8 +165,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
     for (auto pip : ctx->getPips()) {
         if (ctx->getBoundPipNet(pip) != IdString()) {
             if (ctx->getPipClass(pip) == 0) { // ignore fixed pips
-                std::string tile = empty_chip.get_tile_by_position_and_type(pip.location.y, pip.location.x,
-                                                                            ctx->getPipTiletype(pip));
+                std::string tile = ctx->getPipTilename(pip);
                 std::string source = get_trellis_wirename(ctx, pip.location, ctx->getPipSrcWire(pip));
                 std::string sink = get_trellis_wirename(ctx, pip.location, ctx->getPipDstWire(pip));
                 cc.tiles[tile].add_arc(sink, source);
@@ -214,15 +203,20 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
     }
 
     // Set all bankref tiles to appropriate VccIO
-    for (const auto &tile : empty_chip.tiles) {
-        std::string type = tile.second->info.type;
-        if (type.find("BANKREF") != std::string::npos && type != "BANKREF8") {
-            int bank = std::stoi(type.substr(7));
-            if (bankVcc.find(bank) != bankVcc.end())
-                cc.tiles[tile.first].add_enum("BANK.VCCIO", iovoltage_to_str(bankVcc[bank]));
-            if (bankLvds[bank]) {
-                cc.tiles[tile.first].add_enum("BANK.DIFF_REF", "ON");
-                cc.tiles[tile.first].add_enum("BANK.LVDSO", "ON");
+    for (int y = 0; y < ctx->getGridDimY(); y++) {
+        for (int x = 0; x < ctx->getGridDimX(); x++) {
+            auto tiles = ctx->getTilesAtLocation(y, x);
+            for (auto tile : tiles) {
+                std::string type = tile.second;
+                if (type.find("BANKREF") != std::string::npos && type != "BANKREF8") {
+                    int bank = std::stoi(type.substr(7));
+                    if (bankVcc.find(bank) != bankVcc.end())
+                        cc.tiles[tile.first].add_enum("BANK.VCCIO", iovoltage_to_str(bankVcc[bank]));
+                    if (bankLvds[bank]) {
+                        cc.tiles[tile.first].add_enum("BANK.DIFF_REF", "ON");
+                        cc.tiles[tile.first].add_enum("BANK.LVDSO", "ON");
+                    }
+                }
             }
         }
     }
@@ -235,7 +229,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
         }
         BelId bel = ci->bel;
         if (ci->type == ctx->id("TRELLIS_SLICE")) {
-            std::string tname = empty_chip.get_tile_by_position_and_type(bel.location.y, bel.location.x, "PLC2");
+            std::string tname = ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x, "PLC2");
             std::string slice = ctx->locInfo(bel)->bel_data[bel.index].name.get();
             int lut0_init = int_or_default(ci->params, ctx->id("LUT0_INITVAL"));
             int lut1_init = int_or_default(ci->params, ctx->id("LUT1_INITVAL"));
@@ -267,8 +261,8 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
             std::string pio = ctx->locInfo(bel)->bel_data[bel.index].name.get();
             std::string iotype = str_or_default(ci->attrs, ctx->id("IO_TYPE"), "LVCMOS33");
             std::string dir = str_or_default(ci->params, ctx->id("DIR"), "INPUT");
-            std::string pio_tile = get_pio_tile(ctx, empty_chip, bel);
-            std::string pic_tile = get_pic_tile(ctx, empty_chip, bel);
+            std::string pio_tile = get_pio_tile(ctx, bel);
+            std::string pic_tile = get_pic_tile(ctx, bel);
             cc.tiles[pio_tile].add_enum(pio + ".BASE_TYPE", dir + "_" + iotype);
             cc.tiles[pic_tile].add_enum(pio + ".BASE_TYPE", dir + "_" + iotype);
             if (is_differential(ioType_from_str(iotype))) {
@@ -293,7 +287,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
                 PipId jpt_pip = *ctx->getPipsUphill(jpt_wire).begin();
                 WireId cib_wire = ctx->getPipSrcWire(jpt_pip);
                 std::string cib_tile =
-                        empty_chip.get_tile_by_position_and_type(cib_wire.location.y, cib_wire.location.x, cib_tiles);
+                        ctx->getTileByTypeAndLocation(cib_wire.location.y, cib_wire.location.x, cib_tiles);
                 std::string cib_wirename = ctx->locInfo(cib_wire)->wire_data[cib_wire.index].name.get();
                 cc.tiles[cib_tile].add_enum("CIB." + cib_wirename + "MUX", "0");
             }
@@ -306,13 +300,9 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
     }
 
     // Configure chip
-    if (!bitstream_file.empty()) {
-        Trellis::Chip cfg_chip = cc.to_chip();
-        Trellis::Bitstream::serialise_chip(cfg_chip).write_bit_py(bitstream_file);
-    }
     if (!text_config_file.empty()) {
         std::ofstream out_config(text_config_file);
-        out_config << cc.to_string();
+        out_config << cc;
     }
 }
 
diff --git a/ecp5/bitstream.h b/ecp5/bitstream.h
index 62617470..f70abb35 100644
--- a/ecp5/bitstream.h
+++ b/ecp5/bitstream.h
@@ -24,8 +24,7 @@
 
 NEXTPNR_NAMESPACE_BEGIN
 
-void write_bitstream(Context *ctx, std::string base_config_file = "", std::string text_config_file = "",
-                     std::string bitstream_file = "");
+void write_bitstream(Context *ctx, std::string base_config_file = "", std::string text_config_file = "");
 
 NEXTPNR_NAMESPACE_END
 
diff --git a/ecp5/family.cmake b/ecp5/family.cmake
index 1c388e99..8315cf87 100644
--- a/ecp5/family.cmake
+++ b/ecp5/family.cmake
@@ -62,11 +62,3 @@ else()
         endforeach (target)
     endforeach (dev)
 endif()
-
-find_library(TRELLIS_LIB trellis PATHS ${TRELLIS_ROOT}/libtrellis)
-
-foreach (target ${family_targets})
-    target_compile_definitions(${target} PRIVATE TRELLIS_ROOT="${TRELLIS_ROOT}")
-    target_include_directories(${target} PRIVATE ${TRELLIS_ROOT}/libtrellis/include)
-    target_link_libraries(${target} PRIVATE ${TRELLIS_LIB})
-endforeach (target)
diff --git a/ecp5/main.cc b/ecp5/main.cc
index 68660ced..f40a5e61 100644
--- a/ecp5/main.cc
+++ b/ecp5/main.cc
@@ -32,10 +32,6 @@
 #include <fstream>
 #include <iostream>
 
-#include "Chip.hpp"
-#include "Database.hpp"
-#include "Tile.hpp"
-
 #include "log.h"
 #include "nextpnr.h"
 #include "version.h"
@@ -75,7 +71,6 @@ int main(int argc, char *argv[])
         options.add_options()("seed", po::value<int>(), "seed value for random number generator");
 
         options.add_options()("basecfg", po::value<std::string>(), "base chip configuration in Trellis text format");
-        options.add_options()("bit", po::value<std::string>(), "bitstream file to write");
         options.add_options()("textcfg", po::value<std::string>(), "textual configuration in Trellis format to write");
 
         po::positional_options_description pos;
@@ -115,8 +110,6 @@ int main(int argc, char *argv[])
             return 1;
         }
 
-        Trellis::load_database(TRELLIS_ROOT "/database");
-
         ArchArgs args;
         args.type = ArchArgs::LFE5U_45F;
 
@@ -189,14 +182,10 @@ int main(int argc, char *argv[])
             if (vm.count("basecfg"))
                 basecfg = vm["basecfg"].as<std::string>();
 
-            std::string bitstream;
-            if (vm.count("bit"))
-                bitstream = vm["bit"].as<std::string>();
-
             std::string textcfg;
             if (vm.count("textcfg"))
                 textcfg = vm["textcfg"].as<std::string>();
-            write_bitstream(ctx.get(), basecfg, textcfg, bitstream);
+            write_bitstream(ctx.get(), basecfg, textcfg);
         }
 
 #ifndef NO_PYTHON
diff --git a/ecp5/synth/.gitignore b/ecp5/synth/.gitignore
index 5b3bf578..f4dfa215 100644
--- a/ecp5/synth/.gitignore
+++ b/ecp5/synth/.gitignore
@@ -1 +1,3 @@
 *.bit
+*_out.config
+
-- 
cgit v1.2.3


From 101de5b7151e996b026fa3705fc5ec5d065142f3 Mon Sep 17 00:00:00 2001
From: Sergiusz Bazanski <q3k@q3k.org>
Date: Wed, 1 Aug 2018 17:40:27 +0100
Subject: gui: treemodel: unregister from parent when we get destroyed

This fixes mysterious crashes when a new context was being loaded. The
'Bels', 'Wires', and 'Nets' roots would get replaced by new ones in
TreeModel::Model::loadContext, but they would not get unregistered from
their parent.
---
 gui/treemodel.h | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/gui/treemodel.h b/gui/treemodel.h
index 4c3f64c3..c3f9fe88 100644
--- a/gui/treemodel.h
+++ b/gui/treemodel.h
@@ -62,6 +62,8 @@ class Item
 
     void addChild(Item *child) { children_.append(child); }
 
+    void deleteChild(Item *child) { children_.removeAll(child); }
+
   public:
     Item(QString name, Item *parent) : name_(name), parent_(parent)
     {
@@ -100,7 +102,12 @@ class Item
     virtual bool canFetchMore() const { return false; }
     virtual void fetchMore() {}
 
-    ~Item() {}
+    ~Item()
+    {
+        if (parent_ != nullptr) {
+            parent_->deleteChild(this);
+        }
+    }
 };
 
 // IdString is an Item that corresponds to a real element in Arch.
-- 
cgit v1.2.3


From 1d6ec0fb8c1c2e68e7f21d724a3e30f7fcab4775 Mon Sep 17 00:00:00 2001
From: David Shah <davey1576@gmail.com>
Date: Wed, 1 Aug 2018 20:11:36 +0200
Subject: json: Fix message for 1'bx values

Signed-off-by: David Shah <davey1576@gmail.com>
---
 json/jsonparse.cc | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/json/jsonparse.cc b/json/jsonparse.cc
index a0a4e8d0..89c2b8d9 100644
--- a/json/jsonparse.cc
+++ b/json/jsonparse.cc
@@ -462,9 +462,8 @@ void json_import_ports(Context *ctx, const string &modname, const std::vector<Id
 
                     ground_net(ctx, net.get());
                     log_info("      Floating wire node value, "
-                             "\'%s\' of port \'%s\' "
-                             "in cell \'%s\' of module \'%s\'\n, converted to zero driver",
-                             wire_node->data_string.c_str(), port_name.c_str(), obj_name.c_str(), modname.c_str());
+                             "'%s' on '%s'/'%s', converted to zero driver\n",
+                             this_port.name.c_str(ctx), modname.c_str(), obj_name.c_str());
 
                 } else
                     log_error("      Unknown fixed type wire node "
-- 
cgit v1.2.3


From 79b844f09c8bc8b33751769990c3ad64c2293676 Mon Sep 17 00:00:00 2001
From: Miodrag Milanovic <mmicko@gmail.com>
Date: Wed, 1 Aug 2018 20:32:15 +0200
Subject: Removes unnecessary unlock causing trouble with placer

---
 common/placer1.cc | 1 -
 1 file changed, 1 deletion(-)

diff --git a/common/placer1.cc b/common/placer1.cc
index 68db9650..fc679b50 100644
--- a/common/placer1.cc
+++ b/common/placer1.cc
@@ -193,7 +193,6 @@ class SAPlacer
             if (temp <= 1e-3 && n_no_progress >= 5) {
                 if (iter % 5 != 0)
                     log_info("  at iteration #%d: temp = %f, cost = %f\n", iter, temp, double(curr_metric));
-                ctx->unlock();
                 break;
             }
 
-- 
cgit v1.2.3


From 86a36ceeef728413a213fa7702d07cf4a6c5298b Mon Sep 17 00:00:00 2001
From: Miodrag Milanovic <mmicko@gmail.com>
Date: Thu, 2 Aug 2018 08:32:16 +0200
Subject: Properly delete element from unordered_map

---
 gui/treemodel.cc | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/gui/treemodel.cc b/gui/treemodel.cc
index 900d5101..33dd6a96 100644
--- a/gui/treemodel.cc
+++ b/gui/treemodel.cc
@@ -70,12 +70,14 @@ void IdStringList::updateElements(Context *ctx, std::vector<IdString> elements)
     }
 
     // For any elements that are in managed_ but not in new, delete them.
-    for (auto &pair : managed_) {
-        if (element_set.count(pair.first) != 0) {
-            continue;
+    auto it = managed_.begin();
+    while (it != managed_.end()) {
+        if (element_set.count(it->first) != 0) {
+            ++it;
+        } else {
+            it = managed_.erase(it);
+            changed = true;
         }
-        managed_.erase(pair.first);
-        changed = true;
     }
 
     // Return early if there are no changes.
-- 
cgit v1.2.3