diff options
-rw-r--r-- | passes/opt/opt_expr.cc | 8 | ||||
-rw-r--r-- | passes/techmap/abc9.cc | 2 | ||||
-rw-r--r-- | passes/techmap/dfflegalize.cc | 2 | ||||
-rw-r--r-- | techlibs/gowin/Makefile.inc | 1 | ||||
-rw-r--r-- | techlibs/gowin/cells_sim.v | 16 | ||||
-rw-r--r-- | techlibs/gowin/determine_init.cc | 72 | ||||
-rw-r--r-- | techlibs/gowin/synth_gowin.cc | 2 | ||||
-rw-r--r-- | techlibs/intel_alm/Makefile.inc | 5 | ||||
-rw-r--r-- | techlibs/intel_alm/common/abc9_map.v | 18 | ||||
-rw-r--r-- | techlibs/intel_alm/common/abc9_model.v | 10 | ||||
-rw-r--r-- | techlibs/intel_alm/common/abc9_unmap.v | 11 | ||||
-rw-r--r-- | techlibs/intel_alm/common/dff_map.v | 123 | ||||
-rw-r--r-- | techlibs/intel_alm/common/dff_sim.v | 41 | ||||
-rw-r--r-- | techlibs/intel_alm/common/dsp_map.v | 49 | ||||
-rw-r--r-- | techlibs/intel_alm/common/dsp_sim.v | 35 | ||||
-rw-r--r-- | techlibs/intel_alm/common/megafunction_bb.v | 28 | ||||
-rw-r--r-- | techlibs/intel_alm/common/mem_sim.v | 10 | ||||
-rw-r--r-- | techlibs/intel_alm/common/quartus_rename.v | 23 | ||||
-rw-r--r-- | techlibs/intel_alm/synth_intel_alm.cc | 90 | ||||
-rw-r--r-- | tests/arch/intel_alm/fsm.ys | 7 | ||||
-rw-r--r-- | tests/arch/intel_alm/mul.ys | 23 | ||||
-rw-r--r-- | tests/opt/bug2221.ys | 16 |
22 files changed, 358 insertions, 234 deletions
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 1051a59f2..649ad83a6 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -1596,6 +1596,14 @@ skip_identity: log_debug("Removing low %d A and %d B bits from cell `%s' in module `%s'.\n", a_zeros, b_zeros, cell->name.c_str(), module->name.c_str()); + if (y_zeros >= GetSize(sig_y)) { + module->connect(sig_y, RTLIL::SigSpec(0, GetSize(sig_y))); + module->remove(cell); + + did_something = true; + goto next_cell; + } + if (a_zeros) { cell->setPort(ID::A, sig_a.extract_end(a_zeros)); cell->parameters[ID::A_WIDTH] = GetSize(sig_a) - a_zeros; diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 127f8934e..e99c56d8d 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -294,7 +294,7 @@ struct Abc9Pass : public ScriptPass run("design -load $abc9_map"); run("proc"); run("wbflip"); - run("techmap"); + run("techmap -wb -map %$abc9 -map +/techmap.v A:abc9_flop"); run("opt"); if (dff_mode || help_mode) { if (!help_mode) diff --git a/passes/techmap/dfflegalize.cc b/passes/techmap/dfflegalize.cc index 7f2cdc6ac..b2fe90702 100644 --- a/passes/techmap/dfflegalize.cc +++ b/passes/techmap/dfflegalize.cc @@ -364,7 +364,7 @@ flip_dqi: // Some DFF is supported with this init val. Just pick a type. if (ff_type == FF_DFF) { // Try adding a set or reset pin. - for (auto new_type: {FF_ADFF0, FF_ADFF1, FF_SDFF0, FF_SDFF1}) + for (auto new_type: {FF_SDFF0, FF_SDFF1, FF_ADFF0, FF_ADFF1}) if (supported_cells[new_type] & initmask) { ff_type = new_type; sig_r = State::S0; diff --git a/techlibs/gowin/Makefile.inc b/techlibs/gowin/Makefile.inc index 0756e3bcf..e6a6be970 100644 --- a/techlibs/gowin/Makefile.inc +++ b/techlibs/gowin/Makefile.inc @@ -1,6 +1,5 @@ OBJS += techlibs/gowin/synth_gowin.o -OBJS += techlibs/gowin/determine_init.o GENFILES += techlibs/gowin/bram_init_16.vh diff --git a/techlibs/gowin/cells_sim.v b/techlibs/gowin/cells_sim.v index a67855dab..da5175975 100644 --- a/techlibs/gowin/cells_sim.v +++ b/techlibs/gowin/cells_sim.v @@ -77,7 +77,7 @@ endmodule // DFFE (positive clock edge; clock enable) module DFFS (output reg Q, input D, CLK, SET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(posedge CLK) begin if (SET) @@ -89,7 +89,7 @@ endmodule // DFFS (positive clock edge; synchronous set) module DFFSE (output reg Q, input D, CLK, CE, SET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(posedge CLK) begin if (SET) @@ -125,7 +125,7 @@ endmodule // DFFRE (positive clock edge; synchronous reset takes precedence over module DFFP (output reg Q, input D, CLK, PRESET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(posedge CLK or posedge PRESET) begin if(PRESET) @@ -137,7 +137,7 @@ endmodule // DFFP (positive clock edge; asynchronous preset) module DFFPE (output reg Q, input D, CLK, CE, PRESET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(posedge CLK or posedge PRESET) begin if(PRESET) @@ -190,7 +190,7 @@ endmodule // DFFNE (negative clock edge; clock enable) module DFFNS (output reg Q, input D, CLK, SET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(negedge CLK) begin if (SET) @@ -202,7 +202,7 @@ endmodule // DFFNS (negative clock edge; synchronous set) module DFFNSE (output reg Q, input D, CLK, CE, SET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(negedge CLK) begin if (SET) @@ -238,7 +238,7 @@ endmodule // DFFNRE (negative clock edge; synchronous reset takes precedence ove module DFFNP (output reg Q, input D, CLK, PRESET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(negedge CLK or posedge PRESET) begin if(PRESET) @@ -250,7 +250,7 @@ endmodule // DFFNP (negative clock edge; asynchronous preset) module DFFNPE (output reg Q, input D, CLK, CE, PRESET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(negedge CLK or posedge PRESET) begin if(PRESET) diff --git a/techlibs/gowin/determine_init.cc b/techlibs/gowin/determine_init.cc deleted file mode 100644 index 15ff115de..000000000 --- a/techlibs/gowin/determine_init.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io> - * - * 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 DetermineInitPass : public Pass { - DetermineInitPass() : Pass("determine_init", "Determine the init value of cells") { } - void help() override - { - log("\n"); - log(" determine_init [selection]\n"); - log("\n"); - log("Determine the init value of cells that doesn't allow unknown init value.\n"); - log("\n"); - } - - Const determine_init(Const init) - { - for (int i = 0; i < GetSize(init); i++) { - if (init[i] != State::S0 && init[i] != State::S1) - init[i] = State::S0; - } - - return init; - } - - void execute(std::vector<std::string> args, RTLIL::Design *design) override - { - log_header(design, "Executing DETERMINE_INIT pass (determine init value for cells).\n"); - - extra_args(args, args.size(), design); - - int cnt = 0; - for (auto module : design->selected_modules()) - { - for (auto cell : module->selected_cells()) - { - if (cell->type == ID(RAM16S4)) - { - cell->setParam(ID(INIT_0), determine_init(cell->getParam(ID(INIT_0)))); - cell->setParam(ID(INIT_1), determine_init(cell->getParam(ID(INIT_1)))); - cell->setParam(ID(INIT_2), determine_init(cell->getParam(ID(INIT_2)))); - cell->setParam(ID(INIT_3), determine_init(cell->getParam(ID(INIT_3)))); - cnt++; - } - } - } - log_header(design, "Updated %d cells with determined init value.\n", cnt); - } -} DetermineInitPass; - -PRIVATE_NAMESPACE_END diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 32d9cc0a5..1e82e1ed6 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -198,7 +198,7 @@ struct SynthGowinPass : public ScriptPass { run("memory_bram -rules +/gowin/lutrams.txt"); run("techmap -map +/gowin/lutrams_map.v"); - run("determine_init"); + run("setundef -params -zero t:RAM16S4"); } if (check_label("map_ffram")) diff --git a/techlibs/intel_alm/Makefile.inc b/techlibs/intel_alm/Makefile.inc index ed6c4510b..552f00c65 100644 --- a/techlibs/intel_alm/Makefile.inc +++ b/techlibs/intel_alm/Makefile.inc @@ -2,11 +2,16 @@ OBJS += techlibs/intel_alm/synth_intel_alm.o # Techmap +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/abc9_map.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/abc9_unmap.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/abc9_model.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/alm_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/alm_sim.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/arith_alm_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_sim.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dsp_sim.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dsp_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/mem_sim.v)) # RAM diff --git a/techlibs/intel_alm/common/abc9_map.v b/techlibs/intel_alm/common/abc9_map.v new file mode 100644 index 000000000..9d11bb240 --- /dev/null +++ b/techlibs/intel_alm/common/abc9_map.v @@ -0,0 +1,18 @@ +// This file exists to map purely-synchronous flops to ABC9 flops, while +// mapping flops with asynchronous-clear as boxes, this is because ABC9 +// doesn't support asynchronous-clear flops in sequential synthesis. + +module MISTRAL_FF( + input DATAIN, CLK, ACLR, ENA, SCLR, SLOAD, SDATA, + output reg Q +); + +parameter _TECHMAP_CONSTMSK_ACLR_ = 1'b0; + +// If the async-clear is constant, we assume it's disabled. +if (_TECHMAP_CONSTMSK_ACLR_ != 1'b0) + $__MISTRAL_FF_SYNCONLY _TECHMAP_REPLACE_ (.DATAIN(DATAIN), .CLK(CLK), .ENA(ENA), .SCLR(SCLR), .SLOAD(SLOAD), .SDATA(SDATA), .Q(Q)); +else + wire _TECHMAP_FAIL_ = 1; + +endmodule diff --git a/techlibs/intel_alm/common/abc9_model.v b/techlibs/intel_alm/common/abc9_model.v new file mode 100644 index 000000000..8f06d3835 --- /dev/null +++ b/techlibs/intel_alm/common/abc9_model.v @@ -0,0 +1,10 @@ +// This is a purely-synchronous flop, that ABC9 can use for sequential synthesis. +(* abc9_flop, lib_whitebox *) +module $__MISTRAL_FF_SYNCONLY ( + input DATAIN, CLK, ENA, SCLR, SLOAD, SDATA, + output reg Q +); + +MISTRAL_FF ff (.DATAIN(DATAIN), .CLK(CLK), .ENA(ENA), .ACLR(1'b1), .SCLR(SCLR), .SLOAD(SLOAD), .SDATA(SDATA), .Q(Q)); + +endmodule diff --git a/techlibs/intel_alm/common/abc9_unmap.v b/techlibs/intel_alm/common/abc9_unmap.v new file mode 100644 index 000000000..4b28866a3 --- /dev/null +++ b/techlibs/intel_alm/common/abc9_unmap.v @@ -0,0 +1,11 @@ +// After performing sequential synthesis, map the synchronous flops back to +// standard MISTRAL_FF flops. + +module $__MISTRAL_FF_SYNCONLY ( + input DATAIN, CLK, ENA, SCLR, SLOAD, SDATA, + output reg Q +); + +MISTRAL_FF _TECHMAP_REPLACE_ (.DATAIN(DATAIN), .CLK(CLK), .ACLR(1'b1), .ENA(ENA), .SCLR(SCLR), .SLOAD(SLOAD), .SDATA(SDATA), .Q(Q)); + +endmodule diff --git a/techlibs/intel_alm/common/dff_map.v b/techlibs/intel_alm/common/dff_map.v index 962be670c..1a4b5d65a 100644 --- a/techlibs/intel_alm/common/dff_map.v +++ b/techlibs/intel_alm/common/dff_map.v @@ -1,124 +1,13 @@ `default_nettype none -// D flip-flops -module \$_DFF_P_ (input D, C, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin +// D flip-flop with async reset and enable +module \$_DFFE_PN0P_ (input D, C, R, E, output Q); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop that initialises to one"); + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(R), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); endmodule -module \$_DFF_N_ (input D, C, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin +// D flip-flop with sync reset and enable (enable has priority) +module \$_SDFFCE_PP0P_ (input D, C, R, E, output Q); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop that initialises to one"); -endmodule - -// D flip-flops with reset -module \$_DFF_PP0_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with reset that initialises to one"); -endmodule - -module \$_DFF_PN0_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with reset that initialises to one"); -endmodule - -module \$_DFF_NP0_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with reset that initialises to one"); -endmodule - -module \$_DFF_NN0_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with reset that initialises to one"); -endmodule - -// D flip-flops with set -module \$_DFF_PP1_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b1; -if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - wire Q_tmp; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); - assign Q = ~Q_tmp; -end else $error("Cannot implement a flip-flop with set that initialises to zero"); -endmodule - -module \$_DFF_PN1_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b1; -if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - wire Q_tmp; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); -end else $error("Cannot implement a flip-flop with set that initialises to zero"); -endmodule - -module \$_DFF_NP1_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b1; -if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - wire Q_tmp; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(~C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); - assign Q = ~Q_tmp; -end else $error("Cannot implement a flip-flop with set that initialises to zero"); -endmodule - -module \$_DFF_NN1_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b1; -if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - wire Q_tmp; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(~C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); - assign Q = ~Q_tmp; -end else $error("Cannot implement a flip-flop with set that initialises to zero"); -endmodule - -// D flip-flops with clock enable -module \$_DFFE_PP_ (input D, C, E, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with enable that initialises to one"); -endmodule - -module \$_DFFE_PN_ (input D, C, E, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(~E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with enable that initialises to one"); -endmodule - -module \$_DFFE_NP_ (input D, C, E, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with enable that initialises to one"); -endmodule - -module \$_DFFE_NN_ (input D, C, E, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(~E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with enable that initialises to one"); + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(E), .SCLR(R), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); endmodule diff --git a/techlibs/intel_alm/common/dff_sim.v b/techlibs/intel_alm/common/dff_sim.v index 32444dd46..9ff8f9f67 100644 --- a/techlibs/intel_alm/common/dff_sim.v +++ b/techlibs/intel_alm/common/dff_sim.v @@ -53,23 +53,44 @@ // Q: data output // // Note: the DFFEAS primitive is mostly emulated; it does not reflect what the hardware implements. + +`ifdef cyclonev +`define SYNCPATH 262 +`define SYNCSETUP 522 +`define COMBPATH 0 +`endif +`ifdef cyclone10gx +`define SYNCPATH 219 +`define SYNCSETUP 268 +`define COMBPATH 0 +`endif + +// fallback for when a family isn't detected (e.g. when techmapping for equivalence) +`ifndef SYNCPATH +`define SYNCPATH 0 +`define SYNCSETUP 0 +`define COMBPATH 0 +`endif + +(* abc9_box, lib_whitebox *) module MISTRAL_FF( input DATAIN, CLK, ACLR, ENA, SCLR, SLOAD, SDATA, output reg Q ); -`ifdef cyclonev -specify - (posedge CLK => (Q : DATAIN)) = 262; - $setup(DATAIN, posedge CLK, 522); -endspecify -`endif -`ifdef cyclone10gx specify - (posedge CLK => (Q : DATAIN)) = 219; - $setup(DATAIN, posedge CLK, 268); + if (ENA && ACLR !== 1'b0 && !SCLR && !SLOAD) (posedge CLK => (Q : DATAIN)) = `SYNCPATH; + if (ENA && SCLR) (posedge CLK => (Q : 1'b0)) = `SYNCPATH; + if (ENA && !SCLR && SLOAD) (posedge CLK => (Q : SDATA)) = `SYNCPATH; + + $setup(DATAIN, posedge CLK, `SYNCSETUP); + $setup(ENA, posedge CLK, `SYNCSETUP); + $setup(SCLR, posedge CLK, `SYNCSETUP); + $setup(SLOAD, posedge CLK, `SYNCSETUP); + $setup(SDATA, posedge CLK, `SYNCSETUP); + + if (ACLR === 1'b0) (ACLR => Q) = `COMBPATH; endspecify -`endif initial begin // Altera flops initialise to zero. diff --git a/techlibs/intel_alm/common/dsp_map.v b/techlibs/intel_alm/common/dsp_map.v new file mode 100644 index 000000000..d1bc25e65 --- /dev/null +++ b/techlibs/intel_alm/common/dsp_map.v @@ -0,0 +1,49 @@ +module __MUL27X27(A, B, Y); + +parameter A_SIGNED = 1; +parameter B_SIGNED = 1; +parameter A_WIDTH = 27; +parameter B_WIDTH = 27; +parameter Y_WIDTH = 54; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +MISTRAL_MUL27X27 _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y)); + +endmodule + + +module __MUL18X18(A, B, Y); + +parameter A_SIGNED = 1; +parameter B_SIGNED = 1; +parameter A_WIDTH = 18; +parameter B_WIDTH = 18; +parameter Y_WIDTH = 36; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +MISTRAL_MUL18X18 _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y)); + +endmodule + + +module __MUL9X9(A, B, Y); + +parameter A_SIGNED = 1; +parameter B_SIGNED = 1; +parameter A_WIDTH = 9; +parameter B_WIDTH = 9; +parameter Y_WIDTH = 18; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +MISTRAL_MUL9X9 _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y)); + +endmodule diff --git a/techlibs/intel_alm/common/dsp_sim.v b/techlibs/intel_alm/common/dsp_sim.v new file mode 100644 index 000000000..5dc4c02de --- /dev/null +++ b/techlibs/intel_alm/common/dsp_sim.v @@ -0,0 +1,35 @@ +(* abc9_box *) +module MISTRAL_MUL27x27(input [26:0] A, input [26:0] B, output [53:0] Y); + +specify + (A *> Y) = 4057; + (B *> Y) = 4057; +endspecify + +assign Y = $signed(A) * $signed(B); + +endmodule + +(* abc9_box *) +module MISTRAL_MUL18X18(input [17:0] A, input [17:0] B, output [35:0] Y); + +specify + (A *> Y) = 4057; + (B *> Y) = 4057; +endspecify + +assign Y = $signed(A) * $signed(B); + +endmodule + +(* abc9_box *) +module MISTRAL_MUL9X9(input [8:0] A, input [8:0] B, output [17:0] Y); + +specify + (A *> Y) = 4057; + (B *> Y) = 4057; +endspecify + +assign Y = $signed(A) * $signed(B); + +endmodule diff --git a/techlibs/intel_alm/common/megafunction_bb.v b/techlibs/intel_alm/common/megafunction_bb.v index c749fa70b..b5a3d8892 100644 --- a/techlibs/intel_alm/common/megafunction_bb.v +++ b/techlibs/intel_alm/common/megafunction_bb.v @@ -129,3 +129,31 @@ output [data_width-1:0] portbdataout; input ena0, clk0, clk1; endmodule + +(* blackbox *) +module cyclonev_mac(ax, ay, resulta); + +parameter ax_width = 9; +parameter ay_scan_in_width = 9; +parameter result_a_width = 18; +parameter operation_mode = "M9x9"; + +input [ax_width-1:0] ax; +input [ay_scan_in_width-1:0] ay; +output [result_a_width-1:0] resulta; + +endmodule + +(* blackbox *) +module cyclone10gx_mac(ax, ay, resulta); + +parameter ax_width = 18; +parameter ay_scan_in_width = 18; +parameter result_a_width = 36; +parameter operation_mode = "M18X18_FULL"; + +input [ax_width-1:0] ax; +input [ay_scan_in_width-1:0] ay; +output [result_a_width-1:0] resulta; + +endmodule
\ No newline at end of file diff --git a/techlibs/intel_alm/common/mem_sim.v b/techlibs/intel_alm/common/mem_sim.v index ae79b19a4..f6f9ecb02 100644 --- a/techlibs/intel_alm/common/mem_sim.v +++ b/techlibs/intel_alm/common/mem_sim.v @@ -48,10 +48,20 @@ // the following model because it's very difficult to trigger this in practice // as clock cycles will be much longer than any potential blip of 'x, so the // model can be treated as always returning a defined result. + +(* abc9_box, lib_whitebox *) module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN, CLK1, input [4:0] B1ADDR, output B1DATA); reg [31:0] mem = 32'b0; +// TODO +specify + $setup(A1ADDR, posedge CLK1, 0); + $setup(A1DATA, posedge CLK1, 0); + + (B1ADDR *> B1DATA) = 0; +endspecify + always @(posedge CLK1) if (A1EN) mem[A1ADDR] <= A1DATA; diff --git a/techlibs/intel_alm/common/quartus_rename.v b/techlibs/intel_alm/common/quartus_rename.v index c40a4e02d..46ef2aa0d 100644 --- a/techlibs/intel_alm/common/quartus_rename.v +++ b/techlibs/intel_alm/common/quartus_rename.v @@ -1,9 +1,11 @@ `ifdef cyclonev `define LCELL cyclonev_lcell_comb +`define MAC cyclonev_mac `define MLAB cyclonev_mlab_cell `endif `ifdef cyclone10gx `define LCELL cyclone10gx_lcell_comb +`define MAC cyclone10gx_mac `define MLAB cyclone10gx_mlab_cell `endif @@ -119,3 +121,24 @@ module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN, CLK1, input [4:0] B1 ); endmodule + + +module MISTRAL_MUL27X27(input [26:0] A, B, output [53:0] Y); + +`MAC #(.ax_width(27), .ay_scan_in_width(27), .result_a_width(54), .operation_mode("M27x27")) _TECHMAP_REPLACE_ (.ax(A), .ay(B), .resulta(Y)); + +endmodule + + +module MISTRAL_MUL18X18(input [17:0] A, B, output [35:0] Y); + +`MAC #(.ax_width(18), .ay_scan_in_width(18), .result_a_width(36), .operation_mode("M18x18_FULL")) _TECHMAP_REPLACE_ (.ax(B), .ay(A), .resulta(Y)); + +endmodule + + +module MISTRAL_MUL9X9(input [8:0] A, B, output [17:0] Y); + +`MAC #(.ax_width(9), .ay_scan_in_width(9), .result_a_width(18), .operation_mode("M9x9")) _TECHMAP_REPLACE_ (.ax(A), .ay(B), .resulta(Y)); + +endmodule diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index fabfc9003..b751e8413 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -38,20 +38,26 @@ struct SynthIntelALMPass : public ScriptPass { log("This command runs synthesis for ALM-based Intel FPGAs.\n"); log("\n"); log(" -top <module>\n"); - log(" use the specified module as top module (default='top')\n"); + log(" use the specified module as top module\n"); log("\n"); log(" -family <family>\n"); log(" target one of:\n"); log(" \"cyclonev\" - Cyclone V (default)\n"); log(" \"cyclone10gx\" - Cyclone 10GX\n"); log("\n"); - log(" -quartus\n"); - log(" output a netlist using Quartus cells instead of MISTRAL_* cells\n"); - log("\n"); log(" -vqm <file>\n"); log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n"); log(" output file is omitted if this parameter is not specified. Implies -quartus.\n"); log("\n"); + log(" -noflatten\n"); + log(" do not flatten design before synthesis; useful for per-module area statistics\n"); + log("\n"); + log(" -quartus\n"); + log(" output a netlist using Quartus cells instead of MISTRAL_* cells\n"); + log("\n"); + log(" -dff\n"); + log(" pass DFFs to ABC to perform sequential logic optimisations (EXPERIMENTAL)\n"); + log("\n"); log(" -run <from_label>:<to_label>\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"); @@ -63,8 +69,8 @@ struct SynthIntelALMPass : public ScriptPass { log(" -nobram\n"); log(" do not use block RAM cells in output netlist\n"); log("\n"); - log(" -noflatten\n"); - log(" do not flatten design before synthesis\n"); + log(" -nodsp\n"); + log(" do not map multipliers to MISTRAL_MUL cells\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); help_script(); @@ -72,7 +78,7 @@ struct SynthIntelALMPass : public ScriptPass { } string top_opt, family_opt, bram_type, vout_file; - bool flatten, quartus, nolutram, nobram; + bool flatten, quartus, nolutram, nobram, dff, nodsp; void clear_flags() override { @@ -84,6 +90,8 @@ struct SynthIntelALMPass : public ScriptPass { quartus = false; nolutram = false; nobram = false; + dff = false; + nodsp = false; } void execute(std::vector<std::string> args, RTLIL::Design *design) override @@ -126,10 +134,18 @@ struct SynthIntelALMPass : public ScriptPass { nobram = true; continue; } + if (args[argidx] == "-nodsp") { + nodsp = true; + continue; + } if (args[argidx] == "-noflatten") { flatten = false; continue; } + if (args[argidx] == "-dff") { + dff = true; + continue; + } break; } extra_args(args, argidx, design); @@ -161,10 +177,13 @@ struct SynthIntelALMPass : public ScriptPass { } if (check_label("begin")) { - run(stringf("read_verilog -sv -lib +/intel/%s/cells_sim.v", family_opt.c_str())); + if (family_opt == "cyclonev") + run(stringf("read_verilog -sv -lib +/intel/%s/cells_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/alm_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/dff_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/dsp_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/mem_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s -icells +/intel_alm/common/abc9_model.v", family_opt.c_str())); // Misc and common cells run("read_verilog -lib +/intel/common/altpll_bb.v"); @@ -172,16 +191,46 @@ struct SynthIntelALMPass : public ScriptPass { run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); } - if (flatten && check_label("flatten", "(unless -noflatten)")) { + if (check_label("coarse")) { run("proc"); - run("flatten"); + if (flatten || help_mode) + run("flatten", "(skip if -noflatten)"); run("tribuf -logic"); run("deminout"); - } - - if (check_label("coarse")) { - run("synth -run coarse -lut 6"); - run("techmap -map +/intel_alm/common/arith_alm_map.v"); + run("opt_expr"); + run("opt_clean"); + run("check"); + run("opt"); + run("wreduce"); + run("peepopt"); + run("opt_clean"); + run("share"); + run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6"); + run("opt_expr"); + run("opt_clean"); + if (help_mode) { + run("techmap -map +/mul2dsp.v [...]", "(unless -nodsp)"); + } else if (!nodsp) { + // Cyclone V supports 9x9 multiplication, Cyclone 10 GX does not. + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=27 -D DSP_B_MAXWIDTH=27 -D DSP_A_MINWIDTH=19 -D DSP_B_MINWIDTH=19 -D DSP_SIGNEDONLY -D DSP_NAME=__MUL27X27"); + run("chtype -set $mul t:$__soft_mul"); + if (family_opt == "cyclonev") { + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=10 -D DSP_SIGNEDONLY -D DSP_NAME=__MUL18X18"); + run("chtype -set $mul t:$__soft_mul"); + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=9 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_SIGNEDONLY -D DSP_NAME=__MUL9X9"); + run("chtype -set $mul t:$__soft_mul"); + } else if (family_opt == "cyclone10gx") { + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_SIGNEDONLY -D DSP_NAME=__MUL18X18"); + run("chtype -set $mul t:$__soft_mul"); + } + } + run("alumacc"); + run("techmap -map +/intel_alm/common/arith_alm_map.v -map +/intel_alm/common/dsp_map.v"); + run("opt"); + run("fsm"); + run("opt -fast"); + run("memory -nomap"); + run("opt_clean"); } if (!nobram && check_label("map_bram", "(skip if -nobram)")) { @@ -199,17 +248,18 @@ struct SynthIntelALMPass : public ScriptPass { } if (check_label("map_ffs")) { + run("techmap"); run("dff2dffe"); - // As mentioned in common/dff_sim.v, Intel flops power up to zero, - // so use `zinit` to add inverters where needed. - run("zinit"); - run("techmap -map +/techmap.v -map +/intel_alm/common/dff_map.v"); + run("dfflegalize -cell $_DFFE_PN0P_ 0 -cell $_SDFFCE_PP0P_ 0"); + run("techmap -map +/intel_alm/common/dff_map.v"); run("opt -full -undriven -mux_undef"); run("clean -purge"); } if (check_label("map_luts")) { - run("abc9 -maxlut 6 -W 200"); + run("techmap -map +/intel_alm/common/abc9_map.v"); + run(stringf("abc9 %s -maxlut 6 -W 200", help_mode ? "[-dff]" : dff ? "-dff" : "")); + run("techmap -map +/intel_alm/common/abc9_unmap.v"); run("techmap -map +/intel_alm/common/alm_map.v"); run("opt -fast"); run("autoname"); diff --git a/tests/arch/intel_alm/fsm.ys b/tests/arch/intel_alm/fsm.ys index 67965569b..60cd23373 100644 --- a/tests/arch/intel_alm/fsm.ys +++ b/tests/arch/intel_alm/fsm.ys @@ -14,6 +14,7 @@ cd fsm # Constrain all select calls below inside the top module select -assert-count 6 t:MISTRAL_FF select -assert-max 2 t:MISTRAL_ALUT2 # Clang returns 2, GCC returns 1 select -assert-count 1 t:MISTRAL_ALUT3 -select -assert-count 5 t:MISTRAL_ALUT5 -select -assert-count 2 t:MISTRAL_ALUT6 -select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D +select -assert-max 1 t:MISTRAL_ALUT4 # Clang returns 0, GCC returns 1 +select -assert-max 6 t:MISTRAL_ALUT5 # Clang returns 5, GCC returns 4 +select -assert-max 2 t:MISTRAL_ALUT6 # Clang returns 1, GCC returns 2 +select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_ALUT4 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D diff --git a/tests/arch/intel_alm/mul.ys b/tests/arch/intel_alm/mul.ys new file mode 100644 index 000000000..92f00156a --- /dev/null +++ b/tests/arch/intel_alm/mul.ys @@ -0,0 +1,23 @@ +read_verilog ../common/mul.v +hierarchy -top top +proc +equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module + +stat + +select -assert-count 1 t:MISTRAL_MUL9X9 +select -assert-none t:MISTRAL_MUL9X9 %% t:* %D + +design -reset +read_verilog ../common/mul.v +hierarchy -top top +proc +equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module + +# Cyclone 10 GX does not have 9x9 multipliers, so we use 18x18. +select -assert-count 1 t:MISTRAL_MUL18X18 +select -assert-none t:MISTRAL_MUL18X18 %% t:* %D diff --git a/tests/opt/bug2221.ys b/tests/opt/bug2221.ys new file mode 100644 index 000000000..8ac380243 --- /dev/null +++ b/tests/opt/bug2221.ys @@ -0,0 +1,16 @@ +read_verilog <<EOT +module test ( + input [1:0] a, + input [1:0] b, + output [5:0] y +); + +wire [5:0] aa = {a, 4'h0}; +wire [5:0] bb = {b, 4'h0}; + +assign y = aa * bb; + +endmodule +EOT + +equiv_opt -assert opt_expr |