From 6e0fb889fafc58d40ef83e61520f68f6767f0c91 Mon Sep 17 00:00:00 2001 From: Robert Ou Date: Sat, 24 Jun 2017 06:59:20 -0700 Subject: coolrunner2: Initial commit --- techlibs/coolrunner2/Makefile.inc | 4 + techlibs/coolrunner2/cells_sim.v | 41 +++++++ techlibs/coolrunner2/synth_coolrunner2.cpp | 178 +++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 techlibs/coolrunner2/Makefile.inc create mode 100644 techlibs/coolrunner2/cells_sim.v create mode 100644 techlibs/coolrunner2/synth_coolrunner2.cpp (limited to 'techlibs/coolrunner2') diff --git a/techlibs/coolrunner2/Makefile.inc b/techlibs/coolrunner2/Makefile.inc new file mode 100644 index 000000000..516238330 --- /dev/null +++ b/techlibs/coolrunner2/Makefile.inc @@ -0,0 +1,4 @@ + +OBJS += techlibs/coolrunner2/synth_coolrunner2.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 new file mode 100644 index 000000000..328e7504d --- /dev/null +++ b/techlibs/coolrunner2/cells_sim.v @@ -0,0 +1,41 @@ +module IBUF(input I, output O); + assign O = I; +endmodule + +module IOBUFE(input I, input E, output O, inout IO); + assign O = IO; + assign IO = E ? I : 1'bz; +endmodule + +module ANDTERM(IN, OUT); + parameter WIDTH = 0; + + input [(WIDTH*2)-1:0] IN; + 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 + end +endmodule + +module ORTERM(IN, OUT); + parameter WIDTH = 0; + + input [WIDTH-1:0] IN; + output reg OUT; + + integer i; + + always @(*) begin + OUT = 0; + for (i = 0; i < WIDTH; i=i+1) begin + OUT = OUT | IN[i]; + end + end +endmodule diff --git a/techlibs/coolrunner2/synth_coolrunner2.cpp b/techlibs/coolrunner2/synth_coolrunner2.cpp new file mode 100644 index 000000000..cc6f6401d --- /dev/null +++ b/techlibs/coolrunner2/synth_coolrunner2.cpp @@ -0,0 +1,178 @@ +/* + * 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/register.h" +#include "kernel/celltypes.h" +#include "kernel/rtlil.h" +#include "kernel/log.h" + +USING_YOSYS_NAMESPACE +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; + +PRIVATE_NAMESPACE_END -- cgit v1.2.3 From a64b56648d6421dec9cb29f7103a3b3ae598fa11 Mon Sep 17 00:00:00 2001 From: Robert Ou Date: Sat, 24 Jun 2017 08:51:24 -0700 Subject: 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 (limited to 'techlibs/coolrunner2') 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 -- cgit v1.2.3 From 908ce3fdcefd095a3cb9928feb9d7dcf314d96bb Mon Sep 17 00:00:00 2001 From: Robert Ou Date: Sun, 25 Jun 2017 02:20:42 -0700 Subject: coolrunner2: Also construct the XOR cell in the macrocell --- techlibs/coolrunner2/cells_sim.v | 14 ++++++++++++++ techlibs/coolrunner2/coolrunner2_sop.cpp | 27 ++++++++++++++++++++------- 2 files changed, 34 insertions(+), 7 deletions(-) (limited to 'techlibs/coolrunner2') diff --git a/techlibs/coolrunner2/cells_sim.v b/techlibs/coolrunner2/cells_sim.v index baeb97fa5..474d35a9a 100644 --- a/techlibs/coolrunner2/cells_sim.v +++ b/techlibs/coolrunner2/cells_sim.v @@ -41,3 +41,17 @@ module ORTERM(IN, OUT); end end endmodule + +module MACROCELL_XOR(IN_PTC, IN_ORTERM, OUT); + parameter INVERT_PTC = 0; + parameter INVERT_OUT = 0; + + input IN_PTC; + input IN_ORTERM; + output wire OUT; + + wire xor_intermed; + + assign OUT = INVERT_OUT ? ~xor_intermed : xor_intermed; + assign xor_intermed = INVERT_PTC ? IN_ORTERM ^ ~IN_PTC : IN_ORTERM ^ IN_PTC; +endmodule diff --git a/techlibs/coolrunner2/coolrunner2_sop.cpp b/techlibs/coolrunner2/coolrunner2_sop.cpp index 36bd77ad6..8ef08b43a 100644 --- a/techlibs/coolrunner2/coolrunner2_sop.cpp +++ b/techlibs/coolrunner2/coolrunner2_sop.cpp @@ -83,21 +83,34 @@ struct Coolrunner2SopPass : public Pass { and_cell->setPort("\\IN_B", and_in_comp); } - // If there is only one term, don't construct an OR cell + // TODO: Find the $_NOT_ on the output + if (sop_depth == 1) { - yosys_xtrace = 1; - module->connect(sop_output, *intermed_wires.begin()); - log("one\n"); + // If there is only one term, don't construct an OR cell. Directly construct the XOR gate + auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR"); + xor_cell->setParam("\\INVERT_PTC", 0); + xor_cell->setParam("\\INVERT_OUT", 0); + xor_cell->setPort("\\IN_PTC", *intermed_wires.begin()); + xor_cell->setPort("\\OUT", sop_output); } else { - log("more\n"); - // Construct the cell + // Wire from OR to XOR + auto or_to_xor_wire = module->addWire(NEW_ID); + + // Construct the OR 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); + or_cell->setPort("\\OUT", or_to_xor_wire); + + // Construct the XOR cell + auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR"); + xor_cell->setParam("\\INVERT_PTC", 0); + xor_cell->setParam("\\INVERT_OUT", 0); + xor_cell->setPort("\\IN_ORTERM", or_to_xor_wire); + xor_cell->setPort("\\OUT", sop_output); } // Finally, remove the $sop cell -- cgit v1.2.3 From 5798105d47cdcdaf4e305ef9dbd5b6c93fef35b1 Mon Sep 17 00:00:00 2001 From: Robert Ou Date: Sun, 25 Jun 2017 02:42:36 -0700 Subject: coolrunner2: Correctly handle $_NOT_ after $sop --- techlibs/coolrunner2/coolrunner2_sop.cpp | 46 ++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 5 deletions(-) (limited to 'techlibs/coolrunner2') diff --git a/techlibs/coolrunner2/coolrunner2_sop.cpp b/techlibs/coolrunner2/coolrunner2_sop.cpp index 8ef08b43a..70d4aa870 100644 --- a/techlibs/coolrunner2/coolrunner2_sop.cpp +++ b/techlibs/coolrunner2/coolrunner2_sop.cpp @@ -38,6 +38,24 @@ struct Coolrunner2SopPass : public Pass { log_header(design, "Executing COOLRUNNER2_SOP pass (break $sop cells into ANDTERM/ORTERM cells).\n"); extra_args(args, 1, design); + // Find all the $_NOT_ cells + dict> not_cells; + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + for (auto cell : module->selected_cells()) + { + if (cell->type == "$_NOT_") + { + log("found not cell %s\n", log_id(cell)); + auto not_input = cell->getPort("\\A")[0]; + auto not_output = cell->getPort("\\Y")[0]; + not_cells[not_input] = {not_output, cell}; + } + } + } + + pool> cells_to_remove; for (auto module : design->selected_modules()) { SigMap sigmap(module); @@ -52,6 +70,20 @@ struct Coolrunner2SopPass : public Pass { auto sop_width = cell->getParam("\\WIDTH").as_int(); auto sop_table = cell->getParam("\\TABLE"); + // Check for a $_NOT_ at the output + bool has_invert = false; + if (not_cells.count(sop_output)) + { + log("sop output is inverted %s\n", log_id(cell)); + auto not_cell = not_cells.at(sop_output); + + has_invert = true; + sop_output = std::get<0>(not_cell); + + // remove the $_NOT_ cell because it gets folded into the xor + cells_to_remove.insert({module, std::get<1>(not_cell)}); + } + // Construct AND cells pool intermed_wires; for (int i = 0; i < sop_depth; i++) { @@ -83,14 +115,12 @@ struct Coolrunner2SopPass : public Pass { and_cell->setPort("\\IN_B", and_in_comp); } - // TODO: Find the $_NOT_ on the output - if (sop_depth == 1) { // If there is only one term, don't construct an OR cell. Directly construct the XOR gate auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR"); xor_cell->setParam("\\INVERT_PTC", 0); - xor_cell->setParam("\\INVERT_OUT", 0); + xor_cell->setParam("\\INVERT_OUT", has_invert); xor_cell->setPort("\\IN_PTC", *intermed_wires.begin()); xor_cell->setPort("\\OUT", sop_output); } @@ -108,16 +138,22 @@ struct Coolrunner2SopPass : public Pass { // Construct the XOR cell auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR"); xor_cell->setParam("\\INVERT_PTC", 0); - xor_cell->setParam("\\INVERT_OUT", 0); + xor_cell->setParam("\\INVERT_OUT", has_invert); xor_cell->setPort("\\IN_ORTERM", or_to_xor_wire); xor_cell->setPort("\\OUT", sop_output); } // Finally, remove the $sop cell - module->remove(cell); + cells_to_remove.insert({module, cell}); } } } + + // Actually do the removal now that we aren't iterating + for (auto mod_and_cell : cells_to_remove) + { + std::get<0>(mod_and_cell)->remove(std::get<1>(mod_and_cell)); + } } } Coolrunner2SopPass; -- cgit v1.2.3 From ffff00100858c5839fbf02e29b14bd7590493608 Mon Sep 17 00:00:00 2001 From: Robert Ou Date: Sun, 25 Jun 2017 02:44:03 -0700 Subject: coolrunner2: Remove debug prints --- techlibs/coolrunner2/coolrunner2_sop.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'techlibs/coolrunner2') diff --git a/techlibs/coolrunner2/coolrunner2_sop.cpp b/techlibs/coolrunner2/coolrunner2_sop.cpp index 70d4aa870..ed11880d5 100644 --- a/techlibs/coolrunner2/coolrunner2_sop.cpp +++ b/techlibs/coolrunner2/coolrunner2_sop.cpp @@ -47,7 +47,6 @@ struct Coolrunner2SopPass : public Pass { { if (cell->type == "$_NOT_") { - log("found not cell %s\n", log_id(cell)); auto not_input = cell->getPort("\\A")[0]; auto not_output = cell->getPort("\\Y")[0]; not_cells[not_input] = {not_output, cell}; @@ -74,7 +73,6 @@ struct Coolrunner2SopPass : public Pass { bool has_invert = false; if (not_cells.count(sop_output)) { - log("sop output is inverted %s\n", log_id(cell)); auto not_cell = not_cells.at(sop_output); has_invert = true; -- cgit v1.2.3 From 1eb5dee79954e48210862980e368c2ce3b2762c9 Mon Sep 17 00:00:00 2001 From: Robert Ou Date: Sun, 25 Jun 2017 02:56:45 -0700 Subject: coolrunner2: Remove redundant INVERT_PTC --- techlibs/coolrunner2/cells_sim.v | 3 +-- techlibs/coolrunner2/coolrunner2_sop.cpp | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'techlibs/coolrunner2') diff --git a/techlibs/coolrunner2/cells_sim.v b/techlibs/coolrunner2/cells_sim.v index 474d35a9a..52326fbb3 100644 --- a/techlibs/coolrunner2/cells_sim.v +++ b/techlibs/coolrunner2/cells_sim.v @@ -43,7 +43,6 @@ module ORTERM(IN, OUT); endmodule module MACROCELL_XOR(IN_PTC, IN_ORTERM, OUT); - parameter INVERT_PTC = 0; parameter INVERT_OUT = 0; input IN_PTC; @@ -53,5 +52,5 @@ module MACROCELL_XOR(IN_PTC, IN_ORTERM, OUT); wire xor_intermed; assign OUT = INVERT_OUT ? ~xor_intermed : xor_intermed; - assign xor_intermed = INVERT_PTC ? IN_ORTERM ^ ~IN_PTC : IN_ORTERM ^ IN_PTC; + assign xor_intermed = IN_ORTERM ^ IN_PTC; endmodule diff --git a/techlibs/coolrunner2/coolrunner2_sop.cpp b/techlibs/coolrunner2/coolrunner2_sop.cpp index ed11880d5..cc214cfd2 100644 --- a/techlibs/coolrunner2/coolrunner2_sop.cpp +++ b/techlibs/coolrunner2/coolrunner2_sop.cpp @@ -117,7 +117,6 @@ struct Coolrunner2SopPass : public Pass { { // If there is only one term, don't construct an OR cell. Directly construct the XOR gate auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR"); - xor_cell->setParam("\\INVERT_PTC", 0); xor_cell->setParam("\\INVERT_OUT", has_invert); xor_cell->setPort("\\IN_PTC", *intermed_wires.begin()); xor_cell->setPort("\\OUT", sop_output); @@ -135,7 +134,6 @@ struct Coolrunner2SopPass : public Pass { // Construct the XOR cell auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR"); - xor_cell->setParam("\\INVERT_PTC", 0); xor_cell->setParam("\\INVERT_OUT", has_invert); xor_cell->setPort("\\IN_ORTERM", or_to_xor_wire); xor_cell->setPort("\\OUT", sop_output); -- cgit v1.2.3 From 4af5baab218a78c3af18269db8501031b457ed64 Mon Sep 17 00:00:00 2001 From: Robert Ou Date: Sun, 25 Jun 2017 20:16:43 -0700 Subject: coolrunner2: Initial mapping of DFFs All DFFs map to either FDCP (matches Xilinx) or a custom FDCP_N (negative-edge triggered) --- techlibs/coolrunner2/Makefile.inc | 1 + techlibs/coolrunner2/cells_sim.v | 40 ++++++++++++++++++++++++++++++ techlibs/coolrunner2/synth_coolrunner2.cpp | 4 +++ techlibs/coolrunner2/xc2_dff.lib | 31 +++++++++++++++++++++++ 4 files changed, 76 insertions(+) create mode 100644 techlibs/coolrunner2/xc2_dff.lib (limited to 'techlibs/coolrunner2') diff --git a/techlibs/coolrunner2/Makefile.inc b/techlibs/coolrunner2/Makefile.inc index 81612ded2..d1672e782 100644 --- a/techlibs/coolrunner2/Makefile.inc +++ b/techlibs/coolrunner2/Makefile.inc @@ -3,3 +3,4 @@ OBJS += techlibs/coolrunner2/synth_coolrunner2.o OBJS += techlibs/coolrunner2/coolrunner2_sop.o $(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/cells_sim.v)) +$(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/xc2_dff.lib)) diff --git a/techlibs/coolrunner2/cells_sim.v b/techlibs/coolrunner2/cells_sim.v index 52326fbb3..f9f990c22 100644 --- a/techlibs/coolrunner2/cells_sim.v +++ b/techlibs/coolrunner2/cells_sim.v @@ -54,3 +54,43 @@ module MACROCELL_XOR(IN_PTC, IN_ORTERM, OUT); assign OUT = INVERT_OUT ? ~xor_intermed : xor_intermed; assign xor_intermed = IN_ORTERM ^ IN_PTC; endmodule + +module FDCP (C, PRE, CLR, D, Q); + parameter INIT = 0; + + input C, PRE, CLR, D; + output reg Q; + + initial begin + Q <= INIT; + end + + always @(posedge C, posedge PRE, posedge CLR) begin + if (CLR == 1) + Q <= 0; + else if (PRE == 1) + Q <= 1; + else + Q <= D; + end +endmodule + +module FDCP_N (C, PRE, CLR, D, Q); + parameter INIT = 0; + + input C, PRE, CLR, D; + output reg Q; + + initial begin + Q <= INIT; + end + + always @(negedge C, posedge PRE, posedge CLR) begin + if (CLR == 1) + Q <= 0; + else if (PRE == 1) + Q <= 1; + else + Q <= D; + end +endmodule diff --git a/techlibs/coolrunner2/synth_coolrunner2.cpp b/techlibs/coolrunner2/synth_coolrunner2.cpp index 516d29ad0..c58b52cdf 100644 --- a/techlibs/coolrunner2/synth_coolrunner2.cpp +++ b/techlibs/coolrunner2/synth_coolrunner2.cpp @@ -145,6 +145,7 @@ struct SynthCoolrunner2Pass : public ScriptPass { run("opt -fast -full"); run("techmap"); + run("dfflibmap -prepare -liberty +/coolrunner2/xc2_dff.lib"); } if (check_label("map_pla")) @@ -156,6 +157,9 @@ struct SynthCoolrunner2Pass : public ScriptPass if (check_label("map_cells")) { + run("dfflibmap -liberty +/coolrunner2/xc2_dff.lib"); + run("dffinit -ff FDCP Q INIT"); + run("dffinit -ff FDCP_N Q INIT"); 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"); } diff --git a/techlibs/coolrunner2/xc2_dff.lib b/techlibs/coolrunner2/xc2_dff.lib new file mode 100644 index 000000000..b578493a1 --- /dev/null +++ b/techlibs/coolrunner2/xc2_dff.lib @@ -0,0 +1,31 @@ +library(xc2_dff) { + cell(FDCP) { + area: 1; + ff("IQ", "IQN") { clocked_on: C; + next_state: D; + clear: "CLR"; + preset: "PRE"; } + pin(C) { direction: input; + clock: true; } + pin(D) { direction: input; } + pin(Q) { direction: output; + function: "IQ"; } + pin(CLR) { direction: input; } + pin(PRE) { direction: input; } + } + + cell(FDCP_N) { + area: 1; + ff("IQ", "IQN") { clocked_on: "!C"; + next_state: D; + clear: "CLR"; + preset: "PRE"; } + pin(C) { direction: input; + clock: true; } + pin(D) { direction: input; } + pin(Q) { direction: output; + function: "IQ"; } + pin(CLR) { direction: input; } + pin(PRE) { direction: input; } + } +} -- cgit v1.2.3 From 36b75dfcb71329e378caa88f5390ef9a8598b674 Mon Sep 17 00:00:00 2001 From: Robert Ou Date: Sun, 25 Jun 2017 20:58:45 -0700 Subject: coolrunner2: Initial mapping of latches --- techlibs/coolrunner2/Makefile.inc | 1 + techlibs/coolrunner2/cells_latch.v | 19 ++++++++++++++ techlibs/coolrunner2/cells_sim.v | 40 ++++++++++++++++++++++++++++++ techlibs/coolrunner2/synth_coolrunner2.cpp | 3 +++ 4 files changed, 63 insertions(+) create mode 100644 techlibs/coolrunner2/cells_latch.v (limited to 'techlibs/coolrunner2') diff --git a/techlibs/coolrunner2/Makefile.inc b/techlibs/coolrunner2/Makefile.inc index d1672e782..96bbb0f47 100644 --- a/techlibs/coolrunner2/Makefile.inc +++ b/techlibs/coolrunner2/Makefile.inc @@ -2,5 +2,6 @@ OBJS += techlibs/coolrunner2/synth_coolrunner2.o OBJS += techlibs/coolrunner2/coolrunner2_sop.o +$(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/cells_latch.v)) $(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/cells_sim.v)) $(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/xc2_dff.lib)) diff --git a/techlibs/coolrunner2/cells_latch.v b/techlibs/coolrunner2/cells_latch.v new file mode 100644 index 000000000..f1e19da3a --- /dev/null +++ b/techlibs/coolrunner2/cells_latch.v @@ -0,0 +1,19 @@ +module $_DLATCH_P_(input E, input D, output Q); + LDCP _TECHMAP_REPLACE_ ( + .D(D), + .G(E), + .Q(Q), + .PRE(1'b0), + .CLR(1'b0) + ); +endmodule + +module $_DLATCH_N_(input E, input D, output Q); + LDCP_N _TECHMAP_REPLACE_ ( + .D(D), + .G(E), + .Q(Q), + .PRE(1'b0), + .CLR(1'b0) + ); +endmodule diff --git a/techlibs/coolrunner2/cells_sim.v b/techlibs/coolrunner2/cells_sim.v index f9f990c22..90eb4eb16 100644 --- a/techlibs/coolrunner2/cells_sim.v +++ b/techlibs/coolrunner2/cells_sim.v @@ -94,3 +94,43 @@ module FDCP_N (C, PRE, CLR, D, Q); Q <= D; end endmodule + +module LDCP (G, PRE, CLR, D, Q); + parameter INIT = 0; + + input G, PRE, CLR, D; + output reg Q; + + initial begin + Q <= INIT; + end + + always @* begin + if (CLR == 1) + Q <= 0; + else if (G == 1) + Q <= D; + else if (PRE == 1) + Q <= 1; + end +endmodule + +module LDCP_N (G, PRE, CLR, D, Q); + parameter INIT = 0; + + input G, PRE, CLR, D; + output reg Q; + + initial begin + Q <= INIT; + end + + always @* begin + if (CLR == 1) + Q <= 0; + else if (G == 0) + Q <= D; + else if (PRE == 1) + Q <= 1; + end +endmodule diff --git a/techlibs/coolrunner2/synth_coolrunner2.cpp b/techlibs/coolrunner2/synth_coolrunner2.cpp index c58b52cdf..791bcffbe 100644 --- a/techlibs/coolrunner2/synth_coolrunner2.cpp +++ b/techlibs/coolrunner2/synth_coolrunner2.cpp @@ -145,6 +145,7 @@ struct SynthCoolrunner2Pass : public ScriptPass { run("opt -fast -full"); run("techmap"); + run("techmap -map +/coolrunner2/cells_latch.v"); run("dfflibmap -prepare -liberty +/coolrunner2/xc2_dff.lib"); } @@ -160,6 +161,8 @@ struct SynthCoolrunner2Pass : public ScriptPass run("dfflibmap -liberty +/coolrunner2/xc2_dff.lib"); run("dffinit -ff FDCP Q INIT"); run("dffinit -ff FDCP_N Q INIT"); + run("dffinit -ff LDCP Q INIT"); + run("dffinit -ff LDCP_N Q INIT"); 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"); } -- cgit v1.2.3 From b102c0e2544d3bba8f8982db9dfb4974a0170368 Mon Sep 17 00:00:00 2001 From: Robert Ou Date: Sun, 25 Jun 2017 23:56:16 -0700 Subject: coolrunner2: Add a few more primitives These cannot be inferred yet, but add them to cells_sim.v for now --- techlibs/coolrunner2/cells_sim.v | 110 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) (limited to 'techlibs/coolrunner2') diff --git a/techlibs/coolrunner2/cells_sim.v b/techlibs/coolrunner2/cells_sim.v index 90eb4eb16..e08ee5f9b 100644 --- a/techlibs/coolrunner2/cells_sim.v +++ b/techlibs/coolrunner2/cells_sim.v @@ -134,3 +134,113 @@ module LDCP_N (G, PRE, CLR, D, Q); Q <= 1; end endmodule + +module BUFG(I, O); + input I; + output O; + + assign O = I; +endmodule + +module BUFGSR(I, O); + input I; + output O; + + assign O = I; +endmodule + +module BUFGTS(I, O); + input I; + output O; + + assign O = I; +endmodule + +module FDDCP (C, PRE, CLR, D, Q); + parameter INIT = 0; + + input C, PRE, CLR, D; + output reg Q; + + initial begin + Q <= INIT; + end + + always @(posedge C, negedge C, posedge PRE, posedge CLR) begin + if (CLR == 1) + Q <= 0; + else if (PRE == 1) + Q <= 1; + else + Q <= D; + end +endmodule + +module FTCP (C, PRE, CLR, T, Q); + parameter INIT = 0; + + input C, PRE, CLR, T; + output wire Q; + reg Q_; + + initial begin + Q_ <= INIT; + end + + always @(posedge C, posedge PRE, posedge CLR) begin + if (CLR == 1) + Q_ <= 0; + else if (PRE == 1) + Q_ <= 1; + else if (T == 1) + Q_ <= ~Q_; + end + + assign Q = Q_; +endmodule + +module FTCP_N (C, PRE, CLR, T, Q); + parameter INIT = 0; + + input C, PRE, CLR, T; + output wire Q; + reg Q_; + + initial begin + Q_ <= INIT; + end + + always @(negedge C, posedge PRE, posedge CLR) begin + if (CLR == 1) + Q_ <= 0; + else if (PRE == 1) + Q_ <= 1; + else if (T == 1) + Q_ <= ~Q_; + end + + assign Q = Q_; +endmodule + +module FTDCP (C, PRE, CLR, T, Q); + parameter INIT = 0; + + input C, PRE, CLR, T; + output wire Q; + reg Q_; + + initial begin + Q_ <= INIT; + end + + always @(posedge C, negedge C, posedge PRE, posedge CLR) begin + if (CLR == 1) + Q_ <= 0; + else if (PRE == 1) + Q_ <= 1; + else if (T == 1) + Q_ <= ~Q_; + end + + assign Q = Q_; +endmodule -- cgit v1.2.3