X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=backends%2Fsimplec%2Fsimplec.cc;h=e283dcf7c1776d899c570596b1af71affd1cf1bb;hb=d8b85e124783b55f414ccfd0513211daa8a94cdb;hp=2b7f4d86b02846867fa78ead021e00e2eb769100;hpb=7931e1ebb4c8bdb218dc9df59a7b0a09f107fd63;p=yosys.git diff --git a/backends/simplec/simplec.cc b/backends/simplec/simplec.cc index 2b7f4d86b..e283dcf7c 100644 --- a/backends/simplec/simplec.cc +++ b/backends/simplec/simplec.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,12 +19,47 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/utils.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct HierDirtyFlags; +static pool reserved_cids; +static dict 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; @@ -33,13 +68,17 @@ struct HierDirtyFlags HierDirtyFlags *parent; pool dirty_bits; pool dirty_cells; + pool sticky_dirty_bits; dict 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)); } } @@ -55,6 +94,7 @@ struct HierDirtyFlags return; dirty_bits.insert(bit); + sticky_dirty_bits.insert(bit); HierDirtyFlags *p = this; while (p != nullptr) { @@ -115,7 +155,6 @@ struct SimplecWorker Design *design; dict sigmaps; - HierDirtyFlags *dirty_flags = nullptr; vector signal_declarations; pool generated_sigtypes; @@ -128,11 +167,14 @@ struct SimplecWorker vector funct_declarations; - pool reserved_cids; - dict id2cid; - dict>>> bit2cell; dict>> bit2output; + dict> driven_bits; + + dict topoidx; + + pool activated_cells; + pool reactivated_cells; SimplecWorker(Design *design) : design(design) { @@ -175,18 +217,22 @@ struct SimplecWorker if ('a' <= s[i] && s[i] <= 'z') s[i] -= 'a' - 'A'; + util_declarations.push_back(""); util_declarations.push_back(stringf("#ifndef %s", s.c_str())); util_declarations.push_back(stringf("#define %s", s.c_str())); } - string util_get_bit(int n, int idx) + string util_get_bit(const string &signame, int n, int idx) { + if (n == 1 && idx == 0) + return signame + ".value_0_0"; + string util_name = stringf("yosys_simplec_get_bit_%d_of_%d", idx, n); if (generated_utils.count(util_name) == 0) { util_ifdef_guard(util_name); - util_declarations.push_back(stringf("bool %s(const %s *sig)", util_name.c_str(), sigtype(n).c_str())); + util_declarations.push_back(stringf("static inline bool %s(const %s *sig)", util_name.c_str(), sigtype(n).c_str())); util_declarations.push_back(stringf("{")); int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize; @@ -199,64 +245,41 @@ struct SimplecWorker generated_utils.insert(util_name); } - return util_name; + return stringf("%s(&%s)", util_name.c_str(), signame.c_str()); } - string util_set_bit(int n, int idx) + string util_set_bit(const string &signame, int n, int idx, const string &expr) { + if (n == 1 && idx == 0) + return stringf(" %s.value_0_0 = %s;", signame.c_str(), expr.c_str()); + string util_name = stringf("yosys_simplec_set_bit_%d_of_%d", idx, n); if (generated_utils.count(util_name) == 0) { util_ifdef_guard(util_name); - util_declarations.push_back(stringf("void %s(%s *sig, bool value)", util_name.c_str(), sigtype(n).c_str())); + util_declarations.push_back(stringf("static inline void %s(%s *sig, bool value)", util_name.c_str(), sigtype(n).c_str())); util_declarations.push_back(stringf("{")); int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize; string value_name = stringf("value_%d_%d", std::min(n-1, (word_idx+1)*max_uintsize-1), word_idx*max_uintsize); + #if 0 util_declarations.push_back(stringf(" if (value)")); util_declarations.push_back(stringf(" sig->%s |= 1UL << %d;", value_name.c_str(), word_offset)); util_declarations.push_back(stringf(" else")); util_declarations.push_back(stringf(" sig->%s &= ~(1UL << %d);", value_name.c_str(), word_offset)); + #else + util_declarations.push_back(stringf(" sig->%s = (sig->%s & ~((uint%d_t)1 << %d)) | ((uint%d_t)value << %d);", + value_name.c_str(), value_name.c_str(), max_uintsize, word_offset, max_uintsize, word_offset)); + #endif util_declarations.push_back(stringf("}")); util_declarations.push_back(stringf("#endif")); generated_utils.insert(util_name); } - return util_name; - } - - 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); + return stringf(" %s(&%s, %s);", util_name.c_str(), signame.c_str(), expr.c_str()); } void create_module_struct(Module *mod) @@ -278,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)) @@ -290,128 +316,181 @@ struct SimplecWorker create_module_struct(design->module(c->type)); } + TopoSort topo; + + for (Cell *c : mod->cells()) + { + topo.node(c->name); + + for (auto &conn : c->connections()) + { + if (!c->input(conn.first)) + continue; + + for (auto bit : sigmaps.at(mod)(conn.second)) + for (auto &it : bit2cell[mod][bit]) + topo.edge(c->name, std::get<0>(it)->name); + } + } + + topo.analyze_loops = false; + topo.sort(); + + for (int i = 0; i < GetSize(topo.sorted); i++) + topoidx[mod->cell(topo.sorted[i])] = i; + + string ifdef_name = stringf("yosys_simplec_%s_state_t", cid(mod->name).c_str()); + + for (int i = 0; i < GetSize(ifdef_name); i++) + if ('a' <= ifdef_name[i] && ifdef_name[i] <= 'z') + ifdef_name[i] -= 'a' - 'A'; + struct_declarations.push_back(""); - struct_declarations.push_back(stringf("struct %s_state_t {", cid(mod->name).c_str())); + struct_declarations.push_back(stringf("#ifndef %s", ifdef_name.c_str())); + struct_declarations.push_back(stringf("#define %s", ifdef_name.c_str())); + struct_declarations.push_back(stringf("struct %s_state_t", cid(mod->name).c_str())); + struct_declarations.push_back("{"); + + struct_declarations.push_back(" // Input Ports"); + for (Wire *w : mod->wires()) + if (w->port_input) + struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); + struct_declarations.push_back(""); + struct_declarations.push_back(" // Output Ports"); for (Wire *w : mod->wires()) - struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); + if (!w->port_input && w->port_output) + struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); + + struct_declarations.push_back(""); + struct_declarations.push_back(" // Internal Wires"); + for (Wire *w : mod->wires()) + if (!w->port_input && !w->port_output) + struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); for (Cell *c : mod->cells()) if (design->module(c->type)) struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type).c_str(), cid(c->name).c_str(), log_id(c))); struct_declarations.push_back(stringf("};")); + struct_declarations.push_back("#endif"); } - void eval_cell(HierDirtyFlags *work, string &prefix, 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 ? stringf("%s(&%s)", util_get_bit(a.wire->width, a.offset).c_str(), (prefix + cid(a.wire->name)).c_str()) : 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(stringf(" %s(&%s, %s); // %s (%s)", util_set_bit(y.wire->width, y.offset).c_str(), - (prefix + cid(y.wire->name)).c_str(), expr.c_str(), log_id(cell), log_id(cell->type))); + 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 ? stringf("%s(&%s)", util_get_bit(a.wire->width, a.offset).c_str(), (prefix + cid(a.wire->name)).c_str()) : a.data ? "1" : "0"; - string b_expr = b.wire ? stringf("%s(&%s)", util_get_bit(b.wire->width, b.offset).c_str(), (prefix + cid(b.wire->name)).c_str()) : 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(stringf(" %s(&%s, %s); // %s (%s)", util_set_bit(y.wire->width, y.offset).c_str(), - (prefix + cid(y.wire->name)).c_str(), expr.c_str(), log_id(cell), log_id(cell->type))); + 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 ? stringf("%s(&%s)", util_get_bit(a.wire->width, a.offset).c_str(), (prefix + cid(a.wire->name)).c_str()) : a.data ? "1" : "0"; - string b_expr = b.wire ? stringf("%s(&%s)", util_get_bit(b.wire->width, b.offset).c_str(), (prefix + cid(b.wire->name)).c_str()) : b.data ? "1" : "0"; - string c_expr = c.wire ? stringf("%s(&%s)", util_get_bit(c.wire->width, c.offset).c_str(), (prefix + cid(c.wire->name)).c_str()) : 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(stringf(" %s(&%s, %s); // %s (%s)", util_set_bit(y.wire->width, y.offset).c_str(), - (prefix + cid(y.wire->name)).c_str(), expr.c_str(), log_id(cell), log_id(cell->type))); + 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 ? stringf("%s(&%s)", util_get_bit(a.wire->width, a.offset).c_str(), (prefix + cid(a.wire->name)).c_str()) : a.data ? "1" : "0"; - string b_expr = b.wire ? stringf("%s(&%s)", util_get_bit(b.wire->width, b.offset).c_str(), (prefix + cid(b.wire->name)).c_str()) : b.data ? "1" : "0"; - string c_expr = c.wire ? stringf("%s(&%s)", util_get_bit(c.wire->width, c.offset).c_str(), (prefix + cid(c.wire->name)).c_str()) : c.data ? "1" : "0"; - string d_expr = d.wire ? stringf("%s(&%s)", util_get_bit(d.wire->width, d.offset).c_str(), (prefix + cid(d.wire->name)).c_str()) : 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(stringf(" %s(&%s, %s); // %s (%s)", util_set_bit(y.wire->width, y.offset).c_str(), - (prefix + cid(y.wire->name)).c_str(), expr.c_str(), log_id(cell), log_id(cell->type))); + 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 ? stringf("%s(&%s)", util_get_bit(a.wire->width, a.offset).c_str(), (prefix + cid(a.wire->name)).c_str()) : a.data ? "1" : "0"; - string b_expr = b.wire ? stringf("%s(&%s)", util_get_bit(b.wire->width, b.offset).c_str(), (prefix + cid(b.wire->name)).c_str()) : b.data ? "1" : "0"; - string s_expr = s.wire ? stringf("%s(&%s)", util_get_bit(s.wire->width, s.offset).c_str(), (prefix + cid(s.wire->name)).c_str()) : s.data ? "1" : "0"; - string expr = stringf("%s ? %s : %s", s_expr.c_str(), b_expr.c_str(), a_expr.c_str()); + 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"; + + // 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(stringf(" %s(&%s, %s); // %s (%s)", util_set_bit(y.wire->width, y.offset).c_str(), - (prefix + cid(y.wire->name)).c_str(), expr.c_str(), log_id(cell), log_id(cell->type))); + 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; @@ -420,10 +499,13 @@ struct SimplecWorker log_error("No C model for %s available at the moment (FIXME).\n", log_id(cell->type)); } - void eval_dirty(HierDirtyFlags *work, string prefix, string log_prefix, string parent_prefix) + void eval_dirty(HierDirtyFlags *work) { while (work->dirty) { + if (verbose && (!work->dirty_bits.empty() || !work->dirty_cells.empty())) + log(" In %s:\n", work->log_prefix.c_str()); + while (!work->dirty_bits.empty() || !work->dirty_cells.empty()) { if (!work->dirty_bits.empty()) @@ -431,8 +513,13 @@ struct SimplecWorker SigSpec dirtysig(work->dirty_bits); dirtysig.sort_and_unify(); - for (SigChunk chunk : dirtysig.chunks()) - funct_declarations.push_back(stringf(" // New dirty bits in %s: %s", log_prefix.c_str(), log_signal(chunk))); + for (SigChunk chunk : dirtysig.chunks()) { + if (chunk.wire == nullptr) + continue; + if (verbose) + 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) { @@ -447,27 +534,34 @@ 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(stringf(" %s(&%s, %s(&%s));", - util_set_bit(parent_bit.wire->width, parent_bit.offset).c_str(), - (parent_prefix + cid(parent_bit.wire->name)).c_str(), - util_get_bit(bit.wire->width, bit.offset).c_str(), - (prefix + cid(bit.wire->name)).c_str())); + 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", 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]) { - if (work->children.count(std::get<0>(port)->name)) { + if (work->children.count(std::get<0>(port)->name)) + { HierDirtyFlags *child = work->children.at(std::get<0>(port)->name); 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(stringf(" %s(&%s, %s(&%s));", - util_set_bit(child_bit.wire->width, child_bit.offset).c_str(), - (prefix + cid(child->hiername) + "." + cid(child_bit.wire->name)).c_str(), - util_get_bit(bit.wire->width, bit.offset).c_str(), - (prefix + cid(bit.wire->name)).c_str())); + + 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", 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", 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)); } } @@ -477,49 +571,156 @@ struct SimplecWorker if (!work->dirty_cells.empty()) { - Cell *cell = *work->dirty_cells.begin(); - eval_cell(work, prefix, log_prefix, cell); + Cell *cell = nullptr; + for (auto c : work->dirty_cells) + if (cell == nullptr || topoidx.at(cell) < topoidx.at(c)) + cell = c; + + 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)); + + if (activated_cells.count(hiername)) + reactivated_cells.insert(hiername); + activated_cells.insert(hiername); + + 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); + eval_dirty(child.second); } } - void run(Module *mod) + void eval_sticky_dirty(HierDirtyFlags *work) { - create_module_struct(mod); + Module *mod = work->module; - dirty_flags = new HierDirtyFlags(mod, IdString(), nullptr); + for (Wire *w : mod->wires()) + for (SigBit bit : SigSpec(w)) + { + SigBit canonical_bit = sigmaps.at(mod)(bit); + + if (canonical_bit == bit) + continue; + + if (work->sticky_dirty_bits.count(canonical_bit) == 0) + continue; + + 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", + 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); + } + + void make_func(HierDirtyFlags *work, const string &func_name, const vector &preamble) + { + log("Generating function %s():\n", func_name.c_str()); + + activated_cells.clear(); + reactivated_cells.clear(); funct_declarations.push_back(""); - funct_declarations.push_back(stringf("void %s_init(struct %s_state_t *state)", cid(mod->name).c_str(), cid(mod->name).c_str())); + 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("{"); + for (auto &line : preamble) + funct_declarations.push_back(line); + eval_dirty(work); + eval_sticky_dirty(work); funct_declarations.push_back("}"); - funct_declarations.push_back(""); - funct_declarations.push_back(stringf("void %s_eval(struct %s_state_t *state)", cid(mod->name).c_str(), cid(mod->name).c_str())); - funct_declarations.push_back("{"); + log(" Activated %d cells (%d activated more than once).\n", GetSize(activated_cells), GetSize(reactivated_cells)); + } + + void eval_init(HierDirtyFlags *work, vector &preamble) + { + 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 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 preamble; for (Wire *w : mod->wires()) { if (w->port_input) for (SigBit bit : sigmaps.at(mod)(w)) - dirty_flags->set_dirty(bit); + work->set_dirty(bit); } - eval_dirty(dirty_flags, "state->", log_id(mod), ""); + make_func(work, cid(work->module->name) + "_eval", preamble); + } - funct_declarations.push_back("}"); + void make_tick_func(HierDirtyFlags* /* work */) + { + // FIXME + } - funct_declarations.push_back(""); - funct_declarations.push_back(stringf("void %s_tick(struct %s_state_t *state)", cid(mod->name).c_str(), cid(mod->name).c_str())); - funct_declarations.push_back("{"); - funct_declarations.push_back("}"); + void run(Module *mod) + { + create_module_struct(mod); + + HierDirtyFlags work(mod, IdString(), nullptr, "state->", log_id(mod->name)); - delete dirty_flags; - dirty_flags = nullptr; + make_init_func(&work); + make_eval_func(&work); + make_tick_func(&work); } void write(std::ostream &f) @@ -543,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"); @@ -562,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 args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) override { + reserved_cids.clear(); + id2cid.clear(); + SimplecWorker worker(design); log_header(design, "Executing SIMPLEC backend.\n");