Random Non overlapping Address (Memory allocator)

Hi,

I have Variable memory partitions with each partition having a variable size. Now the thing I want to do is within each of these partition regions I want to generate N addresses (say N =5). I know I have the starting address of each partition with me, but now within each partition I want to generate 5 addresses that are non overlapping.

What is the easiest way to do this additional thing. Should we do in post_randomize() call or can we do it in pre randomize() itself.

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  
  rand bit [31:0]   m_part_start [];     // Partition start array
  rand int       m_part_size [];       // Size of each partition
  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; }
 
  // Constraint size of each partition
  constraint c_size { m_part_size.size() == m_num_part;
                     m_part_size.sum() == m_ram_end - m_ram_start + 1; 
                     foreach (m_part_size[i]) 
                       m_part_size[i] inside {16, 32, 64, 128, 512, 1024};
                    }
 
  // Constrain start addr of each partition
  constraint c_part { m_part_start.size() == m_num_part;
                      foreach (m_part_start[i]) {
                        if (i>=1) 
                          m_part_start[i] == m_part_start[i-1] + m_part_size[i-1];
                        else
                          m_part_start[i] == m_ram_start;
                      }
                    }                      
 
  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
    mb.randomize();
    mb.display();
  end
endmodule

In reply to sriram.seshagiri:

See:

https://verificationacademy.com/forums/systemverilog/constraint-memories#reply-76718
https://verificationacademy.com/forums/uvm/constraining-address-memory-making-sure-offset-not-within-previous-memory-regions.#reply-63179

Hi Dave,

I tried adding this as an additional constraint, but it does not compile in EDA Playground as it does not like constraints on Multi Dimensional Arrays.

Parameter N = 5;
rand bit [31:0] addr[][];

constraint c_addr { addr.size() == m_num_part;
                      foreach(addr[i])  {
                       addr[i].size == N;
                     }

The idea behind this 2nd constraint is that say N = 5 then each addr(0,0) addr(0,1), addr(0,2), addr(0,3), addr(0,4) will all be unique addresses and, will be less than the next address and, addr(0,4) < starting address of the next block at (i+1).

Is this constraint correct. Please correct me if I am wrong.

constraint c_addr {
   foreach(addr[i,j]) {
       if (j != N-1)  
         addr[i][j] < addr[i][j+1];
		  else
            addr[i][j]< m_part_start[i+1];
               OR
//m_part_start[i]<=addr[i][j]<m_part_start[i+1];
     }
   }

class mem_blocks;
int num = 4;
parameter int mem_boundary = 4096;
rand bit [12:0] sizes;
// 13-bit to hold up to 4096
rand bit [12:0] memory;

  function new();
      memory = new[num];
      sizes  = new[num];
  endfunction

  constraint memory_c {
      sizes.size()  == num;
      memory.size() == num;

      // First block starts at 0
      memory[0] == 0;

      foreach (memory[i]) {
          // Each size is 1024 (swap with inside{[1:...]} for random)
          sizes[i]  inside {[1:mem_boundary-1]};

          // Contiguous: next block starts exactly where this one ends
          if (i < num - 1)
              memory[i+1] == memory[i] + sizes[i];
      }

      // Last block ends exactly at boundary
      memory[num-1] + sizes[num-1] == mem_boundary;
  }

  function void print();
      foreach (memory[i])
          $display("addr[%0d] = %0d,\tsize = %0d  -> ends at %0d",
              i, memory[i], sizes[i], memory[i] + sizes[i] - 1);
      $display("Total size = %0d bytes", sizes.sum());
  endfunction

  function void post_randomize();
      $display("--- Randomization Successful ---\n");
      print();
  endfunction

endclass

module testbench;
initial begin
mem_blocks blk = new();
blk.randomize();
end
endmodule

-– Randomization Successful —

addr[0] = 0, size = 660 → ends at 659
addr[1] = 660, size = 1131 → ends at 1790
addr[2] = 1791, size = 847 → ends at 2637
addr[3] = 2638, size = 1458 → ends at 4095
Total size = 4096 bytes