![]() Creating a simple FPGA project |
![]() FPGA design tutorial contents |
![]() Advanced HDL synthesis |
Hardware description languages
FPGA design services
1-CORE Technologies provides FPGA design services of high quality since 2004. Outsourcing FPGA design to Russia will significantly reduce your design costs.
The basic level for FPGA design entry is Register Transfer Level which represents a digital circuit as a set of connected primitives (adders, counter, multiplexers, registers etc.). There are two basic ways to create an RTL design: schematic entry and HDL entry. Schematic entry is somewhat close to netlist: it is not very convenient to use it for large projects. HDL entry is more convenient, but needs an additional program (synthesizer) in order to translate HDL description to netlist.
Hardware description languages were designed merely to provide means of digital circuits simulation. Synthesizers were created much later. Therefore, each major HDL language has two subsets of language constructs: synthesizable (suitable for synthesis) and non-synthesizable (suitable only for simulation).
The two major HDL languages are VHDL and Verilog. Both of these languages are widespread. VHDL is more Pascal-like (or, to be more precise, Ada-like) and Verilog is more similar to C. VHDL is a strong-typed language, and Verilog is more weak-typed.
The syntax constructs of HDL languages are similar to those of conventional programming languages. However, the semantics is quite different.
Note that in VHDL identifiers are case-insensitive, and in Verilog they are case-sensitive.
Basic language constructs
Ports declaration
At the beginning of the HDL module input and output ports are declared. For instance, consider a 8-bit counter used as an example in the previous article. VHDL description of this counter starts with the entity declaration:
entity counter is Port ( CLK : in STD_LOGIC; CLR : in STD_LOGIC; DOUT : out STD_LOGIC_VECTOR (7 downto 0)); end counter;
STD_LOGIC and STD_LOGIC_VECTOR are basic data types used in VHDL, defined in IEEE standard 1164. STD_LOGIC can represent the following values: 1, 0, U (undefined), X (unknown), Z (high impedance), W (weak), H (weak 1), L (weak 0), - (don't care). STD_LOGIC_VECTOR is an array of STD_LOGIC.
The similar description in Verilog will look like:
module counter(clk, clr, dout); input clk; input clr; output [7:0] dout;
Signals declaration
Signal is a basic element in HDL languages, similar to a variable in programming languages (actually, VHDL supports not only signals, but also the so-called "variables", but the latter are rarely used for purposes other than simulation). Signals must be declared explicitly.
Example of a signal declaration in VHDL:
signal value: std_logic_vector(7 downto 0);
In VHDL signals are declared in the architecture block before the begin keyword.
Unlike VHDL, Verilog uses two types of signals: signals of the first type ("wire") can be outputs of concurrent statements, while signals of the second one ("reg") can be outputs of sequential statements (i.e. registers). Example of a signal declaration in Verilog:
wire [7:0] combinational_value; reg [7:0] register_value;
Concurrent assignments
Concurrent assignment is used to make a signal equal to some expression. Concurrent assignment works always, i.e. it is not an one-time operation, but a permanent binding. Example of concurrent assignment in VHDL:
c <= a and b;
The same statement in Verilog:
assign c = a & b;
Concurrent assignments can be conditional. For example, in the following VHDL code c is assigned a value of a if sw is '1', and a value of b otherwise:
c <= a when sw='1' else b;
The same operation in Verilog:
assign c = sw ? a : b;
Processes
A process in VHDL or Verilog is a mean to take complex actions when some signals change. Flip-flops and latches are typically described as processes. But a process can define something more complex than a simple flip-flop or latch.
Let's consider a counter from our previous example:
process (CLK,CLR) is begin if CLR='1' then val<="00000000"; elsif rising_edge(CLK) then val<=val+1; end if; end process;
The signals in brackets after process keyword make up a sensitivity list. A process can be thought as executing each time when one of the signals in the sensitivity list. This affects only behavioral simulation: synthesizers ignore sensitivity lists.
The same process in Verilog:
always @ (posedge CLK or posedge CLR) begin if (CLR) val<=0; else val<=val+1; end
It should be noted that signals are not changed during the process execution, but only after a process has finished. For instance, the following code:
process (CLK) is begin if rising_edge(CLK) then val<=val+1; val2<=val; end if; end process;
will leave val2=val (and not val+1) after execution.
Structural description
The above examples constitute the so-called behavioral description. There is also structural description, when one module is described as a set of other modules connected to each other.
The modules are instantiated in the top-level module using special language constructs. For example, to instantiate the above counter, one should write something like
counter_inst: component counter port map( CLK => CLK, CLR => CLR, DOUT => counter_value );
Here counter is a name of the component and counter_inst is the name of the instance. One component can be instantiated many times with different instance names.
The names before arrows are formal parameters (names of the ports that should be the same as in entity declaration). The names after arrows are actual parameters (that is, signals in this module).
In order to be able to instantiate component in a top-level VHDL module, that components must be first declared. The declaration of component if similar to the declaration of entity:
component counter is Port ( CLK : in STD_LOGIC; CLR : in STD_LOGIC; DOUT : out STD_LOGIC_VECTOR (7 downto 0)); end component counter;
The component declaration should be located in the architecture block before the begin keyword.
In Verilog there is no need in component declaration, and component instantiation is done as follows:
counter counter_inst(.CLK(CLK),.CLR(CLR),.counter_value(DOUT));
Common mistakes
There are a few common mistakes that are often made by beginner FPGA designers.
HDL language is not a programming language
Although VHDL and Verilog are similar to conventional programming languages, they shouldn't be treated as such. An FPGA designer should write an HDL description keeping in mind the hardware implementation. For example, the following code:
process (CLK) is begin if rising_edge(CLK) or falling_edge(CLK) then val2 <= val; end if; end process;
although feasible, will be incorrect for most FPGA that don't have dual-edged flip-flops. This code can simulate properly, but won't be synthesized.
One signal can have only one driver
It is allowed to assign value to a signal only in one process, or in one concurrent assignment statement (the process or concurrent assignment where the signal is assigned a value is called a driver for that signal). If a signal has multiple drivers, the code won't simulate or synthesize properly.
There is an exception, though, if you use any states other than '0' or '1'. For example, if a signal has two drivers, one of them assigns '1' and the other assigns 'Z' (high-impedance state or simply the third state), the signal will be assigned '1'.




English
Russian