summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2013-01-05 11:13:26 +0100
committerClifford Wolf <clifford@clifford.at>2013-01-05 11:13:26 +0100
commit7764d0ba1dcf064ae487ee985c43083a0909e7f4 (patch)
tree18c05b8729df381af71b707748ce1d605e0df764 /kernel
initial import
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bitpattern.h143
-rw-r--r--kernel/calc.cc392
-rw-r--r--kernel/celltypes.h210
-rw-r--r--kernel/consteval.h198
-rw-r--r--kernel/driver.cc253
-rw-r--r--kernel/log.cc197
-rw-r--r--kernel/log.h51
-rw-r--r--kernel/register.cc288
-rw-r--r--kernel/register.h80
-rw-r--r--kernel/rtlil.cc1081
-rw-r--r--kernel/rtlil.h341
-rw-r--r--kernel/select.cc476
-rw-r--r--kernel/sha1.cpp185
-rw-r--r--kernel/sha1.h49
-rw-r--r--kernel/show.cc343
-rw-r--r--kernel/sigtools.h415
16 files changed, 4702 insertions, 0 deletions
diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h
new file mode 100644
index 00000000..aaefa50f
--- /dev/null
+++ b/kernel/bitpattern.h
@@ -0,0 +1,143 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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 BITPATTERN_H
+#define BITPATTERN_H
+
+#include "kernel/log.h"
+#include "kernel/rtlil.h"
+
+struct BitPatternPool
+{
+ int width;
+ typedef std::vector<RTLIL::State> bits_t;
+ std::set<bits_t> pool;
+
+ BitPatternPool(RTLIL::SigSpec sig)
+ {
+ width = sig.width;
+ if (width > 0) {
+ std::vector<RTLIL::State> pattern(width);
+ sig.optimize();
+ for (int i = 0; i < width; i++) {
+ RTLIL::SigSpec s = sig.extract(i, 1);
+ s.optimize();
+ assert(s.chunks.size() == 1);
+ if (s.chunks[0].wire == NULL && s.chunks[0].data.bits[0] <= RTLIL::State::S1)
+ pattern[i] = s.chunks[0].data.bits[0];
+ else
+ pattern[i] = RTLIL::State::Sa;
+ }
+ pool.insert(pattern);
+ }
+ }
+
+ BitPatternPool(int width)
+ {
+ this->width = width;
+ if (width > 0) {
+ std::vector<RTLIL::State> pattern(width);
+ for (int i = 0; i < width; i++)
+ pattern[i] = RTLIL::State::Sa;
+ pool.insert(pattern);
+ }
+ }
+
+ bits_t sig2bits(RTLIL::SigSpec sig)
+ {
+ sig.optimize();
+ assert(sig.is_fully_const());
+ assert(sig.chunks.size() == 1);
+ bits_t bits = sig.chunks[0].data.bits;
+ for (auto &b : bits)
+ if (b > RTLIL::State::S1)
+ b = RTLIL::State::Sa;
+ return bits;
+ }
+
+ bool match(bits_t a, bits_t b)
+ {
+ assert(int(a.size()) == width);
+ assert(int(b.size()) == width);
+ for (int i = 0; i < width; i++)
+ if (a[i] <= RTLIL::State::S1 && b[i] <= RTLIL::State::S1 && a[i] != b[i])
+ return false;
+ return true;
+ }
+
+ bool has_any(RTLIL::SigSpec sig)
+ {
+ bits_t bits = sig2bits(sig);
+ for (auto &it : pool)
+ if (match(it, bits))
+ return true;
+ return false;
+ }
+
+ bool has_all(RTLIL::SigSpec sig)
+ {
+ bits_t bits = sig2bits(sig);
+ for (auto &it : pool)
+ if (match(it, bits)) {
+ for (int i = 0; i < width; i++)
+ if (bits[i] > RTLIL::State::S1 && it[i] <= RTLIL::State::S1)
+ goto next_pool_entry;
+ return true;
+ next_pool_entry:;
+ }
+ return false;
+ }
+
+ bool take(RTLIL::SigSpec sig)
+ {
+ bool status = false;
+ bits_t bits = sig2bits(sig);
+ std::vector<bits_t> pattern_list;
+ for (auto &it : pool)
+ if (match(it, bits))
+ pattern_list.push_back(it);
+ for (auto pattern : pattern_list) {
+ pool.erase(pattern);
+ for (int i = 0; i < width; i++) {
+ if (pattern[i] != RTLIL::State::Sa || bits[i] == RTLIL::State::Sa)
+ continue;
+ bits_t new_pattern = pattern;
+ new_pattern[i] = bits[i] == RTLIL::State::S1 ? RTLIL::State::S0 : RTLIL::State::S1;
+ pool.insert(new_pattern);
+ }
+ status = true;
+ }
+ return status;
+ }
+
+ bool take_all()
+ {
+ if (pool.empty())
+ return false;
+ pool.clear();
+ return true;
+ }
+
+ bool empty()
+ {
+ return pool.empty();
+ }
+};
+
+#endif
diff --git a/kernel/calc.cc b/kernel/calc.cc
new file mode 100644
index 00000000..f31fed7d
--- /dev/null
+++ b/kernel/calc.cc
@@ -0,0 +1,392 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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 "kernel/rtlil.h"
+#include "bigint/BigIntegerLibrary.hh"
+#include <assert.h>
+
+static BigInteger const2big(const RTLIL::Const &val, bool as_signed, int &undef_bit_pos)
+{
+ BigInteger result = 0, this_bit = 1;
+ for (size_t i = 0; i < val.bits.size(); i++) {
+ if (val.bits[i] == RTLIL::State::S1) {
+ if (as_signed && i+1 == val.bits.size())
+ result -= this_bit;
+ else
+ result += this_bit;
+ }
+ else if (val.bits[i] != RTLIL::State::S0) {
+ if (undef_bit_pos < 0)
+ undef_bit_pos = i;
+ }
+ this_bit *= 2;
+ }
+ return result;
+}
+
+static RTLIL::Const big2const(const BigInteger &val, int result_len, int undef_bit_pos)
+{
+ BigUnsigned mag = val.getMagnitude();
+ RTLIL::Const result(0, result_len);
+
+ if (!mag.isZero())
+ {
+ if (val.getSign() < 0)
+ {
+ mag--;
+ for (int i = 0; i < result_len; i++)
+ result.bits[i] = mag.getBit(i) ? RTLIL::State::S0 : RTLIL::State::S1;
+ }
+ else
+ {
+ for (int i = 0; i < result_len; i++)
+ result.bits[i] = mag.getBit(i) ? RTLIL::State::S1 : RTLIL::State::S0;
+ }
+ }
+
+ if (undef_bit_pos >= 0)
+ for (int i = undef_bit_pos; i < result_len; i++)
+ result.bits[i] = RTLIL::State::Sx;
+
+ return result;
+}
+
+static RTLIL::State logic_and(RTLIL::State a, RTLIL::State b)
+{
+ if (a == RTLIL::State::S0) return RTLIL::State::S0;
+ if (b == RTLIL::State::S0) return RTLIL::State::S0;
+ if (a != RTLIL::State::S1) return RTLIL::State::Sx;
+ if (b != RTLIL::State::S1) return RTLIL::State::Sx;
+ return RTLIL::State::S1;
+}
+
+static RTLIL::State logic_or(RTLIL::State a, RTLIL::State b)
+{
+ if (a == RTLIL::State::S1) return RTLIL::State::S1;
+ if (b == RTLIL::State::S1) return RTLIL::State::S1;
+ if (a != RTLIL::State::S0) return RTLIL::State::Sx;
+ if (b != RTLIL::State::S0) return RTLIL::State::Sx;
+ return RTLIL::State::S0;
+}
+
+static RTLIL::State logic_xor(RTLIL::State a, RTLIL::State b)
+{
+ if (a != RTLIL::State::S0 && a != RTLIL::State::S1) return RTLIL::State::Sx;
+ if (b != RTLIL::State::S0 && b != RTLIL::State::S1) return RTLIL::State::Sx;
+ return a != b ? RTLIL::State::S1 : RTLIL::State::S0;
+}
+
+static RTLIL::State logic_xnor(RTLIL::State a, RTLIL::State b)
+{
+ if (a != RTLIL::State::S0 && a != RTLIL::State::S1) return RTLIL::State::Sx;
+ if (b != RTLIL::State::S0 && b != RTLIL::State::S1) return RTLIL::State::Sx;
+ return a == b ? RTLIL::State::S1 : RTLIL::State::S0;
+}
+
+RTLIL::Const RTLIL::const_not(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int result_len)
+{
+ if (result_len < 0)
+ result_len = arg1.bits.size();
+
+ RTLIL::Const result(RTLIL::State::Sx, result_len);
+ for (size_t i = 0; i < size_t(result_len); i++) {
+ if (i >= arg1.bits.size())
+ result.bits[i] = RTLIL::State::S0;
+ else if (arg1.bits[i] == RTLIL::State::S0)
+ result.bits[i] = RTLIL::State::S1;
+ else if (arg1.bits[i] == RTLIL::State::S1)
+ result.bits[i] = RTLIL::State::S0;
+ }
+
+ return result;
+}
+
+static RTLIL::Const logic_wrapper(RTLIL::State(*logic_func)(RTLIL::State, RTLIL::State),
+ const RTLIL::Const &arg1, const RTLIL::Const &arg2, int result_len = -1)
+{
+ if (result_len < 0)
+ result_len = std::max(arg1.bits.size(), arg2.bits.size());
+
+ RTLIL::Const result(RTLIL::State::Sx, result_len);
+ for (size_t i = 0; i < size_t(result_len); i++) {
+ RTLIL::State a = i < arg1.bits.size() ? arg1.bits[i] : RTLIL::State::S0;
+ RTLIL::State b = i < arg2.bits.size() ? arg2.bits[i] : RTLIL::State::S0;
+ result.bits[i] = logic_func(a, b);
+ }
+
+ return result;
+}
+
+RTLIL::Const RTLIL::const_and(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return logic_wrapper(logic_and, arg1, arg2, result_len);
+}
+
+RTLIL::Const RTLIL::const_or(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return logic_wrapper(logic_or, arg1, arg2, result_len);
+}
+
+RTLIL::Const RTLIL::const_xor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return logic_wrapper(logic_xor, arg1, arg2, result_len);
+}
+
+RTLIL::Const RTLIL::const_xnor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return logic_wrapper(logic_xnor, arg1, arg2, result_len);
+}
+
+static RTLIL::Const logic_reduce_wrapper(RTLIL::State(*logic_func)(RTLIL::State, RTLIL::State), const RTLIL::Const &arg1)
+{
+ RTLIL::State temp = RTLIL::State::S0;
+
+ for (size_t i = 0; i < arg1.bits.size(); i++)
+ temp = logic_func(temp, arg1.bits[i]);
+
+ return RTLIL::Const(temp);
+}
+
+RTLIL::Const RTLIL::const_reduce_and(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
+{
+ return logic_reduce_wrapper(logic_and, arg1);
+}
+
+RTLIL::Const RTLIL::const_reduce_or(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
+{
+ return logic_reduce_wrapper(logic_or, arg1);
+}
+
+RTLIL::Const RTLIL::const_reduce_xor(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
+{
+ return logic_reduce_wrapper(logic_xor, arg1);
+}
+
+RTLIL::Const RTLIL::const_reduce_xnor(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
+{
+ return logic_reduce_wrapper(logic_xnor, arg1);
+}
+
+RTLIL::Const RTLIL::const_reduce_bool(const RTLIL::Const &arg1, const RTLIL::Const&, bool, bool, int)
+{
+ return logic_reduce_wrapper(logic_or, arg1);
+}
+
+RTLIL::Const RTLIL::const_logic_not(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int)
+{
+ int undef_bit_pos_a = -1;
+ BigInteger a = const2big(arg1, signed1, undef_bit_pos_a);
+
+ if (a.isZero()) {
+ if (undef_bit_pos_a >= 0)
+ return RTLIL::Const(RTLIL::State::Sx);
+ return RTLIL::Const(RTLIL::State::S1);
+ }
+
+ return RTLIL::Const(RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_logic_and(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos_a = -1, undef_bit_pos_b = -1;
+ BigInteger a = const2big(arg1, signed1, undef_bit_pos_a);
+ BigInteger b = const2big(arg2, signed2, undef_bit_pos_b);
+
+ if (a.isZero() || b.isZero()) {
+ if (undef_bit_pos_a >= 0 && undef_bit_pos_b >= 0)
+ return RTLIL::Const(RTLIL::State::Sx);
+ return RTLIL::Const(RTLIL::State::S0);
+ }
+
+ return RTLIL::Const(RTLIL::State::S1);
+}
+
+RTLIL::Const RTLIL::const_logic_or(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos_a = -1, undef_bit_pos_b = -1;
+ BigInteger a = const2big(arg1, signed1, undef_bit_pos_a);
+ BigInteger b = const2big(arg2, signed2, undef_bit_pos_b);
+
+ if (a.isZero() && b.isZero()) {
+ if (undef_bit_pos_a >= 0 || undef_bit_pos_b >= 0)
+ return RTLIL::Const(RTLIL::State::Sx);
+ return RTLIL::Const(RTLIL::State::S0);
+ }
+
+ return RTLIL::Const(RTLIL::State::S1);
+}
+
+static RTLIL::Const const_shift(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, int direction, int result_len)
+{
+ int undef_bit_pos = -1;
+ BigInteger offset = const2big(arg2, false, undef_bit_pos) * direction;
+
+ if (result_len < 0)
+ result_len = arg1.bits.size();
+
+ RTLIL::Const result(RTLIL::State::Sx, result_len);
+ if (undef_bit_pos >= 0)
+ return result;
+
+ for (int i = 0; i < result_len; i++) {
+ BigInteger pos = BigInteger(i) + offset;
+ if (pos < 0)
+ result.bits[i] = RTLIL::State::S0;
+ else if (pos >= arg1.bits.size())
+ result.bits[i] = sign_ext ? arg1.bits.back() : RTLIL::State::S0;
+ else
+ result.bits[i] = arg1.bits[pos.toInt()];
+ }
+
+ return result;
+}
+
+RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return const_shift(arg1, arg2, false, -1, result_len);
+}
+
+RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return const_shift(arg1, arg2, false, +1, result_len);
+}
+
+RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return const_shift(arg1, arg2, true, -1, result_len);
+}
+
+RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool, int result_len)
+{
+ return const_shift(arg1, arg2, true, +1, result_len);
+}
+
+RTLIL::Const RTLIL::const_lt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos = -1;
+ bool y = const2big(arg1, signed1, undef_bit_pos) < const2big(arg2, signed2, undef_bit_pos);
+ return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_le(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos = -1;
+ bool y = const2big(arg1, signed1, undef_bit_pos) <= const2big(arg2, signed2, undef_bit_pos);
+ return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_eq(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos = -1;
+ bool y = const2big(arg1, signed1, undef_bit_pos) == const2big(arg2, signed2, undef_bit_pos);
+ return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_ne(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos = -1;
+ bool y = const2big(arg1, signed1, undef_bit_pos) != const2big(arg2, signed2, undef_bit_pos);
+ return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_ge(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos = -1;
+ bool y = const2big(arg1, signed1, undef_bit_pos) >= const2big(arg2, signed2, undef_bit_pos);
+ return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_gt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int)
+{
+ int undef_bit_pos = -1;
+ bool y = const2big(arg1, signed1, undef_bit_pos) > const2big(arg2, signed2, undef_bit_pos);
+ return RTLIL::Const(undef_bit_pos >= 0 ? RTLIL::State::Sx : y ? RTLIL::State::S1 : RTLIL::State::S0);
+}
+
+RTLIL::Const RTLIL::const_add(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+{
+ int undef_bit_pos = -1;
+ BigInteger y = const2big(arg1, signed1, undef_bit_pos) + const2big(arg2, signed2, undef_bit_pos);
+ return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), undef_bit_pos);
+}
+
+RTLIL::Const RTLIL::const_sub(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+{
+ int undef_bit_pos = -1;
+ BigInteger y = const2big(arg1, signed1, undef_bit_pos) - const2big(arg2, signed2, undef_bit_pos);
+ return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), undef_bit_pos);
+}
+
+RTLIL::Const RTLIL::const_mul(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+{
+ int undef_bit_pos = -1;
+ BigInteger y = const2big(arg1, signed1, undef_bit_pos) * const2big(arg2, signed2, undef_bit_pos);
+ return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
+}
+
+RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+{
+ int undef_bit_pos = -1;
+ BigInteger y = const2big(arg1, signed1, undef_bit_pos) / const2big(arg2, signed2, undef_bit_pos);
+ return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
+}
+
+RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+{
+ int undef_bit_pos = -1;
+ BigInteger y = const2big(arg1, signed1, undef_bit_pos) % const2big(arg2, signed2, undef_bit_pos);
+ return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
+}
+
+RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+{
+ int undef_bit_pos = -1;
+
+ BigInteger a = const2big(arg1, signed1, undef_bit_pos);
+ BigInteger b = const2big(arg2, signed2, undef_bit_pos);
+ BigInteger y = 1;
+
+ if (b < 0 || a == 0) {
+ y = 0;
+ } else {
+ while (b > 0) {
+ y = y * a;
+ if (y.getLength() > 0x10000) {
+ undef_bit_pos = 0;
+ break;
+ }
+ b--;
+ }
+ }
+
+ return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0));
+}
+
+RTLIL::Const RTLIL::const_pos(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
+{
+ RTLIL::Const zero(RTLIL::State::S0, 1);
+ return RTLIL::const_add(zero, arg1, false, signed1, result_len);
+}
+
+RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
+{
+ RTLIL::Const zero(RTLIL::State::S0, 1);
+ return RTLIL::const_sub(zero, arg1, false, signed1, result_len);
+}
+
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
new file mode 100644
index 00000000..a13cbf32
--- /dev/null
+++ b/kernel/celltypes.h
@@ -0,0 +1,210 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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 CELLTYPES_H
+#define CELLTYPES_H
+
+#include <set>
+#include <string>
+#include <stdlib.h>
+
+struct CellTypes
+{
+ std::set<std::string> cell_types;
+
+ void setup_internals()
+ {
+ cell_types.insert("$not");
+ cell_types.insert("$pos");
+ cell_types.insert("$neg");
+ cell_types.insert("$and");
+ cell_types.insert("$or");
+ cell_types.insert("$xor");
+ cell_types.insert("$xnor");
+ cell_types.insert("$reduce_and");
+ cell_types.insert("$reduce_or");
+ cell_types.insert("$reduce_xor");
+ cell_types.insert("$reduce_xnor");
+ cell_types.insert("$reduce_bool");
+ cell_types.insert("$shl");
+ cell_types.insert("$shr");
+ cell_types.insert("$sshl");
+ cell_types.insert("$sshr");
+ cell_types.insert("$lt");
+ cell_types.insert("$le");
+ cell_types.insert("$eq");
+ cell_types.insert("$ne");
+ cell_types.insert("$ge");
+ cell_types.insert("$gt");
+ cell_types.insert("$add");
+ cell_types.insert("$sub");
+ cell_types.insert("$mul");
+ cell_types.insert("$div");
+ cell_types.insert("$mod");
+ cell_types.insert("$pow");
+ cell_types.insert("$logic_not");
+ cell_types.insert("$logic_and");
+ cell_types.insert("$logic_or");
+ cell_types.insert("$mux");
+ cell_types.insert("$pmux");
+ cell_types.insert("$safe_pmux");
+ }
+
+ void setup_internals_mem()
+ {
+ cell_types.insert("$dff");
+ cell_types.insert("$adff");
+ cell_types.insert("$memrd");
+ cell_types.insert("$memwr");
+ cell_types.insert("$mem");
+ cell_types.insert("$fsm");
+ }
+
+ void setup_stdcells()
+ {
+ cell_types.insert("$_INV_");
+ cell_types.insert("$_AND_");
+ cell_types.insert("$_OR_");
+ cell_types.insert("$_XOR_");
+ cell_types.insert("$_MUX_");
+ }
+
+ void setup_stdcells_mem()
+ {
+ cell_types.insert("$_DFF_N_");
+ cell_types.insert("$_DFF_P_");
+ cell_types.insert("$_DFF_NN0_");
+ cell_types.insert("$_DFF_NN1_");
+ cell_types.insert("$_DFF_NP0_");
+ cell_types.insert("$_DFF_NP1_");
+ cell_types.insert("$_DFF_PN0_");
+ cell_types.insert("$_DFF_PN1_");
+ cell_types.insert("$_DFF_PP0_");
+ cell_types.insert("$_DFF_PP1_");
+ }
+
+ void clear()
+ {
+ cell_types.clear();
+ }
+
+ bool cell_known(std::string type)
+ {
+ return cell_types.count(type) > 0;
+ }
+
+ bool cell_output(std::string type, std::string port)
+ {
+ if (!cell_known(type))
+ return false;
+ if (port == "\\Y" || port == "\\Q" || port == "\\RD_DATA")
+ return true;
+ if (type == "$memrd" && port == "\\DATA")
+ return true;
+ if (type == "$fsm" && port == "\\CTRL_OUT")
+ return true;
+ return false;
+ }
+
+ bool cell_input(std::string type, std::string port)
+ {
+ if (!cell_known(type))
+ return false;
+ return !cell_output(type, port);
+ }
+
+ static RTLIL::Const eval(std::string type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
+ {
+#define HANDLE_CELL_TYPE(_t) if (type == "$" #_t) return const_ ## _t(arg1, arg2, signed1, signed2, result_len);
+ HANDLE_CELL_TYPE(not)
+ HANDLE_CELL_TYPE(and)
+ HANDLE_CELL_TYPE(or)
+ HANDLE_CELL_TYPE(xor)
+ HANDLE_CELL_TYPE(xnor)
+ HANDLE_CELL_TYPE(reduce_and)
+ HANDLE_CELL_TYPE(reduce_or)
+ HANDLE_CELL_TYPE(reduce_xor)
+ HANDLE_CELL_TYPE(reduce_xnor)
+ HANDLE_CELL_TYPE(reduce_bool)
+ HANDLE_CELL_TYPE(logic_not)
+ HANDLE_CELL_TYPE(logic_and)
+ HANDLE_CELL_TYPE(logic_or)
+ HANDLE_CELL_TYPE(shl)
+ HANDLE_CELL_TYPE(shr)
+ HANDLE_CELL_TYPE(sshl)
+ HANDLE_CELL_TYPE(sshr)
+ HANDLE_CELL_TYPE(lt)
+ HANDLE_CELL_TYPE(le)
+ HANDLE_CELL_TYPE(eq)
+ HANDLE_CELL_TYPE(ne)
+ HANDLE_CELL_TYPE(ge)
+ HANDLE_CELL_TYPE(gt)
+ HANDLE_CELL_TYPE(add)
+ HANDLE_CELL_TYPE(sub)
+ HANDLE_CELL_TYPE(mul)
+ HANDLE_CELL_TYPE(div)
+ HANDLE_CELL_TYPE(mod)
+ HANDLE_CELL_TYPE(pow)
+ HANDLE_CELL_TYPE(pos)
+ HANDLE_CELL_TYPE(neg)
+#undef HANDLE_CELL_TYPE
+
+ if (type == "$_INV_")
+ return const_not(arg1, arg2, false, false, 1);
+ if (type == "$_AND_")
+ return const_and(arg1, arg2, false, false, 1);
+ if (type == "$_OR_")
+ return const_or(arg1, arg2, false, false, 1);
+ if (type == "$_XOR_")
+ return const_xor(arg1, arg2, false, false, 1);
+
+ assert(!"Called CellType.eval() with unsupported cell type!");
+ abort();
+ }
+
+ static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2)
+ {
+ bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool();
+ bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool();
+ int result_len = cell->parameters.count("\\Y_WIDTH") > 0 ? cell->parameters["\\Y_WIDTH"].as_int() : -1;
+ return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len);
+ }
+
+ static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &sel)
+ {
+ if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_") {
+ RTLIL::Const ret = arg1;
+ for (size_t i = 0; i < sel.bits.size(); i++)
+ if (sel.bits[i] == RTLIL::State::S1) {
+ std::vector<RTLIL::State> bits(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size());
+ ret = RTLIL::Const(bits);
+ }
+ return ret;
+ }
+
+ assert(sel.bits.size() == 0);
+ bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool();
+ bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool();
+ int result_len = cell->parameters.count("\\Y_WIDTH") > 0 ? cell->parameters["\\Y_WIDTH"].as_int() : -1;
+ return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len);
+ }
+};
+
+#endif
+
diff --git a/kernel/consteval.h b/kernel/consteval.h
new file mode 100644
index 00000000..d48771fe
--- /dev/null
+++ b/kernel/consteval.h
@@ -0,0 +1,198 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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 CONSTEVAL_H
+#define CONSTEVAL_H
+
+#include "kernel/rtlil.h"
+#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+
+struct ConstEval
+{
+ RTLIL::Module *module;
+ SigMap assign_map;
+ SigMap values_map;
+ SigPool stop_signals;
+ SigSet<RTLIL::Cell*> sig2driver;
+ std::set<RTLIL::Cell*> busy;
+ std::vector<SigMap> stack;
+
+ ConstEval(RTLIL::Module *module) : module(module), assign_map(module)
+ {
+ CellTypes ct;
+ ct.setup_internals();
+ ct.setup_stdcells();
+
+ for (auto &it : module->cells) {
+ if (!ct.cell_known(it.second->type))
+ continue;
+ for (auto &it2 : it.second->connections)
+ if (ct.cell_output(it.second->type, it2.first))
+ sig2driver.insert(assign_map(it2.second), it.second);
+ }
+ }
+
+ void clear()
+ {
+ values_map.clear();
+ stop_signals.clear();
+ }
+
+ void push()
+ {
+ stack.push_back(values_map);
+ }
+
+ void pop()
+ {
+ values_map.swap(stack.back());
+ stack.pop_back();
+ }
+
+ void set(RTLIL::SigSpec sig, RTLIL::Const value)
+ {
+ assign_map.apply(sig);
+#ifndef NDEBUG
+ RTLIL::SigSpec current_val = values_map(sig);
+ current_val.expand();
+ for (size_t i = 0; i < current_val.chunks.size(); i++) {
+ RTLIL::SigChunk &chunk = current_val.chunks[i];
+ assert(chunk.wire != NULL || chunk.data.bits[0] == value.bits[i]);
+ }
+#endif
+ values_map.add(sig, RTLIL::SigSpec(value));
+ }
+
+ void stop(RTLIL::SigSpec sig)
+ {
+ assign_map.apply(sig);
+ stop_signals.add(sig);
+ }
+
+ bool eval(RTLIL::Cell *cell, RTLIL::SigSpec &undef)
+ {
+ RTLIL::SigSpec sig_a, sig_b, sig_s, sig_y;
+ bool ignore_sig_a = false, ignore_sig_b = false;
+ int sig_b_shift = -1;
+
+ assert(cell->connections.count("\\Y") > 0);
+ sig_y = values_map(assign_map(cell->connections["\\Y"]));
+ if (sig_y.is_fully_const())
+ return true;
+
+ if (cell->connections.count("\\S") > 0) {
+ sig_s = cell->connections["\\S"];
+ if (!eval(sig_s, undef, cell))
+ return false;
+ }
+
+ if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_") {
+ bool found_collision = false;
+ for (int i = 0; i < sig_s.width; i++)
+ if (sig_s.extract(i, 1).as_bool()) {
+ if (sig_b_shift >= 0)
+ found_collision = true;
+ sig_b_shift = i;
+ ignore_sig_a = true;
+ if (cell->type != "$safe_pmux")
+ break;
+ }
+ if (found_collision) {
+ sig_b_shift = -1;
+ ignore_sig_a = false;
+ }
+ if (sig_b_shift < 0)
+ ignore_sig_b = true;
+ }
+
+ if (!ignore_sig_a && cell->connections.count("\\A") > 0) {
+ sig_a = cell->connections["\\A"];
+ if (!eval(sig_a, undef, cell))
+ return false;
+ }
+
+ if (!ignore_sig_b && cell->connections.count("\\B") > 0) {
+ sig_b = cell->connections["\\B"];
+ if (sig_b_shift >= 0)
+ sig_b = sig_b.extract(sig_y.width*sig_b_shift, sig_y.width);
+ if (!eval(sig_b, undef, cell))
+ return false;
+ }
+
+ if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_")
+ set(sig_y, sig_s.as_bool() ? sig_b.as_const() : sig_a.as_const());
+ else
+ set(sig_y, CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const()));
+
+ return true;
+ }
+
+ bool eval(RTLIL::SigSpec &sig, RTLIL::SigSpec &undef, RTLIL::Cell *busy_cell = NULL)
+ {
+ assign_map.apply(sig);
+ values_map.apply(sig);
+
+ if (sig.is_fully_const())
+ return true;
+
+ if (stop_signals.check_any(sig)) {
+ undef = stop_signals.extract(sig);
+ return false;
+ }
+
+ if (busy_cell) {
+ if (busy.count(busy_cell) > 0) {
+ undef = sig;
+ return false;
+ }
+ busy.insert(busy_cell);
+ }
+
+ std::set<RTLIL::Cell*> driver_cells;
+ sig2driver.find(sig, driver_cells);
+ for (auto cell : driver_cells) {
+ if (!eval(cell, undef)) {
+ if (busy_cell)
+ busy.erase(busy_cell);
+ return false;
+ }
+ }
+
+ if (busy_cell)
+ busy.erase(busy_cell);
+
+ values_map.apply(sig);
+ if (sig.is_fully_const())
+ return true;
+
+ for (size_t i = 0; i < sig.chunks.size(); i++)
+ if (sig.chunks[i].wire != NULL)
+ undef.append(sig.chunks[i]);
+ return false;
+ }
+
+ bool eval(RTLIL::SigSpec &sig)
+ {
+ RTLIL::SigSpec undef;
+ return eval(sig, undef);
+ }
+};
+
+#endif
diff --git a/kernel/driver.cc b/kernel/driver.cc
new file mode 100644
index 00000000..c49bf657
--- /dev/null
+++ b/kernel/driver.cc
@@ -0,0 +1,253 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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 <stdio.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "kernel/rtlil.h"
+#include "kernel/register.h"
+#include "kernel/log.h"
+#include <string.h>
+#include <unistd.h>
+
+static void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command)
+{
+ if (command == "auto") {
+ if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
+ command = "verilog";
+ else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
+ command = "ilang";
+ else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
+ command = "script";
+ else if (filename == "-")
+ command = "ilang";
+ else
+ log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str());
+ }
+
+ if (command == "script") {
+ log("\n-- Executing script file `%s' --\n", filename.c_str());
+ FILE *f = fopen(filename.c_str(), "r");
+ if (f == NULL)
+ log_error("Can;t open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
+ char buffer[4096];
+ while (fgets(buffer, 4096, f) != NULL) {
+ Pass::call(design, buffer);
+ design->check();
+ }
+ fclose(f);
+ if (backend_command != NULL && *backend_command == "auto")
+ *backend_command = "";
+ return;
+ }
+
+ if (filename == "-") {
+ log("\n-- Parsing stdin using frontend `%s' --\n", command.c_str());
+ } else {
+ log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str());
+ }
+
+ Frontend::frontend_call(design, NULL, filename, command);
+ design->check();
+}
+
+static void run_pass(std::string command, RTLIL::Design *design)
+{
+ log("\n-- Running pass `%s' --\n", command.c_str());
+
+ Pass::call(design, command);
+ design->check();
+}
+
+static void run_backend(std::string filename, std::string command, RTLIL::Design *design)
+{
+ if (command == "auto") {
+ if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
+ command = "verilog";
+ else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
+ command = "ilang";
+ else if (filename == "-")
+ command = "ilang";
+ else
+ log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str());
+ }
+
+ if (filename == "-") {
+ log("\n-- Writing to stdout using backend `%s' --\n", command.c_str());
+ } else {
+ log("\n-- Writing to `%s' using backend `%s' --\n", filename.c_str(), command.c_str());
+ }
+
+ Backend::backend_call(design, NULL, filename, command);
+ design->check();
+}
+
+static char *readline_cmd_generator(const char *text, int state)
+{
+ static std::map<std::string, Pass*>::iterator it;
+ static int len;
+
+ if (!state) {
+ it = REGISTER_INTERN::pass_register.begin();
+ len = strlen(text);
+ }
+
+ for (; it != REGISTER_INTERN::pass_register.end(); it++) {
+ if (it->first.substr(0, len) == text)
+ return strdup((it++)->first.c_str());
+ }
+ return NULL;
+}
+
+static char **readline_completion(const char *text, int start, int)
+{
+ if (start == 0)
+ return rl_completion_matches(text, readline_cmd_generator);
+ return NULL;
+}
+
+static const char *create_prompt(RTLIL::Design *design)
+{
+ static char buffer[100];
+ std::string str = "\nyosys";
+ if (!design->selected_active_module.empty())
+ str += stringf(" [%s]", design->selected_active_module.c_str());
+ if (!design->selection_stack.back().full_selection) {
+ if (design->selected_active_module.empty())
+ str += "*";
+ else if (design->selection_stack.back().selected_modules.size() != 1 || design->selection_stack.back().selected_members.size() != 0 ||
+ design->selection_stack.back().selected_modules.count(design->selected_active_module) == 0)
+ str += "*";
+ }
+ snprintf(buffer, 100, "%s> ", str.c_str());
+ return buffer;
+}
+
+int main(int argc, char **argv)
+{
+ std::string frontend_command = "auto";
+ std::string backend_command = "auto";
+ std::vector<std::string> passes_commands;
+ std::string output_filename = "-";
+ std::string scriptfile = "";
+ bool got_output_filename = false;
+
+ RTLIL::Design *design = new RTLIL::Design;
+ design->selection_stack.push_back(RTLIL::Selection());
+ log_push();
+
+ int opt;
+ while ((opt = getopt(argc, argv, "f:b:o:p:l:qts:")) != -1)
+ {
+ switch (opt)
+ {
+ case 'f':
+ frontend_command = optarg;
+ break;
+ case 'b':
+ backend_command = optarg;
+ break;
+ case 'p':
+ passes_commands.push_back(optarg);
+ break;
+ case 'o':
+ output_filename = optarg;
+ got_output_filename = true;
+ break;
+ case 'l':
+ log_files.push_back(fopen(optarg, "wt"));
+ if (log_files.back() == NULL) {
+ fprintf(stderr, "Can't open log file `%s' for writing!\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'q':
+ log_errfile = stderr;
+ break;
+ case 't':
+ log_time = true;
+ break;
+ case 's':
+ scriptfile = optarg;
+ break;
+ default:
+ fprintf(stderr, "Usage: %s [-q] [-t] [-l logfile] [-o <outfile>] [-f <frontend>] [-s <scriptfile>] [-p <pass> [-p ..]] [-b <backend>] [<infile> [..]]\n", argv[0]);
+ exit(1);
+ }
+ }
+
+ if (log_errfile == NULL)
+ log_files.push_back(stderr);
+
+ if (optind == argc && passes_commands.size() == 0 && scriptfile.empty())
+ {
+ log_cmd_error_throw = true;
+
+ rl_readline_name = "yosys";
+ rl_attempted_completion_function = readline_completion;
+
+ char *command = NULL;
+ while ((command = readline(create_prompt(design))) != NULL)
+ {
+ if (command[strspn(command, " \t\r\n")] == 0)
+ continue;
+ add_history(command);
+
+ try {
+ assert(design->selection_stack.size() == 1);
+ Pass::call(design, command);
+ } catch (int) {
+ while (design->selection_stack.size() > 1)
+ design->selection_stack.pop_back();
+ log_reset_stack();
+ }
+ }
+
+ if (!got_output_filename)
+ backend_command = "";
+ log_cmd_error_throw = false;
+ }
+
+ while (optind < argc)
+ run_frontend(argv[optind++], frontend_command, design, output_filename == "-" ? &backend_command : NULL);
+
+ if (!scriptfile.empty())
+ run_frontend(scriptfile, "script", design, output_filename == "-" ? &backend_command : NULL);
+
+ for (auto it = passes_commands.begin(); it != passes_commands.end(); it++)
+ run_pass(*it, design);
+
+ if (!backend_command.empty())
+ run_backend(output_filename, backend_command, design);
+
+ delete design;
+
+ log("\nREADY.\n");
+ log_pop();
+
+ for (auto f : log_files)
+ if (f != stderr)
+ fclose(f);
+ log_errfile = NULL;
+ log_files.clear();
+
+ return 0;
+}
+
diff --git a/kernel/log.cc b/kernel/log.cc
new file mode 100644
index 00000000..9bf8705e
--- /dev/null
+++ b/kernel/log.cc
@@ -0,0 +1,197 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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 "kernel/log.h"
+#include "backends/ilang/ilang_backend.h"
+
+#include <sys/time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <vector>
+#include <list>
+
+std::vector<FILE*> log_files;
+FILE *log_errfile = NULL;
+bool log_time = false;
+bool log_cmd_error_throw = false;
+
+std::vector<int> header_count;
+std::list<std::string> string_buf;
+
+static struct timeval initial_tv = { 0, 0 };
+static bool next_print_log = false;
+
+std::string stringf(const char *fmt, ...)
+{
+ std::string string;
+ char *str = NULL;
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (vasprintf(&str, fmt, ap) < 0)
+ str = NULL;
+ va_end(ap);
+
+ if (str != NULL) {
+ string = str;
+ free(str);
+ }
+
+ return string;
+}
+
+void logv(const char *format, va_list ap)
+{
+ if (log_time) {
+ while (format[0] == '\n' && format[1] != 0) {
+ format++;
+ log("\n");
+ }
+ if (next_print_log || initial_tv.tv_sec == 0) {
+ next_print_log = false;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ if (initial_tv.tv_sec == 0)
+ initial_tv = tv;
+ if (tv.tv_usec < initial_tv.tv_usec) {
+ tv.tv_sec--;
+ tv.tv_usec += 1000000;
+ }
+ tv.tv_sec -= initial_tv.tv_sec;
+ tv.tv_usec -= initial_tv.tv_usec;
+ log("[%05d.%06d] ", int(tv.tv_sec), int(tv.tv_usec));
+ }
+ if (format[0] && format[strlen(format)-1] == '\n')
+ next_print_log = true;
+ }
+
+ for (auto f : log_files) {
+ va_list aq;
+ va_copy(aq, ap);
+ vfprintf(f, format, aq);
+ va_end(aq);
+ }
+}
+
+void logv_header(const char *format, va_list ap)
+{
+ log("\n");
+ if (header_count.size() > 0)
+ header_count.back()++;
+ for (int c : header_count)
+ log("%d.", c);
+ log(" ");
+ logv(format, ap);
+ log_flush();
+}
+
+void logv_error(const char *format, va_list ap)
+{
+ log("ERROR: ");
+ logv(format, ap);
+ if (log_errfile != NULL) {
+ fprintf(log_errfile, "ERROR: ");
+ vfprintf(log_errfile, format, ap);
+ }
+ log_flush();
+ exit(1);
+}
+
+void log(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ logv(format, ap);
+ va_end(ap);
+}
+
+void log_header(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ logv_header(format, ap);
+ va_end(ap);
+}
+
+void log_error(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ logv_error(format, ap);
+}
+
+void log_cmd_error(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+
+ if (log_cmd_error_throw) {
+ log("ERROR: ");
+ logv(format, ap);
+ log_flush();
+ throw 0;
+ }
+
+ logv_error(format, ap);
+}
+
+void log_push()
+{
+ header_count.push_back(0);
+}
+
+void log_pop()
+{
+ header_count.pop_back();
+ string_buf.clear();
+ log_flush();
+}
+
+void log_reset_stack()
+{
+ while (header_count.size() > 1)
+ header_count.pop_back();
+ string_buf.clear();
+ log_flush();
+}
+
+void log_flush()
+{
+ for (auto f : log_files)
+ fflush(f);
+}
+
+const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
+{
+ char *ptr;
+ size_t size;
+
+ FILE *f = open_memstream(&ptr, &size);
+ ILANG_BACKEND::dump_sigspec(f, sig, autoint);
+ fputc(0, f);
+ fclose(f);
+
+ string_buf.push_back(ptr);
+ free(ptr);
+
+ return string_buf.back().c_str();
+}
+
diff --git a/kernel/log.h b/kernel/log.h
new file mode 100644
index 00000000..9023854d
--- /dev/null
+++ b/kernel/log.h
@@ -0,0 +1,51 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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 LOG_H
+#define LOG_H
+
+#include "kernel/rtlil.h"
+#include <stdio.h>
+#include <vector>
+
+extern std::vector<FILE*> log_files;
+extern FILE *log_errfile;
+extern bool log_time;
+extern bool log_cmd_error_throw;
+
+std::string stringf(const char *fmt, ...);
+
+void logv(const char *format, va_list ap);
+void logv_header(const char *format, va_list ap);
+void logv_error(const char *format, va_list ap) __attribute__ ((noreturn));
+
+void log(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+void log_header(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+void log_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn));
+void log_cmd_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn));
+
+void log_push();
+void log_pop();
+
+void log_reset_stack();
+void log_flush();
+
+const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
+
+#endif
diff --git a/kernel/register.cc b/kernel/register.cc
new file mode 100644
index 00000000..fb70c80d
--- /dev/null
+++ b/kernel/register.cc
@@ -0,0 +1,288 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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 "register.h"
+#include "log.h"
+#include <assert.h>
+#include <string.h>
+
+using namespace REGISTER_INTERN;
+
+namespace REGISTER_INTERN {
+ std::map<std::string, Frontend*> frontend_register;
+ std::map<std::string, Pass*> pass_register;
+ std::map<std::string, Backend*> backend_register;
+}
+
+std::vector<std::string> Frontend::next_args;
+
+Pass::Pass(std::string name) : pass_name(name)
+{
+ assert(pass_register.count(name) == 0);
+ pass_register[name] = this;
+}
+
+Pass::~Pass()
+{
+ pass_register.erase(pass_name);
+}
+
+void Pass::help()
+{
+ log("No help message for this command.\n");
+}
+
+void Pass::cmd_log_args(const std::vector<std::string> &args)
+{
+ if (args.size() <= 1)
+ return;
+ log("Full command line:");
+ for (size_t i = 0; i < args.size(); i++)
+ log(" %s", args[i].c_str());
+ log("\n");
+}
+
+void Pass::cmd_error(const std::vector<std::string> &args, size_t argidx, std::string msg)
+{
+ std::string command_text;
+ int error_pos = 0;
+
+ for (size_t i = 0; i < args.size(); i++) {
+ if (i < argidx)
+ error_pos += args[i].size() + 1;
+ command_text = command_text + (command_text.empty() ? "" : " ") + args[i];
+ }
+
+ log("\nSyntax error in command `%s':\n", command_text.c_str());
+ help();
+
+ log_cmd_error("Command syntax error: %s\n> %s\n> %*s^\n",
+ msg.c_str(), command_text.c_str(), error_pos, "");
+}
+
+void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Design *)
+{
+ for (; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+
+ if (arg.substr(0, 1) == "-")
+ cmd_error(args, argidx, "Unkown option or option in arguments.");
+ cmd_error(args, argidx, "Extra argument.");
+ }
+ cmd_log_args(args);
+}
+
+void Pass::call(RTLIL::Design *design, std::string command)
+{
+ std::vector<std::string> args;
+ char *s = strdup(command.c_str());
+ for (char *p = strtok(s, " \t\r\n"); p; p = strtok(NULL, " \t\r\n"))
+ args.push_back(p);
+ free(s);
+ call(design, args);
+}
+
+void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
+{
+ if (args.size() == 0 || args[0][0] == '#')
+ return;
+ if (pass_register.count(args[0]) == 0)
+ log_cmd_error("No such command: %s\n", args[0].c_str());
+
+ size_t orig_sel_stack_pos = design->selection_stack.size();
+ pass_register[args[0]]->execute(args, design);
+ while (design->selection_stack.size() > orig_sel_stack_pos)
+ design->selection_stack.pop_back();
+}
+
+Frontend::Frontend(std::string name) : Pass("read_"+name), frontend_name(name)
+{
+ assert(frontend_register.count(name) == 0);
+ frontend_register[name] = this;
+}
+
+Frontend::~Frontend()
+{
+ frontend_register.erase(frontend_name);
+}
+
+void Frontend::execute(std::vector<std::string> args, RTLIL::Design *design)
+{
+ assert(next_args.empty());
+ do {
+ FILE *f = NULL;
+ next_args.clear();
+ execute(f, std::string(), args, design);
+ args = next_args;
+ fclose(f);
+ } while (!args.empty());
+}
+
+void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
+{
+ bool called_with_fp = f != NULL;
+
+ next_args.clear();
+ for (; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+
+ if (arg.substr(0, 1) == "-")
+ cmd_error(args, argidx, "Unkown option or option in arguments.");
+ if (f != NULL)
+ cmd_error(args, argidx, "Extra filename argument in direct file mode.");
+
+ filename = arg;
+ f = fopen(filename.c_str(), "r");
+ if (f == NULL)
+ log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
+
+ if (argidx+1 < args.size()) {
+ next_args.insert(next_args.begin(), args.begin(), args.begin()+argidx);
+ next_args.insert(next_args.begin()+argidx, args.begin()+argidx+1, args.end());
+ args.erase(args.begin()+argidx+1, args.end());
+ }
+ break;
+ }
+ if (f == NULL)
+ cmd_error(args, argidx, "No filename given.");
+
+ if (called_with_fp)
+ args.push_back(filename);
+ args[0] = pass_name;
+ cmd_log_args(args);
+}
+
+void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command)
+{
+ std::vector<std::string> args;
+ char *s = strdup(command.c_str());
+ for (char *p = strtok(s, " \t\r\n"); p; p = strtok(NULL, " \t\r\n"))
+ args.push_back(p);
+ free(s);
+ frontend_call(design, f, filename, args);
+}
+
+void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args)
+{
+ if (args.size() == 0)
+ return;
+ if (frontend_register.count(args[0]) == 0)
+ log_cmd_error("No such frontend: %s\n", args[0].c_str());
+
+ if (f != NULL) {
+ frontend_register[args[0]]->execute(f, filename, args, design);
+ } else if (filename == "-") {
+ frontend_register[args[0]]->execute(stdin, "<stdin>", args, design);
+ } else {
+ if (!filename.empty())
+ args.push_back(filename);
+ frontend_register[args[0]]->execute(args, design);
+ }
+}
+
+Backend::Backend(std::string name) : Pass("write_"+name), backend_name(name)
+{
+ assert(backend_register.count(name) == 0);
+ backend_register[name] = this;
+}
+
+Backend::~Backend()
+{
+ backend_register.erase(backend_name);
+}
+
+void Backend::execute(std::vector<std::string> args, RTLIL::Design *design)
+{
+ FILE *f = NULL;
+ execute(f, std::string(), args, design);
+ if (f != stdout)
+ fclose(f);
+}
+
+void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
+{
+ bool called_with_fp = f != NULL;
+
+ for (; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+
+ if (arg.substr(0, 1) == "-" && arg != "-")
+ cmd_error(args, argidx, "Unkown option or option in arguments.");
+ if (f != NULL)
+ cmd_error(args, argidx, "Extra filename argument in direct file mode.");
+
+ if (arg == "-") {
+ filename = "<stdout>";
+ f = stdout;
+ continue;
+ }
+
+ filename = arg;
+ f = fopen(filename.c_str(), "w");
+ if (f == NULL)
+ log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+ }
+
+ if (called_with_fp)
+ args.push_back(filename);
+ args[0] = pass_name;
+ cmd_log_args(args);
+
+ if (f == NULL) {
+ filename = "<stdout>";
+ f = stdout;
+ }
+}
+
+void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command)
+{
+ std::vector<std::string> args;
+ char *s = strdup(command.c_str());
+ for (char *p = strtok(s, " \t\r\n"); p; p = strtok(NULL, " \t\r\n"))
+ args.push_back(p);
+ free(s);
+ backend_call(design, f, filename, args);
+}
+
+void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args)
+{
+ if (args.size() == 0)
+ return;
+ if (backend_register.count(args[0]) == 0)
+ log_cmd_error("No such backend: %s\n", args[0].c_str());
+
+ size_t orig_sel_stack_pos = design->selection_stack.size();
+
+ if (f != NULL) {
+ backend_register[args[0]]->execute(f, filename, args, design);
+ } else if (filename == "-") {
+ backend_register[args[0]]->execute(stdout, "<stdout>", args, design);
+ } else {
+ if (!filename.empty())
+ args.push_back(filename);
+ backend_register[args[0]]->execute(args, design);
+ }
+
+ while (design->selection_stack.size() > orig_sel_stack_pos)
+ design->selection_stack.pop_back();
+}
+
diff --git a/kernel/register.h b/kernel/register.h
new file mode 100644
index 00000000..713d468e
--- /dev/null
+++ b/kernel/register.h
@@ -0,0 +1,80 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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 REGISTER_H
+#define REGISTER_H
+
+#include "kernel/rtlil.h"
+#include <stdio.h>
+#include <string>
+#include <vector>
+#include <map>
+
+struct Pass
+{
+ std::string pass_name;
+ Pass(std::string name);
+ virtual ~Pass();
+ virtual void help();
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0;
+
+ void cmd_log_args(const std::vector<std::string> &args);
+ void cmd_error(const std::vector<std::string> &args, size_t argidx, std::string msg);
+ void extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Design *design);
+
+ static void call(RTLIL::Design *design, std::string command);
+ static void call(RTLIL::Design *design, std::vector<std::string> args);
+};
+
+struct Frontend : Pass
+{
+ std::string frontend_name;
+ Frontend(std::string name);
+ virtual ~Frontend();
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design);
+ virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
+
+ static std::vector<std::string> next_args;
+ void extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
+
+ static void frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command);
+ static void frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args);
+};
+
+struct Backend : Pass
+{
+ std::string backend_name;
+ Backend(std::string name);
+ virtual ~Backend();
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design);
+ virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
+
+ void extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
+
+ static void backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command);
+ static void backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args);
+};
+
+namespace REGISTER_INTERN {
+ extern std::map<std::string, Pass*> pass_register;
+ extern std::map<std::string, Frontend*> frontend_register;
+ extern std::map<std::string, Backend*> backend_register;
+}
+
+#endif
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
new file mode 100644
index 00000000..c97e2e45
--- /dev/null
+++ b/kernel/rtlil.cc
@@ -0,0 +1,1081 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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 "kernel/rtlil.h"
+#include <assert.h>
+#include <algorithm>
+
+int RTLIL::autoidx = 1;
+
+RTLIL::Const::Const(std::string str) : str(str)
+{
+ for (size_t i = 0; i < str.size(); i++) {
+ unsigned char ch = str[i];
+ for (int j = 0; j < 8; j++) {
+ bits.push_back((ch & 1) != 0 ? RTLIL::S1 : RTLIL::S0);
+ ch = ch >> 1;
+ }
+ }
+}
+
+RTLIL::Const::Const(int val, int width)
+{
+ for (int i = 0; i < width; i++) {
+ bits.push_back((val & 1) != 0 ? RTLIL::S1 : RTLIL::S0);
+ val = val >> 1;
+ }
+}
+
+RTLIL::Const::Const(RTLIL::State bit, int width)
+{
+ for (int i = 0; i < width; i++)
+ bits.push_back(bit);
+}
+
+bool RTLIL::Const::operator <(const RTLIL::Const &other) const
+{
+ if (bits.size() != other.bits.size())
+ return bits.size() < other.bits.size();
+ for (size_t i = 0; i < bits.size(); i++)
+ if (bits[i] != other.bits[i])
+ return bits[i] < other.bits[i];
+ return false;
+}
+
+bool RTLIL::Const::operator ==(const RTLIL::Const &other) const
+{
+ return bits == other.bits;
+}
+
+bool RTLIL::Const::operator !=(const RTLIL::Const &other) const
+{
+ return bits != other.bits;
+}
+
+bool RTLIL::Const::as_bool() const
+{
+ for (size_t i = 0; i < bits.size(); i++)
+ if (bits[i] == RTLIL::S1)
+ return true;
+ return false;
+}
+
+int RTLIL::Const::as_int() const
+{
+ int ret = 0;
+ for (size_t i = 0; i < bits.size() && i < 32; i++)
+ if (bits[i] == RTLIL::S1)
+ ret |= 1 << i;
+ return ret;
+}
+
+std::string RTLIL::Const::as_string() const
+{
+ std::string ret;
+ for (size_t i = bits.size(); i > 0; i--)
+ switch (bits[i-1]) {
+ case S0: ret += "0"; break;
+ case S1: ret += "1"; break;
+ case Sx: ret += "x"; break;
+ case Sz: ret += "z"; break;
+ case Sa: ret += "-"; break;
+ case Sm: ret += "m"; break;
+ }
+ return ret;
+}
+
+bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name)
+{
+ if (full_selection)
+ return true;
+ if (selected_modules.count(mod_name) > 0)
+ return true;
+ if (selected_members.count(mod_name) > 0)
+ return true;
+ return false;
+}
+
+bool RTLIL::Selection::selected_whole_module(RTLIL::IdString mod_name)
+{
+ if (full_selection)
+ return true;
+ if (selected_modules.count(mod_name) > 0)
+ return true;
+ return false;
+}
+
+bool RTLIL::Selection::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name)
+{
+ if (full_selection)
+ return true;
+ if (selected_modules.count(mod_name) > 0)
+ return true;
+ if (selected_members.count(mod_name) > 0)
+ if (selected_members[mod_name].count(memb_name) > 0)
+ return true;
+ return false;
+}
+
+void RTLIL::Selection::optimize(RTLIL::Design *design)
+{
+ if (full_selection) {
+ selected_modules.clear();
+ selected_members.clear();
+ return;
+ }
+
+ std::vector<RTLIL::IdString> del_list, add_list;
+
+ del_list.clear();
+ for (auto mod_name : selected_modules) {
+ if (design->modules.count(mod_name) == 0)
+ del_list.push_back(mod_name);
+ selected_members.erase(mod_name);
+ }
+ for (auto mod_name : del_list)
+ selected_modules.erase(mod_name);
+
+ del_list.clear();
+ for (auto &it : selected_members)
+ if (design->modules.count(it.first) == 0)
+ del_list.push_back(it.first);
+ for (auto mod_name : del_list)
+ selected_members.erase(mod_name);
+
+ for (auto &it : selected_members) {
+ del_list.clear();
+ for (auto memb_name : it.second)
+ if (design->modules[it.first]->count_id(memb_name) == 0)
+ del_list.push_back(memb_name);
+ for (auto memb_name : del_list)
+ it.second.erase(memb_name);
+ }
+
+ del_list.clear();
+ add_list.clear();
+ for (auto &it : selected_members)
+ if (it.second.size() == 0)
+ del_list.push_back(it.first);
+ else if (it.second.size() == design->modules[it.first]->wires.size() + design->modules[it.first]->memories.size() +
+ design->modules[it.first]->cells.size() + design->modules[it.first]->processes.size())
+ add_list.push_back(it.first);
+ for (auto mod_name : del_list)
+ selected_members.erase(mod_name);
+ for (auto mod_name : add_list) {
+ selected_members.erase(mod_name);
+ selected_modules.insert(mod_name);
+ }
+
+ if (selected_modules.size() == design->modules.size()) {
+ full_selection = true;
+ selected_modules.clear();
+ selected_members.clear();
+ }
+}
+
+RTLIL::Design::~Design()
+{
+ for (auto it = modules.begin(); it != modules.end(); it++)
+ delete it->second;
+}
+
+void RTLIL::Design::check()
+{
+#ifndef NDEBUG
+ for (auto &it : modules) {
+ assert(it.first == it.second->name);
+ assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$'));
+ it.second->check();
+ }
+#endif
+}
+
+void RTLIL::Design::optimize()
+{
+ for (auto &it : modules)
+ it.second->optimize();
+ for (auto &it : selection_stack)
+ it.optimize(this);
+ for (auto &it : selection_vars)
+ it.second.optimize(this);
+}
+
+bool RTLIL::Design::selected_module(RTLIL::IdString mod_name)
+{
+ if (!selected_active_module.empty() && mod_name != selected_active_module)
+ return false;
+ if (selection_stack.size() == 0)
+ return true;
+ return selection_stack.back().selected_module(mod_name);
+}
+
+bool RTLIL::Design::selected_whole_module(RTLIL::IdString mod_name)
+{
+ if (!selected_active_module.empty() && mod_name != selected_active_module)
+ return false;
+ if (selection_stack.size() == 0)
+ return true;
+ return selection_stack.back().selected_whole_module(mod_name);
+}
+
+bool RTLIL::Design::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name)
+{
+ if (!selected_active_module.empty() && mod_name != selected_active_module)
+ return false;
+ if (selection_stack.size() == 0)
+ return true;
+ return selection_stack.back().selected_member(mod_name, memb_name);
+}
+
+RTLIL::Module::~Module()
+{
+ for (auto it = wires.begin(); it != wires.end(); it++)
+ delete it->second;
+ for (auto it = memories.begin(); it != memories.end(); it++)
+ delete it->second;
+ for (auto it = cells.begin(); it != cells.end(); it++)
+ delete it->second;
+ for (auto it = processes.begin(); it != processes.end(); it++)
+ delete it->second;
+}
+
+RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, std::map<RTLIL::IdString, RTLIL::Const>)
+{
+ assert(!"Called derive() from module base class.");
+ abort();
+}
+
+void RTLIL::Module::update_auto_wires(std::map<RTLIL::IdString, int>)
+{
+ assert(!"Called update_auto_wires() from module base class.");
+}
+
+size_t RTLIL::Module::count_id(RTLIL::IdString id)
+{
+ return wires.count(id) + memories.count(id) + cells.count(id) + processes.count(id);
+}
+
+void RTLIL::Module::check()
+{
+#ifndef NDEBUG
+ for (auto &it : wires) {
+ assert(it.first == it.second->name);
+ assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$'));
+ assert(it.second->width >= 0);
+ assert(it.second->port_id >= 0);
+ for (auto &it2 : it.second->attributes) {
+ assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$'));
+ }
+ }
+
+ for (auto &it : memories) {
+ assert(it.first == it.second->name);
+ assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$'));
+ assert(it.second->width >= 0);
+ assert(it.second->size >= 0);
+ for (auto &it2 : it.second->attributes) {
+ assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$'));
+ }
+ }
+
+ for (auto &it : cells) {
+ assert(it.first == it.second->name);
+ assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$'));
+ assert(it.second->type.size() > 0 && (it.second->type[0] == '\\' || it.second->type[0] == '$'));
+ for (auto &it2 : it.second->connections) {
+ assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$'));
+ it2.second.check();
+ }
+ for (auto &it2 : it.second->attributes) {
+ assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$'));
+ }
+ for (auto &it2 : it.second->parameters) {
+ assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$'));
+ }
+ }
+
+ for (auto &it : processes) {
+ assert(it.first == it.second->name);
+ assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$'));
+ // FIXME: More checks here..
+ }
+
+ for (auto &it : connections) {
+ assert(it.first.width == it.second.width);
+ it.first.check();
+ it.second.check();
+ }
+
+ for (auto &it : attributes) {
+ assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$'));
+ }
+#endif
+}
+
+void RTLIL::Module::optimize()
+{
+ for (auto &it : cells)
+ it.second->optimize();
+ for (auto &it : processes)
+ it.second->optimize();
+ for (auto &it : connections) {
+ it.first.optimize();
+ it.second.optimize();
+ }
+}
+
+void RTLIL::Module::add(RTLIL::Wire *wire) {
+ assert(!wire->name.empty());
+ assert(count_id(wire->name) == 0);
+ wires[wire->name] = wire;
+}
+
+void RTLIL::Module::add(RTLIL::Cell *cell) {
+ assert(!cell->name.empty());
+ assert(count_id(cell->name) == 0);
+ cells[cell->name] = cell;
+}
+
+RTLIL::Wire::Wire()
+{
+ width = 1;
+ start_offset = 0;
+ port_id = 0;
+ port_input = false;
+ port_output = false;
+ auto_width = false;
+}
+
+RTLIL::Memory::Memory()
+{
+ width = 1;
+ size = 0;
+}
+
+void RTLIL::Cell::optimize()
+{
+ for (auto &it : connections)
+ it.second.optimize();
+}
+
+RTLIL::SigChunk::SigChunk()
+{
+ wire = NULL;
+ width = 0;
+ offset = 0;
+}
+
+RTLIL::SigChunk::SigChunk(const RTLIL::Const &data)
+{
+ wire = NULL;
+ this->data = data;
+ width = data.bits.size();
+ offset = 0;
+}
+
+RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire, int width, int offset)
+{
+ this->wire = wire;
+ this->width = width >= 0 ? width : wire->width;
+ this->offset = offset;
+}
+
+RTLIL::SigChunk::SigChunk(const std::string &str)
+{
+ wire = NULL;
+ data = RTLIL::Const(str);
+ width = data.bits.size();
+ offset = 0;
+}
+
+RTLIL::SigChunk::SigChunk(int val, int width)
+{
+ wire = NULL;
+ data = RTLIL::Const(val, width);
+ this->width = data.bits.size();
+ offset = 0;
+}
+
+RTLIL::SigChunk::SigChunk(RTLIL::State bit, int width)
+{
+ wire = NULL;
+ data = RTLIL::Const(bit, width);
+ this->width = data.bits.size();
+ offset = 0;
+}
+
+RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const
+{
+ RTLIL::SigChunk ret;
+ if (wire) {
+ ret.wire = wire;
+ ret.offset = this->offset + offset;
+ ret.width = length;
+ } else {
+ for (int i = 0; i < length; i++)
+ ret.data.bits.push_back(data.bits[offset+i]);
+ ret.width = length;
+ }
+ return ret;
+}
+
+bool RTLIL::SigChunk::operator <(const RTLIL::SigChunk &other) const
+{
+ if (wire && other.wire)
+ if (wire->name != other.wire->name)
+ return wire->name < other.wire->name;
+ if (wire != other.wire)
+ return wire < other.wire;
+
+ if (offset != other.offset)
+ return offset < other.offset;
+
+ if (width != other.width)
+ return width < other.width;
+
+ if (data.bits != other.data.bits)
+ return data.bits < other.data.bits;
+
+ return false;
+}
+
+bool RTLIL::SigChunk::operator ==(const RTLIL::SigChunk &other) const
+{
+ if (wire != other.wire || width != other.width || offset != other.offset)
+ return false;
+ if (data.bits != other.data.bits)
+ return false;
+ return true;
+}
+
+bool RTLIL::SigChunk::operator !=(const RTLIL::SigChunk &other) const
+{
+ if (*this == other)
+ return false;
+ return true;
+}
+
+RTLIL::SigSpec::SigSpec()
+{
+ width = 0;
+}
+
+RTLIL::SigSpec::SigSpec(const RTLIL::Const &data)
+{
+ chunks.push_back(RTLIL::SigChunk(data));
+ width = chunks.back().width;
+ check();
+}
+
+RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk)
+{
+ chunks.push_back(chunk);
+ width = chunks.back().width;
+ check();
+}
+
+RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int width, int offset)
+{
+ chunks.push_back(RTLIL::SigChunk(wire, width, offset));
+ this->width = chunks.back().width;
+ check();
+}
+
+RTLIL::SigSpec::SigSpec(const std::string &str)
+{
+ chunks.push_back(RTLIL::SigChunk(str));
+ width = chunks.back().width;
+ check();
+}
+
+RTLIL::SigSpec::SigSpec(int val, int width)
+{
+ chunks.push_back(RTLIL::SigChunk(val, width));
+ this->width = chunks.back().width;
+ check();
+}
+
+RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width)
+{
+ chunks.push_back(RTLIL::SigChunk(bit, width));
+ this->width = chunks.back().width;
+ check();
+}
+
+void RTLIL::SigSpec::expand()
+{
+ std::vector<RTLIL::SigChunk> new_chunks;
+ for (size_t i = 0; i < chunks.size(); i++) {
+ assert(chunks[i].data.str.empty());
+ for (int j = 0; j < chunks[i].width; j++)
+ new_chunks.push_back(chunks[i].extract(j, 1));
+ }
+ chunks.swap(new_chunks);
+ check();
+}
+
+void RTLIL::SigSpec::optimize()
+{
+ for (size_t i = 0; i < chunks.size(); i++) {
+ if (chunks[i].wire && chunks[i].wire->auto_width)
+ continue;
+ if (chunks[i].width == 0)
+ chunks.erase(chunks.begin()+i--);
+ }
+ for (size_t i = 1; i < chunks.size(); i++) {
+ RTLIL::SigChunk &ch1 = chunks[i-1];
+ RTLIL::SigChunk &ch2 = chunks[i];
+ if (ch1.wire && ch1.wire->auto_width)
+ continue;
+ if (ch2.wire && ch2.wire->auto_width)
+ continue;
+ if (ch1.wire == ch2.wire) {
+ if (ch1.wire != NULL && ch1.offset+ch1.width == ch2.offset) {
+ ch1.width += ch2.width;
+ goto merged_with_next_chunk;
+ }
+ if (ch1.wire == NULL && ch1.data.str.empty() == ch2.data.str.empty()) {
+ ch1.data.str = ch2.data.str + ch1.data.str;
+ ch1.data.bits.insert(ch1.data.bits.end(), ch2.data.bits.begin(), ch2.data.bits.end());
+ ch1.width += ch2.width;
+ goto merged_with_next_chunk;
+ }
+ }
+ if (0) {
+ merged_with_next_chunk:
+ chunks.erase(chunks.begin()+i);
+ i--;
+ }
+ }
+ check();
+}
+
+static bool compare_sigchunks(const RTLIL::SigChunk &a, const RTLIL::SigChunk &b)
+{
+ if (a.wire != b.wire) {
+ if (a.wire == NULL || b.wire == NULL)
+ return a.wire < b.wire;
+ else if (a.wire->name != b.wire->name)
+ return a.wire->name < b.wire->name;
+ else
+ return a.wire < b.wire;
+ }
+ if (a.offset != b.offset)
+ return a.offset < b.offset;
+ if (a.width != b.width)
+ return a.width < b.width;
+ return a.data.bits < b.data.bits;
+}
+
+void RTLIL::SigSpec::sort_and_unify()
+{
+ expand();
+ std::sort(chunks.begin(), chunks.end(), compare_sigchunks);
+ for (size_t i = 1; i < chunks.size(); i++) {
+ RTLIL::SigChunk &ch1 = chunks[i-1];
+ RTLIL::SigChunk &ch2 = chunks[i];
+ if (!compare_sigchunks(ch1, ch2) && !compare_sigchunks(ch2, ch1)) {
+ chunks.erase(chunks.begin()+i);
+ width -= chunks[i].width;
+ i--;
+ }
+ }
+ optimize();
+}
+
+void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with)
+{
+ replace(pattern, with, this);
+}
+
+void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const
+{
+ int pos = 0, restart_pos = 0;
+ assert(other == NULL || width == other->width);
+ for (size_t i = 0; i < chunks.size(); i++) {
+restart:
+ const RTLIL::SigChunk &ch1 = chunks[i];
+ if (chunks[i].wire != NULL && pos >= restart_pos)
+ for (size_t j = 0, poff = 0; j < pattern.chunks.size(); j++) {
+ const RTLIL::SigChunk &ch2 = pattern.chunks[j];
+ assert(ch2.wire != NULL);
+ if (ch1.wire == ch2.wire) {
+ int lower = std::max(ch1.offset, ch2.offset);
+ int upper = std::min(ch1.offset + ch1.width, ch2.offset + ch2.width);
+ if (lower < upper) {
+ restart_pos = pos+upper-ch1.offset;
+ other->replace(pos+lower-ch1.offset, with.extract(poff+lower-ch2.offset, upper-lower));
+ goto restart;
+ }
+ }
+ poff += ch2.width;
+ }
+ pos += chunks[i].width;
+ }
+ check();
+}
+
+void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern)
+{
+ remove2(pattern, NULL);
+}
+
+void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const
+{
+ RTLIL::SigSpec tmp = *this;
+ tmp.remove2(pattern, other);
+}
+
+void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other)
+{
+ int pos = 0;
+ assert(other == NULL || width == other->width);
+ for (size_t i = 0; i < chunks.size(); i++) {
+restart:
+ const RTLIL::SigChunk &ch1 = chunks[i];
+ if (chunks[i].wire != NULL)
+ for (size_t j = 0; j < pattern.chunks.size(); j++) {
+ const RTLIL::SigChunk &ch2 = pattern.chunks[j];
+ assert(ch2.wire != NULL);
+ if (ch1.wire == ch2.wire) {
+ int lower = std::max(ch1.offset, ch2.offset);
+ int upper = std::min(ch1.offset + ch1.width, ch2.offset + ch2.width);
+ if (lower < upper) {
+ if (other)
+ other->remove(pos+lower-ch1.offset, upper-lower);
+ remove(pos+lower-ch1.offset, upper-lower);
+ if (i == chunks.size())
+ break;
+ goto restart;
+ }
+ }
+ }
+ pos += chunks[i].width;
+ }
+ check();
+}
+
+RTLIL::SigSpec RTLIL::SigSpec::extract(RTLIL::SigSpec pattern, RTLIL::SigSpec *other) const
+{
+ int pos = 0;
+ RTLIL::SigSpec ret;
+ pattern.sort_and_unify();
+ assert(other == NULL || width == other->width);
+ for (size_t i = 0; i < chunks.size(); i++) {
+ const RTLIL::SigChunk &ch1 = chunks[i];
+ if (chunks[i].wire != NULL)
+ for (size_t j = 0; j < pattern.chunks.size(); j++) {
+ RTLIL::SigChunk &ch2 = pattern.chunks[j];
+ assert(ch2.wire != NULL);
+ if (ch1.wire == ch2.wire) {
+ int lower = std::max(ch1.offset, ch2.offset);
+ int upper = std::min(ch1.offset + ch1.width, ch2.offset + ch2.width);
+ if (lower < upper) {
+ if (other)
+ ret.append(other->extract(pos+lower-ch1.offset, upper-lower));
+ else
+ ret.append(extract(pos+lower-ch1.offset, upper-lower));
+ }
+ }
+ }
+ pos += chunks[i].width;
+ }
+ ret.check();
+ return ret;
+}
+
+void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with)
+{
+ int pos = 0;
+ assert(offset >= 0);
+ assert(with.width >= 0);
+ assert(offset+with.width <= width);
+ remove(offset, with.width);
+ for (size_t i = 0; i < chunks.size(); i++) {
+ if (pos == offset) {
+ chunks.insert(chunks.begin()+i, with.chunks.begin(), with.chunks.end());
+ width += with.width;
+ check();
+ return;
+ }
+ pos += chunks[i].width;
+ }
+ assert(pos == offset);
+ chunks.insert(chunks.end(), with.chunks.begin(), with.chunks.end());
+ width += with.width;
+ check();
+}
+
+void RTLIL::SigSpec::remove_const()
+{
+ for (size_t i = 0; i < chunks.size(); i++) {
+ if (chunks[i].wire != NULL)
+ continue;
+ width -= chunks[i].width;
+ chunks.erase(chunks.begin() + (i--));
+ }
+ check();
+}
+
+void RTLIL::SigSpec::remove(int offset, int length)
+{
+ int pos = 0;
+ assert(offset >= 0);
+ assert(length >= 0);
+ assert(offset+length <= width);
+ for (size_t i = 0; i < chunks.size(); i++) {
+ int orig_width = chunks[i].width;
+ if (pos+chunks[i].width > offset && pos < offset+length) {
+ int off = offset - pos;
+ int len = length;
+ if (off < 0) {
+ len += off;
+ off = 0;
+ }
+ if (len > chunks[i].width-off)
+ len = chunks[i].width-off;
+ RTLIL::SigChunk lsb_chunk = chunks[i].extract(0, off);
+ RTLIL::SigChunk msb_chunk = chunks[i].extract(off+len, chunks[i].width-off-len);
+ if (lsb_chunk.width == 0 && msb_chunk.width == 0) {
+ chunks.erase(chunks.begin()+i);
+ i--;
+ } else if (lsb_chunk.width == 0 && msb_chunk.width != 0) {
+ chunks[i] = msb_chunk;
+ } else if (lsb_chunk.width != 0 && msb_chunk.width == 0) {
+ chunks[i] = lsb_chunk;
+ } else if (lsb_chunk.width != 0 && msb_chunk.width != 0) {
+ chunks[i] = lsb_chunk;
+ chunks.insert(chunks.begin()+i+1, msb_chunk);
+ i++;
+ } else
+ assert(0);
+ width -= len;
+ }
+ pos += orig_width;
+ }
+ check();
+}
+
+RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const
+{
+ int pos = 0;
+ RTLIL::SigSpec ret;
+ assert(offset >= 0);
+ assert(length >= 0);
+ assert(offset+length <= width);
+ for (size_t i = 0; i < chunks.size(); i++) {
+ if (pos+chunks[i].width > offset && pos < offset+length) {
+ int off = offset - pos;
+ int len = length;
+ if (off < 0) {
+ len += off;
+ off = 0;
+ }
+ if (len > chunks[i].width-off)
+ len = chunks[i].width-off;
+ ret.chunks.push_back(chunks[i].extract(off, len));
+ ret.width += len;
+ offset += len;
+ length -= len;
+ }
+ pos += chunks[i].width;
+ }
+ assert(length == 0);
+ ret.check();
+ return ret;
+}
+
+void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal)
+{
+ for (size_t i = 0; i < signal.chunks.size(); i++) {
+ chunks.push_back(signal.chunks[i]);
+ width += signal.chunks[i].width;
+ }
+ check();
+}
+
+bool RTLIL::SigSpec::combine(RTLIL::SigSpec signal, RTLIL::State freeState, bool override)
+{
+ bool no_collisions = true;
+
+ assert(width == signal.width);
+ expand();
+ signal.expand();
+
+ for (size_t i = 0; i < chunks.size(); i++) {
+ bool self_free = chunks[i].wire == NULL && chunks[i].data.bits[0] == freeState;
+ bool other_free = signal.chunks[i].wire == NULL && signal.chunks[i].data.bits[0] == freeState;
+ if (!self_free && !other_free) {
+ if (override)
+ chunks[i] = signal.chunks[i];
+ else
+ chunks[i] = RTLIL::SigChunk(RTLIL::State::Sx, 1);
+ no_collisions = false;
+ }
+ if (self_free && !other_free)
+ chunks[i] = signal.chunks[i];
+ }
+
+ optimize();
+ return no_collisions;
+}
+
+void RTLIL::SigSpec::extend(int width, bool is_signed)
+{
+ if (this->width > width)
+ remove(width, this->width - width);
+
+ if (this->width < width) {
+ RTLIL::SigSpec padding = this->width > 0 ? extract(this->width - 1, 1) : RTLIL::SigSpec(RTLIL::State::S0);
+ if (!is_signed && padding != RTLIL::SigSpec(RTLIL::State::Sx) && padding != RTLIL::SigSpec(RTLIL::State::Sz) &&
+ padding != RTLIL::SigSpec(RTLIL::State::Sa) && padding != RTLIL::SigSpec(RTLIL::State::Sm))
+ padding = RTLIL::SigSpec(RTLIL::State::S0);
+ while (this->width < width)
+ append(padding);
+ }
+
+ optimize();
+}
+
+void RTLIL::SigSpec::check() const
+{
+ int w = 0;
+ for (size_t i = 0; i < chunks.size(); i++) {
+ const RTLIL::SigChunk chunk = chunks[i];
+ if (chunk.wire == NULL) {
+ assert(chunk.offset == 0);
+ assert(chunk.data.bits.size() == (size_t)chunk.width);
+ assert(chunk.data.str.size() == 0 || chunk.data.str.size()*8 == chunk.data.bits.size());
+ } else {
+ assert(chunk.offset >= 0);
+ assert(chunk.width >= 0);
+ assert(chunk.offset + chunk.width <= chunk.wire->width);
+ assert(chunk.data.bits.size() == 0);
+ assert(chunk.data.str.size() == 0);
+ }
+ w += chunk.width;
+ }
+ assert(w == width);
+}
+
+bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const
+{
+ if (width != other.width)
+ return width < other.width;
+
+ RTLIL::SigSpec a = *this, b = other;
+ a.optimize();
+ b.optimize();
+
+ if (a.chunks.size() != b.chunks.size())
+ return a.chunks.size() < b.chunks.size();
+
+ for (size_t i = 0; i < a.chunks.size(); i++)
+ if (a.chunks[i] != b.chunks[i])
+ return a.chunks[i] < b.chunks[i];
+
+ return false;
+}
+
+bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const
+{
+ if (width != other.width)
+ return false;
+
+ RTLIL::SigSpec a = *this, b = other;
+ a.optimize();
+ b.optimize();
+
+ if (a.chunks.size() != b.chunks.size())
+ return false;
+
+ for (size_t i = 0; i < a.chunks.size(); i++)
+ if (a.chunks[i] != b.chunks[i])
+ return false;
+
+ return true;
+}
+
+bool RTLIL::SigSpec::operator !=(const RTLIL::SigSpec &other) const
+{
+ if (*this == other)
+ return false;
+ return true;
+}
+
+bool RTLIL::SigSpec::is_fully_const() const
+{
+ for (auto it = chunks.begin(); it != chunks.end(); it++)
+ if (it->width > 0 && it->wire != NULL)
+ return false;
+ return true;
+}
+
+bool RTLIL::SigSpec::is_fully_def() const
+{
+ for (auto it = chunks.begin(); it != chunks.end(); it++) {
+ if (it->width > 0 && it->wire != NULL)
+ return false;
+ for (size_t i = 0; i < it->data.bits.size(); i++)
+ if (it->data.bits[i] != RTLIL::State::S0 && it->data.bits[i] != RTLIL::State::S1)
+ return false;
+ }
+ return true;
+}
+
+bool RTLIL::SigSpec::is_fully_undef() const
+{
+ for (auto it = chunks.begin(); it != chunks.end(); it++) {
+ if (it->width > 0 && it->wire != NULL)
+ return false;
+ for (size_t i = 0; i < it->data.bits.size(); i++)
+ if (it->data.bits[i] != RTLIL::State::Sx && it->data.bits[i] != RTLIL::State::Sz)
+ return false;
+ }
+ return true;
+}
+
+bool RTLIL::SigSpec::has_marked_bits() const
+{
+ for (auto it = chunks.begin(); it != chunks.end(); it++)
+ if (it->width > 0 && it->wire == NULL) {
+ for (size_t i = 0; i < it->data.bits.size(); i++)
+ if (it->data.bits[i] == RTLIL::State::Sm)
+ return true;
+ }
+ return false;
+}
+
+bool RTLIL::SigSpec::as_bool() const
+{
+ assert(is_fully_const());
+ SigSpec sig = *this;
+ sig.optimize();
+ if (sig.width)
+ return sig.chunks[0].data.as_bool();
+ return false;
+}
+
+int RTLIL::SigSpec::as_int() const
+{
+ assert(is_fully_const());
+ SigSpec sig = *this;
+ sig.optimize();
+ if (sig.width)
+ return sig.chunks[0].data.as_int();
+ return 0;
+}
+
+std::string RTLIL::SigSpec::as_string() const
+{
+ std::string str;
+ for (size_t i = chunks.size(); i > 0; i--) {
+ const RTLIL::SigChunk &chunk = chunks[i-1];
+ if (chunk.wire != NULL)
+ for (int j = 0; j < chunk.width; j++)
+ str += "?";
+ else
+ str += chunk.data.as_string();
+ }
+ return str;
+}
+
+RTLIL::Const RTLIL::SigSpec::as_const() const
+{
+ assert(is_fully_const());
+ SigSpec sig = *this;
+ sig.optimize();
+ if (sig.width)
+ return sig.chunks[0].data;
+ return RTLIL::Const();
+}
+
+bool RTLIL::SigSpec::match(std::string pattern) const
+{
+ std::string str = as_string();
+ assert(pattern.size() == str.size());
+
+ for (size_t i = 0; i < pattern.size(); i++) {
+ if (pattern[i] == ' ')
+ continue;
+ if (pattern[i] == '*') {
+ if (str[i] != 'z' && str[i] != 'x')
+ return false;
+ continue;
+ }
+ if (pattern[i] != str[i])
+ return false;
+ }
+
+ return true;
+}
+
+RTLIL::CaseRule::~CaseRule()
+{
+ for (auto it = switches.begin(); it != switches.end(); it++)
+ delete *it;
+}
+
+void RTLIL::CaseRule::optimize()
+{
+ for (auto it : switches)
+ it->optimize();
+ for (auto &it : compare)
+ it.optimize();
+ for (auto &it : actions) {
+ it.first.optimize();
+ it.second.optimize();
+ }
+}
+
+RTLIL::SwitchRule::~SwitchRule()
+{
+ for (auto it = cases.begin(); it != cases.end(); it++)
+ delete *it;
+}
+
+void RTLIL::SwitchRule::optimize()
+{
+ signal.optimize();
+ for (auto it : cases)
+ it->optimize();
+}
+
+void RTLIL::SyncRule::optimize()
+{
+ signal.optimize();
+ for (auto &it : actions) {
+ it.first.optimize();
+ it.second.optimize();
+ }
+}
+
+RTLIL::Process::~Process()
+{
+ for (auto it = syncs.begin(); it != syncs.end(); it++)
+ delete *it;
+}
+
+void RTLIL::Process::optimize()
+{
+ root_case.optimize();
+ for (auto it : syncs)
+ it->optimize();
+}
+
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
new file mode 100644
index 00000000..1f45d120
--- /dev/null
+++ b/kernel/rtlil.h
@@ -0,0 +1,341 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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 RTLIL_H
+#define RTLIL_H
+
+#include <map>
+#include <set>
+#include <vector>
+#include <string>
+#include <assert.h>
+
+std::string stringf(const char *fmt, ...);
+
+namespace RTLIL
+{
+ enum State {
+ S0 = 0,
+ S1 = 1,
+ Sx = 2, // undefined value or conflict
+ Sz = 3, // high-impedance / not-connected
+ Sa = 4, // don't care (used only in cases)
+ Sm = 5 // marker (used internally by some passes)
+ };
+ enum SyncType {
+ ST0 = 0, // level sensitive: 0
+ ST1 = 1, // level sensitive: 1
+ STp = 2, // edge sensitive: posedge
+ STn = 3, // edge sensitive: negedge
+ STe = 4, // edge sensitive: both edges
+ STa = 5 // always active
+ };
+
+ extern int autoidx;
+
+ struct Const;
+ struct Selection;
+ struct Design;
+ struct Module;
+ struct Wire;
+ struct Memory;
+ struct Cell;
+ struct SigChunk;
+ struct SigSpec;
+ struct CaseRule;
+ struct SwitchRule;
+ struct SyncRule;
+ struct Process;
+
+ typedef std::pair<SigSpec, SigSpec> SigSig;
+
+#ifdef NDEBUG
+ typedef std::string IdString;
+#else
+ struct IdString : public std::string {
+ IdString() { }
+ IdString(std::string str) : std::string(str) {
+ check();
+ }
+ IdString(const char *s) : std::string(s) {
+ check();
+ }
+ IdString &operator=(const std::string &str) {
+ std::string::operator=(str);
+ check();
+ return *this;
+ }
+ IdString &operator=(const char *s) {
+ std::string::operator=(s);
+ check();
+ return *this;
+ }
+ bool operator<(const IdString &rhs) {
+ check(), rhs.check();
+ return std::string(*this) < std::string(rhs);
+ }
+ void check() const {
+ assert(empty() || (size() >= 2 && (at(0) == '$' || at(0) == '\\')));
+ }
+ };
+#endif
+
+ static IdString escape_id(std::string str) __attribute__((unused));
+ static IdString escape_id(std::string str) {
+ if (str.size() > 0 && str[0] != '\\' && str[0] != '$')
+ return "\\" + str;
+ return str;
+ }
+
+ static std::string unescape_id(std::string str) __attribute__((unused));
+ static std::string unescape_id(std::string str) {
+ if (str.size() > 0 && str[0] == '\\')
+ return str.substr(1);
+ return str;
+ }
+
+ static IdString new_id(std::string file, int line, std::string func) __attribute__((unused));
+ static IdString new_id(std::string file, int line, std::string func) {
+ std::string str = "$auto$";
+ size_t pos = file.find_last_of('/');
+ str += pos != std::string::npos ? file.substr(pos+1) : file;
+ str += stringf(":%d:%s$%d", line, func.c_str(), autoidx++);
+ return str;
+ }
+
+#define NEW_ID \
+ RTLIL::new_id(__FILE__, __LINE__, __FUNCTION__)
+
+ // see calc.cc for the implementation of this functions
+ RTLIL::Const const_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_xor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_xnor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+
+ RTLIL::Const const_reduce_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_reduce_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_reduce_xor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_reduce_xnor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_reduce_bool (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+
+ RTLIL::Const const_logic_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_logic_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_logic_or (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+
+ RTLIL::Const const_shl (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_shr (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_sshl (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_sshr (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+
+ RTLIL::Const const_lt (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_le (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_eq (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_ne (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_ge (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_gt (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+
+ RTLIL::Const const_add (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_sub (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_mul (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_div (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_mod (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+
+ RTLIL::Const const_pos (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+};
+
+struct RTLIL::Const {
+ std::string str;
+ std::vector<RTLIL::State> bits;
+ Const(std::string str = std::string());
+ Const(int val, int width = 32);
+ Const(RTLIL::State bit, int width = 1);
+ Const(std::vector<RTLIL::State> bits) : bits(bits) { };
+ bool operator <(const RTLIL::Const &other) const;
+ bool operator ==(const RTLIL::Const &other) const;
+ bool operator !=(const RTLIL::Const &other) const;
+ bool as_bool() const;
+ int as_int() const;
+ std::string as_string() const;
+};
+
+struct RTLIL::Selection {
+ bool full_selection;
+ std::set<RTLIL::IdString> selected_modules;
+ std::map<RTLIL::IdString, std::set<RTLIL::IdString>> selected_members;
+ Selection(bool full = true) : full_selection(full) { }
+ bool selected_module(RTLIL::IdString mod_name);
+ bool selected_whole_module(RTLIL::IdString mod_name);
+ bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name);
+ void optimize(RTLIL::Design *design);
+};
+
+struct RTLIL::Design {
+ std::map<RTLIL::IdString, RTLIL::Module*> modules;
+ std::vector<RTLIL::Selection> selection_stack;
+ std::map<RTLIL::IdString, RTLIL::Selection> selection_vars;
+ std::string selected_active_module;
+ ~Design();
+ void check();
+ void optimize();
+ bool selected_module(RTLIL::IdString mod_name);
+ bool selected_whole_module(RTLIL::IdString mod_name);
+ bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name);
+ template<typename T1> bool selected(T1 *module) {
+ return selected_module(module->name);
+ }
+ template<typename T1, typename T2> bool selected(T1 *module, T2 *member) {
+ return selected_member(module->name, member->name);
+ }
+};
+
+struct RTLIL::Module {
+ RTLIL::IdString name;
+ std::map<RTLIL::IdString, RTLIL::Wire*> wires;
+ std::map<RTLIL::IdString, RTLIL::Memory*> memories;
+ std::map<RTLIL::IdString, RTLIL::Cell*> cells;
+ std::map<RTLIL::IdString, RTLIL::Process*> processes;
+ std::vector<RTLIL::SigSig> connections;
+ std::map<RTLIL::IdString, RTLIL::Const> attributes;
+ virtual ~Module();
+ virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
+ virtual void update_auto_wires(std::map<RTLIL::IdString, int> auto_sizes);
+ virtual size_t count_id(RTLIL::IdString id);
+ virtual void check();
+ virtual void optimize();
+ void add(RTLIL::Wire *wire);
+ void add(RTLIL::Cell *cell);
+};
+
+struct RTLIL::Wire {
+ RTLIL::IdString name;
+ int width, start_offset, port_id;
+ bool port_input, port_output, auto_width;
+ std::map<RTLIL::IdString, RTLIL::Const> attributes;
+ Wire();
+};
+
+struct RTLIL::Memory {
+ RTLIL::IdString name;
+ int width, start_offset, size;
+ std::map<RTLIL::IdString, RTLIL::Const> attributes;
+ Memory();
+};
+
+struct RTLIL::Cell {
+ RTLIL::IdString name;
+ RTLIL::IdString type;
+ std::map<RTLIL::IdString, RTLIL::SigSpec> connections;
+ std::map<RTLIL::IdString, RTLIL::Const> attributes;
+ std::map<RTLIL::IdString, RTLIL::Const> parameters;
+ void optimize();
+};
+
+struct RTLIL::SigChunk {
+ RTLIL::Wire *wire;
+ RTLIL::Const data; // only used if wire == NULL, LSB at index 0
+ int width, offset;
+ SigChunk();
+ SigChunk(const RTLIL::Const &data);
+ SigChunk(RTLIL::Wire *wire, int width, int offset);
+ SigChunk(const std::string &str);
+ SigChunk(int val, int width = 32);
+ SigChunk(RTLIL::State bit, int width = 1);
+ RTLIL::SigChunk extract(int offset, int length) const;
+ bool operator <(const RTLIL::SigChunk &other) const;
+ bool operator ==(const RTLIL::SigChunk &other) const;
+ bool operator !=(const RTLIL::SigChunk &other) const;
+};
+
+struct RTLIL::SigSpec {
+ std::vector<RTLIL::SigChunk> chunks; // LSB at index 0
+ int width;
+ SigSpec();
+ SigSpec(const RTLIL::Const &data);
+ SigSpec(const RTLIL::SigChunk &chunk);
+ SigSpec(RTLIL::Wire *wire, int width = -1, int offset = 0);
+ SigSpec(const std::string &str);
+ SigSpec(int val, int width = 32);
+ SigSpec(RTLIL::State bit, int width = 1);
+ void expand();
+ void optimize();
+ void sort_and_unify();
+ void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with);
+ void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const;
+ void remove(const RTLIL::SigSpec &pattern);
+ void remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const;
+ void remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other);
+ RTLIL::SigSpec extract(RTLIL::SigSpec pattern, RTLIL::SigSpec *other = NULL) const;
+ void replace(int offset, const RTLIL::SigSpec &with);
+ void remove_const();
+ void remove(int offset, int length);
+ RTLIL::SigSpec extract(int offset, int length) const;
+ void append(const RTLIL::SigSpec &signal);
+ bool combine(RTLIL::SigSpec signal, RTLIL::State freeState = RTLIL::State::Sz, bool override = false);
+ void extend(int width, bool is_signed = false);
+ void check() const;
+ bool operator <(const RTLIL::SigSpec &other) const;
+ bool operator ==(const RTLIL::SigSpec &other) const;
+ bool operator !=(const RTLIL::SigSpec &other) const;
+ bool is_fully_const() const;
+ bool is_fully_def() const;
+ bool is_fully_undef() const;
+ bool has_marked_bits() const;
+ bool as_bool() const;
+ int as_int() const;
+ std::string as_string() const;
+ RTLIL::Const as_const() const;
+ bool match(std::string pattern) const;
+};
+
+struct RTLIL::CaseRule {
+ std::vector<RTLIL::SigSpec> compare;
+ std::vector<RTLIL::SigSig> actions;
+ std::vector<RTLIL::SwitchRule*> switches;
+ ~CaseRule();
+ void optimize();
+};
+
+struct RTLIL::SwitchRule {
+ RTLIL::SigSpec signal;
+ std::map<RTLIL::IdString, RTLIL::Const> attributes;
+ std::vector<RTLIL::CaseRule*> cases;
+ ~SwitchRule();
+ void optimize();
+};
+
+struct RTLIL::SyncRule {
+ RTLIL::SyncType type;
+ RTLIL::SigSpec signal;
+ std::vector<RTLIL::SigSig> actions;
+ void optimize();
+};
+
+struct RTLIL::Process {
+ RTLIL::IdString name;
+ std::map<RTLIL::IdString, RTLIL::Const> attributes;
+ RTLIL::CaseRule root_case;
+ std::vector<RTLIL::SyncRule*> syncs;
+ ~Process();
+ void optimize();
+};
+
+#endif
diff --git a/kernel/select.cc b/kernel/select.cc
new file mode 100644
index 00000000..8a91f1b1
--- /dev/null
+++ b/kernel/select.cc
@@ -0,0 +1,476 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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 "kernel/register.h"
+#include "kernel/log.h"
+#include <string.h>
+#include <fnmatch.h>
+
+static std::vector<RTLIL::Selection> work_stack;
+
+static bool match_ids(RTLIL::IdString id, std::string pattern)
+{
+ if (!fnmatch(pattern.c_str(), id.c_str(), FNM_NOESCAPE))
+ return true;
+ if (id.size() > 0 && id[0] == '\\' && !fnmatch(pattern.c_str(), id.substr(1).c_str(), FNM_NOESCAPE))
+ return true;
+ return false;
+}
+
+static void select_op_neg(RTLIL::Design *design, RTLIL::Selection &lhs)
+{
+ if (lhs.full_selection) {
+ lhs.full_selection = false;
+ lhs.selected_modules.clear();
+ lhs.selected_members.clear();
+ return;
+ }
+
+ if (lhs.selected_modules.size() == 0 && lhs.selected_members.size() == 0) {
+ lhs.full_selection = true;
+ return;
+ }
+
+ RTLIL::Selection new_sel(false);
+
+ for (auto &mod_it : design->modules)
+ {
+ if (lhs.selected_whole_module(mod_it.first))
+ continue;
+ if (!lhs.selected_module(mod_it.first)) {
+ new_sel.selected_modules.insert(mod_it.first);
+ continue;
+ }
+
+ RTLIL::Module *mod = mod_it.second;
+ for (auto &it : mod->wires)
+ if (!lhs.selected_member(mod_it.first, it.first))
+ new_sel.selected_members[mod->name].insert(it.first);
+ for (auto &it : mod->memories)
+ if (!lhs.selected_member(mod_it.first, it.first))
+ new_sel.selected_members[mod->name].insert(it.first);
+ for (auto &it : mod->cells)
+ if (!lhs.selected_member(mod_it.first, it.first))
+ new_sel.selected_members[mod->name].insert(it.first);
+ for (auto &it : mod->processes)
+ if (!lhs.selected_member(mod_it.first, it.first))
+ new_sel.selected_members[mod->name].insert(it.first);
+ }
+
+ lhs.selected_modules.swap(new_sel.selected_modules);
+ lhs.selected_members.swap(new_sel.selected_members);
+}
+
+static void select_op_union(RTLIL::Design*, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
+{
+ if (rhs.full_selection) {
+ lhs.full_selection = true;
+ lhs.selected_modules.clear();
+ lhs.selected_members.clear();
+ return;
+ }
+
+ if (lhs.full_selection)
+ return;
+
+ for (auto &it : rhs.selected_members)
+ for (auto &it2 : it.second)
+ lhs.selected_members[it.first].insert(it2);
+
+ for (auto &it : rhs.selected_modules) {
+ lhs.selected_modules.insert(it);
+ lhs.selected_members.erase(it);
+ }
+}
+
+static void select_op_diff(RTLIL::Design *design, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
+{
+ if (rhs.full_selection) {
+ lhs.full_selection = false;
+ lhs.selected_modules.clear();
+ lhs.selected_members.clear();
+ return;
+ }
+
+ if (lhs.full_selection) {
+ if (!rhs.full_selection && rhs.selected_modules.size() == 0 && rhs.selected_members.size() == 0)
+ return;
+ lhs.full_selection = false;
+ for (auto &it : design->modules)
+ lhs.selected_modules.insert(it.first);
+ }
+
+ for (auto &it : rhs.selected_modules) {
+ lhs.selected_modules.erase(it);
+ lhs.selected_members.erase(it);
+ }
+
+ for (auto &it : rhs.selected_members)
+ {
+ if (design->modules.count(it.first) == 0)
+ continue;
+
+ RTLIL::Module *mod = design->modules[it.first];
+
+ if (lhs.selected_modules.count(mod->name) > 0)
+ {
+ for (auto &it : mod->wires)
+ lhs.selected_members[mod->name].insert(it.first);
+ for (auto &it : mod->memories)
+ lhs.selected_members[mod->name].insert(it.first);
+ for (auto &it : mod->cells)
+ lhs.selected_members[mod->name].insert(it.first);
+ for (auto &it : mod->processes)
+ lhs.selected_members[mod->name].insert(it.first);
+ lhs.selected_modules.erase(mod->name);
+ }
+
+ if (lhs.selected_members.count(mod->name) == 0)
+ continue;
+
+ for (auto &it2 : it.second)
+ lhs.selected_members[mod->name].erase(it2);
+ }
+}
+
+static void select_op_intersect(RTLIL::Design *design, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
+{
+ if (rhs.full_selection)
+ return;
+
+ if (lhs.full_selection) {
+ lhs.full_selection = false;
+ for (auto &it : design->modules)
+ lhs.selected_modules.insert(it.first);
+ }
+
+ std::vector<RTLIL::IdString> del_list;
+
+ for (auto &it : lhs.selected_modules)
+ if (rhs.selected_modules.count(it) == 0) {
+ if (rhs.selected_members.count(it) > 0)
+ for (auto &it2 : rhs.selected_members.at(it))
+ lhs.selected_members[it].insert(it2);
+ del_list.push_back(it);
+ }
+ for (auto &it : del_list)
+ lhs.selected_modules.erase(it);
+
+ del_list.clear();
+ for (auto &it : lhs.selected_members) {
+ if (rhs.selected_modules.count(it.first) > 0)
+ continue;
+ if (rhs.selected_members.count(it.first) == 0) {
+ del_list.push_back(it.first);
+ continue;
+ }
+ std::vector<RTLIL::IdString> del_list2;
+ for (auto &it2 : it.second)
+ if (rhs.selected_members.at(it.first).count(it2) == 0)
+ del_list2.push_back(it2);
+ for (auto &it2 : del_list2)
+ it.second.erase(it2);
+ if (it.second.size() == 0)
+ del_list.push_back(it.first);
+ }
+ for (auto &it : del_list)
+ lhs.selected_members.erase(it);
+}
+
+static void select_filter_active_mod(RTLIL::Design *design, RTLIL::Selection &sel)
+{
+ if (design->selected_active_module.empty())
+ return;
+
+ if (sel.full_selection) {
+ sel.full_selection = false;
+ sel.selected_modules.clear();
+ sel.selected_members.clear();
+ sel.selected_modules.insert(design->selected_active_module);
+ return;
+ }
+
+ std::vector<std::string> del_list;
+ for (auto mod_name : sel.selected_modules)
+ if (mod_name != design->selected_active_module)
+ del_list.push_back(mod_name);
+ for (auto &it : sel.selected_members)
+ if (it.first != design->selected_active_module)
+ del_list.push_back(it.first);
+ for (auto mod_name : del_list) {
+ sel.selected_modules.erase(mod_name);
+ sel.selected_members.erase(mod_name);
+ }
+}
+
+static void select_stmt(RTLIL::Design *design, std::string arg)
+{
+ std::string arg_mod, arg_memb;
+
+ if (arg.size() == 0)
+ return;
+
+ if (arg[0] == '#') {
+ if (arg == "#") {
+ if (design->selection_stack.size() > 0)
+ work_stack.push_back(design->selection_stack.back());
+ } else
+ if (arg == "#n") {
+ if (work_stack.size() < 1)
+ log_cmd_error("Must have at least one element on stack for operator #n.\n");
+ select_op_neg(design, work_stack[work_stack.size()-1]);
+ } else
+ if (arg == "#u") {
+ if (work_stack.size() < 2)
+ log_cmd_error("Must have at least two elements on stack for operator #u.\n");
+ select_op_union(design, work_stack[work_stack.size()-2], work_stack[work_stack.size()-1]);
+ work_stack.pop_back();
+ } else
+ if (arg == "#d") {
+ if (work_stack.size() < 2)
+ log_cmd_error("Must have at least two elements on stack for operator #d.\n");
+ select_op_diff(design, work_stack[work_stack.size()-2], work_stack[work_stack.size()-1]);
+ work_stack.pop_back();
+ } else
+ if (arg == "#i") {
+ if (work_stack.size() < 2)
+ log_cmd_error("Must have at least two elements on stack for operator #i.\n");
+ select_op_intersect(design, work_stack[work_stack.size()-2], work_stack[work_stack.size()-1]);
+ work_stack.pop_back();
+ } else
+ log_cmd_error("Unknown selection operator '%s'.\n", arg.c_str());
+ select_filter_active_mod(design, work_stack.back());
+ return;
+ }
+
+ if (!design->selected_active_module.empty()) {
+ arg_mod = design->selected_active_module;
+ arg_memb = arg;
+ } else {
+ size_t pos = arg.find('/');
+ if (pos == std::string::npos) {
+ arg_mod = arg;
+ } else {
+ arg_mod = arg.substr(0, pos);
+ arg_memb = arg.substr(pos+1);
+ }
+ }
+
+ work_stack.push_back(RTLIL::Selection());
+ RTLIL::Selection &sel = work_stack.back();
+
+ if (arg == "*" && arg_mod == "*") {
+ select_filter_active_mod(design, work_stack.back());
+ return;
+ }
+
+ sel.full_selection = false;
+ for (auto &mod_it : design->modules)
+ {
+ if (!match_ids(mod_it.first, arg_mod))
+ continue;
+
+ if (arg_memb == "") {
+ sel.selected_modules.insert(mod_it.first);
+ continue;
+ }
+
+ RTLIL::Module *mod = mod_it.second;
+ if (arg_memb.substr(0, 2) == "w:") {
+ for (auto &it : mod->wires)
+ if (match_ids(it.first, arg_memb.substr(2)))
+ sel.selected_members[mod->name].insert(it.first);
+ } else
+ if (arg_memb.substr(0, 2) == "m:") {
+ for (auto &it : mod->memories)
+ if (match_ids(it.first, arg_memb.substr(2)))
+ sel.selected_members[mod->name].insert(it.first);
+ } else
+ if (arg_memb.substr(0, 2) == "c:") {
+ for (auto &it : mod->cells)
+ if (match_ids(it.first, arg_memb.substr(2)))
+ sel.selected_members[mod->name].insert(it.first);
+ } else
+ if (arg_memb.substr(0, 2) == "t:") {
+ for (auto &it : mod->cells)
+ if (match_ids(it.second->type, arg_memb.substr(2)))
+ sel.selected_members[mod->name].insert(it.first);
+ } else
+ if (arg_memb.substr(0, 2) == "p:") {
+ for (auto &it : mod->processes)
+ if (match_ids(it.first, arg_memb.substr(2)))
+ sel.selected_members[mod->name].insert(it.first);
+ } else {
+ if (arg_memb.substr(0, 2) == "n:")
+ arg_memb = arg_memb.substr(2);
+ for (auto &it : mod->wires)
+ if (match_ids(it.first, arg_memb))
+ sel.selected_members[mod->name].insert(it.first);
+ for (auto &it : mod->memories)
+ if (match_ids(it.first, arg_memb))
+ sel.selected_members[mod->name].insert(it.first);
+ for (auto &it : mod->cells)
+ if (match_ids(it.first, arg_memb))
+ sel.selected_members[mod->name].insert(it.first);
+ for (auto &it : mod->processes)
+ if (match_ids(it.first, arg_memb))
+ sel.selected_members[mod->name].insert(it.first);
+ }
+ }
+
+ select_filter_active_mod(design, work_stack.back());
+}
+
+struct SelectPass : public Pass {
+ SelectPass() : Pass("select") { }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ bool add_mode = false;
+ bool del_mode = false;
+ bool clear_mode = false;
+ bool list_mode = false;
+ bool got_module = false;
+
+ work_stack.clear();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+ if (arg == "-add") {
+ add_mode = true;
+ continue;
+ }
+ if (arg == "-del") {
+ del_mode = true;
+ continue;
+ }
+ if (arg == "-clear") {
+ clear_mode = true;
+ continue;
+ }
+ if (arg == "-list") {
+ list_mode = true;
+ continue;
+ }
+ if (arg == "-module" && argidx+1 < args.size()) {
+ RTLIL::IdString mod_name = RTLIL::escape_id(args[++argidx]);
+ if (design->modules.count(mod_name) == 0)
+ log_cmd_error("No such module: %s\n", mod_name.c_str());
+ design->selected_active_module = mod_name;
+ got_module = true;
+ continue;
+ }
+ if (arg.size() > 0 && arg[0] == '-')
+ log_cmd_error("Unkown option %s.\n", arg.c_str());
+ select_stmt(design, arg);
+ }
+
+ if (clear_mode && args.size() != 2)
+ log_cmd_error("Option -clear can not be combined with other options.\n");
+
+ if (add_mode && del_mode)
+ log_cmd_error("Options -add and -del can not be combined.\n");
+
+ if (list_mode && (add_mode || del_mode))
+ log_cmd_error("Option -list can not be combined with -add or -del.\n");
+
+ if (work_stack.size() == 0 && got_module) {
+ RTLIL::Selection sel;
+ select_filter_active_mod(design, sel);
+ work_stack.push_back(sel);
+ }
+
+ while (work_stack.size() > 1) {
+ select_op_union(design, work_stack.front(), work_stack.back());
+ work_stack.pop_back();
+ }
+
+ assert(design->selection_stack.size() > 0);
+
+ if (clear_mode)
+ {
+ design->selection_stack.back() = RTLIL::Selection(true);
+ design->selected_active_module = std::string();
+ return;
+ }
+
+ if (list_mode)
+ {
+ RTLIL::Selection *sel = &design->selection_stack.back();
+ if (work_stack.size() > 0)
+ sel = &work_stack.back();
+ sel->optimize(design);
+ for (auto mod_it : design->modules)
+ {
+ if (design->selected_whole_module(mod_it.first))
+ log("%s\n", mod_it.first.c_str());
+ if (design->selected_module(mod_it.first)) {
+ for (auto &it : mod_it.second->wires)
+ if (design->selected_member(mod_it.first, it.first))
+ log("%s/%s\n", mod_it.first.c_str(), it.first.c_str());
+ for (auto &it : mod_it.second->memories)
+ if (design->selected_member(mod_it.first, it.first))
+ log("%s/%s\n", mod_it.first.c_str(), it.first.c_str());
+ for (auto &it : mod_it.second->cells)
+ if (design->selected_member(mod_it.first, it.first))
+ log("%s/%s\n", mod_it.first.c_str(), it.first.c_str());
+ for (auto &it : mod_it.second->processes)
+ if (design->selected_member(mod_it.first, it.first))
+ log("%s/%s\n", mod_it.first.c_str(), it.first.c_str());
+ }
+ }
+ return;
+ }
+
+ if (add_mode)
+ {
+ if (work_stack.size() == 0)
+ log_cmd_error("Nothing to add to selection.\n");
+ select_op_union(design, design->selection_stack.back(), work_stack.back());
+ design->selection_stack.back().optimize(design);
+ return;
+ }
+
+ if (del_mode)
+ {
+ if (work_stack.size() == 0)
+ log_cmd_error("Nothing to delete from selection.\n");
+ select_op_diff(design, design->selection_stack.back(), work_stack.back());
+ design->selection_stack.back().optimize(design);
+ return;
+ }
+
+ if (work_stack.size() == 0) {
+ RTLIL::Selection &sel = design->selection_stack.back();
+ if (sel.full_selection)
+ log("*\n");
+ for (auto &it : sel.selected_modules)
+ log("%s\n", it.c_str());
+ for (auto &it : sel.selected_members)
+ for (auto &it2 : it.second)
+ log("%s/%s\n", it.first.c_str(), it2.c_str());
+ return;
+ }
+
+ design->selection_stack.back() = work_stack.back();
+ design->selection_stack.back().optimize(design);
+ }
+} SelectPass;
+
diff --git a/kernel/sha1.cpp b/kernel/sha1.cpp
new file mode 100644
index 00000000..fb7bfed6
--- /dev/null
+++ b/kernel/sha1.cpp
@@ -0,0 +1,185 @@
+/*
+ Copyright (c) 2011, Micael Hildenborg
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of Micael Hildenborg nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ Contributors:
+ Gustav
+ Several members in the gamedev.se forum.
+ Gregory Petrosyan
+ */
+
+#include "sha1.h"
+
+namespace sha1
+{
+ namespace // local
+ {
+ // Rotate an integer value to left.
+ inline unsigned int rol(const unsigned int value,
+ const unsigned int steps)
+ {
+ return ((value << steps) | (value >> (32 - steps)));
+ }
+
+ // Sets the first 16 integers in the buffert to zero.
+ // Used for clearing the W buffert.
+ inline void clearWBuffert(unsigned int* buffert)
+ {
+ for (int pos = 16; --pos >= 0;)
+ {
+ buffert[pos] = 0;
+ }
+ }
+
+ void innerHash(unsigned int* result, unsigned int* w)
+ {
+ unsigned int a = result[0];
+ unsigned int b = result[1];
+ unsigned int c = result[2];
+ unsigned int d = result[3];
+ unsigned int e = result[4];
+
+ int round = 0;
+
+ #define sha1macro(func,val) \
+ { \
+ const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
+ e = d; \
+ d = c; \
+ c = rol(b, 30); \
+ b = a; \
+ a = t; \
+ }
+
+ while (round < 16)
+ {
+ sha1macro((b & c) | (~b & d), 0x5a827999)
+ ++round;
+ }
+ while (round < 20)
+ {
+ w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
+ sha1macro((b & c) | (~b & d), 0x5a827999)
+ ++round;
+ }
+ while (round < 40)
+ {
+ w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
+ sha1macro(b ^ c ^ d, 0x6ed9eba1)
+ ++round;
+ }
+ while (round < 60)
+ {
+ w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
+ sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
+ ++round;
+ }
+ while (round < 80)
+ {
+ w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
+ sha1macro(b ^ c ^ d, 0xca62c1d6)
+ ++round;
+ }
+
+ #undef sha1macro
+
+ result[0] += a;
+ result[1] += b;
+ result[2] += c;
+ result[3] += d;
+ result[4] += e;
+ }
+ } // namespace
+
+ void calc(const void* src, const int bytelength, unsigned char* hash)
+ {
+ // Init the result array.
+ unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };
+
+ // Cast the void src pointer to be the byte array we can work with.
+ const unsigned char* sarray = (const unsigned char*) src;
+
+ // The reusable round buffer
+ unsigned int w[80];
+
+ // Loop through all complete 64byte blocks.
+ const int endOfFullBlocks = bytelength - 64;
+ int endCurrentBlock;
+ int currentBlock = 0;
+
+ while (currentBlock <= endOfFullBlocks)
+ {
+ endCurrentBlock = currentBlock + 64;
+
+ // Init the round buffer with the 64 byte block data.
+ for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
+ {
+ // This line will swap endian on big endian and keep endian on little endian.
+ w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
+ | (((unsigned int) sarray[currentBlock + 2]) << 8)
+ | (((unsigned int) sarray[currentBlock + 1]) << 16)
+ | (((unsigned int) sarray[currentBlock]) << 24);
+ }
+ innerHash(result, w);
+ }
+
+ // Handle the last and not full 64 byte block if existing.
+ endCurrentBlock = bytelength - currentBlock;
+ clearWBuffert(w);
+ int lastBlockBytes = 0;
+ for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes)
+ {
+ w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
+ }
+ w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
+ if (endCurrentBlock >= 56)
+ {
+ innerHash(result, w);
+ clearWBuffert(w);
+ }
+ w[15] = bytelength << 3;
+ innerHash(result, w);
+
+ // Store hash in result pointer, and make sure we get in in the correct order on both endian models.
+ for (int hashByte = 20; --hashByte >= 0;)
+ {
+ hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
+ }
+ }
+
+ void toHexString(const unsigned char* hash, char* hexstring)
+ {
+ const char hexDigits[] = { "0123456789abcdef" };
+
+ for (int hashByte = 20; --hashByte >= 0;)
+ {
+ hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf];
+ hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf];
+ }
+ hexstring[40] = 0;
+ }
+} // namespace sha1
diff --git a/kernel/sha1.h b/kernel/sha1.h
new file mode 100644
index 00000000..540c156d
--- /dev/null
+++ b/kernel/sha1.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (c) 2011, Micael Hildenborg
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of Micael Hildenborg nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SHA1_DEFINED
+#define SHA1_DEFINED
+
+namespace sha1
+{
+
+ /**
+ @param src points to any kind of data to be hashed.
+ @param bytelength the number of bytes to hash from the src pointer.
+ @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.
+ */
+ void calc(const void* src, const int bytelength, unsigned char* hash);
+
+ /**
+ @param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function.
+ @param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string.
+ */
+ void toHexString(const unsigned char* hash, char* hexstring);
+
+} // namespace sha1
+
+#endif // SHA1_DEFINED
diff --git a/kernel/show.cc b/kernel/show.cc
new file mode 100644
index 00000000..d7da62cd
--- /dev/null
+++ b/kernel/show.cc
@@ -0,0 +1,343 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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 "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/log.h"
+#include <string.h>
+#include <dirent.h>
+
+#undef CLUSTER_CELLS_AND_PORTBOXES
+
+struct ShowWorker
+{
+ CellTypes ct;
+
+ std::vector<std::string> dot_escape_store;
+ std::map<RTLIL::IdString, int> dot_id2num_store;
+ std::map<RTLIL::IdString, int> autonames;
+ int single_idx_count;
+
+ struct net_conn { std::set<std::string> in, out; };
+ std::map<std::string, net_conn> net_conn_map;
+
+ FILE *f;
+ RTLIL::Design *design;
+ RTLIL::Module *module;
+ int page_counter;
+
+ const char *escape(std::string id, bool is_name = false)
+ {
+ if (id.size() == 0)
+ return "";
+
+ if (id[0] == '$' && is_name) {
+ if (autonames.count(id) == 0) {
+ autonames[id] = autonames.size() + 1;
+ log("Generated short name for internal identifier: _%d_ -> %s\n", autonames[id], id.c_str());
+ }
+ id = stringf("_%d_", autonames[id]);
+ }
+
+ if (id[0] == '\\')
+ id = id.substr(1);
+
+ std::string str;
+ for (char ch : id) {
+ if (ch == '\\' || ch == '"')
+ str += "\\";
+ str += ch;
+ }
+
+ dot_escape_store.push_back(str);
+ return dot_escape_store.back().c_str();
+ }
+
+ int id2num(RTLIL::IdString id)
+ {
+ if (dot_id2num_store.count(id) > 0)
+ return dot_id2num_store[id];
+ return dot_id2num_store[id] = dot_id2num_store.size() + 1;
+ }
+
+ std::string gen_signode_simple(RTLIL::SigSpec sig, bool range_check = true)
+ {
+ sig.optimize();
+
+ if (sig.chunks.size() == 0) {
+ fprintf(f, "v%d [ label=\"\" ];\n", single_idx_count);
+ return stringf("v%d", single_idx_count++);
+ }
+
+ if (sig.chunks.size() == 1) {
+ RTLIL::SigChunk &c = sig.chunks[0];
+ if (c.wire != NULL && design->selected_member(module->name, c.wire->name)) {
+ if (!range_check || c.wire->width == c.width)
+ return stringf("n%d", id2num(c.wire->name));
+ } else {
+ fprintf(f, "v%d [ label=\"%s\" ];\n", single_idx_count, escape(log_signal(c), true));
+ return stringf("v%d", single_idx_count++);
+ }
+ }
+
+ return std::string();
+ }
+
+ std::string gen_portbox(std::string port, RTLIL::SigSpec sig, bool driver, std::string *node = NULL)
+ {
+ std::string code;
+ std::string net = gen_signode_simple(sig);
+ if (net.empty())
+ {
+ std::string label_string;
+ sig.optimize();
+ int pos = sig.width-1;
+ int idx = single_idx_count++;
+ for (int i = int(sig.chunks.size())-1; i >= 0; i--) {
+ RTLIL::SigChunk &c = sig.chunks[i];
+ net = gen_signode_simple(c, false);
+ assert(!net.empty());
+ if (driver) {
+ label_string += stringf("<s%d> %d:%d - %d:%d |", i, pos, pos-c.width+1, c.offset+c.width-1, c.offset);
+ net_conn_map[net].in.insert(stringf("x%d:s%d", idx, i));
+ } else {
+ label_string += stringf("<s%d> %d:%d - %d:%d |", i, c.offset+c.width-1, c.offset, pos, pos-c.width+1);
+ net_conn_map[net].out.insert(stringf("x%d:s%d", idx, i));
+ }
+ pos -= c.width;
+ }
+ if (label_string[label_string.size()-1] == '|')
+ label_string = label_string.substr(0, label_string.size()-1);
+ code += stringf("x%d [ shape=record, style=rounded, label=\"%s\" ];\n", idx, label_string.c_str());
+ if (!port.empty()) {
+ if (driver)
+ code += stringf("%s:e -> x%d:w [arrowhead=odiamond, arrowtail=odiamond, dir=both];\n", port.c_str(), idx);
+ else
+ code += stringf("x%d:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both];\n", idx, port.c_str());
+ }
+ if (node != NULL)
+ *node = stringf("x%d", idx);
+ }
+ else
+ {
+ if (!port.empty()) {
+ if (driver)
+ net_conn_map[net].in.insert(port);
+ else
+ net_conn_map[net].out.insert(port);
+ }
+ if (node != NULL)
+ *node = net;
+ }
+ return code;
+ }
+
+ void handle_module()
+ {
+ single_idx_count = 0;
+ dot_escape_store.clear();
+ dot_id2num_store.clear();
+ net_conn_map.clear();
+
+ fprintf(f, "digraph \"%s\" {\n", escape(module->name));
+ fprintf(f, "rankdir=\"LR\";\n");
+ fprintf(f, "remincross=true;\n");
+
+ std::map<std::string, std::string> wires_on_demand;
+ for (auto &it : module->wires) {
+ if (!design->selected_member(module->name, it.first))
+ continue;
+ const char *shape = "diamond";
+ if (it.second->port_input || it.second->port_output)
+ shape = "octagon";
+ if (it.first[0] == '\\')
+ fprintf(f, "n%d [ shape=%s, label=\"%s\" ];\n",
+ id2num(it.first), shape, escape(it.first));
+ else {
+ wires_on_demand[stringf("n%d", id2num(it.first))] = it.first;
+ }
+ }
+
+ for (auto &it : module->cells)
+ {
+ if (!design->selected_member(module->name, it.first))
+ continue;
+
+ std::vector<RTLIL::IdString> in_ports, out_ports;
+
+ for (auto &conn : it.second->connections) {
+ if (ct.cell_input(it.second->type, conn.first))
+ in_ports.push_back(conn.first);
+ else
+ out_ports.push_back(conn.first);
+ }
+
+ std::string label_string = "{{";
+
+ for (auto &p : in_ports)
+ label_string += stringf("<p%d> %s|", id2num(p), escape(p));
+ if (label_string[label_string.size()-1] == '|')
+ label_string = label_string.substr(0, label_string.size()-1);
+
+ label_string += stringf("}|%s\\n%s|{", escape(it.first, true), escape(it.second->type));
+
+ for (auto &p : out_ports)
+ label_string += stringf("<p%d> %s|", id2num(p), escape(p));
+ if (label_string[label_string.size()-1] == '|')
+ label_string = label_string.substr(0, label_string.size()-1);
+
+ label_string += "}}";
+
+ std::string code;
+ for (auto &conn : it.second->connections) {
+ code += gen_portbox(stringf("c%d:p%d", id2num(it.first), id2num(conn.first)),
+ conn.second, !ct.cell_input(it.second->type, conn.first));
+ }
+
+#ifdef CLUSTER_CELLS_AND_PORTBOXES
+ if (!code.empty())
+ fprintf(f, "subgraph cluster_c%d {\nc%d [ shape=record, label=\"%s\" ];\n%s}\n",
+ id2num(it.first), id2num(it.first), label_string.c_str(), code.c_str());
+ else
+#endif
+ fprintf(f, "c%d [ shape=record, label=\"%s\" ];\n%s",
+ id2num(it.first), label_string.c_str(), code.c_str());
+ }
+
+ for (auto &conn : module->connections)
+ {
+ bool found_lhs_wire = false;
+ for (auto &c : conn.first.chunks) {
+ if (c.wire != NULL && design->selected_member(module->name, c.wire->name))
+ found_lhs_wire = true;
+ }
+ bool found_rhs_wire = false;
+ for (auto &c : conn.second.chunks) {
+ if (c.wire != NULL && design->selected_member(module->name, c.wire->name))
+ found_rhs_wire = true;
+ }
+ if (!found_lhs_wire || !found_rhs_wire)
+ continue;
+
+ std::string code, left_node, right_node;
+ code += gen_portbox("", conn.second, false, &left_node);
+ code += gen_portbox("", conn.first, true, &right_node);
+ fprintf(f, "%s", code.c_str());
+
+ if (left_node[0] == 'x' && right_node[0] == 'x')
+ fprintf(f, "%s:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both];\n", left_node.c_str(), right_node.c_str());
+ else if (left_node[0] == 'x')
+ net_conn_map[right_node].in.insert(left_node);
+ else if (right_node[0] == 'x')
+ net_conn_map[left_node].out.insert(right_node);
+ else {
+ net_conn_map[right_node].in.insert(stringf("x%d:e", single_idx_count));
+ net_conn_map[left_node].out.insert(stringf("x%d:w", single_idx_count));
+ fprintf(f, "x%d [shape=box, style=rounded, label=\"BUF\"];\n", single_idx_count++);
+ }
+ }
+
+ for (auto &it : net_conn_map)
+ {
+ if (wires_on_demand.count(it.first) > 0) {
+ if (it.second.in.size() == 1 && it.second.out.size() == 1) {
+ fprintf(f, "%s:e -> %s:w;\n", it.second.in.begin()->c_str(), it.second.out.begin()->c_str());
+ continue;
+ }
+ if (it.second.in.size() == 0 || it.second.out.size() == 0)
+ fprintf(f, "%s [ shape=diamond, label=\"%s\" ];\n", it.first.c_str(), escape(wires_on_demand[it.first], true));
+ else
+ fprintf(f, "%s [ shape=point ];\n", it.first.c_str());
+ }
+ for (auto &it2 : it.second.in)
+ fprintf(f, "%s:e -> %s:w;\n", it2.c_str(), it.first.c_str());
+ for (auto &it2 : it.second.out)
+ fprintf(f, "%s:e -> %s:w;\n", it.first.c_str(), it2.c_str());
+ }
+
+ fprintf(f, "};\n");
+ }
+
+ ShowWorker(FILE *f, RTLIL::Design *design) : f(f), design(design)
+ {
+ ct.setup_internals();
+ ct.setup_internals_mem();
+ ct.setup_stdcells();
+ ct.setup_stdcells_mem();
+
+ design->optimize();
+ page_counter = 0;
+ for (auto &mod_it : design->modules)
+ {
+ module = mod_it.second;
+ if (!design->selected_module(module->name))
+ continue;
+ if (design->selected_whole_module(module->name))
+ log("Dumping module %s to page %d.\n", module->name.c_str(), ++page_counter);
+ else
+ log("Dumping selected parts of module %s to page %d.\n", module->name.c_str(), ++page_counter);
+ handle_module();
+ }
+ }
+};
+
+struct ShowPass : public Pass {
+ ShowPass() : Pass("show") { }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("Generating Graphviz representation of design.\n");
+
+ std::string viewer_exe;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+ if (arg == "-viewer" && argidx+1 < args.size()) {
+ viewer_exe = args[++argidx];
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ log("Writing dot description to `yosys-show.dot'.\n");
+ FILE *f = fopen("yosys-show.dot", "w");
+ if (f == NULL)
+ log_cmd_error("Can't open dot file `yosys-show.dot' for writing.\n");
+ ShowWorker worker(f, design);
+ fclose(f);
+
+ if (worker.page_counter == 0)
+ log_cmd_error("Nothing there to show.\n");
+
+ std::string cmd = stringf("dot -Tps -o yosys-show.ps yosys-show.dot");
+ log("Exec: %s\n", cmd.c_str());
+ if (system(cmd.c_str()) != 0)
+ log_cmd_error("Shell command failed!\n");
+
+ if (!viewer_exe.empty()) {
+ cmd = stringf("%s yosys-show.ps &", viewer_exe.c_str());
+ log("Exec: %s\n", cmd.c_str());
+ if (system(cmd.c_str()) != 0)
+ log_cmd_error("Shell command failed!\n");
+ }
+ }
+} ShowPass;
+
diff --git a/kernel/sigtools.h b/kernel/sigtools.h
new file mode 100644
index 00000000..e76fd602
--- /dev/null
+++ b/kernel/sigtools.h
@@ -0,0 +1,415 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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 SIGTOOLS_H
+#define SIGTOOLS_H
+
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+#include <assert.h>
+#include <set>
+
+struct SigPool
+{
+ typedef std::pair<RTLIL::Wire*,int> bitDef_t;
+ std::set<bitDef_t> bits;
+
+ void clear()
+ {
+ bits.clear();
+ }
+
+ void add(RTLIL::SigSpec sig)
+ {
+ sig.expand();
+ for (auto &c : sig.chunks) {
+ if (c.wire == NULL)
+ continue;
+ assert(c.width == 1);
+ bitDef_t bit(c.wire, c.offset);
+ bits.insert(bit);
+ }
+ }
+
+ void add(const SigPool &other)
+ {
+ for (auto &bit : other.bits)
+ bits.insert(bit);
+ }
+
+ void del(RTLIL::SigSpec sig)
+ {
+ sig.expand();
+ for (auto &c : sig.chunks) {
+ if (c.wire == NULL)
+ continue;
+ assert(c.width == 1);
+ bitDef_t bit(c.wire, c.offset);
+ bits.erase(bit);
+ }
+ }
+
+ void del(const SigPool &other)
+ {
+ for (auto &bit : other.bits)
+ bits.insert(bit);
+ }
+
+ void expand(RTLIL::SigSpec from, RTLIL::SigSpec to)
+ {
+ from.expand();
+ to.expand();
+ assert(from.chunks.size() == to.chunks.size());
+ for (size_t i = 0; i < from.chunks.size(); i++) {
+ bitDef_t bit_from(from.chunks[i].wire, from.chunks[i].offset);
+ bitDef_t bit_to(to.chunks[i].wire, to.chunks[i].offset);
+ if (bit_from.first == NULL || bit_to.first == NULL)
+ continue;
+ if (bits.count(bit_from) > 0)
+ bits.insert(bit_to);
+ }
+ }
+
+ RTLIL::SigSpec extract(RTLIL::SigSpec sig)
+ {
+ RTLIL::SigSpec result;
+ sig.expand();
+ for (auto &c : sig.chunks) {
+ if (c.wire == NULL)
+ continue;
+ bitDef_t bit(c.wire, c.offset);
+ if (bits.count(bit) > 0)
+ result.append(c);
+ }
+ return result;
+ }
+
+ RTLIL::SigSpec remove(RTLIL::SigSpec sig)
+ {
+ RTLIL::SigSpec result;
+ sig.expand();
+ for (auto &c : sig.chunks) {
+ if (c.wire == NULL)
+ continue;
+ bitDef_t bit(c.wire, c.offset);
+ if (bits.count(bit) == 0)
+ result.append(c);
+ }
+ return result;
+ }
+
+ bool check_any(RTLIL::SigSpec sig)
+ {
+ sig.expand();
+ for (auto &c : sig.chunks) {
+ if (c.wire == NULL)
+ continue;
+ bitDef_t bit(c.wire, c.offset);
+ if (bits.count(bit) != 0)
+ return true;
+ }
+ return false;
+ }
+
+ bool check_all(RTLIL::SigSpec sig)
+ {
+ sig.expand();
+ for (auto &c : sig.chunks) {
+ if (c.wire == NULL)
+ continue;
+ bitDef_t bit(c.wire, c.offset);
+ if (bits.count(bit) == 0)
+ return false;
+ }
+ return true;
+ }
+};
+
+template <typename T>
+struct SigSet
+{
+ typedef std::pair<RTLIL::Wire*,int> bitDef_t;
+ std::map<bitDef_t, std::set<T>> bits;
+
+ void clear()
+ {
+ bits.clear();
+ }
+
+ void insert(RTLIL::SigSpec sig, T data)
+ {
+ sig.expand();
+ for (auto &c : sig.chunks) {
+ if (c.wire == NULL)
+ continue;
+ assert(c.width == 1);
+ bitDef_t bit(c.wire, c.offset);
+ bits[bit].insert(data);
+ }
+ }
+
+ void erase(RTLIL::SigSpec sig)
+ {
+ sig.expand();
+ for (auto &c : sig.chunks) {
+ if (c.wire == NULL)
+ continue;
+ assert(c.width == 1);
+ bitDef_t bit(c.wire, c.offset);
+ bits[bit].clear();
+ }
+ }
+
+ void erase(RTLIL::SigSpec sig, T data)
+ {
+ sig.expand();
+ for (auto &c : sig.chunks) {
+ if (c.wire == NULL)
+ continue;
+ assert(c.width == 1);
+ bitDef_t bit(c.wire, c.offset);
+ bits[bit].erase(data);
+ }
+ }
+
+ void find(RTLIL::SigSpec sig, std::set<T> &result)
+ {
+ sig.expand();
+ for (auto &c : sig.chunks) {
+ if (c.wire == NULL)
+ continue;
+ assert(c.width == 1);
+ bitDef_t bit(c.wire, c.offset);
+ for (auto &data : bits[bit])
+ result.insert(data);
+ }
+ }
+
+ std::set<T> find(RTLIL::SigSpec sig)
+ {
+ std::set<T> result;
+ find(sig, result);
+ return result;
+ }
+};
+
+struct SigMap
+{
+ typedef std::pair<RTLIL::Wire*,int> bitDef_t;
+
+ struct shared_bit_data_t {
+ RTLIL::SigChunk chunk;
+ std::set<bitDef_t> bits;
+ };
+
+ std::map<bitDef_t, shared_bit_data_t*> bits;
+
+ SigMap(RTLIL::Module *module = NULL)
+ {
+ if (module != NULL)
+ set(module);
+ }
+
+ SigMap(const SigMap &other)
+ {
+ copy(other);
+ }
+
+ const SigMap &operator=(const SigMap &other)
+ {
+ copy(other);
+ return *this;
+ }
+
+ void copy(const SigMap &other)
+ {
+ clear();
+ for (auto &bit : other.bits) {
+ bits[bit.first] = new shared_bit_data_t;
+ bits[bit.first]->chunk = bit.second->chunk;
+ bits[bit.first]->bits = bit.second->bits;
+ }
+ }
+
+ void swap(SigMap &other)
+ {
+ bits.swap(other.bits);
+ }
+
+ ~SigMap()
+ {
+ clear();
+ }
+
+ void clear()
+ {
+ std::set<shared_bit_data_t*> all_bd_ptr;
+ for (auto &it : bits)
+ all_bd_ptr.insert(it.second);
+ for (auto bd_ptr : all_bd_ptr)
+ delete bd_ptr;
+ bits.clear();
+ }
+
+ void set(RTLIL::Module *module)
+ {
+ clear();
+ for (auto &it : module->connections)
+ add(it.first, it.second);
+ }
+
+ // internal helper function
+ void register_bit(const RTLIL::SigChunk &c)
+ {
+ assert(c.width == 1);
+ bitDef_t bit(c.wire, c.offset);
+ if (c.wire && bits.count(bit) == 0) {
+ shared_bit_data_t *bd = new shared_bit_data_t;
+ bd->chunk = c;
+ bd->bits.insert(bit);
+ bits[bit] = bd;
+ }
+ }
+
+ // internal helper function
+ void unregister_bit(const RTLIL::SigChunk &c)
+ {
+ assert(c.width == 1);
+ bitDef_t bit(c.wire, c.offset);
+ if (c.wire && bits.count(bit) > 0) {
+ shared_bit_data_t *bd = bits[bit];
+ bd->bits.erase(bit);
+ if (bd->bits.size() == 0)
+ delete bd;
+ bits.erase(bit);
+ }
+ }
+
+ // internal helper function
+ void merge_bit(const RTLIL::SigChunk &c1, const RTLIL::SigChunk &c2)
+ {
+ assert(c1.wire != NULL && c2.wire != NULL);
+ assert(c1.width == 1 && c2.width == 1);
+
+ bitDef_t b1(c1.wire, c1.offset);
+ bitDef_t b2(c2.wire, c2.offset);
+
+ shared_bit_data_t *bd1 = bits[b1];
+ shared_bit_data_t *bd2 = bits[b2];
+ assert(bd1 != NULL && bd2 != NULL);
+
+ if (bd1 == bd2)
+ return;
+
+ if (bd1->bits.size() < bd2->bits.size())
+ {
+ for (auto &bit : bd1->bits)
+ bits[bit] = bd2;
+ bd2->bits.insert(bd1->bits.begin(), bd1->bits.end());
+ delete bd1;
+ }
+ else
+ {
+ bd1->chunk = bd2->chunk;
+ for (auto &bit : bd2->bits)
+ bits[bit] = bd1;
+ bd1->bits.insert(bd2->bits.begin(), bd2->bits.end());
+ delete bd2;
+ }
+ }
+
+ // internal helper function
+ void set_bit(const RTLIL::SigChunk &c1, const RTLIL::SigChunk &c2)
+ {
+ assert(c1.wire != NULL);
+ assert(c1.width == 1 && c2.width == 1);
+ bitDef_t bit(c1.wire, c1.offset);
+ assert(bits.count(bit) > 0);
+ bits[bit]->chunk = c2;
+ }
+
+ // internal helper function
+ void map_bit(RTLIL::SigChunk &c)
+ {
+ assert(c.width == 1);
+ bitDef_t bit(c.wire, c.offset);
+ if (c.wire && bits.count(bit) > 0)
+ c = bits[bit]->chunk;
+ }
+
+ void add(RTLIL::SigSpec from, RTLIL::SigSpec to)
+ {
+ from.expand();
+ to.expand();
+
+ assert(from.chunks.size() == to.chunks.size());
+ for (size_t i = 0; i < from.chunks.size(); i++)
+ {
+ RTLIL::SigChunk &cf = from.chunks[i];
+ RTLIL::SigChunk &ct = to.chunks[i];
+
+ if (cf.wire == NULL)
+ continue;
+
+ register_bit(cf);
+ register_bit(ct);
+
+ if (ct.wire != NULL)
+ merge_bit(cf, ct);
+ else
+ set_bit(cf, ct);
+ }
+ }
+
+ void add(RTLIL::SigSpec sig)
+ {
+ sig.expand();
+ for (size_t i = 0; i < sig.chunks.size(); i++)
+ {
+ RTLIL::SigChunk &c = sig.chunks[i];
+ if (c.wire != NULL) {
+ register_bit(c);
+ set_bit(c, c);
+ }
+ }
+ }
+
+ void del(RTLIL::SigSpec sig)
+ {
+ sig.expand();
+ for (auto &c : sig.chunks)
+ unregister_bit(c);
+ }
+
+ void apply(RTLIL::SigSpec &sig)
+ {
+ sig.expand();
+ for (auto &c : sig.chunks)
+ map_bit(c);
+ sig.optimize();
+ }
+
+ RTLIL::SigSpec operator()(RTLIL::SigSpec sig)
+ {
+ apply(sig);
+ return sig;
+ }
+};
+
+#endif /* SIGTOOLS_H */