Although you may use C to describe a digital circuit (in fact, the Verilog HDL has some resembling to C), there's one fundamental thing that you cannot model in plain C: parallelism.
If there's anything that belong to digital circuit description is its inherent parallelism in the description itself: functions (modules actually), and even code blocks "execute" in parallel.
Any ordinary C program describes a sequence of operations over time, and therefore, any attempt to describe a digital operation, unless it is a very trivial one, will be compiled as a sequence of steps, not exploiting the parallelism that digital circuits have by nature.
That said, there does exist some HDL (hardware description languages) that are fair close to C. One of them is Handel-C. Handel-C uses syntax borrowed from C, plus some additions to better handle the inherent parallelism present in digital design.
For example: imagine you have to exchange the value of two variables. The classical solution (besides solutions based in bitwise operations and the like) is:
temp = a;
a = b;
b = temp;
However, when someone is learning computer programming, it's a common mistake to code the above sequence as this:
a = b;
b = a;
Because we think in a variable interchange as a parallel operation: "the value of b is copied to a, meanwhile the value of a is copied to b".
The funny thing about this approach is that it actually works... if we manage to execute these two assignments in parallel. Something that is not possible in plain C, but it is in Handel-C:
par
{
a = b;
b = a;
}
The par
statement indicates that each code line is to be "executed" in parallel with respect to the others.
In Verilog, the same interchange would be written as this:
a <= b;
b <= a;
<=
is the nonblocking assignment in Verilog: the second line is not "executed" after the first one is finished, but both start at the same time. This sequence is normally found inside a clocked always (sort of a loop that is "executed" every time the clock signal in the sensitivity list changes from 0 to 1 -posedge
- or from 1 to 0 -negedge
- ).
always @(posedge clk) begin
a <= b;
b <= a;
end
This means: everytime the clock
goes from 0 to 1, interchange the values between a
and b
.
Note that I always quote "executed" when I speak about languages for digital design. The code doesn't actually translate into a sequence of operations to be executed by a processor, but the code IS a circuit. Think of it as a 1D rendering of a 2D schematic, with sentences and operators instead of electronic symbols, and assignments, arguments and "function calls" instead of wires.
If you are familiarized with digital circuits, you will realize that the "always" loop look-alike, is actually translated into this:
Which is something you couldn't do with just translating the same high level description into assembly (unless the ISA of the target processor has some sort of XCHG
instruction, which is actually not uncommon, and the code keeps the two variables to be interchanged into CPU registers).