Modeling of digital circuits in VHDL
VHDL supports the following types of
modeling
·        
Structural
Model
·        
Behavioral
Model
·        
Dataflow
Model 
·        
Mixed
Model
Structural Model:
- An entity is modeled as a set of
     components connected by signals, i.e., 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. 
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. 
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. 
- 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 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. 
            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.
- In named association, an association-list
     is of the form 
locale
=> actual1, local2 => actual2, ..., localn => actualn
- The signals used to interconnect
     components can also be slices, vectors or array elements. 
Dataflow Model:
- A dataflow model specifies the
     functionality of the entity without explicitly specifying its structure.
     This functionality shows the flow of information through the entity, which
     is expressed primarily using concurrent signal assignment statements and
     block statements. 
- Concurrent Signal Assignment
     statement 
–       
One
of the primary mechanisms for modeling the dataflow behavior of an entity is by
using the concurrent signal assignment statement. 
Comparison of Sequential and Concurrent signal
assignment Statements
 
  | 
S.No. | 
Concurrent
  Signal Assignment | 
Sequential Signal
  Assignment | 
  | 
1. | 
signal
  assignment statements that appear outside of a process are called concurrent
  signal assignment statements  | 
signal
  assignment statements can also appear within the body of a process statement.
  Such statements are called sequential signal assignment statements  | 
  | 
2. | 
Concurrent
  signal assignment statements are event triggered, that is, they are executed
  whenever there is an event on a signal that appears in its expression  | 
sequential
  signal assignment statements are not event triggered and are executed in
  sequence in relation to the other sequential statements that appear within
  the process | 
  | 
3. | 
Eg:
   
architecture CON_SIG_ASG of FRAGMENT2 is  
begin
  -- Following are concurrent signal assignment statements:  
A<=B;
   
Z<=A;
   
end;  | 
Eg:
   
architecture SEQ_SIG_ASG of FRAGMENT1 is  
-
  A, B and Z are signals.  
begin
   
process
  (B)  
begin
  -- Following are sequential signal assignment statements:  
A<=B;
   
Z<=A;
   
end
  process;  
end; | 
  | 
4. | 
When
  an event occurs on signal B, say at time T, signal A gets the value of B
  after delta delay, that is, at time T+Δ and this event on A will trigger the
  second signal assignment statement that will cause the new value of A to be
  assigned to Z after another delta delay, that is, at time T+2Δ.  | 
Whenever
  signal B has an event, say at time T, the first signal assignment statement
  is executed and then the second signal assignment statement is executed, both
  in zero time.  Signal A is scheduled to
  get its new value of B only at time T+Δ, and Z is scheduled to be assigned the
  old value of A at time T+Δ also.  | 
  | 
5. | 
The
  concurrent signal assignment statement:  
 
CLEAR
  <= RESET or PRESET after 15 ns;  
--
  RESET and PRESET are signals.  
 
is
  equivalent to the following process statement: 
 
process  
begin  
CLEAR
  <= RESET or PRESET after 15 ns;  
wait on RESET, PRESET;  
end process;  | 
An
  identical signal assignment statement (a sequential signal assignment)
  appears in the body of the process statement along with a wait statement
  whose sensitivity list comprises of signals used in the expression of the
  concurrent signal assignment statement.  
 | 
Conditional Signal Assignment Statement:
- The conditional signal assignment
     statement selects different values for the target signal based on the
     specified, possibly different, conditions (it is like an if statement). 
Target
- signal <= [ waveform-elements when condition else ]
[ waveform-elements
when condition else ]
.
. .
waveform-elements;
- Whenever an event occurs on a signal
     used either in any of the waveform expressions or in any of the
     conditions, the conditional signal assignment statement is executed by
     evaluating the conditions one at a time. For the first true condition
     found, the corresponding value of the waveform is scheduled to be assigned
     to the target signal. 
