Featured post

Top 5 books to refer for a VHDL beginner

VHDL (VHSIC-HDL, Very High-Speed Integrated Circuit Hardware Description Language) is a hardware description language used in electronic des...

Monday 31 December 2012

Happy New Year 2013

We would also like to thanks all our esteemed readers and subscriber as yet again VLSI Encyclopedia has had its most successful year in terms of visitors, articles read, subscriber, Facebook and twitter fans in its history. Happy New Year !!!

2013-happy-new-year-wallpapers-171

Get free daily email updates!

Follow us!

SystemVerilog Interface

Interfaces are a major new construct in SystemVerilog, created specifically to encapsulate the communication between blocks, allowing a smooth refinement from abstract system-level through successive steps down to lower RTL and structural levels of the design. Interfaces also facilitate design re-use. Interfaces are hierarchical structures that can contain other interfaces.

There are several advantages when using an Interface:

  • They encapsulate connectivity: an interface can be passed as a single item through a port, thus replacing a group of names by a single one. This reduces the amount of code needed to model port connections and improves its maintainability as well as readability.
  • They encapsulate functionality, isolated from the modules that are connected via the interface. So, the level of abstraction and the granularity of the communication protocol can be refined totally independent of the modules.
  • They can contain parameters, constants, variables, functions and tasks, processes and continuous assignments, useful for both system-level modelling and testbench applications.
  • They can help build applications such as functional coverage recording and reporting, protocol checking and assertions.
  • They can be used for port-less access: An interface can be instantiated directly as a static data object within a module. So, the methods used to access internal state information about the interface may be called from different points in the design to share information.
  • Flexibility: An interface may be parameterised in the same way as a module. Also, a module header can be created with an unspecified interface instantiation, called a Generic Interface. This interface can be specified later on, when the module is instantiated.

At its simplest, an interface is a named bundle of wires, similar to a struct, except that an interface is allowed as a module port, while a struct is not.

// Interface definition
interface Bus;
  logic [7:0] Addr, Data;
  logic RWn;
endinterface


// Using the interface
module TestRAM;
  Bus TheBus();                   // Instance the interface
  logic[7:0] mem[0:7];
  RAM TheRAM (.MemBus(TheBus));   // Connect it

  initial
  begin
    TheBus.RWn = 0;               // Drive and monitor the bus
    TheBus.Addr = 0;
    for (int I=0; I<7; I++)
      TheBus.Addr = TheBus.Addr + 1;
    TheBus.RWn = 1;
    TheBus.Data  = mem[0];
  end
endmodule


module RAM (Bus MemBus);
  logic [7:0] mem[0:255];

  always @*
    if (MemBus.RWn)
      MemBus.Data = mem[MemBus.Addr];
    else
      mem[MemBus.Addr] = MemBus.Data;
endmodule


Interface Ports

An interface can also have input, output or inout ports. Only the variables or nets declared in the port list of an interface can be connected externally by name or position when the interface is instantiated, and therefore can be shared with other interfaces.  The ports are declared using the ANSI-style.

Here is an example showing an interface with a clock port:

interface ClockedBus (input Clk);
  logic[7:0] Addr, Data;
  logic RWn;
endinterface
module RAM (ClockedBus Bus);
  always @(posedge Bus.Clk)
    if (Bus.RWn)
      Bus.Data = mem[Bus.Addr];
    else
      mem[Bus.Addr] = Bus.Data;
endmodule


// Using the interface
module Top;
  reg Clock;

  // Instance the interface with an input, using named connection
  ClockedBus TheBus (.Clk(Clock));
  RAM TheRAM (.Bus(TheBus));
  ...
endmodule

Parameterised Interface

This is a simple example showing a parameterised interface:

interface Channel #(parameter N = 0)
    (input bit Clock, bit Ack, bit Sig);
  bit Buff[N-1:0];
  initial
    for (int i = 0; i < N; i++)
      Buff[i] = 0;
  always @ (posedge Clock)       
   if(Ack = 1)
     Sig = Buff[N-1];
   else
     Sig = 0;
endinterface

Tasks in Interfaces

Tasks and functions can be defined in interfaces, to allow a more abstract level of modelling.

The next example shows two tasks in an interface being used to model bus functionality. The tasks are called inside the testRAM module:

interface MSBus (input Clk);
  logic [7:0] Addr, Data;
  logic RWn;

  task MasterWrite (input logic [7:0] waddr,
                    input logic [7:0] wdata);
    Addr = waddr;
    Data = wdata;
    RWn = 0;
    #10ns RWn = 1;
    Data = 'z;
  endtask
  task MasterRead (input  logic [7:0] raddr,
                   output logic [7:0] rdata);
    Addr = raddr;
    RWn = 1;
    #10ns rdata = Data;
  endtask
endinterface
module TestRAM;
  logic Clk;
  logic [7:0] data;
  MSBus TheBus(.Clk(Clk));
  RAM TheRAM (.MemBus(TheBus));
  initial
  begin
    // Write to the RAM
    for (int i = 0; i<256; i++)
      TheBus.MasterWrite(i[7:0],i[7:0]);

    // Read from the RAM
    for (int i = 0; i<256; i++)
    begin
      TheBus.MasterRead(i[7:0],data);
      ReadCheck : assert (data === i[7:0])
        else $error("memory read error");
    end
  end
endmodule

Access Type

Formal Definition

A type that provides access to an object of a given type. Access to such an object is achieved by an access value returned by an allocator; the access value is said to designate the object.

Simplified Syntax

access subtype_indication
type identifier;

Description

Access type allows to manipulate data, which are created dynamically during simulation and which exact size is not known in advance. Any reference to them is performed via allocators, which work in a similar way as pointers in programming languages.
The subtype_indication in the access type declaration denotes the type of an object designated by a value of an access type. It can be any scalar, composite or other access type (example 1). File type is not allowed here.
The only objects allowed to be of the access type are variables.
The default value of an access type is null which designates no object at all. To assign any other value to an object of an access type an allocator has to be used (see allocator for details).
The access type allows to create recursive data structures (dynamic lists of objects created during simulation) which consist of the records that contain elements of access types - either the same or different than the actually declared. In order to handle declarations of such recursive data structures so called incomplete type declaration is needed which plays a role of an "announcement" of a type which will be declared later on.
For each incomplete type declaration there must be a corresponding full type declaration with the same name. The complete declaration must appear in the same declarative part. A type declared as incomplete may not be used for any other purposes than to define an access type before the complete type definition is accomplished. Such an incomplete type declaration is presented in example 2 below.

Examples

Example 1
-- declaration of record type Person:
type Person is record
            address:ADRESS_TYPE;
            age:DATE;
end record Person;
-- declaration of access type Person_Access:
type Person_Access is access Person;
The Person_Access type defines a pointer (dynamic link) to a record declared earlier and called Person.
Example 2
-- declaration of an incomplete type Queue_Element:
type Queue_Element;
-- declaration of an access type Queue_Element_Ptr:
type Queue_Element_Ptr is access Queue_Element;
-- declaration of an full record type Queue_Element:
type Queue_Element is record
                  name:STRING(1 to 20);
                  address:ADRESS_TYPE;
                  age:DATE;
                  succ:Queue_Element_Ptr;
end record Queue_Element;
The type Queue_Element contains the Queue_Element_Ptr field, which in turns points to Queue_Element. In order to declare both types sequentially, first the Queue_Element is declared in an incomplete way, which allows declaring the access type Queue_Element_Ptr. Finally, complete declaration of Queue_Element must be provided.

