diff options
author | Ahmed Irfan <irfan@levert.(none)> | 2015-04-03 16:38:07 +0200 |
---|---|---|
committer | Ahmed Irfan <irfan@levert.(none)> | 2015-04-03 16:38:07 +0200 |
commit | bdf6b2b19ab2206f5957ad5b2ec582c2730d45ee (patch) | |
tree | 1d02541701054a1c3b1cdb66478d0cbc31c2d38f /kernel | |
parent | 8acdd90bc918b780ad45cdac42b3baf84d2cc476 (diff) | |
parent | 4b4490761949e738dee54bdfc52e080e0a5c9067 (diff) | |
download | yosys-bdf6b2b19ab2206f5957ad5b2ec582c2730d45ee.tar.gz yosys-bdf6b2b19ab2206f5957ad5b2ec582c2730d45ee.tar.bz2 yosys-bdf6b2b19ab2206f5957ad5b2ec582c2730d45ee.zip |
Merge branch 'master' of https://github.com/cliffordwolf/yosys
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/bitpattern.h | 89 | ||||
-rw-r--r-- | kernel/calc.cc | 2 | ||||
-rw-r--r-- | kernel/celltypes.h | 122 | ||||
-rw-r--r-- | kernel/consteval.h | 24 | ||||
-rw-r--r-- | kernel/cost.h | 84 | ||||
-rw-r--r-- | kernel/driver.cc | 388 | ||||
-rw-r--r-- | kernel/hashlib.h | 887 | ||||
-rw-r--r-- | kernel/log.cc | 228 | ||||
-rw-r--r-- | kernel/log.h | 63 | ||||
-rw-r--r-- | kernel/macc.h | 69 | ||||
-rw-r--r-- | kernel/modtools.h | 194 | ||||
-rw-r--r-- | kernel/register.cc | 92 | ||||
-rw-r--r-- | kernel/register.h | 10 | ||||
-rw-r--r-- | kernel/rtlil.cc | 490 | ||||
-rw-r--r-- | kernel/rtlil.h | 668 | ||||
-rw-r--r-- | kernel/satgen.h | 282 | ||||
-rw-r--r-- | kernel/sigtools.h | 30 | ||||
-rw-r--r-- | kernel/utils.h | 36 | ||||
-rw-r--r-- | kernel/yosys.cc | 479 | ||||
-rw-r--r-- | kernel/yosys.h | 173 |
20 files changed, 3504 insertions, 906 deletions
diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h index 91f54593f..00bbc3bfb 100644 --- a/kernel/bitpattern.h +++ b/kernel/bitpattern.h @@ -23,24 +23,46 @@ #include "kernel/log.h" #include "kernel/rtlil.h" +YOSYS_NAMESPACE_BEGIN + struct BitPatternPool { int width; - typedef std::vector<RTLIL::State> bits_t; - std::set<bits_t> pool; + struct bits_t { + std::vector<RTLIL::State> bitdata; + unsigned int cached_hash; + bits_t(int width = 0) : bitdata(width), cached_hash(0) { } + RTLIL::State &operator[](int index) { + return bitdata[index]; + } + const RTLIL::State &operator[](int index) const { + return bitdata[index]; + } + bool operator==(const bits_t &other) const { + if (hash() != other.hash()) + return false; + return bitdata == other.bitdata; + } + unsigned int hash() const { + if (!cached_hash) + ((bits_t*)this)->cached_hash = hash_ops<std::vector<RTLIL::State>>::hash(bitdata); + return cached_hash; + } + }; + pool<bits_t> database; BitPatternPool(RTLIL::SigSpec sig) { width = sig.size(); if (width > 0) { - std::vector<RTLIL::State> pattern(width); + bits_t pattern(width); for (int i = 0; i < width; i++) { if (sig[i].wire == NULL && sig[i].data <= RTLIL::State::S1) pattern[i] = sig[i].data; else pattern[i] = RTLIL::State::Sa; } - pool.insert(pattern); + database.insert(pattern); } } @@ -48,17 +70,18 @@ struct BitPatternPool { this->width = width; if (width > 0) { - std::vector<RTLIL::State> pattern(width); + bits_t pattern(width); for (int i = 0; i < width; i++) pattern[i] = RTLIL::State::Sa; - pool.insert(pattern); + database.insert(pattern); } } bits_t sig2bits(RTLIL::SigSpec sig) { - bits_t bits = sig.as_const().bits; - for (auto &b : bits) + bits_t bits; + bits.bitdata = sig.as_const().bits; + for (auto &b : bits.bitdata) if (b > RTLIL::State::S1) b = RTLIL::State::Sa; return bits; @@ -66,8 +89,8 @@ struct BitPatternPool bool match(bits_t a, bits_t b) { - log_assert(int(a.size()) == width); - log_assert(int(b.size()) == width); + log_assert(int(a.bitdata.size()) == width); + log_assert(int(b.bitdata.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; @@ -77,7 +100,7 @@ struct BitPatternPool bool has_any(RTLIL::SigSpec sig) { bits_t bits = sig2bits(sig); - for (auto &it : pool) + for (auto &it : database) if (match(it, bits)) return true; return false; @@ -86,13 +109,13 @@ struct BitPatternPool bool has_all(RTLIL::SigSpec sig) { bits_t bits = sig2bits(sig); - for (auto &it : pool) + for (auto &it : database) if (match(it, bits)) { for (int i = 0; i < width; i++) if (bits[i] > RTLIL::State::S1 && it[i] <= RTLIL::State::S1) - goto next_pool_entry; + goto next_database_entry; return true; - next_pool_entry:; + next_database_entry:; } return false; } @@ -101,36 +124,38 @@ struct BitPatternPool { bool status = false; bits_t bits = sig2bits(sig); - std::vector<bits_t> pattern_list; - for (auto &it : pool) - if (match(it, bits)) - pattern_list.push_back(it); - for (auto pattern : pattern_list) { - pool.erase(pattern); - for (int i = 0; i < width; i++) { - if (pattern[i] != RTLIL::State::Sa || bits[i] == RTLIL::State::Sa) - continue; - bits_t new_pattern = pattern; - new_pattern[i] = bits[i] == RTLIL::State::S1 ? RTLIL::State::S0 : RTLIL::State::S1; - pool.insert(new_pattern); - } - status = true; - } + for (auto it = database.begin(); it != database.end();) + if (match(*it, bits)) { + for (int i = 0; i < width; i++) { + if ((*it)[i] != RTLIL::State::Sa || bits[i] == RTLIL::State::Sa) + continue; + bits_t new_pattern; + new_pattern.bitdata = it->bitdata; + new_pattern[i] = bits[i] == RTLIL::State::S1 ? RTLIL::State::S0 : RTLIL::State::S1; + database.insert(new_pattern); + } + it = database.erase(it); + status = true; + continue; + } else + ++it; return status; } bool take_all() { - if (pool.empty()) + if (database.empty()) return false; - pool.clear(); + database.clear(); return true; } bool empty() { - return pool.empty(); + return database.empty(); } }; +YOSYS_NAMESPACE_END + #endif diff --git a/kernel/calc.cc b/kernel/calc.cc index 41179d045..aa3e8b919 100644 --- a/kernel/calc.cc +++ b/kernel/calc.cc @@ -303,7 +303,7 @@ RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2 RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len) { RTLIL::Const arg1_ext = arg1; - extend_u0(arg1_ext, std::max(result_len, SIZE(arg1)), signed1); + extend_u0(arg1_ext, std::max(result_len, GetSize(arg1)), signed1); return const_shift_worker(arg1_ext, arg2, false, +1, result_len); } diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 85c21ef3c..533c370fe 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -27,13 +27,13 @@ YOSYS_NAMESPACE_BEGIN struct CellType { RTLIL::IdString type; - std::set<RTLIL::IdString> inputs, outputs; + pool<RTLIL::IdString> inputs, outputs; bool is_evaluable; }; struct CellTypes { - std::map<RTLIL::IdString, CellType> cell_types; + dict<RTLIL::IdString, CellType> cell_types; CellTypes() { @@ -55,7 +55,7 @@ struct CellTypes setup_stdcells_mem(); } - void setup_type(RTLIL::IdString type, const std::set<RTLIL::IdString> &inputs, const std::set<RTLIL::IdString> &outputs, bool is_evaluable = false) + void setup_type(RTLIL::IdString type, const pool<RTLIL::IdString> &inputs, const pool<RTLIL::IdString> &outputs, bool is_evaluable = false) { CellType ct = {type, inputs, outputs, is_evaluable}; cell_types[ct.type] = ct; @@ -63,7 +63,7 @@ struct CellTypes void setup_module(RTLIL::Module *module) { - std::set<RTLIL::IdString> inputs, outputs; + pool<RTLIL::IdString> inputs, outputs; for (RTLIL::IdString wire_name : module->ports) { RTLIL::Wire *wire = module->wire(wire_name); if (wire->port_input) @@ -96,82 +96,105 @@ struct CellTypes "$logic_and", "$logic_or", "$concat", "$macc" }; + IdString A = "\\A", B = "\\B", S = "\\S", Y = "\\Y"; + IdString P = "\\P", G = "\\G", C = "\\C", X = "\\X"; + IdString BI = "\\BI", CI = "\\CI", CO = "\\CO", EN = "\\EN"; + for (auto type : unary_ops) - setup_type(type, {"\\A"}, {"\\Y"}, true); + setup_type(type, {A}, {Y}, true); for (auto type : binary_ops) - setup_type(type, {"\\A", "\\B"}, {"\\Y"}, true); + 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(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("$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); + setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true); + setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true); + setup_type("$equiv", {A, B}, {Y}, true); } void setup_internals_mem() { - 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"}); + IdString SET = "\\SET", CLR = "\\CLR", CLK = "\\CLK", ARST = "\\ARST", EN = "\\EN"; + IdString Q = "\\Q", D = "\\D", ADDR = "\\ADDR", DATA = "\\DATA"; + IdString RD_CLK = "\\RD_CLK", RD_ADDR = "\\RD_ADDR", WR_CLK = "\\WR_CLK", WR_EN = "\\WR_EN"; + IdString WR_ADDR = "\\WR_ADDR", WR_DATA = "\\WR_DATA", RD_DATA = "\\RD_DATA"; + IdString CTRL_IN = "\\CTRL_IN", CTRL_OUT = "\\CTRL_OUT"; + + setup_type("$sr", {SET, CLR}, {Q}); + setup_type("$dff", {CLK, D}, {Q}); + setup_type("$dffe", {CLK, EN, 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}, pool<RTLIL::IdString>()); + setup_type("$meminit", {ADDR, DATA}, pool<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() { - 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); + IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D", S = "\\S", Y = "\\Y"; + setup_type("$_BUF_", {A}, {Y}, true); + 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() { + IdString S = "\\S", R = "\\R", C = "\\C"; + IdString D = "\\D", Q = "\\Q", E = "\\E"; + 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"}); + 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) - setup_type(stringf("$_DFF_%c_", c1), {"\\C", "\\D"}, {"\\Q"}); + for (auto c2 : list_np) + setup_type(stringf("$_DFFE_%c%c_", c1, c2), {C, D, E}, {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"}); + 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"}); + 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"}); + 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"}); + setup_type(stringf("$_DLATCHSR_%c%c%c_", c1, c2, c3), {E, S, R, D}, {Q}); } void clear() @@ -261,6 +284,8 @@ struct CellTypes HANDLE_CELL_TYPE(neg) #undef HANDLE_CELL_TYPE + if (type == "$_BUF_") + return arg1; if (type == "$_NOT_") return eval_not(arg1); if (type == "$_AND_") @@ -300,7 +325,7 @@ struct CellTypes int width = cell->parameters.at("\\WIDTH").as_int(); std::vector<RTLIL::State> t = cell->parameters.at("\\LUT").bits; - while (SIZE(t) < (1 << width)) + while (GetSize(t) < (1 << width)) t.push_back(RTLIL::S0); t.resize(1 << width); @@ -308,16 +333,16 @@ struct CellTypes 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); + new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + GetSize(t)/2); else if (sel == RTLIL::S1) - new_t = std::vector<RTLIL::State>(t.begin() + SIZE(t)/2, t.end()); + new_t = std::vector<RTLIL::State>(t.begin() + GetSize(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); + for (int j = 0; j < GetSize(t)/2; j++) + new_t.push_back(t[j] == t[j + GetSize(t)/2] ? t[j] : RTLIL::Sx); t.swap(new_t); } - log_assert(SIZE(t) == 1); + log_assert(GetSize(t) == 1); return t; } @@ -360,6 +385,9 @@ struct CellTypes } }; +// initialized by yosys_setup() +extern CellTypes yosys_celltypes; + YOSYS_NAMESPACE_END #endif diff --git a/kernel/consteval.h b/kernel/consteval.h index 2d29d3f7e..c2e9710fb 100644 --- a/kernel/consteval.h +++ b/kernel/consteval.h @@ -25,6 +25,8 @@ #include "kernel/celltypes.h" #include "kernel/macc.h" +YOSYS_NAMESPACE_BEGIN + struct ConstEval { RTLIL::Module *module; @@ -72,7 +74,7 @@ struct ConstEval assign_map.apply(sig); #ifndef NDEBUG RTLIL::SigSpec current_val = values_map(sig); - for (int i = 0; i < SIZE(current_val); i++) + for (int i = 0; i < GetSize(current_val); i++) log_assert(current_val[i].wire != NULL || current_val[i] == value.bits[i]); #endif values_map.add(sig, RTLIL::SigSpec(value)); @@ -107,10 +109,10 @@ struct ConstEval if (sig_p.is_fully_def() && sig_g.is_fully_def() && sig_ci.is_fully_def()) { - RTLIL::Const coval(RTLIL::Sx, SIZE(sig_co)); + RTLIL::Const coval(RTLIL::Sx, GetSize(sig_co)); bool carry = sig_ci.as_bool(); - for (int i = 0; i < SIZE(coval); i++) { + for (int i = 0; i < GetSize(coval); i++) { carry = (sig_g[i] == RTLIL::S1) || (sig_p[i] == RTLIL::S1 && carry); coval.bits[i] = carry ? RTLIL::S1 : RTLIL::S0; } @@ -118,7 +120,7 @@ struct ConstEval set(sig_co, coval); } else - set(sig_co, RTLIL::Const(RTLIL::Sx, SIZE(sig_co))); + set(sig_co, RTLIL::Const(RTLIL::Sx, GetSize(sig_co))); return true; } @@ -196,7 +198,7 @@ struct ConstEval { RTLIL::SigSpec sig_c = cell->getPort("\\C"); RTLIL::SigSpec sig_x = cell->getPort("\\X"); - int width = SIZE(sig_c); + int width = GetSize(sig_c); if (!eval(sig_a, undef, cell)) return false; @@ -214,7 +216,7 @@ struct ConstEval 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++) + for (int i = 0; i < GetSize(val_y); i++) if (val_y.bits[i] == RTLIL::Sx) val_x.bits[i] = RTLIL::Sx; @@ -245,13 +247,13 @@ struct ConstEval 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); + sig_a.extend_u0(GetSize(sig_y), signed_a); + sig_b.extend_u0(GetSize(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++) + for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::SigSpec x_inputs = { sig_a[i], sig_b[i], sig_bi[0] }; @@ -292,7 +294,7 @@ struct ConstEval return false; } - RTLIL::Const result(0, SIZE(cell->getPort("\\Y"))); + RTLIL::Const result(0, GetSize(cell->getPort("\\Y"))); if (!macc.eval(result)) log_abort(); @@ -376,4 +378,6 @@ struct ConstEval } }; +YOSYS_NAMESPACE_END + #endif diff --git a/kernel/cost.h b/kernel/cost.h new file mode 100644 index 000000000..c6c631e0a --- /dev/null +++ b/kernel/cost.h @@ -0,0 +1,84 @@ +/* + * 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 COST_H +#define COST_H + +#include <kernel/yosys.h> + +YOSYS_NAMESPACE_BEGIN + +int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr); + +int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> ¶meters = dict<RTLIL::IdString, RTLIL::Const>(), + RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr) +{ + static dict<RTLIL::IdString, int> gate_cost = { + { "$_BUF_", 1 }, + { "$_NOT_", 2 }, + { "$_AND_", 4 }, + { "$_NAND_", 4 }, + { "$_OR_", 4 }, + { "$_NOR_", 4 }, + { "$_XOR_", 8 }, + { "$_XNOR_", 8 }, + { "$_AOI3_", 6 }, + { "$_OAI3_", 6 }, + { "$_AOI4_", 8 }, + { "$_OAI4_", 8 }, + { "$_MUX_", 4 } + }; + + if (gate_cost.count(type)) + return gate_cost.at(type); + + if (parameters.empty() && design && design->module(type)) + { + RTLIL::Module *mod = design->module(type); + + if (mod->attributes.count("\\cost")) + return mod->attributes.at("\\cost").as_int(); + + dict<RTLIL::IdString, int> local_mod_cost_cache; + if (mod_cost_cache == nullptr) + mod_cost_cache = &local_mod_cost_cache; + + if (mod_cost_cache->count(mod->name)) + return mod_cost_cache->at(mod->name); + + int module_cost = 1; + for (auto c : mod->cells()) + module_cost += get_cell_cost(c, mod_cost_cache); + + (*mod_cost_cache)[mod->name] = module_cost; + return module_cost; + } + + log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(type), GetSize(parameters)); + return 1; +} + +int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache) +{ + return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache); +} + +YOSYS_NAMESPACE_END + +#endif diff --git a/kernel/driver.cc b/kernel/driver.cc index f26d9ef82..dda27c6a6 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -27,13 +27,98 @@ #include <stdio.h> #include <string.h> -#include <unistd.h> -#include <libgen.h> #include <limits.h> #include <errno.h> +#ifdef __linux__ +# include <sys/types.h> +# include <unistd.h> +#endif + +#if !defined(_WIN32) || defined(__MINGW32__) +# include <unistd.h> +#else +char *optarg; +int optind = 1, optcur = 1; +int getopt(int argc, char **argv, const char *optstring) +{ + if (optind >= argc || argv[optind][0] != '-') + return -1; + + bool takes_arg = false; + int opt = argv[optind][optcur]; + for (int i = 0; optstring[i]; i++) + if (opt == optstring[i] && optstring[i + 1] == ':') + takes_arg = true; + + if (!takes_arg) { + if (argv[optind][++optcur] == 0) + optind++, optcur = 1; + return opt; + } + + if (argv[optind][++optcur]) { + optarg = argv[optind++] + optcur; + optcur = 1; + return opt; + } + + optarg = argv[++optind]; + optind++, optcur = 1; + return opt; +} +#endif + + USING_YOSYS_NAMESPACE +#ifdef EMSCRIPTEN +# include <sys/stat.h> +# include <sys/types.h> + +extern "C" int main(int, char**); +extern "C" void run(const char*); +extern "C" const char *errmsg(); +extern "C" const char *prompt(); + +int main(int, char**) +{ + mkdir("/work", 0777); + chdir("/work"); + log_files.push_back(stdout); + log_error_stderr = true; + yosys_banner(); + yosys_setup(); +} + +void run(const char *command) +{ + int selSize = GetSize(yosys_get_design()->selection_stack); + try { + log_last_error = "Internal error (see JavaScript console for details)"; + run_pass(command); + log_last_error = ""; + } catch (...) { + while (GetSize(yosys_get_design()->selection_stack) > selSize) + yosys_get_design()->selection_stack.pop_back(); + throw; + } +} + +const char *errmsg() +{ + return log_last_error.c_str(); +} + +const char *prompt() +{ + const char *p = create_prompt(yosys_get_design(), 0); + while (*p == '\n') p++; + return p; +} + +#else /* EMSCRIPTEN */ + int main(int argc, char **argv) { std::string frontend_command = "auto"; @@ -47,6 +132,9 @@ int main(int argc, char **argv) bool print_banner = true; bool print_stats = true; bool call_abort = false; + bool timing_details = false; + bool mode_v = false; + bool mode_q = false; #ifdef YOSYS_ENABLE_READLINE int history_offset = 0; @@ -58,11 +146,103 @@ int main(int argc, char **argv) } #endif + if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "-help") || !strcmp(argv[1], "--help"))) + { + printf("\n"); + printf("Usage: %s [options] [<infile> [..]]\n", argv[0]); + printf("\n"); + printf(" -Q\n"); + printf(" suppress printing of banner (copyright, disclaimer, version)\n"); + printf("\n"); + printf(" -T\n"); + printf(" suppress printing of footer (log hash, version, timing statistics)\n"); + printf("\n"); + printf(" -q\n"); + printf(" quiet operation. only write warnings and error messages to console\n"); + printf(" use this option twice to also quiet warning messages\n"); + printf("\n"); + printf(" -v <level>\n"); + printf(" print log headers up to level <level> to the console. (this\n"); + printf(" implies -q for everything except the 'End of script.' message.)\n"); + printf("\n"); + printf(" -t\n"); + printf(" annotate all log messages with a time stamp\n"); + printf("\n"); + printf(" -d\n"); + printf(" print more detailed timing stats at exit\n"); + printf("\n"); + printf(" -l logfile\n"); + printf(" write log messages to the specified file\n"); + printf("\n"); + printf(" -L logfile\n"); + printf(" like -l but open log file in line buffered mode\n"); + printf("\n"); + printf(" -o outfile\n"); + printf(" write the design to the specified file on exit\n"); + printf("\n"); + printf(" -b backend\n"); + printf(" use this backend for the output file specified on the command line\n"); + printf("\n"); + printf(" -f backend\n"); + printf(" use the specified front for the input files on the command line\n"); + printf("\n"); + printf(" -H\n"); + printf(" print the command list\n"); + printf("\n"); + printf(" -h command\n"); + printf(" print the help message for the specified command\n"); + printf("\n"); + printf(" -s scriptfile\n"); + printf(" execute the commands in the script file\n"); + printf("\n"); + printf(" -c tcl_scriptfile\n"); + printf(" execute the commands in the tcl script file (see 'help tcl' for details)\n"); + printf("\n"); + printf(" -p command\n"); + printf(" execute the commands\n"); + printf("\n"); + printf(" -m module_file\n"); + printf(" load the specified module (aka plugin)\n"); + printf("\n"); + printf(" -X\n"); + printf(" enable tracing of core data structure changes. for debugging\n"); + printf("\n"); + printf(" -M\n"); + printf(" will slightly randomize allocated pointer addresses. for debugging\n"); + printf("\n"); + printf(" -A\n"); + printf(" will call abort() at the end of the script. for debugging\n"); + printf("\n"); + printf(" -V\n"); + printf(" print version information and exit\n"); + printf("\n"); + printf("The option -S is an shortcut for calling the \"synth\" command, a default\n"); + printf("script for transforming the verilog input to a gate-level netlist. For example:\n"); + printf("\n"); + printf(" yosys -o output.blif -S input.v\n"); + printf("\n"); + printf("For more complex synthesis jobs it is recommended to use the read_* and write_*\n"); + printf("commands in a script file instead of specifying input and output files on the\n"); + printf("command line.\n"); + printf("\n"); + printf("When no commands, script files or input files are specified on the command\n"); + printf("line, yosys automatically enters the interactive command mode. Use the 'help'\n"); + printf("command to get information on the individual commands.\n"); + printf("\n"); + exit(0); + } + int opt; - while ((opt = getopt(argc, argv, "AQTVSm:f:Hh:b:o:p:l:qv:ts:c:")) != -1) + while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:")) != -1) { switch (opt) { + case 'M': + memhasher_on(); + break; + case 'X': + yosys_xtrace++; + break; case 'A': call_abort = true; break; @@ -101,22 +281,32 @@ int main(int argc, char **argv) got_output_filename = true; break; case 'l': + case 'L': log_files.push_back(fopen(optarg, "wt")); if (log_files.back() == NULL) { fprintf(stderr, "Can't open log file `%s' for writing!\n", optarg); exit(1); } + if (opt == 'L') + setvbuf(log_files.back(), NULL, _IOLBF, 0); break; case 'q': + mode_q = true; + if (log_errfile == stderr) + log_quiet_warnings = true; log_errfile = stderr; break; case 'v': + mode_v = true; log_errfile = stderr; log_verbose_level = atoi(optarg); break; case 't': log_time = true; break; + case 'd': + timing_details = true; + break; case 's': scriptfile = optarg; scriptfile_tcl = false; @@ -126,107 +316,19 @@ int main(int argc, char **argv) scriptfile_tcl = true; break; default: - fprintf(stderr, "\n"); - 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"); - fprintf(stderr, " -v <level>\n"); - fprintf(stderr, " print log headers up to level <level> to the console. (implies -q)\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " -t\n"); - fprintf(stderr, " annotate all log messages with a time stamp\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " -l logfile\n"); - fprintf(stderr, " write log messages to the specified file\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " -o outfile\n"); - fprintf(stderr, " write the design to the specified file on exit\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " -b backend\n"); - fprintf(stderr, " use this backend for the output file specified on the command line\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " -f backend\n"); - fprintf(stderr, " use the specified front for the input files on the command line\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " -H\n"); - fprintf(stderr, " print the command list\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " -h command\n"); - fprintf(stderr, " print the help message for the specified command\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " -s scriptfile\n"); - fprintf(stderr, " execute the commands in the script file\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " -c tcl_scriptfile\n"); - fprintf(stderr, " execute the commands in the tcl script file (see 'help tcl' for details)\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " -p command\n"); - fprintf(stderr, " execute the commands\n"); - fprintf(stderr, "\n"); - 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 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, " 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"); - fprintf(stderr, "command line.\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "When no commands, script files or input files are specified on the command\n"); - fprintf(stderr, "line, yosys automatically enters the interactive command mode. Use the 'help'\n"); - fprintf(stderr, "command to get information on the individual commands.\n"); - fprintf(stderr, "\n"); + fprintf(stderr, "Run '%s -h' for help.\n", argv[0]); exit(1); } } - if (log_errfile == NULL) - log_files.push_back(stderr); - - 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 (log_errfile == NULL) { + log_files.push_back(stdout); + log_error_stderr = true; } + if (print_banner) + yosys_banner(); + if (print_stats) log_hasher = new SHA1; @@ -242,7 +344,7 @@ int main(int argc, char **argv) } while (optind < argc) - run_frontend(argv[optind++], frontend_command, yosys_design, output_filename == "-" ? &backend_command : NULL, NULL); + run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL); if (!scriptfile.empty()) { if (scriptfile_tcl) { @@ -253,14 +355,14 @@ 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, NULL); + run_frontend(scriptfile, "script", output_filename == "-" ? &backend_command : NULL); } for (auto it = passes_commands.begin(); it != passes_commands.end(); it++) - run_pass(*it, yosys_design); + run_pass(*it); if (!backend_command.empty()) - run_backend(output_filename, backend_command, yosys_design); + run_backend(output_filename, backend_command); if (print_stats) { @@ -268,12 +370,37 @@ int main(int argc, char **argv) delete log_hasher; log_hasher = nullptr; + log_time = false; + yosys_xtrace = 0; + log_spacer(); + + if (mode_v && !mode_q) + log_files.push_back(stderr); + +#ifdef _WIN32 + log("End of script. Logfile hash: %s\n", hash.c_str()); +#else + std::string meminfo; + std::string stats_divider = ", "; +# ifdef __linux__ + std::ifstream statm; + statm.open(stringf("/proc/%lld/statm", (long long)getpid())); + if (statm.is_open()) { + int sz_total, sz_resident; + statm >> sz_total >> sz_resident; + meminfo = stringf(", MEM: %.2f MB total, %.2f MB resident", + sz_total * (getpagesize() / 1024.0 / 1024.0), + sz_resident * (getpagesize() / 1024.0 / 1024.0)); + stats_divider = "\n"; + } +# endif + 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("End of script. Logfile hash: %s%sCPU: user %.2fs system %.2fs%s\n", hash.c_str(), + stats_divider.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, meminfo.c_str()); +#endif log("%s\n", yosys_version_str); int64_t total_ns = 0; @@ -285,37 +412,49 @@ int main(int argc, char **argv) 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; + if (timing_details) + { + log("Time spent:\n"); + for (auto it = timedat.rbegin(); it != timedat.rend(); it++) { + log("%5d%% %5d calls %8.3f sec %s\n", int(100*std::get<0>(*it) / total_ns), + std::get<1>(*it), std::get<0>(*it) / 1000000000.0, std::get<2>(*it).c_str()); + } + } + else + { + 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 %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"); } - log("%s\n", out_count ? "" : " no commands executed"); } -#ifdef COVER_ACTIVE +#if defined(YOSYS_ENABLE_COVER) && defined(__linux__) if (getenv("YOSYS_COVER_DIR") || getenv("YOSYS_COVER_FILE")) { - char filename_buffer[4096]; + string filename; 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"); + filename = stringf("%s/yosys_cover_%d_XXXXXX.txt", getenv("YOSYS_COVER_DIR"), getpid()); + filename = make_temp_file(filename); } else { - snprintf(filename_buffer, 4096, "%s", getenv("YOSYS_COVER_FILE")); - f = fopen(filename_buffer, "a+"); + filename = getenv("YOSYS_COVER_FILE"); } + f = fopen(filename.c_str(), "a+"); + if (f == NULL) - log_error("Can't create coverage file `%s'.\n", filename_buffer); + log_error("Can't create coverage file `%s'.\n", filename.c_str()); - log("<writing coverage file \"%s\">\n", filename_buffer); + log("<writing coverage file \"%s\">\n", filename.c_str()); for (auto &it : get_coverage_data()) fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str()); @@ -324,6 +463,7 @@ int main(int argc, char **argv) } #endif + memhasher_off(); if (call_abort) abort(); @@ -347,3 +487,5 @@ int main(int argc, char **argv) return 0; } +#endif /* EMSCRIPTEN */ + diff --git a/kernel/hashlib.h b/kernel/hashlib.h new file mode 100644 index 000000000..94b573e47 --- /dev/null +++ b/kernel/hashlib.h @@ -0,0 +1,887 @@ +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. + +// ------------------------------------------------------- +// Written by Clifford Wolf <clifford@clifford.at> in 2014 +// ------------------------------------------------------- + +#ifndef HASHLIB_H + +#include <stdexcept> +#include <algorithm> +#include <string> +#include <vector> + +namespace hashlib { + +const int hashtable_size_trigger = 2; +const int hashtable_size_factor = 3; + +// The XOR version of DJB2 +inline unsigned int mkhash(unsigned int a, unsigned int b) { + return ((a << 5) + a) ^ b; +} + +// traditionally 5381 is used as starting value for the djb2 hash +const unsigned int mkhash_init = 5381; + +// The ADD version of DJB2 +// (usunsigned int mkhashe this version for cache locality in b) +inline unsigned int mkhash_add(unsigned int a, unsigned int b) { + return ((a << 5) + a) + b; +} + +inline unsigned int mkhash_xorshift(unsigned int a) { + if (sizeof(a) == 4) { + a ^= a << 13; + a ^= a >> 17; + a ^= a << 5; + } else if (sizeof(a) == 8) { + a ^= a << 13; + a ^= a >> 7; + a ^= a << 17; + } else + throw std::runtime_error("mkhash_xorshift() only implemented for 32 bit and 64 bit ints"); + return a; +} + +template<typename T> struct hash_ops { + static inline bool cmp(const T &a, const T &b) { + return a == b; + } + static inline unsigned int hash(const T &a) { + return a.hash(); + } +}; + +template<> struct hash_ops<int> { + template<typename T> + static inline bool cmp(T a, T b) { + return a == b; + } + template<typename T> + static inline unsigned int hash(T a) { + return a; + } +}; + +template<> struct hash_ops<std::string> { + static inline bool cmp(const std::string &a, const std::string &b) { + return a == b; + } + static inline unsigned int hash(const std::string &a) { + unsigned int v = 0; + for (auto c : a) + v = mkhash(v, c); + return v; + } +}; + +template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> { + static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) { + return a == b; + } + static inline unsigned int hash(std::pair<P, Q> a) { + hash_ops<P> p_ops; + hash_ops<Q> q_ops; + return mkhash(p_ops.hash(a.first), q_ops.hash(a.second)); + } +}; + +template<typename T> struct hash_ops<std::vector<T>> { + static inline bool cmp(std::vector<T> a, std::vector<T> b) { + return a == b; + } + static inline unsigned int hash(std::vector<T> a) { + hash_ops<T> t_ops; + unsigned int h = mkhash_init; + for (auto k : a) + h = mkhash(h, t_ops.hash(k)); + return h; + } +}; + +struct hash_cstr_ops { + static inline bool cmp(const char *a, const char *b) { + for (int i = 0; a[i] || b[i]; i++) + if (a[i] != b[i]) + return false; + return true; + } + static inline unsigned int hash(const char *a) { + unsigned int hash = mkhash_init; + while (*a) + hash = mkhash(hash, *(a++)); + return hash; + } +}; + +struct hash_ptr_ops { + static inline bool cmp(const void *a, const void *b) { + return a == b; + } + static inline unsigned int hash(const void *a) { + return (unsigned long)a; + } +}; + +struct hash_obj_ops { + static inline bool cmp(const void *a, const void *b) { + return a == b; + } + template<typename T> + static inline unsigned int hash(const T *a) { + return a->hash(); + } +}; + +inline int hashtable_size(int min_size) +{ + static std::vector<int> zero_and_some_primes = { + 0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677, + 853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289, + 12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281, + 120371, 150473, 188107, 235159, 293957, 367453, 459317, 574157, 717697, + 897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037, + 5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411, + 25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239, + 121590311, 151987889, 189984863, 237481091, 296851369, 371064217 + }; + + for (auto p : zero_and_some_primes) + if (p >= min_size) return p; + + if (sizeof(int) == 4) + throw std::length_error("hash table exceeded maximum size. use a ILP64 abi for larger tables."); + + for (auto p : zero_and_some_primes) + if (100129 * p > min_size) return 100129 * p; + + throw std::length_error("hash table exceeded maximum size."); +} + +template<typename K, typename T, typename OPS = hash_ops<K>> class dict; +template<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict; +template<typename K, typename OPS = hash_ops<K>> class pool; + +template<typename K, typename T, typename OPS> +class dict +{ + struct entry_t + { + std::pair<K, T> udata; + int next; + + entry_t() { } + entry_t(const std::pair<K, T> &udata, int next) : udata(udata), next(next) { } + entry_t(std::pair<K, T> &&udata, int next) : udata(std::move(udata)), next(next) { } + }; + + std::vector<int> hashtable; + std::vector<entry_t> entries; + OPS ops; + +#ifdef NDEBUG + static inline void do_assert(bool) { } +#else + static inline void do_assert(bool cond) { + if (!cond) throw std::runtime_error("dict<> assert failed."); + } +#endif + + int do_hash(const K &key) const + { + unsigned int hash = 0; + if (!hashtable.empty()) + hash = ops.hash(key) % (unsigned int)(hashtable.size()); + return hash; + } + + void do_rehash() + { + hashtable.clear(); + hashtable.resize(hashtable_size(entries.size() * hashtable_size_factor), -1); + + for (int i = 0; i < int(entries.size()); i++) { + do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size())); + int hash = do_hash(entries[i].udata.first); + entries[i].next = hashtable[hash]; + hashtable[hash] = i; + } + } + + int do_erase(int index, int hash) + { + do_assert(index < int(entries.size())); + if (hashtable.empty() || index < 0) + return 0; + + int k = hashtable[hash]; + do_assert(0 <= k && k < int(entries.size())); + + if (k == index) { + hashtable[hash] = entries[index].next; + } else { + while (entries[k].next != index) { + k = entries[k].next; + do_assert(0 <= k && k < int(entries.size())); + } + entries[k].next = entries[index].next; + } + + int back_idx = entries.size()-1; + + if (index != back_idx) + { + int back_hash = do_hash(entries[back_idx].udata.first); + + k = hashtable[back_hash]; + do_assert(0 <= k && k < int(entries.size())); + + if (k == back_idx) { + hashtable[back_hash] = index; + } else { + while (entries[k].next != back_idx) { + k = entries[k].next; + do_assert(0 <= k && k < int(entries.size())); + } + entries[k].next = index; + } + + entries[index] = std::move(entries[back_idx]); + } + + entries.pop_back(); + + if (entries.empty()) + hashtable.clear(); + + return 1; + } + + int do_lookup(const K &key, int &hash) const + { + if (hashtable.empty()) + return -1; + + if (entries.size() * hashtable_size_trigger > hashtable.size()) { + ((dict*)this)->do_rehash(); + hash = do_hash(key); + } + + int index = hashtable[hash]; + + while (index >= 0 && !ops.cmp(entries[index].udata.first, key)) { + index = entries[index].next; + do_assert(-1 <= index && index < int(entries.size())); + } + + return index; + } + + int do_insert(const K &key, int &hash) + { + if (hashtable.empty()) { + entries.push_back(entry_t(std::pair<K, T>(key, T()), -1)); + do_rehash(); + hash = do_hash(key); + } else { + entries.push_back(entry_t(std::pair<K, T>(key, T()), hashtable[hash])); + hashtable[hash] = entries.size() - 1; + } + return entries.size() - 1; + } + + int do_insert(const std::pair<K, T> &value, int &hash) + { + if (hashtable.empty()) { + entries.push_back(entry_t(value, -1)); + do_rehash(); + hash = do_hash(value.first); + } else { + entries.push_back(entry_t(value, hashtable[hash])); + hashtable[hash] = entries.size() - 1; + } + return entries.size() - 1; + } + +public: + class const_iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>> + { + friend class dict; + protected: + const dict *ptr; + int index; + const_iterator(const dict *ptr, int index) : ptr(ptr), index(index) { } + public: + const_iterator() { } + const_iterator operator++() { index--; return *this; } + bool operator<(const const_iterator &other) const { return index > other.index; } + bool operator==(const const_iterator &other) const { return index == other.index; } + bool operator!=(const const_iterator &other) const { return index != other.index; } + const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; } + const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; } + }; + + class iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>> + { + friend class dict; + protected: + dict *ptr; + int index; + iterator(dict *ptr, int index) : ptr(ptr), index(index) { } + public: + iterator() { } + iterator operator++() { index--; return *this; } + bool operator<(const iterator &other) const { return index > other.index; } + bool operator==(const iterator &other) const { return index == other.index; } + bool operator!=(const iterator &other) const { return index != other.index; } + std::pair<K, T> &operator*() { return ptr->entries[index].udata; } + std::pair<K, T> *operator->() { return &ptr->entries[index].udata; } + const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; } + const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; } + operator const_iterator() const { return const_iterator(ptr, index); } + }; + + dict() + { + } + + dict(const dict &other) + { + entries = other.entries; + do_rehash(); + } + + dict(dict &&other) + { + swap(other); + } + + dict &operator=(const dict &other) { + entries = other.entries; + do_rehash(); + return *this; + } + + dict &operator=(dict &&other) { + clear(); + swap(other); + return *this; + } + + dict(const std::initializer_list<std::pair<K, T>> &list) + { + for (auto &it : list) + insert(it); + } + + template<class InputIterator> + dict(InputIterator first, InputIterator last) + { + insert(first, last); + } + + template<class InputIterator> + void insert(InputIterator first, InputIterator last) + { + for (; first != last; ++first) + insert(*first); + } + + std::pair<iterator, bool> insert(const K &key) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i >= 0) + return std::pair<iterator, bool>(iterator(this, i), false); + i = do_insert(key, hash); + return std::pair<iterator, bool>(iterator(this, i), true); + } + + std::pair<iterator, bool> insert(const std::pair<K, T> &value) + { + int hash = do_hash(value.first); + int i = do_lookup(value.first, hash); + if (i >= 0) + return std::pair<iterator, bool>(iterator(this, i), false); + i = do_insert(value, hash); + return std::pair<iterator, bool>(iterator(this, i), true); + } + + int erase(const K &key) + { + int hash = do_hash(key); + int index = do_lookup(key, hash); + return do_erase(index, hash); + } + + iterator erase(iterator it) + { + int hash = do_hash(it->first); + do_erase(it.index, hash); + return ++it; + } + + int count(const K &key) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + return i < 0 ? 0 : 1; + } + + int count(const K &key, const_iterator it) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + return i < 0 || i > it.index ? 0 : 1; + } + + iterator find(const K &key) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + return end(); + return iterator(this, i); + } + + const_iterator find(const K &key) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + return end(); + return const_iterator(this, i); + } + + T& at(const K &key) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + throw std::out_of_range("dict::at()"); + return entries[i].udata.second; + } + + const T& at(const K &key) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + throw std::out_of_range("dict::at()"); + return entries[i].udata.second; + } + + T& operator[](const K &key) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + i = do_insert(std::pair<K, T>(key, T()), hash); + return entries[i].udata.second; + } + + template<typename Compare = std::less<K>> + void sort(Compare comp = Compare()) + { + std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata.first, a.udata.first); }); + do_rehash(); + } + + void swap(dict &other) + { + hashtable.swap(other.hashtable); + entries.swap(other.entries); + } + + bool operator==(const dict &other) const { + if (size() != other.size()) + return false; + for (auto &it : entries) { + auto oit = other.find(it.udata.first); + if (oit == other.end() || !(oit->second == it.udata.second)) + return false; + } + return true; + } + + bool operator!=(const dict &other) const { + return !operator==(other); + } + + size_t size() const { return entries.size(); } + bool empty() const { return entries.empty(); } + void clear() { hashtable.clear(); entries.clear(); } + + iterator begin() { return iterator(this, int(entries.size())-1); } + iterator end() { return iterator(nullptr, -1); } + + const_iterator begin() const { return const_iterator(this, int(entries.size())-1); } + const_iterator end() const { return const_iterator(nullptr, -1); } +}; + +template<typename K, typename OPS> +class pool +{ + template<typename, int, typename> friend class idict; + +protected: + struct entry_t + { + K udata; + int next; + + entry_t() { } + entry_t(const K &udata, int next) : udata(udata), next(next) { } + }; + + std::vector<int> hashtable; + std::vector<entry_t> entries; + OPS ops; + +#ifdef NDEBUG + static inline void do_assert(bool) { } +#else + static inline void do_assert(bool cond) { + if (!cond) throw std::runtime_error("pool<> assert failed."); + } +#endif + + int do_hash(const K &key) const + { + unsigned int hash = 0; + if (!hashtable.empty()) + hash = ops.hash(key) % (unsigned int)(hashtable.size()); + return hash; + } + + void do_rehash() + { + hashtable.clear(); + hashtable.resize(hashtable_size(entries.size() * hashtable_size_factor), -1); + + for (int i = 0; i < int(entries.size()); i++) { + do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size())); + int hash = do_hash(entries[i].udata); + entries[i].next = hashtable[hash]; + hashtable[hash] = i; + } + } + + int do_erase(int index, int hash) + { + do_assert(index < int(entries.size())); + if (hashtable.empty() || index < 0) + return 0; + + int k = hashtable[hash]; + if (k == index) { + hashtable[hash] = entries[index].next; + } else { + while (entries[k].next != index) { + k = entries[k].next; + do_assert(0 <= k && k < int(entries.size())); + } + entries[k].next = entries[index].next; + } + + int back_idx = entries.size()-1; + + if (index != back_idx) + { + int back_hash = do_hash(entries[back_idx].udata); + + k = hashtable[back_hash]; + if (k == back_idx) { + hashtable[back_hash] = index; + } else { + while (entries[k].next != back_idx) { + k = entries[k].next; + do_assert(0 <= k && k < int(entries.size())); + } + entries[k].next = index; + } + + entries[index] = std::move(entries[back_idx]); + } + + entries.pop_back(); + + if (entries.empty()) + hashtable.clear(); + + return 1; + } + + int do_lookup(const K &key, int &hash) const + { + if (hashtable.empty()) + return -1; + + if (entries.size() * hashtable_size_trigger > hashtable.size()) { + ((pool*)this)->do_rehash(); + hash = do_hash(key); + } + + int index = hashtable[hash]; + + while (index >= 0 && !ops.cmp(entries[index].udata, key)) { + index = entries[index].next; + do_assert(-1 <= index && index < int(entries.size())); + } + + return index; + } + + int do_insert(const K &value, int &hash) + { + if (hashtable.empty()) { + entries.push_back(entry_t(value, -1)); + do_rehash(); + hash = do_hash(value); + } else { + entries.push_back(entry_t(value, hashtable[hash])); + hashtable[hash] = entries.size() - 1; + } + return entries.size() - 1; + } + +public: + class const_iterator : public std::iterator<std::forward_iterator_tag, K> + { + friend class pool; + protected: + const pool *ptr; + int index; + const_iterator(const pool *ptr, int index) : ptr(ptr), index(index) { } + public: + const_iterator() { } + const_iterator operator++() { index--; return *this; } + bool operator==(const const_iterator &other) const { return index == other.index; } + bool operator!=(const const_iterator &other) const { return index != other.index; } + const K &operator*() const { return ptr->entries[index].udata; } + const K *operator->() const { return &ptr->entries[index].udata; } + }; + + class iterator : public std::iterator<std::forward_iterator_tag, K> + { + friend class pool; + protected: + pool *ptr; + int index; + iterator(pool *ptr, int index) : ptr(ptr), index(index) { } + public: + iterator() { } + iterator operator++() { index--; return *this; } + bool operator==(const iterator &other) const { return index == other.index; } + bool operator!=(const iterator &other) const { return index != other.index; } + K &operator*() { return ptr->entries[index].udata; } + K *operator->() { return &ptr->entries[index].udata; } + const K &operator*() const { return ptr->entries[index].udata; } + const K *operator->() const { return &ptr->entries[index].udata; } + operator const_iterator() const { return const_iterator(ptr, index); } + }; + + pool() + { + } + + pool(const pool &other) + { + entries = other.entries; + do_rehash(); + } + + pool(pool &&other) + { + swap(other); + } + + pool &operator=(const pool &other) { + entries = other.entries; + do_rehash(); + return *this; + } + + pool &operator=(pool &&other) { + clear(); + swap(other); + return *this; + } + + pool(const std::initializer_list<K> &list) + { + for (auto &it : list) + insert(it); + } + + template<class InputIterator> + pool(InputIterator first, InputIterator last) + { + insert(first, last); + } + + template<class InputIterator> + void insert(InputIterator first, InputIterator last) + { + for (; first != last; ++first) + insert(*first); + } + + std::pair<iterator, bool> insert(const K &value) + { + int hash = do_hash(value); + int i = do_lookup(value, hash); + if (i >= 0) + return std::pair<iterator, bool>(iterator(this, i), false); + i = do_insert(value, hash); + return std::pair<iterator, bool>(iterator(this, i), true); + } + + int erase(const K &key) + { + int hash = do_hash(key); + int index = do_lookup(key, hash); + return do_erase(index, hash); + } + + iterator erase(iterator it) + { + int hash = do_hash(*it); + do_erase(it.index, hash); + return ++it; + } + + int count(const K &key) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + return i < 0 ? 0 : 1; + } + + int count(const K &key, const_iterator it) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + return i < 0 || i > it.index ? 0 : 1; + } + + iterator find(const K &key) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + return end(); + return iterator(this, i); + } + + const_iterator find(const K &key) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + return end(); + return const_iterator(this, i); + } + + bool operator[](const K &key) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + return i >= 0; + } + + template<typename Compare = std::less<K>> + void sort(Compare comp = Compare()) + { + std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata, a.udata); }); + do_rehash(); + } + + void swap(pool &other) + { + hashtable.swap(other.hashtable); + entries.swap(other.entries); + } + + bool operator==(const pool &other) const { + if (size() != other.size()) + return false; + for (auto &it : entries) + if (!other.count(it.udata)) + return false; + return true; + } + + bool operator!=(const pool &other) const { + return !operator==(other); + } + + size_t size() const { return entries.size(); } + bool empty() const { return entries.empty(); } + void clear() { hashtable.clear(); entries.clear(); } + + iterator begin() { return iterator(this, int(entries.size())-1); } + iterator end() { return iterator(nullptr, -1); } + + const_iterator begin() const { return const_iterator(this, int(entries.size())-1); } + const_iterator end() const { return const_iterator(nullptr, -1); } +}; + +template<typename K, int offset, typename OPS> +class idict +{ + pool<K, OPS> database; + +public: + typedef typename pool<K, OPS>::const_iterator const_iterator; + + int operator()(const K &key) + { + int hash = database.do_hash(key); + int i = database.do_lookup(key, hash); + if (i < 0) + i = database.do_insert(key, hash); + return i + offset; + } + + int at(const K &key) const + { + int hash = database.do_hash(key); + int i = database.do_lookup(key, hash); + if (i < 0) + throw std::out_of_range("idict::at()"); + return i + offset; + } + + int count(const K &key) const + { + int hash = database.do_hash(key); + int i = database.do_lookup(key, hash); + return i < 0 ? 0 : 1; + } + + void expect(const K &key, int i) + { + int j = (*this)(key); + if (i != j) + throw std::out_of_range("idict::expect()"); + } + + const K &operator[](int index) const + { + return database.entries.at(index - offset).udata; + } + + const_iterator begin() const { return database.begin(); } + const_iterator end() const { return database.end(); } +}; + +} /* namespace hashlib */ + +#endif diff --git a/kernel/log.cc b/kernel/log.cc index 1b0eb6649..bf92daced 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -21,7 +21,14 @@ #include "libs/sha1/sha1.h" #include "backends/ilang/ilang_backend.h" -#include <sys/time.h> +#if !defined(_WIN32) || defined(__MINGW32__) +# include <sys/time.h> +#endif + +#ifdef __linux__ +# include <dlfcn.h> +#endif + #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -37,17 +44,41 @@ FILE *log_errfile = NULL; SHA1 *log_hasher = NULL; bool log_time = false; +bool log_error_stderr = false; bool log_cmd_error_throw = false; +bool log_quiet_warnings = false; int log_verbose_level; +string log_last_error; -std::vector<int> header_count; -std::list<std::string> string_buf; -int string_buf_size = 0; +vector<int> header_count; +pool<RTLIL::IdString> log_id_cache; +vector<string> string_buf; +int string_buf_index = -1; static struct timeval initial_tv = { 0, 0 }; static bool next_print_log = false; static int log_newline_count = 0; +#if defined(_WIN32) && !defined(__MINGW32__) +// this will get time information and return it in timeval, simulating gettimeofday() +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + LARGE_INTEGER counter; + LARGE_INTEGER freq; + + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&counter); + + counter.QuadPart *= 1000000; + counter.QuadPart /= freq.QuadPart; + + tv->tv_sec = long(counter.QuadPart / 1000000); + tv->tv_usec = counter.QuadPart % 1000000; + + return 0; +} +#endif + void logv(const char *format, va_list ap) { while (format[0] == '\n' && format[1] != 0) { @@ -62,9 +93,9 @@ void logv(const char *format, va_list ap) size_t nnl_pos = str.find_last_not_of('\n'); if (nnl_pos == std::string::npos) - log_newline_count += SIZE(str); + log_newline_count += GetSize(str); else - log_newline_count = SIZE(str) - nnl_pos - 1; + log_newline_count = GetSize(str) - nnl_pos - 1; if (log_hasher) log_hasher->update(str); @@ -128,15 +159,43 @@ void logv_header(const char *format, va_list ap) log_files.pop_back(); } +void logv_warning(const char *format, va_list ap) +{ + if (log_errfile != NULL && !log_quiet_warnings) + log_files.push_back(log_errfile); + + log("Warning: "); + logv(format, ap); + log_flush(); + + if (log_errfile != NULL && !log_quiet_warnings) + log_files.pop_back(); +} + void logv_error(const char *format, va_list ap) { +#ifdef EMSCRIPTEN + auto backup_log_files = log_files; +#endif + if (log_errfile != NULL) log_files.push_back(log_errfile); - log("ERROR: "); - logv(format, ap); + if (log_error_stderr) + for (auto &f : log_files) + if (f == stdout) + f = stderr; + + log_last_error = vstringf(format, ap); + log("ERROR: %s", log_last_error.c_str()); log_flush(); + +#ifdef EMSCRIPTEN + log_files = backup_log_files; + throw 0; +#else exit(1); +#endif } void log(const char *format, ...) @@ -155,6 +214,14 @@ void log_header(const char *format, ...) va_end(ap); } +void log_warning(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + logv_warning(format, ap); + va_end(ap); +} + void log_error(const char *format, ...) { va_list ap; @@ -168,10 +235,10 @@ void log_cmd_error(const char *format, ...) va_start(ap, format); if (log_cmd_error_throw) { - log("ERROR: "); - logv(format, ap); + log_last_error = vstringf(format, ap); + log("ERROR: %s", log_last_error.c_str()); log_flush(); - throw log_cmd_error_expection(); + throw log_cmd_error_exception(); } logv_error(format, ap); @@ -191,17 +258,112 @@ void log_push() void log_pop() { header_count.pop_back(); + log_id_cache.clear(); string_buf.clear(); - string_buf_size = 0; + string_buf_index = -1; log_flush(); } +#ifdef __linux__ +void log_backtrace(const char *prefix, int levels) +{ + if (levels <= 0) return; + + Dl_info dli; + void *p; + + if ((p = __builtin_extract_return_addr(__builtin_return_address(0))) && dladdr(p, &dli)) { + log("%sframe #1: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); + } else { + log("%sframe #1: ---\n", prefix); + return; + } + + if (levels <= 1) return; + + if ((p = __builtin_extract_return_addr(__builtin_return_address(1))) && dladdr(p, &dli)) { + log("%sframe #2: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); + } else { + log("%sframe #2: ---\n", prefix); + return; + } + + if (levels <= 2) return; + + if ((p = __builtin_extract_return_addr(__builtin_return_address(2))) && dladdr(p, &dli)) { + log("%sframe #3: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); + } else { + log("%sframe #3: ---\n", prefix); + return; + } + + if (levels <= 3) return; + + if ((p = __builtin_extract_return_addr(__builtin_return_address(3))) && dladdr(p, &dli)) { + log("%sframe #4: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); + } else { + log("%sframe #4: ---\n", prefix); + return; + } + + if (levels <= 4) return; + + if ((p = __builtin_extract_return_addr(__builtin_return_address(4))) && dladdr(p, &dli)) { + log("%sframe #5: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); + } else { + log("%sframe #5: ---\n", prefix); + return; + } + + if (levels <= 5) return; + + if ((p = __builtin_extract_return_addr(__builtin_return_address(5))) && dladdr(p, &dli)) { + log("%sframe #6: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); + } else { + log("%sframe #6: ---\n", prefix); + return; + } + + if (levels <= 6) return; + + if ((p = __builtin_extract_return_addr(__builtin_return_address(6))) && dladdr(p, &dli)) { + log("%sframe #7: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); + } else { + log("%sframe #7: ---\n", prefix); + return; + } + + if (levels <= 7) return; + + if ((p = __builtin_extract_return_addr(__builtin_return_address(7))) && dladdr(p, &dli)) { + log("%sframe #8: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); + } else { + log("%sframe #8: ---\n", prefix); + return; + } + + if (levels <= 8) return; + + if ((p = __builtin_extract_return_addr(__builtin_return_address(8))) && dladdr(p, &dli)) { + log("%sframe #9: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr); + } else { + log("%sframe #9: ---\n", prefix); + return; + } + + if (levels <= 9) return; +} +#else +void log_backtrace(const char*, int) { } +#endif + void log_reset_stack() { while (header_count.size() > 1) header_count.pop_back(); + log_id_cache.clear(); string_buf.clear(); - string_buf_size = 0; + string_buf_index = -1; log_flush(); } @@ -223,22 +385,28 @@ const char *log_signal(const RTLIL::SigSpec &sig, bool autoint) std::stringstream buf; ILANG_BACKEND::dump_sigspec(buf, sig, autoint); - 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(); + if (string_buf.size() < 100) { + string_buf.push_back(buf.str()); + return string_buf.back().c_str(); + } else { + if (++string_buf_index == 100) + string_buf_index = 0; + string_buf[string_buf_index] = buf.str(); + return string_buf[string_buf_index].c_str(); + } } const char *log_id(RTLIL::IdString str) { + log_id_cache.insert(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; + if (p[0] != '\\') + return p; + if (p[1] == '$' || p[1] == '\\' || p[1] == 0) + return p; + if (p[1] >= '0' && p[1] <= '9') + return p; + return p+1; } void log_cell(RTLIL::Cell *cell, std::string indent) @@ -251,9 +419,9 @@ void log_cell(RTLIL::Cell *cell, std::string indent) // --------------------------------------------------- // This is the magic behind the code coverage counters // --------------------------------------------------- -#ifdef COVER_ACTIVE +#if defined(YOSYS_ENABLE_COVER) && defined(__linux__) -std::map<std::string, std::pair<std::string, int>> extra_coverage_data; +dict<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) { @@ -266,9 +434,9 @@ void cover_extra(std::string parent, std::string id, bool increment) { extra_coverage_data[id].second++; } -std::map<std::string, std::pair<std::string, int>> get_coverage_data() +dict<std::string, std::pair<std::string, int>> get_coverage_data() { - std::map<std::string, std::pair<std::string, int>> coverage_data; + dict<std::string, std::pair<std::string, int>> coverage_data; for (auto &it : pass_register) { std::string key = stringf("passes.%s", it.first.c_str()); @@ -278,14 +446,14 @@ std::map<std::string, std::pair<std::string, int>> get_coverage_data() for (auto &it : extra_coverage_data) { if (coverage_data.count(it.first)) - log("WARNING: found duplicate coverage id \"%s\".\n", it.first.c_str()); + 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); + 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; } diff --git a/kernel/log.h b/kernel/log.h index e2b4db87b..16ad7b6c9 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -23,8 +23,14 @@ #define LOG_H #include <time.h> -#include <sys/time.h> -#include <sys/resource.h> + +#ifndef _WIN32 +# include <sys/time.h> +# include <sys/resource.h> +#endif + +// from libs/sha1/sha1.h +class SHA1; YOSYS_NAMESPACE_BEGIN @@ -32,30 +38,36 @@ YOSYS_NAMESPACE_BEGIN #define S__LINE__sub1(x) S__LINE__sub2(x) #define S__LINE__ S__LINE__sub1(__LINE__) -struct log_cmd_error_expection { }; +struct log_cmd_error_exception { }; extern std::vector<FILE*> log_files; extern std::vector<std::ostream*> log_streams; extern FILE *log_errfile; -extern class SHA1 *log_hasher; +extern SHA1 *log_hasher; extern bool log_time; +extern bool log_error_stderr; extern bool log_cmd_error_throw; +extern bool log_quiet_warnings; extern int log_verbose_level; +extern string log_last_error; void logv(const char *format, va_list ap); void logv_header(const char *format, va_list ap); -void logv_error(const char *format, va_list ap) __attribute__ ((noreturn)); +void logv_warning(const char *format, va_list ap); +YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noreturn); -void log(const char *format, ...) __attribute__ ((format (printf, 1, 2))); -void log_header(const char *format, ...) __attribute__ ((format (printf, 1, 2))); -void log_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn)); -void log_cmd_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn)); +void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); +void log_header(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); +void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); +YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); +YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); void log_spacer(); void log_push(); void log_pop(); +void log_backtrace(const char *prefix, int levels); void log_reset_stack(); void log_flush(); @@ -68,36 +80,43 @@ template<typename T> static inline const char *log_id(T *obj) { 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__) +#ifndef NDEBUG +static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) { + if (!cond) log_error("Assert `%s' failed in %s:%d.\n", expr, file, line); +} +# define log_assert(_assert_expr_) YOSYS_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__) +#else +# define log_assert(_assert_expr_) +#endif + +#define log_abort() YOSYS_NAMESPACE_PREFIX log_error("Abort in %s:%d.\n", __FILE__, __LINE__) +#define log_ping() YOSYS_NAMESPACE_PREFIX 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 +#if defined(YOSYS_ENABLE_COVER) && defined(__linux__) #define cover(_id) do { \ - static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1))) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \ + static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \ __d.counter++; \ } while (0) struct CoverData { const char *file, *func, *id; int line, counter; -} __attribute__ ((packed)); +} YS_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; +extern dict<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(); +dict<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__); \ @@ -151,6 +170,8 @@ struct PerformanceTimer t = 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL; t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL; return t; +#elif _WIN32 + return 0; #else #error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?). #endif @@ -169,7 +190,7 @@ struct PerformanceTimer } float sec() const { - return total_ns * 1e-9; + return total_ns * 1e-9f; } #else static int64_t query() { return 0; } @@ -188,8 +209,10 @@ static inline void log_dump_val_worker(int v) { log("%d", v); } static inline void log_dump_val_worker(unsigned int v) { log("%u", v); } static inline void log_dump_val_worker(long int v) { log("%ld", v); } static inline void log_dump_val_worker(unsigned long int v) { log("%lu", v); } +#ifndef _WIN32 static inline void log_dump_val_worker(long long int v) { log("%lld", v); } static inline void log_dump_val_worker(unsigned long long int v) { log("%lld", v); } +#endif static inline void log_dump_val_worker(char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", 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"); } @@ -198,7 +221,7 @@ 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(PerformanceTimer p) { log("%f seconds", p.sec()); } -static inline void log_dump_args_worker(const char *p) { log_assert(*p == 0); } +static inline void log_dump_args_worker(const char *p YS_ATTRIBUTE(unused)) { log_assert(*p == 0); } void log_dump_val_worker(RTLIL::SigSpec v); template<typename T> diff --git a/kernel/macc.h b/kernel/macc.h index 271141112..cac5b00d7 100644 --- a/kernel/macc.h +++ b/kernel/macc.h @@ -42,17 +42,20 @@ struct Macc for (auto &port : ports) { - if (SIZE(port.in_a) == 0 && SIZE(port.in_b) == 0) + if (GetSize(port.in_a) == 0 && GetSize(port.in_b) == 0) continue; - if (SIZE(port.in_a) == 1 && SIZE(port.in_b) == 0 && !port.is_signed && !port.do_subtract) { + if (GetSize(port.in_a) < GetSize(port.in_b)) + std::swap(port.in_a, port.in_b); + + if (GetSize(port.in_a) == 1 && GetSize(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)) + if (GetSize(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); @@ -62,15 +65,15 @@ struct Macc } 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); + while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == port.in_a[GetSize(port.in_a)-2]) + port.in_a.remove(GetSize(port.in_a)-1); + while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == port.in_b[GetSize(port.in_b)-2]) + port.in_b.remove(GetSize(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); + while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == RTLIL::S0) + port.in_a.remove(GetSize(port.in_a)-1); + while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == RTLIL::S0) + port.in_b.remove(GetSize(port.in_b)-1); } new_ports.push_back(port); @@ -102,10 +105,12 @@ struct Macc 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); +#ifndef NDEBUG + int config_width = cell->getParam("\\CONFIG_WIDTH").as_int(); + log_assert(GetSize(config_bits) >= config_width); +#endif int num_bits = 0; if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 1; @@ -114,7 +119,7 @@ struct Macc if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 8; int port_a_cursor = 0; - while (port_a_cursor < SIZE(port_a)) + while (port_a_cursor < GetSize(port_a)) { log_assert(config_cursor + 2 + 2*num_bits <= config_width); @@ -143,7 +148,7 @@ struct Macc } log_assert(config_cursor == config_width); - log_assert(port_a_cursor == SIZE(port_a)); + log_assert(port_a_cursor == GetSize(port_a)); } void to_cell(RTLIL::Cell *cell) const @@ -153,8 +158,8 @@ struct Macc 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)); + max_size = std::max(max_size, GetSize(port.in_a)); + max_size = std::max(max_size, GetSize(port.in_b)); } while (max_size) @@ -168,17 +173,17 @@ struct Macc for (auto &port : ports) { - if (SIZE(port.in_a) == 0) + if (GetSize(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); + int size_a = GetSize(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); + int size_b = GetSize(port.in_b); for (int i = 0; i < num_bits; i++) config_bits.push_back(size_b & (1 << i) ? RTLIL::S1 : RTLIL::S0); @@ -189,9 +194,9 @@ struct Macc 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)); + cell->setParam("\\CONFIG_WIDTH", GetSize(config_bits)); + cell->setParam("\\A_WIDTH", GetSize(port_a)); + cell->setParam("\\B_WIDTH", GetSize(bit_ports)); } bool eval(RTLIL::Const &result) const @@ -205,25 +210,31 @@ struct Macc 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)); + if (GetSize(port.in_b) == 0) + summand = const_pos(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, GetSize(result)); else - summand = const_mul(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, SIZE(result)); + summand = const_mul(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, GetSize(result)); if (port.do_subtract) - result = const_sub(result, summand, port.is_signed, port.is_signed, SIZE(result)); + result = const_sub(result, summand, port.is_signed, port.is_signed, GetSize(result)); else - result = const_add(result, summand, port.is_signed, port.is_signed, SIZE(result)); + result = const_add(result, summand, port.is_signed, port.is_signed, GetSize(result)); } for (auto bit : bit_ports) { if (bit.wire) return false; - result = const_add(result, bit.data, false, false, SIZE(result)); + result = const_add(result, bit.data, false, false, GetSize(result)); } return true; } + + Macc(RTLIL::Cell *cell = nullptr) + { + if (cell != nullptr) + from_cell(cell); + } }; YOSYS_NAMESPACE_END diff --git a/kernel/modtools.h b/kernel/modtools.h index 58cdd5b0e..69c13bd3b 100644 --- a/kernel/modtools.h +++ b/kernel/modtools.h @@ -33,6 +33,7 @@ struct ModIndex : public RTLIL::Monitor RTLIL::IdString port; int offset; + PortInfo() : cell(), port(), offset() { } PortInfo(RTLIL::Cell* _c, RTLIL::IdString _p, int _o) : cell(_c), port(_p), offset(_o) { } bool operator<(const PortInfo &other) const { @@ -42,24 +43,44 @@ struct ModIndex : public RTLIL::Monitor return offset < other.offset; return port < other.port; } + + bool operator==(const PortInfo &other) const { + return cell == other.cell && port == other.port && offset == other.offset; + } + + unsigned int hash() const { + return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset); + } }; struct SigBitInfo { bool is_input, is_output; - std::set<PortInfo> ports; + pool<PortInfo> ports; SigBitInfo() : is_input(false), is_output(false) { } + + bool operator==(const SigBitInfo &other) const { + return is_input == other.is_input && is_output == other.is_output && ports == other.ports; + } + + void merge(const SigBitInfo &other) + { + is_input = is_input || other.is_input; + is_output = is_output || other.is_output; + ports.insert(other.ports.begin(), other.ports.end()); + } }; SigMap sigmap; RTLIL::Module *module; std::map<RTLIL::SigBit, SigBitInfo> database; + int auto_reload_counter; 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++) { + for (int i = 0; i < GetSize(sig); i++) { RTLIL::SigBit bit = sigmap(sig[i]); if (bit.wire) database[bit].ports.insert(PortInfo(cell, port, i)); @@ -68,7 +89,7 @@ struct ModIndex : public RTLIL::Monitor void port_del(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig) { - for (int i = 0; i < SIZE(sig); i++) { + for (int i = 0; i < GetSize(sig); i++) { RTLIL::SigBit bit = sigmap(sig[i]); if (bit.wire) database[bit].ports.erase(PortInfo(cell, port, i)); @@ -80,15 +101,17 @@ struct ModIndex : public RTLIL::Monitor return database[sigmap(bit)]; } - void reload_module() + void reload_module(bool reset_sigmap = true) { - sigmap.clear(); - sigmap.set(module); + if (reset_sigmap) { + 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++) { + for (int i = 0; i < GetSize(wire); i++) { RTLIL::SigBit bit = sigmap(RTLIL::SigBit(wire, i)); if (bit.wire && wire->port_input) database[bit].is_input = true; @@ -99,31 +122,105 @@ struct ModIndex : public RTLIL::Monitor for (auto &conn : cell->connections()) port_add(cell, conn.first, conn.second); - auto_reload_module = false; + if (auto_reload_module) { + if (++auto_reload_counter > 2) + log_warning("Auto-reload in ModIndex -- possible performance bug!\n"); + auto_reload_module = false; + } } - virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) OVERRIDE + void check() { +#ifndef NDEBUG if (auto_reload_module) - reload_module(); + return; + + for (auto it : database) + log_assert(it.first == sigmap(it.first)); + + auto database_bak = std::move(database); + reload_module(false); + + if (!(database == database_bak)) + { + for (auto &it : database_bak) + if (!database.count(it.first)) + log("ModuleIndex::check(): Only in database_bak, not database: %s\n", log_signal(it.first)); + + for (auto &it : database) + if (!database_bak.count(it.first)) + log("ModuleIndex::check(): Only in database, not database_bak: %s\n", log_signal(it.first)); + else if (!(it.second == database_bak.at(it.first))) + log("ModuleIndex::check(): Different content for database[%s].\n", log_signal(it.first)); + + log_assert(database == database_bak); + } +#endif + } + + virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE + { + log_assert(module == cell->module); + + if (auto_reload_module) + return; port_del(cell, port, old_sig); port_add(cell, port, sig); } - virtual void notify_connect(RTLIL::Module *mod, const RTLIL::SigSig&) + virtual void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const RTLIL::SigSig &sigsig) YS_OVERRIDE { log_assert(module == mod); - auto_reload_module = true; + + if (auto_reload_module) + return; + + for (int i = 0; i < GetSize(sigsig.first); i++) + { + RTLIL::SigBit lhs = sigmap(sigsig.first[i]); + RTLIL::SigBit rhs = sigmap(sigsig.second[i]); + bool has_lhs = database.count(lhs); + bool has_rhs = database.count(rhs); + + if (!has_lhs && !has_rhs) { + sigmap.add(lhs, rhs); + } else + if (!has_rhs) { + SigBitInfo new_info = database.at(lhs); + database.erase(lhs); + sigmap.add(lhs, rhs); + lhs = sigmap(lhs); + if (lhs.wire) + database[lhs] = new_info; + } else + if (!has_lhs) { + SigBitInfo new_info = database.at(rhs); + database.erase(rhs); + sigmap.add(lhs, rhs); + rhs = sigmap(rhs); + if (rhs.wire) + database[rhs] = new_info; + } else { + SigBitInfo new_info = database.at(lhs); + new_info.merge(database.at(rhs)); + database.erase(lhs); + database.erase(rhs); + sigmap.add(lhs, rhs); + rhs = sigmap(rhs); + if (rhs.wire) + database[rhs] = new_info; + } + } } - virtual void notify_connect(RTLIL::Module *mod, const std::vector<RTLIL::SigSig>&) + virtual void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const std::vector<RTLIL::SigSig>&) YS_OVERRIDE { log_assert(module == mod); auto_reload_module = true; } - virtual void notify_blackout(RTLIL::Module *mod) + virtual void notify_blackout(RTLIL::Module *mod YS_ATTRIBUTE(unused)) YS_OVERRIDE { log_assert(module == mod); auto_reload_module = true; @@ -131,6 +228,7 @@ struct ModIndex : public RTLIL::Monitor ModIndex(RTLIL::Module *_m) : module(_m) { + auto_reload_counter = 0; auto_reload_module = true; module->monitors.insert(this); } @@ -168,9 +266,9 @@ struct ModIndex : public RTLIL::Monitor return info->is_output; } - std::set<PortInfo> &query_ports(RTLIL::SigBit bit) + pool<PortInfo> &query_ports(RTLIL::SigBit bit) { - static std::set<PortInfo> empty_result_set; + static pool<PortInfo> empty_result_set; SigBitInfo *info = query(bit); if (info == nullptr) return empty_result_set; @@ -193,6 +291,14 @@ struct ModWalker return port < other.port; return offset < other.offset; } + + bool operator==(const PortBit &other) const { + return cell == other.cell && port == other.port && offset == other.offset; + } + + unsigned int hash() const { + return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset); + } }; RTLIL::Design *design; @@ -201,11 +307,11 @@ struct ModWalker 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; + dict<RTLIL::SigBit, pool<PortBit>> signal_drivers; + dict<RTLIL::SigBit, pool<PortBit>> signal_consumers; + pool<RTLIL::SigBit> signal_inputs, signal_outputs; - std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_outputs, cell_inputs; + dict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_outputs, cell_inputs; void add_wire(RTLIL::Wire *wire) { @@ -286,11 +392,11 @@ struct ModWalker // get_* methods -- single RTLIL::SigBit template<typename T> - inline bool get_drivers(std::set<PortBit> &result, RTLIL::SigBit bit) const + inline bool get_drivers(pool<PortBit> &result, RTLIL::SigBit bit) const { bool found = false; if (signal_drivers.count(bit)) { - const std::set<PortBit> &r = signal_drivers.at(bit); + const pool<PortBit> &r = signal_drivers.at(bit); result.insert(r.begin(), r.end()); found = true; } @@ -298,11 +404,11 @@ struct ModWalker } template<typename T> - inline bool get_consumers(std::set<PortBit> &result, RTLIL::SigBit bit) const + inline bool get_consumers(pool<PortBit> &result, RTLIL::SigBit bit) const { bool found = false; if (signal_consumers.count(bit)) { - const std::set<PortBit> &r = signal_consumers.at(bit); + const pool<PortBit> &r = signal_consumers.at(bit); result.insert(r.begin(), r.end()); found = true; } @@ -310,7 +416,7 @@ struct ModWalker } template<typename T> - inline bool get_inputs(std::set<RTLIL::SigBit> &result, RTLIL::SigBit bit) const + inline bool get_inputs(pool<RTLIL::SigBit> &result, RTLIL::SigBit bit) const { bool found = false; if (signal_inputs.count(bit)) @@ -319,7 +425,7 @@ struct ModWalker } template<typename T> - inline bool get_outputs(std::set<RTLIL::SigBit> &result, RTLIL::SigBit bit) const + inline bool get_outputs(pool<RTLIL::SigBit> &result, RTLIL::SigBit bit) const { bool found = false; if (signal_outputs.count(bit)) @@ -330,12 +436,12 @@ struct ModWalker // 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 + inline bool get_drivers(pool<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); + const pool<PortBit> &r = signal_drivers.at(bit); result.insert(r.begin(), r.end()); found = true; } @@ -343,12 +449,12 @@ struct ModWalker } template<typename T> - inline bool get_consumers(std::set<PortBit> &result, const T &bits) const + inline bool get_consumers(pool<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); + const pool<PortBit> &r = signal_consumers.at(bit); result.insert(r.begin(), r.end()); found = true; } @@ -356,7 +462,7 @@ struct ModWalker } template<typename T> - inline bool get_inputs(std::set<RTLIL::SigBit> &result, const T &bits) const + inline bool get_inputs(pool<RTLIL::SigBit> &result, const T &bits) const { bool found = false; for (RTLIL::SigBit bit : bits) @@ -366,7 +472,7 @@ struct ModWalker } template<typename T> - inline bool get_outputs(std::set<RTLIL::SigBit> &result, const T &bits) const + inline bool get_outputs(pool<RTLIL::SigBit> &result, const T &bits) const { bool found = false; for (RTLIL::SigBit bit : bits) @@ -377,25 +483,25 @@ struct ModWalker // get_* methods -- call by RTLIL::SigSpec (always by value) - bool get_drivers(std::set<PortBit> &result, RTLIL::SigSpec signal) const + bool get_drivers(pool<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 + bool get_consumers(pool<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 + bool get_inputs(pool<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 + bool get_outputs(pool<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const { std::vector<RTLIL::SigBit> bits = sigmap(signal); return get_outputs(result, bits); @@ -405,47 +511,47 @@ struct ModWalker template<typename T> inline bool has_drivers(const T &sig) const { - std::set<PortBit> result; + pool<PortBit> result; return get_drivers(result, sig); } template<typename T> inline bool has_consumers(const T &sig) const { - std::set<PortBit> result; + pool<PortBit> result; return get_consumers(result, sig); } template<typename T> inline bool has_inputs(const T &sig) const { - std::set<RTLIL::SigBit> result; + pool<RTLIL::SigBit> result; return get_inputs(result, sig); } template<typename T> inline bool has_outputs(const T &sig) const { - std::set<RTLIL::SigBit> result; + pool<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; + pool<PortBit> result; return get_drivers(result, sig); } inline bool has_consumers(RTLIL::SigSpec sig) const { - std::set<PortBit> result; + pool<PortBit> result; return get_consumers(result, sig); } inline bool has_inputs(RTLIL::SigSpec sig) const { - std::set<RTLIL::SigBit> result; + pool<RTLIL::SigBit> result; return get_inputs(result, sig); } inline bool has_outputs(RTLIL::SigSpec sig) const { - std::set<RTLIL::SigBit> result; + pool<RTLIL::SigBit> result; return get_outputs(result, sig); } }; diff --git a/kernel/register.cc b/kernel/register.cc index 2f7b89ffd..af1cb77b5 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -18,6 +18,8 @@ */ #include "kernel/yosys.h" +#include "kernel/satgen.h" + #include <string.h> #include <stdlib.h> #include <stdio.h> @@ -146,35 +148,39 @@ void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Desig 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 == '#') { - free(sstart); + + std::string cmd_buf = command; + std::string tok = next_token(cmd_buf, " \t\r\n"); + + if (tok.empty()) return; - } - if (*s == '!') { - for (s++; *s == ' ' || *s == '\t'; s++) { } - char *p = s + strlen(s) - 1; - while (p >= s && (*p == '\r' || *p == '\n')) - *(p--) = 0; - log_header("Shell command: %s\n", s); - int retCode = system(s); + + if (tok[0] == '!') { + cmd_buf = command.substr(command.find('!') + 1); + while (!cmd_buf.empty() && (cmd_buf.back() == ' ' || cmd_buf.back() == '\t' || + cmd_buf.back() == '\r' || cmd_buf.back() == '\n')) + cmd_buf.resize(cmd_buf.size()-1); + log_header("Shell command: %s\n", cmd_buf.c_str()); + int retCode = run_command(cmd_buf); 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)) { - std::string str = p; - int strsz = str.size(); - if (str == "#") - break; - if (strsz > 0 && str[strsz-1] == ';') { + + while (!tok.empty()) { + if (tok == "#") { + int stop; + for (stop = 0; stop < GetSize(cmd_buf); stop++) + if (cmd_buf[stop] == '\r' || cmd_buf[stop] == '\n') + break; + cmd_buf = cmd_buf.substr(stop); + } else + if (tok.back() == ';') { int num_semikolon = 0; - while (strsz > 0 && str[strsz-1] == ';') - strsz--, num_semikolon++; - if (strsz > 0) - args.push_back(str.substr(0, strsz)); + while (!tok.empty() && tok.back() == ';') + tok.resize(tok.size()-1), num_semikolon++; + if (!tok.empty()) + args.push_back(tok); call(design, args); args.clear(); if (num_semikolon == 2) @@ -182,9 +188,22 @@ void Pass::call(RTLIL::Design *design, std::string command) if (num_semikolon == 3) call(design, "clean -purge"); } else - args.push_back(str); + args.push_back(tok); + bool found_nl = false; + for (auto c : cmd_buf) { + if (c == ' ' || c == '\t') + continue; + if (c == '\r' || c == '\n') + found_nl = true; + break; + } + if (found_nl) { + call(design, args); + args.clear(); + } + tok = next_token(cmd_buf, " \t\r\n"); } - free(sstart); + call(design, args); } @@ -333,8 +352,8 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s 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) + size_t indent = buffer.find_first_not_of(" \t\r\n"); + if (indent != std::string::npos && buffer.substr(indent, eot_marker.size()) == eot_marker) break; last_here_document += buffer; } @@ -528,11 +547,10 @@ struct HelpPass : public Pass { } void escape_tex(std::string &tex) { - size_t pos = 0; - while ((pos = tex.find('_', pos)) != std::string::npos) { + for (size_t pos = 0; (pos = tex.find('_', pos)) != std::string::npos; pos += 2) tex.replace(pos, 1, "\\_"); - pos += 2; - } + for (size_t pos = 0; (pos = tex.find('$', pos)) != std::string::npos; pos += 2) + tex.replace(pos, 1, "\\$"); } void write_tex(FILE *f, std::string cmd, std::string title, std::string text) { @@ -675,6 +693,18 @@ struct EchoPass : public Pass { log("echo %s\n", echo_mode ? "on" : "off"); } } EchoPass; + +SatSolver *yosys_satsolver_list; +SatSolver *yosys_satsolver; + +struct MinisatSatSolver : public SatSolver { + MinisatSatSolver() : SatSolver("minisat") { + yosys_satsolver = this; + } + virtual ezSAT *create() YS_OVERRIDE { + return new ezMiniSAT(); + } +} MinisatSatSolver; YOSYS_NAMESPACE_END diff --git a/kernel/register.h b/kernel/register.h index a49675ed2..0a10483fd 100644 --- a/kernel/register.h +++ b/kernel/register.h @@ -71,9 +71,9 @@ struct Frontend : Pass std::string frontend_name; Frontend(std::string name, std::string short_help = "** document me **"); - virtual void run_register(); + virtual void run_register() YS_OVERRIDE; virtual ~Frontend(); - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) OVERRIDE FINAL; + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL; virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0; static std::vector<std::string> next_args; @@ -87,9 +87,9 @@ struct Backend : Pass { std::string backend_name; Backend(std::string name, std::string short_help = "** document me **"); - virtual void run_register(); + virtual void run_register() YS_OVERRIDE; virtual ~Backend(); - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) OVERRIDE FINAL; + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL; virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0; void extra_args(std::ostream *&f, std::string &filename, std::vector<std::string> args, size_t argidx); @@ -100,6 +100,8 @@ struct Backend : Pass // 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); +extern RTLIL::Selection eval_select_args(const vector<string> &args, RTLIL::Design *design); +extern void eval_select_op(vector<RTLIL::Selection> &work, const string &op, RTLIL::Design *design); extern std::map<std::string, Pass*> pass_register; extern std::map<std::string, Frontend*> frontend_register; diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 00be796f8..adf89a245 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -19,6 +19,7 @@ #include "kernel/yosys.h" #include "kernel/macc.h" +#include "kernel/celltypes.h" #include "frontends/verilog/verilog_frontend.h" #include "backends/ilang/ilang_backend.h" @@ -27,9 +28,10 @@ YOSYS_NAMESPACE_BEGIN +RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard; 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_; +dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_; std::vector<int> RTLIL::IdString::global_free_idx_list_; RTLIL::Const::Const() @@ -127,6 +129,21 @@ std::string RTLIL::Const::as_string() const return ret; } +RTLIL::Const RTLIL::Const::from_string(std::string str) +{ + Const c; + for (auto it = str.rbegin(); it != str.rend(); it++) + switch (*it) { + case '0': c.bits.push_back(State::S0); break; + case '1': c.bits.push_back(State::S1); break; + case 'x': c.bits.push_back(State::Sx); break; + case 'z': c.bits.push_back(State::Sz); break; + case 'm': c.bits.push_back(State::Sm); break; + default: c.bits.push_back(State::Sa); + } + return c; +} + std::string RTLIL::Const::decode_string() const { std::string string; @@ -235,13 +252,17 @@ void RTLIL::Selection::optimize(RTLIL::Design *design) RTLIL::Design::Design() { + static unsigned int hashidx_count = 123456789; + hashidx_count = mkhash_xorshift(hashidx_count); + hashidx_ = hashidx_count; + 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; } @@ -264,6 +285,11 @@ void RTLIL::Design::add(RTLIL::Module *module) for (auto mon : monitors) mon->notify_module_add(module); + + if (yosys_xtrace) { + log("#X# New Module: %s\n", log_id(module)); + log_backtrace("-X- ", yosys_xtrace-1); + } } RTLIL::Module *RTLIL::Design::addModule(RTLIL::IdString name) @@ -279,6 +305,11 @@ RTLIL::Module *RTLIL::Design::addModule(RTLIL::IdString name) for (auto mon : monitors) mon->notify_module_add(module); + if (yosys_xtrace) { + log("#X# New Module: %s\n", log_id(module)); + log_backtrace("-X- ", yosys_xtrace-1); + } + return module; } @@ -348,11 +379,24 @@ void RTLIL::Design::remove(RTLIL::Module *module) for (auto mon : monitors) mon->notify_module_del(module); + if (yosys_xtrace) { + log("#X# Remove Module: %s\n", log_id(module)); + log_backtrace("-X- ", yosys_xtrace-1); + } + log_assert(modules_.at(module->name) == module); modules_.erase(module->name); delete module; } +void RTLIL::Design::sort() +{ + scratchpad.sort(); + modules_.sort(sort_by_id_str()); + for (auto &it : modules_) + it.second->sort(); +} + void RTLIL::Design::check() { #ifndef NDEBUG @@ -417,7 +461,7 @@ 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)) + if (selected_module(it.first) && !it.second->get_bool_attribute("\\blackbox")) result.push_back(it.second); return result; } @@ -427,7 +471,7 @@ 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)) + if (selected_whole_module(it.first) && !it.second->get_bool_attribute("\\blackbox")) result.push_back(it.second); return result; } @@ -437,15 +481,21 @@ 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)) + if (it.second->get_bool_attribute("\\blackbox")) + continue; + else 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)); + log_warning("Ignoring partially selected module %s.\n", log_id(it.first)); return result; } RTLIL::Module::Module() { + static unsigned int hashidx_count = 123456789; + hashidx_count = mkhash_xorshift(hashidx_count); + hashidx_ = hashidx_count; + design = nullptr; refcount_wires_ = 0; refcount_cells_ = 0; @@ -453,17 +503,17 @@ RTLIL::Module::Module() 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++) + 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++) + for (auto it = processes.begin(); it != processes.end(); ++it) delete it->second; } -RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, std::map<RTLIL::IdString, RTLIL::Const>) +RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>) { log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name)); } @@ -479,7 +529,7 @@ namespace { { RTLIL::Module *module; RTLIL::Cell *cell; - std::set<RTLIL::IdString> expected_params, expected_ports; + pool<RTLIL::IdString> expected_params, expected_ports; InternalCellChecker(RTLIL::Module *module, RTLIL::Cell *cell) : module(module), cell(cell) { } @@ -752,6 +802,17 @@ namespace { return; } + if (cell->type == "$dffe") { + param_bool("\\CLK_POLARITY"); + param_bool("\\EN_POLARITY"); + port("\\CLK", 1); + port("\\EN", 1); + port("\\D", param("\\WIDTH")); + port("\\Q", param("\\WIDTH")); + check_expected(); + return; + } + if (cell->type == "$dffsr") { param_bool("\\CLK_POLARITY"); param_bool("\\SET_POLARITY"); @@ -843,10 +904,20 @@ namespace { return; } + if (cell->type == "$meminit") { + param("\\MEMID"); + param("\\PRIORITY"); + port("\\ADDR", param("\\ABITS")); + port("\\DATA", param("\\WIDTH")); + check_expected(); + return; + } + if (cell->type == "$mem") { param("\\MEMID"); param("\\SIZE"); param("\\OFFSET"); + param("\\INIT"); param_bits("\\RD_CLK_ENABLE", param("\\RD_PORTS")); param_bits("\\RD_CLK_POLARITY", param("\\RD_PORTS")); param_bits("\\RD_TRANSPARENT", param("\\RD_PORTS")); @@ -870,6 +941,22 @@ namespace { return; } + if (cell->type == "$assume") { + port("\\A", 1); + port("\\EN", 1); + check_expected(); + return; + } + + if (cell->type == "$equiv") { + port("\\A", 1); + port("\\B", 1); + port("\\Y", 1); + check_expected(); + return; + } + + if (cell->type == "$_BUF_") { check_gate("AY"); 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; } @@ -891,6 +978,11 @@ namespace { if (cell->type == "$_DFF_N_") { check_gate("DQC"); return; } if (cell->type == "$_DFF_P_") { check_gate("DQC"); return; } + if (cell->type == "$_DFFE_NN_") { check_gate("DQCE"); return; } + if (cell->type == "$_DFFE_NP_") { check_gate("DQCE"); return; } + if (cell->type == "$_DFFE_PN_") { check_gate("DQCE"); return; } + if (cell->type == "$_DFFE_PP_") { check_gate("DQCE"); return; } + if (cell->type == "$_DFF_NN0_") { check_gate("DQCR"); return; } if (cell->type == "$_DFF_NN1_") { check_gate("DQCR"); return; } if (cell->type == "$_DFF_NP0_") { check_gate("DQCR"); return; } @@ -927,6 +1019,21 @@ namespace { } #endif +void RTLIL::Module::sort() +{ + wires_.sort(sort_by_id_str()); + cells_.sort(sort_by_id_str()); + avail_parameters.sort(sort_by_id_str()); + memories.sort(sort_by_id_str()); + processes.sort(sort_by_id_str()); + for (auto &it : cells_) + it.second->sort(); + for (auto &it : wires_) + it.second->attributes.sort(sort_by_id_str()); + for (auto &it : memories) + it.second->attributes.sort(sort_by_id_str()); +} + void RTLIL::Module::check() { #ifndef NDEBUG @@ -940,10 +1047,10 @@ void RTLIL::Module::check() 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(GetSize(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) + if (GetSize(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; @@ -952,7 +1059,7 @@ void RTLIL::Module::check() } for (auto port_declared : ports_declared) log_assert(port_declared == true); - log_assert(SIZE(ports) == SIZE(ports_declared)); + log_assert(GetSize(ports) == GetSize(ports_declared)); for (auto &it : memories) { log_assert(it.first == it.second->name); @@ -988,6 +1095,7 @@ void RTLIL::Module::check() for (auto &it : connections_) { log_assert(it.first.size() == it.second.size()); + log_assert(!it.first.has_const()); it.first.check(); it.second.check(); } @@ -1006,8 +1114,11 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const log_assert(new_mod->refcount_wires_ == 0); log_assert(new_mod->refcount_cells_ == 0); - new_mod->connections_ = connections_; - new_mod->attributes = attributes; + for (auto &conn : connections_) + new_mod->connect(conn); + + for (auto &attr : attributes) + new_mod->attributes[attr.first] = attr.second; for (auto &it : wires_) new_mod->addWire(it.first, it.second); @@ -1061,14 +1172,14 @@ bool RTLIL::Module::has_processes() const 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)); + 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)); + log_warning("Ignoring module %s because it contains processes (run 'proc' command first).\n", log_id(this)); return !processes.empty(); } @@ -1114,7 +1225,7 @@ namespace { struct DeleteWireWorker { RTLIL::Module *module; - const std::set<RTLIL::Wire*> *wires_p; + const pool<RTLIL::Wire*> *wires_p; void operator()(RTLIL::SigSpec &sig) { std::vector<RTLIL::SigChunk> chunks = sig; @@ -1128,16 +1239,7 @@ namespace { }; } -#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) +void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires) { log_assert(refcount_wires_ == 0); @@ -1266,6 +1368,11 @@ void RTLIL::Module::connect(const RTLIL::SigSig &conn) for (auto mon : design->monitors) mon->notify_connect(this, conn); + if (yosys_xtrace) { + log("#X# Connect (SigSig) in %s: %s = %s (%d bits)\n", log_id(this), log_signal(conn.first), log_signal(conn.second), GetSize(conn.first)); + log_backtrace("-X- ", yosys_xtrace-1); + } + connections_.push_back(conn); } @@ -1283,6 +1390,13 @@ void RTLIL::Module::new_connections(const std::vector<RTLIL::SigSig> &new_conn) for (auto mon : design->monitors) mon->notify_connect(this, new_conn); + if (yosys_xtrace) { + log("#X# New connections vector in %s:\n", log_id(this)); + for (auto &conn: new_conn) + log("#X# %s = %s (%d bits)\n", log_signal(conn.first), log_signal(conn.second), GetSize(conn.first)); + log_backtrace("-X- ", yosys_xtrace-1); + } + connections_ = new_conn; } @@ -1566,6 +1680,15 @@ RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, RTLIL::SigSpec sig_a return cell; } +RTLIL::Cell* RTLIL::Module::addEquiv(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y) +{ + RTLIL::Cell *cell = addCell(name, "$equiv"); + cell->setPort("\\A", sig_a); + cell->setPort("\\B", sig_b); + cell->setPort("\\Y", sig_y); + 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"); @@ -1578,7 +1701,7 @@ RTLIL::Cell* RTLIL::Module::addSr(RTLIL::IdString name, RTLIL::SigSpec sig_set, 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* 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; @@ -1589,6 +1712,19 @@ RTLIL::Cell* RTLIL::Module::addDff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, return cell; } +RTLIL::Cell* RTLIL::Module::addDffe(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool en_polarity) +{ + RTLIL::Cell *cell = addCell(name, "$dffe"); + cell->parameters["\\CLK_POLARITY"] = clk_polarity; + cell->parameters["\\EN_POLARITY"] = en_polarity; + cell->parameters["\\WIDTH"] = sig_q.size(); + cell->setPort("\\CLK", sig_clk); + cell->setPort("\\EN", sig_en); + 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) { @@ -1656,6 +1792,16 @@ RTLIL::Cell* RTLIL::Module::addDffGate(RTLIL::IdString name, RTLIL::SigSpec sig_ return cell; } +RTLIL::Cell* RTLIL::Module::addDffeGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool en_polarity) +{ + RTLIL::Cell *cell = addCell(name, stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N')); + cell->setPort("\\C", sig_clk); + cell->setPort("\\E", sig_en); + 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) { @@ -1703,6 +1849,10 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, RTLIL::SigSpec RTLIL::Wire::Wire() { + static unsigned int hashidx_count = 123456789; + hashidx_count = mkhash_xorshift(hashidx_count); + hashidx_ = hashidx_count; + module = nullptr; width = 1; start_offset = 0; @@ -1714,12 +1864,22 @@ RTLIL::Wire::Wire() RTLIL::Memory::Memory() { + static unsigned int hashidx_count = 123456789; + hashidx_count = mkhash_xorshift(hashidx_count); + hashidx_ = hashidx_count; + width = 1; size = 0; } RTLIL::Cell::Cell() : module(nullptr) { + static unsigned int hashidx_count = 123456789; + hashidx_count = mkhash_xorshift(hashidx_count); + hashidx_ = hashidx_count; + + // log("#memtrace# %p\n", this); + memhasher(); } bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const @@ -1741,6 +1901,11 @@ void RTLIL::Cell::unsetPort(RTLIL::IdString portname) for (auto mon : module->design->monitors) mon->notify_connect(this, conn_it->first, conn_it->second, signal); + if (yosys_xtrace) { + log("#X# Unconnect %s.%s.%s\n", log_id(this->module), log_id(this), log_id(portname)); + log_backtrace("-X- ", yosys_xtrace-1); + } + connections_.erase(conn_it); } } @@ -1753,7 +1918,9 @@ void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal) connections_[portname] = RTLIL::SigSpec(); conn_it = connections_.find(portname); log_assert(conn_it != connections_.end()); - } + } else + if (conn_it->second == signal) + return; for (auto mon : module->monitors) mon->notify_connect(this, conn_it->first, conn_it->second, signal); @@ -1762,6 +1929,11 @@ void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal) for (auto mon : module->design->monitors) mon->notify_connect(this, conn_it->first, conn_it->second, signal); + if (yosys_xtrace) { + log("#X# Connect %s.%s.%s = %s (%d)\n", log_id(this->module), log_id(this), log_id(portname), log_signal(signal), GetSize(signal)); + log_backtrace("-X- ", yosys_xtrace-1); + } + conn_it->second = signal; } @@ -1770,14 +1942,47 @@ 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 +const dict<RTLIL::IdString, RTLIL::SigSpec> &RTLIL::Cell::connections() const { return connections_; } +bool RTLIL::Cell::known() const +{ + if (yosys_celltypes.cell_known(type)) + return true; + if (module && module->design && module->design->module(type)) + return true; + return false; +} + +bool RTLIL::Cell::input(RTLIL::IdString portname) const +{ + if (yosys_celltypes.cell_known(type)) + return yosys_celltypes.cell_input(type, portname); + if (module && module->design) { + RTLIL::Module *m = module->design->module(type); + RTLIL::Wire *w = m ? m->wire(portname) : nullptr; + return w && w->port_input; + } + return false; +} + +bool RTLIL::Cell::output(RTLIL::IdString portname) const +{ + if (yosys_celltypes.cell_known(type)) + return yosys_celltypes.cell_output(type, portname); + if (module && module->design) { + RTLIL::Module *m = module->design->module(type); + RTLIL::Wire *w = m ? m->wire(portname) : nullptr; + return w && w->port_output; + } + return false; +} + bool RTLIL::Cell::hasParam(RTLIL::IdString paramname) const { - return parameters.count(paramname); + return parameters.count(paramname) != 0; } void RTLIL::Cell::unsetParam(RTLIL::IdString paramname) @@ -1795,6 +2000,13 @@ const RTLIL::Const &RTLIL::Cell::getParam(RTLIL::IdString paramname) const return parameters.at(paramname); } +void RTLIL::Cell::sort() +{ + connections_.sort(sort_by_id_str()); + parameters.sort(sort_by_id_str()); + attributes.sort(sort_by_id_str()); +} + void RTLIL::Cell::check() { #ifndef NDEBUG @@ -1810,25 +2022,25 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) return; if (type == "$mux" || type == "$pmux") { - parameters["\\WIDTH"] = SIZE(connections_["\\Y"]); + parameters["\\WIDTH"] = GetSize(connections_["\\Y"]); if (type == "$pmux") - parameters["\\S_WIDTH"] = SIZE(connections_["\\S"]); + parameters["\\S_WIDTH"] = GetSize(connections_["\\S"]); check(); return; } if (type == "$lut") { - parameters["\\WIDTH"] = SIZE(connections_["\\A"]); + parameters["\\WIDTH"] = GetSize(connections_["\\A"]); return; } if (type == "$fa") { - parameters["\\WIDTH"] = SIZE(connections_["\\Y"]); + parameters["\\WIDTH"] = GetSize(connections_["\\Y"]); return; } if (type == "$lcu") { - parameters["\\WIDTH"] = SIZE(connections_["\\CO"]); + parameters["\\WIDTH"] = GetSize(connections_["\\CO"]); return; } @@ -1841,7 +2053,7 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) else if (parameters.count("\\A_SIGNED") == 0) parameters["\\A_SIGNED"] = false; } - parameters["\\A_WIDTH"] = SIZE(connections_["\\A"]); + parameters["\\A_WIDTH"] = GetSize(connections_["\\A"]); } if (connections_.count("\\B")) { @@ -1851,11 +2063,11 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) else if (parameters.count("\\B_SIGNED") == 0) parameters["\\B_SIGNED"] = false; } - parameters["\\B_WIDTH"] = SIZE(connections_["\\B"]); + parameters["\\B_WIDTH"] = GetSize(connections_["\\B"]); } if (connections_.count("\\Y")) - parameters["\\Y_WIDTH"] = SIZE(connections_["\\Y"]); + parameters["\\Y_WIDTH"] = GetSize(connections_["\\Y"]); check(); } @@ -1871,7 +2083,7 @@ RTLIL::SigChunk::SigChunk(const RTLIL::Const &value) { wire = NULL; data = value.bits; - width = SIZE(data); + width = GetSize(data); offset = 0; } @@ -1895,7 +2107,7 @@ RTLIL::SigChunk::SigChunk(const std::string &str) { wire = NULL; data = RTLIL::Const(str).bits; - width = SIZE(data); + width = GetSize(data); offset = 0; } @@ -1903,7 +2115,7 @@ RTLIL::SigChunk::SigChunk(int val, int width) { wire = NULL; data = RTLIL::Const(val, width).bits; - this->width = SIZE(data); + this->width = GetSize(data); offset = 0; } @@ -1911,7 +2123,7 @@ RTLIL::SigChunk::SigChunk(RTLIL::State bit, int width) { wire = NULL; data = RTLIL::Const(bit, width).bits; - this->width = SIZE(data); + this->width = GetSize(data); offset = 0; } @@ -2137,6 +2349,17 @@ RTLIL::SigSpec::SigSpec(std::vector<RTLIL::SigBit> bits) check(); } +RTLIL::SigSpec::SigSpec(pool<RTLIL::SigBit> bits) +{ + cover("kernel.rtlil.sigspec.init.pool_bits"); + + width_ = 0; + hash_ = 0; + for (auto &bit : bits) + append_bit(bit); + check(); +} + RTLIL::SigSpec::SigSpec(std::set<RTLIL::SigBit> bits) { cover("kernel.rtlil.sigspec.init.stdset_bits"); @@ -2148,6 +2371,16 @@ RTLIL::SigSpec::SigSpec(std::set<RTLIL::SigBit> bits) check(); } +RTLIL::SigSpec::SigSpec(bool bit) +{ + cover("kernel.rtlil.sigspec.init.bool"); + + width_ = 0; + hash_ = 0; + append_bit(bit); + check(); +} + void RTLIL::SigSpec::pack() const { RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; @@ -2203,9 +2436,7 @@ void RTLIL::SigSpec::unpack() const that->hash_ = 0; } -#define DJB2(_hash, _value) do { (_hash) = (((_hash) << 5) + (_hash)) + (_value); } while (0) - -void RTLIL::SigSpec::hash() const +void RTLIL::SigSpec::updhash() const { RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; @@ -2215,15 +2446,15 @@ void RTLIL::SigSpec::hash() const cover("kernel.rtlil.sigspec.hash"); that->pack(); - that->hash_ = 5381; + that->hash_ = mkhash_init; for (auto &c : that->chunks_) if (c.wire == NULL) { for (auto &v : c.data) - DJB2(that->hash_, v); + that->hash_ = mkhash(that->hash_, v); } else { - DJB2(that->hash_, c.wire->name.index_); - DJB2(that->hash_, c.offset); - DJB2(that->hash_, c.width); + that->hash_ = mkhash(that->hash_, c.wire->name.index_); + that->hash_ = mkhash(that->hash_, c.offset); + that->hash_ = mkhash(that->hash_, c.width); } if (that->hash_ == 0) @@ -2255,15 +2486,39 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec pattern.unpack(); with.unpack(); - std::map<RTLIL::SigBit, RTLIL::SigBit> rules; + dict<RTLIL::SigBit, RTLIL::SigBit> rules; - for (int i = 0; i < SIZE(pattern.bits_); i++) + for (int i = 0; i < GetSize(pattern.bits_); i++) if (pattern.bits_[i].wire != NULL) rules[pattern.bits_[i]] = with.bits_[i]; replace(rules, other); } +void RTLIL::SigSpec::replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules) +{ + replace(rules, this); +} + +void RTLIL::SigSpec::replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const +{ + cover("kernel.rtlil.sigspec.replace_dict"); + + log_assert(other != NULL); + log_assert(width_ == other->width_); + + unpack(); + other->unpack(); + + for (int i = 0; i < GetSize(bits_); i++) { + auto it = rules.find(bits_[i]); + if (it != rules.end()) + other->bits_[i] = it->second; + } + + other->check(); +} + void RTLIL::SigSpec::replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules) { replace(rules, this); @@ -2271,7 +2526,7 @@ void RTLIL::SigSpec::replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules void RTLIL::SigSpec::replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const { - cover("kernel.rtlil.sigspec.replace"); + cover("kernel.rtlil.sigspec.replace_map"); log_assert(other != NULL); log_assert(width_ == other->width_); @@ -2279,7 +2534,7 @@ void RTLIL::SigSpec::replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules unpack(); other->unpack(); - for (int i = 0; i < SIZE(bits_); i++) { + for (int i = 0; i < GetSize(bits_); i++) { auto it = rules.find(bits_[i]); if (it != rules.end()) other->bits_[i] = it->second; @@ -2301,22 +2556,22 @@ void RTLIL::SigSpec::remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) { - std::set<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_set(); + pool<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_pool(); remove2(pattern_bits, other); } -void RTLIL::SigSpec::remove(const std::set<RTLIL::SigBit> &pattern) +void RTLIL::SigSpec::remove(const pool<RTLIL::SigBit> &pattern) { remove2(pattern, NULL); } -void RTLIL::SigSpec::remove(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const +void RTLIL::SigSpec::remove(const pool<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) +void RTLIL::SigSpec::remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) { if (other) cover("kernel.rtlil.sigspec.remove_other"); @@ -2332,12 +2587,12 @@ void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigS std::vector<RTLIL::SigBit> new_bits, new_other_bits; - new_bits.resize(SIZE(bits_)); + new_bits.resize(GetSize(bits_)); if (other != NULL) - new_other_bits.resize(SIZE(bits_)); + new_other_bits.resize(GetSize(bits_)); int k = 0; - for (int i = 0; i < SIZE(bits_); i++) { + for (int i = 0; i < GetSize(bits_); i++) { if (bits_[i].wire != NULL && pattern.count(bits_[i])) continue; if (other != NULL) @@ -2350,11 +2605,11 @@ void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigS new_other_bits.resize(k); bits_.swap(new_bits); - width_ = SIZE(bits_); + width_ = GetSize(bits_); if (other != NULL) { other->bits_.swap(new_other_bits); - other->width_ = SIZE(other->bits_); + other->width_ = GetSize(other->bits_); } check(); @@ -2362,11 +2617,11 @@ void RTLIL::SigSpec::remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigS RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other) const { - std::set<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_set(); + pool<RTLIL::SigBit> pattern_bits = pattern.to_sigbit_pool(); return extract(pattern_bits, other); } -RTLIL::SigSpec RTLIL::SigSpec::extract(const std::set<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other) const +RTLIL::SigSpec RTLIL::SigSpec::extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other) const { if (other) cover("kernel.rtlil.sigspec.extract_other"); @@ -2417,7 +2672,7 @@ void RTLIL::SigSpec::remove_const() cover("kernel.rtlil.sigspec.remove_const.packed"); std::vector<RTLIL::SigChunk> new_chunks; - new_chunks.reserve(SIZE(chunks_)); + new_chunks.reserve(GetSize(chunks_)); width_ = 0; for (auto &chunk : chunks_) @@ -2539,25 +2794,6 @@ void RTLIL::SigSpec::append_bit(const RTLIL::SigBit &bit) check(); } -void RTLIL::SigSpec::extend(int width, bool is_signed) -{ - cover("kernel.rtlil.sigspec.extend"); - - pack(); - - if (width_ > width) - remove(width, width_ - width); - - 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 (width_ < width) - append(padding); - } -} - void RTLIL::SigSpec::extend_u0(int width, bool is_signed) { cover("kernel.rtlil.sigspec.extend_u0"); @@ -2568,9 +2804,9 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed) remove(width, width_ - width); if (width_ < width) { - RTLIL::SigSpec padding = width_ > 0 ? extract(width_ - 1, 1) : RTLIL::SigSpec(RTLIL::State::S0); + RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::S0; if (!is_signed) - padding = RTLIL::SigSpec(RTLIL::State::S0); + padding = RTLIL::State::S0; while (width_ < width) append(padding); } @@ -2623,7 +2859,7 @@ void RTLIL::SigSpec::check() const { cover("kernel.rtlil.sigspec.check.unpacked"); - log_assert(width_ == SIZE(bits_)); + log_assert(width_ == GetSize(bits_)); log_assert(chunks_.empty()); } } @@ -2645,8 +2881,8 @@ bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const if (chunks_.size() != other.chunks_.size()) return chunks_.size() < other.chunks_.size(); - hash(); - other.hash(); + updhash(); + other.updhash(); if (hash_ != other.hash_) return hash_ < other.hash_; @@ -2677,8 +2913,8 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const if (chunks_.size() != chunks_.size()) return false; - hash(); - other.hash(); + updhash(); + other.updhash(); if (hash_ != other.hash_) return false; @@ -2698,7 +2934,7 @@ bool RTLIL::SigSpec::is_wire() const cover("kernel.rtlil.sigspec.is_wire"); pack(); - return SIZE(chunks_) == 1 && chunks_[0].wire && chunks_[0].wire->width == width_; + return GetSize(chunks_) == 1 && chunks_[0].wire && chunks_[0].wire->width == width_; } bool RTLIL::SigSpec::is_chunk() const @@ -2706,7 +2942,7 @@ bool RTLIL::SigSpec::is_chunk() const cover("kernel.rtlil.sigspec.is_chunk"); pack(); - return SIZE(chunks_) == 1; + return GetSize(chunks_) == 1; } bool RTLIL::SigSpec::is_fully_const() const @@ -2750,6 +2986,17 @@ bool RTLIL::SigSpec::is_fully_undef() const return true; } +bool RTLIL::SigSpec::has_const() const +{ + cover("kernel.rtlil.sigspec.has_const"); + + pack(); + for (auto it = chunks_.begin(); it != chunks_.end(); it++) + if (it->width > 0 && it->wire == NULL) + return true; + return false; +} + bool RTLIL::SigSpec::has_marked_bits() const { cover("kernel.rtlil.sigspec.has_marked_bits"); @@ -2769,7 +3016,7 @@ bool RTLIL::SigSpec::as_bool() const cover("kernel.rtlil.sigspec.as_bool"); pack(); - log_assert(is_fully_const() && SIZE(chunks_) <= 1); + log_assert(is_fully_const() && GetSize(chunks_) <= 1); if (width_) return RTLIL::Const(chunks_[0].data).as_bool(); return false; @@ -2780,7 +3027,7 @@ int RTLIL::SigSpec::as_int(bool is_signed) const cover("kernel.rtlil.sigspec.as_int"); pack(); - log_assert(is_fully_const() && SIZE(chunks_) <= 1); + log_assert(is_fully_const() && GetSize(chunks_) <= 1); if (width_) return RTLIL::Const(chunks_[0].data).as_int(is_signed); return 0; @@ -2808,7 +3055,7 @@ RTLIL::Const RTLIL::SigSpec::as_const() const cover("kernel.rtlil.sigspec.as_const"); pack(); - log_assert(is_fully_const() && SIZE(chunks_) <= 1); + log_assert(is_fully_const() && GetSize(chunks_) <= 1); if (width_) return chunks_[0].data; return RTLIL::Const(); @@ -2867,6 +3114,18 @@ std::set<RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_set() const return sigbits; } +pool<RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_pool() const +{ + cover("kernel.rtlil.sigspec.to_sigbit_pool"); + + pack(); + pool<RTLIL::SigBit> sigbits; + for (auto &c : chunks_) + for (int i = 0; i < c.width; i++) + sigbits.insert(RTLIL::SigBit(c, i)); + return sigbits; +} + std::vector<RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_vector() const { cover("kernel.rtlil.sigspec.to_sigbit_vector"); @@ -2891,6 +3150,22 @@ std::map<RTLIL::SigBit, RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_map(const RTLIL return new_map; } +dict<RTLIL::SigBit, RTLIL::SigBit> RTLIL::SigSpec::to_sigbit_dict(const RTLIL::SigSpec &other) const +{ + cover("kernel.rtlil.sigspec.to_sigbit_dict"); + + unpack(); + other.unpack(); + + log_assert(width_ == other.width_); + + dict<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 { cover("kernel.rtlil.sigspec.to_single_sigbit"); @@ -2934,7 +3209,7 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri if (netname.size() == 0) continue; - if ('0' <= netname[0] && netname[0] <= '9') { + if (('0' <= netname[0] && netname[0] <= '9') || netname[0] == '\'') { cover("kernel.rtlil.sigspec.parse.const"); AST::get_line_num = sigspec_parse_get_dummy_line_num; AST::AstNode *ast = VERILOG_FRONTEND::const2ast(netname); @@ -2979,7 +3254,10 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri sigspec_parse_split(index_tokens, indices.substr(1, indices.size()-2), ':'); if (index_tokens.size() == 1) { cover("kernel.rtlil.sigspec.parse.bit_sel"); - sig.append(RTLIL::SigSpec(wire, atoi(index_tokens.at(0).c_str()))); + int a = atoi(index_tokens.at(0).c_str()); + if (a < 0 || a >= wire->width) + return false; + sig.append(RTLIL::SigSpec(wire, a)); } else { cover("kernel.rtlil.sigspec.parse.part_sel"); int a = atoi(index_tokens.at(0).c_str()); @@ -2988,6 +3266,10 @@ bool RTLIL::SigSpec::parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::stri int tmp = a; a = b, b = tmp; } + if (a < 0 || a >= wire->width) + return false; + if (b < 0 || b >= wire->width) + return false; sig.append(RTLIL::SigSpec(wire, a, b-a+1)); } } else @@ -3033,7 +3315,7 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R if (lhs.chunks_.size() == 1) { char *p = (char*)str.c_str(), *endptr; - long long int val = strtoll(p, &endptr, 10); + long int val = strtol(p, &endptr, 10); if (endptr && endptr != p && *endptr == 0) { sig = RTLIL::SigSpec(val, lhs.width_); cover("kernel.rtlil.sigspec.parse.rhs_dec"); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index a0ae8f082..1d0008f9d 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -76,18 +76,15 @@ namespace RTLIL { // 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 struct destruct_guard_t { + bool ok; // POD, will be initialized to zero + destruct_guard_t() { ok = true; } + ~destruct_guard_t() { ok = false; } + } destruct_guard; 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 dict<char*, int, hash_cstr_ops> global_id_index_; static std::vector<int> global_free_idx_list_; static inline int get_reference(int idx) @@ -98,6 +95,8 @@ namespace RTLIL static inline int get_reference(const char *p) { + log_assert(destruct_guard.ok); + if (p[0]) { log_assert(p[1] != 0); log_assert(p[0] == '$' || p[0] == '\\'); @@ -121,16 +120,38 @@ namespace RTLIL global_id_storage_.at(idx) = strdup(p); global_id_index_[global_id_storage_.at(idx)] = idx; global_refcount_storage_.at(idx)++; + + // Avoid Create->Delete->Create pattern + static IdString last_created_id; + put_reference(last_created_id.index_); + last_created_id.index_ = idx; + get_reference(last_created_id.index_); + + if (yosys_xtrace) { + log("#X# New IdString '%s' with index %d.\n", p, idx); + log_backtrace("-X- ", yosys_xtrace-1); + } + return idx; } static inline void put_reference(int idx) { + // put_reference() may be called from destructors after the destructor of + // global_refcount_storage_ has been run. in this case we simply do nothing. + if (!destruct_guard.ok) + return; + log_assert(global_refcount_storage_.at(idx) > 0); if (--global_refcount_storage_.at(idx) != 0) return; + if (yosys_xtrace) { + log("#X# Removed IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx); + log_backtrace("-X- ", yosys_xtrace-1); + } + global_id_index_.erase(global_id_storage_.at(idx)); free(global_id_storage_.at(idx)); global_id_storage_.at(idx) = nullptr; @@ -211,12 +232,16 @@ namespace RTLIL *this = IdString(); } + unsigned int hash() const { + return index_; + } + // 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) { + bool operator()(const T *a, const T *b) const { return (a == nullptr || b == nullptr) ? (a < b) : (a->name < b->name); } }; @@ -225,14 +250,14 @@ namespace RTLIL // of cell types). the following functions helps with that. template<typename T, typename... Args> - bool in(T first, Args... rest) { + bool in(T first, Args... rest) const { 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; } + bool in(IdString rhs) const { return *this == rhs; } + bool in(const char *rhs) const { return *this == rhs; } + bool in(const std::string &rhs) const { return *this == rhs; } + bool in(const pool<IdString> &rhs) const { return rhs.count(*this) != 0; } }; static inline std::string escape_id(std::string str) { @@ -242,9 +267,15 @@ namespace RTLIL } static inline std::string unescape_id(std::string str) { - if (str.size() > 1 && str[0] == '\\' && str[1] != '$') - return str.substr(1); - return str; + if (str.size() < 2) + return str; + if (str[0] != '\\') + return str; + if (str[1] == '$' || str[1] == '\\') + return str; + if (str[1] >= '0' && str[1] <= '9') + return str; + return str.substr(1); } static inline std::string unescape_id(RTLIL::IdString str) { @@ -323,8 +354,8 @@ namespace RTLIL template<typename T> struct ObjIterator { - typename std::map<RTLIL::IdString, T>::iterator it; - std::map<RTLIL::IdString, T> *list_p; + typename dict<RTLIL::IdString, T>::iterator it; + dict<RTLIL::IdString, T> *list_p; int *refcount_p; ObjIterator() : list_p(nullptr), refcount_p(nullptr) { @@ -388,7 +419,7 @@ namespace RTLIL template<typename T> struct ObjRange { - std::map<RTLIL::IdString, T> *list_p; + dict<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) { } @@ -399,8 +430,8 @@ namespace RTLIL return list_p->size(); } - operator std::set<T>() const { - std::set<T> result; + operator pool<T>() const { + pool<T> result; for (auto &it : *list_p) result.insert(it.second); return result; @@ -414,7 +445,7 @@ namespace RTLIL return result; } - std::set<T> to_set() const { return *this; } + pool<T> to_pool() const { return *this; } std::vector<T> to_vector() const { return *this; } }; }; @@ -438,17 +469,249 @@ struct RTLIL::Const bool as_bool() const; int as_int(bool is_signed = false) const; std::string as_string() const; + static Const from_string(std::string str); std::string decode_string() const; inline int size() const { return bits.size(); } + + inline unsigned int hash() const { + unsigned int h = mkhash_init; + for (auto b : bits) + mkhash(h, b); + return h; + } +}; + +struct RTLIL::SigChunk +{ + RTLIL::Wire *wire; + std::vector<RTLIL::State> data; // only used if wire == NULL, LSB at index 0 + int width, offset; + + SigChunk(); + 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; +}; + +struct RTLIL::SigBit +{ + RTLIL::Wire *wire; + union { + RTLIL::State data; // used if wire == NULL + int offset; // used if wire != NULL + }; + + SigBit(); + SigBit(RTLIL::State bit); + SigBit(bool bit); + SigBit(RTLIL::Wire *wire); + SigBit(RTLIL::Wire *wire, int offset); + SigBit(const RTLIL::SigChunk &chunk); + SigBit(const RTLIL::SigChunk &chunk, int index); + SigBit(const RTLIL::SigSpec &sig); + + bool operator <(const RTLIL::SigBit &other) const; + bool operator ==(const RTLIL::SigBit &other) const; + bool operator !=(const RTLIL::SigBit &other) const; + unsigned int hash() const; +}; + +struct RTLIL::SigSpecIterator : public std::iterator<std::input_iterator_tag, RTLIL::SigSpec> +{ + RTLIL::SigSpec *sig_p; + int index; + + inline RTLIL::SigBit &operator*() const; + inline bool operator!=(const RTLIL::SigSpecIterator &other) const { return index != other.index; } + inline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; } + inline void operator++() { index++; } +}; + +struct RTLIL::SigSpecConstIterator : public std::iterator<std::input_iterator_tag, RTLIL::SigSpec> +{ + 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 bool operator==(const RTLIL::SigSpecIterator &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 updhash() const; + + inline bool packed() const { + return bits_.empty(); + } + + inline void inline_unpack() const { + if (!chunks_.empty()) + unpack(); + } + +public: + SigSpec(); + 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); + 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); + SigSpec(pool<RTLIL::SigBit> bits); + SigSpec(std::set<RTLIL::SigBit> bits); + SigSpec(bool bit); + + 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; + } + + size_t get_hash() const { + if (!hash_) hash(); + return hash_; + } + + 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 bool empty() const { return width_ == 0; } + + 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 dict<RTLIL::SigBit, RTLIL::SigBit> &rules); + void replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules, 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); + + void remove(const pool<RTLIL::SigBit> &pattern); + void remove(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const; + void remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other); + + void remove(int offset, int length = 1); + void remove_const(); + + RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const; + RTLIL::SigSpec extract(const pool<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); + + void extend_u0(int width, bool is_signed = false); + + RTLIL::SigSpec repeat(int num) 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_const() const; + bool has_marked_bits() const; + + bool as_bool() 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; + pool<RTLIL::SigBit> to_sigbit_pool() const; + std::vector<RTLIL::SigBit> to_sigbit_vector() const; + std::map<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_map(const RTLIL::SigSpec &other) const; + dict<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_dict(const RTLIL::SigSpec &other) const; + RTLIL::SigBit to_single_sigbit() const; + + static bool parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str); + static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str); + 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(); } + + unsigned int hash() const { if (!hash_) updhash(); return hash_; }; + +#ifndef NDEBUG + void check() const; +#else + void check() const { } +#endif }; struct RTLIL::Selection { bool full_selection; - std::set<RTLIL::IdString> selected_modules; - std::map<RTLIL::IdString, std::set<RTLIL::IdString>> selected_members; + pool<RTLIL::IdString> selected_modules; + dict<RTLIL::IdString, pool<RTLIL::IdString>> selected_members; Selection(bool full = true) : full_selection(full) { } @@ -476,6 +739,15 @@ struct RTLIL::Selection struct RTLIL::Monitor { + unsigned int hashidx_; + unsigned int hash() const { return hashidx_; } + + Monitor() { + static unsigned int hashidx_count = 123456789; + hashidx_count = mkhash_xorshift(hashidx_count); + hashidx_ = hashidx_count; + } + virtual ~Monitor() { } virtual void notify_module_add(RTLIL::Module*) { } virtual void notify_module_del(RTLIL::Module*) { } @@ -487,14 +759,17 @@ struct RTLIL::Monitor struct RTLIL::Design { - std::set<RTLIL::Monitor*> monitors; - std::map<std::string, std::string> scratchpad; + unsigned int hashidx_; + unsigned int hash() const { return hashidx_; } + + pool<RTLIL::Monitor*> monitors; + dict<std::string, std::string> scratchpad; int refcount_modules_; - std::map<RTLIL::IdString, RTLIL::Module*> modules_; + dict<RTLIL::IdString, RTLIL::Module*> modules_; std::vector<RTLIL::Selection> selection_stack; - std::map<RTLIL::IdString, RTLIL::Selection> selection_vars; + dict<RTLIL::IdString, RTLIL::Selection> selection_vars; std::string selected_active_module; Design(); @@ -521,6 +796,7 @@ struct RTLIL::Design 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 sort(); void check(); void optimize(); @@ -531,6 +807,14 @@ struct RTLIL::Design bool selected_module(RTLIL::Module *mod) const; bool selected_whole_module(RTLIL::Module *mod) const; + RTLIL::Selection &selection() { + return selection_stack.back(); + } + + const RTLIL::Selection &selection() const { + return selection_stack.back(); + } + bool full_selection() const { return selection_stack.back().full_selection; } @@ -556,7 +840,7 @@ struct RTLIL::Design }; #define RTLIL_ATTRIBUTE_MEMBERS \ - std::map<RTLIL::IdString, RTLIL::Const> attributes; \ + dict<RTLIL::IdString, RTLIL::Const> attributes; \ void set_bool_attribute(RTLIL::IdString id) { \ attributes[id] = RTLIL::Const(1); \ } \ @@ -568,31 +852,36 @@ struct RTLIL::Design struct RTLIL::Module { + unsigned int hashidx_; + unsigned int hash() const { return hashidx_; } + protected: void add(RTLIL::Wire *wire); void add(RTLIL::Cell *cell); public: RTLIL::Design *design; - std::set<RTLIL::Monitor*> monitors; + pool<RTLIL::Monitor*> monitors; int refcount_wires_; int refcount_cells_; - std::map<RTLIL::IdString, RTLIL::Wire*> wires_; - std::map<RTLIL::IdString, RTLIL::Cell*> cells_; + dict<RTLIL::IdString, RTLIL::Wire*> wires_; + dict<RTLIL::IdString, RTLIL::Cell*> cells_; std::vector<RTLIL::SigSig> connections_; RTLIL::IdString name; - std::set<RTLIL::IdString> avail_parameters; - std::map<RTLIL::IdString, RTLIL::Memory*> memories; - std::map<RTLIL::IdString, RTLIL::Process*> processes; + pool<RTLIL::IdString> avail_parameters; + dict<RTLIL::IdString, RTLIL::Memory*> memories; + dict<RTLIL::IdString, RTLIL::Process*> processes; RTLIL_ATTRIBUTE_MEMBERS Module(); virtual ~Module(); - virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters); + virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters); virtual size_t count_id(RTLIL::IdString id); + + virtual void sort(); virtual void check(); virtual void optimize(); @@ -628,7 +917,7 @@ public: 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(const pool<RTLIL::Wire*> &wires); void remove(RTLIL::Cell *cell); void rename(RTLIL::Wire *wire, RTLIL::IdString new_name); @@ -698,9 +987,11 @@ public: 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* addEquiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y); 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* addDffe (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool en_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, @@ -723,6 +1014,7 @@ public: 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* addDffeGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool en_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, @@ -795,6 +1087,9 @@ public: struct RTLIL::Wire { + unsigned int hashidx_; + unsigned int hash() const { return hashidx_; } + protected: // use module->addWire() and module->remove() to create or destroy wires friend struct RTLIL::Module; @@ -815,6 +1110,9 @@ public: struct RTLIL::Memory { + unsigned int hashidx_; + unsigned int hash() const { return hashidx_; } + Memory(); RTLIL::IdString name; @@ -824,6 +1122,9 @@ struct RTLIL::Memory struct RTLIL::Cell { + unsigned int hashidx_; + unsigned int hash() const { return hashidx_; } + protected: // use module->addCell() and module->remove() to create or destroy cells friend struct RTLIL::Module; @@ -837,8 +1138,8 @@ public: RTLIL::Module *module; RTLIL::IdString name; RTLIL::IdString type; - std::map<RTLIL::IdString, RTLIL::SigSpec> connections_; - std::map<RTLIL::IdString, RTLIL::Const> parameters; + dict<RTLIL::IdString, RTLIL::SigSpec> connections_; + dict<RTLIL::IdString, RTLIL::Const> parameters; RTLIL_ATTRIBUTE_MEMBERS // access cell ports @@ -846,7 +1147,12 @@ public: 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; + const dict<RTLIL::IdString, RTLIL::SigSpec> &connections() const; + + // information about cell ports + bool known() const; + bool input(RTLIL::IdString portname) const; + bool output(RTLIL::IdString portname) const; // access cell parameters bool hasParam(RTLIL::IdString paramname) const; @@ -854,242 +1160,18 @@ public: void setParam(RTLIL::IdString paramname, RTLIL::Const value); const RTLIL::Const &getParam(RTLIL::IdString paramname) const; + void sort(); 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 -{ - RTLIL::Wire *wire; - std::vector<RTLIL::State> data; // only used if wire == NULL, LSB at index 0 - int width, offset; - - SigChunk(); - 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; -}; - -struct RTLIL::SigBit -{ - RTLIL::Wire *wire; - 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 { - 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)); + bool has_keep_attr() const { + return get_bool_attribute("\\keep") || (module && module->design && module->design->module(type) && + module->design->module(type)->get_bool_attribute("\\keep")); } -}; - -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::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); - 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); - 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); - - 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(); - - 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); - - void extend(int width, bool is_signed = false); - void extend_u0(int width, bool is_signed = false); - - RTLIL::SigSpec repeat(int num) 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(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 + template<typename T> void rewrite_sigspecs(T functor); }; -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) { - log_assert(sig.size() == 1 && sig.chunks().size() == 1); - *this = SigBit(sig.chunks().front()); -} - struct RTLIL::CaseRule { std::vector<RTLIL::SigSpec> compare; @@ -1138,6 +1220,50 @@ struct RTLIL::Process RTLIL::Process *clone() const; }; + +inline RTLIL::SigBit::SigBit() : wire(NULL), data(RTLIL::State::S0) { } +inline RTLIL::SigBit::SigBit(RTLIL::State bit) : wire(NULL), data(bit) { } +inline RTLIL::SigBit::SigBit(bool bit) : wire(NULL), data(bit ? RTLIL::S1 : RTLIL::S0) { } +inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_assert(wire && wire->width == 1); } +inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); } +inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; } +inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; } + +inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const { + 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; +} + +inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const { + return (wire == other.wire) && (wire ? (offset == other.offset) : (data == other.data)); +} + +inline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const { + return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data)); +} + +inline unsigned int RTLIL::SigBit::hash() const { + if (wire) + return mkhash_add(wire->name.hash(), offset); + return data; +} + +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) { + log_assert(sig.size() == 1 && sig.chunks().size() == 1); + *this = SigBit(sig.chunks().front()); +} + template<typename T> void RTLIL::Module::rewrite_sigspecs(T functor) { diff --git a/kernel/satgen.h b/kernel/satgen.h index 692c6e7fb..719b0a83a 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -26,7 +26,40 @@ #include "kernel/macc.h" #include "libs/ezsat/ezminisat.h" -typedef ezMiniSAT ezDefaultSAT; + +YOSYS_NAMESPACE_BEGIN + +// defined in kernel/register.cc +extern struct SatSolver *yosys_satsolver_list; +extern struct SatSolver *yosys_satsolver; + +struct SatSolver +{ + string name; + SatSolver *next; + virtual ezSAT *create() = 0; + + SatSolver(string name) : name(name) { + next = yosys_satsolver_list; + yosys_satsolver_list = this; + } + + virtual ~SatSolver() { + auto p = &yosys_satsolver_list; + while (*p) { + if (*p == this) + *p = next; + else + p = &(*p)->next; + } + if (yosys_satsolver == this) + yosys_satsolver = yosys_satsolver_list; + } +}; + +struct ezSatPtr : public std::unique_ptr<ezSAT> { + ezSatPtr() : unique_ptr<ezSAT>(yosys_satsolver->create()) { } +}; struct SatGen { @@ -35,6 +68,8 @@ struct SatGen std::string prefix; SigPool initial_state; std::map<std::string, RTLIL::SigSpec> asserts_a, asserts_en; + std::map<std::string, RTLIL::SigSpec> assumes_a, assumes_en; + std::map<std::string, std::map<RTLIL::SigBit, int>> imported_signals; bool ignore_div_by_zero; bool model_undef; @@ -49,23 +84,24 @@ struct SatGen this->prefix = prefix; } - std::vector<int> importSigSpecWorker(RTLIL::SigSpec &sig, std::string &pf, bool undef_mode, bool dup_undef) + std::vector<int> importSigSpecWorker(RTLIL::SigSpec sig, std::string &pf, bool undef_mode, bool dup_undef) { log_assert(!undef_mode || model_undef); sigmap->apply(sig); std::vector<int> vec; - vec.reserve(SIZE(sig)); + vec.reserve(GetSize(sig)); for (auto &bit : sig) if (bit.wire == NULL) { if (model_undef && dup_undef && bit == RTLIL::State::Sx) vec.push_back(ez->frozen_literal()); else - vec.push_back(bit == (undef_mode ? RTLIL::State::Sx : RTLIL::State::S1) ? ez->TRUE : ez->FALSE); + vec.push_back(bit == (undef_mode ? RTLIL::State::Sx : RTLIL::State::S1) ? ez->CONST_TRUE : ez->CONST_FALSE); } else { - std::string name = pf + stringf(bit.wire->width == 1 ? "%s" : "%s [%d]", RTLIL::id2cstr(bit.wire->name), bit.offset); + std::string name = pf + (bit.wire->width == 1 ? stringf("%s", log_id(bit.wire)) : stringf("%s [%d]", log_id(bit.wire->name), bit.offset)); vec.push_back(ez->frozen_literal(name)); + imported_signals[pf][bit] = vec.back(); } return vec; } @@ -91,6 +127,34 @@ struct SatGen return importSigSpecWorker(sig, pf, true, false); } + int importSigBit(RTLIL::SigBit bit, int timestep = -1) + { + log_assert(timestep != 0); + std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); + return importSigSpecWorker(bit, pf, false, false).front(); + } + + int importDefSigBit(RTLIL::SigBit bit, int timestep = -1) + { + log_assert(timestep != 0); + std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); + return importSigSpecWorker(bit, pf, false, true).front(); + } + + int importUndefSigBit(RTLIL::SigBit bit, int timestep = -1) + { + log_assert(timestep != 0); + std::string pf = "undef:" + prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); + return importSigSpecWorker(bit, pf, true, false).front(); + } + + bool importedSigBit(RTLIL::SigBit bit, int timestep = -1) + { + log_assert(timestep != 0); + std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); + return imported_signals[pf].count(bit) != 0; + } + void getAsserts(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1) { std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); @@ -98,6 +162,13 @@ struct SatGen sig_en = asserts_en[pf]; } + void getAssumes(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1) + { + std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); + sig_a = assumes_a[pf]; + sig_en = assumes_en[pf]; + } + int importAsserts(int timestep = -1) { std::vector<int> check_bits, enable_bits; @@ -112,6 +183,20 @@ struct SatGen return ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits))); } + int importAssumes(int timestep = -1) + { + std::vector<int> check_bits, enable_bits; + std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); + if (model_undef) { + check_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_a[pf], timestep)), importDefSigSpec(assumes_a[pf], timestep)); + enable_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_en[pf], timestep)), importDefSigSpec(assumes_en[pf], timestep)); + } else { + check_bits = importDefSigSpec(assumes_a[pf], timestep); + enable_bits = importDefSigSpec(assumes_en[pf], timestep); + } + return ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits))); + } + int signals_eq(RTLIL::SigSpec lhs, RTLIL::SigSpec rhs, int timestep_lhs = -1, int timestep_rhs = -1) { if (timestep_rhs < 0) @@ -141,9 +226,9 @@ struct SatGen if (!forced_signed && cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters.count("\\B_SIGNED") > 0) is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool(); while (vec_a.size() < vec_b.size() || vec_a.size() < y_width) - vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->FALSE); + vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE); while (vec_b.size() < vec_a.size() || vec_b.size() < y_width) - vec_b.push_back(is_signed && vec_b.size() > 0 ? vec_b.back() : ez->FALSE); + vec_b.push_back(is_signed && vec_b.size() > 0 ? vec_b.back() : ez->CONST_FALSE); } void extendSignalWidth(std::vector<int> &vec_a, std::vector<int> &vec_b, std::vector<int> &vec_y, RTLIL::Cell *cell, bool forced_signed = false) @@ -157,7 +242,7 @@ struct SatGen { bool is_signed = forced_signed || (cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool()); while (vec_a.size() < vec_y.size()) - vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->FALSE); + vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE); while (vec_y.size() < vec_a.size()) vec_y.push_back(ez->literal()); } @@ -207,7 +292,7 @@ struct SatGen if (is_arith_compare) { for (size_t i = 1; i < undef_y.size(); i++) - ez->SET(ez->FALSE, undef_y.at(i)); + ez->SET(ez->CONST_FALSE, undef_y.at(i)); ez->SET(undef_y_bit, undef_y.at(0)); } else { std::vector<int> undef_y_bits(undef_y.size(), undef_y_bit); @@ -288,7 +373,7 @@ struct SatGen 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 d = three_mode ? (aoi_mode ? ez->CONST_TRUE : ez->CONST_FALSE) : importDefSigSpec(cell->getPort("\\D"), timestep).at(0); int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0); int yy = model_undef ? ez->literal() : y; @@ -302,7 +387,7 @@ struct SatGen 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_d = three_mode ? ez->CONST_FALSE : importUndefSigSpec(cell->getPort("\\D"), timestep).at(0); int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0); if (aoi_mode) @@ -414,14 +499,14 @@ struct SatGen 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; + int maybe_one_hot = ez->CONST_FALSE; + int maybe_many_hot = ez->CONST_FALSE; - int sure_one_hot = ez->FALSE; - int sure_many_hot = ez->FALSE; + int sure_one_hot = ez->CONST_FALSE; + int sure_many_hot = ez->CONST_FALSE; - std::vector<int> bits_set = std::vector<int>(undef_y.size(), ez->FALSE); - std::vector<int> bits_clr = std::vector<int>(undef_y.size(), ez->FALSE); + std::vector<int> bits_set = std::vector<int>(undef_y.size(), ez->CONST_FALSE); + std::vector<int> bits_clr = std::vector<int>(undef_y.size(), ez->CONST_FALSE); for (size_t i = 0; i < s.size(); i++) { @@ -463,7 +548,7 @@ struct SatGen if (cell->type == "$pos") { ez->assume(ez->vec_eq(a, yy)); } else { - std::vector<int> zero(a.size(), ez->FALSE); + std::vector<int> zero(a.size(), ez->CONST_FALSE); ez->assume(ez->vec_eq(ez->vec_sub(zero, a), yy)); } @@ -505,7 +590,7 @@ struct SatGen if (cell->type == "$logic_not") ez->SET(ez->NOT(ez->expression(ez->OpOr, a)), yy.at(0)); for (size_t i = 1; i < y.size(); i++) - ez->SET(ez->FALSE, yy.at(i)); + ez->SET(ez->CONST_FALSE, yy.at(i)); if (model_undef) { @@ -527,7 +612,7 @@ struct SatGen log_abort(); for (size_t i = 1; i < undef_y.size(); i++) - ez->SET(ez->FALSE, undef_y.at(i)); + ez->SET(ez->CONST_FALSE, undef_y.at(i)); undefGating(y, yy, undef_y); } @@ -550,7 +635,7 @@ struct SatGen else ez->SET(ez->expression(ez->OpOr, a, b), yy.at(0)); for (size_t i = 1; i < y.size(); i++) - ez->SET(ez->FALSE, yy.at(i)); + ez->SET(ez->CONST_FALSE, yy.at(i)); if (model_undef) { @@ -573,7 +658,7 @@ struct SatGen log_abort(); for (size_t i = 1; i < undef_y.size(); i++) - ez->SET(ez->FALSE, undef_y.at(i)); + ez->SET(ez->CONST_FALSE, undef_y.at(i)); undefGating(y, yy, undef_y); } @@ -611,7 +696,7 @@ struct SatGen if (cell->type == "$gt") ez->SET(is_signed ? ez->vec_gt_signed(a, b) : ez->vec_gt_unsigned(a, b), yy.at(0)); for (size_t i = 1; i < y.size(); i++) - ez->SET(ez->FALSE, yy.at(i)); + ez->SET(ez->CONST_FALSE, yy.at(i)); if (model_undef && (cell->type == "$eqx" || cell->type == "$nex")) { @@ -626,7 +711,7 @@ struct SatGen yy.at(0) = ez->OR(yy.at(0), ez->vec_ne(undef_a, undef_b)); for (size_t i = 0; i < y.size(); i++) - ez->SET(ez->FALSE, undef_y.at(i)); + ez->SET(ez->CONST_FALSE, undef_y.at(i)); ez->assume(ez->vec_eq(y, yy)); } @@ -648,7 +733,7 @@ struct SatGen int undef_y_bit = ez->AND(undef_any, ez->NOT(masked_ne)); for (size_t i = 1; i < undef_y.size(); i++) - ez->SET(ez->FALSE, undef_y.at(i)); + ez->SET(ez->CONST_FALSE, undef_y.at(i)); ez->SET(undef_y_bit, undef_y.at(0)); undefGating(y, yy, undef_y); @@ -670,7 +755,7 @@ struct SatGen std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); - int extend_bit = ez->FALSE; + int extend_bit = ez->CONST_FALSE; if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool()) extend_bit = a.back(); @@ -684,16 +769,16 @@ struct SatGen std::vector<int> shifted_a; if (cell->type == "$shl" || cell->type == "$sshl") - shifted_a = ez->vec_shift_left(a, b, false, ez->FALSE, ez->FALSE); + shifted_a = ez->vec_shift_left(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); if (cell->type == "$shr") - shifted_a = ez->vec_shift_right(a, b, false, ez->FALSE, ez->FALSE); + shifted_a = ez->vec_shift_right(a, b, false, ez->CONST_FALSE, ez->CONST_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); + shifted_a = ez->vec_shift_right(a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->CONST_FALSE, ez->CONST_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); + shifted_a = ez->vec_shift_right(a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE); ez->assume(ez->vec_eq(shifted_a, yy)); @@ -704,7 +789,7 @@ struct SatGen 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; + extend_bit = cell->type == "$shiftx" ? ez->CONST_TRUE : ez->CONST_FALSE; if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool()) extend_bit = undef_a.back(); @@ -714,19 +799,19 @@ struct SatGen undef_a.push_back(extend_bit); if (cell->type == "$shl" || cell->type == "$sshl") - undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->FALSE, ez->FALSE); + undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); if (cell->type == "$shr") - undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->FALSE, ez->FALSE); + undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->CONST_FALSE, ez->CONST_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); + undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? undef_a.back() : ez->CONST_FALSE, ez->CONST_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); + undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_FALSE, ez->CONST_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); + undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_TRUE, ez->CONST_TRUE); int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); std::vector<int> undef_all_y_bits(undef_y.size(), undef_any_b); @@ -745,10 +830,10 @@ struct SatGen std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; - std::vector<int> tmp(a.size(), ez->FALSE); + std::vector<int> tmp(a.size(), ez->CONST_FALSE); for (int i = 0; i < int(a.size()); i++) { - std::vector<int> shifted_a(a.size(), ez->FALSE); + std::vector<int> shifted_a(a.size(), ez->CONST_FALSE); for (int j = i; j < int(a.size()); j++) shifted_a.at(j) = a.at(j-i); tmp = ez->vec_ite(b.at(i), ez->vec_add(tmp, shifted_a), tmp); @@ -772,25 +857,25 @@ struct SatGen Macc macc; macc.from_cell(cell); - std::vector<int> tmp(SIZE(y), ez->FALSE); + std::vector<int> tmp(GetSize(y), ez->CONST_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)); + while (GetSize(in_a) < GetSize(y)) + in_a.push_back(port.is_signed && !in_a.empty() ? in_a.back() : ez->CONST_FALSE); + in_a.resize(GetSize(y)); - if (SIZE(in_b)) + if (GetSize(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)); + while (GetSize(in_b) < GetSize(y)) + in_b.push_back(port.is_signed && !in_b.empty() ? in_b.back() : ez->CONST_FALSE); + in_b.resize(GetSize(y)); - for (int i = 0; i < SIZE(in_b); i++) { - std::vector<int> shifted_a(in_a.size(), ez->FALSE); + for (int i = 0; i < GetSize(in_b); i++) { + std::vector<int> shifted_a(in_a.size(), ez->CONST_FALSE); for (int j = i; j < int(in_a.size()); j++) shifted_a.at(j) = in_a.at(j-i); if (port.do_subtract) @@ -808,8 +893,8 @@ struct SatGen } } - for (int i = 0; i < SIZE(b); i++) { - std::vector<int> val(SIZE(y), ez->FALSE); + for (int i = 0; i < GetSize(b); i++) { + std::vector<int> val(GetSize(y), ez->CONST_FALSE); val.at(0) = b.at(i); tmp = ez->vec_add(tmp, val); } @@ -823,7 +908,7 @@ struct SatGen 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)))); + ez->assume(ez->vec_eq(undef_y, std::vector<int>(GetSize(y), ez->OR(undef_any_a, undef_any_b)))); undefGating(y, tmp, undef_y); } @@ -852,14 +937,14 @@ struct SatGen } std::vector<int> chain_buf = a_u; - std::vector<int> y_u(a_u.size(), ez->FALSE); + std::vector<int> y_u(a_u.size(), ez->CONST_FALSE); for (int i = int(a.size())-1; i >= 0; i--) { - chain_buf.insert(chain_buf.end(), chain_buf.size(), ez->FALSE); + chain_buf.insert(chain_buf.end(), chain_buf.size(), ez->CONST_FALSE); - std::vector<int> b_shl(i, ez->FALSE); + std::vector<int> b_shl(i, ez->CONST_FALSE); b_shl.insert(b_shl.end(), b_u.begin(), b_u.end()); - b_shl.insert(b_shl.end(), chain_buf.size()-b_shl.size(), ez->FALSE); + b_shl.insert(b_shl.end(), chain_buf.size()-b_shl.size(), ez->CONST_FALSE); y_u.at(i) = ez->vec_ge_unsigned(chain_buf, b_shl); chain_buf = ez->vec_ite(y_u.at(i), ez->vec_sub(chain_buf, b_shl), chain_buf); @@ -886,13 +971,13 @@ struct SatGen std::vector<int> div_zero_result; if (cell->type == "$div") { if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) { - std::vector<int> all_ones(y.size(), ez->TRUE); - std::vector<int> only_first_one(y.size(), ez->FALSE); - only_first_one.at(0) = ez->TRUE; + std::vector<int> all_ones(y.size(), ez->CONST_TRUE); + std::vector<int> only_first_one(y.size(), ez->CONST_FALSE); + only_first_one.at(0) = ez->CONST_TRUE; div_zero_result = ez->vec_ite(a.back(), only_first_one, all_ones); } else { - div_zero_result.insert(div_zero_result.end(), cell->getPort("\\A").size(), ez->TRUE); - div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->FALSE); + div_zero_result.insert(div_zero_result.end(), cell->getPort("\\A").size(), ez->CONST_TRUE); + div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); } } else { int copy_a_bits = std::min(cell->getPort("\\A").size(), cell->getPort("\\B").size()); @@ -900,7 +985,7 @@ struct SatGen 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()); else - div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->FALSE); + div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); } ez->assume(ez->vec_eq(yy, ez->vec_ite(ez->expression(ezSAT::OpOr, b), y_tmp, div_zero_result))); } @@ -920,44 +1005,44 @@ struct SatGen 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)); + lut.push_back(bit == RTLIL::S1 ? ez->CONST_TRUE : ez->CONST_FALSE); + while (GetSize(lut) < (1 << GetSize(a))) + lut.push_back(ez->CONST_FALSE); + lut.resize(1 << GetSize(a)); if (model_undef) { std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> t(lut), u(SIZE(t), ez->FALSE); + std::vector<int> t(lut), u(GetSize(t), ez->CONST_FALSE); - for (int i = SIZE(a)-1; i >= 0; i--) + for (int i = GetSize(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> t0(t.begin(), t.begin() + GetSize(t)/2); + std::vector<int> t1(t.begin() + GetSize(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()); + std::vector<int> u0(u.begin(), u.begin() + GetSize(u)/2); + std::vector<int> u1(u.begin() + GetSize(u)/2, u.end()); t = ez->vec_ite(a[i], t1, t0); u = ez->vec_ite(undef_a[i], ez->vec_or(ez->vec_xor(t0, t1), ez->vec_or(u0, u1)), ez->vec_ite(a[i], u1, u0)); } - log_assert(SIZE(t) == 1); - log_assert(SIZE(u) == 1); + log_assert(GetSize(t) == 1); + log_assert(GetSize(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--) + for (int i = GetSize(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> t0(t.begin(), t.begin() + GetSize(t)/2); + std::vector<int> t1(t.begin() + GetSize(t)/2, t.end()); t = ez->vec_ite(a[i], t1, t0); } - log_assert(SIZE(t) == 1); + log_assert(GetSize(t) == 1); ez->assume(ez->vec_eq(y, t)); } return true; @@ -1008,7 +1093,7 @@ struct SatGen std::vector<int> yy = model_undef ? ez->vec_var(co.size()) : co; - for (int i = 0; i < SIZE(co); i++) + for (int i = 0; i < GetSize(co); i++) ez->SET(yy[i], ez->OR(g[i], ez->AND(p[i], i ? yy[i-1] : ci[0]))); if (model_undef) @@ -1049,12 +1134,12 @@ struct SatGen 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); + log_assert(GetSize(y) == GetSize(x)); + log_assert(GetSize(y) == GetSize(co)); + log_assert(GetSize(ci) == 1); + log_assert(GetSize(bi) == 1); - for (int i = 0; i < SIZE(y); i++) + for (int i = 0; i < GetSize(y); i++) { int s1 = a.at(i), s2 = ez->XOR(b.at(i), bi.at(0)), s3 = i ? co.at(i-1) : ci.at(0); ez->SET(def_x.at(i), ez->XOR(s1, s2)); @@ -1084,7 +1169,7 @@ struct SatGen 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++) { + for (int i = 0; i < GetSize(undef_y); i++) { ez->SET(undef_y.at(i), undef_any); ez->SET(undef_x.at(i), ez->OR(undef_a.at(i), undef_b.at(i), undef_bi.at(0))); ez->SET(undef_co.at(i), undef_any); @@ -1144,6 +1229,25 @@ struct SatGen return true; } + if (cell->type == "$_BUF_" || cell->type == "$equiv") + { + 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(a, yy)); + + if (model_undef) { + 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); + } + return true; + } + if (cell->type == "$assert") { std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); @@ -1152,10 +1256,20 @@ struct SatGen return true; } + if (cell->type == "$assume") + { + std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); + assumes_a[pf].append((*sigmap)(cell->getPort("\\A"))); + assumes_en[pf].append((*sigmap)(cell->getPort("\\EN"))); + return true; + } + // Unsupported internal cell types: $pow $lut // .. and all sequential cells except $dff and $_DFF_[NP]_ return false; } }; +YOSYS_NAMESPACE_END + #endif diff --git a/kernel/sigtools.h b/kernel/sigtools.h index 32ef444aa..f92a87dbb 100644 --- a/kernel/sigtools.h +++ b/kernel/sigtools.h @@ -29,9 +29,10 @@ struct SigPool struct bitDef_t : public std::pair<RTLIL::Wire*, int> { bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { } + unsigned int hash() const { return first->name.hash() + second; } }; - std::set<bitDef_t> bits; + pool<bitDef_t> bits; void clear() { @@ -66,8 +67,8 @@ struct SigPool void expand(RTLIL::SigSpec from, RTLIL::SigSpec to) { - log_assert(SIZE(from) == SIZE(to)); - for (int i = 0; i < SIZE(from); i++) { + log_assert(GetSize(from) == GetSize(to)); + for (int i = 0; i < GetSize(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); @@ -122,13 +123,13 @@ struct SigPool RTLIL::SigSpec export_all() { - std::set<RTLIL::SigBit> sig; + pool<RTLIL::SigBit> sig; for (auto &bit : bits) sig.insert(RTLIL::SigBit(bit.first, bit.second)); return sig; } - size_t size() + size_t size() const { return bits.size(); } @@ -140,9 +141,10 @@ struct SigSet struct bitDef_t : public std::pair<RTLIL::Wire*, int> { bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { } + unsigned int hash() const { return first->name.hash() + second; } }; - std::map<bitDef_t, std::set<T, Compare>> bits; + dict<bitDef_t, std::set<T, Compare>> bits; void clear() { @@ -193,6 +195,15 @@ struct SigSet } } + void find(RTLIL::SigSpec sig, pool<T> &result) + { + 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) { std::set<T> result; @@ -214,6 +225,7 @@ struct SigMap struct bitDef_t : public std::pair<RTLIL::Wire*, int> { bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { } + unsigned int hash() const { return first->name.hash() + second; } }; struct shared_bit_data_t { @@ -221,7 +233,7 @@ struct SigMap std::set<bitDef_t> bits; }; - std::map<bitDef_t, shared_bit_data_t*> bits; + dict<bitDef_t, shared_bit_data_t*> bits; SigMap(RTLIL::Module *module = NULL) { @@ -346,9 +358,9 @@ struct SigMap void add(RTLIL::SigSpec from, RTLIL::SigSpec to) { - log_assert(SIZE(from) == SIZE(to)); + log_assert(GetSize(from) == GetSize(to)); - for (int i = 0; i < SIZE(from); i++) + for (int i = 0; i < GetSize(from); i++) { RTLIL::SigBit &bf = from[i]; RTLIL::SigBit &bt = to[i]; diff --git a/kernel/utils.h b/kernel/utils.h index a03caf804..2ec6182ea 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -25,21 +25,23 @@ #ifndef UTILS_H #define UTILS_H +YOSYS_NAMESPACE_BEGIN + // ------------------------------------------------ // A map-like container, but you can save and restore the state // ------------------------------------------------ -template<typename Key, typename T, typename Compare = std::less<Key>> +template<typename Key, typename T, typename OPS = hash_ops<Key>> struct stackmap { private: - std::vector<std::map<Key, T*, Compare>> backup_state; - std::map<Key, T, Compare> current_state; + std::vector<dict<Key, T*, OPS>> backup_state; + dict<Key, T, OPS> current_state; static T empty_tuple; public: stackmap() { } - stackmap(const std::map<Key, T, Compare> &other) : current_state(other) { } + stackmap(const dict<Key, T, OPS> &other) : current_state(other) { } template<typename Other> void operator=(const Other &other) @@ -81,7 +83,7 @@ public: void reset(const Key &k) { - for (int i = SIZE(backup_state)-1; i >= 0; i--) + for (int i = GetSize(backup_state)-1; i >= 0; i--) if (backup_state[i].count(k) != 0) { if (backup_state[i].at(k) == nullptr) current_state.erase(k); @@ -92,7 +94,7 @@ public: current_state.erase(k); } - const std::map<Key, T, Compare> &stdmap() + const dict<Key, T, OPS> &stdmap() { return current_state; } @@ -126,12 +128,12 @@ public: // A simple class for topological sorting // ------------------------------------------------ -template<typename T> +template<typename T, typename C = std::less<T>> struct TopoSort { bool analyze_loops, found_loops; - std::map<T, std::set<T>> database; - std::set<std::set<T>> loops; + std::map<T, std::set<T, C>, C> database; + std::set<std::set<T, C>> loops; std::vector<T> sorted; TopoSort() @@ -143,7 +145,7 @@ struct TopoSort void node(T n) { if (database.count(n) == 0) - database[n] = std::set<T>(); + database[n] = std::set<T, C>(); } void edge(T left, T right) @@ -152,13 +154,13 @@ struct TopoSort 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) + void sort_worker(const T &n, std::set<T, C> &marked_cells, std::set<T, C> &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--) { + std::set<T, C> loop; + for (int i = GetSize(active_stack)-1; i >= 0; i--) { loop.insert(active_stack[i]); if (active_stack[i] == n) break; @@ -195,16 +197,18 @@ struct TopoSort sorted.clear(); found_loops = false; - std::set<T> marked_cells; - std::set<T> active_cells; + std::set<T, C> marked_cells; + std::set<T, C> 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)); + log_assert(GetSize(sorted) == GetSize(database)); return !found_loops; } }; +YOSYS_NAMESPACE_END + #endif diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 0ecb4cdaf..884b2c59b 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -18,26 +18,112 @@ */ #include "kernel/yosys.h" +#include "kernel/celltypes.h" #ifdef YOSYS_ENABLE_READLINE # include <readline/readline.h> # include <readline/history.h> #endif -#include <dlfcn.h> -#include <unistd.h> +#ifdef YOSYS_ENABLE_PLUGINS +# include <dlfcn.h> +#endif + +#ifdef _WIN32 +# include <windows.h> +# include <io.h> +#elif defined(__APPLE__) +# include <mach-o/dyld.h> +# include <unistd.h> +# include <dirent.h> +# include <sys/stat.h> +#else +# include <unistd.h> +# include <dirent.h> +# include <sys/types.h> +# include <sys/stat.h> +#endif + #include <limits.h> #include <errno.h> YOSYS_NAMESPACE_BEGIN int autoidx = 1; +int yosys_xtrace = 0; RTLIL::Design *yosys_design = NULL; +CellTypes yosys_celltypes; #ifdef YOSYS_ENABLE_TCL Tcl_Interp *yosys_tcl_interp = NULL; #endif +bool memhasher_active = false; +uint32_t memhasher_rng = 123456; +std::vector<void*> memhasher_store; + +void memhasher_on() +{ +#ifdef __linux__ + memhasher_rng += time(NULL) << 16 ^ getpid(); +#endif + memhasher_store.resize(0x10000); + memhasher_active = true; +} + +void memhasher_off() +{ + for (auto p : memhasher_store) + if (p) free(p); + memhasher_store.clear(); + memhasher_active = false; +} + +void memhasher_do() +{ + memhasher_rng ^= memhasher_rng << 13; + memhasher_rng ^= memhasher_rng >> 17; + memhasher_rng ^= memhasher_rng << 5; + + int size, index = (memhasher_rng >> 4) & 0xffff; + switch (memhasher_rng & 7) { + case 0: size = 16; break; + case 1: size = 256; break; + case 2: size = 1024; break; + case 3: size = 4096; break; + default: size = 0; + } + if (index < 16) size *= 16; + memhasher_store[index] = realloc(memhasher_store[index], size); +} + +void yosys_banner() +{ + log("\n"); + log(" /----------------------------------------------------------------------------\\\n"); + log(" | |\n"); + log(" | yosys -- Yosys Open SYnthesis Suite |\n"); + log(" | |\n"); + log(" | Copyright (C) 2012 - 2015 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"); +} + std::string stringf(const char *fmt, ...) { std::string string; @@ -55,8 +141,22 @@ std::string vstringf(const char *fmt, va_list ap) std::string string; char *str = NULL; +#ifdef _WIN32 + int sz = 64, rc; + while (1) { + va_list apc; + va_copy(apc, ap); + str = (char*)realloc(str, sz); + rc = vsnprintf(str, sz, fmt, apc); + va_end(apc); + if (rc >= 0 && rc < sz) + break; + sz *= 2; + } +#else if (vasprintf(&str, fmt, ap) < 0) str = NULL; +#endif if (str != NULL) { string = str; @@ -66,15 +166,264 @@ std::string vstringf(const char *fmt, va_list ap) return string; } -int SIZE(RTLIL::Wire *wire) +int readsome(std::istream &f, char *s, int n) +{ + int rc = f.readsome(s, n); + + // f.readsome() sometimes returns 0 on a non-empty stream.. + if (rc == 0) { + int c = f.get(); + if (c != EOF) { + *s = c; + rc = 1; + } + } + + return rc; +} + +std::string next_token(std::string &text, const char *sep) +{ + size_t pos_begin = text.find_first_not_of(sep); + + if (pos_begin == std::string::npos) + pos_begin = text.size(); + + size_t pos_end = text.find_first_of(sep, pos_begin); + + if (pos_end == std::string::npos) + pos_end = text.size(); + + std::string token = text.substr(pos_begin, pos_end-pos_begin); + text = text.substr(pos_end); + return token; +} + +// this is very similar to fnmatch(). the exact rules used by this +// function are: +// +// ? matches any character except +// * matches any sequence of characters +// [...] matches any of the characters in the list +// [!..] matches any of the characters not in the list +// +// a backslash may be used to escape the next characters in the +// pattern. each special character can also simply match itself. +// +bool patmatch(const char *pattern, const char *string) +{ + if (*pattern == 0) + return *string == 0; + + if (*pattern == '\\') { + if (pattern[1] == string[0] && patmatch(pattern+2, string+1)) + return true; + } + + if (*pattern == '?') { + if (*string == 0) + return false; + return patmatch(pattern+1, string+1); + } + + if (*pattern == '*') { + while (*string) { + if (patmatch(pattern+1, string++)) + return true; + } + return pattern[1] == 0; + } + + if (*pattern == '[') { + bool found_match = false; + bool inverted_list = pattern[1] == '!'; + const char *p = pattern + (inverted_list ? 1 : 0); + + while (*++p) { + if (*p == ']') { + if (found_match != inverted_list && patmatch(p+1, string+1)) + return true; + break; + } + + if (*p == '\\') { + if (*++p == *string) + found_match = true; + } else + if (*p == *string) + found_match = true; + } + } + + if (*pattern == *string) + return patmatch(pattern+1, string+1); + + return false; +} + +int run_command(const std::string &command, std::function<void(const std::string&)> process_line) +{ + if (!process_line) + return system(command.c_str()); + + FILE *f = popen(command.c_str(), "r"); + if (f == nullptr) + return -1; + + std::string line; + char logbuf[128]; + while (fgets(logbuf, 128, f) != NULL) { + line += logbuf; + if (!line.empty() && line.back() == '\n') + process_line(line), line.clear(); + } + if (!line.empty()) + process_line(line); + + int ret = pclose(f); + if (ret < 0) + return -1; +#ifdef _WIN32 + return ret; +#else + return WEXITSTATUS(ret); +#endif +} + +std::string make_temp_file(std::string template_str) +{ +#ifdef _WIN32 + if (template_str.rfind("/tmp/", 0) == 0) { +# ifdef __MINGW32__ + char longpath[MAX_PATH + 1]; + char shortpath[MAX_PATH + 1]; +# else + WCHAR longpath[MAX_PATH + 1]; + TCHAR shortpath[MAX_PATH + 1]; +# endif + if (!GetTempPath(MAX_PATH+1, longpath)) + log_error("GetTempPath() failed.\n"); + if (!GetShortPathName(longpath, shortpath, MAX_PATH + 1)) + log_error("GetShortPathName() failed.\n"); + std::string path; + for (int i = 0; shortpath[i]; i++) + path += char(shortpath[i]); + template_str = stringf("%s\\%s", path.c_str(), template_str.c_str() + 5); + } + + size_t pos = template_str.rfind("XXXXXX"); + log_assert(pos != std::string::npos); + + while (1) { + for (int i = 0; i < 6; i++) { + static std::string y = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + static uint32_t x = 314159265 ^ uint32_t(time(NULL)); + x ^= x << 13, x ^= x >> 17, x ^= x << 5; + template_str[pos+i] = y[x % y.size()]; + } + if (_access(template_str.c_str(), 0) != 0) + break; + } +#else + size_t pos = template_str.rfind("XXXXXX"); + log_assert(pos != std::string::npos); + + int suffixlen = GetSize(template_str) - pos - 6; + + char *p = strdup(template_str.c_str()); + close(mkstemps(p, suffixlen)); + template_str = p; + free(p); +#endif + + return template_str; +} + +std::string make_temp_dir(std::string template_str) +{ +#ifdef _WIN32 + template_str = make_temp_file(template_str); + mkdir(template_str.c_str()); + return template_str; +#else +# ifndef NDEBUG + size_t pos = template_str.rfind("XXXXXX"); + log_assert(pos != std::string::npos); + + int suffixlen = GetSize(template_str) - pos - 6; + log_assert(suffixlen == 0); +# endif + + char *p = strdup(template_str.c_str()); + p = mkdtemp(p); + log_assert(p != NULL); + template_str = p; + free(p); + + return template_str; +#endif +} + +#ifdef _WIN32 +bool check_file_exists(std::string filename, bool) +{ + return _access(filename.c_str(), 0) == 0; +} +#else +bool check_file_exists(std::string filename, bool is_exec) +{ + return access(filename.c_str(), is_exec ? X_OK : F_OK) == 0; +} +#endif + +bool is_absolute_path(std::string filename) +{ +#ifdef _WIN32 + return filename[0] == '/' || filename[0] == '\\' || (filename[0] != 0 && filename[1] == ':'); +#else + return filename[0] == '/'; +#endif +} + +void remove_directory(std::string dirname) +{ +#ifdef _WIN32 + run_command(stringf("rmdir /s /q \"%s\"", dirname.c_str())); +#else + struct stat stbuf; + struct dirent **namelist; + int n = scandir(dirname.c_str(), &namelist, nullptr, alphasort); + log_assert(n >= 0); + for (int i = 0; i < n; i++) { + if (strcmp(namelist[i]->d_name, ".") && strcmp(namelist[i]->d_name, "..")) { + std::string buffer = stringf("%s/%s", dirname.c_str(), namelist[i]->d_name); + if (!stat(buffer.c_str(), &stbuf) && S_ISREG(stbuf.st_mode)) { + remove(buffer.c_str()); + } else + remove_directory(buffer); + } + free(namelist[i]); + } + free(namelist); + rmdir(dirname.c_str()); +#endif +} + +int GetSize(RTLIL::Wire *wire) { return wire->width; } void yosys_setup() { + // if there are already IdString objects then we have a global initialization order bug + IdString empty_id; + log_assert(empty_id.index_ == 0); + IdString::get_reference(empty_id.index_); + Pass::init_register(); yosys_design = new RTLIL::Design; + yosys_celltypes.setup(); log_push(); } @@ -92,6 +441,7 @@ void yosys_shutdown() log_files.clear(); Pass::done_register(); + yosys_celltypes.clear(); #ifdef YOSYS_ENABLE_TCL if (yosys_tcl_interp != NULL) { @@ -101,20 +451,33 @@ void yosys_shutdown() } #endif +#ifdef YOSYS_ENABLE_PLUGINS for (auto &it : loaded_plugins) dlclose(it.second); loaded_plugins.clear(); loaded_plugin_aliases.clear(); +#endif + + IdString empty_id; + IdString::put_reference(empty_id.index_); } RTLIL::IdString new_id(std::string file, int line, std::string func) { - std::string str = "$auto$"; +#ifdef _WIN32 + size_t pos = file.find_last_of("/\\"); +#else 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; +#endif + if (pos != std::string::npos) + file = file.substr(pos+1); + + pos = func.find_last_of(':'); + if (pos != std::string::npos) + func = func.substr(pos+1); + + return stringf("$auto$%s:%d:%s$%d", file.c_str(), line, func.c_str(), autoidx++); } RTLIL::Design *yosys_get_design() @@ -210,9 +573,9 @@ struct TclPass : public Pass { #endif #if defined(__linux__) -std::string proc_self_dirname () +std::string proc_self_dirname() { - char path [PATH_MAX]; + 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)); @@ -222,10 +585,9 @@ std::string proc_self_dirname () return std::string(path, buflen); } #elif defined(__APPLE__) -#include <mach-o/dyld.h> -std::string proc_self_dirname () +std::string proc_self_dirname() { - char * path = NULL; + char *path = NULL; uint32_t buflen = 0; while (_NSGetExecutablePath(path, &buflen) != 0) path = (char *) realloc((void *) path, buflen); @@ -233,8 +595,32 @@ std::string proc_self_dirname () buflen--; return std::string(path, buflen); } +#elif defined(_WIN32) +std::string proc_self_dirname() +{ + int i = 0; +# ifdef __MINGW32__ + char longpath[MAX_PATH + 1]; + char shortpath[MAX_PATH + 1]; +# else + WCHAR longpath[MAX_PATH + 1]; + TCHAR shortpath[MAX_PATH + 1]; +# endif + if (!GetModuleFileName(0, longpath, MAX_PATH+1)) + log_error("GetModuleFileName() failed.\n"); + if (!GetShortPathName(longpath, shortpath, MAX_PATH+1)) + log_error("GetShortPathName() failed.\n"); + while (shortpath[i] != 0) + i++; + while (i > 0 && shortpath[i-1] != '/' && shortpath[i-1] != '\\') + shortpath[--i] = 0; + std::string path; + for (i = 0; shortpath[i]; i++) + path += char(shortpath[i]); + return path; +} #elif defined(EMSCRIPTEN) -std::string proc_self_dirname () +std::string proc_self_dirname() { return "/"; } @@ -242,17 +628,33 @@ std::string proc_self_dirname () #error Dont know how to determine process executable base path! #endif -std::string proc_share_dirname () +#ifdef EMSCRIPTEN +std::string proc_share_dirname() +{ + return "/share"; +} +#else +std::string proc_share_dirname() { std::string proc_self_path = proc_self_dirname(); +# ifdef _WIN32 + std::string proc_share_path = proc_self_path + "share\\"; + if (check_file_exists(proc_share_path, true)) + return proc_share_path; + proc_share_path = proc_self_path + "..\\share\\"; + if (check_file_exists(proc_share_path, true)) + return proc_share_path; +# else std::string proc_share_path = proc_self_path + "share/"; - if (access(proc_share_path.c_str(), X_OK) == 0) + if (check_file_exists(proc_share_path, true)) return proc_share_path; proc_share_path = proc_self_path + "../share/yosys/"; - if (access(proc_share_path.c_str(), X_OK) == 0) + if (check_file_exists(proc_share_path, true)) return proc_share_path; +# endif log_error("proc_share_dirname: unable to determine share/ directory!\n"); } +#endif bool fgetline(FILE *f, std::string &buffer) { @@ -275,15 +677,15 @@ static void handle_label(std::string &command, bool &from_to_active, const std:: int pos = 0; std::string label; - while (pos < SIZE(command) && (command[pos] == ' ' || command[pos] == '\t')) + while (pos < GetSize(command) && (command[pos] == ' ' || command[pos] == '\t')) pos++; - while (pos < SIZE(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n') + while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n') label += command[pos++]; - if (label.back() == ':' && SIZE(label) > 1) + if (label.back() == ':' && GetSize(label) > 1) { - label = label.substr(0, SIZE(label)-1); + label = label.substr(0, GetSize(label)-1); command = command.substr(pos); if (label == run_from) @@ -293,8 +695,11 @@ static void handle_label(std::string &command, bool &from_to_active, const std:: } } -void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label) +void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label, RTLIL::Design *design) { + if (design == nullptr) + design = yosys_design; + if (command == "auto") { if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v") command = "verilog"; @@ -361,9 +766,9 @@ void run_frontend(std::string filename, std::string command, RTLIL::Design *desi Pass::call(design, command); } } - catch (log_cmd_error_expection) { + catch (...) { Frontend::current_script_file = backup_script_file; - throw log_cmd_error_expection(); + throw; } Frontend::current_script_file = backup_script_file; @@ -386,15 +791,26 @@ void run_frontend(std::string filename, std::string command, RTLIL::Design *desi Frontend::frontend_call(design, NULL, filename, command); } +void run_frontend(std::string filename, std::string command, RTLIL::Design *design) +{ + run_frontend(filename, command, nullptr, nullptr, design); +} + void run_pass(std::string command, RTLIL::Design *design) { - log("\n-- Running pass `%s' --\n", command.c_str()); + if (design == nullptr) + design = yosys_design; + + log("\n-- Running command `%s' --\n", command.c_str()); Pass::call(design, command); } void run_backend(std::string filename, std::string command, RTLIL::Design *design) { + if (design == nullptr) + design = yosys_design; + if (command == "auto") { if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v") command = "verilog"; @@ -518,11 +934,16 @@ void shell(RTLIL::Design *design) 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 + while (1) { + fputs(create_prompt(design, recursion_counter), stdout); + fflush(stdout); + if ((command = fgets(command_buffer, 4096, stdin)) == NULL) + break; +#endif if (command[strspn(command, " \t\r\n")] == 0) continue; #ifdef YOSYS_ENABLE_READLINE @@ -540,7 +961,7 @@ void shell(RTLIL::Design *design) try { log_assert(design->selection_stack.size() == 1); Pass::call(design, command); - } catch (log_cmd_error_expection) { + } catch (log_cmd_error_exception) { while (design->selection_stack.size() > 1) design->selection_stack.pop_back(); log_reset_stack(); @@ -634,9 +1055,9 @@ struct ScriptPass : public Pass { if (args.size() < 2) log_cmd_error("Missing script file.\n"); else if (args.size() == 2) - run_frontend(args[1], "script", design, NULL, NULL); + run_frontend(args[1], "script", design); else if (args.size() == 3) - run_frontend(args[1], "script", design, NULL, &args[2]); + run_frontend(args[1], "script", NULL, &args[2], design); else extra_args(args, 2, design, false); } diff --git a/kernel/yosys.h b/kernel/yosys.h index b571e177f..231dd4de6 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -45,7 +45,11 @@ #include <string> #include <algorithm> #include <functional> +#include <unordered_map> +#include <unordered_set> #include <initializer_list> +#include <stdexcept> +#include <memory> #include <sstream> #include <fstream> @@ -56,44 +60,164 @@ #include <stdarg.h> #include <stdlib.h> #include <string.h> +#include <stdint.h> #include <stdio.h> +#ifndef _YOSYS_ +# error It looks like you are trying to build Yosys without the config defines set. \ + When building Yosys with a custom make system, make sure you set all the \ + defines the Yosys Makefile would set for your build configuration. +#endif + +#ifdef YOSYS_ENABLE_TCL +# include <tcl.h> +#endif + +#ifdef _WIN32 +# undef NOMINMAX +# define NOMINMAX 1 +# undef YY_NO_UNISTD_H +# define YY_NO_UNISTD_H 1 + +# include <windows.h> +# include <io.h> +# include <direct.h> + +# define strtok_r strtok_s +# define strdup _strdup +# define snprintf _snprintf +# define getcwd _getcwd +# define mkdir _mkdir +# define popen _popen +# define pclose _pclose +# define PATH_MAX MAX_PATH + +# ifndef __MINGW32__ +# define isatty _isatty +# define fileno _fileno +# endif +#endif + #define PRIVATE_NAMESPACE_BEGIN namespace { #define PRIVATE_NAMESPACE_END } +#define YOSYS_NAMESPACE_BEGIN namespace Yosys { +#define YOSYS_NAMESPACE_END } +#define YOSYS_NAMESPACE_PREFIX Yosys:: +#define USING_YOSYS_NAMESPACE using namespace Yosys; -#if 0 -# define YOSYS_NAMESPACE_BEGIN namespace Yosys { -# define YOSYS_NAMESPACE_END } -# define YOSYS_NAMESPACE_PREFIX Yosys:: -# define USING_YOSYS_NAMESPACE using namespace Yosys; +#if __cplusplus >= 201103L +# define YS_OVERRIDE override +# define YS_FINAL final #else -# define YOSYS_NAMESPACE_BEGIN -# define YOSYS_NAMESPACE_END -# define YOSYS_NAMESPACE_PREFIX -# define USING_YOSYS_NAMESPACE +# define YS_OVERRIDE +# define YS_FINAL #endif -#if __cplusplus >= 201103L -# define OVERRIDE override -# define FINAL final +#if defined(__GNUC__) || defined(__clang__) +# define YS_ATTRIBUTE(...) __attribute__((__VA_ARGS__)) +# define YS_NORETURN +#elif defined(_MSC_VER) +# define YS_ATTRIBUTE(...) +# define YS_NORETURN __declspec(noreturn) #else -# define OVERRIDE -# define FINAL +# define YS_ATTRIBUTE(...) +# define YS_NORETURN #endif YOSYS_NAMESPACE_BEGIN +// Note: All headers included in hashlib.h must be included +// outside of YOSYS_NAMESPACE before this or bad things will happen. +#ifdef HASHLIB_H +# undef HASHLIB_H +# include "kernel/hashlib.h" +#else +# include "kernel/hashlib.h" +# undef HASHLIB_H +#endif + +using std::vector; +using std::string; +using std::pair; + +using hashlib::mkhash; +using hashlib::mkhash_init; +using hashlib::mkhash_add; +using hashlib::mkhash_xorshift; +using hashlib::hash_ops; +using hashlib::hash_cstr_ops; +using hashlib::hash_ptr_ops; +using hashlib::hash_obj_ops; +using hashlib::dict; +using hashlib::idict; +using hashlib::pool; + namespace RTLIL { struct IdString; + struct Const; + struct SigBit; struct SigSpec; struct Wire; struct Cell; + struct Module; + struct Design; + struct Monitor; +} + +namespace AST { + struct AstNode; +} + +using RTLIL::IdString; +using RTLIL::Const; +using RTLIL::SigBit; +using RTLIL::SigSpec; +using RTLIL::Wire; +using RTLIL::Cell; +using RTLIL::Module; +using RTLIL::Design; + +namespace hashlib { + template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {}; + template<> struct hash_ops<RTLIL::Cell*> : hash_obj_ops {}; + template<> struct hash_ops<RTLIL::Module*> : hash_obj_ops {}; + template<> struct hash_ops<RTLIL::Design*> : hash_obj_ops {}; + template<> struct hash_ops<RTLIL::Monitor*> : hash_obj_ops {}; + template<> struct hash_ops<AST::AstNode*> : hash_obj_ops {}; + + template<> struct hash_ops<const RTLIL::Wire*> : hash_obj_ops {}; + template<> struct hash_ops<const RTLIL::Cell*> : hash_obj_ops {}; + template<> struct hash_ops<const RTLIL::Module*> : hash_obj_ops {}; + template<> struct hash_ops<const RTLIL::Design*> : hash_obj_ops {}; + template<> struct hash_ops<const RTLIL::Monitor*> : hash_obj_ops {}; + template<> struct hash_ops<const AST::AstNode*> : hash_obj_ops {}; } -std::string stringf(const char *fmt, ...); +void memhasher_on(); +void memhasher_off(); +void memhasher_do(); + +extern bool memhasher_active; +inline void memhasher() { if (memhasher_active) memhasher_do(); } + +void yosys_banner(); +std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); 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); +int readsome(std::istream &f, char *s, int n); +std::string next_token(std::string &text, const char *sep = " \t\r\n"); +bool patmatch(const char *pattern, const char *string); +int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>()); +std::string make_temp_file(std::string template_str = "/tmp/yosys_XXXXXX"); +std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX"); +bool check_file_exists(std::string filename, bool is_exec = false); +bool is_absolute_path(std::string filename); +void remove_directory(std::string dirname); + +template<typename T> int GetSize(const T &obj) { return obj.size(); } +int GetSize(RTLIL::Wire *wire); + +extern int autoidx; +extern int yosys_xtrace; YOSYS_NAMESPACE_END @@ -103,15 +227,19 @@ YOSYS_NAMESPACE_END YOSYS_NAMESPACE_BEGIN +using RTLIL::State; + +namespace hashlib { + template<> struct hash_ops<RTLIL::State> : hash_ops<int> {}; +} + 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); @@ -127,9 +255,10 @@ 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 run_pass(std::string command, RTLIL::Design *design = nullptr); +void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label = nullptr, RTLIL::Design *design = nullptr); +void run_frontend(std::string filename, std::string command, RTLIL::Design *design = nullptr); +void run_backend(std::string filename, std::string command, RTLIL::Design *design = nullptr); void shell(RTLIL::Design *design); // from kernel/version_*.o (cc source generated from Makefile) |