How do I write a coverpoint where part of a variable needs to stay constant and the other changes?

Code for reference:

interface gpr_rd(input clk, reset);
  logic[8:0] addr;        //bits[7:3] is client id, [2:0] is the actual physical address
  logic[1:0] rd_en;       //32 bits are read at once but this determines what was actually requested/used, 2'b01 -> lower 16 bits were requested, 2'b10 -> higher 16 bits were requested, 2'b11-> 32 bits were requested. 
  covergroup gpr_rd_cg;
     rd_size: coverpoint rd_en{
            bins different_sizes = ([1:3] => [1:3]);  
     rd_addr: coverpoint addr[2:0]{
            bins 0_to_31 = {[0:31]};
            ... ...  

I want a coverpoint for the case where the same client is requesting different sizes and the address falls in the bins of rd_addr coverpoint. I thought of this:

rd_client: coverpoint addr[7:3]{
    bins client0 = {0[* 5]};
    bins client31 = {31[*5]};

//Then cross of all three

I don’t like that solution because the number of bins is too large and I don’t really care if each client has made a request. I only want to know if the same client consecutively made read requests of different sizes in the different address ranges. Is there a better/concise way to do this?

In reply to Pooja Pathak:
I don’t understand what you mean by “and I don’t really care if each client has made a request” How does your solution do that? It might help to explain exactly what you want assuming there is only one client. Then we can make array of covergroups to cover each client.

In reply to dave_59:

Hi Dave,

I am doing unit testing so I am not worried about all combinations of addr[7:3] but only addr[2:0](collapsed into bigger bins). Does that answer your question?

The main thing I need help with is how to specify that variable addr is the same value while different_sizes have different transitions.

In reply to Pooja Pathak:

How I understand it as covering all rd_size is important and that must be done for unique addr - covering all client is also important.
So, covering all address space is not important.
We need to try to reduce it.

We need to do a cross of client_id x rd_size x unique_addr_valid_count
Instead of
client_id x rd_size x addr

so, our task is to map unique_add_valid_count to addr[8:0] to reduce the space of cross.

We can try following :

logic bit [8:0]unique_add_arr[2] ; 
logic bit unique_add_valid[2] ; 
logic bit [2:0] unique_addr_valid_count ;

always @(posedge clk) begin
int is_unique[$] ;
2'b01 : begin 
   is_unique = unique_add_arr.find(x) with (x == addr);
   if (is_unique.size == 0) begin 
      unique_add_arr[0] = addr ;
      unique_add_valid[0] = 1 
end // rd_en = 1 
2'b10 : begin 
   is_unique = unique_add_arr find (x) with (x == addr);
   if (is_unique.size == 0) begin 
      unique_add_arr[1] = addr ;
      unique_add_valid[1] = 1 
end // rd_en = 2
2'b11 : begin 
   is_unique = unique_add_arr find (x) with (x == addr);
   if (is_unique.size == 0) begin 
      unique_add_arr[2] = addr ;
      unique_add_valid[2] = 1 
end // rd_en = 3

end // always

unique_addr_valid_count = $countonce(unique_add_valid);

Instead of having a cross :
client_id x rd_size x addr [0-2^8-1]

we will have :
client_id x rd_size x unique_addr_valid_count [1-3]

Now your bins reduces drastically. Here I only see if a client issue a read_of_different_size then see if the address is unique… that is bare minimum to check.

Above code try not to cover all address range but to just store address if it is unique wrt rd_en.

Note : Just try to cover the intention of what should be done… there are many corner things that you can find as an issue for now. But, getting intention of mapping input to some other variable of reduce space is important.