Important Notes

· Application of access types is restricted to variables: only variables can be of an access value. Also, only variables can be designated by an access value.
· Although access types are very useful for modeling potentially large structures, like memories or FIFOs, they are not supported by synthesis tools.













Aggregate

Formal Definition

A basic operation that combines one or more values into a composite value of a record or array type.

Syntax:

aggregate ::= ( element_association { , element association } ) element_association ::= [choices => ] expression choices ::= choice { | choice } choice ::= simple expression          | discrete_range          | element_simple_name          | others

Description

The aggregate assigns one or more values to the elements of a record or array creating the composite value of this type. Aggregates are composed of element associations, which associate expressions to elements (one expression per one or more elements). Element associations are specified in parentheses and are separated by commas.

An expression assigned to an element or elements must be of the same type as the element(s).

Elements can be referred to either by textual order they have in the object declaration (so called positional associations - example 1) or by its name (named associations - example 2). Both methods can be used in the same aggregate, but in such a case all positional associations appear first (in textual order) and all named associations appearing next (in any order). In any case if the association others is used, it must be the last one in an aggregate.

The choice clause, denoting selection of element(s) can have any of the following forms: simple expression, discrete range, simple name or reserved word others.

A value of simple expression can be applied in arrays only and must belong to discrete range of an array type. A simple expression specifies the element at the corresponding index value. Example 2 illustrates this concept.

A discrete range must meet the same conditions as a simple expression. It is useful when several consecutive elements of an array are assigned the same value (example 3). A discrete range serves for defining the set of indexes only and the direction specified or implied has no significance.

The use of element simple name as a choice is restricted to records only. In this case, each element is identified by its name (Example 4).

When some elements are assigned different values and the remaining elements will receive some other value, reserved word others can be used to denote those elements (Example 5). Such a choice must be the last in an aggregate and can be used both in arrays and in records, provided that the remaining elements of the records are of the same type.

The choice others can serve as a very convenient way to assign the same value to all elements of some array, e.g. to reset a wide bus (Example 6).

If several elements are assigned the same value, a multiple choice can be used. In such a case a bar sign (|) separates references to elements (Example 7). If a multiple choice is used in an array aggregate, it may not be mixed with positional associations.

Examples

Example 1

variable Data_1 : BIT_VECTOR (0 to 3) := ('0','1','0','1');

Bits number 0 and 2 are assigned the value '0', while bits 1 and 3 are assigned '1'. All element associations here are positional.

Example 2

variable Data_2 : BIT_VECTOR (0 to 3) := (1=>'1',0=>'0',3=>'1',2=>'0');

Like in the previous example, bits number 0 and 2 are assigned the value '0', while bits 1 and 3 are assigned '1'. The element associations here, however, are named. Note that in this case the elements can be listed in arbitrary order.

Example 3

signal Data_Bus : Std_Logic_Vector (15 downto 0);
. . .
Data_Bus <= (15 downto 8 => '0', 7 downto 0 => '1');

Data_Bus will be assigned the value of "0000000011111111". The first element is associated a value in positional way (thus it is bit number 15), and the other two groups are assigned values using discrete ranges.

Example 4

type Status_Record is record
     Code : Integer;
     Name : String (1 to 4);
end record;
variable Status_Var : Status_Record := (Code => 57, Name => "MOVE");

Choice as an element simple name can be used in record aggregates - each element is associated a value (of the same type as the element itself).

Example 5

signal Data_Bus : Std_Logic_Vector (15 downto 0);
. . .
Data_Bus <= (14 downto 8 => '0', others => '1');

Data_Bus will be assigned the same value as in example 3 ("1000000011111111"), but this aggregate is written in more compact way. Apart from bits 14 through 8, which receive value '0' all the others (15 and 7 through 0) will be assigned '1'. Note that the choice others is the last in the aggregate.

Example 6

signal Data_Bus : Std_Logic_Vector (15 downto 0);
. . .
Data_Bus <= (others => 'Z');

Instead of assigning "ZZZZZZZZZZZZZZZZ" to Data_Bus in order to put it in high impedance state, an aggregate with the others choice representing all the elements can be used.

Example 7

signal Data_Bus : Std_Logic_Vector (15 downto 0);
. . .
Data_Bus <= (15 | 7 downto 0 => '1',
others => '0');

Note the multiple choice specification of the assignment to the bits 15 and 7 through 0. The result of the assignment to Data_Bus will be the same as in examples 3 and 5 ("1000000011111111").

Important Notes

· Associations with elements' simple names are allowed in record aggregates only.

· Associations with simple expressions or discrete ranges as choices are allowed only in array aggregates.

· Each element of the value defined by an aggregate must be represented once and only once in the aggregate.

· Aggregates containing the single element association must always be specified using named association in order to distinguish them from parenthesized expressions.

· The others choice can be only the last in an aggregate.

Alias

Formal Definition

An alternate name for an existing named entity.

Simplified Syntax

alias alias_name : alias_type is object_name;

Description

The alias declares an alternative name for any existing object: signal, variable, constant or file. It can also be used for "non-objects": virtually everything, which was previously declared, except for labels, loop parameters, and generate parameters.

Alias does not define a new object. It is just a specific name assigned to some existing object.

Aliases are prevalently used to assign specific names to slices of vectors in order to improve readability of the specification (see example 1). When an alias denotes a slice of an object and no subtype indication is given then the subtype of the object is viewed as if it was of the subtype specified by the slice.

If the alias refers to some other object than a slice and no subtype indication is supported then the object is viewed in the same way as it was declared.

When a subtype indication is supported then the object is viewed as if it were of the subtype specified. In case of arrays, the subtype indication can be of opposite direction than the original object (example 2).

Subtype indication is allowed only for object alias declarations.

A reference to an alias is implicitly a reference to the object denoted by the alias (example 3).

If an alias denotes a subprogram (including an operator) or enumeration literal then a signature (matching the parameter and result type) is required (example 4). See signature for details.

Examples

Example 1

signal Instruction : Bit_Vector(15 downto 0);
alias OpCode : Bit_Vector(3 downto 0) is Instruction(15 downto 12);
alias Source : Bit_Vector(1 downto 0) is Instruction(11 downto 10);
alias Destin : Bit_Vector(1 downto 0) is Instruction(9 downto 8);
alias ImmDat : Bit_Vector(7 downto 0) is Instruction(7 downto 0);

The four aliases in the example above denote four elements of an instruction: operation code, source code, destination code and immediate data supported for some operations. Note that in all declarations the number of bits in the subtype indication and the subtype of the original object match.

Example 2

signal DataBus : Bit_Vector(31 downto 0);
alias FirstNibble : Bit_Vector(0 to 3) is DataBus(31 downto 28);

DataBus and FirstNibble have opposite directions. A reference to FirstNibble(0 to 1) is equivalent to a reference to DataBus(31 downto 30).

Example 3

signal Instruction : Bit_Vector(15 downto 0);
alias OpCode : Bit_Vector(3 downto 0) is Instruction(15 downto 12);
. . .
if Opcode = "0101" -- equivalent to if Instruction(15 downto 12) = "0101"
then
    . . .

Both conditions are exactly the same, but the one where alias is used is more readable.

Important Notes

· VHDL Language Reference Manual uses the name 'entity' to denote a language unit, i.e. object, parameter etc. It is completely different idea than a design entity.