Z <= IN0 after 10ns when S0 = '0' and S1 = '0' else 
IN1 after 10ns when S0 = '1' and S1 = '0' else 
IN2 after 10ns when S0 = '0' and S1 = '1' else 
IN3 after 10 ns; 
Selected Signal Assignment Statement:
- The selected signal assignment
     statement selects different values for a target signal based on the value
     of a select expression (it is like a case statement). 
with
expression select —This is the select expression. 
target-signal
<= waveform-elements when choices, 
waveform-elements
when choices, 
…
waveform-elements
when choices ; 
type OP is (ADD, SUB, MUL,
DIV); 
signal OP_CODE: OP; 
. . . 
with OP_CODE select 
Z <= A+B after ADD_PROP_DLY when ADD, 
A - B after SUB_PROP_DLY when SUB, 
A * B after MUL_PROP_DLY when MUL, 
A / B after DIV_PROP_DLY when DIV; 
Block Statement:
- A block statement is a concurrent
     statement. It can be used for three major purposes: 
1. to disable signal drivers by using guards, 
2. to limit signal scope, 
3. to represent a portion of a design. 
- A block statement itself has no
     execution semantics but provides additional semantics for statements that
     appear within it. 
block-label: block [ ( guard-expression ) ] 
[ block-header] 
[ block-declarations] 
begin
concurrent-statements 
end
block [ block-label ]; 
B1: block (STROBE = '1') 
begin 
Z <= guarded not A; 
end block B1; 
Behavioral Modeling:
Entity Declaration:
- An entity declaration describes the
     external interface of the entity, that is, it gives the black-box view. It
     specifies the name of the entity, the names of interface ports, their mode
     (i.e., direction), and the type of ports. 
entity entity-name is 
[ generic ( list-of-generics-and-their-types
) ; ] 
[ port ( list-of-interface-port-names-and-their-types)
; ] 
[ entity-item-declarations
] 
[ begin 
entity-statements
] 
end [ entity-name ]; 
- The
     entity-name is the name of the entity and the interface ports are the
     signals through which the entity passes information to and from its
     external environment. Each interface port can have one of the following
     modes: 
1.     
in:
the value of an input port can only be read within the entity model. 
2.     
out:
the value of an output port can only be updated within the entity model; it
cannot be read. 
3.     
inout:
the value of a bidirectional port can be read and updated within the entity
model. 
4.     
buffer:
the value of a buffer port can be read and updated within the entity model.
However, it differs from the inout mode in that it cannot have more than one
source and that the only kind of signal that can be connected to it can be
another buffer port or a signal with at most one source. 
Architecture Body:
- An architecture body describes the
     internal view of an entity. 
- It describes the functionality or
     the structure of the entity. 
architecture
architecture-name of entity-name is 
[ architecture-item-declarations ] 
begin
concurrent-statements; these are —> 
process-statement 
block-statement 
concurrent-procedure-call 
concurrent-assertion-statement 
concurrent-signal-assignment-statement 
component-instantiation-statement 
generate-statement 
end
[ architecture-name ] ; 
Process Statement:
- A process statement contains
     sequential statements that describe the functionality of a portion of
     an entity in sequential terms. 
[ process-label: ] process [ ( sensitivity-list ) ] 
•        
[process-item-declarations]
begin
•        
sequential-statements;
these are -> 
–       
variable-assignment-statement
–       
signal-assignment-statement
–       
wait-statement 
–       
if-statement 
–       
case-statement 
–       
loop-statement 
–       
null-statement 
–       
exit-statement 
–       
next-statement 
–       
assertion-statement
–       
procedure-call-statement
–       
return-statement.
end
process [ process-label]; 
Variable Assignment Statement:
- Variables can be declared and used
     inside a process statement. 
- A variable is assigned a value
     using the variable assignment statement that typically has the form 
                                                variable-object
:= expression; 
- The expression is evaluated when
     the statement is executed and the computed value is assigned to the
     variable object instantaneously, that is, at the current simulation time. 
- Variables are created at the time
     of elaboration and retain their values throughout the entire simulation
     run (like static variables in C high-level programming language). This is
     because a process is never exited; it is either in an active state, that
     is, being executed, or in a suspended state, that is, waiting for a
     certain event to occur. 
