diff options
author | Eddie Hung <eddie@fpgeh.com> | 2020-05-18 08:06:50 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-18 08:06:50 -0700 |
commit | 2d573a0ff680eb9f38358943fbf134f765ba1451 (patch) | |
tree | f68589c127fcb0972636699b888252972ed63385 | |
parent | fa8cb3e35da68ceb55a9147bc1faacf68ad8bbfa (diff) | |
parent | 67fc0c3698693f049e805211c49d6219f17d7c7d (diff) | |
download | yosys-2d573a0ff680eb9f38358943fbf134f765ba1451.tar.gz yosys-2d573a0ff680eb9f38358943fbf134f765ba1451.tar.bz2 yosys-2d573a0ff680eb9f38358943fbf134f765ba1451.zip |
Merge pull request #1926 from YosysHQ/eddie/abc9_auto_dff
abc9: support seq synthesis when module has (* abc9_flop *) and bypass non-combinatorial (* abc9_box *)
34 files changed, 1656 insertions, 1853 deletions
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 1fb7210cb..69797ceaf 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,35 @@ 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()); + 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 (!cell->parameters.empty()) { + auto derived_type = inst_module->derive(design, cell->parameters); + inst_module = design->module(derived_type); + log_assert(inst_module); + log_assert(inst_module->get_blackbox_attribute()); } - 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 +283,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 +294,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 +327,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 +393,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 +408,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 +576,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 +594,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 +614,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 +654,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 +693,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 +750,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 +761,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 +783,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 +804,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/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/kernel/constids.inc b/kernel/constids.inc index 6b40a5908..345bfaee8 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) 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/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..10c980f73 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) @@ -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/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/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index 217151e96..9a337b2b6 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -23,9 +23,6 @@ $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/brams.txt)) $(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 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_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/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..e5c1f7550 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,13 @@ 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"); + run("read_verilog -icells -lib -specify +/ecp5/abc9_model.v"); std::string abc9_opts; if (nowidelut) abc9_opts += " -maxlut 4"; @@ -338,26 +344,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/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/cells_map.v b/techlibs/ice40/cells_map.v index d5362eb83..e9ccca239 100644 --- a/techlibs/ice40/cells_map.v +++ b/techlibs/ice40/cells_map.v @@ -1,33 +1,3 @@ -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; @@ -59,4 +29,3 @@ module \$lut (A, Y); end endgenerate endmodule -`endif diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 5d107989d..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 @@ -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 6e05ab0b2..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,6 +224,10 @@ 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; @@ -354,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"); @@ -378,7 +387,7 @@ struct SynthIce40Pass : public ScriptPass } 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)) @@ -387,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_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index bf9e746b8..0f844961e 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -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/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/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/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/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/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 |