diff options
119 files changed, 3075 insertions, 2069 deletions
@@ -82,7 +82,6 @@ YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) VPATH := $(YOSYS_SRC) CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(PREFIX)/include -LDFLAGS := $(LDFLAGS) -L$(LIBDIR) LDLIBS := $(LDLIBS) -lstdc++ -lm PLUGIN_LDFLAGS := @@ -371,7 +370,7 @@ BOOST_PYTHON_LIB ?= $(shell \ endif ifeq ($(BOOST_PYTHON_LIB),) -$(error BOOST_PYTHON_LIB could not be detected. Please define manualy) +$(error BOOST_PYTHON_LIB could not be detected. Please define manually) endif ifeq ($(OS), Darwin) @@ -722,7 +721,7 @@ ifneq ($(ABCREV),default) test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \ echo "Pulling ABC from $(ABCURL):"; set -x; \ test -d abc || git clone $(ABCURL) abc; \ - cd abc && $(MAKE) DEP= clean && git fetch origin master && git checkout $(ABCREV); \ + cd abc && $(MAKE) DEP= clean && git fetch $(ABCURL) && git checkout $(ABCREV); \ fi endif $(Q) rm -f abc/abc-[0-9a-f]* @@ -781,6 +780,7 @@ test: $(TARGETS) $(EXTRA_TARGETS) +cd tests/arch/intel_alm && bash run-test.sh $(SEEDOPT) +cd tests/rpc && bash run-test.sh +cd tests/memfile && bash run-test.sh + +cd tests/verilog && bash run-test.sh @echo "" @echo " Passed \"make test\"." @echo "" @@ -281,6 +281,9 @@ Verilog Attributes and non-standard features temporary variable within an always block. This is mostly used internally by Yosys to synthesize Verilog functions and access arrays. +- The ``nowrshmsk`` attribute on a register prohibits the generation of + shift-and-mask type circuits for writing to bit slices of that register. + - The ``onehot`` attribute on wires mark them as one-hot state register. This is used for example for memory port sharing and set by the fsm_map pass. diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 1fb7210cb..6b910eecd 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -76,9 +76,11 @@ void aiger_encode(std::ostream &f, int x) struct XAigerWriter { + Design *design; Module *module; SigMap sigmap; + dict<SigBit, State> init_map; pool<SigBit> input_bits, output_bits; dict<SigBit, SigBit> not_map, alias_map; dict<SigBit, pair<SigBit, SigBit>> and_map; @@ -137,7 +139,7 @@ struct XAigerWriter return a; } - XAigerWriter(Module *module, bool holes_mode=false) : module(module), sigmap(module) + XAigerWriter(Module *module, bool dff_mode) : design(module->design), module(module), sigmap(module) { pool<SigBit> undriven_bits; pool<SigBit> unused_bits; @@ -157,7 +159,8 @@ struct XAigerWriter if (wire->get_bool_attribute(ID::keep)) sigmap.add(wire); - for (auto wire : module->wires()) + for (auto wire : module->wires()) { + auto it = wire->attributes.find(ID::init); for (int i = 0; i < GetSize(wire); i++) { SigBit wirebit(wire, i); @@ -174,17 +177,27 @@ struct XAigerWriter undriven_bits.insert(bit); unused_bits.insert(bit); - bool scc = wire->attributes.count(ID::abc9_scc); - if (wire->port_input || scc) + bool keep = wire->get_bool_attribute(ID::abc9_keep); + if (wire->port_input || keep) input_bits.insert(bit); - bool keep = wire->get_bool_attribute(ID::keep); - if (wire->port_output || keep || scc) { + keep = keep || wire->get_bool_attribute(ID::keep); + if (wire->port_output || keep) { if (bit != wirebit) alias_map[wirebit] = bit; output_bits.insert(wirebit); } + + if (it != wire->attributes.end()) { + auto s = it->second[i]; + if (s != State::Sx) { + auto r = init_map.insert(std::make_pair(bit, it->second[i])); + if (!r.second && r.first->second != it->second[i]) + log_error("Bit '%s' has a conflicting (* init *) value.\n", log_signal(bit)); + } + } } + } TimingInfo timing; @@ -212,10 +225,7 @@ struct XAigerWriter continue; } - if (cell->type == ID($__ABC9_FF_) && - // The presence of an abc9_mergeability attribute indicates - // that we do want to pass this flop to ABC - cell->attributes.count(ID::abc9_mergeability)) + if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_)) && !cell->get_bool_attribute(ID::abc9_keep)) { SigBit D = sigmap(cell->getPort(ID::D).as_bit()); SigBit Q = sigmap(cell->getPort(ID::Q).as_bit()); @@ -231,31 +241,29 @@ struct XAigerWriter continue; } - RTLIL::Module* inst_module = module->design->module(cell->type); - if (inst_module) { - IdString derived_type = inst_module->derive(module->design, cell->parameters); - inst_module = module->design->module(derived_type); - log_assert(inst_module); - + RTLIL::Module* inst_module = design->module(cell->type); + if (inst_module && inst_module->get_blackbox_attribute()) { bool abc9_flop = false; - if (!cell->has_keep_attr()) { - auto it = cell->attributes.find(ID::abc9_box_seq); - if (it != cell->attributes.end()) { - int abc9_box_seq = it->second.as_int(); - if (GetSize(box_list) <= abc9_box_seq) - box_list.resize(abc9_box_seq+1); - box_list[abc9_box_seq] = cell; - // Only flop boxes may have arrival times - // (all others are combinatorial) - abc9_flop = inst_module->get_bool_attribute(ID::abc9_flop); - if (!abc9_flop) - continue; - } + + auto it = cell->attributes.find(ID::abc9_box_seq); + if (it != cell->attributes.end()) { + log_assert(!cell->has_keep_attr()); + log_assert(cell->parameters.empty()); + int abc9_box_seq = it->second.as_int(); + if (GetSize(box_list) <= abc9_box_seq) + box_list.resize(abc9_box_seq+1); + box_list[abc9_box_seq] = cell; + // Only flop boxes may have arrival times + // (all others are combinatorial) + log_assert(cell->parameters.empty()); + abc9_flop = inst_module->get_bool_attribute(ID::abc9_flop); + if (!abc9_flop) + continue; } - if (!timing.count(derived_type)) + if (!timing.count(inst_module->name)) timing.setup_module(inst_module); - auto &t = timing.at(derived_type).arrival; + auto &t = timing.at(inst_module->name).arrival; for (const auto &conn : cell->connections()) { auto port_wire = inst_module->wire(conn.first); if (!port_wire->port_output) @@ -269,7 +277,7 @@ struct XAigerWriter #ifndef NDEBUG if (ys_debug(1)) { static std::set<std::tuple<IdString,IdString,int>> seen; - if (seen.emplace(derived_type, conn.first, i).second) log("%s.%s[%d] abc9_arrival = %d\n", + if (seen.emplace(inst_module->name, conn.first, i).second) log("%s.%s[%d] abc9_arrival = %d\n", log_id(cell->type), log_id(conn.first), i, d); } #endif @@ -280,10 +288,6 @@ struct XAigerWriter if (abc9_flop) continue; } - else { - if (cell->type == ID($__ABC9_DELAY)) - log_error("Cell type '%s' not recognised. Check that '+/abc9_model.v' has been read.\n", cell->type.c_str()); - } bool cell_known = inst_module || cell->known(); for (const auto &c : cell->connections()) { @@ -317,9 +321,9 @@ struct XAigerWriter for (auto cell : box_list) { log_assert(cell); - RTLIL::Module* box_module = module->design->module(cell->type); + RTLIL::Module* box_module = design->module(cell->type); log_assert(box_module); - log_assert(box_module->attributes.count(ID::abc9_box_id) || box_module->get_bool_attribute(ID::abc9_flop)); + log_assert(box_module->has_attribute(ID::abc9_box_id)); auto r = box_ports.insert(cell->type); if (r.second) { @@ -383,27 +387,6 @@ struct XAigerWriter undriven_bits.erase(O); } } - - // Connect <cell>.abc9_ff.Q (inserted by abc9_map.v) as the last input to the flop box - if (box_module->get_bool_attribute(ID::abc9_flop)) { - SigSpec rhs = module->wire(stringf("%s.abc9_ff.Q", cell->name.c_str())); - if (rhs.empty()) - log_error("'%s.abc9_ff.Q' is not a wire present in module '%s'.\n", log_id(cell), log_id(module)); - - for (auto b : rhs) { - SigBit I = sigmap(b); - if (b == RTLIL::Sx) - b = State::S0; - else if (I != b) { - if (I == RTLIL::Sx) - alias_map[b] = State::S0; - else - alias_map[b] = I; - } - co_bits.emplace_back(b); - unused_bits.erase(I); - } - } } for (auto bit : input_bits) @@ -419,16 +402,14 @@ struct XAigerWriter undriven_bits.erase(bit); } - if (holes_mode) { - struct sort_by_port_id { - bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const { - return a.wire->port_id < b.wire->port_id || - (a.wire->port_id == b.wire->port_id && a.offset < b.offset); - } - }; - input_bits.sort(sort_by_port_id()); - output_bits.sort(sort_by_port_id()); - } + struct sort_by_port_id { + bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const { + return a.wire->port_id < b.wire->port_id || + (a.wire->port_id == b.wire->port_id && a.offset < b.offset); + } + }; + input_bits.sort(sort_by_port_id()); + output_bits.sort(sort_by_port_id()); aig_map[State::S0] = 0; aig_map[State::S1] = 1; @@ -589,17 +570,14 @@ struct XAigerWriter int box_count = 0; for (auto cell : box_list) { log_assert(cell); + log_assert(cell->parameters.empty()); - RTLIL::Module* box_module = module->design->module(cell->type); - log_assert(box_module); - - IdString derived_type = box_module->derive(box_module->design, cell->parameters); - box_module = box_module->design->module(derived_type); - log_assert(box_module); - - auto r = cell_cache.insert(derived_type); + auto r = cell_cache.insert(cell->type); auto &v = r.first->second; if (r.second) { + RTLIL::Module* box_module = design->module(cell->type); + log_assert(box_module); + int box_inputs = 0, box_outputs = 0; for (auto port_name : box_module->ports) { RTLIL::Wire *w = box_module->wire(port_name); @@ -610,11 +588,6 @@ struct XAigerWriter box_outputs += GetSize(w); } - // For flops only, create an extra 1-bit input that drives a new wire - // called "<cell>.abc9_ff.Q" that is used below - if (box_module->get_bool_attribute(ID::abc9_flop)) - box_inputs++; - std::get<0>(v) = box_inputs; std::get<1>(v) = box_outputs; std::get<2>(v) = box_module->attributes.at(ID::abc9_box_id).as_int(); @@ -635,23 +608,27 @@ struct XAigerWriter auto write_s_buffer = std::bind(write_buffer, std::ref(s_buffer), std::placeholders::_1); write_s_buffer(ff_bits.size()); + dict<SigSpec, int> clk_to_mergeability; for (const auto &i : ff_bits) { const SigBit &d = i.first; const Cell *cell = i.second; - int mergeability = cell->attributes.at(ID::abc9_mergeability).as_int(); + SigSpec clk_and_pol{sigmap(cell->getPort(ID::C)), cell->type[6] == 'P' ? State::S1 : State::S0}; + auto r = clk_to_mergeability.insert(std::make_pair(clk_and_pol, clk_to_mergeability.size()+1)); + int mergeability = r.first->second; log_assert(mergeability > 0); write_r_buffer(mergeability); - Const init = cell->attributes.at(ID::abc9_init, State::Sx); - log_assert(GetSize(init) == 1); + SigBit Q = sigmap(cell->getPort(ID::Q)); + State init = init_map.at(Q, State::Sx); + log_debug("Cell '%s' (type %s) has (* init *) value '%s'.\n", log_id(cell), log_id(cell->type), log_signal(init)); if (init == State::S1) write_s_buffer(1); else if (init == State::S0) write_s_buffer(0); else { log_assert(init == State::Sx); - write_s_buffer(0); + write_s_buffer(2); } // Use arrival time from output of flop box @@ -671,10 +648,16 @@ struct XAigerWriter f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); f.write(buffer_str.data(), buffer_str.size()); - RTLIL::Module *holes_module = module->design->module(stringf("%s$holes", module->name.c_str())); + RTLIL::Design *holes_design; + auto it = saved_designs.find("$abc9_holes"); + if (it != saved_designs.end()) + holes_design = it->second; + else + holes_design = nullptr; + RTLIL::Module *holes_module = holes_design ? holes_design->module(module->name) : nullptr; if (holes_module) { std::stringstream a_buffer; - XAigerWriter writer(holes_module, true /* holes_mode */); + XAigerWriter writer(holes_module, false /* dff_mode */); writer.write_aiger(a_buffer, false /*ascii_mode*/); f << "a"; @@ -704,10 +687,10 @@ struct XAigerWriter f << stringf("Generated by %s\n", yosys_version_str); - module->design->scratchpad_set_int("write_xaiger.num_ands", and_map.size()); - module->design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size()); - module->design->scratchpad_set_int("write_xaiger.num_inputs", input_bits.size()); - module->design->scratchpad_set_int("write_xaiger.num_outputs", output_bits.size()); + design->scratchpad_set_int("write_xaiger.num_ands", and_map.size()); + design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size()); + design->scratchpad_set_int("write_xaiger.num_inputs", input_bits.size()); + design->scratchpad_set_int("write_xaiger.num_outputs", output_bits.size()); } void write_map(std::ostream &f) @@ -761,10 +744,10 @@ struct XAigerBackend : public Backend { log(" write_xaiger [options] [filename]\n"); log("\n"); log("Write the top module (according to the (* top *) attribute or if only one module\n"); - log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, $_ABC9_FF_, or"); - log("non (* abc9_box_id *) cells will be converted into psuedo-inputs and\n"); - log("pseudo-outputs. Whitebox contents will be taken from the '<module-name>$holes'\n"); - log("module, if it exists.\n"); + log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, (optionally\n"); + log("$_DFF_N_, $_DFF_P_), or non (* abc9_box *) cells will be converted into psuedo-\n"); + log("inputs and pseudo-outputs. Whitebox contents will be taken from the equivalent\n"); + log("module in the '$abc9_holes' design, if it exists.\n"); log("\n"); log(" -ascii\n"); log(" write ASCII version of AIGER format\n"); @@ -772,10 +755,13 @@ struct XAigerBackend : public Backend { log(" -map <filename>\n"); log(" write an extra file with port and box symbols\n"); log("\n"); + log(" -dff\n"); + log(" write $_DFF_[NP]_ cells\n"); + log("\n"); } void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { - bool ascii_mode = false; + bool ascii_mode = false, dff_mode = false; std::string map_filename; log_header(design, "Executing XAIGER backend.\n"); @@ -791,6 +777,10 @@ struct XAigerBackend : public Backend { map_filename = args[++argidx]; continue; } + if (args[argidx] == "-dff") { + dff_mode = true; + continue; + } break; } extra_args(f, filename, args, argidx, !ascii_mode); @@ -808,7 +798,7 @@ struct XAigerBackend : public Backend { if (!top_module->memories.empty()) log_error("Found unmapped memories in module %s: unmapped memories are not supported in XAIGER backend!\n", log_id(top_module)); - XAigerWriter writer(top_module); + XAigerWriter writer(top_module, dff_mode); writer.write_aiger(*f, ascii_mode); if (!map_filename.empty()) { diff --git a/backends/cxxrtl/cxxrtl.cc b/backends/cxxrtl/cxxrtl.cc index e7711962f..549404184 100644 --- a/backends/cxxrtl/cxxrtl.cc +++ b/backends/cxxrtl/cxxrtl.cc @@ -1943,13 +1943,13 @@ struct CxxrtlWorker { case RTLIL::STa: break; + case RTLIL::STg: + log_cmd_error("Global clock is not supported.\n"); + // Handling of init-type sync rules is delegated to the `proc_init` pass, so we can use the wire // attribute regardless of input. case RTLIL::STi: log_assert(false); - - case RTLIL::STg: - log_cmd_error("Global clock is not supported.\n"); } } @@ -2306,10 +2306,7 @@ struct CxxrtlBackend : public Backend { log(" like -O3, and localize public wires not marked (*keep*) if possible.\n"); log("\n"); log(" -O5\n"); - log(" like -O4, and run `opt_clean -purge` first.\n"); - log("\n"); - log(" -O6\n"); - log(" like -O5, and run `proc; flatten` first.\n"); + log(" like -O4, and run `proc; flatten` first.\n"); log("\n"); } void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE @@ -2343,19 +2340,22 @@ struct CxxrtlBackend : public Backend { extra_args(f, filename, args, argidx); switch (opt_level) { - case 6: + case 5: worker.max_opt_level = true; worker.run_proc_flatten = true; - case 5: - worker.run_opt_clean_purge = true; + YS_FALLTHROUGH case 4: worker.localize_public = true; + YS_FALLTHROUGH case 3: worker.elide_public = true; + YS_FALLTHROUGH case 2: worker.localize_internal = true; + YS_FALLTHROUGH case 1: worker.elide_internal = true; + YS_FALLTHROUGH case 0: break; default: diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index 40d05a036..f6dae1d8c 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -343,7 +343,7 @@ struct FirrtlWorker switch (dir) { case FD_INOUT: log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second)); - /* FALLTHRU */ + YS_FALLTHROUGH case FD_OUT: sourceExpr = firstName; sinkExpr = secondExpr; @@ -351,7 +351,7 @@ struct FirrtlWorker break; case FD_NODIRECTION: log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second)); - /* FALLTHRU */ + YS_FALLTHROUGH case FD_IN: sourceExpr = secondExpr; sinkExpr = firstName; diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index d3015b066..cc3ebb129 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -1511,7 +1511,7 @@ else: # not tempind, covermode smt_assert_consequent(get_constr_expr(constr_assumes, i)) print_msg("Re-solving with appended steps..") if smt_check_sat() == "unsat": - print("%s Cannot appended steps without violating assumptions!" % smt.timestamp()) + print("%s Cannot append steps without violating assumptions!" % smt.timestamp()) retstatus = "FAILED" break print_anyconsts(step) @@ -1548,7 +1548,7 @@ else: # not tempind, covermode break smt_pop() - if not retstatus: + if retstatus == "FAILED" or retstatus == "PREUNSAT": break else: # gentrace @@ -1568,7 +1568,7 @@ else: # not tempind, covermode step += step_size - if gentrace and retstatus: + if gentrace and retstatus == "PASSED": print_anyconsts(0) write_trace(0, num_steps, '%') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 6fda92d73..d25587e48 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -454,6 +454,14 @@ void AigerReader::parse_xaiger() for (unsigned i = 0; i < flopNum; i++) mergeability.emplace_back(parse_xaiger_literal(f)); } + else if (c == 's') { + uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); + flopNum = parse_xaiger_literal(f); + log_assert(dataSize == (flopNum+1) * sizeof(uint32_t)); + initial_state.reserve(flopNum); + for (unsigned i = 0; i < flopNum; i++) + initial_state.emplace_back(parse_xaiger_literal(f)); + } else if (c == 'n') { parse_xaiger_literal(f); f >> s; @@ -767,6 +775,7 @@ void AigerReader::post_process() } } + dict<int, Wire*> mergeability_to_clock; for (uint32_t i = 0; i < flopNum; i++) { RTLIL::Wire *d = outputs[outputs.size() - flopNum + i]; log_assert(d); @@ -778,10 +787,9 @@ void AigerReader::post_process() log_assert(q->port_input); q->port_input = false; - auto ff = module->addCell(NEW_ID, ID($__ABC9_FF_)); - ff->setPort(ID::D, d); - ff->setPort(ID::Q, q); + Cell* ff = module->addFfGate(NEW_ID, d, q); ff->attributes[ID::abc9_mergeability] = mergeability[i]; + q->attributes[ID::init] = initial_state[i]; } dict<RTLIL::IdString, std::pair<int,int>> wideports_cache; diff --git a/frontends/aiger/aigerparse.h b/frontends/aiger/aigerparse.h index 46ac81212..251a24977 100644 --- a/frontends/aiger/aigerparse.h +++ b/frontends/aiger/aigerparse.h @@ -45,7 +45,7 @@ struct AigerReader std::vector<RTLIL::Wire*> outputs; std::vector<RTLIL::Wire*> bad_properties; std::vector<RTLIL::Cell*> boxes; - std::vector<int> mergeability; + std::vector<int> mergeability, initial_state; AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports); void parse_aiger(); diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 6a9af3f57..689fa9fb4 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -94,6 +94,7 @@ std::string AST::type2str(AstNodeType type) X(AST_TO_BITS) X(AST_TO_SIGNED) X(AST_TO_UNSIGNED) + X(AST_SELFSZ) X(AST_CONCAT) X(AST_REPLICATE) X(AST_BIT_NOT) @@ -110,6 +111,8 @@ std::string AST::type2str(AstNodeType type) X(AST_SHIFT_RIGHT) X(AST_SHIFT_SLEFT) X(AST_SHIFT_SRIGHT) + X(AST_SHIFTX) + X(AST_SHIFT) X(AST_LT) X(AST_LE) X(AST_EQ) @@ -615,6 +618,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const if (0) { case AST_POS: txt = "+"; } if (0) { case AST_NEG: txt = "-"; } if (0) { case AST_LOGIC_NOT: txt = "!"; } + if (0) { case AST_SELFSZ: txt = "@selfsz@"; } fprintf(f, "%s(", txt.c_str()); children[0]->dumpVlog(f, ""); fprintf(f, ")"); @@ -628,6 +632,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const if (0) { case AST_SHIFT_RIGHT: txt = ">>"; } if (0) { case AST_SHIFT_SLEFT: txt = "<<<"; } if (0) { case AST_SHIFT_SRIGHT: txt = ">>>"; } + if (0) { case AST_SHIFTX: txt = "@shiftx@"; } + if (0) { case AST_SHIFT: txt = "@shift@"; } if (0) { case AST_LT: txt = "<"; } if (0) { case AST_LE: txt = "<="; } if (0) { case AST_EQ: txt = "=="; } diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 3f6329112..8932108e3 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -75,6 +75,7 @@ namespace AST AST_TO_BITS, AST_TO_SIGNED, AST_TO_UNSIGNED, + AST_SELFSZ, AST_CONCAT, AST_REPLICATE, AST_BIT_NOT, @@ -91,6 +92,8 @@ namespace AST AST_SHIFT_RIGHT, AST_SHIFT_SLEFT, AST_SHIFT_SRIGHT, + AST_SHIFTX, + AST_SHIFT, AST_LT, AST_LE, AST_EQ, diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 996762715..cdc3adc9c 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -809,6 +809,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun sign_hint = false; break; + case AST_SELFSZ: + sub_width_hint = 0; + children.at(0)->detectSignWidthWorker(sub_width_hint, sign_hint); + break; + case AST_CONCAT: for (auto child : children) { sub_width_hint = 0; @@ -856,6 +861,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_SHIFT_RIGHT: case AST_SHIFT_SLEFT: case AST_SHIFT_SRIGHT: + case AST_SHIFTX: + case AST_SHIFT: case AST_POW: children[0]->detectSignWidthWorker(width_hint, sign_hint, found_real); break; @@ -923,7 +930,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun } break; } - /* fall through */ + YS_FALLTHROUGH // everything should have been handled above -> print error if not. default: @@ -1019,7 +1026,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (GetSize(children) >= 1 && children[0]->type == AST_CONSTANT) { current_module->parameter_default_values[str] = children[0]->asParaConst(); } - /* fall through */ + YS_FALLTHROUGH case AST_LOCALPARAM: if (flag_pwires) { @@ -1048,7 +1055,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (!range_valid) log_file_error(filename, location.first_line, "Signal `%s' with non-constant width!\n", str.c_str()); - if (!(range_left >= range_right || (range_left == -1 && range_right == 0))) + if (!(range_left + 1 >= range_right)) log_file_error(filename, location.first_line, "Signal `%s' with invalid width range %d!\n", str.c_str(), range_left - range_right + 1); RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1); @@ -1205,13 +1212,18 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); - RTLIL::SigSpec shift_val = fake_ast->children[1]->genRTLIL(); + + int fake_ast_width = 0; + bool fake_ast_sign = true; + fake_ast->children[1]->detectSignWidth(fake_ast_width, fake_ast_sign); + RTLIL::SigSpec shift_val = fake_ast->children[1]->genRTLIL(fake_ast_width, fake_ast_sign); + if (id2ast->range_right != 0) { - shift_val = current_module->Sub(NEW_ID, shift_val, id2ast->range_right, fake_ast->children[1]->is_signed); + shift_val = current_module->Sub(NEW_ID, shift_val, id2ast->range_right, fake_ast_sign); fake_ast->children[1]->is_signed = true; } if (id2ast->range_swapped) { - shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast->children[1]->is_signed); + shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast_sign); fake_ast->children[1]->is_signed = true; } if (GetSize(shift_val) >= 32) @@ -1265,7 +1277,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // just pass thru the signal. the parent will evaluate the is_signed property and interpret the SigSpec accordingly case AST_TO_SIGNED: - case AST_TO_UNSIGNED: { + case AST_TO_UNSIGNED: + case AST_SELFSZ: { RTLIL::SigSpec sig = children[0]->genRTLIL(); if (sig.size() < width_hint) sig.extend_u0(width_hint, sign_hint); @@ -1356,6 +1369,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (0) { case AST_SHIFT_RIGHT: type_name = ID($shr); } if (0) { case AST_SHIFT_SLEFT: type_name = ID($sshl); } if (0) { case AST_SHIFT_SRIGHT: type_name = ID($sshr); } + if (0) { case AST_SHIFTX: type_name = ID($shiftx); } + if (0) { case AST_SHIFT: type_name = ID($shift); } { if (width_hint < 0) detectSignWidth(width_hint, sign_hint); @@ -1807,7 +1822,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) is_signed = sign_hint; return SigSpec(wire); } - } /* fall through */ + } + YS_FALLTHROUGH // everything should have been handled above -> print error if not. default: diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 252219094..3314819fb 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -91,7 +91,7 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg case 'D': if (got_len) goto unsupported_format; - /* fall through */ + YS_FALLTHROUGH case 'x': case 'X': if (next_arg >= GetSize(children)) @@ -608,6 +608,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, case AST_TO_BITS: case AST_TO_SIGNED: case AST_TO_UNSIGNED: + case AST_SELFSZ: case AST_CONCAT: case AST_REPLICATE: case AST_REDUCE_AND: @@ -1079,7 +1080,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } if (old_range_valid != range_valid) did_something = true; - if (range_valid && range_left >= 0 && range_right > range_left) { + if (range_valid && range_right > range_left) { int tmp = range_right; range_right = range_left; range_left = tmp; @@ -1097,6 +1098,25 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, range_swapped = children[0]->range_swapped; range_left = children[0]->range_left; range_right = children[0]->range_right; + bool force_upto = false, force_downto = false; + if (attributes.count(ID::force_upto)) { + AstNode *val = attributes[ID::force_upto]; + if (val->type != AST_CONSTANT) + log_file_error(filename, location.first_line, "Attribute `force_upto' with non-constant value!\n"); + force_upto = val->asAttrConst().as_bool(); + } + if (attributes.count(ID::force_downto)) { + AstNode *val = attributes[ID::force_downto]; + if (val->type != AST_CONSTANT) + log_file_error(filename, location.first_line, "Attribute `force_downto' with non-constant value!\n"); + force_downto = val->asAttrConst().as_bool(); + } + if (force_upto && force_downto) + log_file_error(filename, location.first_line, "Attributes `force_downto' and `force_upto' cannot be both set!\n"); + if ((force_upto && !range_swapped) || (force_downto && range_swapped)) { + std::swap(range_left, range_right); + range_swapped = force_upto; + } } } else { if (!range_valid) @@ -1788,7 +1808,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; } - if (0) + bool use_case_method = false; + + if (children[0]->id2ast->attributes.count(ID::nowrshmsk)) { + AstNode *node = children[0]->id2ast->attributes.at(ID::nowrshmsk); + while (node->simplify(true, false, false, stage, -1, false, false)) { } + if (node->type != AST_CONSTANT) + log_file_error(filename, location.first_line, "Non-constant value for `nowrshmsk' attribute on `%s'!\n", children[0]->id2ast->str.c_str()); + if (node->asAttrConst().as_bool()) + use_case_method = true; + } + + if (use_case_method) { // big case block @@ -1796,10 +1827,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, newNode = new AstNode(AST_CASE, shift_expr); for (int i = 0; i < source_width; i++) { int start_bit = children[0]->id2ast->range_right + i; + int end_bit = std::min(start_bit+result_width,source_width) - 1; AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true)); AstNode *lvalue = children[0]->clone(); lvalue->delete_children(); - int end_bit = std::min(start_bit+result_width,source_width) - 1; lvalue->children.push_back(new AstNode(AST_RANGE, mkconst_int(end_bit, true), mkconst_int(start_bit, true))); cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone()))); @@ -1846,11 +1877,40 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, AstNode *shamt = shift_expr; - newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), - new AstNode(AST_SHIFT_LEFT, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), shamt->clone()))); - newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, ref_data->clone(), - new AstNode(AST_SHIFT_LEFT, new AstNode(AST_BIT_AND, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), children[1]->clone()), shamt))); - newNode->children.push_back(new AstNode(type, lvalue, new AstNode(AST_BIT_OR, new AstNode(AST_BIT_AND, old_data, new AstNode(AST_BIT_NOT, ref_mask)), ref_data))); + int shamt_width_hint = 0; + bool shamt_sign_hint = true; + shamt->detectSignWidth(shamt_width_hint, shamt_sign_hint); + + int start_bit = children[0]->id2ast->range_right; + bool use_shift = shamt_sign_hint; + + if (start_bit != 0) { + shamt = new AstNode(AST_SUB, shamt, mkconst_int(start_bit, true)); + use_shift = true; + } + + AstNode *t; + + t = mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false); + if (use_shift) + t = new AstNode(AST_SHIFT, t, new AstNode(AST_NEG, shamt->clone())); + else + t = new AstNode(AST_SHIFT_LEFT, t, shamt->clone()); + t = new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), t); + newNode->children.push_back(t); + + t = new AstNode(AST_BIT_AND, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), children[1]->clone()); + if (use_shift) + t = new AstNode(AST_SHIFT, t, new AstNode(AST_NEG, shamt)); + else + t = new AstNode(AST_SHIFT_LEFT, t, shamt); + t = new AstNode(AST_ASSIGN_EQ, ref_data->clone(), t); + newNode->children.push_back(t); + + t = new AstNode(AST_BIT_AND, old_data, new AstNode(AST_BIT_NOT, ref_mask)); + t = new AstNode(AST_BIT_OR, t, ref_data); + t = new AstNode(type, lvalue, t); + newNode->children.push_back(t); } goto apply_newNode; @@ -3026,6 +3086,7 @@ replace_fcall_later:; } } break; + if (0) { case AST_SELFSZ: const_func = RTLIL::const_pos; } if (0) { case AST_POS: const_func = RTLIL::const_pos; } if (0) { case AST_NEG: const_func = RTLIL::const_neg; } if (children[0]->type == AST_CONSTANT) { @@ -3034,10 +3095,10 @@ replace_fcall_later:; } else if (children[0]->isConst()) { newNode = new AstNode(AST_REALVALUE); - if (type == AST_POS) - newNode->realvalue = +children[0]->asReal(sign_hint); - else + if (type == AST_NEG) newNode->realvalue = -children[0]->asReal(sign_hint); + else + newNode->realvalue = +children[0]->asReal(sign_hint); } break; case AST_TERNARY: diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 5d6e43330..d39b72547 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -645,13 +645,13 @@ non_opt_range: } | '[' expr TOK_POS_INDEXED expr ']' { $$ = new AstNode(AST_RANGE); - AstNode *expr = new AstNode(AST_CONCAT, $2); + AstNode *expr = new AstNode(AST_SELFSZ, $2); $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), $4), AstNode::mkconst_int(1, true))); $$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); } | '[' expr TOK_NEG_INDEXED expr ']' { $$ = new AstNode(AST_RANGE); - AstNode *expr = new AstNode(AST_CONCAT, $2); + AstNode *expr = new AstNode(AST_SELFSZ, $2); $$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), AstNode::mkconst_int(1, true)), $4)); } | @@ -853,7 +853,19 @@ task_func_port: } if (astbuf2 && astbuf2->children.size() != 2) frontend_verilog_yyerror("task/function argument range must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]"); - } wire_name | wire_name; + } wire_name | + { + if (!astbuf1) { + if (!sv_mode) + frontend_verilog_yyerror("task/function argument direction missing"); + albuf = new dict<IdString, AstNode*>; + astbuf1 = new AstNode(AST_WIRE); + current_wire_rand = false; + current_wire_const = false; + astbuf1->is_input = true; + astbuf2 = NULL; + } + } wire_name; task_func_body: task_func_body behavioral_stmt | @@ -2216,24 +2228,24 @@ simple_behavioral_stmt: behavioral_stmt: defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl | non_opt_delay behavioral_stmt | - simple_behavioral_stmt ';' | ';' | - hierarchical_id attr { + attr simple_behavioral_stmt ';' | ';' | + attr hierarchical_id { AstNode *node = new AstNode(AST_TCALL); - node->str = *$1; - delete $1; + node->str = *$2; + delete $2; ast_stack.back()->children.push_back(node); ast_stack.push_back(node); - append_attr(node, $2); + append_attr(node, $1); } opt_arg_list ';'{ ast_stack.pop_back(); } | - TOK_MSG_TASKS attr { + attr TOK_MSG_TASKS { AstNode *node = new AstNode(AST_TCALL); - node->str = *$1; - delete $1; + node->str = *$2; + delete $2; ast_stack.back()->children.push_back(node); ast_stack.push_back(node); - append_attr(node, $2); + append_attr(node, $1); } opt_arg_list ';'{ ast_stack.pop_back(); } | @@ -2330,8 +2342,6 @@ behavioral_stmt: ast_stack.pop_back(); }; - ; - unique_case_attr: /* empty */ { $$ = false; @@ -2537,7 +2547,12 @@ gen_stmt: ast_stack.back()->children.push_back(node); ast_stack.push_back(node); ast_stack.back()->children.push_back($3); - } gen_stmt_block opt_gen_else { + AstNode *block = new AstNode(AST_GENBLOCK); + ast_stack.back()->children.push_back(block); + ast_stack.push_back(block); + } gen_stmt_or_null { + ast_stack.pop_back(); + } opt_gen_else { SET_AST_NODE_LOC(ast_stack.back(), @1, @7); ast_stack.pop_back(); } | diff --git a/kernel/constids.inc b/kernel/constids.inc index aa75a9c09..93c3a7609 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -2,13 +2,12 @@ X(A) X(abc9_box) X(abc9_box_id) X(abc9_box_seq) +X(abc9_bypass) X(abc9_carry) X(abc9_flop) -X(abc9_holes) -X(abc9_init) +X(abc9_keep) X(abc9_lut) X(abc9_mergeability) -X(abc9_scc) X(abc9_scc_id) X(abcgroup) X(ABITS) @@ -80,6 +79,8 @@ X(equiv_merged) X(equiv_region) X(extract_order) X(F) +X(force_downto) +X(force_upto) X(fsm_encoding) X(fsm_export) X(FULL) @@ -125,6 +126,7 @@ X(nomem2init) X(nomem2reg) X(nomeminit) X(nosync) +X(nowrshmsk) X(O) X(OFFSET) X(onehot) diff --git a/kernel/log.cc b/kernel/log.cc index a21ba480a..104bee078 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -42,7 +42,7 @@ std::vector<FILE*> log_files; std::vector<std::ostream*> log_streams; std::map<std::string, std::set<std::string>> log_hdump; std::vector<YS_REGEX_TYPE> log_warn_regexes, log_nowarn_regexes, log_werror_regexes; -std::vector<std::pair<YS_REGEX_TYPE,LogExpectedItem>> log_expect_log, log_expect_warning, log_expect_error; +dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error; std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored; int log_warnings_count = 0; int log_warnings_count_noexpect = 0; @@ -181,7 +181,7 @@ void logv(const char *format, va_list ap) log_warning("Found log message matching -W regex:\n%s", str.c_str()); for (auto &item : log_expect_log) - if (YS_REGEX_NS::regex_search(linebuffer, item.first)) + if (YS_REGEX_NS::regex_search(linebuffer, item.second.pattern)) item.second.current_count++; linebuffer.clear(); @@ -256,7 +256,7 @@ static void logv_warning_with_prefix(const char *prefix, bool warning_match = false; for (auto &item : log_expect_warning) - if (YS_REGEX_NS::regex_search(message, item.first)) { + if (YS_REGEX_NS::regex_search(message, item.second.pattern)) { item.second.current_count++; warning_match = true; } @@ -349,7 +349,7 @@ static void logv_error_with_prefix(const char *prefix, log_error_atexit(); for (auto &item : log_expect_error) - if (YS_REGEX_NS::regex_search(log_last_error, item.first)) + if (YS_REGEX_NS::regex_search(log_last_error, item.second.pattern)) item.second.current_count++; if (check_expected_logs) @@ -672,31 +672,31 @@ void log_check_expected() for (auto &item : log_expect_warning) { if (item.second.current_count == 0) { log_warn_regexes.clear(); - log_error("Expected warning pattern '%s' not found !\n", item.second.pattern.c_str()); + log_error("Expected warning pattern '%s' not found !\n", item.first.c_str()); } if (item.second.current_count != item.second.expected_count) { log_warn_regexes.clear(); log_error("Expected warning pattern '%s' found %d time(s), instead of %d time(s) !\n", - item.second.pattern.c_str(), item.second.current_count, item.second.expected_count); + item.first.c_str(), item.second.current_count, item.second.expected_count); } } for (auto &item : log_expect_log) { if (item.second.current_count == 0) { log_warn_regexes.clear(); - log_error("Expected log pattern '%s' not found !\n", item.second.pattern.c_str()); + log_error("Expected log pattern '%s' not found !\n", item.first.c_str()); } if (item.second.current_count != item.second.expected_count) { log_warn_regexes.clear(); log_error("Expected log pattern '%s' found %d time(s), instead of %d time(s) !\n", - item.second.pattern.c_str(), item.second.current_count, item.second.expected_count); + item.first.c_str(), item.second.current_count, item.second.expected_count); } } for (auto &item : log_expect_error) if (item.second.current_count == item.second.expected_count) { log_warn_regexes.clear(); - log("Expected error pattern '%s' found !!!\n", item.second.pattern.c_str()); + log("Expected error pattern '%s' found !!!\n", item.first.c_str()); #ifdef EMSCRIPTEN throw 0; #elif defined(_MSC_VER) @@ -707,7 +707,7 @@ void log_check_expected() } else { display_error_log_msg = false; log_warn_regexes.clear(); - log_error("Expected error pattern '%s' not found !\n", item.second.pattern.c_str()); + log_error("Expected error pattern '%s' not found !\n", item.first.c_str()); } } diff --git a/kernel/log.h b/kernel/log.h index dee5d44d7..516744b50 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -86,7 +86,7 @@ YOSYS_NAMESPACE_BEGIN # endif # if __has_builtin(__builtin_debugtrap) # define YS_DEBUGTRAP __builtin_debugtrap() -# elif defined(__unix__) +# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) # define YS_DEBUGTRAP raise(SIGTRAP) # else # define YS_DEBUGTRAP do {} while(0) @@ -97,11 +97,11 @@ YOSYS_NAMESPACE_BEGIN // if a debugger is attached, and does nothing otherwise. #if defined(_WIN32) # define YS_DEBUGTRAP_IF_DEBUGGING do { if (IsDebuggerPresent()) DebugBreak(); } while(0) -#elif defined(__unix__) +# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) // There is no reliable (or portable) *nix equivalent of IsDebuggerPresent(). However, // debuggers will stop when SIGTRAP is raised, even if the action is set to ignore. # define YS_DEBUGTRAP_IF_DEBUGGING do { \ - sighandler_t old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \ + auto old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \ } while(0) #else # define YS_DEBUGTRAP_IF_DEBUGGING do {} while(0) @@ -202,19 +202,16 @@ void log_flush(); struct LogExpectedItem { - LogExpectedItem(std::string pattern, int expected) : - expected_count(expected), - current_count(0), - pattern(pattern) - { - } + LogExpectedItem(const YS_REGEX_TYPE &pat, int expected) : + pattern(pat), expected_count(expected), current_count(0) {} + LogExpectedItem() : expected_count(0), current_count(0) {} + YS_REGEX_TYPE pattern; int expected_count; int current_count; - std::string pattern; }; -extern std::vector<std::pair<YS_REGEX_TYPE,LogExpectedItem>> log_expect_log, log_expect_warning, log_expect_error; +extern dict<std::string, LogExpectedItem> log_expect_log, log_expect_warning, log_expect_error; void log_check_expected(); const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true); diff --git a/kernel/timinginfo.h b/kernel/timinginfo.h index fb4e0930d..d818e580b 100644 --- a/kernel/timinginfo.h +++ b/kernel/timinginfo.h @@ -82,6 +82,9 @@ struct TimingInfo for (auto cell : module->cells()) { if (cell->type == ID($specify2)) { + auto en = cell->getPort(ID::EN); + if (en.is_fully_const() && !en.as_bool()) + continue; auto src = cell->getPort(ID::SRC); auto dst = cell->getPort(ID::DST); for (const auto &c : src.chunks()) @@ -128,11 +131,9 @@ struct TimingInfo int rise_max = cell->getParam(ID::T_RISE_MAX).as_int(); int fall_max = cell->getParam(ID::T_FALL_MAX).as_int(); int max = std::max(rise_max,fall_max); - if (max < 0) - log_warning("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell)); - if (max <= 0) { - log_debug("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX <= 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell)); - continue; + if (max < 0) { + log_warning("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Clamping to 0.\n", log_id(module), log_id(cell)); + max = 0; } for (const auto &d : dst) { auto &v = t.arrival[NameBit(d)]; @@ -152,11 +153,9 @@ struct TimingInfo if (!c.wire->port_input) log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(dst)); int max = cell->getParam(ID::T_LIMIT_MAX).as_int(); - if (max < 0) - log_warning("Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell)); - if (max <= 0) { - log_debug("Module '%s' contains specify cell '%s' with T_LIMIT_MAX <= 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell)); - continue; + if (max < 0) { + log_warning("Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Clamping to 0.\n", log_id(module), log_id(cell)); + max = 0; } for (const auto &s : src) { auto &v = t.required[NameBit(s)]; diff --git a/kernel/yosys.h b/kernel/yosys.h index af1e376b1..c922faf26 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -155,6 +155,16 @@ extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *p # define YS_NORETURN #endif +#if __cplusplus >= 201703L +# define YS_FALLTHROUGH [[fallthrough]]; +#elif defined(__clang__) +# define YS_FALLTHROUGH [[clang::fallthrough]]; +#elif defined(__GNUC__) +# define YS_FALLTHROUGH [[gnu::fallthrough]]; +#else +# define YS_FALLTHROUGH +#endif + YOSYS_NAMESPACE_BEGIN // Note: All headers included in hashlib.h must be included diff --git a/passes/cmds/logger.cc b/passes/cmds/logger.cc index 9a27952d4..c9532eced 100644 --- a/passes/cmds/logger.cc +++ b/passes/cmds/logger.cc @@ -58,7 +58,8 @@ struct LoggerPass : public Pass { log(" do not print warnings for the specified experimental feature\n"); log("\n"); log(" -expect <type> <regex> <expected_count>\n"); - log(" expect log,warning or error to appear. In case of error return code is 0.\n"); + log(" expect log, warning or error to appear. matched errors will terminate\n"); + log(" with exit code 0.\n"); log("\n"); log(" -expect-no-warnings\n"); log(" gives error in case there is at least one warning that is not expected.\n"); @@ -158,12 +159,13 @@ struct LoggerPass : public Pass { log_cmd_error("Expected error message occurrences must be 1 !\n"); log("Added regex '%s' for warnings to expected %s list.\n", pattern.c_str(), type.c_str()); try { - if (type=="error") - log_expect_error.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count))); - else if (type=="warning") - log_expect_warning.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count))); - else - log_expect_log.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count))); + if (type == "error") + log_expect_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); + else if (type == "warning") + log_expect_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); + else if (type == "log") + log_expect_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); + else log_abort(); } catch (const YS_REGEX_NS::regex_error& e) { log_cmd_error("Error in regex expression '%s' !\n", pattern.c_str()); diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 6271376f1..f7de02164 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -412,7 +412,7 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos return !del_wires_queue.empty(); } -bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) +bool rmunused_module_init(RTLIL::Module *module, bool verbose) { bool did_something = false; CellTypes fftypes; @@ -445,9 +445,6 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) for (auto wire : module->wires()) { - if (!purge_mode && wire->name[0] == '\\') - continue; - if (wire->attributes.count(ID::init) == 0) continue; @@ -464,11 +461,22 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) if (wire_bit == mapped_wire_bit) goto next_wire; - if (qbits.count(sigmap(SigBit(wire, i))) == 0) - goto next_wire; + if (mapped_wire_bit.wire) { + if (qbits.count(mapped_wire_bit) == 0) + goto next_wire; - if (qbits.at(sigmap(SigBit(wire, i))) != init[i]) - goto next_wire; + if (qbits.at(mapped_wire_bit) != init[i]) + goto next_wire; + } + else { + if (mapped_wire_bit == State::Sx || mapped_wire_bit == State::Sz) + goto next_wire; + + if (mapped_wire_bit != init[i]) { + log_warning("Initial value conflict for %s resolving to %s but with init %s.\n", log_signal(wire_bit), log_signal(mapped_wire_bit), log_signal(init[i])); + goto next_wire; + } + } } if (verbose) @@ -512,7 +520,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool rmunused_module_cells(module, verbose); while (rmunused_module_signals(module, purge_mode, verbose)) { } - if (rminit && rmunused_module_init(module, purge_mode, verbose)) + if (rminit && rmunused_module_init(module, verbose)) while (rmunused_module_signals(module, purge_mode, verbose)) { } } @@ -611,8 +619,7 @@ struct CleanPass : public Pass { } break; } - if (argidx < args.size()) - extra_args(args, argidx, design); + extra_args(args, argidx, design); keep_cache.reset(design); @@ -627,7 +634,7 @@ struct CleanPass : public Pass { for (auto module : design->selected_whole_modules()) { if (module->has_processes()) continue; - rmunused_module(module, purge_mode, ys_debug(), false); + rmunused_module(module, purge_mode, ys_debug(), true); } log_suppressed(); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 0f5bff680..777a24777 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -132,7 +132,7 @@ void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, did_something = true; } -bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap) +bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap, bool keepdc) { IdString b_name = cell->hasPort(ID::B) ? ID::B : ID::A; @@ -156,20 +156,36 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ int group_idx = GRP_DYN; RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i]; - if (cell->type == ID($or) && (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1)) - bit_a = bit_b = RTLIL::State::S1; - - if (cell->type == ID($and) && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0)) - bit_a = bit_b = RTLIL::State::S0; + if (cell->type == ID($or)) { + if (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1) + bit_a = bit_b = RTLIL::State::S1; + } + else if (cell->type == ID($and)) { + if (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0) + bit_a = bit_b = RTLIL::State::S0; + } + else if (!keepdc) { + if (cell->type == ID($xor)) { + if (bit_a == bit_b) + bit_a = bit_b = RTLIL::State::S0; + } + else if (cell->type == ID($xnor)) { + if (bit_a == bit_b) + bit_a = bit_b = RTLIL::State::S1; // For consistency with gate-level which does $xnor -> $_XOR_ + $_NOT_ + } + } - if (bit_a.wire == NULL && bit_b.wire == NULL) - group_idx = GRP_CONST_AB; - else if (bit_a.wire == NULL) - group_idx = GRP_CONST_A; - else if (bit_b.wire == NULL && commutative) - group_idx = GRP_CONST_A, std::swap(bit_a, bit_b); - else if (bit_b.wire == NULL) - group_idx = GRP_CONST_B; + bool def = (bit_a != State::Sx && bit_a != State::Sz && bit_b != State::Sx && bit_b != State::Sz); + if (def || !keepdc) { + if (bit_a.wire == NULL && bit_b.wire == NULL) + group_idx = GRP_CONST_AB; + else if (bit_a.wire == NULL) + group_idx = GRP_CONST_A; + else if (bit_b.wire == NULL && commutative) + group_idx = GRP_CONST_A, std::swap(bit_a, bit_b); + else if (bit_b.wire == NULL) + group_idx = GRP_CONST_B; + } grouped_bits[group_idx][std::pair<RTLIL::SigBit, RTLIL::SigBit>(bit_a, bit_b)].insert(bits_y[i]); } @@ -186,26 +202,77 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ if (grouped_bits[i].empty()) continue; - RTLIL::Wire *new_y = module->addWire(NEW_ID, GetSize(grouped_bits[i])); + RTLIL::SigSpec new_y = module->addWire(NEW_ID, GetSize(grouped_bits[i])); RTLIL::SigSpec new_a, new_b; RTLIL::SigSig new_conn; for (auto &it : grouped_bits[i]) { for (auto &bit : it.second) { new_conn.first.append(bit); - new_conn.second.append(RTLIL::SigBit(new_y, new_a.size())); + new_conn.second.append(new_y[new_a.size()]); } new_a.append(it.first.first); new_b.append(it.first.second); } if (cell->type.in(ID($and), ID($or)) && i == GRP_CONST_A) { + if (!keepdc) { + if (cell->type == ID($and)) + new_a.replace(dict<SigBit,SigBit>{{State::Sx, State::S0}, {State::Sz, State::S0}}, &new_b); + else if (cell->type == ID($or)) + new_a.replace(dict<SigBit,SigBit>{{State::Sx, State::S1}, {State::Sz, State::S1}}, &new_b); + else log_abort(); + } log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a)); module->connect(new_y, new_b); module->connect(new_conn); continue; } + if (cell->type.in(ID($xor), ID($xnor)) && i == GRP_CONST_A) { + SigSpec undef_a, undef_y, undef_b; + SigSpec def_y, def_a, def_b; + for (int i = 0; i < GetSize(new_y); i++) { + bool undef = new_a[i] == State::Sx || new_a[i] == State::Sz; + if (!keepdc && (undef || new_a[i] == new_b[i])) { + undef_a.append(new_a[i]); + if (cell->type == ID($xor)) + undef_b.append(State::S0); + // For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_ + else if (cell->type == ID($xnor)) + undef_b.append(State::S1); + else log_abort(); + undef_y.append(new_y[i]); + } + else if (new_a[i] == State::S0 || new_a[i] == State::S1) { + undef_a.append(new_a[i]); + if (cell->type == ID($xor)) + undef_b.append(new_a[i] == State::S1 ? module->Not(NEW_ID, new_b[i]).as_bit() : new_b[i]); + else if (cell->type == ID($xnor)) + undef_b.append(new_a[i] == State::S1 ? new_b[i] : module->Not(NEW_ID, new_b[i]).as_bit()); + else log_abort(); + undef_y.append(new_y[i]); + } + else { + def_a.append(new_a[i]); + def_b.append(new_b[i]); + def_y.append(new_y[i]); + } + } + if (!undef_y.empty()) { + log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(undef_b), log_id(cell->type), log_signal(undef_a)); + module->connect(undef_y, undef_b); + if (def_y.empty()) { + module->connect(new_conn); + continue; + } + } + new_a = std::move(def_a); + new_b = std::move(def_b); + new_y = std::move(def_y); + } + + RTLIL::Cell *c = module->addCell(NEW_ID, cell->type); c->setPort(ID::A, new_a); @@ -219,7 +286,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ } c->setPort(ID::Y, new_y); - c->parameters[ID::Y_WIDTH] = new_y->width; + c->parameters[ID::Y_WIDTH] = GetSize(new_y); c->check(); module->connect(new_conn); @@ -476,13 +543,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } } - if (detect_const_and && (found_zero || found_inv)) { + if (detect_const_and && (found_zero || found_inv || (found_undef && consume_x))) { cover("opt.opt_expr.const_and"); replace_cell(assign_map, module, cell, "const_and", ID::Y, RTLIL::State::S0); goto next_cell; } - if (detect_const_or && (found_one || found_inv)) { + if (detect_const_or && (found_one || found_inv || (found_undef && consume_x))) { cover("opt.opt_expr.const_or"); replace_cell(assign_map, module, cell, "const_or", ID::Y, RTLIL::State::S1); goto next_cell; @@ -499,6 +566,22 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons { SigBit sig_a = assign_map(cell->getPort(ID::A)); SigBit sig_b = assign_map(cell->getPort(ID::B)); + if (!keepdc && (sig_a == sig_b || sig_a == State::Sx || sig_a == State::Sz || sig_b == State::Sx || sig_b == State::Sz)) { + if (cell->type.in(ID($xor), ID($_XOR_))) { + cover("opt.opt_expr.const_xor"); + replace_cell(assign_map, module, cell, "const_xor", ID::Y, RTLIL::State::S0); + goto next_cell; + } + if (cell->type.in(ID($xnor), ID($_XNOR_))) { + cover("opt.opt_expr.const_xnor"); + // For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_ + int width = cell->getParam(ID::Y_WIDTH).as_int(); + replace_cell(assign_map, module, cell, "const_xnor", ID::Y, SigSpec(RTLIL::State::S1, width)); + goto next_cell; + } + log_abort(); + } + if (!sig_a.wire) std::swap(sig_a, sig_b); if (sig_b == State::S0 || sig_b == State::S1) { @@ -550,7 +633,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (do_fine) { if (cell->type.in(ID($not), ID($pos), ID($and), ID($or), ID($xor), ID($xnor))) - if (group_cell_inputs(module, cell, true, assign_map)) + if (group_cell_inputs(module, cell, true, assign_map, keepdc)) goto next_cell; if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_or), ID($reduce_and), ID($reduce_bool))) @@ -904,8 +987,10 @@ skip_fine_alu: if (input.match("01")) ACTION_DO_Y(1); if (input.match("10")) ACTION_DO_Y(1); if (input.match("11")) ACTION_DO_Y(0); - if (input.match(" *")) ACTION_DO_Y(x); - if (input.match("* ")) ACTION_DO_Y(x); + if (consume_x) { + if (input.match(" *")) ACTION_DO_Y(0); + if (input.match("* ")) ACTION_DO_Y(0); + } } if (cell->type == ID($_MUX_)) { @@ -1088,7 +1173,7 @@ skip_fine_alu: goto next_cell; } - if (!keepdc) + if (consume_x) { bool identity_wrt_a = false; bool identity_wrt_b = false; @@ -1980,11 +2065,12 @@ struct OptExprPass : public Pass { do { do { did_something = false; - replace_const_cells(design, module, false, mux_undef, mux_bool, do_fine, keepdc, clkinv); + replace_const_cells(design, module, false /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, clkinv); if (did_something) design->scratchpad_set_bool("opt.did_something", true); } while (did_something); - replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv); + if (!keepdc) + replace_const_cells(design, module, true /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, clkinv); if (did_something) design->scratchpad_set_bool("opt.did_something", true); } while (did_something); diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 1b3d5ff06..06097a6f7 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -151,8 +151,8 @@ struct Abc9Pass : public ScriptPass log(" specified).\n"); log("\n"); log(" -dff\n"); - log(" also pass $_ABC9_FF_ cells through to ABC. modules with many clock\n"); - log(" domains are marked as such and automatically partitioned by ABC.\n"); + log(" also pass $_DFF_[NP]_ cells through to ABC. modules with many clock\n"); + log(" domains are supported and automatically partitioned by ABC.\n"); log("\n"); log(" -nocleanup\n"); log(" when this option is used, the temporary files created by this pass\n"); @@ -274,40 +274,106 @@ struct Abc9Pass : public ScriptPass void script() YS_OVERRIDE { + if (check_label("check")) { + if (help_mode) + run("abc9_ops -check [-dff]", "(option if -dff)"); + else + run(stringf("abc9_ops -check %s", dff_mode ? "-dff" : "")); + } + + if (check_label("map")) { + if (help_mode) + run("abc9_ops -prep_hier -prep_bypass [-prep_dff -dff]", "(option if -dff)"); + else + run(stringf("abc9_ops -prep_hier -prep_bypass %s", dff_mode ? "-prep_dff -dff" : "")); + if (dff_mode) { + run("design -copy-to $abc9_map @$abc9_flops", "(only if -dff)"); + run("select -unset $abc9_flops", " (only if -dff)"); + } + run("design -stash $abc9"); + run("design -load $abc9_map"); + run("proc"); + run("wbflip"); + run("techmap"); + run("opt"); + if (dff_mode || help_mode) { + if (!help_mode) + active_design->scratchpad_unset("abc9_ops.prep_dff_submod.did_something"); + run("abc9_ops -prep_dff_submod", " (only if -dff)"); // rewrite specify + bool did_something = help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_dff_submod.did_something"); + if (did_something) { + // select all $_DFF_[NP]_ + // then select all its fanins + // then select all fanouts of all that + // lastly remove $_DFF_[NP]_ cells + run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d", " (only if -dff)"); + run("submod", " (only if -dff)"); + run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop", "(only if -dff)"); + if (help_mode) { + run("foreach module in design"); + run(" rename <module-name>_$abc9_flop _TECHMAP_REPLACE_", " (only if -dff)"); + } + else { + // Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs + for (auto module : active_design->selected_modules()) { + active_design->selected_active_module = module->name.str(); + if (module->cell(stringf("%s_$abc9_flop", module->name.c_str()))) + run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str())); + } + active_design->selected_active_module.clear(); + } + run("abc9_ops -prep_dff_unmap", " (only if -dff)"); + run("design -copy-to $abc9 =*_$abc9_flop", " (only if -dff)"); // copy submod out + run("delete =*_$abc9_flop", " (only if -dff)"); + } + } + run("design -stash $abc9_map"); + run("design -load $abc9"); + run("design -delete $abc9"); + if (help_mode) + run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v [-D DFF]", "(option if -dff)"); + else + run(stringf("techmap -wb -max_iter 1 -map %%$abc9_map -map +/abc9_map.v %s", dff_mode ? "-D DFF" : "")); + run("design -delete $abc9_map"); + } + if (check_label("pre")) { - run("abc9_ops -check"); + run("read_verilog -icells -lib -specify +/abc9_model.v"); run("scc -set_attr abc9_scc_id {}"); if (help_mode) run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)"); else - run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); + run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : "")); if (help_mode) run("abc9_ops -prep_lut <maxlut>", "(skip if -lut or -luts)"); else if (!lut_mode) run(stringf("abc9_ops -prep_lut %d", maxlut)); if (help_mode) - run("abc9_ops -prep_box [-dff]", "(skip if -box)"); + run("abc9_ops -prep_box", "(skip if -box)"); else if (box_file.empty()) - run(stringf("abc9_ops -prep_box %s", dff_mode ? "-dff" : "")); - run("select -set abc9_holes A:abc9_holes"); - run("flatten -wb @abc9_holes"); - run("techmap @abc9_holes"); - if (dff_mode || help_mode) - run("abc9_ops -prep_dff", "(only if -dff)"); - run("opt -purge @abc9_holes"); - run("aigmap"); - run("wbflip @abc9_holes"); + run("abc9_ops -prep_box"); + if (saved_designs.count("$abc9_holes") || help_mode) { + run("design -stash $abc9"); + run("design -load $abc9_holes"); + run("techmap -wb -map %$abc9 -map +/techmap.v"); + run("opt -purge"); + run("aigmap"); + run("design -stash $abc9_holes"); + run("design -load $abc9"); + run("design -delete $abc9"); + } } - if (check_label("map")) { + if (check_label("exe")) { + run("aigmap"); if (help_mode) { run("foreach module in selection"); run(" abc9_ops -write_lut <abc-temp-dir>/input.lut", "(skip if '-lut' or '-luts')"); - run(" abc9_ops -write_box <abc-temp-dir>/input.box"); - run(" write_xaiger -map <abc-temp-dir>/input.sym <abc-temp-dir>/input.xaig"); - run(" abc9_exe [options] -cwd <abc-temp-dir> [-lut <abc-temp-dir>/input.lut] -box <abc-temp-dir>/input.box"); + run(" abc9_ops -write_box <abc-temp-dir>/input.box", "(skip if '-box')"); + run(" write_xaiger -map <abc-temp-dir>/input.sym [-dff] <abc-temp-dir>/input.xaig"); + run(" abc9_exe [options] -cwd <abc-temp-dir> -lut [<abc-temp-dir>/input.lut] -box [<abc-temp-dir>/input.box]"); run(" read_aiger -xaiger -wideports -module_name <module-name>$abc9 -map <abc-temp-dir>/input.sym <abc-temp-dir>/output.aig"); - run(" abc9_ops -reintegrate"); + run(" abc9_ops -reintegrate [-dff]"); } else { auto selected_modules = active_design->selected_modules(); @@ -318,7 +384,6 @@ struct Abc9Pass : public ScriptPass log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; } - log_assert(!mod->attributes.count(ID::abc9_box_id)); log_push(); active_design->selection().select(mod); @@ -333,8 +398,9 @@ struct Abc9Pass : public ScriptPass if (!lut_mode) run_nocheck(stringf("abc9_ops -write_lut %s/input.lut", tempdir_name.c_str())); - run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str())); - run_nocheck(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); + if (box_file.empty()) + run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str())); + run_nocheck(stringf("write_xaiger -map %s/input.sym %s %s/input.xaig", tempdir_name.c_str(), dff_mode ? "-dff" : "", tempdir_name.c_str())); int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs"); @@ -349,10 +415,13 @@ struct Abc9Pass : public ScriptPass abc9_exe_cmd += stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str()); if (!lut_mode) abc9_exe_cmd += stringf(" -lut %s/input.lut", tempdir_name.c_str()); - abc9_exe_cmd += stringf(" -box %s/input.box", tempdir_name.c_str()); + if (box_file.empty()) + abc9_exe_cmd += stringf(" -box %s/input.box", tempdir_name.c_str()); + else + abc9_exe_cmd += stringf(" -box %s", box_file.c_str()); run_nocheck(abc9_exe_cmd); run_nocheck(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str())); - run_nocheck("abc9_ops -reintegrate"); + run_nocheck(stringf("abc9_ops -reintegrate %s", dff_mode ? "-dff" : "")); } else log("Don't call ABC as there is nothing to map.\n"); @@ -369,6 +438,14 @@ struct Abc9Pass : public ScriptPass active_design->selection_stack.pop_back(); } } + + if (check_label("unmap")) { + run("techmap -wb -map %$abc9_unmap -map +/abc9_unmap.v"); // techmap user design from submod back to original cell + // ($_DFF_[NP]_ already shorted by -reintegrate) + run("design -delete $abc9_unmap"); + if (saved_designs.count("$abc9_holes") || help_mode) + run("design -delete $abc9_holes"); + } } } Abc9Pass; diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 1345188a4..8d55b18a0 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -34,13 +34,10 @@ inline std::string remap_name(RTLIL::IdString abc9_name) return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); } -void check(RTLIL::Design *design) +void check(RTLIL::Design *design, bool dff_mode) { dict<IdString,IdString> box_lookup; for (auto m : design->modules()) { - if (m->name.begins_with("$paramod")) - continue; - auto flop = m->get_bool_attribute(ID::abc9_flop); auto it = m->attributes.find(ID::abc9_box_id); if (!flop) { @@ -88,6 +85,461 @@ void check(RTLIL::Design *design) log_error("Module '%s' with (* abc9_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs); } } + + if (dff_mode) { + static pool<IdString> unsupported{ + ID($adff), ID($dlatch), ID($dlatchsr), ID($sr), + ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), + ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_), + ID($_DLATCH_N_), ID($_DLATCH_P_), + ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_), + ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_), + ID($_SR_NN_), ID($_SR_NP_), ID($_SR_PN_), ID($_SR_PP_) + }; + pool<IdString> processed; + for (auto module : design->selected_modules()) + for (auto cell : module->cells()) { + auto inst_module = design->module(cell->type); + if (!inst_module) + continue; + if (!inst_module->get_blackbox_attribute()) + continue; + IdString derived_type; + Module *derived_module; + if (cell->parameters.empty()) { + derived_type = cell->type; + derived_module = inst_module; + } + else { + derived_type = inst_module->derive(design, cell->parameters); + derived_module = design->module(derived_type); + log_assert(derived_module); + } + if (!derived_module->get_bool_attribute(ID::abc9_flop)) + continue; + if (derived_module->get_blackbox_attribute(true /* ignore_wb */)) + log_error("Module '%s' with (* abc9_flop *) is a blackbox.\n", log_id(derived_type)); + + if (derived_module->has_processes()) + Pass::call_on_module(design, derived_module, "proc"); + + bool found = false; + for (auto derived_cell : derived_module->cells()) { + if (derived_cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) { + if (found) + log_error("Module '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell.\n", log_id(derived_module)); + found = true; + + SigBit Q = derived_cell->getPort(ID::Q); + log_assert(GetSize(Q.wire) == 1); + + if (!Q.wire->port_output) + log_error("Module '%s' contains a %s cell where its 'Q' port does not drive a module output!\n", log_id(derived_module), log_id(derived_cell->type)); + + Const init = Q.wire->attributes.at(ID::init, State::Sx); + log_assert(GetSize(init) == 1); + } + else if (unsupported.count(derived_cell->type)) + log_error("Module '%s' with (* abc9_flop *) contains a %s cell, which is not supported for sequential synthesis.\n", log_id(derived_module), log_id(derived_cell->type)); + } + } + } +} + +void prep_hier(RTLIL::Design *design, bool dff_mode) +{ + auto r = saved_designs.emplace("$abc9_unmap", nullptr); + if (r.second) + r.first->second = new Design; + Design *unmap_design = r.first->second; + + static const pool<IdString> seq_types{ + ID($dff), ID($dffsr), ID($adff), + ID($dlatch), ID($dlatchsr), ID($sr), + ID($mem), + ID($_DFF_N_), ID($_DFF_P_), + ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_), + ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_), + ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), + ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_), + ID($_DLATCH_N_), ID($_DLATCH_P_), + ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_), + ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_), + ID($_SR_NN_), ID($_SR_NP_), ID($_SR_PN_), ID($_SR_PP_) + }; + + for (auto module : design->selected_modules()) + for (auto cell : module->cells()) { + auto inst_module = design->module(cell->type); + if (!inst_module) + continue; + if (!inst_module->get_blackbox_attribute()) + continue; + IdString derived_type; + Module *derived_module; + if (cell->parameters.empty()) { + derived_type = cell->type; + derived_module = inst_module; + } + else { + derived_type = inst_module->derive(design, cell->parameters); + derived_module = design->module(derived_type); + } + if (derived_module->get_blackbox_attribute(true /* ignore_wb */)) + continue; + + if (derived_module->get_bool_attribute(ID::abc9_flop)) { + if (!dff_mode) + continue; + } + else { + if (!derived_module->get_bool_attribute(ID::abc9_box) && !derived_module->get_bool_attribute(ID::abc9_bypass)) + continue; + } + + if (!unmap_design->module(derived_type)) { + if (derived_module->has_processes()) + Pass::call_on_module(design, derived_module, "proc"); + + if (derived_module->get_bool_attribute(ID::abc9_flop)) { + for (auto derived_cell : derived_module->cells()) + if (derived_cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) { + SigBit Q = derived_cell->getPort(ID::Q); + Const init = Q.wire->attributes.at(ID::init, State::Sx); + log_assert(GetSize(init) == 1); + + // Block sequential synthesis on cells with (* init *) != 1'b0 + // because ABC9 doesn't support them + if (init != State::S0) { + log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(derived_module), log_id(derived_cell->type)); + derived_module->set_bool_attribute(ID::abc9_flop, false); + } + break; + } + } + else if (derived_module->get_bool_attribute(ID::abc9_box)) { + for (auto derived_cell : derived_module->cells()) + if (seq_types.count(derived_cell->type)) { + derived_module->set_bool_attribute(ID::abc9_box, false); + derived_module->set_bool_attribute(ID::abc9_bypass); + break; + } + } + + if (derived_type != cell->type) { + auto unmap_module = unmap_design->addModule(derived_type); + for (auto port : derived_module->ports) { + auto w = unmap_module->addWire(port, derived_module->wire(port)); + // Do not propagate (* init *) values into the box, + // in fact, remove it from outside too + if (w->port_output && w->attributes.erase(ID::init)) { + auto r = unmap_module->addWire(stringf("\\_TECHMAP_REMOVEINIT_%s_", log_id(port))); + unmap_module->connect(r, State::S1); + } + } + unmap_module->ports = derived_module->ports; + unmap_module->check(); + + auto replace_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, cell->type); + for (const auto &conn : cell->connections()) { + auto w = unmap_module->wire(conn.first); + log_assert(w); + replace_cell->setPort(conn.first, w); + } + replace_cell->parameters = cell->parameters; + } + } + + cell->type = derived_type; + cell->parameters.clear(); + } +} + +void prep_bypass(RTLIL::Design *design) +{ + auto r = saved_designs.emplace("$abc9_map", nullptr); + if (r.second) + r.first->second = new Design; + Design *map_design = r.first->second; + + r = saved_designs.emplace("$abc9_unmap", nullptr); + if (r.second) + r.first->second = new Design; + Design *unmap_design = r.first->second; + + pool<IdString> processed; + for (auto module : design->selected_modules()) + for (auto cell : module->cells()) { + if (!processed.insert(cell->type).second) + continue; + auto inst_module = design->module(cell->type); + if (!inst_module) + continue; + if (!inst_module->get_bool_attribute(ID::abc9_bypass)) + continue; + log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */)); + log_assert(cell->parameters.empty()); + + + // The idea is to create two techmap designs, one which maps: + // + // box u0 (.i(i), .o(o)); + // + // to + // + // wire $abc9$o; + // box u0 (.i(i), .o($abc9_byp$o)); + // box_$abc9_byp (.i(i), .$abc9_byp$o($abc9_byp$o), .o(o)); + // + // the purpose being to move the (* abc9_box *) status from 'box' + // (which is stateful) to 'box_$abc9_byp' (which becomes a new + // combinatorial black- (not white-) box with all state elements + // removed). This has the effect of preserving any combinatorial + // paths through an otherwise sequential primitive -- e.g. LUTRAMs. + // + // The unmap design performs the reverse: + // + // wire $abc9$o; + // box u0 (.i(i), .o($abc9_byp$o)); + // box_$abc9_byp (.i(i), .$abc9_byp$o($abc9_byp$o), .o(o)); + // + // to: + // + // wire $abc9$o; + // box u0 (.i(i), .o($abc9_byp$o)); + // assign o = $abc9_byp$o; + + + // Copy inst_module into map_design, with the same interface + // and duplicate $abc9$* wires for its output ports + auto map_module = map_design->addModule(cell->type); + for (auto port_name : inst_module->ports) { + auto w = map_module->addWire(port_name, inst_module->wire(port_name)); + if (w->port_output) + w->attributes.erase(ID::init); + } + map_module->ports = inst_module->ports; + map_module->check(); + map_module->set_bool_attribute(ID::whitebox); + + // Create the bypass module in the user design, which has the same + // interface as the derived module but with additional input + // ports driven by the outputs of the replaced cell + auto bypass_module = design->addModule(cell->type.str() + "_$abc9_byp"); + for (auto port_name : inst_module->ports) { + auto port = inst_module->wire(port_name); + if (!port->port_output) + continue; + auto dst = bypass_module->addWire(port_name, port); + auto src = bypass_module->addWire("$abc9byp$" + port_name.str(), GetSize(port)); + src->port_input = true; + // For these new input ports driven by the replaced + // cell, then create a new simple-path specify entry: + // (input => output) = 0 + auto specify = bypass_module->addCell(NEW_ID, ID($specify2)); + specify->setPort(ID::EN, State::S1); + specify->setPort(ID::SRC, src); + specify->setPort(ID::DST, dst); + specify->setParam(ID::FULL, 0); + specify->setParam(ID::SRC_WIDTH, GetSize(src)); + specify->setParam(ID::DST_WIDTH, GetSize(dst)); + specify->setParam(ID::SRC_DST_PEN, 0); + specify->setParam(ID::SRC_DST_POL, 0); + specify->setParam(ID::T_RISE_MIN, 0); + specify->setParam(ID::T_RISE_TYP, 0); + specify->setParam(ID::T_RISE_MAX, 0); + specify->setParam(ID::T_FALL_MIN, 0); + specify->setParam(ID::T_FALL_TYP, 0); + specify->setParam(ID::T_FALL_MAX, 0); + } + bypass_module->set_bool_attribute(ID::blackbox); + bypass_module->set_bool_attribute(ID::abc9_box); + + // Copy any 'simple' (combinatorial) specify paths from + // the derived module into the bypass module, if EN + // is not false and SRC/DST are driven only by + // module ports; create new input port if one doesn't + // already exist + for (auto cell : inst_module->cells()) { + if (cell->type != ID($specify2)) + continue; + auto EN = cell->getPort(ID::EN).as_bit(); + SigBit newEN; + if (!EN.wire && EN != State::S1) + continue; + auto SRC = cell->getPort(ID::SRC); + for (const auto &c : SRC.chunks()) + if (c.wire && !c.wire->port_input) { + SRC = SigSpec(); + break; + } + if (SRC.empty()) + continue; + auto DST = cell->getPort(ID::DST); + for (const auto &c : DST.chunks()) + if (c.wire && !c.wire->port_output) { + DST = SigSpec(); + break; + } + if (DST.empty()) + continue; + auto rw = [bypass_module](RTLIL::SigSpec &sig) + { + SigSpec new_sig; + for (auto c : sig.chunks()) { + if (c.wire) { + auto port = bypass_module->wire(c.wire->name); + if (!port) + port = bypass_module->addWire(c.wire->name, c.wire); + c.wire = port; + } + new_sig.append(std::move(c)); + } + sig = std::move(new_sig); + }; + auto specify = bypass_module->addCell(NEW_ID, cell); + specify->rewrite_sigspecs(rw); + } + bypass_module->fixup_ports(); + + // Create an _TECHMAP_REPLACE_ cell identical to the original cell, + // and a bypass cell that has the same inputs/outputs as the + // original cell, but with additional inputs taken from the + // replaced cell + auto replace_cell = map_module->addCell(ID::_TECHMAP_REPLACE_, cell->type); + auto bypass_cell = map_module->addCell(NEW_ID, cell->type.str() + "_$abc9_byp"); + for (const auto &conn : cell->connections()) { + auto port = map_module->wire(conn.first); + if (cell->input(conn.first)) { + replace_cell->setPort(conn.first, port); + if (bypass_module->wire(conn.first)) + bypass_cell->setPort(conn.first, port); + } + if (cell->output(conn.first)) { + bypass_cell->setPort(conn.first, port); + auto n = "$abc9byp$" + conn.first.str(); + auto w = map_module->addWire(n, GetSize(conn.second)); + replace_cell->setPort(conn.first, w); + bypass_cell->setPort(n, w); + } + } + + + // Lastly, create a new module in the unmap_design that shorts + // out the bypass cell back to leave the replace cell behind + // driving the outputs + auto unmap_module = unmap_design->addModule(cell->type.str() + "_$abc9_byp"); + for (auto port_name : inst_module->ports) { + auto w = unmap_module->addWire(port_name, inst_module->wire(port_name)); + if (w->port_output) { + w->attributes.erase(ID::init); + auto w2 = unmap_module->addWire("$abc9byp$" + port_name.str(), GetSize(w)); + w2->port_input = true; + unmap_module->connect(w, w2); + } + } + unmap_module->fixup_ports(); + } +} + +void prep_dff(RTLIL::Design *design) +{ + auto r = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection(false))); + auto &modules_sel = r.first->second; + + for (auto module : design->selected_modules()) + for (auto cell : module->cells()) { + if (modules_sel.selected_whole_module(cell->type)) + continue; + auto inst_module = design->module(cell->type); + if (!inst_module) + continue; + if (!inst_module->get_bool_attribute(ID::abc9_flop)) + continue; + log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */)); + log_assert(cell->parameters.empty()); + modules_sel.select(inst_module); + } +} + +void prep_dff_submod(RTLIL::Design *design) +{ + for (auto module : design->modules()) { + vector<Cell*> specify_cells; + SigBit Q; + Cell* dff_cell = nullptr; + + if (!module->get_bool_attribute(ID::abc9_flop)) + continue; + + for (auto cell : module->cells()) + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { + log_assert(!dff_cell); + dff_cell = cell; + Q = cell->getPort(ID::Q); + log_assert(GetSize(Q.wire) == 1); + } + else if (cell->type.in(ID($specify3), ID($specrule))) + specify_cells.emplace_back(cell); + log_assert(dff_cell); + + // Add an always-enabled CE mux that drives $_DFF_[NP]_.D so that: + // (a) flop box will have an output + // (b) $_DFF_[NP]_.Q will be present as an input + SigBit D = module->addWire(NEW_ID); + module->addMuxGate(NEW_ID, dff_cell->getPort(ID::D), Q, State::S0, D); + dff_cell->setPort(ID::D, D); + + // Rewrite $specify cells that end with $_DFF_[NP]_.Q + // to $_DFF_[NP]_.D since it will be moved into + // the submodule + for (auto cell : specify_cells) { + auto DST = cell->getPort(ID::DST); + DST.replace(Q, D); + cell->setPort(ID::DST, DST); + } + + design->scratchpad_set_bool("abc9_ops.prep_dff_submod.did_something", true); + } +} + +void prep_dff_unmap(RTLIL::Design *design) +{ + Design *unmap_design = saved_designs.at("$abc9_unmap"); + + for (auto module : design->modules()) { + if (!module->get_bool_attribute(ID::abc9_flop) || module->get_bool_attribute(ID::abc9_box)) + continue; + + // Make sure the box module has all the same ports present on flop cell + auto replace_cell = module->cell(ID::_TECHMAP_REPLACE_); + log_assert(replace_cell); + auto box_module = design->module(module->name.str() + "_$abc9_flop"); + log_assert(box_module); + for (auto port_name : module->ports) { + auto port = module->wire(port_name); + auto box_port = box_module->wire(port_name); + if (box_port) { + // Do not propagate init -- already captured by box + box_port->attributes.erase(ID::init); + continue; + } + log_assert(port->port_input); + box_module->addWire(port_name, port); + replace_cell->setPort(port_name, port); + } + box_module->fixup_ports(); + + auto unmap_module = unmap_design->addModule(box_module->name); + replace_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, module->name); + for (auto port_name : box_module->ports) { + auto w = unmap_module->addWire(port_name, box_module->wire(port_name)); + if (module->wire(port_name)) + replace_cell->setPort(port_name, w); + } + unmap_module->ports = box_module->ports; + unmap_module->check(); + } } void mark_scc(RTLIL::Module *module) @@ -95,7 +547,7 @@ void mark_scc(RTLIL::Module *module) // For every unique SCC found, (arbitrarily) find the first // cell in the component, and replace its output connections // with a new wire driven by the old connection but with a - // special (* abc9_scc *) attribute set (which is used by + // special (* abc9_keep *) attribute set (which is used by // write_xaiger to break this wire into PI and POs) pool<RTLIL::Const> ids_seen; for (auto cell : module->cells()) { @@ -111,7 +563,7 @@ void mark_scc(RTLIL::Module *module) if (c.second.is_fully_const()) continue; if (cell->output(c.first)) { Wire *w = module->addWire(NEW_ID, GetSize(c.second)); - w->set_bool_attribute(ID::abc9_scc); + w->set_bool_attribute(ID::abc9_keep); module->connect(w, c.second); c.second = w; } @@ -119,80 +571,94 @@ void mark_scc(RTLIL::Module *module) } } -void prep_dff(RTLIL::Module *module) +void prep_delays(RTLIL::Design *design, bool dff_mode) { - auto design = module->design; - log_assert(design); + TimingInfo timing; - SigMap assign_map(module); + // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes + // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations + std::vector<Cell*> cells; + for (auto module : design->selected_modules()) { + if (module->processes.size() > 0) { + log("Skipping module %s as it contains processes.\n", log_id(module)); + continue; + } - typedef SigSpec clkdomain_t; - dict<clkdomain_t, int> clk_to_mergeability; + for (auto cell : module->cells()) { + if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_))) + continue; + log_assert(!cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")); - for (auto cell : module->cells()) { - if (cell->type != ID($__ABC9_FF_)) - continue; + RTLIL::Module* inst_module = design->module(cell->type); + if (!inst_module) + continue; + if (!inst_module->get_blackbox_attribute()) + continue; + if (!cell->parameters.empty()) + continue; - Wire *abc9_clock_wire = module->wire(stringf("%s.clock", cell->name.c_str())); - if (abc9_clock_wire == NULL) - log_error("'%s.clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); - SigSpec abc9_clock = assign_map(abc9_clock_wire); + if (inst_module->get_bool_attribute(ID::abc9_box)) + continue; + if (inst_module->get_bool_attribute(ID::abc9_bypass)) + continue; + + if (dff_mode && inst_module->get_bool_attribute(ID::abc9_flop)) { + continue; // do not add $__ABC9_DELAY boxes to flops + // as delays will be captured in the flop box + } - clkdomain_t key(abc9_clock); + if (!timing.count(cell->type)) + timing.setup_module(inst_module); - auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1)); - auto r2 = cell->attributes.insert(ID::abc9_mergeability); - log_assert(r2.second); - r2.first->second = r.first->second; + cells.emplace_back(cell); + } } - RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str())); - if (holes_module) { - SigMap sigmap(holes_module); + // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes + // (or bypassed white-boxes with required times) + dict<int, IdString> box_cache; + Module *delay_module = design->module(ID($__ABC9_DELAY)); + log_assert(delay_module); + for (auto cell : cells) { + auto module = cell->module; + auto inst_module = design->module(cell->type); + log_assert(inst_module); - dict<SigSpec, SigSpec> replace; - for (auto cell : holes_module->cells().to_vector()) { - if (!cell->type.in(ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), - ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1), ID($_DFF_PP0_), ID($_DFF_PP1_))) + auto &t = timing.at(cell->type).required; + for (auto &conn : cell->connections_) { + auto port_wire = inst_module->wire(conn.first); + if (!port_wire) + log_error("Port %s in cell %s (type %s) from module %s does not actually exist", + log_id(conn.first), log_id(cell), log_id(cell->type), log_id(module)); + if (!port_wire->port_input) continue; - SigBit D = cell->getPort(ID::D); - SigBit Q = cell->getPort(ID::Q); - // Emulate async control embedded inside $_DFF_* cell with mux in front of D - if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_PN0_))) - D = holes_module->MuxGate(NEW_ID, State::S0, D, cell->getPort(ID::R)); - else if (cell->type.in(ID($_DFF_NN1_), ID($_DFF_PN1_))) - D = holes_module->MuxGate(NEW_ID, State::S1, D, cell->getPort(ID::R)); - else if (cell->type.in(ID($_DFF_NP0_), ID($_DFF_PP0_))) - D = holes_module->MuxGate(NEW_ID, D, State::S0, cell->getPort(ID::R)); - else if (cell->type.in(ID($_DFF_NP1_), ID($_DFF_PP1_))) - D = holes_module->MuxGate(NEW_ID, D, State::S1, cell->getPort(ID::R)); - // Remove the $_DFF_* cell from what needs to be a combinatorial box - holes_module->remove(cell); - Wire *port; - if (GetSize(Q.wire) == 1) - port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str())); - else - port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset)); - log_assert(port); - // Prepare to replace "assign <port> = $_DFF_*.Q;" with "assign <port> = $_DFF_*.D;" - // in order to extract just the combinatorial control logic that feeds the box - // (i.e. clock enable, synchronous reset, etc.) - replace.insert(std::make_pair(Q,D)); - // Since `flatten` above would have created wires named "<cell>.Q", - // extract the pre-techmap cell name - auto pos = Q.wire->name.str().rfind("."); - log_assert(pos != std::string::npos); - IdString driver = Q.wire->name.substr(0, pos); - // And drive the signal that was previously driven by "DFF.Q" (typically - // used to implement clock-enable functionality) with the "<cell>.$abc9_currQ" - // wire (which itself is driven an by input port) we inserted above - Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str())); - log_assert(currQ); - holes_module->connect(Q, currQ); - } + if (conn.second.is_fully_const()) + continue; + + SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); + for (int i = 0; i < GetSize(conn.second); i++) { + auto d = t.at(TimingInfo::NameBit(conn.first,i), 0); + if (d == 0) + continue; - for (auto &conn : holes_module->connections_) - conn.second = replace.at(sigmap(conn.second), conn.second); +#ifndef NDEBUG + if (ys_debug(1)) { + static std::set<std::tuple<IdString,IdString,int>> seen; + if (seen.emplace(cell->type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n", + log_id(cell->type), log_id(conn.first), i, d); + } +#endif + auto r = box_cache.insert(d); + if (r.second) { + r.first->second = delay_module->derive(design, {{ID::DELAY, d}}); + log_assert(r.first->second.begins_with("$paramod$__ABC9_DELAY\\DELAY=")); + } + auto box = module->addCell(NEW_ID, r.first->second); + box->setPort(ID::I, conn.second[i]); + box->setPort(ID::O, O[i]); + conn.second[i] = O[i]; + } + } } } @@ -208,17 +674,17 @@ void prep_xaiger(RTLIL::Module *module, bool dff) dict<IdString, std::vector<IdString>> box_ports; for (auto cell : module->cells()) { - if (cell->type == ID($__ABC9_FF_)) + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) continue; if (cell->has_keep_attr()) continue; - auto inst_module = module->design->module(cell->type); + auto inst_module = design->module(cell->type); bool abc9_flop = inst_module && inst_module->get_bool_attribute(ID::abc9_flop); if (abc9_flop && !dff) continue; - if ((inst_module && inst_module->get_bool_attribute(ID::abc9_box)) || abc9_flop) { + if (inst_module && inst_module->get_bool_attribute(ID::abc9_box)) { auto r = box_ports.insert(cell->type); if (r.second) { // Make carry in the last PI, and carry out the last PO @@ -287,9 +753,13 @@ void prep_xaiger(RTLIL::Module *module, bool dff) log_assert(no_loops); - RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str())); + auto r = saved_designs.emplace("$abc9_holes", nullptr); + if (r.second) + r.first->second = new Design; + RTLIL::Design *holes_design = r.first->second; + log_assert(holes_design); + RTLIL::Module *holes_module = holes_design->addModule(module->name); log_assert(holes_module); - holes_module->set_bool_attribute(ID::abc9_holes); dict<IdString, Cell*> cell_cache; TimingInfo timing; @@ -300,22 +770,20 @@ void prep_xaiger(RTLIL::Module *module, bool dff) log_assert(cell); RTLIL::Module* box_module = design->module(cell->type); - if (!box_module || (!box_module->get_bool_attribute(ID::abc9_box) && !box_module->get_bool_attribute(ID::abc9_flop))) + if (!box_module) + continue; + if (!box_module->get_bool_attribute(ID::abc9_box)) continue; + log_assert(cell->parameters.empty()); + log_assert(box_module->get_blackbox_attribute()); cell->attributes[ID::abc9_box_seq] = box_count++; - IdString derived_type = box_module->derive(design, cell->parameters); - box_module = design->module(derived_type); - - auto r = cell_cache.insert(derived_type); + auto r = cell_cache.insert(cell->type); auto &holes_cell = r.first->second; if (r.second) { - if (box_module->has_processes()) - Pass::call_on_module(design, box_module, "proc"); - if (box_module->get_bool_attribute(ID::whitebox)) { - holes_cell = holes_module->addCell(cell->name, derived_type); + holes_cell = holes_module->addCell(cell->name, cell->type); if (box_module->has_processes()) Pass::call_on_module(design, box_module, "proc"); @@ -340,22 +808,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) } } else if (w->port_output) - conn = holes_module->addWire(stringf("%s.%s", derived_type.c_str(), log_id(port_name)), GetSize(w)); - } - - // For flops only, create an extra 1-bit input that drives a new wire - // called "<cell>.abc9_ff.Q" that is used below - if (box_module->get_bool_attribute(ID::abc9_flop)) { - box_inputs++; - Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs)); - if (!holes_wire) { - holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs)); - holes_wire->port_input = true; - holes_wire->port_id = port_id++; - holes_module->ports.push_back(holes_wire->name); - } - Wire *Q = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str())); - holes_module->connect(Q, holes_wire); + conn = holes_module->addWire(stringf("%s.%s", cell->type.c_str(), log_id(port_name)), GetSize(w)); } } else // box_module is a blackbox @@ -379,90 +832,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff) } } -void prep_delays(RTLIL::Design *design, bool dff_mode) -{ - TimingInfo timing; - - // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes - // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations - pool<Module*> flops; - std::vector<Cell*> cells; - for (auto module : design->selected_modules()) { - if (module->processes.size() > 0) { - log("Skipping module %s as it contains processes.\n", log_id(module)); - continue; - } - - for (auto cell : module->cells()) { - if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY))) - continue; - - RTLIL::Module* inst_module = module->design->module(cell->type); - if (!inst_module) - continue; - if (!inst_module->get_blackbox_attribute()) - continue; - if (inst_module->attributes.count(ID::abc9_box)) - continue; - IdString derived_type = inst_module->derive(design, cell->parameters); - inst_module = design->module(derived_type); - log_assert(inst_module); - - if (dff_mode && inst_module->get_bool_attribute(ID::abc9_flop)) { - flops.insert(inst_module); - continue; // do not add $__ABC9_DELAY boxes to flops - // as delays will be captured in the flop box - } - - if (!timing.count(derived_type)) - timing.setup_module(inst_module); - - cells.emplace_back(cell); - } - } - - // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes - // with required times - for (auto cell : cells) { - auto module = cell->module; - RTLIL::Module* inst_module = module->design->module(cell->type); - log_assert(inst_module); - IdString derived_type = inst_module->derive(design, cell->parameters); - inst_module = design->module(derived_type); - log_assert(inst_module); - - auto &t = timing.at(derived_type).required; - for (auto &conn : cell->connections_) { - auto port_wire = inst_module->wire(conn.first); - if (!port_wire) - log_error("Port %s in cell %s (type %s) of module %s does not actually exist", - log_id(conn.first), log_id(cell->name), log_id(cell->type), log_id(module->name)); - if (!port_wire->port_input) - continue; - - SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); - for (int i = 0; i < GetSize(conn.second); i++) { - auto d = t.at(TimingInfo::NameBit(conn.first,i), 0); - if (d == 0) - continue; - -#ifndef NDEBUG - if (ys_debug(1)) { - static std::set<std::tuple<IdString,IdString,int>> seen; - if (seen.emplace(derived_type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n", - log_id(cell->type), log_id(conn.first), i, d); - } -#endif - auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); - box->setPort(ID::I, conn.second[i]); - box->setPort(ID::O, O[i]); - box->setParam(ID::DELAY, d); - conn.second[i] = O[i]; - } - } - } -} - void prep_lut(RTLIL::Design *design, int maxlut) { TimingInfo timing; @@ -540,7 +909,7 @@ void write_lut(RTLIL::Module *module, const std::string &dst) { ofs.close(); } -void prep_box(RTLIL::Design *design, bool dff_mode) +void prep_box(RTLIL::Design *design) { TimingInfo timing; @@ -555,165 +924,162 @@ void prep_box(RTLIL::Design *design, bool dff_mode) dict<IdString,std::vector<IdString>> box_ports; for (auto module : design->modules()) { - auto abc9_flop = module->get_bool_attribute(ID::abc9_flop); - if (abc9_flop) { - auto r = module->attributes.insert(ID::abc9_box_id); - if (!r.second) - continue; - r.first->second = abc9_box_id++; - - if (dff_mode) { - int num_inputs = 0, num_outputs = 0; - for (auto port_name : module->ports) { - auto wire = module->wire(port_name); - log_assert(GetSize(wire) == 1); - if (wire->port_input) num_inputs++; - if (wire->port_output) num_outputs++; - } - log_assert(num_outputs == 1); + auto it = module->attributes.find(ID::abc9_box); + if (it == module->attributes.end()) + continue; + bool box = it->second.as_bool(); + module->attributes.erase(it); + if (!box) + continue; - ss << log_id(module) << " " << r.first->second.as_int(); - ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0"); - ss << " " << num_inputs+1 << " " << num_outputs << std::endl; + auto r = module->attributes.insert(ID::abc9_box_id); + if (!r.second) + continue; + r.first->second = abc9_box_id++; + + if (module->get_bool_attribute(ID::abc9_flop)) { + int num_inputs = 0, num_outputs = 0; + for (auto port_name : module->ports) { + auto wire = module->wire(port_name); + log_assert(GetSize(wire) == 1); + if (wire->port_input) num_inputs++; + if (wire->port_output) num_outputs++; + } + log_assert(num_outputs == 1); + + ss << log_id(module) << " " << r.first->second.as_int(); + log_assert(module->get_bool_attribute(ID::whitebox)); + ss << " " << "1"; + ss << " " << num_inputs << " " << num_outputs << std::endl; + + ss << "#"; + bool first = true; + for (auto port_name : module->ports) { + auto wire = module->wire(port_name); + if (!wire->port_input) + continue; + if (first) + first = false; + else + ss << " "; + ss << log_id(wire); + } + ss << std::endl; - ss << "#"; - bool first = true; - for (auto port_name : module->ports) { - auto wire = module->wire(port_name); - if (!wire->port_input) - continue; - if (first) - first = false; - else - ss << " "; - ss << log_id(wire); - } - ss << " abc9_ff.Q" << std::endl; + auto &t = timing.setup_module(module).required; + if (t.empty()) + log_error("Module '%s' with (* abc9_flop *) has no clk-to-q timing (and thus no connectivity) information.\n", log_id(module)); - auto &t = timing.setup_module(module).required; - first = true; - for (auto port_name : module->ports) { - auto wire = module->wire(port_name); - if (!wire->port_input) - continue; - if (first) - first = false; - else - ss << " "; - log_assert(GetSize(wire) == 1); - auto it = t.find(TimingInfo::NameBit(port_name,0)); - if (it == t.end()) - // Assume that no setup time means zero - ss << 0; - else { - ss << it->second; + first = true; + for (auto port_name : module->ports) { + auto wire = module->wire(port_name); + if (!wire->port_input) + continue; + if (first) + first = false; + else + ss << " "; + log_assert(GetSize(wire) == 1); + auto it = t.find(TimingInfo::NameBit(port_name,0)); + if (it == t.end()) + // Assume no connectivity if no setup time + ss << "-"; + else { + ss << it->second; #ifndef NDEBUG - if (ys_debug(1)) { - static std::set<std::pair<IdString,IdString>> seen; - if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module), - log_id(port_name), it->second); - } -#endif + if (ys_debug(1)) { + static std::set<std::pair<IdString,IdString>> seen; + if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module), + log_id(port_name), it->second); } - +#endif } - // Last input is 'abc9_ff.Q' - ss << " 0" << std::endl << std::endl; - continue; } + ss << " # $_DFF_[NP]_.D" << std::endl; + ss << std::endl; } else { - if (!module->attributes.erase(ID::abc9_box)) - continue; - - auto r = module->attributes.insert(ID::abc9_box_id); - if (!r.second) - continue; - r.first->second = abc9_box_id++; - } + auto r2 = box_ports.insert(module->name); + if (r2.second) { + // Make carry in the last PI, and carry out the last PO + // since ABC requires it this way + IdString carry_in, carry_out; + for (const auto &port_name : module->ports) { + auto w = module->wire(port_name); + log_assert(w); + if (w->get_bool_attribute(ID::abc9_carry)) { + log_assert(w->port_input != w->port_output); + if (w->port_input) + carry_in = port_name; + else if (w->port_output) + carry_out = port_name; + } + else + r2.first->second.push_back(port_name); + } - auto r = box_ports.insert(module->name); - if (r.second) { - // Make carry in the last PI, and carry out the last PO - // since ABC requires it this way - IdString carry_in, carry_out; - for (const auto &port_name : module->ports) { - auto w = module->wire(port_name); - log_assert(w); - if (w->get_bool_attribute(ID::abc9_carry)) { - log_assert(w->port_input != w->port_output); - if (w->port_input) - carry_in = port_name; - else if (w->port_output) - carry_out = port_name; + if (carry_in != IdString()) { + r2.first->second.push_back(carry_in); + r2.first->second.push_back(carry_out); } - else - r.first->second.push_back(port_name); } - if (carry_in != IdString()) { - r.first->second.push_back(carry_in); - r.first->second.push_back(carry_out); + std::vector<SigBit> inputs, outputs; + for (auto port_name : r2.first->second) { + auto wire = module->wire(port_name); + if (wire->port_input) + for (int i = 0; i < GetSize(wire); i++) + inputs.emplace_back(wire, i); + if (wire->port_output) + for (int i = 0; i < GetSize(wire); i++) + outputs.emplace_back(wire, i); } - } - - std::vector<SigBit> inputs; - std::vector<SigBit> outputs; - for (auto port_name : r.first->second) { - auto wire = module->wire(port_name); - if (wire->port_input) - for (int i = 0; i < GetSize(wire); i++) - inputs.emplace_back(wire, i); - if (wire->port_output) - for (int i = 0; i < GetSize(wire); i++) - outputs.emplace_back(wire, i); - } - - ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int(); - ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0"); - ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl; - - bool first = true; - ss << "#"; - for (const auto &i : inputs) { - if (first) - first = false; - else - ss << " "; - if (GetSize(i.wire) == 1) - ss << log_id(i.wire); - else - ss << log_id(i.wire) << "[" << i.offset << "]"; - } - ss << std::endl; - auto &t = timing.setup_module(module).comb; - if (!abc9_flop && t.empty()) - log_warning("(* abc9_box *) module '%s' has no timing (and thus no connectivity) information.\n", log_id(module)); + ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int(); + ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0"); + ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl; - for (const auto &o : outputs) { - first = true; + bool first = true; + ss << "#"; for (const auto &i : inputs) { if (first) first = false; else ss << " "; - auto jt = t.find(TimingInfo::BitBit(i,o)); - if (jt == t.end()) - ss << "-"; + if (GetSize(i.wire) == 1) + ss << log_id(i.wire); else - ss << jt->second; + ss << log_id(i.wire) << "[" << i.offset << "]"; } - ss << " # "; - if (GetSize(o.wire) == 1) - ss << log_id(o.wire); - else - ss << log_id(o.wire) << "[" << o.offset << "]"; ss << std::endl; + auto &t = timing.setup_module(module); + if (t.comb.empty()) + log_error("Module '%s' with (* abc9_box *) has no timing (and thus no connectivity) information.\n", log_id(module)); + + for (const auto &o : outputs) { + first = true; + for (const auto &i : inputs) { + if (first) + first = false; + else + ss << " "; + auto jt = t.comb.find(TimingInfo::BitBit(i,o)); + if (jt == t.comb.end()) + ss << "-"; + else + ss << jt->second; + } + ss << " # "; + if (GetSize(o.wire) == 1) + ss << log_id(o.wire); + else + ss << log_id(o.wire) << "[" << o.offset << "]"; + ss << std::endl; + } + ss << std::endl; } - ss << std::endl; } // ABC expects at least one box @@ -730,7 +1096,7 @@ void write_box(RTLIL::Module *module, const std::string &dst) { ofs.close(); } -void reintegrate(RTLIL::Module *module) +void reintegrate(RTLIL::Module *module, bool dff_mode) { auto design = module->design; log_assert(design); @@ -744,6 +1110,8 @@ void reintegrate(RTLIL::Module *module) for (auto w : mapped_mod->wires()) { auto nw = module->addWire(remap_name(w->name), GetSize(w)); nw->start_offset = w->start_offset; + // Remove all (* init *) since they only existon $_DFF_[NP]_ + w->attributes.erase(ID::init); } dict<IdString,std::vector<IdString>> box_ports; @@ -783,7 +1151,14 @@ void reintegrate(RTLIL::Module *module) for (auto cell : module->cells().to_vector()) { if (cell->has_keep_attr()) continue; - if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) + + // Short out $_DFF_[NP]_ cells since the flop box already has + // all the information we need to reconstruct cell + if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_)) && !cell->get_bool_attribute(ID::abc9_keep)) { + module->connect(cell->getPort(ID::Q), cell->getPort(ID::D)); + module->remove(cell); + } + else if (cell->type.in(ID($_AND_), ID($_NOT_))) module->remove(cell); else if (cell->attributes.erase(ID::abc9_box_seq)) boxes.emplace_back(cell); @@ -797,6 +1172,18 @@ void reintegrate(RTLIL::Module *module) std::map<IdString, int> cell_stats; for (auto mapped_cell : mapped_mod->cells()) { + // Short out $_FF_ cells since the flop box already has + // all the information we need to reconstruct cell + if (dff_mode && mapped_cell->type == ID($_FF_)) { + SigBit D = mapped_cell->getPort(ID::D); + SigBit Q = mapped_cell->getPort(ID::Q); + if (D.wire) + D.wire = module->wires_.at(remap_name(D.wire->name)); + Q.wire = module->wires_.at(remap_name(Q.wire->name)); + module->connect(Q, D); + continue; + } + // TODO: Speed up toposort -- we care about NOT ordering only toposort.node(mapped_cell->name); @@ -846,7 +1233,7 @@ void reintegrate(RTLIL::Module *module) continue; } - if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) { + if (mapped_cell->type == ID($lut)) { RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); cell->parameters = mapped_cell->parameters; cell->attributes = mapped_cell->attributes; @@ -881,7 +1268,7 @@ void reintegrate(RTLIL::Module *module) if (!existing_cell) log_error("Cannot find existing box cell with name '%s' in original design.\n", log_id(mapped_cell)); - if (existing_cell->type == ID($__ABC9_DELAY)) { + if (existing_cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")) { SigBit I = mapped_cell->getPort(ID(i)); SigBit O = mapped_cell->getPort(ID(o)); if (I.wire) @@ -893,10 +1280,8 @@ void reintegrate(RTLIL::Module *module) } RTLIL::Module* box_module = design->module(existing_cell->type); - IdString derived_type = box_module->derive(design, existing_cell->parameters); - RTLIL::Module* derived_module = design->module(derived_type); - log_assert(derived_module); - log_assert(mapped_cell->type == stringf("$__boxid%d", derived_module->attributes.at(ID::abc9_box_id).as_int())); + log_assert(existing_cell->parameters.empty()); + log_assert(mapped_cell->type == stringf("$__boxid%d", box_module->attributes.at(ID::abc9_box_id).as_int())); mapped_cell->type = existing_cell->type; RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); @@ -913,7 +1298,7 @@ void reintegrate(RTLIL::Module *module) SigSpec outputs = std::move(jt->second); mapped_cell->connections_.erase(jt); - auto abc9_flop = box_module->attributes.count(ID::abc9_flop); + auto abc9_flop = box_module->get_bool_attribute(ID::abc9_flop); if (!abc9_flop) { for (const auto &i : inputs) bit_users[i].insert(mapped_cell->name); @@ -924,7 +1309,7 @@ void reintegrate(RTLIL::Module *module) } int input_count = 0, output_count = 0; - for (const auto &port_name : box_ports.at(derived_type)) { + for (const auto &port_name : box_ports.at(existing_cell->type)) { RTLIL::Wire *w = box_module->wire(port_name); log_assert(w); @@ -988,7 +1373,7 @@ void reintegrate(RTLIL::Module *module) RTLIL::Wire *mapped_wire = mapped_mod->wire(port); RTLIL::Wire *wire = module->wire(port); log_assert(wire); - wire->attributes.erase(ID::abc9_scc); + wire->attributes.erase(ID::abc9_keep); RTLIL::Wire *remap_wire = module->wire(remap_name(port)); RTLIL::SigSpec signal(wire, remap_wire->start_offset-wire->start_offset, GetSize(remap_wire)); @@ -1116,6 +1501,37 @@ struct Abc9OpsPass : public Pass { log(" check that the design is valid, e.g. (* abc9_box_id *) values are unique,\n"); log(" (* abc9_carry *) is only given for one input/output port, etc.\n"); log("\n"); + log(" -prep_hier\n"); + log(" derive all used (* abc9_box *) or (* abc9_flop *) (if -dff option)\n"); + log(" whitebox modules. with (* abc9_flop *) modules, only those containing\n"); + log(" $dff/$_DFF_[NP]_ cells with zero initial state -- due to an ABC limitation\n"); + log(" -- will be derived.\n"); + log("\n"); + log(" -prep_bypass\n"); + log(" create techmap rules in the '$abc9_map' and '$abc9_unmap' designs for\n"); + log(" bypassing sequential (* abc9_box *) modules using a combinatorial box\n"); + log(" (named *_$abc9_byp). bypassing is necessary if sequential elements (e.g.\n"); + log(" $dff, $mem, etc.) are discovered inside so that any combinatorial paths\n"); + log(" will be correctly captured. this bypass box will only contain ports that\n"); + log(" are referenced by a simple path declaration ($specify2 cell) inside a\n"); + log(" specify block.\n"); + log("\n"); + log(" -prep_dff\n"); + log(" select all (* abc9_flop *) modules instantiated in the design and store\n"); + log(" in the named selection '$abc9_flops'.\n"); + log("\n"); + log(" -prep_dff_submod\n"); + log(" within (* abc9_flop *) modules, rewrite all edge-sensitive path\n"); + log(" declarations and $setup() timing checks ($specify3 and $specrule cells)\n"); + log(" that share a 'DST' port with the $_DFF_[NP]_.Q port from this 'Q' port to\n"); + log(" the DFF's 'D' port. this is to prepare such specify cells to be moved\n"); + log(" into the flop box.\n"); + log("\n"); + log(" -prep_dff_unmap\n"); + log(" populate the '$abc9_unmap' design with techmap rules for mapping *_$abc9_flop\n"); + log(" cells back into their derived cell types (where the rules created by\n"); + log(" -prep_hier will then map back to the original cell with parameters).\n"); + log("\n"); log(" -prep_delays\n"); log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n"); log(" certain required times.\n"); @@ -1128,18 +1544,13 @@ struct Abc9OpsPass : public Pass { log("\n"); log(" -prep_xaiger\n"); log(" prepare the design for XAIGER output. this includes computing the\n"); - log(" topological ordering of ABC9 boxes, as well as preparing the\n"); - log(" '<module-name>$holes' module that contains the logic behaviour of ABC9\n"); - log(" whiteboxes.\n"); + log(" topological ordering of ABC9 boxes, as well as preparing the '$abc9_holes'\n"); + log(" design that contains the logic behaviour of ABC9 whiteboxes.\n"); log("\n"); log(" -dff\n"); log(" consider flop cells (those instantiating modules marked with (* abc9_flop *))\n"); log(" during -prep_{delays,xaiger,box}.\n"); log("\n"); - log(" -prep_dff\n"); - log(" compute the clock domain and initial value of each flop in the design.\n"); - log(" process the '$holes' module to support clock-enable functionality.\n"); - log("\n"); log(" -prep_lut <maxlut>\n"); log(" pre-compute the lut library by analysing all modules marked with\n"); log(" (* abc9_lut=<area> *).\n"); @@ -1167,7 +1578,9 @@ struct Abc9OpsPass : public Pass { bool check_mode = false; bool prep_delays_mode = false; bool mark_scc_mode = false; - bool prep_dff_mode = false; + bool prep_hier_mode = false; + bool prep_bypass_mode = false; + bool prep_dff_mode = false, prep_dff_submod_mode = false, prep_dff_unmap_mode = false; bool prep_xaiger_mode = false; bool prep_lut_mode = false; bool prep_box_mode = false; @@ -1177,53 +1590,81 @@ struct Abc9OpsPass : public Pass { int maxlut = 0; std::string write_box_dst; + bool valid = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg == "-check") { check_mode = true; + valid = true; continue; } if (arg == "-mark_scc") { mark_scc_mode = true; + valid = true; + continue; + } + if (arg == "-prep_hier") { + prep_hier_mode = true; + valid = true; + continue; + } + if (arg == "-prep_bypass") { + prep_bypass_mode = true; + valid = true; continue; } if (arg == "-prep_dff") { prep_dff_mode = true; + valid = true; + continue; + } + if (arg == "-prep_dff_submod") { + prep_dff_submod_mode = true; + valid = true; + continue; + } + if (arg == "-prep_dff_unmap") { + prep_dff_unmap_mode = true; + valid = true; continue; } if (arg == "-prep_xaiger") { prep_xaiger_mode = true; + valid = true; continue; } if (arg == "-prep_delays") { prep_delays_mode = true; + valid = true; continue; } if (arg == "-prep_lut" && argidx+1 < args.size()) { prep_lut_mode = true; maxlut = atoi(args[++argidx].c_str()); - continue; - } - if (arg == "-maxlut" && argidx+1 < args.size()) { + valid = true; continue; } if (arg == "-write_lut" && argidx+1 < args.size()) { write_lut_dst = args[++argidx]; rewrite_filename(write_lut_dst); + valid = true; continue; } if (arg == "-prep_box") { prep_box_mode = true; + valid = true; continue; } if (arg == "-write_box" && argidx+1 < args.size()) { write_box_dst = args[++argidx]; rewrite_filename(write_box_dst); + valid = true; continue; } if (arg == "-reintegrate") { reintegrate_mode = true; + valid = true; continue; } if (arg == "-dff") { @@ -1234,25 +1675,32 @@ struct Abc9OpsPass : public Pass { } extra_args(args, argidx, design); - if (!(check_mode || mark_scc_mode || prep_delays_mode || prep_xaiger_mode || prep_dff_mode || prep_lut_mode || prep_box_mode || !write_lut_dst.empty() || !write_box_dst.empty() || reintegrate_mode)) - log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff,lut,box}, -write_{lut,box}, -reintegrate must be specified.\n"); + if (!valid) + log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate must be specified.\n"); - if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !prep_box_mode) - log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger,box}.\n"); + if (dff_mode && !check_mode && !prep_hier_mode && !prep_delays_mode && !prep_xaiger_mode && !reintegrate_mode) + log_cmd_error("'-dff' option is only relevant for -prep_{hier,delay,xaiger} or -reintegrate.\n"); if (check_mode) - check(design); + check(design, dff_mode); + if (prep_hier_mode) + prep_hier(design, dff_mode); + if (prep_bypass_mode) + prep_bypass(design); + if (prep_dff_mode) + prep_dff(design); + if (prep_dff_submod_mode) + prep_dff_submod(design); + if (prep_dff_unmap_mode) + prep_dff_unmap(design); if (prep_delays_mode) prep_delays(design, dff_mode); if (prep_lut_mode) prep_lut(design, maxlut); if (prep_box_mode) - prep_box(design, dff_mode); + prep_box(design); for (auto mod : design->selected_modules()) { - if (mod->get_bool_attribute(ID::abc9_holes)) - continue; - if (mod->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; @@ -1267,12 +1715,10 @@ struct Abc9OpsPass : public Pass { write_box(mod, write_box_dst); if (mark_scc_mode) mark_scc(mod); - if (prep_dff_mode) - prep_dff(mod); if (prep_xaiger_mode) prep_xaiger(mod, dff_mode); if (reintegrate_mode) - reintegrate(mod); + reintegrate(mod, dff_mode); } } } Abc9OpsPass; diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc index 42e8a61ea..19f21493d 100644 --- a/passes/tests/test_autotb.cc +++ b/passes/tests/test_autotb.cc @@ -81,6 +81,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s f << stringf("integer i;\n"); f << stringf("integer file;\n\n"); + f << stringf("reg [1023:0] filename;\n\n"); f << stringf("reg [31:0] xorshift128_x = 123456789;\n"); f << stringf("reg [31:0] xorshift128_y = 362436069;\n"); @@ -305,9 +306,15 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s } f << stringf("initial begin\n"); - f << stringf("\t// $dumpfile(\"testbench.vcd\");\n"); - f << stringf("\t// $dumpvars(0, testbench);\n"); - f << stringf("\tfile = $fopen(`outfile);\n"); + f << stringf("\tif ($value$plusargs(\"VCD=%%s\", filename)) begin\n"); + f << stringf("\t\t$dumpfile(filename);\n"); + f << stringf("\t\t$dumpvars(0, testbench);\n"); + f << stringf("\tend\n"); + f << stringf("\tif ($value$plusargs(\"OUT=%%s\", filename)) begin\n"); + f << stringf("\t\tfile = $fopen(filename);\n"); + f << stringf("\tend else begin\n"); + f << stringf("\t\tfile = $fopen(`outfile);\n"); + f << stringf("\tend\n"); for (auto module : design->modules()) if (!module->get_bool_attribute(ID::gentb_skip)) f << stringf("\t%s;\n", idy(module->name.str(), "test").c_str()); diff --git a/techlibs/achronix/speedster22i/cells_arith.v b/techlibs/achronix/speedster22i/cells_arith.v index e2194cbd7..8529706a7 100644 --- a/techlibs/achronix/speedster22i/cells_arith.v +++ b/techlibs/achronix/speedster22i/cells_arith.v @@ -26,8 +26,11 @@ module _80_altera_max10_alu (A, B, CI, BI, X, Y, CO); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] X, Y; input CI, BI; @@ -36,11 +39,14 @@ module _80_altera_max10_alu (A, B, CI, BI, X, Y, CO); wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; + (* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; //wire [Y_WIDTH:0] C = {CO, CI}; wire [Y_WIDTH+1:0] COx; diff --git a/techlibs/achronix/speedster22i/cells_map.v b/techlibs/achronix/speedster22i/cells_map.v index 9f647cbef..a19e53f49 100644 --- a/techlibs/achronix/speedster22i/cells_map.v +++ b/techlibs/achronix/speedster22i/cells_map.v @@ -38,6 +38,7 @@ endmodule module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; generate diff --git a/techlibs/anlogic/arith_map.v b/techlibs/anlogic/arith_map.v index 1186543da..23e190bcb 100644 --- a/techlibs/anlogic/arith_map.v +++ b/techlibs/anlogic/arith_map.v @@ -26,24 +26,33 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] X, Y; input CI, BI; + (* force_downto *) output [Y_WIDTH-1:0] CO; wire CIx; + (* force_downto *) wire [Y_WIDTH-1:0] COx; wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; + (* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + (* force_downto *) wire [Y_WIDTH-1:0] C = { COx, CIx }; wire dummy; diff --git a/techlibs/anlogic/cells_map.v b/techlibs/anlogic/cells_map.v index 8ac087d9d..0bcea9856 100644 --- a/techlibs/anlogic/cells_map.v +++ b/techlibs/anlogic/cells_map.v @@ -32,6 +32,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc index 7b1e4b430..607e772a2 100644 --- a/techlibs/common/Makefile.inc +++ b/techlibs/common/Makefile.inc @@ -30,4 +30,6 @@ $(eval $(call add_share_file,share,techlibs/common/cmp2lut.v)) $(eval $(call add_share_file,share,techlibs/common/cells.lib)) $(eval $(call add_share_file,share,techlibs/common/mul2dsp.v)) $(eval $(call add_share_file,share,techlibs/common/abc9_model.v)) +$(eval $(call add_share_file,share,techlibs/common/abc9_map.v)) +$(eval $(call add_share_file,share,techlibs/common/abc9_unmap.v)) $(eval $(call add_share_file,share,techlibs/common/cmp2lcu.v)) diff --git a/techlibs/common/abc9_map.v b/techlibs/common/abc9_map.v new file mode 100644 index 000000000..6ed90b5f5 --- /dev/null +++ b/techlibs/common/abc9_map.v @@ -0,0 +1,27 @@ +`ifdef DFF +(* techmap_celltype = "$_DFF_N_ $_DFF_P_" *) +module $_DFF_x_(input C, D, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + parameter _TECHMAP_CELLTYPE_ = ""; + wire D_; + generate if (_TECHMAP_CELLTYPE_ == "$_DFF_N_") begin + if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin + $__DFF_N__$abc9_flop _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_)); + $_DFF_N_ ff (.C(C), .D(D_), .Q(Q)); + end + else + (* abc9_keep *) $_DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); + end + else if (_TECHMAP_CELLTYPE_ == "$_DFF_P_") begin + if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin + $__DFF_P__$abc9_flop _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_)); + $_DFF_P_ ff (.C(C), .D(D_), .Q(Q)); + end + else + (* abc9_keep *) $_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); + end + else if (_TECHMAP_CELLTYPE_ != "") + $error("Unrecognised _TECHMAP_CELLTYPE_"); + endgenerate +endmodule +`endif diff --git a/techlibs/common/abc9_model.v b/techlibs/common/abc9_model.v index c0c5dc2fd..4fee60f75 100644 --- a/techlibs/common/abc9_model.v +++ b/techlibs/common/abc9_model.v @@ -1,10 +1,25 @@ -module \$__ABC9_FF_ (input D, output Q); -endmodule - (* abc9_box *) -module \$__ABC9_DELAY (input I, output O); +module $__ABC9_DELAY (input I, output O); parameter DELAY = 0; specify (I => O) = DELAY; endspecify endmodule + +(* abc9_flop, abc9_box, lib_whitebox *) +module $__DFF_N__$abc9_flop (input C, D, Q, output n1); + assign n1 = D; + specify + $setup(D, posedge C, 0); + (posedge C => (n1:D)) = 0; + endspecify +endmodule + +(* abc9_flop, abc9_box, lib_whitebox *) +module $__DFF_P__$abc9_flop (input C, D, Q, output n1); + assign n1 = D; + specify + $setup(D, posedge C, 0); + (posedge C => (n1:D)) = 0; + endspecify +endmodule diff --git a/techlibs/common/abc9_unmap.v b/techlibs/common/abc9_unmap.v new file mode 100644 index 000000000..bcbe91477 --- /dev/null +++ b/techlibs/common/abc9_unmap.v @@ -0,0 +1,11 @@ +(* techmap_celltype = "$__DFF_N__$abc9_flop $__DFF_P__$abc9_flop" *) +module $__DFF_x__$abc9_flop (input C, D, Q, output n1); + parameter _TECHMAP_CELLTYPE_ = ""; + generate if (_TECHMAP_CELLTYPE_ == "$__DFF_N__$abc9_flop") + $_DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); + else if (_TECHMAP_CELLTYPE_ == "$__DFF_P__$abc9_flop") + $_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); + else if (_TECHMAP_CELLTYPE_ != "") + $error("Unrecognised _TECHMAP_CELLTYPE_"); + endgenerate +endmodule diff --git a/techlibs/common/adff2dff.v b/techlibs/common/adff2dff.v index 86744d415..eca0110eb 100644 --- a/techlibs/common/adff2dff.v +++ b/techlibs/common/adff2dff.v @@ -6,8 +6,11 @@ module adff2dff (CLK, ARST, D, Q); parameter ARST_VALUE = 0; input CLK, ARST; + (* force_downto *) input [WIDTH-1:0] D; + (* force_downto *) output reg [WIDTH-1:0] Q; + (* force_downto *) wire reg [WIDTH-1:0] NEXT_Q; wire [1023:0] _TECHMAP_DO_ = "proc;;"; diff --git a/techlibs/common/cmp2lcu.v b/techlibs/common/cmp2lcu.v index b6f4aeed6..a221727e7 100644 --- a/techlibs/common/cmp2lcu.v +++ b/techlibs/common/cmp2lcu.v @@ -12,8 +12,11 @@ parameter A_WIDTH = 0; parameter B_WIDTH = 0; parameter Y_WIDTH = 0; +(* force_downto *) input [A_WIDTH-1:0] A; +(* force_downto *) input [B_WIDTH-1:0] B; +(* force_downto *) output [Y_WIDTH-1:0] Y; parameter _TECHMAP_CELLTYPE_ = ""; @@ -32,7 +35,9 @@ generate else begin // Perform sign extension on A and B localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; + (* force_downto *) wire [WIDTH-1:0] AA = {{(WIDTH-A_WIDTH){A_SIGNED ? A[A_WIDTH-1] : 1'b0}}, A}; + (* force_downto *) wire [WIDTH-1:0] BB = {{(WIDTH-B_WIDTH){B_SIGNED ? B[B_WIDTH-1] : 1'b0}}, B}; // For $ge operation, start with the assumption that A and B are // equal (propagating this equality if A and B turn out to be so) @@ -54,9 +59,13 @@ parameter LCU_WIDTH = 1; parameter BUDGET = 0; parameter CI = 0; +(* force_downto *) input [AB_WIDTH-1:0] A; // A from original $gt/$ge +(* force_downto *) input [AB_WIDTH-1:0] B; // B from original $gt/$ge +(* force_downto *) input [LCU_WIDTH-1:0] P; // P of $lcu +(* force_downto *) input [LCU_WIDTH-1:0] G; // G of $lcu output Y; @@ -66,6 +75,7 @@ parameter [LCU_WIDTH-1:0] _TECHMAP_CONSTMSK_P_ = 0; generate if (AB_WIDTH == 0) begin + (* force_downto *) wire [LCU_WIDTH-1:0] CO; $lcu #(.WIDTH(LCU_WIDTH)) _TECHMAP_REPLACE_ (.P(P), .G(G), .CI(CI), .CO(CO)); assign Y = CO[LCU_WIDTH-1]; @@ -104,12 +114,18 @@ generate else begin // Propagate only if all pairs are equal // (inconclusive evidence to say A >= B) + (* force_downto *) wire [LCU_WIDTH-1:0] P_ = {P[LCU_WIDTH-1:1], P[0] & PP}; // Generate if any comparisons call for it + (* force_downto *) wire [LCU_WIDTH-1:0] G_ = {G[LCU_WIDTH-1:1], G[0] | GG}; end - $__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI)) - _TECHMAP_REPLACE_ (.A(A[AB_WIDTH-2:0]), .B(B[AB_WIDTH-2:0]), .P(P_), .G(G_), .Y(Y)); + if (AB_WIDTH == 1) + $__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI)) + _TECHMAP_REPLACE_ (.A(), .B(), .P(P_), .G(G_), .Y(Y)); + else + $__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI)) + _TECHMAP_REPLACE_ (.A(A[AB_WIDTH-2:0]), .B(B[AB_WIDTH-2:0]), .P(P_), .G(G_), .Y(Y)); end end endgenerate diff --git a/techlibs/common/cmp2lut.v b/techlibs/common/cmp2lut.v index 8ecd356cc..ec8f98e8d 100644 --- a/techlibs/common/cmp2lut.v +++ b/techlibs/common/cmp2lut.v @@ -16,8 +16,11 @@ parameter A_WIDTH = 0; parameter B_WIDTH = 0; parameter Y_WIDTH = 0; +(* force_downto *) input [A_WIDTH-1:0] A; +(* force_downto *) input [B_WIDTH-1:0] B; +(* force_downto *) output [Y_WIDTH-1:0] Y; parameter _TECHMAP_CELLTYPE_ = ""; diff --git a/techlibs/common/dff2ff.v b/techlibs/common/dff2ff.v index 2dc4d20d3..33a79ffff 100644 --- a/techlibs/common/dff2ff.v +++ b/techlibs/common/dff2ff.v @@ -4,7 +4,9 @@ module dff2ff (CLK, D, Q); parameter CLK_POLARITY = 1; input CLK; + (* force_downto *) input [WIDTH-1:0] D; + (* force_downto *) output reg [WIDTH-1:0] Q; wire [1023:0] _TECHMAP_DO_ = "proc;;"; diff --git a/techlibs/common/mul2dsp.v b/techlibs/common/mul2dsp.v index 4cabb4453..bec47d01f 100644 --- a/techlibs/common/mul2dsp.v +++ b/techlibs/common/mul2dsp.v @@ -57,8 +57,11 @@ module _80_mul (A, B, Y); parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
+ (* force_downto *)
input [A_WIDTH-1:0] A;
+ (* force_downto *)
input [B_WIDTH-1:0] B;
+ (* force_downto *)
output [Y_WIDTH-1:0] Y;
parameter _TECHMAP_CELLTYPE_ = "";
@@ -119,13 +122,19 @@ module _80_mul (A, B, Y); localparam last_A_WIDTH = A_WIDTH-n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom);
localparam last_Y_WIDTH = B_WIDTH+last_A_WIDTH;
if (A_SIGNED && B_SIGNED) begin
+ (* force_downto *)
wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
+ (* force_downto *)
wire signed [last_Y_WIDTH-1:0] last_partial;
+ (* force_downto *)
wire signed [Y_WIDTH-1:0] partial_sum [n:0];
end
else begin
+ (* force_downto *)
wire [partial_Y_WIDTH-1:0] partial [n-1:0];
+ (* force_downto *)
wire [last_Y_WIDTH-1:0] last_partial;
+ (* force_downto *)
wire [Y_WIDTH-1:0] partial_sum [n:0];
end
@@ -170,13 +179,19 @@ module _80_mul (A, B, Y); localparam last_B_WIDTH = B_WIDTH-n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom);
localparam last_Y_WIDTH = A_WIDTH+last_B_WIDTH;
if (A_SIGNED && B_SIGNED) begin
+ (* force_downto *)
wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
+ (* force_downto *)
wire signed [last_Y_WIDTH-1:0] last_partial;
+ (* force_downto *)
wire signed [Y_WIDTH-1:0] partial_sum [n:0];
end
else begin
+ (* force_downto *)
wire [partial_Y_WIDTH-1:0] partial [n-1:0];
+ (* force_downto *)
wire [last_Y_WIDTH-1:0] last_partial;
+ (* force_downto *)
wire [Y_WIDTH-1:0] partial_sum [n:0];
end
@@ -249,8 +264,11 @@ module _90_soft_mul (A, B, Y); parameter B_WIDTH = 1;
parameter Y_WIDTH = 1;
+ (* force_downto *)
input [A_WIDTH-1:0] A;
+ (* force_downto *)
input [B_WIDTH-1:0] B;
+ (* force_downto *)
output [Y_WIDTH-1:0] Y;
// Indirection necessary since mapping
diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index ecf4d5dc5..c1efc378b 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -85,8 +85,11 @@ module _90_shift_ops_shr_shl_sshl_sshr (A, B, Y); localparam shift_left = _TECHMAP_CELLTYPE_ == "$shl" || _TECHMAP_CELLTYPE_ == "$sshl"; localparam sign_extend = A_SIGNED && _TECHMAP_CELLTYPE_ == "$sshr"; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] Y; localparam WIDTH = `MAX(A_WIDTH, Y_WIDTH); @@ -96,6 +99,7 @@ module _90_shift_ops_shr_shl_sshl_sshr (A, B, Y); wire [1023:0] _TECHMAP_DO_01_ = "RECURSION; CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;"; integer i; + (* force_downto *) reg [WIDTH-1:0] buffer; reg overflow; @@ -125,8 +129,11 @@ module _90_shift_shiftx (A, B, Y); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] Y; parameter _TECHMAP_CELLTYPE_ = ""; @@ -173,6 +180,7 @@ module _90_shift_shiftx (A, B, Y); wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;"; integer i; + (* force_downto *) reg [WIDTH-1:0] buffer; reg overflow; @@ -216,9 +224,12 @@ endmodule module _90_fa (A, B, C, X, Y); parameter WIDTH = 1; + (* force_downto *) input [WIDTH-1:0] A, B, C; + (* force_downto *) output [WIDTH-1:0] X, Y; + (* force_downto *) wire [WIDTH-1:0] t1, t2, t3; assign t1 = A ^ B, t2 = A & B, t3 = C & t1; @@ -229,12 +240,15 @@ endmodule module _90_lcu (P, G, CI, CO); parameter WIDTH = 2; + (* force_downto *) input [WIDTH-1:0] P, G; input CI; + (* force_downto *) output [WIDTH-1:0] CO; integer i, j; + (* force_downto *) reg [WIDTH-1:0] p, g; wire [1023:0] _TECHMAP_DO_ = "proc; opt -fast"; @@ -278,20 +292,27 @@ module _90_alu (A, B, CI, BI, X, Y, CO); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] X, Y; input CI, BI; + (* force_downto *) output [Y_WIDTH-1:0] CO; + (* force_downto *) + wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) + wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + + (* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); - wire [Y_WIDTH-1:0] AA = A_buf; - wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; - \$lcu #(.WIDTH(Y_WIDTH)) lcu (.P(X), .G(AA & BB), .CI(CI), .CO(CO)); assign X = AA ^ BB; @@ -316,15 +337,19 @@ endmodule module \$__div_mod_u (A, B, Y, R); parameter WIDTH = 1; + (* force_downto *) input [WIDTH-1:0] A, B; + (* force_downto *) output [WIDTH-1:0] Y, R; + (* force_downto *) wire [WIDTH*WIDTH-1:0] chaindata; assign R = chaindata[WIDTH*WIDTH-1:WIDTH*(WIDTH-1)]; genvar i; generate begin for (i = 0; i < WIDTH; i=i+1) begin:stage + (* force_downto *) wire [WIDTH-1:0] stage_in; if (i == 0) begin:cp @@ -350,14 +375,19 @@ module \$__div_mod (A, B, Y, R); A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH : B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] Y, R; + (* force_downto *) wire [WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); + (* force_downto *) wire [WIDTH-1:0] A_buf_u, B_buf_u, Y_u, R_u; assign A_buf_u = A_SIGNED && A_buf[WIDTH-1] ? -A_buf : A_buf; assign B_buf_u = B_SIGNED && B_buf[WIDTH-1] ? -B_buf : B_buf; @@ -383,8 +413,11 @@ module _90_div (A, B, Y); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] Y; \$__div_mod #( @@ -408,8 +441,11 @@ module _90_mod (A, B, Y); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] Y; \$__div_mod #( @@ -438,8 +474,11 @@ module _90_pow (A, B, Y); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] Y; wire _TECHMAP_FAIL_ = 1; @@ -455,20 +494,27 @@ module _90_pmux (A, B, S, Y); parameter WIDTH = 1; parameter S_WIDTH = 1; + (* force_downto *) input [WIDTH-1:0] A; + (* force_downto *) input [WIDTH*S_WIDTH-1:0] B; + (* force_downto *) input [S_WIDTH-1:0] S; + (* force_downto *) output [WIDTH-1:0] Y; + (* force_downto *) wire [WIDTH-1:0] Y_B; genvar i, j; generate + (* force_downto *) wire [WIDTH*S_WIDTH-1:0] B_AND_S; for (i = 0; i < S_WIDTH; i = i + 1) begin:B_AND assign B_AND_S[WIDTH*(i+1)-1:WIDTH*i] = B[WIDTH*(i+1)-1:WIDTH*i] & {WIDTH{S[i]}}; end:B_AND for (i = 0; i < WIDTH; i = i + 1) begin:B_OR + (* force_downto *) wire [S_WIDTH-1:0] B_AND_BITS; for (j = 0; j < S_WIDTH; j = j + 1) begin:B_AND_BITS_COLLECT assign B_AND_BITS[j] = B_AND_S[WIDTH*j+i]; diff --git a/techlibs/coolrunner2/cells_counter_map.v b/techlibs/coolrunner2/cells_counter_map.v index b474fa522..f9c44c80f 100644 --- a/techlibs/coolrunner2/cells_counter_map.v +++ b/techlibs/coolrunner2/cells_counter_map.v @@ -3,6 +3,7 @@ module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP); input wire CE; input wire CLK; output wire OUT; + (* force_downto *) output wire[WIDTH-1:0] POUT; input wire RST; input wire UP; diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index 217151e96..9d564c78c 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -24,10 +24,6 @@ $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dsp_map.v)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_map.v)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_unmap.v)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_model.v)) - EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk .SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk diff --git a/techlibs/ecp5/abc9_map.v b/techlibs/ecp5/abc9_map.v deleted file mode 100644 index 113a35b91..000000000 --- a/techlibs/ecp5/abc9_map.v +++ /dev/null @@ -1,27 +0,0 @@ -// --------------------------------------- - -// Attach a (combinatorial) black-box onto the output -// of this LUTRAM primitive to capture its -// asynchronous read behaviour -module TRELLIS_DPR16X4 ( - (* techmap_autopurge *) input [3:0] DI, - (* techmap_autopurge *) input [3:0] WAD, - (* techmap_autopurge *) input WRE, - (* techmap_autopurge *) input WCK, - (* techmap_autopurge *) input [3:0] RAD, - output [3:0] DO -); - parameter WCKMUX = "WCK"; - parameter WREMUX = "WRE"; - parameter [63:0] INITVAL = 64'h0000000000000000; - wire [3:0] $DO; - - TRELLIS_DPR16X4 #( - .WCKMUX(WCKMUX), .WREMUX(WREMUX), .INITVAL(INITVAL) - ) _TECHMAP_REPLACE_ ( - .DI(DI), .WAD(WAD), .WRE(WRE), .WCK(WCK), - .RAD(RAD), .DO($DO) - ); - - $__ABC9_DPR16X4_COMB do (.$DO($DO), .RAD(RAD), .DO(DO)); -endmodule diff --git a/techlibs/ecp5/abc9_model.v b/techlibs/ecp5/abc9_model.v deleted file mode 100644 index b7ecd7358..000000000 --- a/techlibs/ecp5/abc9_model.v +++ /dev/null @@ -1,12 +0,0 @@ -// --------------------------------------- - -(* abc9_box *) -module \$__ABC9_DPR16X4_COMB (input [3:0] $DO, RAD, output [3:0] DO); - specify - ($DO => DO) = 0; - (RAD[0] *> DO) = 141; - (RAD[1] *> DO) = 379; - (RAD[2] *> DO) = 275; - (RAD[3] *> DO) = 379; - endspecify -endmodule diff --git a/techlibs/ecp5/abc9_unmap.v b/techlibs/ecp5/abc9_unmap.v deleted file mode 100644 index cbdffdaf1..000000000 --- a/techlibs/ecp5/abc9_unmap.v +++ /dev/null @@ -1,5 +0,0 @@ -// --------------------------------------- - -module \$__ABC9_DPR16X4_COMB (input [3:0] $DO, RAD, output [3:0] DO); - assign DO = $DO; -endmodule diff --git a/techlibs/ecp5/arith_map.v b/techlibs/ecp5/arith_map.v index 17bde0497..ffd42469c 100644 --- a/techlibs/ecp5/arith_map.v +++ b/techlibs/ecp5/arith_map.v @@ -26,15 +26,20 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] X, Y; input CI, BI; + (* force_downto *) output [Y_WIDTH-1:0] CO; wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; + (* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); @@ -48,10 +53,15 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO); localparam Y_WIDTH2 = round_up2(Y_WIDTH); + (* force_downto *) wire [Y_WIDTH2-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH2-1:0] BB = BI ? ~B_buf : B_buf; + (* force_downto *) wire [Y_WIDTH2-1:0] BX = B_buf; + (* force_downto *) wire [Y_WIDTH2-1:0] C = {CO, CI}; + (* force_downto *) wire [Y_WIDTH2-1:0] FCO, Y1; genvar i; diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v index ae124e7a3..756f05366 100644 --- a/techlibs/ecp5/cells_bb.v +++ b/techlibs/ecp5/cells_bb.v @@ -652,6 +652,10 @@ module DCUA( parameter CH1_PROTOCOL = "8B10B"; parameter CH0_CDR_MAX_RATE = "2.5"; parameter CH1_CDR_MAX_RATE = "2.5"; + parameter CH0_TXDEPRE = "DISABLED"; + parameter CH1_TXDEPRE = "DISABLED"; + parameter CH0_TXDEPOST = "DISABLED"; + parameter CH1_TXDEPOST = "DISABLED"; endmodule (* blackbox *) diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v index c031703a9..e19ac9ab9 100644 --- a/techlibs/ecp5/cells_map.v +++ b/techlibs/ecp5/cells_map.v @@ -70,6 +70,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index 12b33e925..357fd9173 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -186,6 +186,7 @@ module PFUMX (input ALUT, BLUT, C0, output Z); endmodule // --------------------------------------- +(* abc9_box, lib_whitebox *) module TRELLIS_DPR16X4 ( input [3:0] DI, input [3:0] WAD, @@ -222,10 +223,16 @@ module TRELLIS_DPR16X4 ( mem[WAD] <= DI; assign DO = mem[RAD]; + + specify + // TODO + (RAD *> DO) = 0; + endspecify endmodule // --------------------------------------- +(* abc9_box, lib_whitebox *) module DPR16X4C ( input [3:0] DI, input WCK, WRE, @@ -281,6 +288,10 @@ module DPR16X4C ( assign DO = ram[RAD]; + specify + // TODO + (RAD *> DO) = 0; + endspecify endmodule // --------------------------------------- @@ -294,6 +305,9 @@ endmodule // --------------------------------------- +`ifdef YOSYS +(* abc9_flop=(SRMODE != "ASYNC"), abc9_box=(SRMODE == "ASYNC"), lib_whitebox *) +`endif module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); parameter GSR = "ENABLED"; parameter [127:0] CEMUX = "1"; @@ -340,6 +354,38 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); Q <= DI; end endgenerate + + generate + // TODO + if (CLKMUX == "INV") + specify + $setup(DI, negedge CLK, 0); + $setup(CE, negedge CLK, 0); + $setup(LSR, negedge CLK, 0); +`ifndef YOSYS + if (SRMODE == "ASYNC" && muxlsr) (negedge CLK => (Q : srval)) = 0; +`else + if (SRMODE == "ASYNC" && muxlsr) (LSR => Q) = 0; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif + if (!muxlsr && muxce) (negedge CLK => (Q : DI)) = 0; + endspecify + else + specify + $setup(DI, posedge CLK, 0); + $setup(CE, posedge CLK, 0); + $setup(LSR, posedge CLK, 0); +`ifndef YOSYS + if (SRMODE == "ASYNC" && muxlsr) (posedge CLK => (Q : srval)) = 0; +`else + if (SRMODE == "ASYNC" && muxlsr) (LSR => Q) = 0; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif + if (!muxlsr && muxce) (posedge CLK => (Q : DI)) = 0; + endspecify + endgenerate endmodule // --------------------------------------- diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index b9b236a0c..aceb36abc 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -66,6 +66,9 @@ struct SynthEcp5Pass : public ScriptPass log(" -noflatten\n"); log(" do not flatten design before synthesis\n"); log("\n"); + log(" -dff\n"); + log(" run 'abc'/'abc9' with -dff option\n"); + log("\n"); log(" -retime\n"); log(" run 'abc' with '-dff -D 1' options\n"); log("\n"); @@ -107,7 +110,7 @@ struct SynthEcp5Pass : public ScriptPass } string top_opt, blif_file, edif_file, json_file; - bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, retime, abc2, abc9, nodsp, vpr; + bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, dff, retime, abc2, abc9, nodsp, vpr; void clear_flags() YS_OVERRIDE { @@ -122,6 +125,7 @@ struct SynthEcp5Pass : public ScriptPass nowidelut = false; asyncprld = false; flatten = true; + dff = false; retime = false; abc2 = false; vpr = false; @@ -169,6 +173,10 @@ struct SynthEcp5Pass : public ScriptPass flatten = false; continue; } + if (args[argidx] == "-dff") { + dff = true; + continue; + } if (args[argidx] == "-retime") { retime = true; continue; @@ -307,6 +315,8 @@ struct SynthEcp5Pass : public ScriptPass run("opt_clean"); if (!nodffe) run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); + if ((abc9 && dff) || help_mode) + run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "(only if -abc9 and -dff"); run(stringf("techmap -D NO_LUT %s -map +/ecp5/cells_map.v", help_mode ? "[-D ASYNC_PRLD]" : (asyncprld ? "-D ASYNC_PRLD" : ""))); run("opt_expr -undriven -mux_undef"); run("simplemap"); @@ -318,17 +328,12 @@ struct SynthEcp5Pass : public ScriptPass if (check_label("map_luts")) { - if (abc2 || help_mode) { + if (abc2 || help_mode) run("abc", " (only if -abc2)"); - } - std::string techmap_args = asyncprld ? "" : "-map +/ecp5/latches_map.v"; - if (abc9) - techmap_args += " -map +/ecp5/abc9_map.v -max_iter 1"; - if (!asyncprld || abc9) - run("techmap " + techmap_args); + if (!asyncprld || help_mode) + run("techmap -map +/ecp5/latches_map.v", "(skip if -asyncprld)"); if (abc9) { - run("read_verilog -icells -lib -specify +/abc9_model.v +/ecp5/abc9_model.v"); std::string abc9_opts; if (nowidelut) abc9_opts += " -maxlut 4"; @@ -338,26 +343,29 @@ struct SynthEcp5Pass : public ScriptPass else abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str()); if (nowidelut) - run("abc9 -maxlut 4 -W 200"); - else - run("abc9 -W 200"); - run("techmap -map +/ecp5/abc9_unmap.v"); + abc9_opts += " -maxlut 4"; + if (dff) + abc9_opts += " -dff"; + run("abc9" + abc9_opts); } else { + std::string abc_args = " -dress"; if (nowidelut) - run("abc -lut 4 -dress"); + abc_args += " -lut 4"; else - run("abc -lut 4:7 -dress"); + abc_args += " -lut 4:7"; + if (dff) + abc_args += " -dff"; + run("abc" + abc_args); } run("clean"); } if (check_label("map_cells")) { - if (vpr) - run("techmap -D NO_LUT -map +/ecp5/cells_map.v"); - else - run("techmap -map +/ecp5/cells_map.v", "(with -D NO_LUT in vpr mode)"); - + if (help_mode) + run("techmap -map +/ecp5/cells_map.v", "(skip if -vpr)"); + else if (!vpr) + run("techmap -map +/ecp5/cells_map.v"); run("opt_lut_ins -tech ecp5"); run("clean"); } diff --git a/techlibs/efinix/arith_map.v b/techlibs/efinix/arith_map.v index 178f57bc5..4dac360b9 100644 --- a/techlibs/efinix/arith_map.v +++ b/techlibs/efinix/arith_map.v @@ -26,24 +26,33 @@ module _80_efinix_alu (A, B, CI, BI, X, Y, CO); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] X, Y; input CI, BI; + (* force_downto *) output [Y_WIDTH-1:0] CO; wire CIx; + (* force_downto *) wire [Y_WIDTH-1:0] COx; wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; + (* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + (* force_downto *) wire [Y_WIDTH-1:0] C = { COx, CIx }; EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1)) @@ -76,4 +85,4 @@ module _80_efinix_alu (A, B, CI, BI, X, Y, CO); /* End implementation */ assign X = AA ^ BB; -endmodule
\ No newline at end of file +endmodule diff --git a/techlibs/efinix/cells_map.v b/techlibs/efinix/cells_map.v index 3ecec3bac..1090f8b27 100644 --- a/techlibs/efinix/cells_map.v +++ b/techlibs/efinix/cells_map.v @@ -34,6 +34,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/gowin/arith_map.v b/techlibs/gowin/arith_map.v index b6f9e8c38..42aaba870 100644 --- a/techlibs/gowin/arith_map.v +++ b/techlibs/gowin/arith_map.v @@ -26,21 +26,29 @@ module _80_gw1n_alu(A, B, CI, BI, X, Y, CO); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] X, Y; input CI, BI; + (* force_downto *) output [Y_WIDTH-1:0] CO; wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; + (* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = B_buf; + (* force_downto *) wire [Y_WIDTH-1:0] C = {CO, CI}; genvar i; diff --git a/techlibs/gowin/cells_map.v b/techlibs/gowin/cells_map.v index aee912256..b44350616 100644 --- a/techlibs/gowin/cells_map.v +++ b/techlibs/gowin/cells_map.v @@ -232,6 +232,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/greenpak4/cells_map.v b/techlibs/greenpak4/cells_map.v index 51c85183d..316be3f73 100644 --- a/techlibs/greenpak4/cells_map.v +++ b/techlibs/greenpak4/cells_map.v @@ -115,6 +115,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; @@ -150,6 +151,7 @@ module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP); input wire CE; input wire CLK; output reg OUT; + (* force_downto *) output reg[WIDTH-1:0] POUT; input wire RST; input wire UP; diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc index b9e504a9d..1a8caf9a9 100644 --- a/techlibs/ice40/Makefile.inc +++ b/techlibs/ice40/Makefile.inc @@ -23,6 +23,7 @@ techlibs/ice40/brams_init3.vh: techlibs/ice40/brams_init.mk $(eval $(call add_share_file,share/ice40,techlibs/ice40/arith_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_map.v)) +$(eval $(call add_share_file,share/ice40,techlibs/ice40/ff_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt)) diff --git a/techlibs/ice40/arith_map.v b/techlibs/ice40/arith_map.v index ed4140e44..3950e882b 100644 --- a/techlibs/ice40/arith_map.v +++ b/techlibs/ice40/arith_map.v @@ -25,21 +25,29 @@ module _80_ice40_alu (A, B, CI, BI, X, Y, CO); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] X, Y; input CI, BI; + (* force_downto *) output [Y_WIDTH-1:0] CO; wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; + (* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + (* force_downto *) wire [Y_WIDTH-1:0] C = {CO, CI}; genvar i; diff --git a/techlibs/ice40/cells_map.v b/techlibs/ice40/cells_map.v index d5362eb83..7e5c07879 100644 --- a/techlibs/ice40/cells_map.v +++ b/techlibs/ice40/cells_map.v @@ -1,37 +1,8 @@ -module \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule -module \$_DFF_P_ (input D, C, output Q); SB_DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule - -module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule -module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule - -module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule - -module \$_DFF_NN0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule - -module \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule - -module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule -module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule -module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule -module \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule - -module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule -module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule -module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule -module \$__DFFE_PP1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule - -`ifndef NO_LUT module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; @@ -59,4 +30,3 @@ module \$lut (A, Y); end endgenerate endmodule -`endif diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 6a0e3031e..ad572c877 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -245,6 +245,7 @@ endmodule // Positive Edge SiliconBlue FF Cells +(* abc9_flop, lib_whitebox *) module SB_DFF ( output `SB_DFF_REG, input C, D @@ -280,6 +281,7 @@ module SB_DFF ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFE ( output `SB_DFF_REG, input C, E, D @@ -322,6 +324,7 @@ module SB_DFFE ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFSR ( output `SB_DFF_REG, input C, R, D @@ -369,6 +372,7 @@ module SB_DFFSR ( `endif endmodule +(* abc9_box, lib_whitebox *) module SB_DFFR ( output `SB_DFF_REG, input C, R, D @@ -386,7 +390,13 @@ module SB_DFFR ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(negedge R, posedge C, 160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 599; +`else + if (R) (R => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (!R) (posedge C => (Q : D)) = 540; endspecify @@ -399,7 +409,13 @@ module SB_DFFR ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(negedge R, posedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 883; +`else + if (R) (R => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (!R) (posedge C => (Q : D)) = 796; endspecify @@ -412,13 +428,20 @@ module SB_DFFR ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(negedge R, posedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 1589; +`else + if (R) (R => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (!R) (posedge C => (Q : D)) = 1391; endspecify `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFSS ( output `SB_DFF_REG, input C, S, D @@ -466,6 +489,7 @@ module SB_DFFSS ( `endif endmodule +(* abc9_box, lib_whitebox *) module SB_DFFS ( output `SB_DFF_REG, input C, S, D @@ -483,7 +507,13 @@ module SB_DFFS ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(negedge S, posedge C, 160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 599; +`else + if (S) (S => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (!S) (posedge C => (Q : D)) = 540; endspecify @@ -496,7 +526,13 @@ module SB_DFFS ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(negedge S, posedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 883; +`else + if (S) (S => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (!S) (posedge C => (Q : D)) = 796; endspecify @@ -509,13 +545,20 @@ module SB_DFFS ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(negedge S, posedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 1589; +`else + if (S) (S => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (!S) (posedge C => (Q : D)) = 1391; endspecify `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFESR ( output `SB_DFF_REG, input C, E, R, D @@ -571,6 +614,7 @@ module SB_DFFESR ( `endif endmodule +(* abc9_box, lib_whitebox *) module SB_DFFER ( output `SB_DFF_REG, input C, E, R, D @@ -590,7 +634,13 @@ module SB_DFFER ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(negedge R, posedge C, 160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 599; +`else + if (R) (R => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (E && !R) (posedge C => (Q : D)) = 540; endspecify @@ -605,7 +655,13 @@ module SB_DFFER ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(negedge R, posedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 883; +`else + if (R) (R => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (E && !R) (posedge C => (Q : D)) = 796; endspecify @@ -620,13 +676,20 @@ module SB_DFFER ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(negedge R, posedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 1589; +`else + if (R) (R => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (E && !R) (posedge C => (Q : D)) = 1391; endspecify `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFESS ( output `SB_DFF_REG, input C, E, S, D @@ -682,6 +745,7 @@ module SB_DFFESS ( `endif endmodule +(* abc9_box, lib_whitebox *) module SB_DFFES ( output `SB_DFF_REG, input C, E, S, D @@ -701,7 +765,13 @@ module SB_DFFES ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(posedge S, posedge C, 160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 599; +`else + if (S) (S => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (E && !S) (posedge C => (Q : D)) = 540; endspecify @@ -716,7 +786,13 @@ module SB_DFFES ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(posedge S, posedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 883; +`else + if (S) (S => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (E && !S) (posedge C => (Q : D)) = 796; endspecify @@ -731,7 +807,13 @@ module SB_DFFES ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(posedge S, posedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 1589; +`else + if (S) (S => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (E && !S) (posedge C => (Q : D)) = 1391; endspecify @@ -740,6 +822,7 @@ endmodule // Negative Edge SiliconBlue FF Cells +(* abc9_flop, lib_whitebox *) module SB_DFFN ( output `SB_DFF_REG, input C, D @@ -775,6 +858,7 @@ module SB_DFFN ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFNE ( output `SB_DFF_REG, input C, E, D @@ -817,6 +901,7 @@ module SB_DFFNE ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFNSR ( output `SB_DFF_REG, input C, R, D @@ -864,6 +949,7 @@ module SB_DFFNSR ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFNR ( output `SB_DFF_REG, input C, R, D @@ -881,7 +967,13 @@ module SB_DFFNR ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(negedge R, negedge C, 160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 599; +`else + if (R) (R => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (!R) (negedge C => (Q : D)) = 540; endspecify @@ -894,7 +986,13 @@ module SB_DFFNR ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(negedge R, negedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 883; +`else + if (R) (R => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (!R) (negedge C => (Q : D)) = 796; endspecify @@ -907,13 +1005,20 @@ module SB_DFFNR ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(negedge R, negedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 1589; +`else + if (R) (R => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (!R) (negedge C => (Q : D)) = 1391; endspecify `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFNSS ( output `SB_DFF_REG, input C, S, D @@ -961,6 +1066,7 @@ module SB_DFFNSS ( `endif endmodule +(* abc9_box, lib_whitebox *) module SB_DFFNS ( output `SB_DFF_REG, input C, S, D @@ -978,7 +1084,13 @@ module SB_DFFNS ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(negedge S, negedge C, 160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 599; +`else + if (S) (S => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (!S) (negedge C => (Q : D)) = 540; endspecify @@ -991,7 +1103,13 @@ module SB_DFFNS ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(negedge S, negedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 883; +`else + if (S) (S => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (!S) (negedge C => (Q : D)) = 796; endspecify @@ -1004,13 +1122,20 @@ module SB_DFFNS ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(negedge S, negedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 1589; +`else + if (S) (S => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (!S) (negedge C => (Q : D)) = 1391; endspecify `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFNESR ( output `SB_DFF_REG, input C, E, R, D @@ -1066,6 +1191,7 @@ module SB_DFFNESR ( `endif endmodule +(* abc9_box, lib_whitebox *) module SB_DFFNER ( output `SB_DFF_REG, input C, E, R, D @@ -1085,7 +1211,13 @@ module SB_DFFNER ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(R, negedge C, 2160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 599; +`else + if (R) (R => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (E && !R) (negedge C => (Q : D)) = 540; endspecify @@ -1100,7 +1232,13 @@ module SB_DFFNER ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(R, negedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 883; +`else + if (R) (R => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (E && !R) (negedge C => (Q : D)) = 796; endspecify @@ -1115,13 +1253,20 @@ module SB_DFFNER ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(negedge R, negedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 1589; +`else + if (R) (R => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (E && !R) (negedge C => (Q : D)) = 1391; endspecify `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFNESS ( output `SB_DFF_REG, input C, E, S, D @@ -1177,6 +1322,7 @@ module SB_DFFNESS ( `endif endmodule +(* abc9_box, lib_whitebox *) module SB_DFFNES ( output `SB_DFF_REG, input C, E, S, D @@ -1196,7 +1342,14 @@ module SB_DFFNES ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(negedge S, negedge C, 160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 599; +`else + if (S) (S => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif + // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (E && !S) (negedge C => (Q : D)) = 540; endspecify @@ -1211,7 +1364,13 @@ module SB_DFFNES ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(negedge S, negedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 883; +`else + if (S) (S => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (E && !S) (negedge C => (Q : D)) = 796; endspecify @@ -1226,7 +1385,13 @@ module SB_DFFNES ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(negedge S, negedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 1589; +`else + if (S) (S => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (E && !S) (negedge C => (Q : D)) = 1391; endspecify @@ -1908,7 +2073,7 @@ module ICESTORM_LC ( o_reg <= SR_pd ? SET_NORESET : lut_o; reg o_reg_async = 1'b0; - always @(posedge polarized_clk, posedge SR) + always @(posedge polarized_clk, posedge SR_pd) if (SR_pd) o_reg_async <= SET_NORESET; else if (CEN_pu) @@ -2723,6 +2888,7 @@ module SB_IO_OD ( `endif endmodule +//(* abc9_box, lib_whitebox *) // TODO module SB_MAC16 ( input CLK, CE, input [15:0] C, A, B, D, diff --git a/techlibs/ice40/ff_map.v b/techlibs/ice40/ff_map.v new file mode 100644 index 000000000..e8807e0bd --- /dev/null +++ b/techlibs/ice40/ff_map.v @@ -0,0 +1,28 @@ +module \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule +module \$_DFF_P_ (input D, C, output Q); SB_DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule + +module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule +module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule + +module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule +module \$_DFF_NN1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule + +module \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule + +module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule +module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule +module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule +module \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule + +module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule +module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule +module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule +module \$__DFFE_PP1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 2b211572d..27850b075 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -71,6 +71,9 @@ struct SynthIce40Pass : public ScriptPass log(" -noflatten\n"); log(" do not flatten design before synthesis\n"); log("\n"); + log(" -dff\n"); + log(" run 'abc'/'abc9' with -dff option\n"); + log("\n"); log(" -retime\n"); log(" run 'abc' with '-dff -D 1' options\n"); log("\n"); @@ -113,7 +116,7 @@ struct SynthIce40Pass : public ScriptPass } string top_opt, blif_file, edif_file, json_file, device_opt; - bool nocarry, nodffe, nobram, dsp, flatten, retime, noabc, abc2, vpr, abc9, flowmap; + bool nocarry, nodffe, nobram, dsp, flatten, retime, noabc, abc2, vpr, abc9, dff, flowmap; int min_ce_use; void clear_flags() YS_OVERRIDE @@ -221,14 +224,18 @@ struct SynthIce40Pass : public ScriptPass abc9 = true; continue; } + if (args[argidx] == "-dff") { + dff = true; + continue; + } if (args[argidx] == "-device" && argidx+1 < args.size()) { device_opt = args[++argidx]; continue; } - if (args[argidx] == "-flowmap") { - flowmap = true; - continue; - } + if (args[argidx] == "-flowmap") { + flowmap = true; + continue; + } break; } extra_args(args, argidx, design); @@ -240,13 +247,12 @@ struct SynthIce40Pass : public ScriptPass if (abc9 && retime) log_cmd_error("-retime option not currently compatible with -abc9!\n"); - - if (abc9 && noabc) - log_cmd_error("-abc9 is incompatible with -noabc!\n"); - if (abc9 && flowmap) - log_cmd_error("-abc9 is incompatible with -flowmap!\n"); - if (flowmap && noabc) - log_cmd_error("-flowmap is incompatible with -noabc!\n"); + if (abc9 && noabc) + log_cmd_error("-abc9 is incompatible with -noabc!\n"); + if (abc9 && flowmap) + log_cmd_error("-abc9 is incompatible with -flowmap!\n"); + if (flowmap && noabc) + log_cmd_error("-flowmap is incompatible with -noabc!\n"); log_header(design, "Executing SYNTH_ICE40 pass.\n"); log_push(); @@ -355,7 +361,9 @@ struct SynthIce40Pass : public ScriptPass run(stringf("dff2dffe -unmap-mince %d", min_ce_use)); run("simplemap t:$dff"); } - run("techmap -D NO_LUT -D NO_ADDER -map +/ice40/cells_map.v"); + if ((abc9 && dff) || help_mode) + run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "(only if -abc9 and -dff"); + run("techmap -map +/ice40/ff_map.v"); run("opt_expr -mux_undef"); run("simplemap"); run("ice40_ffinit"); @@ -372,14 +380,14 @@ struct SynthIce40Pass : public ScriptPass run("techmap -map +/ice40/latches_map.v"); if (noabc || flowmap || help_mode) { run("simplemap", " (if -noabc or -flowmap)"); - if (noabc || help_mode) - run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)"); - if (flowmap || help_mode) - run("flowmap -maxlut 4", "(only if -flowmap)"); + if (noabc || help_mode) + run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)"); + if (flowmap || help_mode) + run("flowmap -maxlut 4", "(only if -flowmap)"); } if (!noabc) { if (abc9) { - run("read_verilog " + define + " -icells -lib -specify +/abc9_model.v +/ice40/abc9_model.v"); + run("read_verilog " + define + " -icells -lib -specify +/ice40/abc9_model.v"); std::string abc9_opts; std::string k = "synth_ice40.abc9.W"; if (active_design && active_design->scratchpad.count(k)) @@ -388,24 +396,25 @@ struct SynthIce40Pass : public ScriptPass k = stringf("synth_ice40.abc9.%s.W", device_opt.c_str()); abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str()); } + if (dff) + abc9_opts += " -dff"; run("abc9 " + abc9_opts); } else - run("abc -dress -lut 4", "(skip if -noabc)"); + run(stringf("abc -dress -lut 4 %s", dff ? "-dff" : ""), "(skip if -noabc)"); } run("ice40_wrapcarry -unwrap"); - run("techmap -D NO_LUT -map +/ice40/cells_map.v"); + run("techmap -map +/ice40/ff_map.v"); run("clean"); run("opt_lut -dlogic SB_CARRY:I0=2:I1=1:CI=0"); } if (check_label("map_cells")) { - if (vpr) - run("techmap -D NO_LUT -map +/ice40/cells_map.v"); - else - run("techmap -map +/ice40/cells_map.v", "(with -D NO_LUT in vpr mode)"); - + if (help_mode) + run("techmap -map +/ice40/cells_map.v", "(skip if -vpr)"); + else if (!vpr) + run("techmap -map +/ice40/cells_map.v"); run("clean"); } diff --git a/techlibs/intel/arria10gx/cells_arith.v b/techlibs/intel/arria10gx/cells_arith.v index 89fb4561f..6a52a0f95 100644 --- a/techlibs/intel/arria10gx/cells_arith.v +++ b/techlibs/intel/arria10gx/cells_arith.v @@ -26,8 +26,11 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] X, Y; input CI, BI; @@ -36,11 +39,14 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO); wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; + (* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; //wire [Y_WIDTH:0] C = {CO, CI}; wire [Y_WIDTH+1:0] COx; diff --git a/techlibs/intel/arria10gx/cells_map.v b/techlibs/intel/arria10gx/cells_map.v index 1430e8551..83f5881da 100644 --- a/techlibs/intel/arria10gx/cells_map.v +++ b/techlibs/intel/arria10gx/cells_map.v @@ -30,6 +30,7 @@ endmodule module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; generate diff --git a/techlibs/intel/cyclone10lp/cells_arith.v b/techlibs/intel/cyclone10lp/cells_arith.v index 5ae8d6cea..d8c46e865 100644 --- a/techlibs/intel/cyclone10lp/cells_arith.v +++ b/techlibs/intel/cyclone10lp/cells_arith.v @@ -26,8 +26,11 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] X, Y; input CI, BI; @@ -36,11 +39,14 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO); wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; + (* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; //wire [Y_WIDTH:0] C = {CO, CI}; wire [Y_WIDTH+1:0] COx; diff --git a/techlibs/intel/cyclone10lp/cells_map.v b/techlibs/intel/cyclone10lp/cells_map.v index c2f6f403c..2a80ea678 100644 --- a/techlibs/intel/cyclone10lp/cells_map.v +++ b/techlibs/intel/cyclone10lp/cells_map.v @@ -71,6 +71,7 @@ endmodule module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; generate diff --git a/techlibs/intel/cycloneiv/cells_arith.v b/techlibs/intel/cycloneiv/cells_arith.v index 010a4b5da..f7bc3cd65 100644 --- a/techlibs/intel/cycloneiv/cells_arith.v +++ b/techlibs/intel/cycloneiv/cells_arith.v @@ -70,8 +70,11 @@ module _80_cycloneiv_alu (A, B, CI, BI, X, Y, CO); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] X, Y; input CI, BI; @@ -79,11 +82,14 @@ module _80_cycloneiv_alu (A, B, CI, BI, X, Y, CO); wire _TECHMAP_FAIL_ = Y_WIDTH < 6; + (* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH:0] C = {CO, CI}; diff --git a/techlibs/intel/cycloneiv/cells_map.v b/techlibs/intel/cycloneiv/cells_map.v index 191488430..9d8a5a2b7 100644 --- a/techlibs/intel/cycloneiv/cells_map.v +++ b/techlibs/intel/cycloneiv/cells_map.v @@ -71,6 +71,7 @@ endmodule module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; generate diff --git a/techlibs/intel/cycloneive/arith_map.v b/techlibs/intel/cycloneive/arith_map.v index 49e36aa25..a755e10db 100644 --- a/techlibs/intel/cycloneive/arith_map.v +++ b/techlibs/intel/cycloneive/arith_map.v @@ -66,8 +66,11 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] X, Y; input CI, BI; @@ -75,11 +78,14 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO); wire _TECHMAP_FAIL_ = Y_WIDTH < 5; + (* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH:0] C = {CO, CI}; diff --git a/techlibs/intel/cycloneive/cells_map.v b/techlibs/intel/cycloneive/cells_map.v index abeb92eef..fead2837b 100644 --- a/techlibs/intel/cycloneive/cells_map.v +++ b/techlibs/intel/cycloneive/cells_map.v @@ -71,6 +71,7 @@ endmodule module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; generate diff --git a/techlibs/intel/cyclonev/cells_arith.v b/techlibs/intel/cyclonev/cells_arith.v index 89fb4561f..6a52a0f95 100644 --- a/techlibs/intel/cyclonev/cells_arith.v +++ b/techlibs/intel/cyclonev/cells_arith.v @@ -26,8 +26,11 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] X, Y; input CI, BI; @@ -36,11 +39,14 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO); wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; + (* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; //wire [Y_WIDTH:0] C = {CO, CI}; wire [Y_WIDTH+1:0] COx; diff --git a/techlibs/intel/cyclonev/cells_map.v b/techlibs/intel/cyclonev/cells_map.v index f8d142bc9..eb4cd54d1 100644 --- a/techlibs/intel/cyclonev/cells_map.v +++ b/techlibs/intel/cyclonev/cells_map.v @@ -71,6 +71,7 @@ endmodule module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; wire VCC; diff --git a/techlibs/intel/max10/cells_arith.v b/techlibs/intel/max10/cells_arith.v index e2194cbd7..8529706a7 100644 --- a/techlibs/intel/max10/cells_arith.v +++ b/techlibs/intel/max10/cells_arith.v @@ -26,8 +26,11 @@ module _80_altera_max10_alu (A, B, CI, BI, X, Y, CO); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] X, Y; input CI, BI; @@ -36,11 +39,14 @@ module _80_altera_max10_alu (A, B, CI, BI, X, Y, CO); wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; + (* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; //wire [Y_WIDTH:0] C = {CO, CI}; wire [Y_WIDTH+1:0] COx; diff --git a/techlibs/intel/max10/cells_map.v b/techlibs/intel/max10/cells_map.v index 6d604e072..6a4072049 100644 --- a/techlibs/intel/max10/cells_map.v +++ b/techlibs/intel/max10/cells_map.v @@ -71,6 +71,7 @@ endmodule module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; generate diff --git a/techlibs/intel_alm/Makefile.inc b/techlibs/intel_alm/Makefile.inc index bbf233aeb..ed6c4510b 100644 --- a/techlibs/intel_alm/Makefile.inc +++ b/techlibs/intel_alm/Makefile.inc @@ -7,13 +7,13 @@ $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/al $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/arith_alm_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_sim.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/mem_sim.v)) # RAM bramtypes := m10k m20k $(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype).txt))) $(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype)_map.v))) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab.txt)) -$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab_map.v)) # Miscellaneous $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/megafunction_bb.v)) diff --git a/techlibs/intel_alm/common/alm_map.v b/techlibs/intel_alm/common/alm_map.v index fe646c5d6..6697b2e78 100644 --- a/techlibs/intel_alm/common/alm_map.v +++ b/techlibs/intel_alm/common/alm_map.v @@ -3,6 +3,7 @@ module \$lut (A, Y); parameter WIDTH = 1; parameter LUT = 0; +(* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/intel_alm/common/arith_alm_map.v b/techlibs/intel_alm/common/arith_alm_map.v index ddf81d9d0..8515eeb56 100644 --- a/techlibs/intel_alm/common/arith_alm_map.v +++ b/techlibs/intel_alm/common/arith_alm_map.v @@ -11,17 +11,24 @@ parameter Y_WIDTH = 1; parameter _TECHMAP_CONSTMSK_CI_ = 0; parameter _TECHMAP_CONSTVAL_CI_ = 0; +(* force_downto *) input [A_WIDTH-1:0] A; +(* force_downto *) input [B_WIDTH-1:0] B; input CI, BI; +(* force_downto *) output [Y_WIDTH-1:0] X, Y, CO; +(* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); +(* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; +(* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; +(* force_downto *) wire [Y_WIDTH-1:0] BX = B_buf; wire [Y_WIDTH:0] ALM_CARRY; diff --git a/techlibs/intel_alm/common/bram_m10k_map.v b/techlibs/intel_alm/common/bram_m10k_map.v index e5566010d..061463c3e 100644 --- a/techlibs/intel_alm/common/bram_m10k_map.v +++ b/techlibs/intel_alm/common/bram_m10k_map.v @@ -28,4 +28,4 @@ altsyncram #( .clock1(CLK1)
);
-endmodule +endmodule
diff --git a/techlibs/intel_alm/common/lutram_mlab.txt b/techlibs/intel_alm/common/lutram_mlab.txt index 1d6174d85..3cc69399d 100644 --- a/techlibs/intel_alm/common/lutram_mlab.txt +++ b/techlibs/intel_alm/common/lutram_mlab.txt @@ -1,20 +1,18 @@ -bram __MISTRAL_MLAB
- init 0 # TODO: Re-enable when I figure out how LUTRAM init works
- abits 5
- dbits 16 @D32x16
- dbits 18 @D32x18
- dbits 20 @D32x20
- groups 2
- ports 1 1
- wrmode 1 0
- # read enable
- enable 1 0
- transp 1 0
- clocks 1 2
- clkpol 1 1
-endbram
-
-match __MISTRAL_MLAB
- min efficiency 5
- make_outreg
-endmatch
+bram MISTRAL_MLAB + init 0 # TODO: Re-enable when Yosys remembers the original filename. + abits 5 + dbits 1 + groups 2 + ports 1 1 + wrmode 1 0 + # write enable + enable 1 0 + transp 0 0 + clocks 1 0 + clkpol 1 1 +endbram + +match MISTRAL_MLAB + min efficiency 5 + make_outreg +endmatch
\ No newline at end of file diff --git a/techlibs/intel_alm/common/lutram_mlab_map.v b/techlibs/intel_alm/common/lutram_mlab_map.v deleted file mode 100644 index 3a9c8590e..000000000 --- a/techlibs/intel_alm/common/lutram_mlab_map.v +++ /dev/null @@ -1,29 +0,0 @@ -module __MISTRAL_MLAB(CLK1, CLK2, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA);
-
-parameter CFG_ABITS = 5;
-parameter CFG_DBITS = 20;
-
-input CLK1, CLK2;
-input [CFG_ABITS-1:0] A1ADDR, B1ADDR;
-input [CFG_DBITS-1:0] A1DATA;
-input A1EN;
-output [CFG_DBITS-1:0] B1DATA;
-
-altsyncram #(
- .operation_mode("dual_port"),
- .ram_block_type("mlab"),
- .widthad_a(CFG_ABITS),
- .width_a(CFG_DBITS),
- .widthad_b(CFG_ABITS),
- .width_b(CFG_DBITS),
-) _TECHMAP_REPLACE_ (
- .address_a(A1ADDR),
- .data_a(A1DATA),
- .wren_a(A1EN),
- .address_b(B1ADDR),
- .q_b(B1DATA),
- .clock0(CLK1),
- .clock1(CLK1),
-);
-
-endmodule
diff --git a/techlibs/intel_alm/common/megafunction_bb.v b/techlibs/intel_alm/common/megafunction_bb.v index 21ba73a09..c749fa70b 100644 --- a/techlibs/intel_alm/common/megafunction_bb.v +++ b/techlibs/intel_alm/common/megafunction_bb.v @@ -106,3 +106,26 @@ input aclr1; output eccstatus; endmodule + +(* blackbox *) +module cyclonev_mlab_cell(portaaddr, portadatain, portbaddr, portbdataout, ena0, clk0, clk1); + +parameter logical_ram_name = ""; +parameter logical_ram_depth = 32; +parameter logical_ram_width = 20; +parameter mixed_port_feed_through_mode = "new"; +parameter first_bit_number = 0; +parameter first_address = 0; +parameter last_address = 31; +parameter address_width = 5; +parameter data_width = 1; +parameter byte_enable_mask_width = 1; +parameter port_b_data_out_clock = "NONE"; +parameter [639:0] mem_init0 = 640'b0; + +input [address_width-1:0] portaaddr, portbaddr; +input [data_width-1:0] portadatain; +output [data_width-1:0] portbdataout; +input ena0, clk0, clk1; + +endmodule diff --git a/techlibs/intel_alm/common/mem_sim.v b/techlibs/intel_alm/common/mem_sim.v new file mode 100644 index 000000000..ae79b19a4 --- /dev/null +++ b/techlibs/intel_alm/common/mem_sim.v @@ -0,0 +1,60 @@ +// The MLAB +// -------- +// In addition to Logic Array Blocks (LABs) that contain ten Adaptive Logic +// Modules (ALMs, see alm_sim.v), the Cyclone V/10GX also contain +// Memory/Logic Array Blocks (MLABs) that can act as either ten ALMs, or utilise +// the memory the ALM uses to store the look-up table data for general usage, +// producing a 32 address by 20-bit block of memory. MLABs are spread out +// around the chip, so they can be placed near where they are needed, rather than +// being comparatively limited in placement for a deep but narrow memory such as +// the M10K memory block. +// +// MLABs are used mainly for shallow but wide memories, such as CPU register +// files (which have perhaps 32 registers that are comparatively wide (16/32-bit)) +// or shift registers (by using the output of the Nth bit as input for the N+1th +// bit). +// +// Oddly, instead of providing a block 32 address by 20-bit cell, Quartus asks +// synthesis tools to build MLABs out of 32 address by 1-bit cells, and tries +// to put these cells in the same MLAB during cell placement. Because of this +// a MISTRAL_MLAB cell represents one of these 32 address by 1-bit cells, and +// 20 of them represent a physical MLAB. +// +// How the MLAB works +// ------------------ +// MLABs are poorly documented, so the following information is based mainly +// on the simulation model and my knowledge of how memories like these work. +// Additionally, note that the ports of MISTRAL_MLAB are the ones auto-generated +// by the Yosys `memory_bram` pass, and it doesn't make sense to me to use +// `techmap` just for the sake of renaming the cell ports. +// +// The MLAB can be initialised to any value, but unfortunately Quartus only +// allows memory initialisation from a file. Since Yosys doesn't preserve input +// file information, or write the contents of an `initial` block to a file, +// Yosys can't currently initialise the MLAB in a way Quartus will accept. +// +// The MLAB takes in data from A1DATA at the rising edge of CLK1, and if A1EN +// is high, writes it to the address in A1ADDR. A1EN can therefore be used to +// conditionally write data to the MLAB. +// +// Simultaneously, the MLAB reads data from B1ADDR, and outputs it to B1DATA, +// asynchronous to CLK1 and ignoring A1EN. If a synchronous read is needed +// then the output can be fed to embedded flops. Presently, Yosys assumes +// Quartus will pack external flops into the MLAB, but this is an assumption +// that needs testing. + +// The vendor sim model outputs 'x for a very short period (a few +// combinational delta cycles) after each write. This has been omitted from +// the following model because it's very difficult to trigger this in practice +// as clock cycles will be much longer than any potential blip of 'x, so the +// model can be treated as always returning a defined result. +module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN, CLK1, input [4:0] B1ADDR, output B1DATA); + +reg [31:0] mem = 32'b0; + +always @(posedge CLK1) + if (A1EN) mem[A1ADDR] <= A1DATA; + +assign B1DATA = mem[B1ADDR]; + +endmodule diff --git a/techlibs/intel_alm/common/quartus_rename.v b/techlibs/intel_alm/common/quartus_rename.v index ac0fe12aa..c40a4e02d 100644 --- a/techlibs/intel_alm/common/quartus_rename.v +++ b/techlibs/intel_alm/common/quartus_rename.v @@ -1,8 +1,10 @@ `ifdef cyclonev `define LCELL cyclonev_lcell_comb +`define MLAB cyclonev_mlab_cell `endif `ifdef cyclone10gx `define LCELL cyclone10gx_lcell_comb +`define MLAB cyclone10gx_mlab_cell `endif module __MISTRAL_VCC(output Q); @@ -80,3 +82,40 @@ parameter LUT1 = 16'h0000; `LCELL #(.lut_mask({16'h0, LUT1, 16'h0, LUT0})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D0), .dataf(D1), .cin(CI), .sumout(SO), .cout(CO)); endmodule + + +module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN, CLK1, input [4:0] B1ADDR, output B1DATA); + +// Here we get to an unfortunate situation. The cell has a mem_init0 parameter, +// which takes in a hexadecimal string that could be used to initialise RAM. +// In the vendor simulation models, this appears to work fine, but Quartus, +// either intentionally or not, forgets about this parameter and initialises the +// RAM to zero. +// +// Because of this, RAM initialisation is presently disabled, but the source +// used to generate mem_init0 is kept (commented out) in case this gets fixed +// or an undocumented way to get Quartus to initialise from mem_init0 is found. + +`MLAB #( + .logical_ram_name("MISTRAL_MLAB"), + .logical_ram_depth(32), + .logical_ram_width(1), + .mixed_port_feed_through_mode("Dont Care"), + .first_bit_number(0), + .first_address(0), + .last_address(31), + .address_width(5), + .data_width(1), + .byte_enable_mask_width(1), + .port_b_data_out_clock("NONE"), + // .mem_init0($sformatf("%08x", INIT)) +) _TECHMAP_REPLACE_ ( + .portaaddr(A1ADDR), + .portadatain(A1DATA), + .portbaddr(B1ADDR), + .portbdataout(B1DATA), + .ena0(A1EN), + .clk0(CLK1) +); + +endmodule diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index 200b0cdd1..0f844961e 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -164,6 +164,7 @@ struct SynthIntelALMPass : public ScriptPass { run(stringf("read_verilog -sv -lib +/intel/%s/cells_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/alm_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/dff_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/mem_sim.v", family_opt.c_str())); // Misc and common cells run("read_verilog -lib +/intel/common/altpll_bb.v"); @@ -190,7 +191,6 @@ struct SynthIntelALMPass : public ScriptPass { if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) { run("memory_bram -rules +/intel_alm/common/lutram_mlab.txt", "(for Cyclone V / Cyclone 10GX)"); - run("techmap -map +/intel_alm/common/lutram_mlab_map.v", "(for Cyclone V / Cyclone 10GX)"); } if (check_label("map_ffram")) { @@ -209,7 +209,6 @@ struct SynthIntelALMPass : public ScriptPass { } if (check_label("map_luts")) { - run("read_verilog -icells -specify -lib +/abc9_model.v"); run("abc9 -maxlut 6 -W 200"); run("techmap -map +/intel_alm/common/alm_map.v"); run("opt -fast"); diff --git a/techlibs/sf2/cells_map.v b/techlibs/sf2/cells_map.v index 6ad7807d2..9fddc0f41 100644 --- a/techlibs/sf2/cells_map.v +++ b/techlibs/sf2/cells_map.v @@ -59,6 +59,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index 9984290a6..d4d863831 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -54,8 +54,6 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc5v_dsp_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_dsp_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcu_dsp_map.v)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_map.v)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_unmap.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_model.v)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh)) diff --git a/techlibs/xilinx/abc9_map.v b/techlibs/xilinx/abc9_map.v deleted file mode 100644 index 81f8a1d42..000000000 --- a/techlibs/xilinx/abc9_map.v +++ /dev/null @@ -1,786 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * 2019 Eddie Hung <eddie@fpgeh.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. - * - */ - -// The following techmapping rules are intended to be run (with -max_iter 1) -// before invoking the `abc9` pass in order to transform the design into -// a format that it understands. - -`ifdef DFF_MODE -// For example, (complex) flip-flops are expected to be described as an -// combinatorial box (containing all control logic such as clock enable -// or synchronous resets) followed by a basic D-Q flop. -// Yosys will automatically analyse the simulation model (described in -// cells_sim.v) and detach any $_DFF_P_ or $_DFF_N_ cells present in -// order to extract the combinatorial control logic left behind. -// Specifically, a simulation model similar to the one below: -// -// ++===================================++ -// || Sim model || -// || /\/\/\/\ || -// D -->>-----< > +------+ || -// R -->>-----< Comb. > |$_DFF_| || -// CE -->>-----< logic >-----| [NP]_|---+---->>-- Q -// || +--< > +------+ | || -// || | \/\/\/\/ | || -// || | | || -// || +----------------------------+ || -// || || -// ++===================================++ -// -// is transformed into: -// -// ++==================++ -// || Comb box || -// || || -// || /\/\/\/\ || -// D -->>-----< > || -// R -->>-----< Comb. > || +-----------+ -// CE -->>-----< logic >--->>-- $Q --|$__ABC9_FF_|--+-->> Q -// abc9_ff.Q +-->>-----< > || +-----------+ | -// | || \/\/\/\/ || | -// | || || | -// | ++==================++ | -// | | -// +-----------------------------------------------+ -// -// The purpose of the following FD* rules are to wrap the flop with: -// (a) a special $__ABC9_FF_ in front of the FD*'s output, indicating to abc9 -// the connectivity of its basic D-Q flop -// (b) an optional $__ABC9_ASYNC_ cell in front of $__ABC_FF_'s output to -// capture asynchronous behaviour -// (c) a special abc9_ff.clock wire to capture its clock domain and polarity -// (indicated to `abc9' so that it only performs sequential synthesis -// (with reachability analysis) correctly on one domain at a time) -// (d) an (* abc9_init *) attribute on the $__ABC9_FF_ cell capturing its -// initial state -// NOTE: in order to perform sequential synthesis, `abc9' requires that -// the initial value of all flops be zero -// (e) a special _TECHMAP_REPLACE_.abc9_ff.Q wire that will be used for feedback -// into the (combinatorial) FD* cell to facilitate clock-enable behaviour - -module FDRE (output Q, (* techmap_autopurge *) input C, CE, D, R); - parameter [0:0] INIT = 1'b0; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter [0:0] IS_R_INVERTED = 1'b0; - wire QQ, $Q; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDSE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_S_INVERTED(IS_R_INVERTED) - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .S(R) - ); - end - else begin - assign Q = QQ; - FDRE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_R_INVERTED(IS_R_INVERTED) - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .R(R) - ); - end - endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; -endmodule -module FDRE_1 (output Q, (* techmap_autopurge *) input C, CE, D, R); - parameter [0:0] INIT = 1'b0; - wire QQ, $Q; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDSE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .S(R) - ); - end - else begin - assign Q = QQ; - FDRE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .R(R) - ); - end - endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; -endmodule - -module FDSE (output Q, (* techmap_autopurge *) input C, CE, D, S); - parameter [0:0] INIT = 1'b1; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter [0:0] IS_S_INVERTED = 1'b0; - wire QQ, $Q; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDRE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_R_INVERTED(IS_S_INVERTED) - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .R(S) - ); - end - else begin - assign Q = QQ; - FDSE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_S_INVERTED(IS_S_INVERTED) - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .S(S) - ); - end endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; -endmodule -module FDSE_1 (output Q, (* techmap_autopurge *) input C, CE, D, S); - parameter [0:0] INIT = 1'b1; - wire QQ, $Q; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDRE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .R(S) - ); - end - else begin - assign Q = QQ; - FDSE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .S(S) - ); - end endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; -endmodule - -module FDCE (output Q, (* techmap_autopurge *) input C, CE, D, CLR); - parameter [0:0] INIT = 1'b0; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter [0:0] IS_CLR_INVERTED = 1'b0; - wire QQ, $Q, $QQ; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDPE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_PRE_INVERTED(IS_CLR_INVERTED) - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .PRE(CLR) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC1 below - ); - // Since this is an async flop, async behaviour is dealt with here - $__ABC9_ASYNC1 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ)); - end - else begin - assign Q = QQ; - FDCE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_CLR_INVERTED(IS_CLR_INVERTED) - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .CLR(CLR) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC0 below - ); - // Since this is an async flop, async behaviour is dealt with here - $__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ)); - end endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; -endmodule -module FDCE_1 (output Q, (* techmap_autopurge *) input C, CE, D, CLR); - parameter [0:0] INIT = 1'b0; - wire QQ, $Q, $QQ; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDPE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .PRE(CLR) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC1 below - ); - $__ABC9_ASYNC1 abc_async (.A($QQ), .S(CLR), .Y(QQ)); - end - else begin - assign Q = QQ; - FDCE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .CLR(CLR) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC0 below - ); - $__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR), .Y(QQ)); - end endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; -endmodule - -module FDPE (output Q, (* techmap_autopurge *) input C, CE, D, PRE); - parameter [0:0] INIT = 1'b1; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter [0:0] IS_PRE_INVERTED = 1'b0; - wire QQ, $Q, $QQ; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDCE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_CLR_INVERTED(IS_PRE_INVERTED), - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .CLR(PRE) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC0 below - ); - $__ABC9_ASYNC0 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ)); - end - else begin - assign Q = QQ; - FDPE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_PRE_INVERTED(IS_PRE_INVERTED), - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .PRE(PRE) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC1 below - ); - $__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ)); - end endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; -endmodule -module FDPE_1 (output Q, (* techmap_autopurge *) input C, CE, D, PRE); - parameter [0:0] INIT = 1'b1; - wire QQ, $Q, $QQ; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDCE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .CLR(PRE) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC0 below - ); - $__ABC9_ASYNC0 abc_async (.A($QQ), .S(PRE), .Y(QQ)); - end - else begin - assign Q = QQ; - FDPE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .PRE(PRE) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC1 below - ); - $__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE), .Y(QQ)); - end endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; -endmodule -`endif - -// Attach a (combinatorial) black-box onto the output -// of thes LUTRAM primitives to capture their -// asynchronous read behaviour -module RAM32X1D ( - output DPO, SPO, - (* techmap_autopurge *) input D, - (* techmap_autopurge *) input WCLK, - (* techmap_autopurge *) input WE, - (* techmap_autopurge *) input A0, A1, A2, A3, A4, - (* techmap_autopurge *) input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4 -); - parameter INIT = 32'h0; - parameter IS_WCLK_INVERTED = 1'b0; - wire $DPO, $SPO; - RAM32X1D #( - .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .DPO($DPO), .SPO($SPO), - .D(D), .WCLK(WCLK), .WE(WE), - .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), - .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4) - ); - $__ABC9_RAM6 spo (.A($SPO), .S({1'b1, A4, A3, A2, A1, A0}), .Y(SPO)); - $__ABC9_RAM6 dpo (.A($DPO), .S({1'b1, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO)); -endmodule - -module RAM64X1D ( - output DPO, SPO, - (* techmap_autopurge *) input D, - (* techmap_autopurge *) input WCLK, - (* techmap_autopurge *) input WE, - (* techmap_autopurge *) input A0, A1, A2, A3, A4, A5, - (* techmap_autopurge *) input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 -); - parameter INIT = 64'h0; - parameter IS_WCLK_INVERTED = 1'b0; - wire $DPO, $SPO; - RAM64X1D #( - .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .DPO($DPO), .SPO($SPO), - .D(D), .WCLK(WCLK), .WE(WE), - .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5), - .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5) - ); - $__ABC9_RAM6 spo (.A($SPO), .S({A5, A4, A3, A2, A1, A0}), .Y(SPO)); - $__ABC9_RAM6 dpo (.A($DPO), .S({DPRA5, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO)); -endmodule - -module RAM128X1D ( - output DPO, SPO, - (* techmap_autopurge *) input D, - (* techmap_autopurge *) input WCLK, - (* techmap_autopurge *) input WE, - (* techmap_autopurge *) input [6:0] A, DPRA -); - parameter INIT = 128'h0; - parameter IS_WCLK_INVERTED = 1'b0; - wire $DPO, $SPO; - RAM128X1D #( - .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .DPO($DPO), .SPO($SPO), - .D(D), .WCLK(WCLK), .WE(WE), - .A(A), - .DPRA(DPRA) - ); - $__ABC9_RAM7 spo (.A($SPO), .S(A), .Y(SPO)); - $__ABC9_RAM7 dpo (.A($DPO), .S(DPRA), .Y(DPO)); -endmodule - -module RAM32M ( - output [1:0] DOA, - output [1:0] DOB, - output [1:0] DOC, - output [1:0] DOD, - (* techmap_autopurge *) input [4:0] ADDRA, - (* techmap_autopurge *) input [4:0] ADDRB, - (* techmap_autopurge *) input [4:0] ADDRC, - (* techmap_autopurge *) input [4:0] ADDRD, - (* techmap_autopurge *) input [1:0] DIA, - (* techmap_autopurge *) input [1:0] DIB, - (* techmap_autopurge *) input [1:0] DIC, - (* techmap_autopurge *) input [1:0] DID, - (* techmap_autopurge *) input WCLK, - (* techmap_autopurge *) input WE -); - parameter [63:0] INIT_A = 64'h0000000000000000; - parameter [63:0] INIT_B = 64'h0000000000000000; - parameter [63:0] INIT_C = 64'h0000000000000000; - parameter [63:0] INIT_D = 64'h0000000000000000; - parameter [0:0] IS_WCLK_INVERTED = 1'b0; - wire [1:0] $DOA, $DOB, $DOC, $DOD; - RAM32M #( - .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D), - .IS_WCLK_INVERTED(IS_WCLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .DOA($DOA), .DOB($DOB), .DOC($DOC), .DOD($DOD), - .WCLK(WCLK), .WE(WE), - .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD), - .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID) - ); - $__ABC9_RAM6 doa0 (.A($DOA[0]), .S({1'b1, ADDRA}), .Y(DOA[0])); - $__ABC9_RAM6 doa1 (.A($DOA[1]), .S({1'b1, ADDRA}), .Y(DOA[1])); - $__ABC9_RAM6 dob0 (.A($DOB[0]), .S({1'b1, ADDRB}), .Y(DOB[0])); - $__ABC9_RAM6 dob1 (.A($DOB[1]), .S({1'b1, ADDRB}), .Y(DOB[1])); - $__ABC9_RAM6 doc0 (.A($DOC[0]), .S({1'b1, ADDRC}), .Y(DOC[0])); - $__ABC9_RAM6 doc1 (.A($DOC[1]), .S({1'b1, ADDRC}), .Y(DOC[1])); - $__ABC9_RAM6 dod0 (.A($DOD[0]), .S({1'b1, ADDRD}), .Y(DOD[0])); - $__ABC9_RAM6 dod1 (.A($DOD[1]), .S({1'b1, ADDRD}), .Y(DOD[1])); -endmodule - -module RAM64M ( - output DOA, - output DOB, - output DOC, - output DOD, - (* techmap_autopurge *) input [5:0] ADDRA, - (* techmap_autopurge *) input [5:0] ADDRB, - (* techmap_autopurge *) input [5:0] ADDRC, - (* techmap_autopurge *) input [5:0] ADDRD, - (* techmap_autopurge *) input DIA, - (* techmap_autopurge *) input DIB, - (* techmap_autopurge *) input DIC, - (* techmap_autopurge *) input DID, - (* techmap_autopurge *) input WCLK, - (* techmap_autopurge *) input WE -); - parameter [63:0] INIT_A = 64'h0000000000000000; - parameter [63:0] INIT_B = 64'h0000000000000000; - parameter [63:0] INIT_C = 64'h0000000000000000; - parameter [63:0] INIT_D = 64'h0000000000000000; - parameter [0:0] IS_WCLK_INVERTED = 1'b0; - wire $DOA, $DOB, $DOC, $DOD; - RAM64M #( - .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D), - .IS_WCLK_INVERTED(IS_WCLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .DOA($DOA), .DOB($DOB), .DOC($DOC), .DOD($DOD), - .WCLK(WCLK), .WE(WE), - .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD), - .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID) - ); - $__ABC9_RAM6 doa (.A($DOA), .S(ADDRA), .Y(DOA)); - $__ABC9_RAM6 dob (.A($DOB), .S(ADDRB), .Y(DOB)); - $__ABC9_RAM6 doc (.A($DOC), .S(ADDRC), .Y(DOC)); - $__ABC9_RAM6 dod (.A($DOD), .S(ADDRD), .Y(DOD)); -endmodule - -module SRL16 ( - output Q, - (* techmap_autopurge *) input A0, A1, A2, A3, CLK, D -); - parameter [15:0] INIT = 16'h0000; - wire $Q; - SRL16 #( - .INIT(INIT), - ) _TECHMAP_REPLACE_ ( - .Q($Q), - .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CLK(CLK), .D(D) - ); - $__ABC9_RAM6 q (.A($Q), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q)); -endmodule - -module SRL16E ( - output Q, - (* techmap_autopurge *) input A0, A1, A2, A3, CE, CLK, D -); - parameter [15:0] INIT = 16'h0000; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - wire $Q; - SRL16E #( - .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .Q($Q), - .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D) - ); - $__ABC9_RAM6 q (.A($Q), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q)); -endmodule - -module SRLC16 ( - output Q, Q15, - (* techmap_autopurge *) input A0, A1, A2, A3, CLK, D -); - parameter [15:0] INIT = 16'h0000; - wire $Q; - SRLC16 #( - .INIT(INIT), - ) _TECHMAP_REPLACE_ ( - .Q($Q), .Q(Q15), - .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CLK(CLK), .D(D) - ); - $__ABC9_RAM6 q (.A($Q), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q)); -endmodule - -module SRLC16E ( - output Q, Q15, - (* techmap_autopurge *) input A0, A1, A2, A3, CE, CLK, D -); - parameter [15:0] INIT = 16'h0000; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - wire $Q; - SRLC16E #( - .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .Q($Q), .Q(Q15), - .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D) - ); - $__ABC9_RAM6 q (.A($Q), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q)); -endmodule - -module SRLC32E ( - output Q, - output Q31, - (* techmap_autopurge *) input [4:0] A, - (* techmap_autopurge *) input CE, CLK, D -); - parameter [31:0] INIT = 32'h00000000; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - wire $Q; - SRLC32E #( - .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .Q($Q), .Q31(Q31), - .A(A), .CE(CE), .CLK(CLK), .D(D) - ); - $__ABC9_RAM6 q (.A($Q), .S({1'b1, A}), .Y(Q)); -endmodule - -module DSP48E1 ( - (* techmap_autopurge *) output [29:0] ACOUT, - (* techmap_autopurge *) output [17:0] BCOUT, - (* techmap_autopurge *) output reg CARRYCASCOUT, - (* techmap_autopurge *) output reg [3:0] CARRYOUT, - (* techmap_autopurge *) output reg MULTSIGNOUT, - (* techmap_autopurge *) output OVERFLOW, - (* techmap_autopurge *) output reg signed [47:0] P, - (* techmap_autopurge *) output PATTERNBDETECT, - (* techmap_autopurge *) output PATTERNDETECT, - (* techmap_autopurge *) output [47:0] PCOUT, - (* techmap_autopurge *) output UNDERFLOW, - (* techmap_autopurge *) input signed [29:0] A, - (* techmap_autopurge *) input [29:0] ACIN, - (* techmap_autopurge *) input [3:0] ALUMODE, - (* techmap_autopurge *) input signed [17:0] B, - (* techmap_autopurge *) input [17:0] BCIN, - (* techmap_autopurge *) input [47:0] C, - (* techmap_autopurge *) input CARRYCASCIN, - (* techmap_autopurge *) input CARRYIN, - (* techmap_autopurge *) input [2:0] CARRYINSEL, - (* techmap_autopurge *) input CEA1, - (* techmap_autopurge *) input CEA2, - (* techmap_autopurge *) input CEAD, - (* techmap_autopurge *) input CEALUMODE, - (* techmap_autopurge *) input CEB1, - (* techmap_autopurge *) input CEB2, - (* techmap_autopurge *) input CEC, - (* techmap_autopurge *) input CECARRYIN, - (* techmap_autopurge *) input CECTRL, - (* techmap_autopurge *) input CED, - (* techmap_autopurge *) input CEINMODE, - (* techmap_autopurge *) input CEM, - (* techmap_autopurge *) input CEP, - (* techmap_autopurge *) input CLK, - (* techmap_autopurge *) input [24:0] D, - (* techmap_autopurge *) input [4:0] INMODE, - (* techmap_autopurge *) input MULTSIGNIN, - (* techmap_autopurge *) input [6:0] OPMODE, - (* techmap_autopurge *) input [47:0] PCIN, - (* techmap_autopurge *) input RSTA, - (* techmap_autopurge *) input RSTALLCARRYIN, - (* techmap_autopurge *) input RSTALUMODE, - (* techmap_autopurge *) input RSTB, - (* techmap_autopurge *) input RSTC, - (* techmap_autopurge *) input RSTCTRL, - (* techmap_autopurge *) input RSTD, - (* techmap_autopurge *) input RSTINMODE, - (* techmap_autopurge *) input RSTM, - (* techmap_autopurge *) input RSTP -); - parameter integer ACASCREG = 1; - parameter integer ADREG = 1; - parameter integer ALUMODEREG = 1; - parameter integer AREG = 1; - parameter AUTORESET_PATDET = "NO_RESET"; - parameter A_INPUT = "DIRECT"; - parameter integer BCASCREG = 1; - parameter integer BREG = 1; - parameter B_INPUT = "DIRECT"; - parameter integer CARRYINREG = 1; - parameter integer CARRYINSELREG = 1; - parameter integer CREG = 1; - parameter integer DREG = 1; - parameter integer INMODEREG = 1; - parameter integer MREG = 1; - parameter integer OPMODEREG = 1; - parameter integer PREG = 1; - parameter SEL_MASK = "MASK"; - parameter SEL_PATTERN = "PATTERN"; - parameter USE_DPORT = "FALSE"; - parameter USE_MULT = "MULTIPLY"; - parameter USE_PATTERN_DETECT = "NO_PATDET"; - parameter USE_SIMD = "ONE48"; - parameter [47:0] MASK = 48'h3FFFFFFFFFFF; - parameter [47:0] PATTERN = 48'h000000000000; - parameter [3:0] IS_ALUMODE_INVERTED = 4'b0; - parameter [0:0] IS_CARRYIN_INVERTED = 1'b0; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - parameter [4:0] IS_INMODE_INVERTED = 5'b0; - parameter [6:0] IS_OPMODE_INVERTED = 7'b0; - - wire [47:0] $P, $PCOUT; - - DSP48E1 #( - .ACASCREG(ACASCREG), - .ADREG(ADREG), - .ALUMODEREG(ALUMODEREG), - .AREG(AREG), - .AUTORESET_PATDET(AUTORESET_PATDET), - .A_INPUT(A_INPUT), - .BCASCREG(BCASCREG), - .BREG(BREG), - .B_INPUT(B_INPUT), - .CARRYINREG(CARRYINREG), - .CARRYINSELREG(CARRYINSELREG), - .CREG(CREG), - .DREG(DREG), - .INMODEREG(INMODEREG), - .MREG(MREG), - .OPMODEREG(OPMODEREG), - .PREG(PREG), - .SEL_MASK(SEL_MASK), - .SEL_PATTERN(SEL_PATTERN), - .USE_DPORT(USE_DPORT), - .USE_MULT(USE_MULT), - .USE_PATTERN_DETECT(USE_PATTERN_DETECT), - .USE_SIMD(USE_SIMD), - .MASK(MASK), - .PATTERN(PATTERN), - .IS_ALUMODE_INVERTED(IS_ALUMODE_INVERTED), - .IS_CARRYIN_INVERTED(IS_CARRYIN_INVERTED), - .IS_CLK_INVERTED(IS_CLK_INVERTED), - .IS_INMODE_INVERTED(IS_INMODE_INVERTED), - .IS_OPMODE_INVERTED(IS_OPMODE_INVERTED) - ) _TECHMAP_REPLACE_ ( - .ACOUT(ACOUT), - .BCOUT(BCOUT), - .CARRYCASCOUT(CARRYCASCOUT), - .CARRYOUT(CARRYOUT), - .MULTSIGNOUT(MULTSIGNOUT), - .OVERFLOW(OVERFLOW), - .P($P), - .PATTERNBDETECT(PATTERNBDETECT), - .PATTERNDETECT(PATTERNDETECT), - .PCOUT($PCOUT), - .UNDERFLOW(UNDERFLOW), - .A(A), - .ACIN(ACIN), - .ALUMODE(ALUMODE), - .B(B), - .BCIN(BCIN), - .C(C), - .CARRYCASCIN(CARRYCASCIN), - .CARRYIN(CARRYIN), - .CARRYINSEL(CARRYINSEL), - .CEA1(CEA1), - .CEA2(CEA2), - .CEAD(CEAD), - .CEALUMODE(CEALUMODE), - .CEB1(CEB1), - .CEB2(CEB2), - .CEC(CEC), - .CECARRYIN(CECARRYIN), - .CECTRL(CECTRL), - .CED(CED), - .CEINMODE(CEINMODE), - .CEM(CEM), - .CEP(CEP), - .CLK(CLK), - .D(D), - .INMODE(INMODE), - .MULTSIGNIN(MULTSIGNIN), - .OPMODE(OPMODE), - .PCIN(PCIN), - .RSTA(RSTA), - .RSTALLCARRYIN(RSTALLCARRYIN), - .RSTALUMODE(RSTALUMODE), - .RSTB(RSTB), - .RSTC(RSTC), - .RSTCTRL(RSTCTRL), - .RSTD(RSTD), - .RSTINMODE(RSTINMODE), - .RSTM(RSTM), - .RSTP(RSTP) - ); - $__ABC9_DSP48E1 #( - .ADREG(ADREG), - .AREG(AREG), - .BREG(BREG), - .CREG(CREG), - .DREG(DREG), - .MREG(MREG), - .PREG(PREG), - .USE_DPORT(USE_DPORT), - .USE_MULT(USE_MULT) - ) dsp_comb ( - .$A(A), .$B(B), .$C(C), .$D(D), .$P($P), .$PCIN(PCIN), .$PCOUT($PCOUT), .P(P), .PCOUT(PCOUT)); -endmodule diff --git a/techlibs/xilinx/abc9_model.v b/techlibs/xilinx/abc9_model.v index 2d109ef8a..db44ff00b 100644 --- a/techlibs/xilinx/abc9_model.v +++ b/techlibs/xilinx/abc9_model.v @@ -37,174 +37,3 @@ module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1); (S1 => O) = 273; endspecify endmodule - -// Box to emulate async behaviour of FDC* -(* abc9_box, lib_whitebox *) -module \$__ABC9_ASYNC0 (input A, S, output Y); - assign Y = S ? 1'b0 : A; - specify - (A => Y) = 0; - // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 - (S => Y) = 764; - endspecify -endmodule - -// Box to emulate async behaviour of FDP* -(* abc9_box, lib_whitebox *) -module \$__ABC9_ASYNC1 (input A, S, output Y); - assign Y = S ? 1'b1 : A; - specify - (A => Y) = 0; - // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 - (S => Y) = 764; - endspecify -endmodule - -// Box to emulate comb/seq behaviour of RAM{32,64} and SRL{16,32} -// Necessary since RAMD* and SRL* have both combinatorial (i.e. -// same-cycle read operation) and sequential (write operation -// is only committed on the next clock edge). -// To model the combinatorial path, such cells have to be split -// into comb and seq parts, with this box modelling only the former. -(* abc9_box *) -module \$__ABC9_RAM6 (input A, input [5:0] S, output Y); - specify - (A => Y) = 0; - (S[0] => Y) = 642; - (S[1] => Y) = 631; - (S[2] => Y) = 472; - (S[3] => Y) = 407; - (S[4] => Y) = 238; - (S[5] => Y) = 127; - endspecify -endmodule -// Box to emulate comb/seq behaviour of RAM128 -(* abc9_box *) -module \$__ABC9_RAM7 (input A, input [6:0] S, output Y); - specify - (A => Y) = 0; - // https://github.com/SymbiFlow/prjxray-db/blob/1c85daf1b115da4d27ca83c6b89f53a94de39748/artix7/timings/slicel.sdf#L867 - (S[0] => Y) = 642 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; - (S[1] => Y) = 631 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; - (S[2] => Y) = 472 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; - (S[3] => Y) = 407 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; - (S[4] => Y) = 238 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; - (S[5] => Y) = 127 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; - (S[6] => Y) = 0 + 296 /* to select F7BMUX */ + 174 /* CMUX */; - endspecify -endmodule - -// Boxes used to represent the comb behaviour of DSP48E1 -(* abc9_box *) -module $__ABC9_DSP48E1 ( - input [29:0] $A, - input [17:0] $B, - input [47:0] $C, - input [24:0] $D, - input [47:0] $P, - input [47:0] $PCIN, - input [47:0] $PCOUT, - output [47:0] P, - output [47:0] PCOUT -); - parameter integer ADREG = 1; - parameter integer AREG = 1; - parameter integer BREG = 1; - parameter integer CREG = 1; - parameter integer DREG = 1; - parameter integer MREG = 1; - parameter integer PREG = 1; - parameter USE_DPORT = "FALSE"; - parameter USE_MULT = "MULTIPLY"; - - function integer \A.P.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \A.P.comb = 2823; - else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \A.P.comb = 3806; - else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \A.P.comb = 1523; - end - endfunction - function integer \A.PCOUT.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \A.PCOUT.comb = 2970; - else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \A.PCOUT.comb = 3954; - else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \A.PCOUT.comb = 1671; - end - endfunction - function integer \B.P.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \B.P.comb = 2690; - else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \B.P.comb = 2690; - else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \B.P.comb = 1509; - end - endfunction - function integer \B.PCOUT.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \B.PCOUT.comb = 2838; - else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \B.PCOUT.comb = 2838; - else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \B.PCOUT.comb = 1658; - end - endfunction - function integer \C.P.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \C.P.comb = 1325; - else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \C.P.comb = 1325; - else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \C.P.comb = 1325; - end - endfunction - function integer \C.PCOUT.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \C.PCOUT.comb = 1474; - else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \C.PCOUT.comb = 1474; - else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \C.PCOUT.comb = 1474; - end - endfunction - function integer \D.P.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \D.P.comb = 3717; - end - endfunction - function integer \D.PCOUT.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \D.PCOUT.comb = 3700; - end - endfunction - - specify - ($P *> P) = 0; - ($PCOUT *> PCOUT) = 0; - endspecify - - // Identical comb delays to DSP48E1 in cells_sim.v - generate - if (PREG == 0 && MREG == 0 && AREG == 0 && ADREG == 0) - specify - ($A *> P) = \A.P.comb (); - ($A *> PCOUT) = \A.PCOUT.comb (); - endspecify - - if (PREG == 0 && MREG == 0 && BREG == 0) - specify - ($B *> P) = \B.P.comb (); - ($B *> PCOUT) = \B.PCOUT.comb (); - endspecify - - if (PREG == 0 && CREG == 0) - specify - ($C *> P) = \C.P.comb (); - ($C *> PCOUT) = \C.PCOUT.comb (); - endspecify - - if (PREG == 0 && MREG == 0 && ADREG == 0 && DREG == 0) - specify - ($D *> P) = \D.P.comb (); - ($D *> PCOUT) = \D.PCOUT.comb (); - endspecify - - if (PREG == 0) - specify - ($PCIN *> P) = 1107; - ($PCIN *> PCOUT) = 1255; - endspecify - endgenerate -endmodule diff --git a/techlibs/xilinx/abc9_unmap.v b/techlibs/xilinx/abc9_unmap.v deleted file mode 100644 index 5604ceb0a..000000000 --- a/techlibs/xilinx/abc9_unmap.v +++ /dev/null @@ -1,61 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * 2019 Eddie Hung <eddie@fpgeh.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. - * - */ - -// ============================================================================ - -(* techmap_celltype = "$__ABC9_ASYNC0 $__ABC9_ASYNC1" *) -module $__ABC9_ASYNC01(input A, S, output Y); - assign Y = A; -endmodule - -module $__ABC9_FF_(input D, output Q); - assign Q = D; -endmodule - -module $__ABC9_RAM6(input A, input [5:0] S, output Y); - assign Y = A; -endmodule -module $__ABC9_RAM7(input A, input [6:0] S, output Y); - assign Y = A; -endmodule - -module $__ABC9_DSP48E1( - input [29:0] $A, - input [17:0] $B, - input [47:0] $C, - input [24:0] $D, - input [47:0] $P, - input [47:0] $PCIN, - input [47:0] $PCOUT, - output [47:0] P, - output [47:0] PCOUT -); - parameter integer ADREG = 1; - parameter integer AREG = 1; - parameter integer BREG = 1; - parameter integer CREG = 1; - parameter integer DREG = 1; - parameter integer MREG = 1; - parameter integer PREG = 1; - parameter USE_DPORT = "FALSE"; - parameter USE_MULT = "MULTIPLY"; - - assign P = $P, PCOUT = $PCOUT; -endmodule diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v index 2b8b0dcc1..2fc216908 100644 --- a/techlibs/xilinx/arith_map.v +++ b/techlibs/xilinx/arith_map.v @@ -24,9 +24,11 @@ module _80_xilinx_lcu (P, G, CI, CO); parameter WIDTH = 2; + (* force_downto *) input [WIDTH-1:0] P, G; input CI; + (* force_downto *) output [WIDTH-1:0] CO; wire _TECHMAP_FAIL_ = WIDTH <= 2; @@ -41,7 +43,9 @@ module _80_xilinx_lcu (P, G, CI, CO); generate if (EXPLICIT_CARRY || `LUT_SIZE == 4) begin + (* force_downto *) wire [WIDTH-1:0] C = {CO, CI}; + (* force_downto *) wire [WIDTH-1:0] S = P & ~G; generate for (i = 0; i < WIDTH; i = i + 1) begin:slice @@ -59,8 +63,11 @@ end else begin localparam MAX_WIDTH = CARRY4_COUNT * 4; localparam PAD_WIDTH = MAX_WIDTH - WIDTH; + (* force_downto *) wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, P & ~G}; + (* force_downto *) wire [MAX_WIDTH-1:0] GG = {{PAD_WIDTH{1'b0}}, G}; + (* force_downto *) wire [MAX_WIDTH-1:0] C; assign CO = C; @@ -103,20 +110,27 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); parameter _TECHMAP_CONSTVAL_CI_ = 0; parameter _TECHMAP_CONSTMSK_CI_ = 0; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] X, Y; input CI, BI; + (* force_downto *) output [Y_WIDTH-1:0] CO; wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; + (* force_downto *) wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; genvar i; @@ -129,7 +143,9 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); generate if (`LUT_SIZE == 4) begin + (* force_downto *) wire [Y_WIDTH-1:0] C = {CO, CI}; + (* force_downto *) wire [Y_WIDTH-1:0] S = {AA ^ BB}; genvar i; @@ -149,6 +165,7 @@ generate if (`LUT_SIZE == 4) begin end else if (EXPLICIT_CARRY) begin + (* force_downto *) wire [Y_WIDTH-1:0] S = AA ^ BB; wire CINIT; @@ -161,7 +178,9 @@ end else if (EXPLICIT_CARRY) begin // So we maintain two wire sets, CO_CHAIN is the carry that is for VPR, // e.g. off fabric dedicated chain. CO is the carry outputs that are // available to the fabric. + (* force_downto *) wire [Y_WIDTH-1:0] CO_CHAIN; + (* force_downto *) wire [Y_WIDTH-1:0] C = {CO_CHAIN, CINIT}; // If carry chain is being initialized to a constant, techmap the constant @@ -250,10 +269,14 @@ end else begin localparam MAX_WIDTH = CARRY4_COUNT * 4; localparam PAD_WIDTH = MAX_WIDTH - Y_WIDTH; + (* force_downto *) wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, AA ^ BB}; + (* force_downto *) wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA}; + (* force_downto *) wire [MAX_WIDTH-1:0] O; + (* force_downto *) wire [MAX_WIDTH-1:0] C; assign Y = O, CO = C; diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index cc180f2b9..801949d22 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -184,8 +184,11 @@ module \$__XILINX_SHIFTX (A, B, Y); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] Y; parameter [A_WIDTH-1:0] _TECHMAP_CONSTMSK_A_ = 0; @@ -321,8 +324,11 @@ module _90__XILINX_SHIFTX (A, B, Y); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] Y; \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y)); diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 63223afbf..d87cfe91b 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -36,6 +36,9 @@ module IBUF( parameter IOSTANDARD = "default"; parameter IBUF_LOW_PWR = 0; assign O = I; + specify + (I => O) = 0; + endspecify endmodule module IBUFG( @@ -57,6 +60,9 @@ module OBUF( parameter DRIVE = 12; parameter SLEW = "SLOW"; assign O = I; + specify + (I => O) = 0; + endspecify endmodule module IOBUF ( @@ -72,6 +78,10 @@ module IOBUF ( parameter SLEW = "SLOW"; assign IO = T ? 1'bz : I; assign O = IO; + specify + (I => IO) = 0; + (IO => O) = 0; + endspecify endmodule module OBUFT ( @@ -85,14 +95,20 @@ module OBUFT ( parameter IOSTANDARD = "DEFAULT"; parameter SLEW = "SLOW"; assign O = T ? 1'bz : I; + specify + (I => O) = 0; + endspecify endmodule module BUFG( (* clkbuf_driver *) output O, input I); - assign O = I; + specify + // https://github.com/SymbiFlow/prjxray-db/blob/4bc6385ab300b1819848371f508185f57b649a0e/artix7/timings/CLK_BUFG_TOP_R.sdf#L11 + (I => O) = 96; + endspecify endmodule module BUFGCTRL( @@ -499,8 +515,8 @@ module FDRE ( endgenerate specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , posedge C &&& CE && !IS_C_INVERTED , -46); // Negative times not currently supported - //$setup(D , negedge C &&& CE && IS_C_INVERTED , -46); // Negative times not currently supported + $setup(D , posedge C &&& CE && !IS_C_INVERTED , /*-46*/ 0); // Negative times not currently supported + $setup(D , negedge C &&& CE && IS_C_INVERTED , /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE, posedge C &&& !IS_C_INVERTED, 109); $setup(CE, negedge C &&& IS_C_INVERTED, 109); @@ -508,10 +524,10 @@ module FDRE ( $setup(R , posedge C &&& !IS_C_INVERTED, 404); $setup(R , negedge C &&& IS_C_INVERTED, 404); // https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L243 - if (!IS_C_INVERTED && R ^ IS_R_INVERTED) (posedge C => (Q : 1'b0)) = 303; - if ( IS_C_INVERTED && R ^ IS_R_INVERTED) (negedge C => (Q : 1'b0)) = 303; - if (!IS_C_INVERTED && R ~^ IS_R_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; - if ( IS_C_INVERTED && R ~^ IS_R_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; + if (!IS_C_INVERTED && R != IS_R_INVERTED) (posedge C => (Q : 1'b0)) = 303; + if ( IS_C_INVERTED && R != IS_R_INVERTED) (negedge C => (Q : 1'b0)) = 303; + if (!IS_C_INVERTED && R == IS_R_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; + if ( IS_C_INVERTED && R == IS_R_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; endspecify endmodule @@ -529,7 +545,7 @@ module FDRE_1 ( always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D; specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , negedge C &&& CE, -46); // Negative times not currently supported + $setup(D , negedge C &&& CE, /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE, negedge C, 109); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274 @@ -564,8 +580,8 @@ module FDSE ( endgenerate specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , posedge C &&& !IS_C_INVERTED && CE, -46); // Negative times not currently supported - //$setup(D , negedge C &&& IS_C_INVERTED && CE, -46); // Negative times not currently supported + $setup(D , posedge C &&& !IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported + $setup(D , negedge C &&& IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE, posedge C &&& !IS_C_INVERTED, 109); $setup(CE, negedge C &&& IS_C_INVERTED, 109); @@ -573,10 +589,10 @@ module FDSE ( $setup(S , posedge C &&& !IS_C_INVERTED, 404); $setup(S , negedge C &&& IS_C_INVERTED, 404); // https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L243 - if (!IS_C_INVERTED && S ^ IS_S_INVERTED) (posedge C => (Q : 1'b1)) = 303; - if ( IS_C_INVERTED && S ^ IS_S_INVERTED) (negedge C => (Q : 1'b1)) = 303; - if (!IS_C_INVERTED && S ~^ IS_S_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; - if ( IS_C_INVERTED && S ~^ IS_S_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; + if (!IS_C_INVERTED && S != IS_S_INVERTED) (posedge C => (Q : 1'b1)) = 303; + if ( IS_C_INVERTED && S != IS_S_INVERTED) (negedge C => (Q : 1'b1)) = 303; + if (!IS_C_INVERTED && S == IS_S_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; + if ( IS_C_INVERTED && S == IS_S_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; endspecify endmodule @@ -594,7 +610,7 @@ module FDSE_1 ( always @(negedge C) if (S) Q <= 1'b1; else if (CE) Q <= D; specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , negedge C &&& CE, -46); // Negative times not currently supported + $setup(D , negedge C &&& CE, /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE, negedge C, 109); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274 @@ -640,7 +656,7 @@ module FDRSE ( Q <= d; endmodule -(* abc9_flop, lib_whitebox *) +(* abc9_box, lib_whitebox *) module FDCE ( output reg Q, (* clkbuf_sink *) @@ -667,8 +683,8 @@ module FDCE ( endgenerate specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , posedge C &&& !IS_C_INVERTED && CE, -46); // Negative times not currently supported - //$setup(D , negedge C &&& IS_C_INVERTED && CE, -46); // Negative times not currently supported + $setup(D , posedge C &&& !IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported + $setup(D , negedge C &&& IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE , posedge C &&& !IS_C_INVERTED, 109); $setup(CE , negedge C &&& IS_C_INVERTED, 109); @@ -676,14 +692,20 @@ module FDCE ( $setup(CLR, posedge C &&& !IS_C_INVERTED, 404); $setup(CLR, negedge C &&& IS_C_INVERTED, 404); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 - //if (!IS_CLR_INVERTED) (posedge CLR => (Q : 1'b0)) = 764; // Captured by $__ABC9_ASYNC0 - //if ( IS_CLR_INVERTED) (negedge CLR => (Q : 1'b0)) = 764; // Captured by $__ABC9_ASYNC0 - if (!IS_C_INVERTED && CLR ~^ IS_CLR_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; - if ( IS_C_INVERTED && CLR ~^ IS_CLR_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; +`ifndef YOSYS + if (!IS_CLR_INVERTED) (posedge CLR => (Q : 1'b0)) = 764; + if ( IS_CLR_INVERTED) (negedge CLR => (Q : 1'b0)) = 764; +`else + if (IS_CLR_INVERTED != CLR) (CLR => Q) = 764; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif + if (!IS_C_INVERTED && CLR == IS_CLR_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; + if ( IS_C_INVERTED && CLR == IS_CLR_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; endspecify endmodule -(* abc9_flop, lib_whitebox *) +(* abc9_box, lib_whitebox *) module FDCE_1 ( output reg Q, (* clkbuf_sink *) @@ -697,18 +719,24 @@ module FDCE_1 ( always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D; specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , negedge C &&& CE, -46); // Negative times not currently supported + $setup(D , negedge C &&& CE, /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE , negedge C, 109); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274 $setup(CLR, negedge C, 404); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 - //(posedge CLR => (Q : 1'b0)) = 764; // Captured by $__ABC9_ASYNC0 +`ifndef YOSYS + (posedge CLR => (Q : 1'b0)) = 764; +`else + if (CLR) (CLR => Q) = 764; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif if (!CLR && CE) (negedge C => (Q : D)) = 303; endspecify endmodule -(* abc9_flop, lib_whitebox *) +(* abc9_box, lib_whitebox *) module FDPE ( output reg Q, (* clkbuf_sink *) @@ -734,8 +762,8 @@ module FDPE ( endgenerate specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , posedge C &&& !IS_C_INVERTED && CE, -46); // Negative times not currently supported - //$setup(D , negedge C &&& IS_C_INVERTED && CE, -46); // Negative times not currently supported + $setup(D , posedge C &&& !IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported + $setup(D , negedge C &&& IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE , posedge C &&& !IS_C_INVERTED, 109); $setup(CE , negedge C &&& IS_C_INVERTED, 109); @@ -743,14 +771,20 @@ module FDPE ( $setup(PRE, posedge C &&& !IS_C_INVERTED, 404); $setup(PRE, negedge C &&& IS_C_INVERTED, 404); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 - //if (!IS_PRE_INVERTED) (posedge PRE => (Q : 1'b1)) = 764; // Captured by $__ABC9_ASYNC1 - //if ( IS_PRE_INVERTED) (negedge PRE => (Q : 1'b1)) = 764; // Captured by $__ABC9_ASYNC1 - if (!IS_C_INVERTED && PRE ~^ IS_PRE_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; - if ( IS_C_INVERTED && PRE ~^ IS_PRE_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; +`ifndef YOSYS + if (!IS_PRE_INVERTED) (posedge PRE => (Q : 1'b1)) = 764; + if ( IS_PRE_INVERTED) (negedge PRE => (Q : 1'b1)) = 764; +`else + if (IS_PRE_INVERTED != PRE) (PRE => Q) = 764; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif + if (!IS_C_INVERTED && PRE == IS_PRE_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; + if ( IS_C_INVERTED && PRE == IS_PRE_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; endspecify endmodule -(* abc9_flop, lib_whitebox *) +(* abc9_box, lib_whitebox *) module FDPE_1 ( output reg Q, (* clkbuf_sink *) @@ -764,14 +798,19 @@ module FDPE_1 ( always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , negedge C &&& CE, -46); // Negative times not currently supported + $setup(D , negedge C &&& CE, /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE , negedge C, 109); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274 $setup(PRE, negedge C, 404); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 - //if (!IS_PRE_INVERTED) (posedge PRE => (Q : 1'b1)) = 764; // Captured by $__ABC9_ASYNC1 - //if (IS_PRE_INVERTED) (negedge PRE => (Q : 1'b1)) = 764; // Captured by $__ABC9_ASYNC1 +`ifndef YOSYS + (posedge PRE => (Q : 1'b1)) = 764; +`else + if (PRE) (PRE => Q) = 764; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif if (!PRE && CE) (negedge C => (Q : D)) = 303; endspecify endmodule @@ -1383,6 +1422,7 @@ module RAM16X1D_1 ( always @(negedge clk) if (WE) mem[a] <= D; endmodule +(* abc9_box, lib_whitebox *) module RAM32X1D ( output DPO, SPO, input D, @@ -1429,15 +1469,15 @@ module RAM32X1D ( if (!IS_WCLK_INVERTED) (posedge WCLK => (DPO : 1'bx)) = 1153; if ( IS_WCLK_INVERTED) (posedge WCLK => (SPO : D)) = 1153; if ( IS_WCLK_INVERTED) (negedge WCLK => (DPO : 1'bx)) = 1153; - // Captured by $__ABC9_RAM6 - //({A0,DPRA0} => {SPO,DPO}) = 642; - //({A1,DPRA1} => {SPO,DPO}) = 631; - //({A2,DPRA2} => {SPO,DPO}) = 472; - //({A3,DPRA3} => {SPO,DPO}) = 407; - //({A4,DPRA4} => {SPO,DPO}) = 238; + (A0 => SPO) = 642; (DPRA0 => DPO) = 642; + (A1 => SPO) = 632; (DPRA1 => DPO) = 631; + (A2 => SPO) = 472; (DPRA2 => DPO) = 472; + (A3 => SPO) = 407; (DPRA3 => DPO) = 407; + (A4 => SPO) = 238; (DPRA4 => DPO) = 238; endspecify endmodule +(* abc9_box, lib_whitebox *) module RAM32X1D_1 ( output DPO, SPO, input D, @@ -1479,15 +1519,15 @@ module RAM32X1D_1 ( // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 if (WE) (negedge WCLK => (SPO : D)) = 1153; if (WE) (negedge WCLK => (DPO : 1'bx)) = 1153; - // Captured by $__ABC9_RAM6 - //({A0,DPRA0} => {SPO,DPO}) = 642; - //({A1,DPRA1} => {SPO,DPO}) = 631; - //({A2,DPRA2} => {SPO,DPO}) = 472; - //({A3,DPRA3} => {SPO,DPO}) = 407; - //({A4,DPRA4} => {SPO,DPO}) = 238; + (A0 => SPO) = 642; (DPRA0 => DPO) = 642; + (A1 => SPO) = 632; (DPRA1 => DPO) = 631; + (A2 => SPO) = 472; (DPRA2 => DPO) = 472; + (A3 => SPO) = 407; (DPRA3 => DPO) = 407; + (A4 => SPO) = 238; (DPRA4 => DPO) = 238; endspecify endmodule +(* abc9_box, lib_whitebox *) module RAM64X1D ( output DPO, SPO, input D, @@ -1537,13 +1577,12 @@ module RAM64X1D ( if (!IS_WCLK_INVERTED && WE) (posedge WCLK => (DPO : 1'bx)) = 1153; if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (SPO : D)) = 1153; if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (DPO : 1'bx)) = 1153; - // Captured by $__ABC9_RAM6 - //({A0,DPRA0} => {SPO,DPO}) = 642; - //({A1,DPRA1} => {SPO,DPO}) = 631; - //({A2,DPRA2} => {SPO,DPO}) = 472; - //({A3,DPRA3} => {SPO,DPO}) = 407; - //({A4,DPRA4} => {SPO,DPO}) = 238; - //({A5,DPRA5} => {SPO,DPO}) = 127; + (A0 => SPO) = 642; (DPRA0 => DPO) = 642; + (A1 => SPO) = 632; (DPRA1 => DPO) = 631; + (A2 => SPO) = 472; (DPRA2 => DPO) = 472; + (A3 => SPO) = 407; (DPRA3 => DPO) = 407; + (A4 => SPO) = 238; (DPRA4 => DPO) = 238; + (A5 => SPO) = 127; (DPRA5 => DPO) = 127; endspecify endmodule @@ -1586,9 +1625,16 @@ module RAM64X1D_1 ( // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 if (WE) (negedge WCLK => (SPO : D)) = 1153; if (WE) (negedge WCLK => (DPO : 1'bx)) = 1153; + (A0 => SPO) = 642; (DPRA0 => DPO) = 642; + (A1 => SPO) = 632; (DPRA1 => DPO) = 631; + (A2 => SPO) = 472; (DPRA2 => DPO) = 472; + (A3 => SPO) = 407; (DPRA3 => DPO) = 407; + (A4 => SPO) = 238; (DPRA4 => DPO) = 238; + (A5 => SPO) = 127; (DPRA5 => DPO) = 127; endspecify endmodule +(* abc9_box, lib_whitebox *) module RAM128X1D ( output DPO, SPO, input D, @@ -1632,22 +1678,21 @@ module RAM128X1D ( // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 if (!IS_WCLK_INVERTED && WE) (posedge WCLK => (SPO : D)) = 1153 + 217 /* to cross F7AMUX */ + 175 /* AMUX */; if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (DPO : 1'bx)) = 1153 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; + (A[0] => SPO) = 642 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; + (A[1] => SPO) = 631 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; + (A[2] => SPO) = 472 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; + (A[3] => SPO) = 407 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; + (A[4] => SPO) = 238 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; + (A[5] => SPO) = 127 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; + (A[6] => SPO) = 0 + 276 /* to select F7AMUX */ + 175 /* AMUX */; + (DPRA[0] => DPO) = 642 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; + (DPRA[1] => DPO) = 631 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; + (DPRA[2] => DPO) = 472 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; + (DPRA[3] => DPO) = 407 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; + (DPRA[4] => DPO) = 238 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; + (DPRA[5] => DPO) = 127 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; + (DPRA[6] => DPO) = 0 + 296 /* to select MUXF7 */ + 174 /* CMUX */; `endif - // Captured by $__ABC9_RAM7 - //(A[0] => SPO) = 642 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; - //(A[1] => SPO) = 631 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; - //(A[2] => SPO) = 472 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; - //(A[3] => SPO) = 407 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; - //(A[4] => SPO) = 238 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; - //(A[5] => SPO) = 127 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; - //(A[6] => SPO) = 0 + 276 /* to select F7AMUX */ + 175 /* AMUX */; - //(DPRA[0] => DPO) = 642 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; - //(DPRA[1] => DPO) = 631 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; - //(DPRA[2] => DPO) = 472 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; - //(DPRA[3] => DPO) = 407 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; - //(DPRA[4] => DPO) = 238 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; - //(DPRA[5] => DPO) = 127 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; - //(DPRA[6] => DPO) = 0 + 296 /* to select MUXF7 */ + 174 /* CMUX */; endspecify endmodule @@ -1671,6 +1716,7 @@ endmodule // Multi port. +(* abc9_box, lib_whitebox *) module RAM32M ( output [1:0] DOA, output [1:0] DOB, @@ -1767,12 +1813,11 @@ module RAM32M ( // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1061 if (!IS_WCLK_INVERTED && WE) (posedge WCLK => (DOD[1] : DID[1])) = 1190; if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (DOD[1] : DID[1])) = 1190; - // Captured by $__ABC9_RAM6 - //({{2{ADDRA[0]}},{2{ADDRB[0]}},{2{ADDRC[0]}},{2{ADDRD[0]}}} => {DOA,DOB,DOC,DOD}) = 642; - //({{2{ADDRA[1]}},{2{ADDRB[1]}},{2{ADDRC[1]}},{2{ADDRD[1]}}} => {DOA,DOB,DOC,DOD}) = 631; - //({{2{ADDRA[2]}},{2{ADDRB[2]}},{2{ADDRC[2]}},{2{ADDRD[2]}}} => {DOA,DOB,DOC,DOD}) = 472; - //({{2{ADDRA[3]}},{2{ADDRB[3]}},{2{ADDRC[3]}},{2{ADDRD[3]}}} => {DOA,DOB,DOC,DOD}) = 407; - //({{2{ADDRA[4]}},{2{ADDRB[4]}},{2{ADDRC[4]}},{2{ADDRD[4]}}} => {DOA,DOB,DOC,DOD}) = 238; + (ADDRA[0] *> DOA) = 642; (ADDRB[0] *> DOB) = 642; (ADDRC[0] *> DOC) = 642; (ADDRD[0] *> DOD) = 642; + (ADDRA[1] *> DOA) = 631; (ADDRB[1] *> DOB) = 631; (ADDRC[1] *> DOC) = 631; (ADDRD[1] *> DOD) = 631; + (ADDRA[2] *> DOA) = 472; (ADDRB[2] *> DOB) = 472; (ADDRC[2] *> DOC) = 472; (ADDRD[2] *> DOD) = 472; + (ADDRA[3] *> DOA) = 407; (ADDRB[3] *> DOB) = 407; (ADDRC[3] *> DOC) = 407; (ADDRD[3] *> DOD) = 407; + (ADDRA[4] *> DOA) = 238; (ADDRB[4] *> DOB) = 238; (ADDRC[4] *> DOC) = 238; (ADDRD[4] *> DOD) = 238; endspecify endmodule @@ -1845,6 +1890,7 @@ module RAM32M16 ( end endmodule +(* abc9_box, lib_whitebox *) module RAM64M ( output DOA, output DOB, @@ -1923,12 +1969,11 @@ module RAM64M ( // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093 if (!IS_WCLK_INVERTED && WE) (posedge WCLK => (DOD : DID)) = 1163; if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (DOD : DID)) = 1163; - // Captured by $__ABC9_RAM6 - //({ADDRA[0],ADDRB[0],ADDRC[0],ADDRD[0]} => {DOA,DOB,DOC,DOD}) = 642; - //({ADDRA[1],ADDRB[1],ADDRC[1],ADDRD[1]} => {DOA,DOB,DOC,DOD}) = 631; - //({ADDRA[2],ADDRB[2],ADDRC[2],ADDRD[2]} => {DOA,DOB,DOC,DOD}) = 472; - //({ADDRA[3],ADDRB[3],ADDRC[3],ADDRD[3]} => {DOA,DOB,DOC,DOD}) = 407; - //({ADDRA[4],ADDRB[4],ADDRC[4],ADDRD[4]} => {DOA,DOB,DOC,DOD}) = 238; + (ADDRA[0] => DOA) = 642; (ADDRB[0] => DOB) = 642; (ADDRC[0] => DOC) = 642; (ADDRD[0] => DOD) = 642; + (ADDRA[1] => DOA) = 631; (ADDRB[1] => DOB) = 631; (ADDRC[1] => DOC) = 631; (ADDRD[1] => DOD) = 631; + (ADDRA[2] => DOA) = 472; (ADDRB[2] => DOB) = 472; (ADDRC[2] => DOC) = 472; (ADDRD[2] => DOD) = 472; + (ADDRA[3] => DOA) = 407; (ADDRB[3] => DOB) = 407; (ADDRC[3] => DOC) = 407; (ADDRD[3] => DOD) = 407; + (ADDRA[4] => DOA) = 238; (ADDRB[4] => DOB) = 238; (ADDRC[4] => DOC) = 238; (ADDRD[4] => DOD) = 238; endspecify endmodule @@ -2045,6 +2090,7 @@ endmodule // Shift registers. +(* abc9_box, lib_whitebox *) module SRL16 ( output Q, input A0, A1, A2, A3, @@ -2063,14 +2109,14 @@ module SRL16 ( (posedge CLK => (Q : 1'bx)) = 1472; // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L912 $setup(D , posedge CLK, 173); - // Captured by $__ABC9_RAM6 - //(A0 => Q) = 631; - //(A1 => Q) = 472; - //(A2 => Q) = 407; - //(A3 => Q) = 238; + (A0 => Q) = 631; + (A1 => Q) = 472; + (A2 => Q) = 407; + (A3 => Q) = 238; endspecify endmodule +(* abc9_box, lib_whitebox *) module SRL16E ( output Q, input A0, A1, A2, A3, CE, @@ -2096,16 +2142,19 @@ module SRL16E ( $setup(D , posedge CLK &&& !IS_CLK_INVERTED, 173); $setup(D , negedge CLK &&& IS_CLK_INVERTED, 173); // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905 + if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : D)) = 1472; + if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : D)) = 1472; + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905 if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : 1'bx)) = 1472; if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : 1'bx)) = 1472; - // Captured by $__ABC9_RAM6 - //(A0 => Q) = 631; - //(A1 => Q) = 472; - //(A2 => Q) = 407; - //(A3 => Q) = 238; + (A0 => Q) = 631; + (A1 => Q) = 472; + (A2 => Q) = 407; + (A3 => Q) = 238; endspecify endmodule +(* abc9_box, lib_whitebox *) module SRLC16 ( output Q, output Q15, @@ -2122,18 +2171,20 @@ module SRLC16 ( always @(posedge CLK) r <= { r[14:0], D }; specify - // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905 - (posedge CLK => (Q : 1'bx)) = 1472; // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L912 $setup(D , posedge CLK, 173); - // Captured by $__ABC9_RAM6 - //(A0 => Q) = 631; - //(A1 => Q) = 472; - //(A2 => Q) = 407; - //(A3 => Q) = 238; + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905 + (posedge CLK => (Q : 1'bx)) = 1472; + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904 + (posedge CLK => (Q15 : 1'bx)) = 1114; + (A0 => Q) = 631; + (A1 => Q) = 472; + (A2 => Q) = 407; + (A3 => Q) = 238; endspecify endmodule +(* abc9_box, lib_whitebox *) module SRLC16E ( output Q, output Q15, @@ -2160,18 +2211,23 @@ module SRLC16E ( // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L912 $setup(D , posedge CLK &&& !IS_CLK_INVERTED, 173); $setup(D , negedge CLK &&& IS_CLK_INVERTED, 173); + // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 + $setup(CE, posedge CLK &&& !IS_CLK_INVERTED, 109); + $setup(CE, negedge CLK &&& IS_CLK_INVERTED, 109); // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905 if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : D)) = 1472; if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : D)) = 1472; - // Captured by $__ABC9_RAM6 - //(A0 => Q) = 642; - //(A1 => Q) = 631; - //(A2 => Q) = 472; - //(A3 => Q) = 407; - //(A4 => Q) = 238; + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904 + if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q15 : 1'bx)) = 1114; + if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q15 : 1'bx)) = 1114; + (A0 => Q) = 631; + (A1 => Q) = 472; + (A2 => Q) = 407; + (A3 => Q) = 238; endspecify endmodule +(* abc9_box, lib_whitebox *) module SRLC32E ( output Q, output Q31, @@ -2199,18 +2255,20 @@ module SRLC32E ( // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L912 $setup(D , posedge CLK &&& !IS_CLK_INVERTED, 173); $setup(D , negedge CLK &&& IS_CLK_INVERTED, 173); + // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 + $setup(CE, posedge CLK &&& !IS_CLK_INVERTED, 109); + $setup(CE, negedge CLK &&& IS_CLK_INVERTED, 109); // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905 if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : 1'bx)) = 1472; if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : 1'bx)) = 1472; // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904 - if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : 1'bx)) = 1114; - if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : 1'bx)) = 1114; - // Captured by $__ABC9_RAM6 - //(A0 => Q) = 642; - //(A1 => Q) = 631; - //(A2 => Q) = 472; - //(A3 => Q) = 407; - //(A4 => Q) = 238; + if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q31 : 1'bx)) = 1114; + if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q31 : 1'bx)) = 1114; + (A[0] => Q) = 642; + (A[1] => Q) = 631; + (A[2] => Q) = 472; + (A[3] => Q) = 407; + (A[4] => Q) = 238; endspecify endmodule @@ -2978,6 +3036,10 @@ endmodule // Virtex 6, Series 7. +`ifdef YOSYS +(* abc9_box=!(PREG || AREG || ADREG || BREG || CREG || DREG || MREG), + lib_whitebox=!(PREG || AREG || ADREG || BREG || CREG || DREG || MREG) *) +`endif module DSP48E1 ( output [29:0] ACOUT, output [17:0] BCOUT, diff --git a/techlibs/xilinx/lut_map.v b/techlibs/xilinx/lut_map.v index ec2e3b234..2ab6075f1 100644 --- a/techlibs/xilinx/lut_map.v +++ b/techlibs/xilinx/lut_map.v @@ -26,6 +26,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/xilinx/mux_map.v b/techlibs/xilinx/mux_map.v index 91aaf2118..bb31d21ec 100644 --- a/techlibs/xilinx/mux_map.v +++ b/techlibs/xilinx/mux_map.v @@ -30,8 +30,11 @@ module \$shiftx (A, B, Y); parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] Y; parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0; diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 229ffcb3d..d0de73f83 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -143,7 +143,7 @@ struct SynthXilinxPass : public ScriptPass std::string top_opt, edif_file, blif_file, family; bool flatten, retime, vpr, ise, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, uram; - bool abc9, dff_mode; + bool abc9, dff; bool flatten_before_abc; int widemux; int lut_size; @@ -170,7 +170,7 @@ struct SynthXilinxPass : public ScriptPass nodsp = false; uram = false; abc9 = false; - dff_mode = false; + dff = false; flatten_before_abc = false; widemux = 0; lut_size = 6; @@ -217,7 +217,7 @@ struct SynthXilinxPass : public ScriptPass continue; } if (args[argidx] == "-retime") { - dff_mode = true; + dff = true; retime = true; continue; } @@ -281,7 +281,7 @@ struct SynthXilinxPass : public ScriptPass continue; } if (args[argidx] == "-dff") { - dff_mode = true; + dff = true; continue; } break; @@ -595,9 +595,11 @@ struct SynthXilinxPass : public ScriptPass run("clean"); } - if (check_label("map_ffs")) { + if (check_label("map_ffs", "('-abc9' only)")) { if (abc9 || help_mode) { - run("techmap -map " + ff_map_file, "('-abc9' only)"); + if (dff || help_mode) + run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "('-dff' only)"); + run("techmap -map " + ff_map_file); } } @@ -606,18 +608,14 @@ struct SynthXilinxPass : public ScriptPass if (flatten_before_abc) run("flatten"); if (help_mode) - run("abc -luts 2:2,3,6:5[,10,20] [-dff] [-D 1]", "(option for 'nowidelut', '-dff', '-retime')"); + run("abc -luts 2:2,3,6:5[,10,20] [-dff] [-D 1]", "(option for '-nowidelut', '-dff', '-retime')"); else if (abc9) { if (lut_size != 6) log_error("'synth_xilinx -abc9' not currently supported for LUT4-based devices.\n"); if (family != "xc7") log_warning("'synth_xilinx -abc9' not currently supported for the '%s' family, " "will use timing for 'xc7' instead.\n", family.c_str()); - std::string techmap_args = "-map +/xilinx/abc9_map.v -max_iter 1"; - if (dff_mode) - techmap_args += " -D DFF_MODE"; - run("techmap " + techmap_args); - run("read_verilog -icells -lib -specify +/abc9_model.v +/xilinx/abc9_model.v"); + run("read_verilog -icells -lib -specify +/xilinx/abc9_model.v"); std::string abc9_opts; std::string k = "synth_xilinx.abc9.W"; if (active_design && active_design->scratchpad.count(k)) @@ -628,10 +626,9 @@ struct SynthXilinxPass : public ScriptPass } if (nowidelut) abc9_opts += stringf(" -maxlut %d", lut_size); - if (dff_mode) + if (dff) abc9_opts += " -dff"; run("abc9" + abc9_opts); - run("techmap -map +/xilinx/abc9_unmap.v"); } else { std::string abc_opts; @@ -648,7 +645,7 @@ struct SynthXilinxPass : public ScriptPass else abc_opts += " -luts 2:2,3,6:5,10,20,40"; } - if (dff_mode) + if (dff) abc_opts += " -dff"; if (retime) abc_opts += " -D 1"; diff --git a/tests/arch/intel_alm/lutram.ys b/tests/arch/intel_alm/lutram.ys new file mode 100644 index 000000000..6f997b67b --- /dev/null +++ b/tests/arch/intel_alm/lutram.ys @@ -0,0 +1,20 @@ +read_verilog ../common/lutram.v +hierarchy -top lutram_1w1r +proc +memory -nomap +equiv_opt -run :prove -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v -map +/intel_alm/common/mem_sim.v synth_intel_alm -family cyclonev -nobram +memory +opt -full + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter + +design -load postopt +cd lutram_1w1r +select -assert-count 16 t:MISTRAL_MLAB +select -assert-count 1 t:MISTRAL_NOT +select -assert-count 2 t:MISTRAL_ALUT2 +select -assert-count 8 t:MISTRAL_ALUT3 +select -assert-count 17 t:MISTRAL_FF +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_FF t:MISTRAL_MLAB %% t:* %D + diff --git a/tests/arch/xilinx/abc9_dff.ys b/tests/arch/xilinx/abc9_dff.ys index b457cefce..fd343969b 100644 --- a/tests/arch/xilinx/abc9_dff.ys +++ b/tests/arch/xilinx/abc9_dff.ys @@ -1,32 +1,85 @@ +logger -nowarn "Yosys has only limited support for tri-state logic at the moment\. .*" + +read_verilog <<EOT +module top(input C, D, output [7:0] Q); +FDRE /*#(.INIT(0))*/ fd1(.C(C), .CE(1'b1), .D(D), .R(1'b1), .Q(Q[0])); +FDSE #(.INIT(0)) fd2(.C(C), .CE(1'b1), .D(D), .S(1'b1), .Q(Q[1])); +FDCE #(.INIT(0)) fd3(.C(C), .CE(1'b1), .D(D), .CLR(1'b1), .Q(Q[2])); +FDPE #(.INIT(0)) fd4(.C(C), .CE(1'b1), .D(D), .PRE(1'b1), .Q(Q[3])); +FDRE_1 #(.INIT(0)) fd5(.C(C), .CE(1'b1), .D(D), .R(1'b1), .Q(Q[4])); +FDSE_1 #(.INIT(0)) fd6(.C(C), .CE(1'b1), .D(D), .S(1'b1), .Q(Q[5])); +FDCE_1 #(.INIT(0)) fd7(.C(C), .CE(1'b1), .D(D), .CLR(1'b1), .Q(Q[6])); +FDPE_1 #(.INIT(0)) fd8(.C(C), .CE(1'b1), .D(D), .PRE(1'b1), .Q(Q[7])); +endmodule +EOT +equiv_opt -assert -multiclock -map +/xilinx/cells_sim.v synth_xilinx -abc9 -dff -noiopad -noclkbuf +design -load postopt +select -assert-count 6 t:FD* +select -assert-count 6 c:fd2 c:fd3 c:fd4 c:fd6 c:fd7 c:fd8 + + +design -reset read_verilog <<EOT module top(input C, D, output [7:0] Q); -FDRE fd1(.C(C), .CE(1'b1), .D(D), .R(1'b1), .Q(Q[0])); -FDSE fd2(.C(C), .CE(1'b1), .D(D), .S(1'b1), .Q(Q[1])); -FDCE fd3(.C(C), .CE(1'b1), .D(D), .CLR(1'b1), .Q(Q[2])); -FDPE fd4(.C(C), .CE(1'b1), .D(D), .PRE(1'b1), .Q(Q[3])); -FDRE_1 fd5(.C(C), .CE(1'b1), .D(D), .R(1'b1), .Q(Q[4])); -FDSE_1 fd6(.C(C), .CE(1'b1), .D(D), .S(1'b1), .Q(Q[5])); -FDCE_1 fd7(.C(C), .CE(1'b1), .D(D), .CLR(1'b1), .Q(Q[6])); -FDPE_1 fd8(.C(C), .CE(1'b1), .D(D), .PRE(1'b1), .Q(Q[7])); +FDRE #(.INIT(0)) fd1(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[0])); +FDSE #(.INIT(0)) fd2(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[1])); +FDCE #(.INIT(0)) fd3(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[2])); +FDPE #(.INIT(0)) fd4(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[3])); +FDRE_1 /*#(.INIT(0))*/ fd5(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[4])); +FDSE_1 #(.INIT(0)) fd6(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[5])); +FDCE_1 #(.INIT(0)) fd7(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[6])); +FDPE_1 #(.INIT(0)) fd8(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[7])); endmodule EOT equiv_opt -assert -multiclock -map +/xilinx/cells_sim.v synth_xilinx -abc9 -dff -noiopad -noclkbuf design -load postopt -select -assert-none t:FD* +select -assert-count 4 t:FD* +select -assert-count 4 c:fd3 c:fd4 c:fd7 c:fd8 + design -reset read_verilog <<EOT module top(input C, D, output [7:0] Q); -FDRE fd1(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[0])); -FDSE fd2(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[1])); -FDCE fd3(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[2])); -FDPE fd4(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[3])); -FDRE_1 fd5(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[4])); -FDSE_1 fd6(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[5])); -FDCE_1 fd7(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[6])); -FDPE_1 fd8(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[7])); +FDRE #(.INIT(1)) fd1(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[0])); +FDSE /*#(.INIT(1))*/ fd2(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[1])); +FDCE #(.INIT(1)) fd3(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[2])); +FDPE #(.INIT(1)) fd4(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[3])); +FDRE_1 #(.INIT(1)) fd5(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[4])); +FDSE_1 #(.INIT(1)) fd6(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[5])); +FDCE_1 /*#(.INIT(1))*/ fd7(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[6])); +FDPE_1 #(.INIT(1)) fd8(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[7])); +endmodule +EOT +logger -expect warning "Module '\$paramod\\FDRE\\INIT=1' contains a \$dff cell .*" 1 +logger -expect warning "Module '\$paramod\\FDRE_1\\INIT=1' contains a \$dff cell .*" 1 +logger -expect warning "Module 'FDSE' contains a \$dff cell .*" 1 +logger -expect warning "Module '\$paramod\\FDSE_1\\INIT=1' contains a \$dff cell .*" 1 +equiv_opt -assert -multiclock -map +/xilinx/cells_sim.v synth_xilinx -abc9 -dff -noiopad -noclkbuf +design -load postopt +select -assert-count 8 t:FD* + + +design -reset +read_verilog <<EOT +module top(input clk, clr, pre, output reg q0 = 1'b0, output reg q1 = 1'b1); +always @(posedge clk or posedge clr) + if (clr) + q0 <= 1'b0; + else + q0 <= ~q0; +always @(posedge clk or posedge pre) + if (pre) + q1 <= 1'b1; + else + q1 <= ~q1; endmodule EOT +proc equiv_opt -assert -multiclock -map +/xilinx/cells_sim.v synth_xilinx -abc9 -dff -noiopad -noclkbuf design -load postopt -select -assert-none t:FD* +select -assert-count 1 t:FDCE +select -assert-count 1 t:FDPE +select -assert-count 2 t:INV +select -assert-count 0 t:FD* t:INV %% t:* %D + +logger -expect-no-warnings diff --git a/tests/arch/xilinx/abc9_map.ys b/tests/arch/xilinx/abc9_map.ys deleted file mode 100644 index 4a7b9384a..000000000 --- a/tests/arch/xilinx/abc9_map.ys +++ /dev/null @@ -1,91 +0,0 @@ -read_verilog <<EOT -module top(input C, CE, D, R, output [1:0] Q); -FDRE #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .R(R), .Q(Q[0])); -FDRE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .R(R), .Q(Q[1])); -endmodule -EOT -design -save gold - -techmap -map +/xilinx/abc9_map.v -max_iter 1 -D DFF_MODE -techmap -map +/xilinx/abc9_unmap.v -select -assert-count 1 t:FDSE -select -assert-count 1 t:FDSE_1 -techmap -autoproc -map +/xilinx/cells_sim.v -design -stash gate - -design -import gold -as gold -design -import gate -as gate -techmap -autoproc -map +/xilinx/cells_sim.v - -miter -equiv -flatten -make_assert -make_outputs gold gate miter -sat -seq 2 -verify -prove-asserts -show-ports miter - -design -reset -read_verilog <<EOT -module top(input C, CE, D, S, output [1:0] Q); -FDSE #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .S(S), .Q(Q[0])); -FDSE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .S(S), .Q(Q[1])); -endmodule -EOT -design -save gold - -techmap -map +/xilinx/abc9_map.v -max_iter 1 -D DFF_MODE -techmap -map +/xilinx/abc9_unmap.v -select -assert-count 1 t:FDRE -select -assert-count 1 t:FDRE_1 -techmap -autoproc -map +/xilinx/cells_sim.v -design -stash gate - -design -import gold -as gold -design -import gate -as gate -techmap -autoproc -map +/xilinx/cells_sim.v - -miter -equiv -flatten -make_assert -make_outputs gold gate miter -sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter - -design -reset -read_verilog <<EOT -module top(input C, CE, D, PRE, output [1:0] Q); -FDPE #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .PRE(PRE), .Q(Q[0])); -FDPE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .PRE(PRE), .Q(Q[1])); -endmodule -EOT -design -save gold - -techmap -map +/xilinx/abc9_map.v -max_iter 1 -D DFF_MODE -techmap -map +/xilinx/abc9_unmap.v -select -assert-count 1 t:FDCE -select -assert-count 1 t:FDCE_1 -techmap -autoproc -map +/xilinx/cells_sim.v -design -stash gate - -design -import gold -as gold -design -import gate -as gate -techmap -autoproc -map +/xilinx/cells_sim.v -clk2fflogic - -miter -equiv -flatten -make_assert -make_outputs gold gate miter -sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter - -design -reset -read_verilog <<EOT -module top(input C, CE, D, CLR, output [1:0] Q); -FDCE #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .CLR(CLR), .Q(Q[0])); -FDCE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .CLR(CLR), .Q(Q[1])); -endmodule -EOT -design -save gold - -techmap -map +/xilinx/abc9_map.v -max_iter 1 -D DFF_MODE -techmap -map +/xilinx/abc9_unmap.v -select -assert-count 1 t:FDPE -techmap -autoproc -map +/xilinx/cells_sim.v -design -stash gate - -design -import gold -as gold -design -import gate -as gate -techmap -autoproc -map +/xilinx/cells_sim.v -clk2fflogic - -miter -equiv -flatten -make_assert -make_outputs gold gate miter -sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter diff --git a/tests/arch/xilinx/mux.ys b/tests/arch/xilinx/mux.ys index 99817738d..1b2788448 100644 --- a/tests/arch/xilinx/mux.ys +++ b/tests/arch/xilinx/mux.ys @@ -40,8 +40,10 @@ proc equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux16 # Constrain all select calls below inside the top module -select -assert-min 5 t:LUT6 +select -assert-max 2 t:LUT4 +select -assert-min 4 t:LUT6 select -assert-max 7 t:LUT6 select -assert-max 2 t:MUXF7 +dump -select -assert-none t:LUT6 t:MUXF7 %% t:* %D +select -assert-none t:LUT6 t:LUT4 t:MUXF7 %% t:* %D diff --git a/tests/fsm/generate.py b/tests/fsm/generate.py index c8eda0cd1..784e5a054 100644 --- a/tests/fsm/generate.py +++ b/tests/fsm/generate.py @@ -36,9 +36,11 @@ parser.add_argument('-S', '--seed', type = int, help = 'seed for PRNG') parser.add_argument('-c', '--count', type = int, default = 50, help = 'number of test cases to generate') args = parser.parse_args() -if args.seed is not None: - print("PRNG seed: %d" % args.seed) - random.seed(args.seed) +seed = args.seed +if seed is None: + seed = random.randrange(sys.maxsize) +print("PRNG seed: %d" % seed) +random.seed(seed) for idx in range(args.count): with open('temp/uut_%05d.v' % idx, 'w') as f: diff --git a/tests/opt/bug1758.ys b/tests/opt/bug1758.ys new file mode 100644 index 000000000..85dfaceb8 --- /dev/null +++ b/tests/opt/bug1758.ys @@ -0,0 +1,21 @@ +read_verilog -noopt <<EOT +module gold(input i, output o); +assign o = 1'bx | i; +endmodule +EOT +copy gold coarse +copy gold fine + +cd coarse +opt_expr +select -assert-none c:* + +cd fine +opt_expr +select -assert-none c:* + +cd +miter -equiv -flatten -make_assert -make_outputs coarse fine miter +sat -verify -prove-asserts -show-ports miter +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter2 +sat -verify -prove-asserts -show-ports -enable_undef miter2 diff --git a/tests/opt/opt_clean_init.ys b/tests/opt/opt_clean_init.ys new file mode 100644 index 000000000..0d567608d --- /dev/null +++ b/tests/opt/opt_clean_init.ys @@ -0,0 +1,13 @@ +logger -expect warning "Initial value conflict for \\y resolving to 1'0 but with init 1'1" 1 +logger -expect-no-warnings +read_verilog <<EOT +module top; +(* init=1'b0 *) wire w = 1'b0; +(* init=1'bx *) wire x = 1'b0; +(* init=1'b1 *) wire y = 1'b0; +(* init=1'b0 *) wire z = 1'bx; +endmodule +EOT +clean +select -assert-count 1 a:init +select -assert-count 1 w:y a:init %i diff --git a/tests/opt/opt_expr_alu.ys b/tests/opt/opt_expr_alu.ys index 9121c0096..477555da9 100644 --- a/tests/opt/opt_expr_alu.ys +++ b/tests/opt/opt_expr_alu.ys @@ -59,9 +59,8 @@ EOT alumacc equiv_opt -assert opt_expr -fine design -load postopt -select -assert-count 1 t:$pos select -assert-count 1 t:$not -select -assert-none t:$pos t:$not %% t:* %D +select -assert-none t:$not %% t:* %D design -reset diff --git a/tests/opt/opt_expr_and.ys b/tests/opt/opt_expr_and.ys new file mode 100644 index 000000000..a7676a1df --- /dev/null +++ b/tests/opt/opt_expr_and.ys @@ -0,0 +1,85 @@ +# Single-bit $and +read_verilog -noopt <<EOT +module gold(input i, output o); +assign o = 1'bx & i; +endmodule +EOT +select -assert-count 1 t:$and +copy gold coarse +copy gold fine +copy gold coarse_keepdc +copy gold fine_keepdc + +cd coarse +opt_expr +select -assert-none c:* + +cd fine +simplemap +opt_expr +select -assert-none c:* + +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter +sat -verify -prove-asserts -show-ports -enable_undef miter +miter -equiv -flatten -make_assert -make_outputs coarse fine miter2 +sat -verify -prove-asserts -show-ports -enable_undef miter2 + +cd coarse_keepdc +opt_expr -keepdc +select -assert-count 1 c:* + +cd fine_keepdc +simplemap +opt_expr -keepdc +select -assert-count 1 c:* + +cd +miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3 +sat -verify -prove-asserts -show-ports -enable_undef miter3 +miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4 +sat -verify -prove-asserts -show-ports -enable_undef miter4 + + +# Multi-bit $and +design -reset +read_verilog -noopt <<EOT +module gold(input i, output [6:0] o); +assign o = {1'bx, 1'b0, 1'b0, 1'b1, 1'bx, 1'b1, i} & {7{i}}; +endmodule +EOT +select -assert-count 1 t:$and +copy gold coarse +copy gold fine +copy gold coarse_keepdc +copy gold fine_keepdc + +cd coarse +opt_expr -fine +select -assert-none c:* + +cd fine +simplemap +opt_expr +select -assert-none c:* + +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter +sat -verify -prove-asserts -show-ports -enable_undef miter +miter -equiv -flatten -make_assert -make_outputs coarse fine miter2 +sat -verify -prove-asserts -show-ports -enable_undef miter2 + +cd coarse_keepdc +opt_expr -fine -keepdc +select -assert-count 1 c:* + +cd fine_keepdc +simplemap +opt_expr -keepdc +select -assert-count 2 c:* + +cd +miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3 +sat -verify -prove-asserts -show-ports -enable_undef miter3 +miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4 +sat -verify -prove-asserts -show-ports -enable_undef miter4 diff --git a/tests/opt/opt_expr_consumex.ys b/tests/opt/opt_expr_consumex.ys new file mode 100644 index 000000000..d4af10f22 --- /dev/null +++ b/tests/opt/opt_expr_consumex.ys @@ -0,0 +1,35 @@ +read_verilog <<EOT +module top(input a, b, output o); +wire tmp; +assign o = tmp | 1'bx; +assign tmp = a & 1'b0; +endmodule +EOT +design -save read +select -assert-count 1 t:$and +select -assert-count 1 t:$or + + +opt_expr +select -assert-none t:$and t:$or +sat -verify -enable_undef -prove o 1'bx + + +design -load read +opt_expr -keepdc +select -assert-none t:$and t:$or +sat -verify -enable_undef -prove o 1'bx + + +design -load read +simplemap +opt_expr -keepdc +select -assert-none t:$_AND_ t:$_OR_ +sat -verify -enable_undef -prove o 1'bx + + +design -load read +simplemap +opt_expr -keepdc +select -assert-none t:$_AND_ t:$_OR_ +sat -verify -enable_undef -prove o 1'bx diff --git a/tests/opt/opt_expr_or.ys b/tests/opt/opt_expr_or.ys new file mode 100644 index 000000000..f86da0d46 --- /dev/null +++ b/tests/opt/opt_expr_or.ys @@ -0,0 +1,85 @@ +# Single-bit $or +read_verilog -noopt <<EOT +module gold(input i, output o); +assign o = 1'bx | i; +endmodule +EOT +select -assert-count 1 t:$or +copy gold coarse +copy gold fine +copy gold coarse_keepdc +copy gold fine_keepdc + +cd coarse +opt_expr +select -assert-none c:* + +cd fine +simplemap +opt_expr +select -assert-none c:* + +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter +sat -verify -prove-asserts -show-ports -enable_undef miter +miter -equiv -flatten -make_assert -make_outputs coarse fine miter2 +sat -verify -prove-asserts -show-ports -enable_undef miter2 + +cd coarse_keepdc +opt_expr -keepdc +select -assert-count 1 c:* + +cd fine_keepdc +simplemap +opt_expr -keepdc +select -assert-count 1 c:* + +cd +miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3 +sat -verify -prove-asserts -show-ports -enable_undef miter3 +miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4 +sat -verify -prove-asserts -show-ports -enable_undef miter4 + + +# Multi-bit $or +design -reset +read_verilog -noopt <<EOT +module gold(input i, output [6:0] o); +assign o = {1'bx, 1'b0, 1'b0, 1'b1, 1'bx, 1'b1, i} | {7{i}}; +endmodule +EOT +select -assert-count 1 t:$or +copy gold coarse +copy gold fine +copy gold coarse_keepdc +copy gold fine_keepdc + +cd coarse +opt_expr -fine +select -assert-none c:* + +cd fine +simplemap +opt_expr +select -assert-none c:* + +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter +sat -verify -prove-asserts -show-ports -enable_undef miter +miter -equiv -flatten -make_assert -make_outputs coarse fine miter2 +sat -verify -prove-asserts -show-ports -enable_undef miter2 + +cd coarse_keepdc +opt_expr -fine -keepdc +select -assert-count 1 c:* + +cd fine_keepdc +simplemap +opt_expr -keepdc +select -assert-count 2 c:* + +cd +miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3 +sat -verify -prove-asserts -show-ports -enable_undef miter3 +miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4 +sat -verify -prove-asserts -show-ports -enable_undef miter4 diff --git a/tests/opt/opt_expr_xnor.ys b/tests/opt/opt_expr_xnor.ys new file mode 100644 index 000000000..f8ef0d352 --- /dev/null +++ b/tests/opt/opt_expr_xnor.ys @@ -0,0 +1,131 @@ +# Single-bit $xnor +read_verilog -noopt <<EOT +module gold(input i, output o); +assign o = 1'bx ~^ i; +endmodule +EOT +select -assert-count 1 t:$xnor +copy gold coarse +copy gold fine +copy gold coarse_keepdc +copy gold fine_keepdc + +cd coarse +opt_expr +select -assert-none t:$xnor + +cd fine +simplemap +opt_expr +select -assert-none c:t$_XNOR_ + +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter +sat -verify -prove-asserts -show-ports -enable_undef miter +miter -equiv -flatten -make_assert -make_outputs coarse fine miter2 +sat -verify -prove-asserts -show-ports -enable_undef miter2 + +cd coarse_keepdc +opt_expr -keepdc +select -assert-count 1 c:* + +cd fine_keepdc +simplemap +opt_expr -keepdc +select -assert-count 1 t:$_XOR_ + +cd +miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3 +sat -verify -prove-asserts -show-ports -enable_undef miter3 +miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4 +sat -verify -prove-asserts -show-ports -enable_undef miter4 + + +# Multi-bit $xnor +design -reset +read_verilog -noopt <<EOT +module gold(input i, output [6:0] o); +assign o = {1'bx, 1'b0, 1'b0, 1'b1, 1'bx, 1'b1, i} ~^ {7{i}}; +endmodule +EOT +select -assert-count 1 t:$xnor +copy gold coarse +copy gold fine +copy gold coarse_keepdc +copy gold fine_keepdc + +cd coarse +opt_expr -fine +select -assert-none t:$xnor + +cd fine +simplemap +opt_expr +select -assert-none t:$_XNOR_ + +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter +sat -verify -prove-asserts -show-ports -enable_undef miter +miter -equiv -flatten -make_assert -make_outputs coarse fine miter2 +sat -verify -prove-asserts -show-ports -enable_undef miter2 + +cd coarse_keepdc +opt_expr -keepdc -fine +select -assert-count 1 t:$xnor + +cd fine_keepdc +simplemap +opt_expr -keepdc +select -assert-count 0 c:$_XOR_ + +cd +miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3 +sat -verify -prove-asserts -show-ports -enable_undef miter3 +miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4 +sat -verify -prove-asserts -show-ports -enable_undef miter4 + + +# Single-bit $xnor extension +design -reset +read_verilog -noopt <<EOT +module gold(input i, output [1:0] o, p, q); +assign o = i ~^ i; +assign p = 1'b0 ~^ i; +assign q = 1'b1 ~^ i; +endmodule +EOT +select -assert-count 3 t:$xnor +copy gold coarse +copy gold fine +copy gold coarse_keepdc +copy gold fine_keepdc + +cd coarse +opt_expr -fine +select -assert-none t:$xnor + +cd fine +simplemap +opt_expr +select -assert-none t:$_XNOR_ + +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter +sat -verify -prove-asserts -show-ports -enable_undef miter +miter -equiv -flatten -make_assert -make_outputs coarse fine miter2 +sat -verify -prove-asserts -show-ports -enable_undef miter2 + +cd coarse_keepdc +opt_expr -keepdc -fine +select -assert-count 1 t:$xnor + +cd fine_keepdc +simplemap +opt_expr -keepdc +select -assert-count 0 c:$_XNOR_ + +cd +miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3 +sat -verify -prove-asserts -show-ports -enable_undef miter3 +miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4 +sat -verify -prove-asserts -show-ports -enable_undef miter4 diff --git a/tests/opt/opt_expr_xor.ys b/tests/opt/opt_expr_xor.ys index 21439fd53..a879f3ec9 100644 --- a/tests/opt/opt_expr_xor.ys +++ b/tests/opt/opt_expr_xor.ys @@ -50,3 +50,91 @@ assign z = a~^1'b1; endmodule EOT equiv_opt opt_expr + + +# Single-bit $xor +design -reset +read_verilog -noopt <<EOT +module gold(input i, output o); +assign o = 1'bx ^ i; +endmodule +EOT +select -assert-count 1 t:$xor +copy gold coarse +copy gold fine +copy gold coarse_keepdc +copy gold fine_keepdc + +cd coarse +opt_expr +select -assert-none c:* + +cd fine +simplemap +opt_expr +select -assert-none c:* + +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter +sat -verify -prove-asserts -show-ports -enable_undef miter +miter -equiv -flatten -make_assert -make_outputs coarse fine miter2 +sat -verify -prove-asserts -show-ports -enable_undef miter2 + +cd coarse_keepdc +opt_expr -keepdc +select -assert-count 1 c:* + +cd fine_keepdc +simplemap +opt_expr -keepdc +select -assert-count 1 c:* + +cd +miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3 +sat -verify -prove-asserts -show-ports -enable_undef miter3 +miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4 +sat -verify -prove-asserts -show-ports -enable_undef miter4 + + +# Multi-bit $xor +design -reset +read_verilog -noopt <<EOT +module gold(input i, output [6:0] o); +assign o = {1'bx, 1'b0, 1'b0, 1'b1, 1'bx, 1'b1, i} ^ {7{i}}; +endmodule +EOT +select -assert-count 1 t:$xor +copy gold coarse +copy gold fine +copy gold coarse_keepdc +copy gold fine_keepdc + +cd coarse +opt_expr -fine +select -assert-count 0 t:$xor + +cd fine +simplemap +opt_expr +select -assert-none t:$_XOR_ + +cd +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold coarse miter +sat -verify -prove-asserts -show-ports -enable_undef miter +miter -equiv -flatten -make_assert -make_outputs coarse fine miter2 +sat -verify -prove-asserts -show-ports -enable_undef miter2 + +cd coarse_keepdc +opt_expr -keepdc -fine +select -assert-count 1 t:$xor + +cd fine_keepdc +simplemap +opt_expr -keepdc +select -assert-count 3 t:$_XOR_ + +cd +miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3 +sat -verify -prove-asserts -show-ports -enable_undef miter3 +miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4 +sat -verify -prove-asserts -show-ports -enable_undef miter4 diff --git a/tests/simple/partsel.v b/tests/simple/partsel.v index 83493fcb0..5e9730d6b 100644 --- a/tests/simple/partsel.v +++ b/tests/simple/partsel.v @@ -64,3 +64,49 @@ endmodule module partsel_test003(input [2:0] a, b, input [31:0] din, output [3:0] dout); assign dout = din[a*b +: 2]; endmodule + +module partsel_test004 ( + input [31:0] din, + input signed [4:0] n, + output reg [31:0] dout +); + always @(*) begin + dout = 0; + dout[n+1 +: 2] = din[n +: 2]; + end +endmodule + + +module partsel_test005 ( + input [31:0] din, + input signed [4:0] n, + output reg [31:0] dout +); + always @(*) begin + dout = 0; + dout[n+1] = din[n]; + end +endmodule + +module partsel_test006 ( + input [31:-32] din, + input signed [4:0] n, + output reg [31:-32] dout +); + always @(*) begin + dout = 0; + dout[n+1 +: 2] = din[n +: 2]; + end +endmodule + + +module partsel_test007 ( + input [31:-32] din, + input signed [4:0] n, + output reg [31:-32] dout +); + always @(*) begin + dout = 0; + dout[n+1] = din[n]; + end +endmodule diff --git a/tests/simple_abc9/abc9.box b/tests/simple_abc9/abc9.box new file mode 100644 index 000000000..b3c88437c --- /dev/null +++ b/tests/simple_abc9/abc9.box @@ -0,0 +1,3 @@ +MUXF8 1 0 3 1 +#I0 I1 S +0 0 0 # O diff --git a/tests/simple_abc9/abc9.v b/tests/simple_abc9/abc9.v index 688b47586..5e969c614 100644 --- a/tests/simple_abc9/abc9.v +++ b/tests/simple_abc9/abc9.v @@ -213,7 +213,7 @@ module arbiter (clk, rst, request, acknowledge, grant, grant_valid, grant_encode input rst; endmodule -(* abc9_box, blackbox *) +(* abc9_box_id=1, blackbox *) module MUXF8(input I0, I1, S, output O); specify (I0 => O) = 0; diff --git a/tests/simple_abc9/run-test.sh b/tests/simple_abc9/run-test.sh index 424d8f417..650e42fca 100755 --- a/tests/simple_abc9/run-test.sh +++ b/tests/simple_abc9/run-test.sh @@ -25,7 +25,7 @@ exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v *.sv EXTRA_FLAGS="-n 300 -p synth -run coarse; \ opt -full; \ techmap; \ - abc9 -lut 4; \ + abc9 -lut 4 -box ../abc9.box; \ clean; \ check -assert; \ select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%; \ diff --git a/tests/various/abc9.ys b/tests/various/abc9.ys index 6e2415ad7..ac714665f 100644 --- a/tests/various/abc9.ys +++ b/tests/various/abc9.ys @@ -45,14 +45,16 @@ sat -seq 10 -verify -prove-asserts -show-ports miter design -reset read_verilog -icells <<EOT module abc9_test036(input clk, d, output q); -(* keep *) reg w; -$__ABC9_FF_ ff(.D(d), .Q(w)); -wire \ff.clock = clk; -wire \ff.init = 1'b0; +(* keep, init=1'b0 *) wire w; +$_DFF_P_ ff(.C(clk), .D(d), .Q(w)); assign q = w; endmodule EOT -abc9 -lut 4 -dff +equiv_opt -assert abc9 -lut 4 -dff +design -load postopt +cd abc9_test036 +select -assert-count 1 t:$_DFF_P_ +select -assert-none t:* t:$_DFF_P_ %d design -reset @@ -67,8 +69,32 @@ specify endspecify endmodule -module top(input [1:0] i, output o); +module abc9_test037(input [1:0] i, output o); LUT2 #(.mask(4'b0)) lut (.i(i), .o(o)); endmodule EOT abc9 + + +design -reset +read_verilog -icells <<EOT +module abc9_test038(input clk, output w, x, y, z); +(* init=1'b1 *) wire w; +$_DFF_N_ ff1(.C(clk), .D(1'b1), .Q(w)); +(* init=1'bx *) wire x; +$_DFF_N_ ff2(.C(clk), .D(1'b0), .Q(x)); +(* init=1'b0 *) wire y; +$_DFF_N_ ff3(.C(clk), .D(1'b0), .Q(y)); +(* init=1'b0 *) wire z; +$_DFF_N_ ff4(.C(clk), .D(1'b1), .Q(z)); +endmodule +EOT +simplemap +equiv_opt abc9 -lut 4 -dff +design -load postopt +cd abc9_test038 +select -assert-count 3 t:$_DFF_N_ +select -assert-none c:ff1 c:ff2 c:ff4 %% c:* %D +clean +select -assert-count 2 a:init +select -assert-none w:w w:z %% a:init %D diff --git a/tests/various/gen_if_null.v b/tests/various/gen_if_null.v new file mode 100644 index 000000000..a12ac6288 --- /dev/null +++ b/tests/various/gen_if_null.v @@ -0,0 +1,13 @@ +module test(x, y, z); + localparam OFF = 0; + generate + if (OFF) ; + else input x; + if (!OFF) input y; + else ; + if (OFF) ; + else ; + if (OFF) ; + input z; + endgenerate +endmodule diff --git a/tests/various/gen_if_null.ys b/tests/various/gen_if_null.ys new file mode 100644 index 000000000..31dfc444b --- /dev/null +++ b/tests/various/gen_if_null.ys @@ -0,0 +1,4 @@ +read_verilog gen_if_null.v +select -assert-count 1 test/x +select -assert-count 1 test/y +select -assert-count 1 test/z diff --git a/tests/various/xaiger.ys b/tests/various/xaiger.ys new file mode 100644 index 000000000..f612d2e18 --- /dev/null +++ b/tests/various/xaiger.ys @@ -0,0 +1,13 @@ +read_verilog <<EOT +module top(input a, b, output c); +bb #(1) bb(); +endmodule + +module bb(input a, b, output c); +parameter p = 0; +assign c = a ^ b; +endmodule +EOT +blackbox bb +hierarchy +write_xaiger /dev/null diff --git a/tests/verilog/.gitignore b/tests/verilog/.gitignore new file mode 100644 index 000000000..b48f808a1 --- /dev/null +++ b/tests/verilog/.gitignore @@ -0,0 +1,3 @@ +/*.log +/*.out +/run-test.mk diff --git a/tests/verilog/bug2042-sv.ys b/tests/verilog/bug2042-sv.ys new file mode 100644 index 000000000..e815d7fc5 --- /dev/null +++ b/tests/verilog/bug2042-sv.ys @@ -0,0 +1,59 @@ +read_verilog -sv <<EOT +module Task_Test_Top +( +input a, +output b +); + + task SomeTaskName(a); + b = ~a; + endtask + + always @* + SomeTaskName(a); + + assert property (b == ~a); + +endmodule +EOT +proc +sat -verify -prove-asserts + + +design -reset +read_verilog -sv <<EOT +module Task_Test_Top +( +input a, +output b, c +); + + task SomeTaskName(x, output y, z); + y = ~x; + z = x; + endtask + + always @* + SomeTaskName(a, b, c); + + assert property (b == ~a); + assert property (c == a); + +endmodule +EOT +proc +sat -verify -prove-asserts + + +design -reset +logger -expect error "syntax error, unexpected TOK_ENDTASK, expecting ';'" 1 +read_verilog -sv <<EOT +module Task_Test_Top +( +); + + task SomeTaskName(a) + endtask + +endmodule +EOT diff --git a/tests/verilog/bug2042.ys b/tests/verilog/bug2042.ys new file mode 100644 index 000000000..f9d8e2837 --- /dev/null +++ b/tests/verilog/bug2042.ys @@ -0,0 +1,11 @@ +logger -expect error "task/function argument direction missing" 1 +read_verilog <<EOT +module Task_Test_Top +( +); + + task SomeTaskName(a) + endtask + +endmodule +EOT diff --git a/tests/verilog/run-test.sh b/tests/verilog/run-test.sh new file mode 100755 index 000000000..ea56b70f0 --- /dev/null +++ b/tests/verilog/run-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -e +{ +echo "all::" +for x in *.ys; do + echo "all:: run-$x" + echo "run-$x:" + echo " @echo 'Running $x..'" + echo " @../../yosys -ql ${x%.ys}.log $x" +done +for s in *.sh; do + if [ "$s" != "run-test.sh" ]; then + echo "all:: run-$s" + echo "run-$s:" + echo " @echo 'Running $s..'" + echo " @bash $s" + fi +done +} > run-test.mk +exec ${MAKE:-make} -f run-test.mk diff --git a/tests/verilog/task_attr.ys b/tests/verilog/task_attr.ys new file mode 100644 index 000000000..d6e75f85f --- /dev/null +++ b/tests/verilog/task_attr.ys @@ -0,0 +1,28 @@ +read_verilog <<EOT +module top; + task foo; + endtask + + always @* + (* foo *) foo; + + initial + if (0) $info("bar"); +endmodule +EOT +# Since task enables are not an RTLIL object, +# any attributes on their AST get dropped +select -assert-none a:* a:src %d + + +logger -expect error "syntax error, unexpected ATTR_BEGIN" 1 +design -reset +read_verilog <<EOT +module top; + task foo; + endtask + + always @* + foo (* foo *); +endmodule +EOT diff --git a/tests/verilog/upto.ys b/tests/verilog/upto.ys new file mode 100644 index 000000000..2f3394761 --- /dev/null +++ b/tests/verilog/upto.ys @@ -0,0 +1,4 @@ +read_verilog <<EOT +module top(input [-128:-65] a); +endmodule +EOT |