| // Copyright 2023 Google LLC |
| // Copyright lowRISC contributors |
| // |
| // 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. |
| |
| module clkgen_xilultrascaleplus |
| #(parameter int ClockFrequencyMhz = 80, |
| // Add BUFG if not done by downstream logic |
| parameter bit AddClkBuf = 1) |
| (input clk_i, |
| input clk_n_i, |
| input rst_ni, |
| input srst_ni, |
| output clk_main_o, |
| output clk_48MHz_o, |
| output clk_aon_o, |
| output rst_no); |
| logic locked_pll; |
| logic io_clk_buf; |
| logic io_rst_buf_n; |
| logic clk_10_buf; |
| logic clk_10_unbuf; |
| logic clk_fb_buf; |
| logic clk_fb_unbuf; |
| logic clk_48_buf; |
| logic clk_48_unbuf; |
| logic clk_aon_buf; |
| logic clk_aon_unbuf; |
| logic clk_ibufds_o; |
| |
| // Input IBUFDS conver diff-pair to single-end |
| IBUFDS clk_ibufds(.I(clk_i), |
| .IB(clk_n_i), |
| .O(clk_ibufds_o)); |
| |
| localparam real CLKOUT0_DIVIDE_F_CALC = 1200.0 / ClockFrequencyMhz; |
| |
| MMCME2_ADV #( |
| .BANDWIDTH("OPTIMIZED"), |
| .COMPENSATION("ZHOLD"), |
| .STARTUP_WAIT("FALSE"), |
| .DIVCLK_DIVIDE(1), |
| .CLKFBOUT_MULT_F(12.000), |
| .CLKFBOUT_PHASE(0.000), |
| .CLKOUT0_DIVIDE_F(CLKOUT0_DIVIDE_F_CALC), |
| .CLKOUT0_PHASE(0.000), |
| .CLKOUT0_DUTY_CYCLE(0.500), |
| .CLKOUT1_DIVIDE(25), |
| .CLKOUT1_PHASE(0.000), |
| .CLKOUT1_DUTY_CYCLE(0.500), |
| // With CLKOUT4_CASCADE, CLKOUT6's divider is an input to CLKOUT4's |
| // divider. The effective ratio is a multiplication of the two. |
| .CLKOUT4_DIVIDE(40), |
| .CLKOUT4_PHASE(0.000), |
| .CLKOUT4_DUTY_CYCLE(0.500), |
| .CLKOUT4_CASCADE("TRUE"), |
| .CLKOUT6_DIVIDE(120), |
| .CLKIN1_PERIOD(10.000)) |
| pll(.CLKFBOUT(clk_fb_unbuf), |
| .CLKFBOUTB(), |
| .CLKOUT0(clk_10_unbuf), |
| .CLKOUT0B(), |
| .CLKOUT1(clk_48_unbuf), |
| .CLKOUT1B(), |
| .CLKOUT2(), |
| .CLKOUT2B(), |
| .CLKOUT3(), |
| .CLKOUT3B(), |
| .CLKOUT4(clk_aon_unbuf), |
| .CLKOUT5(), |
| .CLKOUT6(), |
| // Input clock control |
| .CLKFBIN(clk_fb_buf), |
| .CLKIN1(clk_ibufds_o), |
| .CLKIN2(1'b0), |
| // Tied to always select the primary input clock |
| .CLKINSEL(1'b1), |
| // Ports for dynamic reconfiguration |
| .DADDR(7'h0), |
| .DCLK(1'b0), |
| .DEN(1'b0), |
| .DI(16'h0), |
| .DO(), |
| .DRDY(), |
| .DWE(1'b0), |
| // Phase shift signals |
| .PSCLK(1'b0), |
| .PSEN(1'b0), |
| .PSINCDEC(1'b0), |
| .PSDONE(), |
| // Other control and status signals |
| .CLKFBSTOPPED(), |
| .CLKINSTOPPED(), |
| .LOCKED(locked_pll), |
| .PWRDWN(1'b0), |
| // Do not reset MMCM on external reset, otherwise ILA disconnects at a |
| // reset |
| .RST(1'b0)); |
| |
| // output buffering |
| BUFGCE clk_fb_bufgce(.I(clk_fb_unbuf), |
| .O(clk_fb_buf)); |
| |
| BUFGCE clk_aon_bufgce(.I(clk_aon_unbuf), |
| .O(clk_aon_buf)); |
| |
| if (AddClkBuf == 1) begin : gen_clk_bufs |
| BUFGCE clk_10_bufgce(.I(clk_10_unbuf), |
| .O(clk_10_buf)); |
| |
| BUFGCE clk_48_bufgce(.I(clk_48_unbuf), |
| .O(clk_48_buf)); |
| |
| end else begin : gen_no_clk_bufs |
| // BUFGs added by downstream modules, no need to add here |
| assign clk_10_buf = clk_10_unbuf; |
| assign clk_48_buf = clk_48_unbuf; |
| end |
| |
| // outputs |
| // clock |
| assign clk_main_o = clk_10_buf; |
| assign clk_48MHz_o = clk_48_buf; |
| assign clk_aon_o = clk_aon_buf; |
| |
| // reset |
| assign rst_no = locked_pll & rst_ni & srst_ni; |
| endmodule |