diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/bitpattern.h | 10 | ||||
-rw-r--r-- | kernel/calc.cc | 59 | ||||
-rw-r--r-- | kernel/cellaigs.cc | 481 | ||||
-rw-r--r-- | kernel/cellaigs.h | 52 | ||||
-rw-r--r-- | kernel/celltypes.h | 67 | ||||
-rw-r--r-- | kernel/consteval.h | 4 | ||||
-rw-r--r-- | kernel/cost.h | 4 | ||||
-rw-r--r-- | kernel/driver.cc | 90 | ||||
-rw-r--r-- | kernel/hashlib.h | 241 | ||||
-rw-r--r-- | kernel/log.cc | 55 | ||||
-rw-r--r-- | kernel/log.h | 59 | ||||
-rw-r--r-- | kernel/macc.h | 8 | ||||
-rw-r--r-- | kernel/modtools.h | 31 | ||||
-rw-r--r-- | kernel/register.cc | 148 | ||||
-rw-r--r-- | kernel/register.h | 25 | ||||
-rw-r--r-- | kernel/rtlil.cc | 372 | ||||
-rw-r--r-- | kernel/rtlil.h | 104 | ||||
-rw-r--r-- | kernel/satgen.h | 150 | ||||
-rw-r--r-- | kernel/sigtools.h | 174 | ||||
-rw-r--r-- | kernel/utils.h | 6 | ||||
-rw-r--r-- | kernel/yosys.cc | 106 | ||||
-rw-r--r-- | kernel/yosys.h | 37 |
22 files changed, 1884 insertions, 399 deletions
diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h index 00bbc3bfb..894a95ed1 100644 --- a/kernel/bitpattern.h +++ b/kernel/bitpattern.h @@ -2,11 +2,11 @@ * 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 @@ -30,7 +30,7 @@ struct BitPatternPool int width; struct bits_t { std::vector<RTLIL::State> bitdata; - unsigned int cached_hash; + mutable unsigned int cached_hash; bits_t(int width = 0) : bitdata(width), cached_hash(0) { } RTLIL::State &operator[](int index) { return bitdata[index]; @@ -45,7 +45,7 @@ struct BitPatternPool } unsigned int hash() const { if (!cached_hash) - ((bits_t*)this)->cached_hash = hash_ops<std::vector<RTLIL::State>>::hash(bitdata); + cached_hash = hash_ops<std::vector<RTLIL::State>>::hash(bitdata); return cached_hash; } }; @@ -154,7 +154,7 @@ struct BitPatternPool { return database.empty(); } -}; +}; YOSYS_NAMESPACE_END diff --git a/kernel/calc.cc b/kernel/calc.cc index aa3e8b919..a24fa2abf 100644 --- a/kernel/calc.cc +++ b/kernel/calc.cc @@ -2,11 +2,11 @@ * 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 @@ -41,21 +41,28 @@ static void extend_u0(RTLIL::Const &arg, int width, bool is_signed) 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; + BigUnsigned mag; + + BigInteger::Sign sign = BigInteger::positive; + State inv_sign_bit = RTLIL::State::S1; + size_t num_bits = val.bits.size(); + + if (as_signed && num_bits && val.bits[num_bits-1] == RTLIL::State::S1) { + inv_sign_bit = RTLIL::State::S0; + sign = BigInteger::negative; + num_bits--; } - return result; + + for (size_t i = 0; i < num_bits; i++) + if (val.bits[i] == RTLIL::State::S0 || val.bits[i] == RTLIL::State::S1) + mag.setBit(i, val.bits[i] == inv_sign_bit); + else if (undef_bit_pos < 0) + undef_bit_pos = i; + + if (sign == BigInteger::negative) + mag += 1; + + return BigInteger(mag, sign); } static RTLIL::Const big2const(const BigInteger &val, int result_len, int undef_bit_pos) @@ -147,7 +154,7 @@ static RTLIL::Const logic_wrapper(RTLIL::State(*logic_func)(RTLIL::State, RTLIL: RTLIL::Const arg1, RTLIL::Const arg2, bool signed1, bool signed2, int result_len = -1) { if (result_len < 0) - result_len = std::max(arg1.bits.size(), arg2.bits.size()); + result_len = max(arg1.bits.size(), arg2.bits.size()); extend_u0(arg1, result_len, signed1); extend_u0(arg2, result_len, signed2); @@ -303,7 +310,7 @@ RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2 RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len) { RTLIL::Const arg1_ext = arg1; - extend_u0(arg1_ext, std::max(result_len, GetSize(arg1)), signed1); + extend_u0(arg1_ext, max(result_len, GetSize(arg1)), signed1); return const_shift_worker(arg1_ext, arg2, false, +1, result_len); } @@ -382,7 +389,7 @@ RTLIL::Const RTLIL::const_eq(const RTLIL::Const &arg1, const RTLIL::Const &arg2, RTLIL::Const arg2_ext = arg2; RTLIL::Const result(RTLIL::State::S0, result_len); - int width = std::max(arg1_ext.bits.size(), arg2_ext.bits.size()); + int width = max(arg1_ext.bits.size(), arg2_ext.bits.size()); extend_u0(arg1_ext, width, signed1 && signed2); extend_u0(arg2_ext, width, signed1 && signed2); @@ -416,7 +423,7 @@ RTLIL::Const RTLIL::const_eqx(const RTLIL::Const &arg1, const RTLIL::Const &arg2 RTLIL::Const arg2_ext = arg2; RTLIL::Const result(RTLIL::State::S0, result_len); - int width = std::max(arg1_ext.bits.size(), arg2_ext.bits.size()); + int width = max(arg1_ext.bits.size(), arg2_ext.bits.size()); extend_u0(arg1_ext, width, signed1 && signed2); extend_u0(arg2_ext, width, signed1 && signed2); @@ -465,21 +472,21 @@ RTLIL::Const RTLIL::const_add(const RTLIL::Const &arg1, const RTLIL::Const &arg2 { 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); + return big2const(y, result_len >= 0 ? result_len : 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); + return big2const(y, result_len >= 0 ? result_len : 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)); + return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), 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) @@ -492,7 +499,7 @@ RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2 bool result_neg = (a.getSign() == BigInteger::negative) != (b.getSign() == BigInteger::negative); a = a.getSign() == BigInteger::negative ? -a : a; b = b.getSign() == BigInteger::negative ? -b : b; - return big2const(result_neg ? -(a / b) : (a / b), result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0)); + return big2const(result_neg ? -(a / b) : (a / b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), 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) @@ -505,7 +512,7 @@ RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2 bool result_neg = a.getSign() == BigInteger::negative; a = a.getSign() == BigInteger::negative ? -a : a; b = b.getSign() == BigInteger::negative ? -b : b; - return big2const(result_neg ? -(a % b) : (a % b), result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0)); + return big2const(result_neg ? -(a % b) : (a % b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), 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) @@ -556,7 +563,7 @@ RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2 y *= -1; } - return big2const(y, result_len >= 0 ? result_len : std::max(arg1.bits.size(), arg2.bits.size()), std::min(undef_bit_pos, 0)); + return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); } RTLIL::Const RTLIL::const_pos(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len) diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc new file mode 100644 index 000000000..41f81355d --- /dev/null +++ b/kernel/cellaigs.cc @@ -0,0 +1,481 @@ +/* + * 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/cellaigs.h" + +YOSYS_NAMESPACE_BEGIN + +AigNode::AigNode() +{ + portbit = -1; + inverter = false; + left_parent = -1; + right_parent = -1; +} + +bool AigNode::operator==(const AigNode &other) const +{ + if (portname != other.portname) return false; + if (portbit != other.portbit) return false; + if (inverter != other.inverter) return false; + if (left_parent != other.left_parent) return false; + if (right_parent != other.right_parent) return false; + return true; +} + +unsigned int AigNode::hash() const +{ + unsigned int h = mkhash_init; + h = mkhash(portname.hash(), portbit); + h = mkhash(h, inverter); + h = mkhash(h, left_parent); + h = mkhash(h, right_parent); + return h; +} + +bool Aig::operator==(const Aig &other) const +{ + return name == other.name; +} + +unsigned int Aig::hash() const +{ + return hash_ops<std::string>::hash(name); +} + +struct AigMaker +{ + Aig *aig; + Cell *cell; + idict<AigNode> aig_indices; + + int the_true_node; + int the_false_node; + + AigMaker(Aig *aig, Cell *cell) : aig(aig), cell(cell) + { + the_true_node = -1; + the_false_node = -1; + } + + int node2index(const AigNode &node) + { + if (node.left_parent > node.right_parent) { + AigNode n(node); + std::swap(n.left_parent, n.right_parent); + return node2index(n); + } + + if (!aig_indices.count(node)) { + aig_indices.expect(node, GetSize(aig->nodes)); + aig->nodes.push_back(node); + } + + return aig_indices.at(node); + } + + int bool_node(bool value) + { + AigNode node; + node.inverter = value; + return node2index(node); + } + + int inport(IdString portname, int portbit = 0, bool inverter = false) + { + if (portbit >= GetSize(cell->getPort(portname))) { + if (cell->parameters.count(portname.str() + "_SIGNED") && cell->getParam(portname.str() + "_SIGNED").as_bool()) + return inport(portname, GetSize(cell->getPort(portname))-1, inverter); + return bool_node(inverter); + } + + AigNode node; + node.portname = portname; + node.portbit = portbit; + node.inverter = inverter; + return node2index(node); + } + + vector<int> inport_vec(IdString portname, int width) + { + vector<int> vec; + for (int i = 0; i < width; i++) + vec.push_back(inport(portname, i)); + return vec; + } + + int not_inport(IdString portname, int portbit = 0) + { + return inport(portname, portbit, true); + } + + int not_gate(int A) + { + AigNode node(aig_indices[A]); + node.outports.clear(); + node.inverter = !node.inverter; + return node2index(node); + } + + int and_gate(int A, int B, bool inverter = false) + { + if (A == B) + return inverter ? not_gate(A) : A; + + const AigNode &nA = aig_indices[A]; + const AigNode &nB = aig_indices[B]; + + AigNode nB_inv(nB); + nB_inv.inverter = !nB_inv.inverter; + + if (nA == nB_inv) + return bool_node(inverter); + + bool nA_bool = nA.portbit < 0 && nA.left_parent < 0 && nA.right_parent < 0; + bool nB_bool = nB.portbit < 0 && nB.left_parent < 0 && nB.right_parent < 0; + + if (nA_bool && nB_bool) { + bool bA = nA.inverter; + bool bB = nB.inverter; + return bool_node(inverter != (bA && bB)); + } + + if (nA_bool) { + bool bA = nA.inverter; + if (inverter) + return bA ? not_gate(B) : bool_node(true); + return bA ? B : bool_node(false); + } + + if (nB_bool) { + bool bB = nB.inverter; + if (inverter) + return bB ? not_gate(A) : bool_node(true); + return bB ? A : bool_node(false); + } + + AigNode node; + node.inverter = inverter; + node.left_parent = A; + node.right_parent = B; + return node2index(node); + } + + int nand_gate(int A, int B) + { + return and_gate(A, B, true); + } + + int or_gate(int A, int B) + { + return nand_gate(not_gate(A), not_gate(B)); + } + + int nor_gate(int A, int B) + { + return and_gate(not_gate(A), not_gate(B)); + } + + int xor_gate(int A, int B) + { + return nor_gate(and_gate(A, B), nor_gate(A, B)); + } + + int xnor_gate(int A, int B) + { + return or_gate(and_gate(A, B), nor_gate(A, B)); + } + + int mux_gate(int A, int B, int S) + { + return or_gate(and_gate(A, not_gate(S)), and_gate(B, S)); + } + + vector<int> adder(const vector<int> &A, const vector<int> &B, int carry, vector<int> *X = nullptr, vector<int> *CO = nullptr) + { + vector<int> Y(GetSize(A)); + log_assert(GetSize(A) == GetSize(B)); + for (int i = 0; i < GetSize(A); i++) { + Y[i] = xor_gate(xor_gate(A[i], B[i]), carry); + carry = or_gate(and_gate(A[i], B[i]), and_gate(or_gate(A[i], B[i]), carry)); + if (X != nullptr) + X->at(i) = xor_gate(A[i], B[i]); + if (CO != nullptr) + CO->at(i) = carry; + } + return Y; + } + + void outport(int node, IdString portname, int portbit = 0) + { + if (portbit < GetSize(cell->getPort(portname))) + aig->nodes.at(node).outports.push_back(pair<IdString, int>(portname, portbit)); + } + + void outport_bool(int node, IdString portname) + { + outport(node, portname); + for (int i = 1; i < GetSize(cell->getPort(portname)); i++) + outport(bool_node(false), portname, i); + } + + void outport_vec(const vector<int> &vec, IdString portname) + { + for (int i = 0; i < GetSize(vec); i++) + outport(vec.at(i), portname, i); + } +}; + +Aig::Aig(Cell *cell) +{ + if (cell->type[0] != '$') + return; + + AigMaker mk(this, cell); + name = cell->type.str(); + + string mkname_last; + bool mkname_a_signed = false; + bool mkname_b_signed = false; + bool mkname_is_signed = false; + + cell->parameters.sort(); + for (auto p : cell->parameters) + { + if (p.first == "\\A_WIDTH" && mkname_a_signed) { + name = mkname_last + stringf(":%d%c", p.second.as_int(), mkname_is_signed ? 'S' : 'U'); + } else if (p.first == "\\B_WIDTH" && mkname_b_signed) { + name = mkname_last + stringf(":%d%c", p.second.as_int(), mkname_is_signed ? 'S' : 'U'); + } else { + mkname_last = name; + name += stringf(":%d", p.second.as_int()); + } + + mkname_a_signed = false; + mkname_b_signed = false; + mkname_is_signed = false; + if (p.first == "\\A_SIGNED") { + mkname_a_signed = true; + mkname_is_signed = p.second.as_bool(); + } + if (p.first == "\\B_SIGNED") { + mkname_b_signed = true; + mkname_is_signed = p.second.as_bool(); + } + } + + if (cell->type.in("$not", "$_NOT_", "$pos", "$_BUF_")) + { + for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) { + int A = mk.inport("\\A", i); + int Y = cell->type.in("$not", "$_NOT_") ? mk.not_gate(A) : A; + mk.outport(Y, "\\Y", i); + } + goto optimize; + } + + if (cell->type.in("$and", "$_AND_", "$_NAND_", "$or", "$_OR_", "$_NOR_", "$xor", "$xnor", "$_XOR_", "$_XNOR_")) + { + for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) { + int A = mk.inport("\\A", i); + int B = mk.inport("\\B", i); + int Y = cell->type.in("$and", "$_AND_") ? mk.and_gate(A, B) : + cell->type.in("$_NAND_") ? mk.nand_gate(A, B) : + cell->type.in("$or", "$_OR_") ? mk.or_gate(A, B) : + cell->type.in("$_NOR_") ? mk.nor_gate(A, B) : + cell->type.in("$xor", "$_XOR_") ? mk.xor_gate(A, B) : + cell->type.in("$xnor", "$_XNOR_") ? mk.xnor_gate(A, B) : -1; + mk.outport(Y, "\\Y", i); + } + goto optimize; + } + + if (cell->type.in("$mux", "$_MUX_")) + { + int S = mk.inport("\\S"); + for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) { + int A = mk.inport("\\A", i); + int B = mk.inport("\\B", i); + int Y = mk.mux_gate(A, B, S); + mk.outport(Y, "\\Y", i); + } + goto optimize; + } + + if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool")) + { + int Y = mk.inport("\\A", 0); + for (int i = 1; i < GetSize(cell->getPort("\\A")); i++) { + int A = mk.inport("\\A", i); + if (cell->type == "$reduce_and") Y = mk.and_gate(A, Y); + if (cell->type == "$reduce_or") Y = mk.or_gate(A, Y); + if (cell->type == "$reduce_bool") Y = mk.or_gate(A, Y); + if (cell->type == "$reduce_xor") Y = mk.xor_gate(A, Y); + if (cell->type == "$reduce_xnor") Y = mk.xor_gate(A, Y); + } + if (cell->type == "$reduce_xnor") + Y = mk.not_gate(Y); + mk.outport(Y, "\\Y", 0); + for (int i = 1; i < GetSize(cell->getPort("\\Y")); i++) + mk.outport(mk.bool_node(false), "\\Y", i); + goto optimize; + } + + if (cell->type.in("$logic_not", "$logic_and", "$logic_or")) + { + int A = mk.inport("\\A", 0), Y = -1; + for (int i = 1; i < GetSize(cell->getPort("\\A")); i++) + A = mk.or_gate(mk.inport("\\A", i), A); + if (cell->type.in("$logic_and", "$logic_or")) { + int B = mk.inport("\\B", 0); + for (int i = 1; i < GetSize(cell->getPort("\\B")); i++) + B = mk.or_gate(mk.inport("\\B", i), B); + if (cell->type == "$logic_and") Y = mk.and_gate(A, B); + if (cell->type == "$logic_or") Y = mk.or_gate(A, B); + } else { + if (cell->type == "$logic_not") Y = mk.not_gate(A); + } + mk.outport_bool(Y, "\\Y"); + goto optimize; + } + + if (cell->type.in("$add", "$sub")) + { + int width = GetSize(cell->getPort("\\Y")); + vector<int> A = mk.inport_vec("\\A", width); + vector<int> B = mk.inport_vec("\\B", width); + int carry = mk.bool_node(false); + if (cell->type == "$sub") { + for (auto &n : B) + n = mk.not_gate(n); + carry = mk.not_gate(carry); + } + vector<int> Y = mk.adder(A, B, carry); + mk.outport_vec(Y, "\\Y"); + goto optimize; + } + + if (cell->type == "$alu") + { + int width = GetSize(cell->getPort("\\Y")); + vector<int> A = mk.inport_vec("\\A", width); + vector<int> B = mk.inport_vec("\\B", width); + int carry = mk.inport("\\CI"); + int binv = mk.inport("\\BI"); + for (auto &n : B) + n = mk.xor_gate(n, binv); + vector<int> X(width), CO(width); + vector<int> Y = mk.adder(A, B, carry, &X, &CO); + for (int i = 0; i < width; i++) + X[i] = mk.xor_gate(A[i], B[i]); + mk.outport_vec(Y, "\\Y"); + mk.outport_vec(X, "\\X"); + mk.outport_vec(CO, "\\CO"); + goto optimize; + } + + if (cell->type.in("$eq", "$ne")) + { + int width = max(GetSize(cell->getPort("\\A")), GetSize(cell->getPort("\\B"))); + vector<int> A = mk.inport_vec("\\A", width); + vector<int> B = mk.inport_vec("\\B", width); + int Y = mk.bool_node(false); + for (int i = 0; i < width; i++) + Y = mk.or_gate(Y, mk.xor_gate(A[i], B[i])); + if (cell->type == "$eq") + Y = mk.not_gate(Y); + mk.outport_bool(Y, "\\Y"); + goto optimize; + } + + if (cell->type == "$_AOI3_") + { + int A = mk.inport("\\A"); + int B = mk.inport("\\B"); + int C = mk.inport("\\C"); + int Y = mk.nor_gate(mk.and_gate(A, B), C); + mk.outport(Y, "\\Y"); + goto optimize; + } + + if (cell->type == "$_OAI3_") + { + int A = mk.inport("\\A"); + int B = mk.inport("\\B"); + int C = mk.inport("\\C"); + int Y = mk.nand_gate(mk.or_gate(A, B), C); + mk.outport(Y, "\\Y"); + goto optimize; + } + + if (cell->type == "$_AOI4_") + { + int A = mk.inport("\\A"); + int B = mk.inport("\\B"); + int C = mk.inport("\\C"); + int D = mk.inport("\\D"); + int Y = mk.nor_gate(mk.and_gate(A, B), mk.and_gate(C, D)); + mk.outport(Y, "\\Y"); + goto optimize; + } + + if (cell->type == "$_OAI4_") + { + int A = mk.inport("\\A"); + int B = mk.inport("\\B"); + int C = mk.inport("\\C"); + int D = mk.inport("\\D"); + int Y = mk.nand_gate(mk.nor_gate(A, B), mk.nor_gate(C, D)); + mk.outport(Y, "\\Y"); + goto optimize; + } + + name.clear(); + return; + +optimize:; + pool<int> used_old_ids; + vector<AigNode> new_nodes; + dict<int, int> old_to_new_ids; + old_to_new_ids[-1] = -1; + + for (int i = GetSize(nodes)-1; i >= 0; i--) { + if (!nodes[i].outports.empty()) + used_old_ids.insert(i); + if (!used_old_ids.count(i)) + continue; + if (nodes[i].left_parent >= 0) + used_old_ids.insert(nodes[i].left_parent); + if (nodes[i].right_parent >= 0) + used_old_ids.insert(nodes[i].right_parent); + } + + for (int i = 0; i < GetSize(nodes); i++) { + if (!used_old_ids.count(i)) + continue; + nodes[i].left_parent = old_to_new_ids.at(nodes[i].left_parent); + nodes[i].right_parent = old_to_new_ids.at(nodes[i].right_parent); + old_to_new_ids[i] = GetSize(new_nodes); + new_nodes.push_back(nodes[i]); + } + + new_nodes.swap(nodes); +} + +YOSYS_NAMESPACE_END diff --git a/kernel/cellaigs.h b/kernel/cellaigs.h new file mode 100644 index 000000000..1417a614c --- /dev/null +++ b/kernel/cellaigs.h @@ -0,0 +1,52 @@ +/* + * 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 CELLAIGS_H +#define CELLAIGS_H + +#include "kernel/yosys.h" + +YOSYS_NAMESPACE_BEGIN + +struct AigNode +{ + IdString portname; + int portbit; + bool inverter; + int left_parent, right_parent; + vector<pair<IdString, int>> outports; + + AigNode(); + bool operator==(const AigNode &other) const; + unsigned int hash() const; +}; + +struct Aig +{ + string name; + vector<AigNode> nodes; + Aig(Cell *cell); + + bool operator==(const Aig &other) const; + unsigned int hash() const; +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 60e6606f8..cf7bc2dcf 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -2,11 +2,11 @@ * 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 @@ -85,7 +85,7 @@ struct CellTypes std::vector<RTLIL::IdString> unary_ops = { "$not", "$pos", "$neg", "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", - "$logic_not", "$slice", "$lut" + "$logic_not", "$slice", "$lut", "$sop" }; std::vector<RTLIL::IdString> binary_ops = { @@ -95,7 +95,6 @@ struct CellTypes "$add", "$sub", "$mul", "$div", "$mod", "$pow", "$logic_and", "$logic_or", "$concat", "$macc" }; - IdString A = "\\A", B = "\\B", S = "\\S", Y = "\\Y"; IdString P = "\\P", G = "\\G", C = "\\C", X = "\\X"; IdString BI = "\\BI", CI = "\\CI", CO = "\\CO", EN = "\\EN"; @@ -113,14 +112,17 @@ struct CellTypes setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true); setup_type("$fa", {A, B, C}, {X, Y}, true); + setup_type("$tribuf", {A, EN}, {Y}, true); + setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true); + setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true); setup_type("$equiv", {A, B}, {Y}, true); } void setup_internals_mem() { IdString SET = "\\SET", CLR = "\\CLR", CLK = "\\CLK", ARST = "\\ARST", EN = "\\EN"; - IdString Q = "\\Q", D = "\\D", ADDR = "\\ADDR", DATA = "\\DATA"; + IdString Q = "\\Q", D = "\\D", ADDR = "\\ADDR", DATA = "\\DATA", RD_EN = "\\RD_EN"; IdString RD_CLK = "\\RD_CLK", RD_ADDR = "\\RD_ADDR", WR_CLK = "\\WR_CLK", WR_EN = "\\WR_EN"; IdString WR_ADDR = "\\WR_ADDR", WR_DATA = "\\WR_DATA", RD_DATA = "\\RD_DATA"; IdString CTRL_IN = "\\CTRL_IN", CTRL_OUT = "\\CTRL_OUT"; @@ -133,16 +135,23 @@ struct CellTypes setup_type("$dlatch", {EN, D}, {Q}); setup_type("$dlatchsr", {EN, SET, CLR, D}, {Q}); - setup_type("$memrd", {CLK, ADDR}, {DATA}); + setup_type("$memrd", {CLK, EN, ADDR}, {DATA}); setup_type("$memwr", {CLK, EN, ADDR, DATA}, pool<RTLIL::IdString>()); - setup_type("$mem", {RD_CLK, RD_ADDR, WR_CLK, WR_EN, WR_ADDR, WR_DATA}, {RD_DATA}); + setup_type("$meminit", {ADDR, DATA}, pool<RTLIL::IdString>()); + setup_type("$mem", {RD_CLK, RD_EN, RD_ADDR, WR_CLK, WR_EN, WR_ADDR, WR_DATA}, {RD_DATA}); setup_type("$fsm", {CLK, ARST, CTRL_IN}, {CTRL_OUT}); } void setup_stdcells() { - IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D", S = "\\S", Y = "\\Y"; + IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D"; + IdString E = "\\E", F = "\\F", G = "\\G", H = "\\H"; + IdString I = "\\I", J = "\\J", K = "\\K", L = "\\L"; + IdString M = "\\I", N = "\\N", O = "\\O", P = "\\P"; + IdString S = "\\S", T = "\\T", U = "\\U", V = "\\V"; + IdString Y = "\\Y"; + setup_type("$_BUF_", {A}, {Y}, true); setup_type("$_NOT_", {A}, {Y}, true); setup_type("$_AND_", {A, B}, {Y}, true); @@ -152,10 +161,14 @@ struct CellTypes setup_type("$_XOR_", {A, B}, {Y}, true); setup_type("$_XNOR_", {A, B}, {Y}, true); setup_type("$_MUX_", {A, B, S}, {Y}, true); + setup_type("$_MUX4_", {A, B, C, D, S, T}, {Y}, true); + setup_type("$_MUX8_", {A, B, C, D, E, F, G, H, S, T, U}, {Y}, true); + setup_type("$_MUX16_", {A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V}, {Y}, true); setup_type("$_AOI3_", {A, B, C}, {Y}, true); setup_type("$_OAI3_", {A, B, C}, {Y}, true); setup_type("$_AOI4_", {A, B, C, D}, {Y}, true); setup_type("$_OAI4_", {A, B, C, D}, {Y}, true); + setup_type("$_TBUF_", {A, E}, {Y}, true); } void setup_stdcells_mem() @@ -344,6 +357,44 @@ struct CellTypes return t; } + if (cell->type == "$sop") + { + int width = cell->parameters.at("\\WIDTH").as_int(); + int depth = cell->parameters.at("\\DEPTH").as_int(); + std::vector<RTLIL::State> t = cell->parameters.at("\\TABLE").bits; + + while (GetSize(t) < width*depth*2) + t.push_back(RTLIL::S0); + + RTLIL::State default_ret = State::S0; + + for (int i = 0; i < depth; i++) + { + bool match = true; + bool match_x = true; + + for (int j = 0; j < width; j++) { + RTLIL::State a = arg1.bits.at(j); + if (t.at(2*width*i + 2*j + 0) == State::S1) { + if (a == State::S1) match_x = false; + if (a != State::S0) match = false; + } + if (t.at(2*width*i + 2*j + 1) == State::S1) { + if (a == State::S0) match_x = false; + if (a != State::S1) match = false; + } + } + + if (match) + return State::S1; + + if (match_x) + default_ret = State::Sx; + } + + return default_ret; + } + 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; diff --git a/kernel/consteval.h b/kernel/consteval.h index c2e9710fb..4d48b45ea 100644 --- a/kernel/consteval.h +++ b/kernel/consteval.h @@ -2,11 +2,11 @@ * 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 diff --git a/kernel/cost.h b/kernel/cost.h index c6c631e0a..4f12889f4 100644 --- a/kernel/cost.h +++ b/kernel/cost.h @@ -2,11 +2,11 @@ * 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 diff --git a/kernel/driver.cc b/kernel/driver.cc index 116df542c..45cdd461d 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -2,11 +2,11 @@ * 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 @@ -72,6 +72,53 @@ int getopt(int argc, char **argv, const char *optstring) USING_YOSYS_NAMESPACE +#ifdef EMSCRIPTEN +# include <sys/stat.h> +# include <sys/types.h> + +extern "C" int main(int, char**); +extern "C" void run(const char*); +extern "C" const char *errmsg(); +extern "C" const char *prompt(); + +int main(int, char**) +{ + mkdir("/work", 0777); + chdir("/work"); + log_files.push_back(stdout); + log_error_stderr = true; + yosys_banner(); + yosys_setup(); +} + +void run(const char *command) +{ + int selSize = GetSize(yosys_get_design()->selection_stack); + try { + log_last_error = "Internal error (see JavaScript console for details)"; + run_pass(command); + log_last_error = ""; + } catch (...) { + while (GetSize(yosys_get_design()->selection_stack) > selSize) + yosys_get_design()->selection_stack.pop_back(); + throw; + } +} + +const char *errmsg() +{ + return log_last_error.c_str(); +} + +const char *prompt() +{ + const char *p = create_prompt(yosys_get_design(), 0); + while (*p == '\n') p++; + return p; +} + +#else /* EMSCRIPTEN */ + int main(int argc, char **argv) { std::string frontend_command = "auto"; @@ -136,8 +183,8 @@ int main(int argc, char **argv) printf(" -b backend\n"); printf(" use this backend for the output file specified on the command line\n"); printf("\n"); - printf(" -f backend\n"); - printf(" use the specified front for the input files on the command line\n"); + printf(" -f frontend\n"); + printf(" use the specified frontend for the input files on the command line\n"); printf("\n"); printf(" -H\n"); printf(" print the command list\n"); @@ -166,11 +213,16 @@ int main(int argc, char **argv) printf(" -A\n"); printf(" will call abort() at the end of the script. for debugging\n"); printf("\n"); + printf(" -D <header_id>[:<filename>]\n"); + printf(" dump the design when printing the specified log header to a file.\n"); + printf(" yosys_dump_<header_id>.il is used as filename if none is specified.\n"); + printf(" Use 'ALL' as <header_id> to dump at every header.\n"); + printf("\n"); printf(" -V\n"); printf(" print version information and exit\n"); printf("\n"); printf("The option -S is an shortcut for calling the \"synth\" command, a default\n"); - printf("script for transforming the verilog input to a gate-level netlist. For example:\n"); + printf("script for transforming the Verilog input to a gate-level netlist. For example:\n"); printf("\n"); printf(" yosys -o output.blif -S input.v\n"); printf("\n"); @@ -186,7 +238,7 @@ int main(int argc, char **argv) } int opt; - while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:")) != -1) + while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:D:")) != -1) { switch (opt) { @@ -268,6 +320,28 @@ int main(int argc, char **argv) scriptfile = optarg; scriptfile_tcl = true; break; + case 'D': + { + auto args = split_tokens(optarg, ":"); + if (!args.empty() && args[0] == "ALL") { + if (GetSize(args) != 1) { + fprintf(stderr, "Invalid number of tokens in -D ALL.\n"); + exit(1); + } + log_hdump_all = true; + } else { + if (!args.empty() && !args[0].empty() && args[0].back() == '.') + args[0].pop_back(); + if (GetSize(args) == 1) + args.push_back("yosys_dump_" + args[0] + ".il"); + if (GetSize(args) != 2) { + fprintf(stderr, "Invalid number of tokens in -D.\n"); + exit(1); + } + log_hdump[args[0]].insert(args[1]); + } + } + break; default: fprintf(stderr, "Run '%s -h' for help.\n", argv[0]); exit(1); @@ -357,7 +431,7 @@ int main(int argc, char **argv) log("%s\n", yosys_version_str); int64_t total_ns = 0; - std::set<std::tuple<int64_t, int, std::string>> timedat; + std::set<tuple<int64_t, int, std::string>> timedat; for (auto &it : pass_register) if (it.second->call_counter) { @@ -440,3 +514,5 @@ int main(int argc, char **argv) return 0; } +#endif /* EMSCRIPTEN */ + diff --git a/kernel/hashlib.h b/kernel/hashlib.h index c96023920..3c824b8c3 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -1,5 +1,5 @@ // This is free and unencumbered software released into the public domain. -// +// // Anyone is free to copy, modify, publish, use, compile, sell, or // distribute this software, either in source code form or as a compiled // binary, for any purpose, commercial or non-commercial, and by any @@ -10,6 +10,7 @@ // ------------------------------------------------------- #ifndef HASHLIB_H +#define HASHLIB_H #include <stdexcept> #include <algorithm> @@ -30,7 +31,7 @@ inline unsigned int mkhash(unsigned int a, unsigned int b) { const unsigned int mkhash_init = 5381; // The ADD version of DJB2 -// (usunsigned int mkhashe this version for cache locality in b) +// (use this version for cache locality in b) inline unsigned int mkhash_add(unsigned int a, unsigned int b) { return ((a << 5) + a) + b; } @@ -58,16 +59,25 @@ template<typename T> struct hash_ops { } }; -template<> struct hash_ops<int> { +struct hash_int_ops { template<typename T> static inline bool cmp(T a, T b) { return a == b; } - template<typename T> - static inline unsigned int hash(T a) { +}; + +template<> struct hash_ops<int32_t> : hash_int_ops +{ + static inline unsigned int hash(int32_t a) { return a; } }; +template<> struct hash_ops<int64_t> : hash_int_ops +{ + static inline unsigned int hash(int64_t a) { + return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); + } +}; template<> struct hash_ops<std::string> { static inline bool cmp(const std::string &a, const std::string &b) { @@ -86,9 +96,22 @@ template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> { return a == b; } static inline unsigned int hash(std::pair<P, Q> a) { - hash_ops<P> p_ops; - hash_ops<Q> q_ops; - return mkhash(p_ops.hash(a.first), q_ops.hash(a.second)); + return mkhash(hash_ops<P>::hash(a.first), hash_ops<Q>::hash(a.second)); + } +}; + +template<typename... T> struct hash_ops<std::tuple<T...>> { + static inline bool cmp(std::tuple<T...> a, std::tuple<T...> b) { + return a == b; + } + template<size_t I = 0> + static inline typename std::enable_if<I == sizeof...(T), unsigned int>::type hash(std::tuple<T...>) { + return mkhash_init; + } + template<size_t I = 0> + static inline typename std::enable_if<I != sizeof...(T), unsigned int>::type hash(std::tuple<T...> a) { + typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t; + return mkhash(hash<I+1>(a), element_ops_t::hash(std::get<I>(a))); } }; @@ -97,10 +120,9 @@ template<typename T> struct hash_ops<std::vector<T>> { return a == b; } static inline unsigned int hash(std::vector<T> a) { - hash_ops<T> t_ops; unsigned int h = mkhash_init; for (auto k : a) - h = mkhash(h, t_ops.hash(k)); + h = mkhash(h, hash_ops<T>::hash(k)); return h; } }; @@ -115,8 +137,8 @@ struct hash_cstr_ops { static inline unsigned int hash(const char *a) { unsigned int hash = mkhash_init; while (*a) - hash = mkhash(hash, *(a++)); - return hash; + hash = mkhash(hash, *(a++)); + return hash; } }; @@ -135,10 +157,15 @@ struct hash_obj_ops { } template<typename T> static inline unsigned int hash(const T *a) { - return a->hash(); + return a ? a->hash() : 0; } }; +template<typename T> +inline unsigned int mkhash(const T &v) { + return hash_ops<T>().hash(v); +} + inline int hashtable_size(int min_size) { static std::vector<int> zero_and_some_primes = { @@ -167,6 +194,7 @@ inline int hashtable_size(int min_size) template<typename K, typename T, typename OPS = hash_ops<K>> class dict; template<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict; template<typename K, typename OPS = hash_ops<K>> class pool; +template<typename K, typename OPS = hash_ops<K>> class mfp; template<typename K, typename T, typename OPS> class dict @@ -178,18 +206,19 @@ class dict entry_t() { } entry_t(const std::pair<K, T> &udata, int next) : udata(udata), next(next) { } + entry_t(std::pair<K, T> &&udata, int next) : udata(std::move(udata)), next(next) { } }; std::vector<int> hashtable; std::vector<entry_t> entries; OPS ops; -#if 0 +#ifdef NDEBUG + static inline void do_assert(bool) { } +#else static inline void do_assert(bool cond) { if (!cond) throw std::runtime_error("dict<> assert failed."); } -#else - static inline void do_assert(bool) { } #endif int do_hash(const K &key) const @@ -203,7 +232,7 @@ class dict void do_rehash() { hashtable.clear(); - hashtable.resize(hashtable_size(entries.size() * hashtable_size_factor), -1); + hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1); for (int i = 0; i < int(entries.size()); i++) { do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size())); @@ -220,6 +249,8 @@ class dict return 0; int k = hashtable[hash]; + do_assert(0 <= k && k < int(entries.size())); + if (k == index) { hashtable[hash] = entries[index].next; } else { @@ -237,6 +268,8 @@ class dict int back_hash = do_hash(entries[back_idx].udata.first); k = hashtable[back_hash]; + do_assert(0 <= k && k < int(entries.size())); + if (k == back_idx) { hashtable[back_hash] = index; } else { @@ -278,6 +311,19 @@ class dict return index; } + int do_insert(const K &key, int &hash) + { + if (hashtable.empty()) { + entries.push_back(entry_t(std::pair<K, T>(key, T()), -1)); + do_rehash(); + hash = do_hash(key); + } else { + entries.push_back(entry_t(std::pair<K, T>(key, T()), hashtable[hash])); + hashtable[hash] = entries.size() - 1; + } + return entries.size() - 1; + } + int do_insert(const std::pair<K, T> &value, int &hash) { if (hashtable.empty()) { @@ -375,6 +421,16 @@ public: insert(*first); } + std::pair<iterator, bool> insert(const K &key) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i >= 0) + return std::pair<iterator, bool>(iterator(this, i), false); + i = do_insert(key, hash); + return std::pair<iterator, bool>(iterator(this, i), true); + } + std::pair<iterator, bool> insert(const std::pair<K, T> &value) { int hash = do_hash(value.first); @@ -449,6 +505,15 @@ public: return entries[i].udata.second; } + T at(const K &key, const T &defval) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + return defval; + return entries[i].udata.second; + } + T& operator[](const K &key) { int hash = do_hash(key); @@ -476,16 +541,17 @@ public: return false; for (auto &it : entries) { auto oit = other.find(it.udata.first); - if (oit == other.end() || oit->second != it.udata.second) + if (oit == other.end() || !(oit->second == it.udata.second)) return false; } return true; } bool operator!=(const dict &other) const { - return !(*this == other); + return !operator==(other); } + void reserve(size_t n) { entries.reserve(n); } size_t size() const { return entries.size(); } bool empty() const { return entries.empty(); } void clear() { hashtable.clear(); entries.clear(); } @@ -516,12 +582,12 @@ protected: std::vector<entry_t> entries; OPS ops; -#if 0 +#ifdef NDEBUG + static inline void do_assert(bool) { } +#else static inline void do_assert(bool cond) { if (!cond) throw std::runtime_error("pool<> assert failed."); } -#else - static inline void do_assert(bool) { } #endif int do_hash(const K &key) const @@ -535,7 +601,7 @@ protected: void do_rehash() { hashtable.clear(); - hashtable.resize(hashtable_size(entries.size() * hashtable_size_factor), -1); + hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1); for (int i = 0; i < int(entries.size()); i++) { do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size())); @@ -775,6 +841,14 @@ public: do_rehash(); } + K pop() + { + iterator it = begin(); + K ret = *it; + erase(it); + return ret; + } + void swap(pool &other) { hashtable.swap(other.hashtable); @@ -791,9 +865,10 @@ public: } bool operator!=(const pool &other) const { - return !(*this == other); + return !operator==(other); } + void reserve(size_t n) { entries.reserve(n); } size_t size() const { return entries.size(); } bool empty() const { return entries.empty(); } void clear() { hashtable.clear(); entries.clear(); } @@ -831,6 +906,15 @@ public: return i + offset; } + int at(const K &key, int defval) const + { + int hash = database.do_hash(key); + int i = database.do_lookup(key, hash); + if (i < 0) + return defval; + return i + offset; + } + int count(const K &key) const { int hash = database.do_hash(key); @@ -850,6 +934,115 @@ public: return database.entries.at(index - offset).udata; } + void swap(idict &other) + { + database.swap(other.database); + } + + void reserve(size_t n) { database.reserve(n); } + size_t size() const { return database.size(); } + bool empty() const { return database.empty(); } + void clear() { database.clear(); } + + const_iterator begin() const { return database.begin(); } + const_iterator end() const { return database.end(); } +}; + +template<typename K, typename OPS> +class mfp +{ + mutable idict<K, 0, OPS> database; + mutable std::vector<int> parents; + +public: + typedef typename idict<K, 0, OPS>::const_iterator const_iterator; + + int operator()(const K &key) const + { + int i = database(key); + parents.resize(database.size(), -1); + return i; + } + + const K &operator[](int index) const + { + return database[index]; + } + + int ifind(int i) const + { + int p = i, k = i; + + while (parents[p] != -1) + p = parents[p]; + + while (k != p) { + int next_k = parents[k]; + parents[k] = p; + k = next_k; + } + + return p; + } + + void imerge(int i, int j) + { + i = ifind(i); + j = ifind(j); + + if (i != j) + parents[i] = j; + } + + void ipromote(int i) + { + int k = i; + + while (k != -1) { + int next_k = parents[k]; + parents[k] = i; + k = next_k; + } + + parents[i] = -1; + } + + int lookup(const K &a) const + { + return ifind((*this)(a)); + } + + const K &find(const K &a) const + { + int i = database.at(a, -1); + if (i < 0) + return a; + return (*this)[ifind(i)]; + } + + void merge(const K &a, const K &b) + { + imerge((*this)(a), (*this)(b)); + } + + void promote(const K &a) + { + int i = database.at(a, -1); + if (i >= 0) + ipromote(i); + } + + void swap(mfp &other) + { + database.swap(other.database); + parents.swap(other.parents); + } + + void reserve(size_t n) { database.reserve(n); } + size_t size() const { return database.size(); } + bool empty() const { return database.empty(); } + void clear() { database.clear(); parents.clear(); } + const_iterator begin() const { return database.begin(); } const_iterator end() const { return database.end(); } }; diff --git a/kernel/log.cc b/kernel/log.cc index ada2cabb2..fe84184a5 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -2,11 +2,11 @@ * 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 @@ -40,6 +40,8 @@ YOSYS_NAMESPACE_BEGIN std::vector<FILE*> log_files; std::vector<std::ostream*> log_streams; +std::map<std::string, std::set<std::string>> log_hdump; +bool log_hdump_all = false; FILE *log_errfile = NULL; SHA1 *log_hasher = NULL; @@ -48,10 +50,11 @@ bool log_error_stderr = false; bool log_cmd_error_throw = false; bool log_quiet_warnings = false; int log_verbose_level; +string log_last_error; vector<int> header_count; pool<RTLIL::IdString> log_id_cache; -vector<string> string_buf; +vector<shared_str> string_buf; int string_buf_index = -1; static struct timeval initial_tv = { 0, 0 }; @@ -135,7 +138,7 @@ void logv(const char *format, va_list ap) *f << str; } -void logv_header(const char *format, va_list ap) +void logv_header(RTLIL::Design *design, const char *format, va_list ap) { bool pop_errfile = false; @@ -148,12 +151,24 @@ void logv_header(const char *format, va_list ap) pop_errfile = true; } + std::string header_id; + for (int c : header_count) - log("%d.", c); - log(" "); + header_id += stringf("%s%d", header_id.empty() ? "" : ".", c); + + log("%s. ", header_id.c_str()); logv(format, ap); log_flush(); + if (log_hdump_all) + log_hdump[header_id].insert("yosys_dump_" + header_id + ".il"); + + if (log_hdump.count(header_id) && design != nullptr) + for (auto &filename : log_hdump.at(header_id)) { + log("Dumping current design to '%s'.\n", filename.c_str()); + Pass::call(design, {"dump", "-o", filename}); + } + if (pop_errfile) log_files.pop_back(); } @@ -173,6 +188,10 @@ void logv_warning(const char *format, va_list ap) void logv_error(const char *format, va_list ap) { +#ifdef EMSCRIPTEN + auto backup_log_files = log_files; +#endif + if (log_errfile != NULL) log_files.push_back(log_errfile); @@ -181,10 +200,16 @@ void logv_error(const char *format, va_list ap) if (f == stdout) f = stderr; - log("ERROR: "); - logv(format, ap); + log_last_error = vstringf(format, ap); + log("ERROR: %s", log_last_error.c_str()); log_flush(); + +#ifdef EMSCRIPTEN + log_files = backup_log_files; + throw 0; +#else exit(1); +#endif } void log(const char *format, ...) @@ -195,11 +220,11 @@ void log(const char *format, ...) va_end(ap); } -void log_header(const char *format, ...) +void log_header(RTLIL::Design *design, const char *format, ...) { va_list ap; va_start(ap, format); - logv_header(format, ap); + logv_header(design, format, ap); va_end(ap); } @@ -224,8 +249,8 @@ void log_cmd_error(const char *format, ...) va_start(ap, format); if (log_cmd_error_throw) { - log("ERROR: "); - logv(format, ap); + log_last_error = vstringf(format, ap); + log("ERROR: %s", log_last_error.c_str()); log_flush(); throw log_cmd_error_exception(); } @@ -253,7 +278,7 @@ void log_pop() log_flush(); } -#ifdef __linux__ +#if defined(__linux__) && defined(YOSYS_ENABLE_PLUGINS) void log_backtrace(const char *prefix, int levels) { if (levels <= 0) return; @@ -365,6 +390,10 @@ void log_flush() f->flush(); } +void log_dump_val_worker(RTLIL::IdString v) { + log("%s", log_id(v)); +} + void log_dump_val_worker(RTLIL::SigSpec v) { log("%s", log_signal(v)); } diff --git a/kernel/log.h b/kernel/log.h index fd35c7bf7..33e624dcb 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -2,11 +2,11 @@ * 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 @@ -29,6 +29,11 @@ # include <sys/resource.h> #endif +#if defined(_MSC_VER) +// At least this is not in MSVC++ 2013. +# define __PRETTY_FUNCTION__ __FUNCTION__ +#endif + // from libs/sha1/sha1.h class SHA1; @@ -42,6 +47,8 @@ struct log_cmd_error_exception { }; extern std::vector<FILE*> log_files; extern std::vector<std::ostream*> log_streams; +extern std::map<std::string, std::set<std::string>> log_hdump; +extern bool log_hdump_all; extern FILE *log_errfile; extern SHA1 *log_hasher; @@ -50,14 +57,15 @@ extern bool log_error_stderr; extern bool log_cmd_error_throw; extern bool log_quiet_warnings; extern int log_verbose_level; +extern string log_last_error; void logv(const char *format, va_list ap); -void logv_header(const char *format, va_list ap); +void logv_header(RTLIL::Design *design, const char *format, va_list ap); void logv_warning(const char *format, va_list ap); YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noreturn); void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); -void log_header(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); +void log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3)); void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); @@ -144,7 +152,7 @@ std::string cover_list_worker(std::string prefix, std::string first, T... rest) // ------------------------------------------------------------ // simple timer for performance measurements -// toggle the '#if 1' to get a baseline for the perormance penalty added by the measurement +// toggle the '#if 1' to get a baseline for the performance penalty added by the measurement struct PerformanceTimer { #if 1 @@ -155,11 +163,13 @@ struct PerformanceTimer } static int64_t query() { -#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) +# if _WIN32 + return 0; +# elif defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) struct timespec ts; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); return int64_t(ts.tv_sec)*1000000000 + ts.tv_nsec; -#elif defined(RUSAGE_SELF) +# elif defined(RUSAGE_SELF) struct rusage rusage; int64_t t; if (getrusage(RUSAGE_SELF, &rusage) == -1) { @@ -169,11 +179,9 @@ struct PerformanceTimer t = 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL; t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL; return t; -#elif _WIN32 - return 0; -#else - #error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?). -#endif +# else +# error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?). +# endif } void reset() { @@ -221,8 +229,35 @@ static inline void log_dump_val_worker(const char *v) { log("%s", v); } static inline void log_dump_val_worker(std::string v) { log("%s", v.c_str()); } static inline void log_dump_val_worker(PerformanceTimer p) { log("%f seconds", p.sec()); } static inline void log_dump_args_worker(const char *p YS_ATTRIBUTE(unused)) { log_assert(*p == 0); } +void log_dump_val_worker(RTLIL::IdString v); void log_dump_val_worker(RTLIL::SigSpec v); +template<typename K, typename T, typename OPS> +static inline void log_dump_val_worker(dict<K, T, OPS> &v) { + log("{"); + bool first = true; + for (auto &it : v) { + log(first ? " " : ", "); + log_dump_val_worker(it.first); + log(": "); + log_dump_val_worker(it.second); + first = false; + } + log(" }"); +} + +template<typename K, typename OPS> +static inline void log_dump_val_worker(pool<K, OPS> &v) { + log("{"); + bool first = true; + for (auto &it : v) { + log(first ? " " : ", "); + log_dump_val_worker(it); + first = false; + } + log(" }"); +} + template<typename T> static inline void log_dump_val_worker(T *ptr) { log("%p", ptr); } diff --git a/kernel/macc.h b/kernel/macc.h index cac5b00d7..286ce567f 100644 --- a/kernel/macc.h +++ b/kernel/macc.h @@ -2,11 +2,11 @@ * 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 @@ -158,8 +158,8 @@ struct Macc int max_size = 0, num_bits = 0; for (auto &port : ports) { - max_size = std::max(max_size, GetSize(port.in_a)); - max_size = std::max(max_size, GetSize(port.in_b)); + max_size = max(max_size, GetSize(port.in_a)); + max_size = max(max_size, GetSize(port.in_b)); } while (max_size) diff --git a/kernel/modtools.h b/kernel/modtools.h index 69c13bd3b..ffcb48d44 100644 --- a/kernel/modtools.h +++ b/kernel/modtools.h @@ -2,11 +2,11 @@ * 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 @@ -180,8 +180,8 @@ struct ModIndex : public RTLIL::Monitor { RTLIL::SigBit lhs = sigmap(sigsig.first[i]); RTLIL::SigBit rhs = sigmap(sigsig.second[i]); - bool has_lhs = database.count(lhs); - bool has_rhs = database.count(rhs); + bool has_lhs = database.count(lhs) != 0; + bool has_rhs = database.count(rhs) != 0; if (!has_lhs && !has_rhs) { sigmap.add(lhs, rhs); @@ -226,7 +226,7 @@ struct ModIndex : public RTLIL::Monitor auto_reload_module = true; } - ModIndex(RTLIL::Module *_m) : module(_m) + ModIndex(RTLIL::Module *_m) : sigmap(_m), module(_m) { auto_reload_counter = 0; auto_reload_module = true; @@ -274,6 +274,27 @@ struct ModIndex : public RTLIL::Monitor return empty_result_set; return info->ports; } + + void dump_db() + { + log("--- ModIndex Dump ---\n"); + + if (auto_reload_module) { + log("AUTO-RELOAD\n"); + reload_module(); + } + + for (auto &it : database) { + log("BIT %s:\n", log_signal(it.first)); + if (it.second.is_input) + log(" PRIMARY INPUT\n"); + if (it.second.is_output) + log(" PRIMARY OUTPUT\n"); + for (auto &port : it.second.ports) + log(" PORT: %s.%s[%d] (%s)\n", log_id(port.cell), + log_id(port.port), port.offset, log_id(port.cell->type)); + } + } }; struct ModWalker diff --git a/kernel/register.cc b/kernel/register.cc index 56dc695aa..115880ed6 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -2,11 +2,11 @@ * 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 @@ -18,6 +18,8 @@ */ #include "kernel/yosys.h" +#include "kernel/satgen.h" + #include <string.h> #include <stdlib.h> #include <stdio.h> @@ -78,6 +80,7 @@ Pass::pre_post_exec_state_t Pass::pre_execute() state.begin_ns = PerformanceTimer::query(); state.parent_pass = current_pass; current_pass = this; + clear_flags(); return state; } @@ -97,6 +100,10 @@ void Pass::help() log("\n"); } +void Pass::clear_flags() +{ +} + void Pass::cmd_log_args(const std::vector<std::string> &args) { if (args.size() <= 1) @@ -148,7 +155,7 @@ void Pass::call(RTLIL::Design *design, std::string command) std::vector<std::string> args; std::string cmd_buf = command; - std::string tok = next_token(cmd_buf, " \t\r\n"); + std::string tok = next_token(cmd_buf, " \t\r\n", true); if (tok.empty()) return; @@ -158,7 +165,7 @@ void Pass::call(RTLIL::Design *design, std::string command) while (!cmd_buf.empty() && (cmd_buf.back() == ' ' || cmd_buf.back() == '\t' || cmd_buf.back() == '\r' || cmd_buf.back() == '\n')) cmd_buf.resize(cmd_buf.size()-1); - log_header("Shell command: %s\n", cmd_buf.c_str()); + log_header(design, "Shell command: %s\n", cmd_buf.c_str()); int retCode = run_command(cmd_buf); if (retCode != 0) log_cmd_error("Shell command returned error code %d.\n", retCode); @@ -199,7 +206,7 @@ void Pass::call(RTLIL::Design *design, std::string command) call(design, args); args.clear(); } - tok = next_token(cmd_buf, " \t\r\n"); + tok = next_token(cmd_buf, " \t\r\n", true); } call(design, args); @@ -207,7 +214,7 @@ void Pass::call(RTLIL::Design *design, std::string command) void Pass::call(RTLIL::Design *design, std::vector<std::string> args) { - if (args.size() == 0 || args[0][0] == '#') + if (args.size() == 0 || args[0][0] == '#' || args[0][0] == ':') return; if (echo_mode) { @@ -280,6 +287,60 @@ void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vec design->selected_active_module = backup_selected_active_module; } +bool ScriptPass::check_label(std::string label, std::string info) +{ + if (active_design == nullptr) { + log("\n"); + if (info.empty()) + log(" %s:\n", label.c_str()); + else + log(" %s: %s\n", label.c_str(), info.c_str()); + return true; + } else { + if (!active_run_from.empty() && active_run_from == active_run_to) { + block_active = (label == active_run_from); + } else { + if (label == active_run_from) + block_active = true; + if (label == active_run_to) + block_active = false; + } + return block_active; + } +} + +void ScriptPass::run(std::string command, std::string info) +{ + if (active_design == nullptr) { + if (info.empty()) + log(" %s\n", command.c_str()); + else + log(" %s %s\n", command.c_str(), info.c_str()); + } else + Pass::call(active_design, command); +} + +void ScriptPass::run_script(RTLIL::Design *design, std::string run_from, std::string run_to) +{ + help_mode = false; + active_design = design; + block_active = run_from.empty(); + active_run_from = run_from; + active_run_to = run_to; + script(); +} + +void ScriptPass::help_script() +{ + clear_flags(); + help_mode = true; + active_design = nullptr; + block_active = true; + active_run_from.clear(); + active_run_to.clear(); + script(); +} + Frontend::Frontend(std::string name, std::string short_help) : Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help), frontend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name) @@ -357,8 +418,7 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s } f = new std::istringstream(last_here_document); } else { - if (filename.substr(0, 2) == "+/") - filename = proc_share_dirname() + filename.substr(1); + rewrite_filename(filename); std::ifstream *ff = new std::ifstream; ff->open(filename.c_str()); if (ff->fail()) @@ -533,23 +593,36 @@ void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string f design->check(); } +static struct CellHelpMessages { + dict<string, string> cell_help, cell_code; + CellHelpMessages() { +#include "techlibs/common/simlib_help.inc" +#include "techlibs/common/simcells_help.inc" + cell_help.sort(); + cell_code.sort(); + } +} cell_help_messages; + struct HelpPass : public Pass { HelpPass() : Pass("help", "display help messages") { } virtual void help() { log("\n"); - log(" help ............. list all commands\n"); - log(" help <command> ... print help message for given command\n"); - log(" help -all ........ print complete command reference\n"); + log(" help ................ list all commands\n"); + log(" help <command> ...... print help message for given command\n"); + log(" help -all ........... print complete command reference\n"); + log("\n"); + log(" help -cells .......... list all cell types\n"); + log(" help <celltype> ..... print help message for given cell type\n"); + log(" help <celltype>+ .... print verilog code for given cell type\n"); log("\n"); } void escape_tex(std::string &tex) { - size_t pos = 0; - while ((pos = tex.find('_', pos)) != std::string::npos) { + for (size_t pos = 0; (pos = tex.find('_', pos)) != std::string::npos; pos += 2) tex.replace(pos, 1, "\\_"); - pos += 2; - } + for (size_t pos = 0; (pos = tex.find('$', pos)) != std::string::npos; pos += 2) + tex.replace(pos, 1, "\\$"); } void write_tex(FILE *f, std::string cmd, std::string title, std::string text) { @@ -609,6 +682,7 @@ struct HelpPass : public Pass { log(" %-20s %s\n", it.first.c_str(), it.second->short_help.c_str()); log("\n"); log("Type 'help <command>' for more information on a command.\n"); + log("Type 'help -cells' for a list of all cell types.\n"); log("\n"); return; } @@ -624,6 +698,18 @@ struct HelpPass : public Pass { it.second->help(); } } + else if (args[1] == "-cells") { + log("\n"); + for (auto &it : cell_help_messages.cell_help) { + string line = split_tokens(it.second, "\n").at(0); + string cell_name = next_token(line); + log(" %-15s %s\n", cell_name.c_str(), line.c_str()); + } + log("\n"); + log("Type 'help <cell_type>' for more information on a cell type.\n"); + log("\n"); + return; + } // this option is undocumented as it is for internal use only else if (args[1] == "-write-tex-command-reference-manual") { FILE *f = fopen("command-reference-manual.tex", "wt"); @@ -649,17 +735,27 @@ struct HelpPass : public Pass { } fclose(f); } - else if (pass_register.count(args[1]) == 0) - log("No such command: %s\n", args[1].c_str()); - else + else if (pass_register.count(args[1])) { pass_register.at(args[1])->help(); + } + else if (cell_help_messages.cell_help.count(args[1])) { + log("%s", cell_help_messages.cell_help.at(args[1]).c_str()); + log("Run 'help %s+' to display the Verilog model for this cell type.\n", args[1].c_str()); + log("\n"); + } + else if (cell_help_messages.cell_code.count(args[1])) { + log("\n"); + log("%s", cell_help_messages.cell_code.at(args[1]).c_str()); + } + else + log("No such command or cell type: %s\n", args[1].c_str()); return; } help(); } } HelpPass; - + struct EchoPass : public Pass { EchoPass() : Pass("echo", "turning echoing back of commands on and off") { } virtual void help() @@ -692,6 +788,18 @@ struct EchoPass : public Pass { log("echo %s\n", echo_mode ? "on" : "off"); } } EchoPass; - + +SatSolver *yosys_satsolver_list; +SatSolver *yosys_satsolver; + +struct MinisatSatSolver : public SatSolver { + MinisatSatSolver() : SatSolver("minisat") { + yosys_satsolver = this; + } + virtual ezSAT *create() YS_OVERRIDE { + return new ezMiniSAT(); + } +} MinisatSatSolver; + YOSYS_NAMESPACE_END diff --git a/kernel/register.h b/kernel/register.h index 71ab6ea6e..8024c56a0 100644 --- a/kernel/register.h +++ b/kernel/register.h @@ -2,11 +2,11 @@ * 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 @@ -31,6 +31,7 @@ struct Pass virtual ~Pass(); virtual void help(); + virtual void clear_flags(); virtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0; int call_counter; @@ -63,6 +64,22 @@ struct Pass static void done_register(); }; +struct ScriptPass : Pass +{ + bool block_active, help_mode; + RTLIL::Design *active_design; + std::string active_run_from, active_run_to; + + ScriptPass(std::string name, std::string short_help = "** document me **") : Pass(name, short_help) { } + + virtual void script() = 0; + + bool check_label(std::string label, std::string info = std::string()); + void run(std::string command, std::string info = std::string()); + void run_script(RTLIL::Design *design, std::string run_from = std::string(), std::string run_to = std::string()); + void help_script(); +}; + struct Frontend : Pass { // for reading of here documents @@ -71,7 +88,7 @@ struct Frontend : Pass std::string frontend_name; Frontend(std::string name, std::string short_help = "** document me **"); - virtual void run_register(); + virtual void run_register() YS_OVERRIDE; virtual ~Frontend(); virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL; virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0; @@ -87,7 +104,7 @@ struct Backend : Pass { std::string backend_name; Backend(std::string name, std::string short_help = "** document me **"); - virtual void run_register(); + virtual void run_register() YS_OVERRIDE; virtual ~Backend(); virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL; virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0; diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 776625b9c..9da6d2816 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -2,11 +2,11 @@ * 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 @@ -147,7 +147,7 @@ RTLIL::Const RTLIL::Const::from_string(std::string str) std::string RTLIL::Const::decode_string() const { std::string string; - std::vector <char> string_chars; + std::vector<char> string_chars; for (int i = 0; i < int (bits.size()); i += 8) { char ch = 0; for (int j = 0; j < 8 && i + j < int (bits.size()); j++) @@ -161,6 +161,46 @@ std::string RTLIL::Const::decode_string() const return string; } +void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id) +{ + attributes[id] = RTLIL::Const(1); +} + +bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const +{ + if (attributes.count(id) == 0) + return false; + return attributes.at(id).as_bool(); +} + +void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data) +{ + string attrval; + for (auto &s : data) { + if (!attrval.empty()) + attrval += "|"; + attrval += s; + } + attributes[id] = RTLIL::Const(attrval); +} + +void RTLIL::AttrObject::add_strpool_attribute(RTLIL::IdString id, const pool<string> &data) +{ + pool<string> union_data = get_strpool_attribute(id); + union_data.insert(data.begin(), data.end()); + if (!union_data.empty()) + set_strpool_attribute(id, union_data); +} + +pool<string> RTLIL::AttrObject::get_strpool_attribute(RTLIL::IdString id) const +{ + pool<string> data; + if (attributes.count(id) != 0) + for (auto s : split_tokens(attributes.at(id).decode_string(), "|")) + data.insert(s); + return data; +} + bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const { if (full_selection) @@ -264,6 +304,8 @@ RTLIL::Design::~Design() { for (auto it = modules_.begin(); it != modules_.end(); ++it) delete it->second; + for (auto n : verilog_packages) + delete n; } RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules() @@ -276,6 +318,21 @@ RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) return modules_.count(name) ? modules_.at(name) : NULL; } +RTLIL::Module *RTLIL::Design::top_module() +{ + RTLIL::Module *module = nullptr; + int module_count = 0; + + for (auto mod : selected_modules()) { + if (mod->get_bool_attribute("\\top")) + return mod; + module_count++; + module = mod; + } + + return module_count == 1 ? module : nullptr; +} + void RTLIL::Design::add(RTLIL::Module *module) { log_assert(modules_.count(module->name) == 0); @@ -389,6 +446,13 @@ void RTLIL::Design::remove(RTLIL::Module *module) delete module; } +void RTLIL::Design::rename(RTLIL::Module *module, RTLIL::IdString new_name) +{ + modules_.erase(module->name); + module->name = new_name; + add(module); +} + void RTLIL::Design::sort() { scratchpad.sort(); @@ -783,6 +847,15 @@ namespace { return; } + if (cell->type == "$sop") { + param("\\DEPTH"); + param("\\TABLE"); + port("\\A", param("\\WIDTH")); + port("\\Y", 1); + check_expected(); + return; + } + if (cell->type == "$sr") { param_bool("\\SET_POLARITY"); param_bool("\\CLR_POLARITY"); @@ -885,6 +958,7 @@ namespace { param_bool("\\CLK_POLARITY"); param_bool("\\TRANSPARENT"); port("\\CLK", 1); + port("\\EN", 1); port("\\ADDR", param("\\ABITS")); port("\\DATA", param("\\WIDTH")); check_expected(); @@ -904,16 +978,27 @@ namespace { return; } + if (cell->type == "$meminit") { + param("\\MEMID"); + param("\\PRIORITY"); + port("\\ADDR", param("\\ABITS")); + port("\\DATA", param("\\WIDTH") * param("\\WORDS")); + check_expected(); + return; + } + if (cell->type == "$mem") { param("\\MEMID"); param("\\SIZE"); param("\\OFFSET"); - param_bits("\\RD_CLK_ENABLE", param("\\RD_PORTS")); - param_bits("\\RD_CLK_POLARITY", param("\\RD_PORTS")); - param_bits("\\RD_TRANSPARENT", param("\\RD_PORTS")); - param_bits("\\WR_CLK_ENABLE", param("\\WR_PORTS")); - param_bits("\\WR_CLK_POLARITY", param("\\WR_PORTS")); + param("\\INIT"); + param_bits("\\RD_CLK_ENABLE", max(1, param("\\RD_PORTS"))); + param_bits("\\RD_CLK_POLARITY", max(1, param("\\RD_PORTS"))); + param_bits("\\RD_TRANSPARENT", max(1, param("\\RD_PORTS"))); + param_bits("\\WR_CLK_ENABLE", max(1, param("\\WR_PORTS"))); + param_bits("\\WR_CLK_POLARITY", max(1, param("\\WR_PORTS"))); port("\\RD_CLK", param("\\RD_PORTS")); + port("\\RD_EN", param("\\RD_PORTS")); port("\\RD_ADDR", param("\\RD_PORTS") * param("\\ABITS")); port("\\RD_DATA", param("\\RD_PORTS") * param("\\WIDTH")); port("\\WR_CLK", param("\\WR_PORTS")); @@ -924,6 +1009,14 @@ namespace { return; } + if (cell->type == "$tribuf") { + port("\\A", param("\\WIDTH")); + port("\\Y", param("\\WIDTH")); + port("\\EN", 1); + check_expected(); + return; + } + if (cell->type == "$assert") { port("\\A", 1); port("\\EN", 1); @@ -931,6 +1024,13 @@ namespace { return; } + if (cell->type == "$assume") { + port("\\A", 1); + port("\\EN", 1); + check_expected(); + return; + } + if (cell->type == "$equiv") { port("\\A", 1); port("\\B", 1); @@ -953,6 +1053,12 @@ namespace { if (cell->type == "$_AOI4_") { check_gate("ABCDY"); return; } if (cell->type == "$_OAI4_") { check_gate("ABCDY"); return; } + if (cell->type == "$_TBUF_") { check_gate("AYE"); return; } + + if (cell->type == "$_MUX4_") { check_gate("ABCDSTY"); return; } + if (cell->type == "$_MUX8_") { check_gate("ABCDEFGHSTUY"); return; } + if (cell->type == "$_MUX16_") { check_gate("ABCDEFGHIJKLMNOPSTUVY"); return; } + if (cell->type == "$_SR_NN_") { check_gate("SRQ"); return; } if (cell->type == "$_SR_NP_") { check_gate("SRQ"); return; } if (cell->type == "$_SR_PN_") { check_gate("SRQ"); return; } @@ -1097,6 +1203,8 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const log_assert(new_mod->refcount_wires_ == 0); log_assert(new_mod->refcount_cells_ == 0); + new_mod->avail_parameters = avail_parameters; + for (auto &conn : connections_) new_mod->connect(conn); @@ -1351,6 +1459,19 @@ void RTLIL::Module::connect(const RTLIL::SigSig &conn) for (auto mon : design->monitors) mon->notify_connect(this, conn); + // ignore all attempts to assign constants to other constants + if (conn.first.has_const()) { + RTLIL::SigSig new_conn; + for (int i = 0; i < GetSize(conn.first); i++) + if (conn.first[i].wire) { + new_conn.first.append(conn.first[i]); + new_conn.second.append(conn.second[i]); + } + if (GetSize(new_conn.first)) + connect(new_conn); + return; + } + if (yosys_xtrace) { log("#X# Connect (SigSig) in %s: %s = %s (%d bits)\n", log_id(this), log_signal(conn.first), log_signal(conn.second), GetSize(conn.first)); log_backtrace("-X- ", yosys_xtrace-1); @@ -1491,10 +1612,10 @@ DEF_METHOD(LogicNot, 1, "$logic_not") add ## _func(name, sig_a, sig_b, sig_y, is_signed); \ return sig_y; \ } -DEF_METHOD(And, std::max(sig_a.size(), sig_b.size()), "$and") -DEF_METHOD(Or, std::max(sig_a.size(), sig_b.size()), "$or") -DEF_METHOD(Xor, std::max(sig_a.size(), sig_b.size()), "$xor") -DEF_METHOD(Xnor, std::max(sig_a.size(), sig_b.size()), "$xnor") +DEF_METHOD(And, max(sig_a.size(), sig_b.size()), "$and") +DEF_METHOD(Or, max(sig_a.size(), sig_b.size()), "$or") +DEF_METHOD(Xor, max(sig_a.size(), sig_b.size()), "$xor") +DEF_METHOD(Xnor, max(sig_a.size(), sig_b.size()), "$xnor") DEF_METHOD(Shl, sig_a.size(), "$shl") DEF_METHOD(Shr, sig_a.size(), "$shr") DEF_METHOD(Sshl, sig_a.size(), "$sshl") @@ -1509,11 +1630,11 @@ DEF_METHOD(Eqx, 1, "$eqx") DEF_METHOD(Nex, 1, "$nex") DEF_METHOD(Ge, 1, "$ge") DEF_METHOD(Gt, 1, "$gt") -DEF_METHOD(Add, std::max(sig_a.size(), sig_b.size()), "$add") -DEF_METHOD(Sub, std::max(sig_a.size(), sig_b.size()), "$sub") -DEF_METHOD(Mul, std::max(sig_a.size(), sig_b.size()), "$mul") -DEF_METHOD(Div, std::max(sig_a.size(), sig_b.size()), "$div") -DEF_METHOD(Mod, std::max(sig_a.size(), sig_b.size()), "$mod") +DEF_METHOD(Add, max(sig_a.size(), sig_b.size()), "$add") +DEF_METHOD(Sub, max(sig_a.size(), sig_b.size()), "$sub") +DEF_METHOD(Mul, max(sig_a.size(), sig_b.size()), "$mul") +DEF_METHOD(Div, max(sig_a.size(), sig_b.size()), "$div") +DEF_METHOD(Mod, max(sig_a.size(), sig_b.size()), "$mod") DEF_METHOD(LogicAnd, 1, "$logic_and") DEF_METHOD(LogicOr, 1, "$logic_or") #undef DEF_METHOD @@ -1592,6 +1713,7 @@ DEF_METHOD(Pmux, "$pmux", 1) add ## _func(name, sig1, sig2, sig3, sig4, sig5); \ return sig5; \ } +DEF_METHOD_2(BufGate, "$_BUF_", A, Y) DEF_METHOD_2(NotGate, "$_NOT_", A, Y) DEF_METHOD_3(AndGate, "$_AND_", A, B, Y) DEF_METHOD_3(NandGate, "$_NAND_", A, B, Y) @@ -1645,13 +1767,23 @@ RTLIL::Cell* RTLIL::Module::addConcat(RTLIL::IdString name, RTLIL::SigSpec sig_a return cell; } -RTLIL::Cell* RTLIL::Module::addLut(RTLIL::IdString name, RTLIL::SigSpec sig_i, RTLIL::SigSpec sig_o, RTLIL::Const lut) +RTLIL::Cell* RTLIL::Module::addLut(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const lut) { RTLIL::Cell *cell = addCell(name, "$lut"); cell->parameters["\\LUT"] = lut; - cell->parameters["\\WIDTH"] = sig_i.size(); - cell->setPort("\\A", sig_i); - cell->setPort("\\Y", sig_o); + cell->parameters["\\WIDTH"] = sig_a.size(); + cell->setPort("\\A", sig_a); + cell->setPort("\\Y", sig_y); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addTribuf(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y) +{ + RTLIL::Cell *cell = addCell(name, "$tribuf"); + cell->parameters["\\WIDTH"] = sig_a.size(); + cell->setPort("\\A", sig_a); + cell->setPort("\\EN", sig_en); + cell->setPort("\\Y", sig_y); return cell; } @@ -2012,7 +2144,7 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) return; } - if (type == "$lut") { + if (type == "$lut" || type == "$sop") { parameters["\\WIDTH"] = GetSize(connections_["\\A"]); return; } @@ -2453,8 +2585,18 @@ void RTLIL::SigSpec::sort() void RTLIL::SigSpec::sort_and_unify() { + unpack(); cover("kernel.rtlil.sigspec.sort_and_unify"); - *this = this->to_sigbit_set(); + + // A copy of the bits vector is used to prevent duplicating the logic from + // SigSpec::SigSpec(std::vector<SigBit>). This incurrs an extra copy but + // that isn't showing up as significant in profiles. + std::vector<SigBit> unique_bits = bits_; + std::sort(unique_bits.begin(), unique_bits.end()); + auto last = std::unique(unique_bits.begin(), unique_bits.end()); + unique_bits.erase(last, unique_bits.end()); + + *this = unique_bits; } void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with) @@ -2464,18 +2606,26 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const { + log_assert(other != NULL); + log_assert(width_ == other->width_); log_assert(pattern.width_ == with.width_); pattern.unpack(); with.unpack(); + unpack(); + other->unpack(); - dict<RTLIL::SigBit, RTLIL::SigBit> rules; - - for (int i = 0; i < GetSize(pattern.bits_); i++) - if (pattern.bits_[i].wire != NULL) - rules[pattern.bits_[i]] = with.bits_[i]; + for (int i = 0; i < GetSize(pattern.bits_); i++) { + if (pattern.bits_[i].wire != NULL) { + for (int j = 0; j < GetSize(bits_); j++) { + if (bits_[j] == pattern.bits_[i]) { + other->bits_[j] = with.bits_[i]; + } + } + } + } - replace(rules, other); + other->check(); } void RTLIL::SigSpec::replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules) @@ -2539,8 +2689,35 @@ void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) { - pool<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_pool(); - remove2(pattern_bits, other); + if (other) + cover("kernel.rtlil.sigspec.remove_other"); + else + cover("kernel.rtlil.sigspec.remove"); + + unpack(); + if (other != NULL) { + log_assert(width_ == other->width_); + other->unpack(); + } + + for (int i = GetSize(bits_) - 1; i >= 0; i--) { + if (bits_[i].wire == NULL) continue; + + for (auto &pattern_chunk : pattern.chunks()) { + if (bits_[i].wire == pattern_chunk.wire && + bits_[i].offset >= pattern_chunk.offset && + bits_[i].offset < pattern_chunk.offset + pattern_chunk.width) { + bits_.erase(bits_.begin() + i); + width_--; + if (other != NULL) { + other->bits_.erase(other->bits_.begin() + i); + other->width_--; + } + } + } + } + + check(); } void RTLIL::SigSpec::remove(const pool<RTLIL::SigBit> &pattern) @@ -2568,31 +2745,43 @@ void RTLIL::SigSpec::remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec other->unpack(); } - std::vector<RTLIL::SigBit> new_bits, new_other_bits; - - new_bits.resize(GetSize(bits_)); - if (other != NULL) - new_other_bits.resize(GetSize(bits_)); - - int k = 0; - for (int i = 0; i < GetSize(bits_); i++) { - if (bits_[i].wire != NULL && pattern.count(bits_[i])) - continue; - if (other != NULL) - new_other_bits[k] = other->bits_[i]; - new_bits[k++] = bits_[i]; + for (int i = GetSize(bits_) - 1; i >= 0; i--) { + if (bits_[i].wire != NULL && pattern.count(bits_[i])) { + bits_.erase(bits_.begin() + i); + width_--; + if (other != NULL) { + other->bits_.erase(other->bits_.begin() + i); + other->width_--; + } + } } - new_bits.resize(k); - if (other != NULL) - new_other_bits.resize(k); + check(); +} - bits_.swap(new_bits); - width_ = GetSize(bits_); +void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) +{ + if (other) + cover("kernel.rtlil.sigspec.remove_other"); + else + cover("kernel.rtlil.sigspec.remove"); + + unpack(); if (other != NULL) { - other->bits_.swap(new_other_bits); - other->width_ = GetSize(other->bits_); + log_assert(width_ == other->width_); + other->unpack(); + } + + for (int i = GetSize(bits_) - 1; i >= 0; i--) { + if (bits_[i].wire != NULL && pattern.count(bits_[i])) { + bits_.erase(bits_.begin() + i); + width_--; + if (other != NULL) { + other->bits_.erase(other->bits_.begin() + i); + other->width_--; + } + } } check(); @@ -2600,8 +2789,37 @@ void RTLIL::SigSpec::remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other) const { - pool<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_pool(); - return extract(pattern_bits, other); + if (other) + cover("kernel.rtlil.sigspec.extract_other"); + else + cover("kernel.rtlil.sigspec.extract"); + + log_assert(other == NULL || width_ == other->width_); + + RTLIL::SigSpec ret; + std::vector<RTLIL::SigBit> bits_match = to_sigbit_vector(); + + for (auto& pattern_chunk : pattern.chunks()) { + if (other) { + std::vector<RTLIL::SigBit> bits_other = other->to_sigbit_vector(); + for (int i = 0; i < width_; i++) + if (bits_match[i].wire && + bits_match[i].wire == pattern_chunk.wire && + bits_match[i].offset >= pattern_chunk.offset && + bits_match[i].offset < pattern_chunk.offset + pattern_chunk.width) + ret.append_bit(bits_other[i]); + } else { + for (int i = 0; i < width_; i++) + if (bits_match[i].wire && + bits_match[i].wire == pattern_chunk.wire && + bits_match[i].offset >= pattern_chunk.offset && + bits_match[i].offset < pattern_chunk.offset + pattern_chunk.width) + ret.append_bit(bits_match[i]); + } + } + + ret.check(); + return ret; } RTLIL::SigSpec RTLIL::SigSpec::extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other) const @@ -2785,7 +3003,7 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed) if (width_ > width) remove(width, width_ - width); - + if (width_ < width) { RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::S0; if (!is_signed) @@ -2939,6 +3157,21 @@ bool RTLIL::SigSpec::is_fully_const() const return true; } +bool RTLIL::SigSpec::is_fully_zero() const +{ + cover("kernel.rtlil.sigspec.is_fully_zero"); + + pack(); + 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.size(); i++) + if (it->data[i] != RTLIL::State::S0) + return false; + } + return true; +} + bool RTLIL::SigSpec::is_fully_def() const { cover("kernel.rtlil.sigspec.is_fully_def"); @@ -3062,6 +3295,17 @@ RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const return chunks_[0]; } +RTLIL::SigBit RTLIL::SigSpec::as_bit() const +{ + cover("kernel.rtlil.sigspec.as_bit"); + + log_assert(width_ == 1); + if (packed()) + return RTLIL::SigBit(*chunks_.begin()); + else + return bits_[0]; +} + bool RTLIL::SigSpec::match(std::string pattern) const { cover("kernel.rtlil.sigspec.match"); @@ -3149,18 +3393,6 @@ dict<RTLIL::SigBit, RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_dict(const RTLIL::S return new_map; } -RTLIL::SigBit RTLIL::SigSpec::to_single_sigbit() const -{ - cover("kernel.rtlil.sigspec.to_single_sigbit"); - - pack(); - log_assert(width_ == 1); - for (auto &c : chunks_) - if (c.width) - return RTLIL::SigBit(c); - log_abort(); -} - static void sigspec_parse_split(std::vector<std::string> &tokens, const std::string &text, char sep) { size_t start = 0, end = 0; @@ -3180,6 +3412,10 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri { cover("kernel.rtlil.sigspec.parse"); + AST::current_filename = "input"; + AST::use_internal_line_num(); + AST::set_line_num(0); + std::vector<std::string> tokens; sigspec_parse_split(tokens, str, ','); @@ -3339,7 +3575,7 @@ RTLIL::SwitchRule *RTLIL::SwitchRule::clone() const for (auto &it : cases) new_switchrule->cases.push_back(it->clone()); return new_switchrule; - + } RTLIL::SyncRule *RTLIL::SyncRule::clone() const @@ -3371,7 +3607,7 @@ RTLIL::Process *RTLIL::Process::clone() const for (auto &it : syncs) new_proc->syncs.push_back(it->clone()); - + return new_proc; } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index dd40e2fba..274f97023 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -2,11 +2,11 @@ * 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 @@ -53,6 +53,7 @@ namespace RTLIL }; struct Const; + struct AttrObject; struct Selection; struct Monitor; struct Design; @@ -191,14 +192,14 @@ namespace RTLIL return std::string(global_id_storage_.at(index_)); } - bool operator<(IdString rhs) const { + bool operator<(const IdString &rhs) const { return index_ < rhs.index_; } - bool operator==(IdString rhs) const { return index_ == rhs.index_; } - bool operator!=(IdString rhs) const { return index_ != rhs.index_; } + bool operator==(const IdString &rhs) const { return index_ == rhs.index_; } + bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; } - // The methods below are just convinience functions for better compatibility with std::string. + // The methods below are just convenience functions for better compatibility with std::string. bool operator==(const std::string &rhs) const { return str() == rhs; } bool operator!=(const std::string &rhs) const { return str() != rhs; } @@ -208,7 +209,7 @@ namespace RTLIL char operator[](size_t i) const { const char *p = c_str(); - for (; i != 0; i--, p++) + for (; i != 0; i--, p++) log_assert(*p != 0); return *p; } @@ -459,7 +460,7 @@ struct RTLIL::Const Const(std::string str); Const(int val, int width = 32); Const(RTLIL::State bit, int width = 1); - Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; }; + Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; } Const(const std::vector<bool> &bits); bool operator <(const RTLIL::Const &other) const; @@ -474,6 +475,16 @@ struct RTLIL::Const std::string decode_string() const; inline int size() const { return bits.size(); } + inline RTLIL::State &operator[](int index) { return bits.at(index); } + inline const RTLIL::State &operator[](int index) const { return bits.at(index); } + + inline RTLIL::Const extract(int offset, int len = 1, RTLIL::State padding = RTLIL::State::S0) const { + RTLIL::Const ret; + ret.bits.reserve(len); + for (int i = offset; i < offset + len; i++) + ret.bits.push_back(i < GetSize(bits) ? bits[i] : padding); + return ret; + } inline unsigned int hash() const { unsigned int h = mkhash_init; @@ -483,6 +494,17 @@ struct RTLIL::Const } }; +struct RTLIL::AttrObject +{ + dict<RTLIL::IdString, RTLIL::Const> attributes; + + void set_bool_attribute(RTLIL::IdString id); + bool get_bool_attribute(RTLIL::IdString id) const; + void set_strpool_attribute(RTLIL::IdString id, const pool<string> &data); + void add_strpool_attribute(RTLIL::IdString id, const pool<string> &data); + pool<string> get_strpool_attribute(RTLIL::IdString id) const; +}; + struct RTLIL::SigChunk { RTLIL::Wire *wire; @@ -647,6 +669,7 @@ public: void remove(const pool<RTLIL::SigBit> &pattern); void remove(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const; void remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other); + void remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other); void remove(int offset, int length = 1); void remove_const(); @@ -668,8 +691,10 @@ public: bool is_wire() const; bool is_chunk() const; + inline bool is_bit() const { return width_ == 1; } bool is_fully_const() const; + bool is_fully_zero() const; bool is_fully_def() const; bool is_fully_undef() const; bool has_const() const; @@ -681,6 +706,7 @@ public: RTLIL::Const as_const() const; RTLIL::Wire *as_wire() const; RTLIL::SigChunk as_chunk() const; + RTLIL::SigBit as_bit() const; bool match(std::string pattern) const; @@ -689,7 +715,6 @@ public: std::vector<RTLIL::SigBit> to_sigbit_vector() const; std::map<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_map(const RTLIL::SigSpec &other) const; dict<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_dict(const RTLIL::SigSpec &other) const; - RTLIL::SigBit to_single_sigbit() const; static bool parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str); static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str); @@ -767,6 +792,7 @@ struct RTLIL::Design int refcount_modules_; dict<RTLIL::IdString, RTLIL::Module*> modules_; + std::vector<AST::AstNode*> verilog_packages; std::vector<RTLIL::Selection> selection_stack; dict<RTLIL::IdString, RTLIL::Selection> selection_vars; @@ -777,6 +803,7 @@ struct RTLIL::Design RTLIL::ObjRange<RTLIL::Module*> modules(); RTLIL::Module *module(RTLIL::IdString name); + RTLIL::Module *top_module(); bool has(RTLIL::IdString id) const { return modules_.count(id) != 0; @@ -785,6 +812,7 @@ struct RTLIL::Design void add(RTLIL::Module *module); RTLIL::Module *addModule(RTLIL::IdString name); void remove(RTLIL::Module *module); + void rename(RTLIL::Module *module, RTLIL::IdString new_name); void scratchpad_unset(std::string varname); @@ -807,6 +835,14 @@ struct RTLIL::Design bool selected_module(RTLIL::Module *mod) const; bool selected_whole_module(RTLIL::Module *mod) const; + RTLIL::Selection &selection() { + return selection_stack.back(); + } + + const RTLIL::Selection &selection() const { + return selection_stack.back(); + } + bool full_selection() const { return selection_stack.back().full_selection; } @@ -831,18 +867,7 @@ struct RTLIL::Design std::vector<RTLIL::Module*> selected_whole_modules_warn() const; }; -#define RTLIL_ATTRIBUTE_MEMBERS \ - dict<RTLIL::IdString, RTLIL::Const> attributes; \ - void set_bool_attribute(RTLIL::IdString id) { \ - attributes[id] = RTLIL::Const(1); \ - } \ - bool get_bool_attribute(RTLIL::IdString id) const { \ - if (attributes.count(id) == 0) \ - return false; \ - return attributes.at(id).as_bool(); \ - } - -struct RTLIL::Module +struct RTLIL::Module : public RTLIL::AttrObject { unsigned int hashidx_; unsigned int hash() const { return hashidx_; } @@ -866,7 +891,6 @@ public: pool<RTLIL::IdString> avail_parameters; dict<RTLIL::IdString, RTLIL::Memory*> memories; dict<RTLIL::IdString, RTLIL::Process*> processes; - RTLIL_ATTRIBUTE_MEMBERS Module(); virtual ~Module(); @@ -933,25 +957,25 @@ public: RTLIL::Cell* addNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addPos (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addNeg (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false); - + RTLIL::Cell* addAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); - + RTLIL::Cell* addReduceAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addReduceOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addReduceXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addReduceXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addReduceBool (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false); - + RTLIL::Cell* addShl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addShr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addSshl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addSshr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addShift (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addShiftx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); - + RTLIL::Cell* addLt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addLe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addEq (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); @@ -960,24 +984,25 @@ public: RTLIL::Cell* addNex (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addGe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addGt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); - + RTLIL::Cell* addAdd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addSub (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addMul (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addDiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addMod (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addPow (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool a_signed = false, bool b_signed = false); - + RTLIL::Cell* addLogicNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addLogicAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); RTLIL::Cell* addLogicOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); - + RTLIL::Cell* addMux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y); RTLIL::Cell* addPmux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y); - + RTLIL::Cell* addSlice (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const offset); RTLIL::Cell* addConcat (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y); - RTLIL::Cell* addLut (RTLIL::IdString name, RTLIL::SigSpec sig_i, RTLIL::SigSpec sig_o, RTLIL::Const lut); + RTLIL::Cell* addLut (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const lut); + RTLIL::Cell* addTribuf (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y); RTLIL::Cell* addAssert (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en); RTLIL::Cell* addEquiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y); @@ -992,6 +1017,7 @@ public: RTLIL::Cell* addDlatchsr (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true); + RTLIL::Cell* addBufGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y); RTLIL::Cell* addNotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y); RTLIL::Cell* addAndGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y); RTLIL::Cell* addNandGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y); @@ -1063,6 +1089,7 @@ public: RTLIL::SigSpec Mux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s); RTLIL::SigSpec Pmux (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s); + RTLIL::SigBit BufGate (RTLIL::IdString name, RTLIL::SigBit sig_a); RTLIL::SigBit NotGate (RTLIL::IdString name, RTLIL::SigBit sig_a); RTLIL::SigBit AndGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b); RTLIL::SigBit NandGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b); @@ -1077,7 +1104,7 @@ public: RTLIL::SigBit Oai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d); }; -struct RTLIL::Wire +struct RTLIL::Wire : public RTLIL::AttrObject { unsigned int hashidx_; unsigned int hash() const { return hashidx_; } @@ -1097,10 +1124,9 @@ public: RTLIL::IdString name; int width, start_offset, port_id; bool port_input, port_output, upto; - RTLIL_ATTRIBUTE_MEMBERS }; -struct RTLIL::Memory +struct RTLIL::Memory : public RTLIL::AttrObject { unsigned int hashidx_; unsigned int hash() const { return hashidx_; } @@ -1109,10 +1135,9 @@ struct RTLIL::Memory RTLIL::IdString name; int width, start_offset, size; - RTLIL_ATTRIBUTE_MEMBERS }; -struct RTLIL::Cell +struct RTLIL::Cell : public RTLIL::AttrObject { unsigned int hashidx_; unsigned int hash() const { return hashidx_; } @@ -1132,7 +1157,6 @@ public: RTLIL::IdString type; dict<RTLIL::IdString, RTLIL::SigSpec> connections_; dict<RTLIL::IdString, RTLIL::Const> parameters; - RTLIL_ATTRIBUTE_MEMBERS // access cell ports bool hasPort(RTLIL::IdString portname) const; @@ -1177,10 +1201,9 @@ struct RTLIL::CaseRule RTLIL::CaseRule *clone() const; }; -struct RTLIL::SwitchRule +struct RTLIL::SwitchRule : public RTLIL::AttrObject { RTLIL::SigSpec signal; - RTLIL_ATTRIBUTE_MEMBERS std::vector<RTLIL::CaseRule*> cases; ~SwitchRule(); @@ -1199,10 +1222,9 @@ struct RTLIL::SyncRule RTLIL::SyncRule *clone() const; }; -struct RTLIL::Process +struct RTLIL::Process : public RTLIL::AttrObject { RTLIL::IdString name; - RTLIL_ATTRIBUTE_MEMBERS RTLIL::CaseRule root_case; std::vector<RTLIL::SyncRule*> syncs; diff --git a/kernel/satgen.h b/kernel/satgen.h index 2f5efe674..e118c1569 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -2,11 +2,11 @@ * 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 @@ -29,7 +29,37 @@ YOSYS_NAMESPACE_BEGIN -typedef ezMiniSAT ezDefaultSAT; +// defined in kernel/register.cc +extern struct SatSolver *yosys_satsolver_list; +extern struct SatSolver *yosys_satsolver; + +struct SatSolver +{ + string name; + SatSolver *next; + virtual ezSAT *create() = 0; + + SatSolver(string name) : name(name) { + next = yosys_satsolver_list; + yosys_satsolver_list = this; + } + + virtual ~SatSolver() { + auto p = &yosys_satsolver_list; + while (*p) { + if (*p == this) + *p = next; + else + p = &(*p)->next; + } + if (yosys_satsolver == this) + yosys_satsolver = yosys_satsolver_list; + } +}; + +struct ezSatPtr : public std::unique_ptr<ezSAT> { + ezSatPtr() : unique_ptr<ezSAT>(yosys_satsolver->create()) { } +}; struct SatGen { @@ -38,6 +68,7 @@ struct SatGen std::string prefix; SigPool initial_state; std::map<std::string, RTLIL::SigSpec> asserts_a, asserts_en; + std::map<std::string, RTLIL::SigSpec> assumes_a, assumes_en; std::map<std::string, std::map<RTLIL::SigBit, int>> imported_signals; bool ignore_div_by_zero; bool model_undef; @@ -131,6 +162,13 @@ struct SatGen sig_en = asserts_en[pf]; } + void getAssumes(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1) + { + std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); + sig_a = assumes_a[pf]; + sig_en = assumes_en[pf]; + } + int importAsserts(int timestep = -1) { std::vector<int> check_bits, enable_bits; @@ -145,6 +183,20 @@ struct SatGen return ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits))); } + int importAssumes(int timestep = -1) + { + std::vector<int> check_bits, enable_bits; + std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); + if (model_undef) { + check_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_a[pf], timestep)), importDefSigSpec(assumes_a[pf], timestep)); + enable_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_en[pf], timestep)), importDefSigSpec(assumes_en[pf], timestep)); + } else { + check_bits = importDefSigSpec(assumes_a[pf], timestep); + enable_bits = importDefSigSpec(assumes_en[pf], timestep); + } + return ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits))); + } + int signals_eq(RTLIL::SigSpec lhs, RTLIL::SigSpec rhs, int timestep_lhs = -1, int timestep_rhs = -1) { if (timestep_rhs < 0) @@ -928,7 +980,7 @@ struct SatGen div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); } } else { - int copy_a_bits = std::min(cell->getPort("\\A").size(), cell->getPort("\\B").size()); + int copy_a_bits = min(cell->getPort("\\A").size(), cell->getPort("\\B").size()); div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits); if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), div_zero_result.back()); @@ -996,6 +1048,88 @@ struct SatGen return true; } + if (cell->type == "$sop") + { + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0); + + int width = cell->getParam("\\WIDTH").as_int(); + int depth = cell->getParam("\\DEPTH").as_int(); + + vector<State> table_raw = cell->getParam("\\TABLE").bits; + while (GetSize(table_raw) < 2*width*depth) + table_raw.push_back(State::S0); + + vector<vector<int>> table(depth); + + for (int i = 0; i < depth; i++) + for (int j = 0; j < width; j++) + { + bool pat0 = (table_raw[2*width*i + 2*j + 0] == State::S1); + bool pat1 = (table_raw[2*width*i + 2*j + 1] == State::S1); + + if (pat0 && !pat1) + table.at(i).push_back(0); + else if (!pat0 && pat1) + table.at(i).push_back(1); + else + table.at(i).push_back(-1); + } + + if (model_undef) + { + std::vector<int> products, undef_products; + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0); + + for (int i = 0; i < depth; i++) + { + std::vector<int> cmp_a, cmp_ua, cmp_b; + + for (int j = 0; j < width; j++) + if (table.at(i).at(j) >= 0) { + cmp_a.push_back(a.at(j)); + cmp_ua.push_back(undef_a.at(j)); + cmp_b.push_back(table.at(i).at(j) ? ez->CONST_TRUE : ez->CONST_FALSE); + } + + std::vector<int> masked_a = ez->vec_or(cmp_a, cmp_ua); + std::vector<int> masked_b = ez->vec_or(cmp_b, cmp_ua); + + int masked_eq = ez->vec_eq(masked_a, masked_b); + int any_undef = ez->expression(ezSAT::OpOr, cmp_ua); + + undef_products.push_back(ez->AND(any_undef, masked_eq)); + products.push_back(ez->AND(ez->NOT(any_undef), masked_eq)); + } + + int yy = ez->expression(ezSAT::OpOr, products); + ez->SET(undef_y, ez->AND(ez->NOT(yy), ez->expression(ezSAT::OpOr, undef_products))); + undefGating(y, yy, undef_y); + } + else + { + std::vector<int> products; + + for (int i = 0; i < depth; i++) + { + std::vector<int> cmp_a, cmp_b; + + for (int j = 0; j < width; j++) + if (table.at(i).at(j) >= 0) { + cmp_a.push_back(a.at(j)); + cmp_b.push_back(table.at(i).at(j) ? ez->CONST_TRUE : ez->CONST_FALSE); + } + + products.push_back(ez->vec_eq(cmp_a, cmp_b)); + } + + ez->SET(y, ez->expression(ezSAT::OpOr, products)); + } + + return true; + } + if (cell->type == "$fa") { std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); @@ -1204,6 +1338,14 @@ struct SatGen return true; } + if (cell->type == "$assume") + { + std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); + assumes_a[pf].append((*sigmap)(cell->getPort("\\A"))); + assumes_en[pf].append((*sigmap)(cell->getPort("\\EN"))); + return true; + } + // Unsupported internal cell types: $pow $lut // .. and all sequential cells except $dff and $_DFF_[NP]_ return false; diff --git a/kernel/sigtools.h b/kernel/sigtools.h index f92a87dbb..4e97bb775 100644 --- a/kernel/sigtools.h +++ b/kernel/sigtools.h @@ -2,11 +2,11 @@ * 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 @@ -222,18 +222,7 @@ struct SigSet struct SigMap { - struct bitDef_t : public std::pair<RTLIL::Wire*, int> { - bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { } - bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { } - unsigned int hash() const { return first->name.hash() + second; } - }; - - struct shared_bit_data_t { - RTLIL::SigBit map_to; - std::set<bitDef_t> bits; - }; - - dict<bitDef_t, shared_bit_data_t*> bits; + mfp<SigBit> database; SigMap(RTLIL::Module *module = NULL) { @@ -241,119 +230,27 @@ struct SigMap 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]->map_to = bit.second->map_to; - bits[bit.first]->bits = bit.second->bits; - } - } - void swap(SigMap &other) { - bits.swap(other.bits); - } - - ~SigMap() - { - clear(); + database.swap(other.database); } 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(); + database.clear(); } void set(RTLIL::Module *module) { - clear(); + int bitcount = 0; for (auto &it : module->connections()) - add(it.first, it.second); - } + bitcount += it.first.size(); - // internal helper function - void register_bit(const RTLIL::SigBit &bit) - { - if (bit.wire && bits.count(bit) == 0) { - shared_bit_data_t *bd = new shared_bit_data_t; - bd->map_to = bit; - bd->bits.insert(bit); - bits[bit] = bd; - } - } + database.clear(); + database.reserve(bitcount); - // internal helper function - void unregister_bit(const RTLIL::SigBit &bit) - { - if (bit.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::SigBit &bit1, const RTLIL::SigBit &bit2) - { - log_assert(bit1.wire != NULL && bit2.wire != NULL); - - shared_bit_data_t *bd1 = bits[bit1]; - shared_bit_data_t *bd2 = bits[bit2]; - log_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->map_to = bd2->map_to; - 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::SigBit &bit1, const RTLIL::SigBit &bit2) - { - log_assert(bit1.wire != NULL); - log_assert(bits.count(bit1) > 0); - bits[bit1]->map_to = bit2; - } - - // internal helper function - void map_bit(RTLIL::SigBit &bit) const - { - if (bit.wire && bits.count(bit) > 0) - bit = bits.at(bit)->map_to; + for (auto &it : module->connections()) + add(it.first, it.second); } void add(RTLIL::SigSpec from, RTLIL::SigSpec to) @@ -362,45 +259,43 @@ struct SigMap for (int i = 0; i < GetSize(from); i++) { - RTLIL::SigBit &bf = from[i]; - RTLIL::SigBit &bt = to[i]; + int bfi = database.lookup(from[i]); + int bti = database.lookup(to[i]); - if (bf.wire == NULL) - continue; + const RTLIL::SigBit &bf = database[bfi]; + const RTLIL::SigBit &bt = database[bti]; - register_bit(bf); - register_bit(bt); + if (bf.wire || bt.wire) + { + database.imerge(bfi, bti); - if (bt.wire != NULL) - merge_bit(bf, bt); - else - set_bit(bf, bt); + if (bf.wire == nullptr) + database.ipromote(bfi); + + if (bt.wire == nullptr) + database.ipromote(bti); + } } } void add(RTLIL::SigSpec sig) { for (auto &bit : sig) { - register_bit(bit); - set_bit(bit, bit); + RTLIL::SigBit b = database.find(bit); + if (b.wire != nullptr) + database.promote(bit); } } - void del(RTLIL::SigSpec sig) - { - for (auto &bit : sig) - unregister_bit(bit); - } - void apply(RTLIL::SigBit &bit) const { - map_bit(bit); + bit = database.find(bit); } void apply(RTLIL::SigSpec &sig) const { for (auto &bit : sig) - map_bit(bit); + apply(bit); } RTLIL::SigBit operator()(RTLIL::SigBit bit) const @@ -417,10 +312,19 @@ struct SigMap RTLIL::SigSpec operator()(RTLIL::Wire *wire) const { - RTLIL::SigSpec sig(wire); + SigSpec sig(wire); apply(sig); return sig; } + + RTLIL::SigSpec allbits() const + { + RTLIL::SigSpec sig; + for (auto &bit : database) + if (bit.wire != nullptr) + sig.append(bit); + return sig; + } }; YOSYS_NAMESPACE_END diff --git a/kernel/utils.h b/kernel/utils.h index 2ec6182ea..8942905fe 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -2,11 +2,11 @@ * 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 @@ -186,7 +186,7 @@ struct TopoSort active_stack.pop_back(); active_cells.erase(n); } - + marked_cells.insert(n); sorted.push_back(n); } diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 530d78796..8da57fd4e 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -2,11 +2,11 @@ * 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 @@ -104,7 +104,7 @@ void yosys_banner() log(" | |\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n"); log(" | |\n"); - log(" | Copyright (C) 2012 - 2015 Clifford Wolf <clifford@clifford.at> |\n"); + log(" | Copyright (C) 2012 - 2016 Clifford Wolf <clifford@clifford.at> |\n"); log(" | |\n"); log(" | Permission to use, copy, modify, and/or distribute this software for any |\n"); log(" | purpose with or without fee is hereby granted, provided that the above |\n"); @@ -124,6 +124,18 @@ void yosys_banner() log("\n"); } +int ceil_log2(int x) +{ + if (x <= 0) + return 0; + + for (int i = 0; i < 32; i++) + if (((x-1) >> i) == 0) + return i; + + log_abort(); +} + std::string stringf(const char *fmt, ...) { std::string string; @@ -168,7 +180,7 @@ std::string vstringf(const char *fmt, va_list ap) int readsome(std::istream &f, char *s, int n) { - int rc = f.readsome(s, n); + int rc = int(f.readsome(s, n)); // f.readsome() sometimes returns 0 on a non-empty stream.. if (rc == 0) { @@ -182,13 +194,23 @@ int readsome(std::istream &f, char *s, int n) return rc; } -std::string next_token(std::string &text, const char *sep) +std::string next_token(std::string &text, const char *sep, bool long_strings) { size_t pos_begin = text.find_first_not_of(sep); if (pos_begin == std::string::npos) pos_begin = text.size(); + if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') { + string sep_string = sep; + for (size_t i = pos_begin+1; i < text.size(); i++) + if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) { + std::string token = text.substr(pos_begin, i-pos_begin+1); + text = text.substr(i+1); + return token; + } + } + size_t pos_end = text.find_first_of(sep, pos_begin); if (pos_end == std::string::npos) @@ -199,6 +221,26 @@ std::string next_token(std::string &text, const char *sep) return token; } +std::vector<std::string> split_tokens(const std::string &text, const char *sep) +{ + std::vector<std::string> tokens; + std::string current_token; + for (char c : text) { + if (strchr(sep, c)) { + if (!current_token.empty()) { + tokens.push_back(current_token); + current_token.clear(); + } + } else + current_token += c; + } + if (!current_token.empty()) { + tokens.push_back(current_token); + current_token.clear(); + } + return tokens; +} + // this is very similar to fnmatch(). the exact rules used by this // function are: // @@ -376,6 +418,15 @@ bool check_file_exists(std::string filename, bool is_exec) } #endif +bool is_absolute_path(std::string filename) +{ +#ifdef _WIN32 + return filename[0] == '/' || filename[0] == '\\' || (filename[0] != 0 && filename[1] == ':'); +#else + return filename[0] == '/'; +#endif +} + void remove_directory(std::string dirname) { #ifdef _WIN32 @@ -496,6 +547,14 @@ const char *create_prompt(RTLIL::Design *design, int recursion_counter) return buffer; } +void rewrite_filename(std::string &filename) +{ + if (filename.substr(0, 1) == "\"" && filename.substr(GetSize(filename)-1) == "\"") + filename = filename.substr(1, GetSize(filename)-2); + if (filename.substr(0, 2) == "+/") + filename = proc_share_dirname() + filename.substr(2); +} + #ifdef YOSYS_ENABLE_TCL static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[]) { @@ -549,7 +608,7 @@ struct TclPass : public Pass { log("The tcl command 'yosys -import' can be used to import all yosys\n"); log("commands directly as tcl commands to the tcl shell. The yosys\n"); log("command 'proc' is wrapped using the tcl command 'procs' in order\n"); - log("to avoid a name collision with the tcl builting command 'proc'.\n"); + log("to avoid a name collision with the tcl builtin command 'proc'.\n"); log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { @@ -619,26 +678,38 @@ std::string proc_self_dirname() #error Dont know how to determine process executable base path! #endif +#ifdef EMSCRIPTEN +std::string proc_share_dirname() +{ + return "/share"; +} +#else std::string proc_share_dirname() { std::string proc_self_path = proc_self_dirname(); -#ifdef _WIN32 +# ifdef _WIN32 std::string proc_share_path = proc_self_path + "share\\"; if (check_file_exists(proc_share_path, true)) return proc_share_path; proc_share_path = proc_self_path + "..\\share\\"; if (check_file_exists(proc_share_path, true)) return proc_share_path; -#else +# else std::string proc_share_path = proc_self_path + "share/"; if (check_file_exists(proc_share_path, true)) return proc_share_path; proc_share_path = proc_self_path + "../share/yosys/"; if (check_file_exists(proc_share_path, true)) return proc_share_path; -#endif +# ifdef YOSYS_DATDIR + proc_share_path = YOSYS_DATDIR "/"; + if (check_file_exists(proc_share_path, true)) + return proc_share_path; +# endif +# endif log_error("proc_share_dirname: unable to determine share/ directory!\n"); } +#endif bool fgetline(FILE *f, std::string &buffer) { @@ -664,6 +735,9 @@ static void handle_label(std::string &command, bool &from_to_active, const std:: while (pos < GetSize(command) && (command[pos] == ' ' || command[pos] == '\t')) pos++; + if (pos < GetSize(command) && command[pos] == '#') + return; + while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n') label += command[pos++]; @@ -689,6 +763,10 @@ void run_frontend(std::string filename, std::string command, std::string *backen command = "verilog"; else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv") command = "verilog -sv"; + else if (filename.size() > 2 && filename.substr(filename.size()-4) == ".vhd") + command = "vhdl"; + else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif") + command = "blif"; else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") command = "ilang"; else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys") @@ -802,6 +880,10 @@ void run_backend(std::string filename, std::string command, RTLIL::Design *desig command = "ilang"; else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif") command = "blif"; + else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".edif") + command = "edif"; + else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".json") + command = "json"; else if (filename == "-") command = "ilang"; else if (filename.empty()) @@ -1018,8 +1100,8 @@ struct HistoryPass : public Pass { } HistoryPass; #endif -struct ScriptPass : public Pass { - ScriptPass() : Pass("script", "execute commands from script file") { } +struct ScriptCmdPass : public Pass { + ScriptCmdPass() : Pass("script", "execute commands from script file") { } virtual void help() { log("\n"); log(" script <filename> [<from_label>:<to_label>]\n"); @@ -1045,7 +1127,7 @@ struct ScriptPass : public Pass { else extra_args(args, 2, design, false); } -} ScriptPass; +} ScriptCmdPass; YOSYS_NAMESPACE_END diff --git a/kernel/yosys.h b/kernel/yosys.h index 47275ecd4..0df750a13 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -2,11 +2,11 @@ * 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 @@ -41,6 +41,7 @@ #include <map> #include <set> +#include <tuple> #include <vector> #include <string> #include <algorithm> @@ -49,6 +50,8 @@ #include <unordered_set> #include <initializer_list> #include <stdexcept> +#include <memory> +#include <cmath> #include <sstream> #include <fstream> @@ -89,9 +92,9 @@ # define mkdir _mkdir # define popen _popen # define pclose _pclose -# define PATH_MAX MAX_PATH # ifndef __MINGW32__ +# define PATH_MAX MAX_PATH # define isatty _isatty # define fileno _fileno # endif @@ -137,8 +140,27 @@ YOSYS_NAMESPACE_BEGIN using std::vector; using std::string; +using std::tuple; using std::pair; +using std::make_tuple; +using std::make_pair; +using std::min; +using std::max; + +// A primitive shared string implementation that does not +// move its .c_str() when the object is copied or moved. +struct shared_str { + std::shared_ptr<string> content; + shared_str() { } + shared_str(string s) { content = std::shared_ptr<string>(new string(s)); } + shared_str(const char *s) { content = std::shared_ptr<string>(new string(s)); } + const char *c_str() const { return content->c_str(); } + const string &str() const { return *content; } + bool operator==(const shared_str &other) const { return *content == *other.content; } + unsigned int hash() const { return hashlib::hash_ops<std::string>::hash(*content); } +}; + using hashlib::mkhash; using hashlib::mkhash_init; using hashlib::mkhash_add; @@ -150,6 +172,7 @@ using hashlib::hash_obj_ops; using hashlib::dict; using hashlib::idict; using hashlib::pool; +using hashlib::mfp; namespace RTLIL { struct IdString; @@ -200,15 +223,18 @@ extern bool memhasher_active; inline void memhasher() { if (memhasher_active) memhasher_do(); } void yosys_banner(); +int ceil_log2(int x); std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); std::string vstringf(const char *fmt, va_list ap); int readsome(std::istream &f, char *s, int n); -std::string next_token(std::string &text, const char *sep = " \t\r\n"); +std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false); +std::vector<std::string> split_tokens(const std::string &text, const char *sep = " \t\r\n"); bool patmatch(const char *pattern, const char *string); int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>()); std::string make_temp_file(std::string template_str = "/tmp/yosys_XXXXXX"); std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX"); bool check_file_exists(std::string filename, bool is_exec = false); +bool is_absolute_path(std::string filename); void remove_directory(std::string dirname); template<typename T> int GetSize(const T &obj) { return obj.size(); } @@ -226,6 +252,8 @@ YOSYS_NAMESPACE_END YOSYS_NAMESPACE_BEGIN using RTLIL::State; +using RTLIL::SigChunk; +using RTLIL::SigSig; namespace hashlib { template<> struct hash_ops<RTLIL::State> : hash_ops<int> {}; @@ -252,6 +280,7 @@ RTLIL::Design *yosys_get_design(); std::string proc_self_dirname(); std::string proc_share_dirname(); const char *create_prompt(RTLIL::Design *design, int recursion_counter); +void rewrite_filename(std::string &filename); void run_pass(std::string command, RTLIL::Design *design = nullptr); void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label = nullptr, RTLIL::Design *design = nullptr); |