Friday, July 31, 2015

Structural Modeling

In structural style of modeling, an entity is modeled as a set of components connected by signals, that is, as a netlist.

The behavior of the entity is not explicitly apparent from its model. The component instantiation statement is the primary mechanism used for describing such a model of an entity.
Eg.,

Fig.1: Circuit generating control signals
library IEEE;
use IEEE.std_logic_1164.all;

entity GATING is
port (A, CK, MR, DIN: in BIT; RDY, CTRLA: out BIT);
end GATING;

architecture STRUCTURE_VIEW of GATING is
component AND2
port (X, Y: in BIT; Z: out BIT);
end component;
component DFF
port (D, CLOCK: in BIT; Q, QBAR: out BIT);
end component;
component NOR2
port (A, B: in BIT; Z: out BIT);
end component;
signal SI, S2: BIT;
begin
D1: DFF port map (A, CK, SI, S2);
A1: AND2 port map (S2, DIN, CTRLA);
N1: NOR2 port map (SI, MR, RDY);
end STRUCTURE_VIEW;
library IEEE;
use IEEE.std_logic_1164.all;

entity AND2 is
port (X, Y: in BIT; Z: out BIT);
end AND2;

architecture DATAFLOW of AND2 is
begin
Z<=X and Y;
end DATAFLOW;

library IEEE;
use IEEE.std_logic_1164.all;

entity NOR2 is
port (A, B: in BIT; Z: out BIT);
end NOR2;

architecture DATAFLOW of NOR2 is
begin
Z<=A nor B;
end DATAFLOW;

library IEEE;
use IEEE.std_logic_1164.all;

entity DFF is
port (D, CLOCK: in BIT; Q, QBAR: out BIT);
end DFF;

architecture BEHAVIORAL of DFF is
begin
process(D<CLOCK)
begin
if(CLOCK=’1’ and CLOCK’ event) then
Q<=D;
QBAR<=not D;
else
Q<=Q;
QBAR<=QBAR;
end if;
end process;
end DATAFLOW;

Three components, AND2, DFF, and NOR2, are declared, which are instantiated in the architecture body via three component instantiation statements, and the instantiated components are connected to each other via signals SI and S2.

The component instantiation statements are concurrent statements, and therefore, their order of appearance in the architecture body is not important.

A component can, in general, be instantiated any number of times. However, each instantiation must have a unique component label; as an example, A1 is the component label for the AND2 component instantiation.

Component Declaration

A component instantiated in a structural description must first be declared using a component declaration. A component declaration declares the name and the interface of a component. The interface specifies the mode and the type of ports.

The syntax of a simple form of component declaration is

component component-name
port ( list-of-interface-ports ) ;
end component;

The component-name may or may not refer to the name of an already existing entity in a library. If it does not, it must be explicitly bound to an entity; otherwise, the model cannot be simulated. This is done using a configuration.

The list-of-interface-ports specify the name, mode, and type for each port of the component in a manner similar to that specified in an entity declaration.

component NAND2
port (A, B: in MVL;
Z: out MVL);
end component;

component MP
port (CK, RESET, RON, WRN: in BIT;
DATA_BUS: inout INTEGER range 0 to 255;
ADDR_BUS: in BIT_VECTOR(15 downto 0));
end component;

component RX
port (CK, RESET, ENABLE, DATAIN, RD: in BIT;
DATA_OUT: out INTEGER range 0 to (2**8 - 1);
PARITY_ERROR, FRAME_ERROR,
OVERRUN_ERROR: out BOOLEAN);
end component;

Component declarations appear in the declarations part of an architecture body. Alternately, they may also appear in a package declaration. Items declared in this package can then be made visible within any architecture body by using the library and use context clauses.

Eg., consider a package created to hold the component declarations.

package COMP_LIST is
component AND2
port (X, Y: in BIT: Z: out BIT):
end component;
component DFF
port (D, CLOCK: in BIT; Q, QBAR: out BIT);
end component;
component NOR2
port (A, B: in BIT; Z: out BIT);
end component;
end COMP_LIST;

Assuming that this package has been compiled into design library DES_LIB, the architecture body can be rewritten as

library DES_LIB;
use DES_LIB.COMP_LIST.all;
architecture STRUCTURE_VIEW of GATING is
signal S1, S2: BIT;
-- No need for specifying component declarations here, as they are        
-- made visible to architecture body using the context clauses.
begin
-- The component instantiations here.
end STRUCTURE_VIEW;

