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...

Sunday, 23 December 2012

Operator Overloading

Definition:

Operator overloading is a declaration of a function whose designator is an operator symbol.

Simplified Syntax

function "operator" (parameters) return type is

function "operator" (parameters) return type is

declarations

  begin

    sequential statements

  end function;

Description

The operator is called overloaded if there is more than one function specifying it for different data and result types. VHDL allows defining operators of the same names as predefined operators, but for different operand types. Both can exist together in one specification, offering greater versatility to the user.

Such functions can be invoked both with prefix notation (Example 1) and usual infix notation (Example 2).

In the case when the operator is called and the operand values belong to different types, it is necessary to use the type conversion or the qualified expression in order to select appropriate operator (Example 3).

Examples

Example 1

type Log4 is ('0', '1', 'Z', 'X');
function "nand" (Left, Right: Log4) return Log4;
function "or" (Left, Right: Log4) return Log4;
signal S1, S2: Log4;
S1 <= "or" ('1', 'Z');
S2 <= "nand"(S1, 'X');

Functions or and nand implement basic logic operations for operands of type Log4 overloading the predefined operations of the same names. In the above example these functions are called using the standard call syntax function (prefix).

Example 2

signal S3, S4: Log4;
S3 <= (S1 nand S2) or 'X';

The operators or and nand are overloaded through the declarations as in the Example 1. Here the overloaded operators are used in the infix form, i.e. with the operator name between the operands.

Example 3

function "or" (Left, Right: Log4) return Bit;
signal S4: Bit;
S4 <= log4('1') or Log4('0');

The or operator is used here in a 4-value logical expression by connecting '1' and '0' operands with the or symbol. The qualified expression was used here to indicate the type of operands (which otherwise would be considered to be of the type BIT).

Important Notes

· Operators "+" and "-" can be defined both as binary operators (with two operands) or unary operators (with one operand).

· Invoking a user-defined overloaded operator always requires evaluation of both operands before the operation is executed (some predefined operators do not evaluate the right operand if the result can be decided from the left operand only).

Null Statement

Formal Definition

A statement which does not perform any action.

Simplified Syntax

null;

Description

The null statement does not perform any action and its only function is to pass on to the next statement. It can be used to indicate that when some conditions are met no action is to be performed. Such an application is useful in particular in conjunction with case statements to exclude some conditions (see example).

Examples

case OPCODE is
  when "001" => TmpData := RegA and RegB;
  when "010" => TmpData := RegA or RegB;
  when "100" => TmpData := not RegA;
  when others => null;
end case;

The example shows an operand detection of a processor, restricted to some simple logical operations performed on registers. All other operations are blocked ("if the OPCODE is other than the explicitly listed, do nothing").

Important Notes

· The keyword null is used not only for "no operation" statements. It has a special meaning for variables of access types ("pointing at no object", which is the default value for such variables - see access type and allocator). There is also a null transaction in waveforms. These three applications of the keyword null should not be confused.

Operators

Definition:

Operators are means for constructing expressions.

Syntax:

adding_operator ::= + | - | &

logical_operator ::= and | or | nand | nor | xor | xnor

miscellaneous_operator ::= ** | abs | not

multiplying_operator ::= * | / | mod | rem

relational_operator ::= = | /= | < | <= | > | >=

shift_operator ::= sll | srl | sla | sra | rol | ror

Description

VHDL has a wide set of different operators, which can be divided into groups of the same precedence level (priority). The table below lists operators grouped according to priority level, highest priority first.

Table 1. Operator priority

miscellaneous operators

** | abs | not

multiplying operators

* | / | mod | rem

sign operators

+ | -

adding operators

+ | - | &

shift operators

sll | srl | sla | sra | rol | ror

relational operators

= | /= | < | <= | > | >=

logical operators

and | or | nand| nor | xor | xnor

The expressions are evaluated form left to right, operations with higher precedence are evaluated first. If the order should be different from the one resulting from this rule, parentheses can be used (Example 1).

The operands, connected with each other by an operator, are evaluated before the operation described by that operator is carried out. For some operators the right operand is evaluated only when the left operand has a certain value assigned to it. The logical operators such as and, or, nand, nor defined for the BIT and BOOLEAN operands belong to those operators.

The operators for the predefined types are defined in the STANDARD package in the STD library. These operators are functions, which always return the same value when they are called with the same values of the actual parameters. These functions are called the pure function (see function for details).

