blob: 583ae84e5b92dac53767d1039dcbd3ee9796f989 [file] [log] [blame]
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -07001// Copyright lowRISC contributors.
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5// This module should be instantiated within flops of CDC synchronization primitives,
6// and allows DV to model real CDC delays within simulations, especially useful at the chip level
7// or in IPs that communicate across clock domains.
8//
9// If not, delay randomization is enabled - the faster of the two clocks is used to latch src_data,
10// dst_data is synchronously driven with a random combination of the current src_data and
11// the delayed version of src_data.
12//
13// If a source clock isn't used, the input src_data is latched after a parameterizable latency
14// as `src_data_with_latency`, and an internal version of the output data `src_data_delayed` is set
15// to this same value after a parameterizable jitter period.
16//
17// This is meant to model skew between synchronizer bits and wire delay between the src and dst
18// flops.
19//
Srikrishna Iyer43a24e62022-04-07 00:37:07 -070020// Four different random delay modes are available:
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -070021//
Srikrishna Iyer43a24e62022-04-07 00:37:07 -070022// - RandDelayDisable: If this delay mode is picked, this module acts as a passthrough.
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -070023//
Srikrishna Iyer43a24e62022-04-07 00:37:07 -070024// - RandDelaySlow: If this delay mode is picked, the output to the dst domain is
25// continuously driven to `src_data_delayed`.
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -070026//
Srikrishna Iyer43a24e62022-04-07 00:37:07 -070027// - RandDelayOnce: If this delay mode is picked, the mask `out_data_mask` used to combine
28// `src_data_with_latency` and `src_data_delayed` is randomized once at the
29// start of the simulation.
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -070030//
Srikrishna Iyer43a24e62022-04-07 00:37:07 -070031// - RandDelayInterval: If this delay mode is picked, the mask `out_data_mask` used to
32// combine `src_data_with_latency` and `src_data_delayed` is fully
33// randomized every `prim_cdc_rand_delay_interval` times the src_data
34// value changes. If the `prim_cdc_rand_delay_interval` is set to 0,
35// then out_data_mask is randomized on every src_data change.
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -070036//
37// DV has control of the weights corresponding to each random delay mode when the delay mode is
38// randomized, but can also directly override the delay mode as desired.
39//
40// DV also has control over whether the source clock is used, the latency, and the jitter values -
41// these can be modified through the provided setter tasks.
42
43module prim_cdc_rand_delay #(
44 parameter int DataWidth = 1,
45 parameter bit UseSourceClock = 1,
Srikrishna Iyer43a24e62022-04-07 00:37:07 -070046 parameter int LatencyPs = 1000,
47 parameter int JitterPs = 1000
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -070048) (
49 input logic src_clk,
50 input logic [DataWidth-1:0] src_data,
51
52 input logic dst_clk,
53 output logic [DataWidth-1:0] dst_data
54);
55
Srikrishna Iyer43a24e62022-04-07 00:37:07 -070056 `ASSERT_INIT(LegalDataWidth_A, DataWidth > 0)
57 `ASSERT_INIT(LegalLatencyPs_A, LatencyPs >= 0)
58 `ASSERT_INIT(LegalJitterPs_A, JitterPs >= 0)
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -070059
Srikrishna Iyer43a24e62022-04-07 00:37:07 -070060`ifdef SIMULATION
61`ifndef DISABLE_PRIM_CDC_RAND_DELAY
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -070062
Timothy Chen4545d522022-04-18 11:28:28 -070063 // macro includes
64 `include "uvm_macros.svh"
65 `include "dv_macros.svh"
66
Srikrishna Iyer43a24e62022-04-07 00:37:07 -070067 typedef enum bit [1:0] {
68 RandDelayModeDisable,
69 RandDelayModeSlow,
70 RandDelayModeOnce,
71 RandDelayModeInterval
72 } rand_delay_mode_e;
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -070073
Srikrishna Iyer43a24e62022-04-07 00:37:07 -070074 rand_delay_mode_e prim_cdc_rand_delay_mode;
75 int unsigned prim_cdc_rand_delay_interval = 10;
76 int unsigned prim_cdc_rand_delay_disable_weight = 1;
77 int unsigned prim_cdc_rand_delay_slow_weight = 2;
78 int unsigned prim_cdc_rand_delay_once_weight = 4;
79 int unsigned prim_cdc_rand_delay_interval_weight = 3;
80 bit [3:0] mode; // onehot encoded version of prim_cdc_rand_delay_mode.
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -070081
Srikrishna Iyer43a24e62022-04-07 00:37:07 -070082 int unsigned prim_cdc_jitter_ps = JitterPs;
83 int unsigned prim_cdc_latency_ps = LatencyPs;
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -070084
85 logic [DataWidth-1:0] out_data_mask;
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -070086 logic [DataWidth-1:0] src_data_with_latency;
87 logic [DataWidth-1:0] src_data_delayed;
88
Srikrishna Iyer43a24e62022-04-07 00:37:07 -070089 function automatic void set_prim_cdc_rand_delay_mode(int val);
90 prim_cdc_rand_delay_mode = rand_delay_mode_e'(val);
91 update_settings();
92 endfunction
93
94 function automatic void set_prim_cdc_rand_delay_interval(int unsigned val);
95 prim_cdc_rand_delay_interval = val;
96 endfunction
97
98 function automatic void set_prim_cdc_jitter_ps(int val);
99 `ASSERT_I(LegalJitter_A, prim_cdc_jitter_ps >= 0)
100 prim_cdc_jitter_ps = val;
101 endfunction
102
103 function automatic void set_prim_cdc_latency_ps(int val);
104 `ASSERT_I(LegalLatencyPs_A, val >= 0)
105 prim_cdc_latency_ps = val;
106 endfunction
107
108 // Internal method called after prim_cdc_rand_delay_mode is set.
109 function automatic void update_settings();
110 mode = '0;
111 mode[prim_cdc_rand_delay_mode] = 1'b1;
112 if (prim_cdc_rand_delay_mode == RandDelayModeSlow) out_data_mask = '1;
113 if (prim_cdc_rand_delay_mode == RandDelayModeOnce) fast_randomize(out_data_mask);
114 endfunction
115
116 // A slightly more performant version of std::randomize(), using $urandom.
117 //
118 // Empirically, using std::randomize() has been found to be slower than $urandom, since the latter
119 // operates on a fixed data width of 32-bits. There may be an incredibly large number of instances
Timothy Chen8111eb22022-04-11 11:07:37 -0700120 // of this module in the DUT, causing this preformance hit to be noticeable. This method
121 // randomizes the data piece-wise, 32-bits at a time using $urandom instead.
Srikrishna Iyer43a24e62022-04-07 00:37:07 -0700122 function automatic void fast_randomize(output logic [DataWidth-1:0] data);
123 for (int i = 0; i < DataWidth; i += 32) data = (data << 32) | $urandom();
124 endfunction
125
126 // Retrieves settings via plusargs.
127 //
128 // prefix is a string prefix to retrieve the plusarg.
129 // Returns 1 if prim_cdc_rand_delay_mode was set, else 0.
130 function automatic bit get_plusargs(string prefix = "");
131 string mode = "";
132 int unsigned val;
133 if (prefix != "") prefix = {prefix, "."};
134 void'($value$plusargs({prefix, "prim_cdc_rand_delay_mode=%0s"}, mode));
135 `ASSERT_I(ValidMode_A, mode inside {"", "disable", "slow", "once", "interval"})
136 void'($value$plusargs({prefix, "prim_cdc_rand_delay_interval=%0d"},
137 prim_cdc_rand_delay_interval));
138 void'($value$plusargs({prefix, "prim_cdc_rand_delay_disable_weight=%0d"},
139 prim_cdc_rand_delay_disable_weight));
140 void'($value$plusargs({prefix, "prim_cdc_rand_delay_slow_weight=%0d"},
141 prim_cdc_rand_delay_slow_weight));
142 void'($value$plusargs({prefix, "prim_cdc_rand_delay_once_weight=%0d"},
143 prim_cdc_rand_delay_once_weight));
144 void'($value$plusargs({prefix, "prim_cdc_rand_delay_interval_weight=%0d"},
145 prim_cdc_rand_delay_interval_weight));
146 void'($value$plusargs({prefix, "prim_cdc_jitter_ps=%0d"}, prim_cdc_jitter_ps));
147 void'($value$plusargs({prefix, "prim_cdc_latency_ps=%0d"}, prim_cdc_latency_ps));
148
149 case (mode)
150 "disable": prim_cdc_rand_delay_mode = RandDelayModeDisable;
151 "slow": prim_cdc_rand_delay_mode = RandDelayModeSlow;
152 "once": prim_cdc_rand_delay_mode = RandDelayModeOnce;
153 "interval": prim_cdc_rand_delay_mode = RandDelayModeInterval;
154 default: return 0;
155 endcase
156 return 1;
157 endfunction
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -0700158
159 initial begin
Srikrishna Iyer43a24e62022-04-07 00:37:07 -0700160 bit res;
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -0700161
Srikrishna Iyer43a24e62022-04-07 00:37:07 -0700162 // Command-line override via plusargs (global, applies to ALL instances).
163 // Example: +prim_cdc_rand_delay_mode=once
164 res = get_plusargs();
165
166 // Command-line override via plusargs (instance-specific).
167 // Example: +tb.dut.u_foo.u_bar.u_flop_2sync.u_prim_cdc_rand_delay.prim_cdc_latency_ps=200
168 res |= get_plusargs($sformatf("%m"));
169
170 if (!res) begin
171 `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(prim_cdc_rand_delay_mode,
172 prim_cdc_rand_delay_mode dist {
173 RandDelayModeDisable :/ prim_cdc_rand_delay_disable_weight,
174 RandDelayModeSlow :/ prim_cdc_rand_delay_slow_weight,
175 RandDelayModeOnce :/ prim_cdc_rand_delay_once_weight,
176 RandDelayModeInterval :/ prim_cdc_rand_delay_interval_weight
177 };,
178 , $sformatf("%m"))
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -0700179 end
Srikrishna Iyer43a24e62022-04-07 00:37:07 -0700180 update_settings();
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -0700181 end
182
183 // TODO: Run some performance experiments using this implementation versus an implementation that
Srikrishna Iyer43a24e62022-04-07 00:37:07 -0700184 // primarily uses `forever` blocks rather than RTL constructs. Need to also check if this
185 // alternate implementation is still valid when compiling/simulating the design.
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -0700186 if (UseSourceClock) begin : gen_use_source_clock
Srikrishna Iyer43a24e62022-04-07 00:37:07 -0700187
188 // If relying on src_clk, insert a delay on the faster clock.
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -0700189 always_ff @(posedge src_clk or posedge dst_clk) begin
190 src_data_delayed <= src_data;
191 end
192 assign src_data_with_latency = src_data;
Srikrishna Iyer43a24e62022-04-07 00:37:07 -0700193
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -0700194 end else begin : gen_no_use_source_clock
Srikrishna Iyer43a24e62022-04-07 00:37:07 -0700195
196 // If not relying on src_clk, delay by a fixed number of ps determined by the module parameters.
197 always @(src_data) begin
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -0700198 src_data_with_latency <= #(prim_cdc_latency_ps * 1ps) src_data;
199 end
Srikrishna Iyer43a24e62022-04-07 00:37:07 -0700200 always @(src_data_with_latency) begin
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -0700201 src_data_delayed <= #(prim_cdc_jitter_ps * 1ps) src_data_with_latency;
202 end
Srikrishna Iyer43a24e62022-04-07 00:37:07 -0700203
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -0700204 end : gen_no_use_source_clock
205
Srikrishna Iyer43a24e62022-04-07 00:37:07 -0700206 // Randomize delayed random data selection when input data changes, every
207 // prim_cdc_rand_delay_interval number of changes.
208 int counter = 0;
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -0700209 always @(src_data_with_latency) begin
Srikrishna Iyer43a24e62022-04-07 00:37:07 -0700210 if (mode[RandDelayModeInterval]) begin
211 counter <= (counter >= prim_cdc_rand_delay_interval) ? '0 : counter + 1;
212 if (counter == prim_cdc_rand_delay_interval) fast_randomize(out_data_mask);
213 end else begin
214 counter <= 0;
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -0700215 end
216 end
217
Srikrishna Iyer43a24e62022-04-07 00:37:07 -0700218 assign dst_data = mode[RandDelayModeDisable] ? src_data :
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -0700219 ((src_data_delayed & out_data_mask) | (src_data_with_latency & ~out_data_mask));
220
Srikrishna Iyer43a24e62022-04-07 00:37:07 -0700221`else
222
223 // Direct pass through.
224 assign dst_data = src_data;
225
226`endif // DISABLE_PRIM_CDC_RAND_DELAY
227
228`else
229
230 // Direct pass through.
231 assign dst_data = src_data;
232
233`endif // SIMULATION
234
Udi Jonnalagadda9e78b5e2021-08-17 20:01:56 -0700235 //TODO: coverage
236
237endmodule