Expression bit length determination with cast

I have a small program below. I understand the results from the first 2 statements inside the initial block. But I am not able to understand the last $display statement. How did it yield 'hff_ffff_ffff? I thought it should give the same result as in the first $display ('hffff_ffff). I am not sure what I am missing here.



typedef bit unsigned [63 : 0] my_type;
int unsigned addr_width = 40;

initial begin
    $display("A: $bits((1 << addr_width)-1) = %0d\n ((1 << addr_width) -1) ='h%0h\n",
             $bits( (1 << addr_width) -1 ),  
             (1 << addr_width) -1);          

    $display("B: $bits( 64'd1 << addr_width) = %0d\n ((64'd1 << addr_width) -1) ='h%0h\n",
             $bits( 64'd1 << addr_width),     
             ( 64'd1 << addr_width) -1);      
    
    $display("C: $bits( my_type'( ((1 << addr_width)-1)) ) = %0d\n my_type'( ((1 << addr_width)-1)) = 'h%0h\n",
             $bits( my_type'( ((1 << addr_width)-1)) ),    
             my_type'( ((1 << addr_width)-1)));            
end



Simulation results:

A: $bits((1 << addr_width)-1) = 32
((1 << addr_width) -1) ='hffffffff

B: $bits( 64’d1 << addr_width) = 64
((64’d1 << addr_width) -1) ='hffffffffff

C: $bits( my_type’( ((1 << addr_width)-1)) ) = 64
my_type’( ((1 << addr_width)-1)) = 'hffffffffff

In reply to verifsc:

Here is what I thought the last $display does:

  1. 1 << addr_width yields a 32 bit signed result. The value is 0.
  2. (1 << addr_width) -1 yields a 32 bits signed result. The value is -1.
  3. my_type’( ((1 << addr_width)-1)) casts “-1” to my_type which is an unsigned 64 bit data type. It should pad the 32 bits signed value (-1) with 0s to 64 bits. The value should be 'h0000_0000_ffff_ffff.

In reply to verifsc:

No, extension of operands occurs before any operation. The steps of the expression become

  1. Extend two operands in context: ((64’d1 << addr_width)-64’d1))
  2. Evaluate shift: 64 'h10000000000 - 64’d1
  3. Subtraction: 64’hff_ffff_ffff