Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: ccu_clks_states.vr | |
4 | // Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved | |
5 | // 4150 Network Circle, Santa Clara, California 95054, U.S.A. | |
6 | // | |
7 | // * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
8 | // | |
9 | // This program is free software; you can redistribute it and/or modify | |
10 | // it under the terms of the GNU General Public License as published by | |
11 | // the Free Software Foundation; version 2 of the License. | |
12 | // | |
13 | // This program is distributed in the hope that it will be useful, | |
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | // GNU General Public License for more details. | |
17 | // | |
18 | // You should have received a copy of the GNU General Public License | |
19 | // along with this program; if not, write to the Free Software | |
20 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | // | |
22 | // For the avoidance of doubt, and except that if any non-GPL license | |
23 | // choice is available it will apply instead, Sun elects to use only | |
24 | // the General Public License version 2 (GPLv2) at this time for any | |
25 | // software where a choice of GPL license versions is made | |
26 | // available with the language indicating that GPLv2 or any later version | |
27 | // may be used, or where a choice of which version of the GPL is applied is | |
28 | // otherwise unspecified. | |
29 | // | |
30 | // Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
31 | // CA 95054 USA or visit www.sun.com if you need additional information or | |
32 | // have any questions. | |
33 | // | |
34 | // ========== Copyright Header End ============================================ | |
35 | #include <vera_defines.vrh> | |
36 | #include "std_display_class.vrh" | |
37 | #include "ucb_defines.vri" | |
38 | #include "ucb___packet.vrh" | |
39 | #include "ccu_defines.vri" | |
40 | #include "ucb_top.vri" | |
41 | #include "ccu_top.vri" | |
42 | #include "ucb_monitor.vrh" | |
43 | #include "ccu_clk_packet.vrh" | |
44 | ||
45 | class CCU_clks_states { | |
46 | //---ports and classes-- | |
47 | local UCB_port ccu_ucb_port; // CCU-NCU interface | |
48 | local CCU_clk_port ccu_clk_port; // port for all CCU clk signals | |
49 | local CCU_mon_port ccu_mon_port; | |
50 | local UCB_monitor ccu_ucb_monitor; // monitor UCB bus | |
51 | local StandardDisplay dbg; // Standard display for printing | |
52 | ||
53 | //---CCU CSRs--- | |
54 | local bit [63:0] pll_ctl; | |
55 | local bit [63:0] rng_ctl; | |
56 | local bit [63:0] rng_data; | |
57 | local bit [63:0] pll_ctl_staging; // staging reg | |
58 | //---pll inputs---- | |
59 | local integer sys_clk_per; // sys clk per sampled at CCU input | |
60 | ||
61 | //---vars: limits/deviations--- | |
62 | local integer cmp_per_dev; // deviation in cmp clk per in % from nominal | |
63 | local integer cmp_pw_dev; // deviation in cmp clk pulse width in % from nominal | |
64 | local integer dr_per_dev; | |
65 | local integer dr_pw_dev; | |
66 | local integer iox_per_dev, iox_pw_dev; // deviation of IO and io2X clk period and duty cycle (in %) | |
67 | local integer dtm_dr_iox_pw_dev; // dtm-mode: dr and iox pulse width deviation | |
68 | ||
69 | //---vars: control--- | |
70 | local string name; // name of this object | |
71 | local string dispScope; // for standard display | |
72 | local integer error_cnt; // Error count. Init to 0. WARN: become negative if exeed max integer | |
73 | local integer max_error_printed; // not print error msg if (errors > max_error_printed) | |
74 | local integer running; // 0: not running; otherwise, running | |
75 | local event stop_e; // triggered by stop_it() to terminate start() | |
76 | local integer is_fc_bench; // 0: not FC_bench; otherwise, it's FC bench | |
77 | local integer pllbypass_mode;// 0: not pll bypass mode; otherwise, it's pll bypass | |
78 | local bit [5:0] pllbypass_virtual_div2; // imaginary values of div2 that produce same effect as non-bypass mode | |
79 | local bit [6:0] pllbypass_virtual_div4; // imaginary values of div4 that produce same effect as non-bypass mode | |
80 | ||
81 | //---public tasks--- | |
82 | task new(string name="CCU_clks_states", StandardDisplay dbg, integer start_it=0); | |
83 | task start(); | |
84 | task stop_it(); | |
85 | function CCU_clk_packet get_exp_clk_pkt(); | |
86 | task show_clk_pkt(CCU_clk_packet pkt); | |
87 | task put_per_pw_dev(integer cmp_per_dev, integer cmp_pw_dev, | |
88 | integer iox_per_dev, integer iox_pw_dev, | |
89 | integer dr_per_dev, integer dr_pw_dev); | |
90 | ||
91 | //---public one-line subroutines--- | |
92 | function integer get_error_cnt() { get_error_cnt = (error_cnt >= 0)? error_cnt : 1; } | |
93 | task ignore_ccu_ucb_error() { this.ccu_ucb_monitor.ignore_err = 1; } | |
94 | task put_pllbypass_mode(integer value) { this.pllbypass_mode = (value == 0)? 0 : 1; } | |
95 | task put_pllbypass_virtual_div(bit [5:0] div2, bit [6:0] div4) { this.pllbypass_virtual_div2 = div2; this.pllbypass_virtual_div4 = div4; } | |
96 | function bit [63:0] get_pll_ctl() { get_pll_ctl = this.pll_ctl; } | |
97 | ||
98 | //---local subroutines--- | |
99 | local task mon_update_ccu_csrs(); | |
100 | local function integer get_sys_clk_per(integer wait_cycs=0); | |
101 | local function CCU_clk_packet get_expClkPkt_func_mode(); | |
102 | local function CCU_clk_packet get_expClkPkt_dtm_mode(); | |
103 | } | |
104 | ||
105 | //################################################################ | |
106 | //######### implementation of subroutines ########### | |
107 | //################################################################ | |
108 | ||
109 | task CCU_clks_states::new(string name="CCU_clks_states", StandardDisplay dbg, integer start_it=0) { | |
110 | //---from arg list--- | |
111 | this.dbg = dbg; | |
112 | this.name = name; | |
113 | ||
114 | //---ports and classes--- | |
115 | this.ccu_ucb_port = ccu_ucb_mon_bind; | |
116 | this.ccu_clk_port = ccu_clk_bind; | |
117 | this.ccu_mon_port = ccu_mon_bind; | |
118 | this.ccu_ucb_monitor = new("ccu_ucb_mon", dbg, ccu_ucb_port, 4, 8'h83); // 4: ucb bus data width | |
119 | ||
120 | //---others--- | |
121 | this.pll_ctl = CCU__PLL_CTL__INIT_VALUE; | |
122 | this.rng_ctl = 0; // review: may need to change | |
123 | this.rng_data = 0; // review: may need to change | |
124 | this.pll_ctl_staging = this.pll_ctl; | |
125 | ||
126 | //--- testing limits for clk period and duty cycle---- | |
127 | //--- WARNING: per CCU designer, these limits should be as follows: | |
128 | this.cmp_per_dev = 7; // in % (ie. nominal +/- per_dev in percent) | |
129 | this.cmp_pw_dev = 7; // in % (ie. 50% +/- (pw_dev% of clk per)) | |
130 | this.iox_per_dev = 7; | |
131 | this.iox_pw_dev = 7; | |
132 | this.dr_per_dev = 7; | |
133 | this.dr_pw_dev = 10; // in % (ie. 50% +/- (pw_dev% of clk per)) | |
134 | this.dtm_dr_iox_pw_dev = 10; // in % (ie. 50% +/- (pw_dev% of clk per)) | |
135 | ||
136 | //----the rest ----- | |
137 | this.dispScope = this.name; | |
138 | this.error_cnt = 0; | |
139 | this.max_error_printed = 20; | |
140 | this.running = 0; | |
141 | #ifdef FC_BENCH | |
142 | this.is_fc_bench = 1; | |
143 | dbg.dispmon(name, MON_ALWAYS, "FC testbench"); | |
144 | #else | |
145 | this.is_fc_bench = 0; | |
146 | dbg.dispmon(name, MON_ALWAYS, "SAT-level testbench"); | |
147 | #endif | |
148 | this.pllbypass_mode = 0; | |
149 | this.pllbypass_virtual_div2 = 6'h7; | |
150 | this.pllbypass_virtual_div4 = 7'h8; | |
151 | ||
152 | //---process plus_arg to override default values--- | |
153 | if (get_plus_arg(CHECK, "cmp_per_dev=")) | |
154 | this.cmp_per_dev = get_plus_arg(NUM, "cmp_per_dev="); | |
155 | if (get_plus_arg(CHECK, "cmp_pw_dev=")) | |
156 | this.cmp_pw_dev = get_plus_arg(NUM, "cmp_pw_dev="); | |
157 | if (get_plus_arg(CHECK, "iox_per_dev=")) | |
158 | this.iox_per_dev = get_plus_arg(NUM, "iox_per_dev="); | |
159 | if (get_plus_arg(CHECK, "iox_pw_dev=")) | |
160 | this.iox_pw_dev = get_plus_arg(NUM, "iox_pw_dev="); | |
161 | if (get_plus_arg(CHECK, "dr_per_dev=")) | |
162 | this.dr_per_dev = get_plus_arg(NUM, "dr_per_dev="); | |
163 | if (get_plus_arg(CHECK, "dr_pw_dev=")) | |
164 | this.dr_pw_dev = get_plus_arg(NUM, "dr_pw_dev="); | |
165 | ||
166 | //---start background threads --- | |
167 | if (start_it) | |
168 | start(); | |
169 | fork { // always do this | |
170 | this.sys_clk_per = this.get_sys_clk_per(3); | |
171 | } join none | |
172 | } | |
173 | ||
174 | //============================================================= | |
175 | // WHAT: start this object | |
176 | //============================================================= | |
177 | task CCU_clks_states::start() { | |
178 | if (running) | |
179 | return; | |
180 | dbg.dispmon(this.dispScope, MON_INFO, "starts ..."); | |
181 | this.running = 1; | |
182 | ccu_ucb_monitor.start(); // run in back ground | |
183 | fork { | |
184 | fork { | |
185 | mon_update_ccu_csrs(); | |
186 | } join none | |
187 | sync(ALL, this.stop_e); // stop_it() triggers this event | |
188 | terminate; | |
189 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("%s stopped", this.name)); | |
190 | this.running = 0; | |
191 | } join none | |
192 | } | |
193 | ||
194 | //============================================================= | |
195 | // WHAT: stop this object | |
196 | //============================================================= | |
197 | task CCU_clks_states::stop_it() { | |
198 | if (this.running) { | |
199 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("stopping %s ...", this.name)); | |
200 | trigger(this.stop_e); // this event terminates start() | |
201 | } | |
202 | } | |
203 | ||
204 | //============================================================= | |
205 | // WHAT: monitor CCU's UCB bus and update CSRs when NCU writes to them. | |
206 | // When RST does WMR reset, copy staging CSRs to real CSR | |
207 | //============================================================= | |
208 | task CCU_clks_states::mon_update_ccu_csrs() { | |
209 | UCB___packet ucb_pkt; | |
210 | ||
211 | //---Update CSRs when NCU writes to them--- | |
212 | fork { | |
213 | while (1) { | |
214 | sync(ALL, ccu_ucb_monitor.req_end); // wait NCU completes a req | |
215 | ucb_pkt = ccu_ucb_monitor.get_req_pkt(); // get write req pkt | |
216 | if (ucb_pkt.pkt_type == UCB_PKT_WRITE_REQ) { | |
217 | case (ucb_pkt.addr) { | |
218 | CCU__PLL_CTL : this.pll_ctl_staging = ucb_pkt.payload; // update staging CSR only | |
219 | CCU__RNG_CTL : this.rng_ctl = ucb_pkt.payload; | |
220 | CCU__RNG_DATA : this.rng_data = ucb_pkt.payload; | |
221 | // ignore if other addrs | |
222 | } | |
223 | } | |
224 | } | |
225 | } join none | |
226 | ||
227 | //---copy staging CSRs into real CSRs when PLL is reseted-- | |
228 | fork { | |
229 | while (1) { | |
230 | @(posedge ccu_clk_port.$rst_ccu_pll_); // PLL got reset | |
231 | if (this.is_fc_bench) { // FC bench forces values onto these signals | |
232 | this.pll_ctl[CCU__PLL_CTL__PLL_DIV1__MSB : CCU__PLL_CTL__PLL_DIV1__POS] = ccu_mon_port.$pll_div1_at_csrblk async; | |
233 | this.pll_ctl[CCU__PLL_CTL__PLL_DIV2__MSB : CCU__PLL_CTL__PLL_DIV2__POS] = ccu_mon_port.$pll_div2_at_csrblk async; | |
234 | this.pll_ctl[CCU__PLL_CTL__PLL_DIV3__MSB : CCU__PLL_CTL__PLL_DIV3__POS] = ccu_mon_port.$pll_div3_at_csrblk async; | |
235 | this.pll_ctl[CCU__PLL_CTL__PLL_DIV4__MSB : CCU__PLL_CTL__PLL_DIV4__POS] = ccu_mon_port.$pll_div4_at_csrblk async; | |
236 | this.pll_ctl[CCU__PLL_CTL__SERDES_DTM1__POS] = ccu_mon_port.$serdes_dtm1_at_csrblk async; | |
237 | this.pll_ctl[CCU__PLL_CTL__SERDES_DTM2__POS] = ccu_mon_port.$serdes_dtm2_at_csrblk async; | |
238 | } | |
239 | else { // TCU SAT which programs CCU's CSR via UCB bus | |
240 | this.pll_ctl = this.pll_ctl_staging; // copy staging CSR into real CSR | |
241 | if (this.pllbypass_mode) { | |
242 | this.pll_ctl[CCU__PLL_CTL__PLL_DIV2__MSB : CCU__PLL_CTL__PLL_DIV2__POS] = this.pllbypass_virtual_div2; | |
243 | this.pll_ctl[CCU__PLL_CTL__PLL_DIV4__MSB : CCU__PLL_CTL__PLL_DIV4__POS] = this.pllbypass_virtual_div4; | |
244 | } | |
245 | } | |
246 | } | |
247 | } join none | |
248 | } | |
249 | ||
250 | //============================================================= | |
251 | // WHAT: get sys clk period by sampling CCU input | |
252 | // ARGs: | |
253 | // wait_cycs: number of sys clk cycles need to wait before sampling | |
254 | ||
255 | //============================================================= | |
256 | function integer CCU_clks_states::get_sys_clk_per(integer wait_cycs=0) { | |
257 | integer old_posedge; | |
258 | if (wait_cycs > 0) | |
259 | repeat (wait_cycs) @(posedge ccu_clk_port.$sys_clk); | |
260 | @(posedge ccu_clk_port.$sys_clk); | |
261 | old_posedge = get_time(LO); | |
262 | @(posedge ccu_clk_port.$sys_clk); | |
263 | get_sys_clk_per = get_time(LO) - old_posedge; | |
264 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("sys clk period at CCU input is %0d ticks", get_sys_clk_per)); | |
265 | } | |
266 | ||
267 | //============================================================= | |
268 | // WHAT: compute expected values for clk pkt | |
269 | //============================================================= | |
270 | function CCU_clk_packet CCU_clks_states::get_exp_clk_pkt() { | |
271 | string mode = "func"; // default is functional/mission mode | |
272 | ||
273 | if (this.pll_ctl[CCU__PLL_CTL__SERDES_DTM1__POS] == 1'b1 | |
274 | || this.pll_ctl[CCU__PLL_CTL__SERDES_DTM2__POS] == 1'b1) | |
275 | mode = "dtm"; | |
276 | ||
277 | case (mode) { | |
278 | "dtm" : get_exp_clk_pkt = get_expClkPkt_dtm_mode(); | |
279 | default : get_exp_clk_pkt = get_expClkPkt_func_mode(); | |
280 | } | |
281 | } | |
282 | ||
283 | //============================================================= | |
284 | // WHAT: compute expected values for clk pkt in functional/normal/mission mode | |
285 | //============================================================= | |
286 | function CCU_clk_packet CCU_clks_states::get_expClkPkt_func_mode() { | |
287 | CCU_clk_packet clk_pkt = new(); // create a separate copy | |
288 | bit [CCU__PLL_CTL__PLL_DIV1__SIZE-1:0] div1 = this.pll_ctl[CCU__PLL_CTL__PLL_DIV1__MSB : CCU__PLL_CTL__PLL_DIV1__POS]; // encoded values | |
289 | bit [CCU__PLL_CTL__PLL_DIV2__SIZE-1:0] div2 = this.pll_ctl[CCU__PLL_CTL__PLL_DIV2__MSB : CCU__PLL_CTL__PLL_DIV2__POS]; | |
290 | bit [CCU__PLL_CTL__PLL_DIV3__SIZE-1:0] div3 = this.pll_ctl[CCU__PLL_CTL__PLL_DIV3__MSB : CCU__PLL_CTL__PLL_DIV3__POS]; | |
291 | bit [CCU__PLL_CTL__PLL_DIV4__SIZE-1:0] div4 = this.pll_ctl[CCU__PLL_CTL__PLL_DIV4__MSB : CCU__PLL_CTL__PLL_DIV4__POS]; | |
292 | integer d1_eff, d2_eff, d3_eff; // effective values (ie. 2 means divided by 2, etc.) | |
293 | integer d4_int, d4_frac; // d4_int: integral part. d4_frac: fractional part (0 means 0.0 and 1 means 0.5) | |
294 | integer nom_4_min, nom_4_max; // nominal value for calculating min and max by rounding down or up | |
295 | ||
296 | //--- compute effective values of clk dividers--- | |
297 | d1_eff = div1 + 1; // warn: bit to integer conversion | |
298 | d2_eff = div2 + 1; | |
299 | d3_eff = div3 + 1; | |
300 | d4_int = div4[CCU__PLL_CTL__PLL_DIV4__SIZE-1:1]; // integral part | |
301 | d4_frac = div4[0]; // fractional part. 0 means 0.0 and 1 means 0.5 | |
302 | ||
303 | //---compute expected clk pkt---- | |
304 | clk_pkt.mode = CCU_FUNC_MODE; | |
305 | clk_pkt.pll_ctl = this.pll_ctl; | |
306 | clk_pkt.sys_clk_per = this.sys_clk_per; | |
307 | clk_pkt.cmp2io_ratio = 4; | |
308 | clk_pkt.cmp2io2x_ratio = 2; | |
309 | clk_pkt.cmp_mult = d2_eff / d1_eff; | |
310 | clk_pkt.cmp_mult_frac = (d2_eff % d1_eff)? 1'b1 : 1'b0; | |
311 | // note: dr_mult and dr_mult_frac are computed in DR section down below | |
312 | clk_pkt.cmp_per_dev = this.cmp_per_dev; | |
313 | clk_pkt.cmp_pw_dev = this.cmp_pw_dev; | |
314 | clk_pkt.dr_per_dev = this.dr_per_dev; | |
315 | clk_pkt.dr_pw_dev = this.dr_pw_dev; | |
316 | clk_pkt.iox_per_dev = this.iox_per_dev; | |
317 | clk_pkt.iox_pw_dev = this.iox_pw_dev; | |
318 | ||
319 | //---compute expected clk pkt: period/pulse_with/effective_multipler for cmp/io/io2x clk------ | |
320 | clk_pkt.cmp_clk_per_nom = (this.sys_clk_per * d1_eff) / d2_eff; | |
321 | nom_4_min = clk_pkt.cmp_clk_per_nom - 1; // rounding down | |
322 | nom_4_max = clk_pkt.cmp_clk_per_nom + 1; // rounding up | |
323 | clk_pkt.cmp_clk_per_min = nom_4_min - (((nom_4_max / 100) + 1) * this.cmp_per_dev); // rounding down | |
324 | clk_pkt.cmp_clk_per_max = nom_4_max + (((nom_4_max / 100) + 1) * this.cmp_per_dev); // rounding up | |
325 | ||
326 | clk_pkt.io_out_per_nom = (this.sys_clk_per * d1_eff * 4) / d2_eff; | |
327 | nom_4_min = clk_pkt.io_out_per_nom - 1; // rounding down | |
328 | nom_4_max = clk_pkt.io_out_per_nom + 1; // rounding up | |
329 | clk_pkt.io_out_per_min = nom_4_min - (((nom_4_max / 100) + 1) * this.iox_per_dev); // rouding down | |
330 | clk_pkt.io_out_per_max = nom_4_max + (((nom_4_max / 100) + 1) * this.iox_per_dev); // rouding up | |
331 | ||
332 | clk_pkt.io2x_out_per_nom = (this.sys_clk_per * d1_eff * 2) / d2_eff; | |
333 | nom_4_min = clk_pkt.io2x_out_per_nom - 1; // rounding down | |
334 | nom_4_max = clk_pkt.io2x_out_per_nom + 1; // rounding up | |
335 | clk_pkt.io2x_out_per_min = nom_4_min - (((nom_4_max / 100) + 1) * this.iox_per_dev); // rouding down | |
336 | clk_pkt.io2x_out_per_max = nom_4_max + (((nom_4_max / 100) + 1) * this.iox_per_dev); // rouding up | |
337 | ||
338 | //---compute expected clk pkt: period/pulse_with/effective_multipler for dr clk------ | |
339 | if ((div1 == 1) && (div3 == 1) && ((div2 + CCU__PLL_CTL__PLL_DIV2__SIZE'h1) == div4)) { // ie. div4 is 1/2 of div2 | |
340 | clk_pkt.dr_mult = 2; | |
341 | clk_pkt.dr_mult_frac = 1'b0; | |
342 | clk_pkt.dr_clk_per_nom = this.sys_clk_per / 2; // DR clk freq is twice sys clk freq | |
343 | nom_4_min = clk_pkt.dr_clk_per_nom - 1; // rounding down | |
344 | nom_4_max = clk_pkt.dr_clk_per_nom + 1; // rounding up | |
345 | clk_pkt.dr_clk_per_min = nom_4_min - (((nom_4_max / 100) + 1) * this.dr_per_dev); // rounding down | |
346 | clk_pkt.dr_clk_per_max = nom_4_max + (((nom_4_max / 100) + 1) * this.dr_per_dev); // rounding up | |
347 | //---compute dr sync locations at the cluster outputs --- | |
348 | case (d2_eff) { | |
349 | 8: { clk_pkt.dr_sync_loc[0] = 1; clk_pkt.dr_sync_loc[1] = 3; clk_pkt.dr_sync_loc[2] = 5; clk_pkt.dr_sync_loc[3] = 7; } | |
350 | 9: { clk_pkt.dr_sync_loc[0] = 1; clk_pkt.dr_sync_loc[1] = 3; clk_pkt.dr_sync_loc[2] = 6; clk_pkt.dr_sync_loc[3] = 8; } | |
351 | 10: { clk_pkt.dr_sync_loc[0] = 1; clk_pkt.dr_sync_loc[1] = 4; clk_pkt.dr_sync_loc[2] = 6; clk_pkt.dr_sync_loc[3] = 9; } | |
352 | 11: { clk_pkt.dr_sync_loc[0] = 1; clk_pkt.dr_sync_loc[1] = 4; clk_pkt.dr_sync_loc[2] = 7; clk_pkt.dr_sync_loc[3] = 10; } | |
353 | 12: { clk_pkt.dr_sync_loc[0] = 1; clk_pkt.dr_sync_loc[1] = 4; clk_pkt.dr_sync_loc[2] = 7; clk_pkt.dr_sync_loc[3] = 10; } | |
354 | 13: { clk_pkt.dr_sync_loc[0] = 2; clk_pkt.dr_sync_loc[1] = 5; clk_pkt.dr_sync_loc[2] = 8; clk_pkt.dr_sync_loc[3] = 11; } | |
355 | 14: { clk_pkt.dr_sync_loc[0] = 2; clk_pkt.dr_sync_loc[1] = 5; clk_pkt.dr_sync_loc[2] = 9; clk_pkt.dr_sync_loc[3] = 12; } | |
356 | 15: { clk_pkt.dr_sync_loc[0] = 2; clk_pkt.dr_sync_loc[1] = 6; clk_pkt.dr_sync_loc[2] = 9; clk_pkt.dr_sync_loc[3] = 13; } | |
357 | 16: { clk_pkt.dr_sync_loc[0] = 2; clk_pkt.dr_sync_loc[1] = 6; clk_pkt.dr_sync_loc[2] = 10; clk_pkt.dr_sync_loc[3] = 14; } | |
358 | 17: { clk_pkt.dr_sync_loc[0] = 2; clk_pkt.dr_sync_loc[1] = 6; clk_pkt.dr_sync_loc[2] = 11; clk_pkt.dr_sync_loc[3] = 15; } | |
359 | 18: { clk_pkt.dr_sync_loc[0] = 2; clk_pkt.dr_sync_loc[1] = 7; clk_pkt.dr_sync_loc[2] = 11; clk_pkt.dr_sync_loc[3] = 16; } | |
360 | 19: { clk_pkt.dr_sync_loc[0] = 2; clk_pkt.dr_sync_loc[1] = 7; clk_pkt.dr_sync_loc[2] = 12; clk_pkt.dr_sync_loc[3] = 17; } | |
361 | 20: { clk_pkt.dr_sync_loc[0] = 2; clk_pkt.dr_sync_loc[1] = 7; clk_pkt.dr_sync_loc[2] = 12; clk_pkt.dr_sync_loc[3] = 17; } | |
362 | 21: { clk_pkt.dr_sync_loc[0] = 3; clk_pkt.dr_sync_loc[1] = 8; clk_pkt.dr_sync_loc[2] = 13; clk_pkt.dr_sync_loc[3] = 18; } | |
363 | default: | |
364 | dbg.dispmon(this.dispScope, MON_ERR, psprintf("div2_eff=%0d <= no spec for dr_sync locations", d2_eff)); | |
365 | } | |
366 | } | |
367 | else { | |
368 | dbg.dispmon(this.dispScope, MON_ERR, psprintf("PLL_CTL: d1_eff=%0d, d2_eff=%0d, d3_eff=%0d, d4=0x%h <= illegal combinations\n", | |
369 | d1_eff, d2_eff, d3_eff, div4)); | |
370 | } | |
371 | get_expClkPkt_func_mode = clk_pkt; // return value | |
372 | } | |
373 | ||
374 | //============================================================= | |
375 | // WHAT: compute expected values for clk pkt in dtm mode | |
376 | // review: need to revise this task to better handling rounding effect of Vera integer division | |
377 | //============================================================= | |
378 | function CCU_clk_packet CCU_clks_states::get_expClkPkt_dtm_mode() { | |
379 | CCU_clk_packet clk_pkt = new(); // create a separate copy | |
380 | integer nom_4_min, nom_4_max; // nominal value for calculating min and max by rounding down or up | |
381 | ||
382 | if (! ((this.pll_ctl[CCU__PLL_CTL__PLL_DIV1__MSB : CCU__PLL_CTL__PLL_DIV1__POS] == 6'h0) | |
383 | && (this.pll_ctl[CCU__PLL_CTL__PLL_DIV3__MSB : CCU__PLL_CTL__PLL_DIV3__POS] == 6'h1) | |
384 | && ((this.pll_ctl[CCU__PLL_CTL__PLL_DIV2__MSB : CCU__PLL_CTL__PLL_DIV2__POS] == 6'h7) | |
385 | || (this.pll_ctl[CCU__PLL_CTL__PLL_DIV2__MSB : CCU__PLL_CTL__PLL_DIV2__POS] == 6'ha) | |
386 | || (this.pll_ctl[CCU__PLL_CTL__PLL_DIV2__MSB : CCU__PLL_CTL__PLL_DIV2__POS] == 6'he)))) { | |
387 | dbg.dispmon(this.dispScope, MON_ERR, psprintf("pll_ctl=0x%h <= values of div1, div2, div3 are illegal for dtm mode", this.pll_ctl)); | |
388 | get_expClkPkt_dtm_mode = clk_pkt; // just satisfy function return requirement | |
389 | return; | |
390 | } | |
391 | ||
392 | //---compute clk pkt--- | |
393 | clk_pkt.mode = CCU_DTM_MODE; | |
394 | clk_pkt.pll_ctl = this.pll_ctl; | |
395 | clk_pkt.sys_clk_per = this.sys_clk_per; | |
396 | clk_pkt.cmp2io_ratio = this.pll_ctl[CCU__PLL_CTL__PLL_DIV2__MSB : CCU__PLL_CTL__PLL_DIV2__POS] + 1; | |
397 | clk_pkt.cmp2io2x_ratio = this.pll_ctl[CCU__PLL_CTL__PLL_DIV2__MSB : CCU__PLL_CTL__PLL_DIV2__POS] + 1; | |
398 | clk_pkt.cmp_mult = this.pll_ctl[CCU__PLL_CTL__PLL_DIV2__MSB : CCU__PLL_CTL__PLL_DIV2__POS] + 1; | |
399 | clk_pkt.cmp_mult_frac = 0; | |
400 | clk_pkt.dr_mult = 1; | |
401 | clk_pkt.dr_mult_frac = 1'b0; | |
402 | clk_pkt.cmp_per_dev = this.cmp_per_dev; | |
403 | clk_pkt.cmp_pw_dev = this.cmp_pw_dev; | |
404 | clk_pkt.dr_per_dev = this.dr_per_dev; | |
405 | clk_pkt.dr_pw_dev = this.dtm_dr_iox_pw_dev; | |
406 | clk_pkt.iox_per_dev = this.iox_per_dev; | |
407 | clk_pkt.iox_pw_dev = this.dtm_dr_iox_pw_dev; | |
408 | ||
409 | clk_pkt.cmp_clk_per_nom = this.sys_clk_per / clk_pkt.cmp_mult; | |
410 | nom_4_min = clk_pkt.cmp_clk_per_nom - 1; // rounding down | |
411 | nom_4_max = clk_pkt.cmp_clk_per_nom + 1; // rounding up | |
412 | clk_pkt.cmp_clk_per_min = nom_4_min - (((nom_4_max / 100) + 1) * this.cmp_per_dev); // rounding down | |
413 | clk_pkt.cmp_clk_per_max = nom_4_max + (((nom_4_max / 100) + 1) * this.cmp_per_dev); // rounding up | |
414 | ||
415 | clk_pkt.dr_clk_per_nom = this.sys_clk_per; | |
416 | clk_pkt.dr_clk_per_min = clk_pkt.dr_clk_per_nom - (((clk_pkt.dr_clk_per_nom / 100) + 1) * this.dr_per_dev); // rounding down | |
417 | clk_pkt.dr_clk_per_max = clk_pkt.dr_clk_per_nom + (((clk_pkt.dr_clk_per_nom / 100) + 1) * this.dr_per_dev); // rounding up | |
418 | ||
419 | clk_pkt.io_out_per_nom = this.sys_clk_per; | |
420 | clk_pkt.io_out_per_min = clk_pkt.io_out_per_nom - (((clk_pkt.io_out_per_nom / 100) + 1) * this.cmp_per_dev); // rounding down | |
421 | clk_pkt.io_out_per_max = clk_pkt.io_out_per_nom + (((clk_pkt.io_out_per_nom / 100) + 1) * this.cmp_per_dev); // rounding up | |
422 | ||
423 | clk_pkt.io2x_out_per_nom = this.sys_clk_per; | |
424 | clk_pkt.io2x_out_per_min = clk_pkt.io2x_out_per_nom - (((clk_pkt.io2x_out_per_nom / 100) + 1) * this.cmp_per_dev); // rounding down | |
425 | clk_pkt.io2x_out_per_max = clk_pkt.io2x_out_per_nom + (((clk_pkt.io2x_out_per_nom / 100) + 1) * this.cmp_per_dev); // rounding up | |
426 | ||
427 | case (clk_pkt.cmp_mult) { | |
428 | 8: { clk_pkt.dr_sync_loc[0] = 0; clk_pkt.dr_sync_loc[1] = 0; clk_pkt.dr_sync_loc[2] = 0; clk_pkt.dr_sync_loc[3] = 0; } // review: not done | |
429 | 11: { clk_pkt.dr_sync_loc[0] = 0; clk_pkt.dr_sync_loc[1] = 0; clk_pkt.dr_sync_loc[2] = 0; clk_pkt.dr_sync_loc[3] = 0; } // review: not done | |
430 | 15: { clk_pkt.dr_sync_loc[0] = 0; clk_pkt.dr_sync_loc[1] = 0; clk_pkt.dr_sync_loc[2] = 0; clk_pkt.dr_sync_loc[3] = 0; } // review: not done | |
431 | default: | |
432 | dbg.dispmon(this.dispScope, MON_ERR, psprintf("get_expClkPkt_dtm_mode(): div2=0x%h <= bad value", | |
433 | this.pll_ctl[CCU__PLL_CTL__PLL_DIV2__MSB : CCU__PLL_CTL__PLL_DIV2__POS])); | |
434 | } | |
435 | get_expClkPkt_dtm_mode = clk_pkt; | |
436 | } | |
437 | ||
438 | //============================================================= | |
439 | // WHAT: print out clk pkt for info. | |
440 | // NOTE: it's ugly to put here, but we don't want 'class CCU_clk_packet' | |
441 | // requiring a StandardDisplay handle. | |
442 | //============================================================= | |
443 | task CCU_clks_states::show_clk_pkt(CCU_clk_packet pkt) { | |
444 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("----- info of %s -----", pkt.name)); | |
445 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- operational mode: %s", pkt.get_mode_name())); | |
446 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- sys_clk per: %0d ticks", pkt.sys_clk_per)); | |
447 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- PLL_CTL=0x%h", pkt.pll_ctl)); | |
448 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- PLL_CTL: div1=0x%h, div2=0x%h, div3=0x%h, div4=0x%h, serdes_dtm1=%b, serdes_dtm2=%b, change=%b", | |
449 | pkt.pll_ctl[CCU__PLL_CTL__PLL_DIV1__MSB : CCU__PLL_CTL__PLL_DIV1__POS], | |
450 | pkt.pll_ctl[CCU__PLL_CTL__PLL_DIV2__MSB : CCU__PLL_CTL__PLL_DIV2__POS], | |
451 | pkt.pll_ctl[CCU__PLL_CTL__PLL_DIV3__MSB : CCU__PLL_CTL__PLL_DIV3__POS], | |
452 | pkt.pll_ctl[CCU__PLL_CTL__PLL_DIV4__MSB : CCU__PLL_CTL__PLL_DIV4__POS], | |
453 | pkt.pll_ctl[CCU__PLL_CTL__SERDES_DTM1__POS], | |
454 | pkt.pll_ctl[CCU__PLL_CTL__SERDES_DTM2__POS], | |
455 | pkt.pll_ctl[CCU__PLL_CTL__CHANGE__POS])); | |
456 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- cmp-to-sys clk ratio : %0d.%0d", pkt.cmp_mult, (pkt.cmp_mult_frac)? 5 : 0)); | |
457 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- dr-to-sys clk ratio: dr_mult: %0d", pkt.dr_mult)); | |
458 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- cmp-to-IO clk ratio: %0d", pkt.cmp2io_ratio)); | |
459 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- cmp-to-IO2X clk ratio: %0d", pkt.cmp2io2x_ratio)); | |
460 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- cmp clk period deviation limit: %0d %%", pkt.cmp_per_dev)); | |
461 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- cmp clk pw deviation limit: %0d %%", pkt.cmp_pw_dev)); | |
462 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- iox clk period deviation limit: %0d %%", pkt.iox_per_dev)); | |
463 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- iox clk pw deviation limit: %0d %%", pkt.iox_pw_dev)); | |
464 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- dr clk period deviation limit: %0d %%", pkt.dr_per_dev)); | |
465 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- dr clk pw deviation limit: %0d %%", pkt.dr_pw_dev)); | |
466 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- cmp clk period: nom=%0d, min=%0d, max=%0d", pkt.cmp_clk_per_nom, pkt.cmp_clk_per_min, pkt.cmp_clk_per_max)); | |
467 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- dr clk period: nom=%0d, min=%0d, max=%0d", pkt.dr_clk_per_nom, pkt.dr_clk_per_min, pkt.dr_clk_per_max)); | |
468 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- io clk period: nom=%0d, min=%0d, max=%0d", pkt.io_out_per_nom, pkt.io_out_per_min, pkt.io_out_per_max)); | |
469 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- io2x clk period: nom=%0d, min=%0d, max=%0d", pkt.io2x_out_per_nom, pkt.io2x_out_per_min, pkt.io2x_out_per_max)); | |
470 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- DR sync locations at cluster header outputs: %0d, %0d, %0d and %0d", | |
471 | pkt.dr_sync_loc[0], pkt.dr_sync_loc[1], pkt.dr_sync_loc[2], pkt.dr_sync_loc[3])); | |
472 | dbg.dispmon(this.dispScope, MON_INFO, psprintf("- pllbypass mode: %0d, pllbypass_virtual_div2=0x%h, pllbypass_virtual_div4=0x%h", | |
473 | pllbypass_mode, pllbypass_virtual_div2, pllbypass_virtual_div4)); | |
474 | dbg.dispmon(this.dispScope, MON_INFO, "\n"); | |
475 | } | |
476 | ||
477 | //################################################################ | |
478 | //### subroutines to put/get local vars | |
479 | //################################################################ | |
480 | task CCU_clks_states::put_per_pw_dev(integer cmp_per_dev, integer cmp_pw_dev, | |
481 | integer iox_per_dev, integer iox_pw_dev, | |
482 | integer dr_per_dev, integer dr_pw_dev) { | |
483 | this.cmp_per_dev = cmp_per_dev; | |
484 | this.cmp_pw_dev = cmp_pw_dev; | |
485 | this.iox_per_dev = iox_per_dev; | |
486 | this.iox_pw_dev = iox_pw_dev; | |
487 | this.dr_per_dev = dr_per_dev; | |
488 | this.dr_pw_dev = dr_pw_dev; | |
489 | } | |
490 | ||
491 | ||
492 | ||
493 |