From a64b56648d6421dec9cb29f7103a3b3ae598fa11 Mon Sep 17 00:00:00 2001 From: Robert Ou Date: Sat, 24 Jun 2017 08:51:24 -0700 Subject: [PATCH] coolrunner2: Initial techmapping for $sop --- techlibs/coolrunner2/Makefile.inc | 1 + techlibs/coolrunner2/cells_sim.v | 16 +- techlibs/coolrunner2/coolrunner2_sop.cpp | 111 ++++++++ techlibs/coolrunner2/synth_coolrunner2.cpp | 293 +++++++++++---------- 4 files changed, 268 insertions(+), 153 deletions(-) create mode 100644 techlibs/coolrunner2/coolrunner2_sop.cpp diff --git a/techlibs/coolrunner2/Makefile.inc b/techlibs/coolrunner2/Makefile.inc index 516238330..81612ded2 100644 --- a/techlibs/coolrunner2/Makefile.inc +++ b/techlibs/coolrunner2/Makefile.inc @@ -1,4 +1,5 @@ OBJS += techlibs/coolrunner2/synth_coolrunner2.o +OBJS += techlibs/coolrunner2/coolrunner2_sop.o $(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/cells_sim.v)) diff --git a/techlibs/coolrunner2/cells_sim.v b/techlibs/coolrunner2/cells_sim.v index 328e7504d..baeb97fa5 100644 --- a/techlibs/coolrunner2/cells_sim.v +++ b/techlibs/coolrunner2/cells_sim.v @@ -7,20 +7,22 @@ module IOBUFE(input I, input E, output O, inout IO); assign IO = E ? I : 1'bz; endmodule -module ANDTERM(IN, OUT); - parameter WIDTH = 0; +module ANDTERM(IN, IN_B, OUT); + parameter TRUE_INP = 0; + parameter COMP_INP = 0; - input [(WIDTH*2)-1:0] IN; + input [TRUE_INP-1:0] IN; + input [COMP_INP-1:0] IN_B; output reg OUT; integer i; always @(*) begin OUT = 1; - for (i = 0; i < WIDTH; i=i+1) begin - OUT = OUT & ~IN[i * 2 + 0]; - OUT = OUT & IN[i * 2 + 1]; - end + for (i = 0; i < TRUE_INP; i=i+1) + OUT = OUT & IN[i]; + for (i = 0; i < COMP_INP; i=i+1) + OUT = OUT & ~IN_B[i]; end endmodule diff --git a/techlibs/coolrunner2/coolrunner2_sop.cpp b/techlibs/coolrunner2/coolrunner2_sop.cpp new file mode 100644 index 000000000..36bd77ad6 --- /dev/null +++ b/techlibs/coolrunner2/coolrunner2_sop.cpp @@ -0,0 +1,111 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2017 Robert Ou + * + * 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 Coolrunner2SopPass : public Pass { + Coolrunner2SopPass() : Pass("coolrunner2_sop", "break $sop cells into ANDTERM/ORTERM cells") { } + virtual void help() + { + log("\n"); + log(" coolrunner2_sop [options] [selection]\n"); + log("\n"); + log("Break $sop cells into ANDTERM/ORTERM cells.\n"); + log("\n"); + } + virtual void execute(std::vector args, RTLIL::Design *design) + { + log_header(design, "Executing COOLRUNNER2_SOP pass (break $sop cells into ANDTERM/ORTERM cells).\n"); + extra_args(args, 1, design); + + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + for (auto cell : module->selected_cells()) + { + if (cell->type == "$sop") + { + // Read the inputs/outputs/parameters of the $sop cell + auto sop_inputs = sigmap(cell->getPort("\\A")); + auto sop_output = sigmap(cell->getPort("\\Y"))[0]; + auto sop_depth = cell->getParam("\\DEPTH").as_int(); + auto sop_width = cell->getParam("\\WIDTH").as_int(); + auto sop_table = cell->getParam("\\TABLE"); + + // Construct AND cells + pool intermed_wires; + for (int i = 0; i < sop_depth; i++) { + // Wire for the output + auto and_out = module->addWire(NEW_ID); + intermed_wires.insert(and_out); + + // Signals for the inputs + pool and_in_true; + pool and_in_comp; + for (int j = 0; j < sop_width; j++) + { + if (sop_table[2 * (i * sop_width + j) + 0]) + { + and_in_comp.insert(sop_inputs[j]); + } + if (sop_table[2 * (i * sop_width + j) + 1]) + { + and_in_true.insert(sop_inputs[j]); + } + } + + // Construct the cell + auto and_cell = module->addCell(NEW_ID, "\\ANDTERM"); + and_cell->setParam("\\TRUE_INP", GetSize(and_in_true)); + and_cell->setParam("\\COMP_INP", GetSize(and_in_comp)); + and_cell->setPort("\\OUT", and_out); + and_cell->setPort("\\IN", and_in_true); + and_cell->setPort("\\IN_B", and_in_comp); + } + + // If there is only one term, don't construct an OR cell + if (sop_depth == 1) + { + yosys_xtrace = 1; + module->connect(sop_output, *intermed_wires.begin()); + log("one\n"); + } + else + { + log("more\n"); + // Construct the cell + auto or_cell = module->addCell(NEW_ID, "\\ORTERM"); + or_cell->setParam("\\WIDTH", sop_depth); + or_cell->setPort("\\IN", intermed_wires); + or_cell->setPort("\\OUT", sop_output); + } + + // Finally, remove the $sop cell + module->remove(cell); + } + } + } + } +} Coolrunner2SopPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/coolrunner2/synth_coolrunner2.cpp b/techlibs/coolrunner2/synth_coolrunner2.cpp index cc6f6401d..516d29ad0 100644 --- a/techlibs/coolrunner2/synth_coolrunner2.cpp +++ b/techlibs/coolrunner2/synth_coolrunner2.cpp @@ -27,152 +27,153 @@ PRIVATE_NAMESPACE_BEGIN struct SynthCoolrunner2Pass : public ScriptPass { - SynthCoolrunner2Pass() : ScriptPass("synth_coolrunner2", "synthesis for Xilinx Coolrunner-II CPLDs") { } - - virtual void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" synth_coolrunner2 [options]\n"); - log("\n"); - log("This command runs synthesis for Coolrunner-II CPLDs. This work is experimental.\n"); - log("It is intended to be used with https://github.com/azonenberg/openfpga as the\n"); - log("place-and-route.\n"); - log("\n"); - log(" -top \n"); - log(" use the specified module as top module (default='top')\n"); - log("\n"); - log(" -json \n"); - log(" write the design to the specified JSON file. writing of an output file\n"); - log(" is omitted if this parameter is not specified.\n"); - log("\n"); - log(" -run :\n"); - log(" only run the commands between the labels (see below). an empty\n"); - log(" from label is synonymous to 'begin', and empty to label is\n"); - log(" synonymous to the end of the command list.\n"); - log("\n"); - log(" -noflatten\n"); - log(" do not flatten design before synthesis\n"); - log("\n"); - log(" -retime\n"); - log(" run 'abc' with -dff option\n"); - log("\n"); - log("\n"); - log("The following commands are executed by this synthesis command:\n"); - help_script(); - log("\n"); - } - - string top_opt, json_file; - bool flatten, retime; - - virtual void clear_flags() YS_OVERRIDE - { - top_opt = "-auto-top"; - json_file = ""; - flatten = true; - retime = false; - } - - virtual void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - string run_from, run_to; - clear_flags(); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-top" && argidx+1 < args.size()) { - top_opt = "-top " + args[++argidx]; - continue; - } - if (args[argidx] == "-json" && argidx+1 < args.size()) { - json_file = args[++argidx]; - continue; - } - if (args[argidx] == "-run" && argidx+1 < args.size()) { - size_t pos = args[argidx+1].find(':'); - if (pos == std::string::npos) - break; - run_from = args[++argidx].substr(0, pos); - run_to = args[argidx].substr(pos+1); - continue; - } - if (args[argidx] == "-noflatten") { - flatten = false; - continue; - } - if (args[argidx] == "-retime") { - retime = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); - - log_header(design, "Executing SYNTH_COOLRUNNER2 pass.\n"); - log_push(); - - run_script(design, run_from, run_to); - - log_pop(); - } - - virtual void script() YS_OVERRIDE - { - if (check_label("begin")) - { - run("read_verilog -lib +/coolrunner2/cells_sim.v"); - run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt.c_str())); - } - - if (flatten && check_label("flatten", "(unless -noflatten)")) - { - run("proc"); - run("flatten"); - run("tribuf -logic"); - } - - if (check_label("coarse")) - { - run("synth -run coarse"); - } - - if (check_label("fine")) - { - run("opt -fast -full"); - run("techmap"); - } - - if (check_label("map_pla")) - { - run("abc -sop -I 40 -P 56"); - run("opt -fast"); - } - - if (check_label("map_cells")) - { - run("iopadmap -bits -inpad IBUF O:I -outpad IOBUFE I:IO -inoutpad IOBUFE O:IO -toutpad IOBUFE E:I:IO -tinoutpad IOBUFE E:O:I:IO"); - } - - if (check_label("check")) - { - run("hierarchy -check"); - run("stat"); - run("check -noinit"); - } - - if (check_label("json")) - { - if (!json_file.empty() || help_mode) - run(stringf("write_json %s", help_mode ? "" : json_file.c_str())); - } - - log_pop(); - } + SynthCoolrunner2Pass() : ScriptPass("synth_coolrunner2", "synthesis for Xilinx Coolrunner-II CPLDs") { } + + virtual void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth_coolrunner2 [options]\n"); + log("\n"); + log("This command runs synthesis for Coolrunner-II CPLDs. This work is experimental.\n"); + log("It is intended to be used with https://github.com/azonenberg/openfpga as the\n"); + log("place-and-route.\n"); + log("\n"); + log(" -top \n"); + log(" use the specified module as top module (default='top')\n"); + log("\n"); + log(" -json \n"); + log(" write the design to the specified JSON file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -run :\n"); + log(" only run the commands between the labels (see below). an empty\n"); + log(" from label is synonymous to 'begin', and empty to label is\n"); + log(" synonymous to the end of the command list.\n"); + log("\n"); + log(" -noflatten\n"); + log(" do not flatten design before synthesis\n"); + log("\n"); + log(" -retime\n"); + log(" run 'abc' with -dff option\n"); + log("\n"); + log("\n"); + log("The following commands are executed by this synthesis command:\n"); + help_script(); + log("\n"); + } + + string top_opt, json_file; + bool flatten, retime; + + virtual void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + json_file = ""; + flatten = true; + retime = false; + } + + virtual void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + string run_from, run_to; + clear_flags(); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-top" && argidx+1 < args.size()) { + top_opt = "-top " + args[++argidx]; + continue; + } + if (args[argidx] == "-json" && argidx+1 < args.size()) { + json_file = args[++argidx]; + continue; + } + if (args[argidx] == "-run" && argidx+1 < args.size()) { + size_t pos = args[argidx+1].find(':'); + if (pos == std::string::npos) + break; + run_from = args[++argidx].substr(0, pos); + run_to = args[argidx].substr(pos+1); + continue; + } + if (args[argidx] == "-noflatten") { + flatten = false; + continue; + } + if (args[argidx] == "-retime") { + retime = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (!design->full_selection()) + log_cmd_error("This comannd only operates on fully selected designs!\n"); + + log_header(design, "Executing SYNTH_COOLRUNNER2 pass.\n"); + log_push(); + + run_script(design, run_from, run_to); + + log_pop(); + } + + virtual void script() YS_OVERRIDE + { + if (check_label("begin")) + { + run("read_verilog -lib +/coolrunner2/cells_sim.v"); + run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt.c_str())); + } + + if (flatten && check_label("flatten", "(unless -noflatten)")) + { + run("proc"); + run("flatten"); + run("tribuf -logic"); + } + + if (check_label("coarse")) + { + run("synth -run coarse"); + } + + if (check_label("fine")) + { + run("opt -fast -full"); + run("techmap"); + } + + if (check_label("map_pla")) + { + run("abc -sop -I 40 -P 56"); + run("coolrunner2_sop"); + run("opt -fast"); + } + + if (check_label("map_cells")) + { + run("iopadmap -bits -inpad IBUF O:I -outpad IOBUFE I:IO -inoutpad IOBUFE O:IO -toutpad IOBUFE E:I:IO -tinoutpad IOBUFE E:O:I:IO"); + } + + if (check_label("check")) + { + run("hierarchy -check"); + run("stat"); + run("check -noinit"); + } + + if (check_label("json")) + { + if (!json_file.empty() || help_mode) + run(stringf("write_json %s", help_mode ? "" : json_file.c_str())); + } + + log_pop(); + } } SynthCoolrunner2Pass; PRIVATE_NAMESPACE_END -- 2.30.2