diff options
author | Clifford Wolf <clifford@clifford.at> | 2013-01-05 11:13:26 +0100 |
---|---|---|
committer | Clifford Wolf <clifford@clifford.at> | 2013-01-05 11:13:26 +0100 |
commit | 7764d0ba1dcf064ae487ee985c43083a0909e7f4 (patch) | |
tree | 18c05b8729df381af71b707748ce1d605e0df764 /kernel | |
download | yosys-7764d0ba1dcf064ae487ee985c43083a0909e7f4.tar.gz yosys-7764d0ba1dcf064ae487ee985c43083a0909e7f4.tar.bz2 yosys-7764d0ba1dcf064ae487ee985c43083a0909e7f4.zip |
initial import
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/bitpattern.h | 143 | ||||
-rw-r--r-- | kernel/calc.cc | 392 | ||||
-rw-r--r-- | kernel/celltypes.h | 210 | ||||
-rw-r--r-- | kernel/consteval.h | 198 | ||||
-rw-r--r-- | kernel/driver.cc | 253 | ||||
-rw-r--r-- | kernel/log.cc | 197 | ||||
-rw-r--r-- | kernel/log.h | 51 | ||||
-rw-r--r-- | kernel/register.cc | 288 | ||||
-rw-r--r-- | kernel/register.h | 80 | ||||
-rw-r--r-- | kernel/rtlil.cc | 1081 | ||||
-rw-r--r-- | kernel/rtlil.h | 341 | ||||
-rw-r--r-- | kernel/select.cc | 476 | ||||
-rw-r--r-- | kernel/sha1.cpp | 185 | ||||
-rw-r--r-- | kernel/sha1.h | 49 | ||||
-rw-r--r-- | kernel/show.cc | 343 | ||||
-rw-r--r-- | kernel/sigtools.h | 415 |
16 files changed, 4702 insertions, 0 deletions
diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h new file mode 100644 index 000000000..aaefa50fc --- /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 000000000..f31fed7d0 --- /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 000000000..a13cbf32c --- /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 000000000..d48771fea --- /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 000000000..c49bf6575 --- /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 000000000..9bf8705e3 --- /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 000000000..9023854d0 --- /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 000000000..fb70c80d9 --- /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 000000000..713d468e3 --- /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 000000000..c97e2e455 --- /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 000000000..1f45d1204 --- /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 000000000..8a91f1b1a --- /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 000000000..fb7bfed6f --- /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 000000000..540c156d1 --- /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 000000000..d7da62cd2 --- /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 000000000..e76fd6023 --- /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 */ |