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

Showing posts with label VHDL Code. Show all posts
Showing posts with label VHDL Code. Show all posts

Thursday, 31 July 2014

VHDL Coding Tips For Excellent Design

Here are the Ten Commandments of Excellent Design:
  1. All state machine outputs shall always be registered
  2. Thou shalt use registers, never latches
  3. Thy state machine inputs, including resets, shall be synchronous
  4. Beware fast paths lest they bite thine ankles
  5. Minimize skew of thine clocks
  6. Cross clock domains with the greatest of caution. Synchronize thy sig- nals!
  7. Have no dead states in thy state machines
  8. Have no logic with unbroken asynchronous feedback lest the fleas of myriad Test Engineers infest thee
  9. All decode logic must be crafted carefully—eschew asynchronicity
  10. Trust not thy simulator—it may beguile thee when thy design is junk
How to Write Ten-Commandment Code

Conforming to the Ten Commandments is not difficult. In this section you’ll see how to write VHDL (your author doesn’t do Verilog, but the translation is easy) that complies with the rules. Robust design and first-silicon success are the goals!

The philosophy behind Ten-Commandment code is that synthesizers are not to be trusted too much. Most of the code you will see is close to the structural level; some more overtly than others. Most of the code is self-explanatory. It is assumed that the reader is familiar with VHDL. Signal names are also obvious to anyone “skilled in the art.”

How to Create a Flip-Flop
One of the basic primitives that we need to create robust synchronous designs is the D-type flip-flop. Look at the code in Code Sample 1: A D-type Flip Flop

-- VHDL Code for a D-Type Flip-Flop with an -- Asynchronous Clear
D_Type_Flip_Flop: process(Reset_n, Clock_In)
  begin
    if (Reset_n = ’0’) then
      Q_Output <= ’0’ after 1 ns;
  elsif (Clock_In’event and Clock_In = ’1’) then
      Q_Output <= D_Input after 1 ns;
  end if;
end process D_Type_Flip_Flop;

This flip-flop has the following properties:
  • An asynchronous active-low clear input sets the Q output to zero.
  • It is triggered on the rising edge of the clock.

How to Create a Latch
While the Ten Commandments specifically forbid the use of latches, there are still those heretics who will insist on the use of latches. The code to instantiate a transparent latch is shown in Code Sample 2: A Transparent Latch

-- VHDL Code for a Transparent Latch
Latch_Data: process(Latch_Open, D_Input)
  begin
    if (Latch_Open = ’1’) then
      Latched_Data <= D_Input;
    -- If Latch_Open = 0, then Latched_Data keeps its old value, -- i.e. the latch is closed.
    end if;
end process Latch_Data;

This latch has the following properties:
  • A latch control that opens the latch when high (the latch is transparent).
How to Create a Metastable- Hardened Flip-Flop

The use of a metastable-hardened flip flop is nothing more than the direct instantiation of a suitable library element in this case, a “dfntns” flip-flop. This is pure structural VHDL. The component declaration is shown in Code Sample 3:  A Metastable-Hardened Flip-Flop, Component Declaration

-- VHDL Code for a Nice Metastable-Hardened Flip-Flop
component dfntns
  Port (
    CP : In std_logic;
    D : In std_logic;
    Q : Out std_logic
  );
end component;

To use the flip-flop in your circuit, instantiate it as shown in Code Sample 4: A Metastable-Hardened Flip-Flop, Instantiation

-- VHDL Code to Instantiate the Metastable-Hardened Flip-Flop
Metastable_Hardened_Flip_Flop_Please: dfntns port map (
  D => D_Input,
  CP => Clock_In,
  Q => Q_Output
  );

This flip-flop has the following properties:
  • A maximum clock-to-out time under worst-case setup and hold time violations. This time is available in the library element specifications.
The Care and Feeding of Toggle Signals

Receiving a Toggle Signal
The Ten Commandments paper suggested that a method for exchanging single- point information across clock domains is by the use of toggle signals. Here, it is assumed that the toggle event should generate an active-high pulse to pass to a state machine. Every toggle—rising edge and falling edge—must create the pulse. In addition, the pulse must be synchronized correctly to the receiver’s clock. The code to accomplish this is shown in Code Sample 5: Receiving a Toggle Signal

-- VHDL Code to Create a Pulse from an Asynchronous -- Toggle Signal
-- First, use a metastable-hardened flip-flop to synchronize the -- toggle input
Metastable_Hardened_Flip_Flop_Please: dfntns port map (
  D => Handshake_T,
  CP => Clock_In,
  Q => Sync_Handshake_T
  );

