Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 1 | // 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 Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 20 | // Four different random delay modes are available: |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 21 | // |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 22 | // - RandDelayDisable: If this delay mode is picked, this module acts as a passthrough. |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 23 | // |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 24 | // - RandDelaySlow: If this delay mode is picked, the output to the dst domain is |
| 25 | // continuously driven to `src_data_delayed`. |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 26 | // |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 27 | // - 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 Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 30 | // |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 31 | // - 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 Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 36 | // |
| 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 | |
| 43 | module prim_cdc_rand_delay #( |
| 44 | parameter int DataWidth = 1, |
| 45 | parameter bit UseSourceClock = 1, |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 46 | parameter int LatencyPs = 1000, |
| 47 | parameter int JitterPs = 1000 |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 48 | ) ( |
| 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 Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 56 | `ASSERT_INIT(LegalDataWidth_A, DataWidth > 0) |
| 57 | `ASSERT_INIT(LegalLatencyPs_A, LatencyPs >= 0) |
| 58 | `ASSERT_INIT(LegalJitterPs_A, JitterPs >= 0) |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 59 | |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 60 | `ifdef SIMULATION |
| 61 | `ifndef DISABLE_PRIM_CDC_RAND_DELAY |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 62 | |
Timothy Chen | 4545d52 | 2022-04-18 11:28:28 -0700 | [diff] [blame] | 63 | // macro includes |
| 64 | `include "uvm_macros.svh" |
| 65 | `include "dv_macros.svh" |
| 66 | |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 67 | typedef enum bit [1:0] { |
| 68 | RandDelayModeDisable, |
| 69 | RandDelayModeSlow, |
| 70 | RandDelayModeOnce, |
| 71 | RandDelayModeInterval |
| 72 | } rand_delay_mode_e; |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 73 | |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 74 | 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 Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 81 | |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 82 | int unsigned prim_cdc_jitter_ps = JitterPs; |
| 83 | int unsigned prim_cdc_latency_ps = LatencyPs; |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 84 | |
| 85 | logic [DataWidth-1:0] out_data_mask; |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 86 | logic [DataWidth-1:0] src_data_with_latency; |
| 87 | logic [DataWidth-1:0] src_data_delayed; |
| 88 | |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 89 | 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 Chen | 8111eb2 | 2022-04-11 11:07:37 -0700 | [diff] [blame] | 120 | // 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 Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 122 | 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 Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 158 | |
| 159 | initial begin |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 160 | bit res; |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 161 | |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 162 | // 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 Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 179 | end |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 180 | update_settings(); |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 181 | end |
| 182 | |
| 183 | // TODO: Run some performance experiments using this implementation versus an implementation that |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 184 | // 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 Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 186 | if (UseSourceClock) begin : gen_use_source_clock |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 187 | |
| 188 | // If relying on src_clk, insert a delay on the faster clock. |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 189 | 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 Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 193 | |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 194 | end else begin : gen_no_use_source_clock |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 195 | |
| 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 Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 198 | src_data_with_latency <= #(prim_cdc_latency_ps * 1ps) src_data; |
| 199 | end |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 200 | always @(src_data_with_latency) begin |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 201 | src_data_delayed <= #(prim_cdc_jitter_ps * 1ps) src_data_with_latency; |
| 202 | end |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 203 | |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 204 | end : gen_no_use_source_clock |
| 205 | |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 206 | // Randomize delayed random data selection when input data changes, every |
| 207 | // prim_cdc_rand_delay_interval number of changes. |
| 208 | int counter = 0; |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 209 | always @(src_data_with_latency) begin |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 210 | 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 Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 215 | end |
| 216 | end |
| 217 | |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 218 | assign dst_data = mode[RandDelayModeDisable] ? src_data : |
Udi Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 219 | ((src_data_delayed & out_data_mask) | (src_data_with_latency & ~out_data_mask)); |
| 220 | |
Srikrishna Iyer | 43a24e6 | 2022-04-07 00:37:07 -0700 | [diff] [blame] | 221 | `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 Jonnalagadda | 9e78b5e | 2021-08-17 20:01:56 -0700 | [diff] [blame] | 235 | //TODO: coverage |
| 236 | |
| 237 | endmodule |