THDL++ tutorial - operators and statements
<<Previous | Next >> |
Overview
This part of the tutorial lists THDL++ operators and statements - everything you need to write process bodies. If you want to skip formal definitions, just scroll to the end of the page to see a code example.
THDL++ operators
THDL++ operators are very similar to C/C++. The operator precedence is similar to C++ operator precedence:
Precedence | Operators | Associativity |
1 | Function call, array access, template resolution | |
2 | Scope resolution (.), ++, -- | Left to Right |
3 | Unary !, ~ and - | Left to Right |
4 | *, /, % | Left to Right |
5 | +,-, vector concatenation (cat keyword) | Left to Right |
6 | lt, le, gt, ge | Left to Right |
7 | Equals (=), Not equals (!=) | Left to Right |
8 | Bitwise AND (&) | Left to Right |
9 | Bitwise XOR (^) | Left to Right |
10 | Bitwise OR (|) | Left to Right |
11 | Logical AND (&&) | Left to Right |
12 | Logical OR (||) | Left to Right |
13 | Assignment operators: =, +=, -=, *=, /=, %=, &=, |=, ^= | Right to Left |
14 | Array range operator ("to" keyword) | Left to Right |
15 | Comma (,) | Left to Right |
Important note: to avoid ambiguity with template resolution operator (<>) and VHDL-style signal assignment operator (<=), the 'less than', 'greater than', 'less or equals' and 'greater or equals' operators are 'lt', 'gt', 'le' and 'ge' respectively.
Constants
THDL++ supports integral, boolean, logic, time and string constants:
-
Integral constants can be defined using either a decimal (e.g. 15), hexadecimal (e.g. 0xF), or binary (e.g. 0b1111) system. You can safely assign integral values to vectors (e.g. logic[8] instruction = 0x12), THDL++ compiler will automatically convert them into VHDL vector declarations.
-
Boolean constants are equivalent to C++: true and false.
-
Logic constants can be '0', '1', 'X', 'W' and 'Z' matching VHDL constants.
-
Time constants can are defined as {number}{unit prefix}s. E.g.: 100ms or 1ns.
Type conversion
TThe THDL++ compiler automatically converts between integers and logic vectors, as well as between boolean and logic values. Moreover, assigning a logic value (e.g. '1') to a logic vector is equivalent to VHDL "others => '1'" construct. If you want to convert a type explicitly, use the {type}({value}) syntax. E.g.: logic[8] logic_val = logic[8](int_val);
Lists
THDL++ supports compile-time lists. The use of lists makes several operations more compact (see example in the end of this part). To declare a list, use the following syntax:
Lists can be used in foreach() statements and allow efficiently separating algorithms and data.
Statements
THDL++ supports if(), for() and switch() statements having C++ syntax and adds foreach() statement borrowing syntax from C# and select() statement derived from the switch() one.
Conditional statement (if)
The syntax is identical to C++ syntax:
single_statement;
else if (OtherCondition)
another_statement;
else
something_else;
If you want to use multiple statements instead of single statements, use curly brackets ({}), just like in C.
Note: normally, an if statement will be compiled into an equivalent VHDL if statement. If you want to ensure, that the Condition is a constant known during compilation time, use the keyword ifc (if at compile-time) instead of if. In that case, depending on the Condition value, the contents of 'ifc' block will either be compiled into unconditional VHDL, or skipped completely. If an ifc confition is not a compile-time constant, the THDL++ compiler will report an error.
Loop statement (for)
The for statements in THDL++ are identical to C++:
single_statement;
Like in C++, you can declare variables inside for loop initialization statements. Example:
{
some_function(i);
something_else(-i);
}
Note: the for statements are ALWAYS unrolled while compiling to VHDL. If the for() statement condition depends on non-constants (e.g. signal values), the compiler will report an error.
Foreach loops
The syntax is similar to C#:
foreach_loop_body;
Foreach loops are very powerful, as they can iterate constants, types, classes, entity instances and many other things.
Switch statements
The syntax matches the C syntax:
{
case value_1:
case value_2:
some_action();
break;
case value_3:
something_else();
break;
default:
default_action();
}
Select statements
Select() is a short form of switch() practically usable to describe multiplexers:
{
case value_1: result_1;
case value_2: result_2:
default: result_3;
}
Conditional generation statements
THDL++ has an equivalent of the 'generate' statement from VHDL. The syntax is the following:
{
block_contents; //Signals, ports, whatever an entity can have
}
else
{
//Something else
}
The for/foreach form is:
{
block_contents; //Signals, ports, whatever an entity can have
}
Declaring functions
The function declaration syntax is completely equivalent to C syntax:
{
function_body;
return returned_value;
}
Built-in functions
THDL++ has the following built-in functions:
Function | Description | Example |
sizeof() | Returns a size of a vector or a vector variable/signal | port out logic[sizeof(ArrayInput)] ArrayOutput; |
typeof() | Returns a type of a vector variable/signal | signal typeof(SignalA) SignalB; |
log2() | Returns ceil(log2(argument)) | signal logic[log2(sizeof(Array))] ArrayAddress; |
pow2() | Equivalent to (1 << argument) in C++. | bool MSB = (value & pow2(BitCount)) != 0; |
min()/max() | Returns the minimum/maximum value from a list of constants | const int BusSize = min(MinBusSize, comp1.MinBusSize, comp2.MinBusSize); |
extend_sign() | Performs a sign extension on a given value | DataType val = extend_sign(SignedInput, sizeof(DataType)); |
extend_zero() | Performs an unsigned extension of a value | DataType val = extend_zero(UnsignedInput, sizeof(DataType)); |
__defined() | Returns true if a given identifier is defined | if (__defined(Configuration.AdditionalBusWidth)) {...} |
__error() | Generates a compilation error with a given text | ifc (sizeof(a) != sizeof(b)) __error("Argument size mismatch"); |
ite | If-the-else operator | logic[2] encodedValue = ite(inputVal, 0b10, 0b01)l |
__equal_obj | Returns true if 2 given objects (classes/entities) are equal | See code samples |
The example
Let's combine the main of the features mentioned in this chapter into a single example.
{
const int ValueSize = 16;
typedef logic[ValueSize] ValueType;
port in logic InputClock;
signal ValueType Val1 = 0, Val2 = 0, Val3, Val4;
process main (InputClock.rising)
{
Val1++;
Val2 += 2;
}
Val3 = Val2 - Val1;
ValueType SubtractIfGreater(ValueType x, int limit, int bias)
{
if (x gt limit)
x -= bias;
return x;
}
process ComputeVal4 (any)
{
typeof(Val4) tempValue = SubtractIfGreater(Val1, 5, 10);
tempValue++;
Val4 = tempValue;
}
}
entity ClockTest
{
DemoEntity demo(
InputClock = auto,
);
process GenerateClock ()
{
demo.InputClock = '0';
wait(10ns);
demo.InputClock = '1';
wait(10ns);
}
}
simulate_entity(ClockTest);
<<Previous | Next >> |