1
0
mirror of https://github.com/aolofsson/oh.git synced 2025-01-17 20:02:53 +08:00
oh/elink/hdl/eclocks.v
Andreas Olofsson f141a0e320 Clock cleanup
-Adding enable signal to clock out. Definitely right decision to keep
separate bit from the divider field.
-Fixed settings for to fit new register field
-XILINX version is still broken!!
2015-04-18 16:24:26 -04:00

298 lines
10 KiB
Verilog

/*###########################################################################
# Function: High speed clock generator elink module
#
# cclk_p/n - Epiphany Core Clock, Differential, must be connected
# directly to IO pins.
#
# tx_lclk_par - Parallel data clock, at bit rate / 8 for etx
#
# tx_lclk - Serial DDR data clock, at bit rate / 2 for etx
#
# tx_lclk_out - DDR "Clock" clock, to generate tx_lclk_p/n output
# At bit rate / 2, 90deg shifted from tx_lclk
#
# Notes: Uses Xilinx macros throughout
#
############################################################################
*/
`timescale 1ns/1ps
module eclocks (/*AUTOARG*/
// Outputs
cclk_p, cclk_n, tx_lclk, tx_lclk_out, tx_lclk_par,
// Inputs
clkin, hard_reset, ecfg_clk_settings, clkbypass
);
// Parameters must be set as follows:
// PFD input frequency = 1/CLKIN1_PERIOD / DIVCLK_DIVIDE (10-450MHz)
// VCO frequency = PFD input frequency * CLKFBOUT_MULT (800-1600MHz)
// Output frequency = VCO frequency / CLKOUTn_DIVIDE
parameter CLKIN_PERIOD = 10.000; // ns -> 100MHz
parameter CLKIN_DIVIDE = 1;
parameter VCO_MULT = 12; // VCO = 1200MHz
parameter CCLK_DIVIDE = 2; // CCLK = 600MHz
parameter LCLK_DIVIDE = 4; // LCLK = 300MHz (600MB/s eLink)
parameter FEATURE_CCLK_DIV = 1'b1;
parameter IOSTD_ELINK = "LVDS_25";
parameter INC_PLL = 1;
//Input clock, reset, config interface
input clkin; // primary input clock
input hard_reset; //
input [15:0] ecfg_clk_settings; // clock settings
input [2:0] clkbypass; // for bypassing PLL
//Output Clocks
output cclk_p, cclk_n; // high speed Epiphany clock (up to 1GHz)
output tx_lclk; // elink tx serdes clock
output tx_lclk_out; // center aligned output clock for elink tx
output tx_lclk_par; // lclk/8 slow clock for tx parallel logic
// Wires
wire cclk_en;
wire lclk_en;
//Register decoding
assign cclk_en=ecfg_clk_settings[0];
assign lclk_en=ecfg_clk_settings[1];
`ifdef TARGET_XILINX
wire clkfb;
wire pll_cclk; //full speed cclk
wire pll_lclk; //full speed lclk etx
wire pll_lclk_out; //full speed lclk for pin for etx
wire pll_lclk_par; //low speed lclk for etx
wire pll_cclk_div; //low speed cclk
wire pll_cclk_standby; //standby clock
wire cclk;
wire cclk_base;
wire cclk_div;
// PLL Primitive
generate
for (i=0; i< INC_PLL; i=i+1) begin : PLL
PLLE2_BASE
#(
.BANDWIDTH("OPTIMIZED"), // OPTIMIZED, HIGH, LOW
.CLKFBOUT_MULT(VCO_MULT), // Multiply value for all CLKOUT, (2-64)
.CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB, (-360.000-360.000).
.CLKIN1_PERIOD(CLKIN_PERIOD),// Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz).
// CLKOUT0_DIVIDE - CLKOUT5_DIVIDE: Divide amount for each CLKOUT (1-128)
.CLKOUT0_DIVIDE(CCLK_DIVIDE), //full speed
.CLKOUT1_DIVIDE(LCLK_DIVIDE), //full speed
.CLKOUT2_DIVIDE(LCLK_DIVIDE), //full speed
.CLKOUT3_DIVIDE(LCLK_DIVIDE * 4), //low speed
.CLKOUT4_DIVIDE(CCLK_DIVIDE * 4), //low speed
.CLKOUT5_DIVIDE(128), //veeery low speed
// CLKOUT0_DUTY_CYCLE - CLKOUT5_DUTY_CYCLE: Duty cycle for each CLKOUT (0.001-0.999).
.CLKOUT0_DUTY_CYCLE(0.5),
.CLKOUT1_DUTY_CYCLE(0.5),
.CLKOUT2_DUTY_CYCLE(0.5),
.CLKOUT3_DUTY_CYCLE(0.5),
.CLKOUT4_DUTY_CYCLE(0.5),
.CLKOUT5_DUTY_CYCLE(0.5),
// CLKOUT0_PHASE - CLKOUT5_PHASE: Phase offset for each CLKOUT (-360.000-360.000).
.CLKOUT0_PHASE(0.0),
.CLKOUT1_PHASE(0.0),
.CLKOUT2_PHASE(90.0),
.CLKOUT3_PHASE(0.0),
.CLKOUT4_PHASE(0.0),
.CLKOUT5_PHASE(0.0),
.DIVCLK_DIVIDE(CLKIN_DIVIDE),// Master division value, (1-56)
.REF_JITTER1(0.01), // Reference input jitter (0.000-0.999).
.STARTUP_WAIT("FALSE") // Delay DONE until PLL Locks, ("TRUE"/"FALSE")
) eclk_pll
(
// Clock Outputs: 1-bit (each) output: User configurable clock outputs
.CLKOUT0(pll_cclk), //full speed cclk
.CLKOUT1(pll_lclk), //full speed lclk etx
.CLKOUT2(pll_lclk_out), //full speed lclk for pin for etx
.CLKOUT3(pll_lclk_par), //low speed lclk for etx
.CLKOUT4(pll_cclk_div), //low speed cclk
.CLKOUT5(pll_cclk_standby), //standby clock
.CLKFBOUT(clkfb), //feedback clock output
.LOCKED(), //lock signal
.CLKIN1(clkin), //main input clock
.PWRDWN(1'b0), //pll power down
.RST(1'b0), //reset
.CLKFBIN(clkfb) //feedback clock input
);
//TODO!! Redesign this all together!!!
// Output buffering
BUFG cclk_buf (.O (cclk_base), .I (pll_cclk));
BUFG cclk_div_buf (.O (cclk_div), .I (pll_cclk_div));
BUFG lclk_buf (.O (tx_lclk), .I (pll_lclk));
BUFG lclk_out_buf (.O (tx_lclk_out), .I (pll_lclk_out));
BUFG lclk_par_buf (.O (tx_lclk_par), .I (pll_lclk_par));
generate
if( FEATURE_CCLK_DIV ) begin : gen_cclk_div
// Create adjustable (but fast) CCLK
wire rxi_cclk_out;
reg [8:1] cclk_pattern;
reg [4:0] clk_div_sync;
reg enb_sync;
always @ (posedge cclk_div) begin // Might need x-clock TIG here
clk_div_sync <= {cclk_en,ecfg_clk_settings[7:4]};
if(enb_sync)
case(clk_div_sync)
4'h0: cclk_pattern <= 8'd0; // Clock OFF
4'h0: cclk_pattern <= 8'b10101010; // Divide by 1
4'h6: cclk_pattern <= 8'b11001100; // Divide by 2
4'h5: cclk_pattern <= 8'b11110000; // Divide by 4
default: cclk_pattern <= {8{~cclk_pattern[1]}}; // /8
endcase
else
cclk_pattern <= 8'b00000000;
end // always @ (posedge cclk_div)
//CCLK CLOCK DIVIDER
OSERDESE2
#(
.DATA_RATE_OQ("DDR"), // DDR, SDR
.DATA_RATE_TQ("SDR"), // DDR, BUF, SDR
.DATA_WIDTH(8), // Parallel data width (2-8,10,14)
.INIT_OQ(1'b0), // Initial value of OQ output (1'b0,1'b1)
.INIT_TQ(1'b0), // Initial value of TQ output (1'b0,1'b1)
.SERDES_MODE("MASTER"), // MASTER, SLAVE
.SRVAL_OQ(1'b0), // OQ output value when SR is used (1'b0,1'b1)
.SRVAL_TQ(1'b0), // TQ output value when SR is used (1'b0,1'b1)
.TBYTE_CTL("FALSE"), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC("FALSE"), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH(1) // 3-state converter width (1,4)
) OSERDESE2_inst
(
.OFB(), // Feedback path for data
.OQ(cclk), // Data path output
.SHIFTOUT1(),
.SHIFTOUT2(),
.TBYTEOUT(), // Byte group tristate
.TFB(), // 1-bit output: 3-state control
.TQ(), // 3-state control
.CLK(cclk_base), // High speed clock
.CLKDIV(cclk_div), // Divided clock
.D1(cclk_pattern[1]), // Parallel data inputs
.D2(cclk_pattern[2]),
.D3(cclk_pattern[3]),
.D4(cclk_pattern[4]),
.D5(cclk_pattern[5]),
.D6(cclk_pattern[6]),
.D7(cclk_pattern[7]),
.D8(cclk_pattern[8]),
.OCE(1'b1), // Output data clock enable TODO: gating?
.RST(hard_reset), // Reset
.SHIFTIN1(1'b0), // Data input expansion (1-bit each)
.SHIFTIN2(1'b0),
.T1(1'b0), // Parallel 3-state inputs
.T2(1'b0),
.T3(1'b0),
.T4(1'b0),
.TBYTEIN(1'b0), // Byte group tristate
.TCE(1'b0) // 3-state clock enable
);
end else
begin : gen_fixed_cclk // Non-dividable CCLK
reg enb_sync;
always @ (posedge cclk_div)
enb_sync <= ~(ecfg_clk_settings[3:0]==4'b0000);
// The following does not result in timing failures,
// but doesn't seem glitch-safe
assign cclk = cclk_base & enb_sync;
end
endgenerate
//Clock output
OBUFDS #(.IOSTANDARD (IOSTD_ELINK)) obufds_cclk_inst (.O (cclk_p), .OB (cclk_n), .I (cclk));
end // block: PLL
endgenerate
`elsif TARGET_CLEAN
wire cclk;
wire lclk_par;
wire lclk;
wire lclk_out;
clock_divider cclk_divider(
// Outputs
.clkout (cclk),
.clkout90 (),
// Inputs
.clkin (clkin),
.reset (hard_reset),
.divcfg (ecfg_clk_settings[7:4])
);
assign cclk_p = cclk & cclk_en ;
assign cclk_n = ~cclk_p;
clock_divider lclk_divider(
// Outputs
.clkout (lclk),
.clkout90 (lclk_out),
// Inputs
.clkin (clkin),
.reset (hard_reset),
.divcfg (ecfg_clk_settings[11:8])
);
clock_divider lclk_par_divider(
// Outputs
.clkout (lclk_par),
.clkout90 (),
// Inputs
.clkin (clkin),
.reset (hard_reset),
.divcfg (ecfg_clk_settings[11:8] + 4'd2)
);
//Clock enables
assign tx_lclk_par = lclk_par & lclk_en;
assign tx_lclk = lclk & lclk_en;
assign tx_lclk_out = lclk_out & lclk_en;
`endif
endmodule // eclocks
// Local Variables:
// verilog-library-directories:("." "../../common/hdl")
// End:
/*
Copyright (C) 2014 Adapteva, Inc.
Contributed by Fred Huettig <fred@adapteva.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.This program is distributed in the hope
that it will be useful,but WITHOUT ANY WARRANTY without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. You should have received a copy
of the GNU General Public License along with this program (see the file
COPYING). If not, see <http://www.gnu.org/licenses/>.
*/