-- Now pass the synchronized toggle through another flip-flop
Toggle_Reg_Proc: process(Clock_In)
  begin
    if (Clock_In'event and Clock_In = ’1’) then
      Reg_Handshake_T <= Sync_Handshake_T after 1 ns;
    end if;
  end process Toggle_Reg_Proc;

-- Finally XOR the two synchronized signals to create a pulse
Toggle_Pulse <= Reg_Handshake_T xor Sync_Handshake_T;

When synthesizing this code, remember to use the “fix hold” option so a fast path doesn't occur between the two flip-flops in this circuit.

Generating a Toggle Signal
Recall that a toggle signal is generated by simply inverting a level to pass the information. The trivial code to do this is shown in Code Sample 6:  Generating a Toggle Signal

The suffix “_T” is used to denote a toggle signal.

-- VHDL Code to Create a Toggle Signal
Handshake_T <= not (Handshake_T) after 1 ns;

Coding State Machines
The creation of state machines is a mixture of art and science. A well-crafted state machine will possess a sense of elegance; it will be appealing, both functionally and visually.
Here, a very simple example is presented as an illustration of state machine design. The state diagram for the Flintstones State Machine is shown in figure below popularly known as The Flintstones State Machine.


The Flintstones State Machine operates as follows:
  1. The State Machine has two states, State Bed and State Rock.
  2. There is one output, Fred, which takes the value 0 in State Bed and 1 in State Rock.
  3. A reset, caused by a low level on Reset_n, puts the State Machine into State Bed.
  4. The State Machine waits in State Bed while Barney is low, and enters State Rock when Barney goes high.
  5. The State Machine then waits in State Rock while Wilma is low, and returns to State Bed when Wilma goes high.
Implementing the Flintstones State Machine

An example implementation of the Flintstones State Machine is shown in Code Sample 7 below:

-- VHDL Code to Implement the Flintstones State Machine

Flintstones_SM_Proc: process(Sync_Reset_n, Clock_In)
  -- Enumerate state types:
  type Flintstones_Statetype is (
  Bed, Rock
  );

  -- define the state variable:
  variable Flint_State: Flintstones_Statetype;

  -- Here’s the state machine:
  begin
  -- Define the asynchronously set reset states...
    if (Sync_Reset_n = ’0’) then
      Fred <= ’0’ after 1 ns;
      Flint_State := Bed
      -- Default conditions for each output, in this case identical to the -- reset state:
    elsif (Clock_In’event and Clock_In = ’1’) then
      Fred <= ’0’ after 1 ns;

    -- Here are the state transitions:
    case Flint_State is
      when Bed =>
      -- Transition from Bed to Rock:
        if (Barney = ’1’) then
          Fred <= ’1’ after 1 ns;
          Flint_State := Rock;
          -- Holding term in Bed:
        else
          Flint_State := Bed;
        end if;
      when Rock =>
        -- Transition from Rock to Bed:
        if (Wilma = ’1’) then
          Fred <= ’0’ after 1 ns;
          Flint_State := Bed;
        -- Holding term in Rock:
        else
          Fred <= ’1’ after 1 ns;
          Flint_State := Rock;
        end if;
      -- Default term for dead states:
      when others =>
        Flint_State := Bed;
    end case;
  end if;
end process Flintstones_SM_Proc;


Notes on the State machine Implementation
For the most part, the Flintstones State Machine’s operation should be clear. A few points are worth noting, however:
  1. The reset signal (Sync_Reset_n) is synchronized with Clock_In before being sent to the State Machine.
  2. Barney and Wilma must also be synchronous to Clock_In; at the very least, there must be an assurance that the State Machine’s state and output regis- ter’s setup and hold times are not violated.
  3. This design assigns a default value to each output and to the state variable before entering the case statement. This ensures that only those signals that are not taking default (usually inactive) values need be listed in the case statement. This is optional; it is entirely reasonable to list every signal under each transition term, including inactive signals.
  4. Note that the output signal Fred comes directly from a D-type flip-flop: it is not a decode of the state variable. This ensures Fred’s cleanliness (so to speak).
  5. The “when others” in the case statement handles the possibility that the State Machine might end up in a dead state.
The code examples in this tutorial should be considered as examples only. There are many ways to code excellent VHDL; this code is a place to start. If you have a neat snippet of VHDL to add to the list, then please post your valuable comments below.

Wednesday, 5 December 2012

Creating a simple FPGA Project with Xilinx ISE

Xilinx Virtex5 LX300 FPGA chip on the board

We would like to write this post for our friends who wants to create a simple FPGA Project with Xilinx ISE. 

Software

Xilinx ISE as a software package containing a graphical IDE, design entry tools, a simulator, a synthesizer (XST) and implementation tools. Limited version of Xilinx ISE (WebPack) can be downloaded for free from the Xilinx website.

It is not mandatory to use Xilinx software for all tasks (for example, synthesis can be done with Synplify, simulation - with Modelsim etc.), but it is the easier option to start off.

The information in this article applies to Xilinx ISE version 9.2.03i, but other versions (since 8.x) shouldn't be very different. If your version is older than 8.x, you'd better upgrade.

Creating a project

To create a project, start a Project Navigator and select File->New Project. You will be asked for project name and folder. Leave "top-level source type" as HDL.

Now we should choose a target device (we will use a Spartan-3A xc3s50a device as an example) as well as set up some other options:

A dialog of creating project in Xilinx ISE

The Project Navigator window contains a sidebar, which is on the left side by default. The upper part of this sidebar lists all project files, and the lower part lists tasks that are applicable for the file selected in the upper part.

Design Entry

Now, let's add a new source file to our project. We'll start from a simple 8-bit counter, which adds 1 to its value every clock cycle. This counter will have the following ports:

  • CLK - input clock signal;
  • CLR - input asynchronous clear signal (set counter value to 0);
  • DOUT - output counter value (8-bit bus).

We'll define our counter as a VHDL module. VHDL language will be covered in more details in further chapters.

To create a new source file, choose "Create New Source" task and select "VHDL module" source type. The name of our module will becounter.vhd. Then you will be asked which module to associate the testbench with; choose counter.

A dialog of creating a new source file in Xilinx ISE

Let's write the following code in counter.vhd:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity counter is
    Port ( CLK : in  STD_LOGIC;
           CLR : in  STD_LOGIC;
           DOUT : out  STD_LOGIC_VECTOR (7 downto 0));
end counter;

architecture Behavioral of counter is

signal val: std_logic_vector(7 downto 0);

begin

process (CLK,CLR) is
begin
    if CLR='1' then
        val<="00000000";
    elsif rising_edge(CLK) then
        val<=val+1;
    end if;
end process;

DOUT<=val;

end Behavioral;

ISE inserted library and ports declarations automatically, we only need to write an essential part of VHDL description (inside thearchitecture block).

To check VHDL syntax, select "Synthesize - XST => Check Syntax" task for our module.

Simulation

In order to check that our code works as intended, we need to define input signals and check that output signals are correct. It can be done by creating a testbench.

To create a testbench for our counter, select "Create New Source" task, choose "VHDL Test Bench" module type and name it, for instance, counter_tb.vhd.

VHDL test bench is written in VHDL, just like a hardware device description. The difference is that a testbench can utilize some additional language constructs that aren't synthesizable and therefore cannot be used in real hardware (for example wait statements for delay definition).

In order for testbench file to be visible, choose "Behavioral Simulation" in the combobox in the upper part of the sidebar.

ISE automatically generates most of the testbench code, we need only to add our "stimulus":

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;

ENTITY counter_tb_vhd IS
END counter_tb_vhd;

ARCHITECTURE behavior OF counter_tb_vhd IS

    -- Component Declaration for the Unit Under Test (UUT)
    COMPONENT counter
    PORT(
        CLK : IN std_logic;
        CLR : IN std_logic;         
        DOUT : OUT std_logic_vector(7 downto 0)
        );
    END COMPONENT;

    --Inputs
    SIGNAL CLK :  std_logic := '0';
    SIGNAL CLR :  std_logic := '0';

    --Outputs
    SIGNAL DOUT :  std_logic_vector(7 downto 0);

BEGIN

    -- Instantiate the Unit Under Test (UUT)
    uut: counter PORT MAP(
        CLK => CLK,
        CLR => CLR,
        DOUT => DOUT
    );
    -- Clock generation   
    process is
    begin
        CLK<='1';
        wait for 5 ns;
        CLK<='0';
        wait for 5 ns;
    end process;

    tb : PROCESS
    BEGIN

        CLR<='1';
        wait for 100 ns;

        CLR<='0';

        wait; -- will wait forever
    END PROCESS;

END;

We have added the clock generation process (which generates 100MHz frequency clock) and reset stimulus.

Now select a test bench source file and apply "Xilinx ISE Simulator => Simulate Behavioral Model" task. We should get something like this:

Xilinx ISE Simulator window

It can be seen that our counter works properly.

Synthesis

The next step is to convert our VHDL code into a gate-level netlist (represented in the terms of the UNISIM component library, which contains basic primitives). This process is called "synthesis". By default Xilinx ISE uses built-in synthesizer XST (Xilinx Synthesis Technology).

In order to run synthesis, one should select "Synthesis/Implementation" in the combobox in the upper part of the sidebar, select a top-level module and apply a "Synthesize - XST" task. If the code is correct, there shouldn't be any pproblems during the synthesis.

Synthesizer report contains many useful information. There is a maximum frequency estimate in the "timing summary" chapter. One should also pay attention to warnings since they can indicate hidden problems.

After a successful synthesis one can run "View RTL Schematic" task (RTL stands for register transfer level) to view a gate-level schematic produced by a synthesizer:

RTL schematic view in Xilinx ISE

Notice that an RTL schematic in question contains only one primitive: a counter, which is directly an element from the UNISIM library.

Synthesizer output is stored in NGC format.

Implementation
Implementation design flow
  1. Translate - convert NGC netlist (represented in the terms of the UNISIM library) to NGD netlist (represented in the terms of the SIMPRIM library). The difference between these libraries is that UNISIM is intended for behavioral simulation, and SIMPRIM is a physically-oriented library (containing information about delays etc.) This conversion is performed by the program NGDBUILD and is rather straightforward. The main reason for it to be included is to convert netlist generated by different design entry methods (e.g. schematic entry, different synthesizers etc.) into one unified format.
  2. Map is a process of mapping the NGD netlist onto the specific resources of the particular device (logic cells, RAM modules, etc.) This operation is performed by the MAP program with resutls being stored in NCD format. For Virtex-5 MAP also does placement (see below).
  3. Place and route - as can be inferred from its name, this stage is responsible for the layout. It performs placement (logic resources distribution) and routing (connectivity resources distribution). Place and route is performed by a PAR program. For Virtex-5 devices, though, placement is performed by MAP program (and routing still by PAR program). The output of PAR is stored, again, in NCD format.
Implementation Constraints

Constraints are very important during the implementation. They define pin assignments, clocking requirements and other parameters influencing implementation. Constraints are stored in UCF format (user constraints file).

In order to add constraints one need to add a new source (using "Create New Source" task) and choose "Implementation constraints file" source type. UCF file is a text file that can be directly edited by a user, however, simple consraints can be defined with graphical interface.

When a constraints file is selected in the upper part of the sidebar, the specific tasks become available. These include "Create Timing Constraints" and "Assign Package Pins".

For example, if we specify a frequency requirement on CLK as 100 MHz, the corresponding section of the constraints file will be:

NET "CLK" TNM_NET = CLK;
TIMESPEC TS_CLK = PERIOD "CLK" 100 MHz;

When timing requirements are specified in the constraints file, the implementation tools will strive to meet them (and report an error in the case it can't be met).

Package pins constraints must also be set (according to the board layout).

MAP program converts UCF constraints to the PCF format which is later used by PAR.

There are also synthesis constraints stored in XCF files. They are used rarely and shouldn't be confused with implementation constraints.

Programming file generation

After placement and routing, a file should be generated that will be loaded into the FPGA device to program it. This task is performed by a BITGEN program.

The programming file has .bit extension.

The programming file is loaded to the FPGA using iMPACT.

Get free daily email updates!

Follow us!

Saturday, 13 October 2012

VHDL- Delta Delay

VHDL-Delta_Delay

VHDL allows the designer to describe systems at various levels of abstraction. As such, timing and delay information may not always be included in a VHDL description.

A delta (or delta cycle) is essentially an infinitesimal, but quantized, unit of time. The delta delay mechanism is used to provide a minimum delay in a signal assignment statement so that the simulation cycle described earlier can operate correctly when signal assignment statements do not include explicitly specified delays. That is:

1) all active processes can execute in the same simulation cycle

2) each active process will suspend at wait statement

