opt_ffinv: Use ModIndex instead of ModWalker.
[yosys.git] / kernel / timinginfo.h
index 8c16fff6c2008ac91d44eaf8df37354e9dc2813a..e7e4eab6e2e4df489529a3f5b28dc23270cb5803 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>
  *            (C) 2020  Eddie Hung    <eddie@fpgeh.com>
  *
  *  Permission to use, copy, modify, and/or distribute this software for any
  *
  */
 
-#ifndef TIMINGARCS_H
-#define TIMINGARCS_H
+#ifndef TIMINGINFO_H
+#define TIMINGINFO_H
 
 #include "kernel/yosys.h"
 
 YOSYS_NAMESPACE_BEGIN
 
-typedef std::pair<RTLIL::SigBit,RTLIL::SigBit> BitBit;
-
-struct ModuleTiming
-{
-       RTLIL::IdString type;
-       dict<BitBit, int> comb;
-       dict<RTLIL::SigBit, int> arrival, required;
-};
-
 struct TimingInfo
 {
-        dict<RTLIL::IdString, ModuleTiming> data;
+       struct NameBit
+       {
+               RTLIL::IdString name;
+               int offset;
+               NameBit() : offset(0) {}
+               NameBit(const RTLIL::IdString name, int offset) : name(name), offset(offset) {}
+               explicit NameBit(const RTLIL::SigBit &b) : name(b.wire->name), offset(b.offset) {}
+               bool operator==(const NameBit& nb) const { return nb.name == name && nb.offset == offset; }
+               bool operator!=(const NameBit& nb) const { return !operator==(nb); }
+               unsigned int hash() const { return mkhash_add(name.hash(), offset); }
+       };
+       struct BitBit
+       {
+               NameBit first, second;
+               BitBit(const NameBit &first, const NameBit &second) : first(first), second(second) {}
+               BitBit(const SigBit &first, const SigBit &second) : first(first), second(second) {}
+               bool operator==(const BitBit& bb) const { return bb.first == first && bb.second == second; }
+               unsigned int hash() const { return mkhash_add(first.hash(), second.hash()); }
+       };
+
+       struct ModuleTiming
+       {
+               dict<BitBit, int> comb;
+               dict<NameBit, std::pair<int,NameBit>> arrival, required;
+               bool has_inputs;
+       };
+
+       dict<RTLIL::IdString, ModuleTiming> data;
 
        TimingInfo()
        {
@@ -53,119 +71,120 @@ struct TimingInfo
                        if (!module->get_blackbox_attribute())
                                continue;
                        setup_module(module);
-                }
+               }
        }
 