- A process is first entered at the
     start of simulation (during the initialization phase of simulation) at
     which time it is executed until it suspends because of a wait statement or
     a sensitivity list. 
                                                process (A) 
                                                variable
EVENTS_ON_A: INTEGER := 0; 
                                                begin
                                                EVENTS_ON_A
:= EVENTS_ON_A+1; 
                                                end
process; 
Signal
Assignment Statement:
- Signals are assigned values using a
     signal assignment statement The simplest form of a signal assignment
     statement is 
                                                signal-object
<= expression [ after delay-value ]; 
- A signal assignment statement can
     appear within a process or outside of a process. If it occurs outside of a
     process, it is considered to be a concurrent signal assignment statement. 
- When a signal assignment statement
     is executed, the value of the expression is computed and this value is
     scheduled to be assigned to the signal after the specified delay. 
- The expression is evaluated at the
     time the statement is executed (which is the current simulation time) and
     not after the specified delay. If no after clause is specified, the delay
     is assumed to be a default delta delay. 
COUNTER <=
COUNTER+ "0010"; - Assign after a delta delay. 
PAR <= PAR xor DIN after 12 ns; 
Z <= (AO and A1) or (BO and B1) or (CO and C1) after 6
ns; 
Delta Delay:
- A delta delay is a very small delay (infinitesimally small). It does
     not correspond to any real delay and actual simulation time does not
     advance. 
- This
     delay models hardware where a minimal amount of time is needed for a
     change to occur in performing zero delay simulation. Delta delay allows
     for ordering of events that occur at the same simulation time during a
     simulation. 
- Each
     unit of simulation time can be considered to be composed of an infinite
     number of delta delays. Therefore, an event always occurs at a real
     simulation time plus an integral multiple of delta delays. 
- Eg:
     events can occur at 15 ns, 15 ns+IA, 15 ns+2A, 15 ns+3A, 22 ns, 22 ns+A,
     27 ns, 27 ns+A, and so on. 
Fig: Delta Delay
Wait Statement:
- when a process has a sensitivity
     list, it always suspends after executing the last sequential statement in
     the process. 
- The wait statement provides an
     alternate way to suspend the execution of a process.
- There are three basic forms of the
     wait statement. 
wait
on sensitivity-list; 
wait
until boolean-expression ; 
wait
for time-expression ; 
- They may also be combined in a
     single wait statement. Eg: 
                                    wait on sensitivity-list
until boolean-expression for time-expression; 
wait on A, B, C; 
wait until (A = B); 
wait for 10ns; 
wait on CLOCK for 20ns; 
wait until (SUM > 100) for 50 ms; 
If Statement:
- An if statement selects a sequence
     of statements for execution based on the value of a condition. The
     condition can be any expression that evaluates to a boolean value. The
     general form of an if statement is 
if
boolean-expressionthen 
sequential-statements
[ elsif
boolean-expression then -- elsif clause; if stmt can have 0 or 
sequential-statements
] -- more elsif clauses. 
[ else
-- else clause. 
sequential-statements
] 
end
if; 
Example:
if SUM <= 100 then -- This is a less-than-or-equal-to operator. 
SUM := SUM+10; end if; 
if NICKEL_IN then DEPOSITED
<=TOTAL_10; 
elsif DIME_IN then DEPOSITED
<= TOTAL_15; 
elsif QUARTERJN then DEPOSITED <= TOTAL_30; 
else DEPOSITED
<= TOTAL_ERROR; end if; 
Case Statement:
- The format of a case statement is 
case
expression is 
when
choices => sequential-statements -- branch #1 
when
choices => sequential-statements -- branch #2 
--
Can have any number of branches. 
[ when
others => sequential-statements ] -- last branch 
end
case; 
Example:
type WEEK_DAY is (MON, TUE, WED, THU, FRI, SAT, SUN); 
type DOLLARS is range 0 to 10; 
variable DAY: WEEK_DAY; 
variable POCKET_MONEY: DOLLARS; 
case DAY is 
when TUE => POCKET_MONEY := 6; -- branch 1 
when MON I WED => POCKET_MONEY := 2; -- branch 2 
when FRI to SUN => POCKET_MONEY := 7; -- branch 3 
when others => POCKET_MONEY := 0; -- branch 4 
end case; 
Null Statement:
            null; 
