Blocks are the simplest form of design partitioning. They provide an easy way to segment a large VHDL architecture into multiple self-contained parts. Blocks allow the logical grouping of statements within an architecture, and provide a place to declare locally-used signals, constants, and other objects as needed.

 

VHDL blocks are analogous to sheets in a multi-sheet schematic. They do not represent re-usable components (unless you re-use them by copying them with your text editor or by using configurations), but do enhance readability by allowing declarations of objects to be kept close to where those objects are actually used.

 

The general form of the block statement is shown below:

 

architecture my_arch of my_entity is

begin

 

    BLOCK1: block

        signal a,b: std_logic;

    begin

        -- some local statements here

    end block BLOCK1;

 

    BLOCK2: block

        signal a,b std_logic;

    begin

        -- some other local statements here

        -- Note that ‘a’ and ‘b’ are unique to this block!

    end block BLOCK2;

 

end my_arch;

 

This simple example includes two blocks, named BLOCK1 and BLOCK2, that each include declarations for local signals. In the first block, BLOCK1, the signals a and b are declared prior to the begin statement of the block. These signals are therefore local to block BLOCK1 and are not visible outside of it. The second block, BLOCK2, also has declarations for local signals named a and b, but these are not the same signals as those declared in block BLOCK1.

 

This concept of local declarations is important to understand and is probably familiar to you if you have used high-level programming languages. One of the most important techniques of structured programming (whether you are describing software or hardware) is to minimize the overall complexity of your design description by localizing the declarations as much as is practical. Keeping signals local will make the design description easier to read, allow it to be modified more easily in the future, and also enhance design re-use, since it will be easier to copy one portion of the design to another project or source file.

 

Nested Blocks

Blocks can be nested, as shown in the following example:

 

architecture my_arch of my_entity is

begin

 

    BLOCK1: block

        signal a,b: std_logic;

    begin

 

        BLOCK2: block

            signal c,d std_logic;

        begin

            -- This block is now local to block BLOCK1 and has

            -- access to ‘a’ and ‘b’

        end block BLOCK2;

 

    end block BLOCK1;

 

end my_arch;

 

In this example, block BLOCK2 has been placed within block BLOCK1. This means that all declarations made within BLOCK1 (signals a and b, in this example) are visible both within block BLOCK1 and block BLOCK2.  The reverse is not true, however. The declarations

for c and d within block BLOCK2 are local only to BLOCK2 and are not visible outside that block.

 

What happens when the same signals are declared in two blocks that are nested? Consider the following:

 

architecture my_arch of my_entity is

begin

 

    BLOCK1: block

        signal a,b: std_logic;

    begin

 

        BLOCK2: block

            signal a,b std_logic;

        begin

            -- This a and b overrides previous

        end block BLOCK2;

 

    end block BLOCK1;

 

end my_arch;

 

In this example, the signals a and b are declared both in the outer block (BLOCK1) and in the inner block (BLOCK2). The result is that the signals a and b in the outer block are hidden (but not replaced or overwritten) by the declarations of a and b in the inner block.

 

Note: If you need to access a signal that has been effectively hidden by a declaration of the same name, you can qualify the signal name with a block name prefix, as in BLOCK1.a or BLOCK1.b.

 

Guarded Blocks

Guarded blocks are special forms of block declarations that include an additional expression known as a guard expression. The guard expression enables or disables drivers within the block, allowing circuits such as latches and output enables to be easily described using a dataflow style of VHDL.

 

The following example shows how a guarded block can be used to described the operation of a latch:

 

use ieee.std_logic_1164.all;

entity latch is

    port( D, LE: in std_logic;

             Q, QBar: out std_logic);

end latch;

 

architecture mylatch of latch is

begin

 

    L1: block (LE = ‘1’)

    begin

        Q <= guarded D after 5 ns;

        QBar <= guarded not(D) after 7 ns;

    end block L1;

 

end mylatch;

 

In this example, the guard expression LE = '1' applies to all signal assignments that include the guarded keyword. (Guard expressions are placed in parentheses after the block keyword.) The signal assignments for Q and QBar therefore depend on the value of LE being '1'. When LE is not '1', the guarded signals hold their values.

 

Note: Guarded blocks are not supported by all synthesis tools, so it is not recommended that you use them for designs intended for synthesis. Instead, you should use a process or subprogram to describe the behavior of registered or latched circuits. The section Sequential Statements discusses a number of ways of describing register and latch behavior.

 

See also

image\diamond.gif  Architecture Keyword

image\diamond.gif  Partitioning Features