3) when all processes are suspended simulation is advanced the minimum time necessary so that some signals can take on their new values

4) processes then determine if the new signal values satisfy the conditions to proceed from the wait statement at which they are suspended

Get free daily email updates!

Follow us!

VHDL-Inertial Delay

VHDL-Inertial_Delay

The keyword INERTIAL may be used in the signal assignment statement to specify an inertial delay, or it may be left out because inertial delay is used by default in VHDL signal assignment statements which contain “after” clauses.

If the optional REJECT construct is not used, the specified delay is then used as both the ‘inertia’ (i.e. minimum input pulse width requirement) and the propagation delay for the signal. Note that in the example above, pulses on Input narrower than 10ns are not observed on Output.

Get free daily email updates!

Follow us!

VHDL-Transport Delay

VHDL-Transport Delay

VHDL-Transport Delay
The keyword TRANSPORT must be used to specify a transport delay.

Transport delay is the simplest in that when it is specified, any change in an input signal value may result in a new value being assigned to the output signal after the specified propagation delay.

Note that no restrictions are specified on input pulse widths. In this example, Output will be an inverted copy of Input delayed by the 10ns propagation delay regardless of the pulse widths seen on Input .

Get free daily email updates!

Follow us!

Thursday, 11 October 2012

VHDL Timing Model

