From 36bd07586506a1a60fa8dae3215baad54d03ccbf Mon Sep 17 00:00:00 2001 From: Artur Swiderski Date: Sat, 10 Oct 2020 19:08:54 +0200 Subject: [PATCH] start implementing support for intel le based logic devices --- techlibs/intel_le/Makefile.inc | 27 + techlibs/intel_le/common/abc9_map.v | 18 + techlibs/intel_le/common/abc9_model.v | 10 + techlibs/intel_le/common/abc9_unmap.v | 11 + techlibs/intel_le/common/arith_alm_map.v | 71 +++ techlibs/intel_le/common/bram_m10k.txt | 33 ++ techlibs/intel_le/common/bram_m20k.txt | 33 ++ techlibs/intel_le/common/bram_m20k_map.v | 31 + techlibs/intel_le/common/dff_map.v | 13 + techlibs/intel_le/common/dff_sim.v | 114 ++++ techlibs/intel_le/common/dsp_map.v | 51 ++ techlibs/intel_le/common/dsp_sim.v | 83 +++ techlibs/intel_le/common/le_map.v | 57 ++ techlibs/intel_le/common/le_sim.v | 561 ++++++++++++++++++ techlibs/intel_le/common/lutram_mlab.txt | 18 + techlibs/intel_le/common/megafunction_bb.v | 629 +++++++++++++++++++++ techlibs/intel_le/common/mem_sim.v | 109 ++++ techlibs/intel_le/common/quartus_rename.v | 235 ++++++++ techlibs/intel_le/cycloneiv/cells_sim.v | 150 +++++ techlibs/intel_le/synth_intel_le.cc | 280 +++++++++ tests/arch/intel_le/add_sub.ys | 18 + tests/arch/intel_le/adffs.ys | 94 +++ tests/arch/intel_le/blockram.ys | 6 + tests/arch/intel_le/counter.ys | 27 + tests/arch/intel_le/dffs.ys | 43 ++ tests/arch/intel_le/fsm.ys | 44 ++ tests/arch/intel_le/logic.ys | 25 + tests/arch/intel_le/lutram.ys | 41 ++ tests/arch/intel_le/mul.ys | 60 ++ tests/arch/intel_le/mux.ys | 88 +++ tests/arch/intel_le/quartus_ice.ys | 26 + tests/arch/intel_le/run-test.sh | 4 + tests/arch/intel_le/shifter.ys | 21 + tests/arch/intel_le/tribuf.ys | 27 + 34 files changed, 3058 insertions(+) create mode 100644 techlibs/intel_le/Makefile.inc create mode 100644 techlibs/intel_le/common/abc9_map.v create mode 100644 techlibs/intel_le/common/abc9_model.v create mode 100644 techlibs/intel_le/common/abc9_unmap.v create mode 100644 techlibs/intel_le/common/arith_alm_map.v create mode 100644 techlibs/intel_le/common/bram_m10k.txt create mode 100644 techlibs/intel_le/common/bram_m20k.txt create mode 100644 techlibs/intel_le/common/bram_m20k_map.v create mode 100644 techlibs/intel_le/common/dff_map.v create mode 100644 techlibs/intel_le/common/dff_sim.v create mode 100644 techlibs/intel_le/common/dsp_map.v create mode 100644 techlibs/intel_le/common/dsp_sim.v create mode 100644 techlibs/intel_le/common/le_map.v create mode 100644 techlibs/intel_le/common/le_sim.v create mode 100644 techlibs/intel_le/common/lutram_mlab.txt create mode 100644 techlibs/intel_le/common/megafunction_bb.v create mode 100644 techlibs/intel_le/common/mem_sim.v create mode 100644 techlibs/intel_le/common/quartus_rename.v create mode 100644 techlibs/intel_le/cycloneiv/cells_sim.v create mode 100644 techlibs/intel_le/synth_intel_le.cc create mode 100644 tests/arch/intel_le/add_sub.ys create mode 100644 tests/arch/intel_le/adffs.ys create mode 100644 tests/arch/intel_le/blockram.ys create mode 100644 tests/arch/intel_le/counter.ys create mode 100644 tests/arch/intel_le/dffs.ys create mode 100644 tests/arch/intel_le/fsm.ys create mode 100644 tests/arch/intel_le/logic.ys create mode 100644 tests/arch/intel_le/lutram.ys create mode 100644 tests/arch/intel_le/mul.ys create mode 100644 tests/arch/intel_le/mux.ys create mode 100644 tests/arch/intel_le/quartus_ice.ys create mode 100755 tests/arch/intel_le/run-test.sh create mode 100644 tests/arch/intel_le/shifter.ys create mode 100644 tests/arch/intel_le/tribuf.ys diff --git a/techlibs/intel_le/Makefile.inc b/techlibs/intel_le/Makefile.inc new file mode 100644 index 000000000..efc9de821 --- /dev/null +++ b/techlibs/intel_le/Makefile.inc @@ -0,0 +1,27 @@ + +OBJS += techlibs/intel_le/synth_intel_le.o + +# Techmap +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/abc9_map.v)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/abc9_unmap.v)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/abc9_model.v)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/alm_map.v)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/alm_sim.v)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/arith_alm_map.v)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/dff_map.v)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/dff_sim.v)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/dsp_sim.v)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/dsp_map.v)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/mem_sim.v)) + +$(eval $(call add_share_file,share/intel_le/cyclonev,techlibs/intel_le/cycloneiv/cells_sim.v)) + +# RAM +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/bram_m10k.txt)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/bram_m20k.txt)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/bram_m20k_map.v)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/lutram_mlab.txt)) + +# Miscellaneous +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/megafunction_bb.v)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/quartus_rename.v)) diff --git a/techlibs/intel_le/common/abc9_map.v b/techlibs/intel_le/common/abc9_map.v new file mode 100644 index 000000000..9d11bb240 --- /dev/null +++ b/techlibs/intel_le/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_le/common/abc9_model.v b/techlibs/intel_le/common/abc9_model.v new file mode 100644 index 000000000..8f06d3835 --- /dev/null +++ b/techlibs/intel_le/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_le/common/abc9_unmap.v b/techlibs/intel_le/common/abc9_unmap.v new file mode 100644 index 000000000..4b28866a3 --- /dev/null +++ b/techlibs/intel_le/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_le/common/arith_alm_map.v b/techlibs/intel_le/common/arith_alm_map.v new file mode 100644 index 000000000..8515eeb56 --- /dev/null +++ b/techlibs/intel_le/common/arith_alm_map.v @@ -0,0 +1,71 @@ +`default_nettype none + +module \$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; +input CI, BI; +(* force_downto *) +output [Y_WIDTH-1:0] X, Y, CO; + +(* 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] BX = B_buf; +wire [Y_WIDTH:0] ALM_CARRY; + +// Start of carry chain +generate + if (_TECHMAP_CONSTMSK_CI_ == 1) begin + assign ALM_CARRY[0] = _TECHMAP_CONSTVAL_CI_; + end else begin + MISTRAL_ALUT_ARITH #( + .LUT0(16'b1010_1010_1010_1010), // Q = A + .LUT1(16'b0000_0000_0000_0000), // Q = 0 (LUT1's input to the adder is inverted) + ) alm_start ( + .A(CI), .B(1'b1), .C(1'b1), .D0(1'b1), .D1(1'b1), + .CI(1'b0), + .CO(ALM_CARRY[0]) + ); + end +endgenerate + +// Carry chain +genvar i; +generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice + // TODO: mwk suggests that a pass could merge pre-adder logic into this. + MISTRAL_ALUT_ARITH #( + .LUT0(16'b1010_1010_1010_1010), // Q = A + .LUT1(16'b1100_0011_1100_0011), // Q = C ? B : ~B (LUT1's input to the adder is inverted) + ) alm_i ( + .A(AA[i]), .B(BX[i]), .C(BI), .D0(1'b1), .D1(1'b1), + .CI(ALM_CARRY[i]), + .SO(Y[i]), + .CO(ALM_CARRY[i+1]) + ); + + // ALM carry chain is not directly accessible, so calculate the carry through soft logic if really needed. + assign CO[i] = (AA[i] && BB[i]) || ((Y[i] ^ AA[i] ^ BB[i]) && (AA[i] || BB[i])); +end endgenerate + +assign X = AA ^ BB; + +endmodule diff --git a/techlibs/intel_le/common/bram_m10k.txt b/techlibs/intel_le/common/bram_m10k.txt new file mode 100644 index 000000000..e9355fe2c --- /dev/null +++ b/techlibs/intel_le/common/bram_m10k.txt @@ -0,0 +1,33 @@ +bram MISTRAL_M10K + init 0 # TODO: Re-enable when I figure out how BRAM init works + abits 13 @D8192x1 + dbits 1 @D8192x1 + abits 12 @D4096x2 + dbits 2 @D4096x2 + abits 11 @D2048x4 @D2048x5 + dbits 4 @D2048x4 + dbits 5 @D2048x5 + abits 10 @D1024x8 @D1024x10 + dbits 8 @D1024x8 + dbits 10 @D1024x10 + abits 9 @D512x16 @D512x20 + dbits 16 @D512x16 + dbits 20 @D512x20 + abits 8 @D256x32 @D256x40 + dbits 32 @D256x32 + dbits 40 @D256x40 + groups 2 + ports 1 1 + wrmode 1 0 + # read enable; write enable + byte enables (only for multiples of 8) + enable 1 1 + transp 0 0 + clocks 1 1 + clkpol 1 1 +endbram + + +match MISTRAL_M10K + min efficiency 5 + make_transp +endmatch diff --git a/techlibs/intel_le/common/bram_m20k.txt b/techlibs/intel_le/common/bram_m20k.txt new file mode 100644 index 000000000..b4c5a5372 --- /dev/null +++ b/techlibs/intel_le/common/bram_m20k.txt @@ -0,0 +1,33 @@ +bram __MISTRAL_M20K_SDP + init 1 # TODO: Re-enable when I figure out how BRAM init works + abits 14 @D16384x1 + dbits 1 @D16384x1 + abits 13 @D8192x2 + dbits 2 @D8192x2 + abits 12 @D4096x4 @D4096x5 + dbits 4 @D4096x4 + dbits 5 @D4096x5 + abits 11 @D2048x8 @D2048x10 + dbits 8 @D2048x8 + dbits 10 @D2048x10 + abits 10 @D1024x16 @D1024x20 + dbits 16 @D1024x16 + dbits 20 @D1024x20 + abits 9 @D512x32 @D512x40 + dbits 32 @D512x32 + dbits 40 @D512x40 + groups 2 + ports 1 1 + wrmode 1 0 + # read enable; write enable + byte enables (only for multiples of 8) + enable 1 1 + transp 0 0 + clocks 1 1 + clkpol 1 1 +endbram + + +match __MISTRAL_M20K_SDP + min efficiency 5 + make_transp +endmatch diff --git a/techlibs/intel_le/common/bram_m20k_map.v b/techlibs/intel_le/common/bram_m20k_map.v new file mode 100644 index 000000000..92f41310f --- /dev/null +++ b/techlibs/intel_le/common/bram_m20k_map.v @@ -0,0 +1,31 @@ +module __MISTRAL_M20K_SDP(CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + +parameter CFG_ABITS = 10; +parameter CFG_DBITS = 20; +parameter CFG_ENABLE_A = 1; +parameter CFG_ENABLE_B = 1; + +input CLK1; +input [CFG_ABITS-1:0] A1ADDR, B1ADDR; +input [CFG_DBITS-1:0] A1DATA; +output [CFG_DBITS-1:0] B1DATA; +input [CFG_ENABLE_A-1:0] A1EN, B1EN; + +altsyncram #( + .operation_mode("dual_port"), + .ram_block_type("m20k"), + .widthad_a(CFG_ABITS), + .width_a(CFG_DBITS), + .widthad_b(CFG_ABITS), + .width_b(CFG_DBITS), +) _TECHMAP_REPLACE_ ( + .address_a(A1ADDR), + .data_a(A1DATA), + .wren_a(A1EN), + .address_b(B1ADDR), + .q_b(B1DATA), + .clock0(CLK1), + .clock1(CLK1) +); + +endmodule diff --git a/techlibs/intel_le/common/dff_map.v b/techlibs/intel_le/common/dff_map.v new file mode 100644 index 000000000..1a4b5d65a --- /dev/null +++ b/techlibs/intel_le/common/dff_map.v @@ -0,0 +1,13 @@ +`default_nettype none + +// 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(R), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +endmodule + +// 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(E), .SCLR(R), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); +endmodule diff --git a/techlibs/intel_le/common/dff_sim.v b/techlibs/intel_le/common/dff_sim.v new file mode 100644 index 000000000..d2cff0adb --- /dev/null +++ b/techlibs/intel_le/common/dff_sim.v @@ -0,0 +1,114 @@ +// The four D flip-flops (DFFs) in a Cyclone V/10GX Adaptive Logic Module (ALM) +// act as one-bit memory cells that can be placed very flexibly (wherever there's +// an ALM); each flop is represented by a MISTRAL_FF cell. +// +// The flops in these chips are rather flexible in some ways, but in practice +// quite crippled by FPGA standards. +// +// What the flops can do +// --------------------- +// The core flop acts as a single-bit memory that initialises to zero at chip +// reset. It takes in data on the rising edge of CLK if ENA is high, +// and outputs it to Q. The ENA (clock enable) pin can therefore be used to +// capture the input only if a condition is true. +// +// The data itself is zero if SCLR (synchronous clear) is high, else it comes +// from SDATA (synchronous data) if SLOAD (synchronous load) is high, or DATAIN +// if SLOAD is low. +// +// If ACLR (asynchronous clear) is low then Q is forced to zero, regardless of +// the synchronous inputs or CLK edge. This is most often used for an FPGA-wide +// power-on reset. +// +// An asynchronous set that sets Q to one can be emulated by inverting the input +// and output of the flop, resulting in ACLR forcing Q to zero, which then gets +// inverted to produce one. Likewise, logic can operate on the falling edge of +// CLK if CLK is inverted before being passed as an input. +// +// What the flops *can't* do +// ------------------------- +// The trickiest part of the above capabilities is the lack of configurable +// initialisation state. For example, it isn't possible to implement a flop with +// asynchronous clear that initialises to one, because the hardware initialises +// to zero. Likewise, you can't emulate a flop with asynchronous set that +// initialises to zero, because the inverters mean the flop initialises to one. +// +// If the input design requires one of these cells (which appears to be rare +// in practice) then synth_intel_alm will fail to synthesize the design where +// other Yosys synthesis scripts might succeed. +// +// This stands in notable contrast to e.g. Xilinx flip-flops, which have +// configurable initialisation state and native synchronous/asynchronous +// set/clear (although not at the same time), which means they can generally +// implement a much wider variety of logic. + +// DATAIN: synchronous data input +// CLK: clock input (positive edge) +// ACLR: asynchronous clear (negative-true) +// ENA: clock-enable +// SCLR: synchronous clear +// SLOAD: synchronous load +// SDATA: synchronous load data +// +// Q: data output +// +// Note: the DFFEAS primitive is mostly emulated; it does not reflect what the hardware implements. + +(* abc9_box, lib_whitebox *) +module MISTRAL_FF( + input DATAIN, CLK, ACLR, ENA, SCLR, SLOAD, SDATA, + output reg Q +); + +`ifdef cyclonev +specify + if (ENA && ACLR !== 1'b0 && !SCLR && !SLOAD) (posedge CLK => (Q : DATAIN)) = 731; + if (ENA && SCLR) (posedge CLK => (Q : 1'b0)) = 890; + if (ENA && !SCLR && SLOAD) (posedge CLK => (Q : SDATA)) = 618; + + $setup(DATAIN, posedge CLK, /* -196 */ 0); + $setup(ENA, posedge CLK, /* -196 */ 0); + $setup(SCLR, posedge CLK, /* -196 */ 0); + $setup(SLOAD, posedge CLK, /* -196 */ 0); + $setup(SDATA, posedge CLK, /* -196 */ 0); + + if (ACLR === 1'b0) (ACLR => Q) = 282; +endspecify +`endif +`ifdef cyclone10gx +specify + // TODO (long-term): investigate these numbers. + // It seems relying on the Quartus Timing Analyzer was not the best idea; it's too fiddly. + if (ENA && ACLR !== 1'b0 && !SCLR && !SLOAD) (posedge CLK => (Q : DATAIN)) = 219; + if (ENA && SCLR) (posedge CLK => (Q : 1'b0)) = 219; + if (ENA && !SCLR && SLOAD) (posedge CLK => (Q : SDATA)) = 219; + + $setup(DATAIN, posedge CLK, 268); + $setup(ENA, posedge CLK, 268); + $setup(SCLR, posedge CLK, 268); + $setup(SLOAD, posedge CLK, 268); + $setup(SDATA, posedge CLK, 268); + + if (ACLR === 1'b0) (ACLR => Q) = 0; +endspecify +`endif + +initial begin + // Altera flops initialise to zero. + Q = 0; +end + +always @(posedge CLK, negedge ACLR) begin + // Asynchronous clear + if (!ACLR) Q <= 0; + // Clock-enable + else if (ENA) begin + // Synchronous clear + if (SCLR) Q <= 0; + // Synchronous load + else if (SLOAD) Q <= SDATA; + else Q <= DATAIN; + end +end + +endmodule diff --git a/techlibs/intel_le/common/dsp_map.v b/techlibs/intel_le/common/dsp_map.v new file mode 100644 index 000000000..e12e777a4 --- /dev/null +++ b/techlibs/intel_le/common/dsp_map.v @@ -0,0 +1,51 @@ +`default_nettype none + +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_le/common/dsp_sim.v b/techlibs/intel_le/common/dsp_sim.v new file mode 100644 index 000000000..bdb6d18d5 --- /dev/null +++ b/techlibs/intel_le/common/dsp_sim.v @@ -0,0 +1,83 @@ +(* abc9_box *) +module MISTRAL_MUL27X27(input [26:0] A, input [26:0] B, output [53:0] Y); + +parameter A_SIGNED = 1; +parameter B_SIGNED = 1; + +// TODO: Cyclone 10 GX timings; the below are for Cyclone V +specify + (A *> Y) = 3732; + (B *> Y) = 3928; +endspecify + +wire [53:0] A_, B_; + +if (A_SIGNED) + assign A_ = $signed(A); +else + assign A_ = $unsigned(A); + +if (B_SIGNED) + assign B_ = $signed(B); +else + assign B_ = $unsigned(B); + +assign Y = A_ * B_; + +endmodule + +(* abc9_box *) +module MISTRAL_MUL18X18(input [17:0] A, input [17:0] B, output [35:0] Y); + +parameter A_SIGNED = 1; +parameter B_SIGNED = 1; + +// TODO: Cyclone 10 GX timings; the below are for Cyclone V +specify + (A *> Y) = 3180; + (B *> Y) = 3982; +endspecify + +wire [35:0] A_, B_; + +if (A_SIGNED) + assign A_ = $signed(A); +else + assign A_ = $unsigned(A); + +if (B_SIGNED) + assign B_ = $signed(B); +else + assign B_ = $unsigned(B); + +assign Y = A_ * B_; + +endmodule + +(* abc9_box *) +module MISTRAL_MUL9X9(input [8:0] A, input [8:0] B, output [17:0] Y); + +parameter A_SIGNED = 1; +parameter B_SIGNED = 1; + +// TODO: Cyclone 10 GX timings; the below are for Cyclone V +specify + (A *> Y) = 2818; + (B *> Y) = 3051; +endspecify + +wire [17:0] A_, B_; + +if (A_SIGNED) + assign A_ = $signed(A); +else + assign A_ = $unsigned(A); + +if (B_SIGNED) + assign B_ = $signed(B); +else + assign B_ = $unsigned(B); + +assign Y = A_ * B_; + +endmodule diff --git a/techlibs/intel_le/common/le_map.v b/techlibs/intel_le/common/le_map.v new file mode 100644 index 000000000..6697b2e78 --- /dev/null +++ b/techlibs/intel_le/common/le_map.v @@ -0,0 +1,57 @@ +module \$lut (A, Y); + +parameter WIDTH = 1; +parameter LUT = 0; + +(* force_downto *) +input [WIDTH-1:0] A; +output Y; + +generate + if (WIDTH == 1) begin + generate + if (LUT == 2'b00) begin + assign Y = 1'b0; + end + else if (LUT == 2'b01) begin + MISTRAL_NOT _TECHMAP_REPLACE_( + .A(A[0]), .Q(Y) + ); + end + else if (LUT == 2'b10) begin + assign Y = A; + end + else if (LUT == 2'b11) begin + assign Y = 1'b1; + end + endgenerate + end else + if (WIDTH == 2) begin + MISTRAL_ALUT2 #(.LUT(LUT)) _TECHMAP_REPLACE_( + .A(A[0]), .B(A[1]), .Q(Y) + ); + end else + if (WIDTH == 3) begin + MISTRAL_ALUT3 #(.LUT(LUT)) _TECHMAP_REPLACE_( + .A(A[0]), .B(A[1]), .C(A[2]), .Q(Y) + ); + end else + if (WIDTH == 4) begin + MISTRAL_ALUT4 #(.LUT(LUT)) _TECHMAP_REPLACE_( + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .Q(Y) + ); + end else + if (WIDTH == 5) begin + MISTRAL_ALUT5 #(.LUT(LUT)) _TECHMAP_REPLACE_ ( + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .E(A[4]), .Q(Y) + ); + end else + if (WIDTH == 6) begin + MISTRAL_ALUT6 #(.LUT(LUT)) _TECHMAP_REPLACE_ ( + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]), .E(A[4]), .F(A[5]), .Q(Y) + ); + end else begin + wire _TECHMAP_FAIL_ = 1'b1; + end +endgenerate +endmodule diff --git a/techlibs/intel_le/common/le_sim.v b/techlibs/intel_le/common/le_sim.v new file mode 100644 index 000000000..906a95b0b --- /dev/null +++ b/techlibs/intel_le/common/le_sim.v @@ -0,0 +1,561 @@ +// The core logic primitive of the Cyclone V/10GX is the Adaptive Logic Module +// (ALM). Each ALM is made up of an 8-input, 2-output look-up table, covered +// in this file, connected to combinational outputs, a carry chain, and four +// D flip-flops (which are covered as MISTRAL_FF in dff_sim.v). +// +// The ALM is vertically symmetric, so I find it helps to think in terms of +// half-ALMs, as that's predominantly the unit that synth_intel_alm uses. +// +// ALMs are quite flexible, having multiple modes. +// +// Normal (combinational) mode +// --------------------------- +// The ALM can implement: +// - a single 6-input function (with the other inputs usable for flip-flop access) +// - two 5-input functions that share two inputs +// - a 5-input and a 4-input function that share one input +// - a 5-input and a 3-or-less-input function that share no inputs +// - two 4-or-less-input functions that share no inputs +// +// Normal-mode functions are represented as MISTRAL_ALUTN cells with N inputs. +// It would be possible to represent a normal mode function as a single cell - +// the vendor cyclone{v,10gx}_lcell_comb cell does exactly that - but I felt +// it was more user-friendly to print out the specific function sizes +// separately. +// +// With the exception of MISTRAL_ALUT6, you can think of two normal-mode cells +// fitting inside a single ALM. +// +// Extended (7-input) mode +// ----------------------- +// The ALM can also fit a 7-input function made of two 5-input functions that +// share four inputs, multiplexed by another input. +// +// Because this can't accept arbitrary 7-input functions, Yosys can't handle +// it, so it doesn't have a cell, but I would likely call it MISTRAL_ALUT7(E?) +// if it did, and it would take up a full ALM. +// +// It might be possible to add an extraction pass to examine all ALUT5 cells +// that feed into ALUT3 cells to see if they can be combined into an extended +// ALM, but I don't think it will be worth it. +// +// Arithmetic mode +// --------------- +// In arithmetic mode, each half-ALM uses its carry chain to perform fast addition +// of two four-input functions that share three inputs. Oddly, the result of +// one of the functions is inverted before being added (you can see this as +// the dot on a full-adder input of Figure 1-8 in the Handbook). +// +// The cell for an arithmetic-mode half-ALM is MISTRAL_ALM_ARITH. One idea +// I've had (or rather was suggested by mwk) is that functions that feed into +// arithmetic-mode cells could be packed directly into the arithmetic-mode +// cell as a function, which reduces the number of ALMs needed. +// +// Shared arithmetic mode +// ---------------------- +// Shared arithmetic mode looks a lot like arithmetic mode, but here the +// output of every other four-input function goes to the input of the adder +// the next bit along. What this means is that adding three bits together can +// be done in an ALM, because functions can be used to implement addition that +// then feeds into the carry chain. This means that three bits can be added per +// ALM, as opposed to two in the arithmetic mode. +// +// Shared arithmetic mode doesn't currently have a cell, but I intend to add +// it as MISTRAL_ALM_SHARED, and have it occupy a full ALM. Because it adds +// three bits per cell, it makes addition shorter and use less ALMs, but +// I don't know enough to tell whether it's more efficient to use shared +// arithmetic mode to shorten the carry chain, or plain arithmetic mode with +// the functions packed in. + +`default_nettype none + +// Cyclone V LUT output timings (picoseconds): +// +// CARRY A B C D E F G +// COMBOUT - 605 583 510 512 - 97 400 (LUT6) +// COMBOUT - 602 583 457 510 302 93 483 (LUT7) +// SUMOUT 368 1342 1323 887 927 - 785 - +// CARRYOUT 71 1082 1062 866 813 - 1198 - + +(* abc9_lut=2, lib_whitebox *) +module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q); + +parameter [63:0] LUT = 64'h0000_0000_0000_0000; + +`ifdef cyclonev +specify + (A => Q) = 605; + (B => Q) = 583; + (C => Q) = 510; + (D => Q) = 512; + (E => Q) = 400; + (F => Q) = 97; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 275; + (B => Q) = 272; + (C => Q) = 175; + (D => Q) = 165; + (E => Q) = 162; + (F => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {F, E, D, C, B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_ALUT5(input A, B, C, D, E, output Q); + +parameter [31:0] LUT = 32'h0000_0000; + +`ifdef cyclonev +specify + (A => Q) = 583; + (B => Q) = 510; + (C => Q) = 512; + (D => Q) = 400; + (E => Q) = 97; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 272; + (B => Q) = 175; + (C => Q) = 165; + (D => Q) = 162; + (E => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {E, D, C, B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_ALUT4(input A, B, C, D, output Q); + +parameter [15:0] LUT = 16'h0000; + +`ifdef cyclonev +specify + (A => Q) = 510; + (B => Q) = 512; + (C => Q) = 400; + (D => Q) = 97; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 175; + (B => Q) = 165; + (C => Q) = 162; + (D => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {D, C, B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_ALUT3(input A, B, C, output Q); + +parameter [7:0] LUT = 8'h00; + +`ifdef cyclonev +specify + (A => Q) = 510; + (B => Q) = 400; + (C => Q) = 97; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 165; + (B => Q) = 162; + (C => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {C, B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_ALUT2(input A, B, output Q); + +parameter [3:0] LUT = 4'h0; + +`ifdef cyclonev +specify + (A => Q) = 400; + (B => Q) = 97; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 162; + (B => Q) = 53; +endspecify +`endif + +assign Q = LUT >> {B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_NOT(input A, output Q); + +`ifdef cyclonev +specify + (A => Q) = 97; +endspecify +`endif +`ifdef cyclone10gx +specify + (A => Q) = 53; +endspecify +`endif + +assign Q = ~A; + +endmodule + +(* abc9_box, lib_whitebox *) +module MISTRAL_ALUT_ARITH(input A, B, C, D0, D1, (* abc9_carry *) input CI, output SO, (* abc9_carry *) output CO); + +parameter LUT0 = 16'h0000; +parameter LUT1 = 16'h0000; + +`ifdef cyclonev +specify + (A => SO) = 1342; + (B => SO) = 1323; + (C => SO) = 927; + (D0 => SO) = 887; + (D1 => SO) = 785; + (CI => SO) = 368; + + (A => CO) = 1082; + (B => CO) = 1062; + (C => CO) = 813; + (D0 => CO) = 866; + (D1 => CO) = 1198; + (CI => CO) = 36; // Divided by 2 to account for there being two ALUT_ARITHs in an ALM) +endspecify +`endif +`ifdef cyclone10gx +specify + (A => SO) = 644; + (B => SO) = 477; + (C => SO) = 416; + (D0 => SO) = 380; + (D1 => SO) = 431; + (CI => SO) = 276; + + (A => CO) = 525; + (B => CO) = 433; + (C => CO) = 712; + (D0 => CO) = 653; + (D1 => CO) = 593; + (CI => CO) = 16; +endspecify +`endif + +wire q0, q1; + +assign q0 = LUT0 >> {D0, C, B, A}; +assign q1 = LUT1 >> {D1, C, B, A}; + +assign {CO, SO} = q0 + !q1 + CI; + +endmodule + + +/* +// A, B, C0, C1, E0, E1, F0, F1: data inputs +// CARRYIN: carry input +// SHAREIN: shared-arithmetic input +// CLK0, CLK1, CLK2: clock inputs +// +// COMB0, COMB1: combinational outputs +// FF0, FF1, FF2, FF3: DFF outputs +// SUM0, SUM1: adder outputs +// CARRYOUT: carry output +// SHAREOUT: shared-arithmetic output +module MISTRAL_ALM( + input A, B, C0, C1, E0, E1, F0, F1, CARRYIN, SHAREIN, // LUT path + input CLK0, CLK1, CLK2, AC0, AC1, // FF path + output COMB0, COMB1, SUM0, SUM1, CARRYOUT, SHAREOUT, + output FF0, FF1, FF2, FF3 +); + +parameter LUT0 = 16'b0000; +parameter LUT1 = 16'b0000; +parameter LUT2 = 16'b0000; +parameter LUT3 = 16'b0000; + +parameter INIT0 = 1'b0; +parameter INIT1 = 1'b0; +parameter INIT2 = 1'b0; +parameter INIT3 = 1'b0; + +parameter C0_MUX = "C0"; +parameter C1_MUX = "C1"; + +parameter F0_MUX = "VCC"; +parameter F1_MUX = "GND"; + +parameter FEEDBACK0 = "FF0"; +parameter FEEDBACK1 = "FF2"; + +parameter ADD_MUX = "LUT"; + +parameter DFF01_DATA_MUX = "COMB"; +parameter DFF23_DATA_MUX = "COMB"; + +parameter DFF0_CLK = "CLK0"; +parameter DFF1_CLK = "CLK0"; +parameter DFF2_CLK = "CLK0"; +parameter DFF3_CLK = "CLK0"; + +parameter DFF0_AC = "AC0"; +parameter DFF1_AC = "AC0"; +parameter DFF2_AC = "AC0"; +parameter DFF3_AC = "AC0"; + +// Feedback muxes from the flip-flop outputs. +wire ff_feedback_mux0, ff_feedback_mux1; + +// C-input muxes which can be set to also use the F-input. +wire c0_input_mux, c1_input_mux; + +// F-input muxes which can be set to a constant to allow LUT5 use. +wire f0_input_mux, f1_input_mux; + +// Adder input muxes to select between shared-arithmetic mode and arithmetic mode. +wire add0_input_mux, add1_input_mux; + +// Combinational-output muxes for LUT #1 and LUT #3 +wire lut1_comb_mux, lut3_comb_mux; + +// Sum-output muxes for LUT #1 and LUT #3 +wire lut1_sum_mux, lut3_sum_mux; + +// DFF data-input muxes +wire dff01_data_mux, dff23_data_mux; + +// DFF clock selectors +wire dff0_clk, dff1_clk, dff2_clk, dff3_clk; + +// DFF asynchronous-clear selectors +wire dff0_ac, dff1_ac, dff2_ac, dff3_ac; + +// LUT, DFF and adder output wires for routing. +wire lut0_out, lut1a_out, lut1b_out, lut2_out, lut3a_out, lut3b_out; +wire dff0_out, dff1_out, dff2_out, dff3_out; +wire add0_sum, add1_sum, add0_carry, add1_carry; + +generate + if (FEEDBACK0 === "FF0") + assign ff_feedback_mux0 = dff0_out; + else if (FEEDBACK0 === "FF1") + assign ff_feedback_mux0 = dff1_out; + else + $error("Invalid FEEDBACK0 setting!"); + + if (FEEDBACK1 == "FF2") + assign ff_feedback_mux1 = dff2_out; + else if (FEEDBACK1 == "FF3") + assign ff_feedback_mux1 = dff3_out; + else + $error("Invalid FEEDBACK1 setting!"); + + if (C0_MUX === "C0") + assign c0_input_mux = C0; + else if (C0_MUX === "F1") + assign c0_input_mux = F1; + else if (C0_MUX === "FEEDBACK1") + assign c0_input_mux = ff_feedback_mux1; + else + $error("Invalid C0_MUX setting!"); + + if (C1_MUX === "C1") + assign c1_input_mux = C1; + else if (C1_MUX === "F0") + assign c1_input_mux = F0; + else if (C1_MUX === "FEEDBACK0") + assign c1_input_mux = ff_feedback_mux0; + else + $error("Invalid C1_MUX setting!"); + + // F0 == VCC is LUT5 + // F0 == F0 is LUT6 + // F0 == FEEDBACK is unknown + if (F0_MUX === "VCC") + assign f0_input_mux = 1'b1; + else if (F0_MUX === "F0") + assign f0_input_mux = F0; + else if (F0_MUX === "FEEDBACK0") + assign f0_input_mux = ff_feedback_mux0; + else + $error("Invalid F0_MUX setting!"); + + // F1 == GND is LUT5 + // F1 == F1 is LUT6 + // F1 == FEEDBACK is unknown + if (F1_MUX === "GND") + assign f1_input_mux = 1'b0; + else if (F1_MUX === "F1") + assign f1_input_mux = F1; + else if (F1_MUX === "FEEDBACK1") + assign f1_input_mux = ff_feedback_mux1; + else + $error("Invalid F1_MUX setting!"); + + if (ADD_MUX === "LUT") begin + assign add0_input_mux = ~lut1_sum_mux; + assign add1_input_mux = ~lut3_sum_mux; + end else if (ADD_MUX === "SHARE") begin + assign add0_input_mux = SHAREIN; + assign add1_input_mux = lut1_comb_mux; + end else + $error("Invalid ADD_MUX setting!"); + + if (DFF01_DATA_MUX === "COMB") + assign dff01_data_mux = COMB0; + else if (DFF01_DATA_MUX === "SUM") + assign dff01_data_mux = SUM0; + else + $error("Invalid DFF01_DATA_MUX setting!"); + + if (DFF23_DATA_MUX === "COMB") + assign dff23_data_mux = COMB0; + else if (DFF23_DATA_MUX === "SUM") + assign dff23_data_mux = SUM0; + else + $error("Invalid DFF23_DATA_MUX setting!"); + + if (DFF0_CLK === "CLK0") + assign dff0_clk = CLK0; + else if (DFF0_CLK === "CLK1") + assign dff0_clk = CLK1; + else if (DFF0_CLK === "CLK2") + assign dff0_clk = CLK2; + else + $error("Invalid DFF0_CLK setting!"); + + if (DFF1_CLK === "CLK0") + assign dff1_clk = CLK0; + else if (DFF1_CLK === "CLK1") + assign dff1_clk = CLK1; + else if (DFF1_CLK === "CLK2") + assign dff1_clk = CLK2; + else + $error("Invalid DFF1_CLK setting!"); + + if (DFF2_CLK === "CLK0") + assign dff2_clk = CLK0; + else if (DFF2_CLK === "CLK1") + assign dff2_clk = CLK1; + else if (DFF2_CLK === "CLK2") + assign dff2_clk = CLK2; + else + $error("Invalid DFF2_CLK setting!"); + + if (DFF3_CLK === "CLK0") + assign dff3_clk = CLK0; + else if (DFF3_CLK === "CLK1") + assign dff3_clk = CLK1; + else if (DFF3_CLK === "CLK2") + assign dff3_clk = CLK2; + else + $error("Invalid DFF3_CLK setting!"); + + if (DFF0_AC === "AC0") + assign dff0_ac = AC0; + else if (DFF0_AC === "AC1") + assign dff0_ac = AC1; + else + $error("Invalid DFF0_AC setting!"); + + if (DFF1_AC === "AC0") + assign dff1_ac = AC0; + else if (DFF1_AC === "AC1") + assign dff1_ac = AC1; + else + $error("Invalid DFF1_AC setting!"); + + if (DFF2_AC === "AC0") + assign dff2_ac = AC0; + else if (DFF2_AC === "AC1") + assign dff2_ac = AC1; + else + $error("Invalid DFF2_AC setting!"); + + if (DFF3_AC === "AC0") + assign dff3_ac = AC0; + else if (DFF3_AC === "AC1") + assign dff3_ac = AC1; + else + $error("Invalid DFF3_AC setting!"); + +endgenerate + +// F0 on the Quartus diagram +MISTRAL_ALUT4 #(.LUT(LUT0)) lut0 (.A(A), .B(B), .C(C0), .D(c1_input_mux), .Q(lut0_out)); + +// F2 on the Quartus diagram +MISTRAL_ALUT4 #(.LUT(LUT1)) lut1_comb (.A(A), .B(B), .C(C0), .D(c1_input_mux), .Q(lut1_comb_mux)); +MISTRAL_ALUT4 #(.LUT(LUT1)) lut1_sum (.A(A), .B(B), .C(C0), .D(E0), .Q(lut1_sum_mux)); + +// F1 on the Quartus diagram +MISTRAL_ALUT4 #(.LUT(LUT2)) lut2 (.A(A), .B(B), .C(C1), .D(c0_input_mux), .Q(lut2_out)); + +// F3 on the Quartus diagram +MISTRAL_ALUT4 #(.LUT(LUT3)) lut3_comb (.A(A), .B(B), .C(C1), .D(c0_input_mux), .Q(lut3_comb_mux)); +MISTRAL_ALUT4 #(.LUT(LUT3)) lut3_sum (.A(A), .B(B), .C(C1), .D(E1), .Q(lut3_sum_mux)); + +MISTRAL_FF #(.INIT(INIT0)) dff0 (.D(dff01_data_mux), .CLK(dff0_clk), .ACn(dff0_ac), .Q(dff0_out)); +MISTRAL_FF #(.INIT(INIT1)) dff1 (.D(dff01_data_mux), .CLK(dff1_clk), .ACn(dff1_ac), .Q(dff1_out)); +MISTRAL_FF #(.INIT(INIT2)) dff2 (.D(dff23_data_mux), .CLK(dff2_clk), .ACn(dff2_ac), .Q(dff2_out)); +MISTRAL_FF #(.INIT(INIT3)) dff3 (.D(dff23_data_mux), .CLK(dff3_clk), .ACn(dff3_ac), .Q(dff3_out)); + +// Adders +assign {add0_carry, add0_sum} = CARRYIN + lut0_out + lut1_sum_mux; +assign {add1_carry, add1_sum} = add0_carry + lut2_out + lut3_sum_mux; + +// COMBOUT outputs on the Quartus diagram +assign COMB0 = E0 ? (f0_input_mux ? lut3_comb_mux : lut1_comb_mux) + : (f0_input_mux ? lut2_out : lut0_out); + +assign COMB1 = E1 ? (f1_input_mux ? lut3_comb_mux : lut1_comb_mux) + : (f1_input_mux ? lut2_out : lut0_out); + +// SUMOUT output on the Quartus diagram +assign SUM0 = add0_sum; +assign SUM1 = add1_sum; + +// COUT output on the Quartus diagram +assign CARRYOUT = add1_carry; + +// SHAREOUT output on the Quartus diagram +assign SHAREOUT = lut3_comb_mux; + +// REGOUT outputs on the Quartus diagram +assign FF0 = dff0_out; +assign FF1 = dff1_out; +assign FF2 = dff2_out; +assign FF3 = dff3_out; + +endmodule +*/ diff --git a/techlibs/intel_le/common/lutram_mlab.txt b/techlibs/intel_le/common/lutram_mlab.txt new file mode 100644 index 000000000..3cc69399d --- /dev/null +++ b/techlibs/intel_le/common/lutram_mlab.txt @@ -0,0 +1,18 @@ +bram MISTRAL_MLAB + init 0 # TODO: Re-enable when Yosys remembers the original filename. + abits 5 + dbits 1 + groups 2 + ports 1 1 + wrmode 1 0 + # write enable + enable 1 0 + transp 0 0 + clocks 1 0 + clkpol 1 1 +endbram + +match MISTRAL_MLAB + min efficiency 5 + make_outreg +endmatch \ No newline at end of file diff --git a/techlibs/intel_le/common/megafunction_bb.v b/techlibs/intel_le/common/megafunction_bb.v new file mode 100644 index 000000000..874f293b1 --- /dev/null +++ b/techlibs/intel_le/common/megafunction_bb.v @@ -0,0 +1,629 @@ +// Intel megafunction declarations, to avoid Yosys complaining. +`default_nettype none + +(* blackbox *) +module altera_pll +#( + parameter reference_clock_frequency = "0 ps", + parameter fractional_vco_multiplier = "false", + parameter pll_type = "General", + parameter pll_subtype = "General", + parameter number_of_clocks = 1, + parameter operation_mode = "internal feedback", + parameter deserialization_factor = 4, + parameter data_rate = 0, + + parameter sim_additional_refclk_cycles_to_lock = 0, + parameter output_clock_frequency0 = "0 ps", + parameter phase_shift0 = "0 ps", + parameter duty_cycle0 = 50, + + parameter output_clock_frequency1 = "0 ps", + parameter phase_shift1 = "0 ps", + parameter duty_cycle1 = 50, + + parameter output_clock_frequency2 = "0 ps", + parameter phase_shift2 = "0 ps", + parameter duty_cycle2 = 50, + + parameter output_clock_frequency3 = "0 ps", + parameter phase_shift3 = "0 ps", + parameter duty_cycle3 = 50, + + parameter output_clock_frequency4 = "0 ps", + parameter phase_shift4 = "0 ps", + parameter duty_cycle4 = 50, + + parameter output_clock_frequency5 = "0 ps", + parameter phase_shift5 = "0 ps", + parameter duty_cycle5 = 50, + + parameter output_clock_frequency6 = "0 ps", + parameter phase_shift6 = "0 ps", + parameter duty_cycle6 = 50, + + parameter output_clock_frequency7 = "0 ps", + parameter phase_shift7 = "0 ps", + parameter duty_cycle7 = 50, + + parameter output_clock_frequency8 = "0 ps", + parameter phase_shift8 = "0 ps", + parameter duty_cycle8 = 50, + + parameter output_clock_frequency9 = "0 ps", + parameter phase_shift9 = "0 ps", + parameter duty_cycle9 = 50, + + + parameter output_clock_frequency10 = "0 ps", + parameter phase_shift10 = "0 ps", + parameter duty_cycle10 = 50, + + parameter output_clock_frequency11 = "0 ps", + parameter phase_shift11 = "0 ps", + parameter duty_cycle11 = 50, + + parameter output_clock_frequency12 = "0 ps", + parameter phase_shift12 = "0 ps", + parameter duty_cycle12 = 50, + + parameter output_clock_frequency13 = "0 ps", + parameter phase_shift13 = "0 ps", + parameter duty_cycle13 = 50, + + parameter output_clock_frequency14 = "0 ps", + parameter phase_shift14 = "0 ps", + parameter duty_cycle14 = 50, + + parameter output_clock_frequency15 = "0 ps", + parameter phase_shift15 = "0 ps", + parameter duty_cycle15 = 50, + + parameter output_clock_frequency16 = "0 ps", + parameter phase_shift16 = "0 ps", + parameter duty_cycle16 = 50, + + parameter output_clock_frequency17 = "0 ps", + parameter phase_shift17 = "0 ps", + parameter duty_cycle17 = 50, + + parameter clock_name_0 = "", + parameter clock_name_1 = "", + parameter clock_name_2 = "", + parameter clock_name_3 = "", + parameter clock_name_4 = "", + parameter clock_name_5 = "", + parameter clock_name_6 = "", + parameter clock_name_7 = "", + parameter clock_name_8 = "", + + parameter clock_name_global_0 = "false", + parameter clock_name_global_1 = "false", + parameter clock_name_global_2 = "false", + parameter clock_name_global_3 = "false", + parameter clock_name_global_4 = "false", + parameter clock_name_global_5 = "false", + parameter clock_name_global_6 = "false", + parameter clock_name_global_7 = "false", + parameter clock_name_global_8 = "false", + + parameter m_cnt_hi_div = 1, + parameter m_cnt_lo_div = 1, + parameter m_cnt_bypass_en = "false", + parameter m_cnt_odd_div_duty_en = "false", + parameter n_cnt_hi_div = 1, + parameter n_cnt_lo_div = 1, + parameter n_cnt_bypass_en = "false", + parameter n_cnt_odd_div_duty_en = "false", + parameter c_cnt_hi_div0 = 1, + parameter c_cnt_lo_div0 = 1, + parameter c_cnt_bypass_en0 = "false", + parameter c_cnt_in_src0 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en0 = "false", + parameter c_cnt_prst0 = 1, + parameter c_cnt_ph_mux_prst0 = 0, + parameter c_cnt_hi_div1 = 1, + parameter c_cnt_lo_div1 = 1, + parameter c_cnt_bypass_en1 = "false", + parameter c_cnt_in_src1 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en1 = "false", + parameter c_cnt_prst1 = 1, + parameter c_cnt_ph_mux_prst1 = 0, + parameter c_cnt_hi_div2 = 1, + parameter c_cnt_lo_div2 = 1, + parameter c_cnt_bypass_en2 = "false", + parameter c_cnt_in_src2 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en2 = "false", + parameter c_cnt_prst2 = 1, + parameter c_cnt_ph_mux_prst2 = 0, + parameter c_cnt_hi_div3 = 1, + parameter c_cnt_lo_div3 = 1, + parameter c_cnt_bypass_en3 = "false", + parameter c_cnt_in_src3 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en3 = "false", + parameter c_cnt_prst3 = 1, + parameter c_cnt_ph_mux_prst3 = 0, + parameter c_cnt_hi_div4 = 1, + parameter c_cnt_lo_div4 = 1, + parameter c_cnt_bypass_en4 = "false", + parameter c_cnt_in_src4 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en4 = "false", + parameter c_cnt_prst4 = 1, + parameter c_cnt_ph_mux_prst4 = 0, + parameter c_cnt_hi_div5 = 1, + parameter c_cnt_lo_div5 = 1, + parameter c_cnt_bypass_en5 = "false", + parameter c_cnt_in_src5 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en5 = "false", + parameter c_cnt_prst5 = 1, + parameter c_cnt_ph_mux_prst5 = 0, + parameter c_cnt_hi_div6 = 1, + parameter c_cnt_lo_div6 = 1, + parameter c_cnt_bypass_en6 = "false", + parameter c_cnt_in_src6 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en6 = "false", + parameter c_cnt_prst6 = 1, + parameter c_cnt_ph_mux_prst6 = 0, + parameter c_cnt_hi_div7 = 1, + parameter c_cnt_lo_div7 = 1, + parameter c_cnt_bypass_en7 = "false", + parameter c_cnt_in_src7 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en7 = "false", + parameter c_cnt_prst7 = 1, + parameter c_cnt_ph_mux_prst7 = 0, + parameter c_cnt_hi_div8 = 1, + parameter c_cnt_lo_div8 = 1, + parameter c_cnt_bypass_en8 = "false", + parameter c_cnt_in_src8 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en8 = "false", + parameter c_cnt_prst8 = 1, + parameter c_cnt_ph_mux_prst8 = 0, + parameter c_cnt_hi_div9 = 1, + parameter c_cnt_lo_div9 = 1, + parameter c_cnt_bypass_en9 = "false", + parameter c_cnt_in_src9 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en9 = "false", + parameter c_cnt_prst9 = 1, + parameter c_cnt_ph_mux_prst9 = 0, + parameter c_cnt_hi_div10 = 1, + parameter c_cnt_lo_div10 = 1, + parameter c_cnt_bypass_en10 = "false", + parameter c_cnt_in_src10 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en10 = "false", + parameter c_cnt_prst10 = 1, + parameter c_cnt_ph_mux_prst10 = 0, + parameter c_cnt_hi_div11 = 1, + parameter c_cnt_lo_div11 = 1, + parameter c_cnt_bypass_en11 = "false", + parameter c_cnt_in_src11 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en11 = "false", + parameter c_cnt_prst11 = 1, + parameter c_cnt_ph_mux_prst11 = 0, + parameter c_cnt_hi_div12 = 1, + parameter c_cnt_lo_div12 = 1, + parameter c_cnt_bypass_en12 = "false", + parameter c_cnt_in_src12 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en12 = "false", + parameter c_cnt_prst12 = 1, + parameter c_cnt_ph_mux_prst12 = 0, + parameter c_cnt_hi_div13 = 1, + parameter c_cnt_lo_div13 = 1, + parameter c_cnt_bypass_en13 = "false", + parameter c_cnt_in_src13 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en13 = "false", + parameter c_cnt_prst13 = 1, + parameter c_cnt_ph_mux_prst13 = 0, + parameter c_cnt_hi_div14 = 1, + parameter c_cnt_lo_div14 = 1, + parameter c_cnt_bypass_en14 = "false", + parameter c_cnt_in_src14 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en14 = "false", + parameter c_cnt_prst14 = 1, + parameter c_cnt_ph_mux_prst14 = 0, + parameter c_cnt_hi_div15 = 1, + parameter c_cnt_lo_div15 = 1, + parameter c_cnt_bypass_en15 = "false", + parameter c_cnt_in_src15 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en15 = "false", + parameter c_cnt_prst15 = 1, + parameter c_cnt_ph_mux_prst15 = 0, + parameter c_cnt_hi_div16 = 1, + parameter c_cnt_lo_div16 = 1, + parameter c_cnt_bypass_en16 = "false", + parameter c_cnt_in_src16 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en16 = "false", + parameter c_cnt_prst16 = 1, + parameter c_cnt_ph_mux_prst16 = 0, + parameter c_cnt_hi_div17 = 1, + parameter c_cnt_lo_div17 = 1, + parameter c_cnt_bypass_en17 = "false", + parameter c_cnt_in_src17 = "ph_mux_clk", + parameter c_cnt_odd_div_duty_en17 = "false", + parameter c_cnt_prst17 = 1, + parameter c_cnt_ph_mux_prst17 = 0, + parameter pll_vco_div = 1, + parameter pll_slf_rst = "false", + parameter pll_bw_sel = "low", + parameter pll_output_clk_frequency = "0 MHz", + parameter pll_cp_current = 0, + parameter pll_bwctrl = 0, + parameter pll_fractional_division = 1, + parameter pll_fractional_cout = 24, + parameter pll_dsm_out_sel = "1st_order", + parameter mimic_fbclk_type = "gclk", + parameter pll_fbclk_mux_1 = "glb", + parameter pll_fbclk_mux_2 = "fb_1", + parameter pll_m_cnt_in_src = "ph_mux_clk", + parameter pll_vcoph_div = 1, + parameter refclk1_frequency = "0 MHz", + parameter pll_clkin_0_src = "clk_0", + parameter pll_clkin_1_src = "clk_0", + parameter pll_clk_loss_sw_en = "false", + parameter pll_auto_clk_sw_en = "false", + parameter pll_manu_clk_sw_en = "false", + parameter pll_clk_sw_dly = 0, + parameter pll_extclk_0_cnt_src = "pll_extclk_cnt_src_vss", + parameter pll_extclk_1_cnt_src = "pll_extclk_cnt_src_vss" +) ( + //input + input refclk, + input refclk1, + input fbclk, + input rst, + input phase_en, + input updn, + input [2:0] num_phase_shifts, + input scanclk, + input [4:0] cntsel, + input [63:0] reconfig_to_pll, + input extswitch, + input adjpllin, + input cclk, + + //output + output [ number_of_clocks -1 : 0] outclk, + output fboutclk, + output locked, + output phase_done, + output [63:0] reconfig_from_pll, + output activeclk, + output [1:0] clkbad, + output [7:0] phout, + output [1:0] lvds_clk, + output [1:0] loaden, + output [1:0] extclk_out, + output [ number_of_clocks -1 : 0] cascade_out, + + //inout + inout zdbfbclk +); + +endmodule + + +(* blackbox *) +module altera_std_synchronizer(clk, din, dout, reset_n); + +parameter depth = 2; + +input clk; +input reset_n; +input din; +output dout; + +endmodule + +(* blackbox *) +module altddio_in ( + datain, // required port, DDR input data + inclock, // required port, input reference clock to sample data by + inclocken, // enable data clock + aset, // asynchronous set + aclr, // asynchronous clear + sset, // synchronous set + sclr, // synchronous clear + dataout_h, // data sampled at the rising edge of inclock + dataout_l // data sampled at the falling edge of inclock +); + +parameter width = 1; +parameter power_up_high = "OFF"; +parameter invert_input_clocks = "OFF"; +parameter intended_device_family = "Stratix"; +parameter lpm_type = "altddio_in"; +parameter lpm_hint = "UNUSED"; + +input [width-1:0] datain; +input inclock; +input inclocken; +input aset; +input aclr; +input sset; +input sclr; + +output [width-1:0] dataout_h; +output [width-1:0] dataout_l; + +endmodule + + +(* blackbox *) +module altddio_out ( + datain_h, + datain_l, + outclock, + outclocken, + aset, + aclr, + sset, + sclr, + oe, + dataout, + oe_out +); + +parameter width = 1; +parameter power_up_high = "OFF"; +parameter oe_reg = "UNUSED"; +parameter extend_oe_disable = "UNUSED"; +parameter intended_device_family = "Stratix"; +parameter invert_output = "OFF"; +parameter lpm_type = "altddio_out"; +parameter lpm_hint = "UNUSED"; + +input [width-1:0] datain_h; +input [width-1:0] datain_l; +input outclock; +input outclocken; +input aset; +input aclr; +input sset; +input sclr; +input oe; + +output [width-1:0] dataout; +output [width-1:0] oe_out; + +endmodule + + +(* blackbox *) +module altddio_bidir ( + datain_h, + datain_l, + inclock, + inclocken, + outclock, + outclocken, + aset, + aclr, + sset, + sclr, + oe, + dataout_h, + dataout_l, + combout, + oe_out, + dqsundelayedout, + padio +); + +// GLOBAL PARAMETER DECLARATION +parameter width = 1; // required parameter +parameter power_up_high = "OFF"; +parameter oe_reg = "UNUSED"; +parameter extend_oe_disable = "UNUSED"; +parameter implement_input_in_lcell = "UNUSED"; +parameter invert_output = "OFF"; +parameter intended_device_family = "Stratix"; +parameter lpm_type = "altddio_bidir"; +parameter lpm_hint = "UNUSED"; + +// INPUT PORT DECLARATION +input [width-1:0] datain_h; +input [width-1:0] datain_l; +input inclock; +input inclocken; +input outclock; +input outclocken; +input aset; +input aclr; +input sset; +input sclr; +input oe; + +// OUTPUT PORT DECLARATION +output [width-1:0] dataout_h; +output [width-1:0] dataout_l; +output [width-1:0] combout; +output [width-1:0] oe_out; +output [width-1:0] dqsundelayedout; +// BIDIRECTIONAL PORT DECLARATION +inout [width-1:0] padio; + +endmodule + + +(* blackbox *) +module altiobuf_in(datain, dataout); + +parameter enable_bus_hold = "FALSE"; +parameter use_differential_mode = "FALSE"; +parameter number_of_channels = 1; + +input [number_of_channels-1:0] datain; +output [number_of_channels-1:0] dataout; + +endmodule + +(* blackbox *) +module altiobuf_out(datain, dataout); + +parameter enable_bus_hold = "FALSE"; +parameter use_differential_mode = "FALSE"; +parameter use_oe = "FALSE"; +parameter number_of_channels = 1; + +input [number_of_channels-1:0] datain; +output [number_of_channels-1:0] dataout; + +endmodule + +(* blackbox *) +module altiobuf_bidir(dataio, oe, datain, dataout); + +parameter number_of_channels = 1; +parameter enable_bus_hold = "OFF"; + +inout [number_of_channels-1:0] dataio; +input [number_of_channels-1:0] datain; +output [number_of_channels-1:0] dataout; +input [number_of_channels-1:0] oe; + +endmodule + +(* blackbox *) +module altsyncram(clock0, clock1, address_a, data_a, rden_a, wren_a, byteena_a, q_a, addressstall_a, address_b, data_b, rden_b, wren_b, byteena_b, q_b, addressstall_b, clocken0, clocken1, clocken2, clocken3, aclr0, aclr1, eccstatus); + +parameter lpm_type = "altsyncram"; +parameter operation_mode = "dual_port"; +parameter ram_block_type = "auto"; +parameter intended_device_family = "auto"; +parameter power_up_uninitialized = "false"; +parameter read_during_write_mode_mixed_ports = "dontcare"; +parameter byte_size = 8; +parameter widthad_a = 1; +parameter width_a = 1; +parameter width_byteena_a = 1; +parameter numwords_a = 1; +parameter clock_enable_input_a = "clocken0"; +parameter widthad_b = 1; +parameter width_b = 1; +parameter numwords_b = 1; +parameter address_aclr_b = "aclr0"; +parameter address_reg_b = ""; +parameter outdata_aclr_b = "aclr0"; +parameter outdata_reg_b = ""; +parameter clock_enable_input_b = "clocken0"; +parameter clock_enable_output_b = "clocken0"; + +input clock0, clock1; +input [widthad_a-1:0] address_a; +input [width_a-1:0] data_a; +input rden_a; +input wren_a; +input [(width_a/8)-1:0] byteena_a; +input addressstall_a; + +output [width_a-1:0] q_a; + +input wren_b; +input rden_b; +input [widthad_b-1:0] address_b; +input [width_b-1:0] data_b; +input [(width_b/8)-1:0] byteena_b; +input addressstall_b; + +output [width_b-1:0] q_b; + +input clocken0; +input clocken1; +input clocken2; +input clocken3; + +input aclr0; +input aclr1; + +output eccstatus; + +endmodule + +(* blackbox *) +module cyclonev_mlab_cell(portaaddr, portadatain, portbaddr, portbdataout, ena0, clk0, clk1); + +parameter logical_ram_name = ""; +parameter logical_ram_depth = 32; +parameter logical_ram_width = 20; +parameter mixed_port_feed_through_mode = "new"; +parameter first_bit_number = 0; +parameter first_address = 0; +parameter last_address = 31; +parameter address_width = 5; +parameter data_width = 1; +parameter byte_enable_mask_width = 1; +parameter port_b_data_out_clock = "NONE"; +parameter [639:0] mem_init0 = 640'b0; + +input [address_width-1:0] portaaddr, portbaddr; +input [data_width-1:0] portadatain; +output [data_width-1:0] portbdataout; +input ena0, clk0, clk1; + +endmodule + +(* blackbox *) +module cyclonev_mac(ax, ay, resulta); + +parameter ax_width = 9; +parameter signed_max = "true"; +parameter ay_scan_in_width = 9; +parameter signed_may = "true"; +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 signed_max = "true"; +parameter ay_scan_in_width = 18; +parameter signed_may = "true"; +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 + +(* blackbox *) +module cyclonev_ram_block(portaaddr, portadatain, portawe, portbaddr, portbdataout, portbre, clk0); + +parameter operation_mode = "dual_port"; +parameter logical_ram_name = ""; +parameter port_a_address_width = 10; +parameter port_a_data_width = 10; +parameter port_a_logical_ram_depth = 1024; +parameter port_a_logical_ram_width = 10; +parameter port_a_first_address = 0; +parameter port_a_last_address = 1023; +parameter port_a_first_bit_number = 0; +parameter port_b_address_width = 10; +parameter port_b_data_width = 10; +parameter port_b_logical_ram_depth = 1024; +parameter port_b_logical_ram_width = 10; +parameter port_b_first_address = 0; +parameter port_b_last_address = 1023; +parameter port_b_first_bit_number = 0; +parameter port_b_address_clock = "clock0"; +parameter port_b_read_enable_clock = "clock0"; +parameter mem_init0 = ""; +parameter mem_init1 = ""; +parameter mem_init2 = ""; +parameter mem_init3 = ""; +parameter mem_init4 = ""; + +input [port_a_address_width-1:0] portaaddr; +input [port_b_address_width-1:0] portbaddr; +input [port_a_data_width-1:0] portadatain; +output [port_b_data_width-1:0] portbdataout; +input clk0, portawe, portbre; + +endmodule diff --git a/techlibs/intel_le/common/mem_sim.v b/techlibs/intel_le/common/mem_sim.v new file mode 100644 index 000000000..e09aafaa2 --- /dev/null +++ b/techlibs/intel_le/common/mem_sim.v @@ -0,0 +1,109 @@ +// The MLAB +// -------- +// In addition to Logic Array Blocks (LABs) that contain ten Adaptive Logic +// Modules (ALMs, see alm_sim.v), the Cyclone V/10GX also contain +// Memory/Logic Array Blocks (MLABs) that can act as either ten ALMs, or utilise +// the memory the ALM uses to store the look-up table data for general usage, +// producing a 32 address by 20-bit block of memory. MLABs are spread out +// around the chip, so they can be placed near where they are needed, rather than +// being comparatively limited in placement for a deep but narrow memory such as +// the M10K memory block. +// +// MLABs are used mainly for shallow but wide memories, such as CPU register +// files (which have perhaps 32 registers that are comparatively wide (16/32-bit)) +// or shift registers (by using the output of the Nth bit as input for the N+1th +// bit). +// +// Oddly, instead of providing a block 32 address by 20-bit cell, Quartus asks +// synthesis tools to build MLABs out of 32 address by 1-bit cells, and tries +// to put these cells in the same MLAB during cell placement. Because of this +// a MISTRAL_MLAB cell represents one of these 32 address by 1-bit cells, and +// 20 of them represent a physical MLAB. +// +// How the MLAB works +// ------------------ +// MLABs are poorly documented, so the following information is based mainly +// on the simulation model and my knowledge of how memories like these work. +// Additionally, note that the ports of MISTRAL_MLAB are the ones auto-generated +// by the Yosys `memory_bram` pass, and it doesn't make sense to me to use +// `techmap` just for the sake of renaming the cell ports. +// +// The MLAB can be initialised to any value, but unfortunately Quartus only +// allows memory initialisation from a file. Since Yosys doesn't preserve input +// file information, or write the contents of an `initial` block to a file, +// Yosys can't currently initialise the MLAB in a way Quartus will accept. +// +// The MLAB takes in data from A1DATA at the rising edge of CLK1, and if A1EN +// is high, writes it to the address in A1ADDR. A1EN can therefore be used to +// conditionally write data to the MLAB. +// +// Simultaneously, the MLAB reads data from B1ADDR, and outputs it to B1DATA, +// asynchronous to CLK1 and ignoring A1EN. If a synchronous read is needed +// then the output can be fed to embedded flops. Presently, Yosys assumes +// Quartus will pack external flops into the MLAB, but this is an assumption +// that needs testing. + +// The vendor sim model outputs 'x for a very short period (a few +// combinational delta cycles) after each write. This has been omitted from +// 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: Cyclone 10 GX timings; the below timings are for Cyclone V +specify + $setup(A1ADDR, posedge CLK1, 86); + $setup(A1DATA, posedge CLK1, 86); + $setup(A1EN, posedge CLK1, 86); + + (B1ADDR[0] => B1DATA) = 487; + (B1ADDR[1] => B1DATA) = 475; + (B1ADDR[2] => B1DATA) = 382; + (B1ADDR[3] => B1DATA) = 284; + (B1ADDR[4] => B1DATA) = 96; +endspecify + +always @(posedge CLK1) + if (A1EN) mem[A1ADDR] <= A1DATA; + +assign B1DATA = mem[B1ADDR]; + +endmodule + +// The M10K +// -------- +// TODO + +module MISTRAL_M10K(CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + +parameter CFG_ABITS = 10; +parameter CFG_DBITS = 10; + +input CLK1; +input [CFG_ABITS-1:0] A1ADDR, B1ADDR; +input [CFG_DBITS-1:0] A1DATA; +input A1EN, B1EN; +output reg [CFG_DBITS-1:0] B1DATA; + +reg [2**CFG_ABITS * CFG_DBITS - 1 : 0] mem = 0; + +specify + $setup(A1ADDR, posedge CLK1, 0); + $setup(A1DATA, posedge CLK1, 0); + + if (B1EN) (posedge CLK1 => (B1DATA : A1DATA)) = 0; +endspecify + +always @(posedge CLK1) begin + if (A1EN) + mem[(A1ADDR + 1) * CFG_DBITS - 1 : A1ADDR * CFG_DBITS] <= A1DATA; + + if (B1EN) + B1DATA <= mem[(B1ADDR + 1) * CFG_DBITS - 1 : B1ADDR * CFG_DBITS]; +end + +endmodule diff --git a/techlibs/intel_le/common/quartus_rename.v b/techlibs/intel_le/common/quartus_rename.v new file mode 100644 index 000000000..3b4628675 --- /dev/null +++ b/techlibs/intel_le/common/quartus_rename.v @@ -0,0 +1,235 @@ +`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 + +module __MISTRAL_VCC(output Q); + +MISTRAL_ALUT2 #(.LUT(4'b1111)) _TECHMAP_REPLACE_ (.A(1'b1), .B(1'b1), .Q(Q)); + +endmodule + + +module __MISTRAL_GND(output Q); + +MISTRAL_ALUT2 #(.LUT(4'b0000)) _TECHMAP_REPLACE_ (.A(1'b1), .B(1'b1), .Q(Q)); + +endmodule + + +module MISTRAL_FF(input DATAIN, CLK, ACLR, ENA, SCLR, SLOAD, SDATA, output reg Q); + +dffeas #(.power_up("low"), .is_wysiwyg("true")) _TECHMAP_REPLACE_ (.d(DATAIN), .clk(CLK), .clrn(ACLR), .ena(ENA), .sclr(SCLR), .sload(SLOAD), .asdata(SDATA), .q(Q)); + +endmodule + + +module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q); +parameter [63:0] LUT = 64'h0000_0000_0000_0000; + +`LCELL #(.lut_mask(LUT)) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .dataf(F), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT5(input A, B, C, D, E, output Q); +parameter [31:0] LUT = 32'h0000_0000; + +`LCELL #(.lut_mask({2{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT4(input A, B, C, D, output Q); +parameter [15:0] LUT = 16'h0000; + +`LCELL #(.lut_mask({4{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT3(input A, B, C, output Q); +parameter [7:0] LUT = 8'h00; + +`LCELL #(.lut_mask({8{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT2(input A, B, output Q); +parameter [3:0] LUT = 4'h0; + +`LCELL #(.lut_mask({16{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .combout(Q)); + +endmodule + + +module MISTRAL_NOT(input A, output Q); + +NOT _TECHMAP_REPLACE_ (.IN(A), .OUT(Q)); + +endmodule + + +module MISTRAL_ALUT_ARITH(input A, B, C, D0, D1, CI, output SO, CO); +parameter LUT0 = 16'h0000; +parameter LUT1 = 16'h0000; + +`LCELL #(.lut_mask({16'h0, LUT1, 16'h0, LUT0})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D0), .dataf(D1), .cin(CI), .sumout(SO), .cout(CO)); + +endmodule + + +module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN, CLK1, input [4:0] B1ADDR, output B1DATA); + +parameter _TECHMAP_CELLNAME_ = ""; + +// Here we get to an unfortunate situation. The cell has a mem_init0 parameter, +// which takes in a hexadecimal string that could be used to initialise RAM. +// In the vendor simulation models, this appears to work fine, but Quartus, +// either intentionally or not, forgets about this parameter and initialises the +// RAM to zero. +// +// Because of this, RAM initialisation is presently disabled, but the source +// used to generate mem_init0 is kept (commented out) in case this gets fixed +// or an undocumented way to get Quartus to initialise from mem_init0 is found. + +`MLAB #( + .logical_ram_name(_TECHMAP_CELLNAME_), + .logical_ram_depth(32), + .logical_ram_width(1), + .mixed_port_feed_through_mode("Dont Care"), + .first_bit_number(0), + .first_address(0), + .last_address(31), + .address_width(5), + .data_width(1), + .byte_enable_mask_width(1), + .port_b_data_out_clock("NONE"), + // .mem_init0($sformatf("%08x", INIT)) +) _TECHMAP_REPLACE_ ( + .portaaddr(A1ADDR), + .portadatain(A1DATA), + .portbaddr(B1ADDR), + .portbdataout(B1DATA), + .ena0(A1EN), + .clk0(CLK1) +); + +endmodule + + +module MISTRAL_M10K(A1ADDR, A1DATA, A1EN, CLK1, B1ADDR, B1DATA, B1EN); + +parameter CFG_ABITS = 10; +parameter CFG_DBITS = 10; + +parameter _TECHMAP_CELLNAME_ = ""; + +input [CFG_ABITS-1:0] A1ADDR, B1ADDR; +input [CFG_DBITS-1:0] A1DATA; +input CLK1, A1EN, B1EN; +output [CFG_DBITS-1:0] B1DATA; + +// Much like the MLAB, the M10K has mem_init[01234] parameters which would let +// you initialise the RAM cell via hex literals. If they were implemented. + +cyclonev_ram_block #( + .operation_mode("dual_port"), + .logical_ram_name(_TECHMAP_CELLNAME_), + .port_a_address_width(CFG_ABITS), + .port_a_data_width(CFG_DBITS), + .port_a_logical_ram_depth(2**CFG_ABITS), + .port_a_logical_ram_width(CFG_DBITS), + .port_a_first_address(0), + .port_a_last_address(2**CFG_ABITS - 1), + .port_a_first_bit_number(0), + .port_b_address_width(CFG_ABITS), + .port_b_data_width(CFG_DBITS), + .port_b_logical_ram_depth(2**CFG_ABITS), + .port_b_logical_ram_width(CFG_DBITS), + .port_b_first_address(0), + .port_b_last_address(2**CFG_ABITS - 1), + .port_b_first_bit_number(0), + .port_b_address_clock("clock0"), + .port_b_read_enable_clock("clock0") +) _TECHMAP_REPLACE_ ( + .portaaddr(A1ADDR), + .portadatain(A1DATA), + .portawe(A1EN), + .portbaddr(B1ADDR), + .portbdataout(B1DATA), + .portbre(B1EN), + .clk0(CLK1) +); + +endmodule + + +module MISTRAL_MUL27X27(input [26:0] A, B, output [53:0] Y); + +parameter A_SIGNED = 1; +parameter B_SIGNED = 1; + +`MAC #( + .ax_width(27), + .signed_max(A_SIGNED ? "true" : "false"), + .ay_scan_in_width(27), + .signed_may(B_SIGNED ? "true" : "false"), + .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); + +parameter A_SIGNED = 1; +parameter B_SIGNED = 1; + +`MAC #( + .ax_width(18), + .signed_max(A_SIGNED ? "true" : "false"), + .ay_scan_in_width(18), + .signed_may(B_SIGNED ? "true" : "false"), + .result_a_width(36), + .operation_mode("M18x18_FULL") +) _TECHMAP_REPLACE_ ( + .ax(A), + .ay(B), + .resulta(Y) +); + +endmodule + + +module MISTRAL_MUL9X9(input [8:0] A, B, output [17:0] Y); + +parameter A_SIGNED = 1; +parameter B_SIGNED = 1; + +`MAC #( + .ax_width(9), + .signed_max(A_SIGNED ? "true" : "false"), + .ay_scan_in_width(9), + .signed_may(B_SIGNED ? "true" : "false"), + .result_a_width(18), + .operation_mode("M9x9") +) _TECHMAP_REPLACE_ ( + .ax(A), + .ay(B), + .resulta(Y) +); + +endmodule diff --git a/techlibs/intel_le/cycloneiv/cells_sim.v b/techlibs/intel_le/cycloneiv/cells_sim.v new file mode 100644 index 000000000..f7abfaf14 --- /dev/null +++ b/techlibs/intel_le/cycloneiv/cells_sim.v @@ -0,0 +1,150 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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. + * + */ +module VCC (output V); + assign V = 1'b1; +endmodule // VCC + +module GND (output G); + assign G = 1'b0; +endmodule // GND + +/* Altera Cyclone IV devices Input Buffer Primitive */ +module cyclonev_io_ibuf + (output o, input i, input ibar); + assign ibar = ibar; + assign o = i; +endmodule // cyclonev_io_ibuf + +/* Altera Cyclone IV devices Output Buffer Primitive */ +module cyclonev_io_obuf + (output o, input i, input oe); + assign o = i; + assign oe = oe; +endmodule // cyclonev_io_obuf + +/* Altera Cyclone V LUT Primitive */ +module cyclonev_lcell_comb + (output combout, cout, sumout, shareout, + input dataa, datab, datac, datad, + input datae, dataf, datag, cin, + input sharein); + + parameter lut_mask = 64'hFFFFFFFFFFFFFFFF; + parameter dont_touch = "off"; + parameter lpm_type = "cyclonev_lcell_comb"; + parameter shared_arith = "off"; + parameter extended_lut = "off"; + + // Internal variables + // Sub mask for fragmented LUTs + wire [15:0] mask_a, mask_b, mask_c, mask_d; + // Independent output for fragmented LUTs + wire output_0, output_1, output_2, output_3; + // Extended mode uses mux to define the output + wire mux_0, mux_1; + // Input for hold the shared LUT mode value + wire shared_lut_alm; + + // Simulation model of 4-input LUT + function lut4; + input [15:0] mask; + input dataa, datab, datac, datad; + reg [7:0] s3; + reg [3:0] s2; + reg [1:0] s1; + begin + s3 = datad ? mask[15:8] : mask[7:0]; + s2 = datac ? s3[7:4] : s3[3:0]; + s1 = datab ? s2[3:2] : s2[1:0]; + lut4 = dataa ? s1[1] : s1[0]; + end + endfunction // lut4 + + // Simulation model of 5-input LUT + function lut5; + input [31:0] mask; // wp-01003.pdf, page 3: "a 5-LUT can be built with two 4-LUTs and a multiplexer. + input dataa, datab, datac, datad, datae; + reg upper_lut_value; + reg lower_lut_value; + begin + upper_lut_value = lut4(mask[31:16], dataa, datab, datac, datad); + lower_lut_value = lut4(mask[15:0], dataa, datab, datac, datad); + lut5 = (datae) ? upper_lut_value : lower_lut_value; + end + endfunction // lut5 + + // Simulation model of 6-input LUT + function lut6; + input [63:0] mask; + input dataa, datab, datac, datad, datae, dataf; + reg upper_lut_value; + reg lower_lut_value; + reg out_0, out_1, out_2, out_3; + begin + upper_lut_value = lut5(mask[63:32], dataa, datab, datac, datad, datae); + lower_lut_value = lut5(mask[31:0], dataa, datab, datac, datad, datae); + lut6 = (dataf) ? upper_lut_value : lower_lut_value; + end + endfunction // lut6 + + assign {mask_a, mask_b, mask_c, mask_d} = {lut_mask[15:0], lut_mask[31:16], lut_mask[47:32], lut_mask[63:48]}; +`ifdef ADVANCED_ALM + always @(*) begin + if(extended_lut == "on") + shared_lut_alm = datag; + else + shared_lut_alm = datac; + // Build the ALM behaviour + out_0 = lut4(mask_a, dataa, datab, datac, datad); + out_1 = lut4(mask_b, dataa, datab, shared_lut_alm, datad); + out_2 = lut4(mask_c, dataa, datab, datac, datad); + out_3 = lut4(mask_d, dataa, datab, shared_lut_alm, datad); + end +`else + `ifdef DEBUG + initial $display("Advanced ALM lut combine is not implemented yet"); + `endif +`endif +endmodule // cyclonev_lcell_comb + + +/* Altera D Flip-Flop Primitive */ +module dffeas + (output q, + input d, clk, clrn, prn, ena, + input asdata, aload, sclr, sload); + + // Timing simulation is not covered + parameter power_up="dontcare"; + parameter is_wysiwyg="false"; + + reg q_tmp; + wire reset; + reg [7:0] debug_net; + + assign reset = (prn && sclr && ~clrn && ena); + assign q = q_tmp & 1'b1; + + always @(posedge clk, posedge aload) begin + if(reset) q_tmp <= 0; + else q_tmp <= d; + end + assign q = q_tmp; + +endmodule // dffeas diff --git a/techlibs/intel_le/synth_intel_le.cc b/techlibs/intel_le/synth_intel_le.cc new file mode 100644 index 000000000..8c65c43fa --- /dev/null +++ b/techlibs/intel_le/synth_intel_le.cc @@ -0,0 +1,280 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Wolf + * Copyright (C) 2019 Dan Ravensloft + * + * 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 SynthIntelLEPass : public ScriptPass { + SynthIntelLEPass() : ScriptPass("synth_intel_le", "synthesis for LE-based Intel (Altera) FPGAs.") {} + + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth_intel_le [options]\n"); + log("\n"); + log("This command runs synthesis for LE-based Intel FPGAs.\n"); + log("\n"); + log(" -top \n"); + log(" use the specified module as top module\n"); + log("\n"); + log(" -family \n"); + log(" target one of:\n"); + log(" \"cycloneiv\" - Cyclone IV (default)\n"); + log("\n"); + log(" -vqm \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 :\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(" -nolutram\n"); + log(" do not use LUT RAM cells in output netlist\n"); + log("\n"); + log(" -nobram\n"); + log(" do not use block RAM cells in output netlist\n"); + log("\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(); + log("\n"); + } + + string top_opt, family_opt, bram_type, vout_file; + bool flatten, quartus, nolutram, nobram, dff, nodsp; + + void clear_flags() override + { + top_opt = "-auto-top"; + family_opt = "cycloneiv"; + bram_type = "m10k"; + vout_file = ""; + flatten = true; + quartus = false; + nolutram = false; + nobram = false; + dff = false; + nodsp = false; + } + + 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] == "-family" && argidx + 1 < args.size()) { + family_opt = args[++argidx]; + continue; + } + if (args[argidx] == "-top" && argidx + 1 < args.size()) { + top_opt = "-top " + args[++argidx]; + continue; + } + if (args[argidx] == "-vqm" && argidx + 1 < args.size()) { + quartus = true; + vout_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] == "-quartus") { + quartus = true; + continue; + } + if (args[argidx] == "-nolutram") { + nolutram = true; + continue; + } + if (args[argidx] == "-nobram") { + 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); + + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + + if (family_opt == "cycloneiv") { + bram_type = "m9k"; + } else { + log_cmd_error("Invalid family specified: '%s'\n", family_opt.c_str()); + } + + log_header(design, "Executing SYNTH_intel_le pass.\n"); + log_push(); + + run_script(design, run_from, run_to); + + log_pop(); + } + + void script() override + { + if (help_mode) { + family_opt = ""; + bram_type = ""; + } + + if (check_label("begin")) { + if (family_opt == "cyclonev") + run(stringf("read_verilog -sv -lib +/intel_le/%s/cells_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s +/intel_le/common/alm_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s +/intel_le/common/dff_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s +/intel_le/common/dsp_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s +/intel_le/common/mem_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s -icells +/intel_le/common/abc9_model.v", family_opt.c_str())); + + // Misc and common cells + run("read_verilog -lib +/intel/common/altpll_bb.v"); + run("read_verilog -lib +/intel_le/common/megafunction_bb.v"); + run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt.c_str())); + } + + if (check_label("coarse")) { + run("proc"); + if (flatten || help_mode) + run("flatten", "(skip if -noflatten)"); + run("tribuf -logic"); + run("deminout"); + run("opt_expr"); + run("opt_clean"); + run("check"); + run("opt -nodffe -nosdff"); + run("fsm"); + run("opt"); + run("wreduce"); + run("peepopt"); + run("opt_clean"); + run("share"); + run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); + run("opt_expr"); + run("opt_clean"); + run("alumacc"); + run("techmap -map +/intel_le/common/arith_alm_map.v -map +/intel_le/common/dsp_map.v"); + run("opt"); + run("memory -nomap"); + run("opt_clean"); + } + + if (!nobram && check_label("map_bram", "(skip if -nobram)")) { + run(stringf("memory_bram -rules +/intel_le/common/bram_%s.txt", bram_type.c_str())); + if (help_mode || bram_type != "m9k") + run(stringf("techmap -map +/intel_le/common/bram_%s_map.v", bram_type.c_str())); + } + + if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) { + run("memory_bram -rules +/intel_le/common/lutram_mlab.txt", "(for Cyclone IV )"); + } + + if (check_label("map_ffram")) { + run("memory_map"); + run("opt -full"); + } + + if (check_label("map_ffs")) { + run("techmap"); + run("dfflegalize -cell $_DFFE_PN0P_ 0 -cell $_SDFFCE_PP0P_ 0"); + run("techmap -map +/intel_le/common/dff_map.v"); + run("opt -full -undriven -mux_undef"); + run("clean -purge"); + } + + if (check_label("map_luts")) { + run("techmap -map +/intel_le/common/abc9_map.v"); + run(stringf("abc9 %s -maxlut 6 -W 600", help_mode ? "[-dff]" : dff ? "-dff" : "")); + run("techmap -map +/intel_le/common/abc9_unmap.v"); + run("techmap -map +/intel_le/common/alm_map.v"); + run("opt -fast"); + run("autoname"); + run("clean"); + } + + if (check_label("check")) { + run("hierarchy -check"); + run("stat"); + run("check"); + } + + if (check_label("quartus")) { + if (quartus || help_mode) { + // Quartus ICEs if you have a wire which has `[]` in its name, + // which Yosys produces when building memories out of flops. + run("rename -hide w:*[* w:*]*"); + // VQM mode does not support 'x, so replace those with zero. + run("setundef -zero"); + // VQM mode does not support multi-bit constant assignments + // (e.g. 2'b00 is an error), so as a workaround use references + // to constant driver cells, which Quartus accepts. + run("hilomap -singleton -hicell __MISTRAL_VCC Q -locell __MISTRAL_GND Q"); + // Rename from Yosys-internal MISTRAL_* cells to Quartus cells. + run(stringf("techmap -D %s -map +/intel_le/common/quartus_rename.v", family_opt.c_str())); + } + } + + if (check_label("vqm")) { + if (!vout_file.empty() || help_mode) { + run(stringf("write_verilog -attr2comment -defparam -nohex -decimal %s", help_mode ? "" : vout_file.c_str())); + } + } + } +} SynthIntelLEPass; + +PRIVATE_NAMESPACE_END diff --git a/tests/arch/intel_le/add_sub.ys b/tests/arch/intel_le/add_sub.ys new file mode 100644 index 000000000..ac75935b7 --- /dev/null +++ b/tests/arch/intel_le/add_sub.ys @@ -0,0 +1,18 @@ +read_verilog ../common/add_sub.v +hierarchy -top top +equiv_opt -assert -map +/intel_le/common/alm_sim.v synth_intel_le -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 8 t:MISTRAL_ALUT_ARITH +select -assert-none t:MISTRAL_ALUT_ARITH %% t:* %D + +design -reset +read_verilog ../common/add_sub.v +hierarchy -top top +equiv_opt -assert -map +/intel_le/common/alm_sim.v synth_intel_le -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 +stat +select -assert-count 8 t:MISTRAL_ALUT_ARITH +select -assert-none t:MISTRAL_ALUT_ARITH %% t:* %D diff --git a/tests/arch/intel_le/adffs.ys b/tests/arch/intel_le/adffs.ys new file mode 100644 index 000000000..ec0085d65 --- /dev/null +++ b/tests/arch/intel_le/adffs.ys @@ -0,0 +1,94 @@ +read_verilog ../common/adffs.v +design -save read + +hierarchy -top adff +proc +equiv_opt -async2sync -assert -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd adff # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF +select -assert-count 1 t:MISTRAL_NOT + +select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% t:* %D + + +design -load read +hierarchy -top adff +proc +equiv_opt -async2sync -assert -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd adff # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF +select -assert-count 1 t:MISTRAL_NOT + +select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% t:* %D + + +design -load read +hierarchy -top adffn +proc +equiv_opt -async2sync -assert -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd adffn # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF + +select -assert-none t:MISTRAL_FF %% t:* %D + + +design -load read +hierarchy -top adffn +proc +equiv_opt -async2sync -assert -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd adffn # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF + +select -assert-none t:MISTRAL_FF %% t:* %D + + +design -load read +hierarchy -top dffs +proc +equiv_opt -async2sync -assert -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd dffs # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF +select -assert-count 1 t:MISTRAL_ALUT2 + +select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 %% t:* %D + + +design -load read +hierarchy -top dffs +proc +equiv_opt -async2sync -assert -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd dffs # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF +select -assert-count 1 t:MISTRAL_ALUT2 + +select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 %% t:* %D + + +design -load read +hierarchy -top ndffnr +proc +equiv_opt -async2sync -assert -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd ndffnr # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF +select -assert-count 2 t:MISTRAL_NOT + +select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% t:* %D + + +design -load read +hierarchy -top ndffnr +proc +equiv_opt -async2sync -assert -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd ndffnr # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF +select -assert-count 2 t:MISTRAL_NOT + +select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% t:* %D diff --git a/tests/arch/intel_le/blockram.ys b/tests/arch/intel_le/blockram.ys new file mode 100644 index 000000000..ce7502571 --- /dev/null +++ b/tests/arch/intel_le/blockram.ys @@ -0,0 +1,6 @@ +read_verilog ../common/blockram.v +chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 10 sync_ram_sdp +synth_intel_le -family cyclonev +cd sync_ram_sdp +select -assert-count 1 t:MISTRAL_M10K +select -assert-none t:MISTRAL_M10K %% t:* %D diff --git a/tests/arch/intel_le/counter.ys b/tests/arch/intel_le/counter.ys new file mode 100644 index 000000000..147b3d4c0 --- /dev/null +++ b/tests/arch/intel_le/counter.ys @@ -0,0 +1,27 @@ +read_verilog ../common/counter.v +hierarchy -top top +proc +flatten +equiv_opt -async2sync -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -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 + +select -assert-count 2 t:MISTRAL_NOT +select -assert-count 8 t:MISTRAL_ALUT_ARITH +select -assert-count 8 t:MISTRAL_FF +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT_ARITH t:MISTRAL_FF %% t:* %D + + +design -reset +read_verilog ../common/counter.v +hierarchy -top top +proc +flatten +equiv_opt -async2sync -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -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 + +select -assert-count 2 t:MISTRAL_NOT +select -assert-count 8 t:MISTRAL_ALUT_ARITH +select -assert-count 8 t:MISTRAL_FF +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT_ARITH t:MISTRAL_FF %% t:* %D diff --git a/tests/arch/intel_le/dffs.ys b/tests/arch/intel_le/dffs.ys new file mode 100644 index 000000000..484e4b7ba --- /dev/null +++ b/tests/arch/intel_le/dffs.ys @@ -0,0 +1,43 @@ +read_verilog ../common/dffs.v +design -save read + +hierarchy -top dff +proc +equiv_opt -async2sync -assert -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd dff # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF + +select -assert-none t:MISTRAL_FF %% t:* %D + +design -load read +hierarchy -top dff +proc +equiv_opt -async2sync -assert -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd dff # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF + +select -assert-none t:MISTRAL_FF %% t:* %D + + +design -load read +hierarchy -top dffe +proc +equiv_opt -async2sync -assert -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd dffe # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF + +select -assert-none t:MISTRAL_FF %% t:* %D + + +design -load read +hierarchy -top dffe +proc +equiv_opt -async2sync -assert -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd dffe # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF + +select -assert-none t:MISTRAL_FF %% t:* %D diff --git a/tests/arch/intel_le/fsm.ys b/tests/arch/intel_le/fsm.ys new file mode 100644 index 000000000..0bccaf549 --- /dev/null +++ b/tests/arch/intel_le/fsm.ys @@ -0,0 +1,44 @@ +read_verilog ../common/fsm.v +hierarchy -top fsm +proc +flatten + +equiv_opt -run :prove -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cyclonev +async2sync +miter -equiv -make_assert -flatten gold gate miter +sat -verify -prove-asserts -show-public -set-at 1 in_reset 1 -seq 20 -prove-skip 1 miter + +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd fsm # Constrain all select calls below inside the top module + +select -assert-count 6 t:MISTRAL_FF +select -assert-max 1 t:MISTRAL_NOT +select -assert-max 2 t:MISTRAL_ALUT2 # Clang returns 2, GCC returns 1 +select -assert-max 1 t:MISTRAL_ALUT3 +select -assert-max 2 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_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_ALUT4 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D + +design -reset +read_verilog ../common/fsm.v +hierarchy -top fsm +proc +flatten + +equiv_opt -run :prove -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cyclone10gx +async2sync +miter -equiv -make_assert -flatten gold gate miter +sat -verify -prove-asserts -show-public -set-at 1 in_reset 1 -seq 20 -prove-skip 1 miter + +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd fsm # Constrain all select calls below inside the top module + +select -assert-count 6 t:MISTRAL_FF +select -assert-max 1 t:MISTRAL_NOT +select -assert-max 2 t:MISTRAL_ALUT2 # Clang returns 2, GCC returns 1 +select -assert-max 2 t:MISTRAL_ALUT3 # Clang returns 2, GCC returns 1 +select -assert-max 2 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_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_ALUT4 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D diff --git a/tests/arch/intel_le/logic.ys b/tests/arch/intel_le/logic.ys new file mode 100644 index 000000000..689c9908f --- /dev/null +++ b/tests/arch/intel_le/logic.ys @@ -0,0 +1,25 @@ +read_verilog ../common/logic.v +hierarchy -top top +proc +equiv_opt -assert -map +/intel_le/common/alm_sim.v synth_intel_le -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 + +select -assert-count 1 t:MISTRAL_NOT +select -assert-count 6 t:MISTRAL_ALUT2 +select -assert-count 2 t:MISTRAL_ALUT4 +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT4 %% t:* %D + + +design -reset +read_verilog ../common/logic.v +hierarchy -top top +proc +equiv_opt -assert -map +/intel_le/common/alm_sim.v synth_intel_le -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 + +select -assert-count 1 t:MISTRAL_NOT +select -assert-count 6 t:MISTRAL_ALUT2 +select -assert-count 2 t:MISTRAL_ALUT4 +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT4 %% t:* %D \ No newline at end of file diff --git a/tests/arch/intel_le/lutram.ys b/tests/arch/intel_le/lutram.ys new file mode 100644 index 000000000..f08bb1c7c --- /dev/null +++ b/tests/arch/intel_le/lutram.ys @@ -0,0 +1,41 @@ +read_verilog ../common/lutram.v +hierarchy -top lutram_1w1r +proc +memory -nomap +equiv_opt -run :prove -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v -map +/intel_le/common/mem_sim.v synth_intel_le -family cyclonev -nobram +memory +opt -full + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter + +design -load postopt +cd lutram_1w1r +select -assert-count 16 t:MISTRAL_MLAB +select -assert-count 1 t:MISTRAL_NOT +select -assert-count 2 t:MISTRAL_ALUT2 +select -assert-count 8 t:MISTRAL_ALUT3 +select -assert-count 17 t:MISTRAL_FF +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_FF t:MISTRAL_MLAB %% t:* %D + + +design -reset +read_verilog ../common/lutram.v +hierarchy -top lutram_1w1r +proc +memory -nomap +equiv_opt -run :prove -map +/intel_le/common/alm_sim.v -map +/intel_le/common/dff_sim.v -map +/intel_le/common/mem_sim.v synth_intel_le -family cyclonev -nobram +memory +opt -full + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter + +design -load postopt +cd lutram_1w1r +select -assert-count 16 t:MISTRAL_MLAB +select -assert-count 1 t:MISTRAL_NOT +select -assert-count 2 t:MISTRAL_ALUT2 +select -assert-count 8 t:MISTRAL_ALUT3 +select -assert-count 17 t:MISTRAL_FF +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_FF t:MISTRAL_MLAB %% t:* %D diff --git a/tests/arch/intel_le/mul.ys b/tests/arch/intel_le/mul.ys new file mode 100644 index 000000000..e0b8e8142 --- /dev/null +++ b/tests/arch/intel_le/mul.ys @@ -0,0 +1,60 @@ +read_verilog ../common/mul.v +chparam -set X_WIDTH 8 -set Y_WIDTH 8 -set A_WIDTH 16 +hierarchy -top top +proc +equiv_opt -assert -map +/intel_le/common/dsp_sim.v synth_intel_le -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 + +select -assert-count 1 t:MISTRAL_MUL9X9 +select -assert-none t:MISTRAL_MUL9X9 %% t:* %D + +# Cyclone 10 GX does not have 9x9 multipliers. + +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 17 -set Y_WIDTH 17 -set A_WIDTH 34 +hierarchy -top top +proc +equiv_opt -assert -map +/intel_le/common/dsp_sim.v synth_intel_le -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 + +select -assert-count 1 t:MISTRAL_MUL18X18 +select -assert-none t:MISTRAL_MUL18X18 %% t:* %D + +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 17 -set Y_WIDTH 17 -set A_WIDTH 34 +hierarchy -top top +proc +equiv_opt -assert -map +/intel_le/common/dsp_sim.v synth_intel_le -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 + +select -assert-count 1 t:MISTRAL_MUL18X18 +select -assert-none t:MISTRAL_MUL18X18 %% t:* %D + +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 26 -set Y_WIDTH 26 -set A_WIDTH 52 +hierarchy -top top +proc +equiv_opt -assert -map +/intel_le/common/dsp_sim.v synth_intel_le -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 + +select -assert-count 1 t:MISTRAL_MUL27X27 +select -assert-none t:MISTRAL_MUL27X27 %% t:* %D + +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 26 -set Y_WIDTH 26 -set A_WIDTH 52 +hierarchy -top top +proc +equiv_opt -assert -map +/intel_le/common/dsp_sim.v synth_intel_le -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 + +select -assert-count 1 t:MISTRAL_MUL27X27 +select -assert-none t:MISTRAL_MUL27X27 %% t:* %D diff --git a/tests/arch/intel_le/mux.ys b/tests/arch/intel_le/mux.ys new file mode 100644 index 000000000..67bdabae1 --- /dev/null +++ b/tests/arch/intel_le/mux.ys @@ -0,0 +1,88 @@ +read_verilog ../common/mux.v +design -save read + + +hierarchy -top mux2 +proc +equiv_opt -assert -map +/intel_le/common/alm_sim.v synth_intel_le -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux2 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT3 +select -assert-none t:MISTRAL_ALUT3 %% t:* %D + + +design -load read +hierarchy -top mux2 +proc +equiv_opt -assert -map +/intel_le/common/alm_sim.v synth_intel_le -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux2 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT3 +select -assert-none t:MISTRAL_ALUT3 %% t:* %D + + +design -load read +hierarchy -top mux4 +proc +equiv_opt -assert -map +/intel_le/common/alm_sim.v synth_intel_le -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux4 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT6 +select -assert-none t:MISTRAL_ALUT6 %% t:* %D + + +design -load read +hierarchy -top mux4 +proc +equiv_opt -assert -map +/intel_le/common/alm_sim.v synth_intel_le -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux4 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT6 +select -assert-none t:MISTRAL_ALUT6 %% t:* %D + + +design -load read +hierarchy -top mux8 +proc +equiv_opt -assert -map +/intel_le/common/alm_sim.v synth_intel_le -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux8 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT3 +select -assert-count 2 t:MISTRAL_ALUT6 +select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT6 %% t:* %D + + +design -load read +hierarchy -top mux8 +proc +equiv_opt -assert -map +/intel_le/common/alm_sim.v synth_intel_le -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux8 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT3 +select -assert-count 2 t:MISTRAL_ALUT6 +select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT6 %% t:* %D + + +design -load read +hierarchy -top mux16 +proc +equiv_opt -assert -map +/intel_le/common/alm_sim.v synth_intel_le -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux16 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT3 +select -assert-max 2 t:MISTRAL_ALUT5 +select -assert-max 5 t:MISTRAL_ALUT6 +select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D + + +design -load read +hierarchy -top mux16 +proc +equiv_opt -assert -map +/intel_le/common/alm_sim.v synth_intel_le -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux16 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT3 +select -assert-count 2 t:MISTRAL_ALUT5 +select -assert-count 4 t:MISTRAL_ALUT6 + +select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D diff --git a/tests/arch/intel_le/quartus_ice.ys b/tests/arch/intel_le/quartus_ice.ys new file mode 100644 index 000000000..0f15f4d86 --- /dev/null +++ b/tests/arch/intel_le/quartus_ice.ys @@ -0,0 +1,26 @@ +read_verilog <