pass metadata: fixed some of the output formatting
[yosys.git] / backends / simplec / simplec.cc
index c8a812748973a322231b2541e85092126901bac6..e283dcf7c1776d899c570596b1af71affd1cf1bb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  yosys -- Yosys Open SYnthesis Suite
  *
- *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.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
@@ -26,6 +26,40 @@ PRIVATE_NAMESPACE_BEGIN
 
 struct HierDirtyFlags;
 
+static pool<string> reserved_cids;
+static dict<IdString, string> id2cid;
+
+static string cid(IdString id)
+{
+       if (id2cid.count(id) == 0)
+       {
+               string s = id.str();
+               if (GetSize(s) < 2) log_abort();
+
+               if (s[0] == '\\')
+                       s = s.substr(1);
+
+               if ('0' <= s[0] && s[0] <= '9') {
+                       s = "_" + s;
+               }
+
+               for (int i = 0; i < GetSize(s); i++) {
+                       if ('0' <= s[i] && s[i] <= '9') continue;
+                       if ('A' <= s[i] && s[i] <= 'Z') continue;
+                       if ('a' <= s[i] && s[i] <= 'z') continue;
+                       s[i] = '_';
+               }
+
+               while (reserved_cids.count(s))
+                       s += "_";
+
+               reserved_cids.insert(s);
+               id2cid[id] = s;
+       }
+
+       return id2cid.at(id);
+}
+
 struct HierDirtyFlags
 {
        int dirty;
@@ -36,12 +70,15 @@ struct HierDirtyFlags
        pool<Cell*> dirty_cells;
        pool<SigBit> sticky_dirty_bits;
        dict<IdString, HierDirtyFlags*> children;
+       string prefix, log_prefix;
 
-       HierDirtyFlags(Module *module, IdString hiername, HierDirtyFlags *parent) : dirty(0), module(module), hiername(hiername), parent(parent)
+       HierDirtyFlags(Module *module, IdString hiername, HierDirtyFlags *parent, const string &prefix, const string &log_prefix) :
+                       dirty(0), module(module), hiername(hiername), parent(parent), prefix(prefix), log_prefix(log_prefix)
        {
                for (Cell *cell : module->cells()) {
                        Module *mod = module->design->module(cell->type);
-                       if (mod) children[cell->name] = new HierDirtyFlags(mod, cell->name, this);
+                       if (mod) children[cell->name] = new HierDirtyFlags(mod, cell->name, this,
+                                       prefix + cid(cell->name) + ".", log_prefix + "." + prefix + log_id(cell->name));
                }
        }
 
@@ -130,11 +167,9 @@ struct SimplecWorker
 
        vector<string> funct_declarations;
 
-       pool<string> reserved_cids;
-       dict<IdString, string> id2cid;
-
        dict<Module*, dict<SigBit, pool<tuple<Cell*, IdString, int>>>> bit2cell;
        dict<Module*, dict<SigBit, pool<SigBit>>> bit2output;
+       dict<Module*, pool<SigBit>> driven_bits;
 
        dict<Cell*, int> topoidx;
 
@@ -247,37 +282,6 @@ struct SimplecWorker
                return stringf("  %s(&%s, %s);", util_name.c_str(), signame.c_str(), expr.c_str());
        }
 