· Many synthesis tools do not support aliases.

Allocator

Formal Definition

An operation used to create anonymous, variable objects accessible by means of access values.

Simplified Syntax

new subtype_indication

new qualified_expression

Description

Each time an allocator is evaluated, a new object is created and the object is designated (pointed) by an access value (pointer). The type of the object created by an allocator is defined either by a subtype indication (example 1 and 2) or a qualified expression (example 3 and 4).

In case of allocators with a subtype indication, the initial value of the created object is the same as the default initial value of a directly declared variable of the same subtype (example 1 and 2). When qualified expression is used, the initial value is defined by the expression itself (example 3 and 4).

If an allocator creates an object of the array type, then the array must be constrained. This can be achieved through using a constrained subtype or specified in the subtype indication with an explicit index constraint (example 2).

Copying a value of a variable with allocated object to other variable does not create new object. Instead, both variables point to the same object (example 5).

See also access type.

Examples

Example 1

type Table is array (1 to 8) of Natural;
type TableAccess is access Table;
variable y : TableAccess;
...
y := new Table; -- will be initialized with
-- (0, 0, 0, 0, 0, 0, 0, 0)

The allocator (note that the allocator is of the access type) creates a new object of the Table type, which is initialized to a default value, equal in this case to (0, 0, 0, 0, 0, 0, 0, 0).

Example 2

z:= new BIT_VECTOR(1 to 3);

This allocator creates a new object of the BIT_VECTOR type, consisting of three elements. The default initial value of this object is equal to ('0','0','0'). Note that the subtype indication is constrained as the BIT_VECTOR type is unconstrained.

Example 3

type test_record is record
            test_time : time;
            test_value : Bit_Vector (0 to 3);
end record test_record;
type AccTR is access test_record;
variable x,z : AccTR;
x := new test_record'(30 ns, B"1100"); -- record allocation with aggregate
z := new test_record;
z.test_time := 30 ns;
z.test_value := B"1100";

Initial values can be assigned to an object (in this case a record) created by an allocator both using a qualified expression (in this case with an aggregate - allocator for x) or using a subtype indication and later on direct assignments (allocator for z). In both cases above the objects created will be identical (although it will not be the same object).

Example 4

type AccBV is access Bit_Vector(7 downto 0);
variable Ptr1, Ptr2 : AccBV;
Ptr1 := new Bit_Vector(7 downto 0);
Ptr2 := Ptr1;

There is no allocator assigned to Ptr2, thus no new object will be created for it. Instead it will point to the same object, which was created for Ptr1.

Important Notes

· For each access type an implicitly declared procedure Deallocate is defined. The procedure reverses the evaluation of an allocator, i.e. releases the storage occupied by an object created by an allocator.

· Allocators (and access types) are not synthesizable.

· A subtype indication in allocator must not include a resolution function.

· An object created by an allocator has not its own name (indicator). Instead, it is referred to through the name, which it was allocated to.

· The concept of access types and allocators is very much the same as the concept of pointers in software programming languages.

Architecture

Formal Definition

A body associated with an entity declaration to describe the internal organization or operation of a design entity. An architecture body is used to describe the behavior, data flow, or structure of a design entity.

Simplified Syntax

architecture architecture_name of entity_name is

  architecture_declarations

begin

  concurrent_statements

end [ architecture ] [ architecture_name ];

Description

Architecture assigned to an entity describes internal relationship between input and output ports of the entity. It consists of two parts: declarations and concurrent statements.

First (declarative) part of an architecture may contain declarations of types, signals, constants, subprograms (functions and procedures), components, and groups. See respective topics for details.

Concurrent statements in the architecture body define the relationship between inputs and outputs. This relationship can be specified using different types of statements: concurrent signal assignment, process statement, component instantiation, concurrent procedure call, generate statement, concurrent assertion statement and block statement. It can be written in different styles: structural, dataflow, behavioral (functional) or mixed.

The description of a structural body is based on component instantiation and generate statements. It allows to create hierarchical projects, from simple gates to very complex components, describing entire subsystems. The connections among components are realized through ports. Example 1 illustrates this concept for a BCD decoder.

The Dataflow description is built with concurrent signal assignment statements. Each of the statements can be activated when any of its input signals changes its value. While these statements describe the behavior of the circuit, a lot of information about its structure can be extracted form the description as well. Example 2 contains this type of description for the same BCD decoder as in the previous example.

The architecture body describes only the expected functionality (behavior) of the circuit, without any direct indication as to the hardware implementation. Such description consists only of one or more processes, each of which contains sequential statements (Example 3).

The architecture body may contain statements that define both behavior and structure of the circuit at the same time. Such architecture description is called mixed (Example 4).

Examples

Example 1

architecture Structure of Decoder_bcd is
signal S: Bit_Vector(0 to 1);
component AND_Gate
  port(A,B:in Bit; D:out Bit);
end component;
component Inverter
port(A:in Bit; B:out Bit);
end component;
begin
Inv1:Inverter port map(A=>bcd(0), B=>S(0));
Inv2:Inverter port map(A=>bcd(1), B=>S(1));
A1:AND_Gate port map(A=>bcd(0), B=>bcd(1), D=>led(3));
A2:AND_Gate port map(A=>bcd(0), B=>S(1), D=>led(2));
A3:AND_Gate port map(A=>S(0), B=>bcd(1), D=>led(1));
   A4:AND_Gate port map(A=>S(0), B=>S(1), D=>led(0));
end Structure;

The components Inverter and AND_Gate are instantiated under the names Inv1, Inv2, A1, A2, A3 and A4. The connections among the components are realized by the use of signals S(0), S(1) declared in the architecture's declarative part.

Example 2

architecture Dataflow of Decoder_bcd is
begin
   led(3) <= bcd(0) and bcd(1);
   led(2) <= bcd(0) and (not bcd(1));
   led(1) <= (not bcd(0)) and bcd(1);
   led(0) <= (not bcd(0)) and (not bcd(1));
end Dataflow;

All the four statements here are executed concurrently and each of them is activated individually when any of its input signals changes its value.

Example 3

architecture procedural of Decoder_bcd is
signal S: bit_vector (3 downto 0);
begin
P1: process (bcd, S)
   begin
     case bcd is
         when "00" => S <= "0001" after 5 ns;
         when "01" => S <= "0010" after 5 ns;
         when "10" => S <= "0100" after 5 ns;
         when "11" => S <= "1000" after 5 ns;
     end case;
led <= S;
   end process;
end procedural;

The clause "after 5 ns" here allows to introduce time delay of the circuit. The assignment of a new value to the led signal will be done only after 5 nanoseconds of the simulated time.

Example 4

architecture Mixed of Decoder_bcd is
signal S: Bit_Vector(0 to 2);
component Inverter
port(A: in Bit; B: out Bit);
end component;
begin
Inv1: Inverter port map (A=>bcd(0), B=>S(0));
Inv2: Inverter port map (A=>bcd(1), B=>S(1));
P: process (S, bcd)
begin
      led(0) <= S(0) and S(1) after 5 ns;
      led(1) <= S(0) and bcd(1) after 5 ns;
      led(2) <= bcd(0) and S(1) after 5 ns;
      led(3) <= bcd(0) and bcd(1) after 5 ns;
end process;
end Mixed;

Above, two Inverter component instantiation statements define the circuit responsible for determining the value of the signal S. This signal is read by behavioral part i.e. the process statement P. In this process, the values computed by the and operation are assigned to the led output port.