- is a sequential statement that does
     not cause any action to take place and execution continues with the next
     statement. 
- Eg: use in an if statement or in a
     case statement where for certain conditions, it may be useful or necessary
     to explicitly specify that no action needs to be performed. 
Loop Statement:
- A loop statement is used to iterate
     through a set of sequential statements. 
[ loop-label
: ] iteration-scheme loop 
sequential-statements
end
loop [ loop-label ] ; 
- There are three types of iteration
     schemes. The first is the for iteration scheme that has the form 
                                    for identifier
in range 
FACTORIAL := 1; 
for NUMBER in 2 to N loop 
FACTORIAL :=
FACTORIAL * NUMBER; 
end loop; 
- The second
     form of the iteration scheme is the while scheme that has the form 
                                    while boolean-expression
J:=0;SUM:=10; 
WH-LOOP: while J < 20 loop - This loop has a label,
WH_LOOP. 
SUM := SUM *
2; 
J:=J+3; 
end loop; 
- The third
     and final form of the iteration scheme is one where no iteration scheme is
     specified. In this form of loop statement, all statements in the loop body
     are repeatedly executed until some other action causes it to exit the
     loop. 
- These actions can be caused by an
     exit statement, a next statement, or a return statement. 
SUM:=1;J:=0; 
L2: loop -- This loop also has a label. 
J:=J+21; 
SUM := SUM*
10; 
exit when SUM > 100; 
end loop L2; --
This loop label, if present, must be the same 
-- as the
initial loop label. 
- The exit statement causes the
     execution to jump out of loop L2 when SUM becomes greater than 100. If the
     exit statement were not present, the loop would execute indefinitely. 
Exit Statement:
- The exit statement is a sequential
     statement that can be used only inside a loop. It causes execution to jump
     out of the innermost loop or the loop whose label is specified. 
                                                exit
[ loop-label] [ when condition ]: 
- If no loop label is specified, the
     innermost loop is exited. If the when clause is used, the specified loop
     is exited only if the given condition is true, otherwise, execution
     continues with the next statement. 
- An alternate form for loop L2
SUM := 1; J :=
0; 
L3: loop 
J:=J+21; 
SUM := SUM* 10; 
if (SUM > 100) then 
exit L3; -- "exit;" also would have been sufficient. 
end if; 
end loop L3; 
Next Statement:
- The next statement is also a
     sequential statement that can be used only inside a loop. The syntax is
     the same as that for the exit statement except that the keyword next
     replaces the keyword exit. 
                                                next
[ loop-label] [ when condition ]; 
- The next statement results in
     skipping the remaining statements in the current iteration of the
     specified loop and execution resumes with the first statement in the next
     iteration of this loop. 
- If no loop label is specified, the
     innermost loop is assumed. In contrast to the exit statement that causes
     the loop to be terminated (i.e., exits the specified loop), the next
     statement causes the current loop iteration of the specified loop to be
     prematurely terminated and execution resumes with the next iteration. 
for J in 10 downto 5 loop 
if (SUM < TOTAL_SUM) then 
SUM := SUM
+2; 
elsif (SUM = TOTAL_SUM) then 
next; 
else 
null; 
end if; 
K:=K+1; 
end loop; 
- When the
     next statement is executed, execution jumps to the end of the loop (the
     last statement, K:= K+1, is not executed), decrements the value of the
     loop identifier, J, and resumes loop execution with this new value of J. 
Assertion Statement:
- Assertion statements are useful in
     modeling constraints of an entity. To check if a signal value lies within
     a specified range, or check the setup and hold times for signals arriving
     at the inputs of an entity. If the check fails, an error is reported. 
- The syntax of an assertion
     statement is 