VHDL_Timing_Model

The VHDL timing model controls the stimulus and response sequence of signals in a VHDL model. At the start of a simulation, signals with default values are assigned those values. In the first execution of the simulation cycle, all processes are executed until they reach their first wait statement. These process executions will include signal assignment statements that assign new signal values after prescribed delays.

After all the processes are suspended at their respective wait statements, the simulator will advance simulation time just enough so that the first pending signal assignments can be made (e.g. 1 ns, 3 ns, 1 delta cycle).

After the relevant signals assume their new values, all processes examine their wait conditions to determine if they can proceed. Processes that can proceed will then execute concurrently again until they all reach their respective subsequent wait conditions.

This cycle continues until the simulation termination conditions are met or until all processes are suspended indefinitely because no new signal assignments are scheduled to unsuspend any waiting processes.

img038

There are several types of delay in VHDL, and understanding of how delay works in a process is key to writing and understanding VHDL.

It bears repeating that any signal assignment in VHDL is actually a scheduling for a future value to be placed on that signal. When a signal assignment statement is executed, the signal maintains its original value until the time for the scheduled update to the new value. Any signal assignment statement will incur a delay of one of the three types listed below.

Get free daily email updates!

Follow us!

Sunday, 4 March 2012

VHDL Attributes

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

Simplified Syntax
object'attribute_name

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

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

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

Table 1. Attributes available for all types

Attribute

Result

T'Base

base type of T

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

Table 2. Scalar type attributes

Attribute

Result type

Result

T'Left

same as T

leftmost value of T

T'Right

same as T

rightmost value of T

T'Low

same as T

least value in T

T'High

same as T

greatest value in T

T'Ascending

