La aletaorización corre a cargo de la llamada al método predefinido “randomize” a cualquier objeto del tipo definido por la clase.
Definir un objeto, requiere el uso de la declaración del objeto y de la instanciación.
1 2 |
Bus P; //declarar: generar un identificador a un objeto de tipo Bus – inicializado en null P=new; //instanciar: asignar el espacio para el objeto y ejecutar automáticamente la función new() en la clase para la inicialización |
- Evidentemente para poder hacer esto la clase que se referencia debe de ser visible
- Evidentemente ambas acciones (declarar e instanciar) se pueden hacer en una única línea: Bus P =new;
- La función new() es el contructor – sin valor de retorno. El constructor se puede omitir en la clase: en este caso, se asigna el espacio para el nuevo objeto y se conservan los valores iniciales de las propiedades.
- new() puede tomar argumentos:
1 2 3 |
function new(bit [40:0] a); addr = a; endfunction |
Llegado a este punto supongamos que quiero aleatorizar . Bastaría, si ya tenemos el objeto construido , en llamar el método «randomize» . En el siguiente ejemplo mostramos la construcción y la realización de dos randomizaciones:
1 2 3 4 5 6 7 8 9 10 11 12 |
initial begin Bus busInst; busInst = new; // now busInt.addr and busInst.data are both zeroes if (!busInst.randomize()) begin $display(“randomization failed”); $finish(); end // now bustInst.addr and busInst.data have random values that satisfy the constraints assert (busInst.randomize()) else $fatal(“randomization failed”); // now bustInst.addr and busInst.data have other random values that satisfy the constraints end |
Cada vez que aleatorizamos una clase, se selecciona aleatoriamente una entre todas las combinaciones posibles de todas las variables aleatorias que satisfacen todas las restricciones que hemos colocado. En el caso de que no haya ninguna combinación posible, la función randomize dará un «0»
Acciones adicionales en el método randomize
Añadir más restricciones
Se realiza con la palabra reservada «with»
1 |
res = bus.randomize() with {addr[0] || addr[1];}; |
Se puede observar que al randomizar indicamos una restricción adicional expresada entre las llaves. Además de todas las restricciones dadas en la clase, para sólo esta aleatorización agregamos la restricción que addr[0] o addr[1] debe ser 1.
Cambiar el carácter de las variables
- Las clases pueden tener miembros rand y no-rand
- al aleatorizar una clase, aleatorizamos solo las variables aleatorias, los no aleatorios mantienen sus valores
- Las restricciones pueden mezclar en sus expresiones variables rand y no rand
Veamos un ejemplo
1 2 3 4 5 6 |
class B; rand bit a, b; bit c, d; constraint c1 { d -> b;}; constraint c2 { a & b == c;}; endclass |
Cuando llamámos al método randomize podemos cambiar el caracter de dichas variables
- inst.randomize(a) : poniendo como argumento la variable a indicamos que solo esta variable va a ser considerada como randomizable. La variable b será considerada como variable estática.
- inst.randomize(a,c): El efecto sobre a y b es el mismo del ejemplo anterior; sin embargo la variable c que era estática, pasa a ser ahora en esta randomización como variable.
Métodos adicionales
constraint_mode
Veamos el siguiente ejemplo. Como puede observarse podemos inhabilitar antes de cada llamada a randomize las restricciones que deseemos con tan solo llamar el método constraint_mode asociadas a dicha restricción y poniendo como argumento un cero.
Cuando deseemos podremos volver a habilitar la restricción con el mismo método asociada a la misma y con un argumento uno.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class Bus; rand bit[15:0] addr; rand bit[31:0] data; constraint word_align {addr[1:0] == 2’b0;} constraint addr_data_dep {addr==0 -> data==0;} endclass initial begin Bus bus; bus = new; bus.randomize(); // turn off the word_align constraint bus.word_align.constraint_mode(0); bus.randomize(); bus.randomize() with {addr[0]==1;}; // turn on the word_align constraint bus.word_align.constraint_mode(1); bus.randomize(); |
rand_mode
Tomando como ejemplo el código anterior en el que tenemos dos variables aleatorizables : addr y data Después de esta declaración: bus.addr.rand_mode(0);
«addr” dentro del objeto “bus” se considera como una variable no-rand(no aleatorizado cuando realizamos el randomize())
Para volver a su situación rand, usamos: bus.addr.rand_mode(1);
pre_randomize y post_randomize
En nuestra clase podemos definir unas funciones pre_randomize y post_randomize. Veamos el siguiente ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
program ordering; class frame_t; rand bit zero; rand bit [15:0] data []; constraint frame_sizes { solve zero before data.size; zero -> data.size == 0; data.size inside {[0:10]}; foreach (data[i]) data[i] == i; } function void pre_randomize(); begin assert (zero==1'b0) else $display("zero estaba activo"); end endfunction function void post_randomize(); begin assert (zero==1'b0) else $display("zero esta activo"); $display("length : %0d", data.size()); for (integer i = 0; i < data.size(); i++) begin $write ("%2x ",data[i]); end $write("\n"); end endfunction endclass initial begin frame_t frame = new(); integer i,j = 0; for (j=0;j < 10; j++) begin $write("-------------------------------\n"); $write("Randomize Value\n"); i = frame.randomize(); end $write("-------------------------------\n"); end endprogram |
Dichos métodos serán ejecutados automáticamente (sin necesidad de llamarlos explícitamente) justo antes y después de que tenga lugar la aleatorización al llamar randomize()
el flujo de ejecución será el siguiente:
- frame.pre_randomize();
- frame is randomized
- frame.post_randomize();
Veamos el funcionamiento en el siguiente laboratorio virtual

randcase
A veces lo que deseamos aleatorizar mediante el «solver» es la ejecución de un determinada rutina u otra en función de unos pesos que indiquen la probabilidad de las mismas. Eso lo realizaremos mediante «randcase«. Veamos el siguiente ejemplo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
while (driver.sb.size>0) //empiezo a vaciar fork begin fork randcase 10: driver.genPop_rand(); 5: driver.genPush_rand(); endcase randcase 10: driver.genPop_rand(); 6: driver.genPush_rand(); endcase join_any $display("la fifo tiene %d palabras", driver.sb.size); $display("Instance coverage is %e", driver.COV_entradas.get_coverage()); disable fork; end join |
Podemos observar en el «fork join_any» central que realizamos dos operaciones concurrentes representadas cada una de ellas con un randcase. Estas operaciones concurrentes tienen una mayor probabilidad de ser operaciones de lectura (en este caso de una FIFO) que de escritura. Si ambos procesos concurrentes coinciden con la misma rutina, ésta se realiza una única vez. Si la rutina es diferente se realizarán ambas (lo cual permitiría lectura y escritura simultánea de la FIFO).
Con esta estructura podemos lograr un vaciado progresivo random de la FIFO, sin impedir que puedan haber escrituras o escrituras y lecturas simultáneas.