Uso de Randomização em System Verilog

Em projetos digiatis complexos, testes direcionados isoladamente não conseguem cobrir toda a lógica do código. Por isso, adota-se a técnica de teste aleatório com restrições (Constrained Random Test) para gerar automaticamente conjuntos de teste não direcionados.

  1. Sintaxe de Restrições (Constraints)

2.1 Expressões de Restrição

Apenas variáveis compostas por bits (inteiros, vetores de bits) podem ser randomizadas; strings não são suportadas. A randomização de variáveis envolve três etapas: declaração com rand ou randc, definição de restrições com a palavra-chave constraint e chamada da função randomize(). Diferenças entre rand e randc:

  • rand: a cada randomização a variável gera um valor, podendo repetir valores entre execuções consecutivas.
  • randc: periodicidaed cíclica; o valor só se repete depois que todos os valores possíveis tiverem sido gerados.

Exemplo de expressão de restrição (verifique sempre o resultado da randomização – uma falha pode gerar valores desconhecidos):

class pacote;
    rand logic [3:0] src, dst;  
    randc logic [9:0] dados;
    constraint cons_src {
             src > 0;
             src < 10;
             dst > 0;
    }
    constraint cons_randc {
             dados > 100;
    }
endclass

module test_tb;
    pacote p;
    initial begin
        p = new();
        assert(p.randomize()); // retorna 1 se ok, 0 se falha
    end
endmodule

Operações matemáticas também podem ser usadas:

class pacote;
    rand logic [9:0] addr;  
    rand logic [4:0] odd_dat, even_dat;
    constraint cons_addr {
        addr % 8 == 0;
    }
    constraint cons_dat {
        odd_dat % 2 == 1;
        even_dat % 2 == 0;
    }
endclass

2.2 Restrições com Pesos (Weight Constraints)

O operador dist gera valores aleatórios com pesos diferentes. A sintaxe usa := ou :/:

  • := – cada valor dentro do intervalo tem o mesmo peso.
  • :/ – o peso total é distribuído igualmente entre os valores do intervalo.

A soma dos pesos não precisa ser 100. O operador inside gera valores com pesos iguais. Exemplo:

class pacote;
    rand logic [4:0] src, dst;
    rand logic [9:0] addr;
    constraint cons_src {
        src dist {0:=40, [1:3]:=60};
        // src=0: 40/220; src=1,2,3: cada um 60/220
    }
    constraint cons_dst {
        dst dist {0:/40, [1:3]:/60};
        // dst=0: 40/100; dst=1,2,3: cada um 20/100
    }
    constraint cons_addr {
        addr inside {[$:10],[100:$]}; // $ representa máximo/mínimo
    }
endclass

2.3 Restrições Condicionais

Os operadores -> e if-else ativam restrições apenas quando certas condições são verdadeiras:

class pacote;
    bit en;
    rand logic [1:0] src, dst;
    rand logic [1:0] addr;

    constraint cons_src_dst {
        (src==0) -> dst==0; // se src=0, dst só pode ser 0
    }
    constraint cons_addr {
        if (en != 0) {
          src inside {[1:3]}; // en != 0: src entre 1 e 3
          dst inside {[1:3]};
        }
        else {
            src == 0;
            dst == 0;
        }   
    }

O uso de solve...before guia a distribuição de probabilidade (válido apenas para rand):

class pacote;
    rand bit x;
    rand logic [1:0] y;

    constraint cons_rand {
        (x==0) -> y==3; 
    }
    constraint cons_xy {
        (x==0) -> y==3; 
        solve x before y; // x é escolhido primeiro, depois y
    }
endclass

Sem solve before: 5 combinações equiprováveis (x=0,y=3; x=1,y=0..3). Com solve before: x tem 50% cada, e dentro de cada x a distribuição de y é uniforme (y=3 quando x=0; y=0..3 com 25% cada quando x=1).

2.4 Restrições Bidirecionais

