From fefe0fc0430f4f173a25e674708aa0f4f0854b31 Mon Sep 17 00:00:00 2001 From: Ruben Undheim Date: Thu, 3 Nov 2016 23:18:00 +0100 Subject: Imported yosys 0.7 --- passes/cmds/setattr.cc | 16 ++- passes/fsm/fsm.cc | 12 ++- passes/fsm/fsm_expand.cc | 40 +++++--- passes/fsm/fsm_map.cc | 3 +- passes/fsm/fsm_recode.cc | 6 +- passes/hierarchy/hierarchy.cc | 4 + passes/opt/opt.cc | 10 +- passes/opt/opt_rmdff.cc | 35 +++++-- passes/proc/proc_dff.cc | 26 +++-- passes/sat/Makefile.inc | 1 + passes/sat/clk2fflogic.cc | 226 ++++++++++++++++++++++++++++++++++++++++++ passes/sat/miter.cc | 38 +++++-- passes/techmap/Makefile.inc | 1 + passes/techmap/attrmap.cc | 23 ++++- passes/techmap/attrmvcp.cc | 2 + passes/techmap/simplemap.cc | 20 +++- passes/techmap/techmap.cc | 9 +- passes/techmap/zinit.cc | 151 ++++++++++++++++++++++++++++ 18 files changed, 569 insertions(+), 54 deletions(-) create mode 100644 passes/sat/clk2fflogic.cc create mode 100644 passes/techmap/zinit.cc (limited to 'passes') diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc index 9b05ae32..689e3148 100644 --- a/passes/cmds/setattr.cc +++ b/passes/cmds/setattr.cc @@ -134,15 +134,18 @@ struct SetparamPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" setparam [ -set name value | -unset name ]... [selection]\n"); + log(" setparam [ -type cell_type ] [ -set name value | -unset name ]... [selection]\n"); log("\n"); log("Set/unset the given parameters on the selected cells. String values must be\n"); log("passed in double quotes (\").\n"); log("\n"); + log("The -type option can be used to change the cell type of the selected cells.\n"); + log("\n"); } virtual void execute(std::vector args, RTLIL::Design *design) { - std::vector setunset_list; + vector setunset_list; + string new_cell_type; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -158,6 +161,10 @@ struct SetparamPass : public Pass { setunset_list.push_back(setunset_t(args[++argidx])); continue; } + if (arg == "-type" && argidx+1 < args.size()) { + new_cell_type = RTLIL::escape_id(args[++argidx]); + continue; + } break; } extra_args(args, argidx, design); @@ -170,8 +177,11 @@ struct SetparamPass : public Pass { continue; for (auto &it : module->cells_) - if (design->selected(module, it.second)) + if (design->selected(module, it.second)) { + if (!new_cell_type.empty()) + it.second->type = new_cell_type; do_setunset(it.second->parameters, setunset_list); + } } } } SetparamPass; diff --git a/passes/fsm/fsm.cc b/passes/fsm/fsm.cc index 3b537ecd..997558b8 100644 --- a/passes/fsm/fsm.cc +++ b/passes/fsm/fsm.cc @@ -59,6 +59,9 @@ struct FsmPass : public Pass { log(" -expand, -norecode, -export, -nomap\n"); log(" enable or disable passes as indicated above\n"); log("\n"); + log(" -fullexpand\n"); + log(" call expand with -full option\n"); + log("\n"); log(" -encoding type\n"); log(" -fm_set_fsm_file file\n"); log(" -encfile file\n"); @@ -71,6 +74,7 @@ struct FsmPass : public Pass { bool flag_norecode = false; bool flag_nodetect = false; bool flag_expand = false; + bool flag_fullexpand = false; bool flag_export = false; std::string fm_set_fsm_file_opt; std::string encfile_opt; @@ -110,6 +114,10 @@ struct FsmPass : public Pass { flag_expand = true; continue; } + if (arg == "-fullexpand") { + flag_fullexpand = true; + continue; + } if (arg == "-export") { flag_export = true; continue; @@ -126,8 +134,8 @@ struct FsmPass : public Pass { Pass::call(design, "opt_clean"); Pass::call(design, "fsm_opt"); - if (flag_expand) { - Pass::call(design, "fsm_expand"); + if (flag_expand || flag_fullexpand) { + Pass::call(design, flag_fullexpand ? "fsm_expand -full" : "fsm_expand"); Pass::call(design, "opt_clean"); Pass::call(design, "fsm_opt"); } diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc index 3ded3f37..e7b9dcf9 100644 --- a/passes/fsm/fsm_expand.cc +++ b/passes/fsm/fsm_expand.cc @@ -32,6 +32,8 @@ struct FsmExpand { RTLIL::Module *module; RTLIL::Cell *fsm_cell; + bool full_mode; + SigMap assign_map; SigSet> sig2driver, sig2user; CellTypes ct; @@ -45,6 +47,9 @@ struct FsmExpand bool is_cell_merge_candidate(RTLIL::Cell *cell) { + if (full_mode || cell->type == "$_MUX_") + return true; + if (cell->type == "$mux" || cell->type == "$pmux") if (cell->getPort("\\A").size() < 2) return true; @@ -68,17 +73,6 @@ struct FsmExpand if (new_signals.size() > 3) return false; - if (cell->hasPort("\\Y")) { - new_signals.append(assign_map(cell->getPort("\\Y"))); - new_signals.sort_and_unify(); - new_signals.remove_const(); - new_signals.remove(assign_map(fsm_cell->getPort("\\CTRL_IN"))); - new_signals.remove(assign_map(fsm_cell->getPort("\\CTRL_OUT"))); - } - - if (new_signals.size() > 2) - return false; - return true; } @@ -200,13 +194,15 @@ struct FsmExpand fsm_data.copy_to_cell(fsm_cell); } - FsmExpand(RTLIL::Cell *cell, RTLIL::Design *design, RTLIL::Module *mod) + FsmExpand(RTLIL::Cell *cell, RTLIL::Design *design, RTLIL::Module *mod, bool full) { module = mod; fsm_cell = cell; + full_mode = full; assign_map.set(module); ct.setup_internals(); + ct.setup_stdcells(); for (auto &cell_it : module->cells_) { RTLIL::Cell *c = cell_it.second; @@ -249,17 +245,31 @@ struct FsmExpandPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" fsm_expand [selection]\n"); + log(" fsm_expand [-full] [selection]\n"); log("\n"); log("The fsm_extract pass is conservative about the cells that belong to a finite\n"); log("state machine. This pass can be used to merge additional auxiliary gates into\n"); log("the finite state machine.\n"); log("\n"); + log("By default, fsm_expand is still a bit conservative regarding merging larger\n"); + log("word-wide cells. Call with -full to consider all cells for merging.\n"); + log("\n"); } virtual void execute(std::vector args, RTLIL::Design *design) { + bool full_mode = false; + log_header(design, "Executing FSM_EXPAND pass (merging auxiliary logic into FSMs).\n"); - extra_args(args, 1, design); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-full") { + full_mode = true; + continue; + } + break; + } + extra_args(args, argidx, design); for (auto &mod_it : design->modules_) { if (!design->selected(mod_it.second)) @@ -269,7 +279,7 @@ struct FsmExpandPass : public Pass { if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second)) fsm_cells.push_back(cell_it.second); for (auto c : fsm_cells) { - FsmExpand fsm_expand(c, design, mod_it.second); + FsmExpand fsm_expand(c, design, mod_it.second, full_mode); fsm_expand.execute(); } } diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc index 5b32ed59..c4230375 100644 --- a/passes/fsm/fsm_map.cc +++ b/passes/fsm/fsm_map.cc @@ -272,7 +272,8 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module) } else { - RTLIL::SigSpec sig_a, sig_b, sig_s; + RTLIL::SigSpec sig_a(RTLIL::State::Sx, next_state_wire->width); + RTLIL::SigSpec sig_b, sig_s; int reset_state = fsm_data.reset_state; if (reset_state < 0) reset_state = 0; diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc index 5102d833..e1bde728 100644 --- a/passes/fsm/fsm_recode.cc +++ b/passes/fsm/fsm_recode.cc @@ -57,13 +57,13 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs log("Recoding FSM `%s' from module `%s' using `%s' encoding:\n", cell->name.c_str(), module->name.c_str(), encoding.c_str()); - if (encoding != "none" && encoding != "one-hot" && encoding != "binary" && encoding != "auto") { + if (encoding != "none" && encoding != "user" && encoding != "one-hot" && encoding != "binary" && encoding != "auto") { log(" unknown encoding `%s': using auto instead.\n", encoding.c_str()); encoding = "auto"; } - if (encoding == "none") { - log(" nothing to do for encoding `none'.\n"); + if (encoding == "none" || encoding == "user") { + log(" nothing to do for encoding `%s'.\n", encoding.c_str()); return; } diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 4d1e3987..e21a7a4e 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -212,6 +212,10 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check } else if (mod->wire(conn.first) == nullptr || mod->wire(conn.first)->port_id == 0) log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n", log_id(cell->type), log_id(module), log_id(cell), log_id(conn.first)); + for (auto ¶m : cell->parameters) + if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$') + log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a parameter named '%s'.\n", + log_id(cell->type), log_id(module), log_id(cell), log_id(param.first)); } if (cell->parameters.size() == 0) diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc index 13ea5469..021c1a03 100644 --- a/passes/opt/opt.cc +++ b/passes/opt/opt.cc @@ -44,7 +44,7 @@ struct OptPass : public Pass { log(" opt_muxtree\n"); log(" opt_reduce [-fine] [-full]\n"); log(" opt_merge [-share_all]\n"); - log(" opt_rmdff\n"); + log(" opt_rmdff [-keepdc]\n"); log(" opt_clean [-purge]\n"); log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n"); log(" while \n"); @@ -54,7 +54,7 @@ struct OptPass : public Pass { log(" do\n"); log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n"); log(" opt_merge [-share_all]\n"); - log(" opt_rmdff\n"); + log(" opt_rmdff [-keepdc]\n"); log(" opt_clean [-purge]\n"); log(" while \n"); log("\n"); @@ -69,6 +69,7 @@ struct OptPass : public Pass { std::string opt_expr_args; std::string opt_reduce_args; std::string opt_merge_args; + std::string opt_rmdff_args; bool fast_mode = false; log_header(design, "Executing OPT pass (performing simple optimizations).\n"); @@ -108,6 +109,7 @@ struct OptPass : public Pass { } if (args[argidx] == "-keepdc") { opt_expr_args += " -keepdc"; + opt_rmdff_args += " -keepdc"; continue; } if (args[argidx] == "-share_all") { @@ -128,7 +130,7 @@ struct OptPass : public Pass { Pass::call(design, "opt_expr" + opt_expr_args); Pass::call(design, "opt_merge" + opt_merge_args); design->scratchpad_unset("opt.did_something"); - Pass::call(design, "opt_rmdff"); + Pass::call(design, "opt_rmdff" + opt_rmdff_args); if (design->scratchpad_get_bool("opt.did_something") == false) break; Pass::call(design, "opt_clean" + opt_clean_args); @@ -145,7 +147,7 @@ struct OptPass : public Pass { Pass::call(design, "opt_muxtree"); Pass::call(design, "opt_reduce" + opt_reduce_args); Pass::call(design, "opt_merge" + opt_merge_args); - Pass::call(design, "opt_rmdff"); + Pass::call(design, "opt_rmdff" + opt_rmdff_args); Pass::call(design, "opt_clean" + opt_clean_args); Pass::call(design, "opt_expr" + opt_expr_args); if (design->scratchpad_get_bool("opt.did_something") == false) diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc index fa954afa..922f086f 100644 --- a/passes/opt/opt_rmdff.cc +++ b/passes/opt/opt_rmdff.cc @@ -29,6 +29,7 @@ PRIVATE_NAMESPACE_BEGIN SigMap assign_map, dff_init_map; SigSet mux_drivers; dict> init_attributes; +bool keepdc; void remove_init_attr(SigSpec sig) { @@ -71,7 +72,11 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r; RTLIL::Const val_cp, val_rp, val_rv; - if (dff->type == "$_DFF_N_" || dff->type == "$_DFF_P_") { + if (dff->type == "$_FF_") { + sig_d = dff->getPort("\\D"); + sig_q = dff->getPort("\\Q"); + } + else if (dff->type == "$_DFF_N_" || dff->type == "$_DFF_P_") { sig_d = dff->getPort("\\D"); sig_q = dff->getPort("\\Q"); sig_c = dff->getPort("\\C"); @@ -89,6 +94,10 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) val_rp = RTLIL::Const(dff->type[7] == 'P', 1); val_rv = RTLIL::Const(dff->type[8] == '1', 1); } + else if (dff->type == "$ff") { + sig_d = dff->getPort("\\D"); + sig_q = dff->getPort("\\Q"); + } else if (dff->type == "$dff") { sig_d = dff->getPort("\\D"); sig_q = dff->getPort("\\Q"); @@ -115,12 +124,12 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) bool has_init = false; RTLIL::Const val_init; for (auto bit : dff_init_map(sig_q).to_sigbit_vector()) { - if (bit.wire == NULL) + if (bit.wire == NULL || keepdc) has_init = true; val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx); } - if (dff->type == "$dff" && mux_drivers.has(sig_d)) { + if (dff->type.in("$ff", "$dff") && mux_drivers.has(sig_d)) { std::set muxes; mux_drivers.find(sig_d, muxes); for (auto mux : muxes) { @@ -137,7 +146,7 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) } } - if (sig_c.is_fully_const() && (!sig_r.size() || !has_init || val_init == val_rv)) { + if (!sig_c.empty() && sig_c.is_fully_const() && (!sig_r.size() || !has_init || val_init == val_rv)) { if (val_rv.bits.size() == 0) val_rv = val_init; mod->connect(sig_q, val_rv); @@ -182,7 +191,7 @@ struct OptRmdffPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" opt_rmdff [selection]\n"); + log(" opt_rmdff [-keepdc] [selection]\n"); log("\n"); log("This pass identifies flip-flops with constant inputs and replaces them with\n"); log("a constant driver.\n"); @@ -193,7 +202,17 @@ struct OptRmdffPass : public Pass { int total_count = 0, total_initdrv = 0; log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n"); - extra_args(args, 1, design); + keepdc = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-keepdc") { + keepdc = true; + continue; + } + break; + } + extra_args(args, argidx, design); for (auto module : design->selected_modules()) { @@ -243,10 +262,10 @@ struct OptRmdffPass : public Pass { if (!design->selected(module, cell)) continue; - if (cell->type.in("$_DFF_N_", "$_DFF_P_", + if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_", - "$dff", "$adff")) + "$ff", "$dff", "$adff")) dff_list.push_back(cell->name); if (cell->type == "$dlatch") diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc index f532990c..98653dc6 100644 --- a/passes/proc/proc_dff.cc +++ b/passes/proc/proc_dff.cc @@ -196,7 +196,7 @@ void gen_dff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::Const val_rst, RT std::stringstream sstr; sstr << "$procdff$" << (autoidx++); - RTLIL::Cell *cell = mod->addCell(sstr.str(), arst ? "$adff" : "$dff"); + RTLIL::Cell *cell = mod->addCell(sstr.str(), clk.empty() ? "$ff" : arst ? "$adff" : "$dff"); cell->attributes = proc->attributes; cell->parameters["\\WIDTH"] = RTLIL::Const(sig_in.size()); @@ -204,15 +204,21 @@ void gen_dff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::Const val_rst, RT cell->parameters["\\ARST_POLARITY"] = RTLIL::Const(arst_polarity, 1); cell->parameters["\\ARST_VALUE"] = val_rst; } - cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity, 1); + if (!clk.empty()) { + cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity, 1); + } cell->setPort("\\D", sig_in); cell->setPort("\\Q", sig_out); if (arst) cell->setPort("\\ARST", *arst); - cell->setPort("\\CLK", clk); + if (!clk.empty()) + cell->setPort("\\CLK", clk); - log(" created %s cell `%s' with %s edge clock", cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative"); + if (!clk.empty()) + log(" created %s cell `%s' with %s edge clock", cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative"); + else + log(" created %s cell `%s' with global clock", cell->type.c_str(), cell->name.c_str()); if (arst) log(" and %s level reset", arst_polarity ? "positive" : "negative"); log(".\n"); @@ -236,6 +242,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce) RTLIL::SyncRule *sync_level = NULL; RTLIL::SyncRule *sync_edge = NULL; RTLIL::SyncRule *sync_always = NULL; + bool global_clock = false; std::map> many_async_rules; @@ -267,6 +274,10 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce) sig.replace(action.first, action.second, &insig); sync_always = sync; } + else if (sync->type == RTLIL::SyncType::STg) { + sig.replace(action.first, action.second, &insig); + global_clock = true; + } else { log_error("Event with any-edge sensitivity found for this signal!\n"); } @@ -328,7 +339,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce) continue; } - if (!sync_edge) + if (!sync_edge && !global_clock) log_error("Missing edge-sensitive event for this signal!\n"); if (many_async_rules.size() > 0) @@ -346,9 +357,10 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce) } else gen_dff(mod, insig, rstval.as_const(), sig, - sync_edge->type == RTLIL::SyncType::STp, + sync_edge && sync_edge->type == RTLIL::SyncType::STp, sync_level && sync_level->type == RTLIL::SyncType::ST1, - sync_edge->signal, sync_level ? &sync_level->signal : NULL, proc); + sync_edge ? sync_edge->signal : SigSpec(), + sync_level ? &sync_level->signal : NULL, proc); if (free_sync_level) delete sync_level; diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc index 0c5f6fc6..6785b750 100644 --- a/passes/sat/Makefile.inc +++ b/passes/sat/Makefile.inc @@ -5,4 +5,5 @@ OBJS += passes/sat/eval.o OBJS += passes/sat/miter.o OBJS += passes/sat/expose.o OBJS += passes/sat/assertpmux.o +OBJS += passes/sat/clk2fflogic.o diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc new file mode 100644 index 00000000..ef6d5dd7 --- /dev/null +++ b/passes/sat/clk2fflogic.cc @@ -0,0 +1,226 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct Clk2fflogicPass : public Pass { + Clk2fflogicPass() : Pass("clk2fflogic", "convert clocked FFs to generic $ff cells") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" clk2fflogic [options] [selection]\n"); + log("\n"); + log("This command replaces clocked flip-flops with generic $ff cells that use the\n"); + log("implicit global clock. This is useful for formal verification of designs with\n"); + log("multiple clocks.\n"); + log("\n"); + } + virtual void execute(std::vector args, RTLIL::Design *design) + { + // bool flag_noinit = false; + + log_header(design, "Executing CLK2FFLOGIC pass (convert clocked FFs to generic $ff cells).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-noinit") { + // flag_noinit = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + dict initbits; + pool del_initbits; + + for (auto wire : module->wires()) + if (wire->attributes.count("\\init") > 0) + { + Const initval = wire->attributes.at("\\init"); + SigSpec initsig = sigmap(wire); + + for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++) + if (initval[i] == State::S0 || initval[i] == State::S1) + initbits[initsig[i]] = initval[i]; + } + + for (auto cell : vector(module->selected_cells())) + { + if (cell->type.in("$dlatch")) + { + bool enpol = cell->parameters["\\EN_POLARITY"].as_bool(); + + SigSpec sig_en = cell->getPort("\\EN"); + SigSpec sig_d = cell->getPort("\\D"); + SigSpec sig_q = cell->getPort("\\Q"); + + log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n", + log_id(module), log_id(cell), log_id(cell->type), + log_signal(sig_en), log_signal(sig_d), log_signal(sig_q)); + + Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q)); + module->addFf(NEW_ID, sig_q, past_q); + + if (enpol) + module->addMux(NEW_ID, past_q, sig_d, sig_en, sig_q); + else + module->addMux(NEW_ID, sig_d, past_q, sig_en, sig_q); + + Const initval; + bool assign_initval = false; + for (int i = 0; i < GetSize(sig_d); i++) { + SigBit qbit = sigmap(sig_q[i]); + if (initbits.count(qbit)) { + initval.bits.push_back(initbits.at(qbit)); + del_initbits.insert(qbit); + } else + initval.bits.push_back(State::Sx); + if (initval.bits.back() != State::Sx) + assign_initval = true; + } + + if (assign_initval) + past_q->attributes["\\init"] = initval; + + module->remove(cell); + continue; + } + + if (cell->type.in("$dff", "$adff", "$dffsr")) + { + bool clkpol = cell->parameters["\\CLK_POLARITY"].as_bool(); + + SigSpec clk = cell->getPort("\\CLK"); + Wire *past_clk = module->addWire(NEW_ID); + past_clk->attributes["\\init"] = clkpol ? State::S1 : State::S0; + module->addFf(NEW_ID, clk, past_clk); + + SigSpec sig_d = cell->getPort("\\D"); + SigSpec sig_q = cell->getPort("\\Q"); + + log("Replacing %s.%s (%s): CLK=%s, D=%s, Q=%s\n", + log_id(module), log_id(cell), log_id(cell->type), + log_signal(clk), log_signal(sig_d), log_signal(sig_q)); + + SigSpec clock_edge_pattern; + + if (clkpol) { + clock_edge_pattern.append_bit(State::S0); + clock_edge_pattern.append_bit(State::S1); + } else { + clock_edge_pattern.append_bit(State::S1); + clock_edge_pattern.append_bit(State::S0); + } + + SigSpec clock_edge = module->Eqx(NEW_ID, {clk, SigSpec(past_clk)}, clock_edge_pattern); + + Wire *past_d = module->addWire(NEW_ID, GetSize(sig_d)); + Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q)); + module->addFf(NEW_ID, sig_d, past_d); + module->addFf(NEW_ID, sig_q, past_q); + + if (cell->type == "$adff") + { + SigSpec arst = cell->getPort("\\ARST"); + SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge); + Const rstval = cell->parameters["\\ARST_VALUE"]; + + if (cell->parameters["\\ARST_POLARITY"].as_bool()) + module->addMux(NEW_ID, qval, rstval, arst, sig_q); + else + module->addMux(NEW_ID, rstval, qval, arst, sig_q); + } + else + if (cell->type == "$dffsr") + { + SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge); + SigSpec setval = cell->getPort("\\SET"); + SigSpec clrval = cell->getPort("\\CLR"); + + if (!cell->parameters["\\SET_POLARITY"].as_bool()) + setval = module->Not(NEW_ID, setval); + + if (cell->parameters["\\CLR_POLARITY"].as_bool()) + clrval = module->Not(NEW_ID, clrval); + + qval = module->Or(NEW_ID, qval, setval); + module->addAnd(NEW_ID, qval, clrval, sig_q); + } + else + { + module->addMux(NEW_ID, past_q, past_d, clock_edge, sig_q); + } + + Const initval; + bool assign_initval = false; + for (int i = 0; i < GetSize(sig_d); i++) { + SigBit qbit = sigmap(sig_q[i]); + if (initbits.count(qbit)) { + initval.bits.push_back(initbits.at(qbit)); + del_initbits.insert(qbit); + } else + initval.bits.push_back(State::Sx); + if (initval.bits.back() != State::Sx) + assign_initval = true; + } + + if (assign_initval) { + past_d->attributes["\\init"] = initval; + past_q->attributes["\\init"] = initval; + } + + module->remove(cell); + continue; + } + } + + for (auto wire : module->wires()) + if (wire->attributes.count("\\init") > 0) + { + bool delete_initattr = true; + Const initval = wire->attributes.at("\\init"); + SigSpec initsig = sigmap(wire); + + for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++) + if (del_initbits.count(initsig[i]) > 0) + initval[i] = State::Sx; + else if (initval[i] != State::Sx) + delete_initattr = false; + + if (delete_initattr) + wire->attributes.erase("\\init"); + else + wire->attributes.at("\\init") = initval; + } + } + + } +} Clk2fflogicPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc index 4854e19b..9e150b60 100644 --- a/passes/sat/miter.cc +++ b/passes/sat/miter.cc @@ -312,18 +312,42 @@ void create_miter_assert(struct Pass *that, std::vector args, RTLIL log_pop(); } - SigSpec or_signals; + SigSpec assert_signals, assume_signals; vector cell_list = module->cells(); - for (auto cell : cell_list) { + for (auto cell : cell_list) + { + if (!cell->type.in("$assert", "$assume")) + continue; + + SigBit is_active = module->Nex(NEW_ID, cell->getPort("\\A"), State::S1); + SigBit is_enabled = module->Eqx(NEW_ID, cell->getPort("\\EN"), State::S1); + if (cell->type == "$assert") { - SigBit is_active = module->Nex(NEW_ID, cell->getPort("\\A"), State::S1); - SigBit is_enabled = module->Eqx(NEW_ID, cell->getPort("\\EN"), State::S1); - or_signals.append(module->And(NEW_ID, is_active, is_enabled)); - module->remove(cell); + assert_signals.append(module->And(NEW_ID, is_active, is_enabled)); + } else { + assume_signals.append(module->And(NEW_ID, is_active, is_enabled)); } + + module->remove(cell); } - module->addReduceOr(NEW_ID, or_signals, trigger); + if (assume_signals.empty()) + { + module->addReduceOr(NEW_ID, assert_signals, trigger); + } + else + { + Wire *assume_q = module->addWire(NEW_ID); + assume_q->attributes["\\init"] = State::S0; + assume_signals.append(assume_q); + + SigSpec assume_nok = module->ReduceOr(NEW_ID, assume_signals); + SigSpec assume_ok = module->Not(NEW_ID, assume_nok); + module->addFf(NEW_ID, assume_nok, assume_q); + + SigSpec assert_fail = module->ReduceOr(NEW_ID, assert_signals); + module->addAnd(NEW_ID, assert_fail, assume_ok, trigger); + } if (flag_flatten) { log_push(); diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index b5024fa9..311a1af9 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -31,6 +31,7 @@ OBJS += passes/techmap/deminout.o OBJS += passes/techmap/insbuf.o OBJS += passes/techmap/attrmvcp.o OBJS += passes/techmap/attrmap.o +OBJS += passes/techmap/zinit.o endif GENFILES += passes/techmap/techmap.inc diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc index f715b63e..dec81d21 100644 --- a/passes/techmap/attrmap.cc +++ b/passes/techmap/attrmap.cc @@ -33,13 +33,32 @@ Const make_value(string &value) return sig.as_const(); } +bool string_compare_nocase(const string &str1, const string &str2) +{ + if (str1.size() != str2.size()) + return false; + + for (size_t i = 0; i < str1.size(); i++) + { + char ch1 = str1[i], ch2 = str2[i]; + if ('a' <= ch1 && ch1 <= 'z') + ch1 -= 'a' - 'A'; + if ('a' <= ch2 && ch2 <= 'z') + ch2 -= 'a' - 'A'; + if (ch1 != ch2) + return false; + } + + return true; +} + bool match_name(string &name, IdString &id, bool ignore_case=false) { string str1 = RTLIL::escape_id(name); string str2 = id.str(); if (ignore_case) - return !strcasecmp(str1.c_str(), str2.c_str()); + return string_compare_nocase(str1, str2); return str1 == str2; } @@ -49,7 +68,7 @@ bool match_value(string &value, Const &val, bool ignore_case=false) if (ignore_case && ((val.flags & RTLIL::CONST_FLAG_STRING) != 0) && GetSize(value) && value.front() == '"' && value.back() == '"') { string str1 = value.substr(1, GetSize(value)-2); string str2 = val.decode_string(); - return !strcasecmp(str1.c_str(), str2.c_str()); + return string_compare_nocase(str1, str2); } return make_value(value) == val; diff --git a/passes/techmap/attrmvcp.cc b/passes/techmap/attrmvcp.cc index 50eaf61d..1537def0 100644 --- a/passes/techmap/attrmvcp.cc +++ b/passes/techmap/attrmvcp.cc @@ -93,6 +93,7 @@ struct AttrmvcpPass : public Pass { for (auto cell : module->selected_cells()) for (auto &conn : cell->connections()) + { if (driven_mode) { if (cell->input(conn.first)) for (auto bit : sigmap(conn.second)) @@ -102,6 +103,7 @@ struct AttrmvcpPass : public Pass { for (auto bit : sigmap(conn.second)) net2cells[bit].insert(cell); } + } for (auto wire : module->selected_wires()) { diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index 0fb64734..c6b932bd 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -388,6 +388,23 @@ void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell) } } +void simplemap_ff(RTLIL::Module *module, RTLIL::Cell *cell) +{ + int width = cell->parameters.at("\\WIDTH").as_int(); + + RTLIL::SigSpec sig_d = cell->getPort("\\D"); + RTLIL::SigSpec sig_q = cell->getPort("\\Q"); + + std::string gate_type = "$_FF_"; + + for (int i = 0; i < width; i++) { + RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); + gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); + gate->setPort("\\D", sig_d[i]); + gate->setPort("\\Q", sig_q[i]); + } +} + void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell) { int width = cell->parameters.at("\\WIDTH").as_int(); @@ -532,6 +549,7 @@ void simplemap_get_mappers(std::map args, RTLIL::Design *design) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index b2cc492b..6784f48c 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -345,6 +345,12 @@ struct TechmapWorker c->setParam("\\MEMID", Const(memory_renames[memid].str())); } + if (c->type == "$mem") { + string memid = c->getParam("\\MEMID").decode_string(); + apply_prefix(cell->name.str(), memid); + c->setParam("\\MEMID", Const(memid)); + } + if (c->attributes.count("\\src")) c->add_strpool_attribute("\\src", extra_src_attrs); } @@ -1164,8 +1170,9 @@ struct FlattenPass : public Pass { worker.flatten_do_list.erase(mod->name); } } else { - for (auto mod : vector(design->modules())) + for (auto mod : vector(design->modules())) { while (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) { } + } } log("No more expansions possible.\n"); diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc new file mode 100644 index 00000000..a577e123 --- /dev/null +++ b/passes/techmap/zinit.cc @@ -0,0 +1,151 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct ZinitPass : public Pass { + ZinitPass() : Pass("zinit", "add inverters so all FF are zero-initialized") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" zinit [options] [selection]\n"); + log("\n"); + log("Add inverters as needed to make all FFs zero-initialized.\n"); + log("\n"); + log(" -all\n"); + log(" also add zero initialization to uninitialized FFs\n"); + log("\n"); + } + virtual void execute(std::vector args, RTLIL::Design *design) + { + bool all_mode = false; + + log_header(design, "Executing ZINIT pass (make all FFs zero-initialized).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-singleton") { + all_mode = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + dict initbits; + pool donebits; + + for (auto wire : module->selected_wires()) + { + if (wire->attributes.count("\\init") == 0) + continue; + + SigSpec wirebits = sigmap(wire); + Const initval = wire->attributes.at("\\init"); + wire->attributes.erase("\\init"); + + for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) + { + SigBit bit = wirebits[i]; + State val = initval[i]; + + if (val != State::S0 && val != State::S1 && bit.wire != nullptr) + continue; + + if (initbits.count(bit)) { + if (initbits.at(bit) != val) + log_error("Conflicting init values for signal %s (%s = %s != %s).\n", + log_signal(bit), log_signal(SigBit(wire, i)), + log_signal(val), log_signal(initbits.at(bit))); + continue; + } + + initbits[bit] = val; + } + } + + pool dff_types = { + "$ff", "$dff", "$dffe", "$dffsr", "$adff", + "$_FF_", "$_DFFE_NN_", "$_DFFE_NP_", "$_DFFE_PN_", "$_DFFE_PP_", + "$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_", + "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_", + "$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", + "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_" + }; + + for (auto cell : module->selected_cells()) + { + if (!dff_types.count(cell->type)) + continue; + + SigSpec sig_d = sigmap(cell->getPort("\\D")); + SigSpec sig_q = sigmap(cell->getPort("\\Q")); + + if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1) + continue; + + Const initval; + + for (int i = 0; i < GetSize(sig_q); i++) { + if (initbits.count(sig_q[i])) { + initval.bits.push_back(initbits.at(sig_q[i])); + donebits.insert(sig_q[i]); + } else + initval.bits.push_back(all_mode ? State::S0 : State::Sx); + } + + Wire *initwire = module->addWire(NEW_ID, GetSize(initval)); + initwire->attributes["\\init"] = initval; + + for (int i = 0; i < GetSize(initwire); i++) + if (initval.bits.at(i) == State::S1) + { + sig_d[i] = module->NotGate(NEW_ID, sig_d[i]); + module->addNotGate(NEW_ID, SigSpec(initwire, i), sig_q[i]); + initwire->attributes["\\init"].bits.at(i) = State::S0; + } + else + { + module->connect(sig_q[i], SigSpec(initwire, i)); + } + + log("FF init value for cell %s (%s): %s = %s\n", log_id(cell), log_id(cell->type), + log_signal(sig_q), log_signal(initval)); + + cell->setPort("\\D", sig_d); + cell->setPort("\\Q", initwire); + } + + for (auto &it : initbits) + if (donebits.count(it.first) == 0) + log_error("Failed to handle init bit %s = %s.\n", log_signal(it.first), log_signal(it.second)); + } + } +} ZinitPass; + +PRIVATE_NAMESPACE_END -- cgit v1.2.3