boolean

true if T is an ascending range, false otherwise

T'Image(x)

string

a textual representation of the value x of type T

T'Value(s)

base type of T

value in T represented by the string s

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

Table 3. Attributes of discrete or physical types and subtypes

Attribute

Result type

Result

T'Pos(s)

universal integer

position number of s in T

T'Val(x)

base type of T

value at position x in T (x is integer)

T'Succ(s)

base type of T

value at position one greater than s in T

T'Pred(s)

base type of T

value at position one less than s in T

T'Leftof(s)

base type of T

value at position one to the left of s in T

T'Rightof(s)

base type of T

value at position one to the right of s in T

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

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

Attribute

Result

A'Left(n)

leftmost value in index range of dimension n

A'Right(n)

rightmost value in index range of dimension n

A'Low(n)

lower bound of index range of dimension n

A'High(n)

upper bound of index range of dimension n

A'Range(n)

index range of dimension n

A'Reverse_range(n)

reversed index range of dimension n

A'Length (n)

number of values in the n-th index range

A'Ascending(n)

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

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

Table 5. Signals attributes

Attribute

Result

S'Delayed(t)

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

S'Stable(t)

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

S'Quiet(t)

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

S'Transaction

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

S'Event

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

S'Active

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

S'Last_event

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

S'Last_active

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

S'Last_value

the previous value of S before last event occurred on it

S'Driving

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

S'Driving_value

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

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

Table 6. Attributes of named entities

Attribute

Result

E'Simple_name

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

E'Path_name

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

E'Instance_name

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

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

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

 

Examples

Example 1

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

Example 2

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

Example 3

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

Example 4

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

Example 5

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

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

 

Important Notes

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

Monday, 16 January 2012

Shared Variable in VHDL

How to use a single variable in more than one process…!!

VHDL87 limited the scope of the variable to the process in which it was declared. Signals were the only means of communication between processes, but signal assignments require an advance in either delta time or simulation time.

VHDL '93 introduced shared variables which are available to more than one process. Like ordinary VHDL variables, their assignments take effect immediately. However, caution must be exercised when using shared variables because multiple processes making assignments to the same shared variable can lead to unpredictable behavior if the assignments are made concurrently. The VHDL ‘93 standard does not define the value of a shared variable it two or more processes make assignments in the same simulation cycle.

The syntax of the shared variable is similar to that of the normal variable. However, the keyword SHARED is placed in front of VARIABLE in the declaration

Example:

Architecture SV_example of example is
      shared variable status_signal : bit;
begin
     p1 : process (Clock,In1)
     begin
          if(status_signal) then
          ...
          end if;
          status_signal :='0';
     end process;

     p2 : process (Clock,In2)
     begin
          if(!(status_signal)) then
          ....
          end if;
          status_signal:='1';
     end process p2;

end SV_example;

Above example shows the use of shared variable in more than one process.

Saturday, 14 January 2012

VHDL Procedures

The procedure is a form of subprograms. It contains local declarations and a sequence of statements. Procedure can be called in any place of the architecture. The procedure definition consists of two parts:

  • The procedure declaration, which contains the procedure name and the parameter list required when the procedure is called;

  • The procedure body, which consists of the local declarations and statements required to execute the procedure.

PROCEDURE DECLARATION

The procedure declaration consists of the procedure name and the formal parameter list.

In the procedure specification, the identifier and optional formal parameter list follow the reserved word procedure.

procedure Procedure_1 (variable X, Y: inout Real);

Objects classes constants, variables, signals, and files can be used as formal parameters. The class of each parameter is specified by the appropriate reserved word, unless the default class can be assumed (see below). In case of constants, variables and signals, the parameter mode determines the direction of the information flow and it decides which formal parameters can be read or written inside the procedure. Parameters of the file type have no mode assigned.

There are three modes available: in, out, and inout. When in mode is declared and object class is not defined, then by default it is assumed that the object is a constant. In case ofinout and out modes, the default class is variable. When a procedure is called, formal parameters are substituted by actual parameters. If a formal parameter is a constant, then actual parameter must be an expression. In case of formal parameters such as signal, variable and file, the actual parameters must be objects of the same class. Below example presents several procedure declarations with parameters of different classes and modes.

procedure Proc_1 (constant In1: in Integer; variable O1: out Integer);
procedure Proc_2 (signal Sig: inout Bit);

A procedure can be declared also without any parameters.

PROCEDURE BODY

Procedure body defines the procedure's algorithm composed of sequential statements. When the procedure is called it starts executing the sequence of statements declared inside the procedure body.

The procedure body consists of the subprogram declarative part After the reserved word is and the subprogram statement part placed between the reserved words begin and end. The key word procedure and the procedure name may optionally follow the end reserved word.

Declarations of a procedure are local to this declaration and can declare subprogram declarations, subprogram bodies, types, subtypes, constants, variables, files, aliases, attribute declarations, attribute specifications, use clauses, group templates and group declarations.

procedure Proc_3 (X,Y : inout Integer) is
  type Word_16 is range 0 to 65536;
  subtype Byte is Word_16 range 0 to 255;
  variable Vb1,Vb2,Vb3 : Real;
  constant Pi : Real :=3.14;

