// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: ccu_csr.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 PLL_REG 40'h8300000000
`define RNGCTL_REG 40'h8300000020
`define RNGDAT_REG 40'h8300000030
// x64 + x61 + x57 + x56 + x52 + x51 + x50 + x48 + x47 +
// x46 + x43 + x42 + x41 + x39 + x38 + x37 + x35 + x32 +
// x28 + x25 + x22 + x21 + x17 + x15 + x13 + x12 + x11 +
// poly coeffecients starting with x^63 going down to x^0 (x^64 tap is always 1)
`define RNGCRC_POLY 64'b00100011000111011_100111011101001_000100100110001010111_00010100011
// default values - currently set to 62
`define DEFAULT_RNG_WAIT_VAL 16'h003E
`define ST_DELAY_CMP 27:26
`define ALIGN_SHIFT 31:30
`define ST_DELAY_DR 35:34
`define PLL_CLAMP_FLTR 36
`define RNG_WAIT_CNT 24:9
`define RNG_VCOCTRL_SEL 7:6
`define CCUCSR_IDLE 3'b000
`define CCUCSR_WRITE 3'b001
`define CCUCSR_READ 3'b010
`define CCUCSR_READ_SUCCESS 3'b011
`define CCUCSR_READ_PROB 3'b100
// other block connectivity
// *****************************************
// *****************************************
// ------------------------
input wr_req_vld; // when signal is asserted, following are valid to Local Unit
input [39:0] addr_in; // Based on addr_in Local Unit will update the CSR info accordingly
input [63:0] data_in; // Write command to invalid address should be discarded silently
output req_accepted; // CSR Reg Block will assert a 1 clock pulse to indicate acceptance
input rd_req_vld; // when signal is asserted, following are valid to Local Unit
// input [39:0] addr_in; // Based on addr_in Local Unit will read the CSR info accordingly
input rack_busy; // until deasserted, CSR reg Block should NOT assert rd_ack_vld/"rd_nack_vld
// output req_accepted; // CSR Reg Block will assert a 1 clock pulse to indicate acceptance
output rd_ack_vld; // CSR Reg Block asserts this to send return data to CSR Interface logic
output rd_nack_vld; // if not valid, Reg Block asserts this along with thr_id_in and buf_id_in
// Interrupts : // unused stuff for now
output [5:0] dev_id; // When Local Unit needs to send intr to NCU, there should be set
output int_vld; // asserted indicates a valid interrupt to NCU, and asserts only when int_busy is 0.
// other block connectivity
// ------------------------
output [1:0] align_shift;
output [1:0] st_delay_cmp;
output [1:0] st_delay_dr;
output [1:0] rng_vcoctrl_sel;
output [1:0] rng_anlg_sel;
// *****************************************
// *****************************************
wire [1:0] rng_vcoctrl_sel;
wire [15:0] rng_wait_cnt;
// ---------------------------------
// internal wire/reg stuff
// ---------------------------------
// for instantiated flops
wire [63:0] msb_sel; // pick out msb based on poly coeff
wire [63:0] poly; // given in decreasing powers of x
wire [63:0] lfsr_data_muxed;
// ***********************************************************
// ***********************************************************
assign dev_id = 6'b0_0000;
// ***********************************************************
// ***********************************************************
assign pll_div1 = pll_r[`PLL_DIV1];
assign pll_div2 = pll_r[`PLL_DIV2];
assign pll_div3 = pll_r[`PLL_DIV3];
assign pll_div4 = pll_r[`PLL_DIV4];
assign st_phase_hi = pll_r[`ST_PHASE_HI];
assign st_delay_cmp = pll_r[`ST_DELAY_CMP];
assign serdes_dtm1 = pll_r[`SERDES_DTM1];
assign serdes_dtm2 = pll_r[`SERDES_DTM2];
assign align_shift = pll_r[`ALIGN_SHIFT];
assign change = pll_r[`CHANGE];
assign pll_char_in = pll_r[`PLL_CHAR_IN];
assign st_delay_dr = pll_r[`ST_DELAY_DR]; // late addition
assign pll_clamp_fltr = pll_r[`PLL_CLAMP_FLTR]; // late addition
assign rng_ctl1 = rngctl_r[`RNG_CTL1];
assign rng_ctl2 = rngctl_r[`RNG_CTL2];
assign rng_ctl3 = rngctl_r[`RNG_CTL3];
assign rng_ctl4 = rngctl_r[`RNG_CTL4];
assign rng_anlg_sel = rngctl_r[`RNG_ANLG_SEL];
assign rng_vcoctrl_sel = rngctl_r[`RNG_VCOCTRL_SEL];
assign rng_bypass = rngctl_r[`RNG_BYPASS];
assign rng_wait_cnt = rngctl_r[`RNG_WAIT_CNT];
// address decodes & read/write enables
assign pll_match = (addr_in == `PLL_REG);
assign rngctl_match = (addr_in == `RNGCTL_REG);
assign rngdat_match = (addr_in == `RNGDAT_REG);
assign pll_wr_en = wr_req_vld & pll_match;
assign rngctl_wr_en = wr_req_vld & rngctl_match;
// assign rngdat_wr_en = wr_req_vld & rngdat_match;
assign pll_rd_en = rd_req_vld & pll_match;
assign rngctl_rd_en = rd_req_vld & rngctl_match;
assign rngdat_rd_en = rd_req_vld & rngdat_match;
// write success -- has no effect on acknowledge
assign wr_ok = (pll_wr_en | rngctl_wr_en | wr_req_vld);
assign rd_ok = (pll_rd_en | rngctl_rd_en | rngdat_rd_en );
assign rd_nok = rd_req_vld & ~(pll_match | rngctl_match | rngdat_match);
// ***********************************************************
// CSR Write implementation:
// ***********************************************************
assign rst_gated_n = rst_n | wmr_protect;
// WARM RESET PROTECTED FLOPS
/* commented out to replace with instantiated flops
always @(posedge l1clk or negedge rst_gated_n) begin
`PLL_DIV1 <= 6'h01; // /2 of sysclk 00_0001
`PLL_DIV2 <= 6'h07; // x8 of sysclk/2 00_0111
`PLL_DIV3 <= 6'h00; // no post-division 00_0000
`PLL_DIV4 <= 7'h04; // divide by 2 00_0010_0
`PLL_RES <= 30'b0; 00_0000_0000_0000_0000
pll_r <= (!wmr_protect && pll_wr_en)?data_in:pll_r;
assign rst_gated = ~rst_gated_n;
wire [63:0] pll_r_pre_in;
// mask bits help to set to 1 during reset where needed
// (aka use default values)
assign mask_div1 = 6'b00_0001;
assign mask_div2 = 6'b00_0111;
assign mask_div3 = 6'b00_0001;
assign mask_div4 = 7'b00_0100_0;
assign pll_r_pre_in = (!wmr_protect && pll_wr_en)?data_in:pll_r;
// invert inputs where needed
assign pll_r_in = pll_r_pre_in ^ {31'b0, 1'b1, 7'b0, mask_div4, mask_div3, mask_div2, mask_div1};
ccu_msff_arst_4x_64 pll_r_bank64 (
.q (pll_r_tmp), .reset_n (rst_gated_n), .d (pll_r_in), .l1clk (l1clk),
.si (1'b0), .siclk (1'b0), .soclk (1'b0), .so ()
assign pll_r[`PLL_DIV1 ] = pll_r_tmp[`PLL_DIV1 ] ^ mask_div1;
assign pll_r[`PLL_DIV2 ] = pll_r_tmp[`PLL_DIV2 ] ^ mask_div2;
assign pll_r[`PLL_DIV3 ] = pll_r_tmp[`PLL_DIV3 ] ^ mask_div3;
assign pll_r[`PLL_DIV4 ] = pll_r_tmp[`PLL_DIV4 ] ^ mask_div4;
assign pll_r[`ST_PHASE_HI ] = pll_r_tmp[`ST_PHASE_HI ];
assign pll_r[`ST_DELAY_CMP] = pll_r_tmp[`ST_DELAY_CMP]; // from `st_delay_a
assign pll_r[`SERDES_DTM1 ] = pll_r_tmp[`SERDES_DTM1 ];
assign pll_r[`SERDES_DTM2 ] = pll_r_tmp[`SERDES_DTM2 ];
assign pll_r[`ALIGN_SHIFT ] = pll_r_tmp[`ALIGN_SHIFT ];
assign pll_r[`CHANGE ] = ~pll_r_tmp[`CHANGE ]; // bit is 1 by default
assign pll_r[`PLL_CHAR_IN ] = pll_r_tmp[`PLL_CHAR_IN ];
assign pll_r[`ST_DELAY_DR ] = pll_r_tmp[`ST_DELAY_DR ]; // late addition
assign pll_r[`PLL_CLAMP_FLTR] = pll_r_tmp[`PLL_CLAMP_FLTR]; // late addition
assign pll_r[`PLL_RES ] = pll_r_tmp[`PLL_RES ];
// NOT WARM RESET PROTECTED
/* commented out to replace with instantiated flops
always @(posedge l1clk or negedge rst_n) begin
`RNG_VCOCTRL_SEL <= 2'b0;
rngctl_r <= (rngctl_wr_en)?data_in:rngctl_r;
wire [63:0] rngctl_r_tmp;
wire [63:0] rngctl_r_pre_in;
assign rngctl_r_pre_in = (rngctl_wr_en)?data_in:rngctl_r;
assign rngctl_r_in = rngctl_r_pre_in ^
{39'b0,`DEFAULT_RNG_WAIT_VAL,9'b0_0000_1111}; // invert mask bits
ccu_msff_arst_4x_64 rngctl_r_bank64 (
.q (rngctl_r_tmp), .reset_n (rst_n), .d (rngctl_r_in), .l1clk (l1clk),
.si (1'b0), .siclk (1'b0), .soclk (1'b0), .so ()
// inversion needed when asynchronously resetting to 1 is desired
assign rngctl_r[`RNG_RES] = rngctl_r_tmp[`RNG_RES];
assign rngctl_r[`RNG_WAIT_CNT] = rngctl_r_tmp[`RNG_WAIT_CNT] ^ `DEFAULT_RNG_WAIT_VAL;
assign rngctl_r[`RNG_BYPASS] = rngctl_r_tmp[`RNG_BYPASS];
assign rngctl_r[`RNG_VCOCTRL_SEL] = rngctl_r_tmp[`RNG_VCOCTRL_SEL];
assign rngctl_r[`RNG_ANLG_SEL] = rngctl_r_tmp[`RNG_ANLG_SEL];
assign rngctl_r[`RNG_CTL4] = ~rngctl_r_tmp[`RNG_CTL4];
assign rngctl_r[`RNG_CTL3] = ~rngctl_r_tmp[`RNG_CTL3];
assign rngctl_r[`RNG_CTL2] = ~rngctl_r_tmp[`RNG_CTL2];
assign rngctl_r[`RNG_CTL1] = ~rngctl_r_tmp[`RNG_CTL1];
// ***********************************************************
// CSR read implementation:
// ***********************************************************
always @(posedge l1clk) begin
if (pll_rd_en) data_out <= pll_r;
else if (rngctl_rd_en) data_out <= rngctl_r;
else if (rngdat_rd_en && rng_wait_done) data_out <= rngdat_r;
else data_out <= data_out;
// thread and dev id reads
assign thr_id_out[5:0] = thr_id_in[5:0];
assign buf_id_out[1:0] = buf_id_in[1:0];
// ***********************************************************
// CSR read/write acknowledgement:
// ***********************************************************
// finally settled for a simpler moore machine design
`CCUCSR_READ_SUCCESS: begin
always @(wr_ok or rd_req_vld or rack_busy or rng_busy or rd_ok or rd_nok or state) begin
state_in = `CCUCSR_WRITE;
`CCUCSR_WRITE: state_in = `CCUCSR_IDLE; // always return to idle
if (rack_busy || rng_busy) // handles special rng read
state_in = `CCUCSR_READ_SUCCESS;
state_in = `CCUCSR_READ_PROB;
`CCUCSR_READ_PROB: state_in = `CCUCSR_IDLE; // always return to idle
`CCUCSR_READ_SUCCESS: state_in = `CCUCSR_IDLE; // always return to idle
default: state_in = `CCUCSR_IDLE;
ccu_msff_arst_4x_3 state_bank3 (
// ***********************************************************
// rng read mode for diagnostics
// ***********************************************************
assign rng_cnt_reached = (rng_cnt == max_cnt);
// assign rng_busy = rngdat_rd_en & rng_ctl4 & ~rng_cnt_reached;
assign rng_busy = rngdat_rd_en & ~rng_wait_done;
assign max_cnt = (rng_ctl4) ? rng_wait_cnt : 16'd62; // + 2 cycles for states
// convert rng_cnt_reached to a pulse
assign rng_wait_done = ~rng_cnt_reached_q1 & rng_cnt_reached;
always @(posedge l1clk) begin
rng_cnt_reached_q1 <= 1'b0;
rng_cnt_reached_q1 <= rng_cnt_reached;
// count up to max_cnt and hold till "idle"
always @(posedge l1clk) begin
if (state == `CCUCSR_IDLE)
rng_cnt <= rng_cnt + 16'h0001;
// ***********************************************
// synchronizer flop (for rngdata)
// ***********************************************
assign rng_data_in_gated = (rng_ctl1 | rng_ctl2 | rng_ctl3) & rng_data_in;
cl_a1_clksyncff_4x rng_data_syncff (
.l1clk (l1clk), .d (rng_data_in_gated), .q(rng_data_synced),
.si(1'b0), .siclk(1'b0), .soclk (1'b0), .so()
// ***********************************************************
// LFSR implementation & update register
// ***********************************************************
// load serial shift reg/LFSR
assign poly = `RNGCRC_POLY ; // [a63..a0] for a63.x^63 + ... a0.x^0, a64=1
// added xor for quicker entropy building; (ctl4==0) -> shift reg, period.
assign lfsr_fdbk = rng_ctl4 & (lfsr_data[63] ^ rng_data_synced);
assign msb_sel = {64{lfsr_fdbk}} & `RNGCRC_POLY;
// flush with one's when a read is successful & (ctl4==1)
// need to break next statement into 2 pieces to fix shift-reg bug
// assign lfsr_in[63:0] = ((state == `CCUCSR_READ_SUCCESS) && rng_ctl4) ?
// 64'hFFFF_FFFF_FFFF_FFFF : {lfsr_data[62:0],1'b0} ^ msb_sel[63:0];
assign lfsr_in[63:1] = ((state == `CCUCSR_READ_SUCCESS) && rng_ctl4) ?
63'h7FFF_FFFF_FFFF_FFFF : lfsr_data[62:0] ^ msb_sel[63:1];
assign lfsr_in[0] = (rng_ctl4 == 1'b0) ? rng_data_synced :
((state == `CCUCSR_READ_SUCCESS) && rng_ctl4) ? 1'b1 : msb_sel[0];
// convert to sync reset for convenience
always @(posedge l1clk) begin
lfsr_data <= 64'hFFFF_FFFF_FFFF_FFFF;
// update rngdat_r register when done waiting
assign lfsr_data_muxed = (rng_wait_done) ? lfsr_data: rngdat_r;
// always @(posedge l1clk) rngdat_r <= lfsr_data_muxed;
// do not flop in this stage
assign rngdat_r = lfsr_data_muxed;
// ***********************************************************
// ***********************************************************
cl_a1_l1hdr_8x header_io (