Half Adder
In this example, we will learn about a few basic operators in Virdant.
A HalfAdder module is the simplest circuit which does something you might call “arithmetic”. This is a classic circuit everyone should know.
mod HalfAdder {
incoming a : Bit
incoming b : Bit
// sum is true when one of a and b is true (but not both)
outgoing sum : Bit dependson a, b {
it := a ^^ b
}
// carry is true when a and b are both true
outgoing carry_out : Bit dependson a, b {
it := a && b
}
}
Note
This is the first in a series of three modules which appear in full in Complete Adder Example.
The Bit Type
HalfAdder takes two 1-bit inputs, a and b:
incoming a : Bit
incoming b : Bit
The Bit type is used for a 1-bit value. Or we might say a boolean value.
The two values a Bit can take are true and false.
Driver Blocks
The outgoing ports of HalfAdder are written a bit differently than before:
// sum is true when one of a and b is true (but not both)
outgoing sum : Bit dependson a, b {
it := a ^^ b
}
// carry is true when a and b are both true
outgoing carry_out : Bit dependson a, b {
it := a && b
}
These define sum and carry_out, both with type Bit.
But in both cases, there is a block directly beneath them. This is called a driver block.
Inside a driver block, you can put drivers related to that component. As a convenience, rather than spelling the name of the component over and over again, you can just write it as it.
And so this is the same as if you had written
// sum is true when one of a and b is true (but not both)
outgoing sum : Bit dependson a, b
sum := a ^^ b
// carry is true when a and b are both true
outgoing carry_out : Bit dependson a, b
carry_out := a && b
Driver blocks are nice because they allow you to tuck away the details inside a level of indentation. A friend who reads your code can then skim down the margin of a module definition,
Truth Table
Back in elementary school, you learned to do addition vertically. You learned how to add all combinations of numbers this way.
Let’s do that with binary numbers. It’s much easier, since there’s only four possibilities:
The only difference is the last one: 1 + 1 = ‘10’. The number 2 is written ‘10’ in binary, since it has a ‘1’ in the two’s place and a ‘0’ in the one’s place.
Representing 0 with false and 1 with true, we can convert these number facts to a truth table for HalfAdder:
| a | b | carry_out | sum |
|---|---|---|---|
| false | false | false | false |
| false | true | false | true |
| true | false | false | true |
| true | true | true | false |
Logical Operations
If you look carefully at the truth table, carry_out is only true for the last row, when when both a and b are true. Therefore, carry_out is the logical AND of a and b, which we write as a && b in Virdant:
outgoing carry_out : Bit dependson a, b {
it := a && b
}
Again, looking very carefully at the table, we see sum is only true when a and b are opposites of each other. Therefore, sum is the logical XOR of a and b. We write this as a ^^ b (which is a bit unique) in Virdant:
// sum is true when one of a and b is true (but not both)
outgoing sum : Bit dependson a, b {
it := a ^^ b
}
Note
The other logical operations in Virdant are a || b for logical OR and !a for logical NOT.
Waveform
The final waveform of HalfAdder looks like this:
Remember that both top.a and top.b are inputs. All four possible combinations of inputs are represented here. Squint and try to “find” the addition table hidden among the squiggles.
Comments
Before going on to how this module works, it’s worth pointing out that comments in Virdant begin with // and go to the end of the line:
// sum is true when one of a and b is true (but not both)There are no multi-line comments in Virdant.