procedure Compute (variable V1, V2: Real) is
  begin
    -- subprogram_statement_part
  end procedure Compute;

begin
    -- subprogram_statement_part
end procedure Proc_3;

A procedure can contain any sequential statements (including wait statements). A wait statement, however, cannot be used in procedures which are called from a process with a sensitivity list or from within a function.

procedure Transcoder_1 (variable Value: inout bit_vector (0 to 7)) is
begin
  case Value is
    when "00000000" => Value:="01010101";
    when "01010101" => Value:="00000000";
    when others => Value:="11111111";
  end case;
end procedure Transcoder_1;

The procedure Transcoder_1 transforms the value of a single variable, which is therefore a bi-directional parameter.

procedure Comp_3(In1,R:in real; Step :in integer; W1,W2:out real) is
variable counter: Integer;
begin
  W1 := 1.43 * In1;
  W2 := 1.0;
  L1: for counter in 1 to Step loop
    W2 := W2 * W1;
    exit L1 when W2 > R;
  end loop L1;
  assert ( W2 < R )
    report "Out of range"
      severity Error;
end procedure Comp_3;

The Comp_3 procedure calculates two variables of mode out: W1 and W2, both of the REAL type. The parameters of mode in: In1 and R constants are of real type and Step of the integer type. The W2 variable is calculated inside the loop statement. When the value of W2 variable is greater than R, the execution of the loop statement is terminated and the error report appears.

PROCEDURE CALL

A procedure call is a sequential or concurrent statement, depending on where it is used. A sequential procedure call is executed whenever control reaches it, while a concurrent procedure call is activated whenever any of its parameters of in or inout mode changes its value.

All actual parameters in a procedure call must be of the same type as formal parameters they substitute.

OVERLOADED PROCEDURES

The overloaded procedures are procedures with the same name but with different number or different types of formal parameters. The actual parameters decide which overloaded procedure will be called.

procedure Calculate (W1,W2: in Real; signal Out1:inout Integer);
procedure Calculate (W1,W2: in Integer; signal Out1: inout Real);
-- calling of overloaded procedures:
Calculate(23.76, 1.632, Sign1);
Calculate(23, 826, Sign2);

The procedure Calculate is an overloaded procedure as the parameters can be of different types. Only when the procedure is called the simulator determines which version of the procedure should be used, depending on the actual parameters.

Properties of Procedures

  • Synthesis tools usually support procedures as long as they do not contain the wait statements.
  • The Procedure declaration is optional - procedure body can exist without it. If, however, a procedure declaration is used, then a procedure body must accompany it.

Friday, 13 January 2012

VHDL Functions and Procedures

Functions and procedures in VHDL, which are collectively known as subprograms, are directly analogous to functions and procedures in a high-level software programming language such as C or Pascal. A procedure is a subprogram that has an argument list consisting of inputs and outputs, and no return value. A function is a subprogram that has only inputs in its argument list, and has a return value.

Subprograms are useful for isolating commonly-used segments of VHDL source code. They can either be defined locally (within an architecture, for example), or they can be placed in a package and used globally throughout the design description or project.

Statements within a subprogram are sequential (like a process), regardless of where the subprogram is invoked. Subprograms can be invoked from within the concurrent area of an architecture or from within a sequential process or higher-level subprogram. They can also be invoked from within other subprograms.

Subprograms are very much like processes in VHDL. In fact, any statement that you can enter in a VHDL process can also be entered in a function or procedure, with the exception of a wait statement (since a subprogram executes once each time it is invoked and cannot be suspended while it is executing). It is therefore useful to think of subprograms as processes that (1) have been located outside the body of an architecture, and (2) operate only on their input and (in the case of procedures) their output parameters.

Nesting of functions and procedures is allowed to any level of complexity, and recursion is also supported in the language. (Of course, if you expect to generate actual hardware from your VHDL descriptions using synthesis tools, then you will need to avoid writing recursive functions and procedures, as such descriptions are not synthesizable).

Thursday, 12 January 2012

VHDL Functions

I think all of the Designer wanted the Code simple and understandable. In simulation functions can be used to accomplish all kinds of things but For synthesis we must be more careful. Functions can be useful to model a component or a type conversion.

Warning, though!!! You must THINK HARDWARE!!!

Many functions have been defined in the IEEE libraries, e.g. rising_edge(CLK)

Function Properties :

  • Function parameters can only be inputs.
  • Functions can only return one value, specified by “return”.
  • Statements inside the function are sequential except signal assignment and wait.
  • No new signals can be declared, but variables can be.
  • A function may declare local variables. These do not retain their values between successive calls, but are re-initialized each time.
  • A function can be called as an expression, in either a concurrent or sequential statement
  • Functions can be included either explicitly or through the use of packages.

Syntax:

function function_name (parameter_list) return type is
    declarations
begin
    sequential statements
end function_name;

Example:
entity full_add is
port(
         a, b, carry_in: in bit;
         sum, carry_out: out bit);
end full_add;

architecture full_add_arch of full_add is

