Ready-to-run snippets

Code Examples

Ready-to-run Verilog, SystemVerilog, and UVM examples. Click any to open it live in the IDE.

← All examples

Variable Memory Partitions

SystemVerilog Constraints

Shows how to create memory regions of different sizes

Open in IDE
Related tutorial:
testbench.v
class MemoryBlock;
  
  bit [31:0]        m_ram_start;            // Start address of RAM
  bit [31:0]        m_ram_end;              // End address of RAM
  
  rand int          m_num_part;             // Number of partitions  
  bit [31:0]        m_part_start [];        // Partition start array (Removed 'rand')
  int               m_part_size [];         // Size of each partition (Removed 'rand')
  rand int          m_tmp;
    
  // Constrain number of partitions RAM has to be divided into
  constraint c_parts { m_num_part > 4; m_num_part < 10; }
  
  // Simulator Quirk: Verilator has trouble handling complex constraints, so do these in post_randomize method
  // Procedurally generate sizes and start addresses to completely bypass solver limitations
  function void post_randomize();
    int total_target_size = m_ram_end - m_ram_start + 1;
    int current_sum = 0;
    int allowed_sizes[] = '{16, 32, 64, 128, 512, 1024};
    bit valid_distribution = 0;

    m_part_size  = new[m_num_part];
    m_part_start = new[m_num_part];

    // Loop to find a random combination of allowed sizes that sums up exactly to total_target_size
    while (!valid_distribution) begin
      current_sum = 0;
      
      for (int i = 0; i < m_num_part; i++) begin
        if (i == m_num_part - 1) begin
          // The last partition takes the remaining space
          m_part_size[i] = total_target_size - current_sum;
        end else begin
          // Pick a random allowed size
          int idx = $urandom_range(0, allowed_sizes.size() - 1);
          m_part_size[i] = allowed_sizes[idx];
        end
        current_sum += m_part_size[i];
      end

      // Validate if the last partition's forced size belongs to the allowed bucket
      valid_distribution = 0;
      foreach (allowed_sizes[k]) begin
        if (m_part_size[m_num_part - 1] == allowed_sizes[k]) begin
          valid_distribution = 1;
          break;
        end
      end
    end

    // Now populate the start addresses sequentially
    foreach (m_part_start[i]) begin
      if (i == 0) 
        m_part_start[i] = m_ram_start;
      else
        m_part_start[i] = m_part_start[i-1] + m_part_size[i-1];
    end
  endfunction                      
  
  function void display();
    $display ("------ Memory Block --------");
    $display ("RAM StartAddr   = 0x%0h", m_ram_start);
    $display ("RAM EndAddr     = 0x%0h", m_ram_end);
    $display ("# Partitions = %0d", m_num_part);
    $display ("------ Partitions --------");
    foreach (m_part_start[i]) 
      $display ("Partition %0d start = 0x%0h, size = %0d bytes", i, m_part_start[i], m_part_size[i]);
  endfunction
endclass

module tb;
  initial begin
    MemoryBlock mb = new;
    mb.m_ram_start = 32'h0;
    mb.m_ram_end   = 32'h7FF;       // 2KB RAM
    if (!mb.randomize()) begin
      $display("Randomization failed");
    end
    mb.display();
  end
endmodule
Admin mode — edit and delete controls are visible on each row. Use the IDE to add new snippets via File → Save as Snippet.