From 2a56dda5a4fad71434b4602a41c64156639e9793 Mon Sep 17 00:00:00 2001 From: Karol Gugala Date: Wed, 10 Mar 2021 13:45:28 +0100 Subject: [PATCH] Add qlf_k4n8 plugin Signed-off-by: Karol Gugala --- Makefile | 2 +- Makefile_plugin.common | 1 + ql-qlf-k4n8-plugin/Makefile | 10 + ql-qlf-k4n8-plugin/cells_sim.v | 24 ++ ql-qlf-k4n8-plugin/qlf_k4n8_arith_map.v | 135 ++++++++++ ql-qlf-k4n8-plugin/qlf_k4n8_cells_sim.v | 70 +++++ ql-qlf-k4n8-plugin/synth_quicklogic.cc | 250 ++++++++++++++++++ ql-qlf-k4n8-plugin/tests/Makefile | 13 + ql-qlf-k4n8-plugin/tests/dffs/dffs.tcl | 29 ++ ql-qlf-k4n8-plugin/tests/dffs/dffs.v | 24 ++ .../tests/iob_no_flatten/iob_no_flatten.tcl | 10 + .../tests/iob_no_flatten/iob_no_flatten.v | 28 ++ .../tests/iob_no_flatten/iob_no_flatten.ys | 6 + ql-qlf-k4n8-plugin/tests/latches/latches.tcl | 20 ++ ql-qlf-k4n8-plugin/tests/latches/latches.v | 22 ++ ql-qlf-k4n8-plugin/tests/logic/logic.tcl | 13 + ql-qlf-k4n8-plugin/tests/logic/logic.v | 16 ++ ql-qlf-k4n8-plugin/tests/logic/logic.ys | 9 + .../tests/ql_qlf_k4n8/run-test.sh | 20 ++ .../tests/soft_adder/soft_adder.tcl | 17 ++ .../tests/soft_adder/soft_adder.v | 21 ++ 21 files changed, 739 insertions(+), 1 deletion(-) create mode 100644 ql-qlf-k4n8-plugin/Makefile create mode 100644 ql-qlf-k4n8-plugin/cells_sim.v create mode 100644 ql-qlf-k4n8-plugin/qlf_k4n8_arith_map.v create mode 100644 ql-qlf-k4n8-plugin/qlf_k4n8_cells_sim.v create mode 100644 ql-qlf-k4n8-plugin/synth_quicklogic.cc create mode 100644 ql-qlf-k4n8-plugin/tests/Makefile create mode 100644 ql-qlf-k4n8-plugin/tests/dffs/dffs.tcl create mode 100644 ql-qlf-k4n8-plugin/tests/dffs/dffs.v create mode 100644 ql-qlf-k4n8-plugin/tests/iob_no_flatten/iob_no_flatten.tcl create mode 100644 ql-qlf-k4n8-plugin/tests/iob_no_flatten/iob_no_flatten.v create mode 100644 ql-qlf-k4n8-plugin/tests/iob_no_flatten/iob_no_flatten.ys create mode 100644 ql-qlf-k4n8-plugin/tests/latches/latches.tcl create mode 100644 ql-qlf-k4n8-plugin/tests/latches/latches.v create mode 100644 ql-qlf-k4n8-plugin/tests/logic/logic.tcl create mode 100644 ql-qlf-k4n8-plugin/tests/logic/logic.v create mode 100644 ql-qlf-k4n8-plugin/tests/logic/logic.ys create mode 100755 ql-qlf-k4n8-plugin/tests/ql_qlf_k4n8/run-test.sh create mode 100644 ql-qlf-k4n8-plugin/tests/soft_adder/soft_adder.tcl create mode 100644 ql-qlf-k4n8-plugin/tests/soft_adder/soft_adder.v diff --git a/Makefile b/Makefile index bc0edc9ad..41d358ae7 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PLUGIN_LIST := fasm xdc params sdc ql-iob design_introspection integrateinv +PLUGIN_LIST := fasm xdc params sdc ql-iob design_introspection integrateinv ql-qlf-k4n8 PLUGINS := $(foreach plugin,$(PLUGIN_LIST),$(plugin).so) PLUGINS_INSTALL := $(foreach plugin,$(PLUGIN_LIST),install_$(plugin)) PLUGINS_CLEAN := $(foreach plugin,$(PLUGIN_LIST),clean_$(plugin)) diff --git a/Makefile_plugin.common b/Makefile_plugin.common index 06f2c61fb..053a79f82 100644 --- a/Makefile_plugin.common +++ b/Makefile_plugin.common @@ -41,6 +41,7 @@ CXXFLAGS = $(shell yosys-config --cxxflags) #-DSDC_DEBUG LDFLAGS = $(shell yosys-config --ldflags) LDLIBS = $(shell yosys-config --ldlibs) PLUGINS_DIR = $(shell yosys-config --datdir)/plugins +DATA_DIR = $(shell yosys-config --datdir) OBJS := $(SOURCES:cc=o) diff --git a/ql-qlf-k4n8-plugin/Makefile b/ql-qlf-k4n8-plugin/Makefile new file mode 100644 index 000000000..bf201eb64 --- /dev/null +++ b/ql-qlf-k4n8-plugin/Makefile @@ -0,0 +1,10 @@ +NAME = ql-qlf-k4n8 +SOURCES = synth_quicklogic.cc +include ../Makefile_plugin.common + +VERILOG_MODULES = cells_sim.v qlf_k4n8_arith_map.v qlf_k4n8_cells_sim.v + +install_modules: $(VERILOG_MODULES) + $(foreach f,$^,install -D $(f) $(DATA_DIR)/quicklogic/$(f);) + +install: install_modules diff --git a/ql-qlf-k4n8-plugin/cells_sim.v b/ql-qlf-k4n8-plugin/cells_sim.v new file mode 100644 index 000000000..4c17762eb --- /dev/null +++ b/ql-qlf-k4n8-plugin/cells_sim.v @@ -0,0 +1,24 @@ + +module inv(output Q, input A); + assign Q = A ? 0 : 1; +endmodule + +module buff(output Q, input A); + assign Q = A; +endmodule + +module logic_0(output a); + assign a = 0; +endmodule + +module logic_1(output a); + assign a = 1; +endmodule + +(* blackbox *) +module gclkbuff (input A, output Z); + +assign Z = A; + +endmodule + diff --git a/ql-qlf-k4n8-plugin/qlf_k4n8_arith_map.v b/ql-qlf-k4n8-plugin/qlf_k4n8_arith_map.v new file mode 100644 index 000000000..5cbfdc791 --- /dev/null +++ b/ql-qlf-k4n8-plugin/qlf_k4n8_arith_map.v @@ -0,0 +1,135 @@ +(* techmap_celltype = "$alu" *) +module _80_quicklogic_alu (A, B, CI, BI, X, Y, CO); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + parameter _TECHMAP_CONSTMSK_CI_ = 0; + parameter _TECHMAP_CONSTVAL_CI_ = 0; + + (* force_downto *) + input [A_WIDTH-1:0] A; + (* force_downto *) + input [B_WIDTH-1:0] B; + (* force_downto *) + output [Y_WIDTH-1:0] X, Y; + + input CI, BI; + (* force_downto *) + output [Y_WIDTH-1:0] CO; + + wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; + + (* force_downto *) + wire [Y_WIDTH-1:0] A_buf, B_buf; + \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); + \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + + (* force_downto *) + wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) + wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + (* force_downto *) + wire [Y_WIDTH-1:0] C; + + assign CO = C[Y_WIDTH-1]; + + genvar i; + generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice + + wire ci; + wire co; + + // First in chain + generate if (i == 0) begin + + // CI connected to a constant + if (_TECHMAP_CONSTMSK_CI_ == 1) begin + + localparam INIT = (_TECHMAP_CONSTVAL_CI_ == 0) ? + 16'b0110_0000_0000_0001 : + 16'b1001_0000_0000_0111; + + // LUT4 configured as 1-bit adder with CI=const + adder_lut4 #( + .LUT(INIT), + .IN2_IS_CIN(1'b0) + ) lut_ci_adder ( + .in({AA[i], BB[i], 1'b0, 1'b0}), + .cin(), + .lut4_out(Y[i]), + .cout(ci) + ); + + // CI connected to a non-const driver + end else begin + + // LUT4 configured as passthrough to drive CI of the next stage + adder_lut4 #( + .LUT(16'b1100_0000_0000_0011), + .IN2_IS_CIN(1'b0) + ) lut_ci ( + .in({1'b0,CI,1'b0,1'b0}), + .cin(), + .lut4_out(), + .cout(ci) + ); + end + + // Not first in chain + end else begin + assign ci = C[i-1]; + + end endgenerate + + // .................................................... + + // Single 1-bit adder, mid-chain adder or non-const CI + // adder + generate if ((i == 0 && _TECHMAP_CONSTMSK_CI_ == 0) || (i > 0)) begin + + // LUT4 configured as full 1-bit adder + adder_lut4 #( + .LUT(16'b0110_1001_0110_0001), + .IN2_IS_CIN(1'b1) + ) lut_adder ( + .in({AA[i], BB[i], 1'b0, 1'b0}), + .cin(ci), + .lut4_out(Y[i]), + .cout(co) + ); + end else begin + assign co = ci; + + end endgenerate + + // .................................................... + + // Last in chain + generate if (i == Y_WIDTH-1) begin + + // LUT4 configured for passing its CI input to output. This should + // get pruned if the actual CO port is not connected anywhere. + adder_lut4 #( + .LUT(16'b0000_1111_0000_1111), + .IN2_IS_CIN(1'b1) + ) lut_co ( + .in({1'b0, co, 1'b0, 1'b0}), + .cin(co), + .lut4_out(C[i]), + .cout() + ); + // Not last in chain + end else begin + assign C[i] = co; + + end endgenerate + + end: slice + endgenerate + + /* End implementation */ + assign X = AA ^ BB; +endmodule diff --git a/ql-qlf-k4n8-plugin/qlf_k4n8_cells_sim.v b/ql-qlf-k4n8-plugin/qlf_k4n8_cells_sim.v new file mode 100644 index 000000000..a66a88d67 --- /dev/null +++ b/ql-qlf-k4n8-plugin/qlf_k4n8_cells_sim.v @@ -0,0 +1,70 @@ +(* abc9_box, lib_whitebox *) +module adder_lut4( + output lut4_out, + (* abc9_carry *) + output cout, + input [0:3] in, + (* abc9_carry *) + input cin +); + parameter [0:15] LUT=0; + parameter IN2_IS_CIN = 0; + + wire [0:3] li = (IN2_IS_CIN) ? {in[0], in[1], cin, in[3]} : {in[0], in[1], in[2], in[3]}; + + // Output function + wire [0:7] s1 = li[0] ? + {LUT[1], LUT[3], LUT[5], LUT[7], LUT[9], LUT[11], LUT[13], LUT[15]}: + {LUT[0], LUT[2], LUT[4], LUT[6], LUT[8], LUT[10], LUT[12], LUT[14]}; + + wire [0:3] s2 = li[1] ? {s1[1], s1[3], s1[5], s1[7]} : + {s1[0], s1[2], s1[4], s1[6]}; + + wire [0:1] s3 = li[2] ? {s2[1], s2[3]} : {s2[0], s2[2]}; + + assign lut4_out = li[3] ? s3[1] : s3[0]; + + // Carry out function + assign cout = (s2[2]) ? cin : s2[3]; +endmodule + +(* abc9_lut=1, lib_whitebox *) +module frac_lut4( + input [0:3] in, + output [0:1] lut2_out, + output lut4_out +); + parameter [0:15] LUT = 0; + + // Effective LUT input + wire [0:3] li = in; + + // Output function + wire [0:7] s1 = li[0] ? + {LUT[1], LUT[3], LUT[5], LUT[7], LUT[9], LUT[11], LUT[13], LUT[15]}: + {LUT[0], LUT[2], LUT[4], LUT[6], LUT[8], LUT[10], LUT[12], LUT[14]}; + + wire [0:3] s2 = li[1] ? {s1[1], s1[3], s1[5], s1[7]} : + {s1[0], s1[2], s1[4], s1[6]}; + + wire [0:1] s3 = li[2] ? {s2[1], s2[3]} : {s2[0], s2[2]}; + + assign lut2_out[0] = s2[2]; + assign lut2_out[1] = s2[3]; + + assign lut4_out = li[3] ? s3[1] : s3[0]; + +endmodule + +(* abc9_flop, lib_whitebox *) +module scff( + output reg Q, + input D, + input clk +); + parameter [0:0] INIT = 1'b0; + initial Q = INIT; + + always @(posedge clk) + Q <= D; +endmodule diff --git a/ql-qlf-k4n8-plugin/synth_quicklogic.cc b/ql-qlf-k4n8-plugin/synth_quicklogic.cc new file mode 100644 index 000000000..b7909e409 --- /dev/null +++ b/ql-qlf-k4n8-plugin/synth_quicklogic.cc @@ -0,0 +1,250 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2021 Lalit Sharma + * + * 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/celltypes.h" +#include "kernel/log.h" +#include "kernel/register.h" +#include "kernel/rtlil.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct SynthQuickLogicPass : public ScriptPass { + + SynthQuickLogicPass() : ScriptPass("synth_quicklogic", "Synthesis for QuickLogic FPGAs") {} + + void help() override + { + log("\n"); + log(" synth_quicklogic [options]\n"); + log("This command runs synthesis for QuickLogic FPGAs\n"); + log("\n"); + log(" -top \n"); + log(" use the specified module as top module\n"); + log("\n"); + log(" -family \n"); + log(" run synthesis for the specified QuickLogic architecture\n"); + log(" generate the synthesis netlist for the specified family.\n"); + log(" supported values:\n"); + log(" - qlf_k4n8: qlf_k4n8 \n"); + log("\n"); + log(" -no_abc_opt\n"); + log(" By default most of ABC logic optimization features is\n"); + log(" enabled. Specifying this switch turns them off.\n"); + log("\n"); + log(" -edif \n"); + log(" write the design to the specified edif file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -blif \n"); + log(" write the design to the specified BLIF file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -verilog \n"); + log(" write the design to the specified verilog file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -no_adder\n"); + log(" By default use adder cells in output netlist.\n"); + log(" Specifying this switch turns it off.\n"); + log("\n"); + log("\n"); + log("The following commands are executed by this synthesis command:\n"); + help_script(); + log("\n"); + } + + string top_opt, edif_file, blif_file, family, currmodule, verilog_file; + bool inferAdder; + bool abcOpt; + + void clear_flags() override + { + top_opt = "-auto-top"; + edif_file = ""; + blif_file = ""; + verilog_file = ""; + currmodule = ""; + family = "qlf_k4n8"; + inferAdder = true; + abcOpt = true; + } + + void execute(std::vector args, RTLIL::Design *design) 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] == "-edif" && argidx + 1 < args.size()) { + edif_file = args[++argidx]; + continue; + } + + if (args[argidx] == "-family" && argidx + 1 < args.size()) { + family = args[++argidx]; + continue; + } + if (args[argidx] == "-blif" && argidx + 1 < args.size()) { + blif_file = args[++argidx]; + continue; + } + if (args[argidx] == "-verilog" && argidx + 1 < args.size()) { + verilog_file = args[++argidx]; + continue; + } + if (args[argidx] == "-no_adder") { + inferAdder = false; + continue; + } + if (args[argidx] == "-no_abc_opt") { + abcOpt = false; + continue; + } + + break; + } + extra_args(args, argidx, design); + + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + + log_header(design, "Executing SYNTH_QUICKLOGIC pass.\n"); + log_push(); + + run_script(design, run_from, run_to); + + log_pop(); + } + + void script() override + { + if (check_label("begin")) { + std::string readVelArgs; + readVelArgs = " +/quicklogic/" + family + "_cells_sim.v"; + + run("read_verilog -lib -specify +/quicklogic/cells_sim.v" + readVelArgs); + run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt.c_str())); + } + + if (check_label("prepare")) { + run("proc"); + run("flatten"); + run("opt_expr"); + run("opt_clean"); + run("deminout"); + run("opt"); + } + + if (check_label("coarse")) { + run("opt_expr"); + run("opt_clean"); + run("check"); + run("opt"); + run("wreduce -keepdc"); + run("peepopt"); + run("pmuxtree"); + run("opt_clean"); + + run("alumacc"); + run("opt"); + run("fsm"); + run("opt -fast"); + run("memory -nomap"); + run("opt_clean"); + } + + if (check_label("map_ffram")) { + run("opt -fast -mux_undef -undriven -fine"); + run("memory_map -iattr -attr !ram_block -attr !rom_block -attr logic_block " + "-attr syn_ramstyle=auto -attr syn_ramstyle=registers " + "-attr syn_romstyle=auto -attr syn_romstyle=logic"); + run("opt -undriven -fine"); + } + + if (check_label("map_gates")) { + if (inferAdder) { + run("techmap -map +/techmap.v -map +/quicklogic/" + family + "_arith_map.v"); + } else { + run("techmap"); + } + run("opt -fast"); + run("opt_expr"); + run("opt_merge"); + run("opt_clean"); + run("opt"); + } + + if (check_label("map_ffs")) { + + run("opt_expr -mux_undef"); + run("simplemap"); + run("opt_expr"); + run("opt_merge"); + run("opt_clean"); + run("opt"); + } + + if (check_label("map_luts")) { + run("abc -lut 4 "); + run("clean"); + run("opt_lut"); + } + + if (check_label("check")) { + run("autoname"); + run("hierarchy -check"); + run("stat"); + run("check -noinit"); + } + + if (check_label("finalize")) { + run("check"); + run("opt_clean -purge"); + } + + if (check_label("edif")) { + if (!edif_file.empty()) + run(stringf("write_edif -nogndvcc -attrprop -pvector par %s %s", this->currmodule.c_str(), edif_file.c_str())); + } + + if (check_label("blif")) { + if (!blif_file.empty()) { + if (inferAdder) { + run(stringf("write_blif -param %s", help_mode ? "" : blif_file.c_str())); + } else { + run(stringf("write_blif %s", help_mode ? "" : blif_file.c_str())); + } + } + } + + if (check_label("verilog")) { + if (!verilog_file.empty()) { + run("write_verilog -noattr -nohex " + verilog_file); + } + } + } + +} SynthQuicklogicPass; + +PRIVATE_NAMESPACE_END diff --git a/ql-qlf-k4n8-plugin/tests/Makefile b/ql-qlf-k4n8-plugin/tests/Makefile new file mode 100644 index 000000000..b0c98f8ca --- /dev/null +++ b/ql-qlf-k4n8-plugin/tests/Makefile @@ -0,0 +1,13 @@ +TESTS = dffs \ + iob_no_flatten \ + latches \ + soft_adder \ + logic + +include $(shell pwd)/../../Makefile_test.common + +dffs_verify = true +iob_no_flatten_verify = true +latches_verify = true +soft_adder_verify = true +logic_verify = true diff --git a/ql-qlf-k4n8-plugin/tests/dffs/dffs.tcl b/ql-qlf-k4n8-plugin/tests/dffs/dffs.tcl new file mode 100644 index 000000000..ba968b773 --- /dev/null +++ b/ql-qlf-k4n8-plugin/tests/dffs/dffs.tcl @@ -0,0 +1,29 @@ +yosys -import +if { [info procs ql-qlf-k4n8] == {} } { plugin -i ql-qlf-k4n8 } +yosys -import ;# ingest plugin commands + +read_verilog dffs.v +design -save read + +# DFF +hierarchy -top my_dff +yosys proc +equiv_opt -assert -map +/quicklogic/qlf_k4n8_cells_sim.v synth_quicklogic -top my_dff +design -load postopt +yosys cd my_dff +stat +select -assert-count 1 t:*_DFF_P_ + +# DFFC +design -load read +synth_quicklogic -top my_dffc +yosys cd my_dffc +stat +select -assert-count 1 t:*DFF_P* + +# DFFP +design -load read +synth_quicklogic -top my_dffp +yosys cd my_dffp +stat +select -assert-count 1 t:*DFF_P* diff --git a/ql-qlf-k4n8-plugin/tests/dffs/dffs.v b/ql-qlf-k4n8-plugin/tests/dffs/dffs.v new file mode 100644 index 000000000..32f02b63e --- /dev/null +++ b/ql-qlf-k4n8-plugin/tests/dffs/dffs.v @@ -0,0 +1,24 @@ +module my_dff ( input d, clk, output reg q ); + initial q <= 1'b0; + always @( posedge clk ) + q <= d; +endmodule + +module my_dffc ( input d, clk, clr, output reg q ); + initial q <= 1'b0; + always @( posedge clk or posedge clr ) + if ( clr ) + q <= 1'b0; + else + q <= d; +endmodule + +module my_dffp ( input d, clk, pre, output reg q ); + initial q <= 1'b0; + always @( posedge clk or posedge pre ) + if ( pre ) + q <= 1'b1; + else + q <= d; +endmodule + diff --git a/ql-qlf-k4n8-plugin/tests/iob_no_flatten/iob_no_flatten.tcl b/ql-qlf-k4n8-plugin/tests/iob_no_flatten/iob_no_flatten.tcl new file mode 100644 index 000000000..d9b0fa039 --- /dev/null +++ b/ql-qlf-k4n8-plugin/tests/iob_no_flatten/iob_no_flatten.tcl @@ -0,0 +1,10 @@ +yosys -import +if { [info procs ql-qlf-k4n8] == {} } { plugin -i ql-qlf-k4n8 } +yosys -import ;# ingest plugin commands + +read_verilog iob_no_flatten.v + +synth_quicklogic -top my_top +yosys stat +yosys cd my_top +select -assert-count 2 t:\$_DFF_P_ diff --git a/ql-qlf-k4n8-plugin/tests/iob_no_flatten/iob_no_flatten.v b/ql-qlf-k4n8-plugin/tests/iob_no_flatten/iob_no_flatten.v new file mode 100644 index 000000000..ce713a7ce --- /dev/null +++ b/ql-qlf-k4n8-plugin/tests/iob_no_flatten/iob_no_flatten.v @@ -0,0 +1,28 @@ +module my_dff ( input d, clk, output reg q ); + initial q <= 1'b0; + always @( posedge clk ) + q <= d; +endmodule + +module my_top ( + inout wire pad, + input wire i, + input wire t, + output wire o, + input wire clk +); + + wire i_r; + wire t_r; + wire o_r; + + // IOB + assign pad = (t_r) ? i_r : 1'bz; + assign o_r = pad; + + // DFFs + my_dff dff_i (i, clk, i_r); + my_dff dff_t (t, clk, t_r); + my_dff dff_o (o_r, clk, o); + +endmodule diff --git a/ql-qlf-k4n8-plugin/tests/iob_no_flatten/iob_no_flatten.ys b/ql-qlf-k4n8-plugin/tests/iob_no_flatten/iob_no_flatten.ys new file mode 100644 index 000000000..4530a8d72 --- /dev/null +++ b/ql-qlf-k4n8-plugin/tests/iob_no_flatten/iob_no_flatten.ys @@ -0,0 +1,6 @@ +read_verilog v/iob_no_flatten.v + +synth_quicklogic -top my_top +stat +cd my_top +select -assert-count 2 t:$_DFF_P_ diff --git a/ql-qlf-k4n8-plugin/tests/latches/latches.tcl b/ql-qlf-k4n8-plugin/tests/latches/latches.tcl new file mode 100644 index 000000000..7816461c6 --- /dev/null +++ b/ql-qlf-k4n8-plugin/tests/latches/latches.tcl @@ -0,0 +1,20 @@ +yosys -import +if { [info procs ql-qlf-k4n8] == {} } { plugin -i ql-qlf-k4n8 } +yosys -import ;# ingest plugin commands + +read_verilog latches.v +design -save read + +# LATCHP +synth_quicklogic -top latchp +yosys cd latchp +stat +select -assert-count 1 t:\$_DLATCH_P_ + +# LATCHN +design -load read +synth_quicklogic -top latchn +yosys cd latchn +stat +select -assert-count 1 t:\$_DLATCH_N_ + diff --git a/ql-qlf-k4n8-plugin/tests/latches/latches.v b/ql-qlf-k4n8-plugin/tests/latches/latches.v new file mode 100644 index 000000000..1485ffb99 --- /dev/null +++ b/ql-qlf-k4n8-plugin/tests/latches/latches.v @@ -0,0 +1,22 @@ +module latchp ( input d, clk, en, output reg q ); + initial q <= 1'b0; + always @* + if ( en ) + q <= d; +endmodule + +module latchn ( input d, clk, en, output reg q ); + always @* + if ( !en ) + q <= d; +endmodule + +module latchsr ( input d, clk, en, clr, pre, output reg q ); + always @* + if ( clr ) + q <= 1'b0; + else if ( pre ) + q <= 1'b1; + else if ( en ) + q <= d; +endmodule diff --git a/ql-qlf-k4n8-plugin/tests/logic/logic.tcl b/ql-qlf-k4n8-plugin/tests/logic/logic.tcl new file mode 100644 index 000000000..6db75e89f --- /dev/null +++ b/ql-qlf-k4n8-plugin/tests/logic/logic.tcl @@ -0,0 +1,13 @@ +yosys -import +if { [info procs ql-qlf-k4n8] == {} } { plugin -i ql-qlf-k4n8 } +yosys -import ;# ingest plugin commands + +read_verilog logic.v +hierarchy -top top +yosys proc +equiv_opt -assert -map +/quicklogic/qlf_k4n8_cells_sim.v synth_quicklogic +design -load postopt +yosys cd top + +stat +select -assert-count 9 t:\$lut diff --git a/ql-qlf-k4n8-plugin/tests/logic/logic.v b/ql-qlf-k4n8-plugin/tests/logic/logic.v new file mode 100644 index 000000000..c17899fa0 --- /dev/null +++ b/ql-qlf-k4n8-plugin/tests/logic/logic.v @@ -0,0 +1,16 @@ +module top +( + input [0:7] in, + output B1,B2,B3,B4,B5,B6,B7,B8,B9,B10 +); + assign B1 = in[0] & in[1]; + assign B2 = in[0] | in[1]; + assign B3 = in[0] ~& in[1]; + assign B4 = in[0] ~| in[1]; + assign B5 = in[0] ^ in[1]; + assign B6 = in[0] ~^ in[1]; + assign B7 = ~in[0]; + assign B8 = in[0]; + assign B9 = in[0:1] && in [2:3]; + assign B10 = in[0:1] || in [2:3]; +endmodule diff --git a/ql-qlf-k4n8-plugin/tests/logic/logic.ys b/ql-qlf-k4n8-plugin/tests/logic/logic.ys new file mode 100644 index 000000000..ae40af153 --- /dev/null +++ b/ql-qlf-k4n8-plugin/tests/logic/logic.ys @@ -0,0 +1,9 @@ +read_verilog ../common/logic.v +hierarchy -top top +proc +equiv_opt -assert -map +/quicklogic/qlf_k4n8_cells_sim.v synth_quicklogic +design -load postopt +cd top + +stat +select -assert-count 9 t:$lut diff --git a/ql-qlf-k4n8-plugin/tests/ql_qlf_k4n8/run-test.sh b/ql-qlf-k4n8-plugin/tests/ql_qlf_k4n8/run-test.sh new file mode 100755 index 000000000..bf19b887d --- /dev/null +++ b/ql-qlf-k4n8-plugin/tests/ql_qlf_k4n8/run-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -e +{ +echo "all::" +for x in *.ys; do + echo "all:: run-$x" + echo "run-$x:" + echo " @echo 'Running $x..'" + echo " @../../../yosys -ql ${x%.ys}.log -w 'Yosys has only limited support for tri-state logic at the moment.' $x" +done +for s in *.sh; do + if [ "$s" != "run-test.sh" ]; then + echo "all:: run-$s" + echo "run-$s:" + echo " @echo 'Running $s..'" + echo " @bash $s" + fi +done +} > run-test.mk +exec ${MAKE:-make} -f run-test.mk diff --git a/ql-qlf-k4n8-plugin/tests/soft_adder/soft_adder.tcl b/ql-qlf-k4n8-plugin/tests/soft_adder/soft_adder.tcl new file mode 100644 index 000000000..7f5466546 --- /dev/null +++ b/ql-qlf-k4n8-plugin/tests/soft_adder/soft_adder.tcl @@ -0,0 +1,17 @@ +yosys -import +if { [info procs ql-qlf-k4n8] == {} } { plugin -i ql-qlf-k4n8 } +yosys -import ;# ingest plugin commands + +# Equivalence check for adder synthesis +read_verilog -icells -DWIDTH=4 soft_adder.v +hierarchy -check -top adder +yosys proc +equiv_opt -assert -map +/quicklogic/qlf_k4n8_cells_sim.v synth_quicklogic -family qlf_k4n8 + +design -reset + +# Equivalence check for subtractor synthesis +read_verilog -icells -DWIDTH=4 soft_adder.v +hierarchy -check -top subtractor +yosys proc +equiv_opt -assert -map +/quicklogic/qlf_k4n8_cells_sim.v synth_quicklogic -family qlf_k4n8 diff --git a/ql-qlf-k4n8-plugin/tests/soft_adder/soft_adder.v b/ql-qlf-k4n8-plugin/tests/soft_adder/soft_adder.v new file mode 100644 index 000000000..124341de4 --- /dev/null +++ b/ql-qlf-k4n8-plugin/tests/soft_adder/soft_adder.v @@ -0,0 +1,21 @@ +module adder ( + input wire [`WIDTH-1:0] A, + input wire [`WIDTH-1:0] B, + output wire [`WIDTH :0] S, +); + + // Implicit adder + assign S = A + B; + +endmodule + +module subtractor ( + input wire [`WIDTH-1:0] A, + input wire [`WIDTH-1:0] B, + output wire [`WIDTH :0] S, +); + + // Implicit subtractor + assign S = A - B; + +endmodule