assert
boolean-expression 
[ report
string-expression ] 
[ severity
expression ];
- If the value of the boolean
     expression is false, the report message is printed along with the severity
     level. The expression in the severity clause must generate a value of type
     SEVERTTY_LEVEL (a predefined enumerated type in the language with values
     NOTE, WARNING, ERROR, and FAILURE). The severity level is typically used
     by a simulator to initiate appropriate actions depending on its value. 
- Example: if the severity level is
     ERROR, the simulator may abort the simulation process and provide relevant
     diagnostic information. At the very least, the severity level is
     displayed. 
Signal Assignment Statements:
Inertial Delay
Model:
- Inertial
     delay models the delays often found in switching circuits. It represents
     the time for which an input value must be stable before the value is
     allowed to propagate to the output. 
- In
     addition, the value appears at the output after the specified delay. If
     the input is not stable for the specified time, no output change occurs. 
- When
     used with signal assignments, the input value is represented by the value
     of the expression on the right-hand-side and the output is represented by
     the target signal. 
- Example of a noninverting buffer
     with an inertial delay of 10 ns. 
Fig.2: Inertial
Delay
Transport
Delay Model:
- Transport delay models the delays in hardware
     that do not exhibit any inertial delay. 
- This delay represents pure propagation delay,
     that is, any changes on an input is transported to the output, no matter
     how small, after the specified delay. 
- To use a transport delay model, the keyword
     transport must be used in a signal assignment statement. Figure 4.4 shows
     an example of a noninverting buffer using a transport delay of 10 ns. 
Fig.3: Transport
Delay
§ 
Example:
Entity WIRE14 is 
port (A: in BIT; Z: out BIT); 
end WIRE14; 
architedture WIRE14_TRANSPORT of WIRE14 is 
begin 
process (A) 
begin 
Z <= transport A after 0.1 ms; 
end process; 
end WIRE14_TRANSPORT; 
Need for testing:
1.     
To verify the functionality of the design according to
specifications.
2.     
To perform random testing and hence to reduce the test
time of the design.
3.     
To detect failures so that
bugs (in software code) can be identified and corrected before it gets shipped
to costumer. (There are possibilities that error may in the specification
itself. Sometimes miscommunications between teams may lead to wrong design.)
A 
test bench or testing workbench is a virtual environment used to
verify the correctness or soundness of a design or model, for example, a
software product.
In hardware testing of electronic devices, where an engineer would sit at a
lab bench with tools for measurement and manipulation, such as 
oscilloscopes,
multimeters,
soldering irons, wire cutters and manually verify the correctness of the 
device
under test (DUT).
In software or firmware or hardware engineering, a test bench refers to an
environment in which the product under development is tested with the aid of
software and hardware tools. 
The software may need to be modified slightly in some cases to work with the
test bench but careful coding can ensure that the changes can be undone easily
and without introducing bugs.
Components
of a test bench:
A test bench has four components:
- Input: The entrance criteria or deliverables needed to
     perform work
- Procedures to do: The tasks or processes that will
     transform the input into the output
- Procedures to check: The processes that determine that
     the output meets the standards
- Output: The exit criteria or deliverables produced from
     the workbench
Kinds
of test benches:
The following types of test bench
are the most common: Test Benches
- Stimulus only — contains only the stimulus driver and
     DUT; does not contain any results verification.
- Full test bench — Contains stimulus driver, known good
     results, and results comparison.
- Simulator specific — the test bench is written in a
     simulator-specific format.
- Hybrid test bench — Combines techniques from more than
     one test bench style.
- Fast test bench — Test bench written to get ultimate
     speed from simulation.
Test
Benches:
To
simulate your design, you need both the design under test (DUT) or unit under
test (UUT) and the stimulus provided by the test bench.  
A test bench is HDL code that allows
you to provide a documented, repeatable set of stimuli that is portable across
different simulators. 
A test bench can be as simple as a
file with clock and input data or a more complicated file that includes error
checking, file input and output, and conditional testing.
Methods
to create the test bench:
This is
used to verify complex designs. It allows you to use all the features available
in the HDL language and gives you flexibility in verifying the design. 
Advantages:  It produces more precise and accurate results
than using the Test Bench Waveform Editor.
Disadvantages:
It is more challenging to create the code.
To assist
in creating the test bench, you can create a template that lays out the initial
framework, including the instantiation of the UUT and the initializing stimulus
for your design. 
-  Test Bench
     Waveform Editor
