From 85a1bb17edca9ab105ae5e11aaa65b5a85c8fe86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sun, 19 Jul 2020 00:17:02 +0200 Subject: satgen: Move importCell out of the header. This function has no hope of ever getting inlined anyway, and it speeds up yosys compile time by 7%. --- kernel/satgen.cc | 1188 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1188 insertions(+) create mode 100644 kernel/satgen.cc (limited to 'kernel/satgen.cc') diff --git a/kernel/satgen.cc b/kernel/satgen.cc new file mode 100644 index 000000000..b90b43fb7 --- /dev/null +++ b/kernel/satgen.cc @@ -0,0 +1,1188 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * 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/satgen.h" + +USING_YOSYS_NAMESPACE + +bool SatGen::importCell(RTLIL::Cell *cell, int timestep) +{ + bool arith_undef_handled = false; + bool is_arith_compare = cell->type.in(ID($lt), ID($le), ID($ge), ID($gt)); + + if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor)) || is_arith_compare)) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + if (is_arith_compare) + extendSignalWidth(undef_a, undef_b, cell, true); + else + extendSignalWidth(undef_a, undef_b, undef_y, cell, true); + + int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); + int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); + int undef_y_bit = ez->OR(undef_any_a, undef_any_b); + + if (cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) { + std::vector b = importSigSpec(cell->getPort(ID::B), timestep); + undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b))); + } + + if (is_arith_compare) { + for (size_t i = 1; i < undef_y.size(); i++) + ez->SET(ez->CONST_FALSE, undef_y.at(i)); + ez->SET(undef_y_bit, undef_y.at(0)); + } else { + std::vector undef_y_bits(undef_y.size(), undef_y_bit); + ez->assume(ez->vec_eq(undef_y_bits, undef_y)); + } + + arith_undef_handled = true; + } + + if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), + ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($sub))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidth(a, b, y, cell); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + if (cell->type.in(ID($and), ID($_AND_))) + ez->assume(ez->vec_eq(ez->vec_and(a, b), yy)); + if (cell->type == ID($_NAND_)) + ez->assume(ez->vec_eq(ez->vec_not(ez->vec_and(a, b)), yy)); + if (cell->type.in(ID($or), ID($_OR_))) + ez->assume(ez->vec_eq(ez->vec_or(a, b), yy)); + if (cell->type == ID($_NOR_)) + ez->assume(ez->vec_eq(ez->vec_not(ez->vec_or(a, b)), yy)); + if (cell->type.in(ID($xor), ID($_XOR_))) + ez->assume(ez->vec_eq(ez->vec_xor(a, b), yy)); + if (cell->type.in(ID($xnor), ID($_XNOR_))) + ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(a, b)), yy)); + if (cell->type == ID($_ANDNOT_)) + ez->assume(ez->vec_eq(ez->vec_and(a, ez->vec_not(b)), yy)); + if (cell->type == ID($_ORNOT_)) + ez->assume(ez->vec_eq(ez->vec_or(a, ez->vec_not(b)), yy)); + if (cell->type == ID($add)) + ez->assume(ez->vec_eq(ez->vec_add(a, b), yy)); + if (cell->type == ID($sub)) + ez->assume(ez->vec_eq(ez->vec_sub(a, b), yy)); + + if (model_undef && !arith_undef_handled) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidth(undef_a, undef_b, undef_y, cell, false); + + if (cell->type.in(ID($and), ID($_AND_), ID($_NAND_))) { + std::vector a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a)); + std::vector b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b)); + std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b0))); + ez->assume(ez->vec_eq(yX, undef_y)); + } + else if (cell->type.in(ID($or), ID($_OR_), ID($_NOR_))) { + std::vector a1 = ez->vec_and(a, ez->vec_not(undef_a)); + std::vector b1 = ez->vec_and(b, ez->vec_not(undef_b)); + std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b1))); + ez->assume(ez->vec_eq(yX, undef_y)); + } + else if (cell->type.in(ID($xor), ID($xnor), ID($_XOR_), ID($_XNOR_))) { + std::vector yX = ez->vec_or(undef_a, undef_b); + ez->assume(ez->vec_eq(yX, undef_y)); + } + else if (cell->type == ID($_ANDNOT_)) { + std::vector a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a)); + std::vector b1 = ez->vec_and(b, ez->vec_not(undef_b)); + std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b1))); + ez->assume(ez->vec_eq(yX, undef_y)); + } + + else if (cell->type == ID($_ORNOT_)) { + std::vector a1 = ez->vec_and(a, ez->vec_not(undef_a)); + std::vector b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b)); + std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b0))); + ez->assume(ez->vec_eq(yX, undef_y)); + } + else + log_abort(); + + undefGating(y, yy, undef_y); + } + else if (model_undef) + { + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type.in(ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_))) + { + bool aoi_mode = cell->type.in(ID($_AOI3_), ID($_AOI4_)); + bool three_mode = cell->type.in(ID($_AOI3_), ID($_OAI3_)); + + int a = importDefSigSpec(cell->getPort(ID::A), timestep).at(0); + int b = importDefSigSpec(cell->getPort(ID::B), timestep).at(0); + int c = importDefSigSpec(cell->getPort(ID::C), timestep).at(0); + int d = three_mode ? (aoi_mode ? ez->CONST_TRUE : ez->CONST_FALSE) : importDefSigSpec(cell->getPort(ID::D), timestep).at(0); + int y = importDefSigSpec(cell->getPort(ID::Y), timestep).at(0); + int yy = model_undef ? ez->literal() : y; + + if (cell->type.in(ID($_AOI3_), ID($_AOI4_))) + ez->assume(ez->IFF(ez->NOT(ez->OR(ez->AND(a, b), ez->AND(c, d))), yy)); + else + ez->assume(ez->IFF(ez->NOT(ez->AND(ez->OR(a, b), ez->OR(c, d))), yy)); + + if (model_undef) + { + int undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep).at(0); + int undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep).at(0); + int undef_c = importUndefSigSpec(cell->getPort(ID::C), timestep).at(0); + int undef_d = three_mode ? ez->CONST_FALSE : importUndefSigSpec(cell->getPort(ID::D), timestep).at(0); + int undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep).at(0); + + if (aoi_mode) + { + int a0 = ez->AND(ez->NOT(a), ez->NOT(undef_a)); + int b0 = ez->AND(ez->NOT(b), ez->NOT(undef_b)); + int c0 = ez->AND(ez->NOT(c), ez->NOT(undef_c)); + int d0 = ez->AND(ez->NOT(d), ez->NOT(undef_d)); + + int ab = ez->AND(a, b), cd = ez->AND(c, d); + int undef_ab = ez->AND(ez->OR(undef_a, undef_b), ez->NOT(ez->OR(a0, b0))); + int undef_cd = ez->AND(ez->OR(undef_c, undef_d), ez->NOT(ez->OR(c0, d0))); + + int ab1 = ez->AND(ab, ez->NOT(undef_ab)); + int cd1 = ez->AND(cd, ez->NOT(undef_cd)); + int yX = ez->AND(ez->OR(undef_ab, undef_cd), ez->NOT(ez->OR(ab1, cd1))); + + ez->assume(ez->IFF(yX, undef_y)); + } + else + { + int a1 = ez->AND(a, ez->NOT(undef_a)); + int b1 = ez->AND(b, ez->NOT(undef_b)); + int c1 = ez->AND(c, ez->NOT(undef_c)); + int d1 = ez->AND(d, ez->NOT(undef_d)); + + int ab = ez->OR(a, b), cd = ez->OR(c, d); + int undef_ab = ez->AND(ez->OR(undef_a, undef_b), ez->NOT(ez->OR(a1, b1))); + int undef_cd = ez->AND(ez->OR(undef_c, undef_d), ez->NOT(ez->OR(c1, d1))); + + int ab0 = ez->AND(ez->NOT(ab), ez->NOT(undef_ab)); + int cd0 = ez->AND(ez->NOT(cd), ez->NOT(undef_cd)); + int yX = ez->AND(ez->OR(undef_ab, undef_cd), ez->NOT(ez->OR(ab0, cd0))); + + ez->assume(ez->IFF(yX, undef_y)); + } + + undefGating(y, yy, undef_y); + } + + return true; + } + + if (cell->type.in(ID($_NOT_), ID($not))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidthUnary(a, y, cell); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + ez->assume(ez->vec_eq(ez->vec_not(a), yy)); + + if (model_undef) { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidthUnary(undef_a, undef_y, cell, false); + ez->assume(ez->vec_eq(undef_a, undef_y)); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type.in(ID($_MUX_), ID($mux), ID($_NMUX_))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector s = importDefSigSpec(cell->getPort(ID::S), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + if (cell->type == ID($_NMUX_)) + ez->assume(ez->vec_eq(ez->vec_not(ez->vec_ite(s.at(0), b, a)), yy)); + else + ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy)); + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + + std::vector unequal_ab = ez->vec_not(ez->vec_iff(a, b)); + std::vector undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a, undef_b)); + std::vector yX = ez->vec_ite(undef_s.at(0), undef_ab, ez->vec_ite(s.at(0), undef_b, undef_a)); + ez->assume(ez->vec_eq(yX, undef_y)); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type == ID($pmux)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector s = importDefSigSpec(cell->getPort(ID::S), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + std::vector tmp = a; + for (size_t i = 0; i < s.size(); i++) { + std::vector part_of_b(b.begin()+i*a.size(), b.begin()+(i+1)*a.size()); + tmp = ez->vec_ite(s.at(i), part_of_b, tmp); + } + ez->assume(ez->vec_eq(tmp, yy)); + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + + int maybe_a = ez->CONST_TRUE; + + std::vector bits_set = std::vector(undef_y.size(), ez->CONST_FALSE); + std::vector bits_clr = std::vector(undef_y.size(), ez->CONST_FALSE); + + for (size_t i = 0; i < s.size(); i++) + { + std::vector part_of_b(b.begin()+i*a.size(), b.begin()+(i+1)*a.size()); + std::vector part_of_undef_b(undef_b.begin()+i*a.size(), undef_b.begin()+(i+1)*a.size()); + + int maybe_s = ez->OR(s.at(i), undef_s.at(i)); + int sure_s = ez->AND(s.at(i), ez->NOT(undef_s.at(i))); + + maybe_a = ez->AND(maybe_a, ez->NOT(sure_s)); + + bits_set = ez->vec_ite(maybe_s, ez->vec_or(bits_set, ez->vec_or(part_of_b, part_of_undef_b)), bits_set); + bits_clr = ez->vec_ite(maybe_s, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(part_of_b), part_of_undef_b)), bits_clr); + } + + bits_set = ez->vec_ite(maybe_a, ez->vec_or(bits_set, ez->vec_or(bits_set, ez->vec_or(a, undef_a))), bits_set); + bits_clr = ez->vec_ite(maybe_a, ez->vec_or(bits_clr, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(a), undef_a))), bits_clr); + + ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(bits_set, bits_clr)), undef_y)); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type.in(ID($pos), ID($neg))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidthUnary(a, y, cell); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + if (cell->type == ID($pos)) { + ez->assume(ez->vec_eq(a, yy)); + } else { + std::vector zero(a.size(), ez->CONST_FALSE); + ez->assume(ez->vec_eq(ez->vec_sub(zero, a), yy)); + } + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidthUnary(undef_a, undef_y, cell); + + if (cell->type == ID($pos)) { + ez->assume(ez->vec_eq(undef_a, undef_y)); + } else { + int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); + std::vector undef_y_bits(undef_y.size(), undef_any_a); + ez->assume(ez->vec_eq(undef_y_bits, undef_y)); + } + + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + if (cell->type == ID($reduce_and)) + ez->SET(ez->expression(ez->OpAnd, a), yy.at(0)); + if (cell->type.in(ID($reduce_or), ID($reduce_bool))) + ez->SET(ez->expression(ez->OpOr, a), yy.at(0)); + if (cell->type == ID($reduce_xor)) + ez->SET(ez->expression(ez->OpXor, a), yy.at(0)); + if (cell->type == ID($reduce_xnor)) + ez->SET(ez->NOT(ez->expression(ez->OpXor, a)), yy.at(0)); + if (cell->type == ID($logic_not)) + ez->SET(ez->NOT(ez->expression(ez->OpOr, a)), yy.at(0)); + for (size_t i = 1; i < y.size(); i++) + ez->SET(ez->CONST_FALSE, yy.at(i)); + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + int aX = ez->expression(ezSAT::OpOr, undef_a); + + if (cell->type == ID($reduce_and)) { + int a0 = ez->expression(ezSAT::OpOr, ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a))); + ez->assume(ez->IFF(ez->AND(ez->NOT(a0), aX), undef_y.at(0))); + } + else if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($logic_not))) { + int a1 = ez->expression(ezSAT::OpOr, ez->vec_and(a, ez->vec_not(undef_a))); + ez->assume(ez->IFF(ez->AND(ez->NOT(a1), aX), undef_y.at(0))); + } + else if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) { + ez->assume(ez->IFF(aX, undef_y.at(0))); + } else + log_abort(); + + for (size_t i = 1; i < undef_y.size(); i++) + ez->SET(ez->CONST_FALSE, undef_y.at(i)); + + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type.in(ID($logic_and), ID($logic_or))) + { + std::vector vec_a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector vec_b = importDefSigSpec(cell->getPort(ID::B), timestep); + + int a = ez->expression(ez->OpOr, vec_a); + int b = ez->expression(ez->OpOr, vec_b); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + if (cell->type == ID($logic_and)) + ez->SET(ez->expression(ez->OpAnd, a, b), yy.at(0)); + else + ez->SET(ez->expression(ez->OpOr, a, b), yy.at(0)); + for (size_t i = 1; i < y.size(); i++) + ez->SET(ez->CONST_FALSE, yy.at(i)); + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + + int a0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_a), ez->expression(ezSAT::OpOr, undef_a))); + int b0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_b), ez->expression(ezSAT::OpOr, undef_b))); + int a1 = ez->expression(ezSAT::OpOr, ez->vec_and(vec_a, ez->vec_not(undef_a))); + int b1 = ez->expression(ezSAT::OpOr, ez->vec_and(vec_b, ez->vec_not(undef_b))); + int aX = ez->expression(ezSAT::OpOr, undef_a); + int bX = ez->expression(ezSAT::OpOr, undef_b); + + if (cell->type == ID($logic_and)) + ez->SET(ez->AND(ez->OR(aX, bX), ez->NOT(ez->AND(a1, b1)), ez->NOT(a0), ez->NOT(b0)), undef_y.at(0)); + else if (cell->type == ID($logic_or)) + ez->SET(ez->AND(ez->OR(aX, bX), ez->NOT(ez->AND(a0, b0)), ez->NOT(a1), ez->NOT(b1)), undef_y.at(0)); + else + log_abort(); + + for (size_t i = 1; i < undef_y.size(); i++) + ez->SET(ez->CONST_FALSE, undef_y.at(i)); + + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt))) + { + bool is_signed = cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool(); + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidth(a, b, cell); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + if (model_undef && cell->type.in(ID($eqx), ID($nex))) { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + extendSignalWidth(undef_a, undef_b, cell, true); + a = ez->vec_or(a, undef_a); + b = ez->vec_or(b, undef_b); + } + + if (cell->type == ID($lt)) + ez->SET(is_signed ? ez->vec_lt_signed(a, b) : ez->vec_lt_unsigned(a, b), yy.at(0)); + if (cell->type == ID($le)) + ez->SET(is_signed ? ez->vec_le_signed(a, b) : ez->vec_le_unsigned(a, b), yy.at(0)); + if (cell->type.in(ID($eq), ID($eqx))) + ez->SET(ez->vec_eq(a, b), yy.at(0)); + if (cell->type.in(ID($ne), ID($nex))) + ez->SET(ez->vec_ne(a, b), yy.at(0)); + if (cell->type == ID($ge)) + ez->SET(is_signed ? ez->vec_ge_signed(a, b) : ez->vec_ge_unsigned(a, b), yy.at(0)); + if (cell->type == ID($gt)) + ez->SET(is_signed ? ez->vec_gt_signed(a, b) : ez->vec_gt_unsigned(a, b), yy.at(0)); + for (size_t i = 1; i < y.size(); i++) + ez->SET(ez->CONST_FALSE, yy.at(i)); + + if (model_undef && cell->type.in(ID($eqx), ID($nex))) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidth(undef_a, undef_b, cell, true); + + if (cell->type == ID($eqx)) + yy.at(0) = ez->AND(yy.at(0), ez->vec_eq(undef_a, undef_b)); + else + yy.at(0) = ez->OR(yy.at(0), ez->vec_ne(undef_a, undef_b)); + + for (size_t i = 0; i < y.size(); i++) + ez->SET(ez->CONST_FALSE, undef_y.at(i)); + + ez->assume(ez->vec_eq(y, yy)); + } + else if (model_undef && cell->type.in(ID($eq), ID($ne))) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidth(undef_a, undef_b, cell, true); + + int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); + int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); + int undef_any = ez->OR(undef_any_a, undef_any_b); + + std::vector masked_a_bits = ez->vec_or(a, ez->vec_or(undef_a, undef_b)); + std::vector masked_b_bits = ez->vec_or(b, ez->vec_or(undef_a, undef_b)); + + int masked_ne = ez->vec_ne(masked_a_bits, masked_b_bits); + int undef_y_bit = ez->AND(undef_any, ez->NOT(masked_ne)); + + for (size_t i = 1; i < undef_y.size(); i++) + ez->SET(ez->CONST_FALSE, undef_y.at(i)); + ez->SET(undef_y_bit, undef_y.at(0)); + + undefGating(y, yy, undef_y); + } + else + { + if (model_undef) { + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + undefGating(y, yy, undef_y); + } + log_assert(!model_undef || arith_undef_handled); + } + return true; + } + + if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + + int extend_bit = ez->CONST_FALSE; + + if (!cell->type.in(ID($shift), ID($shiftx)) && cell->parameters[ID::A_SIGNED].as_bool()) + extend_bit = a.back(); + + while (y.size() < a.size()) + y.push_back(ez->literal()); + while (y.size() > a.size()) + a.push_back(extend_bit); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + std::vector shifted_a; + + if (cell->type.in( ID($shl), ID($sshl))) + shifted_a = ez->vec_shift_left(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); + + if (cell->type == ID($shr)) + shifted_a = ez->vec_shift_right(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); + + if (cell->type == ID($sshr)) + shifted_a = ez->vec_shift_right(a, b, false, cell->parameters[ID::A_SIGNED].as_bool() ? a.back() : ez->CONST_FALSE, ez->CONST_FALSE); + + if (cell->type.in(ID($shift), ID($shiftx))) + shifted_a = ez->vec_shift_right(a, b, cell->parameters[ID::B_SIGNED].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE); + + ez->assume(ez->vec_eq(shifted_a, yy)); + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + std::vector undef_a_shifted; + + extend_bit = cell->type == ID($shiftx) ? ez->CONST_TRUE : ez->CONST_FALSE; + if (!cell->type.in(ID($shift), ID($shiftx)) && cell->parameters[ID::A_SIGNED].as_bool()) + extend_bit = undef_a.back(); + + while (undef_y.size() < undef_a.size()) + undef_y.push_back(ez->literal()); + while (undef_y.size() > undef_a.size()) + undef_a.push_back(extend_bit); + + if (cell->type.in(ID($shl), ID($sshl))) + undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); + + if (cell->type == ID($shr)) + undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); + + if (cell->type == ID($sshr)) + undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters[ID::A_SIGNED].as_bool() ? undef_a.back() : ez->CONST_FALSE, ez->CONST_FALSE); + + if (cell->type == ID($shift)) + undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters[ID::B_SIGNED].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE); + + if (cell->type == ID($shiftx)) + undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters[ID::B_SIGNED].as_bool(), ez->CONST_TRUE, ez->CONST_TRUE); + + int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); + std::vector undef_all_y_bits(undef_y.size(), undef_any_b); + ez->assume(ez->vec_eq(ez->vec_or(undef_a_shifted, undef_all_y_bits), undef_y)); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type == ID($mul)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidth(a, b, y, cell); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + std::vector tmp(a.size(), ez->CONST_FALSE); + for (int i = 0; i < int(a.size()); i++) + { + std::vector shifted_a(a.size(), ez->CONST_FALSE); + for (int j = i; j < int(a.size()); j++) + shifted_a.at(j) = a.at(j-i); + tmp = ez->vec_ite(b.at(i), ez->vec_add(tmp, shifted_a), tmp); + } + ez->assume(ez->vec_eq(tmp, yy)); + + if (model_undef) { + log_assert(arith_undef_handled); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type == ID($macc)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + + Macc macc; + macc.from_cell(cell); + + std::vector tmp(GetSize(y), ez->CONST_FALSE); + + for (auto &port : macc.ports) + { + std::vector in_a = importDefSigSpec(port.in_a, timestep); + std::vector in_b = importDefSigSpec(port.in_b, timestep); + + while (GetSize(in_a) < GetSize(y)) + in_a.push_back(port.is_signed && !in_a.empty() ? in_a.back() : ez->CONST_FALSE); + in_a.resize(GetSize(y)); + + if (GetSize(in_b)) + { + while (GetSize(in_b) < GetSize(y)) + in_b.push_back(port.is_signed && !in_b.empty() ? in_b.back() : ez->CONST_FALSE); + in_b.resize(GetSize(y)); + + for (int i = 0; i < GetSize(in_b); i++) { + std::vector shifted_a(in_a.size(), ez->CONST_FALSE); + for (int j = i; j < int(in_a.size()); j++) + shifted_a.at(j) = in_a.at(j-i); + if (port.do_subtract) + tmp = ez->vec_ite(in_b.at(i), ez->vec_sub(tmp, shifted_a), tmp); + else + tmp = ez->vec_ite(in_b.at(i), ez->vec_add(tmp, shifted_a), tmp); + } + } + else + { + if (port.do_subtract) + tmp = ez->vec_sub(tmp, in_a); + else + tmp = ez->vec_add(tmp, in_a); + } + } + + for (int i = 0; i < GetSize(b); i++) { + std::vector val(GetSize(y), ez->CONST_FALSE); + val.at(0) = b.at(i); + tmp = ez->vec_add(tmp, val); + } + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + + int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); + int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); + + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + ez->assume(ez->vec_eq(undef_y, std::vector(GetSize(y), ez->OR(undef_any_a, undef_any_b)))); + + undefGating(y, tmp, undef_y); + } + else + ez->assume(ez->vec_eq(y, tmp)); + + return true; + } + + if (cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidth(a, b, y, cell); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + std::vector a_u, b_u; + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { + a_u = ez->vec_ite(a.back(), ez->vec_neg(a), a); + b_u = ez->vec_ite(b.back(), ez->vec_neg(b), b); + } else { + a_u = a; + b_u = b; + } + + std::vector chain_buf = a_u; + std::vector y_u(a_u.size(), ez->CONST_FALSE); + for (int i = int(a.size())-1; i >= 0; i--) + { + chain_buf.insert(chain_buf.end(), chain_buf.size(), ez->CONST_FALSE); + + std::vector b_shl(i, ez->CONST_FALSE); + b_shl.insert(b_shl.end(), b_u.begin(), b_u.end()); + b_shl.insert(b_shl.end(), chain_buf.size()-b_shl.size(), ez->CONST_FALSE); + + y_u.at(i) = ez->vec_ge_unsigned(chain_buf, b_shl); + chain_buf = ez->vec_ite(y_u.at(i), ez->vec_sub(chain_buf, b_shl), chain_buf); + + chain_buf.erase(chain_buf.begin() + a_u.size(), chain_buf.end()); + } + + std::vector y_tmp = ignore_div_by_zero ? yy : ez->vec_var(y.size()); + + // modulo calculation + std::vector modulo_trunc; + int floored_eq_trunc; + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { + modulo_trunc = ez->vec_ite(a.back(), ez->vec_neg(chain_buf), chain_buf); + // floor == trunc when sgn(a) == sgn(b) or trunc == 0 + floored_eq_trunc = ez->OR(ez->IFF(a.back(), b.back()), ez->NOT(ez->expression(ezSAT::OpOr, modulo_trunc))); + } else { + modulo_trunc = chain_buf; + floored_eq_trunc = ez->CONST_TRUE; + } + + if (cell->type == ID($div)) { + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) + ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(ez->XOR(a.back(), b.back()), ez->vec_neg(y_u), y_u))); + else + ez->assume(ez->vec_eq(y_tmp, y_u)); + } else if (cell->type == ID($mod)) { + ez->assume(ez->vec_eq(y_tmp, modulo_trunc)); + } else if (cell->type == ID($divfloor)) { + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) + ez->assume(ez->vec_eq(y_tmp, ez->vec_ite( + ez->XOR(a.back(), b.back()), + ez->vec_neg(ez->vec_ite( + ez->vec_reduce_or(modulo_trunc), + ez->vec_add(y_u, ez->vec_const_unsigned(1, y_u.size())), + y_u + )), + y_u + ))); + else + ez->assume(ez->vec_eq(y_tmp, y_u)); + } else if (cell->type == ID($modfloor)) { + ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(floored_eq_trunc, modulo_trunc, ez->vec_add(modulo_trunc, b)))); + } + + if (ignore_div_by_zero) { + ez->assume(ez->expression(ezSAT::OpOr, b)); + } else { + std::vector div_zero_result; + if (cell->type.in(ID($div), ID($divfloor))) { + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { + std::vector all_ones(y.size(), ez->CONST_TRUE); + std::vector only_first_one(y.size(), ez->CONST_FALSE); + only_first_one.at(0) = ez->CONST_TRUE; + div_zero_result = ez->vec_ite(a.back(), only_first_one, all_ones); + } else { + div_zero_result.insert(div_zero_result.end(), cell->getPort(ID::A).size(), ez->CONST_TRUE); + div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); + } + } else if (cell->type.in(ID($mod), ID($modfloor))) { + // a mod 0 = a + int copy_a_bits = min(cell->getPort(ID::A).size(), cell->getPort(ID::B).size()); + div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits); + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) + div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), div_zero_result.back()); + else + div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); + } + ez->assume(ez->vec_eq(yy, ez->vec_ite(ez->expression(ezSAT::OpOr, b), y_tmp, div_zero_result))); + } + + if (model_undef) { + log_assert(arith_undef_handled); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type == ID($lut)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + + std::vector lut; + for (auto bit : cell->getParam(ID::LUT).bits) + lut.push_back(bit == State::S1 ? ez->CONST_TRUE : ez->CONST_FALSE); + while (GetSize(lut) < (1 << GetSize(a))) + lut.push_back(ez->CONST_FALSE); + lut.resize(1 << GetSize(a)); + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector t(lut), u(GetSize(t), ez->CONST_FALSE); + + for (int i = GetSize(a)-1; i >= 0; i--) + { + std::vector t0(t.begin(), t.begin() + GetSize(t)/2); + std::vector t1(t.begin() + GetSize(t)/2, t.end()); + + std::vector u0(u.begin(), u.begin() + GetSize(u)/2); + std::vector u1(u.begin() + GetSize(u)/2, u.end()); + + t = ez->vec_ite(a[i], t1, t0); + u = ez->vec_ite(undef_a[i], ez->vec_or(ez->vec_xor(t0, t1), ez->vec_or(u0, u1)), ez->vec_ite(a[i], u1, u0)); + } + + log_assert(GetSize(t) == 1); + log_assert(GetSize(u) == 1); + undefGating(y, t, u); + ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort(ID::Y), timestep), u)); + } + else + { + std::vector t = lut; + for (int i = GetSize(a)-1; i >= 0; i--) + { + std::vector t0(t.begin(), t.begin() + GetSize(t)/2); + std::vector t1(t.begin() + GetSize(t)/2, t.end()); + t = ez->vec_ite(a[i], t1, t0); + } + + log_assert(GetSize(t) == 1); + ez->assume(ez->vec_eq(y, t)); + } + return true; + } + + if (cell->type == ID($sop)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + int y = importDefSigSpec(cell->getPort(ID::Y), timestep).at(0); + + int width = cell->getParam(ID::WIDTH).as_int(); + int depth = cell->getParam(ID::DEPTH).as_int(); + + vector table_raw = cell->getParam(ID::TABLE).bits; + while (GetSize(table_raw) < 2*width*depth) + table_raw.push_back(State::S0); + + vector> 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 products, undef_products; + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + int undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep).at(0); + + for (int i = 0; i < depth; i++) + { + std::vector 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 masked_a = ez->vec_or(cmp_a, cmp_ua); + std::vector 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 products; + + for (int i = 0; i < depth; i++) + { + std::vector 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 == ID($fa)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector c = importDefSigSpec(cell->getPort(ID::C), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + std::vector x = importDefSigSpec(cell->getPort(ID::X), timestep); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + std::vector xx = model_undef ? ez->vec_var(x.size()) : x; + + std::vector t1 = ez->vec_xor(a, b); + ez->assume(ez->vec_eq(yy, ez->vec_xor(t1, c))); + + std::vector t2 = ez->vec_and(a, b); + std::vector t3 = ez->vec_and(c, t1); + ez->assume(ez->vec_eq(xx, ez->vec_or(t2, t3))); + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_c = importUndefSigSpec(cell->getPort(ID::C), timestep); + + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + std::vector undef_x = importUndefSigSpec(cell->getPort(ID::X), timestep); + + ez->assume(ez->vec_eq(undef_y, ez->vec_or(ez->vec_or(undef_a, undef_b), undef_c))); + ez->assume(ez->vec_eq(undef_x, undef_y)); + + undefGating(y, yy, undef_y); + undefGating(x, xx, undef_x); + } + return true; + } + + if (cell->type == ID($lcu)) + { + std::vector p = importDefSigSpec(cell->getPort(ID::P), timestep); + std::vector g = importDefSigSpec(cell->getPort(ID::G), timestep); + std::vector ci = importDefSigSpec(cell->getPort(ID::CI), timestep); + std::vector co = importDefSigSpec(cell->getPort(ID::CO), timestep); + + std::vector yy = model_undef ? ez->vec_var(co.size()) : co; + + for (int i = 0; i < GetSize(co); i++) + ez->SET(yy[i], ez->OR(g[i], ez->AND(p[i], i ? yy[i-1] : ci[0]))); + + if (model_undef) + { + std::vector undef_p = importUndefSigSpec(cell->getPort(ID::P), timestep); + std::vector undef_g = importUndefSigSpec(cell->getPort(ID::G), timestep); + std::vector undef_ci = importUndefSigSpec(cell->getPort(ID::CI), timestep); + std::vector undef_co = importUndefSigSpec(cell->getPort(ID::CO), timestep); + + int undef_any_p = ez->expression(ezSAT::OpOr, undef_p); + int undef_any_g = ez->expression(ezSAT::OpOr, undef_g); + int undef_any_ci = ez->expression(ezSAT::OpOr, undef_ci); + int undef_co_bit = ez->OR(undef_any_p, undef_any_g, undef_any_ci); + + std::vector undef_co_bits(undef_co.size(), undef_co_bit); + ez->assume(ez->vec_eq(undef_co_bits, undef_co)); + + undefGating(co, yy, undef_co); + } + return true; + } + + if (cell->type == ID($alu)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + std::vector x = importDefSigSpec(cell->getPort(ID::X), timestep); + std::vector ci = importDefSigSpec(cell->getPort(ID::CI), timestep); + std::vector bi = importDefSigSpec(cell->getPort(ID::BI), timestep); + std::vector co = importDefSigSpec(cell->getPort(ID::CO), timestep); + + extendSignalWidth(a, b, y, cell); + extendSignalWidth(a, b, x, cell); + extendSignalWidth(a, b, co, cell); + + std::vector def_y = model_undef ? ez->vec_var(y.size()) : y; + std::vector def_x = model_undef ? ez->vec_var(x.size()) : x; + std::vector def_co = model_undef ? ez->vec_var(co.size()) : co; + + log_assert(GetSize(y) == GetSize(x)); + log_assert(GetSize(y) == GetSize(co)); + log_assert(GetSize(ci) == 1); + log_assert(GetSize(bi) == 1); + + for (int i = 0; i < GetSize(y); i++) + { + int s1 = a.at(i), s2 = ez->XOR(b.at(i), bi.at(0)), s3 = i ? co.at(i-1) : ci.at(0); + ez->SET(def_x.at(i), ez->XOR(s1, s2)); + ez->SET(def_y.at(i), ez->XOR(def_x.at(i), s3)); + ez->SET(def_co.at(i), ez->OR(ez->AND(s1, s2), ez->AND(s1, s3), ez->AND(s2, s3))); + } + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_ci = importUndefSigSpec(cell->getPort(ID::CI), timestep); + std::vector undef_bi = importUndefSigSpec(cell->getPort(ID::BI), timestep); + + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + std::vector undef_x = importUndefSigSpec(cell->getPort(ID::X), timestep); + std::vector undef_co = importUndefSigSpec(cell->getPort(ID::CO), timestep); + + extendSignalWidth(undef_a, undef_b, undef_y, cell); + extendSignalWidth(undef_a, undef_b, undef_x, cell); + extendSignalWidth(undef_a, undef_b, undef_co, cell); + + std::vector all_inputs_undef; + all_inputs_undef.insert(all_inputs_undef.end(), undef_a.begin(), undef_a.end()); + all_inputs_undef.insert(all_inputs_undef.end(), undef_b.begin(), undef_b.end()); + all_inputs_undef.insert(all_inputs_undef.end(), undef_ci.begin(), undef_ci.end()); + all_inputs_undef.insert(all_inputs_undef.end(), undef_bi.begin(), undef_bi.end()); + int undef_any = ez->expression(ezSAT::OpOr, all_inputs_undef); + + for (int i = 0; i < GetSize(undef_y); i++) { + ez->SET(undef_y.at(i), undef_any); + ez->SET(undef_x.at(i), ez->OR(undef_a.at(i), undef_b.at(i), undef_bi.at(0))); + ez->SET(undef_co.at(i), undef_any); + } + + undefGating(y, def_y, undef_y); + undefGating(x, def_x, undef_x); + undefGating(co, def_co, undef_co); + } + return true; + } + + if (cell->type == ID($slice)) + { + RTLIL::SigSpec a = cell->getPort(ID::A); + RTLIL::SigSpec y = cell->getPort(ID::Y); + ez->assume(signals_eq(a.extract(cell->parameters.at(ID::OFFSET).as_int(), y.size()), y, timestep)); + return true; + } + + if (cell->type == ID($concat)) + { + RTLIL::SigSpec a = cell->getPort(ID::A); + RTLIL::SigSpec b = cell->getPort(ID::B); + RTLIL::SigSpec y = cell->getPort(ID::Y); + + RTLIL::SigSpec ab = a; + ab.append(b); + + ez->assume(signals_eq(ab, y, timestep)); + return true; + } + + if (timestep > 0 && cell->type.in(ID($ff), ID($dff), ID($_FF_), ID($_DFF_N_), ID($_DFF_P_))) + { + if (timestep == 1) + { + initial_state.add((*sigmap)(cell->getPort(ID::Q))); + } + else + { + std::vector d = importDefSigSpec(cell->getPort(ID::D), timestep-1); + std::vector q = importDefSigSpec(cell->getPort(ID::Q), timestep); + + std::vector qq = model_undef ? ez->vec_var(q.size()) : q; + ez->assume(ez->vec_eq(d, qq)); + + if (model_undef) + { + std::vector undef_d = importUndefSigSpec(cell->getPort(ID::D), timestep-1); + std::vector undef_q = importUndefSigSpec(cell->getPort(ID::Q), timestep); + + ez->assume(ez->vec_eq(undef_d, undef_q)); + undefGating(q, qq, undef_q); + } + } + return true; + } + + if (cell->type == ID($anyconst)) + { + if (timestep < 2) + return true; + + std::vector d = importDefSigSpec(cell->getPort(ID::Y), timestep-1); + std::vector q = importDefSigSpec(cell->getPort(ID::Y), timestep); + + std::vector qq = model_undef ? ez->vec_var(q.size()) : q; + ez->assume(ez->vec_eq(d, qq)); + + if (model_undef) + { + std::vector undef_d = importUndefSigSpec(cell->getPort(ID::Y), timestep-1); + std::vector undef_q = importUndefSigSpec(cell->getPort(ID::Y), timestep); + + ez->assume(ez->vec_eq(undef_d, undef_q)); + undefGating(q, qq, undef_q); + } + return true; + } + + if (cell->type == ID($anyseq)) + { + return true; + } + + if (cell->type.in(ID($_BUF_), ID($equiv))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidthUnary(a, y, cell); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + ez->assume(ez->vec_eq(a, yy)); + + if (model_undef) { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidthUnary(undef_a, undef_y, cell, false); + ez->assume(ez->vec_eq(undef_a, undef_y)); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type == ID($initstate)) + { + auto key = make_pair(prefix, timestep); + if (initstates.count(key) == 0) + initstates[key] = false; + + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + log_assert(GetSize(y) == 1); + ez->SET(y[0], initstates[key] ? ez->CONST_TRUE : ez->CONST_FALSE); + + if (model_undef) { + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + log_assert(GetSize(undef_y) == 1); + ez->SET(undef_y[0], ez->CONST_FALSE); + } + + return true; + } + + if (cell->type == ID($assert)) + { + std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); + asserts_a[pf].append((*sigmap)(cell->getPort(ID::A))); + asserts_en[pf].append((*sigmap)(cell->getPort(ID::EN))); + return true; + } + + if (cell->type == ID($assume)) + { + std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); + assumes_a[pf].append((*sigmap)(cell->getPort(ID::A))); + assumes_en[pf].append((*sigmap)(cell->getPort(ID::EN))); + return true; + } + + // Unsupported internal cell types: $pow $lut + // .. and all sequential cells except $dff and $_DFF_[NP]_ + return false; +} -- cgit v1.2.3