aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorAhmed Irfan <irfan@levert.(none)>2015-04-03 16:38:07 +0200
committerAhmed Irfan <irfan@levert.(none)>2015-04-03 16:38:07 +0200
commitbdf6b2b19ab2206f5957ad5b2ec582c2730d45ee (patch)
tree1d02541701054a1c3b1cdb66478d0cbc31c2d38f /kernel
parent8acdd90bc918b780ad45cdac42b3baf84d2cc476 (diff)
parent4b4490761949e738dee54bdfc52e080e0a5c9067 (diff)
downloadyosys-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.h89
-rw-r--r--kernel/calc.cc2
-rw-r--r--kernel/celltypes.h122
-rw-r--r--kernel/consteval.h24
-rw-r--r--kernel/cost.h84
-rw-r--r--kernel/driver.cc388
-rw-r--r--kernel/hashlib.h887
-rw-r--r--kernel/log.cc228
-rw-r--r--kernel/log.h63
-rw-r--r--kernel/macc.h69
-rw-r--r--kernel/modtools.h194
-rw-r--r--kernel/register.cc92
-rw-r--r--kernel/register.h10
-rw-r--r--kernel/rtlil.cc490
-rw-r--r--kernel/rtlil.h668
-rw-r--r--kernel/satgen.h282
-rw-r--r--kernel/sigtools.h30
-rw-r--r--kernel/utils.h36
-rw-r--r--kernel/yosys.cc479
-rw-r--r--kernel/yosys.h173
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> &parameters = 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)