// SPDX-FileCopyrightText: 2020 Efabless Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // SPDX-License-Identifier: Apache-2.0 `default_nettype none // This routine synchronizes the module caravel_clocking( `ifdef USE_POWER_PINS input vdd1v8, input vss, `endif input resetb, // Master (negative sense) reset input ext_clk_sel, // 0=use PLL clock, 1=use external (pad) clock input ext_clk, // External pad (slow) clock input pll_clk, // Internal PLL (fast) clock input pll_clk90, // Internal PLL (fast) clock, 90 degree phase input [2:0] sel, // Select clock divider value (0=thru, 1=divide-by-2, etc.) input [2:0] sel2, // Select clock divider value for 90 degree phase divided clock input ext_reset, // Positive sense reset from housekeeping SPI. output core_clk, // Output core clock output user_clk, // Output user (secondary) clock output resetb_sync // Output propagated and buffered reset ); wire pll_clk_sel; wire pll_clk_divided; wire pll_clk90_divided; wire core_ext_clk; reg use_pll_first; reg use_pll_second; reg ext_clk_syncd_pre; reg ext_clk_syncd; assign pll_clk_sel = ~ext_clk_sel; // Note that this implementation does not guard against switching to // the PLL clock if the PLL clock is not present. always @(posedge pll_clk or negedge resetb) begin if (resetb == 1'b0) begin use_pll_first <= 1'b0; use_pll_second <= 1'b0; ext_clk_syncd <= 1'b0; end else begin use_pll_first <= pll_clk_sel; use_pll_second <= use_pll_first; ext_clk_syncd_pre <= ext_clk; // Sync ext_clk to pll_clk ext_clk_syncd <= ext_clk_syncd_pre; // Do this twice (resolve metastability) end end // Apply PLL clock divider clock_div #( .SIZE(3) ) divider ( .in(pll_clk), .out(pll_clk_divided), .N(sel), .resetb(resetb) ); // Secondary PLL clock divider for user space access clock_div #( .SIZE(3) ) divider2 ( .in(pll_clk90), .out(pll_clk90_divided), .N(sel2), .resetb(resetb) ); // Multiplex the clock output assign core_ext_clk = (use_pll_first) ? ext_clk_syncd : ext_clk; assign core_clk = (use_pll_second) ? pll_clk_divided : core_ext_clk; assign user_clk = (use_pll_second) ? pll_clk90_divided : core_ext_clk; // Reset assignment. "reset" comes from POR, while "ext_reset" // comes from standalone SPI (and is normally zero unless // activated from the SPI). // Staged-delay reset reg [2:0] reset_delay; always @(posedge core_clk or negedge resetb) begin if (resetb == 1'b0) begin reset_delay <= 3'b111; end else begin reset_delay <= {1'b0, reset_delay[2:1]}; end end assign resetb_sync = ~(reset_delay[0] | ext_reset); endmodule `default_nettype wire