Important Notes

· Single entity can have several architectures, but architecture cannot be assigned to different entities.

· Architecture may not be used without an entity.

· All declarations defined in an entity are fully visible and accessible within each architecture assigned to this entity.

· Different types of statements (i.e. processes, blocks, concurrent signal assignments, component instantiations, etc.) can be used in the same architecture.

Array

Formal Definition

A type, the value of which consists of elements that are all of the same subtype (and hence, of the same type). Each element is uniquely distinguished by an index (for a one-dimensional array) or by a sequence of indexes (for a multidimensional array). Each index must be a value of a discrete type and must lie in the correct index range.

Simplified Syntax

type type_name is array (range) of element_type

type type_name is array (type range <>) of element_type

Description

The array is a composite object, which elements are of the same subtype. Each of the elements is indexed by one or more indices belonging to specified discrete types. The number of indices is the number of dimensions, i.e. one-dimensional array has one index, two-dimensional has two indices, etc. The order of indices is significant and follows the order of dimensions in the type declaration (example 1).

An array may be either constrained or unconstrained. The array is constrained if the size of the array is constrained. The size of the array can be constrained using a discrete type mark or a range. In both cases, the number of the elements in the array is known during the compilation. Several declarations of constrained arrays are presented in example 1.

The array is said to be unconstrained if its size is unconstrained: the size of the unconstrained array is declared in the form of the name of the discrete type, which range is unconstrained. The number of elements of unconstrained array type is unknown. The size of a particular object is specified only when it is declared. Example 2 presents several declarations of unconstrained arrays.

Package STANDARD contains declarations of two one-dimensional unconstrained predefined array types: STRING and BIT_VECTOR. The elements of the STRING type are of the type CHARACTER and are indexed by positive values (i.e. counted from 1), and the elements of the BIT_VECTOR type are of the type BIT and are indexed by natural values (i.e. counted from 0). See string type and Bit_Vector for details.

Array elements are referenced by indices and can be assigned values individually or using concatenation, aggregates, slices or any mixture of those methods. See respective topics for details.

Examples

Example 1

type Real_Matrix is array (1 to 10) of REAL;
type BYTE is array (0 to 7) of BIT;
type Log_4_Vector is array (POSITIVE range 1 to 8, POSITIVE range 1 to 2) of Log_4;
type X is (LOW, HIGH);
type DATA_BUS is array (0 to 7, X) of BIT;

The type Real_Matrix is an array consisting of 10 elements, each of which is of the type REAL. Log_4_Vector is a two-dimensional array 82 and its elements are of type Log_4 (which must have been declared earlier). Also the type DATA_BUS is a two-dimensional array of the same size, but note that one of the dimensions is defined as enumeration type.

Example 2

-- unconstrained array of element of Real type:
type Real_Matrix is array (POSITIVE range <>) of Real;
variable Real_Matrix_Object : Real_Matrix (1 to 8);
-- unconstrained array of elements of Log_4 type:
type Log_4_Vector is array (NATURAL range <>, POSITIVE range<>) of Log_4;
variable L4_Object : Log_4_Vector (0 to 7, 1 to 2);

Examples of unconstrained types: Real_Matrix is when an unconstrained type and an object of this type is declared (Real_Matrix_Object) it is restricted to 8 elements. In similar way L4_Object is constrained from an unconstrained two-dimensional type Log_4_Vector.

Important Notes

· Synthesis tools do generally not support multidimensional arrays. The only exceptions to this are two-dimensional "vectors of vectors". Some synthesis tools allow two-dimensional arrays.

· Arrays may not be composed of files.

Assertion Statement

Formal Definition

A statement that checks that a specified condition is true and reports an error if it is not.

Simplified Syntax

assert condition

  report string

  severity severity_level;

Description

The assertion statement has three optional fields and usually all three are used.

The condition specified in an assertion statement must evaluate to a boolean value (true or false). If it is false, it is said that an assertion violation occurred.

The expression specified in the report clause must be of predefined type STRING and is a message to be reported when assertion violation occurred.

If the severity clause is present, it must specify an expression of predefined type SEVERITY_LEVEL, which determines the severity level of the assertion violation. The SEVERITY_LEVEL type is specified in the STANDARD package and contains following values: NOTE, WARNING, ERROR, and FAILURE. If the severity clause is omitted it is implicitly assumed to be ERROR.

When an assertion violation occurs, the report is issued and displayed on the screen. The supported severity level supplies an information to the simulator. The severity level defines the degree to which the violation of the assertion affects operation of the process:

· NOTE can be used to pass information messages from simulation (example 1);

· WARNING can be used in unusual situation in which the simulation can be continued, but the results may be unpredictable (example 2);

· ERROR can be used when assertion violation makes continuation of the simulation not feasible (example 3);

· FAILURE can be used when the assertion violation is a fatal error and the simulation must be stopped at once (example 4).

Assertion statements are not only sequential, but can be used as concurrent statements as well. A concurrent assertion statement represents a passive process statement containing the specified assertion statement.

Examples

Example 1

assert Status = OPEN_OK
  report "The call to FILE_OPEN was not successful"
  severity WARNING;

Having called the procedure FILE_OPEN, if the status is different from OPEN_OK, it is indicated by the warning message.

Example 2

assert not (S= '1' and R= '1')
  report "Both values of signals S and R are equal to '1'"
  severity ERROR;

When the values of the signals S and R are equal to '1', the message is displayed and the simulation is stopped because the severity is set to ERROR.

Example 3

assert Operation_Code = "0000"
  report "Illegal Code of Operation"
  severity FAILURE;

Event like illegal operation code are severe errors and should cause immediate termination of the simulation, which is forced by the severity level FAILURE.

Important Notes

· The message is displayed when the condition is NOT met, therefore the message should be an opposite to the condition.

· Concurrent assertion statement is a passive process and as such can be specified in an entity.

· Concurrent assertion statement monitors specified condition continuously.

· Synthesis tools generally ignore assertion statements.

Attributes (predefined)

Formal Definition

A value, function, type, range, signal, or constant that may be associated with one or more named entities in a description.

Simplified Syntax

object'attribute_name

Description

Attributes allow retrieving information about named entities: types, objects, subprograms etc. VHDL standard defines a set of predefined attributes. Additionally, users can define new attributes, and then assign them to named entities by specifying the entity and the attribute values for it. See attributes (user-defined) for details.

Predefined attributes denote values, functions, types, and ranges that characterize various VHDL entities. Separate sets of attributes are predefined for types, array objects or their aliases, signals and named entities.

Each type or subtype T has a basic attribute called T'Base, which indicates the base type for type T (Table 1). It should be noted that this attribute could be used only as a prefix for other attributes.

Table 1. Attributes available for all types

Attribute

Result

T'Base

base type of T

Scalar types have attributes, which are described in the Table 2. Letter T indicates the scalar type.

Table 2. Scalar type attributes

Attribute

Result type

Result

T'Left

same as T

leftmost value of T

T'Right

same as T

rightmost value of T

T'Low

same as T

least value in T

T'High

same as T

greatest value in T

T'Ascending

boolean

true if T is an ascending range, false otherwise

T'Image(x)

string

a textual representation of the value x of type T

T'Value(s)

base type of T

value in T represented by the string s

Discrete or physical types and subtypes additionally have attributes, which are described in Table 3. The discrete or physical types are marked with letter T before their names.

Table 3. Attributes of discrete or physical types and subtypes

