constraintsverilogsystem-veriloghdltest-bench

Random constraints on array of structure elements


typedef enum {HEARTS, DIAMONDS, CLUBS, SPADES} Suit;
typedef enum {TWO = 2, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE} Value;
typedef struct{
    randc Suit card_type;
    rand Value card_value;  
}card;

class Deck;
  rand card cards_drawn[2:0];
  
  // Constraint to ensure that the cards are in increasing order
  constraint cards_order_and_suit {
    foreach (cards_drawn[i]) {
      if (i > 0) {
        cards_drawn[i].card_value > cards_drawn[i-1].card_value;
      }
    }        
  }
        
endclass

module test;
  initial repeat(5) begin
    automatic Deck deck = new();
    assert(deck.randomize()) else $display("Failed to draw three cards");
    foreach (deck.cards_drawn[i]) begin
      $display("Card %0d: Suit = %s, Value = %s", i, deck.cards_drawn[i].card_type.name(), deck.cards_drawn[i].card_value.name());
      end
  end
endmodule

I want unique suits for the three cards drawn. I've tried using randc on the enum type suit variable, but it doesn't seem to work. I am not getting any simulation errors as well with three simulators.

The code works fine if I specify separate constraint for the uniqueness of card suit, but I wanted to explore if we can do something like this mentioning randc inside a structure on an enum type variable.


Solution

  • randc only works on subsequent calls to randomize, not within a single call to randomize. For example, the first time you call randomize, randc has no effect on the array of card objects. It will randomly select a Suit for each element of the array with no constraints. You may get 2 or more cards of the same suit in the array. The 2nd time you call randomize, it will remember the random values from the first call. Refer to IEEE Std 1800-2023, section 18.4 Random variables for a thorough discussion.

    Just declare card_type as rand. One straightforward way to get unique suits is to use the unique keyword inside the constraint block. Yes, you need to repeat similar code 3 times, but it's only 3 lines of code:

    typedef struct{
        rand  Suit card_type;
        rand Value card_value;  
    } card;
    
    class Deck;
      rand card cards_drawn [3];
      
      // Constraint to ensure that the cards are in increasing order
      constraint cards_order_and_suit {
        foreach (cards_drawn[i]) {
          if (i > 0) {
            cards_drawn[i].card_value > cards_drawn[i-1].card_value;
          }
        }        
        unique {
            cards_drawn[0].card_type,
            cards_drawn[1].card_type,
            cards_drawn[2].card_type
        };
      }     
    endclass
    

    Refer to IEEE Std 1800-2023, section 18.5.4 Uniqueness constraints