diff options
Diffstat (limited to 'passes/techmap')
41 files changed, 2096 insertions, 1698 deletions
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index a54b4913d..98ccfc303 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -27,9 +27,10 @@ OBJS += passes/techmap/extract_fa.o OBJS += passes/techmap/extract_counter.o OBJS += passes/techmap/extract_reduce.o OBJS += passes/techmap/alumacc.o -OBJS += passes/techmap/dff2dffe.o OBJS += passes/techmap/dffinit.o OBJS += passes/techmap/pmuxtree.o +OBJS += passes/techmap/bmuxmap.o +OBJS += passes/techmap/demuxmap.o OBJS += passes/techmap/muxcover.o OBJS += passes/techmap/aigmap.o OBJS += passes/techmap/tribuf.o @@ -41,7 +42,8 @@ OBJS += passes/techmap/insbuf.o OBJS += passes/techmap/attrmvcp.o OBJS += passes/techmap/attrmap.o OBJS += passes/techmap/zinit.o -OBJS += passes/techmap/dff2dffs.o +OBJS += passes/techmap/dfflegalize.o +OBJS += passes/techmap/dffunmap.o OBJS += passes/techmap/flowmap.o OBJS += passes/techmap/extractinv.o endif diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 0a58fdcc0..80c6282c4 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -38,12 +38,13 @@ #define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}" #define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p" #define ABC_FAST_COMMAND_LUT "strash; dretime; if" -#define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}" +#define ABC_FAST_COMMAND_SOP "strash; dretime; cover {I} {P}" #define ABC_FAST_COMMAND_DFL "strash; dretime; map" #include "kernel/register.h" #include "kernel/sigtools.h" #include "kernel/celltypes.h" +#include "kernel/ffinit.h" #include "kernel/cost.h" #include "kernel/log.h" #include <stdlib.h> @@ -53,6 +54,7 @@ #include <cerrno> #include <sstream> #include <climits> +#include <vector> #ifndef _WIN32 # include <unistd.h> @@ -111,7 +113,7 @@ SigMap assign_map; RTLIL::Module *module; std::vector<gate_t> signal_list; std::map<RTLIL::SigBit, int> signal_map; -std::map<RTLIL::SigBit, RTLIL::State> signal_init; +FfInitVals initvals; pool<std::string> enabled_gates; bool recover_init, cmos_cost; @@ -133,10 +135,7 @@ int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, gate.in4 = -1; gate.is_port = false; gate.bit = bit; - if (signal_init.count(bit)) - gate.init = signal_init.at(bit); - else - gate.init = State::Sx; + gate.init = initvals(bit); signal_list.push_back(gate); signal_map[bit] = gate.id; } @@ -656,8 +655,9 @@ struct abc_output_filter }; void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, - std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, - bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, + std::vector<std::string> &liberty_files, std::vector<std::string> &genlib_files, std::string constr_file, + bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, + std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode, bool abc_dress) { module = current_module; @@ -711,8 +711,11 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin std::string abc_script = stringf("read_blif %s/input.blif; ", tempdir_name.c_str()); - if (!liberty_file.empty()) { - abc_script += stringf("read_lib -w %s; ", liberty_file.c_str()); + if (!liberty_files.empty() || !genlib_files.empty()) { + for (std::string liberty_file : liberty_files) + abc_script += stringf("read_lib -w %s; ", liberty_file.c_str()); + for (std::string liberty_file : genlib_files) + abc_script += stringf("read_library %s; ", liberty_file.c_str()); if (!constr_file.empty()) abc_script += stringf("read_constr -v %s; ", constr_file.c_str()); } else @@ -740,7 +743,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; if (all_luts_cost_same && !fast_mode) abc_script += "; lutpack {S}"; - } else if (!liberty_file.empty()) + } else if (!liberty_files.empty() || !genlib_files.empty()) abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR); else if (sop_mode) abc_script += fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP; @@ -1021,7 +1024,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin if (ifs.fail()) log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); - bool builtin_lib = liberty_file.empty(); + bool builtin_lib = liberty_files.empty() && genlib_files.empty(); RTLIL::Design *mapped_design = new RTLIL::Design; parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, sop_mode); @@ -1303,10 +1306,10 @@ struct AbcPass : public Pass { log("\n"); log(" if no -script parameter is given, the following scripts are used:\n"); log("\n"); - log(" for -liberty without -constr:\n"); + log(" for -liberty/-genlib without -constr:\n"); log("%s\n", fold_abc_cmd(ABC_COMMAND_LIB).c_str()); log("\n"); - log(" for -liberty with -constr:\n"); + log(" for -liberty/-genlib with -constr:\n"); log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR).c_str()); log("\n"); log(" for -lut/-luts (only one LUT size):\n"); @@ -1325,10 +1328,10 @@ struct AbcPass : public Pass { log(" use different default scripts that are slightly faster (at the cost\n"); log(" of output quality):\n"); log("\n"); - log(" for -liberty without -constr:\n"); + log(" for -liberty/-genlib without -constr:\n"); log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LIB).c_str()); log("\n"); - log(" for -liberty with -constr:\n"); + log(" for -liberty/-genlib with -constr:\n"); log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_CTR).c_str()); log("\n"); log(" for -lut/-luts:\n"); @@ -1344,8 +1347,13 @@ struct AbcPass : public Pass { log(" generate netlists for the specified cell library (using the liberty\n"); log(" file format).\n"); log("\n"); + log(" -genlib <file>\n"); + log(" generate netlists for the specified cell library (using the SIS Genlib\n"); + log(" file format).\n"); + log("\n"); log(" -constr <file>\n"); - log(" pass this file with timing constraints to ABC. use with -liberty.\n"); + log(" pass this file with timing constraints to ABC.\n"); + log(" use with -liberty/-genlib.\n"); log("\n"); log(" a constr file contains two lines:\n"); log(" set_driving_cell <cell_name>\n"); @@ -1391,7 +1399,7 @@ struct AbcPass : public Pass { log("\n"); // log(" -mux4, -mux8, -mux16\n"); // log(" try to extract 4-input, 8-input, and/or 16-input muxes\n"); - // log(" (ignored when used with -liberty or -lut)\n"); + // log(" (ignored when used with -liberty/-genlib or -lut)\n"); // log("\n"); log(" -g type1,type2,...\n"); log(" Map to the specified list of gate types. Supported gates types are:\n"); @@ -1447,7 +1455,7 @@ struct AbcPass : public Pass { log(" preserve naming by an equivalence check between the original and post-ABC\n"); log(" netlists (experimental).\n"); log("\n"); - log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n"); + log("When no target cell library is specified the Yosys standard cell library is\n"); log("loaded into ABC before the ABC script is executed.\n"); log("\n"); log("Note that this is a logic optimization pass within Yosys that is calling ABC\n"); @@ -1468,16 +1476,13 @@ struct AbcPass : public Pass { assign_map.clear(); signal_list.clear(); signal_map.clear(); - signal_init.clear(); + initvals.clear(); pi_map.clear(); po_map.clear(); -#ifdef ABCEXTERNAL - std::string exe_file = ABCEXTERNAL; -#else - std::string exe_file = proc_self_dirname() + proc_program_prefix() + "yosys-abc"; -#endif - std::string script_file, liberty_file, constr_file, clk_str; + std::string exe_file = yosys_abc_executable; + std::string script_file, default_liberty_file, constr_file, clk_str; + std::vector<std::string> liberty_files, genlib_files; std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1"; bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; bool show_tempdir = false, sop_mode = false; @@ -1491,18 +1496,11 @@ struct AbcPass : public Pass { enabled_gates.clear(); cmos_cost = false; -#ifdef _WIN32 -#ifndef ABCEXTERNAL - if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\" + proc_program_prefix()+ "yosys-abc.exe")) - exe_file = proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc"; -#endif -#endif - // get arguments from scratchpad first, then override by command arguments std::string lut_arg, luts_arg, g_arg; exe_file = design->scratchpad_get_string("abc.exe", exe_file /* inherit default value if not set */); script_file = design->scratchpad_get_string("abc.script", script_file); - liberty_file = design->scratchpad_get_string("abc.liberty", liberty_file); + default_liberty_file = design->scratchpad_get_string("abc.liberty", default_liberty_file); constr_file = design->scratchpad_get_string("abc.constr", constr_file); if (design->scratchpad.count("abc.D")) { delay_target = "-D " + design->scratchpad_get_string("abc.D"); @@ -1564,7 +1562,11 @@ struct AbcPass : public Pass { continue; } if (arg == "-liberty" && argidx+1 < args.size()) { - liberty_file = args[++argidx]; + liberty_files.push_back(args[++argidx]); + continue; + } + if (arg == "-genlib" && argidx+1 < args.size()) { + genlib_files.push_back(args[++argidx]); continue; } if (arg == "-constr" && argidx+1 < args.size()) { @@ -1656,12 +1658,22 @@ struct AbcPass : public Pass { } extra_args(args, argidx, design); + if (genlib_files.empty() && liberty_files.empty() && !default_liberty_file.empty()) + liberty_files.push_back(default_liberty_file); + rewrite_filename(script_file); if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+') script_file = std::string(pwd) + "/" + script_file; - rewrite_filename(liberty_file); - if (!liberty_file.empty() && !is_absolute_path(liberty_file)) - liberty_file = std::string(pwd) + "/" + liberty_file; + for (int i = 0; i < GetSize(liberty_files); i++) { + rewrite_filename(liberty_files[i]); + if (!liberty_files[i].empty() && !is_absolute_path(liberty_files[i])) + liberty_files[i] = std::string(pwd) + "/" + liberty_files[i]; + } + for (int i = 0; i < GetSize(genlib_files); i++) { + rewrite_filename(genlib_files[i]); + if (!genlib_files[i].empty() && !is_absolute_path(genlib_files[i])) + genlib_files[i] = std::string(pwd) + "/" + genlib_files[i]; + } rewrite_filename(constr_file); if (!constr_file.empty() && !is_absolute_path(constr_file)) constr_file = std::string(pwd) + "/" + constr_file; @@ -1807,6 +1819,7 @@ struct AbcPass : public Pass { gate_list.push_back("OAI4"); gate_list.push_back("MUX"); gate_list.push_back("NMUX"); + goto ok_alias; } if (g_arg_from_cmd) cmd_error(args, g_argidx, stringf("Unsupported gate type: %s", g.c_str())); @@ -1824,10 +1837,10 @@ struct AbcPass : public Pass { } } - if (!lut_costs.empty() && !liberty_file.empty()) - log_cmd_error("Got -lut and -liberty! These two options are exclusive.\n"); - if (!constr_file.empty() && liberty_file.empty()) - log_cmd_error("Got -constr but no -liberty!\n"); + if (!lut_costs.empty() && !(liberty_files.empty() && genlib_files.empty())) + log_cmd_error("Got -lut and -liberty/-genlib! These two options are exclusive.\n"); + if (!constr_file.empty() && (liberty_files.empty() && genlib_files.empty())) + log_cmd_error("Got -constr but no -liberty/-genlib!\n"); if (enabled_gates.empty()) { enabled_gates.insert("AND"); @@ -1854,27 +1867,10 @@ struct AbcPass : public Pass { } assign_map.set(mod); - signal_init.clear(); - - for (Wire *wire : mod->wires()) - if (wire->attributes.count(ID::init)) { - SigSpec initsig = assign_map(wire); - Const initval = wire->attributes.at(ID::init); - for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) - switch (initval[i]) { - case State::S0: - signal_init[initsig[i]] = State::S0; - break; - case State::S1: - signal_init[initsig[i]] = State::S1; - break; - default: - break; - } - } + initvals.set(&assign_map, mod); if (!dff_mode || !clk_str.empty()) { - abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, + abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress); continue; } @@ -2019,7 +2015,7 @@ struct AbcPass : public Pass { clk_sig = assign_map(std::get<1>(it.first)); en_polarity = std::get<2>(it.first); en_sig = assign_map(std::get<3>(it.first)); - abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$", + abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$", keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress); assign_map.set(mod); } @@ -2028,7 +2024,7 @@ struct AbcPass : public Pass { assign_map.clear(); signal_list.clear(); signal_map.clear(); - signal_init.clear(); + initvals.clear(); pi_map.clear(); po_map.clear(); diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 127f8934e..1f00fc3e7 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * (C) 2019 Eddie Hung <eddie@fpgeh.com> * * Permission to use, copy, modify, and/or distribute this software for any @@ -283,9 +283,16 @@ struct Abc9Pass : public ScriptPass if (check_label("map")) { if (help_mode) - run("abc9_ops -prep_hier -prep_bypass [-prep_dff -dff]", "(option if -dff)"); + run("abc9_ops -prep_hier [-dff]", "(option if -dff)"); else - run(stringf("abc9_ops -prep_hier -prep_bypass %s", dff_mode ? "-prep_dff -dff" : "")); + run(stringf("abc9_ops -prep_hier %s", dff_mode ? "-dff" : "")); + run("scc -specify -set_attr abc9_scc_id {}"); + if (help_mode) + run("abc9_ops -prep_bypass [-prep_dff]", "(option if -dff)"); + else { + active_design->scratchpad_unset("abc9_ops.prep_bypass.did_something"); + run(stringf("abc9_ops -prep_bypass %s", dff_mode ? "-prep_dff" : "")); + } if (dff_mode) { run("design -copy-to $abc9_map @$abc9_flops", "(only if -dff)"); run("select -unset $abc9_flops", " (only if -dff)"); @@ -294,8 +301,8 @@ struct Abc9Pass : public ScriptPass run("design -load $abc9_map"); run("proc"); run("wbflip"); - run("techmap"); - run("opt"); + run("techmap -wb -map %$abc9 -map +/techmap.v A:abc9_flop"); + run("opt -nodffe -nosdff"); if (dff_mode || help_mode) { if (!help_mode) active_design->scratchpad_unset("abc9_ops.prep_dff_submod.did_something"); @@ -330,20 +337,20 @@ struct Abc9Pass : public ScriptPass run("design -stash $abc9_map"); run("design -load $abc9"); run("design -delete $abc9"); + // Insert bypass modules (and perform +/abc9_map.v transformations), except for those cells part of a SCC 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(stringf("techmap -wb -max_iter 1 -map %%$abc9_map -map +/abc9_map.v %s a:abc9_scc_id %%n", dff_mode ? "-D DFF" : "")); run("design -delete $abc9_map"); } if (check_label("pre")) { 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)"); + run("abc9_ops -break_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)"); else - run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : "")); + run("abc9_ops -break_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) @@ -445,6 +452,9 @@ struct Abc9Pass : public ScriptPass run("design -delete $abc9_unmap"); if (saved_designs.count("$abc9_holes") || help_mode) run("design -delete $abc9_holes"); + if (help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_bypass.did_something")) + run("delete =*_$abc9_byp"); + run("setattr -mod -unset abc9_box_id"); } } } Abc9Pass; diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc index 7355840aa..a66e95e21 100644 --- a/passes/techmap/abc9_exe.cc +++ b/passes/techmap/abc9_exe.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * 2019 Eddie Hung <eddie@fpgeh.com> * * Permission to use, copy, modify, and/or distribute this software for any @@ -379,11 +379,7 @@ struct Abc9ExePass : public Pass { { log_header(design, "Executing ABC9_EXE pass (technology mapping using ABC9).\n"); -#ifdef ABCEXTERNAL - std::string exe_file = ABCEXTERNAL; -#else - std::string exe_file = proc_self_dirname() + proc_program_prefix()+ "yosys-abc"; -#endif + std::string exe_file = yosys_abc_executable; std::string script_file, clk_str, box_file, lut_file; std::string delay_target, lutin_shared = "-S 1", wire_delay; std::string tempdir_name; @@ -396,13 +392,6 @@ struct Abc9ExePass : public Pass { show_tempdir = true; #endif -#ifdef _WIN32 -#ifndef ABCEXTERNAL - if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc.exe")) - exe_file = proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc"; -#endif -#endif - std::string lut_arg, luts_arg; exe_file = design->scratchpad_get_string("abc9.exe", exe_file /* inherit default value if not set */); script_file = design->scratchpad_get_string("abc9.script", script_file); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 98d0207c4..29fe74ec7 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * 2019 Eddie Hung <eddie@fpgeh.com> * * Permission to use, copy, modify, and/or distribute this software for any @@ -155,21 +155,6 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) 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); @@ -189,16 +174,22 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) 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)) + if (!derived_module->get_bool_attribute(ID::abc9_box) && !derived_module->get_bool_attribute(ID::abc9_bypass)) { + if (unmap_design->module(derived_type)) { + // If derived_type is present in unmap_design, it means that it was processed previously, but found to be incompatible -- e.g. if + // it contained a non-zero initial state. In this case, continue to replace the cell type/parameters so that it has the same properties + // as a compatible type, yet will be safely unmapped later + cell->type = derived_type; + cell->parameters.clear(); + } continue; + } } if (!unmap_design->module(derived_type)) { @@ -223,7 +214,7 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) } else if (derived_module->get_bool_attribute(ID::abc9_box)) { for (auto derived_cell : derived_module->cells()) - if (seq_types.count(derived_cell->type)) { + if (derived_cell->is_mem_cell() || RTLIL::builtin_ff_cell_types().count(derived_cell->type)) { derived_module->set_bool_attribute(ID::abc9_box, false); derived_module->set_bool_attribute(ID::abc9_bypass); break; @@ -441,6 +432,8 @@ void prep_bypass(RTLIL::Design *design) } } unmap_module->fixup_ports(); + + design->scratchpad_set_bool("abc9_ops.prep_bypass.did_something", true); } } @@ -459,7 +452,14 @@ void prep_dff(RTLIL::Design *design) 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()); + if (!cell->parameters.empty()) + { + // At this stage of the ABC9 flow, cells instantiating (* abc9_flop *) modules must not contain any parameters -- instead it should + // be instantiating the derived module which will have had any parameters constant-propagated. + // This task is expected to be performed by `abc9_ops -prep_hier`, but it looks like it failed to do so for this design. + // Please file a bug report! + log_error("Not expecting parameters on cell '%s' instantiating module '%s' marked (* abc9_flop *)\n", log_id(cell->name), log_id(cell->type)); + } modules_sel.select(inst_module); } } @@ -544,18 +544,31 @@ void prep_dff_unmap(RTLIL::Design *design) } } -void mark_scc(RTLIL::Module *module) +void break_scc(RTLIL::Module *module) { // For every unique SCC found, (arbitrarily) find the first - // cell in the component, and replace its output connections - // with a new wire driven by the old connection but with a - // special (* abc9_keep *) attribute set (which is used by - // write_xaiger to break this wire into PI and POs) + // cell in the component, and interrupt all its output connections + // with the $__ABC9_SCC_BREAKER cell + + // Do not break SCCs which have a cell instantiating an abc9_bypass-able + // module (but which wouldn't have been bypassed) + auto design = module->design; + pool<RTLIL::Cell*> scc_cells; pool<RTLIL::Const> ids_seen; for (auto cell : module->cells()) { auto it = cell->attributes.find(ID::abc9_scc_id); if (it == cell->attributes.end()) continue; + scc_cells.insert(cell); + auto inst_module = design->module(cell->type); + if (inst_module && inst_module->has_attribute(ID::abc9_bypass)) + ids_seen.insert(it->second); + } + + SigSpec I, O; + for (auto cell : scc_cells) { + auto it = cell->attributes.find(ID::abc9_scc_id); + log_assert(it != cell->attributes.end()); auto id = it->second; auto r = ids_seen.insert(id); cell->attributes.erase(it); @@ -565,12 +578,21 @@ 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_keep); - module->connect(w, c.second); + I.append(w); + O.append(c.second); c.second = w; } } } + + if (!I.empty()) + { + auto cell = module->addCell(NEW_ID, ID($__ABC9_SCC_BREAKER)); + log_assert(GetSize(I) == GetSize(O)); + cell->setParam(ID::WIDTH, GetSize(I)); + cell->setPort(ID::I, std::move(I)); + cell->setPort(ID::O, std::move(O)); + } } void prep_delays(RTLIL::Design *design, bool dff_mode) @@ -626,40 +648,38 @@ void prep_delays(RTLIL::Design *design, bool dff_mode) auto inst_module = design->module(cell->type); log_assert(inst_module); - auto &t = timing.at(cell->type).required; - for (auto &conn : cell->connections_) { - auto port_wire = inst_module->wire(conn.first); + for (auto &i : timing.at(cell->type).required) { + auto port_wire = inst_module->wire(i.first.name); 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; - if (conn.second.is_fully_const()) + log_id(i.first.name), log_id(cell), log_id(cell->type), log_id(module)); + log_assert(port_wire->port_input); + + auto d = i.second.first; + if (d == 0) 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; + auto offset = i.first.offset; + auto O = module->addWire(NEW_ID); + auto rhs = cell->getPort(i.first.name); #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); - } + if (ys_debug(1)) { + static pool<std::pair<IdString,TimingInfo::NameBit>> seen; + if (seen.emplace(cell->type, i.first).second) log("%s.%s[%d] abc9_required = %d\n", + log_id(cell->type), log_id(i.first.name), offset, 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]; + 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, rhs[offset]); + box->setPort(ID::O, O); + rhs[offset] = O; + cell->setPort(i.first.name, rhs); } } } @@ -721,10 +741,8 @@ void prep_xaiger(RTLIL::Module *module, bool dff) bit_users[bit].insert(cell->name); if (cell->output(conn.first) && !abc9_flop) - for (const auto &chunk : conn.second.chunks()) - if (!chunk.wire->get_bool_attribute(ID::abc9_keep)) - for (auto b : sigmap(SigSpec(chunk))) - bit_drivers[b].insert(cell->name); + for (auto bit : sigmap(conn.second)) + bit_drivers[bit].insert(cell->name); } toposort.node(cell->name); } @@ -778,7 +796,14 @@ void prep_xaiger(RTLIL::Module *module, bool dff) continue; if (!box_module->get_bool_attribute(ID::abc9_box)) continue; - log_assert(cell->parameters.empty()); + if (!cell->parameters.empty()) + { + // At this stage of the ABC9 flow, cells instantiating (* abc9_box *) modules must not contain any parameters -- instead it should + // be instantiating the derived module which will have had any parameters constant-propagated. + // This task is expected to be performed by `abc9_ops -prep_hier`, but it looks like it failed to do so for this design. + // Please file a bug report! + log_error("Not expecting parameters on cell '%s' instantiating module '%s' marked (* abc9_box *)\n", log_id(cell_name), log_id(cell->type)); + } log_assert(box_module->get_blackbox_attribute()); cell->attributes[ID::abc9_box_seq] = box_count++; @@ -787,7 +812,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) auto &holes_cell = r.first->second; if (r.second) { if (box_module->get_bool_attribute(ID::whitebox)) { - holes_cell = holes_module->addCell(cell->name, cell->type); + holes_cell = holes_module->addCell(NEW_ID, cell->type); if (box_module->has_processes()) Pass::call_on_module(design, box_module, "proc"); @@ -917,15 +942,8 @@ void prep_box(RTLIL::Design *design) { TimingInfo timing; - std::stringstream ss; int abc9_box_id = 1; - for (auto module : design->modules()) { - auto it = module->attributes.find(ID::abc9_box_id); - if (it == module->attributes.end()) - continue; - abc9_box_id = std::max(abc9_box_id, it->second.as_int()); - } - + std::stringstream ss; dict<IdString,std::vector<IdString>> box_ports; for (auto module : design->modules()) { auto it = module->attributes.find(ID::abc9_box); @@ -986,16 +1004,16 @@ void prep_box(RTLIL::Design *design) 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 << "-"; + // Assume that no setup time means zero + ss << 0; else { - ss << it->second; + ss << it->second.first; #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); + log_id(port_name), it->second.first); } #endif } @@ -1416,7 +1434,6 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) RTLIL::Wire *mapped_wire = mapped_mod->wire(port); RTLIL::Wire *wire = module->wire(port); log_assert(wire); - 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)); @@ -1579,11 +1596,11 @@ struct Abc9OpsPass : public Pass { log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n"); log(" certain required times.\n"); log("\n"); - log(" -mark_scc\n"); + log(" -break_scc\n"); log(" for an arbitrarily chosen cell in each unique SCC of each selected module\n"); - log(" (tagged with an (* abc9_scc_id = <int> *) attribute), temporarily mark all\n"); - log(" wires driven by this cell's outputs with a (* keep *) attribute in order\n"); - log(" to break the SCC. this temporary attribute will be removed on -reintegrate.\n"); + log(" (tagged with an (* abc9_scc_id = <int> *) attribute) interrupt all wires\n"); + log(" driven by this cell's outputs with a temporary $__ABC9_SCC_BREAKER cell\n"); + log(" to break the SCC.\n"); log("\n"); log(" -prep_xaiger\n"); log(" prepare the design for XAIGER output. this includes computing the\n"); @@ -1620,7 +1637,7 @@ struct Abc9OpsPass : public Pass { bool check_mode = false; bool prep_delays_mode = false; - bool mark_scc_mode = false; + bool break_scc_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; @@ -1642,8 +1659,8 @@ struct Abc9OpsPass : public Pass { valid = true; continue; } - if (arg == "-mark_scc") { - mark_scc_mode = true; + if (arg == "-break_scc") { + break_scc_mode = true; valid = true; continue; } @@ -1719,7 +1736,7 @@ struct Abc9OpsPass : public Pass { extra_args(args, argidx, design); 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"); + log_cmd_error("At least one of -check, -break_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate must be specified.\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"); @@ -1756,8 +1773,8 @@ struct Abc9OpsPass : public Pass { write_lut(mod, write_lut_dst); if (!write_box_dst.empty()) write_box(mod, write_box_dst); - if (mark_scc_mode) - mark_scc(mod); + if (break_scc_mode) + break_scc(mod); if (prep_xaiger_mode) prep_xaiger(mod, dff_mode); if (reintegrate_mode) diff --git a/passes/techmap/aigmap.cc b/passes/techmap/aigmap.cc index ce151c7f3..4836ebe34 100644 --- a/passes/techmap/aigmap.cc +++ b/passes/techmap/aigmap.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index b16e9750e..e4e70004c 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc index 8643543c8..96e65ff2e 100644 --- a/passes/techmap/attrmap.cc +++ b/passes/techmap/attrmap.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/attrmvcp.cc b/passes/techmap/attrmvcp.cc index b3202c587..65b63daf1 100644 --- a/passes/techmap/attrmvcp.cc +++ b/passes/techmap/attrmvcp.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/bmuxmap.cc b/passes/techmap/bmuxmap.cc new file mode 100644 index 000000000..03673c278 --- /dev/null +++ b/passes/techmap/bmuxmap.cc @@ -0,0 +1,76 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2022 Marcelina Kościelnicka <mwk@0x04.net> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct BmuxmapPass : public Pass { + BmuxmapPass() : Pass("bmuxmap", "transform $bmux cells to trees of $mux cells") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" bmuxmap [selection]\n"); + log("\n"); + log("This pass transforms $bmux cells to trees of $mux cells.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) override + { + log_header(design, "Executing BMUXMAP pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + for (auto cell : module->selected_cells()) + { + if (cell->type != ID($bmux)) + continue; + + SigSpec sel = cell->getPort(ID::S); + SigSpec data = cell->getPort(ID::A); + int width = GetSize(cell->getPort(ID::Y)); + + for (int idx = 0; idx < GetSize(sel); idx++) { + SigSpec new_data = module->addWire(NEW_ID, GetSize(data)/2); + for (int i = 0; i < GetSize(new_data); i += width) { + RTLIL::Cell *mux = module->addMux(NEW_ID, + data.extract(i*2, width), + data.extract(i*2+width, width), + sel[idx], + new_data.extract(i, width)); + mux->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + } + data = new_data; + } + + module->connect(cell->getPort(ID::Y), data); + module->remove(cell); + } + } +} BmuxmapPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc index 451325fee..a7b96a9c6 100644 --- a/passes/techmap/clkbufmap.cc +++ b/passes/techmap/clkbufmap.cc @@ -1,8 +1,8 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * Copyright (C) 2019 Marcin Kościelnicki <mwk@0x04.net> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> + * Copyright (C) 2019 Marcelina Kościelnicka <mwk@0x04.net> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -34,33 +34,34 @@ void split_portname_pair(std::string &port1, std::string &port2) } struct ClkbufmapPass : public Pass { - ClkbufmapPass() : Pass("clkbufmap", "insert global buffers on clock networks") { } + ClkbufmapPass() : Pass("clkbufmap", "insert clock buffers on clock networks") { } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" clkbufmap [options] [selection]\n"); log("\n"); - log("Inserts global buffers between nets connected to clock inputs and their drivers.\n"); + log("Inserts clock buffers between nets connected to clock inputs and their drivers.\n"); log("\n"); log("In the absence of any selection, all wires without the 'clkbuf_inhibit'\n"); - log("attribute will be considered for global buffer insertion.\n"); + log("attribute will be considered for clock buffer insertion.\n"); log("Alternatively, to consider all wires without the 'buffer_type' attribute set to\n"); log("'none' or 'bufr' one would specify:\n"); log(" 'w:* a:buffer_type=none a:buffer_type=bufr %%u %%d'\n"); log("as the selection.\n"); log("\n"); log(" -buf <celltype> <portname_out>:<portname_in>\n"); - log(" Specifies the cell type to use for the global buffers\n"); + log(" Specifies the cell type to use for the clock buffers\n"); log(" and its port names. The first port will be connected to\n"); log(" the clock network sinks, and the second will be connected\n"); - log(" to the actual clock source. This option is required.\n"); + log(" to the actual clock source.\n"); log("\n"); log(" -inpad <celltype> <portname_out>:<portname_in>\n"); log(" If specified, a PAD cell of the given type is inserted on\n"); log(" clock nets that are also top module's inputs (in addition\n"); - log(" to the global buffer).\n"); + log(" to the clock buffer, if any).\n"); log("\n"); + log("At least one of -buf or -inpad should be specified.\n"); } void module_queue(Design *design, Module *module, std::vector<Module *> &modules_sorted, pool<Module *> &modules_processed) { @@ -78,7 +79,7 @@ struct ClkbufmapPass : public Pass { void execute(std::vector<std::string> args, RTLIL::Design *design) override { - log_header(design, "Executing CLKBUFMAP pass (inserting global clock buffers).\n"); + log_header(design, "Executing CLKBUFMAP pass (inserting clock buffers).\n"); std::string buf_celltype, buf_portname, buf_portname2; std::string inpad_celltype, inpad_portname, inpad_portname2; @@ -109,8 +110,8 @@ struct ClkbufmapPass : public Pass { extra_args(args, argidx, design); } - if (buf_celltype.empty()) - log_error("The -buf option is required.\n"); + if (buf_celltype.empty() && inpad_celltype.empty()) + log_error("Either the -buf option or -inpad option is required.\n"); // Cell type, port name, bit index. pool<pair<IdString, pair<IdString, int>>> sink_ports; @@ -118,6 +119,16 @@ struct ClkbufmapPass : public Pass { dict<pair<IdString, pair<IdString, int>>, pair<IdString, int>> inv_ports_out; dict<pair<IdString, pair<IdString, int>>, pair<IdString, int>> inv_ports_in; + // If true, use both ther -buf and -inpad cell for input ports that are clocks. + bool buffer_inputs = true; + + Module *inpad_mod = design->module(RTLIL::escape_id(inpad_celltype)); + if (inpad_mod) { + Wire *buf_wire = inpad_mod->wire(RTLIL::escape_id(buf_portname)); + if (buf_wire && buf_wire->get_bool_attribute(ID::clkbuf_driver)) + buffer_inputs = false; + } + // Process submodules before module using them. std::vector<Module *> modules_sorted; pool<Module *> modules_processed; @@ -242,19 +253,30 @@ struct ClkbufmapPass : public Pass { // Clock network not yet buffered, driven by one of // our cells or a top-level input -- buffer it. - log("Inserting %s on %s.%s[%d].\n", buf_celltype.c_str(), log_id(module), log_id(wire), i); - RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(buf_celltype)); - Wire *iwire = module->addWire(NEW_ID); - cell->setPort(RTLIL::escape_id(buf_portname), mapped_wire_bit); - cell->setPort(RTLIL::escape_id(buf_portname2), iwire); - if (wire->port_input && !inpad_celltype.empty() && module->get_bool_attribute(ID::top)) { + Wire *iwire = nullptr; + RTLIL::Cell *cell = nullptr; + bool is_input = wire->port_input && !inpad_celltype.empty() && module->get_bool_attribute(ID::top); + if (!buf_celltype.empty() && (!is_input || buffer_inputs)) { + log("Inserting %s on %s.%s[%d].\n", buf_celltype.c_str(), log_id(module), log_id(wire), i); + cell = module->addCell(NEW_ID, RTLIL::escape_id(buf_celltype)); + iwire = module->addWire(NEW_ID); + cell->setPort(RTLIL::escape_id(buf_portname), mapped_wire_bit); + cell->setPort(RTLIL::escape_id(buf_portname2), iwire); + } + if (is_input) { log("Inserting %s on %s.%s[%d].\n", inpad_celltype.c_str(), log_id(module), log_id(wire), i); RTLIL::Cell *cell2 = module->addCell(NEW_ID, RTLIL::escape_id(inpad_celltype)); - cell2->setPort(RTLIL::escape_id(inpad_portname), iwire); + if (iwire) { + cell2->setPort(RTLIL::escape_id(inpad_portname), iwire); + } else { + cell2->setPort(RTLIL::escape_id(inpad_portname), mapped_wire_bit); + cell = cell2; + } iwire = module->addWire(NEW_ID); cell2->setPort(RTLIL::escape_id(inpad_portname2), iwire); } - buffered_bits[mapped_wire_bit] = make_pair(cell, iwire); + if (iwire) + buffered_bits[mapped_wire_bit] = make_pair(cell, iwire); if (wire->port_input) { input_bits.insert(i); diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc index 9a23cb90e..5245331f8 100644 --- a/passes/techmap/deminout.cc +++ b/passes/techmap/deminout.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/demuxmap.cc b/passes/techmap/demuxmap.cc new file mode 100644 index 000000000..292b18bad --- /dev/null +++ b/passes/techmap/demuxmap.cc @@ -0,0 +1,80 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2022 Marcelina Kościelnicka <mwk@0x04.net> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct DemuxmapPass : public Pass { + DemuxmapPass() : Pass("demuxmap", "transform $demux cells to $eq + $mux cells") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" demuxmap [selection]\n"); + log("\n"); + log("This pass transforms $demux cells to a bunch of equality comparisons.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) override + { + log_header(design, "Executing DEMUXMAP pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + for (auto cell : module->selected_cells()) + { + if (cell->type != ID($demux)) + continue; + + SigSpec sel = cell->getPort(ID::S); + SigSpec data = cell->getPort(ID::A); + SigSpec out = cell->getPort(ID::Y); + int width = GetSize(cell->getPort(ID::A)); + + for (int i = 0; i < 1 << GetSize(sel); i++) { + if (width == 1 && data == State::S1) { + RTLIL::Cell *eq_cell = module->addEq(NEW_ID, sel, Const(i, GetSize(sel)), out[i]); + eq_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + } else { + Wire *eq = module->addWire(NEW_ID); + RTLIL::Cell *eq_cell = module->addEq(NEW_ID, sel, Const(i, GetSize(sel)), eq); + eq_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + RTLIL::Cell *mux = module->addMux(NEW_ID, + Const(State::S0, width), + data, + eq, + out.extract(i*width, width)); + mux->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + } + } + + module->remove(cell); + } + } +} DemuxmapPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc deleted file mode 100644 index 62ee3fea6..000000000 --- a/passes/techmap/dff2dffe.cc +++ /dev/null @@ -1,414 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" -#include "kernel/celltypes.h" -#include "passes/techmap/simplemap.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct Dff2dffeWorker -{ - const dict<IdString, IdString> &direct_dict; - - RTLIL::Module *module; - SigMap sigmap; - CellTypes ct; - - typedef std::pair<RTLIL::Cell*, int> cell_int_t; - std::map<RTLIL::SigBit, cell_int_t> bit2mux; - std::vector<RTLIL::Cell*> dff_cells; - std::map<RTLIL::SigBit, int> bitusers; - - typedef std::map<RTLIL::SigBit, bool> pattern_t; - typedef std::set<pattern_t> patterns_t; - - - Dff2dffeWorker(RTLIL::Module *module, const dict<IdString, IdString> &direct_dict) : - direct_dict(direct_dict), module(module), sigmap(module), ct(module->design) - { - for (auto wire : module->wires()) { - if (wire->port_output) - for (auto bit : sigmap(wire)) - bitusers[bit]++; - } - - for (auto cell : module->cells()) { - if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) { - RTLIL::SigSpec sig_y = sigmap(cell->getPort(ID::Y)); - for (int i = 0; i < GetSize(sig_y); i++) - bit2mux[sig_y[i]] = cell_int_t(cell, i); - } - if (direct_dict.empty()) { - if (cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) - dff_cells.push_back(cell); - } else { - if (direct_dict.count(cell->type)) - dff_cells.push_back(cell); - } - for (auto conn : cell->connections()) { - if (ct.cell_output(cell->type, conn.first)) - continue; - for (auto bit : sigmap(conn.second)) - bitusers[bit]++; - } - } - } - - patterns_t find_muxtree_feedback_patterns(RTLIL::SigBit d, RTLIL::SigBit q, pattern_t path) - { - patterns_t ret; - - if (d == q) { - ret.insert(path); - return ret; - } - - if (bit2mux.count(d) == 0 || bitusers[d] > 1) - return ret; - - cell_int_t mux_cell_int = bit2mux.at(d); - RTLIL::SigSpec sig_a = sigmap(mux_cell_int.first->getPort(ID::A)); - RTLIL::SigSpec sig_b = sigmap(mux_cell_int.first->getPort(ID::B)); - RTLIL::SigSpec sig_s = sigmap(mux_cell_int.first->getPort(ID::S)); - int width = GetSize(sig_a), index = mux_cell_int.second; - - for (int i = 0; i < GetSize(sig_s); i++) - if (path.count(sig_s[i]) && path.at(sig_s[i])) - { - ret = find_muxtree_feedback_patterns(sig_b[i*width + index], q, path); - - if (sig_b[i*width + index] == q) { - RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::B); - s[i*width + index] = RTLIL::Sx; - mux_cell_int.first->setPort(ID::B, s); - } - - return ret; - } - - pattern_t path_else = path; - - for (int i = 0; i < GetSize(sig_s); i++) - { - if (path.count(sig_s[i])) - continue; - - pattern_t path_this = path; - path_else[sig_s[i]] = false; - path_this[sig_s[i]] = true; - - for (auto &pat : find_muxtree_feedback_patterns(sig_b[i*width + index], q, path_this)) - ret.insert(pat); - - if (sig_b[i*width + index] == q) { - RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::B); - s[i*width + index] = RTLIL::Sx; - mux_cell_int.first->setPort(ID::B, s); - } - } - - for (auto &pat : find_muxtree_feedback_patterns(sig_a[index], q, path_else)) - ret.insert(pat); - - if (sig_a[index] == q) { - RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::A); - s[index] = RTLIL::Sx; - mux_cell_int.first->setPort(ID::A, s); - } - - return ret; - } - - void simplify_patterns(patterns_t&) - { - // TBD - } - - RTLIL::SigSpec make_patterns_logic(patterns_t patterns, bool make_gates) - { - RTLIL::SigSpec or_input; - - for (auto pat : patterns) - { - RTLIL::SigSpec s1, s2; - for (auto it : pat) { - s1.append(it.first); - s2.append(it.second); - } - - RTLIL::SigSpec y = module->addWire(NEW_ID); - RTLIL::Cell *c = module->addNe(NEW_ID, s1, s2, y); - - if (make_gates) { - simplemap(module, c); - module->remove(c); - } - - or_input.append(y); - } - - if (GetSize(or_input) == 0) - return State::S1; - - if (GetSize(or_input) == 1) - return or_input; - - RTLIL::SigSpec y = module->addWire(NEW_ID); - RTLIL::Cell *c = module->addReduceAnd(NEW_ID, or_input, y); - - if (make_gates) { - simplemap(module, c); - module->remove(c); - } - - return y; - } - - void handle_dff_cell(RTLIL::Cell *dff_cell) - { - RTLIL::SigSpec sig_d = sigmap(dff_cell->getPort(ID::D)); - RTLIL::SigSpec sig_q = sigmap(dff_cell->getPort(ID::Q)); - - std::map<patterns_t, std::set<int>> grouped_patterns; - std::set<int> remaining_indices; - - for (int i = 0 ; i < GetSize(sig_d); i++) { - patterns_t patterns = find_muxtree_feedback_patterns(sig_d[i], sig_q[i], pattern_t()); - if (!patterns.empty()) { - simplify_patterns(patterns); - grouped_patterns[patterns].insert(i); - } else - remaining_indices.insert(i); - } - - for (auto &it : grouped_patterns) { - RTLIL::SigSpec new_sig_d, new_sig_q; - for (int i : it.second) { - new_sig_d.append(sig_d[i]); - new_sig_q.append(sig_q[i]); - } - if (!direct_dict.empty()) { - log(" converting %s cell %s to %s for %s -> %s.\n", log_id(dff_cell->type), log_id(dff_cell), log_id(direct_dict.at(dff_cell->type)), log_signal(new_sig_d), log_signal(new_sig_q)); - dff_cell->setPort(ID::E, make_patterns_logic(it.first, true)); - dff_cell->type = direct_dict.at(dff_cell->type); - } else - if (dff_cell->type == ID($dff)) { - RTLIL::Cell *new_cell = module->addDffe(NEW_ID, dff_cell->getPort(ID::CLK), make_patterns_logic(it.first, false), - new_sig_d, new_sig_q, dff_cell->getParam(ID::CLK_POLARITY).as_bool(), true); - log(" created $dffe cell %s for %s -> %s.\n", log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q)); - } else { - RTLIL::Cell *new_cell = module->addDffeGate(NEW_ID, dff_cell->getPort(ID::C), make_patterns_logic(it.first, true), - new_sig_d, new_sig_q, dff_cell->type == ID($_DFF_P_), true); - log(" created %s cell %s for %s -> %s.\n", log_id(new_cell->type), log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q)); - } - } - - if (!direct_dict.empty()) - return; - - if (remaining_indices.empty()) { - log(" removing now obsolete cell %s.\n", log_id(dff_cell)); - module->remove(dff_cell); - } else if (GetSize(remaining_indices) != GetSize(sig_d)) { - log(" removing %d now obsolete bits from cell %s.\n", GetSize(sig_d) - GetSize(remaining_indices), log_id(dff_cell)); - RTLIL::SigSpec new_sig_d, new_sig_q; - for (int i : remaining_indices) { - new_sig_d.append(sig_d[i]); - new_sig_q.append(sig_q[i]); - } - dff_cell->setPort(ID::D, new_sig_d); - dff_cell->setPort(ID::Q, new_sig_q); - dff_cell->setParam(ID::WIDTH, GetSize(remaining_indices)); - } - } - - void run() - { - log("Transforming FF to FF+Enable cells in module %s:\n", log_id(module)); - for (auto dff_cell : dff_cells) { - // log("Handling candidate %s:\n", log_id(dff_cell)); - handle_dff_cell(dff_cell); - } - } -}; - -struct Dff2dffePass : public Pass { - Dff2dffePass() : Pass("dff2dffe", "transform $dff cells to $dffe cells") { } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" dff2dffe [options] [selection]\n"); - log("\n"); - log("This pass transforms $dff cells driven by a tree of multiplexers with one or\n"); - log("more feedback paths to $dffe cells. It also works on gate-level cells such as\n"); - log("$_DFF_P_, $_DFF_N_ and $_MUX_.\n"); - log("\n"); - log(" -unmap\n"); - log(" operate in the opposite direction: replace $dffe cells with combinations\n"); - log(" of $dff and $mux cells. the options below are ignored in unmap mode.\n"); - log("\n"); - log(" -unmap-mince N\n"); - log(" Same as -unmap but only unmap $dffe where the clock enable port\n"); - log(" signal is used by less $dffe than the specified number\n"); - log("\n"); - log(" -direct <internal_gate_type> <external_gate_type>\n"); - log(" map directly to external gate type. <internal_gate_type> can\n"); - log(" be any internal gate-level FF cell (except $_DFFE_??_). the\n"); - log(" <external_gate_type> is the cell type name for a cell with an\n"); - log(" identical interface to the <internal_gate_type>, except it\n"); - log(" also has an high-active enable port 'E'.\n"); - log(" Usually <external_gate_type> is an intermediate cell type\n"); - log(" that is then translated to the final type using 'techmap'.\n"); - log("\n"); - log(" -direct-match <pattern>\n"); - log(" like -direct for all DFF cell types matching the expression.\n"); - log(" this will use $_DFFE_* as <external_gate_type> matching the\n"); - log(" internal gate type $_DFF_*_, and $_SDFFE_* for those matching\n"); - log(" $_SDFF_*_, except for $_DFF_[NP]_, which is converted to \n"); - log(" $_DFFE_[NP]_.\n"); - log("\n"); - } - void execute(std::vector<std::string> args, RTLIL::Design *design) override - { - log_header(design, "Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n"); - - bool unmap_mode = false; - int min_ce_use = -1; - dict<IdString, IdString> direct_dict; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-unmap") { - unmap_mode = true; - continue; - } - if (args[argidx] == "-unmap-mince" && argidx + 1 < args.size()) { - unmap_mode = true; - min_ce_use = atoi(args[++argidx].c_str()); - continue; - } - if (args[argidx] == "-direct" && argidx + 2 < args.size()) { - string direct_from = RTLIL::escape_id(args[++argidx]); - string direct_to = RTLIL::escape_id(args[++argidx]); - direct_dict[direct_from] = direct_to; - continue; - } - if (args[argidx] == "-direct-match" && argidx + 1 < args.size()) { - bool found_match = false; - const char *pattern = args[++argidx].c_str(); - if (patmatch(pattern, "$_DFF_P_" )) found_match = true, direct_dict[ID($_DFF_P_) ] = ID($_DFFE_PP_); - if (patmatch(pattern, "$_DFF_N_" )) found_match = true, direct_dict[ID($_DFF_N_) ] = ID($_DFFE_NP_); - if (patmatch(pattern, "$_DFF_NN0_")) found_match = true, direct_dict[ID($_DFF_NN0_)] = ID($_DFFE_NN0P_); - if (patmatch(pattern, "$_DFF_NN1_")) found_match = true, direct_dict[ID($_DFF_NN1_)] = ID($_DFFE_NN1P_); - if (patmatch(pattern, "$_DFF_NP0_")) found_match = true, direct_dict[ID($_DFF_NP0_)] = ID($_DFFE_NP0P_); - if (patmatch(pattern, "$_DFF_NP1_")) found_match = true, direct_dict[ID($_DFF_NP1_)] = ID($_DFFE_NP1P_); - if (patmatch(pattern, "$_DFF_PN0_")) found_match = true, direct_dict[ID($_DFF_PN0_)] = ID($_DFFE_PN0P_); - if (patmatch(pattern, "$_DFF_PN1_")) found_match = true, direct_dict[ID($_DFF_PN1_)] = ID($_DFFE_PN1P_); - if (patmatch(pattern, "$_DFF_PP0_")) found_match = true, direct_dict[ID($_DFF_PP0_)] = ID($_DFFE_PP0P_); - if (patmatch(pattern, "$_DFF_PP1_")) found_match = true, direct_dict[ID($_DFF_PP1_)] = ID($_DFFE_PP1P_); - - if (patmatch(pattern, "$_SDFF_NN0_")) found_match = true, direct_dict[ID($_SDFF_NN0_)] = ID($_SDFFE_NN0P_); - if (patmatch(pattern, "$_SDFF_NN1_")) found_match = true, direct_dict[ID($_SDFF_NN1_)] = ID($_SDFFE_NN1P_); - if (patmatch(pattern, "$_SDFF_NP0_")) found_match = true, direct_dict[ID($_SDFF_NP0_)] = ID($_SDFFE_NP0P_); - if (patmatch(pattern, "$_SDFF_NP1_")) found_match = true, direct_dict[ID($_SDFF_NP1_)] = ID($_SDFFE_NP1P_); - if (patmatch(pattern, "$_SDFF_PN0_")) found_match = true, direct_dict[ID($_SDFF_PN0_)] = ID($_SDFFE_PN0P_); - if (patmatch(pattern, "$_SDFF_PN1_")) found_match = true, direct_dict[ID($_SDFF_PN1_)] = ID($_SDFFE_PN1P_); - if (patmatch(pattern, "$_SDFF_PP0_")) found_match = true, direct_dict[ID($_SDFF_PP0_)] = ID($_SDFFE_PP0P_); - if (patmatch(pattern, "$_SDFF_PP1_")) found_match = true, direct_dict[ID($_SDFF_PP1_)] = ID($_SDFFE_PP1P_); - if (!found_match) - log_cmd_error("No cell types matched pattern '%s'.\n", pattern); - continue; - } - break; - } - extra_args(args, argidx, design); - - if (!direct_dict.empty()) { - log("Selected cell types for direct conversion:\n"); - for (auto &it : direct_dict) - log(" %s -> %s\n", log_id(it.first), log_id(it.second)); - } - - for (auto mod : design->selected_modules()) - if (!mod->has_processes_warn()) - { - if (unmap_mode) { - SigMap sigmap(mod); - for (auto cell : mod->selected_cells()) { - if (cell->type == ID($dffe)) { - if (min_ce_use >= 0) { - int ce_use = 0; - for (auto cell_other : mod->selected_cells()) { - if (cell_other->type != cell->type) - continue; - if (sigmap(cell->getPort(ID::EN)) == sigmap(cell_other->getPort(ID::EN))) - ce_use++; - } - if (ce_use >= min_ce_use) - continue; - } - - RTLIL::SigSpec tmp = mod->addWire(NEW_ID, GetSize(cell->getPort(ID::D))); - mod->addDff(NEW_ID, cell->getPort(ID::CLK), tmp, cell->getPort(ID::Q), cell->getParam(ID::CLK_POLARITY).as_bool()); - if (cell->getParam(ID::EN_POLARITY).as_bool()) - mod->addMux(NEW_ID, cell->getPort(ID::Q), cell->getPort(ID::D), cell->getPort(ID::EN), tmp); - else - mod->addMux(NEW_ID, cell->getPort(ID::D), cell->getPort(ID::Q), cell->getPort(ID::EN), tmp); - mod->remove(cell); - continue; - } - if (cell->type.begins_with("$_DFFE_")) { - if (min_ce_use >= 0) { - int ce_use = 0; - for (auto cell_other : mod->selected_cells()) { - if (cell_other->type != cell->type) - continue; - if (sigmap(cell->getPort(ID::E)) == sigmap(cell_other->getPort(ID::E))) - ce_use++; - } - if (ce_use >= min_ce_use) - continue; - } - - bool clk_pol = cell->type.compare(7, 1, "P") == 0; - bool en_pol = cell->type.compare(8, 1, "P") == 0; - RTLIL::SigSpec tmp = mod->addWire(NEW_ID); - mod->addDff(NEW_ID, cell->getPort(ID::C), tmp, cell->getPort(ID::Q), clk_pol); - if (en_pol) - mod->addMux(NEW_ID, cell->getPort(ID::Q), cell->getPort(ID::D), cell->getPort(ID::E), tmp); - else - mod->addMux(NEW_ID, cell->getPort(ID::D), cell->getPort(ID::Q), cell->getPort(ID::E), tmp); - mod->remove(cell); - continue; - } - } - continue; - } - - Dff2dffeWorker worker(mod, direct_dict); - worker.run(); - } - } -} Dff2dffePass; - -PRIVATE_NAMESPACE_END diff --git a/passes/techmap/dff2dffs.cc b/passes/techmap/dff2dffs.cc deleted file mode 100644 index 6c2cca4bc..000000000 --- a/passes/techmap/dff2dffs.cc +++ /dev/null @@ -1,165 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * Copyright (C) 2018 David Shah <dave@ds0.me> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct Dff2dffsPass : public Pass { - Dff2dffsPass() : Pass("dff2dffs", "process sync set/reset with SR over CE priority") { } - void help() override - { - log("\n"); - log(" dff2dffs [options] [selection]\n"); - log("\n"); - log("Merge synchronous set/reset $_MUX_ cells to create $_SDFF_[NP][NP][01]_, to be run before\n"); - log("dff2dffe for SR over CE priority.\n"); - log("\n"); - log(" -match-init\n"); - log(" Disallow merging synchronous set/reset that has polarity opposite of the\n"); - log(" output wire's init attribute (if any).\n"); - log("\n"); - } - void execute(std::vector<std::string> args, RTLIL::Design *design) override - { - log_header(design, "Executing dff2dffs pass (merge synchronous set/reset into FF cells).\n"); - - bool match_init = false; - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - // if (args[argidx] == "-singleton") { - // singleton_mode = true; - // continue; - // } - if (args[argidx] == "-match-init") { - match_init = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - pool<IdString> dff_types; - dff_types.insert(ID($_DFF_N_)); - dff_types.insert(ID($_DFF_P_)); - - for (auto module : design->selected_modules()) - { - log("Merging set/reset $_MUX_ cells into DFFs in %s.\n", log_id(module)); - - SigMap sigmap(module); - dict<SigBit, Cell*> sr_muxes; - vector<Cell*> ff_cells; - - for (auto cell : module->selected_cells()) - { - if (dff_types.count(cell->type)) { - ff_cells.push_back(cell); - continue; - } - - if (cell->type != ID($_MUX_)) - continue; - - SigBit bit_a = sigmap(cell->getPort(ID::A)); - SigBit bit_b = sigmap(cell->getPort(ID::B)); - - if (bit_a.wire == nullptr || bit_b.wire == nullptr) - sr_muxes[sigmap(cell->getPort(ID::Y))] = cell; - } - - for (auto cell : ff_cells) - { - SigSpec sig_d = cell->getPort(ID::D); - - if (GetSize(sig_d) < 1) - continue; - - SigBit bit_d = sigmap(sig_d[0]); - - if (sr_muxes.count(bit_d) == 0) - continue; - - Cell *mux_cell = sr_muxes.at(bit_d); - SigBit bit_a = sigmap(mux_cell->getPort(ID::A)); - SigBit bit_b = sigmap(mux_cell->getPort(ID::B)); - SigBit bit_s = sigmap(mux_cell->getPort(ID::S)); - - SigBit sr_val, sr_sig; - bool invert_sr; - sr_sig = bit_s; - if (bit_a.wire == nullptr) { - bit_d = bit_b; - sr_val = bit_a; - invert_sr = true; - } else { - log_assert(bit_b.wire == nullptr); - bit_d = bit_a; - sr_val = bit_b; - invert_sr = false; - } - - if (match_init) { - SigBit bit_q = cell->getPort(ID::Q); - if (bit_q.wire) { - auto it = bit_q.wire->attributes.find(ID::init); - if (it != bit_q.wire->attributes.end()) { - auto init_val = it->second[bit_q.offset]; - if (init_val == State::S1 && sr_val != State::S1) - continue; - if (init_val == State::S0 && sr_val != State::S0) - continue; - } - } - } - - log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell), - log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type)); - - if (sr_val == State::S1) { - if (cell->type == ID($_DFF_N_)) { - if (invert_sr) cell->type = ID($_SDFF_NN1_); - else cell->type = ID($_SDFF_NP1_); - } else { - log_assert(cell->type == ID($_DFF_P_)); - if (invert_sr) cell->type = ID($_SDFF_PN1_); - else cell->type = ID($_SDFF_PP1_); - } - } else { - if (cell->type == ID($_DFF_N_)) { - if (invert_sr) cell->type = ID($_SDFF_NN0_); - else cell->type = ID($_SDFF_NP0_); - } else { - log_assert(cell->type == ID($_DFF_P_)); - if (invert_sr) cell->type = ID($_SDFF_PN0_); - else cell->type = ID($_SDFF_PP0_); - } - } - cell->setPort(ID::R, sr_sig); - cell->setPort(ID::D, bit_d); - } - } - } -} Dff2dffsPass; - -PRIVATE_NAMESPACE_END diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc index c60a901c1..9cfe55947 100644 --- a/passes/techmap/dffinit.cc +++ b/passes/techmap/dffinit.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,6 +19,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/ffinit.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -94,29 +95,10 @@ struct DffinitPass : public Pass { for (auto module : design->selected_modules()) { SigMap sigmap(module); - dict<SigBit, State> init_bits; - pool<SigBit> cleanup_bits; - pool<SigBit> used_bits; - - for (auto wire : module->selected_wires()) { - if (wire->attributes.count(ID::init)) { - Const value = wire->attributes.at(ID::init); - for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) - if (value[i] != State::Sx) - init_bits[sigmap(SigBit(wire, i))] = value[i]; - } - if (wire->port_output) - for (auto bit : sigmap(wire)) - used_bits.insert(bit); - } + FfInitVals initvals(&sigmap, module); for (auto cell : module->selected_cells()) { - for (auto it : cell->connections()) - if (!cell->known() || cell->input(it.first)) - for (auto bit : sigmap(it.second)) - used_bits.insert(bit); - if (ff_types.count(cell->type) == 0) continue; @@ -131,17 +113,18 @@ struct DffinitPass : public Pass { if (cell->hasParam(it.second)) value = cell->getParam(it.second); + Const initval = initvals(sig); + initvals.remove_init(sig); for (int i = 0; i < GetSize(sig); i++) { - if (init_bits.count(sig[i]) == 0) + if (initval[i] == State::Sx) continue; while (GetSize(value.bits) <= i) value.bits.push_back(State::S0); - if (noreinit && value.bits[i] != State::Sx && value.bits[i] != init_bits.at(sig[i])) + if (noreinit && value.bits[i] != State::Sx && value.bits[i] != initval[i]) log_error("Trying to assign a different init value for %s.%s.%s which technically " "have a conflicted init value.\n", log_id(module), log_id(cell), log_id(it.second)); - value.bits[i] = init_bits.at(sig[i]); - cleanup_bits.insert(sig[i]); + value.bits[i] = initval[i]; } if (highlow_mode && GetSize(value) != 0) { @@ -161,23 +144,6 @@ struct DffinitPass : public Pass { } } } - - for (auto wire : module->selected_wires()) - if (wire->attributes.count(ID::init)) { - Const &value = wire->attributes.at(ID::init); - bool do_cleanup = true; - for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) { - SigBit bit = sigmap(SigBit(wire, i)); - if (cleanup_bits.count(bit) || !used_bits.count(bit)) - value[i] = State::Sx; - else if (value[i] != State::Sx) - do_cleanup = false; - } - if (do_cleanup) { - log("Removing init attribute from wire %s.%s.\n", log_id(module), log_id(wire)); - wire->attributes.erase(ID::init); - } - } } } } DffinitPass; diff --git a/passes/techmap/dfflegalize.cc b/passes/techmap/dfflegalize.cc new file mode 100644 index 000000000..1d99caa3a --- /dev/null +++ b/passes/techmap/dfflegalize.cc @@ -0,0 +1,1235 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2020 Marcelina Kościelnicka <mwk@0x04.net> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" +#include "kernel/ffinit.h" +#include "kernel/ff.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +enum FfType { + FF_DFF, + FF_DFFE, + FF_ADFF, + FF_ADFFE, + FF_ALDFF, + FF_ALDFFE, + FF_DFFSR, + FF_DFFSRE, + FF_SDFF, + FF_SDFFE, + FF_SDFFCE, + FF_RLATCH, + FF_SR, + FF_DLATCH, + FF_ADLATCH, + FF_DLATCHSR, + NUM_FFTYPES, +}; + +enum FfNeg { + NEG_CE = 0x1, + NEG_R = 0x2, + NEG_S = 0x4, + NEG_L = 0x8, + NEG_C = 0x10, + NUM_NEG = 0x20, +}; + +enum FfInit { + INIT_X = 0x1, + INIT_0 = 0x2, + INIT_1 = 0x4, + INIT_X_R0 = 0x10, + INIT_0_R0 = 0x20, + INIT_1_R0 = 0x40, + INIT_X_R1 = 0x100, + INIT_0_R1 = 0x200, + INIT_1_R1 = 0x400, +}; + +struct DffLegalizePass : public Pass { + DffLegalizePass() : Pass("dfflegalize", "convert FFs to types supported by the target") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" dfflegalize [options] [selection]\n"); + log("\n"); + log("Converts FFs to types supported by the target.\n"); + log("\n"); + log(" -cell <cell_type_pattern> <init_values>\n"); + log(" specifies a supported group of FF cells. <cell_type_pattern>\n"); + log(" is a yosys internal fine cell name, where ? characters can be\n"); + log(" as a wildcard matching any character. <init_values> specifies\n"); + log(" which initialization values these FF cells can support, and can\n"); + log(" be one of:\n"); + log("\n"); + log(" - x (no init value supported)\n"); + log(" - 0\n"); + log(" - 1\n"); + log(" - r (init value has to match reset value, only for some FF types)\n"); + log(" - 01 (both 0 and 1 supported).\n"); + log("\n"); + log(" -mince <num>\n"); + log(" specifies a minimum number of FFs that should be using any given\n"); + log(" clock enable signal. If a clock enable signal doesn't meet this\n"); + log(" threshold, it is unmapped into soft logic.\n"); + log("\n"); + log(" -minsrst <num>\n"); + log(" specifies a minimum number of FFs that should be using any given\n"); + log(" sync set/reset signal. If a sync set/reset signal doesn't meet this\n"); + log(" threshold, it is unmapped into soft logic.\n"); + log("\n"); + log("The following cells are supported by this pass (ie. will be ingested,\n"); + log("and can be specified as allowed targets):\n"); + log("\n"); + log("- $_DFF_[NP]_\n"); + log("- $_DFFE_[NP][NP]_\n"); + log("- $_DFF_[NP][NP][01]_\n"); + log("- $_DFFE_[NP][NP][01][NP]_\n"); + log("- $_ALDFF_[NP][NP]_\n"); + log("- $_ALDFFE_[NP][NP][NP]_\n"); + log("- $_DFFSR_[NP][NP][NP]_\n"); + log("- $_DFFSRE_[NP][NP][NP][NP]_\n"); + log("- $_SDFF_[NP][NP][01]_\n"); + log("- $_SDFFE_[NP][NP][01][NP]_\n"); + log("- $_SDFFCE_[NP][NP][01][NP]_\n"); + log("- $_SR_[NP][NP]_\n"); + log("- $_DLATCH_[NP]_\n"); + log("- $_DLATCH_[NP][NP][01]_\n"); + log("- $_DLATCHSR_[NP][NP][NP]_\n"); + log("\n"); + log("The following transformations are performed by this pass:"); + log("\n"); + log("- upconversion from a less capable cell to a more capable cell, if the less"); + log(" capable cell is not supported (eg. dff -> dffe, or adff -> dffsr)"); + log("\n"); + log("- unmapping FFs with clock enable (due to unsupported cell type or -mince)"); + log("\n"); + log("- unmapping FFs with sync reset (due to unsupported cell type or -minsrst)"); + log("\n"); + log("- adding inverters on the control pins (due to unsupported polarity)"); + log("\n"); + log("- adding inverters on the D and Q pins and inverting the init/reset values\n"); + log(" (due to unsupported init or reset value)"); + log("\n"); + log("- converting sr into adlatch (by tying D to 1 and using E as set input)"); + log("\n"); + log("- emulating unsupported dffsr cell by adff + adff + sr + mux"); + log("\n"); + log("- emulating unsupported dlatchsr cell by adlatch + adlatch + sr + mux"); + log("\n"); + log("- emulating adff when the (reset, init) value combination is unsupported by\n"); + log(" dff + adff + dlatch + mux"); + log("\n"); + log("- emulating adlatch when the (reset, init) value combination is unsupported by\n"); + log("- dlatch + adlatch + dlatch + mux"); + log("\n"); + log("If the pass is unable to realize a given cell type (eg. adff when only plain dff"); + log("is available), an error is raised."); + } + + // Table of all supported cell types. + // First index in the array is one of the FF_* values, second + // index is the set of negative-polarity inputs (OR of NEG_* + // values), and the value is the set of supported init values + // (OR of INIT_* values). + int supported_cells_neg[NUM_FFTYPES][NUM_NEG]; + // Aggregated table ignoring signal polarity. + int supported_cells[NUM_FFTYPES]; + // Aggregated for all *dff* cells. + int supported_dff; + // Aggregated for all *dffe* cells. + int supported_dffe; + // Aggregated for all dffsr* cells. + int supported_dffsr; + // Aggregated for all aldff cells. + int supported_aldff; + // Aggregated for all aldffe cells. + int supported_aldffe; + // Aggregated for all adff* cells and trivial emulations. + int supported_adff; + // Aggregated for all adffe* cells and trivial emulations. + int supported_adffe; + // Aggregated for all sdff* cells. + int supported_sdff; + // Aggregated for all ways to obtain a SR latch. + int supported_sr; + int supported_sr_plain; + // Aggregated for all *dlatch* cells. + int supported_dlatch; + int supported_dlatch_plain; + // Aggregated for all ways to obtain an R latch. + int supported_rlatch; + // Aggregated for all adlatch cells and trivial emulations. + int supported_adlatch; + + int mince; + int minsrst; + + dict<SigBit, int> ce_used; + dict<SigBit, int> srst_used; + + SigMap sigmap; + FfInitVals initvals; + + int flip_initmask(int mask) { + int res = mask & INIT_X; + if (mask & INIT_0) + res |= INIT_1; + if (mask & INIT_1) + res |= INIT_0; + if (mask & INIT_X_R0) + res |= INIT_X_R1; + if (mask & INIT_0_R0) + res |= INIT_1_R1; + if (mask & INIT_1_R0) + res |= INIT_0_R1; + if (mask & INIT_X_R1) + res |= INIT_X_R0; + if (mask & INIT_0_R1) + res |= INIT_1_R0; + if (mask & INIT_1_R1) + res |= INIT_0_R0; + return res; + } + + int get_ff_type(const FfData &ff) { + if (ff.has_clk) { + if (ff.has_sr) { + return ff.has_ce ? FF_DFFSRE : FF_DFFSR; + } else if (ff.has_arst) { + return ff.has_ce ? FF_ADFFE : FF_ADFF; + } else if (ff.has_aload) { + return ff.has_ce ? FF_ALDFFE : FF_ALDFF; + } else if (ff.has_srst) { + if (ff.has_ce) + return ff.ce_over_srst ? FF_SDFFCE : FF_SDFFE; + else + return FF_SDFF; + } else { + return ff.has_ce ? FF_DFFE : FF_DFF; + } + } else { + if (ff.has_aload) { + if (ff.has_sr) + return FF_DLATCHSR; + else if (ff.has_arst) + return FF_ADLATCH; + else + return FF_DLATCH; + } else { + if (ff.has_sr) { + return FF_SR; + } else if (ff.has_arst) { + return FF_RLATCH; + } else { + log_assert(0); + return 0; + } + } + } + } + + int get_initmask(FfData &ff) { + int res = 0; + if (ff.val_init[0] == State::S0) + res = INIT_0; + else if (ff.val_init[0] == State::S1) + res = INIT_1; + else + res = INIT_X; + if (ff.has_arst) { + if (ff.val_arst[0] == State::S0) + res <<= 4; + else if (ff.val_arst[0] == State::S1) + res <<= 8; + } else if (ff.has_srst) { + if (ff.val_srst[0] == State::S0) + res <<= 4; + else if (ff.val_srst[0] == State::S1) + res <<= 8; + } + return res; + } + + void fail_ff(const FfData &ff, const char *reason) { + log_error("FF %s.%s (type %s) cannot be legalized: %s\n", log_id(ff.module->name), log_id(ff.cell->name), log_id(ff.cell->type), reason); + } + + bool try_flip(FfData &ff, int supported_mask) { + int initmask = get_initmask(ff); + if (supported_mask & initmask) + return true; + if (supported_mask & flip_initmask(initmask)) { + ff.flip_bits({0}); + return true; + } + return false; + } + + void emulate_split_init_arst(FfData &ff) { + ff.remove(); + + FfData ff_dff(ff.module, &initvals, NEW_ID); + ff_dff.width = ff.width; + ff_dff.has_aload = ff.has_aload; + ff_dff.sig_aload = ff.sig_aload; + ff_dff.pol_aload = ff.pol_aload; + ff_dff.sig_ad = ff.sig_ad; + ff_dff.has_clk = ff.has_clk; + ff_dff.sig_clk = ff.sig_clk; + ff_dff.pol_clk = ff.pol_clk; + ff_dff.sig_d = ff.sig_d; + ff_dff.has_ce = ff.has_ce; + ff_dff.sig_ce = ff.sig_ce; + ff_dff.pol_ce = ff.pol_ce; + ff_dff.sig_q = ff.module->addWire(NEW_ID, ff.width); + ff_dff.val_init = ff.val_init; + ff_dff.is_fine = ff.is_fine; + + FfData ff_adff(ff.module, &initvals, NEW_ID); + ff_adff.width = ff.width; + ff_adff.has_aload = ff.has_aload; + ff_adff.sig_aload = ff.sig_aload; + ff_adff.pol_aload = ff.pol_aload; + ff_adff.sig_ad = ff.sig_ad; + ff_adff.has_clk = ff.has_clk; + ff_adff.sig_clk = ff.sig_clk; + ff_adff.pol_clk = ff.pol_clk; + ff_adff.sig_d = ff.sig_d; + ff_adff.has_ce = ff.has_ce; + ff_adff.sig_ce = ff.sig_ce; + ff_adff.pol_ce = ff.pol_ce; + ff_adff.sig_q = ff.module->addWire(NEW_ID, ff.width); + ff_adff.val_init = Const(State::Sx, ff.width); + ff_adff.has_arst = true; + ff_adff.sig_arst = ff.sig_arst; + ff_adff.pol_arst = ff.pol_arst; + ff_adff.val_arst = ff.val_arst; + ff_adff.is_fine = ff.is_fine; + + FfData ff_sel(ff.module, &initvals, NEW_ID); + ff_sel.width = 1; + ff_sel.sig_q = ff.module->addWire(NEW_ID); + ff_sel.has_arst = true; + ff_sel.sig_arst = ff.sig_arst; + ff_sel.pol_arst = ff.pol_arst; + ff_sel.val_arst = State::S1; + ff_sel.val_init = State::S0; + ff_sel.is_fine = ff.is_fine; + + if (ff.is_fine) + ff.module->addMuxGate(NEW_ID, ff_dff.sig_q, ff_adff.sig_q, ff_sel.sig_q, ff.sig_q); + else + ff.module->addMux(NEW_ID, ff_dff.sig_q, ff_adff.sig_q, ff_sel.sig_q, ff.sig_q); + + legalize_ff(ff_dff); + legalize_ff(ff_adff); + legalize_ff(ff_sel); + } + + void emulate_split_set_clr(FfData &ff) { + // No native DFFSR. However, if we can conjure + // a SR latch and ADFF, it can still be emulated. + int initmask = get_initmask(ff); + int flipmask = flip_initmask(initmask); + bool init_clr = true; + bool init_set = true; + State initsel = State::Sx; + int supported_arst = ff.has_clk ? supported_adff : supported_adlatch; + bool init_clr_ok = (supported_arst & initmask << 4) || (supported_arst & flipmask << 8); + bool init_set_ok = (supported_arst & initmask << 8) || (supported_arst & flipmask << 4); + if (init_clr_ok && init_set_ok && supported_sr) { + // OK + } else if (init_clr_ok && (supported_sr & INIT_0)) { + init_set = false; + initsel = State::S0; + } else if (init_set_ok && (supported_sr & INIT_1)) { + init_clr = false; + initsel = State::S1; + } else if (init_clr_ok && (supported_sr & INIT_1)) { + init_set = false; + initsel = State::S0; + } else if (init_set_ok && (supported_sr & INIT_0)) { + init_clr = false; + initsel = State::S1; + } else { + if (ff.has_clk) { + if (!supported_dffsr) + fail_ff(ff, "dffs with async set and reset are not supported"); + else + fail_ff(ff, "initialized dffs with async set and reset are not supported"); + } else { + if (!supported_cells[FF_DLATCHSR]) + fail_ff(ff, "dlatch with async set and reset are not supported"); + else + fail_ff(ff, "initialized dlatch with async set and reset are not supported"); + } + } + + // If we have to unmap enable anyway, do it before breakdown. + if (ff.has_ce && !supported_cells[FF_ADFFE]) + ff.unmap_ce(); + + log_warning("Emulating async set + reset with several FFs and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name)); + + log_assert(ff.width == 1); + ff.remove(); + + FfData ff_clr(ff.module, &initvals, NEW_ID); + ff_clr.width = ff.width; + ff_clr.has_aload = ff.has_aload; + ff_clr.sig_aload = ff.sig_aload; + ff_clr.pol_aload = ff.pol_aload; + ff_clr.sig_ad = ff.sig_ad; + ff_clr.has_clk = ff.has_clk; + ff_clr.sig_clk = ff.sig_clk; + ff_clr.pol_clk = ff.pol_clk; + ff_clr.sig_d = ff.sig_d; + ff_clr.has_ce = ff.has_ce; + ff_clr.sig_ce = ff.sig_ce; + ff_clr.pol_ce = ff.pol_ce; + ff_clr.has_arst = true; + ff_clr.sig_arst = ff.sig_clr; + ff_clr.pol_arst = ff.pol_clr; + ff_clr.val_arst = Const(State::S0, ff.width); + ff_clr.sig_q = ff.module->addWire(NEW_ID, ff.width); + ff_clr.val_init = init_clr ? ff.val_init : Const(State::Sx, ff.width); + ff_clr.is_fine = ff.is_fine; + + FfData ff_set(ff.module, &initvals, NEW_ID); + ff_set.width = ff.width; + ff_set.has_aload = ff.has_aload; + ff_set.sig_aload = ff.sig_aload; + ff_set.pol_aload = ff.pol_aload; + ff_set.sig_ad = ff.sig_ad; + ff_set.has_clk = ff.has_clk; + ff_set.sig_clk = ff.sig_clk; + ff_set.pol_clk = ff.pol_clk; + ff_set.sig_d = ff.sig_d; + ff_set.has_ce = ff.has_ce; + ff_set.sig_ce = ff.sig_ce; + ff_set.pol_ce = ff.pol_ce; + ff_set.has_arst = true; + ff_set.sig_arst = ff.sig_set; + ff_set.pol_arst = ff.pol_set; + ff_set.val_arst = Const(State::S1, ff.width); + ff_set.sig_q = ff.module->addWire(NEW_ID, ff.width); + ff_set.val_init = init_set ? ff.val_init : Const(State::Sx, ff.width); + ff_set.is_fine = ff.is_fine; + + FfData ff_sel(ff.module, &initvals, NEW_ID); + ff_sel.width = ff.width; + ff_sel.has_sr = true; + ff_sel.pol_clr = ff.pol_clr; + ff_sel.pol_set = ff.pol_set; + ff_sel.sig_clr = ff.sig_clr; + ff_sel.sig_set = ff.sig_set; + ff_sel.sig_q = ff.module->addWire(NEW_ID, ff.width); + ff_sel.val_init = Const(initsel, ff.width); + ff_sel.is_fine = ff.is_fine; + + if (!ff.is_fine) + ff.module->addMux(NEW_ID, ff_clr.sig_q, ff_set.sig_q, ff_sel.sig_q, ff.sig_q); + else + ff.module->addMuxGate(NEW_ID, ff_clr.sig_q, ff_set.sig_q, ff_sel.sig_q, ff.sig_q); + + legalize_ff(ff_clr); + legalize_ff(ff_set); + legalize_ff(ff_sel); + } + + void legalize_dff(FfData &ff) { + if (!try_flip(ff, supported_dff)) { + if (!supported_dff) + fail_ff(ff, "D flip-flops are not supported"); + else + fail_ff(ff, "initialized D flip-flops are not supported"); + } + + int initmask = get_initmask(ff); + // Some DFF is supported with this init val. Just pick a type. + if (ff.has_ce && !(supported_dffe & initmask)) { + ff.unmap_ce(); + } + + if (!ff.has_ce) { + if (supported_cells[FF_DFF] & initmask) { + legalize_finish(ff); + return; + } + // Try adding a set or reset pin. + if (supported_cells[FF_SDFF] & initmask) { + ff.add_dummy_srst(); + legalize_finish(ff); + return; + } + if (supported_cells[FF_ADFF] & initmask) { + ff.add_dummy_arst(); + legalize_finish(ff); + return; + } + // Try adding async load. + if (supported_cells[FF_ALDFF] & initmask) { + ff.add_dummy_aload(); + legalize_finish(ff); + return; + } + // Try adding both. + if (supported_cells[FF_DFFSR] & initmask) { + ff.add_dummy_sr(); + legalize_finish(ff); + return; + } + // Nope. Will need to add enable and go the DFFE route. + ff.add_dummy_ce(); + } + if (supported_cells[FF_DFFE] & initmask) { + legalize_finish(ff); + return; + } + // Try adding a set or reset pin. + if (supported_cells[FF_SDFFCE] & initmask) { + ff.add_dummy_srst(); + ff.ce_over_srst = true; + legalize_finish(ff); + return; + } + if (supported_cells[FF_SDFFE] & initmask) { + ff.add_dummy_srst(); + legalize_finish(ff); + return; + } + if (supported_cells[FF_ADFFE] & initmask) { + ff.add_dummy_arst(); + legalize_finish(ff); + return; + } + if (supported_cells[FF_ALDFFE] & initmask) { + ff.add_dummy_aload(); + legalize_finish(ff); + return; + } + // Try adding both. + if (supported_cells[FF_DFFSRE] & initmask) { + ff.add_dummy_sr(); + legalize_finish(ff); + return; + } + log_assert(0); + } + + void legalize_sdffce(FfData &ff) { + if (!try_flip(ff, supported_cells[FF_SDFFCE] | supported_cells[FF_SDFFE])) { + ff.unmap_srst(); + legalize_dff(ff); + return; + } + + int initmask = get_initmask(ff); + if (supported_cells[FF_SDFFCE] & initmask) { + // OK + } else if (supported_cells[FF_SDFFE] & initmask) { + ff.convert_ce_over_srst(false); + } else { + log_assert(0); + } + legalize_finish(ff); + } + + void legalize_sdff(FfData &ff) { + if (!try_flip(ff, supported_sdff)) { + ff.unmap_srst(); + legalize_dff(ff); + return; + } + + int initmask = get_initmask(ff); + if (!ff.has_ce) { + if (supported_cells[FF_SDFF] & initmask) { + // OK + } else if (supported_cells[FF_SDFFE] & initmask) { + ff.add_dummy_ce(); + } else if (supported_cells[FF_SDFFCE] & initmask) { + ff.add_dummy_ce(); + ff.ce_over_srst = true; + } else { + log_assert(0); + } + } else { + log_assert(!ff.ce_over_srst); + if (supported_cells[FF_SDFFE] & initmask) { + // OK + } else if (supported_cells[FF_SDFFCE] & initmask) { + ff.convert_ce_over_srst(true); + } else if (supported_cells[FF_SDFF] & initmask) { + ff.unmap_ce(); + } else { + log_assert(0); + } + } + legalize_finish(ff); + } + + void legalize_adff(FfData &ff) { + if (!try_flip(ff, supported_adff)) { + if (!supported_adff) + fail_ff(ff, "dffs with async set or reset are not supported"); + if (!(supported_dff & (INIT_0 | INIT_1))) + fail_ff(ff, "initialized dffs are not supported"); + + // If we got here, initialized dff is supported, but not this + // particular reset+init combination (nor its negation). + // The only hope left is breaking down to adff + dff + dlatch + mux. + + if (!((supported_rlatch) & (INIT_0_R1 | INIT_1_R0))) + fail_ff(ff, "unsupported initial value and async reset value combination"); + + // If we have to unmap enable anyway, do it before breakdown. + if (ff.has_ce && !supported_cells[FF_ADFFE]) + ff.unmap_ce(); + + if (ff.cell) + log_warning("Emulating mismatched async reset and init with several FFs and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name)); + emulate_split_init_arst(ff); + return; + } + + int initmask = get_initmask(ff); + if (ff.has_ce && !(supported_adffe & initmask)) { + ff.unmap_ce(); + } + + if (!ff.has_ce) { + if (supported_cells[FF_ADFF] & initmask) { + legalize_finish(ff); + return; + } + // Try converting to async load. + if (supported_cells[FF_ALDFF] & initmask) { + ff.arst_to_aload(); + legalize_finish(ff); + return; + } + // Try convertint to SR. + if (supported_cells[FF_DFFSR] & initmask) { + ff.arst_to_sr(); + legalize_finish(ff); + return; + } + ff.add_dummy_ce(); + } + if (supported_cells[FF_ADFFE] & initmask) { + legalize_finish(ff); + return; + } + // Try converting to async load. + if (supported_cells[FF_ALDFFE] & initmask) { + ff.arst_to_aload(); + legalize_finish(ff); + return; + } + // Try convertint to SR. + if (supported_cells[FF_DFFSRE] & initmask) { + ff.arst_to_sr(); + legalize_finish(ff); + return; + } + log_assert(0); + } + + void legalize_aldff(FfData &ff) { + if (!try_flip(ff, supported_aldff)) { + ff.aload_to_sr(); + emulate_split_set_clr(ff); + return; + } + + int initmask = get_initmask(ff); + if (ff.has_ce && !(supported_aldffe & initmask)) { + ff.unmap_ce(); + } + + if (!ff.has_ce) { + if (supported_cells[FF_ALDFF] & initmask) { + legalize_finish(ff); + return; + } + if (supported_cells[FF_DFFSR] & initmask) { + ff.aload_to_sr(); + legalize_finish(ff); + return; + } + ff.add_dummy_ce(); + } + if (supported_cells[FF_ALDFFE] & initmask) { + legalize_finish(ff); + return; + } + if (supported_cells[FF_DFFSRE] & initmask) { + ff.aload_to_sr(); + legalize_finish(ff); + return; + } + log_assert(0); + } + + void legalize_dffsr(FfData &ff) { + if (!try_flip(ff, supported_dffsr)) { + emulate_split_set_clr(ff); + return; + } + + int initmask = get_initmask(ff); + if (ff.has_ce && !(supported_cells[FF_DFFSRE] & initmask)) { + ff.unmap_ce(); + } + + if (!ff.has_ce) { + if (supported_cells[FF_DFFSR] & initmask) { + legalize_finish(ff); + return; + } + ff.add_dummy_ce(); + } + + log_assert(supported_cells[FF_DFFSRE] & initmask); + legalize_finish(ff); + } + + void legalize_dlatch(FfData &ff) { + if (!try_flip(ff, supported_dlatch)) { + if (!supported_dlatch) + fail_ff(ff, "D latches are not supported"); + else + fail_ff(ff, "initialized D latches are not supported"); + } + + int initmask = get_initmask(ff); + // Some DLATCH is supported with this init val. Just pick a type. + if (supported_cells[FF_DLATCH] & initmask) { + legalize_finish(ff); + } else if (supported_cells[FF_ADLATCH] & initmask) { + ff.add_dummy_arst(); + legalize_finish(ff); + } else if (supported_cells[FF_DLATCHSR] & initmask) { + ff.add_dummy_sr(); + legalize_finish(ff); + } else if (supported_cells[FF_ALDFF] & initmask) { + ff.add_dummy_clk(); + legalize_finish(ff); + } else if (supported_cells[FF_ALDFFE] & initmask) { + ff.add_dummy_clk(); + ff.add_dummy_ce(); + legalize_finish(ff); + } else if (supported_sr & initmask) { + ff.aload_to_sr(); + legalize_sr(ff); + } else { + log_assert(0); + } + } + + void legalize_adlatch(FfData &ff) { + if (!try_flip(ff, supported_adlatch)) { + if (!supported_adlatch) + fail_ff(ff, "D latches with async set or reset are not supported"); + if (!(supported_dlatch & (INIT_0 | INIT_1))) + fail_ff(ff, "initialized D latches are not supported"); + + // If we got here, initialized dlatch is supported, but not this + // particular reset+init combination (nor its negation). + // The only hope left is breaking down to adlatch + dlatch + dlatch + mux. + + if (ff.cell) + log_warning("Emulating mismatched async reset and init with several latches and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name)); + ff.remove(); + + emulate_split_init_arst(ff); + return; + } + int initmask = get_initmask(ff); + if (supported_cells[FF_ADLATCH] & initmask) { + // OK + } else if (supported_cells[FF_DLATCHSR] & initmask) { + ff.arst_to_sr(); + } else { + log_assert(0); + } + legalize_finish(ff); + } + + void legalize_dlatchsr(FfData &ff) { + if (!try_flip(ff, supported_cells[FF_DLATCHSR])) { + emulate_split_set_clr(ff); + return; + } + legalize_finish(ff); + } + + void legalize_rlatch(FfData &ff) { + if (!try_flip(ff, supported_rlatch)) { + if (!supported_dlatch) + fail_ff(ff, "D latches are not supported"); + else + fail_ff(ff, "initialized D latches are not supported"); + } + + int initmask = get_initmask(ff); + if (((supported_dlatch_plain & 7) * 0x111) & initmask) { + ff.arst_to_aload(); + legalize_dlatch(ff); + } else if (supported_sr & initmask) { + ff.arst_to_sr(); + legalize_sr(ff); + } else if (supported_adff & initmask) { + ff.add_dummy_clk(); + legalize_adff(ff); + } else { + log_assert(0); + } + } + + void legalize_sr(FfData &ff) { + if (!try_flip(ff, supported_sr)) { + if (!supported_sr) + fail_ff(ff, "sr latches are not supported"); + else + fail_ff(ff, "initialized sr latches are not supported"); + } + int initmask = get_initmask(ff); + if (supported_cells[FF_SR] & initmask) { + // OK + } else if (supported_cells[FF_DLATCHSR] & initmask) { + // Upgrade to DLATCHSR. + ff.add_dummy_aload(); + } else if (supported_cells[FF_DFFSR] & initmask) { + // Upgrade to DFFSR. + ff.add_dummy_clk(); + } else if (supported_cells[FF_DFFSRE] & initmask) { + // Upgrade to DFFSRE. + ff.add_dummy_clk(); + ff.add_dummy_ce(); + } else if (supported_cells[FF_ADLATCH] & (initmask << 4)) { + ff.has_sr = false; + ff.has_aload = true; + ff.has_arst = true; + ff.pol_arst = ff.pol_clr; + ff.sig_arst = ff.sig_clr; + ff.sig_aload = ff.sig_set; + ff.pol_aload = ff.pol_set; + ff.sig_ad = State::S1; + ff.val_arst = State::S0; + } else if (supported_cells[FF_ADLATCH] & (flip_initmask(initmask) << 8)) { + ff.has_sr = false; + ff.has_aload = true; + ff.has_arst = true; + ff.pol_arst = ff.pol_clr; + ff.sig_arst = ff.sig_clr; + ff.sig_aload = ff.sig_set; + ff.pol_aload = ff.pol_set; + ff.sig_ad = State::S0; + ff.val_arst = State::S1; + ff.remove_init(); + Wire *new_q = ff.module->addWire(NEW_ID); + if (ff.is_fine) + ff.module->addNotGate(NEW_ID, new_q, ff.sig_q); + else + ff.module->addNot(NEW_ID, new_q, ff.sig_q); + ff.sig_q = new_q; + if (ff.val_init == State::S0) + ff.val_init = State::S1; + else if (ff.val_init == State::S1) + ff.val_init = State::S0; + } else { + log_assert(0); + } + legalize_finish(ff); + } + + void fixup_reset_x(FfData &ff, int supported) { + for (int i = 0; i < ff.width; i++) { + int mask; + if (ff.val_init[i] == State::S0) + mask = INIT_0; + else if (ff.val_init[i] == State::S1) + mask = INIT_1; + else + mask = INIT_X; + if (ff.has_arst) { + if (ff.val_arst[i] == State::Sx) { + if (!(supported & (mask << 8))) + ff.val_arst[i] = State::S0; + if (!(supported & (mask << 4))) + ff.val_arst[i] = State::S1; + } + } + if (ff.has_srst) { + if (ff.val_srst[i] == State::Sx) { + if (!(supported & (mask << 8))) + ff.val_srst[i] = State::S0; + if (!(supported & (mask << 4))) + ff.val_srst[i] = State::S1; + } + } + } + } + + void legalize_ff(FfData &ff) { + if (ff.has_gclk) + return; + + // TODO: consider supporting coarse as well. + if (!ff.is_fine) + return; + + if (mince && ff.has_ce && ff.sig_ce[0].wire && ce_used[ff.sig_ce[0]] < mince) + ff.unmap_ce(); + if (minsrst && ff.has_srst && ff.sig_srst[0].wire && srst_used[ff.sig_srst[0]] < minsrst) + ff.unmap_srst(); + + if (ff.has_clk) { + if (ff.has_sr) { + legalize_dffsr(ff); + } else if (ff.has_aload) { + legalize_aldff(ff); + } else if (ff.has_arst) { + legalize_adff(ff); + } else if (ff.has_srst) { + if (ff.has_ce && ff.ce_over_srst) + legalize_sdffce(ff); + else + legalize_sdff(ff); + } else { + legalize_dff(ff); + } + } else if (ff.has_aload) { + if (ff.has_sr) { + legalize_dlatchsr(ff); + } else if (ff.has_arst) { + legalize_adlatch(ff); + } else { + legalize_dlatch(ff); + } + } else { + if (ff.has_sr) { + legalize_sr(ff); + } else if (ff.has_arst) { + legalize_rlatch(ff); + } else { + log_assert(0); + } + } + } + + void flip_pol(FfData &ff, SigSpec &sig, bool &pol) { + if (sig == State::S0) { + sig = State::S1; + } else if (sig == State::S1) { + sig = State::S0; + } else if (ff.is_fine) { + sig = ff.module->NotGate(NEW_ID, sig); + } else { + sig = ff.module->Not(NEW_ID, sig); + } + pol = !pol; + } + + void legalize_finish(FfData &ff) { + int ff_type = get_ff_type(ff); + int initmask = get_initmask(ff); + log_assert(supported_cells[ff_type] & initmask); + int ff_neg = 0; + if (ff.has_sr) { + if (!ff.pol_clr) + ff_neg |= NEG_R; + if (!ff.pol_set) + ff_neg |= NEG_S; + } + if (ff.has_arst) { + if (!ff.pol_arst) + ff_neg |= NEG_R; + } + if (ff.has_srst) { + if (!ff.pol_srst) + ff_neg |= NEG_R; + } + if (ff.has_aload) { + if (!ff.pol_aload) + ff_neg |= NEG_L; + } + if (ff.has_clk) { + if (!ff.pol_clk) + ff_neg |= NEG_C; + } + if (ff.has_ce) { + if (!ff.pol_ce) + ff_neg |= NEG_CE; + } + if (!(supported_cells_neg[ff_type][ff_neg] & initmask)) { + // Cell is supported, but not with those polarities. + // Will need to add some inverters. + + // Find the smallest value that xored with the neg mask + // results in a supported one — this results in preferentially + // inverting resets before clocks, etc. + int xneg; + for (xneg = 0; xneg < NUM_NEG; xneg++) + if (supported_cells_neg[ff_type][ff_neg ^ xneg] & initmask) + break; + log_assert(xneg < NUM_NEG); + if (xneg & NEG_CE) + flip_pol(ff, ff.sig_ce, ff.pol_ce); + if (ff.has_sr) { + if (xneg & NEG_R) + flip_pol(ff, ff.sig_clr, ff.pol_clr); + if (xneg & NEG_S) + flip_pol(ff, ff.sig_set, ff.pol_set); + } + if (ff.has_arst && xneg & NEG_R) + flip_pol(ff, ff.sig_arst, ff.pol_arst); + if (ff.has_srst && xneg & NEG_R) + flip_pol(ff, ff.sig_srst, ff.pol_srst); + if (xneg & NEG_L) + flip_pol(ff, ff.sig_aload, ff.pol_aload); + if (xneg & NEG_C) + flip_pol(ff, ff.sig_clk, ff.pol_clk); + ff_neg ^= xneg; + } + + fixup_reset_x(ff, supported_cells_neg[ff_type][ff_neg]); + ff.emit(); + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) override + { + + log_header(design, "Executing DFFLEGALIZE pass (convert FFs to types supported by the target).\n"); + + for (int i = 0; i < NUM_FFTYPES; i++) { + for (int j = 0; j < NUM_NEG; j++) + supported_cells_neg[i][j] = 0; + supported_cells[i] = 0; + } + mince = 0; + minsrst = 0; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-cell" && argidx + 2 < args.size()) { + std::string celltype = args[++argidx]; + std::string inittype = args[++argidx]; + enum FfType ff_type; + char pol_c = 0; + char pol_l = 0; + char pol_s = 0; + char pol_r = 0; + char pol_ce = 0; + char srval = 0; + if (celltype.substr(0, 5) == "$_SR_" && celltype.size() == 8 && celltype[7] == '_') { + ff_type = FF_SR; + pol_s = celltype[5]; + pol_r = celltype[6]; + } else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 8 && celltype[7] == '_') { + ff_type = FF_DFF; + pol_c = celltype[6]; + } else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 10 && celltype[9] == '_') { + ff_type = FF_DFFE; + pol_c = celltype[7]; + pol_ce = celltype[8]; + } else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 10 && celltype[9] == '_') { + ff_type = FF_ADFF; + pol_c = celltype[6]; + pol_r = celltype[7]; + srval = celltype[8]; + } else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 12 && celltype[11] == '_') { + ff_type = FF_ADFFE; + pol_c = celltype[7]; + pol_r = celltype[8]; + srval = celltype[9]; + pol_ce = celltype[10]; + } else if (celltype.substr(0, 8) == "$_ALDFF_" && celltype.size() == 11 && celltype[10] == '_') { + ff_type = FF_ALDFF; + pol_c = celltype[8]; + pol_l = celltype[9]; + } else if (celltype.substr(0, 9) == "$_ALDFFE_" && celltype.size() == 13 && celltype[12] == '_') { + ff_type = FF_ALDFFE; + pol_c = celltype[9]; + pol_l = celltype[10]; + pol_ce = celltype[11]; + } else if (celltype.substr(0, 8) == "$_DFFSR_" && celltype.size() == 12 && celltype[11] == '_') { + ff_type = FF_DFFSR; + pol_c = celltype[8]; + pol_s = celltype[9]; + pol_r = celltype[10]; + } else if (celltype.substr(0, 9) == "$_DFFSRE_" && celltype.size() == 14 && celltype[13] == '_') { + ff_type = FF_DFFSRE; + pol_c = celltype[9]; + pol_s = celltype[10]; + pol_r = celltype[11]; + pol_ce = celltype[12]; + } else if (celltype.substr(0, 7) == "$_SDFF_" && celltype.size() == 11 && celltype[10] == '_') { + ff_type = FF_SDFF; + pol_c = celltype[7]; + pol_r = celltype[8]; + srval = celltype[9]; + } else if (celltype.substr(0, 8) == "$_SDFFE_" && celltype.size() == 13 && celltype[12] == '_') { + ff_type = FF_SDFFE; + pol_c = celltype[8]; + pol_r = celltype[9]; + srval = celltype[10]; + pol_ce = celltype[11]; + } else if (celltype.substr(0, 9) == "$_SDFFCE_" && celltype.size() == 14 && celltype[13] == '_') { + ff_type = FF_SDFFCE; + pol_c = celltype[9]; + pol_r = celltype[10]; + srval = celltype[11]; + pol_ce = celltype[12]; + } else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 11 && celltype[10] == '_') { + ff_type = FF_DLATCH; + pol_l = celltype[9]; + } else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 13 && celltype[12] == '_') { + ff_type = FF_ADLATCH; + pol_l = celltype[9]; + pol_r = celltype[10]; + srval = celltype[11]; + } else if (celltype.substr(0, 11) == "$_DLATCHSR_" && celltype.size() == 15 && celltype[14] == '_') { + ff_type = FF_DLATCHSR; + pol_l = celltype[11]; + pol_s = celltype[12]; + pol_r = celltype[13]; + } else { +unrecognized: + log_error("unrecognized cell type %s.\n", celltype.c_str()); + } + int mask = 0; + int match = 0; + for (auto pair : { + std::make_pair(pol_c, NEG_C), + std::make_pair(pol_l, NEG_L), + std::make_pair(pol_s, NEG_S), + std::make_pair(pol_r, NEG_R), + std::make_pair(pol_ce, NEG_CE), + }) { + if (pair.first == 'N') { + mask |= pair.second; + match |= pair.second; + } else if (pair.first == 'P' || pair.first == 0) { + mask |= pair.second; + } else if (pair.first != '?') { + goto unrecognized; + } + } + int initmask; + if (inittype == "x") { + initmask = 0x111; + } else if (inittype == "0") { + initmask = 0x333; + } else if (inittype == "1") { + initmask = 0x555; + } else if (inittype == "r") { + if (srval == 0) + log_error("init type r not valid for cell type %s.\n", celltype.c_str()); + initmask = 0x537; + } else if (inittype == "01") { + initmask = 0x777; + } else { + log_error("unrecognized init type %s for cell type %s.\n", inittype.c_str(), celltype.c_str()); + } + if (srval == '0') { + initmask &= 0x0ff; + } else if (srval == '1') { + initmask &= 0xf0f; + } else if (srval != 0 && srval != '?') { + goto unrecognized; + } + for (int neg = 0; neg < NUM_NEG; neg++) + if ((neg & mask) == match) + supported_cells_neg[ff_type][neg] |= initmask; + supported_cells[ff_type] |= initmask; + continue; + } else if (args[argidx] == "-mince" && argidx + 1 < args.size()) { + mince = atoi(args[++argidx].c_str()); + continue; + } else if (args[argidx] == "-minsrst" && argidx + 1 < args.size()) { + minsrst = atoi(args[++argidx].c_str()); + continue; + } + break; + } + extra_args(args, argidx, design); + supported_dffsr = supported_cells[FF_DFFSR] | supported_cells[FF_DFFSRE]; + supported_aldff = supported_cells[FF_ALDFF] | supported_cells[FF_ALDFFE] | supported_dffsr; + supported_aldffe = supported_cells[FF_ALDFFE] | supported_cells[FF_DFFSRE]; + supported_adff = supported_cells[FF_ADFF] | supported_cells[FF_ADFFE] | supported_dffsr | supported_aldff; + supported_adffe = supported_cells[FF_ADFFE] | supported_cells[FF_ALDFFE] | supported_cells[FF_DFFSRE]; + supported_sdff = supported_cells[FF_SDFF] | supported_cells[FF_SDFFE] | supported_cells[FF_SDFFCE]; + supported_dff = supported_cells[FF_DFF] | supported_cells[FF_DFFE] | supported_adff | supported_sdff; + supported_dffe = supported_cells[FF_DFFE] | supported_cells[FF_DFFSRE] | supported_cells[FF_ALDFFE] | supported_cells[FF_ADFFE] | supported_cells[FF_SDFFE] | supported_cells[FF_SDFFCE]; + supported_sr_plain = supported_dffsr | supported_cells[FF_DLATCHSR] | supported_cells[FF_SR]; + supported_sr = supported_sr_plain; + supported_sr |= (supported_cells[FF_ADLATCH] >> 4 & 7) * 0x111; + supported_sr |= (flip_initmask(supported_cells[FF_ADLATCH]) >> 4 & 7) * 0x111; + supported_dlatch_plain = supported_cells[FF_DLATCH] | supported_cells[FF_ADLATCH] | supported_cells[FF_DLATCHSR] | supported_cells[FF_ALDFF] | supported_cells[FF_ALDFFE]; + supported_dlatch = supported_dlatch_plain | supported_sr_plain; + supported_rlatch = supported_adff | (supported_dlatch & 7) * 0x111; + supported_adlatch = supported_cells[FF_ADLATCH] | supported_cells[FF_DLATCHSR]; + + for (auto module : design->selected_modules()) + { + sigmap.set(module); + initvals.set(&sigmap, module); + + if (mince || minsrst) { + ce_used.clear(); + srst_used.clear(); + + for (auto cell : module->cells()) { + if (!RTLIL::builtin_ff_cell_types().count(cell->type)) + continue; + + FfData ff(&initvals, cell); + if (ff.has_ce && ff.sig_ce[0].wire) + ce_used[ff.sig_ce[0]] += ff.width; + if (ff.has_srst && ff.sig_srst[0].wire) + srst_used[ff.sig_srst[0]] += ff.width; + } + } + for (auto cell : module->selected_cells()) + { + if (!RTLIL::builtin_ff_cell_types().count(cell->type)) + continue; + FfData ff(&initvals, cell); + legalize_ff(ff); + } + } + + sigmap.clear(); + initvals.clear(); + ce_used.clear(); + srst_used.clear(); + } +} DffLegalizePass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index c189d649b..252baae9a 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -115,7 +115,7 @@ static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name, return false; } -static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool prepare_mode) +static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval) { LibertyAst *best_cell = nullptr; std::map<std::string, char> best_cell_ports; @@ -222,21 +222,12 @@ static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has if (best_cell != nullptr) { log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str()); - if (prepare_mode) { - cell_mappings[cell_type].cell_name = cell_type; - cell_mappings[cell_type].ports["C"] = 'C'; - if (has_reset) - cell_mappings[cell_type].ports["R"] = 'R'; - cell_mappings[cell_type].ports["D"] = 'D'; - cell_mappings[cell_type].ports["Q"] = 'Q'; - } else { - cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); - cell_mappings[cell_type].ports = best_cell_ports; - } + cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); + cell_mappings[cell_type].ports = best_cell_ports; } } -static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol, bool prepare_mode) +static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol) { LibertyAst *best_cell = nullptr; std::map<std::string, char> best_cell_ports; @@ -339,141 +330,12 @@ static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool if (best_cell != nullptr) { log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str()); - if (prepare_mode) { - cell_mappings[cell_type].cell_name = cell_type; - cell_mappings[cell_type].ports["C"] = 'C'; - cell_mappings[cell_type].ports["S"] = 'S'; - cell_mappings[cell_type].ports["R"] = 'R'; - cell_mappings[cell_type].ports["D"] = 'D'; - cell_mappings[cell_type].ports["Q"] = 'Q'; - } else { - cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); - cell_mappings[cell_type].ports = best_cell_ports; - } + cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); + cell_mappings[cell_type].ports = best_cell_ports; } } -static bool expand_cellmap_worker(std::string from, std::string to, std::string inv) -{ - if (cell_mappings.count(to) > 0) - return false; - - log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str()); - cell_mappings[to].cell_name = cell_mappings[from].cell_name; - cell_mappings[to].ports = cell_mappings[from].ports; - - for (auto &it : cell_mappings[to].ports) { - char cmp_ch = it.second; - if ('a' <= cmp_ch && cmp_ch <= 'z') - cmp_ch -= 'a' - 'A'; - if (inv.find(cmp_ch) == std::string::npos) - continue; - if ('a' <= it.second && it.second <= 'z') - it.second -= 'a' - 'A'; - else if ('A' <= it.second && it.second <= 'Z') - it.second += 'a' - 'A'; - } - return true; -} - -static bool expand_cellmap(std::string pattern, std::string inv) -{ - std::vector<std::pair<std::string, std::string>> from_to_list; - bool return_status = false; - - for (auto &it : cell_mappings) { - std::string from = it.first.str(), to = it.first.str(); - if (from.size() != pattern.size()) - continue; - for (size_t i = 0; i < from.size(); i++) { - if (pattern[i] == '*') { - to[i] = from[i] == 'P' ? 'N' : - from[i] == 'N' ? 'P' : - from[i] == '1' ? '0' : - from[i] == '0' ? '1' : '*'; - } else - if (pattern[i] != '?' && pattern[i] != from[i]) - goto pattern_failed; - } - from_to_list.push_back(std::pair<std::string, std::string>(from, to)); - pattern_failed:; - } - - for (auto &it : from_to_list) - return_status = return_status || expand_cellmap_worker(it.first, it.second, inv); - return return_status; -} - -static void map_sr_to_arst(IdString from, IdString to) -{ - if (!cell_mappings.count(from) || cell_mappings.count(to) > 0) - return; - - char from_clk_pol = from[8]; - char from_set_pol = from[9]; - char from_clr_pol = from[10]; - char to_clk_pol = to[6]; - char to_rst_pol = to[7]; - char to_rst_val = to[8]; - - log_assert(from_clk_pol == to_clk_pol); - log_assert(to_rst_pol == from_set_pol && to_rst_pol == from_clr_pol); - - log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str()); - cell_mappings[to].cell_name = cell_mappings[from].cell_name; - cell_mappings[to].ports = cell_mappings[from].ports; - - for (auto &it : cell_mappings[to].ports) - { - bool is_set_pin = it.second == 'S' || it.second == 's'; - bool is_clr_pin = it.second == 'R' || it.second == 'r'; - - if (!is_set_pin && !is_clr_pin) - continue; - - if ((to_rst_val == '0' && is_set_pin) || (to_rst_val == '1' && is_clr_pin)) - { - // this is the unused set/clr pin -- deactivate it - if (is_set_pin) - it.second = (from_set_pol == 'P') == (it.second == 'S') ? '0' : '1'; - else - it.second = (from_clr_pol == 'P') == (it.second == 'R') ? '0' : '1'; - } - else - { - // this is the used set/clr pin -- rename it to 'reset' - if (it.second == 'S') - it.second = 'R'; - if (it.second == 's') - it.second = 'r'; - } - } -} - -static void map_adff_to_dff(IdString from, IdString to) -{ - if (!cell_mappings.count(from) || cell_mappings.count(to) > 0) - return; - - char from_clk_pol = from[6]; - char from_rst_pol = from[7]; - char to_clk_pol = to[6]; - - log_assert(from_clk_pol == to_clk_pol); - - log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str()); - cell_mappings[to].cell_name = cell_mappings[from].cell_name; - cell_mappings[to].ports = cell_mappings[from].ports; - - for (auto &it : cell_mappings[to].ports) { - if (it.second == 'S' || it.second == 'R') - it.second = from_rst_pol == 'P' ? '0' : '1'; - if (it.second == 's' || it.second == 'r') - it.second = from_rst_pol == 'P' ? '1' : '0'; - } -} - -static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare_mode) +static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module) { log("Mapping DFF cells in module `%s':\n", module->name.c_str()); @@ -499,7 +361,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare module->remove(cell); cell_mapping &cm = cell_mappings[cell_type]; - RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : cm.cell_name); + RTLIL::Cell *new_cell = module->addCell(cell_name, cm.cell_name); new_cell->set_src_attribute(src); @@ -552,7 +414,7 @@ struct DfflibmapPass : public Pass { void help() override { log("\n"); - log(" dfflibmap [-prepare] -liberty <file> [selection]\n"); + log(" dfflibmap [-prepare] [-map-only] [-info] -liberty <file> [selection]\n"); log("\n"); log("Map internal flip-flop cells to the flip-flop cells in the technology\n"); log("library specified in the given liberty file.\n"); @@ -562,15 +424,27 @@ struct DfflibmapPass : public Pass { log("\n"); log("When called with -prepare, this command will convert the internal FF cells\n"); log("to the internal cell types that best match the cells found in the given\n"); - log("liberty file.\n"); + log("liberty file, but won't actually map them to the target cells.\n"); + log("\n"); + log("When called with -map-only, this command will only map internal cell\n"); + log("types that are already of exactly the right type to match the target\n"); + log("cells, leaving remaining internal cells untouched.\n"); + log("\n"); + log("When called with -info, this command will only print the target cell\n"); + log("list, along with their associated internal cell types, and the arguments"); + log("that would be passed to the dfflegalize pass. The design will not be\n"); + log("changed.\n"); log("\n"); } void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n"); + log_push(); std::string liberty_file; bool prepare_mode = false; + bool map_only_mode = false; + bool info_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -585,10 +459,28 @@ struct DfflibmapPass : public Pass { prepare_mode = true; continue; } + if (arg == "-map-only") { + map_only_mode = true; + continue; + } + if (arg == "-info") { + info_mode = true; + continue; + } break; } extra_args(args, argidx, design); + int modes = 0; + if (prepare_mode) + modes++; + if (map_only_mode) + modes++; + if (info_mode) + modes++; + if (modes > 1) + log_cmd_error("Only one of -prepare, -map-only, or -info options should be given!\n"); + if (liberty_file.empty()) log_cmd_error("Missing `-liberty liberty_file' option!\n"); @@ -599,74 +491,49 @@ struct DfflibmapPass : public Pass { LibertyParser libparser(f); f.close(); - find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false, prepare_mode); - - find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true, prepare_mode); - find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true, prepare_mode); - find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true, prepare_mode); - find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true, prepare_mode); - - find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true, prepare_mode); - - // try to implement as many cells as possible just by inverting - // the SET and RESET pins. If necessary, implement cell types - // by inverting both D and Q. Only invert clock pins if there - // is no other way of implementing the cell. - while (1) - { - if (expand_cellmap("$_DFF_?*?_", "R") || - expand_cellmap("$_DFFSR_?*?_", "S") || - expand_cellmap("$_DFFSR_??*_", "R")) - continue; - - if (expand_cellmap("$_DFF_??*_", "DQ")) - continue; - - if (expand_cellmap("$_DFF_*_", "C") || - expand_cellmap("$_DFF_*??_", "C") || - expand_cellmap("$_DFFSR_*??_", "C")) - continue; - - break; - } - - map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN0_)); - map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN1_)); - map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP0_)); - map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP1_)); - map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN0_)); - map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN1_)); - map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP0_)); - map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP1_)); - - map_adff_to_dff(ID($_DFF_NN0_), ID($_DFF_N_)); - map_adff_to_dff(ID($_DFF_NN1_), ID($_DFF_N_)); - map_adff_to_dff(ID($_DFF_NP0_), ID($_DFF_N_)); - map_adff_to_dff(ID($_DFF_NP1_), ID($_DFF_N_)); - map_adff_to_dff(ID($_DFF_PN0_), ID($_DFF_P_)); - map_adff_to_dff(ID($_DFF_PN1_), ID($_DFF_P_)); - map_adff_to_dff(ID($_DFF_PP0_), ID($_DFF_P_)); - map_adff_to_dff(ID($_DFF_PP1_), ID($_DFF_P_)); + find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false); + find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false); + + find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false); + find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true); + find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false); + find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true); + find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false); + find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true); + find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false); + find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true); + + find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false); + find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true); + find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false); + find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true); + find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false); + find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true); + find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false); + find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true); log(" final dff cell mappings:\n"); logmap_all(); - for (auto module : design->selected_modules()) - if (!module->get_blackbox_attribute()) - dfflibmap(design, module, prepare_mode); + if (!map_only_mode) { + std::string dfflegalize_cmd = "dfflegalize"; + for (auto it : cell_mappings) + dfflegalize_cmd += stringf(" -cell %s 01", it.first.c_str()); + dfflegalize_cmd += " t:$_DFF* t:$_SDFF*"; + if (info_mode) { + log("dfflegalize command line: %s\n", dfflegalize_cmd.c_str()); + } else { + Pass::call(design, dfflegalize_cmd); + } + } + + if (!prepare_mode && !info_mode) { + for (auto module : design->selected_modules()) + if (!module->get_blackbox_attribute()) + dfflibmap(design, module); + } + log_pop(); cell_mappings.clear(); } } DfflibmapPass; diff --git a/passes/techmap/dffunmap.cc b/passes/techmap/dffunmap.cc new file mode 100644 index 000000000..7312015f1 --- /dev/null +++ b/passes/techmap/dffunmap.cc @@ -0,0 +1,106 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2020 Marcelina Kościelnicka <mwk@0x04.net> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" +#include "kernel/ff.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct DffunmapPass : public Pass { + DffunmapPass() : Pass("dffunmap", "unmap clock enable and synchronous reset from FFs") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" dffunmap [options] [selection]\n"); + log("\n"); + log("This pass transforms FF types with clock enable and/or synchronous reset into\n"); + log("their base type (with neither clock enable nor sync reset) by emulating the clock\n"); + log("enable and synchronous reset with multiplexers on the cell input.\n"); + log("\n"); + log(" -ce-only\n"); + log(" unmap only clock enables, leave synchronous resets alone.\n"); + log("\n"); + log(" -srst-only\n"); + log(" unmap only synchronous resets, leave clock enables alone.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) override + { + log_header(design, "Executing DFFUNMAP pass (unmap clock enable and synchronous reset from FFs).\n"); + + bool ce_only = false; + bool srst_only = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-ce-only") { + ce_only = true; + continue; + } + if (args[argidx] == "-srst-only") { + srst_only = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (ce_only && srst_only) + log_cmd_error("Options -ce-only and -srst-only are mutually exclusive!\n"); + + for (auto mod : design->selected_modules()) + { + SigMap sigmap(mod); + FfInitVals initvals(&sigmap, mod); + + for (auto cell : mod->selected_cells()) + { + if (!RTLIL::builtin_ff_cell_types().count(cell->type)) + continue; + + FfData ff(&initvals, cell); + IdString name = cell->name; + + if (!ff.has_clk) + continue; + + if (ce_only) { + if (!ff.has_ce) + continue; + ff.unmap_ce(); + } else if (srst_only) { + if (!ff.has_srst) + continue; + ff.unmap_srst(); + } else { + if (!ff.has_ce && !ff.has_srst) + continue; + ff.unmap_ce_srst(); + } + + ff.emit(); + } + } + } +} DffunmapPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc index 7278cb680..137d22170 100644 --- a/passes/techmap/extract.cc +++ b/passes/techmap/extract.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -74,6 +74,7 @@ public: param_int(ID::CTRL_IN_WIDTH) param_int(ID::CTRL_OUT_WIDTH) param_int(ID::OFFSET) + param_int(ID::PORTID) param_int(ID::PRIORITY) param_int(ID::RD_PORTS) param_int(ID::SIZE) @@ -354,7 +355,7 @@ struct ExtractPass : public Pass { log("\n"); log("This pass looks for subcircuits that are isomorphic to any of the modules\n"); log("in the given map file and replaces them with instances of this modules. The\n"); - log("map file can be a Verilog source file (*.v) or an ilang file (*.il).\n"); + log("map file can be a Verilog source file (*.v) or an RTLIL source file (*.il).\n"); log("\n"); log(" -map <map_file>\n"); log(" use the modules in this file as reference. This option can be used\n"); @@ -409,7 +410,7 @@ struct ExtractPass : public Pass { log("the following options are to be used instead of the -map option.\n"); log("\n"); log(" -mine <out_file>\n"); - log(" mine for frequent subcircuits and write them to the given ilang file\n"); + log(" mine for frequent subcircuits and write them to the given RTLIL file\n"); log("\n"); log(" -mine_cells_span <min> <max>\n"); log(" only mine for subcircuits with the specified number of cells\n"); @@ -578,7 +579,7 @@ struct ExtractPass : public Pass { } if (map_filenames.empty() && mine_outfile.empty()) - log_cmd_error("Missing option -map <verilog_or_ilang_file> or -mine <output_ilang_file>.\n"); + log_cmd_error("Missing option -map <verilog_or_rtlil_file> or -mine <output_rtlil_file>.\n"); RTLIL::Design *map = nullptr; @@ -606,7 +607,7 @@ struct ExtractPass : public Pass { delete map; log_cmd_error("Can't open map file `%s'.\n", filename.c_str()); } - Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "ilang" : "verilog")); + Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : "verilog")); f.close(); if (filename.size() <= 3 || filename.compare(filename.size()-3, std::string::npos, ".il") != 0) { @@ -744,7 +745,7 @@ struct ExtractPass : public Pass { f.open(mine_outfile.c_str(), std::ofstream::trunc); if (f.fail()) log_error("Can't open output file `%s'.\n", mine_outfile.c_str()); - Backend::backend_call(map, &f, mine_outfile, "ilang"); + Backend::backend_call(map, &f, mine_outfile, "rtlil"); f.close(); } diff --git a/passes/techmap/extract_counter.cc b/passes/techmap/extract_counter.cc index 56b2ea584..9c814af23 100644 --- a/passes/techmap/extract_counter.cc +++ b/passes/techmap/extract_counter.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2017 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2017 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc index 3fcff01c3..117fdd54c 100644 --- a/passes/techmap/extract_fa.cc +++ b/passes/techmap/extract_fa.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -33,7 +33,7 @@ struct ExtractFaConfig int maxbreadth = 6; }; -// http://svn.clifford.at/handicraft/2016/bindec/bindec.c +// http://svn.clairexen.net/handicraft/2016/bindec/bindec.c int bindec(unsigned char v) { int r = v & 1; diff --git a/passes/techmap/extract_reduce.cc b/passes/techmap/extract_reduce.cc index 07b4200cc..892e9a364 100644 --- a/passes/techmap/extract_reduce.cc +++ b/passes/techmap/extract_reduce.cc @@ -152,10 +152,10 @@ struct ExtractReducePass : public Pass log_assert(y.size() == 1); // Should only continue if there is one fanout back into a cell (not to a port) - if (sig_to_sink[y[0]].size() != 1) + if (sig_to_sink[y].size() != 1 || port_sigs.count(y)) break; - x = *sig_to_sink[y[0]].begin(); + x = *sig_to_sink[y].begin(); } sinks.insert(head_cell); @@ -183,13 +183,15 @@ struct ExtractReducePass : public Pass continue; } + auto xy = sigmap(x->getPort(ID::Y)); + //If this signal drives a port, add it to the sinks //(even though it may not be the end of a chain) - if(port_sigs.count(x) && !consumed_cells.count(x)) + if(port_sigs.count(xy) && !consumed_cells.count(x)) sinks.insert(x); //It's a match, search everything out from it - auto& next = sig_to_sink[x]; + auto& next = sig_to_sink[xy]; for(auto z : next) next_loads.insert(z); } @@ -224,89 +226,60 @@ struct ExtractReducePass : public Pass if(consumed_cells.count(head_cell)) continue; - pool<Cell*> cur_supercell; + dict<SigBit, int> sources; + int inner_cells = 0; std::deque<Cell*> bfs_queue = {head_cell}; while (bfs_queue.size()) { Cell* x = bfs_queue.front(); bfs_queue.pop_front(); - cur_supercell.insert(x); + for (auto port: {ID::A, ID::B}) { + auto bit = sigmap(x->getPort(port)[0]); - auto a = sigmap(x->getPort(ID::A)); - log_assert(a.size() == 1); + bool sink_single = sig_to_sink[bit].size() == 1 && !port_sigs.count(bit); - // Must have only one sink unless we're going off chain - // XXX: Check that it is indeed this node? - if( allow_off_chain || (sig_to_sink[a[0]].size() + port_sigs.count(a[0]) == 1) ) - { - Cell* cell_a = sig_to_driver[a[0]]; - if(cell_a && IsRightType(cell_a, gt)) - { - // The cell here is the correct type, and it's definitely driving - // this current cell. - bfs_queue.push_back(cell_a); - } - } + Cell* drv = sig_to_driver[bit]; + bool drv_ok = drv && drv->type == head_cell->type; - auto b = sigmap(x->getPort(ID::B)); - log_assert(b.size() == 1); - - // Must have only one sink - // XXX: Check that it is indeed this node? - if( allow_off_chain || (sig_to_sink[b[0]].size() + port_sigs.count(b[0]) == 1) ) - { - Cell* cell_b = sig_to_driver[b[0]]; - if(cell_b && IsRightType(cell_b, gt)) - { - // The cell here is the correct type, and it's definitely driving only - // this current cell. - bfs_queue.push_back(cell_b); + if (drv_ok && (allow_off_chain || sink_single)) { + inner_cells++; + bfs_queue.push_back(drv); + } else { + sources[bit]++; } } } - log(" Cells:\n"); - for (auto x : cur_supercell) - log(" %s\n", x->name.c_str()); - - if (cur_supercell.size() > 1) + if (inner_cells) { // Worth it to create reduce cell log(" Creating $reduce_* cell!\n"); - pool<SigBit> input_pool; - pool<SigBit> input_pool_intermed; - for (auto x : cur_supercell) - { - input_pool.insert(sigmap(x->getPort(ID::A))[0]); - input_pool.insert(sigmap(x->getPort(ID::B))[0]); - input_pool_intermed.insert(sigmap(x->getPort(ID::Y))[0]); - } - SigSpec input; - for (auto b : input_pool) - if (input_pool_intermed.count(b) == 0) - input.append(b); - SigBit output = sigmap(head_cell->getPort(ID::Y)[0]); - auto new_reduce_cell = module->addCell(NEW_ID, - gt == GateType::And ? ID($reduce_and) : - gt == GateType::Or ? ID($reduce_or) : - gt == GateType::Xor ? ID($reduce_xor) : ""); - new_reduce_cell->setParam(ID::A_SIGNED, 0); - new_reduce_cell->setParam(ID::A_WIDTH, input.size()); - new_reduce_cell->setParam(ID::Y_WIDTH, 1); - new_reduce_cell->setPort(ID::A, input); - new_reduce_cell->setPort(ID::Y, output); - - if(allow_off_chain) - consumed_cells.insert(head_cell); - else - { - for (auto x : cur_supercell) - consumed_cells.insert(x); + SigSpec input; + for (auto it : sources) { + bool cond; + if (head_cell->type == ID($_XOR_)) + cond = it.second & 1; + else + cond = it.second != 0; + if (cond) + input.append(it.first); + } + + if (head_cell->type == ID($_AND_)) { + module->addReduceAnd(NEW_ID, input, output); + } else if (head_cell->type == ID($_OR_)) { + module->addReduceOr(NEW_ID, input, output); + } else if (head_cell->type == ID($_XOR_)) { + module->addReduceXor(NEW_ID, input, output); + } else { + log_assert(false); } + + consumed_cells.insert(head_cell); } } } diff --git a/passes/techmap/extractinv.cc b/passes/techmap/extractinv.cc index 9b350456f..48d9600fa 100644 --- a/passes/techmap/extractinv.cc +++ b/passes/techmap/extractinv.cc @@ -1,8 +1,8 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * Copyright (C) 2019 Marcin Kościelnicki <mwk@0x04.net> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> + * Copyright (C) 2019 Marcelina Kościelnicka <mwk@0x04.net> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/flatten.cc b/passes/techmap/flatten.cc index b5f55cffa..7e6df5d2c 100644 --- a/passes/techmap/flatten.cc +++ b/passes/techmap/flatten.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -77,7 +77,7 @@ struct FlattenWorker { bool ignore_wb = false; - void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, std::vector<RTLIL::Cell*> &new_cells) + void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, SigMap &sigmap, std::vector<RTLIL::Cell*> &new_cells) { // Copy the contents of the flattened cell @@ -122,6 +122,9 @@ struct FlattenWorker for (auto &tpl_proc_it : tpl->processes) { RTLIL::Process *new_proc = module->addProcess(map_name(cell, tpl_proc_it.second), tpl_proc_it.second); map_attributes(cell, new_proc, tpl_proc_it.second->name); + for (auto new_proc_sync : new_proc->syncs) + for (auto &memwr_action : new_proc_sync->mem_write_actions) + memwr_action.memid = memory_map.at(memwr_action.memid).str(); auto rewriter = [&](RTLIL::SigSpec &sig) { map_sigspec(wire_map, sig); }; new_proc->rewrite_sigspecs(rewriter); design->select(module, new_proc); @@ -130,10 +133,10 @@ struct FlattenWorker for (auto tpl_cell : tpl->cells()) { RTLIL::Cell *new_cell = module->addCell(map_name(cell, tpl_cell), tpl_cell); map_attributes(cell, new_cell, tpl_cell->name); - if (new_cell->type.in(ID($memrd), ID($memwr), ID($meminit))) { + if (new_cell->has_memid()) { IdString memid = new_cell->getParam(ID::MEMID).decode_string(); new_cell->setParam(ID::MEMID, Const(memory_map.at(memid).str())); - } else if (new_cell->type == ID($mem)) { + } else if (new_cell->is_mem_cell()) { IdString memid = new_cell->getParam(ID::MEMID).decode_string(); new_cell->setParam(ID::MEMID, Const(concat_name(cell, memid).str())); } @@ -152,18 +155,16 @@ struct FlattenWorker // Attach port connections of the flattened cell - SigMap tpl_sigmap(tpl); pool<SigBit> tpl_driven; for (auto tpl_cell : tpl->cells()) for (auto &tpl_conn : tpl_cell->connections()) if (tpl_cell->output(tpl_conn.first)) - for (auto bit : tpl_sigmap(tpl_conn.second)) + for (auto bit : tpl_conn.second) tpl_driven.insert(bit); for (auto &tpl_conn : tpl->connections()) - for (auto bit : tpl_sigmap(tpl_conn.first)) + for (auto bit : tpl_conn.first) tpl_driven.insert(bit); - SigMap sigmap(module); for (auto &port_it : cell->connections()) { IdString port_name = port_it.first; @@ -181,16 +182,19 @@ struct FlattenWorker RTLIL::Wire *tpl_wire = tpl->wire(port_name); RTLIL::SigSig new_conn; + bool is_signed = false; if (tpl_wire->port_output && !tpl_wire->port_input) { new_conn.first = port_it.second; new_conn.second = tpl_wire; + is_signed = tpl_wire->is_signed; } else if (!tpl_wire->port_output && tpl_wire->port_input) { new_conn.first = tpl_wire; new_conn.second = port_it.second; + is_signed = new_conn.second.is_wire() && new_conn.second.as_wire()->is_signed; } else { SigSpec sig_tpl = tpl_wire, sig_mod = port_it.second; for (int i = 0; i < GetSize(sig_tpl) && i < GetSize(sig_mod); i++) { - if (tpl_driven.count(tpl_sigmap(sig_tpl[i]))) { + if (tpl_driven.count(sig_tpl[i])) { new_conn.first.append(sig_mod[i]); new_conn.second.append(sig_tpl[i]); } else { @@ -205,14 +209,15 @@ struct FlattenWorker if (new_conn.second.size() > new_conn.first.size()) new_conn.second.remove(new_conn.first.size(), new_conn.second.size() - new_conn.first.size()); if (new_conn.second.size() < new_conn.first.size()) - new_conn.second.append(RTLIL::SigSpec(RTLIL::State::S0, new_conn.first.size() - new_conn.second.size())); + new_conn.second.extend_u0(new_conn.first.size(), is_signed); log_assert(new_conn.first.size() == new_conn.second.size()); if (sigmap(new_conn.first).has_const()) - log_error("Mismatch in directionality for cell port %s.%s.%s: %s <= %s\n", + log_error("Cell port %s.%s.%s is driving constant bits: %s <= %s\n", log_id(module), log_id(cell), log_id(port_it.first), log_signal(new_conn.first), log_signal(new_conn.second)); module->connect(new_conn); + sigmap.add(new_conn.first, new_conn.second); } module->remove(cell); @@ -223,6 +228,7 @@ struct FlattenWorker if (!design->selected(module) || module->get_blackbox_attribute(ignore_wb)) return; + SigMap sigmap(module); std::vector<RTLIL::Cell*> worklist = module->selected_cells(); while (!worklist.empty()) { @@ -246,7 +252,7 @@ struct FlattenWorker // If a design is fully selected and has a top module defined, topological sorting ensures that all cells // added during flattening are black boxes, and flattening is finished in one pass. However, when flattening // individual modules, this isn't the case, and the newly added cells might have to be flattened further. - flatten_cell(design, module, cell, tpl, worklist); + flatten_cell(design, module, cell, tpl, sigmap, worklist); } } }; diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc index b808a8d8e..c1b947221 100644 --- a/passes/techmap/hilomap.cc +++ b/passes/techmap/hilomap.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/insbuf.cc b/passes/techmap/insbuf.cc index a3b5b698d..68c22c317 100644 --- a/passes/techmap/insbuf.cc +++ b/passes/techmap/insbuf.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc index e8530a034..437ad5156 100644 --- a/passes/techmap/iopadmap.cc +++ b/passes/techmap/iopadmap.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -43,26 +43,28 @@ struct IopadmapPass : public Pass { log("can only map to very simple PAD cells. Use 'techmap' to further map\n"); log("the resulting cells to more sophisticated PAD cells.\n"); log("\n"); - log(" -inpad <celltype> <portname>[:<portname>]\n"); + log(" -inpad <celltype> <in_port>[:<ext_port>]\n"); log(" Map module input ports to the given cell type with the\n"); log(" given output port name. if a 2nd portname is given, the\n"); - log(" signal is passed through the pad call, using the 2nd\n"); + log(" signal is passed through the pad cell, using the 2nd\n"); log(" portname as the port facing the module port.\n"); log("\n"); - log(" -outpad <celltype> <portname>[:<portname>]\n"); - log(" -inoutpad <celltype> <portname>[:<portname>]\n"); + log(" -outpad <celltype> <out_port>[:<ext_port>]\n"); + log(" -inoutpad <celltype> <io_port>[:<ext_port>]\n"); log(" Similar to -inpad, but for output and inout ports.\n"); log("\n"); - log(" -toutpad <celltype> <portname>:<portname>[:<portname>]\n"); + log(" -toutpad <celltype> <oe_port>:<out_port>[:<ext_port>]\n"); log(" Merges $_TBUF_ cells into the output pad cell. This takes precedence\n"); log(" over the other -outpad cell. The first portname is the enable input\n"); - log(" of the tristate driver.\n"); + log(" of the tristate driver, which can be prefixed with `~` for negative\n"); + log(" polarity enable.\n"); log("\n"); - log(" -tinoutpad <celltype> <portname>:<portname>:<portname>[:<portname>]\n"); + log(" -tinoutpad <celltype> <oe_port>:<in_port>:<out_port>[:<ext_port>]\n"); log(" Merges $_TBUF_ cells into the inout pad cell. This takes precedence\n"); log(" over the other -inoutpad cell. The first portname is the enable input\n"); log(" of the tristate driver and the 2nd portname is the internal output\n"); - log(" buffering the external signal.\n"); + log(" buffering the external signal. Like with `-toutpad`, the enable can\n"); + log(" be marked as negative polarity by prefixing the name with `~`.\n"); log("\n"); log(" -ignore <celltype> <portname>[:<portname>]*\n"); log(" Skips mapping inputs/outputs that are already connected to given\n"); @@ -106,6 +108,7 @@ struct IopadmapPass : public Pass { std::string inoutpad_celltype, inoutpad_portname_io, inoutpad_portname_pad; std::string toutpad_celltype, toutpad_portname_oe, toutpad_portname_i, toutpad_portname_pad; std::string tinoutpad_celltype, tinoutpad_portname_oe, tinoutpad_portname_o, tinoutpad_portname_i, tinoutpad_portname_pad; + bool toutpad_neg_oe = false, tinoutpad_neg_oe = false; std::string widthparam, nameparam; pool<pair<IdString, IdString>> ignore; bool flag_bits = false; @@ -137,6 +140,10 @@ struct IopadmapPass : public Pass { toutpad_portname_oe = args[++argidx]; split_portname_pair(toutpad_portname_oe, toutpad_portname_i); split_portname_pair(toutpad_portname_i, toutpad_portname_pad); + if (toutpad_portname_oe[0] == '~') { + toutpad_neg_oe = true; + toutpad_portname_oe = toutpad_portname_oe.substr(1); + } continue; } if (arg == "-tinoutpad" && argidx+2 < args.size()) { @@ -145,6 +152,10 @@ struct IopadmapPass : public Pass { split_portname_pair(tinoutpad_portname_oe, tinoutpad_portname_o); split_portname_pair(tinoutpad_portname_o, tinoutpad_portname_i); split_portname_pair(tinoutpad_portname_i, tinoutpad_portname_pad); + if (tinoutpad_portname_oe[0] == '~') { + tinoutpad_neg_oe = true; + tinoutpad_portname_oe = tinoutpad_portname_oe.substr(1); + } continue; } if (arg == "-ignore" && argidx+2 < args.size()) { @@ -318,6 +329,8 @@ struct IopadmapPass : public Pass { module->uniquify(stringf("$iopadmap$%s.%s[%d]", log_id(module), log_id(wire), i)), RTLIL::escape_id(tinoutpad_celltype)); + if (tinoutpad_neg_oe) + en_sig = module->NotGate(NEW_ID, en_sig); cell->setPort(RTLIL::escape_id(tinoutpad_portname_oe), en_sig); cell->attributes[ID::keep] = RTLIL::Const(1); @@ -340,6 +353,8 @@ struct IopadmapPass : public Pass { module->uniquify(stringf("$iopadmap$%s.%s[%d]", log_id(module), log_id(wire), i)), RTLIL::escape_id(toutpad_celltype)); + if (toutpad_neg_oe) + en_sig = module->NotGate(NEW_ID, en_sig); cell->setPort(RTLIL::escape_id(toutpad_portname_oe), en_sig); cell->setPort(RTLIL::escape_id(toutpad_portname_i), data_sig); cell->attributes[ID::keep] = RTLIL::Const(1); diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 349ccc115..3d0ebaea3 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -384,7 +384,7 @@ void LibertyParser::error(const std::string &str) exit(1); } -/**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/ +/**** BEGIN: http://svn.clairexen.net/tools/trunk/examples/check.h ****/ #define CHECK_NV(result, check) \ do { \ @@ -405,7 +405,7 @@ void LibertyParser::error(const std::string &str) } \ } while(0) -/**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/ +/**** END: http://svn.clairexen.net/tools/trunk/examples/check.h ****/ LibertyAst *find_non_null(LibertyAst *node, const char *name) { diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index c9ebd06c5..77e305f0b 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/lut2mux.cc b/passes/techmap/lut2mux.cc index f56eff3e5..ef76e0deb 100644 --- a/passes/techmap/lut2mux.cc +++ b/passes/techmap/lut2mux.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc index 43f2d97f5..2235bdef9 100644 --- a/passes/techmap/maccmap.cc +++ b/passes/techmap/maccmap.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc index 24109b579..a90d81985 100644 --- a/passes/techmap/muxcover.cc +++ b/passes/techmap/muxcover.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/nlutmap.cc b/passes/techmap/nlutmap.cc index e1ebfcad8..016789157 100644 --- a/passes/techmap/nlutmap.cc +++ b/passes/techmap/nlutmap.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc index b937d3fb0..ff6bb549b 100644 --- a/passes/techmap/pmuxtree.cc +++ b/passes/techmap/pmuxtree.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 237c261ae..928182970 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,6 +19,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/ffinit.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -100,9 +101,8 @@ struct ShregmapWorker int dff_count, shreg_count; pool<Cell*> remove_cells; - pool<SigBit> remove_init; - dict<SigBit, bool> sigbit_init; + FfInitVals initvals; dict<SigBit, Cell*> sigbit_chain_next; dict<SigBit, Cell*> sigbit_chain_prev; pool<SigBit> sigbit_with_non_chain_users; @@ -116,16 +116,6 @@ struct ShregmapWorker for (auto bit : sigmap(wire)) sigbit_with_non_chain_users.insert(bit); } - - if (wire->attributes.count(ID::init)) { - SigSpec initsig = sigmap(wire); - Const initval = wire->attributes.at(ID::init); - for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) - if (initval[i] == State::S0 && !opts.zinit) - sigbit_init[initsig[i]] = false; - else if (initval[i] == State::S1) - sigbit_init[initsig[i]] = true; - } } for (auto cell : module->cells()) @@ -137,8 +127,9 @@ struct ShregmapWorker SigBit d_bit = sigmap(cell->getPort(d_port).as_bit()); SigBit q_bit = sigmap(cell->getPort(q_port).as_bit()); + State initval = initvals(q_bit); - if (opts.init || sigbit_init.count(q_bit) == 0) + if (opts.init || initval == State::Sx || (opts.zinit && initval == State::S0)) { auto r = sigbit_chain_next.insert(std::make_pair(d_bit, cell)); if (!r.second) { @@ -310,22 +301,17 @@ struct ShregmapWorker if (opts.init) { vector<State> initval; for (int i = depth-1; i >= 0; i--) { - SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit()); - if (sigbit_init.count(bit) == 0) - initval.push_back(State::Sx); - else if (sigbit_init.at(bit)) - initval.push_back(State::S1); - else - initval.push_back(State::S0); - remove_init.insert(bit); + SigBit bit = chain[cursor+i]->getPort(q_port).as_bit(); + initval.push_back(initvals(bit)); + initvals.remove_init(bit); } first_cell->setParam(ID::INIT, initval); } if (opts.zinit) for (int i = depth-1; i >= 0; i--) { - SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit()); - remove_init.insert(bit); + SigBit bit = chain[cursor+i]->getPort(q_port).as_bit(); + initvals.remove_init(bit); } if (opts.params) @@ -364,22 +350,6 @@ struct ShregmapWorker for (auto cell : remove_cells) module->remove(cell); - for (auto wire : module->wires()) - { - if (wire->attributes.count(ID::init) == 0) - continue; - - SigSpec initsig = sigmap(wire); - Const &initval = wire->attributes.at(ID::init); - - for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) - if (remove_init.count(initsig[i])) - initval[i] = State::Sx; - - if (SigSpec(initval).is_fully_undef()) - wire->attributes.erase(ID::init); - } - remove_cells.clear(); sigbit_chain_next.clear(); sigbit_chain_prev.clear(); @@ -389,6 +359,7 @@ struct ShregmapWorker ShregmapWorker(Module *module, const ShregmapOptions &opts) : module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0) { + initvals.set(&sigmap, module); make_sigbit_chain_next_prev(); find_chain_start_cells(); diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index b9d337da4..7d8dba439 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,6 +19,7 @@ #include "simplemap.h" #include "kernel/sigtools.h" +#include "kernel/ff.h" #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -298,6 +299,30 @@ void simplemap_tribuf(RTLIL::Module *module, RTLIL::Cell *cell) } } +void simplemap_bmux(RTLIL::Module *module, RTLIL::Cell *cell) +{ + SigSpec sel = cell->getPort(ID::S); + SigSpec data = cell->getPort(ID::A); + int width = GetSize(cell->getPort(ID::Y)); + + for (int idx = 0; idx < GetSize(sel); idx++) { + SigSpec new_data = module->addWire(NEW_ID, GetSize(data)/2); + for (int i = 0; i < GetSize(new_data); i += width) { + for (int k = 0; k < width; k++) { + RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); + gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->setPort(ID::A, data[i*2+k]); + gate->setPort(ID::B, data[i*2+width+k]); + gate->setPort(ID::S, sel[idx]); + gate->setPort(ID::Y, new_data[i+k]); + } + } + data = new_data; + } + + module->connect(cell->getPort(ID::Y), data); +} + void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell) { SigSpec lut_ctrl = cell->getPort(ID::A); @@ -305,7 +330,6 @@ void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell) lut_data.extend_u0(1 << cell->getParam(ID::WIDTH).as_int()); for (int idx = 0; GetSize(lut_data) > 1; idx++) { - SigSpec sig_s = lut_ctrl[idx]; SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data)/2); for (int i = 0; i < GetSize(lut_data); i += 2) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); @@ -367,276 +391,13 @@ void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell) module->connect(RTLIL::SigSig(sig_y, sig_ab)); } -void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell) -{ - int width = cell->parameters.at(ID::WIDTH).as_int(); - char set_pol = cell->parameters.at(ID::SET_POLARITY).as_bool() ? 'P' : 'N'; - char clr_pol = cell->parameters.at(ID::CLR_POLARITY).as_bool() ? 'P' : 'N'; - - RTLIL::SigSpec sig_s = cell->getPort(ID::SET); - RTLIL::SigSpec sig_r = cell->getPort(ID::CLR); - RTLIL::SigSpec sig_q = cell->getPort(ID::Q); - - std::string gate_type = stringf("$_SR_%c%c_", set_pol, clr_pol); - - for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - gate->setPort(ID::S, sig_s[i]); - gate->setPort(ID::R, sig_r[i]); - gate->setPort(ID::Q, sig_q[i]); - } -} - -void simplemap_ff(RTLIL::Module *module, RTLIL::Cell *cell) -{ - int width = cell->parameters.at(ID::WIDTH).as_int(); - - RTLIL::SigSpec sig_d = cell->getPort(ID::D); - RTLIL::SigSpec sig_q = cell->getPort(ID::Q); - - IdString gate_type = ID($_FF_); - - for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - gate->setPort(ID::D, sig_d[i]); - gate->setPort(ID::Q, sig_q[i]); - } -} - -void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_ff(RTLIL::Module *, RTLIL::Cell *cell) { - int width = cell->parameters.at(ID::WIDTH).as_int(); - char clk_pol = cell->parameters.at(ID::CLK_POLARITY).as_bool() ? 'P' : 'N'; - - RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK); - RTLIL::SigSpec sig_d = cell->getPort(ID::D); - RTLIL::SigSpec sig_q = cell->getPort(ID::Q); - - IdString gate_type = stringf("$_DFF_%c_", clk_pol); - - for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - gate->setPort(ID::C, sig_clk); - gate->setPort(ID::D, sig_d[i]); - gate->setPort(ID::Q, sig_q[i]); - } -} - -void simplemap_dffe(RTLIL::Module *module, RTLIL::Cell *cell) -{ - int width = cell->parameters.at(ID::WIDTH).as_int(); - char clk_pol = cell->parameters.at(ID::CLK_POLARITY).as_bool() ? 'P' : 'N'; - char en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N'; - - RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK); - RTLIL::SigSpec sig_en = cell->getPort(ID::EN); - RTLIL::SigSpec sig_d = cell->getPort(ID::D); - RTLIL::SigSpec sig_q = cell->getPort(ID::Q); - - IdString gate_type = stringf("$_DFFE_%c%c_", clk_pol, en_pol); - - for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - gate->setPort(ID::C, sig_clk); - gate->setPort(ID::E, sig_en); - gate->setPort(ID::D, sig_d[i]); - gate->setPort(ID::Q, sig_q[i]); - } -} - -void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell) -{ - int width = cell->parameters.at(ID::WIDTH).as_int(); - char clk_pol = cell->parameters.at(ID::CLK_POLARITY).as_bool() ? 'P' : 'N'; - char set_pol = cell->parameters.at(ID::SET_POLARITY).as_bool() ? 'P' : 'N'; - char clr_pol = cell->parameters.at(ID::CLR_POLARITY).as_bool() ? 'P' : 'N'; - - RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK); - RTLIL::SigSpec sig_s = cell->getPort(ID::SET); - RTLIL::SigSpec sig_r = cell->getPort(ID::CLR); - RTLIL::SigSpec sig_d = cell->getPort(ID::D); - RTLIL::SigSpec sig_q = cell->getPort(ID::Q); - - IdString gate_type = stringf("$_DFFSR_%c%c%c_", clk_pol, set_pol, clr_pol); - - for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - gate->setPort(ID::C, sig_clk); - gate->setPort(ID::S, sig_s[i]); - gate->setPort(ID::R, sig_r[i]); - gate->setPort(ID::D, sig_d[i]); - gate->setPort(ID::Q, sig_q[i]); - } -} - -void simplemap_dffsre(RTLIL::Module *module, RTLIL::Cell *cell) -{ - int width = cell->parameters.at(ID::WIDTH).as_int(); - char clk_pol = cell->parameters.at(ID::CLK_POLARITY).as_bool() ? 'P' : 'N'; - char set_pol = cell->parameters.at(ID::SET_POLARITY).as_bool() ? 'P' : 'N'; - char clr_pol = cell->parameters.at(ID::CLR_POLARITY).as_bool() ? 'P' : 'N'; - char en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N'; - - RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK); - RTLIL::SigSpec sig_s = cell->getPort(ID::SET); - RTLIL::SigSpec sig_r = cell->getPort(ID::CLR); - RTLIL::SigSpec sig_e = cell->getPort(ID::EN); - RTLIL::SigSpec sig_d = cell->getPort(ID::D); - RTLIL::SigSpec sig_q = cell->getPort(ID::Q); - - IdString gate_type = stringf("$_DFFSRE_%c%c%c%c_", clk_pol, set_pol, clr_pol, en_pol); - - for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - gate->setPort(ID::C, sig_clk); - gate->setPort(ID::S, sig_s[i]); - gate->setPort(ID::R, sig_r[i]); - gate->setPort(ID::E, sig_e); - gate->setPort(ID::D, sig_d[i]); - gate->setPort(ID::Q, sig_q[i]); - } -} - -void simplemap_adff_sdff(RTLIL::Module *module, RTLIL::Cell *cell) -{ - int width = cell->parameters.at(ID::WIDTH).as_int(); - bool is_async = cell->type == ID($adff); - char clk_pol = cell->parameters.at(ID::CLK_POLARITY).as_bool() ? 'P' : 'N'; - char rst_pol = cell->parameters.at(is_async ? ID::ARST_POLARITY : ID::SRST_POLARITY).as_bool() ? 'P' : 'N'; - const char *type = is_async ? "DFF" : "SDFF"; - - std::vector<RTLIL::State> rst_val = cell->parameters.at(is_async ? ID::ARST_VALUE : ID::SRST_VALUE).bits; - while (int(rst_val.size()) < width) - rst_val.push_back(RTLIL::State::S0); - - RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK); - RTLIL::SigSpec sig_rst = cell->getPort(is_async ? ID::ARST : ID::SRST); - RTLIL::SigSpec sig_d = cell->getPort(ID::D); - RTLIL::SigSpec sig_q = cell->getPort(ID::Q); - - IdString gate_type_0 = stringf("$_%s_%c%c0_", type, clk_pol, rst_pol); - IdString gate_type_1 = stringf("$_%s_%c%c1_", type, clk_pol, rst_pol); - - for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - gate->setPort(ID::C, sig_clk); - gate->setPort(ID::R, sig_rst); - gate->setPort(ID::D, sig_d[i]); - gate->setPort(ID::Q, sig_q[i]); - } -} - -void simplemap_adffe_sdffe_sdffce(RTLIL::Module *module, RTLIL::Cell *cell) -{ - int width = cell->parameters.at(ID::WIDTH).as_int(); - bool is_async = cell->type == ID($adffe); - char clk_pol = cell->parameters.at(ID::CLK_POLARITY).as_bool() ? 'P' : 'N'; - char rst_pol = cell->parameters.at(is_async ? ID::ARST_POLARITY : ID::SRST_POLARITY).as_bool() ? 'P' : 'N'; - char en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N'; - const char *type = is_async ? "DFFE" : cell->type == ID($sdffe) ? "SDFFE" : "SDFFCE"; - - std::vector<RTLIL::State> rst_val = cell->parameters.at(is_async ? ID::ARST_VALUE : ID::SRST_VALUE).bits; - while (int(rst_val.size()) < width) - rst_val.push_back(RTLIL::State::S0); - - RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK); - RTLIL::SigSpec sig_rst = cell->getPort(is_async ? ID::ARST : ID::SRST); - RTLIL::SigSpec sig_e = cell->getPort(ID::EN); - RTLIL::SigSpec sig_d = cell->getPort(ID::D); - RTLIL::SigSpec sig_q = cell->getPort(ID::Q); - - IdString gate_type_0 = stringf("$_%s_%c%c0%c_", type, clk_pol, rst_pol, en_pol); - IdString gate_type_1 = stringf("$_%s_%c%c1%c_", type, clk_pol, rst_pol, en_pol); - - for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - gate->setPort(ID::C, sig_clk); - gate->setPort(ID::R, sig_rst); - gate->setPort(ID::E, sig_e); - gate->setPort(ID::D, sig_d[i]); - gate->setPort(ID::Q, sig_q[i]); - } -} - -void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell) -{ - int width = cell->parameters.at(ID::WIDTH).as_int(); - char en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N'; - - RTLIL::SigSpec sig_en = cell->getPort(ID::EN); - RTLIL::SigSpec sig_d = cell->getPort(ID::D); - RTLIL::SigSpec sig_q = cell->getPort(ID::Q); - - IdString gate_type = stringf("$_DLATCH_%c_", en_pol); - - for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - gate->setPort(ID::E, sig_en); - gate->setPort(ID::D, sig_d[i]); - gate->setPort(ID::Q, sig_q[i]); - } -} - -void simplemap_adlatch(RTLIL::Module *module, RTLIL::Cell *cell) -{ - int width = cell->parameters.at(ID::WIDTH).as_int(); - char en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N'; - char rst_pol = cell->parameters.at(ID::ARST_POLARITY).as_bool() ? 'P' : 'N'; - - std::vector<RTLIL::State> rst_val = cell->parameters.at(ID::ARST_VALUE).bits; - while (int(rst_val.size()) < width) - rst_val.push_back(RTLIL::State::S0); - - RTLIL::SigSpec sig_en = cell->getPort(ID::EN); - RTLIL::SigSpec sig_rst = cell->getPort(ID::ARST); - RTLIL::SigSpec sig_d = cell->getPort(ID::D); - RTLIL::SigSpec sig_q = cell->getPort(ID::Q); - - IdString gate_type_0 = stringf("$_DLATCH_%c%c0_", en_pol, rst_pol); - IdString gate_type_1 = stringf("$_DLATCH_%c%c1_", en_pol, rst_pol); - - for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - gate->setPort(ID::E, sig_en); - gate->setPort(ID::R, sig_rst); - gate->setPort(ID::D, sig_d[i]); - gate->setPort(ID::Q, sig_q[i]); - } -} - -void simplemap_dlatchsr(RTLIL::Module *module, RTLIL::Cell *cell) -{ - int width = cell->parameters.at(ID::WIDTH).as_int(); - char en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N'; - char set_pol = cell->parameters.at(ID::SET_POLARITY).as_bool() ? 'P' : 'N'; - char clr_pol = cell->parameters.at(ID::CLR_POLARITY).as_bool() ? 'P' : 'N'; - - RTLIL::SigSpec sig_en = cell->getPort(ID::EN); - RTLIL::SigSpec sig_s = cell->getPort(ID::SET); - RTLIL::SigSpec sig_r = cell->getPort(ID::CLR); - RTLIL::SigSpec sig_d = cell->getPort(ID::D); - RTLIL::SigSpec sig_q = cell->getPort(ID::Q); - - IdString gate_type = stringf("$_DLATCHSR_%c%c%c_", en_pol, set_pol, clr_pol); - - for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - gate->setPort(ID::E, sig_en); - gate->setPort(ID::S, sig_s[i]); - gate->setPort(ID::R, sig_r[i]); - gate->setPort(ID::D, sig_d[i]); - gate->setPort(ID::Q, sig_q[i]); + FfData ff(nullptr, cell); + for (int i = 0; i < ff.width; i++) { + FfData fff = ff.slice({i}); + fff.is_fine = true; + fff.emit(); } } @@ -662,24 +423,27 @@ void simplemap_get_mappers(dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers[ID($nex)] = simplemap_eqne; mappers[ID($mux)] = simplemap_mux; mappers[ID($tribuf)] = simplemap_tribuf; + mappers[ID($bmux)] = simplemap_bmux; mappers[ID($lut)] = simplemap_lut; mappers[ID($sop)] = simplemap_sop; mappers[ID($slice)] = simplemap_slice; mappers[ID($concat)] = simplemap_concat; - mappers[ID($sr)] = simplemap_sr; + mappers[ID($sr)] = simplemap_ff; mappers[ID($ff)] = simplemap_ff; - mappers[ID($dff)] = simplemap_dff; - mappers[ID($dffe)] = simplemap_dffe; - mappers[ID($dffsr)] = simplemap_dffsr; - mappers[ID($dffsre)] = simplemap_dffsre; - mappers[ID($adff)] = simplemap_adff_sdff; - mappers[ID($sdff)] = simplemap_adff_sdff; - mappers[ID($adffe)] = simplemap_adffe_sdffe_sdffce; - mappers[ID($sdffe)] = simplemap_adffe_sdffe_sdffce; - mappers[ID($sdffce)] = simplemap_adffe_sdffe_sdffce; - mappers[ID($dlatch)] = simplemap_dlatch; - mappers[ID($adlatch)] = simplemap_adlatch; - mappers[ID($dlatchsr)] = simplemap_dlatchsr; + mappers[ID($dff)] = simplemap_ff; + mappers[ID($dffe)] = simplemap_ff; + mappers[ID($dffsr)] = simplemap_ff; + mappers[ID($dffsre)] = simplemap_ff; + mappers[ID($adff)] = simplemap_ff; + mappers[ID($sdff)] = simplemap_ff; + mappers[ID($adffe)] = simplemap_ff; + mappers[ID($sdffe)] = simplemap_ff; + mappers[ID($sdffce)] = simplemap_ff; + mappers[ID($aldff)] = simplemap_ff; + mappers[ID($aldffe)] = simplemap_ff; + mappers[ID($dlatch)] = simplemap_ff; + mappers[ID($adlatch)] = simplemap_ff; + mappers[ID($dlatchsr)] = simplemap_ff; } void simplemap(RTLIL::Module *module, RTLIL::Cell *cell) @@ -712,7 +476,7 @@ struct SimplemapPass : public Pass { log(" $not, $pos, $and, $or, $xor, $xnor\n"); log(" $reduce_and, $reduce_or, $reduce_xor, $reduce_xnor, $reduce_bool\n"); log(" $logic_not, $logic_and, $logic_or, $mux, $tribuf\n"); - log(" $sr, $ff, $dff, $dffe, $dffsr, $dffsre, $adff, $adffe, $sdff, $sdffe, $sdffce, $dlatch, $adlatch, $dlatchsr\n"); + log(" $sr, $ff, $dff, $dffe, $dffsr, $dffsre, $adff, $adffe, $aldff, $aldffe, $sdff, $sdffe, $sdffce, $dlatch, $adlatch, $dlatchsr\n"); log("\n"); } void execute(std::vector<std::string> args, RTLIL::Design *design) override diff --git a/passes/techmap/simplemap.h b/passes/techmap/simplemap.h index 5091050a1..c7654f68c 100644 --- a/passes/techmap/simplemap.h +++ b/passes/techmap/simplemap.h @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -34,12 +34,7 @@ extern void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell); extern void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell); extern void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell); extern void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell); -extern void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell); -extern void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell); -extern void simplemap_dffe(RTLIL::Module *module, RTLIL::Cell *cell); -extern void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell); -extern void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell); -extern void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_ff(RTLIL::Module *module, RTLIL::Cell *cell); extern void simplemap(RTLIL::Module *module, RTLIL::Cell *cell); extern void simplemap_get_mappers(dict<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers); diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index f98d1564a..5cd78fe28 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,6 +20,7 @@ #include "kernel/yosys.h" #include "kernel/utils.h" #include "kernel/sigtools.h" +#include "kernel/ffinit.h" #include "libs/sha1/sha1.h" #include <stdlib.h> @@ -117,19 +118,14 @@ struct TechmapWorker return result; for (auto w : module->wires()) { - const char *p = w->name.c_str(); - if (*p == '$') + if (*w->name.c_str() == '$') continue; - const char *q = strrchr(p+1, '.'); - if (q) - p = q; - - if (!strncmp(p, "\\_TECHMAP_", 10)) { + if (w->name.contains("_TECHMAP_") && !w->name.contains("_TECHMAP_REPLACE_")) { TechmapWireData record; record.wire = w; record.value = w; - result[p].push_back(record); + result[w->name].push_back(record); w->set_bool_attribute(ID::keep); w->set_bool_attribute(ID::_techmap_special_); } @@ -164,7 +160,7 @@ struct TechmapWorker orig_cell_name = cell->name.str(); for (auto tpl_cell : tpl->cells()) - if (tpl_cell->name == ID::_TECHMAP_REPLACE_) { + if (tpl_cell->name.ends_with("_TECHMAP_REPLACE_")) { module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str()); break; } @@ -225,23 +221,21 @@ struct TechmapWorker } design->select(module, w); - if (tpl_w->name.begins_with("\\_TECHMAP_REPLACE_.")) { - IdString replace_name = stringf("%s%s", orig_cell_name.c_str(), tpl_w->name.c_str() + strlen("\\_TECHMAP_REPLACE_")); + if (const char *p = strstr(tpl_w->name.c_str(), "_TECHMAP_REPLACE_.")) { + IdString replace_name = stringf("%s%s", orig_cell_name.c_str(), p + strlen("_TECHMAP_REPLACE_")); Wire *replace_w = module->addWire(replace_name, tpl_w); module->connect(replace_w, w); } } - SigMap tpl_sigmap(tpl); pool<SigBit> tpl_written_bits; - for (auto tpl_cell : tpl->cells()) for (auto &conn : tpl_cell->connections()) if (tpl_cell->output(conn.first)) - for (auto bit : tpl_sigmap(conn.second)) + for (auto bit : conn.second) tpl_written_bits.insert(bit); for (auto &conn : tpl->connections()) - for (auto bit : tpl_sigmap(conn.first)) + for (auto bit : conn.first) tpl_written_bits.insert(bit); SigMap port_signal_map; @@ -279,7 +273,7 @@ struct TechmapWorker SigSpec sig_tpl = w, sig_tpl_pf = w, sig_mod = it.second; apply_prefix(cell->name, sig_tpl_pf, module); for (int i = 0; i < GetSize(sig_tpl) && i < GetSize(sig_mod); i++) { - if (tpl_written_bits.count(tpl_sigmap(sig_tpl[i]))) { + if (tpl_written_bits.count(sig_tpl[i])) { c.first.append(sig_mod[i]); c.second.append(sig_tpl_pf[i]); } else { @@ -328,12 +322,12 @@ struct TechmapWorker for (auto tpl_cell : tpl->cells()) { IdString c_name = tpl_cell->name; - bool techmap_replace_cell = (c_name == ID::_TECHMAP_REPLACE_); + bool techmap_replace_cell = c_name.ends_with("_TECHMAP_REPLACE_"); if (techmap_replace_cell) c_name = orig_cell_name; - else if (tpl_cell->name.begins_with("\\_TECHMAP_REPLACE_.")) - c_name = stringf("%s%s", orig_cell_name.c_str(), c_name.c_str() + strlen("\\_TECHMAP_REPLACE_")); + else if (const char *p = strstr(tpl_cell->name.c_str(), "_TECHMAP_REPLACE_.")) + c_name = stringf("%s%s", orig_cell_name.c_str(), p + strlen("_TECHMAP_REPLACE_")); else apply_prefix(cell->name, c_name); @@ -370,13 +364,11 @@ struct TechmapWorker for (auto &it2 : autopurge_ports) c->unsetPort(it2); - if (c->type.in(ID($memrd), ID($memwr), ID($meminit))) { + if (c->has_memid()) { IdString memid = c->getParam(ID::MEMID).decode_string(); log_assert(memory_renames.count(memid) != 0); c->setParam(ID::MEMID, Const(memory_renames[memid].str())); - } - - if (c->type == ID($mem)) { + } else if (c->is_mem_cell()) { IdString memid = c->getParam(ID::MEMID).decode_string(); apply_prefix(cell->name, memid); c->setParam(ID::MEMID, Const(memid.c_str())); @@ -385,10 +377,12 @@ struct TechmapWorker if (c->attributes.count(ID::src)) c->add_strpool_attribute(ID::src, extra_src_attrs); - if (techmap_replace_cell) + if (techmap_replace_cell) { for (auto attr : cell->attributes) if (!c->attributes.count(attr.first)) c->attributes[attr.first] = attr.second; + c->attributes.erase(ID::reprocess_after); + } } for (auto &it : tpl->connections()) { @@ -426,18 +420,7 @@ struct TechmapWorker LogMakeDebugHdl mkdebug; SigMap sigmap(module); - - dict<SigBit, State> init_bits; - pool<SigBit> remove_init_bits; - - for (auto wire : module->wires()) { - if (wire->attributes.count(ID::init)) { - Const value = wire->attributes.at(ID::init); - for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) - if (value[i] != State::Sx) - init_bits[sigmap(SigBit(wire, i))] = value[i]; - } - } + FfInitVals initvals(&sigmap, module); TopoSort<RTLIL::Cell*, IdString::compare_ptr_by_name<RTLIL::Cell>> cells; dict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_to_inbit; @@ -643,6 +626,8 @@ struct TechmapWorker if (tpl->avail_parameters.count(ID::_TECHMAP_CELLTYPE_) != 0) parameters.emplace(ID::_TECHMAP_CELLTYPE_, RTLIL::unescape_id(cell->type)); + if (tpl->avail_parameters.count(ID::_TECHMAP_CELLNAME_) != 0) + parameters.emplace(ID::_TECHMAP_CELLNAME_, RTLIL::unescape_id(cell->name)); for (auto &conn : cell->connections()) { if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first))) != 0) { @@ -659,15 +644,7 @@ struct TechmapWorker parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const()); } if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first))) != 0) { - auto sig = sigmap(conn.second); - RTLIL::Const value(State::Sx, sig.size()); - for (int i = 0; i < sig.size(); i++) { - auto it = init_bits.find(sig[i]); - if (it != init_bits.end()) { - value[i] = it->second; - } - } - parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), value); + parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), initvals(conn.second)); } } @@ -748,12 +725,16 @@ struct TechmapWorker for (auto &it : twd) techmap_wire_names.insert(it.first); - for (auto &it : twd[ID::_TECHMAP_FAIL_]) { - RTLIL::SigSpec value = it.value; - if (value.is_fully_const() && value.as_bool()) { - log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n", - derived_name.c_str(), log_id(it.wire->name), log_signal(value)); - techmap_do_cache[tpl] = false; + for (auto &it : twd) { + if (!it.first.ends_with("_TECHMAP_FAIL_")) + continue; + for (const TechmapWireData &elem : it.second) { + RTLIL::SigSpec value = elem.value; + if (value.is_fully_const() && value.as_bool()) { + log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n", + derived_name.c_str(), log_id(elem.wire->name), log_signal(value)); + techmap_do_cache[tpl] = false; + } } } @@ -762,7 +743,7 @@ struct TechmapWorker for (auto &it : twd) { - if (!it.first.begins_with("\\_TECHMAP_DO_") || it.second.empty()) + if (!it.first.contains("_TECHMAP_DO_") || it.second.empty()) continue; auto &data = it.second.front(); @@ -774,7 +755,7 @@ struct TechmapWorker const char *p = data.wire->name.c_str(); const char *q = strrchr(p+1, '.'); - q = q ? q : p+1; + q = q ? q+1 : p+1; std::string cmd_string = data.value.as_const().decode_string(); @@ -817,11 +798,31 @@ struct TechmapWorker } } + // Handle outputs first, as these cannot be remapped. + for (auto &conn : cell->connections()) + { + Wire *twire = tpl->wire(conn.first); + if (!twire->port_output) + continue; + + for (int i = 0; i < GetSize(conn.second); i++) { + RTLIL::SigBit bit = sigmap(conn.second[i]); + RTLIL::SigBit tplbit(twire, i); + cellbits_to_tplbits[bit] = tplbit; + } + } + + // Now handle inputs, remapping as necessary. for (auto &conn : cell->connections()) + { + Wire *twire = tpl->wire(conn.first); + if (twire->port_output) + continue; + for (int i = 0; i < GetSize(conn.second); i++) { RTLIL::SigBit bit = sigmap(conn.second[i]); - RTLIL::SigBit tplbit(tpl->wire(conn.first), i); + RTLIL::SigBit tplbit(twire, i); if (bit.wire == nullptr) { @@ -836,6 +837,7 @@ struct TechmapWorker else cellbits_to_tplbits[bit] = tplbit; } + } RTLIL::SigSig port_conn; for (auto &it : port_connmap) { @@ -870,7 +872,7 @@ struct TechmapWorker TechmapWires twd = techmap_find_special_wires(tpl); for (auto &it : twd) { - if (it.first != ID::_TECHMAP_FAIL_ && (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && !it.first.begins_with("\\_TECHMAP_DO_") && !it.first.begins_with("\\_TECHMAP_DONE_")) + if (!it.first.ends_with("_TECHMAP_FAIL_") && (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && !it.first.contains("_TECHMAP_DO_") && !it.first.contains("_TECHMAP_DONE_")) log_error("Techmap yielded unknown config wire %s.\n", log_id(it.first)); if (techmap_do_cache[tpl]) for (auto &it2 : it.second) @@ -912,7 +914,7 @@ struct TechmapWorker auto sig = sigmap(it->second); for (int i = 0; i < sig.size(); i++) if (val[i] == State::S1) - remove_init_bits.insert(sig[i]); + initvals.remove_init(sig[i]); } } } @@ -961,25 +963,6 @@ struct TechmapWorker handled_cells.insert(cell); } - if (!remove_init_bits.empty()) { - for (auto wire : module->wires()) - if (wire->attributes.count(ID::init)) { - Const &value = wire->attributes.at(ID::init); - bool do_cleanup = true; - for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) { - SigBit bit = sigmap(SigBit(wire, i)); - if (remove_init_bits.count(bit)) - value[i] = State::Sx; - else if (value[i] != State::Sx) - do_cleanup = false; - } - if (do_cleanup) { - log("Removing init attribute from wire %s.%s.\n", log_id(module), log_id(wire)); - wire->attributes.erase(ID::init); - } - } - } - if (log_continue) { log_header(design, "Continuing TECHMAP pass.\n"); log_continue = false; @@ -999,7 +982,7 @@ struct TechmapPass : public Pass { log(" techmap [-map filename] [selection]\n"); log("\n"); log("This pass implements a very simple technology mapper that replaces cells in\n"); - log("the design with implementations given in form of a Verilog or ilang source\n"); + log("the design with implementations given in form of a Verilog or RTLIL source\n"); log("file.\n"); log("\n"); log(" -map filename\n"); @@ -1042,7 +1025,9 @@ struct TechmapPass : public Pass { log("\n"); log("When a module in the map file has the 'techmap_celltype' attribute set, it will\n"); log("match cells with a type that match the text value of this attribute. Otherwise\n"); - log("the module name will be used to match the cell.\n"); + log("the module name will be used to match the cell. Multiple space-separated cell\n"); + log("types can be listed, and wildcards using [] will be expanded (ie. \"$_DFF_[PN]_\"\n"); + log("is the same as \"$_DFF_P_ $_DFF_N_\").\n"); log("\n"); log("When a module in the map file has the 'techmap_simplemap' attribute set, techmap\n"); log("will use 'simplemap' (see 'help simplemap') to map cells matching the module.\n"); @@ -1111,6 +1096,10 @@ struct TechmapPass : public Pass { log(" When a parameter with this name exists, it will be set to the type name\n"); log(" of the cell that matches the module.\n"); log("\n"); + log(" _TECHMAP_CELLNAME_\n"); + log(" When a parameter with this name exists, it will be set to the name\n"); + log(" of the cell that matches the module.\n"); + log("\n"); log(" _TECHMAP_CONSTMSK_<port-name>_\n"); log(" _TECHMAP_CONSTVAL_<port-name>_\n"); log(" When this pair of parameters is available in a module for a port, then\n"); @@ -1220,7 +1209,7 @@ struct TechmapPass : public Pass { if (!map->module(mod->name)) map->add(mod->clone()); } else { - Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "ilang" : verilog_frontend)); + Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : verilog_frontend)); } } @@ -1230,8 +1219,27 @@ struct TechmapPass : public Pass { for (auto module : map->modules()) { if (module->attributes.count(ID::techmap_celltype) && !module->attributes.at(ID::techmap_celltype).bits.empty()) { char *p = strdup(module->attributes.at(ID::techmap_celltype).decode_string().c_str()); - for (char *q = strtok(p, " \t\r\n"); q; q = strtok(nullptr, " \t\r\n")) - celltypeMap[RTLIL::escape_id(q)].insert(module->name); + for (char *q = strtok(p, " \t\r\n"); q; q = strtok(nullptr, " \t\r\n")) { + std::vector<std::string> queue; + queue.push_back(q); + while (!queue.empty()) { + std::string name = queue.back(); + queue.pop_back(); + auto pos = name.find('['); + if (pos == std::string::npos) { + // No further expansion. + celltypeMap[RTLIL::escape_id(name)].insert(module->name); + } else { + // Expand [] in this name. + auto epos = name.find(']', pos); + if (epos == std::string::npos) + log_error("Malformed techmap_celltype pattern %s\n", q); + for (size_t i = pos + 1; i < epos; i++) { + queue.push_back(name.substr(0, pos) + name[i] + name.substr(epos + 1, std::string::npos)); + } + } + } + } free(p); } else { IdString module_name = module->name.begins_with("\\$") ? @@ -1239,8 +1247,15 @@ struct TechmapPass : public Pass { celltypeMap[module_name].insert(module->name); } } - for (auto &i : celltypeMap) + log_debug("Cell type mappings to use:\n"); + for (auto &i : celltypeMap) { i.second.sort(RTLIL::sort_by_id_str()); + std::string maps = ""; + for (auto &map : i.second) + maps += stringf(" %s", log_id(map)); + log_debug(" %s:%s\n", log_id(i.first), maps.c_str()); + } + log_debug("\n"); for (auto module : design->modules()) worker.module_queue.insert(module); diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc index 79ddb4bd7..f92b4cdb0 100644 --- a/passes/techmap/tribuf.cc +++ b/passes/techmap/tribuf.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc index cc0b26bcc..cc208c516 100644 --- a/passes/techmap/zinit.cc +++ b/passes/techmap/zinit.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,6 +19,8 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/ffinit.h" +#include "kernel/ff.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -57,158 +59,27 @@ struct ZinitPass : public Pass { for (auto module : design->selected_modules()) { SigMap sigmap(module); - dict<SigBit, std::pair<State,SigBit>> initbits; - - for (auto wire : module->selected_wires()) - { - if (wire->attributes.count(ID::init) == 0) - continue; - - SigSpec wirebits = sigmap(wire); - Const initval = wire->attributes.at(ID::init); - - for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) - { - SigBit bit = wirebits[i]; - State val = initval[i]; - - if (val != State::S0 && val != State::S1 && bit.wire != nullptr) - continue; - - if (initbits.count(bit)) { - if (initbits.at(bit).first != val) - log_error("Conflicting init values for signal %s (%s = %s != %s).\n", - log_signal(bit), log_signal(SigBit(wire, i)), - log_signal(val), log_signal(initbits.at(bit).first)); - continue; - } - - initbits[bit] = std::make_pair(val,SigBit(wire,i)); - } - } - - pool<IdString> dff_types = { - // FIXME: It would appear that supporting - // $dffsr/$_DFFSR_* would require a new - // cell type where S has priority over R - ID($ff), ID($dff), ID($dffe), /*ID($dffsr),*/ ID($adff), ID($adffe), - ID($sdff), ID($sdffe), ID($sdffce), - ID($_FF_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), - /*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_), - // Async set/reset - ID($_DFFE_NN0P_), ID($_DFFE_NN1P_), ID($_DFFE_NP0P_), ID($_DFFE_NP1P_), - ID($_DFFE_PN0P_), ID($_DFFE_PN1P_), ID($_DFFE_PP0P_), ID($_DFFE_PP1P_), - ID($_DFFE_NN0N_), ID($_DFFE_NN1N_), ID($_DFFE_NP0N_), ID($_DFFE_NP1N_), - ID($_DFFE_PN0N_), ID($_DFFE_PN1N_), ID($_DFFE_PP0N_), ID($_DFFE_PP1N_), - // Sync set/reset - ID($_SDFF_NN0_), ID($_SDFF_NN1_), ID($_SDFF_NP0_), ID($_SDFF_NP1_), - ID($_SDFF_PN0_), ID($_SDFF_PN1_), ID($_SDFF_PP0_), ID($_SDFF_PP1_), - ID($_SDFFE_NN0P_), ID($_SDFFE_NN1P_), ID($_SDFFE_NP0P_), ID($_SDFFE_NP1P_), - ID($_SDFFE_PN0P_), ID($_SDFFE_PN1P_), ID($_SDFFE_PP0P_), ID($_SDFFE_PP1P_), - ID($_SDFFE_NN0N_), ID($_SDFFE_NN1N_), ID($_SDFFE_NP0N_), ID($_SDFFE_NP1N_), - ID($_SDFFE_PN0N_), ID($_SDFFE_PN1N_), ID($_SDFFE_PP0N_), ID($_SDFFE_PP1N_), - ID($_SDFFCE_NN0P_), ID($_SDFFCE_NN1P_), ID($_SDFFCE_NP0P_), ID($_SDFFCE_NP1P_), - ID($_SDFFCE_PN0P_), ID($_SDFFCE_PN1P_), ID($_SDFFCE_PP0P_), ID($_SDFFCE_PP1P_), - ID($_SDFFCE_NN0N_), ID($_SDFFCE_NN1N_), ID($_SDFFCE_NP0N_), ID($_SDFFCE_NP1N_), - ID($_SDFFCE_PN0N_), ID($_SDFFCE_PN1N_), ID($_SDFFCE_PP0N_), ID($_SDFFCE_PP1N_) - }; + FfInitVals initvals(&sigmap, module); for (auto cell : module->selected_cells()) { - if (!dff_types.count(cell->type)) + if (!RTLIL::builtin_ff_cell_types().count(cell->type)) continue; - SigSpec sig_d = sigmap(cell->getPort(ID::D)); - SigSpec sig_q = sigmap(cell->getPort(ID::Q)); - - if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1) - continue; - - Const initval; - - for (int i = 0; i < GetSize(sig_q); i++) { - if (initbits.count(sig_q[i])) { - const auto &d = initbits.at(sig_q[i]); - initval.bits.push_back(d.first); - const auto &b = d.second; - b.wire->attributes.at(ID::init)[b.offset] = State::Sx; - } else - initval.bits.push_back(all_mode ? State::S0 : State::Sx); - } - - Wire *initwire = module->addWire(NEW_ID, GetSize(initval)); - initwire->attributes[ID::init] = initval; - - for (int i = 0; i < GetSize(initwire); i++) - if (initval[i] == State::S1) - { - sig_d[i] = module->NotGate(NEW_ID, sig_d[i]); - module->addNotGate(NEW_ID, SigSpec(initwire, i), sig_q[i]); - initwire->attributes[ID::init][i] = State::S0; - } - else - { - module->connect(sig_q[i], SigSpec(initwire, i)); - } + FfData ff(&initvals, cell); log("FF init value for cell %s (%s): %s = %s\n", log_id(cell), log_id(cell->type), - log_signal(sig_q), log_signal(initval)); - - cell->setPort(ID::D, sig_d); - cell->setPort(ID::Q, initwire); - - if (cell->type.in(ID($adff), ID($adffe))) { - auto val = cell->getParam(ID::ARST_VALUE); - for (int i = 0; i < GetSize(initwire); i++) - if (initval[i] == State::S1) - val[i] = (val[i] == State::S1 ? State::S0 : State::S1); - cell->setParam(ID::ARST_VALUE, std::move(val)); - } - else if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) { - auto val = cell->getParam(ID::SRST_VALUE); - for (int i = 0; i < GetSize(initwire); i++) - if (initval[i] == State::S1) - val[i] = (val[i] == State::S1 ? State::S0 : State::S1); - cell->setParam(ID::SRST_VALUE, std::move(val)); - } - else if (initval == State::S1) { - std::string t = cell->type.str(); - if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), - ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_))) - { - t[8] = (t[8] == '0' ? '1' : '0'); - } - else if (cell->type.in(ID($_SDFF_NN0_), ID($_SDFF_NN1_), ID($_SDFF_NP0_), ID($_SDFF_NP1_), - ID($_SDFF_PN0_), ID($_SDFF_PN1_), ID($_SDFF_PP0_), ID($_SDFF_PP1_))) - { - t[9] = (t[9] == '0' ? '1' : '0'); - } - else if (cell->type.in(ID($_DFFE_NN0P_), ID($_DFFE_NN1P_), ID($_DFFE_NP0P_), ID($_DFFE_NP1P_), - ID($_DFFE_PN0P_), ID($_DFFE_PN1P_), ID($_DFFE_PP0P_), ID($_DFFE_PP1P_), - ID($_DFFE_NN0N_), ID($_DFFE_NN1N_), ID($_DFFE_NP0N_), ID($_DFFE_NP1N_), - ID($_DFFE_PN0N_), ID($_DFFE_PN1N_), ID($_DFFE_PP0N_), ID($_DFFE_PP1N_))) - { - t[9] = (t[9] == '0' ? '1' : '0'); - } - else if (cell->type.in(ID($_SDFFE_NN0P_), ID($_SDFFE_NN1P_), ID($_SDFFE_NP0P_), ID($_SDFFE_NP1P_), - ID($_SDFFE_PN0P_), ID($_SDFFE_PN1P_), ID($_SDFFE_PP0P_), ID($_SDFFE_PP1P_), - ID($_SDFFE_NN0N_), ID($_SDFFE_NN1N_), ID($_SDFFE_NP0N_), ID($_SDFFE_NP1N_), - ID($_SDFFE_PN0N_), ID($_SDFFE_PN1N_), ID($_SDFFE_PP0N_), ID($_SDFFE_PP1N_))) - { - t[10] = (t[10] == '0' ? '1' : '0'); - } - else if (cell->type.in(ID($_SDFFCE_NN0P_), ID($_SDFFCE_NN1P_), ID($_SDFFCE_NP0P_), ID($_SDFFCE_NP1P_), - ID($_SDFFCE_PN0P_), ID($_SDFFCE_PN1P_), ID($_SDFFCE_PP0P_), ID($_SDFFCE_PP1P_), - ID($_SDFFCE_NN0N_), ID($_SDFFCE_NN1N_), ID($_SDFFCE_NP0N_), ID($_SDFFCE_NP1N_), - ID($_SDFFCE_PN0N_), ID($_SDFFCE_PN1N_), ID($_SDFFCE_PP0N_), ID($_SDFFCE_PP1N_))) - { - t[11] = (t[11] == '0' ? '1' : '0'); - } - cell->type = t; + log_signal(ff.sig_q), log_signal(ff.val_init)); + + pool<int> bits; + for (int i = 0; i < ff.width; i++) { + if (ff.val_init.bits[i] == State::S1) + bits.insert(i); + else if (ff.val_init.bits[i] != State::S0 && all_mode) + ff.val_init.bits[i] = State::S0; } + ff.flip_bits(bits); + ff.emit(); } } } |