The advantage of this approach is that the package can now be shared by other design units and the component declarations need not be specified inside every design unit.

Component Instantiation

A component instantiation statement defines a subcomponent of the entity in which it appears. It associates the signals in the entity with the ports of that subcomponent.

A format of a component instantiation statement is

component-label: component-name port map ( association-list) ',

The component-label can be any legal identifier and can be considered as the name of the instance.

The component-name must be the name of a component declared earlier using a component declaration.

The association-list associates signals in the entity, called actuals, with the ports of a component, called locals. An actual must be an object of class signal. Expressions or objects of class variable or constant are not allowed. An actual may also be the keyword open to indicate a port that is not connected.

There are two ways to perform the association of locals with actuals:
1. positional association,
2. named association.

In positional association, an association-list is of the form

actuali, actualg, actual3, . . ., actual

Each actual in the component instantiation is mapped by position with each port in the component declaration, i.e., the first port in the component declaration corresponds to the first actual in the component instantiation, the second with the second, and so on.

Consider an instance of a NAND2 component.

-- Component declaration:
component NAND2
port (A, B: in BIT; Z: out BIT);
end component;
-- Component instantiation:

N1: NAND2 port map (S1, S2, S3);

N1 is the component label for the current instantiation of the NAND2 component. Signal S1 (which is an actual) is associated with port A (which is a local) of the NAND2 component, S2 is associated with port B of the NAND2 component, and S3 is associated with port Z. Signals S1 and S2 thus provide the two input values to the NAND2 component and signal S3 receives the output value from the component. The ordering of the actuals is important.

If a port in a component instantiation is not connected to any signal, the keyword open can be used to signify that the port is not connected.

Eg.,
N3: NAND2 port map (S1, open, S3);

The second input port of the NAND2 component is not connected to any signal. An input port may be left open only if its declaration specifies an initial value.

For the previous component instantiation statement to be legal, a component declaration for NAND2 may appear like

component NAND2
port (A, B: in BIT := '0'; Z: out BIT);
-- Both A and B have an initial value of '0'; however, only
-- the initial value of B is necessary in this case.
end component;

A port of any other mode may be left unconnected as long as it is not an unconstrained array.

In named association, an association-list is of the form

locale => actual1, local2 => actual2, ..., localn => actualn

Eg.,
N1: NOR2 port map (B=>MR, Z=>RDY, A=>S1);

In this case, the signal MR (an actual), that is declared in the entity port list, is associated with the second port (port B, a local) of the NOR2 gate, signal RDY is associated with the third port (port Z) and signal S1 is associated with the first port (port A) of the NOR2 gate.

In named association, the ordering of the associations is not important since the mapping between the actuals and locals are explicitly specified.

Note:

The scope of the locals is restricted to be within the port map part of the instantiation for that component; Eg., the locals A, B, and Z of component NOR2 are relevant only within the port map of instantiation of component NOR2.

Rules for either type of association:

1.   The types of the local and the actual being associated must be the same.

2.   The modes of the ports must conform to the rule that if the local is readable, so must the actual and if the local is writable, so must the actual. Since a signal locally declared is considered to be both readable and writable, such a signal may be associated with a local of any mode. If an actual is a port of mode in, it may not be associated with a local of mode out or inout; if the actual is a port of mode out, it may not be associated with a local of mode in or inout; if the actual is a port of mode inout, it may be associated with a local of mode in, out, or inout.

Note:

an actual of mode out or inout indicates the presence of a source for that signal, and therefore, must be resolved if that signal is multiply driven.

A buffer port can never have more than one source; therefore, the only kind of actual that can be associated with a buffer port is another buffer port or a signal that has at most one source.

Eg.,

M1: MICRO port map (UDIN(3 downto 0), WRN, RDN, STATUS(0), STATUS(1 ), UDOUT(0 to 7), TXDATA);

The first actual of the port map refers to a slice of the vectored UDIN signal, WRN and RDN are 1-bit signals, STATUS(0) and STATUS(1) refer to the 0th and 1st element of the STATUS array, UDOUT(0 tp 7) refers to a slice of the UDOUT vector and TXDATA refers to an entire vector signal.

The signals used to interconnect components can also be slices, vectors, or, array elements. 

VHDL Functions and Procedures

