[dv, clk_rst_if] Improve jitter and add scaling - Cleanup existing code / comments - Replace `ifdef VERILATOR` with existing macros - Add support for randomly scaling the frequency on each edge with +- %tage over the initially set frequency - Improve jitter generation - use `$urandom` instead of `std::randomize`. - Fix jitter generation bug where the originally set clk hi and lo half periods get modified Signed-off-by: Srikrishna Iyer <sriyer@google.com>
diff --git a/hw/dv/sv/common_ifs/clk_rst_if.sv b/hw/dv/sv/common_ifs/clk_rst_if.sv index 60fe637..f984c0a 100644 --- a/hw/dv/sv/common_ifs/clk_rst_if.sv +++ b/hw/dv/sv/common_ifs/clk_rst_if.sv
@@ -26,23 +26,70 @@ import uvm_pkg::*; `endif - bit drive_clk; // enable clk generation - logic o_clk; // output clk + // Enables clock to be generated and driven by this interface. + bit drive_clk; - bit drive_rst_n; // enable rst_n generation - logic o_rst_n; // output rst_n + // The internal output clock value. + logic o_clk; - // clk params - bit clk_gate = 1'b0; // clk gate signal - int clk_period_ps = 20_000; // 50MHz default - real clk_freq_mhz = 50; // 50MHz default - int duty_cycle = 50; // 50% default - int max_jitter_ps = 1000; // 1ns default - bit recompute = 1'b1; // compute half periods when period/freq/duty are changed - int clk_hi_ps; // half period hi in ps - int clk_lo_ps; // half period lo in ps - int jitter_chance_pc = 0; // jitter chance in percentage on clock edge - disabled by default - bit sole_clock = 1'b0; // if true, this is the only clock in the system + // Enables the rst_n to be generated and driven by this interface. + bit drive_rst_n; + + // The internal output reset value. + logic o_rst_n; + + // Applies clock gating. + bit clk_gate = 1'b0; + + // The nominal (chosen) frequency (as period in ps) of the driven clock (50MHz by default). + int clk_period_ps = 20_000; + + // The variation of clock period (mimics uncalibrated clocks), to scale the nominal frequency + // down. If set to non-zero value, the clock frequency is scaled randomly on every edge. + int clk_freq_scaling_pc = 0; + + // The percentage chance of freq scaled down randomly on each edge. + int clk_freq_scaling_chance_pc = 50; + + // Clock frequency is scaled down. This enables the frequency to be randomly scaled up as well. + // + // Note: If set, the randomness of the clock frequency being scaled up or down may result in a + // bigger frequency distribution than the intended clk_freq_scaling_pc setting. For example, 50MHz + // with 10% scaling may result in pulses that are < 45MHz and > 55MHz wide as well. + bit clk_freq_scale_up = 1'b0; + + // The computed clock frequency in MHz. + real clk_freq_mhz = 50; + + // The duty cycle of the clock period as percentage. If jitter and scaling is applied, then the + // duty cycle will not be maintained. + int duty_cycle = 50; + + // Maximum jitter applied to each period of the clock - this is expected to be about 20% or less + // than the clock period. The computed jitter is added or subtracted to each edge. + // _________ + // _____:_| : : |_:_______ + // + // The actual jitter value is picked randomly within the window {[-max_jitter_ps:max_jitter_ps]} + // and is added to the time to next edge. + int max_jitter_ps = 1000; + + // The percentage chance of jitter occurring on each edge. If 0 (default value), then jitter is + // disabled altogether. If 100, jitter is computed and applied at every edge. + int jitter_chance_pc = 0; + + // Internal signal indicating the clock half periods need to be recomputed. + bit recompute = 1'b1; + + // Internal signal indicating the amount of time for which the clock stays high / lo in the next + // cycle. + int clk_hi_ps; + int clk_lo_ps; + real clk_hi_modified_ps; + real clk_lo_modified_ps; + + // If true, this is the only clock in the system; there is no need to add initial jitter. + bit sole_clock = 1'b0; // use IfName as a part of msgs to indicate which clk_rst_vif instance string msg_id = {"clk_rst_if::", IfName}; @@ -81,6 +128,22 @@ set_freq_khz(freq_mhz * 1000); endfunction + // Set the clk frequency scaling, chance in percentage and scaling up. + // + // freq_scaling_pc is a positive integer that determines by what amount (as percentage of the + // nominal frequency) is the frequency scaled (jittered) down. + // freq_scaling_chance_pc is a percentage number between 0 and 100 that determines how often is + // the scaling randomly recomputed and applied. + // freq_scale_up is a bit that enables the random scaling up of the frequency as well. + function automatic void set_freq_scaling(int freq_scaling_pc, int freq_scaling_chance_pc = 50, + bit freq_scale_up = 1'b0); + `DV_CHECK_FATAL(freq_scaling_pc >= 0, , msg_id) + `DV_CHECK_FATAL(freq_scaling_chance_pc inside {[0:100]}, , msg_id) + clk_freq_scaling_pc = freq_scaling_pc; + clk_freq_scaling_chance_pc = freq_scaling_chance_pc; + clk_freq_scale_up = freq_scale_up; + endfunction + // call this function at t=0 (from tb top) to enable clk and rst_n to be driven function automatic void set_active(bit drive_clk_val = 1'b1, bit drive_rst_n_val = 1'b1); time t = $time; @@ -89,11 +152,7 @@ drive_rst_n = drive_rst_n_val; end else begin -`ifdef VERILATOR - $error({msg_id, "this function can only be called at t=0"}); -`else - `uvm_fatal(msg_id, "this function can only be called at t=0") -`endif + `dv_fatal("This function can only be called at t=0", msg_id) end endfunction @@ -106,13 +165,7 @@ // set the duty cycle (1-99) function automatic void set_duty_cycle(int duty); - if (!(duty inside {[1:99]})) begin -`ifdef VERILATOR - $error({msg_id, $sformatf("duty cycle %0d is not inside [1:99]", duty)}); -`else - `uvm_fatal(msg_id, $sformatf("duty cycle %0d is not inside [1:99]", duty)) -`endif - end + `DV_CHECK_FATAL(duty inside {[1:99]}, , msg_id) duty_cycle = duty; recompute = 1'b1; endfunction @@ -125,13 +178,7 @@ // set jitter chance in percentage (0 - 100) // 0 - dont add any jitter; 100 - add jitter on every clock edge function automatic void set_jitter_chance_pc(int jitter_chance); - if (!(jitter_chance inside {[0:100]})) begin -`ifdef VERILATOR - $error({msg_id, $sformatf("jitter_chance %0d is not inside [0:100]", jitter_chance)}); -`else - `uvm_fatal(msg_id, $sformatf("jitter_chance %0d is not inside [0:100]", jitter_chance)) -`endif - end + `DV_CHECK_FATAL(jitter_chance inside {[0:100]}, , msg_id) jitter_chance_pc = jitter_chance; endfunction @@ -153,22 +200,30 @@ clk_gate = 1'b1; endfunction - // add jitter to clk_hi and clk_lo half periods based on jitter_chance_pc - function automatic void add_jitter(); - int jitter_ps; + // Scales the clock frequency up and down on every edge. + function automatic void apply_freq_scaling(); + real scaling; + real mult = $urandom_range(0, clk_freq_scale_up) ? 1.0 : -1.0; + + if ($urandom_range(1, 100) <= clk_freq_scaling_chance_pc) begin + scaling = 1.0 + mult * real'($urandom_range(0, clk_freq_scaling_pc)) / 100; + clk_hi_modified_ps = clk_hi_ps * scaling; + scaling = 1.0 + mult * real'($urandom_range(0, clk_freq_scaling_pc)) / 100; + clk_lo_modified_ps = clk_lo_ps * scaling; + end + endfunction + + // Applies jitter to clk_hi and clk_lo half periods based on jitter_chance_pc. + function automatic void apply_jitter(); + int jitter; + if ($urandom_range(1, 100) <= jitter_chance_pc) begin -`ifndef VERILATOR - `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(jitter_ps, - jitter_ps inside {[-1*max_jitter_ps:max_jitter_ps]};, "", msg_id) -`endif - clk_hi_ps += jitter_ps; + jitter = ($urandom_range(0, 1) ? 1 : -1) * $urandom_range(0, max_jitter_ps); + clk_hi_modified_ps = clk_hi_ps + jitter; end if ($urandom_range(1, 100) <= jitter_chance_pc) begin -`ifndef VERILATOR - `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(jitter_ps, - jitter_ps inside {[-1*max_jitter_ps:max_jitter_ps]};, "", msg_id) -`endif - clk_lo_ps += jitter_ps; + jitter = ($urandom_range(0, 1) ? 1 : -1) * $urandom_range(0, max_jitter_ps); + clk_lo_modified_ps = clk_lo_ps + jitter; end endfunction @@ -215,11 +270,7 @@ o_rst_n <= 1'b1; end default: begin -`ifdef VERILATOR - $error({msg_id, $sformatf("rst_n_scheme %0d not supported", rst_n_scheme)}); -`else - `uvm_fatal(msg_id, $sformatf("rst_n_scheme %0d not supported", rst_n_scheme)) -`endif + `dv_fatal($sformatf("rst_n_scheme %0d not supported", rst_n_scheme), msg_id) end endcase wait_clks(post_reset_dly_clks); @@ -252,13 +303,15 @@ if (recompute) begin clk_hi_ps = clk_period_ps * duty_cycle / 100; clk_lo_ps = clk_period_ps - clk_hi_ps; + clk_hi_modified_ps = clk_hi_ps; + clk_lo_modified_ps = clk_lo_ps; recompute = 1'b0; end - if (jitter_chance_pc != 0) add_jitter(); - #(clk_lo_ps * 1ps); - // wiggle output clk if not gated + if (clk_freq_scaling_pc && clk_freq_scaling_chance_pc) apply_freq_scaling(); + if (jitter_chance_pc) apply_jitter(); + #(clk_lo_modified_ps * 1ps); if (!clk_gate) o_clk = 1'b1; - #(clk_hi_ps * 1ps); + #(clk_hi_modified_ps * 1ps); o_clk = 1'b0; end end