// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: ccu_core.v
// Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
// 4150 Network Circle, Santa Clara, California 95054, U.S.A.
// * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
// 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; version 2 of the License.
// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// For the avoidance of doubt, and except that if any non-GPL license
// choice is available it will apply instead, Sun elects to use only
// the General Public License version 2 (GPLv2) at this time for any
// software where a choice of GPL license versions is made
// available with the language indicating that GPLv2 or any later version
// may be used, or where a choice of which version of the GPL is applied is
// otherwise unspecified.
// Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
// CA 95054 USA or visit www.sun.com if you need additional information or
// ========== Copyright Header End ============================================
`define CCU_ALIGN_CNT 5'h08
`define CCU_CSR_RST_CNT 6'h36
output ccu_sys_cmp_sync_en;
output ccu_cmp_sys_sync_en;
// output ccu_vco_aligned;
output [5:0] pll_div3_lat;
output [6:0] pll_div4_lat;
output ccu_dbg1_serdes_dtm;
output ccu_mio_serdes_dtm;
input ccu_pre_dr_sync_en;
output ccu_serdes_dtm_lat;
output ccu_cmp_io_sync_en;
output ccu_io_cmp_sync_en;
output ccu_rst_sync_stable;
output [4:0] dr_shift_amt;
// external wire/reg declarations
wire ccu_sys_cmp_sync_en;
wire ccu_cmp_sys_sync_en;
wire ccu_dbg1_serdes_dtm;
// reg ccu_rst_sync_stable; // for inferred flops
// internal wire/reg declarations
// reg [4:0] csr_rst_cnt; // for inferred flops
// reg [4:0] align_pulse_cnt; // for inferred flops
// for instantiated flops
wire [4:0] align_pulse_cnt;
wire ccu_rst_sync_stable;
wire ccu_rst_sync_stable_in;
wire [5:0] csr_rst_cnt_in;
wire [4:0] align_pulse_cnt_in;
assign gclk_rst = ~gclk_rst_n;
assign gclk_rst_n_gated = tcu_atpg_mode | gclk_rst_n;
assign gclk_rst_gated = ~gclk_rst_n_gated;
// assign rst_ccu_gated = ~tcu_atpg_mode & rst_ccu;
// assign rst_ccu_n_gated = tcu_atpg_mode | rst_ccu_;
assign csr_rst_gated = ~tcu_atpg_mode & csr_rst;
assign csr_rst_n_gated = tcu_atpg_mode | csr_rst_n;
assign dr_shift_amt = shift_amt;
assign csr_rst = ~csr_rst_n;
assign ccu_serdes_dtm_lat = serdes_dtm1_lat | serdes_dtm2_lat;
// clear rng during por_ or wmr_ with frequency change
assign rng_arst_l = rst_ccu_;
assign scan_out = scan_in;
assign ccu_mio_serdes_dtm = serdes_dtm1_lat;
assign ccu_dbg1_serdes_dtm = serdes_dtm1_lat;
// ***********************************************
// ***********************************************
assign gclk_rst_n = rst_ccu_ & pre_gclk_rst_n;
cl_a1_clksyncff_4x bf_sync1 (
.l1clk (l1clk), .d (rst_ccu_), .q(pre_gclk_rst_n),
.si(1'b0), .siclk(1'b0), .soclk (1'b0), .so()
// ***********************************************
// now generate reset aligned w/aligned pulse
// ***********************************************
// BEGIN_ECO POST TAPEOUT - N2 BUG
assign aligned_hold = aligned | aligned_hold_q;
my_msff_arst_4x gclk_rst_hold_eco (
.d ( aligned_hold ), .q ( aligned_hold_q ), .reset ( gclk_rst ), .l1clk ( l1clk ),
.si(1'b0), .siclk(1'b0), .soclk (1'b0), .so()
always @( posedge l1clk) begin
if ( !gclk_rst_n ) begin // POST TAPEOUT ECO
aligned_rst_q1_n <= 1'b0; // internal
aligned_rst_q2_n <= 1'b0; // additional pipe stage
aligned_rst_q3_n <= 1'b0; // external
aligned_rst_q1_n <= aligned & aligned_hold_q; // POST TAPEOUT ECO
aligned_rst_q2_n <= aligned_rst_q1_n;
aligned_rst_q3_n <= aligned_rst_q3_n |
(aligned_rst_q2_n & (~aligned_rst_q1_n));
assign aligned_rst_n = aligned_rst_q3_n;
// ***********************************************
// generate delayd rst signal for csr stuff
// ***********************************************
assign csr_rst_n = (csr_rst_cnt==`CCU_CSR_RST_CNT)? 1'b1: 1'b0;
assign csr_rst_cnt_in[5:0] = (csr_rst_cnt == `CCU_CSR_RST_CNT) ? csr_rst_cnt[5:0] : (csr_rst_cnt + 6'b1) ;
wire aligned_hold_q_gated = aligned_hold_q | tcu_atpg_mode; // POST TAPEOUT ECO
ccu_msff_arst_4x_6 rst_cnt_bank6 (
.reset_n (aligned_hold_q_gated) // POST TAPEOUT ECO - changed from gclk_rst_n_gated
// ***********************************************
// latch in divider value similar to pll's
// ***********************************************
assign pll_div4_msb = pll_div4_lat[4]; // ccu only needs bit 4 of 6:0
assign pll_div4_lat[6] = pll_div4[6]; // this is purely for maintaining 7 inputs to pll
ccu_blatch_4x_6 pll_div2_bnk6 (
.latout (pll_div2_lat), .d(pll_div2), .l1clk(pll_arst_l),
.so(), .si (1'b0), .siclk (1'b0), .soclk (1'b0)
ccu_blatch_4x_6 pll_div3_bnk6 (
.latout (pll_div3_lat), .d(pll_div3), .l1clk(pll_arst_l),
.so(), .si (1'b0), .siclk (1'b0), .soclk (1'b0)
ccu_blatch_4x_6 pll_div4_bnk6 (
.latout (pll_div4_lat[5:0]), .d(pll_div4[5:0]),
.l1clk(pll_arst_l), .so(), .si (1'b0), .siclk (1'b0), .soclk (1'b0)
ccu_blatch_4x_1 serdes_dtm1_bnk1 (
.latout (serdes_dtm1_lat), .d(serdes_dtm1), .l1clk(pll_arst_l),
.so(), .si (1'b0), .siclk (1'b0), .soclk (1'b0)
ccu_blatch_4x_1 serdes_dtm1_bnk2 (
.latout (serdes_dtm2_lat), .d(serdes_dtm2), .l1clk(pll_arst_l),
.so(), .si (1'b0), .siclk (1'b0), .soclk (1'b0)
// ***********************************************
// ***********************************************
always @ (pll_div2_lat) begin
6'h07: shift_amt = 5'h02;
6'h08: shift_amt = 5'h03;
6'h09: shift_amt = 5'h04;
6'h0A: shift_amt = 5'h05;
6'h0B: shift_amt = 5'h06;
6'h0C: shift_amt = 5'h07;
6'h0D: shift_amt = 5'h08;
6'h0E: shift_amt = 5'h09;
6'h0F: shift_amt = 5'h0A;
6'h10: shift_amt = 5'h0B;
6'h11: shift_amt = 5'h0C;
6'h12: shift_amt = 5'h0D;
6'h13: shift_amt = 5'h0E;
6'h14: shift_amt = 5'h0F;
6'h15: shift_amt = 5'h10;
default: shift_amt = 5'h02;
// assign ccu_vco_aligned = aligned;
// count align cycles, repeat after CCU_ALIGN_CNT
assign align_pulse_cnt_in = (aligned == 1'b1) ?
((align_pulse_cnt == `CCU_ALIGN_CNT) ? 5'b0 : (align_pulse_cnt + 5'b1) ) :
ccu_msff_arst_4x_5 align_pulse_cnt_bank5 (
.reset_n (csr_rst_n_gated)
// generate ccu_rst_sync_stable signal after CCU_ALIGN_CNT
// ref_clk (= 2 * CCU_ALIGN_CNT sys_clk cycles)
assign ccu_rst_sync_stable_in = (align_pulse_cnt == `CCU_ALIGN_CNT) ? 1'b1 : ccu_rst_sync_stable;
assign rst_ccu = ~rst_ccu_;
my_msff_arst_4x ccu_rst_sync_stable_ff (
.d(ccu_rst_sync_stable_in),
.reset(csr_rst_gated) // .reset(csr_rst)
// generate cmp->dr ratio
// normal mode: always cmp multiplier/4, range [2.00,5.50]x
// use lsb to determine fractional parts
// d3=2, pll_div4/2 is true ratio
// func: assign ratio[4:0] = pll_div2_lat[4:0];
// dtm: (pll_div2+1)/2 = ratio
// shift io-cmp & cmp-io sync pulses by a cycle in functional mode
my_msff_arst_4x sync1_shift (
.q(io_phase_180_q1), .so(), .d(io_phase_180), .l1clk(l1clk),
.si(1'b0), .siclk(aclk), .soclk(bclk), .reset(gclk_rst_gated)
my_msff_arst_4x sync2_shift (
.q(io_phase_0_q1), .so(), .d(io_phase_0), .l1clk(l1clk),
.si(1'b0), .siclk(aclk), .soclk(bclk), .reset(gclk_rst_gated)
my_msff_arst_4x sys_cmp_sync_shift1 (
.q(ccu_pre_sys_cmp_sync_en ), .so(), .d(aligned), .l1clk(l1clk),
.si(1'b0), .siclk(aclk), .soclk(bclk), .reset(gclk_rst_gated)
wire ccu_pre_cmp_io_sync_en;
wire ccu_pre_io_cmp_sync_en;
wire ccu_pre_io2x_sync_en;
assign ratio[4:0] = ccu_serdes_dtm_lat? pll_div2_lat[4:0] : pll_div4_lat[4:0];
assign io_div = ccu_serdes_dtm_lat? pll_div2_lat[4:0] : 5'b00011;
assign io2x_div = ccu_serdes_dtm_lat? pll_div2_lat[4:0] : 5'b00001;
assign ccu_pre_io2x_sync_en = ccu_serdes_dtm_lat?ccu_dr_sync_en_q1:io2x_phase_180; // removed inversion
assign ccu_pre_cmp_io_sync_en = ccu_serdes_dtm_lat?ccu_dr_sync_en_q1:io_phase_180_q1;
// assign ccu_pre_io_cmp_sync_en=ccu_serdes_dtm_lat?ccu_dr_sync_en_q1:io_phase_0_q1;
assign ccu_pre_io_cmp_sync_en = io_phase_0_q1;
assign ccu_cmp_sys_sync_en = ccu_sys_cmp_sync_en; // unaffected by dtm
// account for # delay in pre-grid driver
assign ccu_dr_sync_en = ccu_dr_sync_en_q2; // shift twice needed here
my_msff_arst_4x dr_sync_shift1 (
.q(ccu_dr_sync_en_q1), .so(), .d(ccu_pre_dr_sync_en), .l1clk(l1clk),
.si(1'b0), .siclk(aclk), .soclk(bclk), .reset(gclk_rst_gated)
my_msff_arst_4x dr_sync_shift2 (
.q(ccu_dr_sync_en_q2), .so(), .d(ccu_dr_sync_en_q1), .l1clk(l1clk),
.si(1'b0), .siclk(aclk), .soclk(bclk), .reset(gclk_rst_gated)
// finally, shift all sync pulses by single cycle to compensate
// for race-thru in cluster header
ccu_msff_arst_4x_4 all_sync_shift (
.q({ccu_sys_cmp_sync_en,ccu_io2x_sync_en,
ccu_io_cmp_sync_en,ccu_cmp_io_sync_en}),
.d({ccu_pre_sys_cmp_sync_en,ccu_pre_io2x_sync_en,
ccu_pre_io_cmp_sync_en,ccu_pre_cmp_io_sync_en}),
.reset_n(gclk_rst_n_gated) ,
.si(1'b0), .siclk(aclk), .soclk(bclk), .so()
// ctl3 ctl2 ctl1 ch_sel[1:0]
// 0 0 0 11 - really don't care
// 1 0 1 11 - select all ch
// 1 1 0 11 - select all ch
// 1 1 1 11 - select all ch
// 0 1 1 11 - select all ch
// a = ctl3, b = ctl2, c = ctl1
assign rng_ch_sel[0] = rng_ctl2 | (rng_ctl3 & rng_ctl1) | (~rng_ctl3 & ~rng_ctl1);
assign rng_ch_sel[1] = rng_ctl3 | (rng_ctl2 & rng_ctl1) | (~rng_ctl2 & ~rng_ctl1);