Functions

Virdant allows you to define functions.

Functions are reusable snippets of combination logic. They may be used anywhere in a design.

Functions are declared with the fn keyword:

fn max(x : Word[8], y : Word[8]) -> Word[8] {
    if x->lt(y) {
        x
    } else {
        y
    }
}

The name and type of each parameter is given in a comma-separated list, and the return type is given after the arrow.

The body of the function definition is a single expression which may make use of the parameters.

To call a function, we do so as you would in math class: max(a, b), where a and b can be any two expressions of the proper type.

Even when a function is only used in one place, they still provide two key benefits. First, they allow you to name a piece of logic in a way that is meaningful to anyone who reads your code. And second, they can be used to guarantee that a given result only depends on the arguments you pass to it. (This is very useful when both the module definition gets large and the function body gets complicated).

Here is a a complete example that shows a module which will always output the larger byte that it has seen as an input:

maximum.vir
 1fn max(x : Word[8], y : Word[8]) -> Word[8] {
 2    if x->lt(y) {
 3        x
 4    } else {
 5        y
 6    }
 7}
 8
 9mod Top {
10    incoming clock : Clock;
11    incoming reset : Bit;
12    incoming inp : Word[8];
13    outgoing max_seen : Word[8];
14
15    reg max_seen_reg : Word[8] on clock;
16
17    max_seen_reg <= if reset {
18        0
19    } else {
20        max(max_seen_reg, inp)
21    };
22
23    max_seen := max_seen_reg;
24}