Differences

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

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
language:expressions [2023/09/07 10:03]
rajit [Expressions]
language:expressions [2024/07/19 10:26] (current)
rajit [Bit-width rules]
Line 19: Line 19:
    * ''bool(x)'': ''x'' must be an integer expression. This returns false if the integer is zero, and true otherwise.    * ''bool(x)'': ''x'' must be an integer expression. This returns false if the integer is zero, and true otherwise.
  
 +Syntactic replication is also supported for the operators ''&'', ''|'', ''^'', ''+'', and ''*''. This means the following expression is valid
 +<code act>
 +  (+ i : 3 : p[i] + 2*i)
 +</code>
 +and is equivalent to
 +<code act>
 +  p[0] + 2*0 + p[1] + 2*1 + p[2] + 2*2
 +</code>
  
 ===== Parameters and constant expressions ===== ===== Parameters and constant expressions =====
Line 40: Line 48:
 ===== Expressions in CHP ===== ===== Expressions in CHP =====
  
-The same expression syntax is also used in the ''chp'' and ''dataflow'' sub-languages. Once again, constant expressions are simplified as above. However, expressions can also include variables that are determined at run-time rather than expansion time (i.e. when the circuit is executing the specified computation.) In this case, we need rules to determine the bit-width of an expression. The rules are as follows:+The same expression syntax is also used in the ''chp'' and ''dataflow'' sub-languages. Once again, constant expressions are simplified as above. However, expressions can also include variables that are determined at run-time rather than expansion time (i.e. when the circuit is executing the specified computation.) In this case, we need rules to determine the bit-width of an expression.  
 + 
 +==== Bit-width rules ==== 
 + 
 +The rules that are used to determine the bit-width of an expression involving circuit variables are as follows:
  
    * Each variable has the bit-width specified by its type.    * Each variable has the bit-width specified by its type.
-   * A constant uses the minimum number of bits needed to represent it. Note that a negative constant is assumed to be a two's complement value, an its bit-width is determined in the same way.+   * A constant uses the minimum number of bits needed to represent it. Note that a negative constant is assumed to be a two's complement value, an its bit-width is determined in the same way. If you are unsure about what is going to happen and want to control the bit-width of a constant, ''int(const, width)'' can be used. Be careful about is negative constants, since the ''int(.)'' operation will zero-extend a value and not sign-extend it.
    * For unary operators, the bit-width of the result is the same as the bit-width of the argument    * For unary operators, the bit-width of the result is the same as the bit-width of the argument
    * For binary operators and ternary operators where the result is an integer, let //left// be the bit-width of the left-hand side of the operator, and //right// be the bit-width of the right hand side. There are six categories of result bit-widths:    * For binary operators and ternary operators where the result is an integer, let //left// be the bit-width of the left-hand side of the operator, and //right// be the bit-width of the right hand side. There are six categories of result bit-widths:
Line 64: Line 76:
      - //left// + 2^//right// - 1      - //left// + 2^//right// - 1
         * left shift ''<<''         * left shift ''<<''
-  * For concatenation, the bit-width is the sum of all the components. For the bitfield extraction, the bitwidth is determined by the number of bits extracted.+  * For concatenation, the bit-width is the sum of all the components.  
 +  * For bitfield extraction, the bitwidth is determined by the number of bits extracted.
  
 +While these bit-width rules are nice because you never lose bits, they can have some unexpected consequences. One of the not-so-nice effects of these rules is that, technically, addition is no longer associative in general! For example, consider the following two different assignment statements:
 +
 +<code act>
 +int<2> a;
 +int<3> b;
 +int<4> c;
 +...
 +chp {
 +   ...
 +   x := (a + b) + c;
 +   y := a + (b + c);
 +   ...
 +}
 +</code>
 +
 +Applying the bit-width rules, the expression ''(a+b) + c'' has bit-width 5, whereas ''a + (b + c)'' has bit-width 6. While this does not have any consequences in this particular example, it could become problematic if the bitwise complement operator is used, or in the case where this expression needs to be negated (since subtraction is essentially taking the two's complement and then adding, which includes the bitwise complement operator).
 +
 +Another strange example is:
 +
 +<code act>
 +...
 +chp {
 +   ...
 +   x := x - 1;
 +   y := y + (-1);
 +   ...
 +}
 +</code>
 +
 +Now the right hand side of the first assignment takes ''x'' and ''1'' and does the subtraction that was expected. The second assignment, on the other hand, takes the bit-pattern for ''-1'' (this turns out to be ''1''), and adds it to ''y''! In other words, ''x-1'' and ''x+(-1)'' are not the same because of the way the bit-width rules operate. If you have any doubts, the ''int(...)'' operator can be used to specify the bit-width.
 +
 +==== Conversion from/to integer to/from pure structures ====
 +
 +A [[language:types2:data#pure_structure|pure structure]] in ACT is a user-defined type that only contains integers and boolean valued variables. This can be interpreted as a collection of bits, where the number of bits is the sum of all the components of the pure structure. The expression syntax allows conversions between pure structures and integers, and vice versa, as in the example below.
 +<code act>
 +  mystructname s;
 +  int<8> x;
 +  ...
 +  chp {
 +    ...
 +    x := int(s);
 +    s := mystructname(x)
 +    ...
 +    }
 +</code>
 +In this example, ''int(s)'' converts the pure structure into an integer with the appropriate bit-width. Note that the assignment may discard bits (if the bits needed exceeds 8) or zero-pad the result (if the bits needed is less than 8).
 +The expression "mystructname(x)" does the opposite. 
 +
 +When a structure has multiple fields, ACT packs them into an integer in left-to-right field order. So, for example, the structure
 +
 +<code act>
 +deftype mystruct (int<4> a; bool b; int<3> c) { }
 +</code>
 +
 +would have the ''a'' field as the highest order bits, followed by ''b'' and then ''c'' Conversion to a structure from an integer follows the same unpacking convention.
 ===== Functions ===== ===== Functions =====
  
Line 208: Line 276:
  
 An example of file I/O implemented with external functions can be found in the ''actsim'' [[https://github.com/asyncvlsi/actsim|git repository]] in the ''simlib/'' directory. An example of file I/O implemented with external functions can be found in the ''actsim'' [[https://github.com/asyncvlsi/actsim|git repository]] in the ''simlib/'' directory.
 +
 +===== Operator Precedence =====
 +
 +The operators have the following precedence, from the highest to lowest:
 +   - ''~'', ''!''
 +   - ''*'', ''/'', ''%''
 +   - ''+'', ''-''
 +   - ''<<'', ''>>'', ''>>>'', ''<'', ''>'', ''<='', ''>='', ''='', ''!=''
 +   - ''&''
 +   - ''^''
 +   - ''|''
 +   - ''?''