Attribute

Result type

Result

T'Pos(s)

universal integer

position number of s in T

T'Val(x)

base type of T

value at position x in T (x is integer)

T'Succ(s)

base type of T

value at position one greater than s in T

T'Pred(s)

base type of T

value at position one less than s in T

T'Leftof(s)

base type of T

value at position one to the left of s in T

T'Rightof(s)

base type of T

value at position one to the right of s in T

Array types or objects of the array types have attributes, which are listed in the Table .4. Aliases of the array type objects have the same attributes. Letter A denotes the array type or array objects below.

Table 4. Attributes of the array type or objects of the array type

Attribute

Result

A'Left(n)

leftmost value in index range of dimension n

A'Right(n)

rightmost value in index range of dimension n

A'Low(n)

lower bound of index range of dimension n

A'High(n)

upper bound of index range of dimension n

A'Range(n)

index range of dimension n

A'Reverse_range(n)

reversed index range of dimension n

A'Length (n)

number of values in the n-th index range

A'Ascending(n)

True if index range of dimension n is ascending, False otherwise

Signal attributes are listed in Table 5. Letter S indicates the signal names.

Table 5. Signals attributes

Attribute

Result

S'Delayed(t)

implicit signal, equivalent to signal S, but delayed t units of time

S'Stable(t)

implicit signal that has the value True when no event has occurred on S for t time units, False otherwise

S'Quiet(t)

implicit signal that has the value True when no transaction has occurred on S for t time units, False otherwise

S'Transaction

implicit signal of type Bit whose value is changed in each simulation cycle in which a transaction occurs on S (signal S becomes active)

S'Event

True if an event has occurred on S in the current simulation cycle, False otherwise

S'Active

True if a transaction has occurred on S in the current simulation cycle, False otherwise

S'Last_event

the amount of time since last event occurred on S, if no event has yet occurred it returns Time'High

S'Last_active

the amount of time since last transaction occurred on S, if no event has yet occurred it returns Time'High

S'Last_value

the previous value of S before last event occurred on it

S'Driving

True if the process is driving S or every element of a composite S, or False if the current value of the driver for S or any element of S in the process is determined by the null transaction

S'Driving_value

the current value of the driver for S in the process containing the assignment statement to S

The named entities have attributes described in Table 6. Letter E denotes the named entities.

Table 6. Attributes of named entities

Attribute

Result

E'Simple_name

a string representing the simple name, character literal or operator symbol defined in the declaration of the item E

E'Path_name

a string describing the path through the design hierarchy, from the root entity or package to the item E

E'Instance_name

a string describing the path through the design hierarchy, from the root entity or package to the item E, but including the names of the entity and architecture bound to each component instance in the path

Paths which can be written using E'Path_name and E'Instance_name are used for reporting and assertion statements. They allow specifying precisely where warnings or errors are generated. E'Simple_name attribute refers to all named entities, E'Path_name and E'Instance_name can refer to all named entities apart from the local ports and generic parameters in the component declaration.

There is one more predefined attribute: 'Foreign' that allows the user to transfer additional information to the simulator. The information contains the instruction for special treatment of a given named entity. The exact interpretation of this attribute, however, depends on its implementation in particular simulator.

Examples

Example 1

type Table is array (1 to 8) of Bit;
variable Array_1 : Table := "10001111";
Array_1'Left, the leftmost value in index range of Table array, is equal to 1.

Example 2

type Table is array (Positive range <>) of Bit;
subtype Table_New is Table (1 to 4);
Table_New'Base, the base type of the Table_New subtype is Table.

Example 3

type New_Range is range 1 to 10;
New_Range'Ascending is TRUE (the New_Range type is of ascending range).

Example 4

type New_Values is (Low, High, Middle);
New_Values'Pred(High) will bring the 'Low' value.

Example 5

type Table is array (1 to 8) of Bit;

Table'Range(1) is the range of the first index of Table type and returns '1 to 8'; Table'Range will have the same interpretation for one dimensional array.

Important Notes

  • Not all predefined attributes are supported by synthesis tools; most tools support 'high, 'low, 'left, 'right, range, 'reverse_range, 'length and 'event. Some also support'last_value and 'stable.

Attributes (user-defined)

Formal Definition

A value, function, type, range, signal, or constant that may be associated with one or more named entities in a description.

Simplified Syntax

attribute attribute_name: type;             -- attribute declaration

attribute attribute_name of item : item_class is expression; -- attribute specification

Description

VHDL allows attaching additional information to design elements through new attributes for specified types. In order to assign an attribute to a given design element, attribute specification is used. The values assigned this way can be referred in the expressions through declared attribute name.

The attribute declaration defines a new attribute within the scope of the given declarative area. It consists of an identifier specification, which represents user defined attribute and type mark that indicates value type for this attribute. A user-defined attribute can be of any VHDL type, except for an access type, file type, and any complex type with elements of any of the two types. See Example 1.

Attribute specification assigns an attribute declared earlier to a chosen named entity. The named entities that can be assigned attributes are: entity, architecture, configuration, procedure, function, package, type, subtype, constant, signal, variable, component, label, literal, units, group, or file. The named entities are enumerated in entity names list. In such a way the attribute is assigned to a given language unit. Finally, the attribute specification contains an expression, which sets an attribute value for the entities listed in the specification. See Example 2.

The attribute specification for most named entities must be declared together with declarations of those entities. For some entities, however, the attribute specification is written in other places.

The attribute specification for library units such as entity, architecture configuration and package cannot be directly placed in the library, which contains library unit declarations. Because of that, the attribute specification is placed in the declaration part of named entity (Example 3).

The attribute specification for a subprogram must be declared in the same visibility region as the subprogram's declaration. In case of overloaded procedures and functions, signatures must be used to point to the subprogram to which the attribute is assigned (Example 4). If no signature is used the attribute relates to all subprograms with the same name.

Functions declared as the operators are always overloaded, and that is why they always require the signature in the attribute specification to differentiate functions (Example 5).

Attribute specifications for ports and generic parameters are placed in the declaration part of the design entity or the block statement to which they belong. The attribute specifications for formal parameters of subprograms are placed in the declaration part of these subprograms (Example 6).

Attribute specifications for labeled statements cannot be located directly in the place of the statements' declarations. Therefore, the attribute specifications for the label connected with any concurrent or sequential statements are placed in the declaration part before the occurrence of a given statement (Example 7).

In case of the sequential statement labels, the attribute specification is placed in the declaration part of the process or subprogram.

The attribute specification for literal must be declared in the same visibility block as the literal declaration. In case when there are several literals with the same names, the attribute specification for a given literal uses a signature in order to distinguish which type a given literal belongs to (Example 8). If no signature is used the attribute can be applied to all literals with the same name.

When specifying attributes reserved words: others and all can be used as entity (item) names. In the first case, the attribute specification refers to all the remaining visible named entities of a given entity class which do not have the attribute value assigned to them. Such an attribute specification must be the last in the declaration that refers to this attribute. When the keyword all is used, the attribute specification refers to all named entities of the given class. Such an attribute specification must be the first in the declaration part, which relates to this attribute. See Example 9.

Examples

Example 1

package Attr_pkg is
attribute Component_symbol : String;
attribute Pin_code : Positive;
attribute Max_delay: Time;
type Point is record
  x, y: Real;
end record;
attribute Coordinate : Point;
    ........
end package Attr_pkg;

The Atrr_pkg contains several attribute declarations, which can be later specified and used in other design units.

