Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / design / sys / iop / ccu / rtl / ccu_core.v
// ========== 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
// have any questions.
//
// ========== Copyright Header End ============================================
`timescale 1 ps/ 1 ps
`define CCU_ALIGN_CNT 5'h08
`define CCU_CSR_RST_CNT 6'h36
module ccu_core (
l1clk,
rst_ccu_,
aligned,
pll_arst_l,
pll_div2,
pll_div3,
pll_div4,
pll_div4_msb,
io2x_phase_180,
io_phase_180,
io_phase_0,
ccu_sys_cmp_sync_en,
shift_amt,
ccu_cmp_sys_sync_en,
ratio,
// ccu_vco_aligned,
pll_div3_lat,
pll_div4_lat,
csr_rst_n,
serdes_dtm1,
serdes_dtm2,
io_div,
io2x_div,
ccu_dbg1_serdes_dtm,
ccu_mio_serdes_dtm,
ccu_io2x_sync_en,
ccu_pre_dr_sync_en,
ccu_dr_sync_en,
tcu_atpg_mode,
scan_in,
aclk,
bclk,
scan_out,
rng_arst_l,
ccu_serdes_dtm_lat,
rng_ctl1,
rng_ctl2,
rng_ctl3 ,
rng_ch_sel,
ccu_cmp_io_sync_en,
ccu_io_cmp_sync_en,
ccu_rst_sync_stable,
aligned_rst_n,
dr_shift_amt
);
// port declarations
input l1clk;
input rst_ccu_;
input aligned;
input pll_arst_l;
input [5:0] pll_div2;
input [5:0] pll_div3;
input [6:0] pll_div4;
input io2x_phase_180;
input io_phase_180;
input io_phase_0;
output ccu_sys_cmp_sync_en;
input serdes_dtm1;
input serdes_dtm2;
output [4:0] io_div;
output [4:0] io2x_div;
output ccu_cmp_sys_sync_en;
output aligned_rst_n;
output [4:0] ratio;
// output ccu_vco_aligned;
output [5:0] pll_div3_lat;
output [6:0] pll_div4_lat;
output csr_rst_n;
output ccu_dbg1_serdes_dtm;
output ccu_mio_serdes_dtm;
output ccu_io2x_sync_en;
input ccu_pre_dr_sync_en;
output ccu_dr_sync_en;
input tcu_atpg_mode;
input scan_in;
input aclk;
input bclk;
output scan_out;
output rng_arst_l;
output ccu_serdes_dtm_lat;
input rng_ctl1;
input rng_ctl2;
input rng_ctl3;
output [1:0] rng_ch_sel;
output ccu_cmp_io_sync_en;
output ccu_io_cmp_sync_en;
output ccu_rst_sync_stable;
output [4:0] shift_amt;
output pll_div4_msb;
output [4:0] dr_shift_amt;
// external wire/reg declarations
wire l1clk;
wire rst_ccu_;
wire aligned;
wire pll_arst_l;
wire [5:0] pll_div2;
wire [5:0] pll_div3;
wire [6:0] pll_div4;
wire io2x_phase_180;
wire io_phase_180;
wire io_phase_0;
wire serdes_dtm1;
wire serdes_dtm2;
wire [4:0] io_div;
wire [4:0] io2x_div;
wire ccu_sys_cmp_sync_en;
wire ccu_cmp_sys_sync_en;
wire aligned_rst_n;
wire [4:0] ratio;
// wire ccu_vco_aligned;
wire [5:0] pll_div3_lat;
wire [6:0] pll_div4_lat;
wire csr_rst_n;
wire ccu_dbg1_serdes_dtm;
wire ccu_mio_serdes_dtm;
wire ccu_io2x_sync_en;
wire ccu_dr_sync_en;
wire tcu_atpg_mode;
wire scan_in;
wire aclk;
wire bclk;
wire scan_out;
wire rng_arst_l;
wire ccu_serdes_dtm_lat;
wire rng_ctl1;
wire rng_ctl2;
wire rng_ctl3;
wire [1:0] rng_ch_sel;
wire ccu_cmp_io_sync_en;
wire ccu_io_cmp_sync_en;
// reg ccu_rst_sync_stable; // for inferred flops
reg [4:0] shift_amt;
wire pll_div4_msb;
wire [4:0] dr_shift_amt;
// internal wire/reg declarations
wire csr_rst;
reg aligned_rst_q1_n;
// reg [4:0] csr_rst_cnt; // for inferred flops
wire [5:0] pll_div2_lat;
wire gclk_rst_n;
// reg [4:0] align_pulse_cnt; // for inferred flops
// for instantiated flops
wire [5:0] csr_rst_cnt;
wire [4:0] align_pulse_cnt;
wire ccu_rst_sync_stable;
wire rst_ccu;
wire ccu_rst_sync_stable_in;
wire [5:0] csr_rst_cnt_in;
wire [4:0] align_pulse_cnt_in;
wire unused;
// wire rst_ccu_gated;
// wire rst_ccu_n_gated;
wire csr_rst_n_gated;
wire csr_rst_gated;
wire io_phase_180_q1;
wire io_phase_0_q1;
wire serdes_dtm1_lat;
wire serdes_dtm2_lat;
reg aligned_rst_q2_n;
reg aligned_rst_q3_n;
wire gclk_rst ;
wire gclk_rst_n_gated ;
wire gclk_rst_gated ;
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;
// ***********************************************
// synchronizer flop
// ***********************************************
wire pre_gclk_rst_n;
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
wire gclk_rst_n_eco;
wire aligned_hold;
wire aligned_hold_q;
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()
);
// END_ECO POST TAPEOUT
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
end else begin
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));
end
end
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 (
.q(csr_rst_cnt),
.so(),
.si (1'b0),
.d(csr_rst_cnt_in),
.l1clk(l1clk),
.siclk (aclk),
.soclk (bclk),
.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)
);
// ***********************************************
// align shift value
// ***********************************************
always @ (pll_div2_lat) begin
case (pll_div2_lat)
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;
endcase
end
// 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) ) :
align_pulse_cnt;
ccu_msff_arst_4x_5 align_pulse_cnt_bank5 (
.q(align_pulse_cnt),
.si(1'b0),
.so(),
.d(align_pulse_cnt_in),
.l1clk(l1clk),
.siclk (aclk),
.soclk (bclk),
.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 (
.q(ccu_rst_sync_stable),
.so(),
.d(ccu_rst_sync_stable_in),
.l1clk(l1clk),
.si(1'b0),
.siclk(aclk),
.soclk(bclk),
.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
// 00 => .00
// 01 => .25
// 10 => .50
// 11 => .75
// 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)
);
// take care of dtm mode
wire ccu_dr_sync_en_q2;
wire ccu_dr_sync_en_q1;
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;
// FREEZE FEATURE BEGIN
// 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;
// FREEZE FEATURE END
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 (
.l1clk(l1clk),
.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()
);
// rng channel encoding
// =====================
// ctl3 ctl2 ctl1 ch_sel[1:0]
// 0 0 0 11 - really don't care
// 0 0 1 00 - select ch1
// 0 1 0 01 - select ch2
// 1 0 0 10 - select ch3
// 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
// ch0 = b + ac + !a!c
// ch1 = a + bc + !b!c
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);
endmodule