diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/bitpattern.h | 19 | ||||
-rw-r--r-- | kernel/calc.cc | 79 | ||||
-rw-r--r-- | kernel/celltypes.h | 335 | ||||
-rw-r--r-- | kernel/consteval.h | 213 | ||||
-rw-r--r-- | kernel/driver.cc | 655 | ||||
-rw-r--r-- | kernel/log.cc | 199 | ||||
-rw-r--r-- | kernel/log.h | 120 | ||||
-rw-r--r-- | kernel/macc.h | 231 | ||||
-rw-r--r-- | kernel/modtools.h | 455 | ||||
-rw-r--r-- | kernel/register.cc | 263 | ||||
-rw-r--r-- | kernel/register.h | 81 | ||||
-rw-r--r-- | kernel/rtlil.cc | 2351 | ||||
-rw-r--r-- | kernel/rtlil.h | 922 | ||||
-rw-r--r-- | kernel/satgen.h | 641 | ||||
-rw-r--r-- | kernel/sigtools.h | 319 | ||||
-rw-r--r-- | kernel/utils.h | 210 | ||||
-rw-r--r-- | kernel/yosys.cc | 646 | ||||
-rw-r--r-- | kernel/yosys.h | 149 |
18 files changed, 5978 insertions, 1910 deletions
diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h index aaefa50fc..91f54593f 100644 --- a/kernel/bitpattern.h +++ b/kernel/bitpattern.h @@ -31,16 +31,12 @@ struct BitPatternPool BitPatternPool(RTLIL::SigSpec sig) { - width = sig.width; + width = sig.size(); if (width > 0) { std::vector<RTLIL::State> pattern(width); - sig.optimize(); for (int i = 0; i < width; i++) { - RTLIL::SigSpec s = sig.extract(i, 1); - s.optimize(); - assert(s.chunks.size() == 1); - if (s.chunks[0].wire == NULL && s.chunks[0].data.bits[0] <= RTLIL::State::S1) - pattern[i] = s.chunks[0].data.bits[0]; + if (sig[i].wire == NULL && sig[i].data <= RTLIL::State::S1) + pattern[i] = sig[i].data; else pattern[i] = RTLIL::State::Sa; } @@ -61,10 +57,7 @@ struct BitPatternPool bits_t sig2bits(RTLIL::SigSpec sig) { - sig.optimize(); - assert(sig.is_fully_const()); - assert(sig.chunks.size() == 1); - bits_t bits = sig.chunks[0].data.bits; + bits_t bits = sig.as_const().bits; for (auto &b : bits) if (b > RTLIL::State::S1) b = RTLIL::State::Sa; @@ -73,8 +66,8 @@ struct BitPatternPool bool match(bits_t a, bits_t b) { - assert(int(a.size()) == width); - assert(int(b.size()) == width); + log_assert(int(a.size()) == width); + log_assert(int(b.size()) == width); for (int i = 0; i < width; i++) if (a[i] <= RTLIL::State::S1 && b[i] <= RTLIL::State::S1 && a[i] != b[i]) return false; diff --git a/kernel/calc.cc b/kernel/calc.cc index a56db93aa..41179d045 100644 --- a/kernel/calc.cc +++ b/kernel/calc.cc @@ -21,21 +21,10 @@ // Schneier, Bruce (1996). Applied Cryptography: Protocols, Algorithms, and Source Code in C, // Second Edition (2nd ed.). Wiley. ISBN 978-0-471-11709-4, page 244 -#include "kernel/log.h" -#include "kernel/rtlil.h" +#include "kernel/yosys.h" #include "libs/bigint/BigIntegerLibrary.hh" -#include <assert.h> -static void extend(RTLIL::Const &arg, int width, bool is_signed) -{ - RTLIL::State padding = RTLIL::State::S0; - - if (arg.bits.size() > 0 && (is_signed || arg.bits.back() > RTLIL::State::S1)) - padding = arg.bits.back(); - - while (int(arg.bits.size()) < width) - arg.bits.push_back(padding); -} +YOSYS_NAMESPACE_BEGIN static void extend_u0(RTLIL::Const &arg, int width, bool is_signed) { @@ -46,6 +35,8 @@ static void extend_u0(RTLIL::Const &arg, int width, bool is_signed) while (int(arg.bits.size()) < width) arg.bits.push_back(padding); + + arg.bits.resize(width); } static BigInteger const2big(const RTLIL::Const &val, bool as_signed, int &undef_bit_pos) @@ -277,7 +268,7 @@ RTLIL::Const RTLIL::const_logic_or(const RTLIL::Const &arg1, const RTLIL::Const return result; } -static RTLIL::Const const_shift(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, int direction, int result_len) +static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, int direction, int result_len) { int undef_bit_pos = -1; BigInteger offset = const2big(arg2, false, undef_bit_pos) * direction; @@ -305,29 +296,62 @@ static RTLIL::Const const_shift(const RTLIL::Const &arg1, const RTLIL::Const &ar RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len) { RTLIL::Const arg1_ext = arg1; - extend(arg1_ext, result_len, signed1); - return const_shift(arg1_ext, arg2, false, -1, result_len); + extend_u0(arg1_ext, result_len, signed1); + return const_shift_worker(arg1_ext, arg2, false, -1, result_len); } 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(arg1_ext, result_len, signed1); - return const_shift(arg1_ext, arg2, false, +1, result_len); + extend_u0(arg1_ext, std::max(result_len, SIZE(arg1)), signed1); + return const_shift_worker(arg1_ext, arg2, false, +1, result_len); } RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) { if (!signed1) return const_shl(arg1, arg2, signed1, signed2, result_len); - return const_shift(arg1, arg2, true, -1, result_len); + return const_shift_worker(arg1, arg2, true, -1, result_len); } RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) { if (!signed1) return const_shr(arg1, arg2, signed1, signed2, result_len); - return const_shift(arg1, arg2, true, +1, result_len); + return const_shift_worker(arg1, arg2, true, +1, result_len); +} + +static RTLIL::Const const_shift_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool signed2, int result_len, RTLIL::State other_bits) +{ + int undef_bit_pos = -1; + BigInteger offset = const2big(arg2, signed2, undef_bit_pos); + + if (result_len < 0) + result_len = arg1.bits.size(); + + RTLIL::Const result(RTLIL::State::Sx, result_len); + if (undef_bit_pos >= 0) + return result; + + for (int i = 0; i < result_len; i++) { + BigInteger pos = BigInteger(i) + offset; + if (pos < 0 || pos >= arg1.bits.size()) + result.bits[i] = other_bits; + else + result.bits[i] = arg1.bits[pos.toInt()]; + } + + return result; +} + +RTLIL::Const RTLIL::const_shift(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) +{ + return const_shift_shiftx(arg1, arg2, signed1, signed2, result_len, RTLIL::State::S0); +} + +RTLIL::Const RTLIL::const_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) +{ + return const_shift_shiftx(arg1, arg2, signed1, signed2, result_len, RTLIL::State::Sx); } RTLIL::Const RTLIL::const_lt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) @@ -538,14 +562,6 @@ RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2 RTLIL::Const RTLIL::const_pos(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len) { RTLIL::Const arg1_ext = arg1; - extend(arg1_ext, result_len, signed1); - - return arg1_ext; -} - -RTLIL::Const RTLIL::const_bu0(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len) -{ - RTLIL::Const arg1_ext = arg1; extend_u0(arg1_ext, result_len, signed1); return arg1_ext; @@ -554,9 +570,10 @@ RTLIL::Const RTLIL::const_bu0(const RTLIL::Const &arg1, const RTLIL::Const&, boo RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len) { RTLIL::Const arg1_ext = arg1; - extend(arg1_ext, result_len, signed1); - RTLIL::Const zero(RTLIL::State::S0, 1); - return RTLIL::const_sub(zero, arg1_ext, false, signed1, result_len); + + return RTLIL::const_sub(zero, arg1_ext, true, signed1, result_len); } +YOSYS_NAMESPACE_END + diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 34a6e56fa..85c21ef3c 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -20,202 +20,204 @@ #ifndef CELLTYPES_H #define CELLTYPES_H -#include <set> -#include <string> -#include <stdlib.h> +#include <kernel/yosys.h> -#include <kernel/rtlil.h> -#include <kernel/log.h> +YOSYS_NAMESPACE_BEGIN + +struct CellType +{ + RTLIL::IdString type; + std::set<RTLIL::IdString> inputs, outputs; + bool is_evaluable; +}; struct CellTypes { - std::set<std::string> cell_types; - std::vector<const RTLIL::Design*> designs; + std::map<RTLIL::IdString, CellType> cell_types; CellTypes() { } - CellTypes(const RTLIL::Design *design) + CellTypes(RTLIL::Design *design) { setup(design); } - void setup(const RTLIL::Design *design = NULL) + void setup(RTLIL::Design *design = NULL) { if (design) setup_design(design); + setup_internals(); setup_internals_mem(); setup_stdcells(); setup_stdcells_mem(); } - void setup_design(const RTLIL::Design *design) + void setup_type(RTLIL::IdString type, const std::set<RTLIL::IdString> &inputs, const std::set<RTLIL::IdString> &outputs, bool is_evaluable = false) + { + CellType ct = {type, inputs, outputs, is_evaluable}; + cell_types[ct.type] = ct; + } + + void setup_module(RTLIL::Module *module) + { + std::set<RTLIL::IdString> inputs, outputs; + for (RTLIL::IdString wire_name : module->ports) { + RTLIL::Wire *wire = module->wire(wire_name); + if (wire->port_input) + inputs.insert(wire->name); + if (wire->port_output) + outputs.insert(wire->name); + } + setup_type(module->name, inputs, outputs); + } + + void setup_design(RTLIL::Design *design) { - designs.push_back(design); + for (auto module : design->modules()) + setup_module(module); } void setup_internals() { - cell_types.insert("$not"); - cell_types.insert("$pos"); - cell_types.insert("$bu0"); - cell_types.insert("$neg"); - cell_types.insert("$and"); - cell_types.insert("$or"); - cell_types.insert("$xor"); - cell_types.insert("$xnor"); - cell_types.insert("$reduce_and"); - cell_types.insert("$reduce_or"); - cell_types.insert("$reduce_xor"); - cell_types.insert("$reduce_xnor"); - cell_types.insert("$reduce_bool"); - cell_types.insert("$shl"); - cell_types.insert("$shr"); - cell_types.insert("$sshl"); - cell_types.insert("$sshr"); - cell_types.insert("$lt"); - cell_types.insert("$le"); - cell_types.insert("$eq"); - cell_types.insert("$ne"); - cell_types.insert("$eqx"); - cell_types.insert("$nex"); - cell_types.insert("$ge"); - cell_types.insert("$gt"); - cell_types.insert("$add"); - cell_types.insert("$sub"); - cell_types.insert("$mul"); - cell_types.insert("$div"); - cell_types.insert("$mod"); - cell_types.insert("$pow"); - cell_types.insert("$logic_not"); - cell_types.insert("$logic_and"); - cell_types.insert("$logic_or"); - cell_types.insert("$mux"); - cell_types.insert("$pmux"); - cell_types.insert("$slice"); - cell_types.insert("$concat"); - cell_types.insert("$safe_pmux"); - cell_types.insert("$lut"); - cell_types.insert("$assert"); + std::vector<RTLIL::IdString> unary_ops = { + "$not", "$pos", "$neg", + "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", + "$logic_not", "$slice", "$lut" + }; + + std::vector<RTLIL::IdString> binary_ops = { + "$and", "$or", "$xor", "$xnor", + "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", + "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt", + "$add", "$sub", "$mul", "$div", "$mod", "$pow", + "$logic_and", "$logic_or", "$concat", "$macc" + }; + + for (auto type : unary_ops) + setup_type(type, {"\\A"}, {"\\Y"}, true); + + for (auto type : binary_ops) + setup_type(type, {"\\A", "\\B"}, {"\\Y"}, true); + + for (auto type : std::vector<RTLIL::IdString>({"$mux", "$pmux"})) + setup_type(type, {"\\A", "\\B", "\\S"}, {"\\Y"}, true); + + setup_type("$lcu", {"\\P", "\\G", "\\CI"}, {"\\CO"}, true); + setup_type("$alu", {"\\A", "\\B", "\\CI", "\\BI"}, {"\\X", "\\Y", "\\CO"}, true); + setup_type("$fa", {"\\A", "\\B", "\\C"}, {"\\X", "\\Y"}, true); + + setup_type("$assert", {"\\A", "\\EN"}, std::set<RTLIL::IdString>(), true); } void setup_internals_mem() { - cell_types.insert("$sr"); - cell_types.insert("$dff"); - cell_types.insert("$dffsr"); - cell_types.insert("$adff"); - cell_types.insert("$dlatch"); - cell_types.insert("$memrd"); - cell_types.insert("$memwr"); - cell_types.insert("$mem"); - cell_types.insert("$fsm"); + setup_type("$sr", {"\\SET", "\\CLR"}, {"\\Q"}); + setup_type("$dff", {"\\CLK", "\\D"}, {"\\Q"}); + setup_type("$dffsr", {"\\CLK", "\\SET", "\\CLR", "\\D"}, {"\\Q"}); + setup_type("$adff", {"\\CLK", "\\ARST", "\\D"}, {"\\Q"}); + setup_type("$dlatch", {"\\EN", "\\D"}, {"\\Q"}); + setup_type("$dlatchsr", {"\\EN", "\\SET", "\\CLR", "\\D"}, {"\\Q"}); + + setup_type("$memrd", {"\\CLK", "\\ADDR"}, {"\\DATA"}); + setup_type("$memwr", {"\\CLK", "\\EN", "\\ADDR", "\\DATA"}, std::set<RTLIL::IdString>()); + setup_type("$mem", {"\\RD_CLK", "\\RD_ADDR", "\\WR_CLK", "\\WR_EN", "\\WR_ADDR", "\\WR_DATA"}, {"\\RD_DATA"}); + + setup_type("$fsm", {"\\CLK", "\\ARST", "\\CTRL_IN"}, {"\\CTRL_OUT"}); } void setup_stdcells() { - cell_types.insert("$_INV_"); - cell_types.insert("$_AND_"); - cell_types.insert("$_OR_"); - cell_types.insert("$_XOR_"); - cell_types.insert("$_MUX_"); + setup_type("$_NOT_", {"\\A"}, {"\\Y"}, true); + setup_type("$_AND_", {"\\A", "\\B"}, {"\\Y"}, true); + setup_type("$_NAND_", {"\\A", "\\B"}, {"\\Y"}, true); + setup_type("$_OR_", {"\\A", "\\B"}, {"\\Y"}, true); + setup_type("$_NOR_", {"\\A", "\\B"}, {"\\Y"}, true); + setup_type("$_XOR_", {"\\A", "\\B"}, {"\\Y"}, true); + setup_type("$_XNOR_", {"\\A", "\\B"}, {"\\Y"}, true); + setup_type("$_MUX_", {"\\A", "\\B", "\\S"}, {"\\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); } void setup_stdcells_mem() { - cell_types.insert("$_SR_NN_"); - cell_types.insert("$_SR_NP_"); - cell_types.insert("$_SR_PN_"); - cell_types.insert("$_SR_PP_"); - cell_types.insert("$_DFF_N_"); - cell_types.insert("$_DFF_P_"); - cell_types.insert("$_DFF_NN0_"); - cell_types.insert("$_DFF_NN1_"); - cell_types.insert("$_DFF_NP0_"); - cell_types.insert("$_DFF_NP1_"); - cell_types.insert("$_DFF_PN0_"); - cell_types.insert("$_DFF_PN1_"); - cell_types.insert("$_DFF_PP0_"); - cell_types.insert("$_DFF_PP1_"); - cell_types.insert("$_DFFSR_NNN_"); - cell_types.insert("$_DFFSR_NNP_"); - cell_types.insert("$_DFFSR_NPN_"); - cell_types.insert("$_DFFSR_NPP_"); - cell_types.insert("$_DFFSR_PNN_"); - cell_types.insert("$_DFFSR_PNP_"); - cell_types.insert("$_DFFSR_PPN_"); - cell_types.insert("$_DFFSR_PPP_"); - cell_types.insert("$_DLATCH_N_"); - cell_types.insert("$_DLATCH_P_"); + std::vector<char> list_np = {'N', 'P'}, list_01 = {'0', '1'}; + + for (auto c1 : list_np) + for (auto c2 : list_np) + setup_type(stringf("$_SR_%c%c_", c1, c2), {"\\S", "\\R"}, {"\\Q"}); + + for (auto c1 : list_np) + setup_type(stringf("$_DFF_%c_", c1), {"\\C", "\\D"}, {"\\Q"}); + + for (auto c1 : list_np) + for (auto c2 : list_np) + for (auto c3 : list_01) + setup_type(stringf("$_DFF_%c%c%c_", c1, c2, c3), {"\\C", "\\R", "\\D"}, {"\\Q"}); + + for (auto c1 : list_np) + for (auto c2 : list_np) + for (auto c3 : list_np) + setup_type(stringf("$_DFFSR_%c%c%c_", c1, c2, c3), {"\\C", "\\S", "\\R", "\\D"}, {"\\Q"}); + + for (auto c1 : list_np) + setup_type(stringf("$_DLATCH_%c_", c1), {"\\E", "\\D"}, {"\\Q"}); + + for (auto c1 : list_np) + for (auto c2 : list_np) + for (auto c3 : list_np) + setup_type(stringf("$_DLATCHSR_%c%c%c_", c1, c2, c3), {"\\E", "\\S", "\\R", "\\D"}, {"\\Q"}); } void clear() { cell_types.clear(); - designs.clear(); } - bool cell_known(std::string type) + bool cell_known(RTLIL::IdString type) { - if (cell_types.count(type) > 0) - return true; - for (auto design : designs) - if (design->modules.count(type) > 0) - return true; - return false; + return cell_types.count(type) != 0; } - bool cell_output(std::string type, std::string port) + bool cell_output(RTLIL::IdString type, RTLIL::IdString port) { - if (cell_types.count(type) == 0) { - for (auto design : designs) - if (design->modules.count(type) > 0) { - if (design->modules.at(type)->wires.count(port)) - return design->modules.at(type)->wires.at(port)->port_output; - return false; - } - return false; - } - - if (port == "\\Y" || port == "\\Q" || port == "\\RD_DATA") - return true; - if (type == "$memrd" && port == "\\DATA") - return true; - if (type == "$fsm" && port == "\\CTRL_OUT") - return true; - if (type == "$lut" && port == "\\O") - return true; - return false; + auto it = cell_types.find(type); + return it != cell_types.end() && it->second.outputs.count(port) != 0; } - bool cell_input(std::string type, std::string port) + bool cell_input(RTLIL::IdString type, RTLIL::IdString port) { - if (cell_types.count(type) == 0) { - for (auto design : designs) - if (design->modules.count(type) > 0) { - if (design->modules.at(type)->wires.count(port)) - return design->modules.at(type)->wires.at(port)->port_input; - return false; - } - return false; - } + auto it = cell_types.find(type); + return it != cell_types.end() && it->second.inputs.count(port) != 0; + } - if (cell_types.count(type) > 0) - return !cell_output(type, port); + bool cell_evaluable(RTLIL::IdString type) + { + auto it = cell_types.find(type); + return it != cell_types.end() && it->second.is_evaluable; + } - return false; + static RTLIL::Const eval_not(RTLIL::Const v) + { + for (auto &bit : v.bits) + if (bit == RTLIL::S0) bit = RTLIL::S1; + else if (bit == RTLIL::S1) bit = RTLIL::S0; + return v; } - static RTLIL::Const eval(std::string type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) + static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) { if (type == "$sshr" && !signed1) type = "$shr"; if (type == "$sshl" && !signed1) type = "$shl"; - if (type != "$sshr" && type != "$sshl" && type != "$shr" && type != "$shl" && + if (type != "$sshr" && type != "$sshl" && type != "$shr" && type != "$shl" && type != "$shift" && type != "$shiftx" && type != "$pos" && type != "$neg" && type != "$not") { if (!signed1 || !signed2) signed1 = false, signed2 = false; @@ -239,6 +241,8 @@ struct CellTypes HANDLE_CELL_TYPE(shr) HANDLE_CELL_TYPE(sshl) HANDLE_CELL_TYPE(sshr) + HANDLE_CELL_TYPE(shift) + HANDLE_CELL_TYPE(shiftx) HANDLE_CELL_TYPE(lt) HANDLE_CELL_TYPE(le) HANDLE_CELL_TYPE(eq) @@ -254,18 +258,23 @@ struct CellTypes HANDLE_CELL_TYPE(mod) HANDLE_CELL_TYPE(pow) HANDLE_CELL_TYPE(pos) - HANDLE_CELL_TYPE(bu0) HANDLE_CELL_TYPE(neg) #undef HANDLE_CELL_TYPE - if (type == "$_INV_") - return const_not(arg1, arg2, false, false, 1); + if (type == "$_NOT_") + return eval_not(arg1); if (type == "$_AND_") return const_and(arg1, arg2, false, false, 1); + if (type == "$_NAND_") + return eval_not(const_and(arg1, arg2, false, false, 1)); if (type == "$_OR_") return const_or(arg1, arg2, false, false, 1); + if (type == "$_NOR_") + return eval_not(const_and(arg1, arg2, false, false, 1)); if (type == "$_XOR_") return const_xor(arg1, arg2, false, false, 1); + if (type == "$_XNOR_") + return const_xnor(arg1, arg2, false, false, 1); log_abort(); } @@ -286,28 +295,72 @@ struct CellTypes return ret; } + if (cell->type == "$lut") + { + int width = cell->parameters.at("\\WIDTH").as_int(); + + std::vector<RTLIL::State> t = cell->parameters.at("\\LUT").bits; + while (SIZE(t) < (1 << width)) + t.push_back(RTLIL::S0); + t.resize(1 << width); + + for (int i = width-1; i >= 0; i--) { + RTLIL::State sel = arg1.bits.at(i); + std::vector<RTLIL::State> new_t; + if (sel == RTLIL::S0) + new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + SIZE(t)/2); + else if (sel == RTLIL::S1) + new_t = std::vector<RTLIL::State>(t.begin() + SIZE(t)/2, t.end()); + else + for (int j = 0; j < SIZE(t)/2; j++) + new_t.push_back(t[j] == t[j + SIZE(t)/2] ? t[j] : RTLIL::Sx); + t.swap(new_t); + } + + log_assert(SIZE(t) == 1); + return t; + } + bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool(); bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool(); int result_len = cell->parameters.count("\\Y_WIDTH") > 0 ? cell->parameters["\\Y_WIDTH"].as_int() : -1; return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len); } - static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &sel) + static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3) { - if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_") { + if (cell->type.in("$mux", "$pmux", "$_MUX_")) { RTLIL::Const ret = arg1; - for (size_t i = 0; i < sel.bits.size(); i++) - if (sel.bits[i] == RTLIL::State::S1) { + for (size_t i = 0; i < arg3.bits.size(); i++) + if (arg3.bits[i] == RTLIL::State::S1) { std::vector<RTLIL::State> bits(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size()); ret = RTLIL::Const(bits); } return ret; } - assert(sel.bits.size() == 0); + if (cell->type == "$_AOI3_") + return eval_not(const_or(const_and(arg1, arg2, false, false, 1), arg3, false, false, 1)); + if (cell->type == "$_OAI3_") + return eval_not(const_and(const_or(arg1, arg2, false, false, 1), arg3, false, false, 1)); + + log_assert(arg3.bits.size() == 0); return eval(cell, arg1, arg2); } + + static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4) + { + if (cell->type == "$_AOI4_") + return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1)); + if (cell->type == "$_OAI4_") + return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1)); + + log_assert(arg4.bits.size() == 0); + return eval(cell, arg1, arg2, arg3); + } }; +YOSYS_NAMESPACE_END + #endif diff --git a/kernel/consteval.h b/kernel/consteval.h index 10116ccfe..2d29d3f7e 100644 --- a/kernel/consteval.h +++ b/kernel/consteval.h @@ -23,6 +23,7 @@ #include "kernel/rtlil.h" #include "kernel/sigtools.h" #include "kernel/celltypes.h" +#include "kernel/macc.h" struct ConstEval { @@ -40,10 +41,10 @@ struct ConstEval ct.setup_internals(); ct.setup_stdcells(); - for (auto &it : module->cells) { + for (auto &it : module->cells_) { if (!ct.cell_known(it.second->type)) continue; - for (auto &it2 : it.second->connections) + for (auto &it2 : it.second->connections()) if (ct.cell_output(it.second->type, it2.first)) sig2driver.insert(assign_map(it2.second), it.second); } @@ -71,11 +72,8 @@ struct ConstEval assign_map.apply(sig); #ifndef NDEBUG RTLIL::SigSpec current_val = values_map(sig); - current_val.expand(); - for (size_t i = 0; i < current_val.chunks.size(); i++) { - RTLIL::SigChunk &chunk = current_val.chunks[i]; - assert(chunk.wire != NULL || chunk.data.bits[0] == value.bits[i]); - } + for (int i = 0; i < SIZE(current_val); i++) + log_assert(current_val[i].wire != NULL || current_val[i] == value.bits[i]); #endif values_map.add(sig, RTLIL::SigSpec(value)); } @@ -88,35 +86,72 @@ struct ConstEval bool eval(RTLIL::Cell *cell, RTLIL::SigSpec &undef) { + if (cell->type == "$lcu") + { + RTLIL::SigSpec sig_p = cell->getPort("\\P"); + RTLIL::SigSpec sig_g = cell->getPort("\\G"); + RTLIL::SigSpec sig_ci = cell->getPort("\\CI"); + RTLIL::SigSpec sig_co = values_map(assign_map(cell->getPort("\\CO"))); + + if (sig_co.is_fully_const()) + return true; + + if (!eval(sig_p, undef, cell)) + return false; + + if (!eval(sig_g, undef, cell)) + return false; + + if (!eval(sig_ci, undef, cell)) + return false; + + if (sig_p.is_fully_def() && sig_g.is_fully_def() && sig_ci.is_fully_def()) + { + RTLIL::Const coval(RTLIL::Sx, SIZE(sig_co)); + bool carry = sig_ci.as_bool(); + + for (int i = 0; i < SIZE(coval); i++) { + carry = (sig_g[i] == RTLIL::S1) || (sig_p[i] == RTLIL::S1 && carry); + coval.bits[i] = carry ? RTLIL::S1 : RTLIL::S0; + } + + set(sig_co, coval); + } + else + set(sig_co, RTLIL::Const(RTLIL::Sx, SIZE(sig_co))); + + return true; + } + RTLIL::SigSpec sig_a, sig_b, sig_s, sig_y; - assert(cell->connections.count("\\Y") > 0); - sig_y = values_map(assign_map(cell->connections["\\Y"])); + log_assert(cell->hasPort("\\Y")); + sig_y = values_map(assign_map(cell->getPort("\\Y"))); if (sig_y.is_fully_const()) return true; - if (cell->connections.count("\\S") > 0) { - sig_s = cell->connections["\\S"]; + if (cell->hasPort("\\S")) { + sig_s = cell->getPort("\\S"); if (!eval(sig_s, undef, cell)) return false; } - if (cell->connections.count("\\A") > 0) - sig_a = cell->connections["\\A"]; + if (cell->hasPort("\\A")) + sig_a = cell->getPort("\\A"); - if (cell->connections.count("\\B") > 0) - sig_b = cell->connections["\\B"]; + if (cell->hasPort("\\B")) + sig_b = cell->getPort("\\B"); - if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_") + if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$_MUX_") { std::vector<RTLIL::SigSpec> y_candidates; int count_maybe_set_s_bits = 0; int count_set_s_bits = 0; - for (int i = 0; i < sig_s.width; i++) + for (int i = 0; i < sig_s.size(); i++) { RTLIL::State s_bit = sig_s.extract(i, 1).as_const().bits.at(0); - RTLIL::SigSpec b_slice = sig_b.extract(sig_y.width*i, sig_y.width); + RTLIL::SigSpec b_slice = sig_b.extract(sig_y.size()*i, sig_y.size()); if (s_bit == RTLIL::State::Sx || s_bit == RTLIL::State::S1) y_candidates.push_back(b_slice); @@ -128,15 +163,12 @@ struct ConstEval count_set_s_bits++; } - if (cell->type == "$safe_pmux" && count_set_s_bits > 1) - y_candidates.clear(); - - if ((cell->type == "$safe_pmux" && count_maybe_set_s_bits > 1) || count_set_s_bits == 0) + if (count_set_s_bits == 0) y_candidates.push_back(sig_a); std::vector<RTLIL::Const> y_values; - assert(y_candidates.size() > 0); + log_assert(y_candidates.size() > 0); for (auto &yc : y_candidates) { if (!eval(yc, undef, cell)) return false; @@ -149,7 +181,7 @@ struct ConstEval for (size_t i = 1; i < y_values.size(); i++) { std::vector<RTLIL::State> &slave_bits = y_values.at(i).bits; - assert(master_bits.size() == slave_bits.size()); + log_assert(master_bits.size() == slave_bits.size()); for (size_t j = 0; j < master_bits.size(); j++) if (master_bits[j] != slave_bits[j]) master_bits[j] = RTLIL::State::Sx; @@ -160,13 +192,134 @@ struct ConstEval else set(sig_y, y_values.front()); } + else if (cell->type == "$fa") + { + RTLIL::SigSpec sig_c = cell->getPort("\\C"); + RTLIL::SigSpec sig_x = cell->getPort("\\X"); + int width = SIZE(sig_c); + + if (!eval(sig_a, undef, cell)) + return false; + + if (!eval(sig_b, undef, cell)) + return false; + + if (!eval(sig_c, undef, cell)) + return false; + + RTLIL::Const t1 = const_xor(sig_a.as_const(), sig_b.as_const(), false, false, width); + RTLIL::Const val_y = const_xor(t1, sig_c.as_const(), false, false, width); + + RTLIL::Const t2 = const_and(sig_a.as_const(), sig_b.as_const(), false, false, width); + RTLIL::Const t3 = const_and(sig_c.as_const(), t1, false, false, width); + RTLIL::Const val_x = const_or(t2, t3, false, false, width); + + for (int i = 0; i < SIZE(val_y); i++) + if (val_y.bits[i] == RTLIL::Sx) + val_x.bits[i] = RTLIL::Sx; + + set(sig_y, val_y); + set(sig_x, val_x); + } + else if (cell->type == "$alu") + { + 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(); + + RTLIL::SigSpec sig_ci = cell->getPort("\\CI"); + RTLIL::SigSpec sig_bi = cell->getPort("\\BI"); + + if (!eval(sig_a, undef, cell)) + return false; + + if (!eval(sig_b, undef, cell)) + return false; + + if (!eval(sig_ci, undef, cell)) + return false; + + if (!eval(sig_bi, undef, cell)) + return false; + + RTLIL::SigSpec sig_x = cell->getPort("\\X"); + RTLIL::SigSpec sig_co = cell->getPort("\\CO"); + + bool any_input_undef = !(sig_a.is_fully_def() && sig_b.is_fully_def() && sig_ci.is_fully_def() && sig_bi.is_fully_def()); + sig_a.extend_u0(SIZE(sig_y), signed_a); + sig_b.extend_u0(SIZE(sig_y), signed_b); + + bool carry = sig_ci[0] == RTLIL::S1; + bool b_inv = sig_bi[0] == RTLIL::S1; + + for (int i = 0; i < SIZE(sig_y); i++) + { + RTLIL::SigSpec x_inputs = { sig_a[i], sig_b[i], sig_bi[0] }; + + if (!x_inputs.is_fully_def()) { + set(sig_x[i], RTLIL::Sx); + } else { + bool bit_a = sig_a[i] == RTLIL::S1; + bool bit_b = (sig_b[i] == RTLIL::S1) != b_inv; + bool bit_x = bit_a != bit_b; + set(sig_x[i], bit_x ? RTLIL::S1 : RTLIL::S0); + } + + if (any_input_undef) { + set(sig_y[i], RTLIL::Sx); + set(sig_co[i], RTLIL::Sx); + } else { + bool bit_a = sig_a[i] == RTLIL::S1; + bool bit_b = (sig_b[i] == RTLIL::S1) != b_inv; + bool bit_y = (bit_a != bit_b) != carry; + carry = (bit_a && bit_b) || (bit_a && carry) || (bit_b && carry); + set(sig_y[i], bit_y ? RTLIL::S1 : RTLIL::S0); + set(sig_co[i], carry ? RTLIL::S1 : RTLIL::S0); + } + } + } + else if (cell->type == "$macc") + { + Macc macc; + macc.from_cell(cell); + + if (!eval(macc.bit_ports, undef, cell)) + return false; + + for (auto &port : macc.ports) { + if (!eval(port.in_a, undef, cell)) + return false; + if (!eval(port.in_b, undef, cell)) + return false; + } + + RTLIL::Const result(0, SIZE(cell->getPort("\\Y"))); + if (!macc.eval(result)) + log_abort(); + + set(cell->getPort("\\Y"), result); + } else { - if (sig_a.width > 0 && !eval(sig_a, undef, cell)) + RTLIL::SigSpec sig_c, sig_d; + + if (cell->type.in("$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_")) { + if (cell->hasPort("\\C")) + sig_c = cell->getPort("\\C"); + if (cell->hasPort("\\D")) + sig_d = cell->getPort("\\D"); + } + + if (sig_a.size() > 0 && !eval(sig_a, undef, cell)) + return false; + if (sig_b.size() > 0 && !eval(sig_b, undef, cell)) return false; - if (sig_b.width > 0 && !eval(sig_b, undef, cell)) + if (sig_c.size() > 0 && !eval(sig_c, undef, cell)) return false; - set(sig_y, CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const())); + if (sig_d.size() > 0 && !eval(sig_d, undef, cell)) + return false; + + set(sig_y, CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), + sig_c.as_const(), sig_d.as_const())); } return true; @@ -210,9 +363,9 @@ struct ConstEval if (sig.is_fully_const()) return true; - for (size_t i = 0; i < sig.chunks.size(); i++) - if (sig.chunks[i].wire != NULL) - undef.append(sig.chunks[i]); + for (auto &c : sig.chunks()) + if (c.wire != NULL) + undef.append(c); return false; } diff --git a/kernel/driver.cc b/kernel/driver.cc index 00a61ec0f..f26d9ef82 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -17,464 +17,38 @@ * */ +#include "kernel/yosys.h" +#include "libs/sha1/sha1.h" + +#ifdef YOSYS_ENABLE_READLINE +# include <readline/readline.h> +# include <readline/history.h> +#endif + #include <stdio.h> -#include <readline/readline.h> -#include <readline/history.h> #include <string.h> #include <unistd.h> #include <libgen.h> -#include <dlfcn.h> - -#include <algorithm> - -#include "kernel/rtlil.h" -#include "kernel/register.h" -#include "kernel/log.h" - -bool fgetline(FILE *f, std::string &buffer) -{ - buffer = ""; - char block[4096]; - while (1) { - if (fgets(block, 4096, f) == NULL) - return false; - buffer += block; - if (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) { - while (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) - buffer.resize(buffer.size()-1); - return true; - } - } -} - -static void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command) -{ - if (command == "auto") { - if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v") - command = "verilog"; - else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") - command = "ilang"; - else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys") - command = "script"; - else if (filename == "-") - command = "script"; - else - log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str()); - } - - if (command == "script") { - log("\n-- Executing script file `%s' --\n", filename.c_str()); - FILE *f = stdin; - if (filename != "-") - f = fopen(filename.c_str(), "r"); - if (f == NULL) - log_error("Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno)); - std::string command; - while (fgetline(f, command)) { - while (!command.empty() && command[command.size()-1] == '\\') { - std::string next_line; - if (!fgetline(f, next_line)) - break; - command.resize(command.size()-1); - command += next_line; - } - Pass::call(design, command); - } - if (!command.empty()) - Pass::call(design, command); - if (filename != "-") - fclose(f); - if (backend_command != NULL && *backend_command == "auto") - *backend_command = ""; - return; - } - - if (filename == "-") { - log("\n-- Parsing stdin using frontend `%s' --\n", command.c_str()); - } else { - log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str()); - } - - Frontend::frontend_call(design, NULL, filename, command); -} - -static void run_pass(std::string command, RTLIL::Design *design) -{ - log("\n-- Running pass `%s' --\n", command.c_str()); - - Pass::call(design, command); -} - -static void run_backend(std::string filename, std::string command, RTLIL::Design *design) -{ - if (command == "auto") { - if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v") - command = "verilog"; - else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") - command = "ilang"; - else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif") - command = "blif"; - else if (filename == "-") - command = "ilang"; - else if (filename.empty()) - return; - else - log_error("Can't guess backend for output file `%s' (missing -b option)!\n", filename.c_str()); - } - - if (filename.empty()) - filename = "-"; - - if (filename == "-") { - log("\n-- Writing to stdout using backend `%s' --\n", command.c_str()); - } else { - log("\n-- Writing to `%s' using backend `%s' --\n", filename.c_str(), command.c_str()); - } - - Backend::backend_call(design, NULL, filename, command); -} - -static char *readline_cmd_generator(const char *text, int state) -{ - static std::map<std::string, Pass*>::iterator it; - static int len; - - if (!state) { - it = REGISTER_INTERN::pass_register.begin(); - len = strlen(text); - } - - for (; it != REGISTER_INTERN::pass_register.end(); it++) { - if (it->first.substr(0, len) == text) - return strdup((it++)->first.c_str()); - } - return NULL; -} - -static char *readline_obj_generator(const char *text, int state) -{ - static std::vector<char*> obj_names; - static size_t idx; - - if (!state) - { - idx = 0; - obj_names.clear(); - - RTLIL::Design *design = yosys_get_design(); - int len = strlen(text); - - if (design->selected_active_module.empty()) - { - for (auto &it : design->modules) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) - obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str()))); - } - else - if (design->modules.count(design->selected_active_module) > 0) - { - RTLIL::Module *module = design->modules.at(design->selected_active_module); - - for (auto &it : module->wires) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) - obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str()))); - - for (auto &it : module->memories) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) - obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str()))); - - for (auto &it : module->cells) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) - obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str()))); - - for (auto &it : module->processes) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) - obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str()))); - } - - std::sort(obj_names.begin(), obj_names.end()); - } - - if (idx < obj_names.size()) - return strdup(obj_names[idx++]); - - idx = 0; - obj_names.clear(); - return NULL; -} - -static char **readline_completion(const char *text, int start, int) -{ - if (start == 0) - return rl_completion_matches(text, readline_cmd_generator); - if (strncmp(rl_line_buffer, "read_", 5) && strncmp(rl_line_buffer, "write_", 6)) - return rl_completion_matches(text, readline_obj_generator); - return NULL; -} - -const char *create_prompt(RTLIL::Design *design, int recursion_counter) -{ - static char buffer[100]; - std::string str = "\n"; - if (recursion_counter > 1) - str += stringf("(%d) ", recursion_counter); - str += "yosys"; - if (!design->selected_active_module.empty()) - str += stringf(" [%s]", RTLIL::id2cstr(design->selected_active_module)); - if (!design->selection_stack.back().full_selection) { - if (design->selected_active_module.empty()) - str += "*"; - else if (design->selection_stack.back().selected_modules.size() != 1 || design->selection_stack.back().selected_members.size() != 0 || - design->selection_stack.back().selected_modules.count(design->selected_active_module) == 0) - str += "*"; - } - snprintf(buffer, 100, "%s> ", str.c_str()); - return buffer; -} - -static void shell(RTLIL::Design *design) -{ - static int recursion_counter = 0; - - recursion_counter++; - log_cmd_error_throw = true; - - rl_readline_name = "yosys"; - rl_attempted_completion_function = readline_completion; - rl_basic_word_break_characters = " \t\n"; - - char *command = NULL; - while ((command = readline(create_prompt(design, recursion_counter))) != NULL) - { - if (command[strspn(command, " \t\r\n")] == 0) - continue; - add_history(command); - - char *p = command + strspn(command, " \t\r\n"); - if (!strncmp(p, "exit", 4)) { - p += 4; - p += strspn(p, " \t\r\n"); - if (*p == 0) - break; - } - - try { - assert(design->selection_stack.size() == 1); - Pass::call(design, command); - } catch (int) { - while (design->selection_stack.size() > 1) - design->selection_stack.pop_back(); - log_reset_stack(); - } - } - if (command == NULL) - printf("exit\n"); - - recursion_counter--; - log_cmd_error_throw = false; -} - -struct ShellPass : public Pass { - ShellPass() : Pass("shell", "enter interactive command mode") { } - virtual void help() { - log("\n"); - log(" shell\n"); - log("\n"); - log("This command enters the interactive command mode. This can be useful\n"); - log("in a script to interrupt the script at a certain point and allow for\n"); - log("interactive inspection or manual synthesis of the design at this point.\n"); - log("\n"); - log("The command prompt of the interactive shell indicates the current\n"); - log("selection (see 'help select'):\n"); - log("\n"); - log(" yosys>\n"); - log(" the entire design is selected\n"); - log("\n"); - log(" yosys*>\n"); - log(" only part of the design is selected\n"); - log("\n"); - log(" yosys [modname]>\n"); - log(" the entire module 'modname' is selected using 'select -module modname'\n"); - log("\n"); - log(" yosys [modname]*>\n"); - log(" only part of current module 'modname' is selected\n"); - log("\n"); - log("When in interactive shell, some errors (e.g. invalid command arguments)\n"); - log("do not terminate yosys but return to the command prompt.\n"); - log("\n"); - log("This command is the default action if nothing else has been specified\n"); - log("on the command line.\n"); - log("\n"); - log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n"); - log("\n"); - } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - extra_args(args, 1, design, false); - shell(design); - } -} ShellPass; - -struct HistoryPass : public Pass { - HistoryPass() : Pass("history", "show last interactive commands") { } - virtual void help() { - log("\n"); - log(" history\n"); - log("\n"); - log("This command prints all commands in the shell history buffer. This are\n"); - log("all commands executed in an interactive session, but not the commands\n"); - log("from executed scripts.\n"); - log("\n"); - } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - extra_args(args, 1, design, false); - for(HIST_ENTRY **list = history_list(); *list != NULL; list++) - log("%s\n", (*list)->line); - } -} HistoryPass; - -struct ScriptPass : public Pass { - ScriptPass() : Pass("script", "execute commands from script file") { } - virtual void help() { - log("\n"); - log(" script <filename>\n"); - log("\n"); - log("This command executes the yosys commands in the specified file.\n"); - log("\n"); - } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - if (args.size() < 2) - log_cmd_error("Missing script file.\n"); - if (args.size() > 2) - extra_args(args, 1, design, false); - run_frontend(args[1], "script", design, NULL); - } -} ScriptPass; - -#ifdef YOSYS_ENABLE_TCL -static Tcl_Interp *yosys_tcl_interp = NULL; - -static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[]) -{ - std::vector<std::string> args; - for (int i = 1; i < argc; i++) - args.push_back(argv[i]); - - if (args.size() >= 1 && args[0] == "-import") { - for (auto &it : REGISTER_INTERN::pass_register) { - std::string tcl_command_name = it.first; - if (tcl_command_name == "proc") - tcl_command_name = "procs"; - Tcl_CmdInfo info; - if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) { - log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str()); - } else { - std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str()); - Tcl_Eval(interp, tcl_script.c_str()); - } - } - return TCL_OK; - } - - if (args.size() == 1) { - Pass::call(yosys_get_design(), args[0]); - return TCL_OK; - } - - Pass::call(yosys_get_design(), args); - return TCL_OK; -} +#include <limits.h> +#include <errno.h> -extern Tcl_Interp *yosys_get_tcl_interp() -{ - if (yosys_tcl_interp == NULL) { - yosys_tcl_interp = Tcl_CreateInterp(); - Tcl_CreateCommand(yosys_tcl_interp, "yosys", tcl_yosys_cmd, NULL, NULL); - } - return yosys_tcl_interp; -} - -struct TclPass : public Pass { - TclPass() : Pass("tcl", "execute a TCL script file") { } - virtual void help() { - log("\n"); - log(" tcl <filename>\n"); - log("\n"); - log("This command executes the tcl commands in the specified file.\n"); - log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n"); - log("\n"); - 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("\n"); - } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - if (args.size() < 2) - log_cmd_error("Missing script file.\n"); - if (args.size() > 2) - extra_args(args, 1, design, false); - if (Tcl_EvalFile(yosys_get_tcl_interp(), args[1].c_str()) != TCL_OK) - log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp())); - } -} TclPass; -#endif - -static RTLIL::Design *yosys_design = NULL; - -extern RTLIL::Design *yosys_get_design() -{ - return yosys_design; -} - -std::string rewrite_yosys_exe(std::string exe) -{ - char buffer[1024]; - ssize_t buflen = readlink("/proc/self/exe", buffer, sizeof(buffer)-1); - - if (buflen < 0) - return exe; - - buffer[buflen] = 0; - std::string newexe = stringf("%s/%s", dirname(buffer), exe.c_str()); - if (access(newexe.c_str(), X_OK) == 0) - return newexe; - - return exe; -} - -std::string get_share_file_name(std::string file) -{ - char buffer[1024]; - ssize_t buflen = readlink("/proc/self/exe", buffer, sizeof(buffer)-1); - - if (buflen < 0) - log_error("Can't find file `%s': reading of /proc/self/exe failed!\n", file.c_str()); - - buffer[buflen] = 0; - const char *dir = dirname(buffer); - - std::string newfile_inplace = stringf("%s/share/%s", dir, file.c_str()); - if (access(newfile_inplace.c_str(), F_OK) == 0) - return newfile_inplace; - - std::string newfile_system = stringf("%s/../share/yosys/%s", dir, file.c_str()); - if (access(newfile_system.c_str(), F_OK) == 0) - return newfile_system; - - log_error("Can't find file `%s': no `%s' and no `%s' found!\n", file.c_str(), newfile_inplace.c_str(), newfile_system.c_str()); -} +USING_YOSYS_NAMESPACE int main(int argc, char **argv) { std::string frontend_command = "auto"; std::string backend_command = "auto"; std::vector<std::string> passes_commands; - std::vector<void*> loaded_modules; + std::vector<std::string> plugin_filenames; std::string output_filename = ""; std::string scriptfile = ""; bool scriptfile_tcl = false; bool got_output_filename = false; + bool print_banner = true; + bool print_stats = true; + bool call_abort = false; +#ifdef YOSYS_ENABLE_READLINE int history_offset = 0; std::string history_file; if (getenv("HOME") != NULL) { @@ -482,30 +56,30 @@ int main(int argc, char **argv) read_history(history_file.c_str()); history_offset = where_history(); } +#endif int opt; - while ((opt = getopt(argc, argv, "VSm:f:Hh:b:o:p:l:qv:ts:c:")) != -1) + while ((opt = getopt(argc, argv, "AQTVSm:f:Hh:b:o:p:l:qv:ts:c:")) != -1) { switch (opt) { + case 'A': + call_abort = true; + break; + case 'Q': + print_banner = false; + break; + case 'T': + print_stats = false; + break; case 'V': printf("%s\n", yosys_version_str); exit(0); case 'S': - passes_commands.push_back("hierarchy"); - passes_commands.push_back("proc"); - passes_commands.push_back("opt"); - passes_commands.push_back("memory"); - passes_commands.push_back("opt"); - passes_commands.push_back("techmap"); - passes_commands.push_back("opt"); + passes_commands.push_back("synth"); break; case 'm': - loaded_modules.push_back(dlopen(optarg, RTLD_LAZY|RTLD_GLOBAL)); - if (loaded_modules.back() == NULL) { - fprintf(stderr, "Can't load module `%s': %s\n", optarg, dlerror()); - exit(1); - } + plugin_filenames.push_back(optarg); break; case 'f': frontend_command = optarg; @@ -553,9 +127,15 @@ int main(int argc, char **argv) break; default: fprintf(stderr, "\n"); - fprintf(stderr, "Usage: %s [-V] [-S] [-q] [-v <level>[-t] [-l <logfile>] [-o <outfile>] [-f <frontend>] [-h cmd] \\\n", argv[0]); + fprintf(stderr, "Usage: %s [-V -S -Q -T -q] [-v <level>[-t] [-l <logfile>] [-o <outfile>] [-f <frontend>] [-h cmd] \\\n", argv[0]); fprintf(stderr, " %*s[{-s|-c} <scriptfile>] [-p <pass> [-p ..]] [-b <backend>] [-m <module_file>] [<infile> [..]]\n", int(strlen(argv[0])+1), ""); fprintf(stderr, "\n"); + fprintf(stderr, " -Q\n"); + fprintf(stderr, " suppress printing of banner (copyright, disclaimer, version)\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " -T\n"); + fprintf(stderr, " suppress printing of footer (log hash, version, timing statistics)\n"); + fprintf(stderr, "\n"); fprintf(stderr, " -q\n"); fprintf(stderr, " quiet operation. only write error messages to console\n"); fprintf(stderr, "\n"); @@ -595,13 +175,16 @@ int main(int argc, char **argv) fprintf(stderr, " -m module_file\n"); fprintf(stderr, " load the specified module (aka plugin)\n"); fprintf(stderr, "\n"); + fprintf(stderr, " -A\n"); + fprintf(stderr, " will call abort() at the end of the script. useful for debugging\n"); + fprintf(stderr, "\n"); fprintf(stderr, " -V\n"); fprintf(stderr, " print version information and exit\n"); fprintf(stderr, "\n"); - fprintf(stderr, "The option -S is an alias for the following options that perform a simple\n"); - fprintf(stderr, "transformation of the input to a gate-level netlist.\n"); + fprintf(stderr, "The option -S is an shortcut for calling the \"synth\" command, a default\n"); + fprintf(stderr, "script for transforming the verilog input to a gate-level netlist. For example:\n"); fprintf(stderr, "\n"); - fprintf(stderr, " -p hierarchy -p proc -p opt -p memory -p opt -p techmap -p opt\n"); + fprintf(stderr, " yosys -o output.blif -S input.v\n"); fprintf(stderr, "\n"); fprintf(stderr, "For more complex synthesis jobs it is recommended to use the read_* and write_*\n"); fprintf(stderr, "commands in a script file instead of specifying input and output files on the\n"); @@ -618,35 +201,39 @@ int main(int argc, char **argv) if (log_errfile == NULL) log_files.push_back(stderr); - log("\n"); - log(" /-----------------------------------------------------------------------------\\\n"); - log(" | |\n"); - log(" | yosys -- Yosys Open SYnthesis Suite |\n"); - log(" | |\n"); - log(" | Copyright (C) 2012 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"); - log(" | copyright notice and this permission notice appear in all copies. |\n"); - log(" | |\n"); - log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n"); - log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n"); - log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n"); - log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n"); - log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n"); - log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n"); - log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n"); - log(" | |\n"); - log(" \\-----------------------------------------------------------------------------/\n"); - log("\n"); - log(" %s\n", yosys_version_str); - log("\n"); - - Pass::init_register(); - - yosys_design = new RTLIL::Design; - yosys_design->selection_stack.push_back(RTLIL::Selection()); - log_push(); + if (print_banner) { + log("\n"); + log(" /-----------------------------------------------------------------------------\\\n"); + log(" | |\n"); + log(" | yosys -- Yosys Open SYnthesis Suite |\n"); + log(" | |\n"); + log(" | Copyright (C) 2012 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"); + log(" | copyright notice and this permission notice appear in all copies. |\n"); + log(" | |\n"); + log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n"); + log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n"); + log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n"); + log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n"); + log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n"); + log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n"); + log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n"); + log(" | |\n"); + log(" \\-----------------------------------------------------------------------------/\n"); + log("\n"); + log(" %s\n", yosys_version_str); + log("\n"); + } + + if (print_stats) + log_hasher = new SHA1; + + yosys_setup(); + + for (auto &fn : plugin_filenames) + load_plugin(fn, {}); if (optind == argc && passes_commands.size() == 0 && scriptfile.empty()) { if (!got_output_filename) @@ -655,7 +242,7 @@ int main(int argc, char **argv) } while (optind < argc) - run_frontend(argv[optind++], frontend_command, yosys_design, output_filename == "-" ? &backend_command : NULL); + run_frontend(argv[optind++], frontend_command, yosys_design, output_filename == "-" ? &backend_command : NULL, NULL); if (!scriptfile.empty()) { if (scriptfile_tcl) { @@ -666,7 +253,7 @@ int main(int argc, char **argv) log_error("Can't exectue TCL script: this version of yosys is not built with TCL support enabled.\n"); #endif } else - run_frontend(scriptfile, "script", yosys_design, output_filename == "-" ? &backend_command : NULL); + run_frontend(scriptfile, "script", yosys_design, output_filename == "-" ? &backend_command : NULL, NULL); } for (auto it = passes_commands.begin(); it != passes_commands.end(); it++) @@ -675,12 +262,72 @@ int main(int argc, char **argv) if (!backend_command.empty()) run_backend(output_filename, backend_command, yosys_design); - delete yosys_design; - yosys_design = NULL; + if (print_stats) + { + std::string hash = log_hasher->final().substr(0, 10); + delete log_hasher; + log_hasher = nullptr; + + struct rusage ru_buffer; + getrusage(RUSAGE_SELF, &ru_buffer); + log_spacer(); + log("End of script. Logfile hash: %s, CPU: user %.2fs system %.2fs\n", hash.c_str(), + ru_buffer.ru_utime.tv_sec + 1e-6 * ru_buffer.ru_utime.tv_usec, + ru_buffer.ru_stime.tv_sec + 1e-6 * ru_buffer.ru_stime.tv_usec); + log("%s\n", yosys_version_str); + + int64_t total_ns = 0; + std::set<std::tuple<int64_t, int, std::string>> timedat; + + for (auto &it : pass_register) + if (it.second->call_counter) { + total_ns += it.second->runtime_ns + 1; + timedat.insert(make_tuple(it.second->runtime_ns + 1, it.second->call_counter, it.first)); + } + + int out_count = 0; + log("Time spent:"); + for (auto it = timedat.rbegin(); it != timedat.rend() && out_count < 4; it++, out_count++) { + if (out_count >= 2 && (std::get<0>(*it) < 1000000000 || int(100*std::get<0>(*it) / total_ns) < 20)) { + log(", ..."); + break; + } + log("%s %d%% %dx %s (%d sec)", out_count ? "," : "", int(100*std::get<0>(*it) / total_ns), + std::get<1>(*it), std::get<2>(*it).c_str(), int(std::get<0>(*it) / 1000000000)); + } + log("%s\n", out_count ? "" : " no commands executed"); + } + +#ifdef COVER_ACTIVE + if (getenv("YOSYS_COVER_DIR") || getenv("YOSYS_COVER_FILE")) + { + char filename_buffer[4096]; + FILE *f; + + if (getenv("YOSYS_COVER_DIR")) { + snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", getenv("YOSYS_COVER_DIR"), getpid()); + f = fdopen(mkstemps(filename_buffer, 4), "w"); + } else { + snprintf(filename_buffer, 4096, "%s", getenv("YOSYS_COVER_FILE")); + f = fopen(filename_buffer, "a+"); + } + + if (f == NULL) + log_error("Can't create coverage file `%s'.\n", filename_buffer); + + log("<writing coverage file \"%s\">\n", filename_buffer); - log("\nREADY.\n"); - log_pop(); + for (auto &it : get_coverage_data()) + fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str()); + fclose(f); + } +#endif + + if (call_abort) + abort(); + +#ifdef YOSYS_ENABLE_READLINE if (!history_file.empty()) { if (history_offset > 0) { history_truncate_file(history_file.c_str(), 100); @@ -693,26 +340,10 @@ int main(int argc, char **argv) HIST_ENTRY **hist_list = history_list(); if (hist_list != NULL) free(hist_list); - - for (auto f : log_files) - if (f != stderr) - fclose(f); - log_errfile = NULL; - log_files.clear(); - - Pass::done_register(); - - for (auto mod : loaded_modules) - dlclose(mod); - -#ifdef YOSYS_ENABLE_TCL - if (yosys_tcl_interp != NULL) { - Tcl_DeleteInterp(yosys_tcl_interp); - Tcl_Finalize(); - yosys_tcl_interp = NULL; - } #endif + yosys_shutdown(); + return 0; } diff --git a/kernel/log.cc b/kernel/log.cc index 779f93737..1b0eb6649 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -17,7 +17,8 @@ * */ -#include "kernel/log.h" +#include "kernel/yosys.h" +#include "libs/sha1/sha1.h" #include "backends/ilang/ilang_backend.h" #include <sys/time.h> @@ -28,44 +29,50 @@ #include <vector> #include <list> +YOSYS_NAMESPACE_BEGIN + std::vector<FILE*> log_files; +std::vector<std::ostream*> log_streams; FILE *log_errfile = NULL; +SHA1 *log_hasher = NULL; + bool log_time = false; bool log_cmd_error_throw = false; int log_verbose_level; std::vector<int> header_count; std::list<std::string> string_buf; +int string_buf_size = 0; static struct timeval initial_tv = { 0, 0 }; static bool next_print_log = false; +static int log_newline_count = 0; -std::string stringf(const char *fmt, ...) +void logv(const char *format, va_list ap) { - std::string string; - char *str = NULL; - va_list ap; + while (format[0] == '\n' && format[1] != 0) { + log("\n"); + format++; + } - va_start(ap, fmt); - if (vasprintf(&str, fmt, ap) < 0) - str = NULL; - va_end(ap); + std::string str = vstringf(format, ap); - if (str != NULL) { - string = str; - free(str); - } + if (str.empty()) + return; - return string; -} + size_t nnl_pos = str.find_last_not_of('\n'); + if (nnl_pos == std::string::npos) + log_newline_count += SIZE(str); + else + log_newline_count = SIZE(str) - nnl_pos - 1; + + if (log_hasher) + log_hasher->update(str); + + if (log_time) + { + std::string time_str; -void logv(const char *format, va_list ap) -{ - if (log_time) { - while (format[0] == '\n' && format[1] != 0) { - format++; - log("\n"); - } if (next_print_log || initial_tv.tv_sec == 0) { next_print_log = false; struct timeval tv; @@ -78,48 +85,56 @@ void logv(const char *format, va_list ap) } tv.tv_sec -= initial_tv.tv_sec; tv.tv_usec -= initial_tv.tv_usec; - log("[%05d.%06d] ", int(tv.tv_sec), int(tv.tv_usec)); + time_str += stringf("[%05d.%06d] ", int(tv.tv_sec), int(tv.tv_usec)); } + if (format[0] && format[strlen(format)-1] == '\n') next_print_log = true; - } - for (auto f : log_files) { - va_list aq; - va_copy(aq, ap); - vfprintf(f, format, aq); - va_end(aq); + for (auto f : log_files) + fputs(time_str.c_str(), f); + + for (auto f : log_streams) + *f << time_str; } + + for (auto f : log_files) + fputs(str.c_str(), f); + + for (auto f : log_streams) + *f << str; } void logv_header(const char *format, va_list ap) { - log("\n"); + bool pop_errfile = false; + + log_spacer(); if (header_count.size() > 0) header_count.back()++; + + if (int(header_count.size()) <= log_verbose_level && log_errfile != NULL) { + log_files.push_back(log_errfile); + pop_errfile = true; + } + for (int c : header_count) log("%d.", c); log(" "); logv(format, ap); log_flush(); - if (int(header_count.size()) <= log_verbose_level && log_errfile != NULL) { - for (int c : header_count) - fprintf(log_errfile, "%d.", c); - fprintf(log_errfile, " "); - vfprintf(log_errfile, format, ap); - fflush(log_errfile); - } + if (pop_errfile) + log_files.pop_back(); } void logv_error(const char *format, va_list ap) { + if (log_errfile != NULL) + log_files.push_back(log_errfile); + log("ERROR: "); logv(format, ap); - if (log_errfile != NULL) { - fprintf(log_errfile, "ERROR: "); - vfprintf(log_errfile, format, ap); - } log_flush(); exit(1); } @@ -156,12 +171,18 @@ void log_cmd_error(const char *format, ...) log("ERROR: "); logv(format, ap); log_flush(); - throw 0; + throw log_cmd_error_expection(); } logv_error(format, ap); } +void log_spacer() +{ + while (log_newline_count < 2) + log("\n"); +} + void log_push() { header_count.push_back(0); @@ -171,6 +192,7 @@ void log_pop() { header_count.pop_back(); string_buf.clear(); + string_buf_size = 0; log_flush(); } @@ -179,6 +201,7 @@ void log_reset_stack() while (header_count.size() > 1) header_count.pop_back(); string_buf.clear(); + string_buf_size = 0; log_flush(); } @@ -186,21 +209,95 @@ void log_flush() { for (auto f : log_files) fflush(f); + + for (auto f : log_streams) + f->flush(); +} + +void log_dump_val_worker(RTLIL::SigSpec v) { + log("%s", log_signal(v)); } const char *log_signal(const RTLIL::SigSpec &sig, bool autoint) { - char *ptr; - size_t size; + std::stringstream buf; + ILANG_BACKEND::dump_sigspec(buf, sig, autoint); - FILE *f = open_memstream(&ptr, &size); - ILANG_BACKEND::dump_sigspec(f, sig, autoint); - fputc(0, f); - fclose(f); - - string_buf.push_back(ptr); - free(ptr); + if (string_buf_size < 100) + string_buf_size++; + else + string_buf.pop_front(); + string_buf.push_back(buf.str()); return string_buf.back().c_str(); } +const char *log_id(RTLIL::IdString str) +{ + const char *p = str.c_str(); + log_assert(RTLIL::IdString::global_refcount_storage_[str.index_] > 1); + if (p[0] == '\\' && p[1] != '$' && p[1] != 0) + return p+1; + return p; +} + +void log_cell(RTLIL::Cell *cell, std::string indent) +{ + std::stringstream buf; + ILANG_BACKEND::dump_cell(buf, indent, cell); + log("%s", buf.str().c_str()); +} + +// --------------------------------------------------- +// This is the magic behind the code coverage counters +// --------------------------------------------------- +#ifdef COVER_ACTIVE + +std::map<std::string, std::pair<std::string, int>> extra_coverage_data; + +void cover_extra(std::string parent, std::string id, bool increment) { + if (extra_coverage_data.count(id) == 0) { + for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) + if (p->id == parent) + extra_coverage_data[id].first = stringf("%s:%d:%s", p->file, p->line, p->func); + log_assert(extra_coverage_data.count(id)); + } + if (increment) + extra_coverage_data[id].second++; +} + +std::map<std::string, std::pair<std::string, int>> get_coverage_data() +{ + std::map<std::string, std::pair<std::string, int>> coverage_data; + + for (auto &it : pass_register) { + std::string key = stringf("passes.%s", it.first.c_str()); + coverage_data[key].first = stringf("%s:%d:%s", __FILE__, __LINE__, __FUNCTION__); + coverage_data[key].second += it.second->call_counter; + } + + for (auto &it : extra_coverage_data) { + if (coverage_data.count(it.first)) + log("WARNING: found duplicate coverage id \"%s\".\n", it.first.c_str()); + coverage_data[it.first].first = it.second.first; + coverage_data[it.first].second += it.second.second; + } + + for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) { + if (coverage_data.count(p->id)) + log("WARNING: found duplicate coverage id \"%s\".\n", p->id); + coverage_data[p->id].first = stringf("%s:%d:%s", p->file, p->line, p->func); + coverage_data[p->id].second += p->counter; + } + + for (auto &it : coverage_data) + if (!it.second.first.compare(0, strlen(YOSYS_SRC "/"), YOSYS_SRC "/")) + it.second.first = it.second.first.substr(strlen(YOSYS_SRC "/")); + + return coverage_data; +} + +#endif + +YOSYS_NAMESPACE_END + diff --git a/kernel/log.h b/kernel/log.h index c4c03352a..e2b4db87b 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -17,22 +17,32 @@ * */ +#include "kernel/yosys.h" + #ifndef LOG_H #define LOG_H -#include "kernel/rtlil.h" -#include <stdio.h> #include <time.h> -#include <vector> +#include <sys/time.h> +#include <sys/resource.h> + +YOSYS_NAMESPACE_BEGIN + +#define S__LINE__sub2(x) #x +#define S__LINE__sub1(x) S__LINE__sub2(x) +#define S__LINE__ S__LINE__sub1(__LINE__) + +struct log_cmd_error_expection { }; extern std::vector<FILE*> log_files; +extern std::vector<std::ostream*> log_streams; extern FILE *log_errfile; +extern class SHA1 *log_hasher; + extern bool log_time; extern bool log_cmd_error_throw; extern int log_verbose_level; -std::string stringf(const char *fmt, ...); - void logv(const char *format, va_list ap); void logv_header(const char *format, va_list ap); void logv_error(const char *format, va_list ap) __attribute__ ((noreturn)); @@ -42,6 +52,7 @@ void log_header(const char *format, ...) __attribute__ ((format (printf, 1, 2))) void log_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn)); void log_cmd_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn)); +void log_spacer(); void log_push(); void log_pop(); @@ -49,9 +60,70 @@ void log_reset_stack(); void log_flush(); const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true); +const char *log_id(RTLIL::IdString id); + +template<typename T> static inline const char *log_id(T *obj) { + return log_id(obj->name); +} + +void log_cell(RTLIL::Cell *cell, std::string indent = ""); #define log_abort() log_error("Abort in %s:%d.\n", __FILE__, __LINE__) #define log_assert(_assert_expr_) do { if (_assert_expr_) break; log_error("Assert `%s' failed in %s:%d.\n", #_assert_expr_, __FILE__, __LINE__); } while (0) +#define log_ping() log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__) + + +// --------------------------------------------------- +// This is the magic behind the code coverage counters +// --------------------------------------------------- + +#if defined(__linux__) && !defined(NDEBUG) +#define COVER_ACTIVE + +#define cover(_id) do { \ + static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1))) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \ + __d.counter++; \ +} while (0) + +struct CoverData { + const char *file, *func, *id; + int line, counter; +} __attribute__ ((packed)); + +// this two symbols are created by the linker for the "yosys_cover_list" ELF section +extern "C" struct CoverData __start_yosys_cover_list[]; +extern "C" struct CoverData __stop_yosys_cover_list[]; + +extern std::map<std::string, std::pair<std::string, int>> extra_coverage_data; + +void cover_extra(std::string parent, std::string id, bool increment = true); +std::map<std::string, std::pair<std::string, int>> get_coverage_data(); + +#define cover_list(_id, ...) do { cover(_id); \ + std::string r = cover_list_worker(_id, __VA_ARGS__); \ + log_assert(r.empty()); \ +} while (0) + +static inline std::string cover_list_worker(std::string, std::string last) { + return last; +} + +template<typename... T> +std::string cover_list_worker(std::string prefix, std::string first, T... rest) { + std::string selected = cover_list_worker(prefix, rest...); + cover_extra(prefix, prefix + "." + first, first == selected); + return first == selected ? "" : selected; +} + +#else +# define cover(...) do { } while (0) +# define cover_list(...) do { } while (0) +#endif + + +// ------------------------------------------------------------ +// everything below this line are utilities for troubleshooting +// ------------------------------------------------------------ // simple timer for performance measurements // toggle the '#if 1' to get a baseline for the perormance penalty added by the measurement @@ -65,30 +137,45 @@ struct PerformanceTimer } static int64_t query() { +#if 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) + struct rusage rusage; + int64_t t; + if (getrusage(RUSAGE_SELF, &rusage) == -1) { + log_cmd_error("getrusage failed!\n"); + log_abort(); + } + 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; +#else + #error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?). +#endif } void reset() { total_ns = 0; } - void add() { - total_ns += query(); + void begin() { + total_ns -= query(); } - void sub() { - total_ns -= query(); + void end() { + total_ns += query(); } float sec() const { return total_ns * 1e-9; } #else + static int64_t query() { return 0; } void reset() { } - void add() { } - void sub() { } + void begin() { } + void end() { } float sec() const { return 0; } #endif }; @@ -107,12 +194,17 @@ static inline void log_dump_val_worker(char c) { log(c >= 32 && c < 127 ? "'%c'" static inline void log_dump_val_worker(unsigned char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", c); } static inline void log_dump_val_worker(bool v) { log("%s", v ? "true" : "false"); } static inline void log_dump_val_worker(double v) { log("%f", v); } +static inline void log_dump_val_worker(char *v) { log("%s", v); } 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(RTLIL::SigSpec v) { log("%s", log_signal(v)); } +static inline void log_dump_val_worker(PerformanceTimer p) { log("%f seconds", p.sec()); } static inline void log_dump_args_worker(const char *p) { log_assert(*p == 0); } +void log_dump_val_worker(RTLIL::SigSpec v); -template <typename T, typename ... Args> +template<typename T> +static inline void log_dump_val_worker(T *ptr) { log("%p", ptr); } + +template<typename T, typename ... Args> void log_dump_args_worker(const char *p, T first, Args ... args) { int next_p_state = 0; @@ -152,4 +244,6 @@ void log_dump_args_worker(const char *p, T first, Args ... args) log("\n"); \ } while (0) +YOSYS_NAMESPACE_END + #endif diff --git a/kernel/macc.h b/kernel/macc.h new file mode 100644 index 000000000..271141112 --- /dev/null +++ b/kernel/macc.h @@ -0,0 +1,231 @@ +/* + * 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 MACC_H +#define MACC_H + +#include "kernel/yosys.h" + +YOSYS_NAMESPACE_BEGIN + +struct Macc +{ + struct port_t { + RTLIL::SigSpec in_a, in_b; + bool is_signed, do_subtract; + }; + + std::vector<port_t> ports; + RTLIL::SigSpec bit_ports; + + void optimize(int width) + { + std::vector<port_t> new_ports; + RTLIL::SigSpec new_bit_ports; + RTLIL::Const off(0, width); + + for (auto &port : ports) + { + if (SIZE(port.in_a) == 0 && SIZE(port.in_b) == 0) + continue; + + if (SIZE(port.in_a) == 1 && SIZE(port.in_b) == 0 && !port.is_signed && !port.do_subtract) { + bit_ports.append(port.in_a); + continue; + } + + if (port.in_a.is_fully_const() && port.in_b.is_fully_const()) { + RTLIL::Const v = port.in_a.as_const(); + if (SIZE(port.in_b)) + v = const_mul(v, port.in_b.as_const(), port.is_signed, port.is_signed, width); + if (port.do_subtract) + off = const_sub(off, v, port.is_signed, port.is_signed, width); + else + off = const_add(off, v, port.is_signed, port.is_signed, width); + continue; + } + + if (port.is_signed) { + while (SIZE(port.in_a) > 1 && port.in_a[SIZE(port.in_a)-1] == port.in_a[SIZE(port.in_a)-2]) + port.in_a.remove(SIZE(port.in_a)-1); + while (SIZE(port.in_b) > 1 && port.in_b[SIZE(port.in_b)-1] == port.in_b[SIZE(port.in_b)-2]) + port.in_b.remove(SIZE(port.in_b)-1); + } else { + while (SIZE(port.in_a) > 1 && port.in_a[SIZE(port.in_a)-1] == RTLIL::S0) + port.in_a.remove(SIZE(port.in_a)-1); + while (SIZE(port.in_b) > 1 && port.in_b[SIZE(port.in_b)-1] == RTLIL::S0) + port.in_b.remove(SIZE(port.in_b)-1); + } + + new_ports.push_back(port); + } + + for (auto &bit : bit_ports) + if (bit == RTLIL::S1) + off = const_add(off, RTLIL::Const(1, width), false, false, width); + else if (bit != RTLIL::S0) + new_bit_ports.append(bit); + + if (off.as_bool()) { + port_t port; + port.in_a = off; + port.is_signed = false; + port.do_subtract = false; + new_ports.push_back(port); + } + + new_ports.swap(ports); + bit_ports = new_bit_ports; + } + + void from_cell(RTLIL::Cell *cell) + { + RTLIL::SigSpec port_a = cell->getPort("\\A"); + + ports.clear(); + bit_ports = cell->getPort("\\B"); + + std::vector<RTLIL::State> config_bits = cell->getParam("\\CONFIG").bits; + int config_width = cell->getParam("\\CONFIG_WIDTH").as_int(); + int config_cursor = 0; + + log_assert(SIZE(config_bits) >= config_width); + + int num_bits = 0; + if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 1; + if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 2; + if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 4; + if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 8; + + int port_a_cursor = 0; + while (port_a_cursor < SIZE(port_a)) + { + log_assert(config_cursor + 2 + 2*num_bits <= config_width); + + port_t this_port; + this_port.is_signed = config_bits[config_cursor++] == RTLIL::S1; + this_port.do_subtract = config_bits[config_cursor++] == RTLIL::S1; + + int size_a = 0; + for (int i = 0; i < num_bits; i++) + if (config_bits[config_cursor++] == RTLIL::S1) + size_a |= 1 << i; + + this_port.in_a = port_a.extract(port_a_cursor, size_a); + port_a_cursor += size_a; + + int size_b = 0; + for (int i = 0; i < num_bits; i++) + if (config_bits[config_cursor++] == RTLIL::S1) + size_b |= 1 << i; + + this_port.in_b = port_a.extract(port_a_cursor, size_b); + port_a_cursor += size_b; + + if (size_a || size_b) + ports.push_back(this_port); + } + + log_assert(config_cursor == config_width); + log_assert(port_a_cursor == SIZE(port_a)); + } + + void to_cell(RTLIL::Cell *cell) const + { + RTLIL::SigSpec port_a; + std::vector<RTLIL::State> config_bits; + int max_size = 0, num_bits = 0; + + for (auto &port : ports) { + max_size = std::max(max_size, SIZE(port.in_a)); + max_size = std::max(max_size, SIZE(port.in_b)); + } + + while (max_size) + num_bits++, max_size /= 2; + + log_assert(num_bits < 16); + config_bits.push_back(num_bits & 1 ? RTLIL::S1 : RTLIL::S0); + config_bits.push_back(num_bits & 2 ? RTLIL::S1 : RTLIL::S0); + config_bits.push_back(num_bits & 4 ? RTLIL::S1 : RTLIL::S0); + config_bits.push_back(num_bits & 8 ? RTLIL::S1 : RTLIL::S0); + + for (auto &port : ports) + { + if (SIZE(port.in_a) == 0) + continue; + + config_bits.push_back(port.is_signed ? RTLIL::S1 : RTLIL::S0); + config_bits.push_back(port.do_subtract ? RTLIL::S1 : RTLIL::S0); + + int size_a = SIZE(port.in_a); + for (int i = 0; i < num_bits; i++) + config_bits.push_back(size_a & (1 << i) ? RTLIL::S1 : RTLIL::S0); + + int size_b = SIZE(port.in_b); + for (int i = 0; i < num_bits; i++) + config_bits.push_back(size_b & (1 << i) ? RTLIL::S1 : RTLIL::S0); + + port_a.append(port.in_a); + port_a.append(port.in_b); + } + + cell->setPort("\\A", port_a); + cell->setPort("\\B", bit_ports); + cell->setParam("\\CONFIG", config_bits); + cell->setParam("\\CONFIG_WIDTH", SIZE(config_bits)); + cell->setParam("\\A_WIDTH", SIZE(port_a)); + cell->setParam("\\B_WIDTH", SIZE(bit_ports)); + } + + bool eval(RTLIL::Const &result) const + { + for (auto &bit : result.bits) + bit = RTLIL::S0; + + for (auto &port : ports) + { + if (!port.in_a.is_fully_const() || !port.in_b.is_fully_const()) + return false; + + RTLIL::Const summand; + if (SIZE(port.in_b) == 0) + summand = const_pos(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, SIZE(result)); + else + summand = const_mul(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, SIZE(result)); + + if (port.do_subtract) + result = const_sub(result, summand, port.is_signed, port.is_signed, SIZE(result)); + else + result = const_add(result, summand, port.is_signed, port.is_signed, SIZE(result)); + } + + for (auto bit : bit_ports) { + if (bit.wire) + return false; + result = const_add(result, bit.data, false, false, SIZE(result)); + } + + return true; + } +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/kernel/modtools.h b/kernel/modtools.h new file mode 100644 index 000000000..58cdd5b0e --- /dev/null +++ b/kernel/modtools.h @@ -0,0 +1,455 @@ +/* + * 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 MODTOOLS_H +#define MODTOOLS_H + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" +#include "kernel/celltypes.h" + +YOSYS_NAMESPACE_BEGIN + +struct ModIndex : public RTLIL::Monitor +{ + struct PortInfo { + RTLIL::Cell* cell; + RTLIL::IdString port; + int offset; + + PortInfo(RTLIL::Cell* _c, RTLIL::IdString _p, int _o) : cell(_c), port(_p), offset(_o) { } + + bool operator<(const PortInfo &other) const { + if (cell != other.cell) + return cell < other.cell; + if (offset != other.offset) + return offset < other.offset; + return port < other.port; + } + }; + + struct SigBitInfo + { + bool is_input, is_output; + std::set<PortInfo> ports; + + SigBitInfo() : is_input(false), is_output(false) { } + }; + + SigMap sigmap; + RTLIL::Module *module; + std::map<RTLIL::SigBit, SigBitInfo> database; + bool auto_reload_module; + + void port_add(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig) + { + for (int i = 0; i < SIZE(sig); i++) { + RTLIL::SigBit bit = sigmap(sig[i]); + if (bit.wire) + database[bit].ports.insert(PortInfo(cell, port, i)); + } + } + + void port_del(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig) + { + for (int i = 0; i < SIZE(sig); i++) { + RTLIL::SigBit bit = sigmap(sig[i]); + if (bit.wire) + database[bit].ports.erase(PortInfo(cell, port, i)); + } + } + + const SigBitInfo &info(RTLIL::SigBit bit) + { + return database[sigmap(bit)]; + } + + void reload_module() + { + sigmap.clear(); + sigmap.set(module); + + database.clear(); + for (auto wire : module->wires()) + if (wire->port_input || wire->port_output) + for (int i = 0; i < SIZE(wire); i++) { + RTLIL::SigBit bit = sigmap(RTLIL::SigBit(wire, i)); + if (bit.wire && wire->port_input) + database[bit].is_input = true; + if (bit.wire && wire->port_output) + database[bit].is_output = true; + } + for (auto cell : module->cells()) + for (auto &conn : cell->connections()) + port_add(cell, conn.first, conn.second); + + auto_reload_module = false; + } + + virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) OVERRIDE + { + if (auto_reload_module) + reload_module(); + + port_del(cell, port, old_sig); + port_add(cell, port, sig); + } + + virtual void notify_connect(RTLIL::Module *mod, const RTLIL::SigSig&) + { + log_assert(module == mod); + auto_reload_module = true; + } + + virtual void notify_connect(RTLIL::Module *mod, const std::vector<RTLIL::SigSig>&) + { + log_assert(module == mod); + auto_reload_module = true; + } + + virtual void notify_blackout(RTLIL::Module *mod) + { + log_assert(module == mod); + auto_reload_module = true; + } + + ModIndex(RTLIL::Module *_m) : module(_m) + { + auto_reload_module = true; + module->monitors.insert(this); + } + + ~ModIndex() + { + module->monitors.erase(this); + } + + SigBitInfo *query(RTLIL::SigBit bit) + { + if (auto_reload_module) + reload_module(); + + auto it = database.find(sigmap(bit)); + if (it == database.end()) + return nullptr; + else + return &it->second; + } + + bool query_is_input(RTLIL::SigBit bit) + { + const SigBitInfo *info = query(bit); + if (info == nullptr) + return false; + return info->is_input; + } + + bool query_is_output(RTLIL::SigBit bit) + { + const SigBitInfo *info = query(bit); + if (info == nullptr) + return false; + return info->is_output; + } + + std::set<PortInfo> &query_ports(RTLIL::SigBit bit) + { + static std::set<PortInfo> empty_result_set; + SigBitInfo *info = query(bit); + if (info == nullptr) + return empty_result_set; + return info->ports; + } +}; + +struct ModWalker +{ + struct PortBit + { + RTLIL::Cell *cell; + RTLIL::IdString port; + int offset; + + bool operator<(const PortBit &other) const { + if (cell != other.cell) + return cell < other.cell; + if (port != other.port) + return port < other.port; + return offset < other.offset; + } + }; + + RTLIL::Design *design; + RTLIL::Module *module; + + CellTypes ct; + SigMap sigmap; + + std::map<RTLIL::SigBit, std::set<PortBit>> signal_drivers; + std::map<RTLIL::SigBit, std::set<PortBit>> signal_consumers; + std::set<RTLIL::SigBit> signal_inputs, signal_outputs; + + std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_outputs, cell_inputs; + + void add_wire(RTLIL::Wire *wire) + { + if (wire->port_input) { + std::vector<RTLIL::SigBit> bits = sigmap(wire); + for (auto bit : bits) + if (bit.wire != NULL) + signal_inputs.insert(bit); + } + + if (wire->port_output) { + std::vector<RTLIL::SigBit> bits = sigmap(wire); + for (auto bit : bits) + if (bit.wire != NULL) + signal_outputs.insert(bit); + } + } + + void add_cell_port(RTLIL::Cell *cell, RTLIL::IdString port, std::vector<RTLIL::SigBit> bits, bool is_output, bool is_input) + { + for (int i = 0; i < int(bits.size()); i++) + if (bits[i].wire != NULL) { + PortBit pbit = { cell, port, i }; + if (is_output) { + signal_drivers[bits[i]].insert(pbit); + cell_outputs[cell].insert(bits[i]); + } + if (is_input) { + signal_consumers[bits[i]].insert(pbit); + cell_inputs[cell].insert(bits[i]); + } + } + } + + void add_cell(RTLIL::Cell *cell) + { + if (ct.cell_known(cell->type)) { + for (auto &conn : cell->connections()) + add_cell_port(cell, conn.first, sigmap(conn.second), + ct.cell_output(cell->type, conn.first), + ct.cell_input(cell->type, conn.first)); + } else { + for (auto &conn : cell->connections()) + add_cell_port(cell, conn.first, sigmap(conn.second), true, true); + } + } + + ModWalker() : design(NULL), module(NULL) + { + } + + ModWalker(RTLIL::Design *design, RTLIL::Module *module, CellTypes *filter_ct = NULL) + { + setup(design, module, filter_ct); + } + + void setup(RTLIL::Design *design, RTLIL::Module *module, CellTypes *filter_ct = NULL) + { + this->design = design; + this->module = module; + + ct.clear(); + ct.setup(design); + sigmap.set(module); + + signal_drivers.clear(); + signal_consumers.clear(); + signal_inputs.clear(); + signal_outputs.clear(); + + for (auto &it : module->wires_) + add_wire(it.second); + for (auto &it : module->cells_) + if (filter_ct == NULL || filter_ct->cell_known(it.second->type)) + add_cell(it.second); + } + + // get_* methods -- single RTLIL::SigBit + + template<typename T> + inline bool get_drivers(std::set<PortBit> &result, RTLIL::SigBit bit) const + { + bool found = false; + if (signal_drivers.count(bit)) { + const std::set<PortBit> &r = signal_drivers.at(bit); + result.insert(r.begin(), r.end()); + found = true; + } + return found; + } + + template<typename T> + inline bool get_consumers(std::set<PortBit> &result, RTLIL::SigBit bit) const + { + bool found = false; + if (signal_consumers.count(bit)) { + const std::set<PortBit> &r = signal_consumers.at(bit); + result.insert(r.begin(), r.end()); + found = true; + } + return found; + } + + template<typename T> + inline bool get_inputs(std::set<RTLIL::SigBit> &result, RTLIL::SigBit bit) const + { + bool found = false; + if (signal_inputs.count(bit)) + result.insert(bit), found = true; + return found; + } + + template<typename T> + inline bool get_outputs(std::set<RTLIL::SigBit> &result, RTLIL::SigBit bit) const + { + bool found = false; + if (signal_outputs.count(bit)) + result.insert(bit), found = true; + return found; + } + + // get_* methods -- container of RTLIL::SigBit's (always by reference) + + template<typename T> + inline bool get_drivers(std::set<PortBit> &result, const T &bits) const + { + bool found = false; + for (RTLIL::SigBit bit : bits) + if (signal_drivers.count(bit)) { + const std::set<PortBit> &r = signal_drivers.at(bit); + result.insert(r.begin(), r.end()); + found = true; + } + return found; + } + + template<typename T> + inline bool get_consumers(std::set<PortBit> &result, const T &bits) const + { + bool found = false; + for (RTLIL::SigBit bit : bits) + if (signal_consumers.count(bit)) { + const std::set<PortBit> &r = signal_consumers.at(bit); + result.insert(r.begin(), r.end()); + found = true; + } + return found; + } + + template<typename T> + inline bool get_inputs(std::set<RTLIL::SigBit> &result, const T &bits) const + { + bool found = false; + for (RTLIL::SigBit bit : bits) + if (signal_inputs.count(bit)) + result.insert(bit), found = true; + return found; + } + + template<typename T> + inline bool get_outputs(std::set<RTLIL::SigBit> &result, const T &bits) const + { + bool found = false; + for (RTLIL::SigBit bit : bits) + if (signal_outputs.count(bit)) + result.insert(bit), found = true; + return found; + } + + // get_* methods -- call by RTLIL::SigSpec (always by value) + + bool get_drivers(std::set<PortBit> &result, RTLIL::SigSpec signal) const + { + std::vector<RTLIL::SigBit> bits = sigmap(signal); + return get_drivers(result, bits); + } + + bool get_consumers(std::set<PortBit> &result, RTLIL::SigSpec signal) const + { + std::vector<RTLIL::SigBit> bits = sigmap(signal); + return get_consumers(result, bits); + } + + bool get_inputs(std::set<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const + { + std::vector<RTLIL::SigBit> bits = sigmap(signal); + return get_inputs(result, bits); + } + + bool get_outputs(std::set<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const + { + std::vector<RTLIL::SigBit> bits = sigmap(signal); + return get_outputs(result, bits); + } + + // has_* methods -- call by reference + + template<typename T> + inline bool has_drivers(const T &sig) const { + std::set<PortBit> result; + return get_drivers(result, sig); + } + + template<typename T> + inline bool has_consumers(const T &sig) const { + std::set<PortBit> result; + return get_consumers(result, sig); + } + + template<typename T> + inline bool has_inputs(const T &sig) const { + std::set<RTLIL::SigBit> result; + return get_inputs(result, sig); + } + + template<typename T> + inline bool has_outputs(const T &sig) const { + std::set<RTLIL::SigBit> result; + return get_outputs(result, sig); + } + + // has_* methods -- call by value + + inline bool has_drivers(RTLIL::SigSpec sig) const { + std::set<PortBit> result; + return get_drivers(result, sig); + } + + inline bool has_consumers(RTLIL::SigSpec sig) const { + std::set<PortBit> result; + return get_consumers(result, sig); + } + + inline bool has_inputs(RTLIL::SigSpec sig) const { + std::set<RTLIL::SigBit> result; + return get_inputs(result, sig); + } + + inline bool has_outputs(RTLIL::SigSpec sig) const { + std::set<RTLIL::SigBit> result; + return get_outputs(result, sig); + } +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/kernel/register.cc b/kernel/register.cc index 325709664..2f7b89ffd 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -17,50 +17,46 @@ * */ -#include "register.h" -#include "log.h" -#include <assert.h> +#include "kernel/yosys.h" #include <string.h> #include <stdlib.h> #include <stdio.h> +#include <errno.h> + +YOSYS_NAMESPACE_BEGIN -using namespace REGISTER_INTERN; #define MAX_REG_COUNT 1000 -namespace REGISTER_INTERN -{ - bool echo_mode = false; - int raw_register_count = 0; - bool raw_register_done = false; - Pass *raw_register_array[MAX_REG_COUNT]; - - std::map<std::string, Frontend*> frontend_register; - std::map<std::string, Pass*> pass_register; - std::map<std::string, Backend*> backend_register; -} +bool echo_mode = false; +Pass *first_queued_pass; +Pass *current_pass; + +std::map<std::string, Frontend*> frontend_register; +std::map<std::string, Pass*> pass_register; +std::map<std::string, Backend*> backend_register; std::vector<std::string> Frontend::next_args; Pass::Pass(std::string name, std::string short_help) : pass_name(name), short_help(short_help) { - assert(!raw_register_done); - assert(raw_register_count < MAX_REG_COUNT); - raw_register_array[raw_register_count++] = this; + next_queued_pass = first_queued_pass; + first_queued_pass = this; + call_counter = 0; + runtime_ns = 0; } void Pass::run_register() { - assert(pass_register.count(pass_name) == 0); + log_assert(pass_register.count(pass_name) == 0); pass_register[pass_name] = this; } void Pass::init_register() { - if (raw_register_done) - done_register(); - while (raw_register_count > 0) - raw_register_array[--raw_register_count]->run_register(); - raw_register_done = true; + while (first_queued_pass) { + first_queued_pass->run_register(); + first_queued_pass = first_queued_pass->next_queued_pass; + } } void Pass::done_register() @@ -68,13 +64,32 @@ void Pass::done_register() frontend_register.clear(); pass_register.clear(); backend_register.clear(); - raw_register_done = false; + log_assert(first_queued_pass == NULL); } Pass::~Pass() { } +Pass::pre_post_exec_state_t Pass::pre_execute() +{ + pre_post_exec_state_t state; + call_counter++; + state.begin_ns = PerformanceTimer::query(); + state.parent_pass = current_pass; + current_pass = this; + return state; +} + +void Pass::post_execute(Pass::pre_post_exec_state_t state) +{ + int64_t time_ns = PerformanceTimer::query() - state.begin_ns; + runtime_ns += time_ns; + current_pass = state.parent_pass; + if (current_pass) + current_pass->runtime_ns -= time_ns; +} + void Pass::help() { log("\n"); @@ -117,7 +132,7 @@ void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Desig std::string arg = args[argidx]; if (arg.substr(0, 1) == "-") - cmd_error(args, argidx, "Unkown option or option in arguments."); + cmd_error(args, argidx, "Unknown option or option in arguments."); if (!select) cmd_error(args, argidx, "Extra argument."); @@ -133,8 +148,10 @@ void Pass::call(RTLIL::Design *design, std::string command) std::vector<std::string> args; char *s = strdup(command.c_str()), *sstart = s, *saveptr; s += strspn(s, " \t\r\n"); - if (*s == 0 || *s == '#') + if (*s == 0 || *s == '#') { + free(sstart); return; + } if (*s == '!') { for (s++; *s == ' ' || *s == '\t'; s++) { } char *p = s + strlen(s) - 1; @@ -144,6 +161,7 @@ void Pass::call(RTLIL::Design *design, std::string command) int retCode = system(s); if (retCode != 0) log_cmd_error("Shell command returned error code %d.\n", retCode); + free(sstart); return; } for (char *p = strtok_r(s, " \t\r\n", &saveptr); p; p = strtok_r(NULL, " \t\r\n", &saveptr)) { @@ -186,18 +204,20 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args) log_cmd_error("No such command: %s (type 'help' for a command overview)\n", args[0].c_str()); size_t orig_sel_stack_pos = design->selection_stack.size(); + auto state = pass_register[args[0]]->pre_execute(); pass_register[args[0]]->execute(args, design); + pass_register[args[0]]->post_execute(state); while (design->selection_stack.size() > orig_sel_stack_pos) design->selection_stack.pop_back(); design->check(); } -void Pass::call_newsel(RTLIL::Design *design, std::string command) +void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command) { std::string backup_selected_active_module = design->selected_active_module; design->selected_active_module.clear(); - design->selection_stack.push_back(RTLIL::Selection()); + design->selection_stack.push_back(selection); Pass::call(design, command); @@ -205,11 +225,11 @@ void Pass::call_newsel(RTLIL::Design *design, std::string command) design->selected_active_module = backup_selected_active_module; } -void Pass::call_newsel(RTLIL::Design *design, std::vector<std::string> args) +void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::vector<std::string> args) { std::string backup_selected_active_module = design->selected_active_module; design->selected_active_module.clear(); - design->selection_stack.push_back(RTLIL::Selection()); + design->selection_stack.push_back(selection); Pass::call(design, args); @@ -217,16 +237,44 @@ void Pass::call_newsel(RTLIL::Design *design, std::vector<std::string> args) design->selected_active_module = backup_selected_active_module; } -Frontend::Frontend(std::string name, std::string short_help) : Pass("read_"+name, short_help), frontend_name(name) +void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::string command) +{ + std::string backup_selected_active_module = design->selected_active_module; + design->selected_active_module = module->name.str(); + design->selection_stack.push_back(RTLIL::Selection(false)); + design->selection_stack.back().select(module); + + Pass::call(design, command); + + design->selection_stack.pop_back(); + design->selected_active_module = backup_selected_active_module; +} + +void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vector<std::string> args) +{ + std::string backup_selected_active_module = design->selected_active_module; + design->selected_active_module = module->name.str(); + design->selection_stack.push_back(RTLIL::Selection(false)); + design->selection_stack.back().select(module); + + Pass::call(design, args); + + design->selection_stack.pop_back(); + design->selected_active_module = backup_selected_active_module; +} + +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) { } void Frontend::run_register() { - assert(pass_register.count(pass_name) == 0); + log_assert(pass_register.count(pass_name) == 0); pass_register[pass_name] = this; - assert(frontend_register.count(frontend_name) == 0); + log_assert(frontend_register.count(frontend_name) == 0); frontend_register[frontend_name] = this; } @@ -236,17 +284,22 @@ Frontend::~Frontend() void Frontend::execute(std::vector<std::string> args, RTLIL::Design *design) { - assert(next_args.empty()); + log_assert(next_args.empty()); do { - FILE *f = NULL; + std::istream *f = NULL; next_args.clear(); + auto state = pre_execute(); execute(f, std::string(), args, design); + post_execute(state); args = next_args; - fclose(f); + delete f; } while (!args.empty()); } -void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx) +FILE *Frontend::current_script_file = NULL; +std::string Frontend::last_here_document; + +void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<std::string> args, size_t argidx) { bool called_with_fp = f != NULL; @@ -256,15 +309,53 @@ void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::stri std::string arg = args[argidx]; if (arg.substr(0, 1) == "-") - cmd_error(args, argidx, "Unkown option or option in arguments."); + cmd_error(args, argidx, "Unknown option or option in arguments."); if (f != NULL) cmd_error(args, argidx, "Extra filename argument in direct file mode."); filename = arg; - f = fopen(filename.c_str(), "r"); + if (filename == "<<" && argidx+1 < args.size()) + filename += args[++argidx]; + if (filename.substr(0, 2) == "<<") { + if (Frontend::current_script_file == NULL) + log_error("Unexpected here document '%s' outside of script!\n", filename.c_str()); + if (filename.size() <= 2) + log_error("Missing EOT marker in here document!\n"); + std::string eot_marker = filename.substr(2); + last_here_document.clear(); + while (1) { + std::string buffer; + char block[4096]; + while (1) { + if (fgets(block, 4096, Frontend::current_script_file) == NULL) + log_error("Unexpected end of file in here document '%s'!\n", filename.c_str()); + buffer += block; + if (buffer.size() > 0 && (buffer[buffer.size() - 1] == '\n' || buffer[buffer.size() - 1] == '\r')) + break; + } + int indent = buffer.find_first_not_of(" \t\r\n"); + if (buffer.substr(indent, eot_marker.size()) == eot_marker) + break; + last_here_document += buffer; + } + f = new std::istringstream(last_here_document); + } else { + if (filename.substr(0, 2) == "+/") + filename = proc_share_dirname() + filename.substr(1); + std::ifstream *ff = new std::ifstream; + ff->open(filename.c_str()); + if (ff->fail()) + delete ff; + else + f = ff; + } if (f == NULL) log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno)); + for (size_t i = argidx+1; i < args.size(); i++) + if (args[i].substr(0, 1) == "-") + cmd_error(args, i, "Found option, expected arguments."); + if (argidx+1 < args.size()) { next_args.insert(next_args.begin(), args.begin(), args.begin()+argidx); next_args.insert(next_args.begin()+argidx, args.begin()+argidx+1, args.end()); @@ -281,7 +372,7 @@ void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::stri // cmd_log_args(args); } -void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command) +void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command) { std::vector<std::string> args; char *s = strdup(command.c_str()); @@ -291,7 +382,7 @@ void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filenam frontend_call(design, f, filename, args); } -void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args) +void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::vector<std::string> args) { if (args.size() == 0) return; @@ -299,9 +390,14 @@ void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filenam log_cmd_error("No such frontend: %s\n", args[0].c_str()); if (f != NULL) { + auto state = frontend_register[args[0]]->pre_execute(); frontend_register[args[0]]->execute(f, filename, args, design); + frontend_register[args[0]]->post_execute(state); } else if (filename == "-") { - frontend_register[args[0]]->execute(stdin, "<stdin>", args, design); + std::istream *f_cin = &std::cin; + auto state = frontend_register[args[0]]->pre_execute(); + frontend_register[args[0]]->execute(f_cin, "<stdin>", args, design); + frontend_register[args[0]]->post_execute(state); } else { if (!filename.empty()) args.push_back(filename); @@ -311,16 +407,18 @@ void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filenam design->check(); } -Backend::Backend(std::string name, std::string short_help) : Pass("write_"+name, short_help), backend_name(name) +Backend::Backend(std::string name, std::string short_help) : + Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "write_" + name, short_help), + backend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name) { } void Backend::run_register() { - assert(pass_register.count(pass_name) == 0); + log_assert(pass_register.count(pass_name) == 0); pass_register[pass_name] = this; - assert(backend_register.count(backend_name) == 0); + log_assert(backend_register.count(backend_name) == 0); backend_register[backend_name] = this; } @@ -330,13 +428,15 @@ Backend::~Backend() void Backend::execute(std::vector<std::string> args, RTLIL::Design *design) { - FILE *f = NULL; + std::ostream *f = NULL; + auto state = pre_execute(); execute(f, std::string(), args, design); - if (f != stdout) - fclose(f); + post_execute(state); + if (f != &std::cout) + delete f; } -void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx) +void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<std::string> args, size_t argidx) { bool called_with_fp = f != NULL; @@ -345,20 +445,24 @@ void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::strin std::string arg = args[argidx]; if (arg.substr(0, 1) == "-" && arg != "-") - cmd_error(args, argidx, "Unkown option or option in arguments."); + cmd_error(args, argidx, "Unknown option or option in arguments."); if (f != NULL) cmd_error(args, argidx, "Extra filename argument in direct file mode."); if (arg == "-") { filename = "<stdout>"; - f = stdout; + f = &std::cout; continue; } filename = arg; - f = fopen(filename.c_str(), "w"); - if (f == NULL) + std::ofstream *ff = new std::ofstream; + ff->open(filename.c_str(), std::ofstream::trunc); + if (ff->fail()) { + delete ff; log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); + } + f = ff; } if (called_with_fp) @@ -368,11 +472,11 @@ void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::strin if (f == NULL) { filename = "<stdout>"; - f = stdout; + f = &std::cout; } } -void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command) +void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::string command) { std::vector<std::string> args; char *s = strdup(command.c_str()); @@ -382,7 +486,7 @@ void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, backend_call(design, f, filename, args); } -void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args) +void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::vector<std::string> args) { if (args.size() == 0) return; @@ -392,9 +496,14 @@ void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, size_t orig_sel_stack_pos = design->selection_stack.size(); if (f != NULL) { + auto state = backend_register[args[0]]->pre_execute(); backend_register[args[0]]->execute(f, filename, args, design); + backend_register[args[0]]->post_execute(state); } else if (filename == "-") { - backend_register[args[0]]->execute(stdout, "<stdout>", args, design); + std::ostream *f_cout = &std::cout; + auto state = backend_register[args[0]]->pre_execute(); + backend_register[args[0]]->execute(f_cout, "<stdout>", args, design); + backend_register[args[0]]->post_execute(state); } else { if (!filename.empty()) args.push_back(filename); @@ -479,7 +588,7 @@ struct HelpPass : public Pass { { if (args.size() == 1) { log("\n"); - for (auto &it : REGISTER_INTERN::pass_register) + for (auto &it : pass_register) 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"); @@ -489,7 +598,7 @@ struct HelpPass : public Pass { if (args.size() == 2) { if (args[1] == "-all") { - for (auto &it : REGISTER_INTERN::pass_register) { + for (auto &it : pass_register) { log("\n\n"); log("%s -- %s\n", it.first.c_str(), it.second->short_help.c_str()); for (size_t i = 0; i < it.first.size() + it.second->short_help.size() + 6; i++) @@ -502,39 +611,31 @@ struct HelpPass : public Pass { else if (args[1] == "-write-tex-command-reference-manual") { FILE *f = fopen("command-reference-manual.tex", "wt"); fprintf(f, "%% Generated using the yosys 'help -write-tex-command-reference-manual' command.\n\n"); - for (auto &it : REGISTER_INTERN::pass_register) { - size_t memsize; - char *memptr; - FILE *memf = open_memstream(&memptr, &memsize); - log_files.push_back(memf); + for (auto &it : pass_register) { + std::ostringstream buf; + log_streams.push_back(&buf); it.second->help(); - log_files.pop_back(); - fclose(memf); - write_tex(f, it.first, it.second->short_help, memptr); - free(memptr); + log_streams.pop_back(); + write_tex(f, it.first, it.second->short_help, buf.str()); } fclose(f); } // this option is undocumented as it is for internal use only else if (args[1] == "-write-web-command-reference-manual") { FILE *f = fopen("templates/cmd_index.in", "wt"); - for (auto &it : REGISTER_INTERN::pass_register) { - size_t memsize; - char *memptr; - FILE *memf = open_memstream(&memptr, &memsize); - log_files.push_back(memf); + for (auto &it : pass_register) { + std::ostringstream buf; + log_streams.push_back(&buf); it.second->help(); - log_files.pop_back(); - fclose(memf); - write_html(f, it.first, it.second->short_help, memptr); - free(memptr); + log_streams.pop_back(); + write_html(f, it.first, it.second->short_help, buf.str()); } fclose(f); } - else if (REGISTER_INTERN::pass_register.count(args[1]) == 0) + else if (pass_register.count(args[1]) == 0) log("No such command: %s\n", args[1].c_str()); else - REGISTER_INTERN::pass_register.at(args[1])->help(); + pass_register.at(args[1])->help(); return; } @@ -575,3 +676,5 @@ struct EchoPass : public Pass { } } EchoPass; +YOSYS_NAMESPACE_END + diff --git a/kernel/register.h b/kernel/register.h index 83e1059c6..a49675ed2 100644 --- a/kernel/register.h +++ b/kernel/register.h @@ -17,38 +17,33 @@ * */ +#include "kernel/yosys.h" + #ifndef REGISTER_H #define REGISTER_H -#include "kernel/rtlil.h" -#include <stdio.h> -#include <string> -#include <vector> -#include <map> - -#ifdef YOSYS_ENABLE_TCL -#include <tcl.h> -extern Tcl_Interp *yosys_get_tcl_interp(); -#endif - -// from kernel/version_*.o (cc source generated from Makefile) -extern const char *yosys_version_str; - -// implemented in driver.cc -extern RTLIL::Design *yosys_get_design(); -std::string rewrite_yosys_exe(std::string exe); -std::string get_share_file_name(std::string file); -const char *create_prompt(RTLIL::Design *design, int recursion_counter); +YOSYS_NAMESPACE_BEGIN struct Pass { std::string pass_name, short_help; Pass(std::string name, std::string short_help = "** document me **"); - virtual void run_register(); virtual ~Pass(); + virtual void help(); virtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0; + int call_counter; + int64_t runtime_ns; + + struct pre_post_exec_state_t { + Pass *parent_pass; + int64_t begin_ns; + }; + + pre_post_exec_state_t pre_execute(); + void post_execute(pre_post_exec_state_t state); + void cmd_log_args(const std::vector<std::string> &args); void cmd_error(const std::vector<std::string> &args, size_t argidx, std::string msg); void extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Design *design, bool select = true); @@ -56,27 +51,36 @@ struct Pass static void call(RTLIL::Design *design, std::string command); static void call(RTLIL::Design *design, std::vector<std::string> args); - static void call_newsel(RTLIL::Design *design, std::string command); - static void call_newsel(RTLIL::Design *design, std::vector<std::string> args); + static void call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command); + static void call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::vector<std::string> args); + + static void call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::string command); + static void call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vector<std::string> args); + Pass *next_queued_pass; + virtual void run_register(); static void init_register(); static void done_register(); }; struct Frontend : Pass { + // for reading of here documents + static FILE *current_script_file; + static std::string last_here_document; + std::string frontend_name; Frontend(std::string name, std::string short_help = "** document me **"); virtual void run_register(); virtual ~Frontend(); - virtual void execute(std::vector<std::string> args, RTLIL::Design *design); - virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0; + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) OVERRIDE FINAL; + virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0; static std::vector<std::string> next_args; - void extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx); + void extra_args(std::istream *&f, std::string &filename, std::vector<std::string> args, size_t argidx); - static void frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command); - static void frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args); + static void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command); + static void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::vector<std::string> args); }; struct Backend : Pass @@ -85,25 +89,22 @@ struct Backend : Pass Backend(std::string name, std::string short_help = "** document me **"); virtual void run_register(); virtual ~Backend(); - virtual void execute(std::vector<std::string> args, RTLIL::Design *design); - virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0; + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) OVERRIDE FINAL; + virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0; - void extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx); + void extra_args(std::ostream *&f, std::string &filename, std::vector<std::string> args, size_t argidx); - static void backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command); - static void backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args); + static void backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::string command); + static void backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::vector<std::string> args); }; // implemented in passes/cmds/select.cc extern void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t argidx, size_t args_size, RTLIL::Design *design); -namespace REGISTER_INTERN { - extern int raw_register_count; - extern bool raw_register_done; - extern Pass *raw_register_array[]; - extern std::map<std::string, Pass*> pass_register; - extern std::map<std::string, Frontend*> frontend_register; - extern std::map<std::string, Backend*> backend_register; -} +extern std::map<std::string, Pass*> pass_register; +extern std::map<std::string, Frontend*> frontend_register; +extern std::map<std::string, Backend*> backend_register; + +YOSYS_NAMESPACE_END #endif diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 396eaf110..00be796f8 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -17,16 +17,20 @@ * */ -#include "kernel/rtlil.h" -#include "kernel/log.h" +#include "kernel/yosys.h" +#include "kernel/macc.h" #include "frontends/verilog/verilog_frontend.h" #include "backends/ilang/ilang_backend.h" -#include <assert.h> #include <string.h> #include <algorithm> -int RTLIL::autoidx = 1; +YOSYS_NAMESPACE_BEGIN + +std::vector<int> RTLIL::IdString::global_refcount_storage_; +std::vector<char*> RTLIL::IdString::global_id_storage_; +std::map<char*, int, RTLIL::IdString::char_ptr_cmp> RTLIL::IdString::global_id_index_; +std::vector<int> RTLIL::IdString::global_free_idx_list_; RTLIL::Const::Const() { @@ -61,6 +65,13 @@ RTLIL::Const::Const(RTLIL::State bit, int width) bits.push_back(bit); } +RTLIL::Const::Const(const std::vector<bool> &bits) +{ + flags = RTLIL::CONST_FLAG_NONE; + for (auto b : bits) + this->bits.push_back(b ? RTLIL::S1 : RTLIL::S0); +} + bool RTLIL::Const::operator <(const RTLIL::Const &other) const { if (bits.size() != other.bits.size()) @@ -89,12 +100,15 @@ bool RTLIL::Const::as_bool() const return false; } -int RTLIL::Const::as_int() const +int RTLIL::Const::as_int(bool is_signed) const { - int ret = 0; + int32_t ret = 0; for (size_t i = 0; i < bits.size() && i < 32; i++) if (bits[i] == RTLIL::S1) ret |= 1 << i; + if (is_signed && bits.back() == RTLIL::S1) + for (size_t i = bits.size(); i < 32; i++) + ret |= 1 << i; return ret; } @@ -174,7 +188,7 @@ void RTLIL::Selection::optimize(RTLIL::Design *design) del_list.clear(); for (auto mod_name : selected_modules) { - if (design->modules.count(mod_name) == 0) + if (design->modules_.count(mod_name) == 0) del_list.push_back(mod_name); selected_members.erase(mod_name); } @@ -183,7 +197,7 @@ void RTLIL::Selection::optimize(RTLIL::Design *design) del_list.clear(); for (auto &it : selected_members) - if (design->modules.count(it.first) == 0) + if (design->modules_.count(it.first) == 0) del_list.push_back(it.first); for (auto mod_name : del_list) selected_members.erase(mod_name); @@ -191,7 +205,7 @@ void RTLIL::Selection::optimize(RTLIL::Design *design) for (auto &it : selected_members) { del_list.clear(); for (auto memb_name : it.second) - if (design->modules[it.first]->count_id(memb_name) == 0) + if (design->modules_[it.first]->count_id(memb_name) == 0) del_list.push_back(memb_name); for (auto memb_name : del_list) it.second.erase(memb_name); @@ -202,8 +216,8 @@ void RTLIL::Selection::optimize(RTLIL::Design *design) for (auto &it : selected_members) if (it.second.size() == 0) del_list.push_back(it.first); - else if (it.second.size() == design->modules[it.first]->wires.size() + design->modules[it.first]->memories.size() + - design->modules[it.first]->cells.size() + design->modules[it.first]->processes.size()) + else if (it.second.size() == design->modules_[it.first]->wires_.size() + design->modules_[it.first]->memories.size() + + design->modules_[it.first]->cells_.size() + design->modules_[it.first]->processes.size()) add_list.push_back(it.first); for (auto mod_name : del_list) selected_members.erase(mod_name); @@ -212,25 +226,140 @@ void RTLIL::Selection::optimize(RTLIL::Design *design) selected_modules.insert(mod_name); } - if (selected_modules.size() == design->modules.size()) { + if (selected_modules.size() == design->modules_.size()) { full_selection = true; selected_modules.clear(); selected_members.clear(); } } +RTLIL::Design::Design() +{ + refcount_modules_ = 0; + selection_stack.push_back(RTLIL::Selection()); +} + RTLIL::Design::~Design() { - for (auto it = modules.begin(); it != modules.end(); it++) + for (auto it = modules_.begin(); it != modules_.end(); it++) delete it->second; } +RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules() +{ + return RTLIL::ObjRange<RTLIL::Module*>(&modules_, &refcount_modules_); +} + +RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) +{ + return modules_.count(name) ? modules_.at(name) : NULL; +} + +void RTLIL::Design::add(RTLIL::Module *module) +{ + log_assert(modules_.count(module->name) == 0); + log_assert(refcount_modules_ == 0); + modules_[module->name] = module; + module->design = this; + + for (auto mon : monitors) + mon->notify_module_add(module); +} + +RTLIL::Module *RTLIL::Design::addModule(RTLIL::IdString name) +{ + log_assert(modules_.count(name) == 0); + log_assert(refcount_modules_ == 0); + + RTLIL::Module *module = new RTLIL::Module; + modules_[name] = module; + module->design = this; + module->name = name; + + for (auto mon : monitors) + mon->notify_module_add(module); + + return module; +} + +void RTLIL::Design::scratchpad_unset(std::string varname) +{ + scratchpad.erase(varname); +} + +void RTLIL::Design::scratchpad_set_int(std::string varname, int value) +{ + scratchpad[varname] = stringf("%d", value); +} + +void RTLIL::Design::scratchpad_set_bool(std::string varname, bool value) +{ + scratchpad[varname] = value ? "true" : "false"; +} + +void RTLIL::Design::scratchpad_set_string(std::string varname, std::string value) +{ + scratchpad[varname] = value; +} + +int RTLIL::Design::scratchpad_get_int(std::string varname, int default_value) const +{ + if (scratchpad.count(varname) == 0) + return default_value; + + std::string str = scratchpad.at(varname); + + if (str == "0" || str == "false") + return 0; + + if (str == "1" || str == "true") + return 1; + + char *endptr = nullptr; + long int parsed_value = strtol(str.c_str(), &endptr, 10); + return *endptr ? default_value : parsed_value; +} + +bool RTLIL::Design::scratchpad_get_bool(std::string varname, bool default_value) const +{ + if (scratchpad.count(varname) == 0) + return default_value; + + std::string str = scratchpad.at(varname); + + if (str == "0" || str == "false") + return false; + + if (str == "1" || str == "true") + return true; + + return default_value; +} + +std::string RTLIL::Design::scratchpad_get_string(std::string varname, std::string default_value) const +{ + if (scratchpad.count(varname) == 0) + return default_value; + return scratchpad.at(varname); +} + +void RTLIL::Design::remove(RTLIL::Module *module) +{ + for (auto mon : monitors) + mon->notify_module_del(module); + + log_assert(modules_.at(module->name) == module); + modules_.erase(module->name); + delete module; +} + void RTLIL::Design::check() { #ifndef NDEBUG - for (auto &it : modules) { - assert(it.first == it.second->name); - assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$')); + for (auto &it : modules_) { + log_assert(this == it.second->design); + log_assert(it.first == it.second->name); + log_assert(!it.first.empty()); it.second->check(); } #endif @@ -238,7 +367,7 @@ void RTLIL::Design::check() void RTLIL::Design::optimize() { - for (auto &it : modules) + for (auto &it : modules_) it.second->optimize(); for (auto &it : selection_stack) it.optimize(this); @@ -273,13 +402,62 @@ bool RTLIL::Design::selected_member(RTLIL::IdString mod_name, RTLIL::IdString me return selection_stack.back().selected_member(mod_name, memb_name); } +bool RTLIL::Design::selected_module(RTLIL::Module *mod) const +{ + return selected_module(mod->name); +} + +bool RTLIL::Design::selected_whole_module(RTLIL::Module *mod) const +{ + return selected_whole_module(mod->name); +} + +std::vector<RTLIL::Module*> RTLIL::Design::selected_modules() const +{ + std::vector<RTLIL::Module*> result; + result.reserve(modules_.size()); + for (auto &it : modules_) + if (selected_module(it.first)) + result.push_back(it.second); + return result; +} + +std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules() const +{ + std::vector<RTLIL::Module*> result; + result.reserve(modules_.size()); + for (auto &it : modules_) + if (selected_whole_module(it.first)) + result.push_back(it.second); + return result; +} + +std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn() const +{ + std::vector<RTLIL::Module*> result; + result.reserve(modules_.size()); + for (auto &it : modules_) + if (selected_whole_module(it.first)) + result.push_back(it.second); + else if (selected_module(it.first)) + log("Warning: Ignoring partially selected module %s.\n", log_id(it.first)); + return result; +} + +RTLIL::Module::Module() +{ + design = nullptr; + refcount_wires_ = 0; + refcount_cells_ = 0; +} + RTLIL::Module::~Module() { - for (auto it = wires.begin(); it != wires.end(); it++) + for (auto it = wires_.begin(); it != wires_.end(); it++) delete it->second; for (auto it = memories.begin(); it != memories.end(); it++) delete it->second; - for (auto it = cells.begin(); it != cells.end(); it++) + for (auto it = cells_.begin(); it != cells_.end(); it++) delete it->second; for (auto it = processes.begin(); it != processes.end(); it++) delete it->second; @@ -292,7 +470,7 @@ RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, std::map<RTLIL::IdString, size_t RTLIL::Module::count_id(RTLIL::IdString id) { - return wires.count(id) + memories.count(id) + cells.count(id) + processes.count(id); + return wires_.count(id) + memories.count(id) + cells_.count(id) + processes.count(id); } #ifndef NDEBUG @@ -307,17 +485,12 @@ namespace { void error(int linenr) { - char *ptr; - size_t size; - - FILE *f = open_memstream(&ptr, &size); - ILANG_BACKEND::dump_cell(f, " ", cell); - fputc(0, f); - fclose(f); + std::stringstream buf; + ILANG_BACKEND::dump_cell(buf, " ", cell); - log_error("Found error in internal cell %s.%s (%s) at %s:%d:\n%s", - module->name.c_str(), cell->name.c_str(), cell->type.c_str(), - __FILE__, linenr, ptr); + log_error("Found error in internal cell %s%s%s (%s) at %s:%d:\n%s", + module ? module->name.c_str() : "", module ? "." : "", + cell->name.c_str(), cell->type.c_str(), __FILE__, linenr, buf.str().c_str()); } int param(const char *name) @@ -347,9 +520,9 @@ namespace { void port(const char *name, int width) { - if (cell->connections.count(name) == 0) + if (!cell->hasPort(name)) error(__LINE__); - if (cell->connections.at(name).width != width) + if (cell->getPort(name).size() != width) error(__LINE__); expected_ports.insert(name); } @@ -359,7 +532,7 @@ namespace { for (auto ¶ : cell->parameters) if (expected_params.count(para.first) == 0) error(__LINE__); - for (auto &conn : cell->connections) + for (auto &conn : cell->connections()) if (expected_ports.count(conn.first) == 0) error(__LINE__); @@ -378,23 +551,27 @@ namespace { for (const char *p = ports; *p; p++) { char portname[3] = { '\\', *p, 0 }; - if (cell->connections.count(portname) == 0) + if (!cell->hasPort(portname)) error(__LINE__); - if (cell->connections.at(portname).width != 1) + if (cell->getPort(portname).size() != 1) error(__LINE__); } - for (auto &conn : cell->connections) { - if (conn.first.size() != 2 || conn.first.at(0) != '\\') + for (auto &conn : cell->connections()) { + if (conn.first.size() != 2 || conn.first[0] != '\\') error(__LINE__); - if (strchr(ports, conn.first.at(1)) == NULL) + if (strchr(ports, conn.first[1]) == NULL) error(__LINE__); } } void check() { - if (cell->type == "$not" || cell->type == "$pos" || cell->type == "$bu0" || cell->type == "$neg") { + if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" || + cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:") + return; + + if (cell->type.in("$not", "$pos", "$neg")) { param_bool("\\A_SIGNED"); port("\\A", param("\\A_WIDTH")); port("\\Y", param("\\Y_WIDTH")); @@ -402,7 +579,7 @@ namespace { return; } - if (cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor") { + if (cell->type.in("$and", "$or", "$xor", "$xnor")) { param_bool("\\A_SIGNED"); param_bool("\\B_SIGNED"); port("\\A", param("\\A_WIDTH")); @@ -412,8 +589,7 @@ namespace { return; } - if (cell->type == "$reduce_and" || cell->type == "$reduce_or" || cell->type == "$reduce_xor" || - cell->type == "$reduce_xnor" || cell->type == "$reduce_bool") { + if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool")) { param_bool("\\A_SIGNED"); port("\\A", param("\\A_WIDTH")); port("\\Y", param("\\Y_WIDTH")); @@ -421,7 +597,7 @@ namespace { return; } - if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr") { + if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx")) { param_bool("\\A_SIGNED"); param_bool("\\B_SIGNED"); port("\\A", param("\\A_WIDTH")); @@ -431,8 +607,7 @@ namespace { return; } - if (cell->type == "$lt" || cell->type == "$le" || cell->type == "$eq" || cell->type == "$ne" || - cell->type == "$eqx" || cell->type == "$nex" || cell->type == "$ge" || cell->type == "$gt") { + if (cell->type.in("$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt")) { param_bool("\\A_SIGNED"); param_bool("\\B_SIGNED"); port("\\A", param("\\A_WIDTH")); @@ -442,8 +617,7 @@ namespace { return; } - if (cell->type == "$add" || cell->type == "$sub" || cell->type == "$mul" || cell->type == "$div" || - cell->type == "$mod" || cell->type == "$pow") { + if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$pow")) { param_bool("\\A_SIGNED"); param_bool("\\B_SIGNED"); port("\\A", param("\\A_WIDTH")); @@ -453,6 +627,50 @@ namespace { return; } + if (cell->type == "$fa") { + port("\\A", param("\\WIDTH")); + port("\\B", param("\\WIDTH")); + port("\\C", param("\\WIDTH")); + port("\\X", param("\\WIDTH")); + port("\\Y", param("\\WIDTH")); + check_expected(); + return; + } + + if (cell->type == "$lcu") { + port("\\P", param("\\WIDTH")); + port("\\G", param("\\WIDTH")); + port("\\CI", 1); + port("\\CO", param("\\WIDTH")); + check_expected(); + return; + } + + if (cell->type == "$alu") { + param_bool("\\A_SIGNED"); + param_bool("\\B_SIGNED"); + port("\\A", param("\\A_WIDTH")); + port("\\B", param("\\B_WIDTH")); + port("\\CI", 1); + port("\\BI", 1); + port("\\X", param("\\Y_WIDTH")); + port("\\Y", param("\\Y_WIDTH")); + port("\\CO", param("\\Y_WIDTH")); + check_expected(); + return; + } + + if (cell->type == "$macc") { + param("\\CONFIG"); + param("\\CONFIG_WIDTH"); + port("\\A", param("\\A_WIDTH")); + port("\\B", param("\\B_WIDTH")); + port("\\Y", param("\\Y_WIDTH")); + check_expected(); + Macc().from_cell(cell); + return; + } + if (cell->type == "$logic_not") { param_bool("\\A_SIGNED"); port("\\A", param("\\A_WIDTH")); @@ -498,7 +716,7 @@ namespace { return; } - if (cell->type == "$pmux" || cell->type == "$safe_pmux") { + if (cell->type == "$pmux") { port("\\A", param("\\WIDTH")); port("\\B", param("\\WIDTH") * param("\\S_WIDTH")); port("\\S", param("\\S_WIDTH")); @@ -509,8 +727,8 @@ namespace { if (cell->type == "$lut") { param("\\LUT"); - port("\\I", param("\\WIDTH")); - port("\\O", 1); + port("\\A", param("\\WIDTH")); + port("\\Y", 1); check_expected(); return; } @@ -568,6 +786,19 @@ namespace { return; } + if (cell->type == "$dlatchsr") { + param_bool("\\EN_POLARITY"); + param_bool("\\SET_POLARITY"); + param_bool("\\CLR_POLARITY"); + port("\\EN", 1); + port("\\SET", param("\\WIDTH")); + port("\\CLR", param("\\WIDTH")); + port("\\D", param("\\WIDTH")); + port("\\Q", param("\\WIDTH")); + check_expected(); + return; + } + if (cell->type == "$fsm") { param("\\NAME"); param_bool("\\CLK_POLARITY"); @@ -605,7 +836,7 @@ namespace { param_bool("\\CLK_POLARITY"); param("\\PRIORITY"); port("\\CLK", 1); - port("\\EN", 1); + port("\\EN", param("\\WIDTH")); port("\\ADDR", param("\\ABITS")); port("\\DATA", param("\\WIDTH")); check_expected(); @@ -625,7 +856,7 @@ namespace { port("\\RD_ADDR", param("\\RD_PORTS") * param("\\ABITS")); port("\\RD_DATA", param("\\RD_PORTS") * param("\\WIDTH")); port("\\WR_CLK", param("\\WR_PORTS")); - port("\\WR_EN", param("\\WR_PORTS")); + port("\\WR_EN", param("\\WR_PORTS") * param("\\WIDTH")); port("\\WR_ADDR", param("\\WR_PORTS") * param("\\ABITS")); port("\\WR_DATA", param("\\WR_PORTS") * param("\\WIDTH")); check_expected(); @@ -639,11 +870,18 @@ namespace { return; } - if (cell->type == "$_INV_") { check_gate("AY"); return; } - if (cell->type == "$_AND_") { check_gate("ABY"); return; } - if (cell->type == "$_OR_") { check_gate("ABY"); return; } - if (cell->type == "$_XOR_") { check_gate("ABY"); return; } - if (cell->type == "$_MUX_") { check_gate("ABSY"); return; } + if (cell->type == "$_NOT_") { check_gate("AY"); return; } + if (cell->type == "$_AND_") { check_gate("ABY"); return; } + if (cell->type == "$_NAND_") { check_gate("ABY"); return; } + if (cell->type == "$_OR_") { check_gate("ABY"); return; } + if (cell->type == "$_NOR_") { check_gate("ABY"); return; } + if (cell->type == "$_XOR_") { check_gate("ABY"); return; } + if (cell->type == "$_XNOR_") { check_gate("ABY"); return; } + if (cell->type == "$_MUX_") { check_gate("ABSY"); return; } + if (cell->type == "$_AOI3_") { check_gate("ABCY"); return; } + if (cell->type == "$_OAI3_") { check_gate("ABCY"); return; } + if (cell->type == "$_AOI4_") { check_gate("ABCDY"); return; } + if (cell->type == "$_OAI4_") { check_gate("ABCDY"); return; } if (cell->type == "$_SR_NN_") { check_gate("SRQ"); return; } if (cell->type == "$_SR_NP_") { check_gate("SRQ"); return; } @@ -674,6 +912,15 @@ namespace { if (cell->type == "$_DLATCH_N_") { check_gate("EDQ"); return; } if (cell->type == "$_DLATCH_P_") { check_gate("EDQ"); return; } + if (cell->type == "$_DLATCHSR_NNN_") { check_gate("ESRDQ"); return; } + if (cell->type == "$_DLATCHSR_NNP_") { check_gate("ESRDQ"); return; } + if (cell->type == "$_DLATCHSR_NPN_") { check_gate("ESRDQ"); return; } + if (cell->type == "$_DLATCHSR_NPP_") { check_gate("ESRDQ"); return; } + if (cell->type == "$_DLATCHSR_PNN_") { check_gate("ESRDQ"); return; } + if (cell->type == "$_DLATCHSR_PNP_") { check_gate("ESRDQ"); return; } + if (cell->type == "$_DLATCHSR_PPN_") { check_gate("ESRDQ"); return; } + if (cell->type == "$_DLATCHSR_PPP_") { check_gate("ESRDQ"); return; } + error(__LINE__); } }; @@ -683,90 +930,93 @@ namespace { void RTLIL::Module::check() { #ifndef NDEBUG - for (auto &it : wires) { - assert(it.first == it.second->name); - assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$')); - assert(it.second->width >= 0); - assert(it.second->port_id >= 0); - for (auto &it2 : it.second->attributes) { - assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$')); - } + std::vector<bool> ports_declared; + for (auto &it : wires_) { + log_assert(this == it.second->module); + log_assert(it.first == it.second->name); + log_assert(!it.first.empty()); + log_assert(it.second->width >= 0); + log_assert(it.second->port_id >= 0); + for (auto &it2 : it.second->attributes) + log_assert(!it2.first.empty()); + if (it.second->port_id) { + log_assert(SIZE(ports) >= it.second->port_id); + log_assert(ports.at(it.second->port_id-1) == it.first); + log_assert(it.second->port_input || it.second->port_output); + if (SIZE(ports_declared) < it.second->port_id) + ports_declared.resize(it.second->port_id); + log_assert(ports_declared[it.second->port_id-1] == false); + ports_declared[it.second->port_id-1] = true; + } else + log_assert(!it.second->port_input && !it.second->port_output); } + for (auto port_declared : ports_declared) + log_assert(port_declared == true); + log_assert(SIZE(ports) == SIZE(ports_declared)); for (auto &it : memories) { - assert(it.first == it.second->name); - assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$')); - assert(it.second->width >= 0); - assert(it.second->size >= 0); - for (auto &it2 : it.second->attributes) { - assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$')); - } + log_assert(it.first == it.second->name); + log_assert(!it.first.empty()); + log_assert(it.second->width >= 0); + log_assert(it.second->size >= 0); + for (auto &it2 : it.second->attributes) + log_assert(!it2.first.empty()); } - for (auto &it : cells) { - assert(it.first == it.second->name); - assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$')); - assert(it.second->type.size() > 0 && (it.second->type[0] == '\\' || it.second->type[0] == '$')); - for (auto &it2 : it.second->connections) { - assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$')); + for (auto &it : cells_) { + log_assert(this == it.second->module); + log_assert(it.first == it.second->name); + log_assert(!it.first.empty()); + log_assert(!it.second->type.empty()); + for (auto &it2 : it.second->connections()) { + log_assert(!it2.first.empty()); it2.second.check(); } - for (auto &it2 : it.second->attributes) { - assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$')); - } - for (auto &it2 : it.second->parameters) { - assert(it2.first.size() > 0 && (it2.first[0] == '\\' || it2.first[0] == '$')); - } - if (it.second->type[0] == '$' && it.second->type.substr(0, 3) != "$__" && it.second->type.substr(0, 8) != "$paramod") { - InternalCellChecker checker(this, it.second); - checker.check(); - } + for (auto &it2 : it.second->attributes) + log_assert(!it2.first.empty()); + for (auto &it2 : it.second->parameters) + log_assert(!it2.first.empty()); + InternalCellChecker checker(this, it.second); + checker.check(); } for (auto &it : processes) { - assert(it.first == it.second->name); - assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$')); + log_assert(it.first == it.second->name); + log_assert(!it.first.empty()); // FIXME: More checks here.. } - for (auto &it : connections) { - assert(it.first.width == it.second.width); + for (auto &it : connections_) { + log_assert(it.first.size() == it.second.size()); it.first.check(); it.second.check(); } - for (auto &it : attributes) { - assert(it.first.size() > 0 && (it.first[0] == '\\' || it.first[0] == '$')); - } + for (auto &it : attributes) + log_assert(!it.first.empty()); #endif } void RTLIL::Module::optimize() { - for (auto &it : cells) - it.second->optimize(); - for (auto &it : processes) - it.second->optimize(); - for (auto &it : connections) { - it.first.optimize(); - it.second.optimize(); - } } void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const { - new_mod->name = name; - new_mod->connections = connections; + log_assert(new_mod->refcount_wires_ == 0); + log_assert(new_mod->refcount_cells_ == 0); + + new_mod->connections_ = connections_; new_mod->attributes = attributes; - for (auto &it : wires) - new_mod->wires[it.first] = new RTLIL::Wire(*it.second); + for (auto &it : wires_) + new_mod->addWire(it.first, it.second); for (auto &it : memories) new_mod->memories[it.first] = new RTLIL::Memory(*it.second); - for (auto &it : cells) - new_mod->cells[it.first] = new RTLIL::Cell(*it.second); + for (auto &it : cells_) + new_mod->addCell(it.first, it.second); for (auto &it : processes) new_mod->processes[it.first] = it.second->clone(); @@ -776,45 +1026,223 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const RTLIL::Module *mod; void operator()(RTLIL::SigSpec &sig) { - for (auto &c : sig.chunks) + std::vector<RTLIL::SigChunk> chunks = sig.chunks(); + for (auto &c : chunks) if (c.wire != NULL) - c.wire = mod->wires.at(c.wire->name); + c.wire = mod->wires_.at(c.wire->name); + sig = chunks; } }; RewriteSigSpecWorker rewriteSigSpecWorker; rewriteSigSpecWorker.mod = new_mod; new_mod->rewrite_sigspecs(rewriteSigSpecWorker); + new_mod->fixup_ports(); } RTLIL::Module *RTLIL::Module::clone() const { RTLIL::Module *new_mod = new RTLIL::Module; + new_mod->name = name; cloneInto(new_mod); return new_mod; } -RTLIL::Wire *RTLIL::Module::new_wire(int width, RTLIL::IdString name) +bool RTLIL::Module::has_memories() const { - RTLIL::Wire *wire = new RTLIL::Wire; - wire->width = width; - wire->name = name; - add(wire); - return wire; + return !memories.empty(); +} + +bool RTLIL::Module::has_processes() const +{ + return !processes.empty(); +} + +bool RTLIL::Module::has_memories_warn() const +{ + if (!memories.empty()) + log("Warning: Ignoring module %s because it contains memories (run 'memory' command first).\n", log_id(this)); + return !memories.empty(); +} + +bool RTLIL::Module::has_processes_warn() const +{ + if (!processes.empty()) + log("Warning: Ignoring module %s because it contains processes (run 'proc' command first).\n", log_id(this)); + return !processes.empty(); +} + +std::vector<RTLIL::Wire*> RTLIL::Module::selected_wires() const +{ + std::vector<RTLIL::Wire*> result; + result.reserve(wires_.size()); + for (auto &it : wires_) + if (design->selected(this, it.second)) + result.push_back(it.second); + return result; +} + +std::vector<RTLIL::Cell*> RTLIL::Module::selected_cells() const +{ + std::vector<RTLIL::Cell*> result; + result.reserve(wires_.size()); + for (auto &it : cells_) + if (design->selected(this, it.second)) + result.push_back(it.second); + return result; } void RTLIL::Module::add(RTLIL::Wire *wire) { - assert(!wire->name.empty()); - assert(count_id(wire->name) == 0); - wires[wire->name] = wire; + log_assert(!wire->name.empty()); + log_assert(count_id(wire->name) == 0); + log_assert(refcount_wires_ == 0); + wires_[wire->name] = wire; + wire->module = this; } void RTLIL::Module::add(RTLIL::Cell *cell) { - assert(!cell->name.empty()); - assert(count_id(cell->name) == 0); - cells[cell->name] = cell; + log_assert(!cell->name.empty()); + log_assert(count_id(cell->name) == 0); + log_assert(refcount_cells_ == 0); + cells_[cell->name] = cell; + cell->module = this; +} + +namespace { + struct DeleteWireWorker + { + RTLIL::Module *module; + const std::set<RTLIL::Wire*> *wires_p; + + void operator()(RTLIL::SigSpec &sig) { + std::vector<RTLIL::SigChunk> chunks = sig; + for (auto &c : chunks) + if (c.wire != NULL && wires_p->count(c.wire)) { + c.wire = module->addWire(NEW_ID, c.width); + c.offset = 0; + } + sig = chunks; + } + }; +} + +#if 0 +void RTLIL::Module::remove(RTLIL::Wire *wire) +{ + std::setPort<RTLIL::Wire*> wires_; + wires_.insert(wire); + remove(wires_); +} +#endif + +void RTLIL::Module::remove(const std::set<RTLIL::Wire*> &wires) +{ + log_assert(refcount_wires_ == 0); + + DeleteWireWorker delete_wire_worker; + delete_wire_worker.module = this; + delete_wire_worker.wires_p = &wires; + rewrite_sigspecs(delete_wire_worker); + + for (auto &it : wires) { + log_assert(wires_.count(it->name) != 0); + wires_.erase(it->name); + delete it; + } +} + +void RTLIL::Module::remove(RTLIL::Cell *cell) +{ + while (!cell->connections_.empty()) + cell->unsetPort(cell->connections_.begin()->first); + + log_assert(cells_.count(cell->name) != 0); + log_assert(refcount_cells_ == 0); + cells_.erase(cell->name); + delete cell; +} + +void RTLIL::Module::rename(RTLIL::Wire *wire, RTLIL::IdString new_name) +{ + log_assert(wires_[wire->name] == wire); + log_assert(refcount_wires_ == 0); + wires_.erase(wire->name); + wire->name = new_name; + add(wire); +} + +void RTLIL::Module::rename(RTLIL::Cell *cell, RTLIL::IdString new_name) +{ + log_assert(cells_[cell->name] == cell); + log_assert(refcount_wires_ == 0); + cells_.erase(cell->name); + cell->name = new_name; + add(cell); +} + +void RTLIL::Module::rename(RTLIL::IdString old_name, RTLIL::IdString new_name) +{ + log_assert(count_id(old_name) != 0); + if (wires_.count(old_name)) + rename(wires_.at(old_name), new_name); + else if (cells_.count(old_name)) + rename(cells_.at(old_name), new_name); + else + log_abort(); +} + +void RTLIL::Module::swap_names(RTLIL::Wire *w1, RTLIL::Wire *w2) +{ + log_assert(wires_[w1->name] == w1); + log_assert(wires_[w2->name] == w2); + log_assert(refcount_wires_ == 0); + + wires_.erase(w1->name); + wires_.erase(w2->name); + + std::swap(w1->name, w2->name); + + wires_[w1->name] = w1; + wires_[w2->name] = w2; +} + +void RTLIL::Module::swap_names(RTLIL::Cell *c1, RTLIL::Cell *c2) +{ + log_assert(cells_[c1->name] == c1); + log_assert(cells_[c2->name] == c2); + log_assert(refcount_cells_ == 0); + + cells_.erase(c1->name); + cells_.erase(c2->name); + + std::swap(c1->name, c2->name); + + cells_[c1->name] = c1; + cells_[c2->name] = c2; +} + +RTLIL::IdString RTLIL::Module::uniquify(RTLIL::IdString name) +{ + int index = 0; + return uniquify(name, index); +} + +RTLIL::IdString RTLIL::Module::uniquify(RTLIL::IdString name, int &index) +{ + if (index == 0) { + if (count_id(name) == 0) + return name; + index++; + } + + while (1) { + RTLIL::IdString new_name = stringf("%s_%d", name.c_str(), index); + if (count_id(new_name) == 0) + return new_name; + index++; + } } static bool fixup_ports_compare(const RTLIL::Wire *a, const RTLIL::Wire *b) @@ -829,28 +1257,459 @@ static bool fixup_ports_compare(const RTLIL::Wire *a, const RTLIL::Wire *b) return a->port_id < b->port_id; } +void RTLIL::Module::connect(const RTLIL::SigSig &conn) +{ + for (auto mon : monitors) + mon->notify_connect(this, conn); + + if (design) + for (auto mon : design->monitors) + mon->notify_connect(this, conn); + + connections_.push_back(conn); +} + +void RTLIL::Module::connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs) +{ + connect(RTLIL::SigSig(lhs, rhs)); +} + +void RTLIL::Module::new_connections(const std::vector<RTLIL::SigSig> &new_conn) +{ + for (auto mon : monitors) + mon->notify_connect(this, new_conn); + + if (design) + for (auto mon : design->monitors) + mon->notify_connect(this, new_conn); + + connections_ = new_conn; +} + +const std::vector<RTLIL::SigSig> &RTLIL::Module::connections() const +{ + return connections_; +} + void RTLIL::Module::fixup_ports() { std::vector<RTLIL::Wire*> all_ports; - for (auto &w : wires) + for (auto &w : wires_) if (w.second->port_input || w.second->port_output) all_ports.push_back(w.second); else w.second->port_id = 0; std::sort(all_ports.begin(), all_ports.end(), fixup_ports_compare); - for (size_t i = 0; i < all_ports.size(); i++) + + ports.clear(); + for (size_t i = 0; i < all_ports.size(); i++) { + ports.push_back(all_ports[i]->name); all_ports[i]->port_id = i+1; + } +} + +RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, int width) +{ + RTLIL::Wire *wire = new RTLIL::Wire; + wire->name = name; + wire->width = width; + add(wire); + return wire; } +RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, const RTLIL::Wire *other) +{ + RTLIL::Wire *wire = addWire(name); + wire->width = other->width; + wire->start_offset = other->start_offset; + wire->port_id = other->port_id; + wire->port_input = other->port_input; + wire->port_output = other->port_output; + wire->upto = other->upto; + wire->attributes = other->attributes; + return wire; +} + +RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, RTLIL::IdString type) +{ + RTLIL::Cell *cell = new RTLIL::Cell; + cell->name = name; + cell->type = type; + add(cell); + return cell; +} + +RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *other) +{ + RTLIL::Cell *cell = addCell(name, other->type); + cell->connections_ = other->connections_; + cell->parameters = other->parameters; + cell->attributes = other->attributes; + return cell; +} + +#define DEF_METHOD(_func, _y_size, _type) \ + RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed) { \ + RTLIL::Cell *cell = addCell(name, _type); \ + cell->parameters["\\A_SIGNED"] = is_signed; \ + cell->parameters["\\A_WIDTH"] = sig_a.size(); \ + cell->parameters["\\Y_WIDTH"] = sig_y.size(); \ + cell->setPort("\\A", sig_a); \ + cell->setPort("\\Y", sig_y); \ + return cell; \ + } \ + RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed) { \ + RTLIL::SigSpec sig_y = addWire(NEW_ID, _y_size); \ + add ## _func(name, sig_a, sig_y, is_signed); \ + return sig_y; \ + } +DEF_METHOD(Not, sig_a.size(), "$not") +DEF_METHOD(Pos, sig_a.size(), "$pos") +DEF_METHOD(Neg, sig_a.size(), "$neg") +DEF_METHOD(ReduceAnd, 1, "$reduce_and") +DEF_METHOD(ReduceOr, 1, "$reduce_or") +DEF_METHOD(ReduceXor, 1, "$reduce_xor") +DEF_METHOD(ReduceXnor, 1, "$reduce_xnor") +DEF_METHOD(ReduceBool, 1, "$reduce_bool") +DEF_METHOD(LogicNot, 1, "$logic_not") +#undef DEF_METHOD + +#define DEF_METHOD(_func, _y_size, _type) \ + RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed) { \ + RTLIL::Cell *cell = addCell(name, _type); \ + cell->parameters["\\A_SIGNED"] = is_signed; \ + cell->parameters["\\B_SIGNED"] = is_signed; \ + cell->parameters["\\A_WIDTH"] = sig_a.size(); \ + cell->parameters["\\B_WIDTH"] = sig_b.size(); \ + cell->parameters["\\Y_WIDTH"] = sig_y.size(); \ + cell->setPort("\\A", sig_a); \ + cell->setPort("\\B", sig_b); \ + cell->setPort("\\Y", sig_y); \ + return cell; \ + } \ + RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed) { \ + RTLIL::SigSpec sig_y = addWire(NEW_ID, _y_size); \ + 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(Shl, sig_a.size(), "$shl") +DEF_METHOD(Shr, sig_a.size(), "$shr") +DEF_METHOD(Sshl, sig_a.size(), "$sshl") +DEF_METHOD(Sshr, sig_a.size(), "$sshr") +DEF_METHOD(Shift, sig_a.size(), "$shift") +DEF_METHOD(Shiftx, sig_a.size(), "$shiftx") +DEF_METHOD(Lt, 1, "$lt") +DEF_METHOD(Le, 1, "$le") +DEF_METHOD(Eq, 1, "$eq") +DEF_METHOD(Ne, 1, "$ne") +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(LogicAnd, 1, "$logic_and") +DEF_METHOD(LogicOr, 1, "$logic_or") +#undef DEF_METHOD + +#define DEF_METHOD(_func, _type, _pmux) \ + RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y) { \ + RTLIL::Cell *cell = addCell(name, _type); \ + cell->parameters["\\WIDTH"] = sig_a.size(); \ + if (_pmux) cell->parameters["\\S_WIDTH"] = sig_s.size(); \ + cell->setPort("\\A", sig_a); \ + cell->setPort("\\B", sig_b); \ + cell->setPort("\\S", sig_s); \ + cell->setPort("\\Y", sig_y); \ + return cell; \ + } \ + RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s) { \ + RTLIL::SigSpec sig_y = addWire(NEW_ID, sig_a.size()); \ + add ## _func(name, sig_a, sig_b, sig_s, sig_y); \ + return sig_y; \ + } +DEF_METHOD(Mux, "$mux", 0) +DEF_METHOD(Pmux, "$pmux", 1) +#undef DEF_METHOD + +#define DEF_METHOD_2(_func, _type, _P1, _P2) \ + RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2) { \ + RTLIL::Cell *cell = addCell(name, _type); \ + cell->setPort("\\" #_P1, sig1); \ + cell->setPort("\\" #_P2, sig2); \ + return cell; \ + } \ + RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1) { \ + RTLIL::SigBit sig2 = addWire(NEW_ID); \ + add ## _func(name, sig1, sig2); \ + return sig2; \ + } +#define DEF_METHOD_3(_func, _type, _P1, _P2, _P3) \ + RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3) { \ + RTLIL::Cell *cell = addCell(name, _type); \ + cell->setPort("\\" #_P1, sig1); \ + cell->setPort("\\" #_P2, sig2); \ + cell->setPort("\\" #_P3, sig3); \ + return cell; \ + } \ + RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2) { \ + RTLIL::SigBit sig3 = addWire(NEW_ID); \ + add ## _func(name, sig1, sig2, sig3); \ + return sig3; \ + } +#define DEF_METHOD_4(_func, _type, _P1, _P2, _P3, _P4) \ + RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4) { \ + RTLIL::Cell *cell = addCell(name, _type); \ + cell->setPort("\\" #_P1, sig1); \ + cell->setPort("\\" #_P2, sig2); \ + cell->setPort("\\" #_P3, sig3); \ + cell->setPort("\\" #_P4, sig4); \ + return cell; \ + } \ + RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3) { \ + RTLIL::SigBit sig4 = addWire(NEW_ID); \ + add ## _func(name, sig1, sig2, sig3, sig4); \ + return sig4; \ + } +#define DEF_METHOD_5(_func, _type, _P1, _P2, _P3, _P4, _P5) \ + RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4, RTLIL::SigBit sig5) { \ + RTLIL::Cell *cell = addCell(name, _type); \ + cell->setPort("\\" #_P1, sig1); \ + cell->setPort("\\" #_P2, sig2); \ + cell->setPort("\\" #_P3, sig3); \ + cell->setPort("\\" #_P4, sig4); \ + cell->setPort("\\" #_P5, sig5); \ + return cell; \ + } \ + RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, RTLIL::SigBit sig1, RTLIL::SigBit sig2, RTLIL::SigBit sig3, RTLIL::SigBit sig4) { \ + RTLIL::SigBit sig5 = addWire(NEW_ID); \ + add ## _func(name, sig1, sig2, sig3, sig4, sig5); \ + return sig5; \ + } +DEF_METHOD_2(NotGate, "$_NOT_", A, Y) +DEF_METHOD_3(AndGate, "$_AND_", A, B, Y) +DEF_METHOD_3(NandGate, "$_NAND_", A, B, Y) +DEF_METHOD_3(OrGate, "$_OR_", A, B, Y) +DEF_METHOD_3(NorGate, "$_NOR_", A, B, Y) +DEF_METHOD_3(XorGate, "$_XOR_", A, B, Y) +DEF_METHOD_3(XnorGate, "$_XNOR_", A, B, Y) +DEF_METHOD_4(MuxGate, "$_MUX_", A, B, S, Y) +DEF_METHOD_4(Aoi3Gate, "$_AOI3_", A, B, C, Y) +DEF_METHOD_4(Oai3Gate, "$_OAI3_", A, B, C, Y) +DEF_METHOD_5(Aoi4Gate, "$_AOI4_", A, B, C, D, Y) +DEF_METHOD_5(Oai4Gate, "$_OAI4_", A, B, C, D, Y) +#undef DEF_METHOD_2 +#undef DEF_METHOD_3 +#undef DEF_METHOD_4 +#undef DEF_METHOD_5 + +RTLIL::Cell* RTLIL::Module::addPow(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool a_signed, bool b_signed) +{ + RTLIL::Cell *cell = addCell(name, "$pow"); + cell->parameters["\\A_SIGNED"] = a_signed; + cell->parameters["\\B_SIGNED"] = b_signed; + cell->parameters["\\A_WIDTH"] = sig_a.size(); + cell->parameters["\\B_WIDTH"] = sig_b.size(); + cell->parameters["\\Y_WIDTH"] = sig_y.size(); + cell->setPort("\\A", sig_a); + cell->setPort("\\B", sig_b); + cell->setPort("\\Y", sig_y); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addSlice(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const offset) +{ + RTLIL::Cell *cell = addCell(name, "$slice"); + cell->parameters["\\A_WIDTH"] = sig_a.size(); + cell->parameters["\\Y_WIDTH"] = sig_y.size(); + cell->parameters["\\OFFSET"] = offset; + cell->setPort("\\A", sig_a); + cell->setPort("\\Y", sig_y); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addConcat(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y) +{ + RTLIL::Cell *cell = addCell(name, "$concat"); + cell->parameters["\\A_WIDTH"] = sig_a.size(); + cell->parameters["\\B_WIDTH"] = sig_b.size(); + cell->setPort("\\A", sig_a); + cell->setPort("\\B", sig_b); + cell->setPort("\\Y", sig_y); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addLut(RTLIL::IdString name, RTLIL::SigSpec sig_i, RTLIL::SigSpec sig_o, 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); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en) +{ + RTLIL::Cell *cell = addCell(name, "$assert"); + cell->setPort("\\A", sig_a); + cell->setPort("\\EN", sig_en); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addSr(RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity, bool clr_polarity) +{ + RTLIL::Cell *cell = addCell(name, "$sr"); + cell->parameters["\\SET_POLARITY"] = set_polarity; + cell->parameters["\\CLR_POLARITY"] = clr_polarity; + cell->parameters["\\WIDTH"] = sig_q.size(); + cell->setPort("\\SET", sig_set); + cell->setPort("\\CLR", sig_clr); + cell->setPort("\\Q", sig_q); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addDff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity) +{ + RTLIL::Cell *cell = addCell(name, "$dff"); + cell->parameters["\\CLK_POLARITY"] = clk_polarity; + cell->parameters["\\WIDTH"] = sig_q.size(); + cell->setPort("\\CLK", sig_clk); + cell->setPort("\\D", sig_d); + cell->setPort("\\Q", sig_q); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addDffsr(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, + RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity) +{ + RTLIL::Cell *cell = addCell(name, "$dffsr"); + cell->parameters["\\CLK_POLARITY"] = clk_polarity; + cell->parameters["\\SET_POLARITY"] = set_polarity; + cell->parameters["\\CLR_POLARITY"] = clr_polarity; + cell->parameters["\\WIDTH"] = sig_q.size(); + cell->setPort("\\CLK", sig_clk); + cell->setPort("\\SET", sig_set); + cell->setPort("\\CLR", sig_clr); + cell->setPort("\\D", sig_d); + cell->setPort("\\Q", sig_q); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addAdff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, + RTLIL::Const arst_value, bool clk_polarity, bool arst_polarity) +{ + RTLIL::Cell *cell = addCell(name, "$adff"); + cell->parameters["\\CLK_POLARITY"] = clk_polarity; + cell->parameters["\\ARST_POLARITY"] = arst_polarity; + cell->parameters["\\ARST_VALUE"] = arst_value; + cell->parameters["\\WIDTH"] = sig_q.size(); + cell->setPort("\\CLK", sig_clk); + cell->setPort("\\ARST", sig_arst); + cell->setPort("\\D", sig_d); + cell->setPort("\\Q", sig_q); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addDlatch(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity) +{ + RTLIL::Cell *cell = addCell(name, "$dlatch"); + cell->parameters["\\EN_POLARITY"] = en_polarity; + cell->parameters["\\WIDTH"] = sig_q.size(); + cell->setPort("\\EN", sig_en); + cell->setPort("\\D", sig_d); + cell->setPort("\\Q", sig_q); + return cell; +} + +RTLIL::Cell* RTLIL::Module::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, bool set_polarity, bool clr_polarity) +{ + RTLIL::Cell *cell = addCell(name, "$dlatchsr"); + cell->parameters["\\EN_POLARITY"] = en_polarity; + cell->parameters["\\SET_POLARITY"] = set_polarity; + cell->parameters["\\CLR_POLARITY"] = clr_polarity; + cell->parameters["\\WIDTH"] = sig_q.size(); + cell->setPort("\\EN", sig_en); + cell->setPort("\\SET", sig_set); + cell->setPort("\\CLR", sig_clr); + cell->setPort("\\D", sig_d); + cell->setPort("\\Q", sig_q); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addDffGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity) +{ + RTLIL::Cell *cell = addCell(name, stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N')); + cell->setPort("\\C", sig_clk); + cell->setPort("\\D", sig_d); + cell->setPort("\\Q", sig_q); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addDffsrGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, + RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity) +{ + RTLIL::Cell *cell = addCell(name, stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N')); + cell->setPort("\\C", sig_clk); + cell->setPort("\\S", sig_set); + cell->setPort("\\R", sig_clr); + cell->setPort("\\D", sig_d); + cell->setPort("\\Q", sig_q); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addAdffGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, + bool arst_value, bool clk_polarity, bool arst_polarity) +{ + RTLIL::Cell *cell = addCell(name, stringf("$_DFF_%c%c%c_", clk_polarity ? 'P' : 'N', arst_polarity ? 'P' : 'N', arst_value ? '1' : '0')); + cell->setPort("\\C", sig_clk); + cell->setPort("\\R", sig_arst); + cell->setPort("\\D", sig_d); + cell->setPort("\\Q", sig_q); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addDlatchGate(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity) +{ + RTLIL::Cell *cell = addCell(name, stringf("$_DLATCH_%c_", en_polarity ? 'P' : 'N')); + cell->setPort("\\E", sig_en); + cell->setPort("\\D", sig_d); + cell->setPort("\\Q", sig_q); + return cell; +} + +RTLIL::Cell* RTLIL::Module::addDlatchsrGate(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, bool set_polarity, bool clr_polarity) +{ + RTLIL::Cell *cell = addCell(name, stringf("$_DLATCHSR_%c%c%c_", en_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N')); + cell->setPort("\\E", sig_en); + cell->setPort("\\S", sig_set); + cell->setPort("\\R", sig_clr); + cell->setPort("\\D", sig_d); + cell->setPort("\\Q", sig_q); + return cell; +} + + RTLIL::Wire::Wire() { + module = nullptr; width = 1; start_offset = 0; port_id = 0; port_input = false; port_output = false; + upto = false; } RTLIL::Memory::Memory() @@ -859,10 +1718,146 @@ RTLIL::Memory::Memory() size = 0; } -void RTLIL::Cell::optimize() +RTLIL::Cell::Cell() : module(nullptr) +{ +} + +bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const +{ + return connections_.count(portname) != 0; +} + +void RTLIL::Cell::unsetPort(RTLIL::IdString portname) +{ + RTLIL::SigSpec signal; + auto conn_it = connections_.find(portname); + + if (conn_it != connections_.end()) + { + for (auto mon : module->monitors) + mon->notify_connect(this, conn_it->first, conn_it->second, signal); + + if (module->design) + for (auto mon : module->design->monitors) + mon->notify_connect(this, conn_it->first, conn_it->second, signal); + + connections_.erase(conn_it); + } +} + +void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal) +{ + auto conn_it = connections_.find(portname); + + if (conn_it == connections_.end()) { + connections_[portname] = RTLIL::SigSpec(); + conn_it = connections_.find(portname); + log_assert(conn_it != connections_.end()); + } + + for (auto mon : module->monitors) + mon->notify_connect(this, conn_it->first, conn_it->second, signal); + + if (module->design) + for (auto mon : module->design->monitors) + mon->notify_connect(this, conn_it->first, conn_it->second, signal); + + conn_it->second = signal; +} + +const RTLIL::SigSpec &RTLIL::Cell::getPort(RTLIL::IdString portname) const +{ + return connections_.at(portname); +} + +const std::map<RTLIL::IdString, RTLIL::SigSpec> &RTLIL::Cell::connections() const +{ + return connections_; +} + +bool RTLIL::Cell::hasParam(RTLIL::IdString paramname) const +{ + return parameters.count(paramname); +} + +void RTLIL::Cell::unsetParam(RTLIL::IdString paramname) +{ + parameters.erase(paramname); +} + +void RTLIL::Cell::setParam(RTLIL::IdString paramname, RTLIL::Const value) { - for (auto &it : connections) - it.second.optimize(); + parameters[paramname] = value; +} + +const RTLIL::Const &RTLIL::Cell::getParam(RTLIL::IdString paramname) const +{ + return parameters.at(paramname); +} + +void RTLIL::Cell::check() +{ +#ifndef NDEBUG + InternalCellChecker checker(NULL, this); + checker.check(); +#endif +} + +void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) +{ + if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" || + type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:") + return; + + if (type == "$mux" || type == "$pmux") { + parameters["\\WIDTH"] = SIZE(connections_["\\Y"]); + if (type == "$pmux") + parameters["\\S_WIDTH"] = SIZE(connections_["\\S"]); + check(); + return; + } + + if (type == "$lut") { + parameters["\\WIDTH"] = SIZE(connections_["\\A"]); + return; + } + + if (type == "$fa") { + parameters["\\WIDTH"] = SIZE(connections_["\\Y"]); + return; + } + + if (type == "$lcu") { + parameters["\\WIDTH"] = SIZE(connections_["\\CO"]); + return; + } + + bool signedness_ab = !type.in("$slice", "$concat", "$macc"); + + if (connections_.count("\\A")) { + if (signedness_ab) { + if (set_a_signed) + parameters["\\A_SIGNED"] = true; + else if (parameters.count("\\A_SIGNED") == 0) + parameters["\\A_SIGNED"] = false; + } + parameters["\\A_WIDTH"] = SIZE(connections_["\\A"]); + } + + if (connections_.count("\\B")) { + if (signedness_ab) { + if (set_b_signed) + parameters["\\B_SIGNED"] = true; + else if (parameters.count("\\B_SIGNED") == 0) + parameters["\\B_SIGNED"] = false; + } + parameters["\\B_WIDTH"] = SIZE(connections_["\\B"]); + } + + if (connections_.count("\\Y")) + parameters["\\Y_WIDTH"] = SIZE(connections_["\\Y"]); + + check(); } RTLIL::SigChunk::SigChunk() @@ -872,51 +1867,62 @@ RTLIL::SigChunk::SigChunk() offset = 0; } -RTLIL::SigChunk::SigChunk(const RTLIL::Const &data) +RTLIL::SigChunk::SigChunk(const RTLIL::Const &value) { wire = NULL; - this->data = data; - width = data.bits.size(); + data = value.bits; + width = SIZE(data); offset = 0; } -RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire, int width, int offset) +RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire) +{ + log_assert(wire != nullptr); + this->wire = wire; + this->width = wire->width; + this->offset = 0; +} + +RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire, int offset, int width) { + log_assert(wire != nullptr); this->wire = wire; - this->width = width >= 0 ? width : wire->width; + this->width = width; this->offset = offset; } RTLIL::SigChunk::SigChunk(const std::string &str) { wire = NULL; - data = RTLIL::Const(str); - width = data.bits.size(); + data = RTLIL::Const(str).bits; + width = SIZE(data); offset = 0; } RTLIL::SigChunk::SigChunk(int val, int width) { wire = NULL; - data = RTLIL::Const(val, width); - this->width = data.bits.size(); + data = RTLIL::Const(val, width).bits; + this->width = SIZE(data); offset = 0; } RTLIL::SigChunk::SigChunk(RTLIL::State bit, int width) { wire = NULL; - data = RTLIL::Const(bit, width); - this->width = data.bits.size(); + data = RTLIL::Const(bit, width).bits; + this->width = SIZE(data); offset = 0; } RTLIL::SigChunk::SigChunk(RTLIL::SigBit bit) { wire = bit.wire; + offset = 0; if (wire == NULL) - data = RTLIL::Const(bit.data); - offset = bit.offset; + data = RTLIL::Const(bit.data).bits; + else + offset = bit.offset; width = 1; } @@ -929,7 +1935,7 @@ RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const ret.width = length; } else { for (int i = 0; i < length; i++) - ret.data.bits.push_back(data.bits[offset+i]); + ret.data.push_back(data[offset+i]); ret.width = length; } return ret; @@ -940,6 +1946,7 @@ bool RTLIL::SigChunk::operator <(const RTLIL::SigChunk &other) const if (wire && other.wire) if (wire->name != other.wire->name) return wire->name < other.wire->name; + if (wire != other.wire) return wire < other.wire; @@ -949,19 +1956,12 @@ bool RTLIL::SigChunk::operator <(const RTLIL::SigChunk &other) const if (width != other.width) return width < other.width; - if (data.bits != other.data.bits) - return data.bits < other.data.bits; - - return false; + return data < other.data; } bool RTLIL::SigChunk::operator ==(const RTLIL::SigChunk &other) const { - if (wire != other.wire || width != other.width || offset != other.offset) - return false; - if (data.bits != other.data.bits) - return false; - return true; + return wire == other.wire && width == other.width && offset == other.offset && data == other.data; } bool RTLIL::SigChunk::operator !=(const RTLIL::SigChunk &other) const @@ -973,146 +1973,274 @@ bool RTLIL::SigChunk::operator !=(const RTLIL::SigChunk &other) const RTLIL::SigSpec::SigSpec() { - width = 0; + width_ = 0; + hash_ = 0; +} + +RTLIL::SigSpec::SigSpec(const RTLIL::SigSpec &other) +{ + *this = other; +} + +RTLIL::SigSpec::SigSpec(std::initializer_list<RTLIL::SigSpec> parts) +{ + cover("kernel.rtlil.sigspec.init.list"); + + width_ = 0; + hash_ = 0; + + std::vector<RTLIL::SigSpec> parts_vec(parts.begin(), parts.end()); + for (auto it = parts_vec.rbegin(); it != parts_vec.rend(); it++) + append(*it); +} + +const RTLIL::SigSpec &RTLIL::SigSpec::operator=(const RTLIL::SigSpec &other) +{ + cover("kernel.rtlil.sigspec.assign"); + + width_ = other.width_; + hash_ = other.hash_; + chunks_ = other.chunks_; + bits_.clear(); + + if (!other.bits_.empty()) + { + RTLIL::SigChunk *last = NULL; + int last_end_offset = 0; + + for (auto &bit : other.bits_) { + if (last && bit.wire == last->wire) { + if (bit.wire == NULL) { + last->data.push_back(bit.data); + last->width++; + continue; + } else if (last_end_offset == bit.offset) { + last_end_offset++; + last->width++; + continue; + } + } + chunks_.push_back(bit); + last = &chunks_.back(); + last_end_offset = bit.offset + 1; + } + + check(); + } + + return *this; } -RTLIL::SigSpec::SigSpec(const RTLIL::Const &data) +RTLIL::SigSpec::SigSpec(const RTLIL::Const &value) { - chunks.push_back(RTLIL::SigChunk(data)); - width = chunks.back().width; + cover("kernel.rtlil.sigspec.init.const"); + + chunks_.push_back(RTLIL::SigChunk(value)); + width_ = chunks_.back().width; + hash_ = 0; check(); } RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk) { - chunks.push_back(chunk); - width = chunks.back().width; + cover("kernel.rtlil.sigspec.init.chunk"); + + chunks_.push_back(chunk); + width_ = chunks_.back().width; + hash_ = 0; + check(); +} + +RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire) +{ + cover("kernel.rtlil.sigspec.init.wire"); + + chunks_.push_back(RTLIL::SigChunk(wire)); + width_ = chunks_.back().width; + hash_ = 0; check(); } -RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int width, int offset) +RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width) { - chunks.push_back(RTLIL::SigChunk(wire, width, offset)); - this->width = chunks.back().width; + cover("kernel.rtlil.sigspec.init.wire_part"); + + chunks_.push_back(RTLIL::SigChunk(wire, offset, width)); + width_ = chunks_.back().width; + hash_ = 0; check(); } RTLIL::SigSpec::SigSpec(const std::string &str) { - chunks.push_back(RTLIL::SigChunk(str)); - width = chunks.back().width; + cover("kernel.rtlil.sigspec.init.str"); + + chunks_.push_back(RTLIL::SigChunk(str)); + width_ = chunks_.back().width; + hash_ = 0; check(); } RTLIL::SigSpec::SigSpec(int val, int width) { - chunks.push_back(RTLIL::SigChunk(val, width)); - this->width = width; + cover("kernel.rtlil.sigspec.init.int"); + + chunks_.push_back(RTLIL::SigChunk(val, width)); + width_ = width; + hash_ = 0; check(); } RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width) { - chunks.push_back(RTLIL::SigChunk(bit, width)); - this->width = width; + cover("kernel.rtlil.sigspec.init.state"); + + chunks_.push_back(RTLIL::SigChunk(bit, width)); + width_ = width; + hash_ = 0; check(); } RTLIL::SigSpec::SigSpec(RTLIL::SigBit bit, int width) { + cover("kernel.rtlil.sigspec.init.bit"); + if (bit.wire == NULL) - chunks.push_back(RTLIL::SigChunk(bit.data, width)); + chunks_.push_back(RTLIL::SigChunk(bit.data, width)); else for (int i = 0; i < width; i++) - chunks.push_back(bit); - this->width = width; + chunks_.push_back(bit); + width_ = width; + hash_ = 0; + check(); +} + +RTLIL::SigSpec::SigSpec(std::vector<RTLIL::SigChunk> chunks) +{ + cover("kernel.rtlil.sigspec.init.stdvec_chunks"); + + width_ = 0; + hash_ = 0; + for (auto &c : chunks) + append(c); check(); } RTLIL::SigSpec::SigSpec(std::vector<RTLIL::SigBit> bits) { - chunks.reserve(bits.size()); + cover("kernel.rtlil.sigspec.init.stdvec_bits"); + + width_ = 0; + hash_ = 0; for (auto &bit : bits) - chunks.push_back(bit); - this->width = bits.size(); + append_bit(bit); check(); } -void RTLIL::SigSpec::expand() +RTLIL::SigSpec::SigSpec(std::set<RTLIL::SigBit> bits) { - std::vector<RTLIL::SigChunk> new_chunks; - for (size_t i = 0; i < chunks.size(); i++) { - for (int j = 0; j < chunks[i].width; j++) - new_chunks.push_back(chunks[i].extract(j, 1)); - } - chunks.swap(new_chunks); + cover("kernel.rtlil.sigspec.init.stdset_bits"); + + width_ = 0; + hash_ = 0; + for (auto &bit : bits) + append_bit(bit); check(); } -void RTLIL::SigSpec::optimize() +void RTLIL::SigSpec::pack() const { - std::vector<RTLIL::SigChunk> new_chunks; - for (auto &c : chunks) - if (new_chunks.size() == 0) { - new_chunks.push_back(c); - } else { - RTLIL::SigChunk &cc = new_chunks.back(); - if (c.wire == NULL && cc.wire == NULL) - cc.data.bits.insert(cc.data.bits.end(), c.data.bits.begin(), c.data.bits.end()); - if (c.wire == cc.wire && (c.wire == NULL || cc.offset + cc.width == c.offset)) - cc.width += c.width; - else - new_chunks.push_back(c); + RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; + + if (that->bits_.empty()) + return; + + cover("kernel.rtlil.sigspec.convert.pack"); + log_assert(that->chunks_.empty()); + + std::vector<RTLIL::SigBit> old_bits; + old_bits.swap(that->bits_); + + RTLIL::SigChunk *last = NULL; + int last_end_offset = 0; + + for (auto &bit : old_bits) { + if (last && bit.wire == last->wire) { + if (bit.wire == NULL) { + last->data.push_back(bit.data); + last->width++; + continue; + } else if (last_end_offset == bit.offset) { + last_end_offset++; + last->width++; + continue; + } } - chunks.swap(new_chunks); + that->chunks_.push_back(bit); + last = &that->chunks_.back(); + last_end_offset = bit.offset + 1; + } + check(); } -RTLIL::SigSpec RTLIL::SigSpec::optimized() const +void RTLIL::SigSpec::unpack() const { - RTLIL::SigSpec ret = *this; - ret.optimize(); - return ret; + RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; + + if (that->chunks_.empty()) + return; + + cover("kernel.rtlil.sigspec.convert.unpack"); + log_assert(that->bits_.empty()); + + that->bits_.reserve(that->width_); + for (auto &c : that->chunks_) + for (int i = 0; i < c.width; i++) + that->bits_.push_back(RTLIL::SigBit(c, i)); + + that->chunks_.clear(); + that->hash_ = 0; } -bool RTLIL::SigChunk::compare(const RTLIL::SigChunk &a, const RTLIL::SigChunk &b) +#define DJB2(_hash, _value) do { (_hash) = (((_hash) << 5) + (_hash)) + (_value); } while (0) + +void RTLIL::SigSpec::hash() const { - if (a.wire != b.wire) { - if (a.wire == NULL || b.wire == NULL) - return a.wire < b.wire; - else if (a.wire->name != b.wire->name) - return a.wire->name < b.wire->name; - else - return a.wire < b.wire; - } - if (a.offset != b.offset) - return a.offset < b.offset; - if (a.width != b.width) - return a.width < b.width; - return a.data.bits < b.data.bits; + RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; + + if (that->hash_ != 0) + return; + + cover("kernel.rtlil.sigspec.hash"); + that->pack(); + + that->hash_ = 5381; + for (auto &c : that->chunks_) + if (c.wire == NULL) { + for (auto &v : c.data) + DJB2(that->hash_, v); + } else { + DJB2(that->hash_, c.wire->name.index_); + DJB2(that->hash_, c.offset); + DJB2(that->hash_, c.width); + } + + if (that->hash_ == 0) + that->hash_ = 1; } void RTLIL::SigSpec::sort() { - expand(); - std::sort(chunks.begin(), chunks.end(), RTLIL::SigChunk::compare); - optimize(); + unpack(); + cover("kernel.rtlil.sigspec.sort"); + std::sort(bits_.begin(), bits_.end()); } void RTLIL::SigSpec::sort_and_unify() { - expand(); - std::sort(chunks.begin(), chunks.end(), RTLIL::SigChunk::compare); - for (size_t i = 1; i < chunks.size(); i++) { - RTLIL::SigChunk &ch1 = chunks[i-1]; - RTLIL::SigChunk &ch2 = chunks[i]; - if (!RTLIL::SigChunk::compare(ch1, ch2) && !RTLIL::SigChunk::compare(ch2, ch1)) { - chunks.erase(chunks.begin()+i); - width -= chunks[i].width; - i--; - } - } - optimize(); + cover("kernel.rtlil.sigspec.sort_and_unify"); + *this = this->to_sigbit_set(); } void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with) @@ -1122,29 +2250,42 @@ 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 { - int pos = 0, restart_pos = 0; - assert(other == NULL || width == other->width); - for (size_t i = 0; i < chunks.size(); i++) { -restart: - const RTLIL::SigChunk &ch1 = chunks[i]; - if (chunks[i].wire != NULL && pos >= restart_pos) - for (size_t j = 0, poff = 0; j < pattern.chunks.size(); j++) { - const RTLIL::SigChunk &ch2 = pattern.chunks[j]; - assert(ch2.wire != NULL); - if (ch1.wire == ch2.wire) { - int lower = std::max(ch1.offset, ch2.offset); - int upper = std::min(ch1.offset + ch1.width, ch2.offset + ch2.width); - if (lower < upper) { - restart_pos = pos+upper-ch1.offset; - other->replace(pos+lower-ch1.offset, with.extract(poff+lower-ch2.offset, upper-lower)); - goto restart; - } - } - poff += ch2.width; - } - pos += chunks[i].width; + log_assert(pattern.width_ == with.width_); + + pattern.unpack(); + with.unpack(); + + std::map<RTLIL::SigBit, RTLIL::SigBit> rules; + + for (int i = 0; i < SIZE(pattern.bits_); i++) + if (pattern.bits_[i].wire != NULL) + rules[pattern.bits_[i]] = with.bits_[i]; + + replace(rules, other); +} + +void RTLIL::SigSpec::replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules) +{ + replace(rules, this); +} + +void RTLIL::SigSpec::replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const +{ + cover("kernel.rtlil.sigspec.replace"); + + log_assert(other != NULL); + log_assert(width_ == other->width_); + + unpack(); + other->unpack(); + + for (int i = 0; i < SIZE(bits_); i++) { + auto it = rules.find(bits_[i]); + if (it != rules.end()) + other->bits_[i] = it->second; } - check(); + + other->check(); } void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern) @@ -1160,49 +2301,91 @@ void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) { - int pos = 0; - assert(other == NULL || width == other->width); - for (size_t i = 0; i < chunks.size(); i++) { -restart: - const RTLIL::SigChunk &ch1 = chunks[i]; - if (chunks[i].wire != NULL) - for (size_t j = 0; j < pattern.chunks.size(); j++) { - const RTLIL::SigChunk &ch2 = pattern.chunks[j]; - assert(ch2.wire != NULL); - if (ch1.wire == ch2.wire) { - int lower = std::max(ch1.offset, ch2.offset); - int upper = std::min(ch1.offset + ch1.width, ch2.offset + ch2.width); - if (lower < upper) { - if (other) - other->remove(pos+lower-ch1.offset, upper-lower); - remove(pos+lower-ch1.offset, upper-lower); - if (i == chunks.size()) - break; - goto restart; - } - } - } - pos += chunks[i].width; + std::set<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_set(); + remove2(pattern_bits, other); +} + +void RTLIL::SigSpec::remove(const std::set<RTLIL::SigBit> &pattern) +{ + remove2(pattern, NULL); +} + +void RTLIL::SigSpec::remove(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const +{ + RTLIL::SigSpec tmp = *this; + tmp.remove2(pattern, other); +} + +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) { + log_assert(width_ == other->width_); + other->unpack(); + } + + std::vector<RTLIL::SigBit> new_bits, new_other_bits; + + new_bits.resize(SIZE(bits_)); + if (other != NULL) + new_other_bits.resize(SIZE(bits_)); + + int k = 0; + for (int i = 0; i < SIZE(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]; + } + + new_bits.resize(k); + if (other != NULL) + new_other_bits.resize(k); + + bits_.swap(new_bits); + width_ = SIZE(bits_); + + if (other != NULL) { + other->bits_.swap(new_other_bits); + other->width_ = SIZE(other->bits_); } + check(); } -RTLIL::SigSpec RTLIL::SigSpec::extract(RTLIL::SigSpec pattern, RTLIL::SigSpec *other) const +RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other) const { - assert(other == NULL || width == other->width); + std::set<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_set(); + return extract(pattern_bits, other); +} + +RTLIL::SigSpec RTLIL::SigSpec::extract(const std::set<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other) const +{ + if (other) + cover("kernel.rtlil.sigspec.extract_other"); + else + cover("kernel.rtlil.sigspec.extract"); + + log_assert(other == NULL || width_ == other->width_); - std::set<RTLIL::SigBit> pat = pattern.to_sigbit_set(); std::vector<RTLIL::SigBit> bits_match = to_sigbit_vector(); RTLIL::SigSpec ret; if (other) { - std::vector<RTLIL::SigBit> bits_other = other ? other->to_sigbit_vector() : bits_match; - for (int i = 0; i < width; i++) - if (bits_match[i].wire && pat.count(bits_match[i])) + std::vector<RTLIL::SigBit> bits_other = other->to_sigbit_vector(); + for (int i = 0; i < width_; i++) + if (bits_match[i].wire && pattern.count(bits_match[i])) ret.append_bit(bits_other[i]); } else { - for (int i = 0; i < width; i++) - if (bits_match[i].wire && pat.count(bits_match[i])) + for (int i = 0; i < width_; i++) + if (bits_match[i].wire && pattern.count(bits_match[i])) ret.append_bit(bits_match[i]); } @@ -1212,259 +2395,326 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(RTLIL::SigSpec pattern, RTLIL::SigSpec *o void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) { - int pos = 0; - assert(offset >= 0); - assert(with.width >= 0); - assert(offset+with.width <= width); - remove(offset, with.width); - for (size_t i = 0; i < chunks.size(); i++) { - if (pos == offset) { - chunks.insert(chunks.begin()+i, with.chunks.begin(), with.chunks.end()); - width += with.width; - check(); - return; - } - pos += chunks[i].width; - } - assert(pos == offset); - chunks.insert(chunks.end(), with.chunks.begin(), with.chunks.end()); - width += with.width; + cover("kernel.rtlil.sigspec.replace_pos"); + + unpack(); + with.unpack(); + + log_assert(offset >= 0); + log_assert(with.width_ >= 0); + log_assert(offset+with.width_ <= width_); + + for (int i = 0; i < with.width_; i++) + bits_.at(offset + i) = with.bits_.at(i); + check(); } void RTLIL::SigSpec::remove_const() { - for (size_t i = 0; i < chunks.size(); i++) { - if (chunks[i].wire != NULL) - continue; - width -= chunks[i].width; - chunks.erase(chunks.begin() + (i--)); + if (packed()) + { + cover("kernel.rtlil.sigspec.remove_const.packed"); + + std::vector<RTLIL::SigChunk> new_chunks; + new_chunks.reserve(SIZE(chunks_)); + + width_ = 0; + for (auto &chunk : chunks_) + if (chunk.wire != NULL) { + new_chunks.push_back(chunk); + width_ += chunk.width; + } + + chunks_.swap(new_chunks); + } + else + { + cover("kernel.rtlil.sigspec.remove_const.unpacked"); + + std::vector<RTLIL::SigBit> new_bits; + new_bits.reserve(width_); + + for (auto &bit : bits_) + if (bit.wire != NULL) + new_bits.push_back(bit); + + bits_.swap(new_bits); + width_ = bits_.size(); } + check(); } void RTLIL::SigSpec::remove(int offset, int length) { - int pos = 0; - assert(offset >= 0); - assert(length >= 0); - assert(offset+length <= width); - for (size_t i = 0; i < chunks.size(); i++) { - int orig_width = chunks[i].width; - if (pos+chunks[i].width > offset && pos < offset+length) { - int off = offset - pos; - int len = length; - if (off < 0) { - len += off; - off = 0; - } - if (len > chunks[i].width-off) - len = chunks[i].width-off; - RTLIL::SigChunk lsb_chunk = chunks[i].extract(0, off); - RTLIL::SigChunk msb_chunk = chunks[i].extract(off+len, chunks[i].width-off-len); - if (lsb_chunk.width == 0 && msb_chunk.width == 0) { - chunks.erase(chunks.begin()+i); - i--; - } else if (lsb_chunk.width == 0 && msb_chunk.width != 0) { - chunks[i] = msb_chunk; - } else if (lsb_chunk.width != 0 && msb_chunk.width == 0) { - chunks[i] = lsb_chunk; - } else if (lsb_chunk.width != 0 && msb_chunk.width != 0) { - chunks[i] = lsb_chunk; - chunks.insert(chunks.begin()+i+1, msb_chunk); - i++; - } else - assert(0); - width -= len; - } - pos += orig_width; - } + cover("kernel.rtlil.sigspec.remove_pos"); + + unpack(); + + log_assert(offset >= 0); + log_assert(length >= 0); + log_assert(offset + length <= width_); + + bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); + width_ = bits_.size(); + check(); } RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const { - int pos = 0; - RTLIL::SigSpec ret; - assert(offset >= 0); - assert(length >= 0); - assert(offset+length <= width); - for (size_t i = 0; i < chunks.size(); i++) { - if (pos+chunks[i].width > offset && pos < offset+length) { - int off = offset - pos; - int len = length; - if (off < 0) { - len += off; - off = 0; - } - if (len > chunks[i].width-off) - len = chunks[i].width-off; - ret.chunks.push_back(chunks[i].extract(off, len)); - ret.width += len; - offset += len; - length -= len; - } - pos += chunks[i].width; - } - assert(length == 0); - ret.check(); - return ret; + unpack(); + cover("kernel.rtlil.sigspec.extract_pos"); + return std::vector<RTLIL::SigBit>(bits_.begin() + offset, bits_.begin() + offset + length); } void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) { - for (size_t i = 0; i < signal.chunks.size(); i++) { - chunks.push_back(signal.chunks[i]); - width += signal.chunks[i].width; + if (signal.width_ == 0) + return; + + if (width_ == 0) { + *this = signal; + return; } - // check(); -} -void RTLIL::SigSpec::append_bit(const RTLIL::SigBit &bit) -{ - if (chunks.size() == 0) - chunks.push_back(bit); + cover("kernel.rtlil.sigspec.append"); + + if (packed() != signal.packed()) { + pack(); + signal.pack(); + } + + if (packed()) + for (auto &other_c : signal.chunks_) + { + auto &my_last_c = chunks_.back(); + if (my_last_c.wire == NULL && other_c.wire == NULL) { + auto &this_data = my_last_c.data; + auto &other_data = other_c.data; + this_data.insert(this_data.end(), other_data.begin(), other_data.end()); + my_last_c.width += other_c.width; + } else + if (my_last_c.wire == other_c.wire && my_last_c.offset + my_last_c.width == other_c.offset) { + my_last_c.width += other_c.width; + } else + chunks_.push_back(other_c); + } else - if (bit.wire == NULL) - if (chunks.back().wire == NULL) - chunks.back().data.bits.push_back(bit.data); - else - chunks.push_back(bit); - else - if (chunks.back().wire == bit.wire && chunks.back().offset + chunks.back().width == bit.offset) - chunks.back().width++; - else - chunks.push_back(bit); - width++; - // check(); + bits_.insert(bits_.end(), signal.bits_.begin(), signal.bits_.end()); + + width_ += signal.width_; + check(); } -bool RTLIL::SigSpec::combine(RTLIL::SigSpec signal, RTLIL::State freeState, bool override) +void RTLIL::SigSpec::append_bit(const RTLIL::SigBit &bit) { - bool no_collisions = true; - - assert(width == signal.width); - expand(); - signal.expand(); + if (packed()) + { + cover("kernel.rtlil.sigspec.append_bit.packed"); - for (size_t i = 0; i < chunks.size(); i++) { - bool self_free = chunks[i].wire == NULL && chunks[i].data.bits[0] == freeState; - bool other_free = signal.chunks[i].wire == NULL && signal.chunks[i].data.bits[0] == freeState; - if (!self_free && !other_free) { - if (override) - chunks[i] = signal.chunks[i]; + if (chunks_.size() == 0) + chunks_.push_back(bit); + else + if (bit.wire == NULL) + if (chunks_.back().wire == NULL) { + chunks_.back().data.push_back(bit.data); + chunks_.back().width++; + } else + chunks_.push_back(bit); else - chunks[i] = RTLIL::SigChunk(RTLIL::State::Sx, 1); - no_collisions = false; - } - if (self_free && !other_free) - chunks[i] = signal.chunks[i]; + if (chunks_.back().wire == bit.wire && chunks_.back().offset + chunks_.back().width == bit.offset) + chunks_.back().width++; + else + chunks_.push_back(bit); + } + else + { + cover("kernel.rtlil.sigspec.append_bit.unpacked"); + bits_.push_back(bit); } - optimize(); - return no_collisions; + width_++; + check(); } void RTLIL::SigSpec::extend(int width, bool is_signed) { - if (this->width > width) - remove(width, this->width - width); + cover("kernel.rtlil.sigspec.extend"); + + pack(); + + if (width_ > width) + remove(width, width_ - width); - if (this->width < width) { - RTLIL::SigSpec padding = this->width > 0 ? extract(this->width - 1, 1) : RTLIL::SigSpec(RTLIL::State::S0); + if (width_ < width) { + RTLIL::SigSpec padding = width_ > 0 ? extract(width_ - 1, 1) : RTLIL::SigSpec(RTLIL::State::S0); if (!is_signed && padding != RTLIL::SigSpec(RTLIL::State::Sx) && padding != RTLIL::SigSpec(RTLIL::State::Sz) && padding != RTLIL::SigSpec(RTLIL::State::Sa) && padding != RTLIL::SigSpec(RTLIL::State::Sm)) padding = RTLIL::SigSpec(RTLIL::State::S0); - while (this->width < width) + while (width_ < width) append(padding); } - - optimize(); } void RTLIL::SigSpec::extend_u0(int width, bool is_signed) { - if (this->width > width) - remove(width, this->width - width); + cover("kernel.rtlil.sigspec.extend_u0"); + + pack(); + + if (width_ > width) + remove(width, width_ - width); - if (this->width < width) { - RTLIL::SigSpec padding = this->width > 0 ? extract(this->width - 1, 1) : RTLIL::SigSpec(RTLIL::State::S0); + if (width_ < width) { + RTLIL::SigSpec padding = width_ > 0 ? extract(width_ - 1, 1) : RTLIL::SigSpec(RTLIL::State::S0); if (!is_signed) padding = RTLIL::SigSpec(RTLIL::State::S0); - while (this->width < width) + while (width_ < width) append(padding); } - optimize(); } +RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const +{ + cover("kernel.rtlil.sigspec.repeat"); + + RTLIL::SigSpec sig; + for (int i = 0; i < num; i++) + sig.append(*this); + return sig; +} + +#ifndef NDEBUG void RTLIL::SigSpec::check() const { - int w = 0; - for (size_t i = 0; i < chunks.size(); i++) { - const RTLIL::SigChunk chunk = chunks[i]; - if (chunk.wire == NULL) { - assert(chunk.offset == 0); - assert(chunk.data.bits.size() == (size_t)chunk.width); - } else { - assert(chunk.offset >= 0); - assert(chunk.width >= 0); - assert(chunk.offset + chunk.width <= chunk.wire->width); - assert(chunk.data.bits.size() == 0); + if (width_ > 64) + { + cover("kernel.rtlil.sigspec.check.skip"); + } + else if (packed()) + { + cover("kernel.rtlil.sigspec.check.packed"); + + int w = 0; + for (size_t i = 0; i < chunks_.size(); i++) { + const RTLIL::SigChunk chunk = chunks_[i]; + if (chunk.wire == NULL) { + if (i > 0) + log_assert(chunks_[i-1].wire != NULL); + log_assert(chunk.offset == 0); + log_assert(chunk.data.size() == (size_t)chunk.width); + } else { + if (i > 0 && chunks_[i-1].wire == chunk.wire) + log_assert(chunk.offset != chunks_[i-1].offset + chunks_[i-1].width); + log_assert(chunk.offset >= 0); + log_assert(chunk.width >= 0); + log_assert(chunk.offset + chunk.width <= chunk.wire->width); + log_assert(chunk.data.size() == 0); + } + w += chunk.width; } - w += chunk.width; + log_assert(w == width_); + log_assert(bits_.empty()); + } + else + { + cover("kernel.rtlil.sigspec.check.unpacked"); + + log_assert(width_ == SIZE(bits_)); + log_assert(chunks_.empty()); } - assert(w == width); } +#endif bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const { - if (width != other.width) - return width < other.width; + cover("kernel.rtlil.sigspec.comp_lt"); + + if (this == &other) + return false; - RTLIL::SigSpec a = *this, b = other; - a.optimize(); - b.optimize(); + if (width_ != other.width_) + return width_ < other.width_; - if (a.chunks.size() != b.chunks.size()) - return a.chunks.size() < b.chunks.size(); + pack(); + other.pack(); - for (size_t i = 0; i < a.chunks.size(); i++) - if (a.chunks[i] != b.chunks[i]) - return a.chunks[i] < b.chunks[i]; + if (chunks_.size() != other.chunks_.size()) + return chunks_.size() < other.chunks_.size(); + hash(); + other.hash(); + + if (hash_ != other.hash_) + return hash_ < other.hash_; + + for (size_t i = 0; i < chunks_.size(); i++) + if (chunks_[i] != other.chunks_[i]) { + cover("kernel.rtlil.sigspec.comp_lt.hash_collision"); + return chunks_[i] < other.chunks_[i]; + } + + cover("kernel.rtlil.sigspec.comp_lt.equal"); return false; } bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const { - if (width != other.width) + cover("kernel.rtlil.sigspec.comp_eq"); + + if (this == &other) + return true; + + if (width_ != other.width_) + return false; + + pack(); + other.pack(); + + if (chunks_.size() != chunks_.size()) return false; - RTLIL::SigSpec a = *this, b = other; - a.optimize(); - b.optimize(); + hash(); + other.hash(); - if (a.chunks.size() != b.chunks.size()) + if (hash_ != other.hash_) return false; - for (size_t i = 0; i < a.chunks.size(); i++) - if (a.chunks[i] != b.chunks[i]) + for (size_t i = 0; i < chunks_.size(); i++) + if (chunks_[i] != other.chunks_[i]) { + cover("kernel.rtlil.sigspec.comp_eq.hash_collision"); return false; + } + cover("kernel.rtlil.sigspec.comp_eq.equal"); return true; } -bool RTLIL::SigSpec::operator !=(const RTLIL::SigSpec &other) const +bool RTLIL::SigSpec::is_wire() const { - if (*this == other) - return false; - return true; + cover("kernel.rtlil.sigspec.is_wire"); + + pack(); + return SIZE(chunks_) == 1 && chunks_[0].wire && chunks_[0].wire->width == width_; +} + +bool RTLIL::SigSpec::is_chunk() const +{ + cover("kernel.rtlil.sigspec.is_chunk"); + + pack(); + return SIZE(chunks_) == 1; } bool RTLIL::SigSpec::is_fully_const() const { - for (auto it = chunks.begin(); it != chunks.end(); it++) + cover("kernel.rtlil.sigspec.is_fully_const"); + + pack(); + for (auto it = chunks_.begin(); it != chunks_.end(); it++) if (it->width > 0 && it->wire != NULL) return false; return true; @@ -1472,11 +2722,14 @@ bool RTLIL::SigSpec::is_fully_const() const bool RTLIL::SigSpec::is_fully_def() const { - for (auto it = chunks.begin(); it != chunks.end(); it++) { + cover("kernel.rtlil.sigspec.is_fully_def"); + + 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.bits.size(); i++) - if (it->data.bits[i] != RTLIL::State::S0 && it->data.bits[i] != RTLIL::State::S1) + for (size_t i = 0; i < it->data.size(); i++) + if (it->data[i] != RTLIL::State::S0 && it->data[i] != RTLIL::State::S1) return false; } return true; @@ -1484,11 +2737,14 @@ bool RTLIL::SigSpec::is_fully_def() const bool RTLIL::SigSpec::is_fully_undef() const { - for (auto it = chunks.begin(); it != chunks.end(); it++) { + cover("kernel.rtlil.sigspec.is_fully_undef"); + + 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.bits.size(); i++) - if (it->data.bits[i] != RTLIL::State::Sx && it->data.bits[i] != RTLIL::State::Sz) + for (size_t i = 0; i < it->data.size(); i++) + if (it->data[i] != RTLIL::State::Sx && it->data[i] != RTLIL::State::Sz) return false; } return true; @@ -1496,10 +2752,13 @@ bool RTLIL::SigSpec::is_fully_undef() const bool RTLIL::SigSpec::has_marked_bits() const { - for (auto it = chunks.begin(); it != chunks.end(); it++) + cover("kernel.rtlil.sigspec.has_marked_bits"); + + pack(); + for (auto it = chunks_.begin(); it != chunks_.end(); it++) if (it->width > 0 && it->wire == NULL) { - for (size_t i = 0; i < it->data.bits.size(); i++) - if (it->data.bits[i] == RTLIL::State::Sm) + for (size_t i = 0; i < it->data.size(); i++) + if (it->data[i] == RTLIL::State::Sm) return true; } return false; @@ -1507,52 +2766,79 @@ bool RTLIL::SigSpec::has_marked_bits() const bool RTLIL::SigSpec::as_bool() const { - assert(is_fully_const()); - SigSpec sig = *this; - sig.optimize(); - if (sig.width) - return sig.chunks[0].data.as_bool(); + cover("kernel.rtlil.sigspec.as_bool"); + + pack(); + log_assert(is_fully_const() && SIZE(chunks_) <= 1); + if (width_) + return RTLIL::Const(chunks_[0].data).as_bool(); return false; } -int RTLIL::SigSpec::as_int() const +int RTLIL::SigSpec::as_int(bool is_signed) const { - assert(is_fully_const()); - SigSpec sig = *this; - sig.optimize(); - if (sig.width) - return sig.chunks[0].data.as_int(); + cover("kernel.rtlil.sigspec.as_int"); + + pack(); + log_assert(is_fully_const() && SIZE(chunks_) <= 1); + if (width_) + return RTLIL::Const(chunks_[0].data).as_int(is_signed); return 0; } std::string RTLIL::SigSpec::as_string() const { + cover("kernel.rtlil.sigspec.as_string"); + + pack(); std::string str; - for (size_t i = chunks.size(); i > 0; i--) { - const RTLIL::SigChunk &chunk = chunks[i-1]; + for (size_t i = chunks_.size(); i > 0; i--) { + const RTLIL::SigChunk &chunk = chunks_[i-1]; if (chunk.wire != NULL) for (int j = 0; j < chunk.width; j++) str += "?"; else - str += chunk.data.as_string(); + str += RTLIL::Const(chunk.data).as_string(); } return str; } RTLIL::Const RTLIL::SigSpec::as_const() const { - assert(is_fully_const()); - SigSpec sig = *this; - sig.optimize(); - if (sig.width) - return sig.chunks[0].data; + cover("kernel.rtlil.sigspec.as_const"); + + pack(); + log_assert(is_fully_const() && SIZE(chunks_) <= 1); + if (width_) + return chunks_[0].data; return RTLIL::Const(); } +RTLIL::Wire *RTLIL::SigSpec::as_wire() const +{ + cover("kernel.rtlil.sigspec.as_wire"); + + pack(); + log_assert(is_wire()); + return chunks_[0].wire; +} + +RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const +{ + cover("kernel.rtlil.sigspec.as_chunk"); + + pack(); + log_assert(is_chunk()); + return chunks_[0]; +} + bool RTLIL::SigSpec::match(std::string pattern) const { + cover("kernel.rtlil.sigspec.match"); + + pack(); std::string str = as_string(); - assert(pattern.size() == str.size()); + log_assert(pattern.size() == str.size()); for (size_t i = 0; i < pattern.size(); i++) { if (pattern[i] == ' ') @@ -1571,8 +2857,11 @@ bool RTLIL::SigSpec::match(std::string pattern) const std::set<RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_set() const { + cover("kernel.rtlil.sigspec.to_sigbit_set"); + + pack(); std::set<RTLIL::SigBit> sigbits; - for (auto &c : chunks) + for (auto &c : chunks_) for (int i = 0; i < c.width; i++) sigbits.insert(RTLIL::SigBit(c, i)); return sigbits; @@ -1580,18 +2869,35 @@ std::set<RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_set() const std::vector<RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_vector() const { - std::vector<RTLIL::SigBit> sigbits; - sigbits.reserve(width); - for (auto &c : chunks) - for (int i = 0; i < c.width; i++) - sigbits.push_back(RTLIL::SigBit(c, i)); - return sigbits; + cover("kernel.rtlil.sigspec.to_sigbit_vector"); + + unpack(); + return bits_; +} + +std::map<RTLIL::SigBit, RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_map(const RTLIL::SigSpec &other) const +{ + cover("kernel.rtlil.sigspec.to_sigbit_map"); + + unpack(); + other.unpack(); + + log_assert(width_ == other.width_); + + std::map<RTLIL::SigBit, RTLIL::SigBit> new_map; + for (int i = 0; i < width_; i++) + new_map[bits_[i]] = other.bits_[i]; + + return new_map; } RTLIL::SigBit RTLIL::SigSpec::to_single_sigbit() const { - log_assert(width == 1); - for (auto &c : chunks) + 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(); @@ -1614,6 +2920,8 @@ static int sigspec_parse_get_dummy_line_num() bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str) { + cover("kernel.rtlil.sigspec.parse"); + std::vector<std::string> tokens; sigspec_parse_split(tokens, str, ','); @@ -1627,6 +2935,7 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri continue; if ('0' <= netname[0] && netname[0] <= '9') { + cover("kernel.rtlil.sigspec.parse.const"); AST::get_line_num = sigspec_parse_get_dummy_line_num; AST::AstNode *ast = VERILOG_FRONTEND::const2ast(netname); if (ast == NULL) @@ -1639,10 +2948,12 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri if (module == NULL) return false; + cover("kernel.rtlil.sigspec.parse.net"); + if (netname[0] != '$' && netname[0] != '\\') netname = "\\" + netname; - if (module->wires.count(netname) == 0) { + if (module->wires_.count(netname) == 0) { size_t indices_pos = netname.size()-1; if (indices_pos > 2 && netname[indices_pos] == ']') { @@ -1659,23 +2970,25 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri } } - if (module->wires.count(netname) == 0) + if (module->wires_.count(netname) == 0) return false; - RTLIL::Wire *wire = module->wires.at(netname); + RTLIL::Wire *wire = module->wires_.at(netname); if (!indices.empty()) { std::vector<std::string> index_tokens; sigspec_parse_split(index_tokens, indices.substr(1, indices.size()-2), ':'); - if (index_tokens.size() == 1) - sig.append(RTLIL::SigSpec(wire, 1, atoi(index_tokens.at(0).c_str()))); - else { + if (index_tokens.size() == 1) { + cover("kernel.rtlil.sigspec.parse.bit_sel"); + sig.append(RTLIL::SigSpec(wire, atoi(index_tokens.at(0).c_str()))); + } else { + cover("kernel.rtlil.sigspec.parse.part_sel"); int a = atoi(index_tokens.at(0).c_str()); int b = atoi(index_tokens.at(1).c_str()); if (a > b) { int tmp = a; a = b, b = tmp; } - sig.append(RTLIL::SigSpec(wire, b-a+1, a)); + sig.append(RTLIL::SigSpec(wire, a, b-a+1)); } } else sig.append(wire); @@ -1689,13 +3002,15 @@ bool RTLIL::SigSpec::parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL if (str.empty() || str[0] != '@') return parse(sig, module, str); + cover("kernel.rtlil.sigspec.parse.sel"); + str = RTLIL::escape_id(str.substr(1)); if (design->selection_vars.count(str) == 0) return false; sig = RTLIL::SigSpec(); RTLIL::Selection &sel = design->selection_vars.at(str); - for (auto &it : module->wires) + for (auto &it : module->wires_) if (sel.selected_member(module->name, it.first)) sig.append(it.second); @@ -1705,20 +3020,23 @@ bool RTLIL::SigSpec::parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str) { if (str == "0") { - sig = RTLIL::SigSpec(RTLIL::State::S0, lhs.width); + cover("kernel.rtlil.sigspec.parse.rhs_zeros"); + sig = RTLIL::SigSpec(RTLIL::State::S0, lhs.width_); return true; } if (str == "~0") { - sig = RTLIL::SigSpec(RTLIL::State::S1, lhs.width); + cover("kernel.rtlil.sigspec.parse.rhs_ones"); + sig = RTLIL::SigSpec(RTLIL::State::S1, lhs.width_); return true; } - if (lhs.chunks.size() == 1) { + if (lhs.chunks_.size() == 1) { char *p = (char*)str.c_str(), *endptr; long long int val = strtoll(p, &endptr, 10); if (endptr && endptr != p && *endptr == 0) { - sig = RTLIL::SigSpec(val, lhs.width); + sig = RTLIL::SigSpec(val, lhs.width_); + cover("kernel.rtlil.sigspec.parse.rhs_dec"); return true; } } @@ -1732,18 +3050,6 @@ RTLIL::CaseRule::~CaseRule() delete *it; } -void RTLIL::CaseRule::optimize() -{ - for (auto it : switches) - it->optimize(); - for (auto &it : compare) - it.optimize(); - for (auto &it : actions) { - it.first.optimize(); - it.second.optimize(); - } -} - RTLIL::CaseRule *RTLIL::CaseRule::clone() const { RTLIL::CaseRule *new_caserule = new RTLIL::CaseRule; @@ -1760,13 +3066,6 @@ RTLIL::SwitchRule::~SwitchRule() delete *it; } -void RTLIL::SwitchRule::optimize() -{ - signal.optimize(); - for (auto it : cases) - it->optimize(); -} - RTLIL::SwitchRule *RTLIL::SwitchRule::clone() const { RTLIL::SwitchRule *new_switchrule = new RTLIL::SwitchRule; @@ -1778,15 +3077,6 @@ RTLIL::SwitchRule *RTLIL::SwitchRule::clone() const } -void RTLIL::SyncRule::optimize() -{ - signal.optimize(); - for (auto &it : actions) { - it.first.optimize(); - it.second.optimize(); - } -} - RTLIL::SyncRule *RTLIL::SyncRule::clone() const { RTLIL::SyncRule *new_syncrule = new RTLIL::SyncRule; @@ -1802,13 +3092,6 @@ RTLIL::Process::~Process() delete *it; } -void RTLIL::Process::optimize() -{ - root_case.optimize(); - for (auto it : syncs) - it->optimize(); -} - RTLIL::Process *RTLIL::Process::clone() const { RTLIL::Process *new_proc = new RTLIL::Process; @@ -1827,3 +3110,5 @@ RTLIL::Process *RTLIL::Process::clone() const return new_proc; } +YOSYS_NAMESPACE_END + diff --git a/kernel/rtlil.h b/kernel/rtlil.h index caadf1981..a0ae8f082 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -17,20 +17,16 @@ * */ +#include "kernel/yosys.h" + #ifndef RTLIL_H #define RTLIL_H -#include <map> -#include <set> -#include <vector> -#include <string> -#include <assert.h> - -std::string stringf(const char *fmt, ...); +YOSYS_NAMESPACE_BEGIN namespace RTLIL { - enum State { + enum State : unsigned char { S0 = 0, S1 = 1, Sx = 2, // undefined value or conflict @@ -39,7 +35,7 @@ namespace RTLIL Sm = 5 // marker (used internally by some passes) }; - enum SyncType { + enum SyncType : unsigned char { ST0 = 0, // level sensitive: 0 ST1 = 1, // level sensitive: 1 STp = 2, // edge sensitive: posedge @@ -49,17 +45,16 @@ namespace RTLIL STi = 6 // init }; - enum ConstFlags { + enum ConstFlags : unsigned char { CONST_FLAG_NONE = 0, CONST_FLAG_STRING = 1, CONST_FLAG_SIGNED = 2, // only used for parameters CONST_FLAG_REAL = 4 // unused -- to be used for parameters }; - extern int autoidx; - struct Const; struct Selection; + struct Monitor; struct Design; struct Module; struct Wire; @@ -67,6 +62,8 @@ namespace RTLIL struct Cell; struct SigChunk; struct SigBit; + struct SigSpecIterator; + struct SigSpecConstIterator; struct SigSpec; struct CaseRule; struct SwitchRule; @@ -75,79 +72,207 @@ namespace RTLIL typedef std::pair<SigSpec, SigSpec> SigSig; -#ifdef NDEBUG - typedef std::string IdString; -#else - struct IdString : public std::string { - IdString() { } - IdString(std::string str) : std::string(str) { - check(); + struct IdString + { + // the global id string cache + + struct char_ptr_cmp { + bool operator()(const char *a, const char *b) const { + for (int i = 0; a[i] || b[i]; i++) + if (a[i] != b[i]) + return a[i] < b[i]; + return false; + } + }; + + static std::vector<int> global_refcount_storage_; + static std::vector<char*> global_id_storage_; + static std::map<char*, int, char_ptr_cmp> global_id_index_; + static std::vector<int> global_free_idx_list_; + + static inline int get_reference(int idx) + { + global_refcount_storage_.at(idx)++; + return idx; } - IdString(const char *s) : std::string(s) { - check(); + + static inline int get_reference(const char *p) + { + if (p[0]) { + log_assert(p[1] != 0); + log_assert(p[0] == '$' || p[0] == '\\'); + } + + auto it = global_id_index_.find((char*)p); + if (it != global_id_index_.end()) { + global_refcount_storage_.at(it->second)++; + return it->second; + } + + if (global_free_idx_list_.empty()) { + log_assert(global_id_storage_.size() < 0x40000000); + global_free_idx_list_.push_back(global_id_storage_.size()); + global_id_storage_.push_back(nullptr); + global_refcount_storage_.push_back(0); + } + + int idx = global_free_idx_list_.back(); + global_free_idx_list_.pop_back(); + global_id_storage_.at(idx) = strdup(p); + global_id_index_[global_id_storage_.at(idx)] = idx; + global_refcount_storage_.at(idx)++; + return idx; } - IdString &operator=(const std::string &str) { - std::string::operator=(str); - check(); - return *this; + + static inline void put_reference(int idx) + { + log_assert(global_refcount_storage_.at(idx) > 0); + + if (--global_refcount_storage_.at(idx) != 0) + return; + + global_id_index_.erase(global_id_storage_.at(idx)); + free(global_id_storage_.at(idx)); + global_id_storage_.at(idx) = nullptr; + global_free_idx_list_.push_back(idx); } - IdString &operator=(const char *s) { - std::string::operator=(s); - check(); - return *this; + + // the actual IdString object is just is a single int + + int index_; + + IdString() : index_(get_reference("")) { } + IdString(const char *str) : index_(get_reference(str)) { } + IdString(const IdString &str) : index_(get_reference(str.index_)) { } + IdString(const std::string &str) : index_(get_reference(str.c_str())) { } + ~IdString() { put_reference(index_); } + + void operator=(const IdString &rhs) { + put_reference(index_); + index_ = get_reference(rhs.index_); + } + + void operator=(const char *rhs) { + IdString id(rhs); + *this = id; + } + + void operator=(const std::string &rhs) { + IdString id(rhs); + *this = id; + } + + const char *c_str() const { + return global_id_storage_.at(index_); } - bool operator<(const IdString &rhs) { - check(), rhs.check(); - return std::string(*this) < std::string(rhs); + + std::string str() const { + return std::string(global_id_storage_.at(index_)); } - void check() const { - assert(empty() || (size() >= 2 && (at(0) == '$' || at(0) == '\\'))); + + bool operator<(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_; } + + // The methods below are just convinience 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; } + + bool operator==(const char *rhs) const { return strcmp(c_str(), rhs) == 0; } + bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; } + + char operator[](size_t i) const { + const char *p = c_str(); + for (; i != 0; i--, p++) + log_assert(*p != 0); + return *p; + } + + std::string substr(size_t pos = 0, size_t len = std::string::npos) const { + if (len == std::string::npos || len >= strlen(c_str() + pos)) + return std::string(c_str() + pos); + else + return std::string(c_str() + pos, len); + } + + size_t size() const { + return str().size(); + } + + bool empty() const { + return c_str()[0] == 0; + } + + void clear() { + *this = IdString(); + } + + // The following is a helper key_compare class. Instead of for example std::set<Cell*> + // use std::set<Cell*, IdString::compare_ptr_by_name<Cell>> if the order of cells in the + // set has an influence on the algorithm. + + template<typename T> struct compare_ptr_by_name { + bool operator()(const T *a, const T *b) { + return (a == nullptr || b == nullptr) ? (a < b) : (a->name < b->name); + } + }; + + // often one needs to check if a given IdString is part of a list (for example a list + // of cell types). the following functions helps with that. + + template<typename T, typename... Args> + bool in(T first, Args... rest) { + return in(first) || in(rest...); + } + + bool in(IdString rhs) { return *this == rhs; } + bool in(const char *rhs) { return *this == rhs; } + bool in(const std::string &rhs) { return *this == rhs; } + bool in(const std::set<IdString> &rhs) { return rhs.count(*this) != 0; } }; -#endif - static IdString escape_id(std::string str) __attribute__((unused)); - static IdString escape_id(std::string str) { + static inline std::string escape_id(std::string str) { if (str.size() > 0 && str[0] != '\\' && str[0] != '$') return "\\" + str; return str; } - static std::string unescape_id(std::string str) __attribute__((unused)); - static std::string unescape_id(std::string str) { + static inline std::string unescape_id(std::string str) { if (str.size() > 1 && str[0] == '\\' && str[1] != '$') return str.substr(1); return str; } - static const char *id2cstr(std::string str) __attribute__((unused)); - static const char *id2cstr(std::string str) { - if (str.size() > 1 && str[0] == '\\' && str[1] != '$') - return str.c_str() + 1; - return str.c_str(); + static inline std::string unescape_id(RTLIL::IdString str) { + return unescape_id(str.str()); } - static IdString new_id(std::string file, int line, std::string func) __attribute__((unused)); - static IdString new_id(std::string file, int line, std::string func) { - std::string str = "$auto$"; - size_t pos = file.find_last_of('/'); - str += pos != std::string::npos ? file.substr(pos+1) : file; - str += stringf(":%d:%s$%d", line, func.c_str(), autoidx++); - return str; + static inline const char *id2cstr(const RTLIL::IdString &str) { + return log_id(str); } -#define NEW_ID \ - RTLIL::new_id(__FILE__, __LINE__, __FUNCTION__) - -#define NEW_WIRE(_mod, _width) \ - (_mod)->new_wire(_width, NEW_ID) - - template <typename T> struct sort_by_name { + template <typename T> struct sort_by_name_id { bool operator()(T *a, T *b) const { return a->name < b->name; } }; + template <typename T> struct sort_by_name_str { + bool operator()(T *a, T *b) const { + return strcmp(a->name.c_str(), b->name.c_str()) < 0; + } + }; + + struct sort_by_id_str { + bool operator()(RTLIL::IdString a, RTLIL::IdString b) const { + return strcmp(a.c_str(), b.c_str()) < 0; + } + }; + // see calc.cc for the implementation of this functions RTLIL::Const const_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); @@ -169,6 +294,8 @@ namespace RTLIL RTLIL::Const const_shr (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_sshl (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_sshr (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); + RTLIL::Const const_shift (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); + RTLIL::Const const_shiftx (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_lt (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_le (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); @@ -187,77 +314,245 @@ namespace RTLIL RTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_pos (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); - RTLIL::Const const_bu0 (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); + + + // This iterator-range-pair is used for Design::modules(), Module::wires() and Module::cells(). + // It maintains a reference counter that is used to make sure that the container is not modified while being iterated over. + + template<typename T> + struct ObjIterator + { + typename std::map<RTLIL::IdString, T>::iterator it; + std::map<RTLIL::IdString, T> *list_p; + int *refcount_p; + + ObjIterator() : list_p(nullptr), refcount_p(nullptr) { + } + + ObjIterator(decltype(list_p) list_p, int *refcount_p) : list_p(list_p), refcount_p(refcount_p) { + if (list_p->empty()) { + this->list_p = nullptr; + this->refcount_p = nullptr; + } else { + it = list_p->begin(); + (*refcount_p)++; + } + } + + ObjIterator(const RTLIL::ObjIterator<T> &other) { + it = other.it; + list_p = other.list_p; + refcount_p = other.refcount_p; + if (refcount_p) + (*refcount_p)++; + } + + ObjIterator &operator=(const RTLIL::ObjIterator<T> &other) { + if (refcount_p) + (*refcount_p)--; + it = other.it; + list_p = other.list_p; + refcount_p = other.refcount_p; + if (refcount_p) + (*refcount_p)++; + return *this; + } + + ~ObjIterator() { + if (refcount_p) + (*refcount_p)--; + } + + inline T operator*() const { + log_assert(list_p != nullptr); + return it->second; + } + + inline bool operator!=(const RTLIL::ObjIterator<T> &other) const { + if (list_p == nullptr || other.list_p == nullptr) + return list_p != other.list_p; + return it != other.it; + } + + inline void operator++() { + log_assert(list_p != nullptr); + if (++it == list_p->end()) { + (*refcount_p)--; + list_p = nullptr; + refcount_p = nullptr; + } + } + }; + + template<typename T> + struct ObjRange + { + std::map<RTLIL::IdString, T> *list_p; + int *refcount_p; + + ObjRange(decltype(list_p) list_p, int *refcount_p) : list_p(list_p), refcount_p(refcount_p) { } + RTLIL::ObjIterator<T> begin() { return RTLIL::ObjIterator<T>(list_p, refcount_p); } + RTLIL::ObjIterator<T> end() { return RTLIL::ObjIterator<T>(); } + + size_t size() const { + return list_p->size(); + } + + operator std::set<T>() const { + std::set<T> result; + for (auto &it : *list_p) + result.insert(it.second); + return result; + } + + operator std::vector<T>() const { + std::vector<T> result; + result.reserve(list_p->size()); + for (auto &it : *list_p) + result.push_back(it.second); + return result; + } + + std::set<T> to_set() const { return *this; } + std::vector<T> to_vector() const { return *this; } + }; }; -struct RTLIL::Const { +struct RTLIL::Const +{ int flags; std::vector<RTLIL::State> bits; + Const(); Const(std::string str); Const(int val, int width = 32); Const(RTLIL::State bit, int width = 1); - 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; bool operator ==(const RTLIL::Const &other) const; bool operator !=(const RTLIL::Const &other) const; + bool as_bool() const; - int as_int() const; + int as_int(bool is_signed = false) const; std::string as_string() const; + std::string decode_string() const; + + inline int size() const { return bits.size(); } }; -struct RTLIL::Selection { +struct RTLIL::Selection +{ bool full_selection; std::set<RTLIL::IdString> selected_modules; std::map<RTLIL::IdString, std::set<RTLIL::IdString>> selected_members; + Selection(bool full = true) : full_selection(full) { } + bool selected_module(RTLIL::IdString mod_name) const; bool selected_whole_module(RTLIL::IdString mod_name) const; bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const; void optimize(RTLIL::Design *design); + template<typename T1> void select(T1 *module) { if (!full_selection && selected_modules.count(module->name) == 0) { selected_modules.insert(module->name); selected_members.erase(module->name); } } + template<typename T1, typename T2> void select(T1 *module, T2 *member) { if (!full_selection && selected_modules.count(module->name) == 0) selected_members[module->name].insert(member->name); } + bool empty() const { return !full_selection && selected_modules.empty() && selected_members.empty(); } }; -struct RTLIL::Design { - std::map<RTLIL::IdString, RTLIL::Module*> modules; +struct RTLIL::Monitor +{ + virtual ~Monitor() { } + virtual void notify_module_add(RTLIL::Module*) { } + virtual void notify_module_del(RTLIL::Module*) { } + virtual void notify_connect(RTLIL::Cell*, const RTLIL::IdString&, const RTLIL::SigSpec&, RTLIL::SigSpec&) { } + virtual void notify_connect(RTLIL::Module*, const RTLIL::SigSig&) { } + virtual void notify_connect(RTLIL::Module*, const std::vector<RTLIL::SigSig>&) { } + virtual void notify_blackout(RTLIL::Module*) { } +}; + +struct RTLIL::Design +{ + std::set<RTLIL::Monitor*> monitors; + std::map<std::string, std::string> scratchpad; + + int refcount_modules_; + std::map<RTLIL::IdString, RTLIL::Module*> modules_; + std::vector<RTLIL::Selection> selection_stack; std::map<RTLIL::IdString, RTLIL::Selection> selection_vars; std::string selected_active_module; + + Design(); ~Design(); + + RTLIL::ObjRange<RTLIL::Module*> modules(); + RTLIL::Module *module(RTLIL::IdString name); + + bool has(RTLIL::IdString id) const { + return modules_.count(id) != 0; + } + + void add(RTLIL::Module *module); + RTLIL::Module *addModule(RTLIL::IdString name); + void remove(RTLIL::Module *module); + + void scratchpad_unset(std::string varname); + + void scratchpad_set_int(std::string varname, int value); + void scratchpad_set_bool(std::string varname, bool value); + void scratchpad_set_string(std::string varname, std::string value); + + int scratchpad_get_int(std::string varname, int default_value = 0) const; + bool scratchpad_get_bool(std::string varname, bool default_value = false) const; + std::string scratchpad_get_string(std::string varname, std::string default_value = std::string()) const; + void check(); void optimize(); + bool selected_module(RTLIL::IdString mod_name) const; bool selected_whole_module(RTLIL::IdString mod_name) const; bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const; + + bool selected_module(RTLIL::Module *mod) const; + bool selected_whole_module(RTLIL::Module *mod) const; + bool full_selection() const { return selection_stack.back().full_selection; } + template<typename T1> bool selected(T1 *module) const { return selected_module(module->name); } + template<typename T1, typename T2> bool selected(T1 *module, T2 *member) const { return selected_member(module->name, member->name); } + template<typename T1, typename T2> void select(T1 *module, T2 *member) { if (selection_stack.size() > 0) { RTLIL::Selection &sel = selection_stack.back(); sel.select(module, member); } } + + std::vector<RTLIL::Module*> selected_modules() const; + std::vector<RTLIL::Module*> selected_whole_modules() const; + std::vector<RTLIL::Module*> selected_whole_modules_warn() const; }; #define RTLIL_ATTRIBUTE_MEMBERS \ @@ -271,159 +566,536 @@ struct RTLIL::Design { return attributes.at(id).as_bool(); \ } -struct RTLIL::Module { +struct RTLIL::Module +{ +protected: + void add(RTLIL::Wire *wire); + void add(RTLIL::Cell *cell); + +public: + RTLIL::Design *design; + std::set<RTLIL::Monitor*> monitors; + + int refcount_wires_; + int refcount_cells_; + + std::map<RTLIL::IdString, RTLIL::Wire*> wires_; + std::map<RTLIL::IdString, RTLIL::Cell*> cells_; + std::vector<RTLIL::SigSig> connections_; + RTLIL::IdString name; std::set<RTLIL::IdString> avail_parameters; - std::map<RTLIL::IdString, RTLIL::Wire*> wires; std::map<RTLIL::IdString, RTLIL::Memory*> memories; - std::map<RTLIL::IdString, RTLIL::Cell*> cells; std::map<RTLIL::IdString, RTLIL::Process*> processes; - std::vector<RTLIL::SigSig> connections; RTLIL_ATTRIBUTE_MEMBERS + + Module(); virtual ~Module(); virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters); virtual size_t count_id(RTLIL::IdString id); virtual void check(); virtual void optimize(); - RTLIL::Wire *new_wire(int width, RTLIL::IdString name); - void add(RTLIL::Wire *wire); - void add(RTLIL::Cell *cell); + + void connect(const RTLIL::SigSig &conn); + void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs); + void new_connections(const std::vector<RTLIL::SigSig> &new_conn); + const std::vector<RTLIL::SigSig> &connections() const; + + std::vector<RTLIL::IdString> ports; void fixup_ports(); template<typename T> void rewrite_sigspecs(T functor); void cloneInto(RTLIL::Module *new_mod) const; virtual RTLIL::Module *clone() const; + bool has_memories() const; + bool has_processes() const; + + bool has_memories_warn() const; + bool has_processes_warn() const; + + std::vector<RTLIL::Wire*> selected_wires() const; + std::vector<RTLIL::Cell*> selected_cells() const; + + template<typename T> bool selected(T *member) const { + return design->selected_member(name, member->name); + } + + RTLIL::Wire* wire(RTLIL::IdString id) { return wires_.count(id) ? wires_.at(id) : nullptr; } + RTLIL::Cell* cell(RTLIL::IdString id) { return cells_.count(id) ? cells_.at(id) : nullptr; } + + RTLIL::ObjRange<RTLIL::Wire*> wires() { return RTLIL::ObjRange<RTLIL::Wire*>(&wires_, &refcount_wires_); } + RTLIL::ObjRange<RTLIL::Cell*> cells() { return RTLIL::ObjRange<RTLIL::Cell*>(&cells_, &refcount_cells_); } + + // Removing wires is expensive. If you have to remove wires, remove them all at once. + void remove(const std::set<RTLIL::Wire*> &wires); + void remove(RTLIL::Cell *cell); + + void rename(RTLIL::Wire *wire, RTLIL::IdString new_name); + void rename(RTLIL::Cell *cell, RTLIL::IdString new_name); + void rename(RTLIL::IdString old_name, RTLIL::IdString new_name); + + void swap_names(RTLIL::Wire *w1, RTLIL::Wire *w2); + void swap_names(RTLIL::Cell *c1, RTLIL::Cell *c2); + + RTLIL::IdString uniquify(RTLIL::IdString name); + RTLIL::IdString uniquify(RTLIL::IdString name, int &index); + + RTLIL::Wire *addWire(RTLIL::IdString name, int width = 1); + RTLIL::Wire *addWire(RTLIL::IdString name, const RTLIL::Wire *other); + + RTLIL::Cell *addCell(RTLIL::IdString name, RTLIL::IdString type); + RTLIL::Cell *addCell(RTLIL::IdString name, const RTLIL::Cell *other); + + // The add* methods create a cell and return the created cell. All signals must exist in advance. + + 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); + RTLIL::Cell* addNe (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); + RTLIL::Cell* addEqx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed = false); + 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* addAssert (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en); + + RTLIL::Cell* addSr (RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity = true, bool clr_polarity = true); + RTLIL::Cell* addDff (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true); + RTLIL::Cell* addDffsr (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, + RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true); + RTLIL::Cell* addAdff (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, + RTLIL::Const arst_value, bool clk_polarity = true, bool arst_polarity = true); + RTLIL::Cell* addDlatch (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true); + 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* 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); + RTLIL::Cell* addOrGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y); + RTLIL::Cell* addNorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y); + RTLIL::Cell* addXorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y); + RTLIL::Cell* addXnorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y); + RTLIL::Cell* addMuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y); + RTLIL::Cell* addAoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y); + RTLIL::Cell* addOai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y); + RTLIL::Cell* addAoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y); + RTLIL::Cell* addOai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y); + + RTLIL::Cell* addDffGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true); + RTLIL::Cell* addDffsrGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, + RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true); + RTLIL::Cell* addAdffGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, + bool arst_value = false, bool clk_polarity = true, bool arst_polarity = true); + RTLIL::Cell* addDlatchGate (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true); + RTLIL::Cell* addDlatchsrGate (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); + + // The methods without the add* prefix create a cell and an output signal. They return the newly created output signal. + + RTLIL::SigSpec Not (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false); + RTLIL::SigSpec Pos (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false); + RTLIL::SigSpec Bu0 (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false); + RTLIL::SigSpec Neg (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false); + + RTLIL::SigSpec And (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Or (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Xor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Xnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + + RTLIL::SigSpec ReduceAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false); + RTLIL::SigSpec ReduceOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false); + RTLIL::SigSpec ReduceXor (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false); + RTLIL::SigSpec ReduceXnor (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false); + RTLIL::SigSpec ReduceBool (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false); + + RTLIL::SigSpec Shl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Shr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Sshl (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Sshr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Shift (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Shiftx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + + RTLIL::SigSpec Lt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Le (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Eq (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Ne (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Eqx (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Nex (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Ge (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Gt (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + + RTLIL::SigSpec Add (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Sub (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Mul (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Div (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Mod (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec Pow (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool a_signed = false, bool b_signed = false); + + RTLIL::SigSpec LogicNot (RTLIL::IdString name, RTLIL::SigSpec sig_a, bool is_signed = false); + RTLIL::SigSpec LogicAnd (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + RTLIL::SigSpec LogicOr (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, bool is_signed = false); + + 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 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); + RTLIL::SigBit OrGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b); + RTLIL::SigBit NorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b); + RTLIL::SigBit XorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b); + RTLIL::SigBit XnorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b); + RTLIL::SigBit MuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s); + RTLIL::SigBit Aoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c); + RTLIL::SigBit Oai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c); + RTLIL::SigBit Aoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d); + 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 +{ +protected: + // use module->addWire() and module->remove() to create or destroy wires + friend struct RTLIL::Module; + Wire(); + ~Wire() { }; + +public: + // do not simply copy wires + Wire(RTLIL::Wire &other) = delete; + void operator=(RTLIL::Wire &other) = delete; + + RTLIL::Module *module; RTLIL::IdString name; int width, start_offset, port_id; - bool port_input, port_output; + bool port_input, port_output, upto; RTLIL_ATTRIBUTE_MEMBERS - Wire(); }; -struct RTLIL::Memory { +struct RTLIL::Memory +{ + Memory(); + RTLIL::IdString name; int width, start_offset, size; RTLIL_ATTRIBUTE_MEMBERS - Memory(); }; -struct RTLIL::Cell { +struct RTLIL::Cell +{ +protected: + // use module->addCell() and module->remove() to create or destroy cells + friend struct RTLIL::Module; + Cell(); + +public: + // do not simply copy cells + Cell(RTLIL::Cell &other) = delete; + void operator=(RTLIL::Cell &other) = delete; + + RTLIL::Module *module; RTLIL::IdString name; RTLIL::IdString type; - std::map<RTLIL::IdString, RTLIL::SigSpec> connections; + std::map<RTLIL::IdString, RTLIL::SigSpec> connections_; std::map<RTLIL::IdString, RTLIL::Const> parameters; RTLIL_ATTRIBUTE_MEMBERS - void optimize(); + + // access cell ports + bool hasPort(RTLIL::IdString portname) const; + void unsetPort(RTLIL::IdString portname); + void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal); + const RTLIL::SigSpec &getPort(RTLIL::IdString portname) const; + const std::map<RTLIL::IdString, RTLIL::SigSpec> &connections() const; + + // access cell parameters + bool hasParam(RTLIL::IdString paramname) const; + void unsetParam(RTLIL::IdString paramname); + void setParam(RTLIL::IdString paramname, RTLIL::Const value); + const RTLIL::Const &getParam(RTLIL::IdString paramname) const; + + void check(); + void fixup_parameters(bool set_a_signed = false, bool set_b_signed = false); template<typename T> void rewrite_sigspecs(T functor); }; -struct RTLIL::SigChunk { +struct RTLIL::SigChunk +{ RTLIL::Wire *wire; - RTLIL::Const data; // only used if wire == NULL, LSB at index 0 + std::vector<RTLIL::State> data; // only used if wire == NULL, LSB at index 0 int width, offset; + SigChunk(); - SigChunk(const RTLIL::Const &data); - SigChunk(RTLIL::Wire *wire, int width, int offset); + SigChunk(const RTLIL::Const &value); + SigChunk(RTLIL::Wire *wire); + SigChunk(RTLIL::Wire *wire, int offset, int width = 1); SigChunk(const std::string &str); SigChunk(int val, int width = 32); SigChunk(RTLIL::State bit, int width = 1); SigChunk(RTLIL::SigBit bit); + RTLIL::SigChunk extract(int offset, int length) const; + bool operator <(const RTLIL::SigChunk &other) const; bool operator ==(const RTLIL::SigChunk &other) const; bool operator !=(const RTLIL::SigChunk &other) const; - static bool compare(const RTLIL::SigChunk &a, const RTLIL::SigChunk &b); }; -struct RTLIL::SigBit { +struct RTLIL::SigBit +{ RTLIL::Wire *wire; - RTLIL::State data; - int offset; - SigBit() : wire(NULL), data(RTLIL::State::S0), offset(0) { } - SigBit(RTLIL::State bit) : wire(NULL), data(bit), offset(0) { } - SigBit(RTLIL::Wire *wire) : wire(wire), data(RTLIL::State::S0), offset(0) { assert(!wire || wire->width == 1); } - SigBit(RTLIL::Wire *wire, int offset) : wire(wire), data(RTLIL::State::S0), offset(offset) { } - SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire), data(chunk.wire ? RTLIL::State::S0 : chunk.data.bits[0]), offset(chunk.offset) { assert(chunk.width == 1); } - SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire), data(chunk.wire ? RTLIL::State::S0 : chunk.data.bits[index]), offset(chunk.wire ? chunk.offset + index : 0) { } + union { + RTLIL::State data; // used if wire == NULL + int offset; // used if wire != NULL + }; + + SigBit() : wire(NULL), data(RTLIL::State::S0) { } + SigBit(RTLIL::State bit) : wire(NULL), data(bit) { } + SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_assert(wire && wire->width == 1); } + SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire); } + SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; } + SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; } SigBit(const RTLIL::SigSpec &sig); + bool operator <(const RTLIL::SigBit &other) const { - return (wire != other.wire) ? (wire < other.wire) : wire ? (offset < other.offset) : (data < other.data); + if (wire == other.wire) + return wire ? (offset < other.offset) : (data < other.data); + if (wire != nullptr && other.wire != nullptr) + return wire->name < other.wire->name; + return wire < other.wire; } + bool operator ==(const RTLIL::SigBit &other) const { return (wire == other.wire) && (wire ? (offset == other.offset) : (data == other.data)); } + bool operator !=(const RTLIL::SigBit &other) const { return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data)); } }; -struct RTLIL::SigSpec { - std::vector<RTLIL::SigChunk> chunks; // LSB at index 0 - int width; +struct RTLIL::SigSpecIterator +{ + RTLIL::SigSpec *sig_p; + int index; + + inline RTLIL::SigBit &operator*() const; + inline bool operator!=(const RTLIL::SigSpecIterator &other) const { return index != other.index; } + inline void operator++() { index++; } +}; + +struct RTLIL::SigSpecConstIterator +{ + const RTLIL::SigSpec *sig_p; + int index; + + inline const RTLIL::SigBit &operator*() const; + inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; } + inline void operator++() { index++; } +}; + +struct RTLIL::SigSpec +{ +private: + int width_; + unsigned long hash_; + std::vector<RTLIL::SigChunk> chunks_; // LSB at index 0 + std::vector<RTLIL::SigBit> bits_; // LSB at index 0 + + void pack() const; + void unpack() const; + void hash() const; + + inline bool packed() const { + return bits_.empty(); + } + + inline void inline_unpack() const { + if (!chunks_.empty()) + unpack(); + } + +public: SigSpec(); - SigSpec(const RTLIL::Const &data); + SigSpec(const RTLIL::SigSpec &other); + SigSpec(std::initializer_list<RTLIL::SigSpec> parts); + const RTLIL::SigSpec &operator=(const RTLIL::SigSpec &other); + + SigSpec(const RTLIL::Const &value); SigSpec(const RTLIL::SigChunk &chunk); - SigSpec(RTLIL::Wire *wire, int width = -1, int offset = 0); + SigSpec(RTLIL::Wire *wire); + SigSpec(RTLIL::Wire *wire, int offset, int width = 1); SigSpec(const std::string &str); SigSpec(int val, int width = 32); SigSpec(RTLIL::State bit, int width = 1); SigSpec(RTLIL::SigBit bit, int width = 1); + SigSpec(std::vector<RTLIL::SigChunk> chunks); SigSpec(std::vector<RTLIL::SigBit> bits); - void expand(); - void optimize(); - RTLIL::SigSpec optimized() const; + SigSpec(std::set<RTLIL::SigBit> bits); + + SigSpec(RTLIL::SigSpec &&other) { + width_ = other.width_; + hash_ = other.hash_; + chunks_ = std::move(other.chunks_); + bits_ = std::move(other.bits_); + } + + const RTLIL::SigSpec &operator=(RTLIL::SigSpec &&other) { + width_ = other.width_; + hash_ = other.hash_; + chunks_ = std::move(other.chunks_); + bits_ = std::move(other.bits_); + return *this; + } + + inline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; } + inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; } + + inline int size() const { return width_; } + + inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); } + inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); } + + inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; } + inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; } + + inline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; } + inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; } + void sort(); void sort_and_unify(); + void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with); void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const; + + void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules); + void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const; + + void replace(int offset, const RTLIL::SigSpec &with); + void remove(const RTLIL::SigSpec &pattern); void remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const; void remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other); - RTLIL::SigSpec extract(RTLIL::SigSpec pattern, RTLIL::SigSpec *other = NULL) const; - void replace(int offset, const RTLIL::SigSpec &with); + + void remove(const std::set<RTLIL::SigBit> &pattern); + void remove(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const; + void remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other); + + void remove(int offset, int length = 1); void remove_const(); - void remove(int offset, int length); - RTLIL::SigSpec extract(int offset, int length) const; + + RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const; + RTLIL::SigSpec extract(const std::set<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const; + RTLIL::SigSpec extract(int offset, int length = 1) const; + void append(const RTLIL::SigSpec &signal); void append_bit(const RTLIL::SigBit &bit); - bool combine(RTLIL::SigSpec signal, RTLIL::State freeState = RTLIL::State::Sz, bool override = false); + void extend(int width, bool is_signed = false); void extend_u0(int width, bool is_signed = false); - void check() const; + + RTLIL::SigSpec repeat(int num) const; + bool operator <(const RTLIL::SigSpec &other) const; bool operator ==(const RTLIL::SigSpec &other) const; - bool operator !=(const RTLIL::SigSpec &other) const; + inline bool operator !=(const RTLIL::SigSpec &other) const { return !(*this == other); } + + bool is_wire() const; + bool is_chunk() const; + bool is_fully_const() const; bool is_fully_def() const; bool is_fully_undef() const; bool has_marked_bits() const; + bool as_bool() const; - int as_int() const; + int as_int(bool is_signed = false) const; std::string as_string() const; RTLIL::Const as_const() const; + RTLIL::Wire *as_wire() const; + RTLIL::SigChunk as_chunk() const; + bool match(std::string pattern) const; + std::set<RTLIL::SigBit> to_sigbit_set() const; std::vector<RTLIL::SigBit> to_sigbit_vector() const; + std::map<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_map(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); static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str); + + operator std::vector<RTLIL::SigChunk>() const { return chunks(); } + operator std::vector<RTLIL::SigBit>() const { return bits(); } + +#ifndef NDEBUG + void check() const; +#else + inline void check() const { } +#endif }; +inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const { + return (*sig_p)[index]; +} + +inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const { + return (*sig_p)[index]; +} + inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) { - assert(sig.width == 1 && sig.chunks.size() == 1); - *this = SigBit(sig.chunks[0]); + log_assert(sig.size() == 1 && sig.chunks().size() == 1); + *this = SigBit(sig.chunks().front()); } -struct RTLIL::CaseRule { +struct RTLIL::CaseRule +{ std::vector<RTLIL::SigSpec> compare; std::vector<RTLIL::SigSig> actions; std::vector<RTLIL::SwitchRule*> switches; + ~CaseRule(); void optimize(); @@ -431,34 +1103,36 @@ struct RTLIL::CaseRule { RTLIL::CaseRule *clone() const; }; -struct RTLIL::SwitchRule { +struct RTLIL::SwitchRule +{ RTLIL::SigSpec signal; RTLIL_ATTRIBUTE_MEMBERS std::vector<RTLIL::CaseRule*> cases; + ~SwitchRule(); - void optimize(); template<typename T> void rewrite_sigspecs(T functor); RTLIL::SwitchRule *clone() const; }; -struct RTLIL::SyncRule { +struct RTLIL::SyncRule +{ RTLIL::SyncType type; RTLIL::SigSpec signal; std::vector<RTLIL::SigSig> actions; - void optimize(); template<typename T> void rewrite_sigspecs(T functor); RTLIL::SyncRule *clone() const; }; -struct RTLIL::Process { +struct RTLIL::Process +{ RTLIL::IdString name; RTLIL_ATTRIBUTE_MEMBERS RTLIL::CaseRule root_case; std::vector<RTLIL::SyncRule*> syncs; + ~Process(); - void optimize(); template<typename T> void rewrite_sigspecs(T functor); RTLIL::Process *clone() const; @@ -467,11 +1141,11 @@ struct RTLIL::Process { template<typename T> void RTLIL::Module::rewrite_sigspecs(T functor) { - for (auto &it : cells) + for (auto &it : cells_) it.second->rewrite_sigspecs(functor); for (auto &it : processes) it.second->rewrite_sigspecs(functor); - for (auto &it : connections) { + for (auto &it : connections_) { functor(it.first); functor(it.second); } @@ -479,7 +1153,7 @@ void RTLIL::Module::rewrite_sigspecs(T functor) template<typename T> void RTLIL::Cell::rewrite_sigspecs(T functor) { - for (auto &it : connections) + for (auto &it : connections_) functor(it.second); } @@ -521,4 +1195,6 @@ void RTLIL::Process::rewrite_sigspecs(T functor) it->rewrite_sigspecs(functor); } +YOSYS_NAMESPACE_END + #endif diff --git a/kernel/satgen.h b/kernel/satgen.h index 840700cbd..692c6e7fb 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -23,14 +23,10 @@ #include "kernel/rtlil.h" #include "kernel/sigtools.h" #include "kernel/celltypes.h" +#include "kernel/macc.h" -#ifdef YOSYS_ENABLE_MINISAT -# include "libs/ezsat/ezminisat.h" +#include "libs/ezsat/ezminisat.h" typedef ezMiniSAT ezDefaultSAT; -#else -# include "libs/ezsat/ezsat.h" -typedef ezSAT ezDefaultSAT; -#endif struct SatGen { @@ -57,21 +53,19 @@ struct SatGen { log_assert(!undef_mode || model_undef); sigmap->apply(sig); - sig.expand(); std::vector<int> vec; - vec.reserve(sig.chunks.size()); + vec.reserve(SIZE(sig)); - for (auto &c : sig.chunks) - if (c.wire == NULL) { - RTLIL::State bit = c.data.bits.at(0); + for (auto &bit : sig) + if (bit.wire == NULL) { if (model_undef && dup_undef && bit == RTLIL::State::Sx) - vec.push_back(ez->literal()); + vec.push_back(ez->frozen_literal()); else vec.push_back(bit == (undef_mode ? RTLIL::State::Sx : RTLIL::State::S1) ? ez->TRUE : ez->FALSE); } else { - std::string name = pf + stringf(c.wire->width == 1 ? "%s" : "%s [%d]", RTLIL::id2cstr(c.wire->name), c.offset); - vec.push_back(ez->literal(name)); + std::string name = pf + stringf(bit.wire->width == 1 ? "%s" : "%s [%d]", RTLIL::id2cstr(bit.wire->name), bit.offset); + vec.push_back(ez->frozen_literal(name)); } return vec; } @@ -123,7 +117,7 @@ struct SatGen if (timestep_rhs < 0) timestep_rhs = timestep_lhs; - assert(lhs.width == rhs.width); + log_assert(lhs.size() == rhs.size()); std::vector<int> vec_lhs = importSigSpec(lhs, timestep_lhs); std::vector<int> vec_rhs = importSigSpec(rhs, timestep_rhs); @@ -135,7 +129,7 @@ struct SatGen std::vector<int> undef_rhs = importUndefSigSpec(rhs, timestep_rhs); std::vector<int> eq_bits; - for (int i = 0; i < lhs.width; i++) + for (int i = 0; i < lhs.size(); i++) eq_bits.push_back(ez->AND(ez->IFF(undef_lhs.at(i), undef_rhs.at(i)), ez->IFF(ez->OR(vec_lhs.at(i), undef_lhs.at(i)), ez->OR(vec_rhs.at(i), undef_rhs.at(i))))); return ez->expression(ezSAT::OpAnd, eq_bits); @@ -170,20 +164,33 @@ struct SatGen void undefGating(std::vector<int> &vec_y, std::vector<int> &vec_yy, std::vector<int> &vec_undef) { - assert(model_undef); - ez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(vec_y, vec_yy)))); + log_assert(model_undef); + log_assert(vec_y.size() == vec_yy.size()); + if (vec_y.size() > vec_undef.size()) { + std::vector<int> trunc_y(vec_y.begin(), vec_y.begin() + vec_undef.size()); + std::vector<int> trunc_yy(vec_yy.begin(), vec_yy.begin() + vec_undef.size()); + ez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(trunc_y, trunc_yy)))); + } else { + log_assert(vec_y.size() == vec_undef.size()); + ez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(vec_y, vec_yy)))); + } + } + + void undefGating(int y, int yy, int undef) + { + ez->assume(ez->OR(undef, ez->IFF(y, yy))); } bool importCell(RTLIL::Cell *cell, int timestep = -1) { bool arith_undef_handled = false; - bool is_arith_compare = cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt"; + bool is_arith_compare = cell->type.in("$lt", "$le", "$ge", "$gt"); - if (model_undef && (cell->type == "$add" || cell->type == "$sub" || cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod" || is_arith_compare)) + if (model_undef && (cell->type.in("$add", "$sub", "$mul", "$div", "$mod") || is_arith_compare)) { - std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); if (is_arith_compare) extendSignalWidth(undef_a, undef_b, cell, true); else @@ -194,7 +201,7 @@ struct SatGen int undef_y_bit = ez->OR(undef_any_a, undef_any_b); if (cell->type == "$div" || cell->type == "$mod") { - std::vector<int> b = importSigSpec(cell->connections.at("\\B"), timestep); + std::vector<int> b = importSigSpec(cell->getPort("\\B"), timestep); undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b))); } @@ -210,24 +217,27 @@ struct SatGen arith_undef_handled = true; } - if (cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_" || - cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor" || - cell->type == "$add" || cell->type == "$sub") + if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", + "$and", "$or", "$xor", "$xnor", "$add", "$sub")) { - std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); extendSignalWidth(a, b, y, cell); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; if (cell->type == "$and" || cell->type == "$_AND_") ez->assume(ez->vec_eq(ez->vec_and(a, b), yy)); + if (cell->type == "$_NAND_") + ez->assume(ez->vec_eq(ez->vec_not(ez->vec_and(a, b)), yy)); if (cell->type == "$or" || cell->type == "$_OR_") ez->assume(ez->vec_eq(ez->vec_or(a, b), yy)); + if (cell->type == "$_NOR_") + ez->assume(ez->vec_eq(ez->vec_not(ez->vec_or(a, b)), yy)); if (cell->type == "$xor" || cell->type == "$_XOR_") ez->assume(ez->vec_eq(ez->vec_xor(a, b), yy)); - if (cell->type == "$xnor") + if (cell->type == "$xnor" || cell->type == "$_XNOR_") ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(a, b)), yy)); if (cell->type == "$add") ez->assume(ez->vec_eq(ez->vec_add(a, b), yy)); @@ -236,24 +246,24 @@ struct SatGen if (model_undef && !arith_undef_handled) { - std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); extendSignalWidth(undef_a, undef_b, undef_y, cell, false); - if (cell->type == "$and" || cell->type == "$_AND_") { + if (cell->type.in("$and", "$_AND_", "$_NAND_")) { std::vector<int> a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a)); std::vector<int> b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b)); std::vector<int> 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 == "$or" || cell->type == "$_OR_") { + else if (cell->type.in("$or", "$_OR_", "$_NOR_")) { std::vector<int> a1 = ez->vec_and(a, ez->vec_not(undef_a)); std::vector<int> b1 = ez->vec_and(b, ez->vec_not(undef_b)); std::vector<int> 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 == "$xor" || cell->type == "$_XOR_" || cell->type == "$xnor") { + else if (cell->type.in("$xor", "$xnor", "$_XOR_", "$_XNOR_")) { std::vector<int> yX = ez->vec_or(undef_a, undef_b); ez->assume(ez->vec_eq(yX, undef_y)); } @@ -264,25 +274,91 @@ struct SatGen } else if (model_undef) { - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type.in("$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_")) + { + bool aoi_mode = cell->type.in("$_AOI3_", "$_AOI4_"); + bool three_mode = cell->type.in("$_AOI3_", "$_OAI3_"); + + int a = importDefSigSpec(cell->getPort("\\A"), timestep).at(0); + int b = importDefSigSpec(cell->getPort("\\B"), timestep).at(0); + int c = importDefSigSpec(cell->getPort("\\C"), timestep).at(0); + int d = three_mode ? (aoi_mode ? ez->TRUE : ez->FALSE) : importDefSigSpec(cell->getPort("\\D"), timestep).at(0); + int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0); + int yy = model_undef ? ez->literal() : y; + + if (cell->type.in("$_AOI3_", "$_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("\\A"), timestep).at(0); + int undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep).at(0); + int undef_c = importUndefSigSpec(cell->getPort("\\C"), timestep).at(0); + int undef_d = three_mode ? ez->FALSE : importUndefSigSpec(cell->getPort("\\D"), timestep).at(0); + int undef_y = importUndefSigSpec(cell->getPort("\\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 == "$_INV_" || cell->type == "$not") + if (cell->type == "$_NOT_" || cell->type == "$not") { - std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); extendSignalWidthUnary(a, y, cell); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; ez->assume(ez->vec_eq(ez->vec_not(a), yy)); if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); - extendSignalWidthUnary(undef_a, undef_y, cell, true); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + extendSignalWidthUnary(undef_a, undef_y, cell, false); ez->assume(ez->vec_eq(undef_a, undef_y)); undefGating(y, yy, undef_y); } @@ -291,20 +367,20 @@ struct SatGen if (cell->type == "$_MUX_" || cell->type == "$mux") { - std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> s = importDefSigSpec(cell->connections.at("\\S"), timestep); - std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> s = importDefSigSpec(cell->getPort("\\S"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy)); if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> undef_s = importUndefSigSpec(cell->connections.at("\\S"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); std::vector<int> unequal_ab = ez->vec_not(ez->vec_iff(a, b)); std::vector<int> undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a, undef_b)); @@ -315,12 +391,12 @@ struct SatGen return true; } - if (cell->type == "$pmux" || cell->type == "$safe_pmux") + if (cell->type == "$pmux") { - std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> s = importDefSigSpec(cell->connections.at("\\S"), timestep); - std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> s = importDefSigSpec(cell->getPort("\\S"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; @@ -329,16 +405,14 @@ struct SatGen std::vector<int> 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); } - if (cell->type == "$safe_pmux") - tmp = ez->vec_ite(ez->onehot(s, true), tmp, a); ez->assume(ez->vec_eq(tmp, yy)); if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> undef_s = importUndefSigSpec(cell->connections.at("\\S"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); int maybe_one_hot = ez->FALSE; int maybe_many_hot = ez->FALSE; @@ -369,12 +443,6 @@ struct SatGen int maybe_a = ez->NOT(maybe_one_hot); - if (cell->type == "$safe_pmux") { - maybe_a = ez->OR(maybe_a, maybe_many_hot); - bits_set = ez->vec_ite(sure_many_hot, ez->vec_or(a, undef_a), bits_set); - bits_clr = ez->vec_ite(sure_many_hot, ez->vec_or(ez->vec_not(a), undef_a), 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); @@ -386,8 +454,8 @@ struct SatGen if (cell->type == "$pos" || cell->type == "$neg") { - std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); extendSignalWidthUnary(a, y, cell); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; @@ -401,9 +469,9 @@ struct SatGen if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); - extendSignalWidthUnary(undef_a, undef_y, cell, true); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + extendSignalWidthUnary(undef_a, undef_y, cell); if (cell->type == "$pos") { ez->assume(ez->vec_eq(undef_a, undef_y)); @@ -421,8 +489,8 @@ struct SatGen if (cell->type == "$reduce_and" || cell->type == "$reduce_or" || cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || cell->type == "$reduce_bool" || cell->type == "$logic_not") { - std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; @@ -441,8 +509,8 @@ struct SatGen if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); int aX = ez->expression(ezSAT::OpOr, undef_a); if (cell->type == "$reduce_and") { @@ -468,12 +536,12 @@ struct SatGen if (cell->type == "$logic_and" || cell->type == "$logic_or") { - std::vector<int> vec_a = importDefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> vec_b = importDefSigSpec(cell->connections.at("\\B"), timestep); + std::vector<int> vec_a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> vec_b = importDefSigSpec(cell->getPort("\\B"), timestep); int a = ez->expression(ez->OpOr, vec_a); int b = ez->expression(ez->OpOr, vec_b); - std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; @@ -486,9 +554,9 @@ struct SatGen if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\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))); @@ -515,16 +583,16 @@ struct SatGen if (cell->type == "$lt" || cell->type == "$le" || cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" || cell->type == "$ge" || cell->type == "$gt") { bool is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool(); - std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); extendSignalWidth(a, b, cell); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; if (model_undef && (cell->type == "$eqx" || cell->type == "$nex")) { - std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); extendSignalWidth(undef_a, undef_b, cell, true); a = ez->vec_or(a, undef_a); b = ez->vec_or(b, undef_b); @@ -547,9 +615,9 @@ struct SatGen if (model_undef && (cell->type == "$eqx" || cell->type == "$nex")) { - std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); extendSignalWidth(undef_a, undef_b, cell, true); if (cell->type == "$eqx") @@ -564,9 +632,9 @@ struct SatGen } else if (model_undef && (cell->type == "$eq" || cell->type == "$ne")) { - std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); extendSignalWidth(undef_a, undef_b, cell, true); int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); @@ -588,7 +656,7 @@ struct SatGen else { if (model_undef) { - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); undefGating(y, yy, undef_y); } log_assert(!model_undef || arith_undef_handled); @@ -596,59 +664,73 @@ struct SatGen return true; } - if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr") + if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx") { - std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); - char shift_left = cell->type == "$shl" || cell->type == "$sshl"; - bool sign_extend = cell->type == "$sshr" && cell->parameters["\\A_SIGNED"].as_bool(); + int extend_bit = ez->FALSE; + + if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\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(cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->FALSE); + a.push_back(extend_bit); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; + std::vector<int> shifted_a; - std::vector<int> tmp = a; - for (size_t i = 0; i < b.size(); i++) - { - std::vector<int> tmp_shifted(tmp.size()); - for (size_t j = 0; j < tmp.size(); j++) { - int idx = j + (1 << (i > 30 ? 30 : i)) * (shift_left ? -1 : +1); - tmp_shifted.at(j) = (0 <= idx && idx < int(tmp.size())) ? tmp.at(idx) : sign_extend ? tmp.back() : ez->FALSE; - } - tmp = ez->vec_ite(b.at(i), tmp_shifted, tmp); - } - ez->assume(ez->vec_eq(tmp, yy)); + if (cell->type == "$shl" || cell->type == "$sshl") + shifted_a = ez->vec_shift_left(a, b, false, ez->FALSE, ez->FALSE); + + if (cell->type == "$shr") + shifted_a = ez->vec_shift_right(a, b, false, ez->FALSE, ez->FALSE); + + if (cell->type == "$sshr") + shifted_a = ez->vec_shift_right(a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->FALSE, ez->FALSE); + + if (cell->type == "$shift" || cell->type == "$shiftx") + shifted_a = ez->vec_shift_right(a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->FALSE, ez->FALSE); + + ez->assume(ez->vec_eq(shifted_a, yy)); if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_a_shifted; + + extend_bit = cell->type == "$shiftx" ? ez->TRUE : ez->FALSE; + if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\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(undef_a.back()); + undef_a.push_back(extend_bit); - tmp = undef_a; - for (size_t i = 0; i < b.size(); i++) - { - std::vector<int> tmp_shifted(tmp.size()); - for (size_t j = 0; j < tmp.size(); j++) { - int idx = j + (1 << (i > 30 ? 30 : i)) * (shift_left ? -1 : +1); - tmp_shifted.at(j) = (0 <= idx && idx < int(tmp.size())) ? tmp.at(idx) : sign_extend ? tmp.back() : ez->FALSE; - } - tmp = ez->vec_ite(b.at(i), tmp_shifted, tmp); - } + if (cell->type == "$shl" || cell->type == "$sshl") + undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->FALSE, ez->FALSE); + + if (cell->type == "$shr") + undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->FALSE, ez->FALSE); + + if (cell->type == "$sshr") + undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? undef_a.back() : ez->FALSE, ez->FALSE); + + if (cell->type == "$shift") + undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->FALSE, ez->FALSE); + + if (cell->type == "$shiftx") + undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->TRUE, ez->TRUE); int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); std::vector<int> undef_all_y_bits(undef_y.size(), undef_any_b); - ez->assume(ez->vec_eq(ez->vec_or(tmp, undef_all_y_bits), undef_y)); + ez->assume(ez->vec_eq(ez->vec_or(undef_a_shifted, undef_all_y_bits), undef_y)); undefGating(y, yy, undef_y); } return true; @@ -656,9 +738,9 @@ struct SatGen if (cell->type == "$mul") { - std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); extendSignalWidth(a, b, y, cell); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; @@ -675,17 +757,87 @@ struct SatGen if (model_undef) { log_assert(arith_undef_handled); - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); undefGating(y, yy, undef_y); } return true; } + if (cell->type == "$macc") + { + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + + Macc macc; + macc.from_cell(cell); + + std::vector<int> tmp(SIZE(y), ez->FALSE); + + for (auto &port : macc.ports) + { + std::vector<int> in_a = importDefSigSpec(port.in_a, timestep); + std::vector<int> in_b = importDefSigSpec(port.in_b, timestep); + + while (SIZE(in_a) < SIZE(y)) + in_a.push_back(port.is_signed && !in_a.empty() ? in_a.back() : ez->FALSE); + in_a.resize(SIZE(y)); + + if (SIZE(in_b)) + { + while (SIZE(in_b) < SIZE(y)) + in_b.push_back(port.is_signed && !in_b.empty() ? in_b.back() : ez->FALSE); + in_b.resize(SIZE(y)); + + for (int i = 0; i < SIZE(in_b); i++) { + std::vector<int> shifted_a(in_a.size(), ez->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 < SIZE(b); i++) { + std::vector<int> val(SIZE(y), ez->FALSE); + val.at(0) = b.at(i); + tmp = ez->vec_add(tmp, val); + } + + if (model_undef) + { + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); + + int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); + int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); + + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + ez->assume(ez->vec_eq(undef_y, std::vector<int>(SIZE(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 == "$div" || cell->type == "$mod") { - std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep); - std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); extendSignalWidth(a, b, y, cell); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; @@ -739,11 +891,11 @@ struct SatGen only_first_one.at(0) = ez->TRUE; div_zero_result = ez->vec_ite(a.back(), only_first_one, all_ones); } else { - div_zero_result.insert(div_zero_result.end(), cell->connections.at("\\A").width, ez->TRUE); + div_zero_result.insert(div_zero_result.end(), cell->getPort("\\A").size(), ez->TRUE); div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->FALSE); } } else { - int copy_a_bits = std::min(cell->connections.at("\\A").width, cell->connections.at("\\B").width); + int copy_a_bits = std::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()); @@ -755,25 +907,209 @@ struct SatGen if (model_undef) { log_assert(arith_undef_handled); - std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type == "$lut") + { + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + + std::vector<int> lut; + for (auto bit : cell->getParam("\\LUT").bits) + lut.push_back(bit == RTLIL::S1 ? ez->TRUE : ez->FALSE); + while (SIZE(lut) < (1 << SIZE(a))) + lut.push_back(ez->FALSE); + lut.resize(1 << SIZE(a)); + + if (model_undef) + { + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> t(lut), u(SIZE(t), ez->FALSE); + + for (int i = SIZE(a)-1; i >= 0; i--) + { + std::vector<int> t0(t.begin(), t.begin() + SIZE(t)/2); + std::vector<int> t1(t.begin() + SIZE(t)/2, t.end()); + + std::vector<int> u0(u.begin(), u.begin() + SIZE(u)/2); + std::vector<int> u1(u.begin() + SIZE(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(SIZE(t) == 1); + log_assert(SIZE(u) == 1); + undefGating(y, t, u); + ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort("\\Y"), timestep), u)); + } + else + { + std::vector<int> t = lut; + for (int i = SIZE(a)-1; i >= 0; i--) + { + std::vector<int> t0(t.begin(), t.begin() + SIZE(t)/2); + std::vector<int> t1(t.begin() + SIZE(t)/2, t.end()); + t = ez->vec_ite(a[i], t1, t0); + } + + log_assert(SIZE(t) == 1); + ez->assume(ez->vec_eq(y, t)); + } + return true; + } + + if (cell->type == "$fa") + { + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> c = importDefSigSpec(cell->getPort("\\C"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> x = importDefSigSpec(cell->getPort("\\X"), timestep); + + std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; + std::vector<int> xx = model_undef ? ez->vec_var(x.size()) : x; + + std::vector<int> t1 = ez->vec_xor(a, b); + ez->assume(ez->vec_eq(yy, ez->vec_xor(t1, c))); + + std::vector<int> t2 = ez->vec_and(a, b); + std::vector<int> t3 = ez->vec_and(c, t1); + ez->assume(ez->vec_eq(xx, ez->vec_or(t2, t3))); + + if (model_undef) + { + std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> undef_c = importUndefSigSpec(cell->getPort("\\C"), timestep); + + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_x = importUndefSigSpec(cell->getPort("\\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 == "$lcu") + { + std::vector<int> p = importDefSigSpec(cell->getPort("\\P"), timestep); + std::vector<int> g = importDefSigSpec(cell->getPort("\\G"), timestep); + std::vector<int> ci = importDefSigSpec(cell->getPort("\\CI"), timestep); + std::vector<int> co = importDefSigSpec(cell->getPort("\\CO"), timestep); + + std::vector<int> yy = model_undef ? ez->vec_var(co.size()) : co; + + for (int i = 0; i < SIZE(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<int> undef_p = importUndefSigSpec(cell->getPort("\\P"), timestep); + std::vector<int> undef_g = importUndefSigSpec(cell->getPort("\\G"), timestep); + std::vector<int> undef_ci = importUndefSigSpec(cell->getPort("\\CI"), timestep); + std::vector<int> undef_co = importUndefSigSpec(cell->getPort("\\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<int> 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 == "$alu") + { + std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> x = importDefSigSpec(cell->getPort("\\X"), timestep); + std::vector<int> ci = importDefSigSpec(cell->getPort("\\CI"), timestep); + std::vector<int> bi = importDefSigSpec(cell->getPort("\\BI"), timestep); + std::vector<int> co = importDefSigSpec(cell->getPort("\\CO"), timestep); + + extendSignalWidth(a, b, y, cell); + extendSignalWidth(a, b, x, cell); + extendSignalWidth(a, b, co, cell); + + std::vector<int> def_y = model_undef ? ez->vec_var(y.size()) : y; + std::vector<int> def_x = model_undef ? ez->vec_var(x.size()) : x; + std::vector<int> def_co = model_undef ? ez->vec_var(co.size()) : co; + + log_assert(SIZE(y) == SIZE(x)); + log_assert(SIZE(y) == SIZE(co)); + log_assert(SIZE(ci) == 1); + log_assert(SIZE(bi) == 1); + + for (int i = 0; i < SIZE(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<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> undef_ci = importUndefSigSpec(cell->getPort("\\CI"), timestep); + std::vector<int> undef_bi = importUndefSigSpec(cell->getPort("\\BI"), timestep); + + std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_x = importUndefSigSpec(cell->getPort("\\X"), timestep); + std::vector<int> undef_co = importUndefSigSpec(cell->getPort("\\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<int> 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 < SIZE(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 == "$slice") { - RTLIL::SigSpec a = cell->connections.at("\\A"); - RTLIL::SigSpec y = cell->connections.at("\\Y"); - ez->assume(signals_eq(a.extract(cell->parameters.at("\\OFFSET").as_int(), y.width), y, timestep)); + RTLIL::SigSpec a = cell->getPort("\\A"); + RTLIL::SigSpec y = cell->getPort("\\Y"); + ez->assume(signals_eq(a.extract(cell->parameters.at("\\OFFSET").as_int(), y.size()), y, timestep)); return true; } if (cell->type == "$concat") { - RTLIL::SigSpec a = cell->connections.at("\\A"); - RTLIL::SigSpec b = cell->connections.at("\\B"); - RTLIL::SigSpec y = cell->connections.at("\\Y"); + RTLIL::SigSpec a = cell->getPort("\\A"); + RTLIL::SigSpec b = cell->getPort("\\B"); + RTLIL::SigSpec y = cell->getPort("\\Y"); RTLIL::SigSpec ab = a; ab.append(b); @@ -786,20 +1122,20 @@ struct SatGen { if (timestep == 1) { - initial_state.add((*sigmap)(cell->connections.at("\\Q"))); + initial_state.add((*sigmap)(cell->getPort("\\Q"))); } else { - std::vector<int> d = importDefSigSpec(cell->connections.at("\\D"), timestep-1); - std::vector<int> q = importDefSigSpec(cell->connections.at("\\Q"), timestep); + std::vector<int> d = importDefSigSpec(cell->getPort("\\D"), timestep-1); + std::vector<int> q = importDefSigSpec(cell->getPort("\\Q"), timestep); std::vector<int> qq = model_undef ? ez->vec_var(q.size()) : q; ez->assume(ez->vec_eq(d, qq)); if (model_undef) { - std::vector<int> undef_d = importUndefSigSpec(cell->connections.at("\\D"), timestep-1); - std::vector<int> undef_q = importUndefSigSpec(cell->connections.at("\\Q"), timestep); + std::vector<int> undef_d = importUndefSigSpec(cell->getPort("\\D"), timestep-1); + std::vector<int> undef_q = importUndefSigSpec(cell->getPort("\\Q"), timestep); ez->assume(ez->vec_eq(undef_d, undef_q)); undefGating(q, qq, undef_q); @@ -811,8 +1147,8 @@ struct SatGen if (cell->type == "$assert") { std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - asserts_a[pf].append((*sigmap)(cell->connections.at("\\A"))); - asserts_en[pf].append((*sigmap)(cell->connections.at("\\EN"))); + asserts_a[pf].append((*sigmap)(cell->getPort("\\A"))); + asserts_en[pf].append((*sigmap)(cell->getPort("\\EN"))); return true; } @@ -823,4 +1159,3 @@ struct SatGen }; #endif - diff --git a/kernel/sigtools.h b/kernel/sigtools.h index ae6a00f8e..32ef444aa 100644 --- a/kernel/sigtools.h +++ b/kernel/sigtools.h @@ -20,14 +20,17 @@ #ifndef SIGTOOLS_H #define SIGTOOLS_H -#include "kernel/rtlil.h" -#include "kernel/log.h" -#include <assert.h> -#include <set> +#include "kernel/yosys.h" + +YOSYS_NAMESPACE_BEGIN struct SigPool { - typedef std::pair<RTLIL::Wire*,int> bitDef_t; + 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) { } + }; + std::set<bitDef_t> bits; void clear() @@ -37,14 +40,9 @@ struct SigPool void add(RTLIL::SigSpec sig) { - sig.expand(); - for (auto &c : sig.chunks) { - if (c.wire == NULL) - continue; - assert(c.width == 1); - bitDef_t bit(c.wire, c.offset); - bits.insert(bit); - } + for (auto &bit : sig) + if (bit.wire != NULL) + bits.insert(bit); } void add(const SigPool &other) @@ -55,14 +53,9 @@ struct SigPool void del(RTLIL::SigSpec sig) { - sig.expand(); - for (auto &c : sig.chunks) { - if (c.wire == NULL) - continue; - assert(c.width == 1); - bitDef_t bit(c.wire, c.offset); - bits.erase(bit); - } + for (auto &bit : sig) + if (bit.wire != NULL) + bits.erase(bit); } void del(const SigPool &other) @@ -73,15 +66,10 @@ struct SigPool void expand(RTLIL::SigSpec from, RTLIL::SigSpec to) { - from.expand(); - to.expand(); - assert(from.chunks.size() == to.chunks.size()); - for (size_t i = 0; i < from.chunks.size(); i++) { - bitDef_t bit_from(from.chunks[i].wire, from.chunks[i].offset); - bitDef_t bit_to(to.chunks[i].wire, to.chunks[i].offset); - if (bit_from.first == NULL || bit_to.first == NULL) - continue; - if (bits.count(bit_from) > 0) + log_assert(SIZE(from) == SIZE(to)); + for (int i = 0; i < SIZE(from); i++) { + bitDef_t bit_from(from[i]), bit_to(to[i]); + if (bit_from.first != NULL && bit_to.first != NULL && bits.count(bit_from) > 0) bits.insert(bit_to); } } @@ -89,73 +77,54 @@ struct SigPool RTLIL::SigSpec extract(RTLIL::SigSpec sig) { RTLIL::SigSpec result; - sig.expand(); - for (auto &c : sig.chunks) { - if (c.wire == NULL) - continue; - bitDef_t bit(c.wire, c.offset); - if (bits.count(bit) > 0) - result.append(c); - } + for (auto &bit : sig) + if (bit.wire != NULL && bits.count(bit)) + result.append_bit(bit); return result; } RTLIL::SigSpec remove(RTLIL::SigSpec sig) { RTLIL::SigSpec result; - sig.expand(); - for (auto &c : sig.chunks) { - if (c.wire == NULL) - continue; - bitDef_t bit(c.wire, c.offset); - if (bits.count(bit) == 0) - result.append(c); - } + for (auto &bit : sig) + if (bit.wire != NULL && bits.count(bit) == 0) + result.append(bit); return result; } + bool check(RTLIL::SigBit bit) + { + return bit.wire != NULL && bits.count(bit); + } + bool check_any(RTLIL::SigSpec sig) { - sig.expand(); - for (auto &c : sig.chunks) { - if (c.wire == NULL) - continue; - bitDef_t bit(c.wire, c.offset); - if (bits.count(bit) != 0) + for (auto &bit : sig) + if (bit.wire != NULL && bits.count(bit)) return true; - } return false; } bool check_all(RTLIL::SigSpec sig) { - sig.expand(); - for (auto &c : sig.chunks) { - if (c.wire == NULL) - continue; - bitDef_t bit(c.wire, c.offset); - if (bits.count(bit) == 0) + for (auto &bit : sig) + if (bit.wire != NULL && bits.count(bit) == 0) return false; - } return true; } RTLIL::SigSpec export_one() { - RTLIL::SigSpec sig; - for (auto &bit : bits) { - sig.append(RTLIL::SigSpec(bit.first, 1, bit.second)); - break; - } - return sig; + for (auto &bit : bits) + return RTLIL::SigSpec(bit.first, bit.second); + return RTLIL::SigSpec(); } RTLIL::SigSpec export_all() { - RTLIL::SigSpec sig; + std::set<RTLIL::SigBit> sig; for (auto &bit : bits) - sig.append(RTLIL::SigSpec(bit.first, 1, bit.second)); - sig.sort_and_unify(); + sig.insert(RTLIL::SigBit(bit.first, bit.second)); return sig; } @@ -168,7 +137,11 @@ struct SigPool template <typename T, class Compare = std::less<T>> struct SigSet { - typedef std::pair<RTLIL::Wire*,int> bitDef_t; + 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) { } + }; + std::map<bitDef_t, std::set<T, Compare>> bits; void clear() @@ -178,75 +151,46 @@ struct SigSet void insert(RTLIL::SigSpec sig, T data) { - sig.expand(); - for (auto &c : sig.chunks) { - if (c.wire == NULL) - continue; - assert(c.width == 1); - bitDef_t bit(c.wire, c.offset); - bits[bit].insert(data); - } + for (auto &bit : sig) + if (bit.wire != NULL) + bits[bit].insert(data); } void insert(RTLIL::SigSpec sig, const std::set<T> &data) { - sig.expand(); - for (auto &c : sig.chunks) { - if (c.wire == NULL) - continue; - assert(c.width == 1); - bitDef_t bit(c.wire, c.offset); - bits[bit].insert(data.begin(), data.end()); - } + for (auto &bit : sig) + if (bit.wire != NULL) + bits[bit].insert(data.begin(), data.end()); } void erase(RTLIL::SigSpec sig) { - sig.expand(); - for (auto &c : sig.chunks) { - if (c.wire == NULL) - continue; - assert(c.width == 1); - bitDef_t bit(c.wire, c.offset); - bits[bit].clear(); - } + for (auto &bit : sig) + if (bit.wire != NULL) + bits[bit].clear(); } void erase(RTLIL::SigSpec sig, T data) { - sig.expand(); - for (auto &c : sig.chunks) { - if (c.wire == NULL) - continue; - assert(c.width == 1); - bitDef_t bit(c.wire, c.offset); - bits[bit].erase(data); - } + for (auto &bit : sig) + if (bit.wire != NULL) + bits[bit].erase(data); } void erase(RTLIL::SigSpec sig, const std::set<T> &data) { - sig.expand(); - for (auto &c : sig.chunks) { - if (c.wire == NULL) - continue; - assert(c.width == 1); - bitDef_t bit(c.wire, c.offset); - bits[bit].erase(data.begin(), data.end()); - } + for (auto &bit : sig) + if (bit.wire != NULL) + bits[bit].erase(data.begin(), data.end()); } void find(RTLIL::SigSpec sig, std::set<T> &result) { - sig.expand(); - for (auto &c : sig.chunks) { - if (c.wire == NULL) - continue; - assert(c.width == 1); - bitDef_t bit(c.wire, c.offset); - for (auto &data : bits[bit]) - result.insert(data); - } + for (auto &bit : sig) + if (bit.wire != NULL) { + auto &data = bits[bit]; + result.insert(data.begin(), data.end()); + } } std::set<T> find(RTLIL::SigSpec sig) @@ -258,25 +202,22 @@ struct SigSet bool has(RTLIL::SigSpec sig) { - sig.expand(); - for (auto &c : sig.chunks) { - if (c.wire == NULL) - continue; - assert(c.width == 1); - bitDef_t bit(c.wire, c.offset); - if (bits.count(bit)) + for (auto &bit : sig) + if (bit.wire != NULL && bits.count(bit)) return true; - } return false; } }; struct SigMap { - typedef std::pair<RTLIL::Wire*,int> bitDef_t; + 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) { } + }; struct shared_bit_data_t { - RTLIL::SigChunk chunk; + RTLIL::SigBit map_to; std::set<bitDef_t> bits; }; @@ -304,7 +245,7 @@ struct SigMap clear(); for (auto &bit : other.bits) { bits[bit.first] = new shared_bit_data_t; - bits[bit.first]->chunk = bit.second->chunk; + bits[bit.first]->map_to = bit.second->map_to; bits[bit.first]->bits = bit.second->bits; } } @@ -332,29 +273,25 @@ struct SigMap void set(RTLIL::Module *module) { clear(); - for (auto &it : module->connections) + for (auto &it : module->connections()) add(it.first, it.second); } // internal helper function - void register_bit(const RTLIL::SigChunk &c) + void register_bit(const RTLIL::SigBit &bit) { - assert(c.width == 1); - bitDef_t bit(c.wire, c.offset); - if (c.wire && bits.count(bit) == 0) { + if (bit.wire && bits.count(bit) == 0) { shared_bit_data_t *bd = new shared_bit_data_t; - bd->chunk = c; + bd->map_to = bit; bd->bits.insert(bit); bits[bit] = bd; } } // internal helper function - void unregister_bit(const RTLIL::SigChunk &c) + void unregister_bit(const RTLIL::SigBit &bit) { - assert(c.width == 1); - bitDef_t bit(c.wire, c.offset); - if (c.wire && bits.count(bit) > 0) { + if (bit.wire && bits.count(bit) > 0) { shared_bit_data_t *bd = bits[bit]; bd->bits.erase(bit); if (bd->bits.size() == 0) @@ -364,17 +301,13 @@ struct SigMap } // internal helper function - void merge_bit(const RTLIL::SigChunk &c1, const RTLIL::SigChunk &c2) + void merge_bit(const RTLIL::SigBit &bit1, const RTLIL::SigBit &bit2) { - assert(c1.wire != NULL && c2.wire != NULL); - assert(c1.width == 1 && c2.width == 1); - - bitDef_t b1(c1.wire, c1.offset); - bitDef_t b2(c2.wire, c2.offset); + log_assert(bit1.wire != NULL && bit2.wire != NULL); - shared_bit_data_t *bd1 = bits[b1]; - shared_bit_data_t *bd2 = bits[b2]; - assert(bd1 != NULL && bd2 != 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; @@ -388,7 +321,7 @@ struct SigMap } else { - bd1->chunk = bd2->chunk; + bd1->map_to = bd2->map_to; for (auto &bit : bd2->bits) bits[bit] = bd1; bd1->bits.insert(bd2->bits.begin(), bd2->bits.end()); @@ -397,81 +330,87 @@ struct SigMap } // internal helper function - void set_bit(const RTLIL::SigChunk &c1, const RTLIL::SigChunk &c2) + void set_bit(const RTLIL::SigBit &bit1, const RTLIL::SigBit &bit2) { - assert(c1.wire != NULL); - assert(c1.width == 1 && c2.width == 1); - bitDef_t bit(c1.wire, c1.offset); - assert(bits.count(bit) > 0); - bits[bit]->chunk = c2; + log_assert(bit1.wire != NULL); + log_assert(bits.count(bit1) > 0); + bits[bit1]->map_to = bit2; } // internal helper function - void map_bit(RTLIL::SigChunk &c) + void map_bit(RTLIL::SigBit &bit) const { - assert(c.width == 1); - bitDef_t bit(c.wire, c.offset); - if (c.wire && bits.count(bit) > 0) - c = bits[bit]->chunk; + if (bit.wire && bits.count(bit) > 0) + bit = bits.at(bit)->map_to; } void add(RTLIL::SigSpec from, RTLIL::SigSpec to) { - from.expand(); - to.expand(); + log_assert(SIZE(from) == SIZE(to)); - assert(from.chunks.size() == to.chunks.size()); - for (size_t i = 0; i < from.chunks.size(); i++) + for (int i = 0; i < SIZE(from); i++) { - RTLIL::SigChunk &cf = from.chunks[i]; - RTLIL::SigChunk &ct = to.chunks[i]; + RTLIL::SigBit &bf = from[i]; + RTLIL::SigBit &bt = to[i]; - if (cf.wire == NULL) + if (bf.wire == NULL) continue; - register_bit(cf); - register_bit(ct); + register_bit(bf); + register_bit(bt); - if (ct.wire != NULL) - merge_bit(cf, ct); + if (bt.wire != NULL) + merge_bit(bf, bt); else - set_bit(cf, ct); + set_bit(bf, bt); } } void add(RTLIL::SigSpec sig) { - sig.expand(); - for (size_t i = 0; i < sig.chunks.size(); i++) - { - RTLIL::SigChunk &c = sig.chunks[i]; - if (c.wire != NULL) { - register_bit(c); - set_bit(c, c); - } + for (auto &bit : sig) { + register_bit(bit); + set_bit(bit, bit); } } void del(RTLIL::SigSpec sig) { - sig.expand(); - for (auto &c : sig.chunks) - unregister_bit(c); + for (auto &bit : sig) + unregister_bit(bit); + } + + void apply(RTLIL::SigBit &bit) const + { + map_bit(bit); + } + + void apply(RTLIL::SigSpec &sig) const + { + for (auto &bit : sig) + map_bit(bit); } - void apply(RTLIL::SigSpec &sig) + RTLIL::SigBit operator()(RTLIL::SigBit bit) const { - sig.expand(); - for (auto &c : sig.chunks) - map_bit(c); - sig.optimize(); + apply(bit); + return bit; } - RTLIL::SigSpec operator()(RTLIL::SigSpec sig) + RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const { apply(sig); return sig; } + + RTLIL::SigSpec operator()(RTLIL::Wire *wire) const + { + RTLIL::SigSpec sig(wire); + apply(sig); + return sig; + } }; +YOSYS_NAMESPACE_END + #endif /* SIGTOOLS_H */ diff --git a/kernel/utils.h b/kernel/utils.h new file mode 100644 index 000000000..a03caf804 --- /dev/null +++ b/kernel/utils.h @@ -0,0 +1,210 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +// This file contains various c++ utility routines and helper classes that +// do not depend on any other components of yosys (except stuff like log_*). + +#include "kernel/yosys.h" + +#ifndef UTILS_H +#define UTILS_H + +// ------------------------------------------------ +// A map-like container, but you can save and restore the state +// ------------------------------------------------ + +template<typename Key, typename T, typename Compare = std::less<Key>> +struct stackmap +{ +private: + std::vector<std::map<Key, T*, Compare>> backup_state; + std::map<Key, T, Compare> current_state; + static T empty_tuple; + +public: + stackmap() { } + stackmap(const std::map<Key, T, Compare> &other) : current_state(other) { } + + template<typename Other> + void operator=(const Other &other) + { + for (auto &it : current_state) + if (!backup_state.empty() && backup_state.back().count(it.first) == 0) + backup_state.back()[it.first] = new T(it.second); + current_state.clear(); + + for (auto &it : other) + set(it.first, it.second); + } + + bool has(const Key &k) + { + return current_state.count(k) != 0; + } + + void set(const Key &k, const T &v) + { + if (!backup_state.empty() && backup_state.back().count(k) == 0) + backup_state.back()[k] = current_state.count(k) ? new T(current_state.at(k)) : nullptr; + current_state[k] = v; + } + + void unset(const Key &k) + { + if (!backup_state.empty() && backup_state.back().count(k) == 0) + backup_state.back()[k] = current_state.count(k) ? new T(current_state.at(k)) : nullptr; + current_state.erase(k); + } + + const T &get(const Key &k) + { + if (current_state.count(k) == 0) + return empty_tuple; + return current_state.at(k); + } + + void reset(const Key &k) + { + for (int i = SIZE(backup_state)-1; i >= 0; i--) + if (backup_state[i].count(k) != 0) { + if (backup_state[i].at(k) == nullptr) + current_state.erase(k); + else + current_state[k] = *backup_state[i].at(k); + return; + } + current_state.erase(k); + } + + const std::map<Key, T, Compare> &stdmap() + { + return current_state; + } + + void save() + { + backup_state.resize(backup_state.size()+1); + } + + void restore() + { + log_assert(!backup_state.empty()); + for (auto &it : backup_state.back()) + if (it.second != nullptr) { + current_state[it.first] = *it.second; + delete it.second; + } else + current_state.erase(it.first); + backup_state.pop_back(); + } + + ~stackmap() + { + while (!backup_state.empty()) + restore(); + } +}; + + +// ------------------------------------------------ +// A simple class for topological sorting +// ------------------------------------------------ + +template<typename T> +struct TopoSort +{ + bool analyze_loops, found_loops; + std::map<T, std::set<T>> database; + std::set<std::set<T>> loops; + std::vector<T> sorted; + + TopoSort() + { + analyze_loops = true; + found_loops = false; + } + + void node(T n) + { + if (database.count(n) == 0) + database[n] = std::set<T>(); + } + + void edge(T left, T right) + { + node(left); + database[right].insert(left); + } + + void sort_worker(const T &n, std::set<T> &marked_cells, std::set<T> &active_cells, std::vector<T> &active_stack) + { + if (active_cells.count(n)) { + found_loops = true; + if (analyze_loops) { + std::set<T> loop; + for (int i = SIZE(active_stack)-1; i >= 0; i--) { + loop.insert(active_stack[i]); + if (active_stack[i] == n) + break; + } + loops.insert(loop); + } + return; + } + + if (marked_cells.count(n)) + return; + + if (!database.at(n).empty()) + { + if (analyze_loops) + active_stack.push_back(n); + active_cells.insert(n); + + for (auto &left_n : database.at(n)) + sort_worker(left_n, marked_cells, active_cells, active_stack); + + if (analyze_loops) + active_stack.pop_back(); + active_cells.erase(n); + } + + marked_cells.insert(n); + sorted.push_back(n); + } + + bool sort() + { + loops.clear(); + sorted.clear(); + found_loops = false; + + std::set<T> marked_cells; + std::set<T> active_cells; + std::vector<T> active_stack; + + for (auto &it : database) + sort_worker(it.first, marked_cells, active_cells, active_stack); + + log_assert(SIZE(sorted) == SIZE(database)); + return !found_loops; + } +}; + +#endif diff --git a/kernel/yosys.cc b/kernel/yosys.cc new file mode 100644 index 000000000..0ecb4cdaf --- /dev/null +++ b/kernel/yosys.cc @@ -0,0 +1,646 @@ +/* + * 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/yosys.h" + +#ifdef YOSYS_ENABLE_READLINE +# include <readline/readline.h> +# include <readline/history.h> +#endif + +#include <dlfcn.h> +#include <unistd.h> +#include <limits.h> +#include <errno.h> + +YOSYS_NAMESPACE_BEGIN + +int autoidx = 1; +RTLIL::Design *yosys_design = NULL; + +#ifdef YOSYS_ENABLE_TCL +Tcl_Interp *yosys_tcl_interp = NULL; +#endif + +std::string stringf(const char *fmt, ...) +{ + std::string string; + va_list ap; + + va_start(ap, fmt); + string = vstringf(fmt, ap); + va_end(ap); + + return string; +} + +std::string vstringf(const char *fmt, va_list ap) +{ + std::string string; + char *str = NULL; + + if (vasprintf(&str, fmt, ap) < 0) + str = NULL; + + if (str != NULL) { + string = str; + free(str); + } + + return string; +} + +int SIZE(RTLIL::Wire *wire) +{ + return wire->width; +} + +void yosys_setup() +{ + Pass::init_register(); + yosys_design = new RTLIL::Design; + log_push(); +} + +void yosys_shutdown() +{ + log_pop(); + + delete yosys_design; + yosys_design = NULL; + + for (auto f : log_files) + if (f != stderr) + fclose(f); + log_errfile = NULL; + log_files.clear(); + + Pass::done_register(); + +#ifdef YOSYS_ENABLE_TCL + if (yosys_tcl_interp != NULL) { + Tcl_DeleteInterp(yosys_tcl_interp); + Tcl_Finalize(); + yosys_tcl_interp = NULL; + } +#endif + + for (auto &it : loaded_plugins) + dlclose(it.second); + + loaded_plugins.clear(); + loaded_plugin_aliases.clear(); +} + +RTLIL::IdString new_id(std::string file, int line, std::string func) +{ + std::string str = "$auto$"; + size_t pos = file.find_last_of('/'); + str += pos != std::string::npos ? file.substr(pos+1) : file; + str += stringf(":%d:%s$%d", line, func.c_str(), autoidx++); + return str; +} + +RTLIL::Design *yosys_get_design() +{ + return yosys_design; +} + +const char *create_prompt(RTLIL::Design *design, int recursion_counter) +{ + static char buffer[100]; + std::string str = "\n"; + if (recursion_counter > 1) + str += stringf("(%d) ", recursion_counter); + str += "yosys"; + if (!design->selected_active_module.empty()) + str += stringf(" [%s]", RTLIL::unescape_id(design->selected_active_module).c_str()); + if (!design->selection_stack.empty() && !design->selection_stack.back().full_selection) { + if (design->selected_active_module.empty()) + str += "*"; + else if (design->selection_stack.back().selected_modules.size() != 1 || design->selection_stack.back().selected_members.size() != 0 || + design->selection_stack.back().selected_modules.count(design->selected_active_module) == 0) + str += "*"; + } + snprintf(buffer, 100, "%s> ", str.c_str()); + return buffer; +} + +#ifdef YOSYS_ENABLE_TCL +static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[]) +{ + std::vector<std::string> args; + for (int i = 1; i < argc; i++) + args.push_back(argv[i]); + + if (args.size() >= 1 && args[0] == "-import") { + for (auto &it : pass_register) { + std::string tcl_command_name = it.first; + if (tcl_command_name == "proc") + tcl_command_name = "procs"; + Tcl_CmdInfo info; + if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) { + log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str()); + } else { + std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str()); + Tcl_Eval(interp, tcl_script.c_str()); + } + } + return TCL_OK; + } + + if (args.size() == 1) { + Pass::call(yosys_get_design(), args[0]); + return TCL_OK; + } + + Pass::call(yosys_get_design(), args); + return TCL_OK; +} + +extern Tcl_Interp *yosys_get_tcl_interp() +{ + if (yosys_tcl_interp == NULL) { + yosys_tcl_interp = Tcl_CreateInterp(); + Tcl_CreateCommand(yosys_tcl_interp, "yosys", tcl_yosys_cmd, NULL, NULL); + } + return yosys_tcl_interp; +} + +struct TclPass : public Pass { + TclPass() : Pass("tcl", "execute a TCL script file") { } + virtual void help() { + log("\n"); + log(" tcl <filename>\n"); + log("\n"); + log("This command executes the tcl commands in the specified file.\n"); + log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n"); + log("\n"); + 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("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + if (args.size() < 2) + log_cmd_error("Missing script file.\n"); + if (args.size() > 2) + extra_args(args, 1, design, false); + if (Tcl_EvalFile(yosys_get_tcl_interp(), args[1].c_str()) != TCL_OK) + log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp())); + } +} TclPass; +#endif + +#if defined(__linux__) +std::string proc_self_dirname () +{ + char path [PATH_MAX]; + ssize_t buflen = readlink("/proc/self/exe", path, sizeof(path)); + if (buflen < 0) { + log_error("readlink(\"/proc/self/exe\") failed: %s\n", strerror(errno)); + } + while (buflen > 0 && path[buflen-1] != '/') + buflen--; + return std::string(path, buflen); +} +#elif defined(__APPLE__) +#include <mach-o/dyld.h> +std::string proc_self_dirname () +{ + char * path = NULL; + uint32_t buflen = 0; + while (_NSGetExecutablePath(path, &buflen) != 0) + path = (char *) realloc((void *) path, buflen); + while (buflen > 0 && path[buflen-1] != '/') + buflen--; + return std::string(path, buflen); +} +#elif defined(EMSCRIPTEN) +std::string proc_self_dirname () +{ + return "/"; +} +#else + #error Dont know how to determine process executable base path! +#endif + +std::string proc_share_dirname () +{ + std::string proc_self_path = proc_self_dirname(); + std::string proc_share_path = proc_self_path + "share/"; + if (access(proc_share_path.c_str(), X_OK) == 0) + return proc_share_path; + proc_share_path = proc_self_path + "../share/yosys/"; + if (access(proc_share_path.c_str(), X_OK) == 0) + return proc_share_path; + log_error("proc_share_dirname: unable to determine share/ directory!\n"); +} + +bool fgetline(FILE *f, std::string &buffer) +{ + buffer = ""; + char block[4096]; + while (1) { + if (fgets(block, 4096, f) == NULL) + return false; + buffer += block; + if (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) { + while (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) + buffer.resize(buffer.size()-1); + return true; + } + } +} + +static void handle_label(std::string &command, bool &from_to_active, const std::string &run_from, const std::string &run_to) +{ + int pos = 0; + std::string label; + + while (pos < SIZE(command) && (command[pos] == ' ' || command[pos] == '\t')) + pos++; + + while (pos < SIZE(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n') + label += command[pos++]; + + if (label.back() == ':' && SIZE(label) > 1) + { + label = label.substr(0, SIZE(label)-1); + command = command.substr(pos); + + if (label == run_from) + from_to_active = true; + else if (label == run_to || (run_from == run_to && !run_from.empty())) + from_to_active = false; + } +} + +void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label) +{ + if (command == "auto") { + if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v") + command = "verilog"; + else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv") + command = "verilog -sv"; + else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") + command = "ilang"; + else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys") + command = "script"; + else if (filename == "-") + command = "script"; + else + log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str()); + } + + if (command == "script") + { + std::string run_from, run_to; + bool from_to_active = true; + + if (from_to_label != NULL) { + size_t pos = from_to_label->find(':'); + if (pos == std::string::npos) { + run_from = *from_to_label; + run_to = *from_to_label; + } else { + run_from = from_to_label->substr(0, pos); + run_to = from_to_label->substr(pos+1); + } + from_to_active = run_from.empty(); + } + + log("\n-- Executing script file `%s' --\n", filename.c_str()); + + FILE *f = stdin; + + if (filename != "-") + f = fopen(filename.c_str(), "r"); + + if (f == NULL) + log_error("Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno)); + + FILE *backup_script_file = Frontend::current_script_file; + Frontend::current_script_file = f; + + try { + std::string command; + while (fgetline(f, command)) { + while (!command.empty() && command[command.size()-1] == '\\') { + std::string next_line; + if (!fgetline(f, next_line)) + break; + command.resize(command.size()-1); + command += next_line; + } + handle_label(command, from_to_active, run_from, run_to); + if (from_to_active) + Pass::call(design, command); + } + + if (!command.empty()) { + handle_label(command, from_to_active, run_from, run_to); + if (from_to_active) + Pass::call(design, command); + } + } + catch (log_cmd_error_expection) { + Frontend::current_script_file = backup_script_file; + throw log_cmd_error_expection(); + } + + Frontend::current_script_file = backup_script_file; + + if (filename != "-") + fclose(f); + + if (backend_command != NULL && *backend_command == "auto") + *backend_command = ""; + + return; + } + + if (filename == "-") { + log("\n-- Parsing stdin using frontend `%s' --\n", command.c_str()); + } else { + log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str()); + } + + Frontend::frontend_call(design, NULL, filename, command); +} + +void run_pass(std::string command, RTLIL::Design *design) +{ + log("\n-- Running pass `%s' --\n", command.c_str()); + + Pass::call(design, command); +} + +void run_backend(std::string filename, std::string command, RTLIL::Design *design) +{ + if (command == "auto") { + if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v") + command = "verilog"; + else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") + command = "ilang"; + else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif") + command = "blif"; + else if (filename == "-") + command = "ilang"; + else if (filename.empty()) + return; + else + log_error("Can't guess backend for output file `%s' (missing -b option)!\n", filename.c_str()); + } + + if (filename.empty()) + filename = "-"; + + if (filename == "-") { + log("\n-- Writing to stdout using backend `%s' --\n", command.c_str()); + } else { + log("\n-- Writing to `%s' using backend `%s' --\n", filename.c_str(), command.c_str()); + } + + Backend::backend_call(design, NULL, filename, command); +} + +#ifdef YOSYS_ENABLE_READLINE +static char *readline_cmd_generator(const char *text, int state) +{ + static std::map<std::string, Pass*>::iterator it; + static int len; + + if (!state) { + it = pass_register.begin(); + len = strlen(text); + } + + for (; it != pass_register.end(); it++) { + if (it->first.substr(0, len) == text) + return strdup((it++)->first.c_str()); + } + return NULL; +} + +static char *readline_obj_generator(const char *text, int state) +{ + static std::vector<char*> obj_names; + static size_t idx; + + if (!state) + { + idx = 0; + obj_names.clear(); + + RTLIL::Design *design = yosys_get_design(); + int len = strlen(text); + + if (design->selected_active_module.empty()) + { + for (auto &it : design->modules_) + if (RTLIL::unescape_id(it.first).substr(0, len) == text) + obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); + } + else + if (design->modules_.count(design->selected_active_module) > 0) + { + RTLIL::Module *module = design->modules_.at(design->selected_active_module); + + for (auto &it : module->wires_) + if (RTLIL::unescape_id(it.first).substr(0, len) == text) + obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); + + for (auto &it : module->memories) + if (RTLIL::unescape_id(it.first).substr(0, len) == text) + obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); + + for (auto &it : module->cells_) + if (RTLIL::unescape_id(it.first).substr(0, len) == text) + obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); + + for (auto &it : module->processes) + if (RTLIL::unescape_id(it.first).substr(0, len) == text) + obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); + } + + std::sort(obj_names.begin(), obj_names.end()); + } + + if (idx < obj_names.size()) + return strdup(obj_names[idx++]); + + idx = 0; + obj_names.clear(); + return NULL; +} + +static char **readline_completion(const char *text, int start, int) +{ + if (start == 0) + return rl_completion_matches(text, readline_cmd_generator); + if (strncmp(rl_line_buffer, "read_", 5) && strncmp(rl_line_buffer, "write_", 6)) + return rl_completion_matches(text, readline_obj_generator); + return NULL; +} +#endif + +void shell(RTLIL::Design *design) +{ + static int recursion_counter = 0; + + recursion_counter++; + log_cmd_error_throw = true; + +#ifdef YOSYS_ENABLE_READLINE + rl_readline_name = "yosys"; + rl_attempted_completion_function = readline_completion; + rl_basic_word_break_characters = " \t\n"; +#endif + + char *command = NULL; +#ifdef YOSYS_ENABLE_READLINE + while ((command = readline(create_prompt(design, recursion_counter))) != NULL) +#else + char command_buffer[4096]; + while ((command = fgets(command_buffer, 4096, stdin)) != NULL) +#endif + { + if (command[strspn(command, " \t\r\n")] == 0) + continue; +#ifdef YOSYS_ENABLE_READLINE + add_history(command); +#endif + + char *p = command + strspn(command, " \t\r\n"); + if (!strncmp(p, "exit", 4)) { + p += 4; + p += strspn(p, " \t\r\n"); + if (*p == 0) + break; + } + + try { + log_assert(design->selection_stack.size() == 1); + Pass::call(design, command); + } catch (log_cmd_error_expection) { + while (design->selection_stack.size() > 1) + design->selection_stack.pop_back(); + log_reset_stack(); + } + } + if (command == NULL) + printf("exit\n"); + + recursion_counter--; + log_cmd_error_throw = false; +} + +struct ShellPass : public Pass { + ShellPass() : Pass("shell", "enter interactive command mode") { } + virtual void help() { + log("\n"); + log(" shell\n"); + log("\n"); + log("This command enters the interactive command mode. This can be useful\n"); + log("in a script to interrupt the script at a certain point and allow for\n"); + log("interactive inspection or manual synthesis of the design at this point.\n"); + log("\n"); + log("The command prompt of the interactive shell indicates the current\n"); + log("selection (see 'help select'):\n"); + log("\n"); + log(" yosys>\n"); + log(" the entire design is selected\n"); + log("\n"); + log(" yosys*>\n"); + log(" only part of the design is selected\n"); + log("\n"); + log(" yosys [modname]>\n"); + log(" the entire module 'modname' is selected using 'select -module modname'\n"); + log("\n"); + log(" yosys [modname]*>\n"); + log(" only part of current module 'modname' is selected\n"); + log("\n"); + log("When in interactive shell, some errors (e.g. invalid command arguments)\n"); + log("do not terminate yosys but return to the command prompt.\n"); + log("\n"); + log("This command is the default action if nothing else has been specified\n"); + log("on the command line.\n"); + log("\n"); + log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + extra_args(args, 1, design, false); + shell(design); + } +} ShellPass; + +#ifdef YOSYS_ENABLE_READLINE +struct HistoryPass : public Pass { + HistoryPass() : Pass("history", "show last interactive commands") { } + virtual void help() { + log("\n"); + log(" history\n"); + log("\n"); + log("This command prints all commands in the shell history buffer. This are\n"); + log("all commands executed in an interactive session, but not the commands\n"); + log("from executed scripts.\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + extra_args(args, 1, design, false); + for(HIST_ENTRY **list = history_list(); *list != NULL; list++) + log("%s\n", (*list)->line); + } +} HistoryPass; +#endif + +struct ScriptPass : public Pass { + ScriptPass() : Pass("script", "execute commands from script file") { } + virtual void help() { + log("\n"); + log(" script <filename> [<from_label>:<to_label>]\n"); + log("\n"); + log("This command executes the yosys commands in the specified file.\n"); + log("\n"); + log("The 2nd argument can be used to only execute the section of the\n"); + log("file between the specified labels. An empty from label is synonymous\n"); + log("for the beginning of the file and an empty to label is synonymous\n"); + log("for the end of the file.\n"); + log("\n"); + log("If only one label is specified (without ':') then only the block\n"); + log("marked with that label (until the next label) is executed.\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + if (args.size() < 2) + log_cmd_error("Missing script file.\n"); + else if (args.size() == 2) + run_frontend(args[1], "script", design, NULL, NULL); + else if (args.size() == 3) + run_frontend(args[1], "script", design, NULL, &args[2]); + else + extra_args(args, 2, design, false); + } +} ScriptPass; + +YOSYS_NAMESPACE_END + diff --git a/kernel/yosys.h b/kernel/yosys.h new file mode 100644 index 000000000..b571e177f --- /dev/null +++ b/kernel/yosys.h @@ -0,0 +1,149 @@ +/* + * 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. + * + */ + + +// *** NOTE TO THE READER *** +// +// Maybe you have just opened this file in the hope to learn more about the +// Yosys API. Let me congratulate you on this great decision! ;) +// +// If you want to know how the design is represented by Yosys in the memory, +// you should read "kernel/rtlil.h". +// +// If you want to know how to register a command with Yosys, you could read +// "kernel/register.h", but it would be easier to just look at a simple +// example instead. A simple one would be "passes/cmds/log.cc". +// +// This header is very boring. It just defines some general things that +// belong nowhere else and includes the interesting headers. +// +// Find more information in the "CodingReadme" file. + + +#ifndef YOSYS_H +#define YOSYS_H + +#include <map> +#include <set> +#include <vector> +#include <string> +#include <algorithm> +#include <functional> +#include <initializer_list> + +#include <sstream> +#include <fstream> +#include <istream> +#include <ostream> +#include <iostream> + +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#define PRIVATE_NAMESPACE_BEGIN namespace { +#define PRIVATE_NAMESPACE_END } + +#if 0 +# define YOSYS_NAMESPACE_BEGIN namespace Yosys { +# define YOSYS_NAMESPACE_END } +# define YOSYS_NAMESPACE_PREFIX Yosys:: +# define USING_YOSYS_NAMESPACE using namespace Yosys; +#else +# define YOSYS_NAMESPACE_BEGIN +# define YOSYS_NAMESPACE_END +# define YOSYS_NAMESPACE_PREFIX +# define USING_YOSYS_NAMESPACE +#endif + +#if __cplusplus >= 201103L +# define OVERRIDE override +# define FINAL final +#else +# define OVERRIDE +# define FINAL +#endif + +YOSYS_NAMESPACE_BEGIN + +namespace RTLIL { + struct IdString; + struct SigSpec; + struct Wire; + struct Cell; +} + +std::string stringf(const char *fmt, ...); +std::string vstringf(const char *fmt, va_list ap); +template<typename T> int SIZE(const T &obj) { return obj.size(); } +int SIZE(RTLIL::Wire *wire); + +YOSYS_NAMESPACE_END + +#include "kernel/log.h" +#include "kernel/rtlil.h" +#include "kernel/register.h" + +YOSYS_NAMESPACE_BEGIN + +void yosys_setup(); +void yosys_shutdown(); + +#ifdef YOSYS_ENABLE_TCL +#include <tcl.h> +Tcl_Interp *yosys_get_tcl_interp(); +#endif + +extern int autoidx; +extern RTLIL::Design *yosys_design; + +RTLIL::IdString new_id(std::string file, int line, std::string func); + +#define NEW_ID \ + YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__) + +#define ID(_str) \ + ([]() { static YOSYS_NAMESPACE_PREFIX RTLIL::IdString _id(_str); return _id; })() + +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 run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label); +void run_pass(std::string command, RTLIL::Design *design); +void run_backend(std::string filename, std::string command, RTLIL::Design *design); +void shell(RTLIL::Design *design); + +// from kernel/version_*.o (cc source generated from Makefile) +extern const char *yosys_version_str; + +// from passes/cmds/design.cc +extern std::map<std::string, RTLIL::Design*> saved_designs; +extern std::vector<RTLIL::Design*> pushed_designs; + +// from passes/cmds/pluginc.cc +extern std::map<std::string, void*> loaded_plugins; +extern std::map<std::string, std::string> loaded_plugin_aliases; +void load_plugin(std::string filename, std::vector<std::string> aliases); + +YOSYS_NAMESPACE_END + +#endif |