Saturday, August 22, 2020

Using System Verilog Constraints judiciously

System verilog constraints take up lot of simulation time if not used properly.

Let me try to illustrate it with an example.

Take a scenario where we need to generate unique address ( for burst traffic ) each time we randomize.

Configuration is as follows....

1. Page - 4096 ( 4K) 

2. Address range - 63: 0

3. Align signal is used to take either offset range ( range starts from offset value to the end of the page )

or to take the whole page as a burst ( 4096 in our case ).

align == 1 -> no page offset

align == 0 -> some page offset

Since the address is 64 bits and Page is 12 bits, I took a variable page_num ( 64 -12 = 52 sized vector ) to represent the pages that can be addressed with the address range ( 63:0 ).

Lets take 2 approaches to prove our point ( to pick the random address )

1. With Constraints

2. Without using constraints  


CASE 1 :

In this case, we simply used a queue to push all the used page numbers in post randomize.

For constraints we used unique keyword to make sure that we do not repeat the same value.


 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
class address_selector;
  rand bit [51:0] page_num;
  rand bit [11:0] page_offset;
  rand bit align;
  bit [51:0] used_pages[$];
  constraint c_addr {
    unique { used_pages, page_num }; 
  }
  constraint c_align {
    solve align before page_offset;
    (align == 1) -> page_offset == 0;
  }
  function void post_randomize();
    used_pages.push_back(page_num);
  endfunction: post_randomize
endclass: address_selector

module top;
  address_selector as;
  
  int transfer_size = 1024 * 1000; // Size of 1000K
  initial begin
    as = new;
    while (transfer_size > 0) begin
      void'(as.randomize());
      transfer_size = transfer_size - (4096 - as.page_offset);
      $display("TRANSFER SIZE:%0x ALIGN:%0d ADDR:%0x PAGE:%0x OFFSET:%0x",transfer_size,as.align, {as.page_num,as.page_offset},as.page_num,as.page_offset);
    end
  end
endmodule

Simulation results:

V C S   S i m u l a t i o n   R e p o r t
Time: 0
CPU Time:    143.710 seconds;       Data structure size:   0.0Mb
Sat Aug 22 04:39:05 2020
CPU time: .134 seconds to compile + .023 seconds to elab + .392 seconds to link + 144.630 seconds in simulation

 

CASE 2:

In this case, we used an associative array instead of  queue.

We removed the constraint for generating unique page numbers, instead we used logic to look for the address used ( page_num) inside the post_randomize() function.

 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
class address_selector;
  rand bit [51:0] page_num;
  rand bit [11:0] page_offset;
  rand bit align;
  bit [51:0] used_pages[*];
  constraint c_align {
    solve align before page_offset;
    (align == 1) -> page_offset == 0;
  }
  function void post_randomize();
    while(used_pages.exists(page_num)) begin
      std::randomize(page_num);
    end
    used_pages[page_num] = 1;
  endfunction: post_randomize
endclass: address_selector

module top;
  address_selector as;
  
  int transfer_size = 1024 * 1000;// 128 * 1024 * 100000;
  initial begin
    as = new;
    while (transfer_size > 0) begin
      void'(as.randomize());
      transfer_size = transfer_size - (4096 - as.page_offset);
      $display("TRANSFER SIZE:%0x ALIGN:%0d ADDR:%0x PAGE:%0x OFFSET:%0x",transfer_size,as.align, {as.page_num,as.page_offset},as.page_num,as.page_offset);
    end
  end
endmodule


Simulation results :

  V C S   S i m u l a t i o n   R e p o r t
Time: 0
CPU Time:      0.430 seconds;       Data structure size:   0.0Mb
Sat Aug 22 04:39:35 2020
CPU time: .141 seconds to compile + .022 seconds to elab + .460 seconds to link + .568 seconds in simulation


Conclusion :

See the difference 143 seconds vs .430 seconds.

For smaller address ranges, it doesn't make much of a difference, but for larger footprints it does show a significant improvement in the simulation times.

 


No comments:

Post a Comment

Constraint to have N elements distributed in M bins

Code to distribute N elements into M bins, you add unique keyword to have each bin will have unique number of elements. class test; param...