To say a little bit more about variables and signals…
First thing to understand is that VHDL is essentially two separate languages - a sequential language, and a parallel language, (think functional programming) in one.
The sequential language is basically Ada without tagged types or tasking.
You can use it for behavioural modelling - to express an algorithm just as you would in a single Ada task - with variables, subprograms, file I/O, access types etc - there is no hardware specific dimension to this, it’s just another program.
Wrap it in a “process” statement, and it vaguely resembles a single Ada task. Within a process. variables are … variables, just as in Ada (ditto, constants), maintaining the semantics you would expect from Ada’s variables/constants. (Subprograms are fine, but strip out the file I/O and access types, from any process you intend to synthesise to hardware!)
Now signals are the inter-process communication mechanism, and synchronisation, with their own semantics, replacing everything to do with rendezvous.
For completeness, “Shared variables” can communicate between processes, but this is deprecated and (since VHDL-2000) restricted to protected types resembling Ada’s. But variables are usually local to processes. Stick to signals…
The main form of process starts execution when it’s woken up, runs to completion (or a WAIT statement; I’ll mostly ignore these) and suspends itself - all in notionally zero time (for simulation). Variable assignments happen immediately, reading the variable sees the new value immediately, as you would expect.
Signal assignment, however, is postponed until the process suspends (actually, until EVERY process suspends). Likewise, any signals read by the process are guaranteed to have the value frozen when the process was woken up. This guarantees consistency between parallel processes regardless of execution order - often called VHDL’s crown jewel.
The secret sauce is how processes are woken up : each process (ignoring WAITs) has a sensitivity list such as (clock, reset) for a synchronous circuit or (a,b,c) for a 3-input gate. This is a list of signals : any event (assignment) on any of these signals will wake the process.
process (a,b,c) is
begin
d <= a and b and c; – “<=” is the token for signal assignment
end process;
describes a single gate. When it wakes, it assigns a new value to d. When it suspends (and all other processes suspend), all signal assignments (including the above to d) are performed, all processes sensitive to modified signals (d) are scheduled to wake, and simulation advances to the next “delta cycle”.
This is the parallel domain of VHDL : a network of such processes, connected by their signals.
As a special case for simple signal assignments, the above process would be inferred from the statement
d <= a and b and c;
in the parallel region (ie, outside a process statement).
I hope this gives a glimpse of how VHDL is both similar (within a process) and quite different to Ada, with the goal of supporting the parallelism of hardware in a uniquely clean way.

