Featured post

Top 5 books to refer for a VHDL beginner

VHDL (VHSIC-HDL, Very High-Speed Integrated Circuit Hardware Description Language) is a hardware description language used in electronic des...

Sunday, 16 December 2012

Variable Declaration

Formal Definition

Variable is an object with a single current value.

Simplified Syntax

variable variable_name : type;

variable variable_name : type := initial_value;

Description

Variables are objects which store information local to processes and subprograms (procedures and functions) in which they are defined. Their values can be changed during simulation through the variable assignment statements.

A variable declaration includes one or more identifiers, a subtype indication and an optional globally static expression defining the initial value for the variable(s). The identifiers specify names for the variables, with one identifier per each variable. The variable can be declared to be of any type or subtype available, either constrained or unconstrained (Example 1).

The initial value of a variable can be assigned by a globally static expression. The expression must reference a value of the same type as the variable itself. If the variable is declared to be of a composite type other than a string, Bit_Vector or Std_Logic_Vector, then an aggregate must be used (see Example 2).

If the initial value of a variable is not specified, then it is implicitly set as the left bound of the type used. For example for a scalar named T, the default initial value will be T'LEFT. For a composite type, the initial value will be the aggregate consisting of the set of the default values of all the scalar elements. The default initial value for a variable of the access type isnull.

Variables declared in processes are initialized with their default values, given either explicitly or implicitly, at the start of the simulation. Variables declared in subprograms are initialized each time the subprogram is called.

The scope of variables is limited to the process or subprogram they are defined in. The only exception to this rule is a shared variable, which may be shared by multiple processes.

Variables can be also declared outside of a procedure or process to be shared between many processes. Shared variables may be declared within an architecture, block, generate statement or package. Declaration of a shared variable must be preceded by the shared keyword (Example 3).

Although the Language Reference Manual allows several processes to access a single shared variable it does not define what happens when two or more conflicting processes try to access the same variable at the same time. Such a situation may lead to unpredictable results and therefore should be avoided.

Examples

Example 1

type Mem is array (Natural range <>, Natural range <>) of Std_Logic;
variable Delay1, Delay2 : Time;
variable RAM1: Mem (0 to 1023, 0 to 8);

The type Mem is specified as an unconstrained memory (the limit depends on the implementation of the Natural subtype). The variable RAM1, specified in the third line, is based on the Mem type and is defined as a subtype constrained to a 1 KB memory.

Both Delay1 and Delay2 variables are of the Time type and are declared in the second line.

Example 2

type Mem is array (Natural range <>, Natural range <>) of Std_Logic;
variable TempCond : Boolean := true;
variable RAM2: Mem (0 to 7, 0 to 7):=
  (('0', '0', '0', '0', '0', '0', '0', '0'),
  ('0', '0', '0', '0', '0', '0', '0', '0'),
  ('0', '0', '0', '0', '0', '0', '0', '0'),
  ('0', '0', '0', '0', '0', '0', '0', '0'),
  ('0', '0', '0', '0', '0', '0', '0', '0'),
  ('0', '0', '0', '0', '0', '0', '0', '0'),
  ('0', '0', '0', '0', '0', '0', '0', '0'),
  ('0', '0', '0', '0', '0', '0', '0', '0'));

Both variables are initialized according to the types used. Note the aggregate has been used for initializing RAM2, which is an 88 bit memory.

Example 3

shared variable FreeAccess : Boolean := true;

The shared variable FreeAccess statement is used to determine whether a shared resource can be accessed at any particular time. However, in real applications a signal declaration would better serve for this purpose because using signals makes the specification more deterministic.

Important Notes

· Unlike signals, variables have neither history nor future, because according to its definition, each variable has only current value. No checking for the last event, time elapsed since the last event, previous value, etc. can be performed on variables.

· The non-shared variables are limited to subprograms and processes only.

· If a value of a variable is read before it is assigned in a clocked process (i.e. where operations are performed when an edge of clock signal is detected) then a register will be synthesized for this variable. A similar situation inside a combinatorial process may lead to generation of a latch.

· Variables declared in a subprogram are synthesized as combinatorial logic.

· During simulation variables consume a lot less (even an order of magnitude) memory space than signals. Therefore, it is highly recommended to use them for storage elements (such as memories) instead of signals.

· Shared variables may cause a system to be non-deterministic and therefore they should be avoided.

Vector

Description

Vector is another name for a one-dimensional array. It is used in particular for the arrays with elements of logical types: bit and std_logic (bit_vector and std_logic_vector, respectively).

Examples

signal DataBus : Bit_Vector(7 downto 0);
  . . .
