Coding Conventions
Virdant is a language we created so that hardware can be designed in a way that is lush and beautiful.
To help with this, we insist on adhering to certain coding conventions when writing Virdant.
Filenames
Virdant files have the .vir
extension and should begin with a lowercase letter.
For files with multiple words, we use snake case.
Spaces not Tabs
Please use only spaces in Virdant designs. When indenting, always use 4 spaces.
Naming Things
Names are incredibly important. They should be descriptive and accurate.
Do not abbreviate things needlessly. Be considerate of others who might want to read and understand your code. Make good use of your IDE, including autocomplete, to save effort on typing.
The names of module definitions, types, and sockets should begin with an uppercase letter. Everything else, including the names of function definitions, should begin with a lowercase letter.
For names that begin with an uppercase letter, use camel case.
For abbreviations that appear in names, such as SPI, UART, or DDR, only the first letter is capitalized.
So we write SpiController
instead of SPIController
.
For names that begin with a lowercase letter, we use snake case.
A good name for a UART receiver is uart_receiver
.
Types
Whenever you give the type of a component, you should put a space both before and after the colon.
That is, we write wire w : Bit
instead of wire w: Bit
.
When declaring many components on consecutive lines, if adding a few extra spaces would cause the colons to line up, you may insert them to make it easier to read off the types.
Curly Braces
Virdant should be written with the opening curly brace at the end of the line which needed to open it. So we write the following:
mod Top {
// ...
}
And similarly, the correct ways to write if
and match
expressions are:
if condition {
0
} else {
1
}
and
match maybe_data {
@Invalid() => 0;
@Valid(payload) => payload;
}
Expressions
When writing driver statements, if the expression on the right hand side is short, you can write it on the same line:
out := is_valid->and(counter[3]);
If an expression is longer, especially if it contains an if
or match
expression, it may be written in one of two ways.
The first is to write it inline, as if the driver is part of the expression:
counter <= if reset {
0
} else {
counter->inc()
};
Or if it makes it clearer, with a newline and an extra layer of indentation:
counter <=
if reset {
0
} else {
counter->inc()
};
The expressions for the arm of each match expression follows a similar rule:
Inline:
match maybe_data {
@Invalid() => 0;
@Valid(payload) => payload;
}
Newline and extra indentation:
match maybe_data {
@Invalid() =>
if default_payload {
default_payload
} else {
0
};
@Valid(payload) => payload;
}