function carry (a, b, c: in bit) return bit is
  begin
        return ((a and b) or (a and c) or (b and c));
end majority;

begin
       sum <= a xor b xor carry_in;
       carry_out <= carry(a, b, carry_in);
end full_add_arch;

Thursday, 8 December 2011

Verilog Design With VHDL Testbench

// Two bit adder design in Verilog

module adder (a,b,carry,sum);
   //Port Declarations
   input [1:0] a;
   input [1:0] b;
   output [1:0] sum;
   output  carry;
   //Drivers for output signals
   reg [1:0]  sum;
   reg   carry;  
   // combination Logic for adder
   always @ (a or b) //Sensitive to inputs a or b
     begin
         {carry,sum} = a+b; 
     end
endmodule

 

--VHDL test bench for Verilog adder

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

entity ADDER_TB is      --Top level entity dosen't have any port
end ADDER_TB;

architecture TB of ADDER_TB is

    component ADDER is
    port( A: in std_logic_vector(1 downto 0);
  B: in std_logic_vector(1 downto 0); 
  carry: out std_logic;     
  sum: out std_logic_vector(1 downto 0)
    );
    end component;

    signal A, B: std_logic_vector(1 downto 0);
    signal carry: std_logic;
    signal sum:  std_logic_vector(1 downto 0);

    begin
        DUT: ADDER port map (A, B, carry, sum);
    process  
variable err_cnt: integer :=0;
    begin -- Generating test vectors
-- case 1
A <= "00";      
B <= "00";
wait for 10 ns;
assert (sum="00") report "Sum Error!" severity error;
assert (carry='0') report "Carry Error!" severity error;
if (sum/="00" or carry/='0') then
     err_cnt:=err_cnt+1;
end if;
  -- case 2  
A <= "11";
B <= "11";
wait for 10 ns;  
assert (sum="10") report "Sum Error!" severity error; 
assert (carry='1') report "Carry Error!" severity error;
if (sum/="10" or carry/='1') then
     err_cnt:=err_cnt+1;
end if;
-- case 3
A <= "01";
B <= "10";
wait for 10 ns;  
assert (sum="11") report "Sum Error!" severity error; 
assert (carry='0') report "Carry Error!" severity error;
if (sum/="11" or carry/='0') then
     err_cnt:=err_cnt+1;
end if;
-- case 4
A <= "10";
B <= "01";
wait for 10 ns;   
assert (sum="11") report "Sum Error!" severity error; 
assert (carry='0') report "Carry Error!" severity error;
if (sum/="11" or carry/='0') then
     err_cnt:=err_cnt+1;
end if;
-- case 5
A <= "01";
B <= "01";
wait for 10 ns;
assert (sum="10") report "Sum Error!" severity error;
assert (carry='0') report "Carry Error!" severity error;
if (sum/="10" or carry/='0') then
     err_cnt:=err_cnt+1;
end if;
-- summary of testbench
if (err_cnt=0) then
     assert false
     report "Test completed successfully for adder!"
     severity note;
else
     assert true
     report "ERROR - Expected and received results are wrong"
     severity error;
end if;
wait;
    end process;
end TB;

VHDL Design With Verilog Testbench

--VHDL Design for 4:1 multiplexor

library ieee;
use ieee.std_logic_1164.all;
entity Mux is
  port(I3  : in  std_logic_vector(2 downto 0);
        I2 : in  std_logic_vector(2 downto 0);
        I1 : in  std_logic_vector(2 downto 0);
        I0 : in  std_logic_vector(2 downto 0);
        S  : in  std_logic_vector(1 downto 0);
        O  : out std_logic_vector(2 downto 0)
        );
end Mux;
architecture behv1 of Mux is
begin
  process(I3, I2, I1, I0, S)
  begin
    -- use case statement
    case S is
      when "00"   => O <= I0;
      when "01"   => O <= I1;
      when "10"   => O <= I2;
      when "11"   => O <= I3;
      when others => O <= "ZZZ";
    end case;
  end process;
end behv1;

 

//Verilog Test Bench for 4:1 VHDL multiplexer

module mux_tb (i3,i2,i1,i0,s,o);
   input  [2:0] o;
   output [2:0] i3;
   output [2:0] i2;
   output [2:0] i1;
   output [2:0] i0;
   output [1:0]  s;
   //Drivers for output
   reg [2:0] i3;
   reg [2:0] i2;
   reg [2:0] i1;
   reg [2:0] i0;
   reg [1:0] s;
   //Error counter
   integer   error_count;
   //Generatiin test cases
   initial
     begin
error_count = 0;
//Assigning different values for different signals
i3 = 3'h4;
i2 = 3'h7;
i1 = 3'h0;
i0 = 3'h5;
        //Case1
