diff --git a/techlibs/intel_le/Makefile.inc b/techlibs/intel_le/Makefile.inc new file mode 100644 index 000000000..06b1c5a84 --- /dev/null +++ b/techlibs/intel_le/Makefile.inc @@ -0,0 +1,22 @@ + +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/le_map.v)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/le_sim.v)) +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/arith_le_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/mem_sim.v)) + +$(eval $(call add_share_file,share/intel_le/cycloneiv,techlibs/intel_le/cycloneiv/cells_sim.v)) + +# RAM +$(eval $(call add_share_file,share/intel_le/common,techlibs/intel_le/common/bram_m9k.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_le_map.v b/techlibs/intel_le/common/arith_le_map.v new file mode 100644 index 000000000..2a3c7cebe --- /dev/null +++ b/techlibs/intel_le/common/arith_le_map.v @@ -0,0 +1,66 @@ +`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-1:0] BTOADDER; +wire [Y_WIDTH:0] LE_CARRY; + + +// Start of carry chain +generate + if (_TECHMAP_CONSTMSK_CI_ == 1) begin + assign LE_CARRY[0] = _TECHMAP_CONSTVAL_CI_; + end else begin + + assign LE_CARRY[0] = CI; + end +endgenerate + +// Carry chain +genvar i; +generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice + + MISTRAL_ALUT_ARITH #( + .LUT(16'b1001_0110_1110_1000), // SUM = A xor B xor CI + // CARRYi+1 = A and B or A and CI or B and CI + + ) le_i ( + .A(AA[i]), .B(BB[i]), .C(1'b1), .D(1'b1), + .CI(LE_CARRY[i]), + .SO(Y[i]), + .CO(LE_CARRY[i+1]) + ); + +end endgenerate + +assign X = AA ^ BB; + +endmodule diff --git a/techlibs/intel_le/common/bram_m9k.txt b/techlibs/intel_le/common/bram_m9k.txt new file mode 100644 index 000000000..2a19ccf3b --- /dev/null +++ b/techlibs/intel_le/common/bram_m9k.txt @@ -0,0 +1,32 @@ +bram MISTRAL_M9K + 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 + dbits 4 @D2048x4 + abits 10 @D1024x8 @D1024x9 + dbits 8 @D1024x8 + dbits 9 @D1024x9 + abits 9 @D512x16 @D512x18 + dbits 16 @D512x16 + dbits 18 @D512x18 + abits 8 @D256x32 @D256x36 + dbits 32 @D256x32 + dbits 36 @D256x36 + 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_M9K + min efficiency 5 + make_transp +endmatch 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..cb3a01185 --- /dev/null +++ b/techlibs/intel_le/common/dff_sim.v @@ -0,0 +1,90 @@ +// 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 cycloneiv +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 + +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/le_map.v b/techlibs/intel_le/common/le_map.v new file mode 100644 index 000000000..a1881e17a --- /dev/null +++ b/techlibs/intel_le/common/le_map.v @@ -0,0 +1,47 @@ +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 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..50a25cb4b --- /dev/null +++ b/techlibs/intel_le/common/le_sim.v @@ -0,0 +1,127 @@ +// The core logic primitive of the Cyclone IVE/IVGX is the Logic Element +// (LE). Each LE is made up of an 4-input, 1-output look-up table, covered +// in this file, connected to combinational outputs, a carry chain, and one +// D flip-flop (which are covered as MISTRAL_FF in dff_sim.v). +// +// LEs are have two modes of operation +// +// Normal (combinational) mode +// --------------------------- +// The LE can implement: +// - a single 4-input(or less) function +// +// Normal-mode functions are represented as MISTRAL_ALUTN cells with N inputs. +// +// Arithmetic mode +// --------------- +// In arithmetic mode, LE implements two bit adder and carry chain +// It can drive either registered or unregistered output. +// +// The cell for an arithmetic-mode is MISTRAL_ALM_ARITH. +// + +`default_nettype none + +// Cyclone V LUT output timings (picoseconds): +// +// CARRY A B C D +// COMBOUT ?408? 332 337 220 119 +// CARRYOUT 200 376 385 ? - + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_ALUT4(input A, B, C, D, output Q); + +parameter [15:0] LUT = 16'h0000; + +`ifdef cycloneiv +specify + (A => Q) = 337; + (B => Q) = 332; + (C => Q) = 220; + (D => Q) = 119; +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 cycloneiv +specify + (A => Q) = 332; + (B => Q) = 220; + (C => Q) = 119; +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 cycloneiv +specify + (A => Q) = 220; + (B => Q) = 119; +endspecify +`endif +assign Q = LUT >> {B, A}; + +endmodule + + +(* abc9_lut=1, lib_whitebox *) +module MISTRAL_NOT(input A, output Q); + +`ifdef cycloneiv +specify + (A => Q) = 119; +endspecify +`endif +assign Q = ~A; + +endmodule + +(* abc9_box, lib_whitebox *) +module MISTRAL_ALUT_ARITH(input A, B, C, D, (* abc9_carry *) input CI, output SO, (* abc9_carry *) output CO); + +parameter LUT = 16'h0000; + + +`ifdef cycloneiv +specify + (A => SO) = 337; + (B => SO) = 332; + (C => SO) = 220; + (D => SO) = 119; + (CI => SO) = 08; + + (A => CO) = 385; + (B => CO) = 376; + (CI => CO) = 200; +endspecify +`endif +wire q0, q1; + + +assign q0 = LUT >> {'b0, CI, B, A}; +assign q1 = LUT >> {D, CI, B, A}; + +assign SO = q1; + +assign CO = q0; + +endmodule + + diff --git a/techlibs/intel_le/common/megafunction_bb.v b/techlibs/intel_le/common/megafunction_bb.v new file mode 100644 index 000000000..8eaaa62b8 --- /dev/null +++ b/techlibs/intel_le/common/megafunction_bb.v @@ -0,0 +1,592 @@ +// 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 cycloneiv_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 cycloneiv_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..b2734b161 --- /dev/null +++ b/techlibs/intel_le/common/mem_sim.v @@ -0,0 +1,34 @@ + +// The M9K +// -------- +// TODO + +module MISTRAL_M9K(CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + +parameter CFG_ABITS = 9; +parameter CFG_DBITS = 9; + +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..7ad5c6283 --- /dev/null +++ b/techlibs/intel_le/common/quartus_rename.v @@ -0,0 +1,116 @@ +`ifdef cycloneiv + `define LCELL cycloneiv_lcell_comb + `define M9K cycloneiv_ram_block +`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_ALUT4(input A, B, C, D, output Q); +parameter [15:0] LUT = 16'h0000; + +`LCELL #(.lut_mask(LUT),.sum_lutc_input("datac")) _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({2{LUT}}),.sum_lutc_input("datac")) _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({4{LUT}}),.sum_lutc_input("datac")) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .combout(Q)); + +endmodule + + +module MISTRAL_NOT(input A, output Q); + +//NOT _TECHMAP_REPLACE_ (.IN(A), .OUT(Q)); +assign Q = ~A; +endmodule + + +module MISTRAL_LE_LUT_ARITH(input A, B, C, D, CI, output SO, CO); +parameter LUT = 16'h0000; + +`LCELL #(.lut_mask({LUT}),.sum_lutc_input("cin")) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .cin(CI), .combout(SO), .cout(CO)); + +endmodule + + + +module MISTRAL_M9K(A1ADDR, A1DATA, A1EN, CLK1, B1ADDR, B1DATA, B1EN); + +parameter CFG_ABITS = 9; +parameter CFG_DBITS = 9; + +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; + +// The M9K has mem_init[01234] parameters which would let +// you initialise the RAM cell via hex literals. If they were implemented. + +`M9K #( + .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 + + diff --git a/techlibs/intel_le/cycloneiv/cells_sim.v b/techlibs/intel_le/cycloneiv/cells_sim.v new file mode 100644 index 000000000..7be70eef5 --- /dev/null +++ b/techlibs/intel_le/cycloneiv/cells_sim.v @@ -0,0 +1,61 @@ + +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 cycloneiv_io_ibuf + (output o, input i, input ibar); + assign ibar = ibar; + assign o = i; +endmodule // cycloneiv_io_ibuf + +/* Altera Cyclone IV devices Output Buffer Primitive */ +module cycloneiv_io_obuf + (output o, input i, input oe); + assign o = i; + assign oe = oe; +endmodule // cycloneiv_io_obuf + +/* Altera Cyclone IV LUT Primitive */ +module cycloneiv_lcell_comb + (output combout, cout, + input dataa, datab, datac, datad, cin); + + parameter lut_mask = 16'hFFFF; + parameter dont_touch = "off"; + parameter lpm_type = "cycloneiv_lcell_comb"; + parameter sum_lutc_input = "datac"; + + +endmodule // cycloneiv_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..044a826bf --- /dev/null +++ b/techlibs/intel_le/synth_intel_le.cc @@ -0,0 +1,265 @@ +/* + * 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(" -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, nobram, dff, nodsp; + + void clear_flags() override + { + top_opt = "-auto-top"; + family_opt = "cycloneiv"; + bram_type = "m9k"; + vout_file = ""; + flatten = true; + quartus = 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] == "-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 == "cycloneiv") + run(stringf("read_verilog -sv -lib +/intel_le/cycloneiv/cells_sim.v")); + run(stringf("read_verilog -specify -lib -D %s +/intel_le/common/le_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/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_le_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 (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 4 -W 400", help_mode ? "[-dff]" : dff ? "-dff" : "")); + run("techmap -map +/intel_le/common/abc9_unmap.v"); + run("techmap -map +/intel_le/common/le_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..f6d3af729 --- /dev/null +++ b/tests/arch/intel_le/add_sub.ys @@ -0,0 +1,12 @@ +read_verilog ../common/add_sub.v +hierarchy -top top +equiv_opt -assert -map +/intel_le/common/le_sim.v synth_intel_le -family cycloneiv # 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-count 4 t:MISTRAL_NOT +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT_ARITH %% t:* %D + + +design -reset diff --git a/tests/arch/intel_le/adffs.ys b/tests/arch/intel_le/adffs.ys new file mode 100644 index 000000000..0086220f9 --- /dev/null +++ b/tests/arch/intel_le/adffs.ys @@ -0,0 +1,49 @@ +read_verilog ../common/adffs.v +design -save read + +hierarchy -top adff +proc +equiv_opt -async2sync -assert -map +/intel_le/common/le_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cycloneiv # 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/le_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cycloneiv # 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/le_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cycloneiv # 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/le_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cycloneiv # 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..8d260dbc3 --- /dev/null +++ b/tests/arch/intel_le/blockram.ys @@ -0,0 +1,6 @@ +read_verilog ../common/blockram.v +chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 9 sync_ram_sdp +synth_intel_le -family cycloneiv +cd sync_ram_sdp +select -assert-count 1 t:MISTRAL_M9K +select -assert-none t:MISTRAL_M9K %% t:* %D diff --git a/tests/arch/intel_le/counter.ys b/tests/arch/intel_le/counter.ys new file mode 100644 index 000000000..13295a747 --- /dev/null +++ b/tests/arch/intel_le/counter.ys @@ -0,0 +1,16 @@ +read_verilog ../common/counter.v +hierarchy -top top +proc +flatten +equiv_opt -async2sync -map +/intel_le/common/le_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cycloneiv # 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 + diff --git a/tests/arch/intel_le/dffs.ys b/tests/arch/intel_le/dffs.ys new file mode 100644 index 000000000..03d40efc2 --- /dev/null +++ b/tests/arch/intel_le/dffs.ys @@ -0,0 +1,24 @@ +read_verilog ../common/dffs.v +design -save read + +hierarchy -top dff +proc +equiv_opt -async2sync -assert -map +/intel_le/common/le_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cycloneiv # 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/le_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cycloneiv # 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..f26165ff8 --- /dev/null +++ b/tests/arch/intel_le/fsm.ys @@ -0,0 +1,21 @@ +read_verilog ../common/fsm.v +hierarchy -top fsm +proc +flatten + +equiv_opt -run :prove -map +/intel_le/common/le_sim.v -map +/intel_le/common/dff_sim.v synth_intel_le -family cycloneiv +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 5 t:MISTRAL_ALUT2 # +select -assert-max 1 t:MISTRAL_ALUT3 +select -assert-max 9 t:MISTRAL_ALUT4 # +select -assert-none t:MISTRAL_FF t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_ALUT4 %% t:* %D + +design -reset diff --git a/tests/arch/intel_le/logic.ys b/tests/arch/intel_le/logic.ys new file mode 100644 index 000000000..0e7beff53 --- /dev/null +++ b/tests/arch/intel_le/logic.ys @@ -0,0 +1,14 @@ +read_verilog ../common/logic.v +hierarchy -top top +proc +equiv_opt -assert -map +/intel_le/common/le_sim.v synth_intel_le -family cycloneiv # 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 diff --git a/tests/arch/intel_le/mux.ys b/tests/arch/intel_le/mux.ys new file mode 100644 index 000000000..169cef00c --- /dev/null +++ b/tests/arch/intel_le/mux.ys @@ -0,0 +1,45 @@ +read_verilog ../common/mux.v +design -save read + + +hierarchy -top mux2 +proc +equiv_opt -assert -map +/intel_le/common/le_sim.v synth_intel_le -family cycloneiv # 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/le_sim.v synth_intel_le -family cycloneiv # 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 3 t:MISTRAL_ALUT3 +select -assert-none t:MISTRAL_ALUT3 %% t:* %D + + + +design -load read +hierarchy -top mux8 +proc +equiv_opt -assert -map +/intel_le/common/le_sim.v synth_intel_le -family cycloneiv # 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 3 t:MISTRAL_ALUT2 +select -assert-count 5 t:MISTRAL_ALUT4 +select -assert-none t:MISTRAL_ALUT2 t:MISTRAL_ALUT4 %% t:* %D + + +design -load read +hierarchy -top mux16 +proc +equiv_opt -assert -map +/intel_le/common/le_sim.v synth_intel_le -family cycloneiv # 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-max 3 t:MISTRAL_ALUT3 +select -assert-max 10 t:MISTRAL_ALUT4 +select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT4 %% 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..ef843f1c3 --- /dev/null +++ b/tests/arch/intel_le/quartus_ice.ys @@ -0,0 +1,14 @@ +read_verilog <