DataBus <= "11000011";

Important Notes

  • Vectors of logical values are not directly transferable to integer values. Neither Standard package nor Std_Logic_1164 package define any conversion functions from logical vector to an integer or vice-versa. Most synthesis tools, however, support such functions (although these functions are tool-specific).
  • No arithmetic functions are allowed on logical vectors.

Vital

Formal Definition

VITAL (VHDL Initiative Towards ASIC Libraries) is an initiative, which objective is to accelerate the development of sign-off quality ASIC macro-cell simulation libraries written in VHDL by leveraging existing methodologies of model development.

Complete description: IEEE Standard 1076.4.

Description

VITAL, which is now standardized by IEEE, was created by an industry-based, informal consortium in order to accelerate the availability of ASIC (Application Specific Integrated Circuits) libraries for use in industrial VHDL simulators. As a result of the effort a new modeling specification has been created.

VITAL contains four main elements:

  • Model Development Specification document, which defines how ASIC libraries should be specified in VITAL-compliant VHDL in order to be simulated in VHDL simulators.
  • VHDL package Vital_Timing, defining standard types and procedures that support development of macro-cell timing models. The package contains routines for delay selections, timing violations checking and reporting and glitch detection.
  • VHDL package Vital_Primitives, defining commonly used combinatorial primitives provided both as functions and concurrent procedures and supporting either behavioral or structural modeling styles, e.g. VitalAND, VitalOR, VitalMux4, etc. The procedure versions of the primitives support separate pin-to-pin delay path and GlitchOnEvent glitch detection. Additionally, general purpose Truth Tables and State Tables are specified which are very useful in defining state machines and registers.
  • VITAL SDF map - specification that defines the mapping (translation) of Standard Delay Files (SDF), used for support timing parameters of real macro-cells, to VHDL generic values.

MODELING SPECIFICATION

The modeling specification of VITAL defines several rules for VHDL files to be VITAL-compliant. This covers in particular:

  • Naming conventions for timing parameters and internal signals, including prefixes for timing parameters, which must be used in the generics specifications (Example 1);
  • How to use the types defined in the Vital_Timing package for specifications of timing parameters;
  • Methodology of coding styles;
  • Two levels of compliance: level 0 for complex models described at higher level, and level 1, which additionally permits model acceleration.

A VITAL-compliant specification consists of an entity with generics defining the timing parameters of the ports (Example 1) and an architecture that can be written in one of two coding styles: either pin-to-pin delay style or distributed delay style.

PIN-TO-PIN DELAY MODELING STYLE

An architecture that follows this style contains two main parts (Example 2):

  • A block called Wire_Delay, which defines input path delays between input ports and internal signals. This block calls the concurrent procedure VitalPropagateWireDelay.
  • A process called VitalBehavior. This process may contain declarations of local aliases, constants and variables. It has a very rigid structure and is divided into three parts:
    • Timing Checks - does calls to procedure VitalTimingCheck which is defined in the package Vital_Timing.
    • Functionality - makes one or more calls to subprograms contained in the Vital_Primitives package and assignments to internal temporal variables. No wait statements, signal assignments or control structures are allowed here.
    • Path Delay - contains a call to VitalPropagateDelay for each output signal.

DISTRIBUTED DELAY MODELING STYLE

In this style the specification (ASIC cell) is composed of structural portions (VITAL primitives), each of which has its own delay. The output is an artifact of the structure, events and actual delays. All the functionality is contained in one block, called Vital_Netlist and this block may contain only calls to primitives defined in the Vital_Primitives package.

Examples

Example 1

library IEEE;
use IEEE.Std_Logic_1164.all;
library VITAL;
use VITAL.Vital_Timing.all;
use VITAL.Vital_Timing;
use VITAL.Vital_Primitives.all;
use VITAL.Vital_Primitives;
entity Counter is
  generic(tpd_ClkOut1 : DelayType01 := (10 ns, 10 ns);
  . . .);
  port (Reset : in Std_Logic := 'U';
    Clk : in Std_logic := 'U';
    CntOut : out Std_logic_Vector(3 downto 0));
end Counter;

This entity is a part of a VITAL-compliant specification of a four-bit synchronous counter with reset. Note that two libraries and three packages are used. In particular, multiple value logic types, defined in Std_Logic_1164, are standard logical types for VITAL.

The example given here specifies the propagation delay between the Clk input and the output number 1. The VITAL prefix tpd determines the timing parameter. The type used is specified in the Vital_Tming package.

Example 2