s  = 2'b00;
#2 //wait for 2 delays
if (o != 3'h5)
   begin
      $display("Error in case 1\n");
      error_count = error_count + 1;     
          end
        //Case2
s  = 2'b01;
#2 //wait for 2 delays
if (o != 3'h0)
   begin
      $display("Error in case 2\n");
      error_count = error_count + 1;     
          end
        //Case3
s  = 2'b10;
#2 //wait for 2 delay
if (o != 3'h7)
   begin
      $display("Error in case 3\n");
      error_count = error_count + 1;     
          end
        //Case4
s  = 2'b11;
#2 //wait for 2 delay
if (o != 3'h4)
   begin
      $display("Error in case 4\n");
      error_count = error_count + 1;     
          end
//Test Summary
if(error_count)
   $display("ERROR in the design");
else
   $display("All test cases are passed");
     end
//mux instantiation and port mapping
   mux one(.i3(i3),.i2(i2),.i1(i1),.i0(i0),.s(s),.o(o));
endmodule

Mixed Language Simulation In VLSI

Most of Simulation Tools supports mixed language project files and mixed language simulation. This enables you to include Verilog modules in a VHDL design, and vice versa. Some restrictions do apply:

  • Mixing VHDL and Verilog is restricted to the module instance or component only. A VHDL design can instantiate Verilog modules and a Verilog design can instantiate VHDL components. Any other kind of mixing between VHDL and Verilog is not supported.
  • A Verilog hierarchical reference cannot refer to a VHDL unit nor can a VHDL expanded/selected name refer to a Verilog unit.
  • Only a small subset of VHDL types, generics and ports are allowed on the boundary to a Verilog module. Similarly, a small subset of Verilog types, parameters and ports are allowed on the boundary to VHDL design unit.
  • Component instantiation-based default binding is used for binding a Verilog module to a VHDL design unit. Specifically, configuration specification, direct instantiation and component configurations are not supported for a Verilog module instantiated inside a VHDL design unit.

Examples:

1. VHDL Design With Verilog Testbench

2. Verilog Design With VHDL Testbench

Monday, 19 September 2011

VHDL Code for Multiplxer using with-select statement

Below written VHDL code is for 4x1 multiplexer using with-select statement.

LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;

ENTITY mux4 IS
  PORT ( i0, i1, i2, i3, a, b : IN std_logic;
                            q : OUT std_logic);
END mux4;

ARCHITECTURE mux4 OF mux4 IS
  SIGNAL sel: INTEGER;
BEGIN
  WITH sel SELECT
    q <= i0 AFTER 10 ns WHEN 0,
         i1 AFTER 10 ns WHEN 1,
         i2 AFTER 10 ns WHEN 2,
         i3 AFTER 10 ns WHEN 3,
         'X' AFTER 10 ns WHEN OTHERS;

  sel <= 0 WHEN a = '0' AND b = '0' ELSE
         1 WHEN a = '1' AND b = '0' ELSE
         2 WHEN a = '0' AND b = '1' ELSE
         3 WHEN a = '1' AND b = '1' ELSE
         4 ;
END mux4;

VHDL Code for Multiplxer using When-else statement

Below written VHDL code is for 4x1 multiplexer using when-else statement.

LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY mux IS
  PORT (i0, i1, i2, i3, a, b: IN std_logic;
        q : OUT std_logic);
END mux;

ARCHITECTURE bad OF mux IS
BEGIN
  q <= i0 WHEN a = '0' AND b = '0' ELSE '0';
  q <= i1 WHEN a = '1' AND b = '0' ELSE '0';
  q <= i2 WHEN a = '0' AND b = '1' ELSE '0';
  q <= i3 WHEN a = '1' AND b = '1' ELSE '0';
END BAD;

ARCHITECTURE better OF mux IS
BEGIN
  q <= i0 WHEN a = '0' AND b = '0' ELSE
       i1 WHEN a = '1' AND b = '0' ELSE
       i2 WHEN a = '0' AND b = '1' ELSE
       i3 WHEN a = '1' AND b = '1' ELSE
       'X';      --- unknown
END better;

Friday, 5 August 2011

2-bit Counter VHDL Code

library ieee;
use ieee.std_logic_1164.all;

entity bit_counter is
  port (
    clk       : in  std_logic;
    rst       : in  std_logic;
    count_out : out std_logic_vector(1 downto 0));

end bit_counter;

architecture bit_counter_ar of bit_counter is

-- Defining Internal Signals

signal sig1,sig2 : std_logic;
  signal count_out_sig : std_logic_vector (1 downto 0);

begin  -- 2bit_counter_ar

   process (clk, rst)

-- purpose: sequential part of counter
  -- type   : sequential
  -- inputs : clk, rst
  -- outputs:

  begin  -- process
    if rst = '1' then                   -- asynchronous reset (active high)
      count_out_sig <= "11";
    elsif clk'event and clk = '1' then  -- rising clock edge
      count_out_sig(0) <= sig1;
      count_out_sig(1) <= sig2;
    end if;
  end process;

-- Combinational Logic 

  sig1 <= not count_out_sig(0);
  sig2 <= count_out_sig(1) xor count_out_sig(0);
  count_out <= count_out_sig;

end bit_counter_ar;

Friday, 31 December 2010

VHDL code for AND gate

 

library ieee;
use ieee.std_logic_1164.all;

entity my_and is

  port (a, b : in  std_logic;
        c    : out std_logic);

end my_and;

architecture my_and_arc of my_and is

  begin
  c <= a and b;

end my_and_arc;