| // 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 clk_ibex_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_ibex_buf; | 
 |   logic clk_ibex_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; | 
 |   localparam int CLKOUT2_DIVIDE_CALC = CLKOUT0_DIVIDE_F_CALC * 4; | 
 |  | 
 |   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), | 
 |           .CLKOUT2_DIVIDE(CLKOUT2_DIVIDE_CALC), | 
 |           .CLKOUT2_PHASE(0.000), | 
 |           .CLKOUT2_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(clk_ibex_unbuf), | 
 |           .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)); | 
 |  | 
 |     BUFGCE clk_ibex_bufgce(.I(clk_ibex_unbuf), | 
 |                          .O(clk_ibex_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; | 
 |     assign clk_ibex_buf = clk_ibex_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; | 
 |   assign clk_ibex_o = clk_ibex_buf; | 
 |  | 
 |   // reset | 
 |   assign rst_no = locked_pll & rst_ni & srst_ni; | 
 | endmodule |