-       void setup_module(RTLIL::Module *module)
+       const ModuleTiming& setup_module(RTLIL::Module *module)
        {
-                auto r = data.insert(module->name);
-                log_assert(r.second);
-                auto &t = r.first->second;
+               auto r = data.insert(module->name);
+               log_assert(r.second);
+               auto &t = r.first->second;
 
                for (auto cell : module->cells()) {
-                        if (cell->type == ID($specify2)) {
-                                auto src = cell->getPort(ID(SRC));
-                                auto dst = cell->getPort(ID(DST));
-                                for (const auto &c : src.chunks())
-                                        if (!c.wire->port_input)
-                                                log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
-                                for (const auto &c : dst.chunks())
-                                        if (!c.wire->port_output)
-                                                log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module output.\n", log_id(module), log_id(cell), log_signal(dst));
-                                int rise_max = cell->getParam(ID(T_RISE_MAX)).as_int();
-                                int fall_max = cell->getParam(ID(T_FALL_MAX)).as_int();
-                                int max = std::max(rise_max,fall_max);
-                                if (max < 0)
-                                        log_error("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0.\n", log_id(module), log_id(cell));
-                                if (cell->getParam(ID(FULL)).as_bool()) {
-                                        for (const auto &s : src)
-                                                for (const auto &d : dst) {
-                                                        auto r = t.comb.insert(BitBit(s,d));
-                                                        if (!r.second)
-                                                                log_error("Module '%s' contains multiple specify cells for SRC '%s' and DST '%s'.\n", log_id(module), log_signal(s), log_signal(d));
-                                                        r.first->second = max;
-                                                }
-                                }
-                                else {
-                                        log_assert(GetSize(src) == GetSize(dst));
-                                        for (auto i = 0; i < GetSize(src); i++) {
-                                                const auto &s = src[i];
-                                                const auto &d = dst[i];
-                                                auto r = t.comb.insert(BitBit(s,d));
-                                                if (!r.second)
-                                                        log_error("Module '%s' contains multiple specify cells for SRC '%s' and DST '%s'.\n", log_id(module), log_signal(s), log_signal(d));
-                                                r.first->second = max;
-                                        }
-                                }
-                        }
-                        else if (cell->type == ID($specify3)) {
-                               auto src = cell->getPort(ID(SRC));
-                               auto dst = cell->getPort(ID(DST));
+                       if (cell->type == ID($specify2)) {
+                               auto en = cell->getPort(ID::EN);
+                               if (en.is_fully_const() && !en.as_bool())
+                                       continue;
+                               auto src = cell->getPort(ID::SRC);
+                               auto dst = cell->getPort(ID::DST);
                                for (const auto &c : src.chunks())
-                                       if (!c.wire->port_input)
+                                       if (!c.wire || !c.wire->port_input)
                                                log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
                                for (const auto &c : dst.chunks())
-                                       if (!c.wire->port_output)
+                                       if (!c.wire || !c.wire->port_output)
                                                log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module output.\n", log_id(module), log_id(cell), log_signal(dst));
-                               int rise_max = cell->getParam(ID(T_RISE_MAX)).as_int();
-                               int fall_max = cell->getParam(ID(T_FALL_MAX)).as_int();
+                               int rise_max = cell->getParam(ID::T_RISE_MAX).as_int();
+                               int fall_max = cell->getParam(ID::T_FALL_MAX).as_int();
                                int max = std::max(rise_max,fall_max);
                                if (max < 0)
-                                       log_warning("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell));
-                               if (max <= 0) {
-                                       log_debug("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX <= 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell));
-                                       continue;
+                                       log_error("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0.\n", log_id(module), log_id(cell));
+                               if (cell->getParam(ID::FULL).as_bool()) {
+                                       for (const auto &s : src)
+                                               for (const auto &d : dst) {
+                                                       auto r = t.comb.insert(BitBit(s,d));
+                                                       if (!r.second)
+                                                               log_error("Module '%s' contains multiple specify cells for SRC '%s' and DST '%s'.\n", log_id(module), log_signal(s), log_signal(d));
+                                                       r.first->second = max;
+                                               }
+                               }
+                               else {
+                                       log_assert(GetSize(src) == GetSize(dst));
+                                       for (auto i = 0; i < GetSize(src); i++) {
+                                               const auto &s = src[i];
+                                               const auto &d = dst[i];
+                                               auto r = t.comb.insert(BitBit(s,d));
+                                               if (!r.second)
+                                                       log_error("Module '%s' contains multiple specify cells for SRC '%s' and DST '%s'.\n", log_id(module), log_signal(s), log_signal(d));
+                                               r.first->second = max;
+                                       }
+                               }
+                       }
+                       else if (cell->type == ID($specify3)) {
+                               auto src = cell->getPort(ID::SRC).as_bit();
+                               auto dst = cell->getPort(ID::DST);
+                               if (!src.wire || !src.wire->port_input)
+                                       log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
+                               for (const auto &c : dst.chunks())
+                                       if (!c.wire->port_output)
+                                               log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module output.\n", log_id(module), log_id(cell), log_signal(dst));
+                               int rise_max = cell->getParam(ID::T_RISE_MAX).as_int();
+                               int fall_max = cell->getParam(ID::T_FALL_MAX).as_int();
+                               int max = std::max(rise_max,fall_max);
+                               if (max < 0) {
+                                       log_warning("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Clamping to 0.\n", log_id(module), log_id(cell));
+                                       max = 0;
                                }
                                for (const auto &d : dst) {
-                                        auto &v = t.arrival[d];
-                                       v = std::max(v, max);
-                                }
+                                       auto r = t.arrival.insert(NameBit(d));
+                                       auto &v = r.first->second;
+                                       if (r.second || v.first < max) {
+                                               v.first = max;
+                                               v.second = NameBit(src);
+                                       }
+                               }
                        }
                        else if (cell->type == ID($specrule)) {
-                               auto type = cell->getParam(ID(TYPE)).decode_string();
-                               if (type != "$setup" && type != "$setuphold")
+                               IdString type = cell->getParam(ID::TYPE).decode_string();
+                               if (type != ID($setup) && type != ID($setuphold))
                                        continue;
-                               auto src = cell->getPort(ID(SRC));
-                               auto dst = cell->getPort(ID(DST));
+                               auto src = cell->getPort(ID::SRC);
+                               auto dst = cell->getPort(ID::DST).as_bit();
                                for (const auto &c : src.chunks())
-                                       if (!c.wire->port_input)
+                                       if (!c.wire || !c.wire->port_input)
                                                log_error("Module '%s' contains specify cell '%s' where SRC '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(src));
-                               for (const auto &c : dst.chunks())
-                                       if (!c.wire->port_input)
-                                               log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(dst));
-                               int max = cell->getParam(ID(T_LIMIT_MAX)).as_int();
-                               if (max < 0)
-                                       log_warning("Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell));
-                               if (max <= 0) {
-                                       log_debug("Module '%s' contains specify cell '%s' with T_LIMIT_MAX <= 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell));
-                                       continue;
+                               if (!dst.wire || !dst.wire->port_input)
+                                       log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(dst));
+                               int max = cell->getParam(ID::T_LIMIT_MAX).as_int();
+                               if (max < 0) {
+                                       log_warning("Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Clamping to 0.\n", log_id(module), log_id(cell));
+                                       max = 0;
                                }
                                for (const auto &s : src) {
-                                        auto &v = t.required[s];
-                                       v = std::max(v, max);
-                                }
+                                       auto r = t.required.insert(NameBit(s));
+                                       auto &v = r.first->second;
+                                       if (r.second || v.first < max) {
+                                               v.first = max;
+                                               v.second = NameBit(dst);
+                                       }
+                               }
                        }
                }
+
+               for (auto port_name : module->ports) {
+                       auto wire = module->wire(port_name);
+                       if (wire->port_input) {
+                               t.has_inputs = true;
+                               break;
+                       }
+               }
+
+               return t;
        }
 
-        int delay(IdString module_name, const SigBit &src, const SigBit &dst) const {
-                auto it = data.find(module_name);
-                if (it == data.end())
-                        return 0;
-                return it->second.comb.at(BitBit(src,dst), 0);
-        }
-        int arrival(IdString module_name, const SigBit &src) const {
-                auto it = data.find(module_name);
-                if (it == data.end())
-                        return 0;
-                return it->second.arrival.at(src, 0);
-        }
-        int required(IdString module_name, const SigBit &dst) const {
-                auto it = data.find(module_name);
-                if (it == data.end())
-                        return 0;
-                return it->second.required.at(dst, 0);
-        }
+       decltype(data)::const_iterator find(RTLIL::IdString module_name) const { return data.find(module_name); }
+       decltype(data)::const_iterator end() const { return data.end(); }
+       int count(RTLIL::IdString module_name) const { return data.count(module_name); }
+       const ModuleTiming& at(RTLIL::IdString module_name) const { return data.at(module_name); }
 };
 
 YOSYS_NAMESPACE_END