Functions and Casts

Functions

Functions allow code reuse. In the current version, they behave like macros at the level of the expression’s abstract syntax tree (AST).

function-definition ::= func $identifier ( [$identifier {, $identifier}] ) { $expression }

Calling a function replaces the call with the function body and introduces bindings for its parameters:

call-expression ::= call $identifier ( [$expression {, $expression}] )

For example:

In this program, we define a function named max that takes two parameters, a and b, and returns the maximum of the two. Inside the Top process, we call this function with the current value of the counter register and the constant 8'd5. The result is bound to the identifier sum, which is then printed in the debug statement.

Note: In the current version, a function can access all bindings in scope at its call site, including registers inside processes.

Cast

Simulators and compilers for traditional HDLs often silently ignore data-width mismatches. These mismatches can lead to unintended behavior. Anvil prevents such issues through strict data-type checking. It also provides an option to restrict casts between abstract data types; this restriction is disabled by default.

When a conversion is necessary, it can be written explicitly with a cast expression:

cast-expression ::= "<" ( $expression ) "::" $data-type-expression ">"

For example:

In this program, the value 2'd2 is first cast to a logic[4], which extends the bit-width, producing 4'b0010. It is then cast to a logic[1], which truncates the higher-order bits, resulting in 1'b0. The debug print statement shows the original value and its casted forms.