https://miyo.github.io/learning_fpga/docs/book01/languages/
两种基本处理方法——并发处理语句和顺序处理语句
重复一下,在硬件编程中,需要处理独立运行的模块。也就是说,用于描述硬件的语言需要能够描述独立运行的同时并行处理。然而,根据想要实现的处理,有时需要描述条件分支等具有依赖关系的处理。为了满足这些要求,VHDL 和 Verilog HDL 都支持两种称为同时处理语句和顺序处理语句的描述方式。具体的描述方法将在后面说明,但请先记住这两种方式的思路。
并行语句
同时处理语句是指不受周围处理影响而独立运行的处理。多个同时处理语句会在某个特定的时间点同时处理。因此,描述顺序或各处理语句之间不存在语法顺序,而是根据“某个时间点”输入的值生成输出。输出确定之前的时间取决于物理上在设备中电流流动的速度或信号延迟。
顺序处理语句
顺序处理语句是指根据语法等规定多个处理之间顺序的处理。例如,软件中必不可少的分支等控制语句的表达需要顺序
在VHDL 和 Verilog HDL 中可以使用加减算、逻辑运算、比较等运算符。在软件编程中,使用运算符编写的处理会被转换为给处理器的指令,但在 HDL 中,这些运算会被合成成相应的硬件逻辑,如 LUT 或 FF 的组合。
在 FPGA 中,有些包含小型数字信号处理器或乘法器,如果条件合适,可以使用它们与软件编程类似,HDL中也可以使用赋值运算将运算结果赋值给其他(或相同)变量。
HDL 的赋值有阻塞赋值和非阻塞赋值两种类型。阻塞赋值是立即在该点赋值并继续的赋值。另一方面,非阻塞赋规定了多个赋值语句中的同时执行。C 语言等单线程软件编程中的赋值相当于 HDL 中的阻塞赋值。
语法注意点
变量可以具有字母数字名称:它们必须以字母或 “_” 开头,并且不能以 “_” 结尾。 Verilog HDL 区分大小写。
值的基本类型 — '0','1','Z','X'
常常使用的数值 包括 0 1 z / Z(高阻关断) x X(0/1)
硬件的值取 '0' 和 '1' 的值。此外,硬件还存在高阻态,表示“电阻无限大”的状态,在 VHDL 或 Verilog HDL 中用 'Z' 表示。值“电阻无限大”可能有些难以理解。物理上,可以想象开关断开状态。当多个信号合并到一个时,'Z' 表示“不影响其他值”。
在 HDL 中可以使用高阻抗来表示开关关闭
另外,'0' 或 '1' 都可以作为不定值的概念存在,这用 'X' 表示。
; 非常重要
模块构成
VHDL 编写的模块的概要。在 VHDL 中,将目标模块大致分为 entity 和 architecture 来编写。 entity 定义了连接到外部的输入输出端口等电路的外部框架, architecture 定义了使用的函数定义和处理内容等电路的内部
library and package
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_1164.ALL;
entity
entity 定义电路的轮廓,例如连接到外部的 input/output 端口的声明
architecture
architecture 定义电路的内部,例如要使用的函数的定义和处理内容
VHDL 中可以描述的常数的例子
VHDL 中的变量都有类型
定义了很多种类型,也可以定义自己的类型。常用的五种类型。
std_logic 、 std_logic_vector 对应硬件信号类型,
signed 和 unsigned 用于表示可以进行加减运算的值,
integer 可以表示一般数值
1-bitの信号
std_logic 是 VHDL 的基本 1 Bit 信号类型。 '0' , '1' ,以及高阻态的 'Z' ,不定值的 'X' 都可以作为其值。这些值直接对应硬件。
n 位信号
std_logic_vector(n downto 0) 是 std_logic 个 std_logi_vector 并排组成的 n 位信号线类型,称为 n 位 std_logi_vector 类型。
std_logic_vector 类型的变量 a 中的元素可以取出 a(3) , a(4 downto 2) 等。前者是 std_logic 类型,后者是 3 位的 std_logic_vector 类型。
downto 表示 std_logic 的序列,从 MSB 降序编号。也就是说,对于 std_logic_vector(n-1 downto 0) 的位序列,MSB 是 std_logic_vector(n-1) ,LSB 是 std_logic_vector(0) 。
也可以使用 to 逆序排列,这时可以像 std_logic_vector(n to 0) 这样表示。
模块的外部描述 — entity
entity 代表模块的外框,通过模块名称和输入输出信号来定义。例如,以下描述相当于定义了一个名为 test ,输入信号为 pClk 和 pReset,输出信号为 Q 的模块的外框。
entity test is
port (
pClk : in std_logic;
Q : out std_logic;
pReset : in std_logic -- 在最后一个之后不加
);
end entity;
定义端口
端口是硬件模块的输入输出。在 entity 的 port(~); 中,通过指定信号的方向和类型来定义。
信号方向有 in (输入)、 out (输出)和 inout (输入输出)三种。
每个端口通过“名称 : 方向 类型”来定义。例如
pClk : in std_logic
-- or together definate
pR, pG, pB : in std_logic
这样的描述相当于定义了 pClk 的 std_logic 输入端口( in )。相同方向和类型的多个端口名也可以用“,”来并列定义。例如,
可以将 3 个输入信号 pR , pG , pB 一起定义。
定义常量
可以在 entity 中定义模块内使用的常量
entity test is
generic (
width : integer := 640;
height : integer := 480
);
port (
pClk : in std_logic;
Q : out std_logic;
pReset : in std_logic
);
end test;
这个以 width 的名称定义了一个值为 640 的 integer 类型,即整数的常量。这个常量可以在 entity 内部,以及内部处理描述的 architecture 中使用
内部处理描述 — architecture
在 VHDL 中, architecture 用于描述模块的处理内容。描述的基本流程如下:
architecture RTL of test is
(在这里写变量的定义等。)
begin
(在这里描述处理内容。)
end RTL;
上述是用于描述名为 test 的模块内容的块。
变量的定义
变量的定义
signal 名前 : 型 := 初期値;
-- second
signal counter : std_logic_vector(9 downto 0); -- 10 bit
--third
signal counter : std_logic_vector(width-1 downto 0); --width
例如,10 位的数组可以这样定义。
此外,可以使用 generic 定义的值 width 来定义宽度为 width 的 std_logic_vector 型的信号。这里 width−1 的值在综合时确定.
运算符和运算
将典型的运算符汇总在表 3 中。如果将逻辑运算符定义为 std_logic_vector 类型,则会对对应的每个比特的值之间应用逻辑运算并返回结果。例如,“ "10" and "11" ”会变成“ "10" ”,“ "10" or "11" ”会变成“ "11" ”。比较运算的结果是 true 或 false 的真值。可以看出它具备了许多常见的编程语言所拥有的运算功能。但是,表 3 的说明中标注了(*1)的算术运算或比较数值大小的运算,只能用于 unsigned 类型、 signed 类型或 integer 的变量或常量,或者相当于数值的立即数
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
• 对于std_logic_vector类型,如果要进行算术运算,通常需要先转换为signed或unsigned类型,再进行运算,运算完后再转换为std_logic_vector类型。
signal B : std_logic_vector(15 downto 0);
-- 取 B 的高 8 位
signal high_byte : std_logic_vector(7 downto 0);
high_byte <= B(15 downto 8);
逻辑移位 :左移逻辑 (sll):将位向量左移指定的位数,右侧补 0。右移逻辑 (srl):将位向量右移指定的位数,左侧补 0。 算术移位 :左移算术 (sla):与sll类似,但通常用于有符号数时。右移算术 (sra):将位向量右移时保留符号位(最左边的比特)。 旋转(循环移位)操作 :左旋 (rol):将最高有效位送到最低有效位,实现循环左移。右旋 (ror):实现循环右移。
计算结果的代入
计算结果可以通过赋值语句赋值给其他(或相同)变量。赋值有阻塞赋值和非阻塞赋值两种。
:= 阻塞赋值
<= 非阻塞赋值
Q <= counter(width-1);
这种描述相当于取出 std_logic_vector 型变量 counter 的 (width-1) 个,并赋值给 Q 的硬件描述。在 VHDL 中, signal 变量在初始化之外不能使用阻塞赋值
类型转换
a <= "00000000" & b; -- 正在用8位的0(即=00000000)填充不足的8位
b <= a(7 downto 0); -- 只将a的下位8位赋值给b。
类型转换需要使用专用函数。例如,将 std_logic_vector 转换为 unsigned 类型或 signed 类型时,分别使用 unsigned 函数或 signed 函数。
unsigned(c);
如果这样写, std_logic_vector 类型的变量 c 可以转换为 unsigned 类型。
反之,将 unsigned 类型或 singed 类型的变量转换为 std_logic_vector 类型时,使用 std_logic_vector 函数
std_logic_vector(d);
如果这样写, unsigned 类型的变量 d 可以转换为 std_logic_vector 类型。