mirror of
https://github.com/fpganinja/taxi.git
synced 2025-12-09 00:48:40 -08:00
hip: Add fractional MMCM wrapper for generating offset clocks for DDMTD
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
194
rtl/hip/us/taxi_mmcm_frac.sv
Normal file
194
rtl/hip/us/taxi_mmcm_frac.sv
Normal file
@@ -0,0 +1,194 @@
|
||||
// SPDX-License-Identifier: CERN-OHL-S-2.0
|
||||
/*
|
||||
|
||||
Copyright (c) 2024-2025 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
`resetall
|
||||
`timescale 1ns / 1ps
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* Fractional MMCM
|
||||
*/
|
||||
module taxi_mmcm_frac #(
|
||||
parameter MMCM_INPUT_CLK_PERIOD = 8.0,
|
||||
parameter MMCM_INPUT_REF_JITTER = 0.010,
|
||||
parameter MMCM_INPUT_DIV = 1,
|
||||
parameter MMCM_MULT = 8,
|
||||
parameter MMCM_OUTPUT_DIV = MMCM_MULT,
|
||||
parameter OFFSET_NUM = 1,
|
||||
parameter OFFSET_DENOM = 65536
|
||||
)
|
||||
(
|
||||
input wire input_clk,
|
||||
input wire input_rst,
|
||||
|
||||
output wire output_clk,
|
||||
output wire output_offset_clk,
|
||||
output wire locked
|
||||
);
|
||||
|
||||
// 1 tap is 1/56th of the VCO period
|
||||
// to shift 1 full cycle of the output clock, 56*MMCM_OUTPUT_DIV shifts are required
|
||||
localparam DIR = OFFSET_NUM >= 0;
|
||||
localparam NUM_1 = (DIR ? OFFSET_NUM : -OFFSET_NUM)*56*MMCM_OUTPUT_DIV;
|
||||
localparam DENOM_1 = OFFSET_DENOM;
|
||||
|
||||
localparam CNT_W = $clog2(DENOM_1)+1;
|
||||
|
||||
logic [CNT_W-1:0] cnt_reg = '0;
|
||||
|
||||
logic ps_en_reg = 1'b0;
|
||||
|
||||
always_ff @(posedge output_clk) begin
|
||||
ps_en_reg <= 1'b0;
|
||||
|
||||
if (cnt_reg + NUM_1 >= DENOM_1) begin
|
||||
cnt_reg <= cnt_reg + NUM_1 - DENOM_1;
|
||||
ps_en_reg <= 1'b1;
|
||||
end else begin
|
||||
cnt_reg <= cnt_reg + NUM_1;
|
||||
end
|
||||
end
|
||||
|
||||
wire clkfb;
|
||||
|
||||
wire output_clk_mmcm;
|
||||
wire output_offset_clk_mmcm;
|
||||
|
||||
MMCME3_ADV #(
|
||||
// input clocks
|
||||
.CLKIN1_PERIOD(MMCM_INPUT_CLK_PERIOD),
|
||||
.REF_JITTER1(MMCM_INPUT_REF_JITTER),
|
||||
.CLKIN2_PERIOD(0.000),
|
||||
.REF_JITTER2(0.010),
|
||||
// divide for PFD input
|
||||
// US/US+: range 10 MHz to 500 MHz
|
||||
.DIVCLK_DIVIDE(MMCM_INPUT_DIV),
|
||||
// multiply for VCO output
|
||||
// US: range 600 MHz to 1440 MHz
|
||||
// US+: range 800 MHz to 1600 MHz
|
||||
.CLKFBOUT_MULT_F(MMCM_MULT),
|
||||
.CLKFBOUT_PHASE(0),
|
||||
.CLKFBOUT_USE_FINE_PS("FALSE"),
|
||||
// divide
|
||||
.CLKOUT0_DIVIDE_F(MMCM_OUTPUT_DIV),
|
||||
.CLKOUT0_DUTY_CYCLE(0.5),
|
||||
.CLKOUT0_PHASE(0),
|
||||
.CLKOUT0_USE_FINE_PS("FALSE"),
|
||||
// divide and phase shift
|
||||
.CLKOUT1_DIVIDE(MMCM_OUTPUT_DIV),
|
||||
.CLKOUT1_DUTY_CYCLE(0.5),
|
||||
.CLKOUT1_PHASE(0),
|
||||
.CLKOUT1_USE_FINE_PS("TRUE"),
|
||||
// Not used
|
||||
.CLKOUT2_DIVIDE(1),
|
||||
.CLKOUT2_DUTY_CYCLE(0.5),
|
||||
.CLKOUT2_PHASE(0),
|
||||
.CLKOUT2_USE_FINE_PS("FALSE"),
|
||||
// Not used
|
||||
.CLKOUT3_DIVIDE(1),
|
||||
.CLKOUT3_DUTY_CYCLE(0.5),
|
||||
.CLKOUT3_PHASE(0),
|
||||
.CLKOUT3_USE_FINE_PS("FALSE"),
|
||||
// Not used
|
||||
.CLKOUT4_DIVIDE(1),
|
||||
.CLKOUT4_DUTY_CYCLE(0.5),
|
||||
.CLKOUT4_PHASE(0),
|
||||
.CLKOUT4_USE_FINE_PS("FALSE"),
|
||||
.CLKOUT4_CASCADE("FALSE"),
|
||||
// Not used
|
||||
.CLKOUT5_DIVIDE(1),
|
||||
.CLKOUT5_DUTY_CYCLE(0.5),
|
||||
.CLKOUT5_PHASE(0),
|
||||
.CLKOUT5_USE_FINE_PS("FALSE"),
|
||||
// Not used
|
||||
.CLKOUT6_DIVIDE(1),
|
||||
.CLKOUT6_DUTY_CYCLE(0.5),
|
||||
.CLKOUT6_PHASE(0),
|
||||
.CLKOUT6_USE_FINE_PS("FALSE"),
|
||||
// no spread spectrum
|
||||
.SS_EN("FALSE"),
|
||||
.SS_MODE("CENTER_HIGH"),
|
||||
.SS_MOD_PERIOD(10000),
|
||||
|
||||
.COMPENSATION("AUTO"),
|
||||
// optimized bandwidth
|
||||
.BANDWIDTH("OPTIMIZED"),
|
||||
// don't wait for lock during startup
|
||||
.STARTUP_WAIT("FALSE")
|
||||
)
|
||||
clk_mmcm_inst (
|
||||
// input clocks
|
||||
.CLKIN1(input_clk),
|
||||
.CLKIN2(1'b0),
|
||||
// select CLKIN1
|
||||
.CLKINSEL(1'b1),
|
||||
// direct clkfb feedback
|
||||
.CLKFBIN(clkfb),
|
||||
.CLKFBOUT(clkfb),
|
||||
.CLKFBOUTB(),
|
||||
// phase-shifted output
|
||||
.CLKOUT0(output_clk_mmcm),
|
||||
.CLKOUT0B(),
|
||||
// Not used
|
||||
.CLKOUT1(output_offset_clk_mmcm),
|
||||
.CLKOUT1B(),
|
||||
// Not used
|
||||
.CLKOUT2(),
|
||||
.CLKOUT2B(),
|
||||
// Not used
|
||||
.CLKOUT3(),
|
||||
.CLKOUT3B(),
|
||||
// Not used
|
||||
.CLKOUT4(),
|
||||
// Not used
|
||||
.CLKOUT5(),
|
||||
// Not used
|
||||
.CLKOUT6(),
|
||||
// reset input
|
||||
.RST(input_rst),
|
||||
// don't power down
|
||||
.PWRDWN(1'b0),
|
||||
// DRP
|
||||
.DADDR(7'd0),
|
||||
.DI(16'd0),
|
||||
.DWE(1'b0),
|
||||
.DEN(1'b0),
|
||||
.DCLK(1'b0),
|
||||
.DO(),
|
||||
// dynamic phase shift
|
||||
.PSINCDEC(DIR ? 1'b0 : 1'b1),
|
||||
.PSEN(ps_en_reg),
|
||||
.PSCLK(output_clk),
|
||||
.PSDONE(),
|
||||
// locked output
|
||||
.LOCKED(locked),
|
||||
// input status
|
||||
.CLKINSTOPPED(),
|
||||
.CLKFBSTOPPED(),
|
||||
// CDDC
|
||||
.CDDCREQ(1'b0),
|
||||
.CDDCDONE()
|
||||
);
|
||||
|
||||
BUFG
|
||||
output_clk_bufg_inst (
|
||||
.I(output_clk_mmcm),
|
||||
.O(output_clk)
|
||||
);
|
||||
|
||||
BUFG
|
||||
output_offset_clk_bufg_inst (
|
||||
.I(output_offset_clk_mmcm),
|
||||
.O(output_offset_clk)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
||||
Reference in New Issue
Block a user