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 ;
- example
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 ];
- Example:
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;
- Eg:
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:
- The 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
- Example
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
- Example:
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:
- Text
editor
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;
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;
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.
No comments:
Post a Comment