add dl814_k7_basic; update dl814_z7 ps project

dl814_k7_basic is the driver instance of board smq7k410t_b9361, along with basic clock, adc and dac configurations; include nulling algorithm into dl814_z7 project
This commit is contained in:
2023-03-29 17:34:49 +08:00
parent cd256a8cd6
commit e8a34c95e0
2060 changed files with 4678610 additions and 198681 deletions
@@ -53,13 +53,13 @@
`timescale 1ps/1ps
(* CORE_GENERATION_INFO = "selectio_lvds_tx,selectio_wiz_v5_1_13,{component_name=selectio_lvds_tx,bus_dir=OUTPUTS,bus_sig_type=SINGLE,bus_io_std=LVCMOS33,use_serialization=false,use_phase_detector=false,serialization_factor=4,enable_bitslip=false,enable_train=false,system_data_width=1,bus_in_delay=NONE,bus_out_delay=NONE,clk_sig_type=SINGLE,clk_io_std=LVCMOS18,clk_buf=BUFIO2,active_edge=RISING,clk_delay=NONE,selio_bus_in_delay=NONE,selio_bus_out_delay=NONE,selio_clk_buf=BUFIO,selio_active_edge=SDR,selio_ddr_alignment=SAME_EDGE_PIPELINED,selio_oddr_alignment=SAME_EDGE,ddr_alignment=C0,selio_interface_type=NETWORKING,interface_type=NETWORKING,selio_bus_in_tap=0,selio_bus_out_tap=0,selio_clk_io_std=LVCMOS33,selio_clk_sig_type=SINGLE}" *)
(* CORE_GENERATION_INFO = "selectio_lvds_tx,selectio_wiz_v5_1_13,{component_name=selectio_lvds_tx,bus_dir=OUTPUTS,bus_sig_type=SINGLE,bus_io_std=LVCMOS33,use_serialization=false,use_phase_detector=false,serialization_factor=4,enable_bitslip=false,enable_train=false,system_data_width=2,bus_in_delay=NONE,bus_out_delay=NONE,clk_sig_type=SINGLE,clk_io_std=LVCMOS18,clk_buf=BUFIO2,active_edge=RISING,clk_delay=NONE,selio_bus_in_delay=NONE,selio_bus_out_delay=NONE,selio_clk_buf=BUFIO,selio_active_edge=SDR,selio_ddr_alignment=SAME_EDGE_PIPELINED,selio_oddr_alignment=SAME_EDGE,ddr_alignment=C0,selio_interface_type=NETWORKING,interface_type=NETWORKING,selio_bus_in_tap=0,selio_bus_out_tap=0,selio_clk_io_std=LVCMOS33,selio_clk_sig_type=SINGLE}" *)
module selectio_lvds_tx
// width of the data for the system
#(parameter SYS_W = 1,
#(parameter SYS_W = 2,
// width of the data for the device
parameter DEV_W = 1)
parameter DEV_W = 2)
(
// From the device out to the system
input [DEV_W-1:0] data_out_from_device,
@@ -57,8 +57,8 @@
selectio_lvds_tx
instance_name
(
.data_out_from_device(data_out_from_device), // input [0:0] data_out_from_device
.data_out_to_pins(data_out_to_pins), // output [0:0] data_out_to_pins
.data_out_from_device(data_out_from_device), // input [1:0] data_out_from_device
.data_out_to_pins(data_out_to_pins), // output [1:0] data_out_to_pins
.clk_in(clk_in), // input clk_in
.clk_out(clk_out), // output clk_out
.io_reset(io_reset) // input io_reset
@@ -55,9 +55,9 @@
module selectio_lvds_tx_selectio_wiz
// width of the data for the system
#(parameter SYS_W = 1,
#(parameter SYS_W = 2,
// width of the data for the device
parameter DEV_W = 1)
parameter DEV_W = 2)
(
// From the device out to the system
input [DEV_W-1:0] data_out_from_device,
@@ -1,7 +1,7 @@
// Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
// --------------------------------------------------------------------------------
// Tool Version: Vivado v.2019.1.3 (lin64) Build 2644227 Wed Sep 4 09:44:18 MDT 2019
// Date : Tue Mar 28 16:21:23 2023
// Date : Wed Mar 29 15:36:55 2023
// Host : JOSH-ASUS-Z690 running 64-bit Ubuntu 20.04.6 LTS
// Command : write_verilog -force -mode funcsim
// /home/josh/Workspace/vivado-git/projects/datalink_814/dl814_z7/ip/managed_ip_project/managed_ip_project.runs/selectio_lvds_tx_synth_1/selectio_lvds_tx_sim_netlist.v
@@ -12,7 +12,7 @@
// --------------------------------------------------------------------------------
`timescale 1 ps / 1 ps
(* DEV_W = "1" *) (* SYS_W = "1" *)
(* DEV_W = "2" *) (* SYS_W = "2" *)
(* NotValidForBitStream *)
module selectio_lvds_tx
(data_out_from_device,
@@ -20,20 +20,20 @@ module selectio_lvds_tx
clk_in,
clk_out,
io_reset);
input [0:0]data_out_from_device;
output [0:0]data_out_to_pins;
input [1:0]data_out_from_device;
output [1:0]data_out_to_pins;
input clk_in;
output clk_out;
input io_reset;
(* IBUF_LOW_PWR *) (* IOSTANDARD = "LVCMOS33" *) wire clk_in;
wire clk_out;
wire [0:0]data_out_from_device;
(* DRIVE = "12" *) (* IOSTANDARD = "LVCMOS33" *) (* SLEW = "SLOW" *) wire [0:0]data_out_to_pins;
wire [1:0]data_out_from_device;
(* DRIVE = "12" *) (* IOSTANDARD = "LVCMOS33" *) (* SLEW = "SLOW" *) wire [1:0]data_out_to_pins;
wire io_reset;
(* DEV_W = "1" *)
(* SYS_W = "1" *)
(* DEV_W = "2" *)
(* SYS_W = "2" *)
selectio_lvds_tx_selectio_lvds_tx_selectio_wiz inst
(.clk_in(clk_in),
.clk_out(clk_out),
@@ -42,15 +42,15 @@ module selectio_lvds_tx
.io_reset(io_reset));
endmodule
(* DEV_W = "1" *) (* ORIG_REF_NAME = "selectio_lvds_tx_selectio_wiz" *) (* SYS_W = "1" *)
(* DEV_W = "2" *) (* ORIG_REF_NAME = "selectio_lvds_tx_selectio_wiz" *) (* SYS_W = "2" *)
module selectio_lvds_tx_selectio_lvds_tx_selectio_wiz
(data_out_from_device,
data_out_to_pins,
clk_in,
clk_out,
io_reset);
input [0:0]data_out_from_device;
output [0:0]data_out_to_pins;
input [1:0]data_out_from_device;
output [1:0]data_out_to_pins;
input clk_in;
output clk_out;
input io_reset;
@@ -58,10 +58,11 @@ module selectio_lvds_tx_selectio_lvds_tx_selectio_wiz
wire clk_in;
wire clk_in_int;
wire clk_out;
wire [0:0]data_out_from_device;
wire [0:0]data_out_to_pins;
wire data_out_to_pins_int;
wire [1:0]data_out_from_device;
wire [1:0]data_out_to_pins;
wire io_reset;
wire \pins[0].data_out_from_device_q ;
wire \pins[1].data_out_from_device_q ;
(* BOX_TYPE = "PRIMITIVE" *)
BUFR #(
@@ -89,14 +90,32 @@ module selectio_lvds_tx_selectio_lvds_tx_selectio_wiz
\pins[0].fdre_out_inst
(.C(clk_out),
.CE(1'b1),
.D(data_out_from_device),
.Q(data_out_to_pins_int),
.D(data_out_from_device[0]),
.Q(\pins[0].data_out_from_device_q ),
.R(io_reset));
(* BOX_TYPE = "PRIMITIVE" *)
(* CAPACITANCE = "DONT_CARE" *)
OBUF \pins[0].obuf_inst
(.I(data_out_to_pins_int),
.O(data_out_to_pins));
(.I(\pins[0].data_out_from_device_q ),
.O(data_out_to_pins[0]));
(* BOX_TYPE = "PRIMITIVE" *)
(* IOB = "TRUE" *)
FDRE #(
.INIT(1'b0),
.IS_C_INVERTED(1'b0),
.IS_D_INVERTED(1'b0),
.IS_R_INVERTED(1'b0))
\pins[1].fdre_out_inst
(.C(clk_out),
.CE(1'b1),
.D(data_out_from_device[1]),
.Q(\pins[1].data_out_from_device_q ),
.R(io_reset));
(* BOX_TYPE = "PRIMITIVE" *)
(* CAPACITANCE = "DONT_CARE" *)
OBUF \pins[1].obuf_inst
(.I(\pins[1].data_out_from_device_q ),
.O(data_out_to_pins[1]));
endmodule
`ifndef GLBL
`define GLBL
@@ -1,7 +1,7 @@
-- Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
-- --------------------------------------------------------------------------------
-- Tool Version: Vivado v.2019.1.3 (lin64) Build 2644227 Wed Sep 4 09:44:18 MDT 2019
-- Date : Tue Mar 28 16:21:23 2023
-- Date : Wed Mar 29 15:36:55 2023
-- Host : JOSH-ASUS-Z690 running 64-bit Ubuntu 20.04.6 LTS
-- Command : write_vhdl -force -mode funcsim
-- /home/josh/Workspace/vivado-git/projects/datalink_814/dl814_z7/ip/managed_ip_project/managed_ip_project.runs/selectio_lvds_tx_synth_1/selectio_lvds_tx_sim_netlist.vhdl
@@ -16,24 +16,25 @@ library UNISIM;
use UNISIM.VCOMPONENTS.ALL;
entity selectio_lvds_tx_selectio_lvds_tx_selectio_wiz is
port (
data_out_from_device : in STD_LOGIC_VECTOR ( 0 to 0 );
data_out_to_pins : out STD_LOGIC_VECTOR ( 0 to 0 );
data_out_from_device : in STD_LOGIC_VECTOR ( 1 downto 0 );
data_out_to_pins : out STD_LOGIC_VECTOR ( 1 downto 0 );
clk_in : in STD_LOGIC;
clk_out : out STD_LOGIC;
io_reset : in STD_LOGIC
);
attribute DEV_W : integer;
attribute DEV_W of selectio_lvds_tx_selectio_lvds_tx_selectio_wiz : entity is 1;
attribute DEV_W of selectio_lvds_tx_selectio_lvds_tx_selectio_wiz : entity is 2;
attribute ORIG_REF_NAME : string;
attribute ORIG_REF_NAME of selectio_lvds_tx_selectio_lvds_tx_selectio_wiz : entity is "selectio_lvds_tx_selectio_wiz";
attribute SYS_W : integer;
attribute SYS_W of selectio_lvds_tx_selectio_lvds_tx_selectio_wiz : entity is 1;
attribute SYS_W of selectio_lvds_tx_selectio_lvds_tx_selectio_wiz : entity is 2;
end selectio_lvds_tx_selectio_lvds_tx_selectio_wiz;
architecture STRUCTURE of selectio_lvds_tx_selectio_lvds_tx_selectio_wiz is
signal clk_in_int : STD_LOGIC;
signal \^clk_out\ : STD_LOGIC;
signal data_out_to_pins_int : STD_LOGIC;
signal \pins[0].data_out_from_device_q\ : STD_LOGIC;
signal \pins[1].data_out_from_device_q\ : STD_LOGIC;
attribute BOX_TYPE : string;
attribute BOX_TYPE of clkout_buf_inst : label is "PRIMITIVE";
attribute BOX_TYPE of ibuf_clk_inst : label is "PRIMITIVE";
@@ -48,6 +49,10 @@ architecture STRUCTURE of selectio_lvds_tx_selectio_lvds_tx_selectio_wiz is
attribute IOB of \pins[0].fdre_out_inst\ : label is "TRUE";
attribute BOX_TYPE of \pins[0].obuf_inst\ : label is "PRIMITIVE";
attribute CAPACITANCE of \pins[0].obuf_inst\ : label is "DONT_CARE";
attribute BOX_TYPE of \pins[1].fdre_out_inst\ : label is "PRIMITIVE";
attribute IOB of \pins[1].fdre_out_inst\ : label is "TRUE";
attribute BOX_TYPE of \pins[1].obuf_inst\ : label is "PRIMITIVE";
attribute CAPACITANCE of \pins[1].obuf_inst\ : label is "DONT_CARE";
begin
clk_out <= \^clk_out\;
clkout_buf_inst: unisim.vcomponents.BUFR
@@ -77,14 +82,33 @@ ibuf_clk_inst: unisim.vcomponents.IBUF
C => \^clk_out\,
CE => '1',
D => data_out_from_device(0),
Q => data_out_to_pins_int,
Q => \pins[0].data_out_from_device_q\,
R => io_reset
);
\pins[0].obuf_inst\: unisim.vcomponents.OBUF
port map (
I => data_out_to_pins_int,
I => \pins[0].data_out_from_device_q\,
O => data_out_to_pins(0)
);
\pins[1].fdre_out_inst\: unisim.vcomponents.FDRE
generic map(
INIT => '0',
IS_C_INVERTED => '0',
IS_D_INVERTED => '0',
IS_R_INVERTED => '0'
)
port map (
C => \^clk_out\,
CE => '1',
D => data_out_from_device(1),
Q => \pins[1].data_out_from_device_q\,
R => io_reset
);
\pins[1].obuf_inst\: unisim.vcomponents.OBUF
port map (
I => \pins[1].data_out_from_device_q\,
O => data_out_to_pins(1)
);
end STRUCTURE;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
@@ -92,8 +116,8 @@ library UNISIM;
use UNISIM.VCOMPONENTS.ALL;
entity selectio_lvds_tx is
port (
data_out_from_device : in STD_LOGIC_VECTOR ( 0 to 0 );
data_out_to_pins : out STD_LOGIC_VECTOR ( 0 to 0 );
data_out_from_device : in STD_LOGIC_VECTOR ( 1 downto 0 );
data_out_to_pins : out STD_LOGIC_VECTOR ( 1 downto 0 );
clk_in : in STD_LOGIC;
clk_out : out STD_LOGIC;
io_reset : in STD_LOGIC
@@ -101,21 +125,21 @@ entity selectio_lvds_tx is
attribute NotValidForBitStream : boolean;
attribute NotValidForBitStream of selectio_lvds_tx : entity is true;
attribute DEV_W : integer;
attribute DEV_W of selectio_lvds_tx : entity is 1;
attribute DEV_W of selectio_lvds_tx : entity is 2;
attribute SYS_W : integer;
attribute SYS_W of selectio_lvds_tx : entity is 1;
attribute SYS_W of selectio_lvds_tx : entity is 2;
end selectio_lvds_tx;
architecture STRUCTURE of selectio_lvds_tx is
attribute DEV_W of inst : label is 1;
attribute SYS_W of inst : label is 1;
attribute DEV_W of inst : label is 2;
attribute SYS_W of inst : label is 2;
begin
inst: entity work.selectio_lvds_tx_selectio_lvds_tx_selectio_wiz
port map (
clk_in => clk_in,
clk_out => clk_out,
data_out_from_device(0) => data_out_from_device(0),
data_out_to_pins(0) => data_out_to_pins(0),
data_out_from_device(1 downto 0) => data_out_from_device(1 downto 0),
data_out_to_pins(1 downto 0) => data_out_to_pins(1 downto 0),
io_reset => io_reset
);
end STRUCTURE;
@@ -1,7 +1,7 @@
// Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
// --------------------------------------------------------------------------------
// Tool Version: Vivado v.2019.1.3 (lin64) Build 2644227 Wed Sep 4 09:44:18 MDT 2019
// Date : Tue Mar 28 16:21:23 2023
// Date : Wed Mar 29 15:36:55 2023
// Host : JOSH-ASUS-Z690 running 64-bit Ubuntu 20.04.6 LTS
// Command : write_verilog -force -mode synth_stub
// /home/josh/Workspace/vivado-git/projects/datalink_814/dl814_z7/ip/managed_ip_project/managed_ip_project.runs/selectio_lvds_tx_synth_1/selectio_lvds_tx_stub.v
@@ -15,9 +15,9 @@
// Please paste the declaration into a Verilog source file or add the file as an additional source.
module selectio_lvds_tx(data_out_from_device, data_out_to_pins,
clk_in, clk_out, io_reset)
/* synthesis syn_black_box black_box_pad_pin="data_out_from_device[0:0],data_out_to_pins[0:0],clk_in,clk_out,io_reset" */;
input [0:0]data_out_from_device;
output [0:0]data_out_to_pins;
/* synthesis syn_black_box black_box_pad_pin="data_out_from_device[1:0],data_out_to_pins[1:0],clk_in,clk_out,io_reset" */;
input [1:0]data_out_from_device;
output [1:0]data_out_to_pins;
input clk_in;
output clk_out;
input io_reset;
@@ -1,7 +1,7 @@
-- Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
-- --------------------------------------------------------------------------------
-- Tool Version: Vivado v.2019.1.3 (lin64) Build 2644227 Wed Sep 4 09:44:18 MDT 2019
-- Date : Tue Mar 28 16:21:23 2023
-- Date : Wed Mar 29 15:36:55 2023
-- Host : JOSH-ASUS-Z690 running 64-bit Ubuntu 20.04.6 LTS
-- Command : write_vhdl -force -mode synth_stub
-- /home/josh/Workspace/vivado-git/projects/datalink_814/dl814_z7/ip/managed_ip_project/managed_ip_project.runs/selectio_lvds_tx_synth_1/selectio_lvds_tx_stub.vhdl
@@ -14,8 +14,8 @@ use IEEE.STD_LOGIC_1164.ALL;
entity selectio_lvds_tx is
Port (
data_out_from_device : in STD_LOGIC_VECTOR ( 0 to 0 );
data_out_to_pins : out STD_LOGIC_VECTOR ( 0 to 0 );
data_out_from_device : in STD_LOGIC_VECTOR ( 1 downto 0 );
data_out_to_pins : out STD_LOGIC_VECTOR ( 1 downto 0 );
clk_in : in STD_LOGIC;
clk_out : out STD_LOGIC;
io_reset : in STD_LOGIC
@@ -27,6 +27,6 @@ architecture stub of selectio_lvds_tx is
attribute syn_black_box : boolean;
attribute black_box_pad_pin : string;
attribute syn_black_box of stub : architecture is true;
attribute black_box_pad_pin of stub : architecture is "data_out_from_device[0:0],data_out_to_pins[0:0],clk_in,clk_out,io_reset";
attribute black_box_pad_pin of stub : architecture is "data_out_from_device[1:0],data_out_to_pins[1:0],clk_in,clk_out,io_reset";
begin
end;
@@ -1,671 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Company: Xilinx
// Engineer: Jim Tatsukawa, Karl Kurbjun and Carl Ribbing
// Date: 7/30/2014
// Design Name: MMCME2 DRP
// Module Name: mmcme2_drp_func.h
// Version: 1.04
// Target Devices: 7 Series || MMCM
// Tool versions: 2014.3
// Description: This header provides the functions necessary to
// calculate the DRP register values for the V6 MMCM.
//
// Revision Notes: 3/12 - Updating lookup_low/lookup_high (CR)
// 4/13 - Fractional divide function in mmcm_frac_count_calc function. CRS610807
//
// Disclaimer: XILINX IS PROVIDING THIS DESIGN, CODE, OR
// INFORMATION "AS IS" SOLELY FOR USE IN DEVELOPING
// PROGRAMS AND SOLUTIONS FOR XILINX DEVICES. BY
// PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
// ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
// APPLICATION OR STANDARD, XILINX IS MAKING NO
// REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
// FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE
// RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY
// REQUIRE FOR YOUR IMPLEMENTATION. XILINX
// EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH
// RESPECT TO THE ADEQUACY OF THE IMPLEMENTATION,
// INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
// REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE.
//
// (c) Copyright 2009-2010 Xilinx, Inc.
// All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
// These are user functions that should not be modified. Changes to the defines
// or code within the functions may alter the accuracy of the calculations.
// Define debug to provide extra messages durring elaboration
//`define DEBUG 1
// FRAC_PRECISION describes the width of the fractional portion of the fixed
// point numbers. These should not be modified, they are for development
// only
`define FRAC_PRECISION 10
// FIXED_WIDTH describes the total size for fixed point calculations(int+frac).
// Warning: L.50 and below will not calculate properly with FIXED_WIDTHs
// greater than 32
`define FIXED_WIDTH 32
// This function takes a fixed point number and rounds it to the nearest
// fractional precision bit.
function [`FIXED_WIDTH:1] round_frac
(
// Input is (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point number
input [`FIXED_WIDTH:1] decimal,
// This describes the precision of the fraction, for example a value
// of 1 would modify the fractional so that instead of being a .16
// fractional, it would be a .1 (rounded to the nearest 0.5 in turn)
input [`FIXED_WIDTH:1] precision
);
begin
`ifdef DEBUG
$display("round_frac - decimal: %h, precision: %h", decimal, precision);
`endif
// If the fractional precision bit is high then round up
if( decimal[(`FRAC_PRECISION-precision)] == 1'b1) begin
round_frac = decimal + (1'b1 << (`FRAC_PRECISION-precision));
end else begin
round_frac = decimal;
end
`ifdef DEBUG
$display("round_frac: %h", round_frac);
`endif
end
endfunction
// This function calculates high_time, low_time, w_edge, and no_count
// of a non-fractional counter based on the divide and duty cycle
//
// NOTE: high_time and low_time are returned as integers between 0 and 63
// inclusive. 64 should equal 6'b000000 (in other words it is okay to
// ignore the overflow)
function [13:0] mmcm_pll_divider
(
input [7:0] divide, // Max divide is 128
input [31:0] duty_cycle // Duty cycle is multiplied by 100,000
);
reg [`FIXED_WIDTH:1] duty_cycle_fix;
// High/Low time is initially calculated with a wider integer to prevent a
// calculation error when it overflows to 64.
reg [6:0] high_time;
reg [6:0] low_time;
reg w_edge;
reg no_count;
reg [`FIXED_WIDTH:1] temp;
begin
// Duty Cycle must be between 0 and 1,000
if(duty_cycle <=0 || duty_cycle >= 100000) begin
`ifndef SYNTHESIS
$display("ERROR: duty_cycle: %d is invalid", duty_cycle);
`endif
$finish;
end
// Convert to FIXED_WIDTH-FRAC_PRECISION.FRAC_PRECISION fixed point
duty_cycle_fix = (duty_cycle << `FRAC_PRECISION) / 100_000;
`ifdef DEBUG
$display("duty_cycle_fix: %h", duty_cycle_fix);
`endif
// If the divide is 1 nothing needs to be set except the no_count bit.
// Other values are dummies
if(divide == 7'h01) begin
high_time = 7'h01;
w_edge = 1'b0;
low_time = 7'h01;
no_count = 1'b1;
end else begin
temp = round_frac(duty_cycle_fix*divide, 1);
// comes from above round_frac
high_time = temp[`FRAC_PRECISION+7:`FRAC_PRECISION+1];
// If the duty cycle * divide rounded is .5 or greater then this bit
// is set.
w_edge = temp[`FRAC_PRECISION]; // comes from round_frac
// If the high time comes out to 0, it needs to be set to at least 1
// and w_edge set to 0
if(high_time == 7'h00) begin
high_time = 7'h01;
w_edge = 1'b0;
end
if(high_time == divide) begin
high_time = divide - 1;
w_edge = 1'b1;
end
// Calculate low_time based on the divide setting and set no_count to
// 0 as it is only used when divide is 1.
low_time = divide - high_time;
no_count = 1'b0;
end
// Set the return value.
mmcm_pll_divider = {w_edge,no_count,high_time[5:0],low_time[5:0]};
end
endfunction
// This function calculates mx, delay_time, and phase_mux
// of a non-fractional counter based on the divide and phase
//
// NOTE: The only valid value for the MX bits is 2'b00 to ensure the coarse mux
// is used.
function [10:0] mmcm_pll_phase
(
// divide must be an integer (use fractional if not)
// assumed that divide already checked to be valid
input [7:0] divide, // Max divide is 128
// Phase is given in degrees (-360,000 to 360,000)
input signed [31:0] phase
);
reg [`FIXED_WIDTH:1] phase_in_cycles;
reg [`FIXED_WIDTH:1] phase_fixed;
reg [1:0] mx;
reg [5:0] delay_time;
reg [2:0] phase_mux;
reg [`FIXED_WIDTH:1] temp;
begin
`ifdef DEBUG
$display("mmcm_pll_phase-divide:%d,phase:%d",
divide, phase);
`endif
if ((phase < -360000) || (phase > 360000)) begin
`ifndef SYNTHESIS
$display("ERROR: phase of $phase is not between -360000 and 360000");
`endif
$finish;
end
// If phase is less than 0, convert it to a positive phase shift
// Convert to (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point
if(phase < 0) begin
phase_fixed = ( (phase + 360000) << `FRAC_PRECISION ) / 1000;
end else begin
phase_fixed = ( phase << `FRAC_PRECISION ) / 1000;
end
// Put phase in terms of decimal number of vco clock cycles
phase_in_cycles = ( phase_fixed * divide ) / 360;
`ifdef DEBUG
$display("phase_in_cycles: %h", phase_in_cycles);
`endif
temp = round_frac(phase_in_cycles, 3);
// set mx to 2'b00 that the phase mux from the VCO is enabled
mx = 2'b00;
phase_mux = temp[`FRAC_PRECISION:`FRAC_PRECISION-2];
delay_time = temp[`FRAC_PRECISION+6:`FRAC_PRECISION+1];
`ifdef DEBUG
$display("temp: %h", temp);
`endif
// Setup the return value
mmcm_pll_phase={mx, phase_mux, delay_time};
end
endfunction
// This function takes the divide value and outputs the necessary lock values
function [39:0] mmcm_pll_lock_lookup
(
input [6:0] divide // Max divide is 64
);
reg [2559:0] lookup;
begin
lookup = {
// This table is composed of:
// LockRefDly_LockFBDly_LockCnt_LockSatHigh_UnlockCnt
40'b00110_00110_1111101000_1111101001_0000000001,
40'b00110_00110_1111101000_1111101001_0000000001,
40'b01000_01000_1111101000_1111101001_0000000001,
40'b01011_01011_1111101000_1111101001_0000000001,
40'b01110_01110_1111101000_1111101001_0000000001,
40'b10001_10001_1111101000_1111101001_0000000001,
40'b10011_10011_1111101000_1111101001_0000000001,
40'b10110_10110_1111101000_1111101001_0000000001,
40'b11001_11001_1111101000_1111101001_0000000001,
40'b11100_11100_1111101000_1111101001_0000000001,
40'b11111_11111_1110000100_1111101001_0000000001,
40'b11111_11111_1100111001_1111101001_0000000001,
40'b11111_11111_1011101110_1111101001_0000000001,
40'b11111_11111_1010111100_1111101001_0000000001,
40'b11111_11111_1010001010_1111101001_0000000001,
40'b11111_11111_1001110001_1111101001_0000000001,
40'b11111_11111_1000111111_1111101001_0000000001,
40'b11111_11111_1000100110_1111101001_0000000001,
40'b11111_11111_1000001101_1111101001_0000000001,
40'b11111_11111_0111110100_1111101001_0000000001,
40'b11111_11111_0111011011_1111101001_0000000001,
40'b11111_11111_0111000010_1111101001_0000000001,
40'b11111_11111_0110101001_1111101001_0000000001,
40'b11111_11111_0110010000_1111101001_0000000001,
40'b11111_11111_0110010000_1111101001_0000000001,
40'b11111_11111_0101110111_1111101001_0000000001,
40'b11111_11111_0101011110_1111101001_0000000001,
40'b11111_11111_0101011110_1111101001_0000000001,
40'b11111_11111_0101000101_1111101001_0000000001,
40'b11111_11111_0101000101_1111101001_0000000001,
40'b11111_11111_0100101100_1111101001_0000000001,
40'b11111_11111_0100101100_1111101001_0000000001,
40'b11111_11111_0100101100_1111101001_0000000001,
40'b11111_11111_0100010011_1111101001_0000000001,
40'b11111_11111_0100010011_1111101001_0000000001,
40'b11111_11111_0100010011_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001
};
// Set lookup_entry with the explicit bits from lookup with a part select
mmcm_pll_lock_lookup = lookup[ ((64-divide)*40) +: 40];
`ifdef DEBUG
$display("lock_lookup: %b", mmcm_pll_lock_lookup);
`endif
end
endfunction
// This function takes the divide value and the bandwidth setting of the MMCM
// and outputs the digital filter settings necessary.
function [9:0] mmcm_pll_filter_lookup
(
input [6:0] divide, // Max divide is 64
input [8*9:0] BANDWIDTH
);
reg [639:0] lookup_low;
reg [639:0] lookup_high;
reg [9:0] lookup_entry;
begin
lookup_low = {
// CP_RES_LFHF
10'b0010_1111_00,
10'b0010_1111_00,
10'b0010_1111_00,
10'b0010_1111_00,
10'b0010_0111_00,
10'b0010_1011_00,
10'b0010_1101_00,
10'b0010_0011_00,
10'b0010_0101_00,
10'b0010_0101_00,
10'b0010_1001_00,
10'b0010_1110_00,
10'b0010_1110_00,
10'b0010_1110_00,
10'b0010_1110_00,
10'b0010_0001_00,
10'b0010_0001_00,
10'b0010_0001_00,
10'b0010_0110_00,
10'b0010_0110_00,
10'b0010_0110_00,
10'b0010_0110_00,
10'b0010_0110_00,
10'b0010_0110_00,
10'b0010_0110_00,
10'b0010_1010_00,
10'b0010_1010_00,
10'b0010_1010_00,
10'b0010_1010_00,
10'b0010_1010_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00
};
lookup_high = {
// CP_RES_LFHF
10'b0010_1111_00,
10'b0100_1111_00,
10'b0101_1011_00,
10'b0111_0111_00,
10'b1101_0111_00,
10'b1110_1011_00,
10'b1110_1101_00,
10'b1111_0011_00,
10'b1110_0101_00,
10'b1111_0101_00,
10'b1111_1001_00,
10'b1101_0001_00,
10'b1111_1001_00,
10'b1111_1001_00,
10'b1111_1001_00,
10'b1111_1001_00,
10'b1111_0101_00,
10'b1111_0101_00,
10'b1100_0001_00,
10'b1100_0001_00,
10'b1100_0001_00,
10'b0101_1100_00,
10'b0101_1100_00,
10'b0101_1100_00,
10'b0101_1100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0011_0100_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0111_0001_00,
10'b0111_0001_00,
10'b0100_1100_00,
10'b0100_1100_00,
10'b0100_1100_00,
10'b0100_1100_00,
10'b0110_0001_00,
10'b0110_0001_00,
10'b0101_0110_00,
10'b0101_0110_00,
10'b0101_0110_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0100_1010_00,
10'b0011_1100_00,
10'b0011_1100_00
};
// Set lookup_entry with the explicit bits from lookup with a part select
if(BANDWIDTH == "LOW") begin
// Low Bandwidth
mmcm_pll_filter_lookup = lookup_low[ ((64-divide)*10) +: 10];
end else begin
// High or optimized bandwidth
mmcm_pll_filter_lookup = lookup_high[ ((64-divide)*10) +: 10];
end
`ifdef DEBUG
$display("filter_lookup: %b", mmcm_pll_filter_lookup);
`endif
end
endfunction
// This function takes in the divide, phase, and duty cycle
// setting to calculate the upper and lower counter registers.
function [37:0] mmcm_pll_count_calc
(
input [7:0] divide, // Max divide is 128
input signed [31:0] phase,
input [31:0] duty_cycle // Multiplied by 100,000
);
reg [13:0] div_calc;
reg [16:0] phase_calc;
begin
`ifdef DEBUG
$display("mmcm_pll_count_calc- divide:%h, phase:%d, duty_cycle:%d",
divide, phase, duty_cycle);
`endif
// w_edge[13], no_count[12], high_time[11:6], low_time[5:0]
div_calc = mmcm_pll_divider(divide, duty_cycle);
// mx[10:9], pm[8:6], dt[5:0]
phase_calc = mmcm_pll_phase(divide, phase);
// Return value is the upper and lower address of counter
// Upper address is:
// RESERVED [31:26]
// MX [25:24]
// EDGE [23]
// NOCOUNT [22]
// DELAY_TIME [21:16]
// Lower Address is:
// PHASE_MUX [15:13]
// RESERVED [12]
// HIGH_TIME [11:6]
// LOW_TIME [5:0]
`ifdef DEBUG
$display("div:%d dc:%d phase:%d ht:%d lt:%d ed:%d nc:%d mx:%d dt:%d pm:%d",
divide, duty_cycle, phase, div_calc[11:6], div_calc[5:0],
div_calc[13], div_calc[12],
phase_calc[16:15], phase_calc[5:0], phase_calc[14:12]);
`endif
mmcm_pll_count_calc =
{
// Upper Address
6'h00, phase_calc[10:9], div_calc[13:12], phase_calc[5:0],
// Lower Address
phase_calc[8:6], 1'b0, div_calc[11:0]
};
end
endfunction
// This function takes in the divide, phase, and duty cycle
// setting to calculate the upper and lower counter registers.
// for fractional multiply/divide functions.
//
//
function [37:0] mmcm_frac_count_calc
(
input [7:0] divide, // Max divide is 128
input signed [31:0] phase,
input [31:0] duty_cycle, // Multiplied by 1,000
input [9:0] frac // Multiplied by 1000
);
//Required for fractional divide calculations
reg [7:0] lt_frac;
reg [7:0] ht_frac;
reg /*[7:0]*/ wf_fall_frac;
reg /*[7:0]*/ wf_rise_frac;
reg [31:0] a;
reg [7:0] pm_rise_frac_filtered ;
reg [7:0] pm_fall_frac_filtered ;
reg [7:0] clkout0_divide_int;
reg [2:0] clkout0_divide_frac;
reg [7:0] even_part_high;
reg [7:0] even_part_low;
reg [7:0] odd;
reg [7:0] odd_and_frac;
reg [7:0] pm_fall;
reg [7:0] pm_rise;
reg [7:0] dt;
reg [7:0] dt_int;
reg [63:0] dt_calc;
reg [7:0] pm_rise_frac;
reg [7:0] pm_fall_frac;
reg [31:0] a_per_in_octets;
reg [31:0] a_phase_in_cycles;
parameter precision = 0.125;
reg [31:0] phase_fixed; // changed to 31:0 from 32:1 jt 5/2/11
reg [31: 0] phase_pos;
reg [31: 0] phase_vco;
reg [31:0] temp;// changed to 31:0 from 32:1 jt 5/2/11
reg [13:0] div_calc;
reg [16:0] phase_calc;
begin
`ifdef DEBUG
$display("mmcm_frac_count_calc- divide:%h, phase:%d, duty_cycle:%d",
divide, phase, duty_cycle);
`endif
//convert phase to fixed
if ((phase < -360000) || (phase > 360000)) begin
`ifndef SYNTHESIS
$display("ERROR: phase of $phase is not between -360000 and 360000");
`endif
$finish;
end
// Return value is
// Transfer data
// RESERVED [37:36]
// FRAC_TIME [35:33]
// FRAC_WF_FALL [32]
// Upper address is:
// RESERVED [31:26]
// MX [25:24]
// EDGE [23]
// NOCOUNT [22]
// DELAY_TIME [21:16]
// Lower Address is:
// PHASE_MUX [15:13]
// RESERVED [12]
// HIGH_TIME [11:6]
// LOW_TIME [5:0]
clkout0_divide_frac = frac / 125;
clkout0_divide_int = divide;
even_part_high = clkout0_divide_int >> 1;//$rtoi(clkout0_divide_int / 2);
even_part_low = even_part_high;
odd = clkout0_divide_int - even_part_high - even_part_low;
odd_and_frac = (8*odd) + clkout0_divide_frac;
lt_frac = even_part_high - (odd_and_frac <= 9);//IF(odd_and_frac>9,even_part_high, even_part_high - 1)
ht_frac = even_part_low - (odd_and_frac <= 8);//IF(odd_and_frac>8,even_part_low, even_part_low- 1)
pm_fall = {odd[6:0],2'b00} + {6'h00, clkout0_divide_frac[2:1]}; // using >> instead of clkout0_divide_frac / 2
pm_rise = 0; //0
wf_fall_frac = ((odd_and_frac >=2) && (odd_and_frac <=9)) || ((clkout0_divide_frac == 1) && (clkout0_divide_int == 2));//CRS610807
wf_rise_frac = (odd_and_frac >=1) && (odd_and_frac <=8);//IF(odd_and_frac>=1,IF(odd_and_frac <= 8,1,0),0)
//Calculate phase in fractional cycles
a_per_in_octets = (8 * divide) + (frac / 125) ;
a_phase_in_cycles = (phase+10) * a_per_in_octets / 360000 ;//Adding 1 due to rounding errors
pm_rise_frac = (a_phase_in_cycles[7:0] ==8'h00)?8'h00:a_phase_in_cycles[7:0] - {a_phase_in_cycles[7:3],3'b000};
dt_calc = ((phase+10) * a_per_in_octets / 8 )/360000 ;//TRUNC(phase* divide / 360); //or_simply (a_per_in_octets / 8)
dt = dt_calc[7:0];
pm_rise_frac_filtered = (pm_rise_frac >=8) ? (pm_rise_frac ) - 8: pm_rise_frac ; //((phase_fixed * (divide + frac / 1000)) / 360) - {pm_rise_frac[7:3],3'b000};//$rtoi(clkout0_phase * clkout0_divide / 45);//a;
dt_int = dt + (& pm_rise_frac[7:4]); //IF(pm_rise_overwriting>7,dt+1,dt)
pm_fall_frac = pm_fall + pm_rise_frac;
pm_fall_frac_filtered = pm_fall + pm_rise_frac - {pm_fall_frac[7:3], 3'b000};
div_calc = mmcm_pll_divider(divide, duty_cycle); //Use to determine edge[7], no count[6]
phase_calc = mmcm_pll_phase(divide, phase);// returns{mx[1:0], phase_mux[2:0], delay_time[5:0]}
mmcm_frac_count_calc[37:0] =
{ 2'b00, pm_fall_frac_filtered[2:0], wf_fall_frac,
1'b0, clkout0_divide_frac[2:0], 1'b1, wf_rise_frac, phase_calc[10:9], div_calc[13:12], dt[5:0],
pm_rise_frac_filtered[2], pm_rise_frac_filtered[1], pm_rise_frac_filtered[0], 1'b0, ht_frac[5:0], lt_frac[5:0]
} ;
`ifdef DEBUG
$display("-%d.%d p%d>> :DADDR_9_15 frac30to28.frac_en.wf_r_frac.dt:%b%d%d_%b:DADDR_7_13 pm_f_frac_filtered_29to27.wf_f_frac_26:%b%d:DADDR_8_14.pm_r_frac_filt_15to13.ht_frac.lt_frac:%b%b%b:", divide, frac, phase, clkout0_divide_frac, 1, wf_rise_frac, dt, pm_fall_frac_filtered, wf_fall_frac, pm_rise_frac_filtered, ht_frac, lt_frac);
`endif
end
endfunction
@@ -1,531 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Company: Xilinx
// Engineer: Jim Tatsukawa, Karl Kurbjun and Carl Ribbing
// Date: 7/30/2014
// Design Name: PLLE2 DRP
// Module Name: plle2_drp_func.h
// Version: 2.00
// Target Devices: 7 Series || PLL
// Tool versions: 2014.3
// Description: This header provides the functions necessary to
// calculate the DRP register values for the V6 PLL.
// Updated for CR663854.
//
// Disclaimer: XILINX IS PROVIDING THIS DESIGN, CODE, OR
// INFORMATION "AS IS" SOLELY FOR USE IN DEVELOPING
// PROGRAMS AND SOLUTIONS FOR XILINX DEVICES. BY
// PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
// ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
// APPLICATION OR STANDARD, XILINX IS MAKING NO
// REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
// FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE
// RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY
// REQUIRE FOR YOUR IMPLEMENTATION. XILINX
// EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH
// RESPECT TO THE ADEQUACY OF THE IMPLEMENTATION,
// INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
// REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE.
//
// (c) Copyright 2009-2010 Xilinx, Inc.
// All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
// These are user functions that should not be modified. Changes to the defines
// or code within the functions may alter the accuracy of the calculations.
// Define debug to provide extra messages durring elaboration
//`define DEBUG 1
// FRAC_PRECISION describes the width of the fractional portion of the fixed
// point numbers. These should not be modified, they are for development
// only
`define FRAC_PRECISION 10
// FIXED_WIDTH describes the total size for fixed point calculations(int+frac).
// Warning: L.50 and below will not calculate properly with FIXED_WIDTHs
// greater than 32
`define FIXED_WIDTH 32
// This function takes a fixed point number and rounds it to the nearest
// fractional precision bit.
function [`FIXED_WIDTH:1] round_frac
(
// Input is (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point number
input [`FIXED_WIDTH:1] decimal,
// This describes the precision of the fraction, for example a value
// of 1 would modify the fractional so that instead of being a .16
// fractional, it would be a .1 (rounded to the nearest 0.5 in turn)
input [`FIXED_WIDTH:1] precision
);
begin
`ifdef DEBUG
$display("round_frac - decimal: %h, precision: %h", decimal, precision);
`endif
// If the fractional precision bit is high then round up
if( decimal[(`FRAC_PRECISION-precision)] == 1'b1) begin
round_frac = decimal + (1'b1 << (`FRAC_PRECISION-precision));
end else begin
round_frac = decimal;
end
`ifdef DEBUG
$display("round_frac: %h", round_frac);
`endif
end
endfunction
// This function calculates high_time, low_time, w_edge, and no_count
// of a non-fractional counter based on the divide and duty cycle
//
// NOTE: high_time and low_time are returned as integers between 0 and 63
// inclusive. 64 should equal 6'b000000 (in other words it is okay to
// ignore the overflow)
function [13:0] mmcm_pll_divider
(
input [7:0] divide, // Max divide is 128
input [31:0] duty_cycle // Duty cycle is multiplied by 100,000
);
reg [`FIXED_WIDTH:1] duty_cycle_fix;
// High/Low time is initially calculated with a wider integer to prevent a
// calculation error when it overflows to 64.
reg [6:0] high_time;
reg [6:0] low_time;
reg w_edge;
reg no_count;
reg [`FIXED_WIDTH:1] temp;
begin
// Duty Cycle must be between 0 and 1,000
if(duty_cycle <=0 || duty_cycle >= 100000) begin
`ifndef SYNTHESIS
$display("ERROR: duty_cycle: %d is invalid", duty_cycle);
`endif
$finish;
end
// Convert to FIXED_WIDTH-FRAC_PRECISION.FRAC_PRECISION fixed point
duty_cycle_fix = (duty_cycle << `FRAC_PRECISION) / 100_000;
`ifdef DEBUG
$display("duty_cycle_fix: %h", duty_cycle_fix);
`endif
// If the divide is 1 nothing needs to be set except the no_count bit.
// Other values are dummies
if(divide == 7'h01) begin
high_time = 7'h01;
w_edge = 1'b0;
low_time = 7'h01;
no_count = 1'b1;
end else begin
temp = round_frac(duty_cycle_fix*divide, 1);
// comes from above round_frac
high_time = temp[`FRAC_PRECISION+7:`FRAC_PRECISION+1];
// If the duty cycle * divide rounded is .5 or greater then this bit
// is set.
w_edge = temp[`FRAC_PRECISION]; // comes from round_frac
// If the high time comes out to 0, it needs to be set to at least 1
// and w_edge set to 0
if(high_time == 7'h00) begin
high_time = 7'h01;
w_edge = 1'b0;
end
if(high_time == divide) begin
high_time = divide - 1;
w_edge = 1'b1;
end
// Calculate low_time based on the divide setting and set no_count to
// 0 as it is only used when divide is 1.
low_time = divide - high_time;
no_count = 1'b0;
end
// Set the return value.
mmcm_pll_divider = {w_edge,no_count,high_time[5:0],low_time[5:0]};
end
endfunction
// This function calculates mx, delay_time, and phase_mux
// of a non-fractional counter based on the divide and phase
//
// NOTE: The only valid value for the MX bits is 2'b00 to ensure the coarse mux
// is used.
function [10:0] mmcm_pll_phase
(
// divide must be an integer (use fractional if not)
// assumed that divide already checked to be valid
input [7:0] divide, // Max divide is 128
// Phase is given in degrees (-360,000 to 360,000)
input signed [31:0] phase
);
reg [`FIXED_WIDTH:1] phase_in_cycles;
reg [`FIXED_WIDTH:1] phase_fixed;
reg [1:0] mx;
reg [5:0] delay_time;
reg [2:0] phase_mux;
reg [`FIXED_WIDTH:1] temp;
begin
`ifdef DEBUG
$display("mmcm_pll_phase-divide:%d,phase:%d",
divide, phase);
`endif
if ((phase < -360000) || (phase > 360000)) begin
`ifndef SYNTHESIS
$display("ERROR: phase of $phase is not between -360000 and 360000");
`endif
$finish;
end
// If phase is less than 0, convert it to a positive phase shift
// Convert to (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point
if(phase < 0) begin
phase_fixed = ( (phase + 360000) << `FRAC_PRECISION ) / 1000;
end else begin
phase_fixed = ( phase << `FRAC_PRECISION ) / 1000;
end
// Put phase in terms of decimal number of vco clock cycles
phase_in_cycles = ( phase_fixed * divide ) / 360;
`ifdef DEBUG
$display("phase_in_cycles: %h", phase_in_cycles);
`endif
temp = round_frac(phase_in_cycles, 3);
// set mx to 2'b00 that the phase mux from the VCO is enabled
mx = 2'b00;
phase_mux = temp[`FRAC_PRECISION:`FRAC_PRECISION-2];
delay_time = temp[`FRAC_PRECISION+6:`FRAC_PRECISION+1];
`ifdef DEBUG
$display("temp: %h", temp);
`endif
// Setup the return value
mmcm_pll_phase={mx, phase_mux, delay_time};
end
endfunction
// This function takes the divide value and outputs the necessary lock values
function [39:0] mmcm_pll_lock_lookup
(
input [6:0] divide // Max divide is 64
);
reg [2559:0] lookup;
begin
lookup = {
// This table is composed of:
// LockRefDly_LockFBDly_LockCnt_LockSatHigh_UnlockCnt
40'b00110_00110_1111101000_1111101001_0000000001,
40'b00110_00110_1111101000_1111101001_0000000001,
40'b01000_01000_1111101000_1111101001_0000000001,
40'b01011_01011_1111101000_1111101001_0000000001,
40'b01110_01110_1111101000_1111101001_0000000001,
40'b10001_10001_1111101000_1111101001_0000000001,
40'b10011_10011_1111101000_1111101001_0000000001,
40'b10110_10110_1111101000_1111101001_0000000001,
40'b11001_11001_1111101000_1111101001_0000000001,
40'b11100_11100_1111101000_1111101001_0000000001,
40'b11111_11111_1110000100_1111101001_0000000001,
40'b11111_11111_1100111001_1111101001_0000000001,
40'b11111_11111_1011101110_1111101001_0000000001,
40'b11111_11111_1010111100_1111101001_0000000001,
40'b11111_11111_1010001010_1111101001_0000000001,
40'b11111_11111_1001110001_1111101001_0000000001,
40'b11111_11111_1000111111_1111101001_0000000001,
40'b11111_11111_1000100110_1111101001_0000000001,
40'b11111_11111_1000001101_1111101001_0000000001,
40'b11111_11111_0111110100_1111101001_0000000001,
40'b11111_11111_0111011011_1111101001_0000000001,
40'b11111_11111_0111000010_1111101001_0000000001,
40'b11111_11111_0110101001_1111101001_0000000001,
40'b11111_11111_0110010000_1111101001_0000000001,
40'b11111_11111_0110010000_1111101001_0000000001,
40'b11111_11111_0101110111_1111101001_0000000001,
40'b11111_11111_0101011110_1111101001_0000000001,
40'b11111_11111_0101011110_1111101001_0000000001,
40'b11111_11111_0101000101_1111101001_0000000001,
40'b11111_11111_0101000101_1111101001_0000000001,
40'b11111_11111_0100101100_1111101001_0000000001,
40'b11111_11111_0100101100_1111101001_0000000001,
40'b11111_11111_0100101100_1111101001_0000000001,
40'b11111_11111_0100010011_1111101001_0000000001,
40'b11111_11111_0100010011_1111101001_0000000001,
40'b11111_11111_0100010011_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001
};
// Set lookup_entry with the explicit bits from lookup with a part select
mmcm_pll_lock_lookup = lookup[ ((64-divide)*40) +: 40];
`ifdef DEBUG
$display("lock_lookup: %b", mmcm_pll_lock_lookup);
`endif
end
endfunction
// This function takes the divide value and the bandwidth setting of the PLL
// and outputs the digital filter settings necessary.
function [9:0] mmcm_pll_filter_lookup
(
input [6:0] divide, // Max divide is 64
input [8*9:0] BANDWIDTH
);
reg [639:0] lookup_low;
reg [639:0] lookup_high;
reg [9:0] lookup_entry;
begin
lookup_low = {
// CP_RES_LFHF
10'b0010_1111_00,
10'b0010_1111_00,
10'b0010_0111_00,
10'b0010_1101_00,
10'b0010_0101_00,
10'b0010_0101_00,
10'b0010_1001_00,
10'b0010_1110_00,
10'b0010_1110_00,
10'b0010_0001_00,
10'b0010_0001_00,
10'b0010_0110_00,
10'b0010_0110_00,
10'b0010_0110_00,
10'b0010_0110_00,
10'b0010_1010_00,
10'b0010_1010_00,
10'b0010_1010_00,
10'b0010_1010_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_1100_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0010_0010_00,
10'b0011_1100_00,
10'b0011_1100_00,
10'b0011_1100_00,
10'b0011_1100_00,
10'b0011_1100_00,
10'b0011_1100_00,
10'b0011_1100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00
};
lookup_high = {
// CP_RES_LFHF
10'b0011_0111_00,
10'b0011_0111_00,
10'b0101_1111_00,
10'b0111_1111_00,
10'b0111_1011_00,
10'b1101_0111_00,
10'b1110_1011_00,
10'b1110_1101_00,
10'b1111_1101_00,
10'b1111_0111_00,
10'b1111_1011_00,
10'b1111_1101_00,
10'b1111_0011_00,
10'b1110_0101_00,
10'b1111_0101_00,
10'b1111_0101_00,
10'b1111_0101_00,
10'b1111_0101_00,
10'b0111_0110_00,
10'b0111_0110_00,
10'b0111_0110_00,
10'b0111_0110_00,
10'b0101_1100_00,
10'b0101_1100_00,
10'b0101_1100_00,
10'b1100_0001_00,
10'b1100_0001_00,
10'b1100_0001_00,
10'b1100_0001_00,
10'b1100_0001_00,
10'b1100_0001_00,
10'b1100_0001_00,
10'b1100_0001_00,
10'b0100_0010_00,
10'b0100_0010_00,
10'b0100_0010_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0011_0100_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0010_1000_00,
10'b0100_1100_00,
10'b0100_1100_00,
10'b0100_1100_00,
10'b0100_1100_00,
10'b0100_1100_00,
10'b0100_1100_00,
10'b0100_1100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00,
10'b0010_0100_00
};
// Set lookup_entry with the explicit bits from lookup with a part select
if(BANDWIDTH == "LOW") begin
// Low Bandwidth
mmcm_pll_filter_lookup = lookup_low[ ((64-divide)*10) +: 10];
end else begin
// High or optimized bandwidth
mmcm_pll_filter_lookup = lookup_high[ ((64-divide)*10) +: 10];
end
`ifdef DEBUG
$display("filter_lookup: %b", mmcm_pll_filter_lookup);
`endif
end
endfunction
// This function takes in the divide, phase, and duty cycle
// setting to calculate the upper and lower counter registers.
function [37:0] mmcm_pll_count_calc
(
input [7:0] divide, // Max divide is 128
input signed [31:0] phase,
input [31:0] duty_cycle // Multiplied by 100,000
);
reg [13:0] div_calc;
reg [16:0] phase_calc;
begin
`ifdef DEBUG
$display("mmcm_pll_count_calc- divide:%h, phase:%d, duty_cycle:%d",
divide, phase, duty_cycle);
`endif
// w_edge[13], no_count[12], high_time[11:6], low_time[5:0]
div_calc = mmcm_pll_divider(divide, duty_cycle);
// mx[10:9], pm[8:6], dt[5:0]
phase_calc = mmcm_pll_phase(divide, phase);
// Return value is the upper and lower address of counter
// Upper address is:
// RESERVED [31:26]
// MX [25:24]
// EDGE [23]
// NOCOUNT [22]
// DELAY_TIME [21:16]
// Lower Address is:
// PHASE_MUX [15:13]
// RESERVED [12]
// HIGH_TIME [11:6]
// LOW_TIME [5:0]
`ifdef DEBUG
$display("div:%d dc:%d phase:%d ht:%d lt:%d ed:%d nc:%d mx:%d dt:%d pm:%d",
divide, duty_cycle, phase, div_calc[11:6], div_calc[5:0],
div_calc[13], div_calc[12],
phase_calc[16:15], phase_calc[5:0], phase_calc[14:12]);
`endif
mmcm_pll_count_calc =
{
// Upper Address
6'h00, phase_calc[10:9], div_calc[13:12], phase_calc[5:0],
// Lower Address
phase_calc[8:6], 1'b0, div_calc[11:0]
};
end
endfunction
@@ -1,671 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Company: Xilinx
// Engineer: Jim Tatsukawa
// Date: 7/30/2014
// Design Name: MMCME2 DRP
// Module Name: mmcme2_drp_func.h
// Version: 1.04
// Target Devices: UltraScale Architecture || MMCM
// Tool versions: 2014.3
// Description: This header provides the functions necessary to
// calculate the DRP register values for the V6 MMCM.
//
// Revision Notes: 3/22 - Updating lookup_low/lookup_high (CR)
// 4/13 - Fractional divide function in mmcm_frac_count_calc function. CRS610807
//
// Disclaimer: XILINX IS PROVIDING THIS DESIGN, CODE, OR
// INFORMATION "AS IS" SOLELY FOR USE IN DEVELOPING
// PROGRAMS AND SOLUTIONS FOR XILINX DEVICES. BY
// PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
// ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
// APPLICATION OR STANDARD, XILINX IS MAKING NO
// REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
// FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE
// RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY
// REQUIRE FOR YOUR IMPLEMENTATION. XILINX
// EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH
// RESPECT TO THE ADEQUACY OF THE IMPLEMENTATION,
// INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
// REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE.
//
// (c) Copyright 2009-2010 Xilinx, Inc.
// All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
// These are user functions that should not be modified. Changes to the defines
// or code within the functions may alter the accuracy of the calculations.
// Define debug to provide extra messages durring elaboration
//`define DEBUG 1
// FRAC_PRECISION describes the width of the fractional portion of the fixed
// point numbers. These should not be modified, they are for development
// only
`define FRAC_PRECISION 10
// FIXED_WIDTH describes the total size for fixed point calculations(int+frac).
// Warning: L.50 and below will not calculate properly with FIXED_WIDTHs
// greater than 32
`define FIXED_WIDTH 32
// This function takes a fixed point number and rounds it to the nearest
// fractional precision bit.
function [`FIXED_WIDTH:1] round_frac
(
// Input is (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point number
input [`FIXED_WIDTH:1] decimal,
// This describes the precision of the fraction, for example a value
// of 1 would modify the fractional so that instead of being a .16
// fractional, it would be a .1 (rounded to the nearest 0.5 in turn)
input [`FIXED_WIDTH:1] precision
);
begin
`ifdef DEBUG
$display("round_frac - decimal: %h, precision: %h", decimal, precision);
`endif
// If the fractional precision bit is high then round up
if( decimal[(`FRAC_PRECISION-precision)] == 1'b1) begin
round_frac = decimal + (1'b1 << (`FRAC_PRECISION-precision));
end else begin
round_frac = decimal;
end
`ifdef DEBUG
$display("round_frac: %h", round_frac);
`endif
end
endfunction
// This function calculates high_time, low_time, w_edge, and no_count
// of a non-fractional counter based on the divide and duty cycle
//
// NOTE: high_time and low_time are returned as integers between 0 and 63
// inclusive. 64 should equal 6'b000000 (in other words it is okay to
// ignore the overflow)
function [13:0] mmcm_pll_divider
(
input [7:0] divide, // Max divide is 128
input [31:0] duty_cycle // Duty cycle is multiplied by 100,000
);
reg [`FIXED_WIDTH:1] duty_cycle_fix;
// High/Low time is initially calculated with a wider integer to prevent a
// calculation error when it overflows to 64.
reg [6:0] high_time;
reg [6:0] low_time;
reg w_edge;
reg no_count;
reg [`FIXED_WIDTH:1] temp;
begin
// Duty Cycle must be between 0 and 1,000
if(duty_cycle <=0 || duty_cycle >= 100000) begin
`ifndef SYNTHESIS
$display("ERROR: duty_cycle: %d is invalid", duty_cycle);
`endif
$finish;
end
// Convert to FIXED_WIDTH-FRAC_PRECISION.FRAC_PRECISION fixed point
duty_cycle_fix = (duty_cycle << `FRAC_PRECISION) / 100_000;
`ifdef DEBUG
$display("duty_cycle_fix: %h", duty_cycle_fix);
`endif
// If the divide is 1 nothing needs to be set except the no_count bit.
// Other values are dummies
if(divide == 7'h01) begin
high_time = 7'h01;
w_edge = 1'b0;
low_time = 7'h01;
no_count = 1'b1;
end else begin
temp = round_frac(duty_cycle_fix*divide, 1);
// comes from above round_frac
high_time = temp[`FRAC_PRECISION+7:`FRAC_PRECISION+1];
// If the duty cycle * divide rounded is .5 or greater then this bit
// is set.
w_edge = temp[`FRAC_PRECISION]; // comes from round_frac
// If the high time comes out to 0, it needs to be set to at least 1
// and w_edge set to 0
if(high_time == 7'h00) begin
high_time = 7'h01;
w_edge = 1'b0;
end
if(high_time == divide) begin
high_time = divide - 1;
w_edge = 1'b1;
end
// Calculate low_time based on the divide setting and set no_count to
// 0 as it is only used when divide is 1.
low_time = divide - high_time;
no_count = 1'b0;
end
// Set the return value.
mmcm_pll_divider = {w_edge,no_count,high_time[5:0],low_time[5:0]};
end
endfunction
// This function calculates mx, delay_time, and phase_mux
// of a non-fractional counter based on the divide and phase
//
// NOTE: The only valid value for the MX bits is 2'b00 to ensure the coarse mux
// is used.
function [10:0] mmcm_pll_phase
(
// divide must be an integer (use fractional if not)
// assumed that divide already checked to be valid
input [7:0] divide, // Max divide is 128
// Phase is given in degrees (-360,000 to 360,000)
input signed [31:0] phase
);
reg [`FIXED_WIDTH:1] phase_in_cycles;
reg [`FIXED_WIDTH:1] phase_fixed;
reg [1:0] mx;
reg [5:0] delay_time;
reg [2:0] phase_mux;
reg [`FIXED_WIDTH:1] temp;
begin
`ifdef DEBUG
$display("mmcm_pll_phase-divide:%d,phase:%d",
divide, phase);
`endif
if ((phase < -360000) || (phase > 360000)) begin
`ifndef SYNTHESIS
$display("ERROR: phase of $phase is not between -360000 and 360000");
`endif
$finish;
end
// If phase is less than 0, convert it to a positive phase shift
// Convert to (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point
if(phase < 0) begin
phase_fixed = ( (phase + 360000) << `FRAC_PRECISION ) / 1000;
end else begin
phase_fixed = ( phase << `FRAC_PRECISION ) / 1000;
end
// Put phase in terms of decimal number of vco clock cycles
phase_in_cycles = ( phase_fixed * divide ) / 360;
`ifdef DEBUG
$display("phase_in_cycles: %h", phase_in_cycles);
`endif
temp = round_frac(phase_in_cycles, 3);
// set mx to 2'b00 that the phase mux from the VCO is enabled
mx = 2'b00;
phase_mux = temp[`FRAC_PRECISION:`FRAC_PRECISION-2];
delay_time = temp[`FRAC_PRECISION+6:`FRAC_PRECISION+1];
`ifdef DEBUG
$display("temp: %h", temp);
`endif
// Setup the return value
mmcm_pll_phase={mx, phase_mux, delay_time};
end
endfunction
// This function takes the divide value and outputs the necessary lock values
function [39:0] mmcm_pll_lock_lookup
(
input [6:0] divide // Max divide is 64
);
reg [2559:0] lookup;
begin
lookup = {
// This table is composed of:
// LockRefDly_LockFBDly_LockCnt_LockSatHigh_UnlockCnt
40'b00110_00110_1111101000_1111101001_0000000001,
40'b00110_00110_1111101000_1111101001_0000000001,
40'b01000_01000_1111101000_1111101001_0000000001,
40'b01011_01011_1111101000_1111101001_0000000001,
40'b01110_01110_1111101000_1111101001_0000000001,
40'b10001_10001_1111101000_1111101001_0000000001,
40'b10011_10011_1111101000_1111101001_0000000001,
40'b10110_10110_1111101000_1111101001_0000000001,
40'b11001_11001_1111101000_1111101001_0000000001,
40'b11100_11100_1111101000_1111101001_0000000001,
40'b11111_11111_1110000100_1111101001_0000000001,
40'b11111_11111_1100111001_1111101001_0000000001,
40'b11111_11111_1011101110_1111101001_0000000001,
40'b11111_11111_1010111100_1111101001_0000000001,
40'b11111_11111_1010001010_1111101001_0000000001,
40'b11111_11111_1001110001_1111101001_0000000001,
40'b11111_11111_1000111111_1111101001_0000000001,
40'b11111_11111_1000100110_1111101001_0000000001,
40'b11111_11111_1000001101_1111101001_0000000001,
40'b11111_11111_0111110100_1111101001_0000000001,
40'b11111_11111_0111011011_1111101001_0000000001,
40'b11111_11111_0111000010_1111101001_0000000001,
40'b11111_11111_0110101001_1111101001_0000000001,
40'b11111_11111_0110010000_1111101001_0000000001,
40'b11111_11111_0110010000_1111101001_0000000001,
40'b11111_11111_0101110111_1111101001_0000000001,
40'b11111_11111_0101011110_1111101001_0000000001,
40'b11111_11111_0101011110_1111101001_0000000001,
40'b11111_11111_0101000101_1111101001_0000000001,
40'b11111_11111_0101000101_1111101001_0000000001,
40'b11111_11111_0100101100_1111101001_0000000001,
40'b11111_11111_0100101100_1111101001_0000000001,
40'b11111_11111_0100101100_1111101001_0000000001,
40'b11111_11111_0100010011_1111101001_0000000001,
40'b11111_11111_0100010011_1111101001_0000000001,
40'b11111_11111_0100010011_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001
};
// Set lookup_entry with the explicit bits from lookup with a part select
mmcm_pll_lock_lookup = lookup[ ((64-divide)*40) +: 40];
`ifdef DEBUG
$display("lock_lookup: %b", mmcm_pll_lock_lookup);
`endif
end
endfunction
// This function takes the divide value and the bandwidth setting of the MMCM
// and outputs the digital filter settings necessary.
function [9:0] mmcm_pll_filter_lookup
(
input [6:0] divide, // Max divide is 64
input [8*9:0] BANDWIDTH
);
reg [639:0] lookup_low;
reg [639:0] lookup_high;
reg [9:0] lookup_entry;
begin
lookup_low = {
// CP_RES_LFHF
10'b0010_1111_11,
10'b0010_1111_11,
10'b0010_1111_11,
10'b0010_1111_11,
10'b0010_1111_11,
10'b0010_1111_11,
10'b0010_0111_11,
10'b0010_0111_11,
10'b0010_0111_11,
10'b0010_1101_11,
10'b0010_1101_11,
10'b0010_1101_11,
10'b0010_0011_11,
10'b0010_0101_11,
10'b0010_0101_11,
10'b0010_0101_11,
10'b0010_1001_11,
10'b0010_1001_11,
10'b0010_1110_11,
10'b0010_1110_11,
10'b0010_1110_11,
10'b0010_1110_11,
10'b0010_1110_11,
10'b0010_1110_11,
10'b0010_0001_11,
10'b0010_0001_11,
10'b0010_0001_11,
10'b0010_0001_11,
10'b0010_0001_11,
10'b0010_0110_11,
10'b0010_0110_11,
10'b0010_0110_11,
10'b0010_0110_11,
10'b0010_0110_11,
10'b0010_0110_11,
10'b0010_0110_11,
10'b0010_0110_11,
10'b0010_0110_11,
10'b0010_0110_11,
10'b0010_1010_11,
10'b0010_1010_11,
10'b0010_1010_11,
10'b0010_1010_11,
10'b0010_1010_11,
10'b0010_1010_11,
10'b0010_1010_11,
10'b0010_1010_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11,
10'b0010_1100_11
};
lookup_high = {
// CP_RES_LFHF
10'b0010_1111_11,
10'b0010_1111_11,
10'b0010_1011_11,
10'b0011_1111_11,
10'b0100_1111_11,
10'b0100_1111_11,
10'b0101_1111_11,
10'b0110_1111_11,
10'b0111_1111_11,
10'b0111_1111_11,
10'b1100_1111_11,
10'b1101_1111_11,
10'b1110_1111_11,
10'b1111_1111_11,
10'b1111_1111_11,
10'b1110_0111_11,
10'b1110_1011_11,
10'b1111_0111_11,
10'b1111_1011_11,
10'b1111_1011_11,
10'b1110_1101_11,
10'b1111_1101_11,
10'b1111_1101_11,
10'b1111_0011_11,
10'b1111_0011_11,
10'b1111_0011_11,
10'b1110_0101_11,
10'b1110_0101_11,
10'b1110_0101_11,
10'b1111_0101_11,
10'b1111_0101_11,
10'b1111_0101_11,
10'b1111_1001_11,
10'b1111_1001_11,
10'b1111_1001_11,
10'b1111_1001_11,
10'b1111_1001_11,
10'b1110_1110_11,
10'b1110_1110_11,
10'b1110_1110_11,
10'b1110_1110_11,
10'b1111_1110_11,
10'b1111_1110_11,
10'b1111_1110_11,
10'b1111_1110_11,
10'b1111_1110_11,
10'b1111_1110_11,
10'b1111_1110_11,
10'b1110_0001_11,
10'b1110_0001_11,
10'b1110_0001_11,
10'b1110_0001_11,
10'b1110_0001_11,
10'b1100_0110_11,
10'b1100_0110_11,
10'b1100_0110_11,
10'b1100_0110_11,
10'b1100_0110_11,
10'b1100_0110_11,
10'b1100_0110_11,
10'b1100_1010_11,
10'b1100_1010_11,
10'b1100_1010_11,
10'b1100_1010_11
};
// Set lookup_entry with the explicit bits from lookup with a part select
if(BANDWIDTH == "LOW") begin
// Low Bandwidth
mmcm_pll_filter_lookup = lookup_low[ ((64-divide)*10) +: 10];
end else begin
// High or optimized bandwidth
mmcm_pll_filter_lookup = lookup_high[ ((64-divide)*10) +: 10];
end
`ifdef DEBUG
$display("filter_lookup: %b", mmcm_pll_filter_lookup);
`endif
end
endfunction
// This function takes in the divide, phase, and duty cycle
// setting to calculate the upper and lower counter registers.
function [37:0] mmcm_pll_count_calc
(
input [7:0] divide, // Max divide is 128
input signed [31:0] phase,
input [31:0] duty_cycle // Multiplied by 100,000
);
reg [13:0] div_calc;
reg [16:0] phase_calc;
begin
`ifdef DEBUG
$display("mmcm_pll_count_calc- divide:%h, phase:%d, duty_cycle:%d",
divide, phase, duty_cycle);
`endif
// w_edge[13], no_count[12], high_time[11:6], low_time[5:0]
div_calc = mmcm_pll_divider(divide, duty_cycle);
// mx[10:9], pm[8:6], dt[5:0]
phase_calc = mmcm_pll_phase(divide, phase);
// Return value is the upper and lower address of counter
// Upper address is:
// RESERVED [31:26]
// MX [25:24]
// EDGE [23]
// NOCOUNT [22]
// DELAY_TIME [21:16]
// Lower Address is:
// PHASE_MUX [15:13]
// RESERVED [12]
// HIGH_TIME [11:6]
// LOW_TIME [5:0]
`ifdef DEBUG
$display("div:%d dc:%d phase:%d ht:%d lt:%d ed:%d nc:%d mx:%d dt:%d pm:%d",
divide, duty_cycle, phase, div_calc[11:6], div_calc[5:0],
div_calc[13], div_calc[12],
phase_calc[16:15], phase_calc[5:0], phase_calc[14:12]);
`endif
mmcm_pll_count_calc =
{
// Upper Address
6'h00, phase_calc[10:9], div_calc[13:12], phase_calc[5:0],
// Lower Address
phase_calc[8:6], 1'b0, div_calc[11:0]
};
end
endfunction
// This function takes in the divide, phase, and duty cycle
// setting to calculate the upper and lower counter registers.
// for fractional multiply/divide functions.
//
//
function [37:0] mmcm_frac_count_calc
(
input [7:0] divide, // Max divide is 128
input signed [31:0] phase,
input [31:0] duty_cycle, // Multiplied by 1,000
input [9:0] frac // Multiplied by 1000
);
//Required for fractional divide calculations
reg [7:0] lt_frac;
reg [7:0] ht_frac;
reg /*[7:0]*/ wf_fall_frac;
reg /*[7:0]*/ wf_rise_frac;
reg [31:0] a;
reg [7:0] pm_rise_frac_filtered ;
reg [7:0] pm_fall_frac_filtered ;
reg [7:0] clkout0_divide_int;
reg [2:0] clkout0_divide_frac;
reg [7:0] even_part_high;
reg [7:0] even_part_low;
reg [7:0] odd;
reg [7:0] odd_and_frac;
reg [7:0] pm_fall;
reg [7:0] pm_rise;
reg [7:0] dt;
reg [7:0] dt_int;
reg [63:0] dt_calc;
reg [7:0] pm_rise_frac;
reg [7:0] pm_fall_frac;
reg [31:0] a_per_in_octets;
reg [31:0] a_phase_in_cycles;
parameter precision = 0.125;
reg [31:0] phase_fixed; // changed to 31:0 from 32:1 jt 5/2/11
reg [31: 0] phase_pos;
reg [31: 0] phase_vco;
reg [31:0] temp;// changed to 31:0 from 32:1 jt 5/2/11
reg [13:0] div_calc;
reg [16:0] phase_calc;
begin
`ifdef DEBUG
$display("mmcm_frac_count_calc- divide:%h, phase:%d, duty_cycle:%d",
divide, phase, duty_cycle);
`endif
//convert phase to fixed
if ((phase < -360000) || (phase > 360000)) begin
`ifndef SYNTHESIS
$display("ERROR: phase of $phase is not between -360000 and 360000");
`endif
$finish;
end
// Return value is
// Transfer data
// RESERVED [37:36]
// FRAC_TIME [35:33]
// FRAC_WF_FALL [32]
// Upper address is:
// RESERVED [31:26]
// MX [25:24]
// EDGE [23]
// NOCOUNT [22]
// DELAY_TIME [21:16]
// Lower Address is:
// PHASE_MUX [15:13]
// RESERVED [12]
// HIGH_TIME [11:6]
// LOW_TIME [5:0]
clkout0_divide_frac = frac / 125;
clkout0_divide_int = divide;
even_part_high = clkout0_divide_int >> 1;//$rtoi(clkout0_divide_int / 2);
even_part_low = even_part_high;
odd = clkout0_divide_int - even_part_high - even_part_low;
odd_and_frac = (8*odd) + clkout0_divide_frac;
lt_frac = even_part_high - (odd_and_frac <= 9);//IF(odd_and_frac>9,even_part_high, even_part_high - 1)
ht_frac = even_part_low - (odd_and_frac <= 8);//IF(odd_and_frac>8,even_part_low, even_part_low- 1)
pm_fall = {odd[6:0],2'b00} + {6'h00, clkout0_divide_frac[2:1]}; // using >> instead of clkout0_divide_frac / 2
pm_rise = 0; //0
wf_fall_frac = ((odd_and_frac >=2) && (odd_and_frac <=9)) || ((clkout0_divide_frac == 1) && (clkout0_divide_int == 2));//CRS610807
wf_rise_frac = (odd_and_frac >=1) && (odd_and_frac <=8);//IF(odd_and_frac>=1,IF(odd_and_frac <= 8,1,0),0)
//Calculate phase in fractional cycles
a_per_in_octets = (8 * divide) + (frac / 125) ;
a_phase_in_cycles = (phase+10) * a_per_in_octets / 360000 ;//Adding 1 due to rounding errors
pm_rise_frac = (a_phase_in_cycles[7:0] ==8'h00)?8'h00:a_phase_in_cycles[7:0] - {a_phase_in_cycles[7:3],3'b000};
dt_calc = ((phase+10) * a_per_in_octets / 8 )/360000 ;//TRUNC(phase* divide / 360); //or_simply (a_per_in_octets / 8)
dt = dt_calc[7:0];
pm_rise_frac_filtered = (pm_rise_frac >=8) ? (pm_rise_frac ) - 8: pm_rise_frac ; //((phase_fixed * (divide + frac / 1000)) / 360) - {pm_rise_frac[7:3],3'b000};//$rtoi(clkout0_phase * clkout0_divide / 45);//a;
dt_int = dt + (& pm_rise_frac[7:4]); //IF(pm_rise_overwriting>7,dt+1,dt)
pm_fall_frac = pm_fall + pm_rise_frac;
pm_fall_frac_filtered = pm_fall + pm_rise_frac - {pm_fall_frac[7:3], 3'b000};
div_calc = mmcm_pll_divider(divide, duty_cycle); //Use to determine edge[7], no count[6]
phase_calc = mmcm_pll_phase(divide, phase);// returns{mx[1:0], phase_mux[2:0], delay_time[5:0]}
mmcm_frac_count_calc[37:0] =
{ 2'b00, pm_fall_frac_filtered[2:0], wf_fall_frac,
1'b0, clkout0_divide_frac[2:0], 1'b1, wf_rise_frac, phase_calc[10:9], div_calc[13:12], dt[5:0],
pm_rise_frac_filtered[2], pm_rise_frac_filtered[1], pm_rise_frac_filtered[0], 1'b0, ht_frac[5:0], lt_frac[5:0]
} ;
`ifdef DEBUG
$display("-%d.%d p%d>> :DADDR_9_15 frac30to28.frac_en.wf_r_frac.dt:%b%d%d_%b:DADDR_7_13 pm_f_frac_filtered_29to27.wf_f_frac_26:%b%d:DADDR_8_14.pm_r_frac_filt_15to13.ht_frac.lt_frac:%b%b%b:", divide, frac, phase, clkout0_divide_frac, 1, wf_rise_frac, dt, pm_fall_frac_filtered, wf_fall_frac, pm_rise_frac_filtered, ht_frac, lt_frac);
`endif
end
endfunction
@@ -1,530 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Company: Xilinx
// Engineer: Jim Tatsukawa
// Date: 6/15/2015
// Design Name: PLLE3 DRP
// Module Name: plle3_drp_func.h
// Version: 1.10
// Target Devices: UltraScale Architecture
// Tool versions: 2015.1
// Description: This header provides the functions necessary to
// calculate the DRP register values for the V6 PLL.
//
// Revision Notes: 8/11 - PLLE3 updated for PLLE3 file 4564419
// Revision Notes: 6/15 - pll_filter_lookup fixed for max M of 19
// PM_Rise bits have been removed for PLLE3
//
// Disclaimer: XILINX IS PROVIDING THIS DESIGN, CODE, OR
// INFORMATION "AS IS" SOLELY FOR USE IN DEVELOPING
// PROGRAMS AND SOLUTIONS FOR XILINX DEVICES. BY
// PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
// ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
// APPLICATION OR STANDARD, XILINX IS MAKING NO
// REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
// FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE
// RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY
// REQUIRE FOR YOUR IMPLEMENTATION. XILINX
// EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH
// RESPECT TO THE ADEQUACY OF THE IMPLEMENTATION,
// INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
// REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE.
//
// (c) Copyright 2009-2010 Xilinx, Inc.
// All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
// These are user functions that should not be modified. Changes to the defines
// or code within the functions may alter the accuracy of the calculations.
// Define debug to provide extra messages durring elaboration
//`define DEBUG 1
// FRAC_PRECISION describes the width of the fractional portion of the fixed
// point numbers. These should not be modified, they are for development
// only
`define FRAC_PRECISION 10
// FIXED_WIDTH describes the total size for fixed point calculations(int+frac).
// Warning: L.50 and below will not calculate properly with FIXED_WIDTHs
// greater than 32
`define FIXED_WIDTH 32
// This function takes a fixed point number and rounds it to the nearest
// fractional precision bit.
function [`FIXED_WIDTH:1] round_frac
(
// Input is (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point number
input [`FIXED_WIDTH:1] decimal,
// This describes the precision of the fraction, for example a value
// of 1 would modify the fractional so that instead of being a .16
// fractional, it would be a .1 (rounded to the nearest 0.5 in turn)
input [`FIXED_WIDTH:1] precision
);
begin
`ifdef DEBUG
$display("round_frac - decimal: %h, precision: %h", decimal, precision);
`endif
// If the fractional precision bit is high then round up
if( decimal[(`FRAC_PRECISION-precision)] == 1'b1) begin
round_frac = decimal + (1'b1 << (`FRAC_PRECISION-precision));
end else begin
round_frac = decimal;
end
`ifdef DEBUG
$display("round_frac: %h", round_frac);
`endif
end
endfunction
// This function calculates high_time, low_time, w_edge, and no_count
// of a non-fractional counter based on the divide and duty cycle
//
// NOTE: high_time and low_time are returned as integers between 0 and 63
// inclusive. 64 should equal 6'b000000 (in other words it is okay to
// ignore the overflow)
function [13:0] mmcm_pll_divider
(
input [7:0] divide, // Max divide is 128
input [31:0] duty_cycle // Duty cycle is multiplied by 100,000
);
reg [`FIXED_WIDTH:1] duty_cycle_fix;
// High/Low time is initially calculated with a wider integer to prevent a
// calculation error when it overflows to 64.
reg [6:0] high_time;
reg [6:0] low_time;
reg w_edge;
reg no_count;
reg [`FIXED_WIDTH:1] temp;
begin
// Duty Cycle must be between 0 and 1,000
if(duty_cycle <=0 || duty_cycle >= 100000) begin
`ifndef SYNTHESIS
$display("ERROR: duty_cycle: %d is invalid", duty_cycle);
`endif
$finish;
end
// Convert to FIXED_WIDTH-FRAC_PRECISION.FRAC_PRECISION fixed point
duty_cycle_fix = (duty_cycle << `FRAC_PRECISION) / 100_000;
`ifdef DEBUG
$display("duty_cycle_fix: %h", duty_cycle_fix);
`endif
// If the divide is 1 nothing needs to be set except the no_count bit.
// Other values are dummies
if(divide == 7'h01) begin
high_time = 7'h01;
w_edge = 1'b0;
low_time = 7'h01;
no_count = 1'b1;
end else begin
temp = round_frac(duty_cycle_fix*divide, 1);
// comes from above round_frac
high_time = temp[`FRAC_PRECISION+7:`FRAC_PRECISION+1];
// If the duty cycle * divide rounded is .5 or greater then this bit
// is set.
w_edge = temp[`FRAC_PRECISION]; // comes from round_frac
// If the high time comes out to 0, it needs to be set to at least 1
// and w_edge set to 0
if(high_time == 7'h00) begin
high_time = 7'h01;
w_edge = 1'b0;
end
if(high_time == divide) begin
high_time = divide - 1;
w_edge = 1'b1;
end
// Calculate low_time based on the divide setting and set no_count to
// 0 as it is only used when divide is 1.
low_time = divide - high_time;
no_count = 1'b0;
end
// Set the return value.
mmcm_pll_divider = {w_edge,no_count,high_time[5:0],low_time[5:0]};
end
endfunction
// This function calculates mx, delay_time, and phase_mux
// of a non-fractional counter based on the divide and phase
//
// NOTE: The only valid value for the MX bits is 2'b00 to ensure the coarse mux
// is used.
function [10:0] mmcm_pll_phase
(
// divide must be an integer (use fractional if not)
// assumed that divide already checked to be valid
input [7:0] divide, // Max divide is 128
// Phase is given in degrees (-360,000 to 360,000)
input signed [31:0] phase
);
reg [`FIXED_WIDTH:1] phase_in_cycles;
reg [`FIXED_WIDTH:1] phase_fixed;
reg [1:0] mx;
reg [5:0] delay_time;
reg [2:0] phase_mux;
reg [`FIXED_WIDTH:1] temp;
begin
`ifdef DEBUG
$display("mmcm_pll_phase-divide:%d,phase:%d",
divide, phase);
`endif
if ((phase < -360000) || (phase > 360000)) begin
`ifndef SYNTHESIS
$display("ERROR: phase of $phase is not between -360000 and 360000");
`endif
$finish;
end
// If phase is less than 0, convert it to a positive phase shift
// Convert to (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point
if(phase < 0) begin
phase_fixed = ( (phase + 360000) << `FRAC_PRECISION ) / 1000;
end else begin
phase_fixed = ( phase << `FRAC_PRECISION ) / 1000;
end
// Put phase in terms of decimal number of vco clock cycles
phase_in_cycles = ( phase_fixed * divide ) / 360;
`ifdef DEBUG
$display("phase_in_cycles: %h", phase_in_cycles);
`endif
temp = round_frac(phase_in_cycles, 3);
// set mx to 2'b00 that the phase mux from the VCO is enabled
mx = 2'b00;
phase_mux = temp[`FRAC_PRECISION:`FRAC_PRECISION-2];
delay_time = temp[`FRAC_PRECISION+6:`FRAC_PRECISION+1];
`ifdef DEBUG
$display("temp: %h", temp);
`endif
// Setup the return value
mmcm_pll_phase={mx, phase_mux, delay_time};
end
endfunction
// This function takes the divide value and outputs the necessary lock values
function [39:0] mmcm_pll_lock_lookup
(
input [6:0] divide // Max divide is 64
);
reg [759:0] lookup;
begin
lookup = {
// This table is composed of:
// LockRefDly_LockFBDly_LockCnt_LockSatHigh_UnlockCnt
40'b00110_00110_1111101000_1111101001_0000000001, //1
40'b00110_00110_1111101000_1111101001_0000000001, //2
40'b01000_01000_1111101000_1111101001_0000000001, //3
40'b01011_01011_1111101000_1111101001_0000000001, //4
40'b01110_01110_1111101000_1111101001_0000000001, //5
40'b10001_10001_1111101000_1111101001_0000000001, //6
40'b10011_10011_1111101000_1111101001_0000000001, //7
40'b10110_10110_1111101000_1111101001_0000000001, //8
40'b11001_11001_1111101000_1111101001_0000000001, //9
40'b11100_11100_1111101000_1111101001_0000000001, //10
40'b11111_11111_1110000100_1111101001_0000000001, //11
40'b11111_11111_1100111001_1111101001_0000000001, //12
40'b11111_11111_1011101110_1111101001_0000000001, //13
40'b11111_11111_1010111100_1111101001_0000000001, //14
40'b11111_11111_1010001010_1111101001_0000000001, //15
40'b11111_11111_1001110001_1111101001_0000000001, //16
40'b11111_11111_1000111111_1111101001_0000000001, //17
40'b11111_11111_1000100110_1111101001_0000000001, //18
40'b11111_11111_1000001101_1111101001_0000000001 //19
};
// Set lookup_entry with the explicit bits from lookup with a part select
mmcm_pll_lock_lookup = lookup[ ((19-divide)*40) +: 40];
`ifdef DEBUG
$display("lock_lookup: %b", mmcm_pll_lock_lookup);
`endif
end
endfunction
// This function takes the divide value and the bandwidth setting of the PLL
// and outputs the digital filter settings necessary. Removing bandwidth setting for PLLE3.
function [9:0] mmcm_pll_filter_lookup
(
input [6:0] divide // Max divide is 19
);
reg [639:0] lookup;
reg [9:0] lookup_entry;
begin
lookup = {
// CP_RES_LFHF
10'b0010_1111_01, //1
10'b0010_0011_11, //2
10'b0011_0011_11, //3
10'b0010_0001_11, //4
10'b0010_0110_11, //5
10'b0010_1010_11, //6
10'b0010_1010_11, //7
10'b0011_0110_11, //8
10'b0010_1100_11, //9
10'b0010_1100_11, //10
10'b0010_1100_11, //11
10'b0010_0010_11, //12
10'b0011_1100_11, //13
10'b0011_1100_11, //14
10'b0011_1100_11, //15
10'b0011_1100_11, //16
10'b0011_0010_11, //17
10'b0011_0010_11, //18
10'b0011_0010_11 //19
};
mmcm_pll_filter_lookup = lookup [ ((19-divide)*10) +: 10];
`ifdef DEBUG
$display("filter_lookup: %b", mmcm_pll_filter_lookup);
`endif
end
endfunction
// This function set the CLKOUTPHY divide settings to match
// the desired CLKOUTPHY_MODE setting. To create VCO_X2, then
// the CLKOUTPHY will be set to 2'b00 since the VCO is internally
// doubled and 2'b00 will represent divide by 1. Similarly "VCO" // will need to divide the doubled clock VCO clock frequency by // 2 therefore 2'b01 will match a divide by 2.And VCO_HALF will // need to divide the doubled VCO by 4, therefore 2'b10
function [9:0] mmcm_pll_clkoutphy_calc
(
input [8*9:0] CLKOUTPHY_MODE
);
if(CLKOUTPHY_MODE == "VCO_X2") begin
mmcm_pll_clkoutphy_calc= 2'b00;
end else if(CLKOUTPHY_MODE == "VCO") begin
mmcm_pll_clkoutphy_calc= 2'b01;
end else if(CLKOUTPHY_MODE == "CLKIN") begin
mmcm_pll_clkoutphy_calc= 2'b11;
end else begin // Assume "VCO_HALF"
mmcm_pll_clkoutphy_calc= 2'b10;
end
endfunction
// This function takes in the divide, phase, and duty cycle
// setting to calculate the upper and lower counter registers.
function [37:0] mmcm_pll_count_calc
(
input [7:0] divide, // Max divide is 128
input signed [31:0] phase,
input [31:0] duty_cycle // Multiplied by 100,000
);
reg [13:0] div_calc;
reg [16:0] phase_calc;
begin
`ifdef DEBUG
$display("mmcm_pll_count_calc- divide:%h, phase:%d, duty_cycle:%d",
divide, phase, duty_cycle);
`endif
// w_edge[13], no_count[12], high_time[11:6], low_time[5:0]
div_calc = mmcm_pll_divider(divide, duty_cycle);
// mx[10:9], pm[8:6], dt[5:0]
phase_calc = mmcm_pll_phase(divide, phase);
// Return value is the upper and lower address of counter
// Upper address is:
// RESERVED [31:26]
// MX [25:24]
// EDGE [23]
// NOCOUNT [22]
// DELAY_TIME [21:16]
// Lower Address is:
// PHASE_MUX [15:13]
// RESERVED [12]
// HIGH_TIME [11:6]
// LOW_TIME [5:0]
`ifdef DEBUG
$display("div:%d dc:%d phase:%d ht:%d lt:%d ed:%d nc:%d mx:%d dt:%d pm:%d",
divide, duty_cycle, phase, div_calc[11:6], div_calc[5:0],
div_calc[13], div_calc[12],
phase_calc[16:15], phase_calc[5:0], 3'b000);//Removed PM_Rise bits
`endif
mmcm_pll_count_calc =
{
// Upper Address
6'h00, phase_calc[10:9], div_calc[13:12], phase_calc[5:0],
// Lower Address
phase_calc[8:6], 1'b0, div_calc[11:0]
};
end
endfunction
// This function takes in the divide, phase, and duty cycle
// setting to calculate the upper and lower counter registers.
// for fractional multiply/divide functions.
//
//
function [37:0] mmcm_pll_frac_count_calc
(
input [7:0] divide, // Max divide is 128
input signed [31:0] phase,
input [31:0] duty_cycle, // Multiplied by 1,000
input [9:0] frac // Multiplied by 1000
);
//Required for fractional divide calculations
reg [7:0] lt_frac;
reg [7:0] ht_frac;
reg /*[7:0]*/ wf_fall_frac;
reg /*[7:0]*/ wf_rise_frac;
reg [31:0] a;
reg [7:0] pm_rise_frac_filtered ;
reg [7:0] pm_fall_frac_filtered ;
reg [7:0] clkout0_divide_int;
reg [2:0] clkout0_divide_frac;
reg [7:0] even_part_high;
reg [7:0] even_part_low;
reg [7:0] odd;
reg [7:0] odd_and_frac;
reg [7:0] pm_fall;
reg [7:0] pm_rise;
reg [7:0] dt;
reg [7:0] dt_int;
reg [63:0] dt_calc;
reg [7:0] pm_rise_frac;
reg [7:0] pm_fall_frac;
reg [31:0] a_per_in_octets;
reg [31:0] a_phase_in_cycles;
parameter precision = 0.125;
reg [31:0] phase_fixed; // changed to 31:0 from 32:1 jt 5/2/11
reg [31: 0] phase_pos;
reg [31: 0] phase_vco;
reg [31:0] temp;// changed to 31:0 from 32:1 jt 5/2/11
reg [13:0] div_calc;
reg [16:0] phase_calc;
begin
`ifdef DEBUG
$display("mmcm_pll_frac_count_calc- divide:%h, phase:%d, duty_cycle:%d",
divide, phase, duty_cycle);
`endif
//convert phase to fixed
if ((phase < -360000) || (phase > 360000)) begin
`ifndef SYNTHESIS
$display("ERROR: phase of $phase is not between -360000 and 360000");
`endif
$finish;
end
// Return value is
// Transfer data
// RESERVED [37:36]
// FRAC_TIME [35:33]
// FRAC_WF_FALL [32]
// Upper address is:
// RESERVED [31:26]
// MX [25:24]
// EDGE [23]
// NOCOUNT [22]
// DELAY_TIME [21:16]
// Lower Address is:
// PHASE_MUX [15:13]
// RESERVED [12]
// HIGH_TIME [11:6]
// LOW_TIME [5:0]
clkout0_divide_frac = frac / 125;
clkout0_divide_int = divide;
even_part_high = clkout0_divide_int >> 1;//$rtoi(clkout0_divide_int / 2);
even_part_low = even_part_high;
odd = clkout0_divide_int - even_part_high - even_part_low;
odd_and_frac = (8*odd) + clkout0_divide_frac;
lt_frac = even_part_high - (odd_and_frac <= 9);//IF(odd_and_frac>9,even_part_high, even_part_high - 1)
ht_frac = even_part_low - (odd_and_frac <= 8);//IF(odd_and_frac>8,even_part_low, even_part_low- 1)
pm_fall = {odd[6:0],2'b00} + {6'h00, clkout0_divide_frac[2:1]}; // using >> instead of clkout0_divide_frac / 2
pm_rise = 0; //0
wf_fall_frac = (odd_and_frac >=2) && (odd_and_frac <=9);//IF(odd_and_frac>=2,IF(odd_and_frac <= 9,1,0),0)
wf_rise_frac = (odd_and_frac >=1) && (odd_and_frac <=8);//IF(odd_and_frac>=1,IF(odd_and_frac <= 8,1,0),0)
//Calculate phase in fractional cycles
a_per_in_octets = (8 * divide) + (frac / 125) ;
a_phase_in_cycles = (phase+10) * a_per_in_octets / 360000 ;//Adding 1 due to rounding errors
pm_rise_frac = (a_phase_in_cycles[7:0] ==8'h00)?8'h00:a_phase_in_cycles[7:0] - {a_phase_in_cycles[7:3],3'b000};
dt_calc = ((phase+10) * a_per_in_octets / 8 )/360000 ;//TRUNC(phase* divide / 360); //or_simply (a_per_in_octets / 8)
dt = dt_calc[7:0];
pm_rise_frac_filtered = (pm_rise_frac >=8) ? (pm_rise_frac ) - 8: pm_rise_frac ; //((phase_fixed * (divide + frac / 1000)) / 360) - {pm_rise_frac[7:3],3'b000};//$rtoi(clkout0_phase * clkout0_divide / 45);//a;
dt_int = dt + (& pm_rise_frac[7:4]); //IF(pm_rise_overwriting>7,dt+1,dt)
pm_fall_frac = pm_fall + pm_rise_frac;
pm_fall_frac_filtered = pm_fall + pm_rise_frac - {pm_fall_frac[7:3], 3'b000};
div_calc = mmcm_pll_divider(divide, duty_cycle); //Use to determine edge[7], no count[6]
phase_calc = mmcm_pll_phase(divide, phase);// returns{mx[1:0], phase_mux[2:0], delay_time[5:0]}
mmcm_pll_frac_count_calc[37:0] =
{ 2'b00, pm_fall_frac_filtered[2:0], wf_fall_frac,
1'b0, clkout0_divide_frac[2:0], 1'b1, wf_rise_frac, phase_calc[10:9], div_calc[13:12], dt[5:0],
3'b000, 1'b0, ht_frac[5:0], lt_frac[5:0] //Removed PM_Rise bits
// pm_rise_frac_filtered[2], pm_rise_frac_filtered[1], pm_rise_frac_filtered[0], 1'b0, ht_frac[5:0], lt_frac[5:0]
} ;
`ifdef DEBUG
$display("-%d.%d p%d>> :DADDR_9_15 frac30to28.frac_en.wf_r_frac.dt:%b%d%d_%b:DADDR_7_13 pm_f_frac_filtered_29to27.wf_f_frac_26:%b%d:DADDR_8_14.pm_r_frac_filt_15to13.ht_frac.lt_frac:%b%b%b:", divide, frac, phase, clkout0_divide_frac, 1, wf_rise_frac, dt, pm_fall_frac_filtered, wf_fall_frac, 3'b000, ht_frac, lt_frac);
`endif
end
endfunction
@@ -1,861 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Company: Xilinx
// Engineer: Jim Tatsukawa. Updated by Ralf Krueger
// Date: 7/30/2014
// Design Name: MMCME4 DRP
// Module Name: mmcme4_drp_func.h
// Version: 1.31
// Target Devices: UltraScale Plus Architecture
// Tool versions: 2017.1
// Description: This header provides the functions necessary to
// calculate the DRP register values for UltraScal+ MMCM.
//
// Revision Notes: 3/22 - Updating lookup_low/lookup_high (CR)
// 4/13 - Fractional divide function in mmcm_frac_count_calc function
// 2/28/17 - Updated for Ultrascale Plus
//
// Disclaimer: XILINX IS PROVIDING THIS DESIGN, CODE, OR
// INFORMATION "AS IS" SOLELY FOR USE IN DEVELOPING
// PROGRAMS AND SOLUTIONS FOR XILINX DEVICES. BY
// PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
// ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
// APPLICATION OR STANDARD, XILINX IS MAKING NO
// REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
// FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE
// RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY
// REQUIRE FOR YOUR IMPLEMENTATION. XILINX
// EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH
// RESPECT TO THE ADEQUACY OF THE IMPLEMENTATION,
// INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
// REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE.
//
// (c) Copyright 2009-2017 Xilinx, Inc.
// All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
// These are user functions that should not be modified. Changes to the defines
// or code within the functions may alter the accuracy of the calculations.
// Define debug to provide extra messages during elaboration
//`define DEBUG 1
// FRAC_PRECISION describes the width of the fractional portion of the fixed
// point numbers. These should not be modified, they are for development only
`define FRAC_PRECISION 10
// FIXED_WIDTH describes the total size for fixed point calculations(int+frac).
// Warning: L.50 and below will not calculate properly with FIXED_WIDTHs
// greater than 32
`define FIXED_WIDTH 32
// This function takes a fixed point number and rounds it to the nearest
// fractional precision bit.
function [`FIXED_WIDTH:1] round_frac
(
// Input is (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point number
input [`FIXED_WIDTH:1] decimal,
// This describes the precision of the fraction, for example a value
// of 1 would modify the fractional so that instead of being a .16
// fractional, it would be a .1 (rounded to the nearest 0.5 in turn)
input [`FIXED_WIDTH:1] precision
);
begin
`ifdef DEBUG
$display("round_frac - decimal: %h, precision: %h", decimal, precision);
`endif
// If the fractional precision bit is high then round up
if( decimal[(`FRAC_PRECISION-precision)] == 1'b1) begin
round_frac = decimal + (1'b1 << (`FRAC_PRECISION-precision));
end else begin
round_frac = decimal;
end
`ifdef DEBUG
$display("round_frac: %h", round_frac);
`endif
end
endfunction
// This function calculates high_time, low_time, w_edge, and no_count
// of a non-fractional counter based on the divide and duty cycle
//
// NOTE: high_time and low_time are returned as integers between 0 and 63
// inclusive. 64 should equal 6'b000000 (in other words it is okay to
// ignore the overflow)
function [13:0] mmcm_pll_divider
(
input [7:0] divide, // Max divide is 128
input [31:0] duty_cycle // Duty cycle is multiplied by 100,000
);
reg [`FIXED_WIDTH:1] duty_cycle_fix;
// High/Low time is initially calculated with a wider integer to prevent a
// calculation error when it overflows to 64.
reg [6:0] high_time;
reg [6:0] low_time;
reg w_edge;
reg no_count;
reg [`FIXED_WIDTH:1] temp;
begin
// Duty Cycle must be between 0 and 1,000
if(duty_cycle <=0 || duty_cycle >= 100000) begin
`ifndef SYNTHESIS
$display("ERROR: duty_cycle: %d is invalid", duty_cycle);
`endif
$finish;
end
// Convert to FIXED_WIDTH-FRAC_PRECISION.FRAC_PRECISION fixed point
duty_cycle_fix = (duty_cycle << `FRAC_PRECISION) / 100_000;
`ifdef DEBUG
$display("duty_cycle_fix: %h", duty_cycle_fix);
`endif
// If the divide is 1 nothing needs to be set except the no_count bit.
// Other values are dummies
if(divide == 7'h01) begin
high_time = 7'h01;
w_edge = 1'b0;
low_time = 7'h01;
no_count = 1'b1;
end else begin
temp = round_frac(duty_cycle_fix*divide, 1);
// comes from above round_frac
high_time = temp[`FRAC_PRECISION+7:`FRAC_PRECISION+1];
// If the duty cycle * divide rounded is .5 or greater then this bit
// is set.
w_edge = temp[`FRAC_PRECISION]; // comes from round_frac
// If the high time comes out to 0, it needs to be set to at least 1
// and w_edge set to 0
if(high_time == 7'h00) begin
high_time = 7'h01;
w_edge = 1'b0;
end
if(high_time == divide) begin
high_time = divide - 1;
w_edge = 1'b1;
end
// Calculate low_time based on the divide setting and set no_count to
// 0 as it is only used when divide is 1.
low_time = divide - high_time;
no_count = 1'b0;
end
// Set the return value.
mmcm_pll_divider = {w_edge,no_count,high_time[5:0],low_time[5:0]};
end
endfunction
// This function calculates mx, delay_time, and phase_mux
// of a non-fractional counter based on the divide and phase
//
// NOTE: The only valid value for the MX bits is 2'b00 to ensure the coarse mux
// is used.
function [10:0] mmcm_pll_phase
(
// divide must be an integer (use fractional if not)
// assumed that divide already checked to be valid
input [7:0] divide, // Max divide is 128
// Phase is given in degrees (-360,000 to 360,000)
input signed [31:0] phase
);
reg [`FIXED_WIDTH:1] phase_in_cycles;
reg [`FIXED_WIDTH:1] phase_fixed;
reg [1:0] mx;
reg [5:0] delay_time;
reg [2:0] phase_mux;
reg [`FIXED_WIDTH:1] temp;
begin
`ifdef DEBUG
$display("mmcm_phase-divide:%d,phase:%d", divide, phase);
`endif
if ((phase < -360000) || (phase > 360000)) begin
`ifndef SYNTHESIS
$display("ERROR: phase of $phase is not between -360000 and 360000");
`endif
$finish;
end
// If phase is less than 0, convert it to a positive phase shift
// Convert to (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point
if(phase < 0) begin
phase_fixed = ( (phase + 360000) << `FRAC_PRECISION ) / 1000;
end else begin
phase_fixed = ( phase << `FRAC_PRECISION ) / 1000;
end
// Put phase in terms of decimal number of vco clock cycles
phase_in_cycles = ( phase_fixed * divide ) / 360;
`ifdef DEBUG
$display("phase_in_cycles: %h", phase_in_cycles);
`endif
temp = round_frac(phase_in_cycles, 3);
// set mx to 2'b00 that the phase mux from the VCO is enabled
mx = 2'b00;
phase_mux = temp[`FRAC_PRECISION:`FRAC_PRECISION-2];
delay_time = temp[`FRAC_PRECISION+6:`FRAC_PRECISION+1];
`ifdef DEBUG
$display("temp: %h", temp);
`endif
// Setup the return value
mmcm_pll_phase={mx, phase_mux, delay_time};
end
endfunction
// This function takes the divide value and outputs the necessary lock values
function [39:0] mmcm_pll_lock_lookup
(
input [7:0] divide // Max M divide is 128 in UltrascalePlus
);
reg [5119:0] lookup;
begin
lookup = {
// This table is composed of:
// LockRefDly_LockFBDly_LockCnt_LockSatHigh_UnlockCnt
40'b00110_00110_1111101000_1111101001_0000000001, // M=1 (not allowed)
40'b00110_00110_1111101000_1111101001_0000000001, // M=2
40'b01000_01000_1111101000_1111101001_0000000001, // M=3
40'b01011_01011_1111101000_1111101001_0000000001, // M=4
40'b01110_01110_1111101000_1111101001_0000000001, // M=5
40'b10001_10001_1111101000_1111101001_0000000001, // M=6
40'b10011_10011_1111101000_1111101001_0000000001, // M=7
40'b10110_10110_1111101000_1111101001_0000000001,
40'b11001_11001_1111101000_1111101001_0000000001,
40'b11100_11100_1111101000_1111101001_0000000001,
40'b11111_11111_1110000100_1111101001_0000000001,
40'b11111_11111_1100111001_1111101001_0000000001,
40'b11111_11111_1011101110_1111101001_0000000001,
40'b11111_11111_1010111100_1111101001_0000000001,
40'b11111_11111_1010001010_1111101001_0000000001,
40'b11111_11111_1001110001_1111101001_0000000001,
40'b11111_11111_1000111111_1111101001_0000000001,
40'b11111_11111_1000100110_1111101001_0000000001,
40'b11111_11111_1000001101_1111101001_0000000001,
40'b11111_11111_0111110100_1111101001_0000000001,
40'b11111_11111_0111011011_1111101001_0000000001,
40'b11111_11111_0111000010_1111101001_0000000001,
40'b11111_11111_0110101001_1111101001_0000000001,
40'b11111_11111_0110010000_1111101001_0000000001,
40'b11111_11111_0110010000_1111101001_0000000001,
40'b11111_11111_0101110111_1111101001_0000000001,
40'b11111_11111_0101011110_1111101001_0000000001,
40'b11111_11111_0101011110_1111101001_0000000001,
40'b11111_11111_0101000101_1111101001_0000000001,
40'b11111_11111_0101000101_1111101001_0000000001,
40'b11111_11111_0100101100_1111101001_0000000001,
40'b11111_11111_0100101100_1111101001_0000000001,
40'b11111_11111_0100101100_1111101001_0000000001,
40'b11111_11111_0100010011_1111101001_0000000001,
40'b11111_11111_0100010011_1111101001_0000000001,
40'b11111_11111_0100010011_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001,
40'b11111_11111_0011111010_1111101001_0000000001, // M=127
40'b11111_11111_0011111010_1111101001_0000000001 // M=128
};
// Set lookup_entry with the explicit bits from lookup with a part select
mmcm_pll_lock_lookup = lookup[ ((128-divide)*40) +: 40];
`ifdef DEBUG
$display("lock_lookup: %b", mmcm_pll_lock_lookup);
`endif
end
endfunction
// This function takes the divide value and the bandwidth setting of the MMCM
// and outputs the digital filter settings necessary.
function [9:0] mmcm_pll_filter_lookup
(
input [7:0] divide, // input [7:0] divide // Max M divide is 128 in UltraScalePlus
input [8*9:0] BANDWIDTH
);
reg [1279:0] lookup_low;
reg [1279:0] lookup_high;
reg [9:0] lookup_entry;
begin
lookup_low = {
// CP_RES_LFHF
10'b0011_1111_11, // M=1 - not legal
10'b0011_1111_11, // M=2
10'b0011_1101_11, // M=3
10'b0011_0101_11, // M=4
10'b0011_1001_11, // M=5
10'b0011_1110_11, // M=6
10'b0011_1110_11, // M=7
10'b0011_0001_11,
10'b0011_0110_11,
10'b0011_0110_11,
10'b0011_0110_11,
10'b0011_1010_11,
10'b0011_1010_11,
10'b0011_1010_11,
10'b0100_0110_11,
10'b0011_1100_11,
10'b1110_0110_11,
10'b1111_0110_11,
10'b1110_1010_11,
10'b1110_1010_11,
10'b1111_1010_11,
10'b1111_1010_11,
10'b1111_1010_11,
10'b1111_1010_11,
10'b1111_1010_11,
10'b1101_1100_11,
10'b1101_1100_11,
10'b1101_1100_11,
10'b1110_1100_11,
10'b1110_1100_11,
10'b1110_1100_11,
10'b1111_1100_11,
10'b1111_1100_11,
10'b1111_1100_11,
10'b1111_1100_11,
10'b1111_1100_11,
10'b1111_1100_11,
10'b1110_0010_11,
10'b1110_0010_11,
10'b1110_0010_11,
10'b1110_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1100_0100_11,
10'b1100_0100_11,
10'b1100_0100_11,
10'b1100_0100_11,
10'b1100_0100_11,
10'b1100_0100_11,
10'b1100_0100_11,
10'b1100_0100_11,
10'b1101_0100_11,
10'b1101_0100_11,
10'b1101_0100_11,
10'b1101_0100_11,
10'b1101_0100_11,
10'b1101_0100_11,
10'b1101_0100_11,
10'b1110_0100_11,
10'b1110_0100_11,
10'b1110_0100_11,
10'b1110_0100_11,
10'b1110_0100_11,
10'b1110_0100_11,
10'b1110_0100_11,
10'b1110_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1101_1000_11,
10'b1101_1000_11,
10'b1101_1000_11,
10'b1101_1000_11,
10'b1101_1000_11,
10'b1101_1000_11,
10'b1101_1000_11,
10'b1101_1000_11, // M=127
10'b1101_1000_11 // M=128
};
lookup_high = {
// CP_RES_LFHF
10'b0111_1111_11, // M=1 - not legal
10'b0111_1111_11, // M=2
10'b1110_1111_11, // M=3
10'b1111_1111_11, // M=4
10'b1111_1011_11, // M=5
10'b1111_1101_11, // M=6
10'b1111_0011_11, // M=7
10'b1110_0101_11,
10'b1111_1001_11,
10'b1111_1001_11,
10'b1110_1110_11,
10'b1111_1110_11,
10'b1111_0001_11,
10'b1111_0001_11,
10'b1111_0001_11,
10'b1110_0110_11,
10'b1110_0110_11,
10'b1111_0110_11,
10'b1110_1010_11,
10'b1110_1010_11,
10'b1111_1010_11,
10'b1111_1010_11,
10'b1111_1010_11,
10'b1111_1010_11,
10'b1111_1010_11,
10'b1101_1100_11,
10'b1101_1100_11,
10'b1101_1100_11,
10'b1110_1100_11,
10'b1110_1100_11,
10'b1110_1100_11,
10'b1111_1100_11,
10'b1111_1100_11,
10'b1111_1100_11,
10'b1111_1100_11,
10'b1111_1100_11,
10'b1111_1100_11,
10'b1110_0010_11,
10'b1110_0010_11,
10'b1110_0010_11,
10'b1110_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1111_0010_11,
10'b1100_0100_11,
10'b1100_0100_11,
10'b1100_0100_11,
10'b1100_0100_11,
10'b1100_0100_11,
10'b1100_0100_11,
10'b1100_0100_11,
10'b1100_0100_11,
10'b1101_0100_11,
10'b1101_0100_11,
10'b1101_0100_11,
10'b1101_0100_11,
10'b1101_0100_11,
10'b1101_0100_11,
10'b1101_0100_11,
10'b1110_0100_11,
10'b1110_0100_11,
10'b1110_0100_11,
10'b1110_0100_11,
10'b1110_0100_11,
10'b1110_0100_11,
10'b1110_0100_11,
10'b1110_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1111_0100_11,
10'b1101_1000_11,
10'b1101_1000_11,
10'b1101_1000_11,
10'b1101_1000_11,
10'b1101_1000_11,
10'b1101_1000_11,
10'b1101_1000_11,
10'b1101_1000_11,
10'b1101_1000_11 // M=128
};
// Set lookup_entry with the explicit bits from lookup with a part select
if(BANDWIDTH == "LOW") begin
// Low Bandwidth
mmcm_pll_filter_lookup = lookup_low[ ((128-divide)*10) +: 10];
end else begin
// High or optimized bandwidth
mmcm_pll_filter_lookup = lookup_high[ ((128-divide)*10) +: 10];
end
`ifdef DEBUG
$display("filter_lookup: %b", mmcm_pll_filter_lookup);
`endif
end
endfunction
// This function takes in the divide, phase, and duty cycle
// setting to calculate the upper and lower counter registers.
function [37:0] mmcm_pll_count_calc
(
input [7:0] divide, // Max divide is 128
input signed [31:0] phase,
input [31:0] duty_cycle // Multiplied by 100,000
);
reg [13:0] div_calc;
reg [16:0] phase_calc;
begin
`ifdef DEBUG
$display("mmcm_pll_count_calc- divide:%h, phase:%d, duty_cycle:%d",
divide, phase, duty_cycle);
`endif
// w_edge[13], no_count[12], high_time[11:6], low_time[5:0]
div_calc = mmcm_pll_divider(divide, duty_cycle);
// mx[10:9], pm[8:6], dt[5:0]
phase_calc = mmcm_pll_phase(divide, phase);
// Return value is the upper and lower address of counter
// Upper address is:
// RESERVED [31:26]
// MX [25:24]
// EDGE [23]
// NOCOUNT [22]
// DELAY_TIME [21:16]
// Lower Address is:
// PHASE_MUX [15:13]
// RESERVED [12]
// HIGH_TIME [11:6]
// LOW_TIME [5:0]
`ifdef DEBUG
$display("div:%d dc:%d phase:%d ht:%d lt:%d ed:%d nc:%d mx:%d dt:%d pm:%d",
divide, duty_cycle, phase, div_calc[11:6], div_calc[5:0],
div_calc[13], div_calc[12],
phase_calc[16:15], phase_calc[5:0], phase_calc[14:12]);
`endif
mmcm_pll_count_calc =
{
// Upper Address
6'h00, phase_calc[10:9], div_calc[13:12], phase_calc[5:0],
// Lower Address
phase_calc[8:6], 1'b0, div_calc[11:0]
};
end
endfunction
// This function takes in the divide, phase, and duty cycle
// setting to calculate the upper and lower counter registers.
// for fractional multiply/divide functions.
//
//
function [37:0] mmcm_frac_count_calc
(
input [7:0] divide, // Max divide is 128
input signed [31:0] phase,
input [31:0] duty_cycle, // Multiplied by 100,000. Not programmable in fractional
input [9:0] frac // Multiplied by 1000
);
//Required for fractional divide calculations
reg [7:0] lt_frac;
reg [7:0] ht_frac;
reg /*[7:0]*/ wf_fall_frac;
reg /*[7:0]*/ wf_rise_frac;
reg [31:0] a;
reg [7:0] pm_rise_frac_filtered ;
reg [7:0] pm_fall_frac_filtered ;
reg [7:0] clkout0_divide_int;
reg [2:0] clkout0_divide_frac;
reg [7:0] even_part_high;
reg [7:0] even_part_low;
reg [7:0] odd;
reg [7:0] odd_and_frac;
reg [7:0] pm_fall;
reg [7:0] pm_rise;
reg [7:0] dt;
reg [7:0] dt_int;
reg [63:0] dt_calc;
reg [7:0] pm_rise_frac;
reg [7:0] pm_fall_frac;
reg [31:0] a_per_in_octets;
reg [31:0] a_phase_in_cycles;
parameter precision = 0.125;
reg [31:0] phase_fixed; // changed to 31:0 from 32:1 jt 5/2/11
reg [31: 0] phase_pos;
reg [31: 0] phase_vco;
reg [31:0] temp;// changed to 31:0 from 32:1 jt 5/2/11
reg [13:0] div_calc;
reg [16:0] phase_calc;
begin
`ifdef DEBUG
$display("mmcm_frac_count_calc- divide:%h, phase:%d, duty_cycle:%d",
divide, phase, duty_cycle);
`endif
//convert phase to fixed
if ((phase < -360000) || (phase > 360000)) begin
`ifndef SYNTHESIS
$display("ERROR: phase of $phase is not between -360000 and 360000");
`endif
$finish;
end
// Return value is
// Transfer data
// RESERVED [37:36]
// FRAC_TIME [35:33]
// FRAC_WF_FALL [32]
// Upper address is:
// RESERVED [31:26]
// MX [25:24]
// EDGE [23]
// NOCOUNT [22]
// DELAY_TIME [21:16]
// Lower Address is:
// PHASE_MUX [15:13]
// RESERVED [12]
// HIGH_TIME [11:6]
// LOW_TIME [5:0]
clkout0_divide_frac = frac / 125;
clkout0_divide_int = divide;
even_part_high = clkout0_divide_int >> 1;//$rtoi(clkout0_divide_int / 2);
even_part_low = even_part_high;
odd = clkout0_divide_int - even_part_high - even_part_low;
odd_and_frac = (8*odd) + clkout0_divide_frac;
lt_frac = even_part_high - (odd_and_frac <= 9);//IF(odd_and_frac>9,even_part_high, even_part_high - 1)
ht_frac = even_part_low - (odd_and_frac <= 8);//IF(odd_and_frac>8,even_part_low, even_part_low- 1)
pm_fall = {odd[6:0],2'b00} + {6'h00, clkout0_divide_frac[2:1]}; // using >> instead of clkout0_divide_frac / 2
pm_rise = 0; //0
wf_fall_frac = ((odd_and_frac >=2) && (odd_and_frac <=9)) || (clkout0_divide_int == 2 && clkout0_divide_frac == 1); //IF(odd_and_frac>=2,IF(odd_and_frac <= 9,1,0),0)
wf_rise_frac = (odd_and_frac >=1) && (odd_and_frac <=8); //IF(odd_and_frac>=1,IF(odd_and_frac <= 8,1,0),0)
//Calculate phase in fractional cycles
a_per_in_octets = (8 * divide) + (frac / 125) ;
a_phase_in_cycles = (phase+10) * a_per_in_octets / 360000 ;//Adding 1 due to rounding errors
pm_rise_frac = (a_phase_in_cycles[7:0] ==8'h00)?8'h00:a_phase_in_cycles[7:0] - {a_phase_in_cycles[7:3],3'b000};
dt_calc = ((phase+10) * a_per_in_octets / 8 )/360000 ;//TRUNC(phase* divide / 360); //or_simply (a_per_in_octets / 8)
dt = dt_calc[7:0];
pm_rise_frac_filtered = (pm_rise_frac >=8) ? (pm_rise_frac ) - 8: pm_rise_frac ; //((phase_fixed * (divide + frac / 1000)) / 360) - {pm_rise_frac[7:3],3'b000};//$rtoi(clkout0_phase * clkout0_divide / 45);//a;
dt_int = dt + (& pm_rise_frac[7:4]); //IF(pm_rise_overwriting>7,dt+1,dt)
pm_fall_frac = pm_fall + pm_rise_frac;
pm_fall_frac_filtered = pm_fall + pm_rise_frac - {pm_fall_frac[7:3], 3'b000};
div_calc = mmcm_pll_divider(divide, duty_cycle); //Use to determine edge[7], no count[6]
phase_calc = mmcm_pll_phase(divide, phase);// returns{mx[1:0], phase_mux[2:0], delay_time[5:0]}
mmcm_frac_count_calc[37:0] =
{ 2'b00, pm_fall_frac_filtered[2:0], wf_fall_frac,
1'b0, clkout0_divide_frac[2:0], 1'b1, wf_rise_frac, phase_calc[10:9], 2'b00, dt[5:0],
pm_rise_frac_filtered[2], pm_rise_frac_filtered[1], pm_rise_frac_filtered[0], 1'b0, ht_frac[5:0], lt_frac[5:0]
} ;
`ifdef DEBUG
$display("-%d.%d p%d>> :DADDR_9_15 frac30to28.frac_en.wf_r_frac.dt:%b%d%d_%b:DADDR_7_13 pm_f_frac_filtered_29to27.wf_f_frac_26:%b%d:DADDR_8_14.pm_r_frac_filt_15to13.ht_frac.lt_frac:%b%b%b:", divide, frac, phase, clkout0_divide_frac, 1, wf_rise_frac, dt, pm_fall_frac_filtered, wf_fall_frac, pm_rise_frac_filtered, ht_frac, lt_frac);
`endif
end
endfunction
@@ -1,536 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Company: Xilinx
// Engineer: Jim Tatsukawa, Ralf Krueger, updated for Ultrascale+
// Date: 6/15/2015
// Design Name: PLLE4 DRP
// Module Name: plle4_drp_func.h
// Version: 2.0
// Target Devices: UltraScale+ Architecture
// Tool versions: 2017.1
// Description: This header provides the functions necessary to
// calculate the DRP register values for the V6 PLL.
//
// Revision Notes: 8/11 - PLLE3 updated for PLLE3 file 4564419
// Revision Notes: 6/15 - pll_filter_lookup fixed for max M of 19
// M_Rise bits have been removed for PLLE3
// Revision Notes: 2/28/17 - pll_filter_lookup and CPRES updated for
// Ultrascale+ and for max M of 21
//
// Disclaimer: XILINX IS PROVIDING THIS DESIGN, CODE, OR
// INFORMATION "AS IS" SOLELY FOR USE IN DEVELOPING
// PROGRAMS AND SOLUTIONS FOR XILINX DEVICES. BY
// PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
// ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
// APPLICATION OR STANDARD, XILINX IS MAKING NO
// REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
// FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE
// RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY
// REQUIRE FOR YOUR IMPLEMENTATION. XILINX
// EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH
// RESPECT TO THE ADEQUACY OF THE IMPLEMENTATION,
// INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
// REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE.
//
// (c) Copyright 2009-2017 Xilinx, Inc.
// All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
// These are user functions that should not be modified. Changes to the defines
// or code within the functions may alter the accuracy of the calculations.
// Define debug to provide extra messages durring elaboration
//`define DEBUG 1
// FRAC_PRECISION describes the width of the fractional portion of the fixed
// point numbers. These should not be modified, they are for development
// only
`define FRAC_PRECISION 10
// FIXED_WIDTH describes the total size for fixed point calculations(int+frac).
// Warning: L.50 and below will not calculate properly with FIXED_WIDTHs
// greater than 32
`define FIXED_WIDTH 32
// This function takes a fixed point number and rounds it to the nearest
// fractional precision bit.
function [`FIXED_WIDTH:1] round_frac
(
// Input is (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point number
input [`FIXED_WIDTH:1] decimal,
// This describes the precision of the fraction, for example a value
// of 1 would modify the fractional so that instead of being a .16
// fractional, it would be a .1 (rounded to the nearest 0.5 in turn)
input [`FIXED_WIDTH:1] precision
);
begin
`ifdef DEBUG
$display("round_frac - decimal: %h, precision: %h", decimal, precision);
`endif
// If the fractional precision bit is high then round up
if( decimal[(`FRAC_PRECISION-precision)] == 1'b1) begin
round_frac = decimal + (1'b1 << (`FRAC_PRECISION-precision));
end else begin
round_frac = decimal;
end
`ifdef DEBUG
$display("round_frac: %h", round_frac);
`endif
end
endfunction
// This function calculates high_time, low_time, w_edge, and no_count
// of a non-fractional counter based on the divide and duty cycle
//
// NOTE: high_time and low_time are returned as integers between 0 and 63
// inclusive. 64 should equal 6'b000000 (in other words it is okay to
// ignore the overflow)
function [13:0] mmcm_pll_divider
(
input [7:0] divide, // Max divide is 128
input [31:0] duty_cycle // Duty cycle is multiplied by 100,000
);
reg [`FIXED_WIDTH:1] duty_cycle_fix;
// High/Low time is initially calculated with a wider integer to prevent a
// calculation error when it overflows to 64.
reg [6:0] high_time;
reg [6:0] low_time;
reg w_edge;
reg no_count;
reg [`FIXED_WIDTH:1] temp;
begin
// Duty Cycle must be between 0 and 1,000
if(duty_cycle <=0 || duty_cycle >= 100000) begin
`ifndef SYNTHESIS
$display("ERROR: duty_cycle: %d is invalid", duty_cycle);
`endif
$finish;
end
// Convert to FIXED_WIDTH-FRAC_PRECISION.FRAC_PRECISION fixed point
duty_cycle_fix = (duty_cycle << `FRAC_PRECISION) / 100_000;
`ifdef DEBUG
$display("duty_cycle_fix: %h", duty_cycle_fix);
`endif
// If the divide is 1 nothing needs to be set except the no_count bit.
// Other values are dummies
if(divide == 7'h01) begin
high_time = 7'h01;
w_edge = 1'b0;
low_time = 7'h01;
no_count = 1'b1;
end else begin
temp = round_frac(duty_cycle_fix*divide, 1);
// comes from above round_frac
high_time = temp[`FRAC_PRECISION+7:`FRAC_PRECISION+1];
// If the duty cycle * divide rounded is .5 or greater then this bit
// is set.
w_edge = temp[`FRAC_PRECISION]; // comes from round_frac
// If the high time comes out to 0, it needs to be set to at least 1
// and w_edge set to 0
if(high_time == 7'h00) begin
high_time = 7'h01;
w_edge = 1'b0;
end
if(high_time == divide) begin
high_time = divide - 1;
w_edge = 1'b1;
end
// Calculate low_time based on the divide setting and set no_count to
// 0 as it is only used when divide is 1.
low_time = divide - high_time;
no_count = 1'b0;
end
// Set the return value.
mmcm_pll_divider = {w_edge,no_count,high_time[5:0],low_time[5:0]};
end
endfunction
// This function calculates mx, delay_time, and phase_mux
// of a non-fractional counter based on the divide and phase
//
// NOTE: The only valid value for the MX bits is 2'b00 to ensure the coarse mux
// is used.
function [10:0] mmcm_pll_phase
(
// divide must be an integer (use fractional if not)
// assumed that divide already checked to be valid
input [7:0] divide, // Max divide is 128
// Phase is given in degrees (-360,000 to 360,000)
input signed [31:0] phase
);
reg [`FIXED_WIDTH:1] phase_in_cycles;
reg [`FIXED_WIDTH:1] phase_fixed;
reg [1:0] mx;
reg [5:0] delay_time;
reg [2:0] phase_mux;
reg [`FIXED_WIDTH:1] temp;
begin
`ifdef DEBUG
$display("pll_phase-divide:%d,phase:%d",
divide, phase);
`endif
if ((phase < -360000) || (phase > 360000)) begin
`ifndef SYNTHESIS
$display("ERROR: phase of $phase is not between -360000 and 360000");
`endif
$finish;
end
// If phase is less than 0, convert it to a positive phase shift
// Convert to (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point
if(phase < 0) begin
phase_fixed = ( (phase + 360000) << `FRAC_PRECISION ) / 1000;
end else begin
phase_fixed = ( phase << `FRAC_PRECISION ) / 1000;
end
// Put phase in terms of decimal number of vco clock cycles
phase_in_cycles = ( phase_fixed * divide ) / 360;
`ifdef DEBUG
$display("phase_in_cycles: %h", phase_in_cycles);
`endif
temp = round_frac(phase_in_cycles, 3);
// set mx to 2'b00 that the phase mux from the VCO is enabled
mx = 2'b00;
phase_mux = temp[`FRAC_PRECISION:`FRAC_PRECISION-2];
delay_time = temp[`FRAC_PRECISION+6:`FRAC_PRECISION+1];
`ifdef DEBUG
$display("temp: %h", temp);
`endif
// Setup the return value
mmcm_pll_phase={mx, phase_mux, delay_time};
end
endfunction
// This function takes the divide value and outputs the necessary lock values
function [39:0] mmcm_pll_lock_lookup
(
input [6:0] divide // Max divide is 21
);
reg [839:0] lookup;
begin
lookup = {
// This table is composed of:
// LockRefDly_LockFBDly_LockCnt_LockSatHigh_UnlockCnt
40'b00110_00110_1111101000_1111101001_0000000001, //1 illegal in Ultrascale+
40'b00110_00110_1111101000_1111101001_0000000001, //2
40'b01000_01000_1111101000_1111101001_0000000001, //3
40'b01011_01011_1111101000_1111101001_0000000001, //4
40'b01110_01110_1111101000_1111101001_0000000001, //5
40'b10001_10001_1111101000_1111101001_0000000001, //6
40'b10011_10011_1111101000_1111101001_0000000001, //7
40'b10110_10110_1111101000_1111101001_0000000001, //8
40'b11001_11001_1111101000_1111101001_0000000001, //9
40'b11100_11100_1111101000_1111101001_0000000001, //10
40'b11111_11111_1110000100_1111101001_0000000001, //11
40'b11111_11111_1100111001_1111101001_0000000001, //12
40'b11111_11111_1011101110_1111101001_0000000001, //13
40'b11111_11111_1010111100_1111101001_0000000001, //14
40'b11111_11111_1010001010_1111101001_0000000001, //15
40'b11111_11111_1001110001_1111101001_0000000001, //16
40'b11111_11111_1000111111_1111101001_0000000001, //17
40'b11111_11111_1000100110_1111101001_0000000001, //18
40'b11111_11111_1000001101_1111101001_0000000001, //19
40'b11111_11111_0111110100_1111101001_0000000001, //20
40'b11111_11111_0111011011_1111101001_0000000001 //21
};
// Set lookup_entry with the explicit bits from lookup with a part select
mmcm_pll_lock_lookup = lookup[ ((21-divide)*40) +: 40];
`ifdef DEBUG
$display("lock_lookup: %b", pll_lock_lookup);
`endif
end
endfunction
// This function takes the divide value and the bandwidth setting of the PLL
// and outputs the digital filter settings necessary. Removing bandwidth setting for PLLE3.
function [9:0] mmcm_pll_filter_lookup
(
input [6:0] divide // Max divide is 21
);
reg [209:0] lookup;
reg [9:0] lookup_entry;
begin
lookup = {
// CP_RES_LFHF
10'b0011_0111_11, //1 not legal in Ultrascale+
10'b0011_0111_11, //2
10'b0011_0011_11, //3
10'b0011_1001_11, //4
10'b0011_0001_11, //5
10'b0100_1110_11, //6
10'b0011_0110_11, //7
10'b0011_1010_11, //8
10'b0111_1001_11, //9
10'b0111_1001_11, //10
10'b0101_0110_11, //11
10'b1100_0101_11, //12
10'b0101_1010_11, //13
10'b0110_0110_11, //14
10'b0110_1010_11, //15
10'b0111_0110_11, //16
10'b1111_0101_11, //17
10'b1100_0110_11, //18
10'b1110_0001_11, //19
10'b1101_0110_11, //20
10'b1111_0001_11 //21
};
mmcm_pll_filter_lookup = lookup [ ((21-divide)*10) +: 10];
`ifdef DEBUG
$display("filter_lookup: %b", pll_filter_lookup);
`endif
end
endfunction
// This function set the CLKOUTPHY divide settings to match
// the desired CLKOUTPHY_MODE setting. To create VCO_X2, then
// the CLKOUTPHY will be set to 2'b00 since the VCO is internally
// doubled and 2'b00 will represent divide by 1. Similarly "VCO"
// will need to divide the doubled clock VCO clock frequency by
// 2 therefore 2'b01 will match a divide by 2.And VCO_HALF will
// need to divide the doubled VCO by 4, therefore 2'b10
function [9:0] mmcm_pll_clkoutphy_calc
(
input [8*9:0] CLKOUTPHY_MODE
);
if(CLKOUTPHY_MODE == "VCO_X2") begin
mmcm_pll_clkoutphy_calc= 2'b00;
end else if(CLKOUTPHY_MODE == "VCO") begin
mmcm_pll_clkoutphy_calc= 2'b01;
end else if(CLKOUTPHY_MODE == "CLKIN") begin
mmcm_pll_clkoutphy_calc= 2'b11;
end else begin // Assume "VCO_HALF"
mmcm_pll_clkoutphy_calc= 2'b10;
end
endfunction
// This function takes in the divide, phase, and duty cycle
// setting to calculate the upper and lower counter registers.
function [37:0] mmcm_pll_count_calc
(
input [7:0] divide, // Max divide is 128
input signed [31:0] phase,
input [31:0] duty_cycle // Multiplied by 100,000
);
reg [13:0] div_calc;
reg [16:0] phase_calc;
begin
`ifdef DEBUG
$display("pll_count_calc- divide:%h, phase:%d, duty_cycle:%d",
divide, phase, duty_cycle);
`endif
// w_edge[13], no_count[12], high_time[11:6], low_time[5:0]
div_calc = mmcm_pll_divider(divide, duty_cycle);
// mx[10:9], pm[8:6], dt[5:0]
phase_calc = mmcm_pll_phase(divide, phase);
// Return value is the upper and lower address of counter
// Upper address is:
// RESERVED [31:26]
// MX [25:24]
// EDGE [23]
// NOCOUNT [22]
// DELAY_TIME [21:16]
// Lower Address is:
// PHASE_MUX [15:13]
// RESERVED [12]
// HIGH_TIME [11:6]
// LOW_TIME [5:0]
`ifdef DEBUG
$display("div:%d dc:%d phase:%d ht:%d lt:%d ed:%d nc:%d mx:%d dt:%d pm:%d",
divide, duty_cycle, phase, div_calc[11:6], div_calc[5:0],
div_calc[13], div_calc[12],
phase_calc[16:15], phase_calc[5:0], 3'b000); //Removed PM_Rise bits
`endif
mmcm_pll_count_calc =
{
// Upper Address
6'h00, phase_calc[10:9], div_calc[13:12], phase_calc[5:0],
// Lower Address
phase_calc[8:6], 1'b0, div_calc[11:0]
};
end
endfunction
// This function takes in the divide, phase, and duty cycle
// setting to calculate the upper and lower counter registers.
// for fractional multiply/divide functions.
//
//
function [37:0] mmcm_pll_frac_count_calc
(
input [7:0] divide, // Max divide is 128
input signed [31:0] phase,
input [31:0] duty_cycle, // Multiplied by 1,000
input [9:0] frac // Multiplied by 1000
);
//Required for fractional divide calculations
reg [7:0] lt_frac;
reg [7:0] ht_frac;
reg /*[7:0]*/ wf_fall_frac;
reg /*[7:0]*/ wf_rise_frac;
reg [31:0] a;
reg [7:0] pm_rise_frac_filtered ;
reg [7:0] pm_fall_frac_filtered ;
reg [7:0] clkout0_divide_int;
reg [2:0] clkout0_divide_frac;
reg [7:0] even_part_high;
reg [7:0] even_part_low;
reg [7:0] odd;
reg [7:0] odd_and_frac;
reg [7:0] pm_fall;
reg [7:0] pm_rise;
reg [7:0] dt;
reg [7:0] dt_int;
reg [63:0] dt_calc;
reg [7:0] pm_rise_frac;
reg [7:0] pm_fall_frac;
reg [31:0] a_per_in_octets;
reg [31:0] a_phase_in_cycles;
parameter precision = 0.125;
reg [31:0] phase_fixed; // changed to 31:0 from 32:1 jt 5/2/11
reg [31: 0] phase_pos;
reg [31: 0] phase_vco;
reg [31:0] temp;// changed to 31:0 from 32:1 jt 5/2/11
reg [13:0] div_calc;
reg [16:0] phase_calc;
begin
`ifdef DEBUG
$display("pll_frac_count_calc- divide:%h, phase:%d, duty_cycle:%d",
divide, phase, duty_cycle);
`endif
//convert phase to fixed
if ((phase < -360000) || (phase > 360000)) begin
`ifndef SYNTHESIS
$display("ERROR: phase of $phase is not between -360000 and 360000");
`endif
$finish;
end
// Return value is
// Transfer data
// RESERVED [37:36]
// FRAC_TIME [35:33]
// FRAC_WF_FALL [32]
// Upper address is:
// RESERVED [31:26]
// MX [25:24]
// EDGE [23]
// NOCOUNT [22]
// DELAY_TIME [21:16]
// Lower Address is:
// PHASE_MUX [15:13]
// RESERVED [12]
// HIGH_TIME [11:6]
// LOW_TIME [5:0]
clkout0_divide_frac = frac / 125;
clkout0_divide_int = divide;
even_part_high = clkout0_divide_int >> 1;//$rtoi(clkout0_divide_int / 2);
even_part_low = even_part_high;
odd = clkout0_divide_int - even_part_high - even_part_low;
odd_and_frac = (8*odd) + clkout0_divide_frac;
lt_frac = even_part_high - (odd_and_frac <= 9);//IF(odd_and_frac>9,even_part_high, even_part_high - 1)
ht_frac = even_part_low - (odd_and_frac <= 8);//IF(odd_and_frac>8,even_part_low, even_part_low- 1)
pm_fall = {odd[6:0],2'b00} + {6'h00, clkout0_divide_frac[2:1]}; // using >> instead of clkout0_divide_frac / 2
pm_rise = 0; //0
wf_fall_frac = (odd_and_frac >=2) && (odd_and_frac <=9);//IF(odd_and_frac>=2,IF(odd_and_frac <= 9,1,0),0)
wf_rise_frac = (odd_and_frac >=1) && (odd_and_frac <=8);//IF(odd_and_frac>=1,IF(odd_and_frac <= 8,1,0),0)
//Calculate phase in fractional cycles
a_per_in_octets = (8 * divide) + (frac / 125) ;
a_phase_in_cycles = (phase+10) * a_per_in_octets / 360000 ;//Adding 1 due to rounding errors
pm_rise_frac = (a_phase_in_cycles[7:0] ==8'h00)?8'h00:a_phase_in_cycles[7:0] - {a_phase_in_cycles[7:3],3'b000};
dt_calc = ((phase+10) * a_per_in_octets / 8 )/360000 ;//TRUNC(phase* divide / 360); //or_simply (a_per_in_octets / 8)
dt = dt_calc[7:0];
pm_rise_frac_filtered = (pm_rise_frac >=8) ? (pm_rise_frac ) - 8: pm_rise_frac ; //((phase_fixed * (divide + frac / 1000)) / 360) - {pm_rise_frac[7:3],3'b000};//$rtoi(clkout0_phase * clkout0_divide / 45);//a;
dt_int = dt + (& pm_rise_frac[7:4]); //IF(pm_rise_overwriting>7,dt+1,dt)
pm_fall_frac = pm_fall + pm_rise_frac;
pm_fall_frac_filtered = pm_fall + pm_rise_frac - {pm_fall_frac[7:3], 3'b000};
div_calc = mmcm_pll_divider(divide, duty_cycle); //Use to determine edge[7], no count[6]
phase_calc = mmcm_pll_phase(divide, phase);// returns{mx[1:0], phase_mux[2:0], delay_time[5:0]}
mmcm_pll_frac_count_calc[37:0] =
{ 2'b00, pm_fall_frac_filtered[2:0], wf_fall_frac,
1'b0, clkout0_divide_frac[2:0], 1'b1, wf_rise_frac, phase_calc[10:9], div_calc[13:12], dt[5:0],
3'b000, 1'b0, ht_frac[5:0], lt_frac[5:0] //Removed PM_Rise bits
} ;
`ifdef DEBUG
$display("-%d.%d p%d>> :DADDR_9_15 frac30to28.frac_en.wf_r_frac.dt:%b%d%d_%b:DADDR_7_13 pm_f_frac_filtered_29to27.wf_f_frac_26:%b%d:DADDR_8_14.pm_r_frac_filt_15to13.ht_frac.lt_frac:%b%b%b:", divide, frac, phase, clkout0_divide_frac, 1, wf_rise_frac, dt, pm_fall_frac_filtered, wf_fall_frac, 3'b000, ht_frac, lt_frac);
`endif
end
endfunction
@@ -4,7 +4,7 @@
# README.txt: Please read the sections below to understand the steps required to
# run the exported script and information about the source files.
#
# Generated by export_simulation on Tue Mar 28 16:23:21 CST 2023
# Generated by export_simulation on Wed Mar 29 15:36:39 CST 2023
#
################################################################################
@@ -9,7 +9,7 @@
# directory, add the library logical mappings in the simulator setup file, create default
# 'do/prj' file, execute compilation, elaboration and simulation steps.
#
# Generated by Vivado on Tue Mar 28 16:23:21 CST 2023
# Generated by Vivado on Wed Mar 29 15:36:39 CST 2023
# SW Build 2644227 on Wed Sep 4 09:44:18 MDT 2019
#
# Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
@@ -4,7 +4,7 @@
# README.txt: Please read the sections below to understand the steps required to
# run the exported script and information about the source files.
#
# Generated by export_simulation on Tue Mar 28 16:23:21 CST 2023
# Generated by export_simulation on Wed Mar 29 15:36:39 CST 2023
#
################################################################################
@@ -9,7 +9,7 @@
# directory, add the library logical mappings in the simulator setup file, create default
# 'do/prj' file, execute compilation, elaboration and simulation steps.
#
# Generated by Vivado on Tue Mar 28 16:23:21 CST 2023
# Generated by Vivado on Wed Mar 29 15:36:39 CST 2023
# SW Build 2644227 on Wed Sep 4 09:44:18 MDT 2019
#
# Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
@@ -4,7 +4,7 @@
# README.txt: Please read the sections below to understand the steps required to
# run the exported script and information about the source files.
#
# Generated by export_simulation on Tue Mar 28 16:23:21 CST 2023
# Generated by export_simulation on Wed Mar 29 15:36:39 CST 2023
#
################################################################################
@@ -9,7 +9,7 @@
# directory, add the library logical mappings in the simulator setup file, create default
# 'do/prj' file, execute compilation, elaboration and simulation steps.
#
# Generated by Vivado on Tue Mar 28 16:23:21 CST 2023
# Generated by Vivado on Wed Mar 29 15:36:39 CST 2023
# SW Build 2644227 on Wed Sep 4 09:44:18 MDT 2019
#
# Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
@@ -4,7 +4,7 @@
# README.txt: Please read the sections below to understand the steps required to
# run the exported script and information about the source files.
#
# Generated by export_simulation on Tue Mar 28 16:23:21 CST 2023
# Generated by export_simulation on Wed Mar 29 15:36:39 CST 2023
#
################################################################################
@@ -9,7 +9,7 @@
# directory, add the library logical mappings in the simulator setup file, create default
# 'do/prj' file, execute compilation, elaboration and simulation steps.
#
# Generated by Vivado on Tue Mar 28 16:23:21 CST 2023
# Generated by Vivado on Wed Mar 29 15:36:39 CST 2023
# SW Build 2644227 on Wed Sep 4 09:44:18 MDT 2019
#
# Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
@@ -102,11 +102,10 @@ setup()
copy_setup_file()
{
file="modelsim.ini"
lib_map_path="<SPECIFY_COMPILED_LIB_PATH>"
if [[ ($1 != "" && -e $1) ]]; then
if [[ ($1 != "") ]]; then
lib_map_path="$1"
else
echo -e "ERROR: Compiled simulation library directory path not specified or does not exist (type "./top.sh -help" for more information)\n"
lib_map_path="/home/josh/Workspace/vivado-git/projects/datalink_814/dl814_z7/ip/managed_ip_project/managed_ip_project.cache/compile_simlib/questa"
fi
if [[ ($lib_map_path != "") ]]; then
src_file="$lib_map_path/$file"
@@ -4,7 +4,7 @@
# README.txt: Please read the sections below to understand the steps required to
# run the exported script and information about the source files.
#
# Generated by export_simulation on Tue Mar 28 16:23:21 CST 2023
# Generated by export_simulation on Wed Mar 29 15:36:39 CST 2023
#
################################################################################
@@ -9,7 +9,7 @@
# directory, add the library logical mappings in the simulator setup file, create default
# 'do/prj' file, execute compilation, elaboration and simulation steps.
#
# Generated by Vivado on Tue Mar 28 16:23:21 CST 2023
# Generated by Vivado on Wed Mar 29 15:36:39 CST 2023
# SW Build 2644227 on Wed Sep 4 09:44:18 MDT 2019
#
# Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
@@ -93,11 +93,10 @@ setup()
map_setup_file()
{
file="library.cfg"
lib_map_path="<SPECIFY_COMPILED_LIB_PATH>"
if [[ ($1 != "" && -e $1) ]]; then
if [[ ($1 != "") ]]; then
lib_map_path="$1"
else
echo -e "ERROR: Compiled simulation library directory path not specified or does not exist (type "./top.sh -help" for more information)\n"
lib_map_path="/home/josh/Workspace/vivado-git/projects/datalink_814/dl814_z7/ip/managed_ip_project/managed_ip_project.cache/compile_simlib/riviera"
fi
if [[ ($lib_map_path != "") ]]; then
src_file="$lib_map_path/$file"
@@ -4,7 +4,7 @@
# README.txt: Please read the sections below to understand the steps required to
# run the exported script and information about the source files.
#
# Generated by export_simulation on Tue Mar 28 16:23:21 CST 2023
# Generated by export_simulation on Wed Mar 29 15:36:39 CST 2023
#
################################################################################
@@ -9,7 +9,7 @@
# directory, add the library logical mappings in the simulator setup file, create default
# 'do/prj' file, execute compilation, elaboration and simulation steps.
#
# Generated by Vivado on Tue Mar 28 16:23:21 CST 2023
# Generated by Vivado on Wed Mar 29 15:36:39 CST 2023
# SW Build 2644227 on Wed Sep 4 09:44:18 MDT 2019
#
# Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
@@ -4,7 +4,7 @@
# README.txt: Please read the sections below to understand the steps required to
# run the exported script and information about the source files.
#
# Generated by export_simulation on Tue Mar 28 16:23:21 CST 2023
# Generated by export_simulation on Wed Mar 29 15:36:39 CST 2023
#
################################################################################
@@ -9,7 +9,7 @@
# directory, add the library logical mappings in the simulator setup file, create default
# 'do/prj' file, execute compilation, elaboration and simulation steps.
#
# Generated by Vivado on Tue Mar 28 16:23:21 CST 2023
# Generated by Vivado on Wed Mar 29 15:36:39 CST 2023
# SW Build 2644227 on Wed Sep 4 09:44:18 MDT 2019
#
# Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
@@ -4,7 +4,7 @@
# README.txt: Please read the sections below to understand the steps required to
# run the exported script and information about the source files.
#
# Generated by export_simulation on Tue Mar 28 16:23:21 CST 2023
# Generated by export_simulation on Wed Mar 29 15:36:39 CST 2023
#
################################################################################
@@ -9,7 +9,7 @@
# directory, add the library logical mappings in the simulator setup file, create default
# 'do/prj' file, execute compilation, elaboration and simulation steps.
#
# Generated by Vivado on Tue Mar 28 16:23:21 CST 2023
# Generated by Vivado on Wed Mar 29 15:36:39 CST 2023
# SW Build 2644227 on Wed Sep 4 09:44:18 MDT 2019
#
# Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.