Example 2

package Some_declarations is
use Work.Attr_pkg.Component_symbol,
    Work.Attr_pkg.Coordinate,
    Work.Attr_pkg.Pin_code,
    Work.Attr_pkg.Max_delay;
constant Const_1: Positive := 10;
signal Sig_1: Bit_vector (0 to 31);
component Comp_1 is
port ( ... );
end component;
attribute Component_symbol of Comp_1: component is "Counter_16";
attribute Coordinate of Comp_1: component is (0.0, 17.5);
attribute Pin_code of Sig_1: signal is 17;
attribute Max_delay of Const_1: constant is 10 ns;
    .........
end package Some_declarations;

The package Some_declarations specifies attributes, which were declared in the package Attr_pkg.

Example 3

package Test_pkg is
attribute Package_atr : String;
attribute Package_atr of Test_pkg:
package is "Training_package";
    .........
end package Test_pkg;

The specification of a package attribute Package_atr for the package Test_pkg is declared in the declaration part of the package.

Example 4

procedure Sub_values (a, b : in Integer; result: out Integer);
procedure Sub_values (a, b : in Bit_vector; result: out Bit_vector);
attribute Description : String;
attribute Description of
        Sub_values [Integer, Integer, Integer]:procedure is "Integer_sub_values";
attribute Description of
        Sub_values [Bit_vector, Bit_vector, Bit_vector] :
procedure is "Bit_vector_sub_values";

The specification of the attribute Description intended for overloaded procedure Sub_values, which subtracts two values of integer or Bit_vector types, requires signature specification. These signatures (simplified parameter lists) enable to distinguish versions of the procedure.

Example 5

function "-" (a, b : New_logic) return New_logic;
attribute Characteristic : String;
attribute Characteristic of
  "-" [ New_logic, New_logic return New_logic]: function is "New_logic_op";

To identify operator ”-” overloaded for two values of type New_logic it is necessary to use signature that will unambiguously identify the overloading function.

Example 6

procedure Insert (fifo : inout Fifo_type; element: in Elem_type) is
attribute Number of fifo: variable is 50;
attribute Trace of element: constant is "Integer/Decimal";
   .........
end procedure Insert;

The procedure Insert has two formal parameters of different classes. Specifications of attributes Number and Trace for parameters fifo and element, respectively, are placed in the declaration part of the procedure.

Example 7

architecture Struct of ALU is
component Adder is
port (...)
end component;
attribute Coordinate of the_Adder: label is (0.0, 0.12);
begin
the_Adder : Adder port map ( ... );
.........
end architecture Struct;

Specification of the attribute Coordinate for the label the_Adder for component instantiation statement is located in the declarative part of the corresponding architecture body Struct.

Example 8

type Three_level_logic is (Low, High, Idle);
type Four_level_logic is (Low, High, Idle, Uninitialized);
attribute Hex_value : string (1 to 2);
attribute Hex_value of Low [return Four_level_logic]: literal is "F0";
attribute Hex_value of High [return Four_level_logic]: literal is "F1";
attribute Hex_value of Idle [return Four_level_logic]: literal is "F2";
attribute Hex_value of Uninitialized: literal is "F3";

As the literals Low, High, Idle are overloaded, it is necessary to use signature indicating their type in the specification of the attribute Hex_value for these literals. However, this is not necessary for the literal Uninitialized as it is not overloaded.

Example 9

B1: block
signal S1, S2, S3: Std_logic;
attribute Delay_attr: Time;
attribute Delay_attr of all: signal is 100 ps;
begin
   .........
end block;

The Delay_attr relates to all signals in the block B1.

Important Notes

· Common attributes can be declared for objects of different classes using one construct - group. See the group topic for details.

Bit

Formal Definition

The Bit type is predefined in the Standard package as an enumerated data type with only two allowable values: '0' and '1'.

Syntax:

type bit is ('0','1');

Description

The bit type is the basic type to represent logical values. Note that there are only two values defined for the bit type and it is not possible to use it for high impedance and other non-trivial values such as Unknown, Resistive Weak, etc. (see Std_logic).

According to the type definition, its leftmost value is '0', therefore the default value of any object of the bit type is '0'.

As the bit type is defined in the Standard package, it can be used in any VHDL specification without additional declarations.

Signals of the bit type are not resolved which means that such a signal can be assigned to an expression only once in the entire architecture.

Examples

Example 1

signal BitSig1, BitSig2 : bit;
. . .
BitSig1 <= '1';
BitSig2 <= not BitSig1;

The BitSig1 and BitSig2 signals are declared without an initial value, therefore by default they will be assigned the '0' value. In the next statement BitSig1 is assigned the '1' value. This value is complemented in the following statement and is assigned to BitSig2. Any additional assignment either to BitSig1 or BitSig2 would be illegal.

Important Notes

· Unlike in traditional ("hand-based") digital design, logical values 0 and 1 (bit type values '0' and '1') are NOT identical to boolean values (false and true), respectively. In VHDL, the latter items form completely different type (Boolean).

· Logical values for object of the bit type MUST be written in quotes to distinguish them from Integer values.

Bit_Vector

Definition:

The Bit_Vector type is predefined in the Standard package as a standard one-dimensional array type with each element being of the Bit type.

Syntax:

type bit_vector is array (natural range <>) of bit;

Description

The Bit_vector type is an unconstrained vector of elements of the bit type. The size of a particular vector is specified during its declaration (see the example below). The way the vector elements are indexed depends on the defined range and can be either ascending or descending (see range).

Assignment to an object of the Bit_vector type can be performed in the same way as in case of any arrays, i.e. using single element assignments, concatenation, aggregates, slices or any combination of them.

Examples

Example 1

signal DataBus : Bit_vector(7 downto 0);
signal FlagC : Bit;
DataBus(0) <= '1';                           -- 1
DataBus <= '0' & "111000" & FlagC;           -- 2
DataBus <= ('0', others => '1');             -- 3
DataBus <= DataBus(6 downto 0) & DataBus(7); -- 4
DataBus <= "01110001";                       -- 5

There is one bit_vector defined in this example - DataBus. Its range is defined as descending, therefore the most significant bit will be DataBus(7). Line 1, marked in the comment field, illustrates assignment of a single element (bit). The line 2 shows typical use of concatenation. Note that both single bits, groups of bits (with double quotes!) and other signals (as long as their type is compatible) can be used. The line 3 demonstrates the use of aggregates. The line 4 illustrates how slices can be used together with concatenation. The value of DataBus will be rotated left in this example. Finally, in line 5 DataBus is assigned an explicit value, specified with double quotes.

Despite that each of the numbered lines above is correct, it would be illegal to put them together in one specification as shown above, due to the fact that bit_vector is an unresolved type and there can be only one assignment to an object of this type in an architecture.

Important Notes

· Logical values for objects of the Bit_vector type MUST be written in double quotes. Single elements, however, are of the bit type, therefore all values assigned to single elements are specified in single quotes.

Block Statement

Formal Definition

The block statement is a representation of design or hierarchy section, used for partitioning architecture into self-contained parts.

Simplified Syntax

block_label : block (optional_guard_condition)

   declarations

begin

   concurrent statements

end block block_label;

Description

The block statement is a way of grouping concurrent statements in an architecture. There are two main purposes for using blocks: to improve readability of the specification and to disable some signals by using the guard expression (see guard for details).

