diff --git a/clock_generator.v b/clock_generator.v index bd6e4b3269a87c89cbaab8d5dcedbf7faed5c520..64345a6499bfdeeb5adb15ae38eb6f9a64206841 100644 --- a/clock_generator.v +++ b/clock_generator.v @@ -1,4 +1,4 @@ -// © 2017 Raptor Engineering, LLC +// © 2017 - 2020 Raptor Engineering, LLC // // Released under the terms of the AGPL v3 // See the LICENSE file for full details @@ -14,9 +14,7 @@ module clock_generator( // Main 12MHz platform clock input wire platform_clock, - output wire platform_pll_lock, - output wire fast_48mhz_platform_clock, - output wire fast_24mhz_platform_clock, + output wire spi_core_pll_lock, output wire slow_1843khz_uart_clock, output wire slow_175khz_platform_clock, output wire slow_183hz_platform_clock, @@ -25,34 +23,27 @@ module clock_generator( // Main 33MHz LPC clock input wire lpc_clock, output wire sequencer_clock, - - input wire fast_24mhz_platform_clock_speed_ctl + output wire spi_core_clock, + input wire reset_lpc_derived_plls ); `ifdef SIMULATION - assign fast_48mhz_platform_clock = platform_clock; + assign spi_core_clock = lpc_clock; `else - // 48MHz fast platform clock + // 66MHz SPI core clock SB_PLL40_CORE #( .FEEDBACK_PATH("SIMPLE"), .PLLOUT_SELECT("GENCLK"), -`ifdef USE_22_875MHZ_CLOCK - .DIVR(4'b0000), - .DIVF(7'b0111100), - .DIVQ(3'b100), - .FILTER_RANGE(3'b001) -`else .DIVR(4'b0000), - .DIVF(7'b0111111), - .DIVQ(3'b100), - .FILTER_RANGE(3'b001) -`endif + .DIVF(7'b0001111), + .DIVQ(3'b011), + .FILTER_RANGE(3'b011) ) platform_pll ( - .LOCK(platform_pll_lock), - .RESETB(1'b1), + .LOCK(spi_core_pll_lock), + .RESETB(~reset_lpc_derived_plls), .BYPASS(1'b0), - .REFERENCECLK(platform_clock), - .PLLOUTGLOBAL(fast_48mhz_platform_clock) + .REFERENCECLK(lpc_clock), + .PLLOUTGLOBAL(spi_core_clock) ); `endif @@ -70,36 +61,10 @@ module clock_generator( // Slow clock generator reg [20:0] slow_clock_counter = 0; - always @(posedge fast_48mhz_platform_clock) begin - slow_clock_counter = slow_clock_counter + 1; + always @(posedge platform_clock) begin + slow_clock_counter = slow_clock_counter + 4; end -`ifdef SIMULATION - wire internal_24mhz_clock; - assign internal_24mhz_clock = fast_48mhz_platform_clock; -`else - // 24MHz fast platform clock - reg internal_24mhz_clock = 0; - reg internal_ref_24mhz_clock = 0; - - always @(posedge fast_48mhz_platform_clock) begin - internal_ref_24mhz_clock = ~internal_ref_24mhz_clock; - - if (fast_24mhz_platform_clock_speed_ctl) begin - // 87.5KHz slumber mode clock - internal_24mhz_clock <= slow_clock_counter[6]; - end else begin - internal_24mhz_clock <= internal_ref_24mhz_clock; - end - end -`endif - - // Buffer 24MHz fast clock - SB_GB platform_24mhz_clock_buffer ( - .USER_SIGNAL_TO_GLOBAL_BUFFER(internal_24mhz_clock), - .GLOBAL_BUFFER_OUTPUT(fast_24mhz_platform_clock) - ); - // Buffer 1843Hz slow clock SB_GB platform_1843khz_clock_buffer ( .USER_SIGNAL_TO_GLOBAL_BUFFER(internal_1843khz_clock), diff --git a/main.v b/main.v index 79a4ef57cdcc7651e25c65aa19dcab585d03e434..5aea00f39435926098b0e1eb24ccbad9ae270964 100644 --- a/main.v +++ b/main.v @@ -158,6 +158,50 @@ module lpc_bridge_top( wire lpc_pll_lock; wire lpc_slave_tx_clock_resynthesized; wire lpc_slave_clock_resynthesized; +`ifdef ENABLE_EXPERIMENTAL_RECLOCKING_PLL_DOUBLING + // NOTE: + // The iCE40 PLL is very poorly documented in the + // external feedback path. Discussion follows: + // + // In the iCE40 Ultra Plus documentation, it is mentioned + // that EXTERNAL_DIVIDE_FACTOR actually influences the clock + // synthesis by acting as a multiplier for GENCLK. + // Therefore, to get a doubled frequency along with the phase + // aligned / duty cycle corrected original frequency, the PLL + // needs to be set for 1:1 clock synthesis and the feedback + // path division factor needs to be set to 2. Feeding the + // GENCLK_HALF signal back into the feedback pin then seems + // to work as intended -- the original clock is aligned, and + // a doubled clock is available on port B via the GENCLK route. + // + // Unfortunately, even with this inferred information, the PLL + // is not exactly phase matching its output with the input. + // Since this is apparently a little used feature of the iCE40 + // PLLs, it's probably not worth debugging in this context. + // Larger devices like the ECP5 have four PLLs to work with, + // making the use of a second PLL to generate the SPI clock + // more reasonable. + wire lpc_slave_clock_doubled; + SB_PLL40_2F_PAD #( + .FEEDBACK_PATH("EXTERNAL"), + .PLLOUT_SELECT_PORTA("GENCLK_HALF"), + .PLLOUT_SELECT_PORTB("GENCLK"), + .EXTERNAL_DIVIDE_FACTOR(2'b10), + .SHIFTREG_DIV_MODE(1'b0), + .DIVR(4'b0000), + .DIVF(7'b0000000), + .DIVQ(3'b100), + .FILTER_RANGE(3'b011) + ) lpc_slave_pll ( + .LOCK(lpc_pll_lock), + .EXTFEEDBACK(lpc_slave_clock_resynthesized), + .RESETB(lpc_slave_reset_n_buffered_gated), + .BYPASS(1'b0), + .PACKAGEPIN(lpc_slave_clock), + .PLLOUTGLOBALA(lpc_slave_clock_resynthesized), + .PLLOUTGLOBALB(lpc_slave_clock_doubled) + ); +`else SB_PLL40_2F_PAD #( .FEEDBACK_PATH("PHASE_AND_DELAY"), .PLLOUT_SELECT_PORTA("SHIFTREG_0deg"), @@ -174,6 +218,7 @@ module lpc_bridge_top( .PACKAGEPIN(lpc_slave_clock), .PLLOUTGLOBALA(lpc_slave_clock_resynthesized) ); +`endif assign lpc_slave_tx_clock_resynthesized = lpc_slave_clock_resynthesized; `else wire lpc_slave_clock_buffered; @@ -215,31 +260,26 @@ module lpc_bridge_top( assign lpc_debug_mirror_clock_extern_uart = lpc_slave_clock_resynthesized; // Instantiate clock generator - wire platform_pll_lock; + wire spi_core_pll_lock; wire platform_pll_unstable; - wire fast_48mhz_platform_clock; - wire fast_24mhz_platform_clock; wire slow_1843khz_uart_clock; wire slow_175khz_platform_clock; wire slow_183hz_platform_clock; wire slow_11hz_platform_clock; wire sequencer_clock; - - reg fast_24mhz_platform_clock_speed_ctl = 0; + wire spi_core_clock; `ifdef RESYNTHESIZE_LPC_CLOCK - assign platform_pll_unstable = ~platform_pll_lock | ~lpc_pll_lock; + assign platform_pll_unstable = ~lpc_pll_lock; `else - assign platform_pll_unstable = ~platform_pll_lock; + assign platform_pll_unstable = 0; `endif clock_generator clock_generator( // Main 12MHz platform clock .platform_clock(primary_platform_clock), - .platform_pll_lock(platform_pll_lock), - .fast_48mhz_platform_clock(fast_48mhz_platform_clock), - .fast_24mhz_platform_clock(fast_24mhz_platform_clock), + .spi_core_pll_lock(spi_core_pll_lock), .slow_1843khz_uart_clock(slow_1843khz_uart_clock), .slow_175khz_platform_clock(slow_175khz_platform_clock), .slow_183hz_platform_clock(slow_183hz_platform_clock), @@ -248,8 +288,8 @@ module lpc_bridge_top( // Main 33MHz LPC clock .lpc_clock(lpc_slave_clock_resynthesized), .sequencer_clock(sequencer_clock), - - .fast_24mhz_platform_clock_speed_ctl(fast_24mhz_platform_clock_speed_ctl) + .spi_core_clock(spi_core_clock), + .reset_lpc_derived_plls(~lpc_pll_lock) ); // Generate power-on reset signals @@ -629,7 +669,7 @@ module lpc_bridge_top( wire spi_external_master_hold_n_buffered; spi_master_interface_quad spi_master_interface_quad( - .platform_clock(lpc_slave_clock_resynthesized), + .platform_clock(spi_core_clock), .reset(fpga_power_on_reset || (~lpc_slave_reset_n_buffered_gated)), .tx_data(spi_external_master_tx_data), .rx_data(spi_external_master_rx_data), diff --git a/timing_constraints.py b/timing_constraints.py index 0e2e92f8119ca84d5a61dc8171ba4cd0ceaaafd4..9a6d2d3fbd2be75f63c130e3b0717a4b91c1b077 100755 --- a/timing_constraints.py +++ b/timing_constraints.py @@ -16,8 +16,9 @@ ctx.addClock("fast_48mhz_platform_clock", 96) ctx.addClock("primary_platform_clock", 12) ctx.addClock("sequencer_clock", 33) ctx.addClock("slow_1843khz_uart_clock", 2) +ctx.addClock("spi_core_clock", lpc_clock_frequency * 2) # For some reason both of these clocks are showing up, for presumably different # sections of the LPC logic. Make sure both can run at LPC speeds. ctx.addClock("lpc_slave_tx_clock_resynthesized", lpc_clock_frequency) -ctx.addClock("lpc_debug_mirror_clock_extern_uart", lpc_clock_frequency) +ctx.addClock("lpc_debug_mirror_clock_extern_uart", lpc_clock_frequency) \ No newline at end of file