LOGICAL OPERATORS

The logical operators and, or, nand, nor, xor, xnor and not are defined for BIT and BOOLEAN types, as well as for one-dimensional arrays containing the elements of BIT and BOOLEAN. All these operators have the lowest priority, except for the operator not, which has the highest priority. The results of the logical operators for the predefined types are presented in the tables 2 through 8. The BIT type is represented by the values '0' and '1', while the Boolean type by True and False.

Table 2. Operator not

A

not A

True

'1'

False

'0'

False

'0'

True

'1'

Table 3. Operator and

A

B

A and B

True

'1'

True

'1'

True

'1'

True

'1'

False

'0'

False

'0'

False

'0'

True

'1'

False

'0'

False

'0'

False

'0'

False

'0'

Table 4. Operator or

A

B

A or B

True

'1'

True

'1'

True

'1'

True

'1'

False

'0'

True

'1'

False

'0'

True

'1'

True

'1'

False

'0'

False

'0'

False

'0'

Table 5. Operator xor

A

B

A xor B

True

'1'

True

'1'

False

'0'

True

'1'

False

'0'

True

'1'

False

'0'

True

'1'

True

'1'

False

'0'

False

'0'

False

'0'

Table 6. Operator nand

A

B

A nand B

True

'1'

True

'1'

False

'0'

True

'1'

False

'0'

True

'1'

False

'0'

True

'1'

True

'1'

False

'0'

False

'0'

True

'1'

Table 7. Operator nor

A

B

A nor B

True

'1'

True

'1'

False

'0'

True

'1'

False

'0'

False

''0'

False

'0'

True

'1'

False

'0'

False

'0'

False

'0'

True

'1'

Table 8. Operator xnor

A

B

A xnor B

True

'1'

True

'1'

True

'1'

True

'1'

False

'0'

False

''0'

False

'0'

True

'1'

False

'0'

False

'0'

False

'0'

True

'1'

RELATIONAL OPERATORS

The relational operators allow checking relation between operands, i.e. to state whether they are equal, not equal or are ordered in a way defined by operator (Table 9). Both operands must be of the same type, and the result received is always of the Boolean type.

Table 9. Relational operations

=

Equality

/=

Inequality

<

Ordering „less than”

<=

Ordering „less than or equal”

>

Ordering „greater than”

>=

Ordering „greater than or equal”

The operators: equality and inequality are predefined for all types available in the language except the file type. For other relations the operands must be of a scalar type or one-dimensional array types.

The equality operator returns the value TRUE only when both operands have the same values, and FALSE when the values are different. The inequality operator returns the value TRUE when the operators are different and FALSE when they are equal. There are certain rules that are used to compare operands depending on their type: in case of the scalar type, the operand values are equal only when the values are the same. Two values of the composite type are equal only when each value of the left operand corresponds to the value of the right operand and vice versa. In the record the corresponding elements have identical identifiers, and in the array the corresponding elements are those which appear at the same positions of arrays. In particular two null arrays of the same type are always equal.

The operators: <, <=, >, and >= return the TRUE logical value only when the condition in the given relation is met, otherwise the FALSE value is returned (Example 4).

SHIFT OPERATORS

The shift operators are defined for the one-dimensional array with the elements of the type BIT or BOOLEAN. For the shift operator an array is the left operand L and integer is the right operand R. The right operand represents the number of positions the left operand should be shifted. As the result of shifting, the value of the same type as the left operand is returned. Table 10 below shows predefined shift operators.

Table 10. Shift operators

sll

Shift left logical

srl

Shift right logical

sla

Shift left arithmetic

sra

Shift right arithmetic

rol

Rotate left logical

ror

Rotate right logical

