4 Ways to Randomize the Number of Ones in a Variable Using SystemVerilog Constraints

Hi, today I am going to write about how to write different constraints in SystemVerilog to achieve the same goal, to randomize the number of ones in a variable.

 

  1. Using built-in $countones function
  2. This is the most intuitive way for me. You can simply just call the built-in function, and SystemVerilog will take care of everything else for you.

    The function $countbits counts the number of bits that have value 1 in a bit vector. A more detailed introduction to $countones is described in RFM 20.9.
     

    program p1;


        class c1;
            rand bit [7:0] w;

            constraint c1 {
                $countones(w) == 3; //call the built-in function
            }


        endclass


        c1 c1_h;

        initial begin
            c1_h = new();

            repeat(3) begin
                if(c1_h.randomize())
                    $display("w is %b", c1_h.w);


            end


        end





    endprogram

     

  3. Using a function call
  4. For constraints, we can always try to build a function to implement more complicated features. So, we are going to build a function outside the constraint, and call it from the constraint.

    Since different vendors may interpret code differently. I tried this on Synopsys VCS, and it didn’t work. It worked seamlessly on Cadence Incisive.

     

    program p2;


        class c1;
            rand bit [7:0] w;

            rand int length;

            constraint c1 {
                count_ones(w) == length;
            }

            constraint c2 {
                length == 3;
            }



            //calculate the set bits in a vector
            function int count_ones (bit [7:0] data_in);
               
                //using for loop to do the bit masking
                for (; data_in !=0; data_in = data_in>>1) begin
                    count_ones +=data_in&1'b1;
                end
               
            endfunction


        endclass


        c1 c1_h;

        initial begin
            c1_h = new();

            repeat(3) begin
                if(c1_h.randomize())
                    $display("w is %b", c1_h.w);


            end


        end





    endprogram

     

  5. Adding every bit up manually
  6. This is the least efficient way, and it is going to be really hard for code reuse. I just write it here as a supplement method.

    We need to unroll all bits manually using bitmasks. This requires us to know the width of the variable, also write the code for each bit.

     

    program p1;


        class c1;
            rand bit [7:0] w;


            //constraint to add every bit up manually
            constraint c1 {
                (((w>>7)&1'b1)+((w>>6)&1'b1)+((w>>5)&1'b1)+((w>>4)&1'b1)+
                ((w>>3)&1'b1)+((w>>2)&1'b1)+((w>>1)&1'b1)+((w)&1'b1)) == 3;
            }


        endclass


        c1 c1_h;

        initial begin
            c1_h = new();

            repeat(3) begin
                if(c1_h.randomize())
                    $display("w is %b", c1_h.w);


            end


        end





    endprogram

     

  7. Using a helper array
  8. We can also approach this problem by adding a helper array. We can create a dynamic array. The size of the array is equal to the number of ones we want to set. The values in the array should be chosen from the bits of the variable that we want to set to 1 and they should be unique. In the post_randomize function, we are going to map each integer in the dynamic array to the corresponding bit in the variable.

 

program p1;


    class c1;
        bit [7:0] w; //not rand anymore

        rand int unsigned bitset[];


        //set the dynamic array size to the number of bits we want to set
        constraint c1 {
            bitset.size() == 3;
        }


        //The values should be chosen from the indexes
        constraint c2 {
            foreach(bitset[i]) 
                bitset[i] inside {[0:$bits(w)-1]}; //This equals to bitset[i] inside {[0:7]};
        }

        //They are different from each other
        constraint c3 {
            unique {bitset};
        }
       


        //map the index to the variable
        function void post_randomize();
            w = 0;
            foreach(bitset[i]) begin
                w[bitset[i]] = 1'b1;
            end


        endfunction

    endclass


    c1 c1_h;

    initial begin
        c1_h = new();

        repeat(3) begin
            if(c1_h.randomize())
                $display("w is %b", c1_h.w);


        end


    end





endprogram

 

Thanks for reading. Those are all the ways I can think of for now. Leave me a comment below if you can come up with another way to do this.

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *