VHDL简介

What can VHDL do?

VHDL can be used to model digital circuits and system.

Some type of circuit model allows simulation and/or testing of the circuit.

比起Graphical Approach来说,在面对有更多门电路时很方便

Synthesiser

image-20220922134232414

  1. VHDL is a hardware-design language.

When you are working with VHDL, you are not programming, you are “designing hardware”.

  1. Have a general concept of what your hardware should look like

If you don’t understand basic digital constructs (e.g. logic gates), you’ll probably fail to generate efficient digital circuits.

“Black-Box” Design Approach

A VHDL module is considered as a black-box which has an entity and an architecture.

entity: the black-box itself input and output specification

entity给出ports的定义

architecture: the stuff that goes inside

architecture描述电路实现的功能

image-20220922135134706

About VHDL

•VHDL is a specific language for describing hardware – digital circuits & systems.

• V = Very High-Speed Integrated Circuit (VHSIC)

HDL = Hardware Descriptive Language

Unlike other high computer languages, VHDL is NOT sequential in nature.

i.e. A; B; may have the meaning as B; A;

VHDL is a concurrent language(并发的 Concurrent)

VHDL instructions/statements are all executed at the same time.

VHDL describes hardware so actions are executed in a concurrent manner, i.e. in parallel

it has the ability to execute a virtually unlimited number of statements at the same time in a concurrent manner.

Basic Rules about VHDL

  1. VHDL is not case senitive.

    You can choose the case of your keywords and identifiers for readability.

    Dout <= A and B; is the same as doUt <= a AnD b;

  2. VHDL is not senitive to white space.

    You should use spaces and tabs to well indent your VHDL

    code.

    nQ <= In_a or In_b; is the same as
    
    nQ     <= in_a OR  in_b; 
  3. Comments

    VHDL comments begins with the symbol (–).

    there is no block-style comments in VHDL

  4. Parentheses(括号)

    if x = '0' and y = '0' or z = '1' then ...
    if ( ((x = '0') and (y = '0')) or (z = '1') ) then
  5. Every VHDL statement is terminated with a semicolon (;)

port (A, B: in std_logic; C: out std_logic);

is actually considered a statement instead of a block

Identifiers

An identifier refers to the name given to items in VHDL

Examples of identifiers in VHDL include signal names, port names, variable names

• Identifiers should be self-describing.

• Identifiers can be as long as you want, it’s up to you.

• Identifiers can only contain a combination of letters (A-Z, a-z), digits (0-9) and the underscore (_).

• It must start with an alphabetic character

• It must not end with an underscore (e.g. xxyy_)

• It must not have two consecutive underscores (e.g. xx__yy)

Reserved Words

You cannot use them as identifiers.

image-20220927143528827

Logic Operator

image-20220927143555071

Relational Operators

image-20220927153819989

begin
F3 <= '1' when (L = '0' and M = '0' and N = '1') else
'1' when (L = '1' and M = '1') else
'0';
end f3_3;

Entity Declaration

• VHDL entity construct provides a method to abstract the functionality of a circuit description to a high level

The main usage of entity:

Interface - the list of signals from the underlying circuit(inputs and outputs )

wrapper: how the black box interfaces with the outside world (other black-boxes)

image-20220922135549657

“–”表示注释

image-20220922140058686

-- interface description of killer_ckt
entity killer_ckt is
port( life_in1: in std_logic;
life_in2: in std_logic;
ctrl_a, ctrl_b: in std_logic;
kill_a: out std_logic;
kill_b, kill_c: out std_logic);
end killer_ckt;

You can have several port names on the same line, separated by commas.(,隔开)

generic 语句

GENERIC(常数名 数据类型 := 设定值);

  1. 定义实体的端口大小;

  2. 设计实体的物理特征;

    在例化时应该加generic map来修改不同需求下的元件例化参数

port语句:

image-20220922140235792

  • 端口模式:

image-20220922140319557

  • 数据类型:

image-20220922140434437

image-20220922140449927

BOOLEAN: 真假

INTEGER:32位整数

CHARACTER : 字符型

Architecture

The architecture describes what the circuit actually does.

there can be any number of equivalent architectures for the same single entity

同一entry可能有多种architecture

一个vhdl文件中可以存在多个architecture

connect Operator

可以将若干个标准逻辑类型或者逻辑向量首尾相接,描述成为一个新的逻辑向量。它的语法如下:
<signal 1> & <signal 2> &

该运算符尤其是在描述串行移位寄存器的时候最为方便,例如: d <= d(2 downto 0) & a;

Signal Assignment Operator

<= 表示 assignment

G <= A and B; --indicates the value of signal G represents an AND logic operation between A and B.
<target> <= <expression>;

Conditional Signal Assignment

WHEN/ELSE语句:

<target> <= <expression> when <condition> else
            <expression> when <condition> else
            <expression>;

each of the expressions associates with a condition

the conditions are evaluated until the first one is true, then the expression is assigned to the target

Only one assignment is applied per assignment statement.

image-20220927153311551

With-select statement:

with <control> select
  <target> <= <expression> when <value>,
              <expression> when <value>,
              <value>;

image-20220928105712914

Intermediate Signals

• The declaration is similar that in entity, except that the mode specification (in/out) is not needed.

在architecture里声明中间信号而不是在entity

There is little (hardware) cost to pay when you use more Intermediate signals.

it is like an internal wire of the circuit, and it helps you to connect different parts of your circuit together.

Never judge the quality of a VHDL code by its length

exercise

  1. 与非门

image-20220927151933439

library IEEE;
use IEEE.std_logic_1164.all;
-- three-input NAND gate named my_nand3
entity my_nand3 is
port( A, B, C: in std_logic;
F : out std_logic);
end my_nand3;
-- behavioural architecture with logic operators
architecture my_nand3_arch of my_nand3 is
signal D: std_logic;
begin
D <= A and B and C; 
F <= not D;
end my_nand3_arch;
  • you must include libraries

  • operators: and, or, nand, nor, xor, xnor(binary) and not (unary)

Implement Boolean Equations using VHDL

Two ways:

(i) express the equation directly in a concurrent statement

(ii) sub-divide the equation into several parts and link them together using intermediate signals

F3 = L’M’N + LM

method (i):

architecture f3_2 of my_ckt_f3 is
begin
F3 <= ((not L) and (not M) and N) or (L and M);
end f3_2;

method (ii):

architecture f3_2 of my_ckt_f3 is
signal A1, A2: std_logic; -- intermediate signals
begin
A1 <= (not L) and (not M) and N;
A2 <= L and M;
F3 <= A1 or A2;
end f3_2;

Bus Signals

In VHDL, a bus signal can be specified by the vector data type,

image-20220927154159950

std_logic_vector

When you declare a bus, you need to decide on the direction, whether the most significant bit (MSB)最高位 is on the left or on the right (assuming left-to-right writing).

  • On the left: downto; on the right: to

    四选一数据选择器

-- a MUX that selects one of four bus lines for the output
entity mux4 is
port( a_data: in std_logic_vector(7 downto 0);
      b_data: in std_logic_vector(7 downto 0);
      c_data: in std_logic_vector(7 downto 0);
      d_data: in std_logic_vector(7 downto 0);
      sel1, sel0: in std_logic;
      data_out: out std_logic_vector(7 downto 0));
end mux4;

image-20220927155023093

IEEE Standard Libraries

The data type std_logic and std_logic_vector is standardised by IEEE for the representation of digital signals.

In its generous definition, it is a nine-valued logic containing:

0, 1, U, X, Z, W, L, H, -.

导入1164库

library IEEE;
use IEEE.std_logic_1164.all;
...

VHDL Module

vhdl代码框架:

library IEEE;
use IEEE.std_logic_1164.all;
---- Descriptions about ----
---- your VHDL code ----
library IEEE;
use IEEE.std_logic_1164.all;
-- ENTITY --
entity module_name is
port( in1: in std_logic;
...
out1: out std_logic;
...); -- this is tricky
end module_name;
-- ARCHITECTURE --
architecture module_arch of module_name is
... -- DECLARATIONS
begin
... -- STATEMENTS
end module_arch;

the order that these statements appear in your VHDL source code makes no difference.

  • exercise:

image-20220927161924224

use IEEE.std_logic_1164.all;
entity my_circuit is
port( A_1, A_2, B_1, B_2, D_1: in std_logic;
E_out : out std_logic);
end my_circuit; 
architecture my_circuit_arch of my_circuit is
signal A_out, B_out, C_out: std_logic;
begin
A_out <= A_1 and A_2;
B_out <= B_1 or B_2;
C_out <= (not D_1) and B_2;
E_out <= A_out or B_out or C_out;
end my_circuit_arch;

Modular Designs in VHDL

• Structural modeling allows modular designs.

• It also supports hierarchical design which is essential in complex digital systems.

packing low-level functionality into modules把低级的代码打包成模块,方便调用(easily reused in other designs as black boxes)-层次化

To further enhance module reuse, the VHDL modules can be placed in named files and libraries

元件例化,简单来说就是将以前设计的实体当做本设计的一个元件,然后利用VHDL语句将各元件之间的连接关系描述出来。元件例化语句由两部分组成,一部分是元件定义,即将现成的设计实体定义为本设计的元件。第2部分是元件连接关系映射,即描述各个元件之间的连接关系。

  • declaration and instantiation of components:
  1. Name the module you plan to describe (entity)

  2. Describe what the module do (architecture)

  3. Let the program know the module exists (declaration)

  4. Use the module in your code (component instantiation or mapping)

以三位比较器为例

image-20220927203426161

Step 1: Generate top-level entity declaration

entity my_compare is
port (A_IN : in std_logic_vector(2 downto 0);
B_IN : in std_logic_vector(2 downto 0);
EQ_OUT : out std_logic);
end my_compare;

Step 2: Declare the lower-level design units used

replace entity with component.

Place the component declarations before begin in the architecture.

放在architecture之前

image-20220927203527650

Step 3: Declare internal signals

architecture structural of my_compare is
-- component declarations
component big_xnor is
port (A, B: in std_logic;
F : out std_logic);
end component;
component big_and3 is
port (A, B, C: in std_logic;
F : out std_logic);
end component;
-- internal signal declarations
signal p1_out, p2_out, p3_out: std_logic;
begin
... 
end structural;

Step 4: Create instances of components and map

begin
    x1: big_xnor port map(A => A_IN(2), B => B_IN(2), F => p1_out); 
    x2: big_xnor port map(A => A_IN(1), B => B_IN(1), F => p2_out); 
    x3: big_xnor port map(A => A_IN(0), B => B_IN(0), F => p3_out); 
    a1: big_and3 port map(A => p1_out, B => p2_out, 
    C => p3_out, F => EQ_OUT); 
end structural;

Mapping: make connections from higher-level signals onto the interface of the lower-level blocks. 将元件预定义的端口与实例化时的实际端口联系起来

Each of the individual mappings include a unique name of the particular instance plus the original entity.

--元件定义部分
COMPONENT 元件名 IS
	[GENERIC(类属表)];
	PORT(端口列表);
END COMPONENT 元件名;
--元件映射部分
例化名1:元件名1 PORT MAP(元件端口名=>连接端口名,...);
......
例化名n:元件名n PORT MAP(元件端口名=>连接端口名,...);

Labels should be always be added to increase the understandability of your VHDL model.

名称映射和位置映射

image-20220927205556802

GENERATE

是一种可以建立重复结构或者是在多个模块的表示形式之间进行选择的语句。由于生成语句可以用来产生多个相同的结构,因此使用生成语句就可以避免多段相同结构的VHDL程序的重复书写。

标号:FOR 变量 IN 不连续区间 GENERATE
<并发处理的生成语句>
END GENERATE [标号名]
-- generation statement
generate_label:
for identifier in discrete_range generate
    concurrent statements;
end generate generate_label;

有两种用途:

  • 生成相同的元件,多次例化
MUX2_GEN: for i in 3 downto 0 generate
      L1: mux2 port map (D0(i), D1(i), shift_n(0), X0(i));
      L2: mux2 port map (X0(i), X1(i), shift_n(1), Y(i));
end generate MUX2_GEN;

同时例化四个MUX

  • 生成结构相同的多次赋值、组合逻辑;
FOR i IN 0 TO 99 GENERATE

a(i)<=b(i)+c(i);

END GENERATE;

Standard Models in VHDL

There are different standard models/approaches in writing VHDL architectures.

image-20221014090238628

More complicated VHDL circuits usually use a mixture of the three styles.

Data-Flow Style Architecture

Data-flow style: circuits are described by showing input and output relationships between the various built-in components.

image-20221014090908715

Behavioural Style Architecture

行为建模

it is fairly straight forward to imagine the underlying circuitry in dataflow style

image-20221014091039835

provides no/fewer details as to how the design is implemented in actual hardware.

• models how the circuit outputs react to the circuit inputs.

只处理电路对输出的反应,而不用研究具体的电路细节

• allows you to leave the implementation details to the synthesizer

image-20221014092739262

sequential circuit 只能用 behavioural modeling

combination circuit 可以用 behavioural modeling和 flow data behavioural

Process Statement

A process statement is a concurrent statement identified by its label, its sensitivity list, a declaration area and the set of instructions

-- this is my first process
my_label: process(sensitivity_list) [is][] - optional
    <item declaration>
begin
    <sequential_statements>
end process my_label;

Major difference: the statements inside a process are executed and interpreted sequentially

entity my_xor is
port ( A, B : in std_logic;
       F : out std_logic);
end my_xor;
architecture dataflow of my_xor is
begin
    F <= A xor B;
end dataflow;
architecture behav of my_xor is
begin
    xor_proc: process (A, B)
    begin
        F <= A xor B
    end process xor_proc;
end behav;

这两种代码形式是等价的

A B是敏感信号,所以一旦有一个改变 process就会执行。

For the behavioral architecture description, any time there is a change in signals in the process sensitivity list, all of the sequential statements in the process are re-evaluated until the end of the process body.

But the whole process itself is a concurrent statement

process 之间是并发关系

写VHDL时可以将预期功能分成不同进程来写,避免一个大进程

image-20221014211355151

IF statement

The if statement creates a branch in the execution flow of the sequential statements.

if (condition) then
    <statements>
elsif (condition) then
       <statements>
else
       <statements>
end if;

The parentheses around the condition are optional .Use them for improving readability

The final else clause, which serves as a catch-all statement, is optional, but should always be included.

example

image-20221014214510752

architecture silly_example of my_ex is
begin
    proc1: process (A, B, C)
    begin
        if (A = '1' and B = '0' and C = '0') then
            F_OUT <= '1';
        elsif (B = '1' and C = '1') then
               F_OUT <= '1';
        else
               F_OUT <= '0';
        end if;
      end process proc1;
end silly_example;

A process label is a form of self-description, which should be meaningful and easy-to-understand.

image-20221014213759573

image-20221014213813100

8-to-1 MUX Example
entity mux_8t1 is
port ( DIN: in std_logic_vector(7 downto 0);
       SEL: in std_logic_vector(2 downto 0);
       F : out std_logic);
end mux_8t1;
architecture mux_8t1_arch of mux_8t1 is
begin
    my_mux: process (DIN, SEL)
    begin
        if (SEL = "111") then F <= DIN(7);
        elsif (SEL = "110") then F <= DIN(6);
        ...
        elsif (SEL = "000") then F <= DIN(0);
        else F <= '0';
        end if;
    end process my_mux;
end mux_8t1_arch;

Case Statement

case (expression) is
    when choices =>
         <statements>
    when choices =>
         <statements>
    when others =>
         <statements>
end case;

Only one set of sequential statements is executed, depending with when branch is evaluated as true.

example

image-20221014214537230

architecture case_ex of my_ex is
    signal INPUT: std_logic_vector(2 downto 0);
begin
    INPUT <= A & B & C;
    proc1: process (INPUT)
    begin
        case (INPUT) is
        when "100" => F_OUT <= '1';
        when "011" => F_OUT <= '1';
        when "111" => F_OUT <= '1';
        when others => F_OUT <= '0';
        end case;
    end process proc1;
end case_ex;

Simulation & Test Benches

After we model a circuit, we have to verify the correctness of the model in terms of functionality and timing

Simulation tools often require a test bench file to specify how the testing is done on the Unit Under Test (UUT)被测单元.

A VHDL test bench is virtual circuit/system that creates an instance of the

top module (UUT) and generates stimuli to inputs of the instance.

Corresponding simulation outputs are recorded and visualised to assist verification.

The test bench itself is not involved in implementation (not synthesisable)

image-20221014220237440

Example

If we are to test the XNOR gate, then we can prepare a test bench like this:

A test bench is a closed system: no inputs/outputs.

Declare the UUT component and internal signals

entity big_xnor_tb is
end big_xnor_tb;
architecture behavior of big_xnor_tb is
    component big_xnor is
    port (A, B: in std_logic;
          F : out std_logic);
    end component;
    signal A, B, F: std_logic;
begin
    uut: big_xnor port map (A=>A, B=>B, F=>F);
    stim_proc: process
    begin
        A <= '0'; B <= '0'; wait for 10 ns;
        A <= '0'; B <= '1'; wait for 10 ns;
        A <= '1'; B <= '0'; wait for 10 ns;
        A <= '1'; B <= '1'; wait for 10 ns;
        wait; -- finished.
    end process;
end behavior;
Clock Signal
entity DFF_tb is
end DFF_tb;
architecture behavior of DFF_tb is
    component DFF is
    port (D, CLK: in std_logic;
          Q : out std_logic);
    end component;
    signal D, CLK, Q: std_logic := '0';
    constant period: TIME := 10 ns;--时间常数
begin
    uut: DFF port map (D=>D, CLK=>CLK, Q=>Q);
    stim_clk: process
    begin
        CLK <= '1'; wait for (period / 2);
        CLK <= '0'; wait for (period / 2);
    end process;
    stim_proc: process
    begin -- add your stimuli
    end process;
end behavior;

initial values given using operator :=

信号初始值要用:=

type 类型

TYPE 数据类型名 IS {枚举1,枚举2,…}

type state_type is **(ST0,**ST1);