aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/calc.cc53
-rw-r--r--kernel/celltypes.h32
-rw-r--r--kernel/constids.inc2
-rw-r--r--kernel/driver.cc79
-rw-r--r--kernel/ff.cc19
-rw-r--r--kernel/ff.h8
-rw-r--r--kernel/fstdata.cc30
-rw-r--r--kernel/hashlib.h2
-rw-r--r--kernel/json.cc172
-rw-r--r--kernel/json.h104
-rw-r--r--kernel/log.cc26
-rw-r--r--kernel/log.h79
-rw-r--r--kernel/mem.cc1
-rw-r--r--kernel/modtools.h4
-rw-r--r--kernel/register.cc187
-rw-r--r--kernel/rtlil.cc245
-rw-r--r--kernel/rtlil.h149
-rw-r--r--kernel/satgen.cc88
-rw-r--r--kernel/satgen.h1
-rw-r--r--kernel/yosys.cc152
-rw-r--r--kernel/yosys.h5
-rw-r--r--kernel/yw.cc209
-rw-r--r--kernel/yw.h182
23 files changed, 1430 insertions, 399 deletions
diff --git a/kernel/calc.cc b/kernel/calc.cc
index 0865db526..9b02a6e30 100644
--- a/kernel/calc.cc
+++ b/kernel/calc.cc
@@ -609,6 +609,36 @@ RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, boo
return RTLIL::const_sub(zero, arg1_ext, true, signed1, result_len);
}
+RTLIL::Const RTLIL::const_mux(const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3)
+{
+ log_assert(arg2.size() == arg1.size());
+ if (arg3[0] == State::S0)
+ return arg1;
+ else if (arg3[0] == State::S1)
+ return arg2;
+
+ RTLIL::Const ret = arg1;
+ for (int i = 0; i < ret.size(); i++)
+ if (ret[i] != arg2[i])
+ ret[i] = State::Sx;
+ return ret;
+}
+
+RTLIL::Const RTLIL::const_pmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3)
+{
+ if (arg3.is_fully_zero())
+ return arg1;
+
+ if (!arg3.is_onehot())
+ return RTLIL::Const(State::Sx, arg1.size());
+
+ for (int i = 0; i < arg3.size(); i++)
+ if (arg3[i] == State::S1)
+ return RTLIL::Const(std::vector<RTLIL::State>(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size()));
+
+ log_abort(); // unreachable
+}
+
RTLIL::Const RTLIL::const_bmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2)
{
std::vector<RTLIL::State> t = arg1.bits;
@@ -660,5 +690,28 @@ RTLIL::Const RTLIL::const_demux(const RTLIL::Const &arg1, const RTLIL::Const &ar
return res;
}
+RTLIL::Const RTLIL::const_bweqx(const RTLIL::Const &arg1, const RTLIL::Const &arg2)
+{
+ log_assert(arg2.size() == arg1.size());
+ RTLIL::Const result(RTLIL::State::S0, arg1.size());
+ for (int i = 0; i < arg1.size(); i++)
+ result[i] = arg1[i] == arg2[i] ? State::S1 : State::S0;
+
+ return result;
+}
+
+RTLIL::Const RTLIL::const_bwmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3)
+{
+ log_assert(arg2.size() == arg1.size());
+ log_assert(arg3.size() == arg1.size());
+ RTLIL::Const result(RTLIL::State::Sx, arg1.size());
+ for (int i = 0; i < arg1.size(); i++) {
+ if (arg3[i] != State::Sx || arg1[i] == arg2[i])
+ result[i] = arg3[i] == State::S1 ? arg2[i] : arg1[i];
+ }
+
+ return result;
+}
+
YOSYS_NAMESPACE_END
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index 7e9cfb38d..63e7408c1 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -51,6 +51,7 @@ struct CellTypes
setup_internals();
setup_internals_mem();
+ setup_internals_anyinit();
setup_stdcells();
setup_stdcells_mem();
}
@@ -115,7 +116,8 @@ struct CellTypes
ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),
ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),
ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow),
- ID($logic_and), ID($logic_or), ID($concat), ID($macc)
+ ID($logic_and), ID($logic_or), ID($concat), ID($macc),
+ ID($bweqx)
};
for (auto type : unary_ops)
@@ -124,7 +126,7 @@ struct CellTypes
for (auto type : binary_ops)
setup_type(type, {ID::A, ID::B}, {ID::Y}, true);
- for (auto type : std::vector<RTLIL::IdString>({ID($mux), ID($pmux)}))
+ for (auto type : std::vector<RTLIL::IdString>({ID($mux), ID($pmux), ID($bwmux)}))
setup_type(type, {ID::A, ID::B, ID::S}, {ID::Y}, true);
for (auto type : std::vector<RTLIL::IdString>({ID($bmux), ID($demux)}))
@@ -155,6 +157,11 @@ struct CellTypes
setup_type(ID($dlatchsr), {ID::EN, ID::SET, ID::CLR, ID::D}, {ID::Q});
}
+ void setup_internals_anyinit()
+ {
+ setup_type(ID($anyinit), {ID::D}, {ID::Q});
+ }
+
void setup_internals_mem()
{
setup_internals_ff();
@@ -424,6 +431,11 @@ struct CellTypes
return const_demux(arg1, arg2);
}
+ if (cell->type == ID($bweqx))
+ {
+ return const_bweqx(arg1, arg2);
+ }
+
if (cell->type == ID($lut))
{
int width = cell->parameters.at(ID::WIDTH).as_int();
@@ -482,16 +494,12 @@ struct CellTypes
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr)
{
- if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) {
- RTLIL::Const ret = arg1;
- for (size_t i = 0; i < arg3.bits.size(); i++)
- if (arg3.bits[i] == RTLIL::State::S1) {
- std::vector<RTLIL::State> bits(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size());
- ret = RTLIL::Const(bits);
- }
- return ret;
- }
-
+ if (cell->type.in(ID($mux), ID($_MUX_)))
+ return const_mux(arg1, arg2, arg3);
+ if (cell->type == ID($bwmux))
+ return const_bwmux(arg1, arg2, arg3);
+ if (cell->type == ID($pmux))
+ return const_pmux(arg1, arg2, arg3);
if (cell->type == ID($_AOI3_))
return eval_not(const_or(const_and(arg1, arg2, false, false, 1), arg3, false, false, 1));
if (cell->type == ID($_OAI3_))
diff --git a/kernel/constids.inc b/kernel/constids.inc
index 0f6dfc29b..39211d0c7 100644
--- a/kernel/constids.inc
+++ b/kernel/constids.inc
@@ -171,6 +171,7 @@ X(RD_TRANSPARENCY_MASK)
X(RD_TRANSPARENT)
X(RD_WIDE_CONTINUATION)
X(reg)
+X(replaced_by_gclk)
X(reprocess_after)
X(rom_block)
X(rom_style)
@@ -258,5 +259,6 @@ X(WR_PORTS)
X(WR_PRIORITY_MASK)
X(WR_WIDE_CONTINUATION)
X(X)
+X(xprop_decoder)
X(Y)
X(Y_WIDTH)
diff --git a/kernel/driver.cc b/kernel/driver.cc
index f8f940e89..ef8e77924 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -33,6 +33,10 @@
#include <string.h>
#include <limits.h>
#include <errno.h>
+#ifndef __STDC_FORMAT_MACROS
+# define __STDC_FORMAT_MACROS
+#endif
+#include <inttypes.h>
#if defined (__linux__) || defined(__FreeBSD__)
# include <sys/resource.h>
@@ -192,6 +196,19 @@ void yosys_atexit()
#endif
}
+#if defined(__OpenBSD__)
+namespace Yosys {
+extern char *yosys_argv0;
+extern char yosys_path[PATH_MAX];
+};
+#endif
+#ifdef YOSYS_ENABLE_TCL
+namespace Yosys {
+ extern int yosys_tcl_iterp_init(Tcl_Interp *interp);
+ extern void yosys_tcl_activate_repl();
+};
+#endif
+
int main(int argc, char **argv)
{
std::string frontend_command = "auto";
@@ -203,12 +220,14 @@ int main(int argc, char **argv)
std::string scriptfile = "";
std::string depsfile = "";
std::string topmodule = "";
+ std::string perffile = "";
bool scriptfile_tcl = false;
bool print_banner = true;
bool print_stats = true;
bool call_abort = false;
bool timing_details = false;
bool run_shell = true;
+ bool run_tcl_shell = false;
bool mode_v = false;
bool mode_q = false;
@@ -272,10 +291,13 @@ int main(int argc, char **argv)
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(" -C\n");
+ printf(" enters TCL interatcive shell mode\n");
#endif
printf("\n");
printf(" -p command\n");
- printf(" execute the commands\n");
+ printf(" execute the commands (to chain commands, separate them with semicolon + whitespace: 'cmd1; cmd2')\n");
printf("\n");
printf(" -m module_file\n");
printf(" load the specified module (aka plugin)\n");
@@ -346,7 +368,7 @@ int main(int argc, char **argv)
}
int opt;
- while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:r:D:P:E:x:")) != -1)
+ while ((opt = getopt(argc, argv, "MXAQTVCSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:r:D:P:E:x:B:")) != -1)
{
switch (opt)
{
@@ -481,6 +503,12 @@ int main(int argc, char **argv)
case 'x':
log_experimentals_ignored.insert(optarg);
break;
+ case 'B':
+ perffile = optarg;
+ break;
+ case 'C':
+ run_tcl_shell = true;
+ break;
default:
fprintf(stderr, "Run '%s -h' for help.\n", argv[0]);
exit(1);
@@ -498,6 +526,12 @@ int main(int argc, char **argv)
if (print_stats)
log_hasher = new SHA1;
+#if defined(__OpenBSD__)
+ // save the executable origin for proc_self_dirname()
+ yosys_argv0 = argv[0];
+ realpath(yosys_argv0, yosys_path);
+#endif
+
#if defined(__linux__)
// set stack size to >= 128 MB
{
@@ -549,10 +583,19 @@ int main(int argc, char **argv)
for (auto it = passes_commands.begin(); it != passes_commands.end(); it++)
run_pass(*it);
- if (run_shell)
- shell(yosys_design);
- else
- run_backend(output_filename, backend_command);
+ if (run_tcl_shell) {
+#ifdef YOSYS_ENABLE_TCL
+ yosys_tcl_activate_repl();
+ Tcl_Main(argc, argv, yosys_tcl_iterp_init);
+#else
+ log_error("Can't exectue TCL shell: this version of yosys is not built with TCL support enabled.\n");
+#endif
+ } else {
+ if (run_shell)
+ shell(yosys_design);
+ else
+ run_backend(output_filename, backend_command);
+ }
yosys_design->check();
for (auto it : saved_designs)
@@ -661,6 +704,29 @@ int main(int argc, char **argv)
}
log("%s\n", out_count ? "" : " no commands executed");
}
+ if(!perffile.empty())
+ {
+ FILE *f = fopen(perffile.c_str(), "wt");
+ if (f == nullptr)
+ log_error("Can't open performance log file for writing: %s\n", strerror(errno));
+
+ fprintf(f, "{\n");
+ fprintf(f, " \"generator\": \"%s\",\n", yosys_version_str);
+ fprintf(f, " \"total_ns\": %" PRIu64 ",\n", total_ns);
+ fprintf(f, " \"passes\": {");
+
+ bool first = true;
+ for (auto it = timedat.rbegin(); it != timedat.rend(); it++) {
+ if (!first)
+ fprintf(f, ",");
+ fprintf(f, "\n \"%s\": {\n", std::get<2>(*it).c_str());
+ fprintf(f, " \"runtime_ns\": %" PRIu64 ",\n", std::get<0>(*it));
+ fprintf(f, " \"num_calls\": %u\n", std::get<1>(*it));
+ fprintf(f, " }");
+ first = false;
+ }
+ fprintf(f, "\n }\n}\n");
+ }
}
#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
@@ -711,4 +777,3 @@ int main(int argc, char **argv)
}
#endif /* EMSCRIPTEN */
-
diff --git a/kernel/ff.cc b/kernel/ff.cc
index b0f1a924f..697ba7342 100644
--- a/kernel/ff.cc
+++ b/kernel/ff.cc
@@ -33,10 +33,14 @@ FfData::FfData(FfInitVals *initvals, Cell *cell_) : FfData(cell_->module, initva
std::string type_str = cell->type.str();
- if (cell->type.in(ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
- if (cell->type == ID($ff)) {
+ if (cell->type.in(ID($anyinit), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
+ if (cell->type.in(ID($anyinit), ID($ff))) {
has_gclk = true;
sig_d = cell->getPort(ID::D);
+ if (cell->type == ID($anyinit)) {
+ is_anyinit = true;
+ log_assert(val_init.is_fully_undef());
+ }
} else if (cell->type == ID($sr)) {
// No data input at all.
} else if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) {
@@ -274,6 +278,7 @@ FfData FfData::slice(const std::vector<int> &bits) {
res.has_sr = has_sr;
res.ce_over_srst = ce_over_srst;
res.is_fine = is_fine;
+ res.is_anyinit = is_anyinit;
res.pol_clk = pol_clk;
res.pol_ce = pol_ce;
res.pol_aload = pol_aload;
@@ -542,7 +547,7 @@ Cell *FfData::emit() {
return nullptr;
}
}
- if (initvals)
+ if (initvals && !is_anyinit)
initvals->set_init(sig_q, val_init);
if (!is_fine) {
if (has_gclk) {
@@ -552,7 +557,12 @@ Cell *FfData::emit() {
log_assert(!has_arst);
log_assert(!has_srst);
log_assert(!has_sr);
- cell = module->addFf(name, sig_d, sig_q);
+ if (is_anyinit) {
+ cell = module->addAnyinit(name, sig_d, sig_q);
+ log_assert(val_init.is_fully_undef());
+ } else {
+ cell = module->addFf(name, sig_d, sig_q);
+ }
} else if (!has_aload && !has_clk) {
log_assert(has_sr);
cell = module->addSr(name, sig_set, sig_clr, sig_q, pol_set, pol_clr);
@@ -603,6 +613,7 @@ Cell *FfData::emit() {
log_assert(!has_arst);
log_assert(!has_srst);
log_assert(!has_sr);
+ log_assert(!is_anyinit);
cell = module->addFfGate(name, sig_d, sig_q);
} else if (!has_aload && !has_clk) {
log_assert(has_sr);
diff --git a/kernel/ff.h b/kernel/ff.h
index 41721b4a1..e684d3c43 100644
--- a/kernel/ff.h
+++ b/kernel/ff.h
@@ -28,7 +28,10 @@ YOSYS_NAMESPACE_BEGIN
// Describes a flip-flop or a latch.
//
// If has_gclk, this is a formal verification FF with implicit global clock:
-// Q is simply previous cycle's D.
+// Q is simply previous cycle's D. Additionally if is_anyinit is true, this is
+// an $anyinit cell which always has an undefined initialization value. Note
+// that $anyinit is not considered to be among the FF celltypes, so a pass has
+// to explicitly opt-in to process $anyinit cells with FfData.
//
// Otherwise, the FF/latch can have any number of features selected by has_*
// attributes that determine Q's value (in order of decreasing priority):
@@ -126,6 +129,8 @@ struct FfData {
// True if this FF is a fine cell, false if it is a coarse cell.
// If true, width must be 1.
bool is_fine;
+ // True if this FF is an $anyinit cell. Depends on has_gclk.
+ bool is_anyinit;
// Polarities, corresponding to sig_*. True means active-high, false
// means active-low.
bool pol_clk;
@@ -156,6 +161,7 @@ struct FfData {
has_sr = false;
ce_over_srst = false;
is_fine = false;
+ is_anyinit = false;
pol_clk = false;
pol_aload = false;
pol_ce = false;
diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc
index b2e574b02..65ae3426c 100644
--- a/kernel/fstdata.cc
+++ b/kernel/fstdata.cc
@@ -78,7 +78,18 @@ uint64_t FstData::getStartTime() { return fstReaderGetStartTime(ctx); }
uint64_t FstData::getEndTime() { return fstReaderGetEndTime(ctx); }
+static void normalize_brackets(std::string &str)
+{
+ for (auto &c : str) {
+ if (c == '<')
+ c = '[';
+ else if (c == '>')
+ c = ']';
+ }
+}
+
fstHandle FstData::getHandle(std::string name) {
+ normalize_brackets(name);
if (name_to_handle.find(name) != name_to_handle.end())
return name_to_handle[name];
else
@@ -120,6 +131,7 @@ void FstData::extractVarNames()
var.is_reg = (fstVarType)h->u.var.typ == FST_VT_VCD_REG;
var.name = remove_spaces(h->u.var.name);
var.scope = fst_scope_name;
+ normalize_brackets(var.scope);
var.width = h->u.var.length;
vars.push_back(var);
if (!var.is_alias)
@@ -134,35 +146,34 @@ void FstData::extractVarNames()
if (clean_name[0]=='\\')
clean_name = clean_name.substr(1);
size_t pos = clean_name.find_last_of("<");
- if (pos != std::string::npos) {
+ if (pos != std::string::npos && clean_name.back() == '>') {
std::string mem_cell = clean_name.substr(0, pos);
+ normalize_brackets(mem_cell);
std::string addr = clean_name.substr(pos+1);
addr.pop_back(); // remove closing bracket
char *endptr;
int mem_addr = strtol(addr.c_str(), &endptr, 16);
if (*endptr) {
- log_warning("Error parsing memory address in : %s\n", clean_name.c_str());
+ log_debug("Error parsing memory address in : %s\n", clean_name.c_str());
} else {
memory_to_handle[var.scope+"."+mem_cell][mem_addr] = var.id;
- name_to_handle[stringf("%s.%s[%d]",var.scope.c_str(),mem_cell.c_str(),mem_addr)] = h->u.var.handle;
- continue;
}
}
pos = clean_name.find_last_of("[");
- if (pos != std::string::npos) {
+ if (pos != std::string::npos && clean_name.back() == ']') {
std::string mem_cell = clean_name.substr(0, pos);
+ normalize_brackets(mem_cell);
std::string addr = clean_name.substr(pos+1);
addr.pop_back(); // remove closing bracket
char *endptr;
int mem_addr = strtol(addr.c_str(), &endptr, 10);
if (*endptr) {
- log_warning("Error parsing memory address in : %s\n", clean_name.c_str());
+ log_debug("Error parsing memory address in : %s\n", clean_name.c_str());
} else {
memory_to_handle[var.scope+"."+mem_cell][mem_addr] = var.id;
- name_to_handle[stringf("%s.%s[%d]",var.scope.c_str(),mem_cell.c_str(),mem_addr)] = h->u.var.handle;
- continue;
}
}
+ normalize_brackets(clean_name);
name_to_handle[var.scope+"."+clean_name] = h->u.var.handle;
break;
}
@@ -186,7 +197,7 @@ static void reconstruct_clb_attimes(void *user_data, uint64_t pnt_time, fstHandl
void FstData::reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t /* plen */)
{
- if (pnt_time > end_time) return;
+ if (pnt_time > end_time || !pnt_value) return;
// if we are past the timestamp
bool is_clock = false;
if (!all_samples) {
@@ -241,6 +252,7 @@ void FstData::reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t sta
past_data = last_data;
callback(last_time);
}
+ past_data = last_data;
callback(end_time);
}
diff --git a/kernel/hashlib.h b/kernel/hashlib.h
index 0c9f25287..af2827153 100644
--- a/kernel/hashlib.h
+++ b/kernel/hashlib.h
@@ -189,7 +189,7 @@ inline int hashtable_size(int min_size)
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.");
+ throw std::length_error("hash table exceeded maximum size.\nDesign is likely too large for yosys to handle, if possible try not to flatten the design.");
for (auto p : zero_and_some_primes)
if (100129 * p > min_size) return 100129 * p;
diff --git a/kernel/json.cc b/kernel/json.cc
new file mode 100644
index 000000000..738746267
--- /dev/null
+++ b/kernel/json.cc
@@ -0,0 +1,172 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2022 Jannis Harder <jix@yosyshq.com> <me@jix.one>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/json.h"
+
+USING_YOSYS_NAMESPACE
+
+void PrettyJson::emit_to_log()
+{
+ struct LogTarget : public Target {
+ void emit(const char *data) override { log("%s", data); }
+ };
+
+ targets.push_back(std::unique_ptr<Target>(new LogTarget));
+}
+
+void PrettyJson::append_to_string(std::string &target)
+{
+ struct AppendStringTarget : public Target {
+ std::string &target;
+ AppendStringTarget(std::string &target) : target(target) {}
+ void emit(const char *data) override { target += data; }
+ };
+
+ targets.push_back(std::unique_ptr<Target>(new AppendStringTarget(target)));
+}
+
+bool PrettyJson::write_to_file(const std::string &path)
+{
+ struct WriteFileTarget : public Target {
+ std::ofstream target;
+ void emit(const char *data) override { target << data; }
+ void flush() override { target.flush(); }
+ };
+
+ auto target = std::unique_ptr<WriteFileTarget>(new WriteFileTarget);
+ target->target.open(path);
+ if (target->target.fail())
+ return false;
+ targets.push_back(std::unique_ptr<Target>(target.release()));
+ return true;
+}
+
+void PrettyJson::line(bool space_if_inline)
+{
+ if (compact_depth != INT_MAX) {
+ if (space_if_inline)
+ raw(" ");
+ return;
+ }
+ int indent = state.size() - (state.empty() ? 0 : state.back() == VALUE);
+ newline_indent.resize(1 + 2 * indent, ' ');
+ raw(newline_indent.c_str());
+}
+
+void PrettyJson::raw(const char *raw_json)
+{
+ for (auto &target : targets)
+ target->emit(raw_json);
+}
+
+void PrettyJson::flush()
+{
+ for (auto &target : targets)
+ target->flush();
+}
+
+void PrettyJson::begin_object()
+{
+ begin_value();
+ raw("{");
+ state.push_back(OBJECT_FIRST);
+}
+
+void PrettyJson::begin_array()
+{
+ begin_value();
+ raw("[");
+ state.push_back(ARRAY_FIRST);
+}
+
+void PrettyJson::end_object()
+{
+ Scope top_scope = state.back();
+ state.pop_back();
+ if (top_scope == OBJECT)
+ line(false);
+ else
+ log_assert(top_scope == OBJECT_FIRST);
+ raw("}");
+ end_value();
+}
+
+void PrettyJson::end_array()
+{
+ Scope top_scope = state.back();
+ state.pop_back();
+ if (top_scope == ARRAY)
+ line(false);
+ else
+ log_assert(top_scope == ARRAY_FIRST);
+ raw("]");
+ end_value();
+}
+
+void PrettyJson::name(const char *name)
+{
+ if (state.back() == OBJECT_FIRST) {
+ state.back() = OBJECT;
+ line(false);
+ } else {
+ raw(",");
+ line();
+ }
+ raw(Json(name).dump().c_str());
+ raw(": ");
+ state.push_back(VALUE);
+}
+
+void PrettyJson::begin_value()
+{
+ if (state.back() == ARRAY_FIRST) {
+ line(false);
+ state.back() = ARRAY;
+ } else if (state.back() == ARRAY) {
+ raw(",");
+ line();
+ } else {
+ log_assert(state.back() == VALUE);
+ state.pop_back();
+ }
+}
+
+void PrettyJson::end_value()
+{
+ if (state.empty()) {
+ raw("\n");
+ flush();
+ }
+ if (GetSize(state) < compact_depth)
+ compact_depth = INT_MAX;
+}
+
+void PrettyJson::value_json(const Json &value)
+{
+ begin_value();
+ raw(value.dump().c_str());
+ end_value();
+}
+
+void PrettyJson::entry_json(const char *name, const Json &value)
+{
+ this->name(name);
+ this->value(value);
+}
+
diff --git a/kernel/json.h b/kernel/json.h
new file mode 100644
index 000000000..c9aa0e045
--- /dev/null
+++ b/kernel/json.h
@@ -0,0 +1,104 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2022 Jannis Harder <jix@yosyshq.com> <me@jix.one>
+ *
+ * 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 JSON_H
+#define JSON_H
+
+#include "kernel/yosys.h"
+#include "libs/json11/json11.hpp"
+#include <functional>
+
+YOSYS_NAMESPACE_BEGIN
+
+using json11::Json;
+
+class PrettyJson
+{
+ enum Scope {
+ VALUE,
+ OBJECT_FIRST,
+ OBJECT,
+ ARRAY_FIRST,
+ ARRAY,
+ };
+
+ struct Target {
+ virtual void emit(const char *data) = 0;
+ virtual void flush() {};
+ virtual ~Target() {};
+ };
+
+ std::string newline_indent = "\n";
+ std::vector<std::unique_ptr<Target>> targets;
+ std::vector<Scope> state = {VALUE};
+ int compact_depth = INT_MAX;
+public:
+
+ void emit_to_log();
+ void append_to_string(std::string &target);
+ bool write_to_file(const std::string &path);
+
+ bool active() { return !targets.empty(); }
+
+ void compact() { compact_depth = GetSize(state); }
+
+ void line(bool space_if_inline = true);
+ void raw(const char *raw_json);
+ void flush();
+ void begin_object();
+ void begin_array();
+ void end_object();
+ void end_array();
+ void name(const char *name);
+ void begin_value();
+ void end_value();
+ void value_json(const Json &value);
+ void value(unsigned int value) { value_json(Json((int)value)); }
+ template<typename T>
+ void value(T &&value) { value_json(Json(std::forward<T>(value))); };
+
+ void entry_json(const char *name, const Json &value);
+ void entry(const char *name, unsigned int value) { entry_json(name, Json((int)value)); }
+ template<typename T>
+ void entry(const char *name, T &&value) { entry_json(name, Json(std::forward<T>(value))); };
+
+ template<typename T>
+ void object(const T &&values)
+ {
+ begin_object();
+ for (auto &item : values)
+ entry(item.first, item.second);
+ end_object();
+ }
+
+ template<typename T>
+ void array(const T &&values)
+ {
+ begin_object();
+ for (auto &item : values)
+ value(item);
+ end_object();
+ }
+};
+
+
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/kernel/log.cc b/kernel/log.cc
index 4bcce3b28..75a1ffb45 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -40,8 +40,9 @@ YOSYS_NAMESPACE_BEGIN
std::vector<FILE*> log_files;
std::vector<std::ostream*> log_streams;
+std::vector<std::string> log_scratchpads;
std::map<std::string, std::set<std::string>> log_hdump;
-std::vector<YS_REGEX_TYPE> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
+std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error;
std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored;
int log_warnings_count = 0;
@@ -158,6 +159,11 @@ void logv(const char *format, va_list ap)
for (auto f : log_streams)
*f << str;
+ RTLIL::Design *design = yosys_get_design();
+ if (design != nullptr)
+ for (auto &scratchpad : log_scratchpads)
+ design->scratchpad[scratchpad].append(str);
+
static std::string linebuffer;
static bool log_warn_regex_recusion_guard = false;
@@ -175,11 +181,11 @@ void logv(const char *format, va_list ap)
if (!linebuffer.empty() && linebuffer.back() == '\n') {
for (auto &re : log_warn_regexes)
- if (YS_REGEX_NS::regex_search(linebuffer, re))
+ if (std::regex_search(linebuffer, re))
log_warning("Found log message matching -W regex:\n%s", str.c_str());
for (auto &item : log_expect_log)
- if (YS_REGEX_NS::regex_search(linebuffer, item.second.pattern))
+ if (std::regex_search(linebuffer, item.second.pattern))
item.second.current_count++;
linebuffer.clear();
@@ -236,7 +242,7 @@ static void logv_warning_with_prefix(const char *prefix,
bool suppressed = false;
for (auto &re : log_nowarn_regexes)
- if (YS_REGEX_NS::regex_search(message, re))
+ if (std::regex_search(message, re))
suppressed = true;
if (suppressed)
@@ -249,12 +255,12 @@ static void logv_warning_with_prefix(const char *prefix,
log_make_debug = 0;
for (auto &re : log_werror_regexes)
- if (YS_REGEX_NS::regex_search(message, re))
+ if (std::regex_search(message, re))
log_error("%s", message.c_str());
bool warning_match = false;
for (auto &item : log_expect_warning)
- if (YS_REGEX_NS::regex_search(message, item.second.pattern)) {
+ if (std::regex_search(message, item.second.pattern)) {
item.second.current_count++;
warning_match = true;
}
@@ -343,7 +349,7 @@ static void logv_error_with_prefix(const char *prefix,
log_make_debug = bak_log_make_debug;
for (auto &item : log_expect_error)
- if (YS_REGEX_NS::regex_search(log_last_error, item.second.pattern))
+ if (std::regex_search(log_last_error, item.second.pattern))
item.second.current_count++;
log_check_expected();
@@ -352,6 +358,9 @@ static void logv_error_with_prefix(const char *prefix,
log_error_atexit();
YS_DEBUGTRAP_IF_DEBUGGING;
+ const char *e = getenv("YOSYS_ABORT_ON_LOG_ERROR");
+ if (e && atoi(e))
+ abort();
#ifdef EMSCRIPTEN
log_files = backup_log_files;
@@ -627,7 +636,7 @@ const char *log_const(const RTLIL::Const &value, bool autoint)
}
}
-const char *log_id(RTLIL::IdString str)
+const char *log_id(const RTLIL::IdString &str)
{
log_id_cache.push_back(strdup(str.c_str()));
const char *p = log_id_cache.back();
@@ -698,6 +707,7 @@ void log_check_expected()
if (item.second.current_count == item.second.expected_count) {
log_warn_regexes.clear();
log("Expected error pattern '%s' found !!!\n", item.first.c_str());
+ yosys_shutdown();
#ifdef EMSCRIPTEN
throw 0;
#elif defined(_MSC_VER)
diff --git a/kernel/log.h b/kernel/log.h
index ea14028dd..3a6ec8758 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -24,51 +24,14 @@
#include <time.h>
-// In the libstdc++ headers that are provided by GCC 4.8, std::regex is not
-// working correctly. In order to make features using regular expressions
-// work, a replacement regex library is used. Just checking for GCC version
-// is not enough though, because at least on RHEL7/CentOS7 even when compiling
-// with Clang instead of GCC, the GCC 4.8 headers are still used for std::regex.
-// We have to check the version of the libstdc++ headers specifically, not the
-// compiler version. GCC headers of libstdc++ before version 3.4 define
-// __GLIBCPP__, later versions define __GLIBCXX__. GCC 7 and newer additionaly
-// define _GLIBCXX_RELEASE with a version number.
-// Include limits std C++ header, so we get the version macros defined:
-#if defined(__cplusplus)
-# include <limits>
-#endif
-// Check if libstdc++ is from GCC
-#if defined(__GLIBCPP__) || defined(__GLIBCXX__)
-// Check if version could be 4.8 or lower (this also matches for some 4.9 and
-// 5.0 releases). See:
-// https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning
-# if !defined(_GLIBCXX_RELEASE) && (defined(__GLIBCPP__) || __GLIBCXX__ <= 20150623)
-# define YS_HAS_BAD_STD_REGEX
-# endif
-#endif
-#if defined(YS_HAS_BAD_STD_REGEX)
- #include <boost/xpressive/xpressive.hpp>
- #define YS_REGEX_TYPE boost::xpressive::sregex
- #define YS_REGEX_MATCH_TYPE boost::xpressive::smatch
- #define YS_REGEX_NS boost::xpressive
- #define YS_REGEX_COMPILE(param) boost::xpressive::sregex::compile(param, \
- boost::xpressive::regex_constants::nosubs | \
- boost::xpressive::regex_constants::optimize)
- #define YS_REGEX_COMPILE_WITH_SUBS(param) boost::xpressive::sregex::compile(param, \
- boost::xpressive::regex_constants::optimize)
-# else
- #include <regex>
- #define YS_REGEX_TYPE std::regex
- #define YS_REGEX_MATCH_TYPE std::smatch
- #define YS_REGEX_NS std
- #define YS_REGEX_COMPILE(param) std::regex(param, \
- std::regex_constants::nosubs | \
- std::regex_constants::optimize | \
- std::regex_constants::egrep)
- #define YS_REGEX_COMPILE_WITH_SUBS(param) std::regex(param, \
- std::regex_constants::optimize | \
- std::regex_constants::egrep)
-#endif
+#include <regex>
+#define YS_REGEX_COMPILE(param) std::regex(param, \
+ std::regex_constants::nosubs | \
+ std::regex_constants::optimize | \
+ std::regex_constants::egrep)
+#define YS_REGEX_COMPILE_WITH_SUBS(param) std::regex(param, \
+ std::regex_constants::optimize | \
+ std::regex_constants::egrep)
#if defined(_WIN32)
# include <intrin.h>
@@ -133,8 +96,9 @@ struct log_cmd_error_exception { };
extern std::vector<FILE*> log_files;
extern std::vector<std::ostream*> log_streams;
+extern std::vector<std::string> log_scratchpads;
extern std::map<std::string, std::set<std::string>> log_hdump;
-extern std::vector<YS_REGEX_TYPE> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
+extern std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
extern std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored;
extern int log_warnings_count;
extern int log_warnings_count_noexpect;
@@ -223,11 +187,11 @@ void log_flush();
struct LogExpectedItem
{
- LogExpectedItem(const YS_REGEX_TYPE &pat, int expected) :
+ LogExpectedItem(const std::regex &pat, int expected) :
pattern(pat), expected_count(expected), current_count(0) {}
LogExpectedItem() : expected_count(0), current_count(0) {}
- YS_REGEX_TYPE pattern;
+ std::regex pattern;
int expected_count;
int current_count;
};
@@ -237,7 +201,7 @@ void log_check_expected();
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
const char *log_const(const RTLIL::Const &value, bool autoint = true);
-const char *log_id(RTLIL::IdString id);
+const char *log_id(const RTLIL::IdString &id);
template<typename T> static inline const char *log_id(T *obj, const char *nullstr = nullptr) {
if (nullstr && obj == nullptr)
@@ -393,6 +357,11 @@ void log_dump_val_worker(RTLIL::IdString v);
void log_dump_val_worker(RTLIL::SigSpec v);
void log_dump_val_worker(RTLIL::State v);
+template<typename K, typename T, typename OPS> static inline void log_dump_val_worker(dict<K, T, OPS> &v);
+template<typename K, typename OPS> static inline void log_dump_val_worker(pool<K, OPS> &v);
+template<typename K> static inline void log_dump_val_worker(std::vector<K> &v);
+template<typename T> static inline void log_dump_val_worker(T *ptr);
+
template<typename K, typename T, typename OPS>
static inline void log_dump_val_worker(dict<K, T, OPS> &v) {
log("{");
@@ -419,6 +388,18 @@ static inline void log_dump_val_worker(pool<K, OPS> &v) {
log(" }");
}
+template<typename K>
+static inline void log_dump_val_worker(std::vector<K> &v) {
+ log("{");
+ bool first = true;
+ for (auto &it : v) {
+ log(first ? " " : ", ");
+ log_dump_val_worker(it);
+ first = false;
+ }
+ log(" }");
+}
+
template<typename T>
static inline void log_dump_val_worker(T *ptr) { log("%p", ptr); }
diff --git a/kernel/mem.cc b/kernel/mem.cc
index e5e855ef7..ed01a0867 100644
--- a/kernel/mem.cc
+++ b/kernel/mem.cc
@@ -504,6 +504,7 @@ void Mem::check() {
int mask = (1 << max_wide_log2) - 1;
log_assert(!(start_offset & mask));
log_assert(!(size & mask));
+ log_assert(width != 0);
}
namespace {
diff --git a/kernel/modtools.h b/kernel/modtools.h
index 4cbaf78d0..34a23b379 100644
--- a/kernel/modtools.h
+++ b/kernel/modtools.h
@@ -409,7 +409,6 @@ struct ModWalker
// get_* methods -- single RTLIL::SigBit
- template<typename T>
inline bool get_drivers(pool<PortBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
@@ -421,7 +420,6 @@ struct ModWalker
return found;
}
- template<typename T>
inline bool get_consumers(pool<PortBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
@@ -433,7 +431,6 @@ struct ModWalker
return found;
}
- template<typename T>
inline bool get_inputs(pool<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
@@ -442,7 +439,6 @@ struct ModWalker
return found;
}
- template<typename T>
inline bool get_outputs(pool<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
diff --git a/kernel/register.cc b/kernel/register.cc
index 226963fda..9ffb17c1a 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -108,7 +108,9 @@ Pass::Pass(std::string name, std::string short_help) : pass_name(name), short_he
void Pass::run_register()
{
- log_assert(pass_register.count(pass_name) == 0);
+ if (pass_register.count(pass_name))
+ log_error("Unable to register pass '%s', pass already exists!\n", pass_name.c_str());
+
pass_register[pass_name] = this;
}
@@ -445,10 +447,13 @@ Frontend::Frontend(std::string name, std::string short_help) :
void Frontend::run_register()
{
- log_assert(pass_register.count(pass_name) == 0);
+ if (pass_register.count(pass_name))
+ log_error("Unable to register pass '%s', pass already exists!\n", pass_name.c_str());
pass_register[pass_name] = this;
- log_assert(frontend_register.count(frontend_name) == 0);
+ if (frontend_register.count(frontend_name))
+ log_error("Unable to register frontend '%s', frontend already exists!\n", frontend_name.c_str());
+
frontend_register[frontend_name] = this;
}
@@ -526,10 +531,11 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
std::ifstream *ff = new std::ifstream;
ff->open(filename.c_str(), bin_input ? std::ifstream::binary : std::ifstream::in);
yosys_input_files.insert(filename);
- if (ff->fail())
+ if (ff->fail()) {
delete ff;
- else
- f = ff;
+ ff = nullptr;
+ }
+ f = ff;
if (f != NULL) {
// Check for gzip magic
unsigned char magic[3];
@@ -626,10 +632,12 @@ Backend::Backend(std::string name, std::string short_help) :
void Backend::run_register()
{
- log_assert(pass_register.count(pass_name) == 0);
+ if (pass_register.count(pass_name))
+ log_error("Unable to register pass '%s', pass already exists!\n", pass_name.c_str());
pass_register[pass_name] = this;
- log_assert(backend_register.count(backend_name) == 0);
+ if (backend_register.count(backend_name))
+ log_error("Unable to register backend '%s', backend already exists!\n", backend_name.c_str());
backend_register[backend_name] = this;
}
@@ -765,61 +773,98 @@ struct HelpPass : public Pass {
log(" help <celltype>+ .... print verilog code for given cell type\n");
log("\n");
}
- void escape_tex(std::string &tex)
- {
- for (size_t pos = 0; (pos = tex.find('_', pos)) != std::string::npos; pos += 2)
- tex.replace(pos, 1, "\\_");
- 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)
+ void write_rst(std::string cmd, std::string title, std::string text)
{
- size_t begin = text.find_first_not_of("\n"), end = text.find_last_not_of("\n");
- if (begin != std::string::npos && end != std::string::npos && begin < end)
- text = text.substr(begin, end-begin+1);
- std::string cmd_unescaped = cmd;
- escape_tex(cmd);
- escape_tex(title);
- fprintf(f, "\\section{%s -- %s}\n", cmd.c_str(), title.c_str());
- fprintf(f, "\\label{cmd:%s}\n", cmd_unescaped.c_str());
- fprintf(f, "\\begin{lstlisting}[numbers=left,frame=single]\n");
- fprintf(f, "%s\n\\end{lstlisting}\n\n", text.c_str());
- }
- void escape_html(std::string &html)
- {
- size_t pos = 0;
- while ((pos = html.find_first_of("<>&", pos)) != std::string::npos)
- switch (html[pos]) {
- case '<':
- html.replace(pos, 1, "&lt;");
- pos += 4;
- break;
- case '>':
- html.replace(pos, 1, "&gt;");
- pos += 4;
- break;
- case '&':
- html.replace(pos, 1, "&amp;");
- pos += 5;
- break;
+ FILE *f = fopen(stringf("docs/source/cmd/%s.rst", cmd.c_str()).c_str(), "wt");
+ // make header
+ size_t char_len = cmd.length() + 3 + title.length();
+ std::string title_line = "\n";
+ title_line.insert(0, char_len, '=');
+ fprintf(f, "%s", title_line.c_str());
+ fprintf(f, "%s - %s\n", cmd.c_str(), title.c_str());
+ fprintf(f, "%s\n", title_line.c_str());
+ fprintf(f, ".. raw:: latex\n\n \\begin{comment}\n\n");
+
+ // render html
+ fprintf(f, ":code:`yosys> help %s`\n", cmd.c_str());
+ fprintf(f, "--------------------------------------------------------------------------------\n\n");
+ fprintf(f, ".. container:: cmdref\n");
+ std::stringstream ss;
+ std::string textcp = text;
+ ss << text;
+ bool IsUsage = true;
+ int blank_count = 0;
+ size_t def_strip_count = 0;
+ bool WasDefinition = false;
+ for (std::string line; std::getline(ss, line, '\n');) {
+ // find position of first non space character
+ std::size_t first_pos = line.find_first_not_of(" \t");
+ std::size_t last_pos = line.find_last_not_of(" \t");
+ if (first_pos == std::string::npos) {
+ // skip formatting empty lines
+ if (!WasDefinition)
+ fputc('\n', f);
+ blank_count += 1;
+ continue;
}
- }
- void write_html(FILE *idxf, std::string cmd, std::string title, std::string text)
- {
- FILE *f = fopen(stringf("cmd_%s.in", cmd.c_str()).c_str(), "wt");
- fprintf(idxf, "<li><a href=\"cmd_%s.html\"> ", cmd.c_str());
- escape_html(cmd);
- escape_html(title);
- escape_html(text);
-
- fprintf(idxf, "%s</a> <span>%s</span></a>\n", cmd.c_str(), title.c_str());
-
- fprintf(f, "@cmd_header %s@\n", cmd.c_str());
- fprintf(f, "<h1>%s - %s</h1>\n", cmd.c_str(), title.c_str());
- fprintf(f, "<pre>%s</pre>\n", text.c_str());
- fprintf(f, "@footer@\n");
+ // strip leading and trailing whitespace
+ std::string stripped_line = line.substr(first_pos, last_pos - first_pos +1);
+ bool IsDefinition = stripped_line[0] == '-';
+ IsDefinition &= stripped_line[1] != ' ' && stripped_line[1] != '>';
+ bool IsDedent = def_strip_count && first_pos <= def_strip_count;
+ bool IsIndent = first_pos == 2 || first_pos == 4;
+ if (cmd.compare(0, 7, "verific") == 0)
+ // verific.cc has strange and different formatting from the rest
+ IsIndent = false;
+
+ // another usage block
+ bool NewUsage = stripped_line.find(cmd) == 0;
+
+ if (IsUsage) {
+ if (stripped_line.compare(0, 4, "See ") == 0) {
+ // description refers to another function
+ fprintf(f, "\n %s\n", stripped_line.c_str());
+ } else {
+ // usage should be the first line of help output
+ fprintf(f, "\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str());
+ WasDefinition = true;
+ }
+ IsUsage = false;
+ } else if (IsIndent && NewUsage && (blank_count >= 2 || WasDefinition)) {
+ // another usage block
+ fprintf(f, "\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str());
+ WasDefinition = true;
+ def_strip_count = 0;
+ } else if (IsIndent && IsDefinition && (blank_count || WasDefinition)) {
+ // format definition term
+ fprintf(f, "\n\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str());
+ WasDefinition = true;
+ def_strip_count = first_pos;
+ } else {
+ if (IsDedent) {
+ fprintf(f, "\n\n ::\n");
+ def_strip_count = first_pos;
+ } else if (WasDefinition) {
+ fprintf(f, " ::\n");
+ WasDefinition = false;
+ }
+ fprintf(f, "\n %s", line.substr(def_strip_count, std::string::npos).c_str());
+ }
+ blank_count = 0;
+ }
+ fputc('\n', f);
+
+ // render latex
+ fprintf(f, ".. raw:: latex\n\n \\end{comment}\n\n");
+ fprintf(f, ".. only:: latex\n\n");
+ fprintf(f, " ::\n\n");
+ std::stringstream ss2;
+ ss2 << textcp;
+ for (std::string line; std::getline(ss2, line, '\n');) {
+ fprintf(f, " %s\n", line.c_str());
+ }
fclose(f);
}
void execute(std::vector<std::string> args, RTLIL::Design*) override
@@ -864,26 +909,7 @@ struct HelpPass : public Pass {
return;
}
// this option is undocumented as it is for internal use only
- else if (args[1] == "-write-tex-command-reference-manual") {
- FILE *f = fopen("command-reference-manual.tex", "wt");
- fprintf(f, "%% Generated using the yosys 'help -write-tex-command-reference-manual' command.\n\n");
- for (auto &it : pass_register) {
- std::ostringstream buf;
- log_streams.push_back(&buf);
- it.second->help();
- if (it.second->experimental_flag) {
- log("\n");
- log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str());
- log("\n");
- }
- log_streams.pop_back();
- write_tex(f, it.first, it.second->short_help, buf.str());
- }
- fclose(f);
- }
- // this option is undocumented as it is for internal use only
- else if (args[1] == "-write-web-command-reference-manual") {
- FILE *f = fopen("templates/cmd_index.in", "wt");
+ else if (args[1] == "-write-rst-command-reference-manual") {
for (auto &it : pass_register) {
std::ostringstream buf;
log_streams.push_back(&buf);
@@ -894,9 +920,8 @@ struct HelpPass : public Pass {
log("\n");
}
log_streams.pop_back();
- write_html(f, it.first, it.second->short_help, buf.str());
+ write_rst(it.first, it.second->short_help, buf.str());
}
- fclose(f);
}
else if (pass_register.count(args[1])) {
pass_register.at(args[1])->help();
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index dc4ea9a78..7f3508b2f 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -199,11 +199,6 @@ const pool<IdString> &RTLIL::builtin_ff_cell_types() {
return res;
}
-RTLIL::Const::Const()
-{
- flags = RTLIL::CONST_FLAG_NONE;
-}
-
RTLIL::Const::Const(const std::string &str)
{
flags = RTLIL::CONST_FLAG_STRING;
@@ -375,6 +370,17 @@ bool RTLIL::Const::is_fully_undef() const
return true;
}
+bool RTLIL::Const::is_fully_undef_x_only() const
+{
+ cover("kernel.rtlil.const.is_fully_undef_x_only");
+
+ for (const auto &bit : bits)
+ if (bit != RTLIL::State::Sx)
+ return false;
+
+ return true;
+}
+
bool RTLIL::Const::is_onehot(int *pos) const
{
cover("kernel.rtlil.const.is_onehot");
@@ -395,12 +401,12 @@ bool RTLIL::Const::is_onehot(int *pos) const
return found;
}
-bool RTLIL::AttrObject::has_attribute(RTLIL::IdString id) const
+bool RTLIL::AttrObject::has_attribute(const RTLIL::IdString &id) const
{
return attributes.count(id);
}
-void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value)
+void RTLIL::AttrObject::set_bool_attribute(const RTLIL::IdString &id, bool value)
{
if (value)
attributes[id] = RTLIL::Const(1);
@@ -408,7 +414,7 @@ void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value)
attributes.erase(id);
}
-bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
+bool RTLIL::AttrObject::get_bool_attribute(const RTLIL::IdString &id) const
{
const auto it = attributes.find(id);
if (it == attributes.end())
@@ -416,7 +422,7 @@ bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
return it->second.as_bool();
}
-void RTLIL::AttrObject::set_string_attribute(RTLIL::IdString id, string value)
+void RTLIL::AttrObject::set_string_attribute(const RTLIL::IdString& id, string value)
{
if (value.empty())
attributes.erase(id);
@@ -424,7 +430,7 @@ void RTLIL::AttrObject::set_string_attribute(RTLIL::IdString id, string value)
attributes[id] = value;
}
-string RTLIL::AttrObject::get_string_attribute(RTLIL::IdString id) const
+string RTLIL::AttrObject::get_string_attribute(const RTLIL::IdString &id) const
{
std::string value;
const auto it = attributes.find(id);
@@ -433,7 +439,7 @@ string RTLIL::AttrObject::get_string_attribute(RTLIL::IdString id) const
return value;
}
-void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
+void RTLIL::AttrObject::set_strpool_attribute(const RTLIL::IdString& id, const pool<string> &data)
{
string attrval;
for (const auto &s : data) {
@@ -444,7 +450,7 @@ void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<str
set_string_attribute(id, attrval);
}
-void RTLIL::AttrObject::add_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
+void RTLIL::AttrObject::add_strpool_attribute(const RTLIL::IdString& id, const pool<string> &data)
{
pool<string> union_data = get_strpool_attribute(id);
union_data.insert(data.begin(), data.end());
@@ -452,7 +458,7 @@ void RTLIL::AttrObject::add_strpool_attribute(RTLIL::IdString id, const pool<str
set_strpool_attribute(id, union_data);
}
-pool<string> RTLIL::AttrObject::get_strpool_attribute(RTLIL::IdString id) const
+pool<string> RTLIL::AttrObject::get_strpool_attribute(const RTLIL::IdString &id) const
{
pool<string> data;
if (attributes.count(id) != 0)
@@ -477,7 +483,7 @@ vector<string> RTLIL::AttrObject::get_hdlname_attribute() const
return split_tokens(get_string_attribute(ID::hdlname), " ");
}
-void RTLIL::AttrObject::set_intvec_attribute(RTLIL::IdString id, const vector<int> &data)
+void RTLIL::AttrObject::set_intvec_attribute(const RTLIL::IdString& id, const vector<int> &data)
{
std::stringstream attrval;
for (auto &i : data) {
@@ -488,7 +494,7 @@ void RTLIL::AttrObject::set_intvec_attribute(RTLIL::IdString id, const vector<in
attributes[id] = RTLIL::Const(attrval.str());
}
-vector<int> RTLIL::AttrObject::get_intvec_attribute(RTLIL::IdString id) const
+vector<int> RTLIL::AttrObject::get_intvec_attribute(const RTLIL::IdString &id) const
{
vector<int> data;
auto it = attributes.find(id);
@@ -506,7 +512,7 @@ vector<int> RTLIL::AttrObject::get_intvec_attribute(RTLIL::IdString id) const
return data;
}
-bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const
+bool RTLIL::Selection::selected_module(const RTLIL::IdString &mod_name) const
{
if (full_selection)
return true;
@@ -517,7 +523,7 @@ bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const
return false;
}
-bool RTLIL::Selection::selected_whole_module(RTLIL::IdString mod_name) const
+bool RTLIL::Selection::selected_whole_module(const RTLIL::IdString &mod_name) const
{
if (full_selection)
return true;
@@ -526,7 +532,7 @@ bool RTLIL::Selection::selected_whole_module(RTLIL::IdString mod_name) const
return false;
}
-bool RTLIL::Selection::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const
+bool RTLIL::Selection::selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const
{
if (full_selection)
return true;
@@ -638,12 +644,12 @@ RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules()
return RTLIL::ObjRange<RTLIL::Module*>(&modules_, &refcount_modules_);
}
-RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name)
+RTLIL::Module *RTLIL::Design::module(const RTLIL::IdString& name)
{
return modules_.count(name) ? modules_.at(name) : NULL;
}
-const RTLIL::Module *RTLIL::Design::module(RTLIL::IdString name) const
+const RTLIL::Module *RTLIL::Design::module(const RTLIL::IdString& name) const
{
return modules_.count(name) ? modules_.at(name) : NULL;
}
@@ -825,7 +831,7 @@ void RTLIL::Design::optimize()
it.second.optimize(this);
}
-bool RTLIL::Design::selected_module(RTLIL::IdString mod_name) const
+bool RTLIL::Design::selected_module(const RTLIL::IdString& mod_name) const
{
if (!selected_active_module.empty() && mod_name != selected_active_module)
return false;
@@ -834,7 +840,7 @@ bool RTLIL::Design::selected_module(RTLIL::IdString mod_name) const
return selection_stack.back().selected_module(mod_name);
}
-bool RTLIL::Design::selected_whole_module(RTLIL::IdString mod_name) const
+bool RTLIL::Design::selected_whole_module(const RTLIL::IdString& mod_name) const
{
if (!selected_active_module.empty() && mod_name != selected_active_module)
return false;
@@ -843,7 +849,7 @@ bool RTLIL::Design::selected_whole_module(RTLIL::IdString mod_name) const
return selection_stack.back().selected_whole_module(mod_name);
}
-bool RTLIL::Design::selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const
+bool RTLIL::Design::selected_member(const RTLIL::IdString& mod_name, const RTLIL::IdString& memb_name) const
{
if (!selected_active_module.empty() && mod_name != selected_active_module)
return false;
@@ -987,7 +993,7 @@ RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, const dict<RTLIL::IdString
log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name));
}
-size_t RTLIL::Module::count_id(RTLIL::IdString id)
+size_t RTLIL::Module::count_id(const RTLIL::IdString& id)
{
return wires_.count(id) + memories.count(id) + cells_.count(id) + processes.count(id);
}
@@ -1012,7 +1018,7 @@ namespace {
cell->name.c_str(), cell->type.c_str(), __FILE__, linenr, buf.str().c_str());
}
- int param(RTLIL::IdString name)
+ int param(const RTLIL::IdString& name)
{
auto it = cell->parameters.find(name);
if (it == cell->parameters.end())
@@ -1021,7 +1027,7 @@ namespace {
return it->second.as_int();
}
- int param_bool(RTLIL::IdString name)
+ int param_bool(const RTLIL::IdString& name)
{
int v = param(name);
if (GetSize(cell->parameters.at(name)) > 32)
@@ -1031,7 +1037,7 @@ namespace {
return v;
}
- int param_bool(RTLIL::IdString name, bool expected)
+ int param_bool(const RTLIL::IdString& name, bool expected)
{
int v = param_bool(name);
if (v != expected)
@@ -1039,14 +1045,14 @@ namespace {
return v;
}
- void param_bits(RTLIL::IdString name, int width)
+ void param_bits(const RTLIL::IdString& name, int width)
{
param(name);
if (GetSize(cell->parameters.at(name).bits) != width)
error(__LINE__);
}
- void port(RTLIL::IdString name, int width)
+ void port(const RTLIL::IdString& name, int width)
{
auto it = cell->connections_.find(name);
if (it == cell->connections_.end())
@@ -1618,6 +1624,23 @@ namespace {
return;
}
+ if (cell->type == ID($bweqx)) {
+ port(ID::A, param(ID::WIDTH));
+ port(ID::B, param(ID::WIDTH));
+ port(ID::Y, param(ID::WIDTH));
+ check_expected();
+ return;
+ }
+
+ if (cell->type == ID($bwmux)) {
+ port(ID::A, param(ID::WIDTH));
+ port(ID::B, param(ID::WIDTH));
+ port(ID::S, param(ID::WIDTH));
+ port(ID::Y, param(ID::WIDTH));
+ check_expected();
+ return;
+ }
+
if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover))) {
port(ID::A, 1);
port(ID::EN, 1);
@@ -1637,6 +1660,13 @@ namespace {
return;
}
+ if (cell->type.in(ID($anyinit))) {
+ port(ID::D, param(ID::WIDTH));
+ port(ID::Q, param(ID::WIDTH));
+ check_expected();
+ return;
+ }
+
if (cell->type == ID($equiv)) {
port(ID::A, 1);
port(ID::B, 1);
@@ -2464,6 +2494,7 @@ DEF_METHOD(Sshr, sig_a.size(), ID($sshr))
return sig_y; \
}
DEF_METHOD(Mux, ID($mux), 0)
+DEF_METHOD(Bwmux, ID($bwmux), 0)
DEF_METHOD(Pmux, ID($pmux), 1)
#undef DEF_METHOD
@@ -2487,6 +2518,24 @@ DEF_METHOD(Bmux, ID($bmux), 0)
DEF_METHOD(Demux, ID($demux), 1)
#undef DEF_METHOD
+#define DEF_METHOD(_func, _type) \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src) { \
+ RTLIL::Cell *cell = addCell(name, _type); \
+ cell->parameters[ID::WIDTH] = sig_a.size(); \
+ cell->setPort(ID::A, sig_a); \
+ cell->setPort(ID::B, sig_b); \
+ cell->setPort(ID::Y, sig_y); \
+ cell->set_src_attribute(src); \
+ return cell; \
+ } \
+ RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src) { \
+ RTLIL::SigSpec sig_y = addWire(NEW_ID, sig_a.size()); \
+ add ## _func(name, sig_a, sig_s, sig_y, src); \
+ return sig_y; \
+ }
+DEF_METHOD(Bweqx, ID($bweqx))
+#undef DEF_METHOD
+
#define DEF_METHOD_2(_func, _type, _P1, _P2) \
RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const std::string &src) { \
RTLIL::Cell *cell = addCell(name, _type); \
@@ -3125,6 +3174,16 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, const RTLIL::S
return cell;
}
+RTLIL::Cell* RTLIL::Module::addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src)
+{
+ RTLIL::Cell *cell = addCell(name, ID($anyinit));
+ cell->parameters[ID::WIDTH] = sig_q.size();
+ cell->setPort(ID::D, sig_d);
+ cell->setPort(ID::Q, sig_q);
+ cell->set_src_attribute(src);
+ return cell;
+}
+
RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const std::string &src)
{
RTLIL::SigSpec sig = addWire(NEW_ID, width);
@@ -3259,12 +3318,12 @@ std::map<unsigned int, RTLIL::Cell*> *RTLIL::Cell::get_all_cells(void)
}
#endif
-bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const
+bool RTLIL::Cell::hasPort(const RTLIL::IdString& portname) const
{
return connections_.count(portname) != 0;
}
-void RTLIL::Cell::unsetPort(RTLIL::IdString portname)
+void RTLIL::Cell::unsetPort(const RTLIL::IdString& portname)
{
RTLIL::SigSpec signal;
auto conn_it = connections_.find(portname);
@@ -3287,7 +3346,7 @@ void RTLIL::Cell::unsetPort(RTLIL::IdString portname)
}
}
-void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
+void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal)
{
auto r = connections_.insert(portname);
auto conn_it = r.first;
@@ -3309,7 +3368,7 @@ void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
conn_it->second = std::move(signal);
}
-const RTLIL::SigSpec &RTLIL::Cell::getPort(RTLIL::IdString portname) const
+const RTLIL::SigSpec &RTLIL::Cell::getPort(const RTLIL::IdString& portname) const
{
return connections_.at(portname);
}
@@ -3328,7 +3387,7 @@ bool RTLIL::Cell::known() const
return false;
}
-bool RTLIL::Cell::input(RTLIL::IdString portname) const
+bool RTLIL::Cell::input(const RTLIL::IdString& portname) const
{
if (yosys_celltypes.cell_known(type))
return yosys_celltypes.cell_input(type, portname);
@@ -3340,7 +3399,7 @@ bool RTLIL::Cell::input(RTLIL::IdString portname) const
return false;
}
-bool RTLIL::Cell::output(RTLIL::IdString portname) const
+bool RTLIL::Cell::output(const RTLIL::IdString& portname) const
{
if (yosys_celltypes.cell_known(type))
return yosys_celltypes.cell_output(type, portname);
@@ -3352,22 +3411,22 @@ bool RTLIL::Cell::output(RTLIL::IdString portname) const
return false;
}
-bool RTLIL::Cell::hasParam(RTLIL::IdString paramname) const
+bool RTLIL::Cell::hasParam(const RTLIL::IdString& paramname) const
{
return parameters.count(paramname) != 0;
}
-void RTLIL::Cell::unsetParam(RTLIL::IdString paramname)
+void RTLIL::Cell::unsetParam(const RTLIL::IdString& paramname)
{
parameters.erase(paramname);
}
-void RTLIL::Cell::setParam(RTLIL::IdString paramname, RTLIL::Const value)
+void RTLIL::Cell::setParam(const RTLIL::IdString& paramname, RTLIL::Const value)
{
parameters[paramname] = std::move(value);
}
-const RTLIL::Const &RTLIL::Cell::getParam(RTLIL::IdString paramname) const
+const RTLIL::Const &RTLIL::Cell::getParam(const RTLIL::IdString& paramname) const
{
const auto &it = parameters.find(paramname);
if (it != parameters.end())
@@ -3472,61 +3531,6 @@ bool RTLIL::Cell::is_mem_cell() const
return type.in(ID($mem), ID($mem_v2)) || has_memid();
}
-RTLIL::SigChunk::SigChunk()
-{
- wire = NULL;
- width = 0;
- offset = 0;
-}
-
-RTLIL::SigChunk::SigChunk(const RTLIL::Const &value)
-{
- wire = NULL;
- data = value.bits;
- width = GetSize(data);
- offset = 0;
-}
-
-RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire)
-{
- log_assert(wire != nullptr);
- this->wire = wire;
- this->width = wire->width;
- this->offset = 0;
-}
-
-RTLIL::SigChunk::SigChunk(RTLIL::Wire *wire, int offset, int width)
-{
- log_assert(wire != nullptr);
- this->wire = wire;
- this->width = width;
- this->offset = offset;
-}
-
-RTLIL::SigChunk::SigChunk(const std::string &str)
-{
- wire = NULL;
- data = RTLIL::Const(str).bits;
- width = GetSize(data);
- offset = 0;
-}
-
-RTLIL::SigChunk::SigChunk(int val, int width)
-{
- wire = NULL;
- data = RTLIL::Const(val, width).bits;
- this->width = GetSize(data);
- offset = 0;
-}
-
-RTLIL::SigChunk::SigChunk(RTLIL::State bit, int width)
-{
- wire = NULL;
- data = RTLIL::Const(bit, width).bits;
- this->width = GetSize(data);
- offset = 0;
-}
-
RTLIL::SigChunk::SigChunk(const RTLIL::SigBit &bit)
{
wire = bit.wire;
@@ -3538,11 +3542,6 @@ RTLIL::SigChunk::SigChunk(const RTLIL::SigBit &bit)
width = 1;
}
-RTLIL::SigChunk::SigChunk(const RTLIL::SigChunk &sigchunk)
-{
- *this = sigchunk;
-}
-
RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const
{
RTLIL::SigChunk ret;
@@ -3588,17 +3587,6 @@ bool RTLIL::SigChunk::operator !=(const RTLIL::SigChunk &other) const
return true;
}
-RTLIL::SigSpec::SigSpec()
-{
- width_ = 0;
- hash_ = 0;
-}
-
-RTLIL::SigSpec::SigSpec(const RTLIL::SigSpec &other)
-{
- *this = other;
-}
-
RTLIL::SigSpec::SigSpec(std::initializer_list<RTLIL::SigSpec> parts)
{
cover("kernel.rtlil.sigspec.init.list");
@@ -3613,23 +3601,26 @@ RTLIL::SigSpec::SigSpec(std::initializer_list<RTLIL::SigSpec> parts)
append(*it--);
}
-RTLIL::SigSpec &RTLIL::SigSpec::operator=(const RTLIL::SigSpec &other)
+RTLIL::SigSpec::SigSpec(const RTLIL::Const &value)
{
- cover("kernel.rtlil.sigspec.assign");
+ cover("kernel.rtlil.sigspec.init.const");
- width_ = other.width_;
- hash_ = other.hash_;
- chunks_ = other.chunks_;
- bits_ = other.bits_;
- return *this;
+ if (GetSize(value) != 0) {
+ chunks_.emplace_back(value);
+ width_ = chunks_.back().width;
+ } else {
+ width_ = 0;
+ }
+ hash_ = 0;
+ check();
}
-RTLIL::SigSpec::SigSpec(const RTLIL::Const &value)
+RTLIL::SigSpec::SigSpec(RTLIL::Const &&value)
{
- cover("kernel.rtlil.sigspec.init.const");
+ cover("kernel.rtlil.sigspec.init.const.move");
if (GetSize(value) != 0) {
- chunks_.emplace_back(value);
+ chunks_.emplace_back(std::move(value));
width_ = chunks_.back().width;
} else {
width_ = 0;
@@ -3652,6 +3643,20 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk)
check();
}
+RTLIL::SigSpec::SigSpec(RTLIL::SigChunk &&chunk)
+{
+ cover("kernel.rtlil.sigspec.init.chunk.move");
+
+ if (chunk.width != 0) {
+ chunks_.emplace_back(std::move(chunk));
+ width_ = chunks_.back().width;
+ } else {
+ width_ = 0;
+ }
+ hash_ = 0;
+ check();
+}
+
RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire)
{
cover("kernel.rtlil.sigspec.init.wire");
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 7a0b6b9c7..7c7669caa 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -168,7 +168,7 @@ namespace RTLIL
log_assert(p[1] != 0);
for (const char *c = p; *c; c++)
if ((unsigned)*c <= (unsigned)' ')
- log_error("Found control character or space (0x%02hhx) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p);
+ log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p);
#ifndef YOSYS_NO_IDS_REFCNT
if (global_free_idx_list_.empty()) {
@@ -414,11 +414,11 @@ namespace RTLIL
return str.substr(1);
}
- static inline std::string unescape_id(RTLIL::IdString str) {
+ static inline std::string unescape_id(const RTLIL::IdString &str) {
return unescape_id(str.str());
}
- static inline const char *id2cstr(RTLIL::IdString str) {
+ static inline const char *id2cstr(const RTLIL::IdString &str) {
return log_id(str);
}
@@ -435,11 +435,26 @@ namespace RTLIL
};
struct sort_by_id_str {
- bool operator()(RTLIL::IdString a, RTLIL::IdString b) const {
+ bool operator()(const RTLIL::IdString &a, const RTLIL::IdString &b) const {
return strcmp(a.c_str(), b.c_str()) < 0;
}
};
+ static inline std::string encode_filename(const std::string &filename)
+ {
+ std::stringstream val;
+ if (!std::any_of(filename.begin(), filename.end(), [](char c) {
+ return static_cast<unsigned char>(c) < 33 || static_cast<unsigned char>(c) > 126;
+ })) return filename;
+ for (unsigned char const c : filename) {
+ if (c < 33 || c > 126)
+ val << stringf("$%02x", c);
+ else
+ val << c;
+ }
+ return val.str();
+ }
+
// see calc.cc for the implementation of this functions
RTLIL::Const const_not (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_and (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
@@ -485,9 +500,14 @@ namespace RTLIL
RTLIL::Const const_pos (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
RTLIL::Const const_neg (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len);
+ RTLIL::Const const_mux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3);
+ RTLIL::Const const_pmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3);
RTLIL::Const const_bmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2);
RTLIL::Const const_demux (const RTLIL::Const &arg1, const RTLIL::Const &arg2);
+ RTLIL::Const const_bweqx (const RTLIL::Const &arg1, const RTLIL::Const &arg2);
+ RTLIL::Const const_bwmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3);
+
// This iterator-range-pair is used for Design::modules(), Module::wires() and Module::cells().
// It maintains a reference counter that is used to make sure that the container is not modified while being iterated over.
@@ -635,7 +655,7 @@ struct RTLIL::Const
int flags;
std::vector<RTLIL::State> bits;
- Const();
+ Const() : flags(RTLIL::CONST_FLAG_NONE) {}
Const(const std::string &str);
Const(int val, int width = 32);
Const(RTLIL::State bit, int width = 1);
@@ -666,6 +686,7 @@ struct RTLIL::Const
bool is_fully_ones() const;
bool is_fully_def() const;
bool is_fully_undef() const;
+ bool is_fully_undef_x_only() const;
bool is_onehot(int *pos = nullptr) const;
inline RTLIL::Const extract(int offset, int len = 1, RTLIL::State padding = RTLIL::State::S0) const {
@@ -696,21 +717,21 @@ struct RTLIL::AttrObject
{
dict<RTLIL::IdString, RTLIL::Const> attributes;
- bool has_attribute(RTLIL::IdString id) const;
+ bool has_attribute(const RTLIL::IdString &id) const;
- void set_bool_attribute(RTLIL::IdString id, bool value=true);
- bool get_bool_attribute(RTLIL::IdString id) const;
+ void set_bool_attribute(const RTLIL::IdString &id, bool value=true);
+ bool get_bool_attribute(const RTLIL::IdString &id) const;
bool get_blackbox_attribute(bool ignore_wb=false) const {
return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox));
}
- void set_string_attribute(RTLIL::IdString id, string value);
- string get_string_attribute(RTLIL::IdString id) const;
+ void set_string_attribute(const RTLIL::IdString& id, string value);
+ string get_string_attribute(const RTLIL::IdString &id) const;
- void set_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
- void add_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
- pool<string> get_strpool_attribute(RTLIL::IdString id) const;
+ void set_strpool_attribute(const RTLIL::IdString& id, const pool<string> &data);
+ void add_strpool_attribute(const RTLIL::IdString& id, const pool<string> &data);
+ pool<string> get_strpool_attribute(const RTLIL::IdString &id) const;
void set_src_attribute(const std::string &src) {
set_string_attribute(ID::src, src);
@@ -722,8 +743,8 @@ struct RTLIL::AttrObject
void set_hdlname_attribute(const vector<string> &hierarchy);
vector<string> get_hdlname_attribute() const;
- void set_intvec_attribute(RTLIL::IdString id, const vector<int> &data);
- vector<int> get_intvec_attribute(RTLIL::IdString id) const;
+ void set_intvec_attribute(const RTLIL::IdString& id, const vector<int> &data);
+ vector<int> get_intvec_attribute(const RTLIL::IdString &id) const;
};
struct RTLIL::SigChunk
@@ -732,16 +753,15 @@ struct RTLIL::SigChunk
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() : wire(nullptr), width(0), offset(0) {}
+ SigChunk(const RTLIL::Const &value) : wire(nullptr), data(value.bits), width(GetSize(data)), offset(0) {}
+ SigChunk(RTLIL::Const &&value) : wire(nullptr), data(std::move(value.bits)), width(GetSize(data)), offset(0) {}
+ SigChunk(RTLIL::Wire *wire) : wire(wire), width(GetSize(wire)), offset(0) {}
+ SigChunk(RTLIL::Wire *wire, int offset, int width = 1) : wire(wire), width(width), offset(offset) {}
+ SigChunk(const std::string &str) : SigChunk(RTLIL::Const(str)) {}
+ SigChunk(int val, int width = 32) : SigChunk(RTLIL::Const(val, width)) {}
+ SigChunk(RTLIL::State bit, int width = 1) : SigChunk(RTLIL::Const(bit, width)) {}
SigChunk(const RTLIL::SigBit &bit);
- SigChunk(const RTLIL::SigChunk &sigchunk);
- RTLIL::SigChunk &operator =(const RTLIL::SigChunk &other) = default;
RTLIL::SigChunk extract(int offset, int length) const;
inline int size() const { return width; }
@@ -827,13 +847,13 @@ private:
friend struct RTLIL::Module;
public:
- SigSpec();
- SigSpec(const RTLIL::SigSpec &other);
+ SigSpec() : width_(0), hash_(0) {}
SigSpec(std::initializer_list<RTLIL::SigSpec> parts);
- RTLIL::SigSpec &operator=(const RTLIL::SigSpec &other);
SigSpec(const RTLIL::Const &value);
+ SigSpec(RTLIL::Const &&value);
SigSpec(const RTLIL::SigChunk &chunk);
+ SigSpec(RTLIL::SigChunk &&chunk);
SigSpec(RTLIL::Wire *wire);
SigSpec(RTLIL::Wire *wire, int offset, int width = 1);
SigSpec(const std::string &str);
@@ -846,21 +866,6 @@ public:
SigSpec(const std::set<RTLIL::SigBit> &bits);
explicit 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_;
@@ -985,9 +990,9 @@ struct RTLIL::Selection
Selection(bool full = true) : full_selection(full) { }
- bool selected_module(RTLIL::IdString mod_name) const;
- bool selected_whole_module(RTLIL::IdString mod_name) const;
- bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const;
+ bool selected_module(const RTLIL::IdString &mod_name) const;
+ bool selected_whole_module(const RTLIL::IdString &mod_name) const;
+ bool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const;
void optimize(RTLIL::Design *design);
template<typename T1> void select(T1 *module) {
@@ -1053,11 +1058,11 @@ struct RTLIL::Design
~Design();
RTLIL::ObjRange<RTLIL::Module*> modules();
- RTLIL::Module *module(RTLIL::IdString name);
- const RTLIL::Module *module(RTLIL::IdString name) const;
+ RTLIL::Module *module(const RTLIL::IdString &name);
+ const RTLIL::Module *module(const RTLIL::IdString &name) const;
RTLIL::Module *top_module();
- bool has(RTLIL::IdString id) const {
+ bool has(const RTLIL::IdString &id) const {
return modules_.count(id) != 0;
}
@@ -1082,9 +1087,9 @@ struct RTLIL::Design
void check();
void optimize();
- bool selected_module(RTLIL::IdString mod_name) const;
- bool selected_whole_module(RTLIL::IdString mod_name) const;
- bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const;
+ bool selected_module(const RTLIL::IdString &mod_name) const;
+ bool selected_whole_module(const RTLIL::IdString &mod_name) const;
+ bool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const;
bool selected_module(RTLIL::Module *mod) const;
bool selected_whole_module(RTLIL::Module *mod) const;
@@ -1165,7 +1170,7 @@ public:
virtual ~Module();
virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, bool mayfail = false);
virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail = false);
- virtual size_t count_id(RTLIL::IdString id);
+ virtual size_t count_id(const RTLIL::IdString& id);
virtual void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces);
virtual bool reprocess_if_necessary(RTLIL::Design *design);
@@ -1200,20 +1205,20 @@ public:
return design->selected_member(name, member->name);
}
- RTLIL::Wire* wire(RTLIL::IdString id) {
+ RTLIL::Wire* wire(const RTLIL::IdString &id) {
auto it = wires_.find(id);
return it == wires_.end() ? nullptr : it->second;
}
- RTLIL::Cell* cell(RTLIL::IdString id) {
+ RTLIL::Cell* cell(const RTLIL::IdString &id) {
auto it = cells_.find(id);
return it == cells_.end() ? nullptr : it->second;
}
- const RTLIL::Wire* wire(RTLIL::IdString id) const{
+ const RTLIL::Wire* wire(const RTLIL::IdString &id) const{
auto it = wires_.find(id);
return it == wires_.end() ? nullptr : it->second;
}
- const RTLIL::Cell* cell(RTLIL::IdString id) const {
+ const RTLIL::Cell* cell(const RTLIL::IdString &id) const {
auto it = cells_.find(id);
return it == cells_.end() ? nullptr : it->second;
}
@@ -1302,6 +1307,9 @@ public:
RTLIL::Cell* addBmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
RTLIL::Cell* addDemux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
+ RTLIL::Cell* addBweqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = "");
+ RTLIL::Cell* addBwmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src = "");
+
RTLIL::Cell* addSlice (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src = "");
RTLIL::Cell* addConcat (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, const std::string &src = "");
RTLIL::Cell* addLut (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const lut, const std::string &src = "");
@@ -1376,6 +1384,8 @@ public:
RTLIL::Cell* addDlatchsrGate (RTLIL::IdString name, const RTLIL::SigSpec &sig_en, const RTLIL::SigSpec &sig_set, const RTLIL::SigSpec &sig_clr,
RTLIL::SigSpec sig_d, const RTLIL::SigSpec &sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true, const std::string &src = "");
+ RTLIL::Cell* addAnyinit(RTLIL::IdString name, const RTLIL::SigSpec &sig_d, const RTLIL::SigSpec &sig_q, const std::string &src = "");
+
// The methods without the add* prefix create a cell and an output signal. They return the newly created output signal.
RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
@@ -1429,6 +1439,9 @@ public:
RTLIL::SigSpec Bmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = "");
RTLIL::SigSpec Demux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const std::string &src = "");
+ RTLIL::SigSpec Bweqx (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const std::string &src = "");
+ RTLIL::SigSpec Bwmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = "");
+
RTLIL::SigBit BufGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = "");
RTLIL::SigBit NotGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const std::string &src = "");
RTLIL::SigBit AndGate (RTLIL::IdString name, const RTLIL::SigBit &sig_a, const RTLIL::SigBit &sig_b, const std::string &src = "");
@@ -1483,6 +1496,10 @@ public:
#endif
};
+inline int GetSize(RTLIL::Wire *wire) {
+ return wire->width;
+}
+
struct RTLIL::Memory : public RTLIL::AttrObject
{
unsigned int hashidx_;
@@ -1521,22 +1538,22 @@ public:
dict<RTLIL::IdString, RTLIL::Const> parameters;
// access cell ports
- bool hasPort(RTLIL::IdString portname) const;
- void unsetPort(RTLIL::IdString portname);
- void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal);
- const RTLIL::SigSpec &getPort(RTLIL::IdString portname) const;
+ bool hasPort(const RTLIL::IdString &portname) const;
+ void unsetPort(const RTLIL::IdString &portname);
+ void setPort(const RTLIL::IdString &portname, RTLIL::SigSpec signal);
+ const RTLIL::SigSpec &getPort(const RTLIL::IdString &portname) 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;
+ bool input(const RTLIL::IdString &portname) const;
+ bool output(const RTLIL::IdString &portname) const;
// access cell parameters
- bool hasParam(RTLIL::IdString paramname) const;
- void unsetParam(RTLIL::IdString paramname);
- void setParam(RTLIL::IdString paramname, RTLIL::Const value);
- const RTLIL::Const &getParam(RTLIL::IdString paramname) const;
+ bool hasParam(const RTLIL::IdString &paramname) const;
+ void unsetParam(const RTLIL::IdString &paramname);
+ void setParam(const RTLIL::IdString &paramname, RTLIL::Const value);
+ const RTLIL::Const &getParam(const RTLIL::IdString &paramname) const;
void sort();
void check();
diff --git a/kernel/satgen.cc b/kernel/satgen.cc
index 9c40ec66d..3a2fa4735 100644
--- a/kernel/satgen.cc
+++ b/kernel/satgen.cc
@@ -223,7 +223,33 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
return true;
}
- if (cell->type.in(ID($_MUX_), ID($mux), ID($_NMUX_)))
+ if (cell->type == ID($bweqx))
+ {
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
+
+ std::vector<int> bweqx = ez->vec_not(ez->vec_xor(a, b));
+
+ if (model_undef)
+ {
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep);
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
+
+ std::vector<int> both_undef = ez->vec_and(undef_a, undef_b);
+ std::vector<int> both_def = ez->vec_and(ez->vec_not(undef_a), ez->vec_not(undef_b));
+
+ bweqx = ez->vec_or(both_undef, ez->vec_and(both_def, bweqx));
+
+ for (int yx : undef_y)
+ ez->assume(ez->NOT(yx));
+ }
+ ez->assume(ez->vec_eq(bweqx, y));
+ return true;
+ }
+
+ if (cell->type.in(ID($_MUX_), ID($mux), ID($_NMUX_), ID($bwmux)))
{
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep);
@@ -233,6 +259,8 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
if (cell->type == ID($_NMUX_))
ez->assume(ez->vec_eq(ez->vec_not(ez->vec_ite(s.at(0), b, a)), yy));
+ else if (cell->type == ID($bwmux))
+ ez->assume(ez->vec_eq(ez->vec_ite(s, b, a), yy));
else
ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy));
@@ -245,7 +273,11 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
std::vector<int> unequal_ab = ez->vec_not(ez->vec_iff(a, b));
std::vector<int> undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a, undef_b));
- std::vector<int> yX = ez->vec_ite(undef_s.at(0), undef_ab, ez->vec_ite(s.at(0), undef_b, undef_a));
+ std::vector<int> yX;
+ if (cell->type == ID($bwmux))
+ yX = ez->vec_ite(undef_s, undef_ab, ez->vec_ite(s, undef_b, undef_a));
+ else
+ yX = ez->vec_ite(undef_s.at(0), undef_ab, ez->vec_ite(s.at(0), undef_b, undef_a));
ez->assume(ez->vec_eq(yX, undef_y));
undefGating(y, yy, undef_y);
}
@@ -375,29 +407,24 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
std::vector<int> undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
- int maybe_a = ez->CONST_TRUE;
+ int all_undef = ez->CONST_FALSE;
+ int found_active = ez->CONST_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);
+ std::vector<int> undef_tmp = undef_a;
for (size_t i = 0; i < s.size(); i++)
{
- std::vector<int> part_of_b(b.begin()+i*a.size(), b.begin()+(i+1)*a.size());
std::vector<int> part_of_undef_b(undef_b.begin()+i*a.size(), undef_b.begin()+(i+1)*a.size());
- int maybe_s = ez->OR(s.at(i), undef_s.at(i));
- int sure_s = ez->AND(s.at(i), ez->NOT(undef_s.at(i)));
-
- maybe_a = ez->AND(maybe_a, ez->NOT(sure_s));
-
- bits_set = ez->vec_ite(maybe_s, ez->vec_or(bits_set, ez->vec_or(part_of_b, part_of_undef_b)), bits_set);
- bits_clr = ez->vec_ite(maybe_s, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(part_of_b), part_of_undef_b)), bits_clr);
+ undef_tmp = ez->vec_ite(s.at(i), part_of_undef_b, undef_tmp);
+ all_undef = ez->OR(all_undef, undef_s.at(i));
+ all_undef = ez->OR(all_undef, ez->AND(s.at(i), found_active));
+ found_active = ez->OR(found_active, s.at(i));
}
- bits_set = ez->vec_ite(maybe_a, ez->vec_or(bits_set, ez->vec_or(bits_set, ez->vec_or(a, undef_a))), bits_set);
- bits_clr = ez->vec_ite(maybe_a, ez->vec_or(bits_clr, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(a), undef_a))), bits_clr);
+ undef_tmp = ez->vec_or(undef_tmp, std::vector<int>(a.size(), all_undef));
- ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(bits_set, bits_clr)), undef_y));
+ ez->assume(ez->vec_eq(undef_tmp, undef_y));
undefGating(y, yy, undef_y);
}
return true;
@@ -1176,7 +1203,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
return true;
}
- if (timestep > 0 && RTLIL::builtin_ff_cell_types().count(cell->type))
+ if (timestep > 0 && (RTLIL::builtin_ff_cell_types().count(cell->type) || cell->type == ID($anyinit)))
{
FfData ff(nullptr, cell);
@@ -1187,6 +1214,10 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
if (timestep == 1)
{
initial_state.add((*sigmap)(cell->getPort(ID::Q)));
+ if (model_undef && def_formal) {
+ std::vector<int> undef_q = importUndefSigSpec(cell->getPort(ID::Q), timestep);
+ ez->assume(ez->NOT(ez->vec_reduce_or(undef_q)));
+ }
}
else
{
@@ -1254,13 +1285,18 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
if (cell->type == ID($anyconst))
{
- if (timestep < 2)
+ if (timestep < 2) {
+ if (model_undef && def_formal) {
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
+ ez->assume(ez->NOT(ez->vec_reduce_or(undef_y)));
+ }
return true;
+ }
std::vector<int> d = importDefSigSpec(cell->getPort(ID::Y), timestep-1);
std::vector<int> q = importDefSigSpec(cell->getPort(ID::Y), timestep);
- std::vector<int> qq = model_undef ? ez->vec_var(q.size()) : q;
+ std::vector<int> qq = (model_undef && !def_formal) ? ez->vec_var(q.size()) : q;
ez->assume(ez->vec_eq(d, qq));
if (model_undef)
@@ -1268,14 +1304,24 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
std::vector<int> undef_d = importUndefSigSpec(cell->getPort(ID::Y), timestep-1);
std::vector<int> undef_q = importUndefSigSpec(cell->getPort(ID::Y), timestep);
- ez->assume(ez->vec_eq(undef_d, undef_q));
- undefGating(q, qq, undef_q);
+ if (def_formal) {
+ for (auto &undef_q_bit : undef_q)
+ ez->SET(ez->CONST_FALSE, undef_q_bit);
+ } else {
+ ez->assume(ez->vec_eq(undef_d, undef_q));
+ undefGating(q, qq, undef_q);
+ }
}
return true;
}
if (cell->type == ID($anyseq))
{
+ if (model_undef && def_formal) {
+ std::vector<int> undef_q = importUndefSigSpec(cell->getPort(ID::Y), timestep);
+ for (auto &undef_q_bit : undef_q)
+ ez->SET(ez->CONST_FALSE, undef_q_bit);
+ }
return true;
}
diff --git a/kernel/satgen.h b/kernel/satgen.h
index da2cec222..8a89ff9db 100644
--- a/kernel/satgen.h
+++ b/kernel/satgen.h
@@ -73,6 +73,7 @@ struct SatGen
std::map<std::pair<std::string, int>, bool> initstates;
bool ignore_div_by_zero;
bool model_undef;
+ bool def_formal = false;
SatGen(ezSAT *ez, SigMap *sigmap, std::string prefix = std::string()) :
ez(ez), sigmap(sigmap), prefix(prefix), ignore_div_by_zero(false), model_undef(false)
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index 64d2b4def..bd8dded4b 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -73,6 +73,8 @@
#include <limits.h>
#include <errno.h>
+#include "libs/json11/json11.hpp"
+
YOSYS_NAMESPACE_BEGIN
int autoidx = 1;
@@ -82,6 +84,7 @@ CellTypes yosys_celltypes;
#ifdef YOSYS_ENABLE_TCL
Tcl_Interp *yosys_tcl_interp = NULL;
+bool yosys_tcl_repl_active = false;
#endif
std::set<std::string> yosys_input_files, yosys_output_files;
@@ -466,8 +469,8 @@ std::string make_temp_dir(std::string template_str)
# endif
char *p = strdup(template_str.c_str());
- p = mkdtemp(p);
- log_assert(p != NULL);
+ char *res = mkdtemp(p);
+ log_assert(res != NULL);
template_str = p;
free(p);
@@ -534,11 +537,6 @@ std::string escape_filename_spaces(const std::string& filename)
return out;
}
-int GetSize(RTLIL::Wire *wire)
-{
- return wire->width;
-}
-
bool already_setup = false;
void yosys_setup()
@@ -595,7 +593,9 @@ void yosys_shutdown()
#ifdef YOSYS_ENABLE_TCL
if (yosys_tcl_interp != NULL) {
- Tcl_DeleteInterp(yosys_tcl_interp);
+ if (!Tcl_InterpDeleted(yosys_tcl_interp)) {
+ Tcl_DeleteInterp(yosys_tcl_interp);
+ }
Tcl_Finalize();
yosys_tcl_interp = NULL;
}
@@ -712,6 +712,42 @@ void rewrite_filename(std::string &filename)
}
#ifdef YOSYS_ENABLE_TCL
+
+static Tcl_Obj *json_to_tcl(Tcl_Interp *interp, const json11::Json &json)
+{
+ if (json.is_null())
+ return Tcl_NewStringObj("null", 4);
+ else if (json.is_string()) {
+ auto string = json.string_value();
+ return Tcl_NewStringObj(string.data(), string.size());
+ } else if (json.is_number()) {
+ double value = json.number_value();
+ double round_val = std::nearbyint(value);
+ if (std::isfinite(round_val) && value == round_val && value >= LONG_MIN && value < -double(LONG_MIN))
+ return Tcl_NewLongObj((long)round_val);
+ else
+ return Tcl_NewDoubleObj(value);
+ } else if (json.is_bool()) {
+ return Tcl_NewBooleanObj(json.bool_value());
+ } else if (json.is_array()) {
+ auto list = json.array_items();
+ Tcl_Obj *result = Tcl_NewListObj(list.size(), nullptr);
+ for (auto &item : list)
+ Tcl_ListObjAppendElement(interp, result, json_to_tcl(interp, item));
+ return result;
+ } else if (json.is_object()) {
+ auto map = json.object_items();
+ Tcl_Obj *result = Tcl_NewListObj(map.size() * 2, nullptr);
+ for (auto &item : map) {
+ Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(item.first.data(), item.first.size()));
+ Tcl_ListObjAppendElement(interp, result, json_to_tcl(interp, item.second));
+ }
+ return result;
+ } else {
+ log_abort();
+ }
+}
+
static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
{
std::vector<std::string> args;
@@ -736,22 +772,73 @@ static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *a
return TCL_OK;
}
- if (args.size() == 1) {
- Pass::call(yosys_get_design(), args[0]);
- return TCL_OK;
+ yosys_get_design()->scratchpad_unset("result.json");
+ yosys_get_design()->scratchpad_unset("result.string");
+
+ bool in_repl = yosys_tcl_repl_active;
+ bool restore_log_cmd_error_throw = log_cmd_error_throw;
+
+ log_cmd_error_throw = true;
+
+ try {
+ if (args.size() == 1) {
+ Pass::call(yosys_get_design(), args[0]);
+ } else {
+ Pass::call(yosys_get_design(), args);
+ }
+ } catch (log_cmd_error_exception) {
+ if (in_repl) {
+ auto design = yosys_get_design();
+ while (design->selection_stack.size() > 1)
+ design->selection_stack.pop_back();
+ log_reset_stack();
+ }
+ Tcl_SetResult(interp, (char *)"Yosys command produced an error", TCL_STATIC);
+
+ yosys_tcl_repl_active = in_repl;
+ log_cmd_error_throw = restore_log_cmd_error_throw;
+ return TCL_ERROR;
+ } catch (...) {
+ log_error("uncaught exception during Yosys command invoked from TCL\n");
+ }
+
+ yosys_tcl_repl_active = in_repl;
+ log_cmd_error_throw = restore_log_cmd_error_throw;
+
+ auto &scratchpad = yosys_get_design()->scratchpad;
+ auto result = scratchpad.find("result.json");
+ if (result != scratchpad.end()) {
+ std::string err;
+ auto json = json11::Json::parse(result->second, err);
+ if (err.empty()) {
+ Tcl_SetObjResult(interp, json_to_tcl(interp, json));
+ } else
+ log_warning("Ignoring result.json scratchpad value due to parse error: %s\n", err.c_str());
+ } else if ((result = scratchpad.find("result.string")) != scratchpad.end()) {
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(result->second.data(), result->second.size()));
}
- Pass::call(yosys_get_design(), args);
return TCL_OK;
}
+int yosys_tcl_iterp_init(Tcl_Interp *interp)
+{
+ if (Tcl_Init(interp)!=TCL_OK)
+ log_warning("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno()));
+ Tcl_CreateCommand(interp, "yosys", tcl_yosys_cmd, NULL, NULL);
+ return TCL_OK ;
+}
+
+void yosys_tcl_activate_repl()
+{
+ yosys_tcl_repl_active = true;
+}
+
extern Tcl_Interp *yosys_get_tcl_interp()
{
if (yosys_tcl_interp == NULL) {
yosys_tcl_interp = Tcl_CreateInterp();
- if (Tcl_Init(yosys_tcl_interp)!=TCL_OK)
- log_warning("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno()));
- Tcl_CreateCommand(yosys_tcl_interp, "yosys", tcl_yosys_cmd, NULL, NULL);
+ yosys_tcl_iterp_init(yosys_tcl_interp);
}
return yosys_tcl_interp;
}
@@ -774,6 +861,10 @@ struct TclPass : public Pass {
log("If any arguments are specified, these arguments are provided to the script via\n");
log("the standard $argc and $argv variables.\n");
log("\n");
+ log("Note, tcl will not recieve the output of any yosys command. If the output\n");
+ log("of the tcl commands are needed, use the yosys command 'tee -s result.string'\n");
+ log("to redirect yosys's output to the 'result.string' scratchpad value.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *) override {
if (args.size() < 2)
@@ -784,11 +875,13 @@ struct TclPass : public Pass {
script_args.push_back(Tcl_NewStringObj((*it).c_str(), (*it).size()));
Tcl_Interp *interp = yosys_get_tcl_interp();
+ Tcl_Preserve(interp);
Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argc", 4), NULL, Tcl_NewIntObj(script_args.size()), 0);
Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv", 4), NULL, Tcl_NewListObj(script_args.size(), script_args.data()), 0);
Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv0", 5), NULL, Tcl_NewStringObj(args[1].c_str(), args[1].size()), 0);
if (Tcl_EvalFile(interp, args[1].c_str()) != TCL_OK)
log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(interp));
+ Tcl_Release(interp);
}
} TclPass;
#endif
@@ -867,6 +960,35 @@ std::string proc_self_dirname()
{
return "/";
}
+#elif defined(__OpenBSD__)
+char yosys_path[PATH_MAX];
+char *yosys_argv0;
+
+std::string proc_self_dirname(void)
+{
+ char buf[PATH_MAX + 1] = "", *path, *p;
+ // if case argv[0] contains a valid path, return it
+ if (strlen(yosys_path) > 0) {
+ p = strrchr(yosys_path, '/');
+ snprintf(buf, sizeof buf, "%*s/", (int)(yosys_path - p), yosys_path);
+ return buf;
+ }
+ // if argv[0] does not, reconstruct the path out of $PATH
+ path = strdup(getenv("PATH"));
+ if (!path)
+ log_error("getenv(\"PATH\") failed: %s\n", strerror(errno));
+ for (p = strtok(path, ":"); p; p = strtok(NULL, ":")) {
+ snprintf(buf, sizeof buf, "%s/%s", p, yosys_argv0);
+ if (access(buf, X_OK) == 0) {
+ *(strrchr(buf, '/') + 1) = '\0';
+ free(path);
+ return buf;
+ }
+ }
+ free(path);
+ log_error("Can't determine yosys executable path\n.");
+ return NULL;
+}
#else
#error "Don't know how to determine process executable base path!"
#endif
diff --git a/kernel/yosys.h b/kernel/yosys.h
index 448f896d4..29415ff84 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -82,6 +82,9 @@
# ifdef YOSYS_MXE_HACKS
extern Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc);
extern Tcl_Interp *Tcl_CreateInterp(void);
+extern void Tcl_Preserve(ClientData data);
+extern void Tcl_Release(ClientData clientData);
+extern int Tcl_InterpDeleted(Tcl_Interp *interp);
extern void Tcl_DeleteInterp(Tcl_Interp *interp);
extern int Tcl_Eval(Tcl_Interp *interp, const char *script);
extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName);
@@ -287,7 +290,7 @@ void remove_directory(std::string dirname);
std::string escape_filename_spaces(const std::string& filename);
template<typename T> int GetSize(const T &obj) { return obj.size(); }
-int GetSize(RTLIL::Wire *wire);
+inline int GetSize(RTLIL::Wire *wire);
extern int autoidx;
extern int yosys_xtrace;
diff --git a/kernel/yw.cc b/kernel/yw.cc
new file mode 100644
index 000000000..73e7710db
--- /dev/null
+++ b/kernel/yw.cc
@@ -0,0 +1,209 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2022 Jannis Harder <jix@yosyshq.com> <me@jix.one>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yw.h"
+#include "libs/json11/json11.hpp"
+
+USING_YOSYS_NAMESPACE
+
+// Use the same formatting as witness.py uses
+static const char *pretty_name(IdString id)
+{
+ const char *c_str = id.c_str();
+ const char *p = c_str;
+
+ if (*p != '\\')
+ return c_str;
+ p++;
+
+ if (*p == '[') {
+ p++;
+ while (*p >= '0' && *p <= '9')
+ p++;
+ if (p[0] != ']' || p[1] != 0)
+ return c_str;
+ return c_str + 1;
+ }
+
+ if (!(*p >= 'a' && *p <= 'z') && !(*p >= 'A' && *p <= 'Z') && *p != '_')
+ return c_str;
+ p++;
+ while ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || *p == '_')
+ p++;
+
+ if (*p != 0)
+ return c_str;
+ return c_str + 1;
+}
+
+std::string IdPath::str() const
+{
+ std::string result;
+
+ for (auto &item : *this) {
+ const char *pretty = pretty_name(item);
+ if (pretty[0] == '[') {
+ result += pretty;
+ continue;
+ }
+ if (!result.empty())
+ result += '.';
+ result += pretty;
+ if (pretty[0] == '\\' || pretty[0] == '$')
+ result += ' ';
+ }
+
+ return result;
+}
+
+bool IdPath::get_address(int &addr) const
+{
+ if (empty())
+ return false;
+ auto &last = back();
+ if (!last.begins_with("\\["))
+ return false;
+ if (last == "\\[0]") {
+ addr = 0;
+ return true;
+ }
+ char first = last.c_str()[2];
+ if (first < '1' || first > '9')
+ return false;
+ char *endptr;
+ addr = std::strtol(last.c_str() + 2, &endptr, 10);
+ return endptr[0] == ']' && endptr[1] == 0;
+}
+
+static std::vector<IdString> get_path(const json11::Json &json)
+{
+ std::vector<IdString> result;
+ for (auto &path_item : json.array_items()) {
+ auto const &path_item_str = path_item.string_value();
+ if (path_item_str.empty())
+ return {};;
+ result.push_back(path_item_str);
+ }
+ return result;
+}
+
+ReadWitness::ReadWitness(const std::string &filename) :
+ filename(filename)
+{
+ std::ifstream f(filename.c_str());
+ if (f.fail() || GetSize(filename) == 0)
+ log_error("Cannot open file `%s`\n", filename.c_str());
+ std::stringstream buf;
+ buf << f.rdbuf();
+ std::string err;
+ json11::Json json = json11::Json::parse(buf.str(), err);
+ if (!err.empty())
+ log_error("Failed to parse `%s`: %s\n", filename.c_str(), err.c_str());
+
+ std::string format = json["format"].string_value();
+
+ if (format.empty())
+ log_error("Failed to parse `%s`: Unknown format\n", filename.c_str());
+ if (format != "Yosys Witness Trace")
+ log_error("Failed to parse `%s`: Unsupported format `%s`\n", filename.c_str(), format.c_str());
+
+ for (auto &clock_json : json["clocks"].array_items()) {
+ Clock clock;
+ clock.path = get_path(clock_json["path"]);
+ if (clock.path.empty())
+ log_error("Failed to parse `%s`: Missing path for clock `%s`\n", filename.c_str(), clock_json.dump().c_str());
+ auto edge_str = clock_json["edge"];
+ if (edge_str.string_value() == "posedge")
+ clock.is_posedge = true;
+ else if (edge_str.string_value() == "negedge")
+ clock.is_negedge = true;
+ else
+ log_error("Failed to parse `%s`: Unknown edge type for clock `%s`\n", filename.c_str(), clock_json.dump().c_str());
+ if (!clock_json["offset"].is_number())
+ log_error("Failed to parse `%s`: Unknown offset for clock `%s`\n", filename.c_str(), clock_json.dump().c_str());
+ clock.offset = clock_json["offset"].int_value();
+ if (clock.offset < 0)
+ log_error("Failed to parse `%s`: Invalid offset for clock `%s`\n", filename.c_str(), clock_json.dump().c_str());
+ clocks.push_back(clock);
+ }
+
+ int bits_offset = 0;
+ for (auto &signal_json : json["signals"].array_items()) {
+ Signal signal;
+ signal.bits_offset = bits_offset;
+ signal.path = get_path(signal_json["path"]);
+ if (signal.path.empty())
+ log_error("Failed to parse `%s`: Missing path for signal `%s`\n", filename.c_str(), signal_json.dump().c_str());
+ if (!signal_json["width"].is_number())
+ log_error("Failed to parse `%s`: Unknown width for signal `%s`\n", filename.c_str(), signal_json.dump().c_str());
+ signal.width = signal_json["width"].int_value();
+ if (signal.width < 0)
+ log_error("Failed to parse `%s`: Invalid width for signal `%s`\n", filename.c_str(), signal_json.dump().c_str());
+ bits_offset += signal.width;
+ if (!signal_json["offset"].is_number())
+ log_error("Failed to parse `%s`: Unknown offset for signal `%s`\n", filename.c_str(), signal_json.dump().c_str());
+ signal.offset = signal_json["offset"].int_value();
+ if (signal.offset < 0)
+ log_error("Failed to parse `%s`: Invalid offset for signal `%s`\n", filename.c_str(), signal_json.dump().c_str());
+ signal.init_only = signal_json["init_only"].bool_value();
+ signals.push_back(signal);
+ }
+
+ for (auto &step_json : json["steps"].array_items()) {
+ Step step;
+ if (!step_json["bits"].is_string())
+ log_error("Failed to parse `%s`: Expected string as bits value for step %d\n", filename.c_str(), GetSize(steps));
+ step.bits = step_json["bits"].string_value();
+ for (char c : step.bits) {
+ if (c != '0' && c != '1' && c != 'x' && c != '?')
+ log_error("Failed to parse `%s`: Invalid bit '%c' value for step %d\n", filename.c_str(), c, GetSize(steps));
+ }
+ steps.push_back(step);
+ }
+}
+
+RTLIL::Const ReadWitness::get_bits(int t, int bits_offset, int width) const
+{
+ log_assert(t >= 0 && t < GetSize(steps));
+
+ const std::string &bits = steps[t].bits;
+
+ RTLIL::Const result(State::Sa, width);
+ result.bits.reserve(width);
+
+ int read_begin = GetSize(bits) - 1 - bits_offset;
+ int read_end = max(-1, read_begin - width);
+
+ min(width, GetSize(bits) - bits_offset);
+
+ for (int i = read_begin, j = 0; i > read_end; i--, j++) {
+ RTLIL::State bit = State::Sa;
+ switch (bits[i]) {
+ case '0': bit = State::S0; break;
+ case '1': bit = State::S1; break;
+ case 'x': bit = State::Sx; break;
+ case '?': bit = State::Sa; break;
+ default:
+ log_abort();
+ }
+ result.bits[j] = bit;
+ }
+
+ return result;
+}
diff --git a/kernel/yw.h b/kernel/yw.h
new file mode 100644
index 000000000..c2f5921b1
--- /dev/null
+++ b/kernel/yw.h
@@ -0,0 +1,182 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2022 Jannis Harder <jix@yosyshq.com> <me@jix.one>
+ *
+ * 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 YW_H
+#define YW_H
+
+#include "kernel/yosys.h"
+#include "kernel/mem.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+struct IdPath : public std::vector<RTLIL::IdString>
+{
+ template<typename... T>
+ IdPath(T&&... args) : std::vector<RTLIL::IdString>(std::forward<T>(args)...) { }
+ IdPath prefix() const { return {begin(), end() - !empty()}; }
+ std::string str() const;
+
+ bool has_address() const { int tmp; return get_address(tmp); };
+ bool get_address(int &addr) const;
+
+ int hash() const { return hashlib::hash_ops<std::vector<RTLIL::IdString>>::hash(*this); }
+};
+
+struct WitnessHierarchyItem {
+ RTLIL::Module *module;
+ RTLIL::Wire *wire = nullptr;
+ RTLIL::Cell *cell = nullptr;
+ Mem *mem = nullptr;
+
+ WitnessHierarchyItem(RTLIL::Module *module, RTLIL::Wire *wire) : module(module), wire(wire) {}
+ WitnessHierarchyItem(RTLIL::Module *module, RTLIL::Cell *cell) : module(module), cell(cell) {}
+ WitnessHierarchyItem(RTLIL::Module *module, Mem *mem) : module(module), mem(mem) {}
+};
+
+template<typename D, typename T>
+void witness_hierarchy(RTLIL::Module *module, D data, T callback);
+
+template<class T> static std::vector<std::string> witness_path(T *obj) {
+ std::vector<std::string> path;
+ if (obj->name.isPublic()) {
+ auto hdlname = obj->get_string_attribute(ID::hdlname);
+ for (auto token : split_tokens(hdlname))
+ path.push_back("\\" + token);
+ }
+ if (path.empty())
+ path.push_back(obj->name.str());
+ return path;
+}
+
+struct ReadWitness
+{
+ struct Clock {
+ IdPath path;
+ int offset;
+ bool is_posedge = false;
+ bool is_negedge = false;
+ };
+
+ struct Signal {
+ IdPath path;
+ int offset;
+ int width;
+ bool init_only;
+
+ int bits_offset;
+ };
+
+ struct Step {
+ std::string bits;
+ };
+
+ std::string filename;
+ std::vector<Clock> clocks;
+ std::vector<Signal> signals;
+ std::vector<Step> steps;
+
+ ReadWitness(const std::string &filename);
+
+ RTLIL::Const get_bits(int t, int bits_offset, int width) const;
+};
+
+template<typename D, typename T>
+void witness_hierarchy_recursion(IdPath &path, int hdlname_mode, RTLIL::Module *module, D data, T &callback)
+{
+ auto const &const_path = path;
+ size_t path_size = path.size();
+ for (auto wire : module->wires())
+ {
+ auto hdlname = hdlname_mode < 0 ? std::vector<std::string>() : wire->get_hdlname_attribute();
+ for (auto item : hdlname)
+ path.push_back("\\" + item);
+ if (hdlname.size() == 1 && path.back() == wire->name)
+ hdlname.clear();
+ if (!hdlname.empty())
+ callback(const_path, WitnessHierarchyItem(module, wire), data);
+ path.resize(path_size);
+ if (hdlname.empty() || hdlname_mode <= 0) {
+ path.push_back(wire->name);
+ callback(const_path, WitnessHierarchyItem(module, wire), data);
+ path.pop_back();
+ }
+ }
+
+ for (auto cell : module->cells())
+ {
+ Module *child = module->design->module(cell->type);
+ if (child == nullptr)
+ continue;
+
+ auto hdlname = hdlname_mode < 0 ? std::vector<std::string>() : cell->get_hdlname_attribute();
+ for (auto item : hdlname)
+ path.push_back("\\" + item);
+ if (hdlname.size() == 1 && path.back() == cell->name)
+ hdlname.clear();
+ if (!hdlname.empty()) {
+ D child_data = callback(const_path, WitnessHierarchyItem(module, cell), data);
+ witness_hierarchy_recursion<D, T>(path, 1, child, child_data, callback);
+ }
+ path.resize(path_size);
+ if (hdlname.empty() || hdlname_mode <= 0) {
+ path.push_back(cell->name);
+ D child_data = callback(const_path, WitnessHierarchyItem(module, cell), data);
+ witness_hierarchy_recursion<D, T>(path, hdlname.empty() ? hdlname_mode : -1, child, child_data, callback);
+ path.pop_back();
+ }
+ }
+
+ for (auto mem : Mem::get_all_memories(module)) {
+ std::vector<std::string> hdlname;
+
+ if (hdlname_mode >= 0 && mem.cell != nullptr)
+ hdlname = mem.cell->get_hdlname_attribute();
+ for (auto item : hdlname)
+ path.push_back("\\" + item);
+ if (hdlname.size() == 1 && path.back() == mem.cell->name)
+ hdlname.clear();
+ if (!hdlname.empty()) {
+ callback(const_path, WitnessHierarchyItem(module, &mem), data);
+ }
+ path.resize(path_size);
+
+ if (hdlname.empty() || hdlname_mode <= 0) {
+ path.push_back(mem.memid);
+ callback(const_path, WitnessHierarchyItem(module, &mem), data);
+ path.pop_back();
+
+ if (mem.cell != nullptr && mem.cell->name != mem.memid) {
+ path.push_back(mem.cell->name);
+ callback(const_path, WitnessHierarchyItem(module, &mem), data);
+ path.pop_back();
+ }
+ }
+ }
+}
+
+template<typename D, typename T>
+void witness_hierarchy(RTLIL::Module *module, D data, T callback)
+{
+ IdPath path;
+ witness_hierarchy_recursion<D, T>(path, 0, module, data, callback);
+}
+
+YOSYS_NAMESPACE_END
+
+#endif