architecture PinToPin of Counter is
-- declarations of internal signals
begin
-- Input path delay
  Wire_Delay: block
  begin
  -- calls to the VitalPropagateWireDelay procedure
  Vital_Timing.VitalPropagateWireDelay (. . .);
  . . .
end block;
-- Behavior section
VitalBehavior: process(. . .)
  -- declarations
begin
  -- Timing Check
  Vital_Timing.VitalTimingCheck (. . .);
  -- Functionality
  Vital_Primitives.VitalStateTable (. . .);
  -- Path Delay
  Vital_Timing.VitalPropagatePathDelay (. . .);
  Vital_Timing.VitalPropagatePathDelay (. . .);
end process VitalBehavior;
end PinToPin;

The above listed architecture PinToPin is a template of a pin-to-pin modeling style. All its procedure calls should be specified with appropriate parameters.

Example 3

architecture DistrDelay of Counter is
  -- internal signals declarations
begin
-- Input path delay
Vital_Netlist: block
  -- internal declarations of the block
  begin
  -- calls to VITAL primitives, for example
  Vital_Primitives.VitalAND2(. . .);
  Vital_Primitives.VitalBuf(. . .);
  Vital_Primitives.VitalStateTable(. . .);
  end block;
end DistrDelay;

The above listed Architecture DistrDelay is a template of a distributed delay modeling style. All its procedure calls should be specified with appropriate parameters.

Saturday, 15 December 2012

Wait Statement

Definition:

The wait statement is a statement that causes suspension of a process or a procedure.

Simplified Syntax

wait;

wait on signal_list;

wait until condition;

wait for time;

Description

The wait statement suspends the execution of the process or procedure in which it is specified. Resuming the process or procedure depends on meting the condition(s) specified in the wait statement. There are three types of conditions supported with wait statements: sensitivity clause, condition clause, and timeout clause.

The most often used is the sensitivity clause. A sensitivity list defines a set of signals to which the process is sensitive and causes the process to resume (example 1).

If a wait statement does not contain a sensitivity list, then an implicit sensitivity list is assumed, one which contains all the signals that are present in that condition. If a process is resumed but no condition is met, then the process will not execute any other statements (example 2).

The second type of a condition supported with the wait statement is the condition clause. A process is resumed when the logical condition turns true due to a change of any signal listed in the condition (example 2).

The timeout clause defines the maximum time interval during which the process is not active. When the time elapses, the process is automatically resumed (example 3).

A single wait statement can have several different conditions. In such a case the process will be resumed when all the conditions are met (example 4).

If a wait on sensitivity_list is the only wait in the process and the last statement of the process, then it can be substituted by a sensitivity list of a process. See sensitivity list for details.

The syntax of the wait statement allows to use it without any conditions. Such a statement is equivalent to wait until true, which suspends a process forever and will never resume. While in simulation of normal models this is a disadvantage, this particular feature of a wait statement is widely used in testbenches. Example 5 shows an example of a testbench section.

Examples

Example 1

signal S1, S2 : Std_Logic;
. . .
process
  begin
   . . .
   wait on S1, S2;
end process;

After executing all statements, the process will be suspended on the wait statement and will be resumed when one of the S1 or S2 signals changes its value.

Example 2

wait until Enable = '1';
-- this is equivalent to
--   loop
--     wait on Enable;
--     exit when Enable = '1';
--   end loop;

In this example, the wait statement will resume the process when the Enable signal changes its value to '1'. This is equivalent to the loop described in the comment below the first line. Please note that the process is resumed on any change of the Enable signal. However, it will awake the rest of the process only when the new value is '1'.

Example 3

wait for 50 ns;

A process containing this statement will be suspended for 50 ns.

Example 4

BIN_COMP : process
begin
wait on A, B until CLK = '1';
  . . .
end process;

The process BIN_COMP is resumed after a change on either A or B signal, but only when the value of the signal CLK is equal to '1'.

Example 5

G: process
begin
  G0 <= '1' after 5 ns,
        '0' after 10 ns,
        '1' after 15 ns,
        '0' after 20 ns;
  G1 <= '1' after 5 ns,
        '0' after 15 ns;
  wait;
end process G;

In this process the values of signals G1 and G0 are set to '11', '10', '01', and '00' at the time intervals 5, 10, 15 and 20 ns, respectively. When the wait statement is encountered, the process is suspended forever.

Important Notes

· The wait statement can be located anywhere between begin and end process.

· A process with a sensitivity list may not contain any wait statements.

Waveform

Definition:

A series of transactions, each of which represents a future value of the driver of a signal. The transactions in a waveform are ordered with respect to time, so that one transaction appears before another if the first represents a value that will occur sooner than the value represented by the other.

Syntax:

