SystemVerilog for Verification: A Guide to Learning the Testbench Language Features

Sometimes you need to perform an action immediately before every randomize call or immediately afterwards. For example, you may want to set some nonrandom class variables (such as limits) before randomization starts, or you may need to calculate the error correction bits for random data.
SystemVerilog lets you do this with two special void functions, pre_randomize and post_randomize. Section 3.3 showed that a void function does not return a value, but, because it is not a task, does not consume time. If you want to call a debug routine from p re_randomize or post_randomize, it must be a function.
For some applications, you want a nonlinear random distribution. For instance, small and large packets are more likely to find a design bug such as buffer overflow than medium-sized packets. So you want a bathtub shaped distribution; high on both ends, and low in the middle. You could build an elaborate dist constraint, but it might require lots of tweaking to get the shape you want. Verilog has several functions for nonlinear distribution such as $dist_exponential but none for a bathtub. However, you can build one by using the exponential function twice.
class Bathtub; int value; // Random variable with bathtub dist int WIDTH = 50, DEPTH=4, seed=1; function void pre_randomize(); // Calculate the left curve...