| // Copyright 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. |
| |
| `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 |