Determining whether type parameter is Signed or Unsigned?

I have the following parameterized class ::



class TP # ( type T = int , T A = 10 ) ;

 T b ; // Could be anything based on T 


endclass

 typedef int unsigned UINT ;

  TP #( UINT , 10 )  tp1 ; 
   TP #( int , 10 )  tp2 ;


Inside the class specialization is there a way to know if type parameter T is signed or unsigned ?
Based on LRM :: $typename() . " In the returned string The default signing is removed " .

So using $typename( T ) inside the class declaration wouldn’t be the solution

In reply to Have_A_Doubt:
You can use this expression

( T'('1) < 0 )

It is true for a signed type. Only works when T is any integral type.

You could use $typename, but you would just have to know what the default signing is for each type.

In reply to dave_59:

Hi Dave ,

**For a value parameter does the LRM define ::
(i) The sign
(ii) Whether its 2-state OR 4-state
**


module  top_tb ;

class  Main1 #( SIZE = 100 ) ;    //  [Q1]  Is  Value parameter  signed  OR  unsigned  ?? 
  
  function  void  display();
    $display(" In  Main1  $typename( SIZE )  is %0s " , $typename( SIZE ) ) ;
    $display(" In  Main1  SIZE   is %0d " , SIZE  ) ;   
  endfunction  
  
endclass  

typedef  int  unsigned  UINT32 ;

class  Main2 #( UINT32 SIZE = 128 ) ;  //  Value  parameter  is   Signed  OR  Unsigned ?
  
  Main1 #( SIZE ) m ;             //  [Q2]   Will  SIZE  be  Unsigned  ?? 
  
  function  new() ;
    m  =  new() ;  
  endfunction  
  
  function  void  display();
    $display(" In  Main2 $typename( SIZE )  is %0s " , $typename( SIZE ) ) ;
    m.display() ;
  endfunction  
  
endclass  

Main1 #( 2**32 - 1 )  m1  ;
Main2 #( 2**32 - 1 )  m2  ;

 initial   begin
   
   m1 = new() ;
   m2 = new() ;
   
   m1.display() ;
   m2.display();
   
 end  
  
endmodule   


I Observe different Output across 3 Simulators

2 Simulators show :: **$typename( SIZE ) as 4-state type ( reg / logic )
whereas 3rd one show it as 2-state ( bit )
**

All 3 simulators show it as signed type with range [31:0]

**[Q2] Shouldn’t the specialization ‘m’ within class Main2 be unsigned as well ?
**

In reply to ABD_91:

The type of a parameter with no explicit datatype in its declaration gets the type of whatever the RHS default value is, or whatever the type of its final overwritten value. The numeric literal 100 is defined to have an integer type, which is a 32-bit signed 4-state type.

Once you declare a parameter with an explicit datatype, any override must be assignment compatible with declared type, and the parameter keeps its explicitly declared type.

$typename is not very well defined, so I suspect it does not get used that often, and has a number of tool specific issues.

In reply to dave_59:


LRM   6.20.2  ::   

"A parameter declaration with no type or range specification shall default to the type and range of the final value assigned to the parameter, after any value overrides have been applied. If the expression is real, the parameter is real. 
If the expression is integral, the parameter is a logic vector of the
same size with range [size-1:0] ."  


Since override in our case is 2 ** 32 - 1 , the expression is integral .
So the parameter is a logic vector ( 4-state ) of size [31:0] .

Since 2 ** 32 - 1 is signed decimal by default , Main1::SIZE is logic signed [31:0]

Also could you please elaborate on ::

" any override must be assignment compatible with declared type"

class Main2 has an explicit datatype ( unsigned ) , so irrespective of the
overridden value ( 2**32 - 1 via m2 in our case )

Both Main2::SIZE and Main2::m::SIZE would ALWAYS be unsigned right ?

In reply to ABD_91:

A parameter with an explicit data type in its declaration always keeps it type. The RHS default or any override cannot change the parameter’s type. That value will be implicitly cast to the declared type.

Main2::SIZE will always be unsigned. Main2::m::SIZE becomes unsigned because Main2::SIZE is unsigned.

This is my interpretation of the LRM.

In reply to dave_59:

Dave ,

An addition to the original question .

As you have stated $typename() doesn’t work according to LRM


 Eg:  LRM   states  signedness  should  Never  be   displayed  via  $typename .

  LRM  20.6.1  :: 

   // source code // $typename would return
   typedef bit node; // "bit"
   node [2:0] X; // "bit [2:0]"
   int signed Y; // "int"




  class  Main1 #( SIZE = 100 )  ;     
   ......................    
 
  endclass

  Main1 #( 128 )  m1  ;   //  128  is  4 - state  signed  parameter  of  Min size [31:0]

  parameter  int  unsigned  UINT  =  128  ;

  Main1 #( UINT )  m2  ;  //  128  is  2 - state  unsigned  parameter of  Min size [31:0]

 


[Q] Since I can’t rely on $typename( SIZE ) within class Main1 to tell me
whether Value parameter is actually signed OR unsigned ,
Is there a better solution ?

[Q2] Isn’t m2 a Different Specialization than m1 since Value parameter is
different ( Unsigned N Signed resp. )


  
//  Within  function  of  class  Main1  

    $display(" Parameter  SIZE  is  %0s " , ( SIZE  > 0 ) ? "unsigned" : "signed" ) ;
  

However this isn’t correct as m1 has Value Parameter as Signed whereas the
above display would give me Unsigned

Unfortunaltely Type Operator [ type( ) ] doesn’t work too :(