Chapter  start   Previous page  Next  page

10.13  Concurrent Statements

A concurrent statement [VHDL LRM9] is one of the following statements:

concurrent_statement ::=
	block_statement
	| process_statement
	| [ label : ] [ postponed ] procedure_call ;
	| [ label : ] [ postponed ] assertion ;
	| [ label : ] [ postponed ] conditional_signal_assignment
	| [ label : ] [ postponed ] selected_signal_assignment
	| component_instantiation_statement
	| generate_statement

The following sections describe each of these statements in turn.

10.13.1  Block Statement

A block statement has the following format [VHDL LRM9.1]:

block_statement ::=
	block_label: block [(guard_expression)] [is]
		[generic (generic_interface_list);
		[generic map (generic_association_list);]]
		[port (port_interface_list);
		[port map (port_association_list);]]
			{block_declarative_item}
			begin
			{concurrent_statement}
	end block [block_label] ;

Blocks may have their own ports and generics and may be used to split an architecture into several hierarchical parts (blocks can also be nested). As a very general rule, for the same reason that it is better to split a computer program into separate small modules, it is usually better to split a large architecture into smaller separate entity-architecture pairs rather than several nested blocks.

A block does have a unique feature: It is possible to specify a guard expression for a block. This creates a special signal, GUARD , that you can use within the block to control execution [VHDL LRM9.5]. It also allows you to model three-state buses by declaring guarded signals (signal kinds register and bus).

When you make an assignment statement to a signal, you define a driver for that signal. If you make assignments to guarded signals in a block, the driver for that signal is turned off, or disconnected, when the GUARD signal is FALSE . The use of guarded signals and guarded blocks can become quite complicated, and not all synthesis tools support these VHDL features.

The following example shows two drivers, A and B , on a three-state bus TSTATE , enabled by signals OEA and OEB . The drivers are enabled by declaring a guard expression after the block declaration and using the keyword guarded in the assignment statements. A disconnect statement [VHDL LRM5.3] models the driver delay from driving the bus to the high-impedance state (time to "float").

library ieee; use ieee.std_logic_1164.all;
entity bus_drivers is end;
architecture Structure_1 of bus_drivers is
signal TSTATE: STD_LOGIC bus; signal A, B, OEA, OEB : STD_LOGIC:= '0';
begin 
process begin OEA <= '1' after 100 ns, '0' after 200 ns; 
OEB <= '1' after 300 ns; wait; end process;
B1 : block (OEA = '1')
disconnect all : STD_LOGIC after 5 ns; -- Only needed for float time.
begin TSTATE <= guarded not A after 3 ns; end block;
B2 : block (OEB = '1')
disconnect all : STD_LOGIC after 5 ns; -- Float time = 5 ns.
begin TSTATE <= guarded not B after 3 ns; end block;
end;
 
                             1    2    3    4    5        6        7
      Time(fs) + Cycle  tstate    a    b  oea  oeb b1.GUARD b2.GUARD
----------------------  ------ ---- ---- ---- ---- -------- --------
                  0+ 0:    'U'  '0'  '0'  '0'  '0'    FALSE    FALSE
                  0+ 1: *  'Z'  '0'  '0'  '0'  '0'    FALSE    FALSE
          100000000+ 0:    'Z'  '0'  '0' *'1'  '0' *   TRUE    FALSE
          103000000+ 0: *  '1'  '0'  '0'  '1'  '0'     TRUE    FALSE
          200000000+ 0:    '1'  '0'  '0' *'0'  '0' *  FALSE    FALSE
          200000000+ 1: *  'Z'  '0'  '0'  '0'  '0'    FALSE    FALSE
          300000000+ 0:    'Z'  '0'  '0'  '0' *'1'    FALSE *   TRUE
          303000000+ 0: *  '1'  '0'  '0'  '0'  '1'    FALSE     TRUE

Notice the creation of implicit guard signals b1.GUARD and b2.GUARD for each guarded block. There is another, equivalent, method that uses the high-impedance value explicitly as in the following example:

architecture Structure_2 of bus_drivers is
signal TSTATE : STD_LOGIC; signal A, B, OEA, OEB : STD_LOGIC := '0';
begin 
process begin
OEA <= '1' after 100 ns, '0' after 200 ns; OEB <= '1' after 300 ns; wait; end process;
process(OEA, OEB, A, B) begin
	if    (OEA = '1') then TSTATE <= not A after 3 ns; 
	elsif (OEB = '1') then TSTATE <= not B after 3 ns; 
	else TSTATE <= 'Z' after 5 ns;
	end if;
end process;
end;

This last method is more widely used than the first, and what is more important, more widely accepted by synthesis tools. Most synthesis tools are capable of recognizing the value 'Z' on the RHS of an assignment statement as a cue to synthesize a three-state driver. It is up to you to make sure that multiple drivers are never enabled simultaneously to cause contention.

10.13.2  Process Statement

A process statement has the following format [VHDL LRM9.2]:

process_statement ::=
[process_label:]
[postponed] process  [(signal_name {, signal_name})]
[is] {subprogram_declaration	| subprogram_body
    | type_declaration	| subtype_declaration
    | constant_declaration	| variable_declaration
    | file_declaration	| alias_declaration
    | attribute_declaration	| attribute_specification
    | use_clause
    | group_declaration 	| group_template_declaration}
begin 
	{sequential_statement}
end [postponed] process [process_label];

The following process models a 2:1 MUX (combinational logic):

entity Mux_1 is port (i0, i1, sel : in BIT := '0'; y : out BIT); end; 
architecture Behave of Mux_1 is
	begin process (i0, i1, sel) begin -- i0, i1, sel = sensitivity set
	case sel is when '0' => y <= i0; when '1' => y <= i1; end case;
end process; end;

This process executes whenever an event occurs on any of the signals in the process sensitivity set (i0, i1, sel). The execution of a process occurs during a simulation cycle--a delta cycle. Assignment statements to signals may trigger further delta cycles. Time advances when all transactions for the current time step are complete and all signals updated.

The following code models a two-input AND gate (combinational logic):

entity And_1 is port (a, b : in BIT := '0'; y : out BIT); end; 
architecture Behave of And_1 is
begin process (a, b) begin y <= a and b; end process; end;

The next example models a D flip-flop (sequential logic). The process statement is executed whenever there is an event on clk . The if statement updates the output q with the input d on the rising edge of the signal clk . If the if statement condition is false (as it is on the falling edge of clk ), then the assignment statement q <= d will not be executed, and q will keep its previous value. The process thus requires the value of q to be stored between successive process executions, and this implies sequential logic.

entity FF_1 is port (clk, d: in BIT := '0'; q : out BIT); end; 
architecture Behave of FF_1 is
begin process (clk) begin
	if clk'EVENT and clk = '1' then q <= d; end if;
end process; end;

The behavior of the next example is identical to the previous model. Notice that the wait statement is at the end of the equivalent process with the signals in the sensitivity set (in this case just one signal, clk ) included in the sensitivity list (that follows the keyword on ).

entity FF_2 is port (clk, d: in BIT := '0'; q : out BIT); end; 
architecture Behave of FF_2 is
begin process begin -- The equivalent process has a wait at the end:
		if clk'event and clk = '1' then q <= d; end if; wait on clk;
end process; end;

If we use a wait statement in a process statement, then we may not use a process sensitivity set (the reverse is true: If we do not have a sensitivity set for a process, we must include a wait statement or the process will execute endlessly):

entity FF_3 is port (clk, d: in BIT := '0'; q : out BIT); end; 
architecture Behave of FF_3 is
begin process begin -- No sensitivity set with a wait statement.
	wait until clk = '1'; q <= d; 
end process; end;

If you include ports (interface signals) in the sensitivity set of a process statement, they must be ports that can be read (they must be of mode in , inout , or buffer , see Section 10.7).

10.13.3  Concurrent Procedure Call

A concurrent procedure call appears outside a process statement [VHDL LRM9.3]. The concurrent procedure call is a shorthand way of writing an equivalent process statement that contains a procedure call (Section 10.10.4):

package And_Pkg is procedure V_And(a,b:BIT; signal c:out BIT); end;
package body And_Pkg is procedure V_And(a,b:BIT; signal c:out BIT) is 
	begin c <= a and b; end; end And_Pkg;
use work.And_Pkg.all; entity Proc_Call_2 is end; 
architecture Behave of Proc_Call_2 is signal A, B, Y : BIT := '0';
	begin V_And (A, B, Y); -- Concurrent procedure call.
process begin wait; end process; -- Extra process to stop.
end;

10.13.4  Concurrent Signal Assignment

There are two forms of concurrent signal assignment statement. A selected signal assignment statement is equivalent to a case statement inside a process statement [VHDL LRM9.5.2]:

selected_signal_assignment ::=
	with expression select
		name|aggregate <= [guarded]
			[transport|[reject time_expression] inertial] 
				waveform when choice {| choice}
					{, waveform when choice {| choice} } ;

The following design unit, Selected_1, uses a selected signal assignment. The equivalent unit, Selected_2, uses a case statement inside a process statement.

entity Selected_1 is end; architecture Behave of Selected_1 is
signal y,i1,i2 : INTEGER; signal sel : INTEGER range 0 to 1;
begin with sel select y <= i1 when 0, i2 when 1; end;
entity Selected_2 is end; architecture Behave of Selected_2 is
signal i1,i2,y : INTEGER; signal sel : INTEGER range 0 to 1;
begin process begin
	case sel is when 0 => y <= i1; when 1 => y <= i2; end case;
	wait on i1, i2;
end process; end;

The other form of concurrent signal assignment is a conditional signal assignment statement that, in its most general form, is equivalent to an if statement inside a process statement [VHDL LRM9.5.1]:

conditional_signal_assignment ::=
		name|aggregate <= [guarded]
	[transport|[reject time_expression] inertial]
			{waveform when boolean_expression else}
				waveform [when boolean_expression];

Notice that in VHDL-93 the else clause is optional. Here is an example of a conditional signal assignment, followed by a model using the equivalent process with an if statement:

entity Conditional_1 is end; architecture Behave of Conditional_1 is
signal y,i,j : INTEGER; signal clk : BIT;
begin y <= i when clk = '1' else j; -- conditional signal assignment
end;
entity Conditional_2 is end; architecture Behave of Conditional_2 is
signal y,i : INTEGER; signal clk : BIT;
begin process begin
	if clk = '1' then y <= i; else y <= y ; end if; wait on clk;
end process; end;

A concurrent signal assignment statement can look just like a sequential signal assignment statement, as in the following example:

entity Assign_1 is end; architecture Behave of Assign_1 is
signal Target, Source : INTEGER;
	begin Target <= Source after 1 ns; -- looks like signal assignment
end;

However, outside a process statement, this statement is a concurrent signal assignment and has its own equivalent process statement. Here is the equivalent process for the example:

entity Assign_2 is end; architecture Behave of Assign_2 is
signal Target, Source : INTEGER; 
begin process begin 
	Target <= Source after 1 ns; wait on Source;
end process; end;

Every process is executed once during initialization. In the previous example, an initial value will be scheduled to be assigned to Target even though there is no event on Source . If, for some reason, you do not want this to happen, you need to rewrite the concurrent assignment statement as a process statement with a wait statement before the assignment statement:

entity Assign_3 is end; architecture Behave of Assign_3 is
signal Target, Source : INTEGER; begin process begin 
	wait on Source; Target <= Source after 1 ns;
end process; end;

10.13.5  Concurrent Assertion Statement

A concurrent assertion statement is equivalent to a passive process statement (without a sensitivity list) that contains an assertion statement followed by a wait statement [VHDL LRM9.4].

concurrent_assertion_statement
::= [ label : ] [ postponed ] assertion ;

If the assertion condition contains a signal, then the equivalent process statement will include a final wait statement with a sensitivity clause. A concurrent assertion statement with a condition that is static expression is equivalent to a process statement that ends in a wait statement that has no sensitivity clause. The equivalent process will execute once, at the beginning of simulation, and then wait indefinitely.

10.13.6  Component Instantiation

A component instantiation statement in VHDL is similar to placement of a component in a schematic--an instantiated component is somewhere between a copy of the component and a reference to the component. Here is the definition [VHDL LRM9.6]:

component_instantiation_statement ::=
instantiation_label: 
 [component] component_name 
|entity entity_name [(architecture_identifier)]
|configuration configuration_name
	[generic map (generic_association_list)]
	[port map (port_association_list)] ;

We examined component instantiation using a component_name in Section 10.5. If we instantiate a component in this way we must declare the component (see BNF [10.9]). To bind a component to an entity-architecture pair we can use a configuration, as illustrated in Figure 10.1, or we can use the default binding as described in Section 10.7. In VHDL-93 we have another alternative--we can directly instantiate an entity or configuration. For example:

entity And_2 is port (i1, i2 : in BIT; y : out BIT); end;
architecture Behave of And_2 is begin y <= i1 and i2; end;
entity Xor_2 is port (i1, i2 : in BIT; y : out BIT); end;
architecture Behave of Xor_2 is begin y <= i1 xor i2; end;
entity Half_Adder_2 is port (a,b : BIT := '0'; sum, cry : out BIT); end;
architecture Netlist_2 of Half_Adder_2 is
use work.all; -- need this to see the entities Xor_2 and And_2
begin
	X1 : entity Xor_2(Behave) port map (a, b, sum); -- VHDL-93 only
	A1 : entity And_2(Behave) port map (a, b, cry); -- VHDL-93 only
end;

10.13.7  Generate Statement

A generate statement [VHDL LRM9.7] simplifies repetitive code:

generate_statement ::=
generate_label: 	 for generate_parameter_specification
		 |if boolean_expression
generate [{block_declarative_item} begin]
	{concurrent_statement}
end generate [generate_label] ;

Here is an example (notice the labels are required):

entity Full_Adder is port (X, Y, Cin : BIT; Cout, Sum: out BIT); end;
architecture Behave of Full_Adder is begin Sum <= X xor Y xor Cin; 
Cout <= (X and Y) or (X and Cin) or (Y and Cin); end;
entity Adder_1 is 
	port (A, B : in BIT_VECTOR (7 downto 0) := (others => '0'); 
	Cin : in BIT := '0'; Sum : out BIT_VECTOR (7 downto 0); 
	Cout : out BIT); end; 
architecture Structure of Adder_1 is use work.all;
component Full_Adder port (X, Y, Cin: BIT; Cout, Sum: out BIT);
end component; 
signal C : BIT_VECTOR(7 downto 0);
begin AllBits : for i in 7 downto 0 generate
	LowBit : if i = 0 generate
		FA : Full_Adder port map (A(0), B(0), Cin, C(0), Sum(0)); 
	end generate;
	OtherBits : if i /= 0 generate
		FA : Full_Adder port map (A(i), B(i), C(i-1), C(i), Sum(i));
	end generate; 
end generate;
Cout <= C(7); 
end;

The instance names within a generate loop include the generate parameter. For example for i=6 , FA'INSTANCE_NAME is

:adder_1(structure):allbits(6):otherbits:fa:


Chapter  start   Previous  page   Next  page