The operator sll returns the value of the L left operand, after it has been shifted R number of times. If R is equal to 0 or L is the null array, the left operand L is returned. The single left logical operation replaces L with concatenation of the rightmost (L'Length -1) elements of L and a single value T'Left, where T is the element type of L. If R > the single shift operation is repeated R number of times. If R is a negative number, the value of the expression L srl -R is returned.

The operator srl returns the value of the left operand L after it has been shifted to right R times. In case when R is equal to 0 or L is the null array, the left operand L is returned. The single shifting operation replaces the operand L with the concatenation of the leftmost L'Length -1 elements of L and a single value T'Left, where T is the element type of L. If R is a negative number then the value of expression L sll -R is returned, otherwise the single shift operation is repeated R number of times.

The operator sla returns the value of the left operand L after it has been shifted to the left R number of times. In case when R is equal to 0 or L is the null array the left operand L is returned. The single shift operation replaces L with concatenation of the rightmost L'Length -1 elements of L and a single value L'Right. If R is a negative number, the value of the expression L sra -R is returned, otherwise the single shift operation is repeated R number of times.

The operator sra returns the value of the left operand L after it has been shifted to the right R number of times. In case when R is equal to 0 or L is the null array, the left operand L is returned. The single shift operation replaces L with a value, which is the result of concatenation whose left argument is the leftmost L'Length -1 elements of L and whose right argument is L'Left. If R is a negative number, the value of the expression L sla -R is returned, otherwise the single shift operation is repeated R number of times.

The operator rol returns the value of the L left operand after it has been rotated to the left R times. In case when R is equal to 0 or L is the null array the left operand L is returned. The single shift operation replaces L with a value which is the result of concatenation of the rightmost L'Length -1 elements of L and a single value L'Left. If R > 1 the sing.le shift operation is repeated R times. If R > 1 is a negative number, the expression L ror -R is returned.

The operator ror returns the value of the L left operand after it has been rotated to the right R number of times. In case when R is equal to 0 or L is the null array, the left operand L is returned. The single shift operation replaces L with a value which is the result of concatenation whose left argument is the leftmost L'Length -1 elements of L and whose right argument is L'Right. If R > 1 the single shift operation is repeated R times. If R is a negative number, the expression L rol -R is returned.

ADDING OPERATORS

Adding operators consist of addition, subtraction and concatenation. The adding operators are shown in the Table 11 below.

Table 11. Adding operators

+

Addition

-

Subtraction

&

Concatenation

The adding and subtraction operators perform mathematical operations, and their operands can be of any numeric type.

The concatenation (&) operator is defined for elements of one-dimensional arrays. In the concatenation, the following situations can take place:

· When both operands are one-dimensional arrays of the same type, the concatenation connects the two arrays into one. The new array contains the elements from both arrays. The direction of the new array is the same as the direction in the array of the left operand, but if the left operand is the null array then it is the same as the direction of the right operand. In case when both operands are null arrays, the direction of the right operand is assumed (Example 6).

· When one of the operands is a one-dimensional array and the second operand is a scalar of the same type as the elements of that array, then the result of the concatenation is the same as in the first point. However, in this case the second operand is treated as a one-dimensional array which contains only one element (Example 6).

· In case when both operands are of the same scalar type, then the result of concatenation is one-dimensional array with elements of the same types as the operands (Example 6).

SIGN OPERATORS

Sign operators are unary operators, i.e. have only one, right operand, which must be of a numeric type. The result of the expression evaluation is of the same type as the operand. There are two sign operators (Table 12).

Table 12. Sign operators

+

Identity

-

Negation

When ( + ) sign operator is used, the operand is returned unchanged, but In case of ( - ) sign operator the value of operand with the negated sign is returned. Because of the lower priority, the sign operator in the expression cannot be directly preceded by the multiplication operator, the exponentiation operator (**) or the abs and not operators. When these operators are used then sign operator and its operand should be enclosed in parentheses (Example 7).

MULTIPLYING OPERATORS

The multiplication and division operators are predefined for all integers, floating point numbers. Under certain conditions, they may be used for operations on physical type objects as well. The mod and rem operators, on the other hand, are defined only for the integers. When mod and rem operators are used, then both the operands and the result are of the same integer type. The multiplying operators are shown in the Table 13.

Table 13. Multiplying operators

*

Multiplication

/

Division

mod

Modulus

rem

Remainder

MISCELLANEOUS

The two miscellaneous operators are shown in the Table 14.

Table 14. Miscellaneous operators

**

Exponentiation

abs

Absolute value

The abs operator has only one operand. It allows defining the operand's absolute value. The result is of the same type as the operand.

The exponentiation operator has two operands. This operator is defined for any integer or floating point number. The right operand (exponent) must be of integer type. When the exponent is the positive integer, then the left operand is repeatedly multiplied by itself. When the exponent is the negative number, then the result is a reverse of exponentiation with the exponent equal to the absolute value of the right operand (Example 9). If the exponent is equal to 0 the result will be 1.

Examples

Example 1

v := a + y * x;

The multiplication y*x is carried out first, then a is added to the result of multiplication. This is because the multiplication operator has higher level of priority than the adding operator.

Example 2

variable We1, We2, We3, Wy : BIT := '1';
Wy := We1 and We2 xnor We1 nor We3;

For the initial value of the variables We1, We2, We3 equal to '1', the result is assigned to the variable Wy and is equal to '0'.

Example 3

variable Zm1: REAL := 100.0;
variable Zm2 : BIT_VECTOR(7 downto 0) := ('0','0','0','0','0','0','0','0');
variable Zm3, Zm4 : BIT_VECTOR(1 to 0);
Zm1 /= 342.54 -- True
Zm1 = 100.0 -- True
Zm2 /= ('1', '0', '0', '0', '0', '0', '0', '0') -- True
Zm3 = Zm4 -- True

Example 4

Zm1 > 42.54 -- True
Zm1 >= 100.0 -- True
Zm2 < ('1', '0', '0', '0', '0', '0', '0', '0') -- True
Zm3 <= Zm2 -- True

Example 5

variable Zm5 : BIT_VECTOR(3 downto 0) := ('1','0','1','1');
Zm5 sll 1 -- ('0', '1', '1', '0')
Zm5 sll 3 -- ('1', '0', '0', '0')
Zm5 sll -3 -- Zm5 srl 3
Zm5 srl 1 -- ('0', '1', '0', '1')
Zm5 srl 3 -- ('0', '0', '0', '1')
Zm5 srl -3 -- Zm5 sll 3
Zm5 sla 1 -- ('0', '1', '1', '1')
Zm5 sla 3 -- ('1', '1', '1', '1')
Zm5 sla -3 -- Zm5 sra 3
Zm5 sra 1 -- ('1', '1', '0', '1')
Zm5 sra 3 -- ('1', '1', '1', '1')
Zm5 sra -3 -- Zm5 sla 3
Zm5 rol 1 -- ('0', '1', '1', '1')
Zm5 rol 3 -- ('1', '1', '0', '1')
Zm5 rol -3 -- Zm5 ror 3
Zm5 ror 1 -- ('1', '1', '0', '1')
Zm5 ror 3 -- ('0', '1', '1', '1')
Zm5 ror -3 -- Zm5 rol 3

Example 6

constant B1: BIT_VECTOR := "0000"; -- four element array
constant B2: BIT_VECTOR := "1111"; -- four element array
constant B3: BIT_VECTOR := B1 & B2; -- eight element array, ascending
-- direction, value "00001111"
subtype BIT_VECTOR_TAB is BIT_VECTOR (1 downto 0);
constant B4: BIT_VECTOR_TAB := "01";
constant B5: BIT_VECTOR:= B4 & B2; -- six element array, descending
-- direction, value "011111"
constant B6 : BIT := '0' ;
constant B7 : BIT_VECTOR := B2 & B6;-- five element array, ascending
-- direction, value "11110"
constant B8: BIT := '1';
constant B9: BIT_VECTOR := B6 & B8; -- two element array, ascending
-- direction value "01"
Example 7
z := x * ( -y) -- A legal expression
z := x / (not y) -- A legal expression

The same expressions without parentheses would be illegal.

Example 7

variable A,B :Integer;
variable C : Real;
C:= 12.34 * ( 234.4 / 43.89 );
A:= B mod 2;

Example 8

2 ** 8 = 256
3.8 ** 3 = 54.872
4 ** (-2) = 1 / (4**2) = 0.0625

Important Notes

· All predefined operators for standard types are declared in the package STANDARD.

· The operator not is classified as a miscellaneous operator only for the purpose of defining precedence. Otherwise, it is classified as a logical operator.

Package

Formal Definition

A package declaration defines the interface to a package.

Simplified Syntax

package package_name is

package_declarations

end package package_name;

Description

The package is a unit that groups various declarations, which can be shared among several designs. Packages are stored in libraries for greater convenience. A package consists of package declaration (mandatory) and may contain a single optional package body.

The purpose of a package is to declare shareable types, subtypes, constants, signals, files, aliases, component, attributes and groups. Once a package is defined, it can be used in multiple independent designs.

Items declared in a package declaration are visible in other design units if the use clause is applied (Example 1).

The two-part specification of a package (declaration and body) allows to declare the so-called deferred constants which have no value assigned in the package declaration (Example 2). The value for a deferred constant, however, must be declared in the package body accompanying the package declaration.

The VHDL Language Standard defines two standard packages, which must be available in any VHDL environment - package STANDARD and package TEXTIO. The former contains basic declarations of types, constants and operators, while the latter defines operations for manipulating text files. Both are located in the library STD. See respective topics for details.

Apart from the VHDL Language Standard there is another standard, which extends the language and supports the extensions in the form of a package: Std_Logic_1164.

Examples

Example 1

library Packages;
use Packages.AUXILIARY.all;
architecture STRUCT of Adder is
................
end architecture STRUCT;

All declarations, which are inside the AUXILIARY package, may be used in the architecture body STRUCT of the design entity Adder. The package itself is stored in the library Packages.

Example 2

library IEEE;
use IEEE.STD_LOGIC_1164.all;
package AUXILIARY is
type MUX_input is array (INTEGER range<>) of STD_LOGIC_VECTOR (0 to 7);
type operation_set is (SHIFT_LEFT, ADD);
subtype MUX_address is POSITIVE;
function Compute_Adress (IN1 : MUX_input) return MUX_address;
constant Deferred_Con : Integer;
end AUXILIARY;

Package AUXILIARY contains a function declaration and a deferred constant, thus a package body had to be declared for this package.

Important Notes

· Package declaration may contain a subprogram (function or procedure) declaration; subprogram body is not allowed here and must appear in the package body.

· Package body must accompany a package declaration if the declaration contains subprogram declarations or deferred constants.

Package Body

Formal Definition

A package body defines the bodies of subprograms and the values of deferred constants declared in the interface to the package.

Simplified Syntax

package body package_name is

package_body_declarations

subprogram bodies declarations

deferred constants declarations

end package body package_name;

Description

The package body includes complete definitions of subprogram body declarations as well as values of deferred constants declared in corresponding package declarations. Other declarations (similar to those of package declaration) are also allowed here, but are visible only inside the package body.

The deferred constant, which has been declared in a package declaration, may be used before its full declaration only in a default expression for a local generic parameter, local port or formal parameter of subprogram.

Examples

Example 1

library IEEE;
use IEEE.STD_LOGIC_1164.all;
package AUXILIARY is
  type MUX_input is array (INTEGER range<>) of STD_LOGIC_VECTOR (0 to 7);
  type operation_set is (SHIFT_LEFT, ADD);
  subtype MUX_Address is POSITIVE;
  function Compute_Address (IN1 : MUX_input) return MUX_address;
  constant Deferred_Con : Integer;
end AUXILIARY;
package body AUXILIARY is
  function Compute_Address (IN1 : MUX_input) return MUX_address is
  begin
  ............
  end;
  constant Deferred_Con : Integer := 177;
end package body AUXILIARY;

First, the package is specified here and then the accompanying package body. Note that both have the same name.

Important Notes

· Declarations other than values of deferred constants and subprogram bodies are not visible outside the package body and can be used only locally, inside it.

· Each package can have only one body.

Physical Type

Formal Definition

Physical type is a numeric scalar that represents some quantity. Each value of a physical type has a position number that is an integer value. Any value of a physical type is a straight multiple of the primary unit of measurement for that type.

Simplified Syntax

type type_name is range left_bound to right_bound

units

  primary_unit_name

  secondary_unit_name = number primary_unit_name

  secondary_unit_name = number primary_unit_name

  . . .

end units type_name

type type_name is range left_bound downto right_bound

units

  primary_unit_name

  secondary_unit_name = number primary_unit_name

  secondary_unit_name = number primary_unit_name

  . . .

end units type_name

Description

A physical type allows to define measurement units for some physical quantity, like length, time, pressure, capacity, etc.

The range, specified at the beginning of a physical type, defines the minimum and maximum values of a given quantity expressed in the base units (see primary unit declaration below). The bounds of the range of a physical type should be in the form of locally static expression. The expression is classified as locally static if it is possible to determine its value without running the code. The value of an expression used as a range for a physical type must be of integer type. It is legal to use negative bounds.

At the core of a physical type declaration is the definition of a primary unit, and optionally, multiple secondary units. The primary unit serves as the base unit for representing values of the specified type. The secondary units are defined as multiplicity of primary units or previously specified secondary units. Their declarations may contain only integer literals.

Each value of a physical type has a corresponding position number, which is the number of primary units represented by that unit name. This way values specified in different units of the same type can be compared (Example 2).

For all physical types, both TIME and user-defined, relational and arithmetic operators can be used.

The VHDL standard predefines only one physical type: TIME, which is defined in the STANDARD package.

The value of one unit can be written in short form using the name of the unit only (i.e. without the value 1 - Example 3).

Examples

Example 1

type CAPACITY is range 0 to 1E5
units
  pF; -- picofarad
  nF = 1000 pF; -- nanofarad
  uF = 1000 nF; -- microfarad
  mF = 1000 uF; -- milifarad
  F = 1000 mF; -- farad
end units CAPACITY;

The primary unit in this example is one picofarad and the maximum value of the CAPACITY type object is 105 pF.

Example 2.

type DISTANCE is range 0 to 1E5
  units
    um; -- micrometer
    mm = 1000 um; -- millimeter
    in_a = 25400 um; -- inch
  end units DISTANCE;
variable Dis1, Dis2 : DISTANCE;
Dis1 := 28 mm;
Dis2 := 2 in_a - 1 mm;
if Dis1 < Dis2 then ...

Both, a comparison and an arithmetic operation can be performed on visually different measurement units as long as they are defined as the same type with the same base unit.

Example 3

SomeVar := mF;

This assignment means that the variable SomeVar will be assigned the value of 1 mF.

Important Notes

· Physical types are not synthesizeable. As a result, delays in signal assignments are not synthesizeable as well.

· It is not allowed to use floating point values in physical type declarations, i.e. if a conversion from millimeters to inches (25.4 mm = 1 in) would have to be performed, then millimeters could not be used as the base unit.

Port

Formal Definition

A channel for dynamic communication between a block and its environment.

Simplified Syntax

port ( port_declaration, port_declaration, &ldots;);

-- port declarations:

port_signal_name : in port_signal_type := initial_value

port_signal_name : out port_signal_type := initial_value

port_signal_name : inout port_signal_type := initial_value

port_signal_name : buffer port_signal_type := initial_value

port_signal_name : linkage port_signal_type := initial_value

Description

Ports are a part of the block interface: external - if defined by a design entity, or internal - if defined by a block statement. Each element listed in a port interface list declares a formal port, which provides a channel for dynamic communication between a block and its environment.

In practice, ports are most often used in entities and components, where they serve for declaring interface signals of a design entity (system design) or component, respectively.

In both cases, each interface element is a signal. It can be preceded by a keyword signal. After the signal's name, a mode is specified. The mode declares the direction of data flow through the port. There are five modes available in VHDL for ports:

· in input port. A variable or a signal can read a value from a port of mode in, but is not allowed to assign a value to it.

· out output port. It is allowed to make signal assignments to a port of the mode out, but it is not legal to read from it.

· inout bi-directional port. Both assignments to such a port and reading from it are allowed.

· buffer output port with read capability. It differs from inout in that it can be updated by at most one source, whereas inout can be updated by zero or more sources.

· linkage . The value of the port may be read or updated, but only by appearing as an actual corresponding to an interface object of mode linkage.

If a port is declared with a reserved word bus, then the signal declared by that port is a guarded signal of signal kind bus.

A port can be assigned a default value, which is specified by an expression evaluating to the same type as the port itself.

Examples

Example 1

entity Mux8to1 is
port (
     Inputs : in Std_Logic_Vector(7 downto 0);
     Select_s : in Std_Logic_Vector(2 downto 0);
     Output : out Std_Logic
     );
end Mux8to1;

Entity of a multiplexor 8-to-1 contains three ports: eight data inputs (specified as a vector), address inputs and one output.

Example 2

component MemDev is
port(
     Data : inout Std_Logic_Vector(7 downto 0);
     Addr : in Std_Logic_Vector(9 downto 0);
     NotCS : in Std_Logic;
     RdNotWr : in Bit
    );
end component MemDev;

Memory device is specified here as a component with four signals: data is a bi-directional data bus, address is a ten-bit input, and NotCS and RdNotWr are single inputs signals. Note that the keyword is in the header can be used in VHDL 93 only (in VHDL 87 it must be omitted).

Important Notes

· Ports declarations are signal declarations and port signals need not to be re-declared.