Function
Procedure
Functions are used to describe frequently used sequential algorithms that return a single value that is returned to the calling program using a return statement.
These are used to partition large behavioral descriptions into modular sections.
Eg., resolution functions, type conversion functions.
Eg., Arithmetic Unit, Memories, Control Unit, etc  
These are usually used for computing a single value.
Procedures can return zero or more values using parameters of mode out and inout.
Functions are used to compute values that are available instantaneously.
A process that calls a procedure with a wait statement cannot have a sensitivity list. This follows from the fact that a process cannot be sensitive to signals and also be made to wait simultaneously.
A function cannot be made to wait.
A procedure body can have a wait statement. Hence any variables declared in the procedure retain their values through this wait period and cease to exist only when the procedure terminates.
The general syntax of a subprogram specification for a function body is

function function-name (parameter-list) return return-type

The parameter-list describes the list of formal parameters for the function. The only mode allowed for the parameters is mode in. Also, only constants and signal objects can be passed in as parameters.
Syntax for a procedure body

procedure procedure-name ( parameter-list )

The parameter-list specifies the list of formal parameters for the procedure. Parameters may be constants, variables, or signals and their modes may be in, out, or inout.
The default object class is constant and its value cannot be modified within the function body.
If the object class of a parameter is not explicitly specified, then the object class is by default a constant if the parameter is of mode in, else it is a variable if the parameter is of mode out or inout.
Eg., function body

function LARGEST (TOTAL_NO: INTEGER; SET: PATTERN)
return REAL is
-- PATTERN is defined to be atype of 1-D array of
-- floating-point values, elsewhere.
variable RETURN_VALUE: REAL := 0.0;
begin
for K in 1 to TOTAL_NO loop
if SET(K) > RETURN_VALUE then
RETURN_VALUE := SET(K);
end if;
end loop;
return RETURN_VALUE;
end LARGEST;

Variable RETURN_VALUE comes into existence with an initial value of 0.0 every time the function is called. It ceases to exist after the function returns back to the calling program.
Eg., procedure body that describes the behavior of an arithmetic logic unit.

type OP_CODE is (ADD, SUB, MUL, DIV, LT, LE, EQ);
procedure ARITH_UNIT (A, B: in INTEGER; OP: in OP_CODE;
Z: out INTEGER; ZCOMP: out BOOLEAN) is
begin
case OP is
when ADD=>Z:=A+B;
when SUB=>Z:=A-B;
when MUL=>Z:=A*B;
when DIV => Z := A/B;
when LT => ZCOMP := A < B;
when LE => ZCOMP := A <= B;
when EQ => ZCOMP := A = B;
end case;
end ARITH_UNIT;
A function call can be used within an expression.
A procedure call may be a sequential or a concurrent statement, which is based on where the actual procedure call statement is present.
Functions are invoked by function call.

A function call is an expression and can, therefore, be used in expressions.

Eg.,

SUM := SUM + LARGEST(MAX_COINS, COLLECTION);
Procedures are invoked by using procedure calls.

If the call is inside a process statement or inside another subprogram, then it is a sequential procedure call statement, else it is a concurrent procedure call statement.

A procedure can normally be used simultaneously as a concurrent and a sequential statement. But, if any of the procedure parameters are of the variable class, the procedure would be restricted to be used as a sequential procedural call, since variables can only be defined inside of a process.

Concurrent procedure calls are useful in representing frequently used processes.

A sequential procedure call statement is executed sequentially with respect to the sequential statements surrounding it inside a process or a subprogram.

A concurrent procedure call statement is executed whenever an event occurs on one of the parameters which is a signal of mode in or inout.

Semantically, a concurrent procedure call is equivalent to a process with a sequential procedure call and a wait statement that waits for an event on the signal parameters of mode in or inout.

Eg., A concurrent procedure call and its equivalent process statement.

architecture DUMMY_ARCH of DUMMY is
-- Following is a procedure body:
procedure INT_2_VEC (signal D: out BIT_VECTOR;
START_BIT, STOP_BIT: in INTEGER;
signal VALUE: in INTEGER)
begin
-- Procedure behavior here.
end INT_2_VEC;
begin
-- This is an example of a concurrent procedure call:
INT_2_VEC (D_ARRAY, START, STOP, SIGNAL.VALUE);
end DUMMY_ARCH;