This is
used to verify less complicated simulation tasks and is recommended if you are
new to HDL simulation. It allows you to graphically enter the test bench to
drive the stimulus to your design. 
Advantages:
Easy to work.
Disadvantages:
Implementation and analysis of complex designs.
Test
Bench Strategies:
Because the test bench becomes a
part of the hierarchy in your code, the following has to be considered:
-  Make the test bench the top level of the code.
The test
bench instantiates the unit under test (UUT), and stimulus is applied from the
top-level test bench to the lower-level design or portion of the design being
tested.
-  Use the instance name UUT for the instantiated
     unit under test.
This is
the default instance name that Project Navigator expects.
The same test bench for both
functional and timing simulation can be used. 
The
general recommendations for simulation are:
-  Initialize all input ports at simulation time
     zero, but do not drive expected stimulus until after 100
     nanoseconds (ns) simulation time.
During
timing simulation, a global set/reset signal is automatically pulsed for the
first 100 ns of simulation. To keep the test bench consistent for both timing
and functional simulation, it is recommended that you hold off input stimulus
until the global set/reset has completed.
-  Do not provide data to the input ports at
     the same time as the clock.
For
non-timing simulation, this can cause some signals to be applied before the
clock and some after the clock. Apply data only after the clock is
applied to the input ports. This makes it easier to keep track of which clock
edge data changes are being applied.
-  If output checking is performed in the test
     bench, apply data just before the next clock cycle.
For timing
simulation, it could take up to an entire clock cycle for the data to propagate
through the logic and settle to a known value. Checking data too early in the
clock cycle may yield incorrect results.
Example: 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity test is
port (clk : in std_logic; 
      count : out std_logic_vector(3 downto 0);
      reset :in std_logic
     );
end test;
architecture Behavioral of test is
signal c : std_logic_vector(3 downto 0) :=(others => '0');
 --initializing count to zero.
