Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
language:types2 [2025/04/21 15:52] – [Functions] rajitlanguage:types2 [2026/08/09 13:10] (current) – [Non-strict template parameters] rajit
Line 153: Line 153:
 the type. Hence, when checking for type compatibility, the values of the type. Hence, when checking for type compatibility, the values of
 parameters are also taken into account. Hence, the full type for parameters are also taken into account. Hence, the full type for
-instance ''a2'' above is in fact ''adder<5>'', not just+instance ''a2'' above is in fact ''adder<16>'', not just
 ''adder''. Types such as ''fulladder'' that do not have ''adder''. Types such as ''fulladder'' that do not have
 parameters are more completely specified as ''fulladder<>'', parameters are more completely specified as ''fulladder<>'',
Line 199: Line 199:
  
 Note that ACT is very strict about type-checking; so, for example, ''driver<4>'' and ''driver<4,true>'' are //not// treated as the same type even though the default parameter value for the second template parameter is ''true''. Note that ACT is very strict about type-checking; so, for example, ''driver<4>'' and ''driver<4,true>'' are //not// treated as the same type even though the default parameter value for the second template parameter is ''true''.
 +
 +==== Grouping parameters ====
 +
 +Parameters can be combined into [[language:types2:data#parameter_structures|parameter structures]], to organize a large number of parameters and treat them as a group. Parameter structures can also be used as a template parameter types.
 +
 ===== Direction flags  ===== ===== Direction flags  =====
  
Line 280: Line 285:
  
 <code act> <code act>
-defproc stack (chan(int)? in; chan(int)!out )+defproc stack (chan(int)? in; chan(int)! out)
 {  { 
   ...   ...
Line 306: Line 311:
    s.pop(x);    s.pop(x);
    ...    ...
 +}
 +</code>
 +
 +Macros can also use the ''chp-txt'' language. The syntax for this is shown below.
 +
 +<code act>
 +defproc stack (chan(int)? in; chan(int)! out)
 +{ 
 +  ...
 +  methods {
 +      macro push(int val) chp-txt {
 +          send(in,val)
 +      }
 +      macro pop(int res) chp-txt {
 +          recv(out,res)
 +      }
 +  }
 } }
 </code> </code>
Line 347: Line 369:
 </code> </code>
  
-=== Operator overloading ===+Note that functions cannot have any side-effects; in particular, this means that a function cannot change 
 +any of the members of the pure structure. Macros can be used to change those. 
 + 
 +==== Operator overloading ==== 
 + 
 +Functions within pure structures are also used to support operator overloading. In particular, the following function methods are interpreted to be the definition of operator overloading for arithmetic operators: 
 +   * ''plus'', ''minus'', ''mult'', ''div'', ''mod'' : addition, subtraction, multiplication, division, and modulo operators 
 +   * ''uminus'' : unary minus 
 +   * ''and'', ''or'', ''xor'' : logical operators 
 +   * ''lsl'', ''lsr'', ''asr'' : logical shift left, logical shift right, arithmetic shift right 
 +   * ''lt'', ''gt'', ''le'', ''ge'', ''eq'', ''ne'' : comparison operators 
 +   * ''not'' : logical negation 
 +An example of a fixed-point arithmetic datatype is provided in the [[https://github.com/asyncvlsi/stdlib/blob/main/math/fxp.act|ACT standard library]], and serves as a useful reference for using operator overloading. 
 +In the linked example, ''fixpoint<a,b>'' corresponds to a fixed-point number with ''a'' integer bits and ''b'' fractional bits following the standard Q(a,b) format. 
 + 
 +==== Example user-defined type with macros and methods ==== 
 + 
 +Combining some of these ideas, the following is an example of a user-defined type corresponding to an N-bit signed integer. Only some methods are defined. 
 + 
 +<code act> 
 +template<pint W> 
 +deftype signed_int (int<W> x) 
 +{ 
 +    { W > 1 : "Need sign bit plus one bit at a minumum" }; 
 +    methods { 
 +        function plus (signed_int<W> s) : signed_int<W> 
 +        { 
 +            chp { 
 +               self.x := x + s.x // 2's complement! 
 +             } 
 +         } 
 +        macro display() 
 +        { 
 +            [ x{W-1} = 1 -> log_p("-", (~x+1))  
 +            [] else -> log_p(x) 
 +            ] 
 +         } 
 +         macro set(int<W> v) 
 +         {   
 +              x := v 
 +          } 
 +     } 
 +} 
 +</code> 
 + 
 +In this scenario, the following CHP adds two numbers, and then displays the result using a ''log'' statement. 
 +<code act> 
 +defproc test() 
 +{ 
 +   signed_int<8> u, v; 
 +   chp { 
 +       v.set(1); 
 +       u.set(-3); 
 +       v := v + u; 
 +       log_st(""); 
 +       v.display(); 
 +       log_nl("") 
 +    } 
 +} 
 +</code> 
 +This should display ''-2'' as a log message when run using ''actsim''. 
 + 
 +===== Non-strict template parameters  ===== 
 + 
 +The following ACT program is a buffer that adds a constant value to its input: 
 +<code act> 
 +template<pint W> 
 +defproc addbuf(chan?(int<W>) L; chan!(int<W>) R) 
 +{ 
 +   int<W> x; 
 +   chp { 
 +      *[ L?x; R!(x+17) ] 
 +   } 
 +} 
 +... 
 +addbuf<8> mybuf; 
 +... 
 +</code> 
 +Since ''17'' is a constant, the circuit generated for this can use this constant value to optimize the adder. 
 +A parameterized version of this buffer is: 
 +<code act> 
 +template<pint W, VAL> 
 +defproc addbuf(chan?(int<W>) L; chan!(int<W>) R) 
 +{ 
 +   int<W> x; 
 +   chp { 
 +      *[ L?x; R!(x+VAL) ] 
 +   } 
 +} 
 + 
 +... 
 +addbuf<8,17> mybuf; 
 +... 
 +</code> 
 +This will also result in the same circuit as the earlier example, because the value ''17'' is a parameter and so, after expansion, the CHP to be synthesized will have the constant value ''17'' as a fixed input to the adder. 
 + 
 +What if we wanted to create an array of these adders? While  
 +<code act> 
 +... 
 +addbuf<8,17> mybuf[8]; 
 +</code> 
 +is fine, the problem arises if we want each ''addbuf'' to add a //different// value. The following program 
 +<code act> 
 +addbuf<8,17> mybuf[0..0]; 
 +addbuf<8,18> mybuf[1..1]; 
 +</code> 
 +will result in the error message 
 +<code> 
 +-[ERROR]-> Sparse array type error on mybuf 
 +                   Orig type: addbuf<8,17> 
 +                   New type: addbuf<8,18> 
 +</code> 
 +This is because elements of an array must have the same type. As this is a useful use-case, ACT has support for a special type of template parameter introduced for this scenario. 
 + 
 +Template parameters for processes can be of two types: 
 +   * //strict// parameters, which are the ones we have been considering so far. Elements of an array must have the same strict template parameters. 
 +   * //non-strict// parameters, which can be varied within an array. 
 + 
 + 
 +Non-strict parameters are separated from strict parameters by a vertical bar. The example above would be written as follows: 
 +<code act> 
 +template<pint W | pint VAL> 
 +defproc addbuf(chan?(int<W>) L; chan!(int<W>) R) 
 +{ 
 +   int<W> x; 
 +   chp { 
 +      *[ L?x; R!(x+VAL) ] 
 +   } 
 +} 
 + 
 +... 
 +addbuf<8,17> mybuf[0..0]; 
 +addbuf<8,18> mybuf[1..1]; 
 +... 
 +</code> 
 +ACT will allow this syntax. This comes with a few caveats: 
 +    * Any ports for the type can only use strict parameters.  In other words, the type signature can only depend on strict parameters. This is what permits different process types to be mixed within a single array, since the external interface to the array elements remains unchanged. So<code act> 
 +template<pint W | pint VAL> 
 +defproc oddbuf(chan?(int<W>) L; chan!(int<W+VAL>) R) 
 +{ 
 +...  
 +}  
 +</code>will lead to the following error<code> 
 +-[ERROR]-> Expressions in port parameter list can only use strict template parameters 
 +</code> 
 +   * Even if the array is dense, it will be treated as a sparse array with multiple chunks where each chunk can have different non-strict parameters. 
 +   * Sub-array expressions cannot be used where different elements have different types. 
 + 
 +Since the general ACT syntax can be used, the following would also be valid: 
 +<code act> 
 +... 
 +(i:8: addbuf<8,17+i> mybuf[i..i];) 
 +... 
 +</code>