The main purpose of block statement is organizational only - introduction of a block does not directly affect the execution of a simulation model. For example, both the upper and lower sections of code in Example 1 will generate the same simulation results.

Each block must be assigned a label placed just before the block reserved word. The same label may be optionally repeated at the end of the block, right after the end block reserved words.

A block statement can be preceded by two optional parts: a header and a declarative part. The latter allows to introduce declarations of subprograms, types, subtypes, constants, signals, shared variables, files, aliases, components, attributes, configurations, disconnections, use clauses and groups (i.e. any of the declarations possible for an architecture). All declarations specified here are local to the block and are not visible outside it.

A block header may contain port and generic declarations (like in an entity), as well as so called port map and generic map declarations. The purpose of port map and generic map statements is to map signals and other objects declared outside of the block into the ports and generic parameters that have been declared inside of the block, respectively. This construct, however, has only a small practical importance. The Example 2 illustrates typical block declarations.

If an optional guard condition is specified at the beginning of the block then this block becomes a guarded block. See guard for details.

The statements part may contain any concurrent constructs allowed in an architecture. In particular, other block statements can be used here. This way, a kind of hierarchical structure can be introduced into a single architecture body.

Examples

Example 1

A1: OUT1 <= '1' after 5 ns;
LEVEL1 : block
begin
A2: OUT2 <= '1' after 5 ns;
A3: OUT3 <= '0' after 4 ns;
end block LEVEL1;
A1: OUT1 <= '1' after 5 ns;
A2: OUT2 <= '1' after 5 ns;
A3: OUT3 <= '0' after 4 ns;

Both pieces of code above will behave in exactly the same way during simulation - block construct only separates part of the code without adding any functionality.

Example 2

entity X_GATE is
generic (LongTime : Time; ShortTime : Time);
port (P1, P2, P3 : inout BIT);
end X_GATE;
architecture STRUCTURE of X_GATE is
-- global declarations of signal:
signal A, B : BIT;
begin
LEVEL1 : block
-- local declaration of generic parameters
generic (GB1, GB2 : Time);
-- local binding of generic parameters
generic map (GB1 => LongTime, GB2 => ShortTime);
-- local declaration of ports
port (PB1: in BIT; PB2 : inout BIT );
-- local binding of ports and signals
port map (PB1 => P1, PB2 => B);
-- local declarations:
constant Delay : Time := 1 ms;
signal S1 : BIT;
begin
   S1 <= PB1 after Delay;
   PB2 <= S1 after GB1, P1 after GB2;
end block LEVEL1;
end architecture STRUCTURE;

The signals PB1 and PB2 have here the same values as P1 and B (in port map statement), respectively, and the generics GB1 and GB2 (see generic map statement) have the same values as Long Time and Short Time, respectively. However, such assignment is redundant because a block may use any declarations of an entity, including generics and ports. The Example 2 is presented here only for illustration purpose of the block syntax.

Important Notes

· Guarded blocks are generally not synthesizable.

· Unguarded blocks are usually ignored by synthesis tools.

· It is strongly recommended NOT to use blocks in non-VITAL designs - the package Std_logic_1164 supports mechanisms and multiple value logic which make the reserved words bus, disconnect, guarded and register unnecessary. Also, instead of guarded blocks for modeling sequential behavior it is recommended to used clocked processes.

· VITAL specifications require the use of blocks.

· VHDL supports a more powerful mechanism of design partitioning which is called component instantiation. Component instantiation allows connecting a component reference in one entity with its declaration in another entity.

Boolean

Definition:

The Boolean type is predefined in the Standard package as an enumerated data type with two possible values: false and true.

Syntax:

type boolean is (false,true);

Description

The boolean type is used for conditional operations. Boolean objects can be used with any of the relational operators <, >, <=, >=, = or /=.

According to the definition type, the leftmost value of the Boolean type is false, therefore the default value of any object of the Boolean type is false.

Since the boolean type is defined in the Standard package, it can be used in any VHDL specification without additional declarations.

Examples

Example 1

signal CondSup : boolean;
. . .
CondSup <= true;
. . .
if CondSup then -- could be: if CondSup = true then

The CondSup signal is declared as boolean but without any initial value. Therefore, by default it will be assigned the false value. A conditional operation could have been used instead as shown in the comment, but such a form would contain useless redundancy and should be avoided.

Important Notes

· Unlike in traditional ("hand-based") digital design, boolean values (false and true) are NOT identical to logical 0 and 1, respectively. In VHDL, the latter form is a completely different type and is called the Bit type.

Case Statement

Formal Definition

The case statement selects for execution one of several alternative sequences of statements; the alternative is chosen based on the value of the associated expression.

Simplified Syntax

case expression is

when choice => sequential_statements

when choice => sequential_statements

         . . .

end case;

Description

The case statement evaluates the listed expressions and selects one alternative sequence of statements according to the expression value. The expression can be of a discrete type or a one-dimensional array of characters (example 1).

The case statement contains a list of alternatives starting with the when reserved word, followed by one or more choices and a sequence of statements.

An alternative may contain several choices (example 2), which must be of the same type as the expression appearing in the case statement. For each expression there should be at least one locally static choice. The values of each choice must be unique (no duplication of values is allowed).

A choice can be either a simple name (example 1), a name of a simple element (example 2) or discrete range (a slice, example 3). The choice types can be mixed.

A subtype with a constraint range (example 4) can substitute a slice.

Another option is to use an object name as the choice. The object must be of the same type as the expression in the case statement. Example 5 shows it for a constant.

When all explicitly listed choices do not cover all the alternatives (all the values available for an expression of given type) the others choice must be used because the choicestatements must cover all the alternatives, see example 5).

Examples

Example 1

P1:process
variable x: Integer range 1 to 3;
variable y: BIT_VECTOR (0 to 1);
begin
C1: case x is
      when 1 => Out_1 <= 0;
      when 2 => Out_1 <= 1;
      when 3 => Out_1 <= 2;
  end case C1;
C2: case y is
      when "00" => Out_2 <= 0;
      when "01" => Out_2 <= 1;
      when "10" => Out_2 <= 2;
      when "11" => Out_2 <= 3;
  end case C2;
end process;

Depending on the values of the variable x and y, we assign the values 0, 1, 2 or 3 (in the second case) to the signals Out_1 and Out_2 (both of type Integer).

Example 2

P2:process
type Codes_Of_Operation is (ADD,SUB,MULT,DIV);
variable Code_Variable: Codes_Of_Operation;
begin
C3: case Code_Variable is
      when ADD | SUB => Operation := 0;
      when MULT | DIV => Operation := 1;
  end case C3;
end process;

When two or more alternatives lead to the same sequence of operations then they can be specified as a multiple choice in one when clause.

Example 3

P3:process
type Some_Characters is ('a','b','c','d','e');
variable Some_Characters_Variable: Some_Characters;
begin
C4: case Some_Characters_Variable is
      when 'a' to 'c' => Operation := 0;
      when 'd' to 'e' => Operation := 1;
   end case C4;
end process;

Slices can be used as choices. In such a case, the slice name must come from the discrete range of the expression type.

Example 4

P5:process
variable Code_of_Operation : INTEGER range 0 to 2;
constant Variable_1 : INTEGER := 0;
begin
C6: case Code_of_Operation is
      when Variable_1 | Variable_1 + 1 =>
Operation := 0;
      when Variable_1 + 2 =>
Operation := 1;
  end case C6;
end process;

Constant used as a choice.

Example 5