begin
count <= c;
process(clk,reset)
begin
if(clk'event and clk='1') then
-- when count reaches its maximum(that is 15) reset it to 0
if(c = "1111") then 
c <="0000";
end if;
c <= c+'1';  --increment count at every positive edge of clk.
end if;
if(reset='1') then  --when reset equal to '1' make count equal to 0.
c <=(others => '0');  -- c ="0000"
end if;
end process;
end Behavioral;
 
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
-- entity declaration for your testbench.Dont declare any ports here
ENTITY test_tb IS 
END test_tb;
ARCHITECTURE behavior OF test_tb IS
   -- Component Declaration for the Unit Under Test (UUT)
    COMPONENT test  --'test' is the name of the module needed to
be tested.
--just copy and paste the input and output ports of your module as such. 
    PORT( 
         clk : IN  std_logic;
         count : OUT  std_logic_vector(3 downto
0);
         reset : IN  std_logic
        );
    END COMPONENT;
   --declare inputs and initialize them
   signal clk : std_logic := '0';
   signal reset : std_logic := '0';
   --declare outputs and initialize them
   signal count : std_logic_vector(3 downto 0);
   -- Clock period definitions
   constant clk_period : time := 1 ns;
BEGIN
    -- Instantiate the Unit Under Test (UUT)
   uut: test PORT MAP (
         clk => clk,
          count => count,
          reset => reset
        );       
   -- Clock process definitions( clock with 50% duty cycle is
generated here.
   clk_process :process
   begin
        clk <= '0';
        wait for clk_period/2;  --for 0.5 ns signal is
'0'.
        clk <= '1';
        wait for clk_period/2;  --for next 0.5 ns
signal is '1'.
   end process;
   -- Stimulus process
  stim_proc: process
   begin         
        wait for 7 ns;
        reset <='1';
        wait for 3 ns;
        reset <='0';
        wait for 17 ns;
        reset <= '1';
        wait for 1 ns;
        reset <= '0';
        wait;
  end process;
END;
2. If multiple clocks are to be generated with different
frequencies, then clock generation can be simplified if a procedure is called
as concurrent procedure call.
library ieee;
use ieee.std_logic_1164.all;
entity tb is
end entity;
architecture sim of tb is
  -- Procedure for
clock generation
  procedure
clk_gen(signal clk : out std_logic; constant FREQ : real) is
    constant
PERIOD    : time := 1 sec / FREQ;        -- Full period
    constant HIGH_TIME
: time := PERIOD / 2;          -- High
time
    constant
LOW_TIME  : time := PERIOD -
HIGH_TIME;  -- Low time; always >=
HIGH_TIME
  begin
    -- Check the
arguments
    assert (HIGH_TIME
/= 0 fs) report "clk_plain: High time is zero; time resolution to large
for frequency" severity FAILURE;
    -- Generate a
clock cycle
    loop
      clk <= '1';
      wait for
HIGH_TIME;
      clk <= '0';
      wait for
LOW_TIME;
    end loop;
  end procedure;
  -- Clock frequency
and signal
  signal clk_166 :
std_logic;
  signal clk_125 :
std_logic;
begin
  -- Clock generation
with concurrent procedure call
  clk_gen(clk_166,
166.667E6);  -- 166.667 MHz clock
  clk_gen(clk_125,
125.000E6);  -- 125.000 MHz clock
  -- Time resolution
show
  assert FALSE report
"Time resolution: " & time'image(time'succ(0 fs)) severity NOTE;
end architecture;
Simulation Overview
During
HDL simulation, the simulator software verifies the functionality and timing of
your design or portion of your design. The simulator interprets VHDL or Verilog
code into circuit functionality and displays logical results of the described
HDL to determine correct circuit operation. Simulation allows you to create and
verify complex functions in a relatively small amount of time. 
Simulation takes place at several
points in the design flow. It is one of the first steps after design entry and
one of the last steps after implementation, as part of verifying the end
functionality and performance of the design. Simulation is an iterative
process, which may require repeating until both design functionality and timing
is met. For a typical design, simulation comprises the following high-level
steps:
- Compilation of the simulation libraries 
- Creation of the design and test bench  
- Functional simulation 
- Implementation of the design and creation of the timing
     simulation netlist 
- Timing simulation 
Functional Simulation
After you compile the simulation libraries and create the
test bench and design code, you can perform functional simulation on the
design.  
Functional simulation is an
iterative process, which may require multiple simulations to achieve the
desired end functionality of the design. 
Once the desired functionality is
achieved, use the output data to create a self-checking testbench. ISim has the
capability to generate a self-checking testbench. It is important to set up the
proper infrastructure for this type of simulation; spending time up front may
save time in back end design debugging. 
The general recommendations are:
-  Spend time up front to create a good test bench.
Creating a
test bench that you can use for both functional and timing simulation can save
time.
-  Ensure that your libraries are properly compiled
     and mapped.
If your
design includes Xilinx CORE Generator cores, make sure that your libraries are
properly compiled and mapped to the simulator. If you are using the ISim or the
ModelSim Xilinx Edition simulator, this is automatically done for you. 
-  Automate the compilation and elaboration
     simulation steps.
When you
invoke the simulator from within Project Navigator, the ISE® tools
automatically run these steps. If you are running the simulator outside of
Project Navigator, it is recommended that you create a script or use another
method to automate these steps. 
-  Customize the simulator interface to present the
     information needed to debug the design.
You
may want to include the information console, the structure or hierarchy view,
and the waveform viewer as well as other facilities to evaluate the
simulation. Customization can improve the simulation experience and can be
tied into the automation of the compilation and elaboration steps. 
If
you are using a waveform viewer as a part of simulation debugging, organize the
waveform view to display the proper signals in the proper order with the proper
radices. This saves time and helps prevent confusion in interpreting
simulation results.