- is equivalent to:
architecture DUMMY_ARCH of DUMMY is
procedure INT_2_VEC (signal D: out BIT_VECTOR;
START_BIT, STOP_BIT: in INTEGER;
signal VALUE: in INTEGER)
begin
-- Procedure behavior here.
end INT_2_VEC;
begin
process
begin
INT_2_VEC (D_ARRAY, START, STOP, SIGNAL_VALUE);
-- This is now a sequential procedure call.
wait on SIGNAL_VALUE;
-- Since SIGNAL_VALUE is an input signal.
end process;
end DUMMY_ARCH;
A function call has the form

function-name ( list-of-actual-values )

The actual values may be associated by position (the first actual value corresponds to the first formal parameter, the second actual value corresponds to the second parameter, and so on) or they may be associated using named association (the association of actual values and formal parameters are explicitly specified). The function call in the last example used positional association.
Syntax of a procedure call statement is

procedure-name (list-of-actual-parameters);

The actual parameters specify the expressions that are to be passed into the procedure and the names of objects that are to receive the computed values from the procedure.

Actual parameters may be specified using positional association or named association.
Function call using position association

LARGEST(MAX_COINS, COLLECTION);

ARITH_UNIT (D1, D2, ADD, SUM, COMP); -- Positional association.

Function call using named association

LARGEST (SET=> COLLECTION, TOTAL_NO => MAX_COINS)

ARITH_UNIT (Z=>SUM, B=>D2, A=>D1, OP=>ADD, ZCOMP=>COMP);
-- Named association.

SubPrograms

Subprograms

A subprogram defines a sequential algorithm that performs a certain computation and executes in zero simulation time.

There are two kinds of subprograms:

Functions: These are usually used for computing a single value. A function call can be used within an expression.

Procedures: These are used to partition large behavioral descriptions. Procedures can return zero or more values. A procedure call may be a sequential or a concurrent statement.

It is possible for two or more subprograms to have the same name. This is called overloading.

A subprogram is defined using a subprogram body. The typical format or syntax for a subprogram body is

subprogram-specification is
subprogram-item-declarations
begin
subprogram-statements -- Same as sequential-statements.
end [ subprogram-name ];

The subprogram-specification specifies the name of a subprogram and defines its interface, that is, it defines the formal parameter names, their class (i.e., signal, variable, or constant), their type, and their mode (whether they are in, out, or inout).

Parameters of mode in are read-only parameters; these cannot be updated within a subprogram body. Parameters of mode out are write-only parameters; their values cannot be used but can only be updated within a subprogram body. Parameters of mode inout can be read as well as updated.

Actual values are passed to and from a subprogram via a subprogram call. Only a signal object may be used to pass a value to a parameter of the signal class. Only a variable object may be used to pass a value to a parameter of the variable class.

A constant or an expression may be used to pass a value to a parameter of constant class. When parameters are of a variable or constant class, values are passed to the subprogram by value.

Arrays may or may not be passed by reference.

For signal objects, the reference to the signal, its driver, or both are passed into the subprogram, i.e., any assignment to a signal in a procedure (signals cannot be assigned values in a function because the parameters are restricted to be of input mode) affects the actual signal driver immediately and is independent of whether the procedure terminates or not.

For a signal of any mode, the signal-valued attributes, STABLE, QUIET, DELAYED, and TRANSACTION cannot be used in a subprogram body.

The type of an actual value in a subprogram call must match that of its corresponding formal parameter. If the formal parameter belongs to an unconstrained type, the size of this parameter is determined from the actual value that is passed in.

The subprogram-item-declarations part contains a set of declarations (e.g., type and object declarations) that are accessible for use locally within the subprogram. These declarations come into effect every time the subprogram is called.

Variables are also created and initialized every time the subprogram is called. They remain in existence until the subprogram completes. This is in contrast with declarations in a process statement that get initialized only once, that is at start of simulation, and any declared variables persist throughout the entire simulation run.

The subprogram-statements part contains sequential statements that define the computation to be performed by the subprogram.

A return statement, which is also a sequential statement, is a special statement that is allowed only within subprograms. The format of a return statement is

return { expression];

The return statement causes the subprogram to terminate and control is returned back to the calling object.

All functions must have a return statement and the value of the expression in the return statement is returned to the calling program.

For procedures, objects of mode out and inout return their values to the calling program.

The subprogram-name appearing at the end of a subprogram body, if present, must be the same as the function or procedure name specified in the subprogram specification part.