Merge pull request #2335 from nelsobe/master
Change MMCME2 advanced COMPENSATION parameter to have a default of INTERNAL
diff --git a/xc/xc7/techmap/cells_map.v b/xc/xc7/techmap/cells_map.v
index e421d5a..51554c7 100644
--- a/xc/xc7/techmap/cells_map.v
+++ b/xc/xc7/techmap/cells_map.v
@@ -4790,7 +4790,17 @@
parameter BANDWIDTH = "OPTIMIZED";
parameter STARTUP_WAIT = "FALSE";
- parameter COMPENSATION = "ZHOLD";
+
+// Previously, the default COMPENSATION value was ZHOLD, resulting in non-functional
+// bitstreams when the feedback loop is closed on-chip.
+ // Setting it to INTERNAL as the default creates working bitstreams for that case.
+// This bug was not previously uncovered since the MMCM tests all explicitly
+// specified a COMPENSATION value so the ZHOLD default was never used.
+// Setting it here in the techmapper means that existing code using on-chip
+// MMCM feedback without specifying a COMPENSATION value can be ported
+// unmodified into the toolflow and will result in functional bitstreams.
+// A test was added to test the case when relying on the default COMPENSATION value.
+ parameter COMPENSATION = "INTERNAL";
parameter CLKIN1_PERIOD = 0.0;
parameter REF_JITTER1 = 0.01;
diff --git a/xc/xc7/tests/mmcm/CMakeLists.txt b/xc/xc7/tests/mmcm/CMakeLists.txt
index 85f7f79..2eaa87a 100644
--- a/xc/xc7/tests/mmcm/CMakeLists.txt
+++ b/xc/xc7/tests/mmcm/CMakeLists.txt
@@ -57,6 +57,7 @@
add_file_target(FILE mmcme2_test.v SCANNER_TYPE verilog)
add_file_target(FILE mmcm_int_basys3_bottom.v SCANNER_TYPE verilog)
+add_file_target(FILE mmcm_none_basys3_bottom.v SCANNER_TYPE verilog)
add_file_target(FILE mmcm_buf_basys3_bottom.v SCANNER_TYPE verilog)
add_file_target(FILE mmcm_ext_basys3_bottom.v SCANNER_TYPE verilog)
add_file_target(FILE mmcm_int_frac_basys3_bottom.v SCANNER_TYPE verilog)
@@ -78,6 +79,14 @@
)
add_fpga_target(
+ NAME mmcm_none_basys3
+ BOARD basys3-bottom
+ SOURCES mmcm_none_basys3_bottom.v
+ INPUT_IO_FILE ${COMMON}/basys3_bottom_pmod.pcf
+ EXPLICIT_ADD_FILE_TARGET
+ )
+
+add_fpga_target(
NAME mmcm_buf_basys3
BOARD basys3-bottom
SOURCES mmcm_buf_basys3_bottom.v
@@ -117,6 +126,13 @@
)
add_vivado_target(
+ NAME mmcm_none_basys3_vivado
+ PARENT_NAME mmcm_none_basys3
+ CLOCK_PINS clk
+ CLOCK_PERIODS 10.0
+ )
+
+add_vivado_target(
NAME mmcm_buf_basys3_vivado
PARENT_NAME mmcm_buf_basys3
CLOCK_PINS clk
@@ -146,6 +162,7 @@
set(TEST_TARGETS
mmcm_packing
mmcm_int_basys3
+ mmcm_none_basys3
mmcm_int_frac_basys3
mmcm_buf_basys3
mmcm_ext_basys3
diff --git a/xc/xc7/tests/mmcm/README.md b/xc/xc7/tests/mmcm/README.md
index 3b10962..2aecf82 100644
--- a/xc/xc7/tests/mmcm/README.md
+++ b/xc/xc7/tests/mmcm/README.md
@@ -20,6 +20,7 @@
There are 3 test variants:
- `mmcm_int_basys3` - Internal feedback
+- `mmcm_int_basys3` - Internal feedback but no COMPENSATION specified in order to test default value in techmapper
- `mmcm_buf_basys3` - Feedback through a BUFG
- `mmcm_ext_basys3` - External feedback. Need to short `JC.1` and `JC.2` on the Basys3 board.
diff --git a/xc/xc7/tests/mmcm/mmcm_none_basys3_bottom.v b/xc/xc7/tests/mmcm/mmcm_none_basys3_bottom.v
new file mode 100644
index 0000000..e51f45f
--- /dev/null
+++ b/xc/xc7/tests/mmcm/mmcm_none_basys3_bottom.v
@@ -0,0 +1,62 @@
+`include "mmcme2_test.v"
+
+`default_nettype none
+
+// ============================================================================
+
+module top
+(
+input wire clk,
+
+input wire [7:0] sw,
+output wire [7:0] led,
+
+input wire jc1, // unused
+output wire jc2,
+input wire jc3, // unused
+input wire jc4
+);
+
+// ============================================================================
+// Reset generator
+wire CLK;
+BUFG bufg(.I(clk), .O(CLK));
+
+reg [3:0] rst_sr;
+initial rst_sr <= 4'hF;
+
+always @(posedge CLK)
+ if (sw[0])
+ rst_sr <= 4'hF;
+ else
+ rst_sr <= rst_sr >> 1;
+
+wire RST = rst_sr[0];
+
+// ============================================================================
+// The tester
+
+mmcme2_test #
+(
+.FEEDBACK ("NONE")
+)
+mmcme2_test
+(
+.CLK (clk),
+.RST (RST),
+
+.CLKFBOUT (),
+.CLKFBIN (),
+
+.I_PWRDWN (sw[1]),
+.I_CLKINSEL (sw[2]),
+
+.O_LOCKED (led[6]),
+.O_CNT (led[5:0])
+);
+
+assign led [7] = |sw[7:3];
+assign jc2 = jc4;
+
+endmodule
+
diff --git a/xc/xc7/tests/mmcm/mmcme2_test.v b/xc/xc7/tests/mmcm/mmcme2_test.v
index 814133a..e4c9a5f 100644
--- a/xc/xc7/tests/mmcm/mmcme2_test.v
+++ b/xc/xc7/tests/mmcm/mmcme2_test.v
@@ -44,68 +44,133 @@
wire [5:0] clk;
wire [5:0] gclk;
-MMCME2_ADV #
-(
-.BANDWIDTH ("HIGH"),
-.COMPENSATION ((FEEDBACK == "EXTERNAL") ? "EXTERNAL" : "INTERNAL"),
+generate if (FEEDBACK == "NONE") begin
-.CLKIN1_PERIOD (20.0), // 50MHz
-.CLKIN2_PERIOD (10.0), // 100MHz
+ MMCME2_ADV #
+ (
+ .BANDWIDTH ("HIGH"),
-.CLKFBOUT_MULT_F (CLKFBOUT_MULT_F),
-.CLKFBOUT_PHASE (0),
+ .CLKIN1_PERIOD (20.0), // 50MHz
+ .CLKIN2_PERIOD (10.0), // 100MHz
-.CLKOUT0_DIVIDE_F (CLKOUT0_DIVIDE_F),
-.CLKOUT0_DUTY_CYCLE (0.50),
-.CLKOUT0_PHASE (45.0),
+ .CLKFBOUT_MULT_F (CLKFBOUT_MULT_F),
+ .CLKFBOUT_PHASE (0),
-.CLKOUT1_DIVIDE (32),
-.CLKOUT1_DUTY_CYCLE (0.53125),
-.CLKOUT1_PHASE (90.0),
+ .CLKOUT0_DIVIDE_F (CLKOUT0_DIVIDE_F),
+ .CLKOUT0_DUTY_CYCLE (0.50),
+ .CLKOUT0_PHASE (45.0),
-.CLKOUT2_DIVIDE (48),
-.CLKOUT2_DUTY_CYCLE (0.50),
-.CLKOUT2_PHASE (135.0),
+ .CLKOUT1_DIVIDE (32),
+ .CLKOUT1_DUTY_CYCLE (0.53125),
+ .CLKOUT1_PHASE (90.0),
-.CLKOUT3_DIVIDE (64),
-.CLKOUT3_DUTY_CYCLE (0.50),
-.CLKOUT3_PHASE (45.0),
+ .CLKOUT2_DIVIDE (48),
+ .CLKOUT2_DUTY_CYCLE (0.50),
+ .CLKOUT2_PHASE (135.0),
-.CLKOUT4_DIVIDE (80),
-.CLKOUT4_DUTY_CYCLE (0.50),
-.CLKOUT4_PHASE (90.0),
+ .CLKOUT3_DIVIDE (64),
+ .CLKOUT3_DUTY_CYCLE (0.50),
+ .CLKOUT3_PHASE (45.0),
-.CLKOUT5_DIVIDE (96),
-.CLKOUT5_DUTY_CYCLE (0.50),
-.CLKOUT5_PHASE (135.0),
+ .CLKOUT4_DIVIDE (80),
+ .CLKOUT4_DUTY_CYCLE (0.50),
+ .CLKOUT4_PHASE (90.0),
-.CLKOUT6_DIVIDE (1),
-.CLKOUT6_DUTY_CYCLE (0.50),
-.CLKOUT6_PHASE (0.0),
+ .CLKOUT5_DIVIDE (96),
+ .CLKOUT5_DUTY_CYCLE (0.50),
+ .CLKOUT5_PHASE (135.0),
-.STARTUP_WAIT ("FALSE")
-)
-mmcm
-(
-.CLKIN1 (clk50),
-.CLKIN2 (clk100),
-.CLKINSEL (I_CLKINSEL),
+ .CLKOUT6_DIVIDE (1),
+ .CLKOUT6_DUTY_CYCLE (0.50),
+ .CLKOUT6_PHASE (0.0),
-.RST (RST),
-.PWRDWN (I_PWRDWN),
-.LOCKED (O_LOCKED),
+ .STARTUP_WAIT ("FALSE")
+ )
+ mmcm
+ (
+ .CLKIN1 (clk50),
+ .CLKIN2 (clk100),
+ .CLKINSEL (I_CLKINSEL),
-.CLKFBIN (clk_fb_i),
-.CLKFBOUT (clk_fb_o),
+ .RST (RST),
+ .PWRDWN (I_PWRDWN),
+ .LOCKED (O_LOCKED),
-.CLKOUT0 (clk[0]),
-.CLKOUT1 (clk[1]),
-.CLKOUT2 (clk[2]),
-.CLKOUT3 (clk[3]),
-.CLKOUT4 (clk[4]),
-.CLKOUT5 (clk[5]),
-.CLKOUT6 () // Deliberately disconnected
-);
+ .CLKFBIN (clk_fb_i),
+ .CLKFBOUT (clk_fb_o),
+
+ .CLKOUT0 (clk[0]),
+ .CLKOUT1 (clk[1]),
+ .CLKOUT2 (clk[2]),
+ .CLKOUT3 (clk[3]),
+ .CLKOUT4 (clk[4]),
+ .CLKOUT5 (clk[5]),
+ .CLKOUT6 () // Deliberately disconnected
+ );
+end else begin
+ MMCME2_ADV #
+ (
+ .BANDWIDTH ("HIGH"),
+ .COMPENSATION ((FEEDBACK == "EXTERNAL") ? "EXTERNAL" : "INTERNAL"),
+
+ .CLKIN1_PERIOD (20.0), // 50MHz
+ .CLKIN2_PERIOD (10.0), // 100MHz
+
+ .CLKFBOUT_MULT_F (CLKFBOUT_MULT_F),
+ .CLKFBOUT_PHASE (0),
+
+ .CLKOUT0_DIVIDE_F (CLKOUT0_DIVIDE_F),
+ .CLKOUT0_DUTY_CYCLE (0.50),
+ .CLKOUT0_PHASE (45.0),
+
+ .CLKOUT1_DIVIDE (32),
+ .CLKOUT1_DUTY_CYCLE (0.53125),
+ .CLKOUT1_PHASE (90.0),
+
+ .CLKOUT2_DIVIDE (48),
+ .CLKOUT2_DUTY_CYCLE (0.50),
+ .CLKOUT2_PHASE (135.0),
+
+ .CLKOUT3_DIVIDE (64),
+ .CLKOUT3_DUTY_CYCLE (0.50),
+ .CLKOUT3_PHASE (45.0),
+
+ .CLKOUT4_DIVIDE (80),
+ .CLKOUT4_DUTY_CYCLE (0.50),
+ .CLKOUT4_PHASE (90.0),
+
+ .CLKOUT5_DIVIDE (96),
+ .CLKOUT5_DUTY_CYCLE (0.50),
+ .CLKOUT5_PHASE (135.0),
+
+ .CLKOUT6_DIVIDE (1),
+ .CLKOUT6_DUTY_CYCLE (0.50),
+ .CLKOUT6_PHASE (0.0),
+
+ .STARTUP_WAIT ("FALSE")
+ )
+ mmcm
+ (
+ .CLKIN1 (clk50),
+ .CLKIN2 (clk100),
+ .CLKINSEL (I_CLKINSEL),
+
+ .RST (RST),
+ .PWRDWN (I_PWRDWN),
+ .LOCKED (O_LOCKED),
+
+ .CLKFBIN (clk_fb_i),
+ .CLKFBOUT (clk_fb_o),
+
+ .CLKOUT0 (clk[0]),
+ .CLKOUT1 (clk[1]),
+ .CLKOUT2 (clk[2]),
+ .CLKOUT3 (clk[3]),
+ .CLKOUT4 (clk[4]),
+ .CLKOUT5 (clk[5]),
+ .CLKOUT6 () // Deliberately disconnected
+ );
+end endgenerate
generate if (FEEDBACK == "INTERNAL") begin
assign clk_fb_i = clk_fb_o;