diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/calc.cc | 51 | ||||
-rw-r--r-- | kernel/celledges.cc | 40 | ||||
-rw-r--r-- | kernel/celltypes.h | 29 | ||||
-rw-r--r-- | kernel/consteval.h | 39 | ||||
-rw-r--r-- | kernel/constids.inc | 15 | ||||
-rw-r--r-- | kernel/driver.cc | 53 | ||||
-rw-r--r-- | kernel/ff.cc | 13 | ||||
-rw-r--r-- | kernel/ff.h | 2 | ||||
-rw-r--r-- | kernel/fstdata.cc | 252 | ||||
-rw-r--r-- | kernel/fstdata.h | 84 | ||||
-rw-r--r-- | kernel/log.cc | 24 | ||||
-rw-r--r-- | kernel/log.h | 2 | ||||
-rw-r--r-- | kernel/mem.cc | 318 | ||||
-rw-r--r-- | kernel/mem.h | 32 | ||||
-rw-r--r-- | kernel/qcsat.cc | 2 | ||||
-rw-r--r-- | kernel/rtlil.cc | 251 | ||||
-rw-r--r-- | kernel/rtlil.h | 133 | ||||
-rw-r--r-- | kernel/satgen.cc | 100 | ||||
-rw-r--r-- | kernel/yosys.cc | 154 | ||||
-rw-r--r-- | kernel/yosys.h | 13 |
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> ¶meters, bool mayfail = false); virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, 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 ¶mname) const; + void unsetParam(const RTLIL::IdString ¶mname); + void setParam(const RTLIL::IdString ¶mname, RTLIL::Const value); + const RTLIL::Const &getParam(const RTLIL::IdString ¶mname) 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); |