We can describe the way an architecture is designed by three coding styles: dataflow, behavioural or structural modelling. The distinction between them is based on the type of concurrent statements used.
In practice, you would use all three of these design styles as they are mainly used for categorisation than as strict guidelines.
Not all valid code written in VHDL is synthesizable. Code written in dataflow and structural modelling is always synthesizable. However, when using behavioural modelling, it depends on the synthesis tool.
Structural Modelling
Structural design involves connecting pre-built components together. You can connect multiple smaller VHDL design units into a larger hierarchical design. Hierarchy simplifies design description and makes it easier to re-use parts of your design in other projects.
Component Declaration
Components must be declared before being instantiated in the concurrent statements area.
The port list should match the port list of that component’s ENTITY declaration. The component name does not need to be the same as defined in its ENTITY, however it must then be bound to that ENTITY using a configuration.
Instead of defining a component in the declaration section of the ARCHITECTURE, we can instead define it in a package declaration. Items declared in this package can be made visible within any ARCHITECTURE body by using the library and use clauses.
Each component has a unique label to avoid naming conflicts. PORT MAP connects the actual signals in design to the ports of the instantiated component.
Full VHDL for Example Circuit
LIBRARY ieee;USE ieee.std_logic_1164.all;Entity DIGIX isPort (D1, D2, SET : in std_logic;A :in std_logic_vector(7 downto 0);Q1, Q2, STATUS :out std_logic);end DIGIX;Architecture implementation of DIGIX issignal I1, I2 : std_logic;component XY_gate IS port(X, Y: in std_logic; s1,s2:out std_logic);end component;component QZ_gate ISport( Z1, Z2 : in std_logic; Q :in std_logic_vector(7 downto 0); ST: out std_logic);end component;beginGate1:XY_Gate port map(x=>D1, y=>D2, s2=>I1, s1=>STATUS);Gate2:XY_Gate port map(x=>I1, y=>I2, s1=>Q1, s2=>Q2);Gate3:QZ_Gate port map(Z2=>I1, Z1=>SET, Q=>A, ST=>I2);End implementation;
Note: you must remember to declare your signals, such as I1 and I2 in the circuit above, e.g. SIGNAL I1, I2: STD_LOGIC.
BEGINGate1:XY_Gate PORT MAP(x=>D1, y=>D2, s1=>STATUS, s2=>I1);Gate2:XY_Gate PORT MAP(x=>I1, y=>I2, s1=>Q1, s2=>Q2);Gate3:QZ_Gate PORT MAP(Z1=>SET, Z2=>I1, Q=>A, ST=>I2);END arch;
Positional Association Connectivity
This is an alternate way to write your PORT MAP:
This method is not recommended, but is good to know as it may be used by others.
Dataflow Modelling
Dataflow modelling involves writing equations to describe the flow of data through a circuit. This is done by using one or more concurrent signal assignment statements, e.g. ‘<=’.
Dataflow modelling works well for small and relatively simple circuits. It builds circuits from scratch and allows us to see how our logic might be synthesised.
Concurrent Statements
Simple concurrent signal assignment: (<=)
Conditional concurrent signal assignment: (when-else)
Selected concurrent signal assignment: (with-select-when)
Conditional Concurrent Signal Assignment
An 8-to-3 priority encoder receives eight request inputs (d0-d7), each assigned a priority. If one or more inputs are asserted, it outputs the 3-bit binary index (a2a1a0) of the highest-priority asserted input.
Implementation using when-else signal assignments:
architecture arch of priority83 isbegin a <= "111" when d(7) = '1' else -- highest priority "110" when d(6) = '1' else "101" when d(5) = '1' else "100" when d(4) = '1' else "011" when d(3) = '1' else "010" when d(2) = '1' else "001" when d(1) = '1' else "000"; -- d0, or none active V <= '0' when d = "00000000" else '1'; end arch;
Note: the when-else statements are concurrent -> meaning they all run in parallel. Reordering the statements has no effect on the circuit.
architecture arch of mux41 isbegin Y <= d0 when S = "00" else d1 when S = "01" else d2 when S = "10" else d3 when S = "11" else 'X'; -- unknown/undriven S surfaces as 'X' end arch;
As seen above, when-else signal assignments are also useful for implementing multiplexers, demultiplexers and tri-state buffers.
Selected Concurrent Signal Assignment
We can also use with-select-when assignments to implement components such as multiplexers and decoders.
It is easiest to see how they work using a basic 2-to-1 multiplexer implementation:
architecture behavioural of mux2to1 isbegin with s select Y <= d0 when '0', d1 when '1', 'X' when others; end behavioural;
As we can see, we can select a different assignment depending on the value of our signal s. This also means that no two choices can overlap and all possible values for smust be covered unless an OTHERS choice is present.
Behavioural Modelling
Behavioural modelling describes the behaviour of the design in an algorithmic manner, as a set of sequential statements. It is the closest coding style to a natural language description of the ENTITY functionality.
The set of sequential statements are specified inside a process statement. A process statement is a concurrent statement that can appear within an ARCHITECTURE.
Not every process can be synthesized!
[Process_label:] process (sensitivity list)-- declarationsBegin-- sequential statementsend process [Process_label];
Above is the structure for defining a process. The sensitivity list is a set of signals to which the process is sensitive. If a signal in the sensitivity list changes, this will cause the process to update -> thus, only signals that, when changed, should trigger the process to execute should be included.
Sequential Statements
Sequential statement examples:
if-then-else, case-when
Signal assignment (when inside process)
loop, while-loop, for-loop
wait until, wait for, wait on
Signal Assignment Operator <=
<= has a different meaning depending on whether it is inside or outside a PROCESS construct:
In both cases, <= schedules a signal update
Outside a PROCESS, the concurrent assignment is re-evaluated when one of its input signals changes
Inside a PROCESS, it means schedule an assignment at the end of the process
IF-THEN-ELSE Statement
The if statement is performed by checking each condition in order until a “true” is found. Each condition is a Boolean expression.
if (condition) then {sequence of statements}elsif (condition) then {sequence of statements}else {sequence of statements}end if;
The elseif and else are optional in the example above.
CASE-WHEN Statement
The case statement differs from if statements in that it selects a block of code to execute based on the value of a single control expression.
case (expression) is when choices => {sequential statements} when choices => {sequential statements} when others => {sequential statements}end case;
Each when choice must be distinct and non-overlapping. Additionally, all possible cases must be covered by whenchoices. You can use when others to account for any edge-case.
You can use | (pipe symbol) to group multiple values in one whenchoice, allowing the same set of statements to execute for several values. For example: when "000" | "001" | "010" =>.
Variables
Variables are used to store temporary values within a process. They can be assigned and updated immediately inside a process unlike a signal. They are local to their process and only exist in simulation.
Variables are assigned to using := instead of <=, unlike signals.
Loop Statements
A loop statement is used to repeatedly execute a sequence of sequential statements. They are used to simplify code for arithmetic operations or signal assignments and generating repetitive logic structures.
The optional next statement terminates current loop iteration. Execution will proceed to the next loop iteration. The optional exit statement skips the rest of the statements, terminating the loop entirely.
Several iteration_scheme options:
FOR-LOOP− executes a specific number of iterations
WHILE-LOOP− executes as long as a Boolean condition is TRUE
LOOP− executes until an EXIT statement is executed
WAIT Statements
The WAIT statement is a sequential statement which allows you to suspend the sequential execution of a process until a specified condition becomes TRUE.