P6:process
type Some_Characters is ('a','b','c','d','e');
variable Code_of_Address : Some_Characters;
begin
C7:case Code_of_Address is
      when 'a' | 'c' => Operation := 0;
      when others => Operation := 1;
   end case C7;
end process;

If the Code_of_Address variable is equal to 'a' and 'c', then the assignment Operation:=0; will be chosen. For the 'b', 'd' and 'e' values, the assignment Operation:=1; will be performed.

Important Notes

· The case expression must be of a discrete type or of a one-dimensional array type, whose element type is a character type.

· Every possible value of the case expression must be covered by the specified alternatives; moreover, every value may appear only once (no duplicates or overlapping of ranges is allowed).

· The When others clause may appear only once and only as the very last choice.

Character Type

Formal Definition

The character type object is an enumeration type object with at least one literal character among its enumeration literals.

Syntax:

Type character is an enumeration type with all acceptable characters listed. Its specificatio can be found in the STANDARD package.

Description

The CHARACTER type is a predefined type declared in the STANDARD package and the values of this type are the 256 characters of the ISO 8859-1 (Latin 1).

The set of predefined operations for the CHARACTER type contains all relational functions: "=", "/=", "<', "<=", ">", ">=".

Component Declaration

Formal Definition

A component declaration declares a virtual design entity interface that may be used in component instantiation statement.

Simplified Syntax

component component_name [ is ]

generic (generic_list);

port (port_list);

end component component_name;

Description

A component represents an entity/architecture pair. It specifies a subsystem, which can be instantiated in another architecture leading to a hierarchical specification. Component instantiation is like plugging a hardware component into a socket in a board (Fig. 1 in Example 1).

A component must be declared before it is instantiated. The component declaration defines the virtual interface of the instantiated design entity ("the socket") but it does not directly indicate the design entity.

The binding of a design entity to a given component may be delayed and may be placed either in the configuration specification or configuration declaration.

The component can be defined in package, design entity, architecture, or block declarations. If the component is declared in an architecture, it must be declared before the beginstatement of the architecture. In such a case, the component can be used (instantiated) in the architecture only.

A more universal approach is to declare a component in the package. Such a component is visible in any architecture, which uses this package.

Generics and ports of a component are copies of generics and ports of the entity the component represents.

Examples

Example 1

architecture STRUCTURE_2 of EXAMPLE is
component XOR_4 is
port(A,B: in BIT_VECTOR(0 to 3);
   C: out BIT_VECTOR(0 to 3));
end component XOR_4;
signal S1,S2 : BIT_VECTOR(0 to 3);
signal S3 : BIT_VECTOR(0 to 3);
begin
X1 : XOR_4 port map(S1,S2,S3);
end architecture STRUCTURE_2;

The XOR_4 component has two 4-bit input ports (A and B) and the 4-bit output port C. The declaration of this component is located in the declaration part of the architecture body STRUCTURE_2. The component instantiation statement assigns the X1 label to instantiated XOR_4 component and it associates its input-output interface with the S1, S2 and S3 signals.

VHDL_Component_Declaration

Figure 1. Example of component declaration and instantiation

Important Notes

· A component declaration does not define which entity/architecture pair is bound to each instance. Such an information is defined by configuration.

Component Instantiation

Formal Definition

A component instantiation statement defines a subcomponent of the design entity in which it appears, associates signals or values with the ports of that subcomponent, and associates values with generics of that subcomponent.

Simplified Syntax

label : [ component ] component_name

generic map ( generic_association_list )

port map ( port_association_list );

label : entity entity_name [(architecture_identifier)]

generic map ( generic_association_list )

port map ( port_association_list );

label : configuration configuration_name

generic map ( generic_association_list )

port map ( port_association_list );

Description

A component represents an entity/architecture pair. It specifies a subsystem, which can be instantiated in another architecture, leading to a hierarchical specification. Component instantiation is like plugging a hardware component into a socket in a board (Fig. 1 in Example 1).

The component instantiation statement introduces a subsystem declared elsewhere, either as a component or as an entity/architecture pair (without declaring it as a component).

The component instantiation contains a reference to the instantiated unit and actual values for generics and ports. There are three forms of component instantiation:

· instantiation of a component;

· instantiation of a design entity;

· instantiation of a configuration;

See configuration for details on the third form.

The actual values of generic map aspect and port map aspect connections allow assigning the components of the actual values to generic parameters and ports.

INSTANTIATION OF A COMPONENT

Instantiation of a component introduces a relationship to a unit defined earlier as a component (see component declaration). The name of the instantiated component must match the name of the declared component. The instantiated component is called with the actual parameters for generics and ports. The association list can be either positional or named.

In the positional association list, the actual parameters (generics and ports) are connected in the same order in which ports were declared in the component (Example 1).

Named association allows to list the generics and ports in an order that is different from the one declared for the component. In such a case the ports have to be explicitly referenced (Example 2).

INSTANTIATION OF A DESIGN ENTITY

It is not necessary to define a component to instantiate it: the entity/architecture pair can be instantiated directly. In such a direct instantiation, the component instantiation statement contains the design entity name and optionally the name of the architecture to be used for this design entity. The reserved word entity follows the declaration of this type of the component instantiation statement (Example 3).

If architecture name is not specified in an instantiation of a design entity, the last compiled architecture associated with the entity will be taken.

Examples

Example 1

architecture Structural of ALU is
signal X,Y,S,C : bit;
component HalfAdder is
port (In1, In2 : in bit;
          Sum, Carry : out bit);
end component HalfAdder;
begin
HA : HalfAdder port map (X,Y,S,C);
. . .
end architecture Structural;

The structural specification of an arithmetic-logic unit ALU uses an instantiation of a HalfAdder component. Note that the component is instantiated with signals of the ALU system. The signals are associated positionally.

Example 2

architecture Structural of ALU is
signal X,Y,S,C : bit;
component HalfAdder is
port (In1, In2 : in bit;
         Sum, Carry : out bit);
end component HalfAdder;
begin
HA : HalfAdder port map (Sum=>S, Carry=>C,
In1=>X, In2=>Y);
. . .
end architecture Structural;

This structural architecture performs the same function as in the Example 1. The only difference lies in the way the association list is specified for the component ports - the signals are associated with named association.

Example 3

entity XOR_GATE_4 is
   port(IN1,IN2: in BIT_VECTOR(0 to 3);
        OUT1 : out BIT_VECTOR(0 to 3));
end entity XOR_GATE_4;
architecture XOR_BODY_4 of XOR_GATE_4 is
begin
OUT1 <= IN1 xor IN2 after 5 ns;
end architecture XOR_BODY_4;
entity EXAMPLE is
end entity EXAMPLE;
architecture STRUCTURE_1 of EXAMPLE is
signal S1,S2 : BIT_VECTOR(0 to 3);
signal S3 : BIT_VECTOR(0 to 3);
begin
X1 : entity WORK.XOR_GATE_4(XOR_BODY_4)
          port map (S1,S2,S3);
end architecture STRUCTURE_1;

Entity XOR_GATE_4 is directly instantiated here, without declaring a component. The architecture, which specifies the body of the entity XOR_GATE_4 is called XOR_BODY_4 and is supported in parentheses. Further specification is similar to the one in instantiation of a component. The entity and architecture instantiated here must be located in the WORK library prior to this instantiation.

Component_Instantiation

Figure 1. Example of a direct instantiation.

Important Notes

· The label for component instantiation is obligatory.