waveform ::= waveform_element { , waveform_element }

| unaffected

waveform_element ::= value_expression [ after time_expression ]

| null [ after time_expression ]

Description

The waveform statement appears on the right-hand side of the signal assignment statement. It supports new values for the signal, possibly together with expected delays when the changes of the values will take effect. Alternatively, in concurrent signal assignments, the reserved word unaffected can be used instead of new values.

Each waveform element is composed of an expression whose value will be assigned to the signal driver and optional time expression is defined following the reserved word after. The type of the expression appearing in the waveform element must be the same as the type of the target signal (Example 1).

If there is no time expression specified in the waveform element of the signal assignment statement, then the time delay is implicitly delcared as after 0 ns (Example 2).

An expression in a waveform can be substituted by the value null. This value can be assigned only to signals declared as guarded, additionally with a resolution function (Example 3).

If the reserved word unaffected is used as a waveform in a concurrent signal assignment, it is equivalent to a process executing a null statement.

Evaluation of a waveform element produces a single transaction, i.e. a pair: new value for a signal and time when this value will be assigned. The time is determined by the current simulation time added to the value of time expression in the waveform element.

Examples

Example 1

signal D_OUT, E_OUT : BIT_VECTOR (3 downto 0);
.............................
D_OUT <= "0000" after 2 ns;
E_OUT <= "0000" after 2 ns, "1111" after 7 ns;

In the first signal assignment statement the "0000" value will be assigned to the driver D_OUT after 2ns. In the second assignment, first the "0000" value will be assigned to the E_OUT after 2ns and then after additional 5 ns the signal will be assigned the "1111" value.

Example 2

C_OUT <= 'X';
if C_OUT = 'X' then ...

Although the signal assignment will take place "after 0 ns", it is not immediate and when the if statement is executed, C_OUT will still have its value unchanged. Update of the C_OUT signal will take place at the end of simulation cycle, i.e. when the process is suspended.

Example 3

architecture test_null of test is
function res_fun (res_val: bit_vector) return bit is
begin
  for i in res_val'RANGE loop
    if res_val (i) = '1' then return '1';
    end if;
    return '0';
  end loop;
end res_fun;
signal H : res_fun BIT register;
begin
P1: process
begin
  A1: H <= '1' after 10 ns, null after 20 ns;
end process P1;
P2: process
begin
  A2: H <= '1' after 5 ns, '0' after 10 ns;
end process P2;
end architecture test_null;

When the signal assignment statements A1 and A2 are executed:

  • two transactions are placed in driver of the signal H in process P1 ('1' after 10 ns), (null after 20 ns) and
  • two transactions are placed in driver of the signal H in process P2 ('1' after 5 ns), ('0' after 10 ns)..

This means that the value of the signal H at 5 ns is determined by the resolution function with the value from process P2 equal to '1' and the value from process P1 equal to '0'. After 10 ns the resolution function will be called with '1' from process P1 and '0' from process P2. After 20 ns the resolution function will be called with a vector containing only one element ('0', contributed by process P2) as the driver from the process P1 is disconnected.

Important Notes

  • The delay values supported with the after clause do not cumulate, but all relate to the same simulation time (compare Example 1).

Wednesday, 12 December 2012

SystemVerilog Virtual Interfaces

This is most common SystemVerilog interview question that is asked while you will appearing for the position of Verification Engineer.

As you know an interface encapsulate a group of inter-related wires, along with their directions (via mod-ports) , synchronization details (via clocking block) , functions and tasks.

The major usage of interface is to simplify the connection between modules.
But Interface can’t be instantiated inside program block, class (or similar non-module entity in System Verilog).

But we needed to be driven from verification environment like class.

To solve this issue virtual interface concept was introduced in System Verilog. A virtual interface is just a pointer to a physical interface. i.e. Virtual interface is a data type (that implies it can be instantiated in a class) which hold reference to an interface (that implies the class can drive the interface using the virtual interface).

Virtual interfaces provide a mechanism for separating abstract models and test programs from the actual signals that make up the design. A virtual interface allows the same subprogram to operate on different portions of a design and to dynamically control the set of signals associated with the subprogram. Instead of referring to the actual set of signals directly, users are able to manipulate a set of virtual signals. 

interface sample_if() ;  // SystemVerilog Interface
  logic a ;
  logic b ;
  modport TB(input a, output b) ; // Modport declaration 
endinterface

class Driver ;
  virtual sample_if inf ;           // Virtual Interface declaration in class
  function new (sample_if inf)
    this.inf = inf ;
  endfunction
  task main () ;
  inf.a =a ;
endtask
endclass

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!