Múltiplas variáveis podem ser restritas mutuamente:

class pacote;
    rand logic [4:0] x, y, z;
    constraint cons_xyz {
        x < y;
        y > 5;
        z < x;
        x > 1;
    }
endclass

2.5 Restrições Embutidas (Inline Constraints)

Usando randomize() with para adicionar restrições temporárias:

class pacote;
    rand logic [3:0] addr;  
    rand logic [9:0] dados;
    constraint cons_addr {
             addr inside {[0:9], [13:15]};
    }
endclass

module test_tb;
    pacote p;
    initial begin
        p = new();
        assert(p.randomize() with {addr == 0; dados > 100;});
        assert(p.randomize() with {addr > 5; dados > 20;});
    end
endmodule

2.6 Restrições com Arrays

Restrições sobre soma, tamanho e valores individuais de arrays:

class pacote;
    rand logic [4:0] len[];
    constraint cons_len {
        len.size() inside {[5:10]};
        len.sum < 50;
        foreach (len[i]) len[i] inside {[1:4]};
    }
endclass

  1. Utilização das Restrições

3.1 Usando Valores Não Aleatórios (rand_mode)

Após várias randomizações, pode-se fixar um valor usando rand_mode(0):

class pacote;
    rand logic [3:0] addr;  
    rand logic [9:0] dados;
    constraint cons_addr {
             addr inside {[0:9], [13:15]};
    }
endclass

module test_tb;
    pacote p;
    initial begin
        p = new();
        assert(p.randomize());
        ...
        p.dados.rand_mode(0);
        p.dados = 541;
        assert(p.randomize()); // dados fixo em 541, addr aleatório
    end
endmodule

3.2 Randomização de Variáveis Específicas

Randomizar apenas algumas variáveis do objeto:

class pacote;
    rand logic [3:0] addr;  
    rand logic [9:0] dados;
    constraint cons_addr {
             addr inside {[0:9], [13:15]};
    }
endclass

module test_tb;
    pacote p;
    initial begin
        p = new();
        assert(p.randomize(addr));  // só randomiza addr
        assert(p.randomize(dados)); // só randomiza dados
    end
endmodule

3.3 Ativar/Desativar Restrições (constraint_mode)

Desligar restrições individuais ou gerais:

class pacote;
    rand logic [3:0] addr;  
    rand logic [9:0] dados;
    constraint cons_addr {
             addr inside {[0:9], [13:15]};
    }
    constraint cons_dados {
             dados inside {[10:105]};
    }
endclass

module test_tb;
    pacote p;
    initial begin
        p = new();
        p.constraint_mode(0);           // desliga todas
        p.cons_addr.constraint_mode(1); // reativa apenas addr
        assert(p.randomize());
    end
endmodule

3.4 Uso de pre_randomize e post_randomize

Funções void, sem retorno, não podem consumir tempo. A ordem de execução: pre_randomize() → randomize() → post_randomize(). Exemplo:

class pacote;
    rand bit [7:0] x, y, z;
    bit en = 0;
    constraint cons_xyz {
        if (en == 0)
            z == x + y;
        else
            z == x;
    }
    function void pre_randomize();
        en = 1;
    endfunction
    function void post_randomize();
        z = y;
    endfunction
endclass

module test_tb;
    pacote p;
    initial begin
        p = new();
        assert(p.randomize());
    end
endmodule

  1. Funções de Randomização

Função Descrição
$random() Distirbuição uniforme, retorna inteiro com sinal de 32 bits
$urandom() Distribuição uniforme, retorna inteiro sem sinal de 32 bits
$urandom_range() Distribuição uniforme em intervalo (obrigatório limite superior, inferior opcional)
$dist_exponential() Decaimento exponencial
$dist_normal() Distribuição normal (gaussiana)
$dist_poisson() Distribuição de Poisson
$dist_uniform() Distribuição uniforme

Tags: SystemVerilog randomização constraints rand randc

Publicado em 6-11 16:45 por Thomas