-       string cid(IdString id)
-       {
-               if (id2cid.count(id) == 0)
-               {
-                       string s = id.str();
-                       if (GetSize(s) < 2) log_abort();
-
-                       if (s[0] == '\\')
-                               s = s.substr(1);
-
-                       if ('0' <= s[0] && s[0] <= '9') {
-                               s = "_" + s;
-                       }
-
-                       for (int i = 0; i < GetSize(s); i++) {
-                               if ('0' <= s[i] && s[i] <= '9') continue;
-                               if ('A' <= s[i] && s[i] <= 'Z') continue;
-                               if ('a' <= s[i] && s[i] <= 'z') continue;
-                               s[i] = '_';
-                       }
-
-                       while (reserved_cids.count(s))
-                               s += "_";
-
-                       reserved_cids.insert(s);
-                       id2cid[id] = s;
-               }
-
-               return id2cid.at(id);
-       }
-
        void create_module_struct(Module *mod)
        {
                if (generated_structs.count(mod->name))
@@ -297,8 +301,11 @@ struct SimplecWorker
                {
                        for (auto &conn : c->connections())
                        {
-                               if (!c->input(conn.first))
+                               if (!c->input(conn.first)) {
+                                       for (auto bit : sigmaps.at(mod)(conn.second))
+                                               driven_bits[mod].insert(bit);
                                        continue;
+                               }
 
                                int idx = 0;
                                for (auto bit : sigmaps.at(mod)(conn.second))
@@ -369,114 +376,120 @@ struct SimplecWorker
                struct_declarations.push_back("#endif");
        }
 
-       void eval_cell(HierDirtyFlags *work, const string &prefix, const string &/* log_prefix */, Cell *cell)
+       void eval_cell(HierDirtyFlags *work, Cell *cell)
        {
-               if (cell->type.in("$_BUF_", "$_NOT_"))
+               if (cell->type.in(ID($_BUF_), ID($_NOT_)))
                {
-                       SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
-                       SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
+                       SigBit a = sigmaps.at(work->module)(cell->getPort(ID::A));
+                       SigBit y = sigmaps.at(work->module)(cell->getPort(ID::Y));
 
-                       string a_expr = a.wire ? util_get_bit(prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
+                       string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
                        string expr;
 
-                       if (cell->type == "$_BUF_")  expr = a_expr;
-                       if (cell->type == "$_NOT_")  expr = "!" + a_expr;
+                       if (cell->type == ID($_BUF_))  expr = a_expr;
+                       if (cell->type == ID($_NOT_))  expr = "!" + a_expr;
 
                        log_assert(y.wire);
-                       funct_declarations.push_back(util_set_bit(prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
+                       funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
                                        stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
 
                        work->set_dirty(y);
                        return;
                }
 
-               if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
+               if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_)))
                {
-                       SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
-                       SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
-                       SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
+                       SigBit a = sigmaps.at(work->module)(cell->getPort(ID::A));
+                       SigBit b = sigmaps.at(work->module)(cell->getPort(ID::B));
+                       SigBit y = sigmaps.at(work->module)(cell->getPort(ID::Y));
 
-                       string a_expr = a.wire ? util_get_bit(prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
-                       string b_expr = b.wire ? util_get_bit(prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
+                       string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
+                       string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
                        string expr;
 
-                       if (cell->type == "$_AND_")  expr = stringf("%s & %s",    a_expr.c_str(), b_expr.c_str());
-                       if (cell->type == "$_NAND_") expr = stringf("!(%s & %s)", a_expr.c_str(), b_expr.c_str());
-                       if (cell->type == "$_OR_")   expr = stringf("%s | %s",    a_expr.c_str(), b_expr.c_str());
-                       if (cell->type == "$_NOR_")  expr = stringf("!(%s | %s)", a_expr.c_str(), b_expr.c_str());
-                       if (cell->type == "$_XOR_")  expr = stringf("%s ^ %s",    a_expr.c_str(), b_expr.c_str());
-                       if (cell->type == "$_XNOR_") expr = stringf("!(%s ^ %s)", a_expr.c_str(), b_expr.c_str());
+                       if (cell->type == ID($_AND_))    expr = stringf("%s & %s",    a_expr.c_str(), b_expr.c_str());
+                       if (cell->type == ID($_NAND_))   expr = stringf("!(%s & %s)", a_expr.c_str(), b_expr.c_str());
+                       if (cell->type == ID($_OR_))     expr = stringf("%s | %s",    a_expr.c_str(), b_expr.c_str());
+                       if (cell->type == ID($_NOR_))    expr = stringf("!(%s | %s)", a_expr.c_str(), b_expr.c_str());
+                       if (cell->type == ID($_XOR_))    expr = stringf("%s ^ %s",    a_expr.c_str(), b_expr.c_str());
+                       if (cell->type == ID($_XNOR_))   expr = stringf("!(%s ^ %s)", a_expr.c_str(), b_expr.c_str());
+                       if (cell->type == ID($_ANDNOT_)) expr = stringf("%s & (!%s)", a_expr.c_str(), b_expr.c_str());
+                       if (cell->type == ID($_ORNOT_))  expr = stringf("%s | (!%s)", a_expr.c_str(), b_expr.c_str());
 
                        log_assert(y.wire);
-                       funct_declarations.push_back(util_set_bit(prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
+                       funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
                                        stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
 
                        work->set_dirty(y);
                        return;
                }
 
-               if (cell->type.in("$_AOI3_", "$_OAI3_"))
+               if (cell->type.in(ID($_AOI3_), ID($_OAI3_)))
                {
-                       SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
-                       SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
-                       SigBit c = sigmaps.at(work->module)(cell->getPort("\\C"));
-                       SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
-
-                       string a_expr = a.wire ? util_get_bit(prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
-                       string b_expr = b.wire ? util_get_bit(prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
-                       string c_expr = c.wire ? util_get_bit(prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0";
+                       SigBit a = sigmaps.at(work->module)(cell->getPort(ID::A));
+                       SigBit b = sigmaps.at(work->module)(cell->getPort(ID::B));
+                       SigBit c = sigmaps.at(work->module)(cell->getPort(ID::C));
+                       SigBit y = sigmaps.at(work->module)(cell->getPort(ID::Y));
+
+                       string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
+                       string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
+                       string c_expr = c.wire ? util_get_bit(work->prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0";
                        string expr;
 
-                       if (cell->type == "$_AOI3_") expr = stringf("!((%s & %s) | %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str());
-                       if (cell->type == "$_OAI3_") expr = stringf("!((%s | %s) & %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str());
+                       if (cell->type == ID($_AOI3_)) expr = stringf("!((%s & %s) | %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str());
+                       if (cell->type == ID($_OAI3_)) expr = stringf("!((%s | %s) & %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str());
 
                        log_assert(y.wire);
-                       funct_declarations.push_back(util_set_bit(prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
+                       funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
                                        stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
 
                        work->set_dirty(y);
                        return;
                }
 
-               if (cell->type.in("$_AOI4_", "$_OAI4_"))
+               if (cell->type.in(ID($_AOI4_), ID($_OAI4_)))
                {
-                       SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
-                       SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
-                       SigBit c = sigmaps.at(work->module)(cell->getPort("\\C"));
-                       SigBit d = sigmaps.at(work->module)(cell->getPort("\\D"));
-                       SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
-
-                       string a_expr = a.wire ? util_get_bit(prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
-                       string b_expr = b.wire ? util_get_bit(prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
-                       string c_expr = c.wire ? util_get_bit(prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0";
-                       string d_expr = d.wire ? util_get_bit(prefix + cid(d.wire->name), d.wire->width, d.offset) : d.data ? "1" : "0";
+                       SigBit a = sigmaps.at(work->module)(cell->getPort(ID::A));
+                       SigBit b = sigmaps.at(work->module)(cell->getPort(ID::B));
+                       SigBit c = sigmaps.at(work->module)(cell->getPort(ID::C));
+                       SigBit d = sigmaps.at(work->module)(cell->getPort(ID::D));
+                       SigBit y = sigmaps.at(work->module)(cell->getPort(ID::Y));
+
+                       string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
+                       string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
+                       string c_expr = c.wire ? util_get_bit(work->prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0";
+                       string d_expr = d.wire ? util_get_bit(work->prefix + cid(d.wire->name), d.wire->width, d.offset) : d.data ? "1" : "0";
                        string expr;
 
-                       if (cell->type == "$_AOI4_") expr = stringf("!((%s & %s) | (%s & %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str());
-                       if (cell->type == "$_OAI4_") expr = stringf("!((%s | %s) & (%s | %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str());
+                       if (cell->type == ID($_AOI4_)) expr = stringf("!((%s & %s) | (%s & %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str());
+                       if (cell->type == ID($_OAI4_)) expr = stringf("!((%s | %s) & (%s | %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str());
 
                        log_assert(y.wire);
-                       funct_declarations.push_back(util_set_bit(prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
+                       funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
                                        stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
 
                        work->set_dirty(y);
                        return;
                }
 
-               if (cell->type == "$_MUX_")
+               if (cell->type.in(ID($_MUX_), ID($_NMUX_)))
                {
-                       SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
-                       SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
-                       SigBit s = sigmaps.at(work->module)(cell->getPort("\\S"));
-                       SigBit y = sigmaps.at(work->module)(cell->getPort("\\Y"));
+                       SigBit a = sigmaps.at(work->module)(cell->getPort(ID::A));
+                       SigBit b = sigmaps.at(work->module)(cell->getPort(ID::B));
+                       SigBit s = sigmaps.at(work->module)(cell->getPort(ID::S));
+                       SigBit y = sigmaps.at(work->module)(cell->getPort(ID::Y));
+
+                       string a_expr = a.wire ? util_get_bit(work->prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
+                       string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
+                       string s_expr = s.wire ? util_get_bit(work->prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0";
 
-                       string a_expr = a.wire ? util_get_bit(prefix + cid(a.wire->name), a.wire->width, a.offset) : a.data ? "1" : "0";
-                       string b_expr = b.wire ? util_get_bit(prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
-                       string s_expr = s.wire ? util_get_bit(prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0";
-                       string expr = stringf("%s ? %s : %s", s_expr.c_str(), b_expr.c_str(), a_expr.c_str());
+                       // casts to bool are a workaround for CBMC bug (https://github.com/diffblue/cbmc/issues/933)
+                       string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr.c_str(),
+                                       cell->type == ID($_NMUX_) ? "!" : "", b_expr.c_str(),
+                                       cell->type == ID($_NMUX_) ? "!" : "", a_expr.c_str());
 
                        log_assert(y.wire);
-                       funct_declarations.push_back(util_set_bit(prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
+                       funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
                                        stringf(" // %s (%s)", log_id(cell), log_id(cell->type)));
 
                        work->set_dirty(y);
@@ -486,12 +499,12 @@ struct SimplecWorker
                log_error("No C model for %s available at the moment (FIXME).\n", log_id(cell->type));
        }
 
-       void eval_dirty(HierDirtyFlags *work, const string &prefix, const string &log_prefix, const string &parent_prefix, const string &parent_log_prefix)
+       void eval_dirty(HierDirtyFlags *work)
        {
                while (work->dirty)
                {
                        if (verbose && (!work->dirty_bits.empty() || !work->dirty_cells.empty()))
-                               log("  In %s:\n", log_prefix.c_str());
+                               log("  In %s:\n", work->log_prefix.c_str());
 
                        while (!work->dirty_bits.empty() || !work->dirty_cells.empty())
                        {
@@ -501,9 +514,11 @@ struct SimplecWorker
                                        dirtysig.sort_and_unify();
 
                                        for (SigChunk chunk : dirtysig.chunks()) {
+                                               if (chunk.wire == nullptr)
+                                                       continue;
                                                if (verbose)
-                                                       log("    Propagating %s.%s[%d:%d].\n", log_prefix.c_str(), log_id(chunk.wire), chunk.offset+chunk.width-1, chunk.offset);
-                                               funct_declarations.push_back(stringf("  // Updated signal in %s: %s", log_prefix.c_str(), log_signal(chunk)));
+                                                       log("    Propagating %s.%s[%d:%d].\n", work->log_prefix.c_str(), log_id(chunk.wire), chunk.offset+chunk.width-1, chunk.offset);
+                                               funct_declarations.push_back(stringf("  // Updated signal in %s: %s", work->log_prefix.c_str(), log_signal(chunk)));
                                        }
 
                                        for (SigBit bit : dirtysig)
@@ -519,13 +534,13 @@ struct SimplecWorker
                                                                SigBit parent_bit = sigmaps.at(parent_mod)(parent_cell->getPort(port_name)[port_offset]);
 
                                                                log_assert(bit.wire && parent_bit.wire);
-                                                               funct_declarations.push_back(util_set_bit(parent_prefix + cid(parent_bit.wire->name), parent_bit.wire->width, parent_bit.offset,
-                                                                               util_get_bit(prefix + cid(bit.wire->name), bit.wire->width, bit.offset)));
+                                                               funct_declarations.push_back(util_set_bit(work->parent->prefix + cid(parent_bit.wire->name), parent_bit.wire->width, parent_bit.offset,
+                                                                               util_get_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset)));
                                                                work->parent->set_dirty(parent_bit);
 
                                                                if (verbose)
-                                                                       log("      Propagating %s.%s[%d] -> %s.%s[%d].\n", log_prefix.c_str(), log_id(bit.wire), bit.offset,
-                                                                                       parent_log_prefix.c_str(), log_id(parent_bit.wire), parent_bit.offset);
+                                                                       log("      Propagating %s.%s[%d] -> %s.%s[%d].\n", work->log_prefix.c_str(), log_id(bit.wire), bit.offset,
+                                                                                       work->parent->log_prefix.c_str(), log_id(parent_bit.wire), parent_bit.offset);
                                                        }
 
                                                for (auto &port : bit2cell[work->module][bit])
@@ -536,17 +551,17 @@ struct SimplecWorker
                                                                SigBit child_bit = sigmaps.at(child->module)(SigBit(child->module->wire(std::get<1>(port)), std::get<2>(port)));
                                                                log_assert(bit.wire && child_bit.wire);
 
-                                                               funct_declarations.push_back(util_set_bit(prefix + cid(child->hiername) + "." + cid(child_bit.wire->name),
-                                                                               child_bit.wire->width, child_bit.offset, util_get_bit(prefix + cid(bit.wire->name), bit.wire->width, bit.offset)));
+                                                               funct_declarations.push_back(util_set_bit(work->prefix + cid(child->hiername) + "." + cid(child_bit.wire->name),
+                                                                               child_bit.wire->width, child_bit.offset, util_get_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset)));
                                                                child->set_dirty(child_bit);
 
                                                                if (verbose)
-                                                                       log("      Propagating %s.%s[%d] -> %s.%s.%s[%d].\n", log_prefix.c_str(), log_id(bit.wire), bit.offset,
-                                                                                       log_prefix.c_str(), log_id(std::get<0>(port)), log_id(child_bit.wire), child_bit.offset);
+                                                                       log("      Propagating %s.%s[%d] -> %s.%s.%s[%d].\n", work->log_prefix.c_str(), log_id(bit.wire), bit.offset,
+                                                                                       work->log_prefix.c_str(), log_id(std::get<0>(port)), log_id(child_bit.wire), child_bit.offset);
                                                        } else {
                                                                if (verbose)
-                                                                       log("      Marking cell %s.%s (via %s.%s[%d]).\n", log_prefix.c_str(), log_id(std::get<0>(port)),
-                                                                                       log_prefix.c_str(), log_id(bit.wire), bit.offset);
+                                                                       log("      Marking cell %s.%s (via %s.%s[%d]).\n", work->log_prefix.c_str(), log_id(std::get<0>(port)),
+                                                                                       work->log_prefix.c_str(), log_id(bit.wire), bit.offset);
                                                                work->set_dirty(std::get<0>(port));
                                                        }
                                                }
@@ -561,7 +576,7 @@ struct SimplecWorker
                                                if (cell == nullptr || topoidx.at(cell) < topoidx.at(c))
                                                        cell = c;
 
-                                       string hiername = log_prefix + "." + log_id(cell);
+                                       string hiername = work->log_prefix + "." + log_id(cell);
 
                                        if (verbose)
                                                log("    Evaluating %s (%s, best of %d).\n", hiername.c_str(), log_id(cell->type), GetSize(work->dirty_cells));
@@ -570,17 +585,17 @@ struct SimplecWorker
                                                reactivated_cells.insert(hiername);
                                        activated_cells.insert(hiername);
 
-                                       eval_cell(work, prefix, log_prefix, cell);
+                                       eval_cell(work, cell);
                                        work->unset_dirty(cell);
                                }
                        }
 
                        for (auto &child : work->children)
-                               eval_dirty(child.second, prefix + cid(child.first) + ".", log_prefix + "." + cid(child.first), prefix, log_prefix);
+                               eval_dirty(child.second);
                }
        }
 
-       void eval_sticky_dirty(HierDirtyFlags *work, const string &prefix, const string &log_prefix)
+       void eval_sticky_dirty(HierDirtyFlags *work)
        {
                Module *mod = work->module;
 
@@ -595,23 +610,25 @@ struct SimplecWorker
                        if (work->sticky_dirty_bits.count(canonical_bit) == 0)
                                continue;
 
-                       log_assert(bit.wire && canonical_bit.wire);
-                       funct_declarations.push_back(util_set_bit(prefix + cid(bit.wire->name), bit.wire->width, bit.offset,
-                                       util_get_bit(prefix + cid(canonical_bit.wire->name), canonical_bit.wire->width, canonical_bit.offset).c_str()));
+                       if (bit.wire == nullptr || canonical_bit.wire == nullptr)
+                               continue;
+
+                       funct_declarations.push_back(util_set_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset,
+                                       util_get_bit(work->prefix + cid(canonical_bit.wire->name), canonical_bit.wire->width, canonical_bit.offset).c_str()));
 
                        if (verbose)
                                log("  Propagating alias %s.%s[%d] -> %s.%s[%d].\n",
-                                               log_prefix.c_str(), log_id(canonical_bit.wire), canonical_bit.offset,
-                                               log_prefix.c_str(), log_id(bit.wire), bit.offset);
+                                               work->log_prefix.c_str(), log_id(canonical_bit.wire), canonical_bit.offset,
+                                               work->log_prefix.c_str(), log_id(bit.wire), bit.offset);
                }
 
                work->sticky_dirty_bits.clear();
 
                for (auto &child : work->children)
-                       eval_sticky_dirty(child.second, prefix + cid(child.first) + ".", log_prefix + "." + cid(child.first));
+                       eval_sticky_dirty(child.second);
        }
 
-       void make_func(HierDirtyFlags *work, const string &func_name)
+       void make_func(HierDirtyFlags *work, const string &func_name, const vector<string> &preamble)
        {
                log("Generating function %s():\n", func_name.c_str());
 
@@ -621,21 +638,65 @@ struct SimplecWorker
                funct_declarations.push_back("");
                funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name.c_str(), cid(work->module->name).c_str()));
                funct_declarations.push_back("{");
-               eval_dirty(work, "state->", log_id(work->module->name), "", "");
-               eval_sticky_dirty(work, "state->", log_id(work->module->name));
+               for (auto &line : preamble)
+                       funct_declarations.push_back(line);
+               eval_dirty(work);
+               eval_sticky_dirty(work);
                funct_declarations.push_back("}");
 
                log("  Activated %d cells (%d activated more than once).\n", GetSize(activated_cells), GetSize(reactivated_cells));
        }
 
-       void make_init_func(HierDirtyFlags* /* work */)
+       void eval_init(HierDirtyFlags *work, vector<string> &preamble)
        {
-               // FIXME
+               Module *module = work->module;
+
+               for (Wire *w : module->wires())
+               {
+                       if (w->attributes.count(ID::init))
+                       {
+                               SigSpec sig = sigmaps.at(module)(w);
+                               Const val = w->attributes.at(ID::init);
+                               val.bits.resize(GetSize(sig), State::Sx);
+
+                               for (int i = 0; i < GetSize(sig); i++)
+                                       if (val[i] == State::S0 || val[i] == State::S1) {
+                                               SigBit bit = sig[i];
+                                               preamble.push_back(util_set_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset, val == State::S1 ? "true" : "false"));
+                                               work->set_dirty(bit);
+                                       }
+                       }
+
+                       for (SigBit bit : SigSpec(w))
+                       {
+                               SigBit val = sigmaps.at(module)(bit);
+
+                               if (val == State::S0 || val == State::S1)
+                                       preamble.push_back(util_set_bit(work->prefix + cid(bit.wire->name), bit.wire->width, bit.offset, val == State::S1 ? "true" : "false"));
+
+                               if (driven_bits.at(module).count(val) == 0)
+                                       work->set_dirty(val);
+                       }
+               }
+
+               work->set_dirty(State::S0);
+               work->set_dirty(State::S1);
+
+               for (auto &child : work->children)
+                       eval_init(child.second, preamble);
+       }
+
+       void make_init_func(HierDirtyFlags *work)
+       {
+               vector<string> preamble;
+               eval_init(work, preamble);
+               make_func(work, cid(work->module->name) + "_init", preamble);
        }
 
        void make_eval_func(HierDirtyFlags *work)
        {
                Module *mod = work->module;
+               vector<string> preamble;
 
                for (Wire *w : mod->wires()) {
                        if (w->port_input)
@@ -643,7 +704,7 @@ struct SimplecWorker
                                        work->set_dirty(bit);
                }
 
-               make_func(work, cid(work->module->name) + "_eval");
+               make_func(work, cid(work->module->name) + "_eval", preamble);
        }
 
        void make_tick_func(HierDirtyFlags* /* work */)
@@ -655,7 +716,7 @@ struct SimplecWorker
        {
                create_module_struct(mod);
 
-               HierDirtyFlags work(mod, IdString(), nullptr);
+               HierDirtyFlags work(mod, IdString(), nullptr, "state->", log_id(mod->name));
 
                make_init_func(&work);
                make_eval_func(&work);
@@ -683,13 +744,13 @@ struct SimplecWorker
 
 struct SimplecBackend : public Backend {
        SimplecBackend() : Backend("simplec", "convert design to simple C code") { }
-       virtual void help()
+       void help() override
        {
                //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
                log("\n");
                log("    write_simplec [options] [filename]\n");
                log("\n");
-               log("Write simple C code for simulating the design. The C code writen can be used to\n");
+               log("Write simple C code for simulating the design. The C code written can be used to\n");
                log("simulate the design in a C environment, but the purpose of this command is to\n");
                log("generate code that works well with C-based formal verification.\n");
                log("\n");
@@ -702,8 +763,11 @@ struct SimplecBackend : public Backend {
                log("THIS COMMAND IS UNDER CONSTRUCTION\n");
                log("\n");
        }
-       virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+       void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
        {
+               reserved_cids.clear();
+               id2cid.clear();
+
                SimplecWorker worker(design);
 
                log_header(design, "Executing SIMPLEC backend.\n");