aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/calc.cc51
-rw-r--r--kernel/celledges.cc40
-rw-r--r--kernel/celltypes.h29
-rw-r--r--kernel/consteval.h39
-rw-r--r--kernel/constids.inc15
-rw-r--r--kernel/driver.cc53
-rw-r--r--kernel/ff.cc13
-rw-r--r--kernel/ff.h2
-rw-r--r--kernel/fstdata.cc252
-rw-r--r--kernel/fstdata.h84
-rw-r--r--kernel/log.cc24
-rw-r--r--kernel/log.h2
-rw-r--r--kernel/mem.cc318
-rw-r--r--kernel/mem.h32
-rw-r--r--kernel/qcsat.cc2
-rw-r--r--kernel/rtlil.cc251
-rw-r--r--kernel/rtlil.h133
-rw-r--r--kernel/satgen.cc100
-rw-r--r--kernel/yosys.cc154
-rw-r--r--kernel/yosys.h13
20 files changed, 1305 insertions, 302 deletions
diff --git a/kernel/calc.cc b/kernel/calc.cc
index 1e6410f7d..0865db526 100644
--- a/kernel/calc.cc
+++ b/kernel/calc.cc
@@ -609,5 +609,56 @@ 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_bmux(const RTLIL::Const &arg1, const RTLIL::Const &arg2)
+{
+ std::vector<RTLIL::State> t = arg1.bits;
+
+ for (int i = GetSize(arg2)-1; i >= 0; i--)
+ {
+ RTLIL::State sel = arg2.bits.at(i);
+ std::vector<RTLIL::State> new_t;
+ if (sel == State::S0)
+ new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + GetSize(t)/2);
+ else if (sel == State::S1)
+ new_t = std::vector<RTLIL::State>(t.begin() + GetSize(t)/2, t.end());
+ else
+ for (int j = 0; j < GetSize(t)/2; j++)
+ new_t.push_back(t[j] == t[j + GetSize(t)/2] ? t[j] : RTLIL::Sx);
+ t.swap(new_t);
+ }
+
+ return t;
+}
+
+RTLIL::Const RTLIL::const_demux(const RTLIL::Const &arg1, const RTLIL::Const &arg2)
+{
+ int width = GetSize(arg1);
+ int s_width = GetSize(arg2);
+ std::vector<RTLIL::State> res;
+ for (int i = 0; i < (1 << s_width); i++)
+ {
+ bool ne = false;
+ bool x = false;
+ for (int j = 0; j < s_width; j++) {
+ bool bit = i & 1 << j;
+ if (arg2[j] == (bit ? RTLIL::S0 : RTLIL::S1))
+ ne = true;
+ else if (arg2[j] != RTLIL::S0 && arg2[j] != RTLIL::S1)
+ x = true;
+ }
+ if (ne) {
+ for (int j = 0; j < width; j++)
+ res.push_back(State::S0);
+ } else if (x) {
+ for (int j = 0; j < width; j++)
+ res.push_back(arg1.bits[j] == State::S0 ? State::S0 : State::Sx);
+ } else {
+ for (int j = 0; j < width; j++)
+ res.push_back(arg1.bits[j]);
+ }
+ }
+ return res;
+}
+
YOSYS_NAMESPACE_END
diff --git a/kernel/celledges.cc b/kernel/celledges.cc
index af07d26b3..c43ba8db3 100644
--- a/kernel/celledges.cc
+++ b/kernel/celledges.cc
@@ -142,6 +142,36 @@ void mux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
}
}
+void bmux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
+{
+ int width = GetSize(cell->getPort(ID::Y));
+ int a_width = GetSize(cell->getPort(ID::A));
+ int s_width = GetSize(cell->getPort(ID::S));
+
+ for (int i = 0; i < width; i++)
+ {
+ for (int k = i; k < a_width; k += width)
+ db->add_edge(cell, ID::A, k, ID::Y, i, -1);
+
+ for (int k = 0; k < s_width; k++)
+ db->add_edge(cell, ID::S, k, ID::Y, i, -1);
+ }
+}
+
+void demux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
+{
+ int width = GetSize(cell->getPort(ID::Y));
+ int a_width = GetSize(cell->getPort(ID::A));
+ int s_width = GetSize(cell->getPort(ID::S));
+
+ for (int i = 0; i < width; i++)
+ {
+ db->add_edge(cell, ID::A, i % a_width, ID::Y, i, -1);
+ for (int k = 0; k < s_width; k++)
+ db->add_edge(cell, ID::S, k, ID::Y, i, -1);
+ }
+}
+
PRIVATE_NAMESPACE_END
bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell)
@@ -187,6 +217,16 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL
return true;
}
+ if (cell->type == ID($bmux)) {
+ bmux_op(this, cell);
+ return true;
+ }
+
+ if (cell->type == ID($demux)) {
+ demux_op(this, cell);
+ return true;
+ }
+
// FIXME: $mul $div $mod $divfloor $modfloor $slice $concat
// FIXME: $lut $sop $alu $lcu $macc $fa
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index 879ac0edc..7e9cfb38d 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -127,6 +127,9 @@ struct CellTypes
for (auto type : std::vector<RTLIL::IdString>({ID($mux), ID($pmux)}))
setup_type(type, {ID::A, ID::B, ID::S}, {ID::Y}, true);
+ for (auto type : std::vector<RTLIL::IdString>({ID($bmux), ID($demux)}))
+ setup_type(type, {ID::A, ID::S}, {ID::Y}, true);
+
setup_type(ID($lcu), {ID::P, ID::G, ID::CI}, {ID::CO}, true);
setup_type(ID($alu), {ID::A, ID::B, ID::CI, ID::BI}, {ID::X, ID::Y, ID::CO}, true);
setup_type(ID($fa), {ID::A, ID::B, ID::C}, {ID::X, ID::Y}, true);
@@ -411,6 +414,16 @@ struct CellTypes
return ret;
}
+ if (cell->type == ID($bmux))
+ {
+ return const_bmux(arg1, arg2);
+ }
+
+ if (cell->type == ID($demux))
+ {
+ return const_demux(arg1, arg2);
+ }
+
if (cell->type == ID($lut))
{
int width = cell->parameters.at(ID::WIDTH).as_int();
@@ -420,21 +433,7 @@ struct CellTypes
t.push_back(State::S0);
t.resize(1 << width);
- for (int i = width-1; i >= 0; i--) {
- RTLIL::State sel = arg1.bits.at(i);
- std::vector<RTLIL::State> new_t;
- if (sel == State::S0)
- new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + GetSize(t)/2);
- else if (sel == State::S1)
- new_t = std::vector<RTLIL::State>(t.begin() + GetSize(t)/2, t.end());
- else
- for (int j = 0; j < GetSize(t)/2; j++)
- new_t.push_back(t[j] == t[j + GetSize(t)/2] ? t[j] : RTLIL::Sx);
- t.swap(new_t);
- }
-
- log_assert(GetSize(t) == 1);
- return t;
+ return const_bmux(t, arg1);
}
if (cell->type == ID($sop))
diff --git a/kernel/consteval.h b/kernel/consteval.h
index 3edfc490c..4c0c26049 100644
--- a/kernel/consteval.h
+++ b/kernel/consteval.h
@@ -135,8 +135,6 @@ struct ConstEval
if (cell->hasPort(ID::S)) {
sig_s = cell->getPort(ID::S);
- if (!eval(sig_s, undef, cell))
- return false;
}
if (cell->hasPort(ID::A))
@@ -148,9 +146,11 @@ struct ConstEval
if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_), ID($_NMUX_)))
{
std::vector<RTLIL::SigSpec> y_candidates;
- int count_maybe_set_s_bits = 0;
int count_set_s_bits = 0;
+ if (!eval(sig_s, undef, cell))
+ return false;
+
for (int i = 0; i < sig_s.size(); i++)
{
RTLIL::State s_bit = sig_s.extract(i, 1).as_const().bits.at(0);
@@ -159,9 +159,6 @@ struct ConstEval
if (s_bit == RTLIL::State::Sx || s_bit == RTLIL::State::S1)
y_candidates.push_back(b_slice);
- if (s_bit == RTLIL::State::S1 || s_bit == RTLIL::State::Sx)
- count_maybe_set_s_bits++;
-
if (s_bit == RTLIL::State::S1)
count_set_s_bits++;
}
@@ -198,6 +195,36 @@ struct ConstEval
else
set(sig_y, y_values.front());
}
+ else if (cell->type == ID($bmux))
+ {
+ if (!eval(sig_s, undef, cell))
+ return false;
+
+ if (sig_s.is_fully_def()) {
+ int sel = sig_s.as_int();
+ int width = GetSize(sig_y);
+ SigSpec res = sig_a.extract(sel * width, width);
+ if (!eval(res, undef, cell))
+ return false;
+ set(sig_y, res.as_const());
+ } else {
+ if (!eval(sig_a, undef, cell))
+ return false;
+ set(sig_y, const_bmux(sig_a.as_const(), sig_s.as_const()));
+ }
+ }
+ else if (cell->type == ID($demux))
+ {
+ if (!eval(sig_a, undef, cell))
+ return false;
+ if (sig_a.is_fully_zero()) {
+ set(sig_y, Const(0, GetSize(sig_y)));
+ } else {
+ if (!eval(sig_s, undef, cell))
+ return false;
+ set(sig_y, const_demux(sig_a.as_const(), sig_s.as_const()));
+ }
+ }
else if (cell->type == ID($fa))
{
RTLIL::SigSpec sig_c = cell->getPort(ID::C);
diff --git a/kernel/constids.inc b/kernel/constids.inc
index 566b76217..0f6dfc29b 100644
--- a/kernel/constids.inc
+++ b/kernel/constids.inc
@@ -29,10 +29,12 @@ X(A_SIGNED)
X(A_WIDTH)
X(B)
X(BI)
+X(BITS_USED)
X(blackbox)
X(B_SIGNED)
X(bugpoint_keep)
X(B_WIDTH)
+X(BYTE)
X(C)
X(cells_not_processed)
X(CE_OVER_SRST)
@@ -116,6 +118,8 @@ X(keep_hierarchy)
X(L)
X(lib_whitebox)
X(localparam)
+X(logic_block)
+X(lram)
X(LUT)
X(lut_keep)
X(M)
@@ -133,6 +137,7 @@ X(nomem2reg)
X(nomeminit)
X(nosync)
X(nowrshmsk)
+X(no_rw_check)
X(O)
X(OFFSET)
X(onehot)
@@ -145,6 +150,9 @@ X(PRIORITY_MASK)
X(Q)
X(qwp_position)
X(R)
+X(ram_block)
+X(ram_style)
+X(ramstyle)
X(RD_ADDR)
X(RD_ARST)
X(RD_ARST_VALUE)
@@ -164,6 +172,9 @@ X(RD_TRANSPARENT)
X(RD_WIDE_CONTINUATION)
X(reg)
X(reprocess_after)
+X(rom_block)
+X(rom_style)
+X(romstyle)
X(S)
X(SET)
X(SET_POLARITY)
@@ -185,7 +196,11 @@ X(STATE_NUM)
X(STATE_NUM_LOG2)
X(STATE_RST)
X(STATE_TABLE)
+X(smtlib2_module)
+X(smtlib2_comb_expr)
X(submod)
+X(syn_ramstyle)
+X(syn_romstyle)
X(S_WIDTH)
X(T)
X(TABLE)
diff --git a/kernel/driver.cc b/kernel/driver.cc
index 2cd1f473c..e52e1fb0e 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -118,7 +118,7 @@ int main(int argc, char **argv)
if (argc == 2)
{
// Run the first argument as a script file
- run_frontend(argv[1], "script", 0, 0, 0);
+ run_frontend(argv[1], "script");
}
}
@@ -192,6 +192,13 @@ void yosys_atexit()
#endif
}
+#if defined(__OpenBSD__)
+namespace Yosys {
+extern char *yosys_argv0;
+extern char yosys_path[PATH_MAX];
+};
+#endif
+
int main(int argc, char **argv)
{
std::string frontend_command = "auto";
@@ -202,12 +209,13 @@ int main(int argc, char **argv)
std::string output_filename = "";
std::string scriptfile = "";
std::string depsfile = "";
+ std::string topmodule = "";
bool scriptfile_tcl = false;
- bool got_output_filename = false;
bool print_banner = true;
bool print_stats = true;
bool call_abort = false;
bool timing_details = false;
+ bool run_shell = true;
bool mode_v = false;
bool mode_q = false;
@@ -288,6 +296,9 @@ int main(int argc, char **argv)
printf(" -A\n");
printf(" will call abort() at the end of the script. for debugging\n");
printf("\n");
+ printf(" -r <module_name>\n");
+ printf(" elaborate command line arguments using the specified top module\n");
+ printf("\n");
printf(" -D <macro>[=<value>]\n");
printf(" set the specified Verilog define (via \"read -define\")\n");
printf("\n");
@@ -342,7 +353,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:D:P:E:x:")) != -1)
+ 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)
{
switch (opt)
{
@@ -366,6 +377,7 @@ int main(int argc, char **argv)
exit(0);
case 'S':
passes_commands.push_back("synth");
+ run_shell = false;
break;
case 'g':
log_force_debug++;
@@ -378,19 +390,23 @@ int main(int argc, char **argv)
break;
case 'H':
passes_commands.push_back("help");
+ run_shell = false;
break;
case 'h':
passes_commands.push_back(stringf("help %s", optarg));
+ run_shell = false;
break;
case 'b':
backend_command = optarg;
+ run_shell = false;
break;
case 'p':
passes_commands.push_back(optarg);
+ run_shell = false;
break;
case 'o':
output_filename = optarg;
- got_output_filename = true;
+ run_shell = false;
break;
case 'l':
case 'L':
@@ -422,10 +438,12 @@ int main(int argc, char **argv)
case 's':
scriptfile = optarg;
scriptfile_tcl = false;
+ run_shell = false;
break;
case 'c':
scriptfile = optarg;
scriptfile_tcl = true;
+ run_shell = false;
break;
case 'W':
log_warn_regexes.push_back(YS_REGEX_COMPILE(optarg));
@@ -436,6 +454,9 @@ int main(int argc, char **argv)
case 'e':
log_werror_regexes.push_back(YS_REGEX_COMPILE(optarg));
break;
+ case 'r':
+ topmodule = optarg;
+ break;
case 'D':
vlog_defines.push_back(optarg);
break;
@@ -484,6 +505,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
{
@@ -506,12 +533,6 @@ int main(int argc, char **argv)
for (auto &fn : plugin_filenames)
load_plugin(fn, {});
- if (optind == argc && passes_commands.size() == 0 && scriptfile.empty()) {
- if (!got_output_filename)
- backend_command = "";
- shell(yosys_design);
- }
-
if (!vlog_defines.empty()) {
std::string vdef_cmd = "read -define";
for (auto vdef : vlog_defines)
@@ -520,7 +541,11 @@ int main(int argc, char **argv)
}
while (optind < argc)
- run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL);
+ if (run_frontend(argv[optind++], frontend_command))
+ run_shell = false;
+
+ if (!topmodule.empty())
+ run_pass("hierarchy -top " + topmodule);
if (!scriptfile.empty()) {
if (scriptfile_tcl) {
@@ -531,13 +556,15 @@ int main(int argc, char **argv)
log_error("Can't exectue TCL script: this version of yosys is not built with TCL support enabled.\n");
#endif
} else
- run_frontend(scriptfile, "script", output_filename == "-" ? &backend_command : NULL);
+ run_frontend(scriptfile, "script");
}
for (auto it = passes_commands.begin(); it != passes_commands.end(); it++)
run_pass(*it);
- if (!backend_command.empty())
+ if (run_shell)
+ shell(yosys_design);
+ else
run_backend(output_filename, backend_command);
yosys_design->check();
diff --git a/kernel/ff.cc b/kernel/ff.cc
index c43482bd2..b0f1a924f 100644
--- a/kernel/ff.cc
+++ b/kernel/ff.cc
@@ -669,14 +669,12 @@ namespace {
}
}
-void FfData::flip_bits(const pool<int> &bits) {
+void FfData::flip_rst_bits(const pool<int> &bits) {
if (!bits.size())
return;
remove_init();
- Wire *new_q = module->addWire(NEW_ID, width);
-
for (auto bit: bits) {
if (has_arst)
val_arst[bit] = invert(val_arst[bit]);
@@ -684,6 +682,15 @@ void FfData::flip_bits(const pool<int> &bits) {
val_srst[bit] = invert(val_srst[bit]);
val_init[bit] = invert(val_init[bit]);
}
+}
+
+void FfData::flip_bits(const pool<int> &bits) {
+ if (!bits.size())
+ return;
+
+ flip_rst_bits(bits);
+
+ Wire *new_q = module->addWire(NEW_ID, width);
if (has_sr && cell) {
log_warning("Flipping D/Q/init and inserting priority fixup to legalize %s.%s [%s].\n", log_id(module->name), log_id(cell->name), log_id(cell->type));
diff --git a/kernel/ff.h b/kernel/ff.h
index 5a629d5dd..41721b4a1 100644
--- a/kernel/ff.h
+++ b/kernel/ff.h
@@ -209,6 +209,8 @@ struct FfData {
// inputs and output, flip the corresponding init/reset bits, swap clr/set
// inputs with proper priority fix.
void flip_bits(const pool<int> &bits);
+
+ void flip_rst_bits(const pool<int> &bits);
};
YOSYS_NAMESPACE_END
diff --git a/kernel/fstdata.cc b/kernel/fstdata.cc
new file mode 100644
index 000000000..b2e574b02
--- /dev/null
+++ b/kernel/fstdata.cc
@@ -0,0 +1,252 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2022 Miodrag Milanovic <micko@yosyshq.com>
+ *
+ * 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/fstdata.h"
+
+USING_YOSYS_NAMESPACE
+
+
+static std::string file_base_name(std::string const & path)
+{
+ return path.substr(path.find_last_of("/\\") + 1);
+}
+
+FstData::FstData(std::string filename) : ctx(nullptr)
+{
+ #if !defined(YOSYS_DISABLE_SPAWN)
+ std::string filename_trim = file_base_name(filename);
+ if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".vcd") == 0) {
+ filename_trim.erase(filename_trim.size()-4);
+ tmp_file = stringf("%s/converted_%s.fst", get_base_tmpdir().c_str(), filename_trim.c_str());
+ std::string cmd = stringf("vcd2fst %s %s", filename.c_str(), tmp_file.c_str());
+ log("Exec: %s\n", cmd.c_str());
+ if (run_command(cmd) != 0)
+ log_cmd_error("Shell command failed!\n");
+ filename = tmp_file;
+ }
+ #endif
+ const std::vector<std::string> g_units = { "s", "ms", "us", "ns", "ps", "fs", "as", "zs" };
+ ctx = (fstReaderContext *)fstReaderOpen(filename.c_str());
+ if (!ctx)
+ log_error("Error opening '%s' as FST file\n", filename.c_str());
+ int scale = (int)fstReaderGetTimescale(ctx);
+ timescale = pow(10.0, scale);
+ timescale_str = "";
+ int unit = 0;
+ int zeros = 0;
+ if (scale > 0) {
+ zeros = scale;
+ } else {
+ if ((scale % 3) == 0) {
+ zeros = (-scale % 3);
+ unit = (-scale / 3);
+ } else {
+ zeros = 3 - (-scale % 3);
+ unit = (-scale / 3) + 1;
+ }
+ }
+ for (int i=0;i<zeros; i++) timescale_str += "0";
+ timescale_str += g_units[unit];
+ extractVarNames();
+}
+
+FstData::~FstData()
+{
+ if (ctx)
+ fstReaderClose(ctx);
+ if (!tmp_file.empty())
+ remove(tmp_file.c_str());
+}
+
+uint64_t FstData::getStartTime() { return fstReaderGetStartTime(ctx); }
+
+uint64_t FstData::getEndTime() { return fstReaderGetEndTime(ctx); }
+
+fstHandle FstData::getHandle(std::string name) {
+ if (name_to_handle.find(name) != name_to_handle.end())
+ return name_to_handle[name];
+ else
+ return 0;
+};
+
+dict<int,fstHandle> FstData::getMemoryHandles(std::string name) {
+ if (memory_to_handle.find(name) != memory_to_handle.end())
+ return memory_to_handle[name];
+ else
+ return dict<int,fstHandle>();
+};
+
+static std::string remove_spaces(std::string str)
+{
+ str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
+ return str;
+}
+
+void FstData::extractVarNames()
+{
+ struct fstHier *h;
+ std::string fst_scope_name;
+
+ while ((h = fstReaderIterateHier(ctx))) {
+ switch (h->htyp) {
+ case FST_HT_SCOPE: {
+ fst_scope_name = fstReaderPushScope(ctx, h->u.scope.name, NULL);
+ break;
+ }
+ case FST_HT_UPSCOPE: {
+ fst_scope_name = fstReaderPopScope(ctx);
+ break;
+ }
+ case FST_HT_VAR: {
+ FstVar var;
+ var.id = h->u.var.handle;
+ var.is_alias = h->u.var.is_alias;
+ 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;
+ var.width = h->u.var.length;
+ vars.push_back(var);
+ if (!var.is_alias)
+ handle_to_var[h->u.var.handle] = var;
+ std::string clean_name;
+ for(size_t i=0;i<strlen(h->u.var.name);i++)
+ {
+ char c = h->u.var.name[i];
+ if(c==' ') break;
+ clean_name += c;
+ }
+ if (clean_name[0]=='\\')
+ clean_name = clean_name.substr(1);
+ size_t pos = clean_name.find_last_of("<");
+ if (pos != std::string::npos) {
+ std::string mem_cell = clean_name.substr(0, pos);
+ 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());
+ } 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) {
+ std::string mem_cell = clean_name.substr(0, pos);
+ 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());
+ } 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;
+ }
+ }
+ name_to_handle[var.scope+"."+clean_name] = h->u.var.handle;
+ break;
+ }
+ }
+ }
+}
+
+
+static void reconstruct_clb_varlen_attimes(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen)
+{
+ FstData *ptr = (FstData*)user_data;
+ ptr->reconstruct_callback_attimes(pnt_time, pnt_facidx, pnt_value, plen);
+}
+
+static void reconstruct_clb_attimes(void *user_data, uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value)
+{
+ FstData *ptr = (FstData*)user_data;
+ uint32_t plen = (pnt_value) ? strlen((const char *)pnt_value) : 0;
+ ptr->reconstruct_callback_attimes(pnt_time, pnt_facidx, pnt_value, plen);
+}
+
+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 we are past the timestamp
+ bool is_clock = false;
+ if (!all_samples) {
+ for(auto &s : clk_signals) {
+ if (s==pnt_facidx) {
+ is_clock=true;
+ break;
+ }
+ }
+ }
+
+ if (pnt_time > past_time) {
+ past_data = last_data;
+ past_time = pnt_time;
+ }
+
+ if (pnt_time > last_time) {
+ if (all_samples) {
+ callback(last_time);
+ last_time = pnt_time;
+ } else {
+ if (is_clock) {
+ std::string val = std::string((const char *)pnt_value);
+ std::string prev = past_data[pnt_facidx];
+ if ((prev!="1" && val=="1") || (prev!="0" && val=="0")) {
+ callback(last_time);
+ last_time = pnt_time;
+ }
+ }
+ }
+ }
+ // always update last_data
+ last_data[pnt_facidx] = std::string((const char *)pnt_value);
+}
+
+void FstData::reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t start, uint64_t end, CallbackFunction cb)
+{
+ clk_signals = signal;
+ callback = cb;
+ start_time = start;
+ end_time = end;
+ last_data.clear();
+ last_time = start_time;
+ past_data.clear();
+ past_time = start_time;
+ all_samples = clk_signals.empty();
+
+ fstReaderSetUnlimitedTimeRange(ctx);
+ fstReaderSetFacProcessMaskAll(ctx);
+ fstReaderIterBlocks2(ctx, reconstruct_clb_attimes, reconstruct_clb_varlen_attimes, this, nullptr);
+ if (last_time!=end_time) {
+ past_data = last_data;
+ callback(last_time);
+ }
+ callback(end_time);
+}
+
+std::string FstData::valueOf(fstHandle signal)
+{
+ if (past_data.find(signal) == past_data.end())
+ log_error("Signal id %d not found\n", (int)signal);
+ return past_data[signal];
+}
diff --git a/kernel/fstdata.h b/kernel/fstdata.h
new file mode 100644
index 000000000..f5cf1d48d
--- /dev/null
+++ b/kernel/fstdata.h
@@ -0,0 +1,84 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2022 Miodrag Milanovic <micko@yosyshq.com>
+ *
+ * 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 FSTDATA_H
+#define FSTDATA_H
+
+#include "kernel/yosys.h"
+#include "libs/fst/fstapi.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+typedef std::function<void(uint64_t)> CallbackFunction;
+struct fst_end_of_data_exception { };
+
+struct FstVar
+{
+ fstHandle id;
+ std::string name;
+ bool is_alias;
+ bool is_reg;
+ std::string scope;
+ int width;
+};
+
+class FstData
+{
+ public:
+ FstData(std::string filename);
+ ~FstData();
+
+ uint64_t getStartTime();
+ uint64_t getEndTime();
+
+ std::vector<FstVar>& getVars() { return vars; };
+
+ void reconstruct_callback_attimes(uint64_t pnt_time, fstHandle pnt_facidx, const unsigned char *pnt_value, uint32_t plen);
+ void reconstructAllAtTimes(std::vector<fstHandle> &signal, uint64_t start_time, uint64_t end_time, CallbackFunction cb);
+
+ std::string valueOf(fstHandle signal);
+ fstHandle getHandle(std::string name);
+ dict<int,fstHandle> getMemoryHandles(std::string name);
+ double getTimescale() { return timescale; }
+ const char *getTimescaleString() { return timescale_str.c_str(); }
+private:
+ void extractVarNames();
+
+ struct fstReaderContext *ctx;
+ std::vector<FstVar> vars;
+ std::map<fstHandle, FstVar> handle_to_var;
+ std::map<std::string, fstHandle> name_to_handle;
+ std::map<std::string, dict<int, fstHandle>> memory_to_handle;
+ std::map<fstHandle, std::string> last_data;
+ uint64_t last_time;
+ std::map<fstHandle, std::string> past_data;
+ uint64_t past_time;
+ double timescale;
+ std::string timescale_str;
+ uint64_t start_time;
+ uint64_t end_time;
+ CallbackFunction callback;
+ std::vector<fstHandle> clk_signals;
+ bool all_samples;
+ std::string tmp_file;
+};
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/kernel/log.cc b/kernel/log.cc
index e7ce4cc46..4403dd0c7 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -71,7 +71,6 @@ int string_buf_index = -1;
static struct timeval initial_tv = { 0, 0 };
static bool next_print_log = false;
static int log_newline_count = 0;
-static bool display_error_log_msg = true;
static void log_id_cache_clear()
{
@@ -338,8 +337,7 @@ static void logv_error_with_prefix(const char *prefix,
f = stderr;
log_last_error = vstringf(format, ap);
- if (display_error_log_msg)
- log("%s%s", prefix, log_last_error.c_str());
+ log("%s%s", prefix, log_last_error.c_str());
log_flush();
log_make_debug = bak_log_make_debug;
@@ -629,7 +627,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();
@@ -665,7 +663,14 @@ void log_wire(RTLIL::Wire *wire, std::string indent)
void log_check_expected()
{
- for (auto &item : log_expect_warning) {
+ // copy out all of the expected logs so that they cannot be re-checked
+ // or match against themselves
+ dict<std::string, LogExpectedItem> expect_log, expect_warning, expect_error;
+ std::swap(expect_warning, log_expect_warning);
+ std::swap(expect_log, log_expect_log);
+ std::swap(expect_error, log_expect_error);
+
+ for (auto &item : expect_warning) {
if (item.second.current_count == 0) {
log_warn_regexes.clear();
log_error("Expected warning pattern '%s' not found !\n", item.first.c_str());
@@ -677,7 +682,7 @@ void log_check_expected()
}
}
- for (auto &item : log_expect_log) {
+ for (auto &item : expect_log) {
if (item.second.current_count == 0) {
log_warn_regexes.clear();
log_error("Expected log pattern '%s' not found !\n", item.first.c_str());
@@ -689,7 +694,7 @@ void log_check_expected()
}
}
- for (auto &item : log_expect_error)
+ for (auto &item : expect_error)
if (item.second.current_count == item.second.expected_count) {
log_warn_regexes.clear();
log("Expected error pattern '%s' found !!!\n", item.first.c_str());
@@ -701,14 +706,9 @@ void log_check_expected()
_Exit(0);
#endif
} else {
- display_error_log_msg = false;
log_warn_regexes.clear();
log_error("Expected error pattern '%s' not found !\n", item.first.c_str());
}
-
- log_expect_warning.clear();
- log_expect_log.clear();
- log_expect_error.clear();
}
// ---------------------------------------------------
diff --git a/kernel/log.h b/kernel/log.h
index ea14028dd..3bc9fd978 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -237,7 +237,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)
diff --git a/kernel/mem.cc b/kernel/mem.cc
index 746f667ea..e5e855ef7 100644
--- a/kernel/mem.cc
+++ b/kernel/mem.cc
@@ -985,7 +985,8 @@ Cell *Mem::extract_rdff(int idx, FfInitVals *initvals) {
c = ff.emit();
}
- log("Extracted %s FF from read port %d of %s.%s: %s\n", trans_use_addr ? "addr" : "data",
+ if (c)
+ log("Extracted %s FF from read port %d of %s.%s: %s\n", trans_use_addr ? "addr" : "data",
idx, log_id(module), log_id(memid), log_id(c));
port.en = State::S1;
@@ -1351,3 +1352,318 @@ void Mem::widen_wr_port(int idx, int wide_log2) {
port.wide_log2 = wide_log2;
}
}
+
+void Mem::emulate_rden(int idx, FfInitVals *initvals) {
+ auto &port = rd_ports[idx];
+ log_assert(port.clk_enable);
+ emulate_rd_ce_over_srst(idx);
+ Wire *new_data = module->addWire(NEW_ID, GetSize(port.data));
+ Wire *prev_data = module->addWire(NEW_ID, GetSize(port.data));
+ Wire *sel = module->addWire(NEW_ID);
+ FfData ff_sel(module, initvals, NEW_ID);
+ FfData ff_data(module, initvals, NEW_ID);
+ ff_sel.width = 1;
+ ff_sel.has_clk = true;
+ ff_sel.sig_clk = port.clk;
+ ff_sel.pol_clk = port.clk_polarity;
+ ff_sel.sig_d = port.en;
+ ff_sel.sig_q = sel;
+ ff_data.width = GetSize(port.data);
+ ff_data.has_clk = true;
+ ff_data.sig_clk = port.clk;
+ ff_data.pol_clk = port.clk_polarity;
+ ff_data.sig_d = port.data;
+ ff_data.sig_q = prev_data;
+ if (!port.init_value.is_fully_undef()) {
+ ff_sel.val_init = State::S0;
+ ff_data.val_init = port.init_value;
+ port.init_value = Const(State::Sx, GetSize(port.data));
+ } else {
+ ff_sel.val_init = State::Sx;
+ ff_data.val_init = Const(State::Sx, GetSize(port.data));
+ }
+ if (port.arst != State::S0) {
+ ff_sel.has_arst = true;
+ ff_sel.val_arst = State::S0;
+ ff_sel.sig_arst = port.arst;
+ ff_sel.pol_arst = true;
+ ff_data.has_arst = true;
+ ff_data.val_arst = port.arst_value;
+ ff_data.sig_arst = port.arst;
+ ff_data.pol_arst = true;
+ port.arst = State::S0;
+ }
+ if (port.srst != State::S0) {
+ log_assert(!port.ce_over_srst);
+ ff_sel.has_srst = true;
+ ff_sel.val_srst = State::S0;
+ ff_sel.sig_srst = port.srst;
+ ff_sel.pol_srst = true;
+ ff_sel.ce_over_srst = false;
+ ff_data.has_srst = true;
+ ff_data.val_srst = port.srst_value;
+ ff_data.sig_srst = port.srst;
+ ff_data.pol_srst = true;
+ ff_data.ce_over_srst = false;
+ port.srst = State::S0;
+ }
+ ff_sel.emit();
+ ff_data.emit();
+ module->addMux(NEW_ID, prev_data, new_data, sel, port.data);
+ port.data = new_data;
+ port.en = State::S1;
+}
+
+void Mem::emulate_reset(int idx, bool emu_init, bool emu_arst, bool emu_srst, FfInitVals *initvals) {
+ auto &port = rd_ports[idx];
+ if (emu_init && !port.init_value.is_fully_undef()) {
+ Wire *sel = module->addWire(NEW_ID);
+ FfData ff_sel(module, initvals, NEW_ID);
+ Wire *new_data = module->addWire(NEW_ID, GetSize(port.data));
+ ff_sel.width = 1;
+ ff_sel.has_clk = true;
+ ff_sel.sig_clk = port.clk;
+ ff_sel.pol_clk = port.clk_polarity;
+ ff_sel.sig_d = State::S1;
+ ff_sel.sig_q = sel;
+ ff_sel.val_init = State::S0;
+ if (port.en != State::S1) {
+ ff_sel.has_ce = true;
+ ff_sel.sig_ce = port.en;
+ ff_sel.pol_ce = true;
+ ff_sel.ce_over_srst = port.ce_over_srst;
+ }
+ if (port.arst != State::S0) {
+ ff_sel.has_arst = true;
+ ff_sel.sig_arst = port.arst;
+ ff_sel.pol_arst = true;
+ if (emu_arst && port.arst_value == port.init_value) {
+ // If we're going to emulate async reset anyway, and the reset
+ // value is the same as init value, reuse the same mux.
+ ff_sel.val_arst = State::S0;
+ port.arst = State::S0;
+ } else {
+ ff_sel.val_arst = State::S1;
+ }
+ }
+ if (port.srst != State::S0) {
+ ff_sel.has_srst = true;
+ ff_sel.sig_srst = port.srst;
+ ff_sel.pol_srst = true;
+ if (emu_srst && port.srst_value == port.init_value) {
+ ff_sel.val_srst = State::S0;
+ port.srst = State::S0;
+ } else {
+ ff_sel.val_srst = State::S1;
+ }
+ }
+ ff_sel.emit();
+ module->addMux(NEW_ID, port.init_value, new_data, sel, port.data);
+ port.data = new_data;
+ port.init_value = Const(State::Sx, GetSize(port.data));
+ }
+ if (emu_arst && port.arst != State::S0) {
+ Wire *sel = module->addWire(NEW_ID);
+ FfData ff_sel(module, initvals, NEW_ID);
+ Wire *new_data = module->addWire(NEW_ID, GetSize(port.data));
+ ff_sel.width = 1;
+ ff_sel.has_clk = true;
+ ff_sel.sig_clk = port.clk;
+ ff_sel.pol_clk = port.clk_polarity;
+ ff_sel.sig_d = State::S1;
+ ff_sel.sig_q = sel;
+ if (port.init_value.is_fully_undef())
+ ff_sel.val_init = State::Sx;
+ else
+ ff_sel.val_init = State::S1;
+ if (port.en != State::S1) {
+ ff_sel.has_ce = true;
+ ff_sel.sig_ce = port.en;
+ ff_sel.pol_ce = true;
+ ff_sel.ce_over_srst = port.ce_over_srst;
+ }
+ ff_sel.has_arst = true;
+ ff_sel.sig_arst = port.arst;
+ ff_sel.pol_arst = true;
+ ff_sel.val_arst = State::S0;
+ if (port.srst != State::S0) {
+ ff_sel.has_srst = true;
+ ff_sel.sig_srst = port.srst;
+ ff_sel.pol_srst = true;
+ if (emu_srst && port.srst_value == port.arst_value) {
+ ff_sel.val_srst = State::S0;
+ port.srst = State::S0;
+ } else {
+ ff_sel.val_srst = State::S1;
+ }
+ }
+ ff_sel.emit();
+ module->addMux(NEW_ID, port.arst_value, new_data, sel, port.data);
+ port.data = new_data;
+ port.arst = State::S0;
+ }
+ if (emu_srst && port.srst != State::S0) {
+ Wire *sel = module->addWire(NEW_ID);
+ FfData ff_sel(module, initvals, NEW_ID);
+ Wire *new_data = module->addWire(NEW_ID, GetSize(port.data));
+ ff_sel.width = 1;
+ ff_sel.has_clk = true;
+ ff_sel.sig_clk = port.clk;
+ ff_sel.pol_clk = port.clk_polarity;
+ ff_sel.sig_d = State::S1;
+ ff_sel.sig_q = sel;
+ if (port.init_value.is_fully_undef())
+ ff_sel.val_init = State::Sx;
+ else
+ ff_sel.val_init = State::S1;
+ if (port.en != State::S1) {
+ ff_sel.has_ce = true;
+ ff_sel.sig_ce = port.en;
+ ff_sel.pol_ce = true;
+ ff_sel.ce_over_srst = port.ce_over_srst;
+ }
+ ff_sel.has_srst = true;
+ ff_sel.sig_srst = port.srst;
+ ff_sel.pol_srst = true;
+ ff_sel.val_srst = State::S0;
+ if (port.arst != State::S0) {
+ ff_sel.has_arst = true;
+ ff_sel.sig_arst = port.arst;
+ ff_sel.pol_arst = true;
+ ff_sel.val_arst = State::S1;
+ }
+ ff_sel.emit();
+ module->addMux(NEW_ID, port.srst_value, new_data, sel, port.data);
+ port.data = new_data;
+ port.srst = State::S0;
+ }
+}
+
+void Mem::emulate_rd_ce_over_srst(int idx) {
+ auto &port = rd_ports[idx];
+ log_assert(port.clk_enable);
+ if (port.en == State::S1 || port.srst == State::S0 || !port.ce_over_srst) {
+ port.ce_over_srst = false;
+ return;
+ }
+ port.ce_over_srst = false;
+ port.srst = module->And(NEW_ID, port.en, port.srst);
+}
+
+void Mem::emulate_rd_srst_over_ce(int idx) {
+ auto &port = rd_ports[idx];
+ log_assert(port.clk_enable);
+ if (port.en == State::S1 || port.srst == State::S0 || port.ce_over_srst) {
+ port.ce_over_srst = true;
+ return;
+ }
+ port.ce_over_srst = true;
+ port.en = module->Or(NEW_ID, port.en, port.srst);
+}
+
+bool Mem::emulate_read_first_ok() {
+ if (wr_ports.empty())
+ return false;
+ SigSpec clk = wr_ports[0].clk;
+ bool clk_polarity = wr_ports[0].clk_polarity;
+ for (auto &port: wr_ports) {
+ if (!port.clk_enable)
+ return false;
+ if (port.clk != clk)
+ return false;
+ if (port.clk_polarity != clk_polarity)
+ return false;
+ }
+ bool found_read_first = false;
+ for (auto &port: rd_ports) {
+ if (!port.clk_enable)
+ return false;
+ if (port.clk != clk)
+ return false;
+ if (port.clk_polarity != clk_polarity)
+ return false;
+ // No point doing this operation if there is no read-first relationship
+ // in the first place.
+ for (int j = 0; j < GetSize(wr_ports); j++)
+ if (!port.transparency_mask[j] && !port.collision_x_mask[j])
+ found_read_first = true;
+ }
+ return found_read_first;
+}
+
+void Mem::emulate_read_first(FfInitVals *initvals) {
+ log_assert(emulate_read_first_ok());
+ for (int i = 0; i < GetSize(rd_ports); i++)
+ for (int j = 0; j < GetSize(wr_ports); j++)
+ if (rd_ports[i].transparency_mask[j])
+ emulate_transparency(j, i, initvals);
+ for (int i = 0; i < GetSize(rd_ports); i++)
+ for (int j = 0; j < GetSize(wr_ports); j++) {
+ log_assert(!rd_ports[i].transparency_mask[j]);
+ rd_ports[i].collision_x_mask[j] = false;
+ rd_ports[i].transparency_mask[j] = true;
+ }
+ for (auto &port: wr_ports) {
+ Wire *new_data = module->addWire(NEW_ID, GetSize(port.data));
+ Wire *new_addr = module->addWire(NEW_ID, GetSize(port.addr));
+ auto compressed = port.compress_en();
+ Wire *new_en = module->addWire(NEW_ID, GetSize(compressed.first));
+ FfData ff_data(module, initvals, NEW_ID);
+ FfData ff_addr(module, initvals, NEW_ID);
+ FfData ff_en(module, initvals, NEW_ID);
+ ff_data.width = GetSize(port.data);
+ ff_data.has_clk = true;
+ ff_data.sig_clk = port.clk;
+ ff_data.pol_clk = port.clk_polarity;
+ ff_data.sig_d = port.data;
+ ff_data.sig_q = new_data;;
+ ff_data.val_init = Const(State::Sx, ff_data.width);
+ ff_data.emit();
+ ff_addr.width = GetSize(port.addr);
+ ff_addr.has_clk = true;
+ ff_addr.sig_clk = port.clk;
+ ff_addr.pol_clk = port.clk_polarity;
+ ff_addr.sig_d = port.addr;
+ ff_addr.sig_q = new_addr;;
+ ff_addr.val_init = Const(State::Sx, ff_addr.width);
+ ff_addr.emit();
+ ff_en.width = GetSize(compressed.first);
+ ff_en.has_clk = true;
+ ff_en.sig_clk = port.clk;
+ ff_en.pol_clk = port.clk_polarity;
+ ff_en.sig_d = compressed.first;
+ ff_en.sig_q = new_en;;
+ if (inits.empty())
+ ff_en.val_init = Const(State::Sx, ff_en.width);
+ else
+ ff_en.val_init = Const(State::S0, ff_en.width);
+ ff_en.emit();
+ port.data = new_data;
+ port.addr = new_addr;
+ port.en = port.decompress_en(compressed.second, new_en);
+ }
+}
+
+std::pair<SigSpec, std::vector<int>> MemWr::compress_en() {
+ SigSpec sig = en[0];
+ std::vector<int> swizzle;
+ SigBit prev_bit = en[0];
+ int idx = 0;
+ for (auto &bit: en) {
+ if (bit != prev_bit) {
+ sig.append(bit);
+ prev_bit = bit;
+ idx++;
+ }
+ swizzle.push_back(idx);
+ }
+ log_assert(idx + 1 == GetSize(sig));
+ return {sig, swizzle};
+}
+
+SigSpec MemWr::decompress_en(const std::vector<int> &swizzle, SigSpec sig) {
+ SigSpec res;
+ for (int i: swizzle)
+ res.append(sig[i]);
+ return res;
+}
diff --git a/kernel/mem.h b/kernel/mem.h
index 87a148beb..8c484274c 100644
--- a/kernel/mem.h
+++ b/kernel/mem.h
@@ -46,7 +46,7 @@ struct MemRd : RTLIL::AttrObject {
std::vector<bool> collision_x_mask;
SigSpec clk, en, arst, srst, addr, data;
- MemRd() : removed(false), cell(nullptr) {}
+ MemRd() : removed(false), cell(nullptr), wide_log2(0), clk_enable(false), clk_polarity(true), ce_over_srst(false), clk(State::Sx), en(State::S1), arst(State::S0), srst(State::S0) {}
// Returns the address of given subword index accessed by this port.
SigSpec sub_addr(int sub) {
@@ -74,6 +74,9 @@ struct MemWr : RTLIL::AttrObject {
res[i] = State(sub >> i & 1);
return res;
}
+
+ std::pair<SigSpec, std::vector<int>> compress_en();
+ SigSpec decompress_en(const std::vector<int> &swizzle, SigSpec sig);
};
struct MemInit : RTLIL::AttrObject {
@@ -191,6 +194,33 @@ struct Mem : RTLIL::AttrObject {
// original address.
void widen_wr_port(int idx, int wide_log2);
+ // Emulates a sync read port's enable functionality in soft logic,
+ // changing the actual read port's enable to be always-on.
+ void emulate_rden(int idx, FfInitVals *initvals);
+
+ // Emulates a sync read port's initial/reset value functionality in
+ // soft logic, removing it from the actual read port.
+ void emulate_reset(int idx, bool emu_init, bool emu_arst, bool emu_srst, FfInitVals *initvals);
+
+ // Given a read port with ce_over_srst set, converts it to a port
+ // with ce_over_srst unset without changing its behavior by adding
+ // emulation logic.
+ void emulate_rd_ce_over_srst(int idx);
+
+ // Given a read port with ce_over_srst unset, converts it to a port
+ // with ce_over_srst set without changing its behavior by adding
+ // emulation logic.
+ void emulate_rd_srst_over_ce(int idx);
+
+ // Returns true iff emulate_read_first makes sense to call.
+ bool emulate_read_first_ok();
+
+ // Emulates all read-first read-write port relationships in terms of
+ // all-transparent ports, by delaying all write ports by one cycle.
+ // This can only be used when all read ports and all write ports are
+ // in the same clock domain.
+ void emulate_read_first(FfInitVals *initvals);
+
Mem(Module *module, IdString memid, int width, int start_offset, int size) : module(module), memid(memid), packed(false), mem(nullptr), cell(nullptr), width(width), start_offset(start_offset), size(size) {}
};
diff --git a/kernel/qcsat.cc b/kernel/qcsat.cc
index b7da958db..aaee984fb 100644
--- a/kernel/qcsat.cc
+++ b/kernel/qcsat.cc
@@ -84,7 +84,7 @@ int QuickConeSat::cell_complexity(RTLIL::Cell *cell)
ID($reduce_xnor), ID($reduce_bool),
ID($logic_not), ID($logic_and), ID($logic_or),
ID($eq), ID($ne), ID($eqx), ID($nex), ID($fa),
- ID($mux), ID($pmux), ID($lut), ID($sop),
+ ID($mux), ID($pmux), ID($bmux), ID($demux), ID($lut), ID($sop),
ID($_NOT_), ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_),
ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_),
ID($_MUX_), ID($_NMUX_), ID($_MUX4_), ID($_MUX8_), ID($_MUX16_),
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index cd0f5ab12..b274bba78 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -199,14 +199,10 @@ const pool<IdString> &RTLIL::builtin_ff_cell_types() {
return res;
}
-RTLIL::Const::Const()
-{
- flags = RTLIL::CONST_FLAG_NONE;
-}
-
-RTLIL::Const::Const(std::string str)
+RTLIL::Const::Const(const std::string &str)
{
flags = RTLIL::CONST_FLAG_STRING;
+ bits.reserve(str.size() * 8);
for (int i = str.size()-1; i >= 0; i--) {
unsigned char ch = str[i];
for (int j = 0; j < 8; j++) {
@@ -219,6 +215,7 @@ RTLIL::Const::Const(std::string str)
RTLIL::Const::Const(int val, int width)
{
flags = RTLIL::CONST_FLAG_NONE;
+ bits.reserve(width);
for (int i = 0; i < width; i++) {
bits.push_back((val & 1) != 0 ? State::S1 : State::S0);
val = val >> 1;
@@ -228,6 +225,7 @@ RTLIL::Const::Const(int val, int width)
RTLIL::Const::Const(RTLIL::State bit, int width)
{
flags = RTLIL::CONST_FLAG_NONE;
+ bits.reserve(width);
for (int i = 0; i < width; i++)
bits.push_back(bit);
}
@@ -235,17 +233,11 @@ RTLIL::Const::Const(RTLIL::State bit, int width)
RTLIL::Const::Const(const std::vector<bool> &bits)
{
flags = RTLIL::CONST_FLAG_NONE;
+ this->bits.reserve(bits.size());
for (const auto &b : bits)
this->bits.emplace_back(b ? State::S1 : State::S0);
}
-RTLIL::Const::Const(const RTLIL::Const &c)
-{
- flags = c.flags;
- for (const auto &b : c.bits)
- this->bits.push_back(b);
-}
-
bool RTLIL::Const::operator <(const RTLIL::Const &other) const
{
if (bits.size() != other.bits.size())
@@ -398,12 +390,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);
@@ -411,7 +403,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())
@@ -419,7 +411,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);
@@ -427,7 +419,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);
@@ -436,7 +428,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) {
@@ -447,7 +439,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());
@@ -455,7 +447,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)
@@ -480,7 +472,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) {
@@ -491,7 +483,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);
@@ -509,7 +501,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;
@@ -520,7 +512,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;
@@ -529,7 +521,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;
@@ -641,12 +633,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;
}
@@ -828,7 +820,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;
@@ -837,7 +829,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;
@@ -846,7 +838,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;
@@ -990,7 +982,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);
}
@@ -1015,7 +1007,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())
@@ -1024,7 +1016,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)
@@ -1034,7 +1026,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)
@@ -1042,14 +1034,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())
@@ -1251,6 +1243,22 @@ namespace {
return;
}
+ if (cell->type == ID($bmux)) {
+ port(ID::A, param(ID::WIDTH) << param(ID::S_WIDTH));
+ port(ID::S, param(ID::S_WIDTH));
+ port(ID::Y, param(ID::WIDTH));
+ check_expected();
+ return;
+ }
+
+ if (cell->type == ID($demux)) {
+ port(ID::A, param(ID::WIDTH));
+ port(ID::S, param(ID::S_WIDTH));
+ port(ID::Y, param(ID::WIDTH) << param(ID::S_WIDTH));
+ check_expected();
+ return;
+ }
+
if (cell->type == ID($lut)) {
param(ID::LUT);
port(ID::A, param(ID::WIDTH));
@@ -1829,6 +1837,8 @@ void RTLIL::Module::check()
log_assert(!it2.first.empty());
}
+ pool<IdString> packed_memids;
+
for (auto &it : cells_) {
log_assert(this == it.second->module);
log_assert(it.first == it.second->name);
@@ -1844,6 +1854,14 @@ void RTLIL::Module::check()
log_assert(!it2.first.empty());
InternalCellChecker checker(this, it.second);
checker.check();
+ if (it.second->has_memid()) {
+ log_assert(memories.count(it.second->parameters.at(ID::MEMID).decode_string()));
+ } else if (it.second->is_mem_cell()) {
+ IdString memid = it.second->parameters.at(ID::MEMID).decode_string();
+ log_assert(!memories.count(memid));
+ log_assert(!packed_memids.count(memid));
+ packed_memids.insert(memid);
+ }
}
for (auto &it : processes) {
@@ -2444,6 +2462,26 @@ DEF_METHOD(Mux, ID($mux), 0)
DEF_METHOD(Pmux, ID($pmux), 1)
#undef DEF_METHOD
+#define DEF_METHOD(_func, _type, _demux) \
+ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_y, const std::string &src) { \
+ RTLIL::Cell *cell = addCell(name, _type); \
+ cell->parameters[ID::WIDTH] = _demux ? sig_a.size() : sig_y.size(); \
+ cell->parameters[ID::S_WIDTH] = sig_s.size(); \
+ cell->setPort(ID::A, sig_a); \
+ cell->setPort(ID::S, sig_s); \
+ 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, _demux ? sig_a.size() << sig_s.size() : sig_a.size() >> sig_s.size()); \
+ add ## _func(name, sig_a, sig_s, sig_y, src); \
+ return sig_y; \
+ }
+DEF_METHOD(Bmux, ID($bmux), 0)
+DEF_METHOD(Demux, ID($demux), 1)
+#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); \
@@ -3216,12 +3254,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);
@@ -3244,7 +3282,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;
@@ -3266,7 +3304,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);
}
@@ -3285,7 +3323,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);
@@ -3297,7 +3335,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);
@@ -3309,22 +3347,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())
@@ -3358,14 +3396,21 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
type.begins_with("$verific$") || type.begins_with("$array:") || type.begins_with("$extern:"))
return;
- if (type == ID($mux) || type == ID($pmux)) {
+ if (type == ID($mux) || type == ID($pmux) || type == ID($bmux)) {
parameters[ID::WIDTH] = GetSize(connections_[ID::Y]);
- if (type == ID($pmux))
+ if (type != ID($mux))
parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]);
check();
return;
}
+ if (type == ID($demux)) {
+ parameters[ID::WIDTH] = GetSize(connections_[ID::A]);
+ parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]);
+ check();
+ return;
+ }
+
if (type == ID($lut) || type == ID($sop)) {
parameters[ID::WIDTH] = GetSize(connections_[ID::A]);
return;
@@ -3422,61 +3467,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;
@@ -3488,11 +3478,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;
@@ -3538,17 +3523,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");
@@ -3563,23 +3537,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;
@@ -3602,6 +3579,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 073110f16..ff5bdf2d7 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,7 +435,7 @@ 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;
}
};
@@ -485,6 +485,9 @@ 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_bmux (const RTLIL::Const &arg1, const RTLIL::Const &arg2);
+ RTLIL::Const const_demux (const RTLIL::Const &arg1, const RTLIL::Const &arg2);
+
// 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.
@@ -632,13 +635,13 @@ struct RTLIL::Const
int flags;
std::vector<RTLIL::State> bits;
- Const();
- Const(std::string str);
+ Const() : flags(RTLIL::CONST_FLAG_NONE) {}
+ Const(const std::string &str);
Const(int val, int width = 32);
Const(RTLIL::State bit, int width = 1);
Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; }
Const(const std::vector<bool> &bits);
- Const(const RTLIL::Const &c);
+ Const(const RTLIL::Const &c) = default;
RTLIL::Const &operator =(const RTLIL::Const &other) = default;
bool operator <(const RTLIL::Const &other) const;
@@ -693,21 +696,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);
@@ -719,8 +722,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
@@ -729,16 +732,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; }
@@ -824,13 +826,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);
@@ -843,21 +845,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_;
@@ -970,7 +957,7 @@ public:
#ifndef NDEBUG
void check(Module *mod = nullptr) const;
#else
- void check(Module *mod = nullptr) const { }
+ void check(Module *mod = nullptr) const { (void)mod; }
#endif
};
@@ -982,9 +969,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) {
@@ -1050,11 +1037,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;
}
@@ -1079,9 +1066,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;
@@ -1162,7 +1149,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);
@@ -1197,20 +1184,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;
}
@@ -1296,6 +1283,8 @@ public:
RTLIL::Cell* addMux (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* addPmux (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* 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* 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 = "");
@@ -1421,6 +1410,8 @@ public:
RTLIL::SigSpec Mux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = "");
RTLIL::SigSpec Pmux (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src = "");
+ 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::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 = "");
@@ -1476,6 +1467,10 @@ public:
#endif
};
+inline int GetSize(RTLIL::Wire *wire) {
+ return wire->width;
+}
+
struct RTLIL::Memory : public RTLIL::AttrObject
{
unsigned int hashidx_;
@@ -1514,22 +1509,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 214826f5a..9c40ec66d 100644
--- a/kernel/satgen.cc
+++ b/kernel/satgen.cc
@@ -252,6 +252,106 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
return true;
}
+ if (cell->type == ID($bmux))
+ {
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> s = importDefSigSpec(cell->getPort(ID::S), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
+ std::vector<int> undef_a, undef_s, undef_y;
+
+ if (model_undef)
+ {
+ undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep);
+ undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
+ }
+
+ if (GetSize(s) == 0) {
+ ez->vec_set(a, y);
+ if (model_undef)
+ ez->vec_set(undef_a, undef_y);
+ } else {
+ for (int i = GetSize(s)-1; i >= 0; i--)
+ {
+ std::vector<int> out = (i == 0) ? y : ez->vec_var(a.size() / 2);
+ std::vector<int> yy = model_undef ? ez->vec_var(out.size()) : out;
+
+ std::vector<int> a0(a.begin(), a.begin() + a.size() / 2);
+ std::vector<int> a1(a.begin() + a.size() / 2, a.end());
+ ez->assume(ez->vec_eq(ez->vec_ite(s.at(i), a1, a0), yy));
+
+ if (model_undef)
+ {
+ std::vector<int> undef_out = (i == 0) ? undef_y : ez->vec_var(a.size() / 2);
+ std::vector<int> undef_a0(undef_a.begin(), undef_a.begin() + a.size() / 2);
+ std::vector<int> undef_a1(undef_a.begin() + a.size() / 2, undef_a.end());
+ std::vector<int> unequal_ab = ez->vec_not(ez->vec_iff(a0, a1));
+ std::vector<int> undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a0, undef_a1));
+ std::vector<int> yX = ez->vec_ite(undef_s.at(i), undef_ab, ez->vec_ite(s.at(i), undef_a1, undef_a0));
+ ez->assume(ez->vec_eq(yX, undef_out));
+ undefGating(out, yy, undef_out);
+
+ undef_a = undef_out;
+ }
+
+ a = out;
+ }
+ }
+ return true;
+ }
+
+ if (cell->type == ID($demux))
+ {
+ std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
+ std::vector<int> s = importDefSigSpec(cell->getPort(ID::S), timestep);
+ std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
+ std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
+ std::vector<int> undef_a, undef_s, undef_y;
+
+ if (model_undef)
+ {
+ undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep);
+ undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep);
+ undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
+ }
+
+ if (GetSize(s) == 0) {
+ ez->vec_set(a, y);
+ if (model_undef)
+ ez->vec_set(undef_a, undef_y);
+ } else {
+ for (int i = 0; i < (1 << GetSize(s)); i++)
+ {
+ std::vector<int> ss;
+ for (int j = 0; j < GetSize(s); j++) {
+ if (i & 1 << j)
+ ss.push_back(s[j]);
+ else
+ ss.push_back(ez->NOT(s[j]));
+ }
+ int sss = ez->expression(ezSAT::OpAnd, ss);
+
+ for (int j = 0; j < GetSize(a); j++) {
+ ez->SET(ez->AND(sss, a[j]), yy.at(i * GetSize(a) + j));
+ }
+
+ if (model_undef)
+ {
+ int s0 = ez->expression(ezSAT::OpOr, ez->vec_and(ez->vec_not(ss), ez->vec_not(undef_s)));
+ int us = ez->AND(ez->NOT(s0), ez->expression(ezSAT::OpOr, undef_s));
+ for (int j = 0; j < GetSize(a); j++) {
+ int a0 = ez->AND(ez->NOT(a[j]), ez->NOT(undef_a[j]));
+ int yX = ez->AND(ez->OR(us, undef_a[j]), ez->NOT(ez->OR(s0, a0)));
+ ez->SET(yX, undef_y.at(i * GetSize(a) + j));
+ }
+ }
+ }
+ if (model_undef)
+ undefGating(y, yy, undef_y);
+ }
+ return true;
+ }
+
if (cell->type == ID($pmux))
{
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index 39d6a1ec1..a56a066fe 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -376,35 +376,54 @@ int run_command(const std::string &command, std::function<void(const std::string
}
#endif
-std::string make_temp_file(std::string template_str)
+std::string get_base_tmpdir()
{
-#if defined(__wasm)
- size_t pos = template_str.rfind("XXXXXX");
- log_assert(pos != std::string::npos);
- static size_t index = 0;
- template_str.replace(pos, 6, stringf("%06zu", index++));
-#elif defined(_WIN32)
- if (template_str.rfind("/tmp/", 0) == 0) {
+ static std::string tmpdir;
+
+ if (!tmpdir.empty()) {
+ return tmpdir;
+ }
+
+#if defined(_WIN32)
# ifdef __MINGW32__
- char longpath[MAX_PATH + 1];
- char shortpath[MAX_PATH + 1];
+ char longpath[MAX_PATH + 1];
+ char shortpath[MAX_PATH + 1];
# else
- WCHAR longpath[MAX_PATH + 1];
- TCHAR shortpath[MAX_PATH + 1];
+ WCHAR longpath[MAX_PATH + 1];
+ TCHAR shortpath[MAX_PATH + 1];
# endif
- if (!GetTempPath(MAX_PATH+1, longpath))
- log_error("GetTempPath() failed.\n");
- if (!GetShortPathName(longpath, shortpath, MAX_PATH + 1))
- log_error("GetShortPathName() failed.\n");
- std::string path;
- for (int i = 0; shortpath[i]; i++)
- path += char(shortpath[i]);
- template_str = stringf("%s\\%s", path.c_str(), template_str.c_str() + 5);
+ if (!GetTempPath(MAX_PATH+1, longpath))
+ log_error("GetTempPath() failed.\n");
+ if (!GetShortPathName(longpath, shortpath, MAX_PATH + 1))
+ log_error("GetShortPathName() failed.\n");
+ for (int i = 0; shortpath[i]; i++)
+ tmpdir += char(shortpath[i]);
+#else
+ char * var = std::getenv("TMPDIR");
+ if (var && strlen(var)!=0) {
+ tmpdir.assign(var);
+ // We return the directory name without the trailing '/'
+ while (!tmpdir.empty() && (tmpdir.back() == '/')) {
+ tmpdir.pop_back();
+ }
+ } else {
+ tmpdir.assign("/tmp");
}
+#endif
+ return tmpdir;
+}
+std::string make_temp_file(std::string template_str)
+{
size_t pos = template_str.rfind("XXXXXX");
log_assert(pos != std::string::npos);
-
+#if defined(__wasm)
+ static size_t index = 0;
+ template_str.replace(pos, 6, stringf("%06zu", index++));
+#elif defined(_WIN32)
+#ifndef YOSYS_WIN32_UNIX_DIR
+ std::replace(template_str.begin(), template_str.end(), '/', '\\');
+#endif
while (1) {
for (int i = 0; i < 6; i++) {
static std::string y = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
@@ -416,9 +435,6 @@ std::string make_temp_file(std::string template_str)
break;
}
#else
- size_t pos = template_str.rfind("XXXXXX");
- log_assert(pos != std::string::npos);
-
int suffixlen = GetSize(template_str) - pos - 6;
char *p = strdup(template_str.c_str());
@@ -518,11 +534,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()
@@ -618,6 +629,23 @@ RTLIL::IdString new_id(std::string file, int line, std::string func)
return stringf("$auto$%s:%d:%s$%d", file.c_str(), line, func.c_str(), autoidx++);
}
+RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix)
+{
+#ifdef _WIN32
+ size_t pos = file.find_last_of("/\\");
+#else
+ size_t pos = file.find_last_of('/');
+#endif
+ if (pos != std::string::npos)
+ file = file.substr(pos+1);
+
+ pos = func.find_last_of(':');
+ if (pos != std::string::npos)
+ func = func.substr(pos+1);
+
+ return stringf("$auto$%s:%d:%s$%s$%d", file.c_str(), line, func.c_str(), suffix.c_str(), autoidx++);
+}
+
RTLIL::Design *yosys_get_design()
{
return yosys_design;
@@ -716,6 +744,8 @@ 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);
}
return yosys_tcl_interp;
@@ -739,6 +769,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' to redirect yosys's\n");
+ log("output to a temporary file.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *) override {
if (args.size() < 2)
@@ -832,6 +866,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
@@ -956,7 +1019,7 @@ static void handle_label(std::string &command, bool &from_to_active, const std::
}
}
-void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label, RTLIL::Design *design)
+bool run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *from_to_label)
{
if (design == nullptr)
design = yosys_design;
@@ -966,11 +1029,11 @@ void run_frontend(std::string filename, std::string command, std::string *backen
if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".gz") == 0)
filename_trim.erase(filename_trim.size()-3);
if (filename_trim.size() > 2 && filename_trim.compare(filename_trim.size()-2, std::string::npos, ".v") == 0)
- command = "verilog";
+ command = " -vlog2k";
else if (filename_trim.size() > 2 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".sv") == 0)
- command = "verilog -sv";
+ command = " -sv";
else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".vhd") == 0)
- command = "vhdl";
+ command = " -vhdl";
else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-5, std::string::npos, ".blif") == 0)
command = "blif";
else if (filename_trim.size() > 5 && filename_trim.compare(filename_trim.size()-6, std::string::npos, ".eblif") == 0)
@@ -1056,10 +1119,12 @@ void run_frontend(std::string filename, std::string command, std::string *backen
if (filename != "-")
fclose(f);
- if (backend_command != NULL && *backend_command == "auto")
- *backend_command = "";
+ return true;
+ }
- return;
+ if (command == "tcl") {
+ Pass::call(design, vector<string>({command, filename}));
+ return true;
}
if (filename == "-") {
@@ -1068,16 +1133,15 @@ void run_frontend(std::string filename, std::string command, std::string *backen
log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str());
}
- if (command == "tcl")
- Pass::call(design, vector<string>({command, filename}));
- else
+ if (command[0] == ' ') {
+ auto argv = split_tokens("read" + command);
+ argv.push_back(filename);
+ Pass::call(design, argv);
+ } else
Frontend::frontend_call(design, NULL, filename, command);
- design->check();
-}
-void run_frontend(std::string filename, std::string command, RTLIL::Design *design)
-{
- run_frontend(filename, command, nullptr, nullptr, design);
+ design->check();
+ return false;
}
void run_pass(std::string command, RTLIL::Design *design)
@@ -1391,7 +1455,7 @@ struct ScriptCmdPass : public Pass {
else if (args.size() == 2)
run_frontend(args[1], "script", design);
else if (args.size() == 3)
- run_frontend(args[1], "script", NULL, &args[2], design);
+ run_frontend(args[1], "script", design, &args[2]);
else
extra_args(args, 2, design, false);
}
diff --git a/kernel/yosys.h b/kernel/yosys.h
index 826e7f4cd..b5b1553f2 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -278,15 +278,16 @@ bool patmatch(const char *pattern, const char *string);
#if !defined(YOSYS_DISABLE_SPAWN)
int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
#endif
-std::string make_temp_file(std::string template_str = "/tmp/yosys_XXXXXX");
-std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX");
+std::string get_base_tmpdir();
+std::string make_temp_file(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
+std::string make_temp_dir(std::string template_str = get_base_tmpdir() + "/yosys_XXXXXX");
bool check_file_exists(std::string filename, bool is_exec = false);
bool is_absolute_path(std::string filename);
void remove_directory(std::string dirname);
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;
@@ -322,9 +323,12 @@ Tcl_Interp *yosys_get_tcl_interp();
extern RTLIL::Design *yosys_design;
RTLIL::IdString new_id(std::string file, int line, std::string func);
+RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix);
#define NEW_ID \
YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__)
+#define NEW_ID_SUFFIX(suffix) \
+ YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix)
// Create a statically allocated IdString object, using for example ID::A or ID($add).
//
@@ -347,8 +351,7 @@ std::vector<std::string> glob_filename(const std::string &filename_pattern);
void rewrite_filename(std::string &filename);
void run_pass(std::string command, RTLIL::Design *design = nullptr);
-void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label = nullptr, RTLIL::Design *design = nullptr);
-void run_frontend(std::string filename, std::string command, RTLIL::Design *design = nullptr);
+bool run_frontend(std::string filename, std::string command, RTLIL::Design *design = nullptr, std::string *from_to_label = nullptr);
void run_backend(std::string filename, std::string command, RTLIL::Design *design = nullptr);
void shell(RTLIL::Design *design);