VHDL Notes
Author: Sijin Yu
文章目录
- VHDL Notes
1. Structure of VHDL code
VHDL 代码主要由四部分组成:
- Lib. declaration. 库的调用.
- Package calling. 程序包的调用.
- Entity description. 实体的描述.
- Architecture description. 结构体的描述.
- Configuration. (Optional)
1.1 Lib. Declaration
VHDL 库:
- STD (Default)
- WORK (Default)
- IEEE
- ASIC Lib. (Payments)
- self-designed lib.
其中 STD 和 WORK 默认调用, IEEE 应当使用以下语句调用.
Library IEEE;
调用库的标准语法为:
-- 调用库
Library <库名>;
1.2 Package Calling
调用程序包的标准语法为:
-- 调用包
Use <库名>.<包名>.<包内容>;
例如:
Library IEEE;
Use IEEE.std_logic_1164.ALL;
Use IEEE.std_logic_arith.ALL;
IEEE 的四个程序包:
std_logic_1164
: 包含标准逻辑电平所需的数据类型和函数. 包括std_logic
和std_logic_vector
两种数据类型. (只允许逻辑运算)std_logic_arith
: 扩展了三个数据类型:unsigned
,signed
,small_int
, 并定义了算数运算符和转换函数. (只允许算数运算)std_logic_signed
: 定义了有符号算数运算函数.std_logic_unsigned
: 重载了可用于integer
和std_logic
,std_logic_vector
的混合运算运算符, 并定义了不同数据类型的转换函数.
1.3 Entity Description
Entity (实体) 的描述格式如下:
-- 实体描述
Entity <实体名> is
[类属参数说明];
<端口说明>;
End [Entity][实体名];
注意:
-
实体名不能以数字开头, 不能与保留字相同.
-
实体结束可以选择两种格式:
End Entity
或End <实体名>
. -
类属参数说明是 Optional 的, 常用于说明器件延时和总线宽度等, 格式如下:
-- 类属参数说明 Generic(<常数名>: <数据类型>:= <设定值>);
例如:
Generic(m: time:= 1ns);
-
端口参数说明是必须的, 格式如下:
-- 端口说明 Port(<端口名>: <端口方向> <数据类型>; ......);
其中, 端口方向有四种:
IN
: 输入, 信号进入实体.OUT
: 输出, 信号离开实体, 且不会在内部反馈作用.INOUT
: 双向输入输出, 信号可进入或离开实体.BUFFER
: 输出缓冲, 信号离开实体, 但在内部有反馈作用.
例如, 一个 3-8 译码器的端口说明如下:
Port(g1, g2a, g2b: IN std_logic; x: IN std_logic_vector(2 DOWNTO 0); y: OUT std_logic_vector(7 DOWNTO 0));
1.4 Architecture Description
Architecture (结构体) 描述实体行为, 或指明实体的所用元件及其连接关系, 描述格式如下:
-- 结构体描述
Architecture <结构体名> of <实体名> is
[定义语句];
BEGIN
[并行处理语句];
END <结构体名>;
注意:
- 定义语句可以定义: 信号, 常数, 数据类型, 函数, 元件等, 这些定义仅对本结构体有效.
- 并行处理语句用于描述结构体的行为, 是并行执行的.
- 可以在并行处理语句中加入进程 (Process) 里, 语句在进程里是串行的, 但是在结构体里, 进程依然与其它语句并行.
2. Basic Law & VHDL Data
2.1 Basic Law of VHDL
- VHDL 大小写不敏感.
- VHDL 是硬件描述语言, 并行执行.
- VHDL 的行内注释以
--
为开头.
2.2 Constant
Constant (常量) 是在设计描述中不变化的值. 其格式如下:
-- 常数定义
CONSTANT <常数名>: <数据类型>:= <表达式>;
例如:
CONSTANT VCC: real := 5.0;
CONSTANT fbus: std_logic_vector(3 DOWNTO 0):= "0101";
2.3 Variable
Variable (变量) 是进程或子程序中的变化量, 是用于计算或暂存中间值的局部量. 其格式如下:
-- 变量定义
VARIABLE <变量名>: <数据类型>:= <表达式>;
注意: 变量的赋值是立刻发生的 (发生在这一条语句被执行的瞬间).
2.4 Signal
Signal (信号) 对应着硬件内部的连线, 或作为一种数据容器, 以保留历史值或当前值. 其格式如下:
-- 信号定义
SIGNAL <信号名>: <数据类型>:= <表达式>; -- 用于赋初始值, 只能仿真, 不能综合
<信号名> <= <表达式>; -- 用于给信号赋值, 可以仿真, 可以综合
注意:
- 信号的赋值有延迟, 不是立刻发生, 在事件发生时, 或进程结束时 (进程的结束也是一种事件), 信号才被赋值.
- 信号的赋值采用符号
<=
, 变量的赋值采用符号:=
. - 信号可以是全局量, 变量只能是局部量.
2.5 Other VHDL Data Tpyes
VHDL 定义了 10 种基本数据类型, 分别为:
-
integer
: 整数. 占 4B, 范围是 -2147483647~2147483647, 不能按位操作, 不能进行逻辑运算.考虑到硬件资源的有限, 可以进行区间约束, 如
integer RANGE 1 TO 100; interge RANGE 100 DOWNTO 1; -- 两者没有本质区别
-
real
: 实数 (浮点数). 范围是 -1.0E-38~1.0E+38, 一般不能被综合. -
bit
: 位. 包括 ‘1’ 和 ‘0’, 只能用单引号. -
bit_vector
: 位串. 用双引号, 如 “0011”. -
std_logic
: 标准位. 其取值有:- ‘0’: Forcing low, 强低电平.
- ‘1’: Forcing high, 强高电平.
- ‘Z’: High impedence, 高阻态.
- ‘L’: Weak low, 弱低电平.
- ‘H’: Weak high, 弱高电平.
- ‘U’: Uninitialized, 未初始化.
- ‘X’: Unknown, 未知.
- ‘-’: Don’t care, 不必理会.
-
std_logic_vector
: 标准位串. -
boolean
: 布尔. 存在两种值: TRUE, FALSE. -
character
: 字符. 用单引号扩起, 区分大小写. -
string
: 字符串. 用双引号扩起, 区分大小写. -
time
: 时间. 只用于仿真, 综合时会被忽略. -
severity level
: 错误等级. 在仿真中提示程序的状态, 如存在 error, 存在 warning, 存在 failure 等. -
natural
: 自然数. 整数的子集. -
positive
: 正整数. 自然数的子集.
2.6 Self-defined Data Types
VHDL 允许用户自己定义数据类型, 格式如下:
-- 数据类型定义
TYPE <数据类型名> IS <数据类型定义>;
-- 数据类型继承
TYPE <数据类型名> IS <数据类型定义> OF <父类型名>;
-
枚举
TYPE week IS (sun, mon, tue, wed, thu, fri, sat);
-
数组
TYPE stb IS array(7 DOWNTO 0) OF std_logic;
-
子类型
SUBTYPE natural IS integer RANGE 0 TO interger'HIGH;
TYPE percent IS interger RANGE -100 TO 100;
-
记录类型
格式如下
-- 记录类型的定义 TYPE <记录类型名> IS RECORD <元素名>: <元素数据类型>; <元素名>: <元素数据类型>; ...... END RECORD [记录类型名];
例如:
TYPE GlitchDataType IS RECORD schedtime: TIME; Schedvalue: STD_LOGIC; END RECORD;
2.7 Vectors
-
1D × \times × 1D 数组.
Type row IS ARRAY(7 DOWNTO 0) OF std_logic; -- row是1维长度8的数组, 每个元素为std_logic类型 Type array1 IS ARRAY(0 TO 3) OF row; -- array是1维长度4的数组, 每个元素为row类型 SIGNAL x: array1; x(0)(0); -- 合法的访问, 表示一个std_logic类型的元素 x(0); -- 表示一个1维长度8的数组(row)类型
-
2D 数组.
Type array2 IS ARRAY(0 TO 3, 7 DOWNTO 0) OF std_logic; -- array是2维形状为[4, 8]的数组, 每个元素为std_logic类型 SIGNAL y: array2; x(0, 0); -- 合法的访问, 表示一个std_logic类型的元素
2.8 Conversion of Data Types
通过 IEEE 库中的一些包可以进行强制类型转换.
-
std_logic_1164
包-
to_stdLogic(A)
: 将bit
转换为std_logic
. -
to_stdLogicVector(A)
: 将bit_vector
转换为std_logic_vector
. -
to_bit(A)
: 将std_logic
转换为bit
. -
to_bitVector(A)
: 将std_logic_vector
转换为bit_vector
.
-
-
std_logic_arith
包conv_std_logic_vector(A, n)
: 将integer
,unsigned
,signed
转换为std_logic_vector
.conv_integer(A)
: 将unsigned
,signed
转换为integer
.
-
std_logic_unsigned
包conv_integer(A)
: 将std_logic_vector
转换为integer
.
2.9 Operators
VHDL 运算符主要有: 算数运算符, 逻辑运算符, 关系运算符等.
-
算数运算符:
+
: Addiction, 加法.-
: Subtraction, 减法.*
: Multiplication, 乘法./
: Division, 除法.**
: Exponentiation, 乘方.MOD
: Modulus, 取模.a MOD b
符号与b
相同, 绝对值小于b
的绝对值.REM
: Remainder, 取余.a REM b
符号与a
相同, 绝对值小于b
的绝对值.ABS()
: 取绝对值.SLA
: 算数左移.SRA
: 算数右移.
-
逻辑运算符:
AND
: 逻辑与.OR
: 逻辑或.NAND
: 逻辑与非.NOR
: 逻辑或非.XOR
: 逻辑异或.XNOR
: 逻辑异或非.NOT
: 逻辑非. 优先级最高.SLL
: 逻辑左移.SRL
: 逻辑右移.ROL
: 逻辑循环左移.ROR
: 逻辑循环右移.
-
关系运算符:
=
: 相等./=
: 不等.<
: 小于.>
: 大于.<=
: 小于等于.>=
: 大于等于.
-
并置:
&
例如:
z <= x & "0100"; -- 若x为'1', 则执行后z为"10100"; z <= "0100" & x; -- 若x为'1', 则执行后z为"01001";
3. Basic VHDL Concurrent Statements
这一节主要讨论 VHDL 的并行语句.
3.1 Assignment Statements
Assignment Statement (赋值语句): 将一个值或一个表达式的计算结果传递给某一数据对象, 格式如下:
-- 赋值语句
<赋值目标> <赋值符号> <赋值源>;
- 当赋值目标为变量, 赋值符号为
:=
. - 当赋值目标为信号, 赋值符号位
<=
.
3.2 When-else Statements
When-else 语句是条件赋值语句, 用于给信号赋值, 格式如下:
-- When-esls 语句
<信号赋值目标> <= <表达式> WHEN <赋值条件> ELSE
<表达式> WHEN <赋值条件> ELSE
......
<表达式>;
ELSE
不可省略, 最后一定要有结尾避免条件涵盖不全.- 执行时, 按书写顺序逐一判断是否满足条件, 一旦满足, 不再检查后续条件.
- 赋值条件允许重叠.
3.3 With-select Statements
With-select 语句是选择赋值语句, 用于给信号赋值, 格式如下:
-- With-select 语句
WITH <选择表达式> SELECT
<信号赋值目标> <= <表达式> WHEN <选择值>,
<表达式> WHEN <选择值>,
......
<表达式> WHEN <选择值>;
- 执行时, 并行地检查选择值是否等于选择表达式, 并将对应的表达式赋值给赋值目标.
- 不允许条件重叠.
- 不允许条件涵盖不全.
3.4 Component Instantiation Statement
Component Instantiation Statement 是元件例化语句, 指引入一种连接关系, 将预先设计好的 Entity 定义为一个元件, 并与当前实体中的指定端口发生连接. 格式如下:
-- 元件例化语句
-- Part1, 将其它实体定义为元件
COMPONENT <元件名> IS
[GENERIC(<类属表>);]
PORT(<端口表>);
END COMPONENT;
-- Part2, 映射(端口连接)
<例化名>: <元件名> [GENERIC MAP(...);]
PORT MAP([端口名=>]连接端口名,...);
PORT MAP
有两种用法:- 忽略端口名, 直接写连接端口名, 则按默认顺序连接.
- 写入端口名, 则按所写对应连接.
例如, 将两个 and2 构成一个 and4:
Library IEEE;
Use IEEE.std_logic_1164.ALL;
-- ENTITY
Entity and4 IS
PORT(in1, in2, in3, in4: IN std_logic;
q: OUT std_logic);
END and4;
----------
-- ARCHITECTURE
Architecture stru OF and4 IS
Component and2 IS
PORT(a, b: IN std_logic;
c: OUT std_logic);
END Component; -- 将已经实现的Entity定义为一个元件and2
Signal u0_c, u1_c: std_logic; -- 定义中间量, 用作描述连线
BEGIN
U0: and2 PORT MAP(in1, in2, u0_c);
U1: and2 PORT MAP(in3, in4, u1_c);
-- 前面两个and2, 得到中间两u0_c和u1_c, u0_c和u1_c相与得到结果
-- 忽略了端口名, 则端口按Component中定义的顺序连接
U2: and2 PORT MAP(c=>q, a=>u0_c, b=>u1_c);
-- 后面一个and2, 写入了端口名, 可以更改顺序
END stru;
3.5 For-generate Statements
For-generate 语句是 For 生成语句, 用于并行地复制相同的元件, 格式如下:
-- For 生成语句
[标号:] FOR <循环变量> IN <取值范围> GENERATE
<说明部分>;
BEGIN -- 可省略
<并行语句>;
END GENERATE [标号];
例如, 设计4位移位寄存器 (输入端口 a
, 时钟信号 clk
, 输出端口 b
), 假设D触发器是已经设计好的 Entity:
Library IEEE;
Use IEEE.std_logic_1164.ALL;
Entity shift4 IS
PORT(a, clk: IN std_logic;
b: OUT std_logic);
End shift4;
Architecture gen of shift4 IS
Component d_ff is
PORT(reset, clk, d: IN std_logic;
q: OUT std_logic);
end Component;
signal z: std_logic_vector(0 to 4);
begin
z(0) <= a;
g1: for i in 0 to 3 generate
dffx: d_ff port map('0', clk, z(i), z(i+1));
end generate g1;
end gen;
3.6 If-generate Statements
If-generate 语句是 If 生成语句, 用于在给定条件下复制相同的元件, 格式如下:
-- If 生成语句
[标号:] If <条件> GENERATE
<说明部分>;
BEGIN -- 可省略
<并行语句>;
END GENERATE [标号];
例如, 设计4位移位寄存器 (输入端口 a
, 时钟信号 clk
, 输出端口 b
), 假设D触发器是已经设计好的 Entity:
Library IEEE;
Use IEEE.std_logic_1164.ALL;
Entity shift4 IS
PORT(a, clk: IN std_logic;
b: OUT std_logic);
END shift4;
Architecture gen of shift4 IS
Component d_ff IS
PORT(reset, clk, d: IN std_logic;
q: OUT std_logic);
END Component;
SIGNAL z: std_logic_vector(0 TO 4);
BEGIN
G1: FOR i IN 0 TO 3 Generate
T1: IF i=0 Generate
Dffx0: d_ff PORT MAP('0', clk, a, z(0));
END Generate T1;
T2: IF i>0 AND i<3 Generate
Dffx1: d_ff PORT MAP('0', clk, z(i-1), z(i));
END Generate T2;
T3: IF i=3 Generate
Dffx2: d_ff PORT MAP('0' clk, z(i-1), b);
END Generate T3;
END Generate G1;
END gen;
4. Basic VHDL Sequential Statements
这一节主要讨论 VHDL 串行语句
4.1 Process Statements
格式:
-- Process 语句
Process(<敏感参数表>);
<串行语句>;
End process;
注意:
- 当敏感参数表里的变量发生改变时, 唤醒 Process 程序并按书写顺序串行执行里面的语句.
- 可以等价地去掉敏感参数表里的变量, 改为在 Process 结束前
wait on
这些信号. - 一个 Architecture 里可以有多个 Process, 语句在 Process 里按书写顺序串行执行, 在 Process 外并行执行.
- 可以在进程里添加 WAIT 语句 (则不能含有敏感参数表)
WAIT FOR <时间表达式>;
等待一段指定的时间, 不能被综合.WAIT ON <信号表>;
WAIT UNITIL <条件>;
- 空操作语句:
NULL;
4.2 If Statements
If 语句有三种方式:
-
If-Then 语句
-- If-Then 语句 IF <条件> THEN <顺序语句>; END IF;
例如:
IF en='1' THEN C<=B; END IF;
-
If-Then-Else 语句
-- If-Then-Else 语句 IF <条件> THEN <顺序语句>; ELSE <顺序语句>; END IF;
例如, 一个简单的二路选择器:
IF sel='1' THEN C<=A; ELSE C<=B; END IF;
-
If-Then-Elsif-Then-Else 语句
-- If-Then-Elsif-Then-Else 语句 IF <条件> THEN <顺序语句>; ELSIF <条件> THEN <顺序语句>; ELSE <顺序语句>; END IF;
注意:
-
任何 If 语句必须放进 Process 里, 即
Process(<敏感参数表>) Begin <IF语句>; END Process;
-
If 语句允许条件重叠, 允许条件不完备. 按书写顺序逐个检查条件是否满足, 若条件不完备, 则生成时序逻辑电路 (生成存储器记录信号曾经的值, 当条件不完备时信号相当于被赋曾经的值), 当条件完备时生成组合逻辑电路.
4.3 Case Statements
格式:
-- Case 语句
CASE <表达式> IS
WHEN <选择值> => <处理语句>;
END CASE;
- CASE 语句并行地比较所有条件, 因此不允许出现条件重叠.
- 如果未能列出所有可能的取值, 则在 CASE 语句结束前使用
OTHERS
.
4.4 Loops
Loop 语句有三种形式:
-
简单 LOOP 语句
[标号:] LOOP <顺序处理语句>; END LOOP [标号];
-
FOR LOOP 语句
[标号:] FOR <循环变量> IN <离散范围> LOOP <顺序处理语句>; END LOOP [标号];
-
WHILE LOOP 语句
[标号:] WHILE <条件> LOOP <顺序处理语句>; END LOOP [标号];
注意:
-
While loop 不可被综合.
-
可以使用 EXIT 语句退出循环:
EXIT;
立即退出循环.EXIT [标号];
立即退出循环并跳转到指定的标号循环结尾处.EXIT [标号] WHEN <条件>;
当条件被满足时退出循环.
-
可以使用 NEXT 语句进入下一趟循环:
NEXT;
无条件进入下一趟循环.NEXT [标号];
无条件进入指定标号的下一趟循环.NEXT [标号] WHEN <条件>;
当条件被满足时进入指定标号的下一趟循环.
5. Combinational Logic
5.1 3-8 Decoder
三八译码器的代码如下:
-- decoder_38
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY decoder_38 IS
PORT(a, b, c, en: IN std_logic;
y: OUT std_logic_vector(7 DOWNTO 0));
END decoder_38;
ARCHITECTURE behav OF decoder_38 IS
SIGNAL indata: std_logic_vector(2 DOWNTO 0);
BEGIN
indata <= c&b&a;
PROCESS(en, indata)
BEGIN
IF(en='1')THEN
CASE indata IS
WHEN "000" => y<="11111110";
WHEN "001" => y<="11111101";
WHEN "010" => y<="11111011";
WHEN "011" => y<="11110111";
WHEN "100" => y<="11101111";
WHEN "101" => y<="11011111";
WHEN "110" => y<="10111111";
WHEN "111" => y<="01111111";
WHEN OTHERS => y<="XXXXXXXX";
END CASE;
ELSE y<="11111111";
END IF;
END PROCESS;
END behav;
RTL 图如下:
仿真时序如下:
5.2 74LS148
优先级编码器 74LS148 的代码如下:
-- encoder_74LS148
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY encoder_74LS148 IS
PORT(en: IN std_logic;
input: IN std_logic_vector(7 DOWNTO 0);
output: OUT std_logic_vector(2 DOWNTO 0));
END ENTITY;
ARCHITECTURE behav OF encoder_74LS148 IS
BEGIN
PROCESS(en, input)
BEGIN
IF(en='1')THEN
IF (input(0)='0')THEN output <= "111";
ELSIF(input(1)='0')THEN output <= "110";
ELSIF(input(2)='0')THEN output <= "101";
ELSIF(input(3)='0')THEN output <= "100";
ELSIF(input(4)='0')THEN output <= "011";
ELSIF(input(5)='0')THEN output <= "010";
ELSIF(input(6)='0')THEN output <= "001";
ELSIF(input(7)='0')THEN output <= "000";
ELSE output <= "XXX";
END IF;
ELSE output <= "XXX";
END IF;
END PROCESS;
END behav;
RTL 图如下:
仿真时序如下:

5.3 Adders
5.3.1 Half Adder
半加器代码如下:
-- halfAdder
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY halfAdder IS
PORT(x, y: IN std_logic;
sum, carry: OUT std_logic);
END halfAdder;
ARCHITECTURE behav OF halfAdder IS
BEGIN
sum <= x xor y;
carry <= x and y;
END behav;
RTL 图如下:
时序仿真图如下:
5.3.2 Full Adder
全加器代码如下:
-- fullAdder
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY fullAdder IS
PORT(x, y, ci: IN std_logic;
sum, co: OUT std_logic);
END fullAdder;
ARCHITECTURE behav OF fullAdder IS
BEGIN
sum <= x xor y xor ci;
co <= (x and y)or(x and ci)or(y and ci);
END behav;
RTL 图如下:
仿真时序图如下:
5.3.3 Sequential 4-bits Adder
串行4位加法器代码如下:
-- sequential4BitAdder
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY sequential4BitAdder IS
PORT(x, y: IN std_logic_vector(3 DOWNTO 0);
ci: IN std_logic;
sum: OUT std_logic_vector(3 DOWNTO 0);
co: OUT std_logic);
END ENTITY;
ARCHITECTURE behav OF sequential4BitAdder IS
COMPONENT fullAdder IS
PORT(x, y, ci: IN std_logic;
sum, co: out std_logic);
END COMPONENT;
SIGNAL z: std_logic_vector(4 DOWNTO 0);
BEGIN
z(0) <= ci;
gen: FOR i IN 0 TO 3 GENERATE
fullAdderx: fullAdder PORT MAP(x(i),y(i),z(i),sum(i),z(i+1));
END GENERATE gen;
co <= z(4);
END behav;
RTL 图如下:
仿真时序图如下:
缺点: 高位的计算需要等待来自低位的进位信号, 位数越多, 速度越慢.
5.3.4 Parallel 4-bits Adder
并行4位加法器代码如下:
-- parallel4BitAdder
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY parallel4BitAdder IS
PORT(x, y: IN std_logic_vector(3 DOWNTO 0);
ci: IN std_logic;
sum: OUT std_logic_vector(3 DOWNTO 0);
co: OUT std_logic);
END parallel4BitAdder;
ARCHITECTURE behav OF parallel4BitAdder IS
SIGNAL d,t,s: std_logic_vector(3 DOWNTO 0);
SIGNAL c: std_logic_vector(4 DOWNTO 0);
BEGIN
gen:FOR i IN 0 TO 3 GENERATE
begin
d(i) <= x(i) and y(i);
t(i) <= x(i) or y(i);
s(i) <= x(i) xor y(i) xor c(i);
END GENERATE;
c(0) <= ci;
c(1) <= d(0) or (t(0) and c(0));
c(2) <= d(1) or (t(1) and d(0)) or (t(1) and t(0) and c(0));
c(3) <= d(2) or (t(2) and d(1)) or (t(1) and t(2) and d(0)) or (t(0) and t(1) and t(2) and c(0));
c(4) <= d(3) or (t(3) and d(2)) or (t(2) and t(3) and d(1)) or (t(1) and t(2) and t(3) and d(0)) or (t(3) and t(2) and t(1) and t(0) and c(0));
sum <= s;
co <= c(4);
END behav;
RTL 图如下:
仿真时序图如下:
优点: 并行计算, 速度更快.
缺点: 计算资源消耗特别大.
4位时, 串行和并行几乎占用相同的资源, 因此以并行4位加法器为基础级联构成更多位数的加法器.
5.3.5 8-bits Adder
8位加法器的代码如下:
-- adder8Bit
--Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY adder8Bit IS
PORT(x, y: IN std_logic_vector(7 DOWNTO 0);
ci: IN std_logic;
sum: OUT std_logic_vector(7 DOWNTO 0);
co: OUT std_logic);
END adder8Bit;
ARCHITECTURE behav OF adder8Bit IS
COMPONENT parallel4BitAdder IS
PORT(x, y: IN std_logic_vector(3 DOWNTO 0);
ci: IN std_logic;
sum: OUT std_logic_vector(3 DOWNTO 0);
co: OUT std_logic);
END COMPONENT;
SIGNAL carry: std_logic;
BEGIN
U0:parallel4BitAdder PORT MAP(x=>x(3 DOWNTO 0), y=>y(3 DOWNTO 0), ci=>ci, sum=>sum(3 DOWNTO 0), co=>carry);
U1:parallel4BitAdder PORT MAP(x=>x(7 DOWNTO 4), y=>y(7 DOWNTO 4), ci=>carry, sum=>sum(7 DOWNTO 4), co=>co);
END behav;
RTL 图如下:
时序仿真图略.
5.4 8-1 Multiplexer
8选1选择器的代码如下:
-- multiplexer_81
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY multiplexer_81 IS
PORT(input: IN std_logic_vector(7 DOWNTO 0);
a, b, c: IN std_logic;
output: OUT std_logic);
END multiplexer_81;
ARCHITECTURE behav OF multiplexer_81 IS
SIGNAL indata: std_logic_vector(2 DOWNTO 0);
BEGIN
indata <= a&b&c;
WITH indata SELECT
output <= input(0) WHEN "000",
input(1) WHEN "001",
input(2) WHEN "010",
input(3) WHEN "011",
input(4) WHEN "100",
input(5) WHEN "101",
input(6) WHEN "110",
input(7) WHEN "111",
'X' WHEN OTHERS;
END behav;
RTL 图如下:
仿真时序图如下:
5.5 Complementer
complementer 是求补器, 用于将 8 位二进制原码输入转化为 8 位二进制补码输出, 补码可以让减法变为加法. 求补器的代码如下:
-- complementer
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;
ENTITY complementer IS
PORT(x: IN std_logic_vector(7 DOWNTO 0);
y: OUT std_logic_vector(7 DOWNTO 0));
END complementer;
ARCHITECTURE behav OF complementer IS
BEGIN
y <= not x+'1';
END behav;
RTL 图如下:
仿真时序图如下:
5.6 Tri-state Gate
三态门的代码如下:
-- triStateGate
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY triStateGate IS
PORT(din, en: IN std_logic;
dout: OUT std_logic);
END triStateGate;
ARCHITECTURE behav OF triStateGate IS
BEGIN
PROCESS(din, en)
BEGIN
IF(en='1')THEN dout<=din;
ELSE dout<='Z';
END IF;
END PROCESS;
END behav;
RTL 图如下:
仿真时序图如下:
5.7 Buffer
双向 8 位总线缓冲器代码如下:
-- bufferBus
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY bufferBus IS
PORT(x, y: INOUT std_logic_vector(7 DOWNTO 0);
en, dir: IN std_logic);
END bufferBus;
ARCHITECTURE behav OF bufferBus IS
SIGNAL xout, yout: std_logic_vector(7 DOWNTO 0);
BEGIN
PROCESS(en, dir, x, yout)
BEGIN
IF((en='1')and(dir='1'))THEN
yout <= x;
ELSE yout<= "ZZZZZZZZ";
END IF;
y <= yout;
END PROCESS;
PROCESS(en, dir, y, xout)
BEGIN
IF((en='1')and(dir='0'))THEN
xout <= y;
ELSE xout<= "ZZZZZZZZ";
END IF;
x <= xout;
END PROCESS;
END behav;
RTL 图如下:
时序仿真图略.
6. Sequence Logic
6.1 Latch
Latch (锁存器) 是电平敏感的寄存器.
6.1.1 RS-Latch
RS 锁存器的代码如下:
-- rsLatch
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY rsLatch IS
PORT(R, S: IN std_logic;
Q, Qbar: OUT std_logic);
END ENTITY;
ARCHITECTURE behav OF rsLatch IS
BEGIN
PROCESS(R,S)
VARIABLE rs: std_logic_vector(1 DOWNTO 0);
BEGIN
rs:=R&S;
CASE rs IS
WHEN "00" => Q<='1'; Qbar<='1';
WHEN "01" => Q<='1'; Qbar<='0';
WHEN "10" => Q<='0'; Qbar<='1';
WHEN OTHERS => NULL;
END CASE;
END PROCESS;
END behav;
RTL 图如下:
仿真时序图如下:
6.1.2 D-Latch
带 Q ˉ \bar Q Qˉ 输出的 D 锁存器代码如下:
-- dLatch
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY Latch_D IS
PORT(D, EN: IN std_logic;
Q, Qbar: OUT std_logic);
END Latch_D;
ARCHITECTURE behav OF Latch_D IS
SIGNAL state: std_logic;
BEGIN
PROCESS(D,EN) -- D写入敏感参数表, 电平敏感
BEGIN
IF(EN='1')THEN state<=D; -- 不完备的 if 语句, 用于生成寄存器
END IF;
END PROCESS;
Q<=state;
Qbar<=not state;
END behav;
RTL 图如下:
注意, 程序中的 state
是为了保证只生成一个寄存器, 如果不使用 state
, 将 ARCHITECTURE
段变为如下:
ARCHITECTURE behav OF Latch_D IS
SIGNAL state: std_logic;
BEGIN
PROCESS(D,EN)
BEGIN
IF(EN='1')THEN Q<=D; Qbar<=not D;
END IF;
END PROCESS;
END behav;
则将生成两个寄存器, RTL 图如下:
6.3 D-Flip-Flop
D 触发器的特征方程为:
Q
n
+
1
=
D
.
Q_{n+1}=D.
Qn+1=D.
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY D_Filp_Flop IS
PORT(D, clk: IN std_logic;
Q: OUT std_logic);
END D_Filp_Flop;
D 触发器是边沿触发的寄存器, 边沿触发的三种方式如下:
-
使用信号的
event
属性ARCHITECTURE behav OF D_Filp_Flop IS BEGIN PROCESS(clk) BEGIN IF(clk'event and clk='1')THEN Q<=D; --使用clk'event保证边沿触发 END IF; END PROCESS; END behav;
其中
clk'event
表示clk
是否发生变化. -
触发信号不放入敏感参数表, 使用
WAIT UNTIL
ARCHITECTURE behav OF D_Filp_Flop IS BEGIN PROCESS -- 敏感参数表无 clk BEGIN WAIT UNTIL(clk='1'); -- 也等价于clk放入敏感参数表, 然后改成 WAIT UNTIL(clk='1'and clk'event) Q<=D; END IF; END PROCESS; END behav;
-
敏感参数表不包含
D
, 直接利用进程的启动特性ARCHITECTURE behav OF D_Filp_Flop IS BEGIN PROCESS(clk) --加入D, 变为D锁存器 BEGIN IF(clk='1')THEN Q<=D; END IF; END PROCESS; END behav;
当需要输出带有
Q
ˉ
\bar Q
Qˉ 的触发器时, 由上面 D 锁存器的讨论知道, 要使用 state
来存储中间变量. 现在详细讨论各种写法的结果:
-- D_Flip_Flop
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY D_Flip_Flop IS
PORT(D, clk, res: IN std_logic;
Q, Qbar: OUT std_logic);
END D_Flip_Flop;
-
用信号定义
state
, 在IF
内完成Q
和Qbar
的赋值.ARCHITECTURE behav OF D_Flip_Flop IS SIGNAL state: std_logic; -- 定义为信号, 注意信号要定义在ARCHITECTURE之初 BEGIN PROCESS(clk, res) BEGIN IF(res='0')THEN state<='0'; Q<=state; Qbar<=not state; -- IF内完成Q和Qbar赋值 ELSIF rising_edge(clk)THEN state<=D; Q<=state; Qbar<=not state; END IF; END PROCESS; END behav;
RTL 图如下:
可见, 生成了三个触发器, 这是因为在不完备的 IF
语句里共有三个信号: state
, Q
, Qbar
, 为每个信号各生成一个寄存器.
-
用变量定义
state
, 在IF
内完成Q
和Qbar
的赋值.ARCHITECTURE behav OF D_Flip_Flop IS BEGIN PROCESS(clk, res) VARIABLE state: std_logic; -- 定义为变量, 注意变量要定义在PROCESS之初 BEGIN IF(res='0')THEN state:='0'; Q<=state; Qbar<=not state; -- IF内完成Q和Qbar赋值 ELSIF rising_edge(clk)THEN state:=D; Q<=state; Qbar<=not state; END IF; END PROCESS; END behav;
RTL 图如下:
可见, 生成了两个触发器. 这是因为不完备的 IF
语句只为信号 (2个: Q
和 Qbar
) 生成寄存器, 不为变量 (state
) 生成寄存器.
-
用变量定义
state
, 并在IF
外完成Q
和Qbar
的赋值.ARCHITECTURE behav OF D_Flip_Flop IS BEGIN PROCESS(clk, res) VARIABLE state: std_logic; BEGIN IF(res='0')THEN state:='0'; ELSIF rising_edge(clk)THEN state:=D; END IF; Q<=state; Qbar<=not state; -- IF外完成Q和Qbar赋值 END PROCESS; END behav;
RTL 图如下:
可见, 只生成了一个触发器, 当不完备 IF
语句里只有变量时, 生成一个寄存器.
-
用信号定义
state
, 并在IF
外和PROCESS
内完成Q
和Qbar
的赋值.ARCHITECTURE behav OF D_Flip_Flop IS SIGNAL state: std_logic; BEGIN PROCESS(clk, res) BEGIN IF(res='0')THEN state<='0'; ELSIF rising_edge(clk)THEN state<=D; END IF; Q<=state; Qbar<=not state; --IF外,PROCESS内完成Q和Qbar赋值 END PROCESS; END behav;
RTL 图如下:
这种情况显然只生成一个寄存器.
-
用信号定义
state
, 并在PROCESS
外完成Q
和Qbar
的赋值.ARCHITECTURE behav OF D_Flip_Flop IS SIGNAL state: std_logic; BEGIN PROCESS(clk, res) BEGIN IF(res='0')THEN state<='0'; ELSIF rising_edge(clk)THEN state<=D; END IF; END PROCESS; Q<=state; Qbar<=not state; --PROCESS外完成Q和Qbar赋值 END behav;
RTL 图如下:
这种情况显然只生成一个寄存器.
6.4 JK-Flip-Flop
JK 触发器的特征方程为:
Q
n
+
1
=
J
Q
ˉ
n
+
K
ˉ
Q
n
.
Q_{n+1}=J\bar Q_n+\bar KQ_n.
Qn+1=JQˉn+KˉQn.
-
当 J K = 00 JK=00 JK=00 时, Q n + 1 = Q n Q_{n+1}=Q_n Qn+1=Qn, 具有保持功能.
-
当 J K = 01 JK=01 JK=01 时, Q n + 1 = 0 Q_{n+1}=0 Qn+1=0, 具有清零功能.
-
当 J K = 10 JK=10 JK=10 时, Q n + 1 = 1 Q_{n+1}=1 Qn+1=1, 具有置位功能.
-
当 J K = 11 JK=11 JK=11 时, Q n + 1 = Q ˉ n Q_{n+1}=\bar Q_n Qn+1=Qˉn, 具有翻转功能.
JK 触发器的代码如下:
-- JK_Flip_Flop
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY JK_Flip_Flop IS
PORT(res, J, K, clk: IN std_logic;
Q, Qbar: OUT std_logic);
END JK_Flip_Flop;
ARCHITECTURE behav OF JK_Flip_Flop IS
SIGNAL state: std_logic;
BEGIN
PROCESS(res, clk)
VARIABLE JK: std_logic_vector(1 DOWNTO 0); -- 这里改成信号,是等价的
BEGIN
JK := J&K;
IF(res='1')THEN state<='0';
ELSIF rising_edge(clk)THEN
CASE JK IS
WHEN "11" => state<=not state;
WHEN "10" => state<='1';
WHEN "01" => state<='0';
WHEN OTHERS => NULL;
END CASE;
END IF;
END PROCESS;
Q<=state;
Qbar<=not state;
END behav;
RTL 图如下:
仿真时序图如下:
6.5 T-Flip-Flop
将 JK 触发器的 J 和 K 连接在一起作为输入端 T, 构成 T 触发器, T 触发器特征方程为:
Q
n
+
1
=
T
Q
ˉ
n
+
T
ˉ
Q
n
.
Q_{n+1}=T\bar Q_n+\bar T Q_n.
Qn+1=TQˉn+TˉQn.
T 触发器的代码如下:
-- T_Flip_Flop
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY T_Flip_Flop IS
PORT(T, clk, res: IN std_logic;
Q, Qbar: OUT std_logic);
END T_Flip_Flop;
ARCHITECTURE behav OF T_Flip_Flop IS
SIGNAL state: std_logic;
BEGIN
PROCESS(clk, res)
BEGIN
IF(res='1')THEN state<='0';
ELSIF rising_edge(clk) THEN
IF(T='1')THEN state<=not state;
END IF;
END IF;
Q<=state; Qbar<=not state;
END PROCESS;
END behav;
RTL 图如下:
仿真时序图略.
6.6 8-bits Register
8位寄存器由8个 D 触发器组合而成, 代码如下:
-- register8bit
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY register8bit IS
PORT(data: IN std_logic_vector(7 DOWNTO 0);
clk, res: IN std_logic;
Qdata: OUT std_logic_vector(7 DOWNTO 0));
END register8bit;
ARCHITECTURE behav OF register8bit IS
BEGIN
PROCESS(clk, res)
BEGIN
IF(res='1')THEN Qdata<="00000000";
ELSIF(rising_edge(clk))THEN Qdata<=data;
END IF;
END PROCESS;
END behav;
RTL 图如下:
仿真时序图如下:
6.7 SIPO (Serial-In, Parallel-Out)
串进并出寄存器是在输入端串行输入 (在时钟的边沿移位), 在输出端并行输出的寄存器. 代码如下:
-- SIPO
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY SIPO IS
PORT(indata: IN std_logic;
clk: IN std_logic;
outdata: OUT std_logic_vector(7 DOWNTO 0));
END SIPO;
ARCHITECTURE behav OF SIPO IS
SIGNAL reg: std_logic_vector(7 DOWNTO 0);
BEGIN
PROCESS(clk)
BEGIN
IF(rising_edge(clk))THEN
reg<=reg(6 DOWNTO 0)&indata; -- 左移位
END IF;
END PROCESS;
outdata<=reg;
END behav;
RTL 图如下:
仿真时序图如下:
6.8 8-bits Counter
计数器用于对脉冲个数进行计数, 可实现对时钟信号的2分频 (0号管脚) 到8分频 (7号管脚). 代码如下:
-- counter8bit
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;
ENTITY counter8bit IS
PORT(clk, res: IN std_logic;
count: OUT std_logic_vector(7 DOWNTO 0));
END counter8bit;
ARCHITECTURE behav OF counter8bit IS
BEGIN
PROCESS(clk, res)
VARIABLE cnt: std_logic_vector(7 DOWNTO 0);
BEGIN
IF(res='0')THEN cnt:="00000000";
ELSIF rising_edge(clk)THEN cnt:=cnt+1; -- IEEE.std_logic_unsigned库保证了+函数可以使用
END IF;
count<=cnt;
END PROCESS;
END behav;
RTL 图如下:
仿真时序图如下:
6.9 4-bits Multiplier
4 位无符号乘法器以两个 4bits 总线作为输入, 以一个 8bits 总线作为输出.
乘法器输入端: A
, B
: 4位总线, 作为乘数输入; clk
: 时钟信号; load
: 表示正在装填乘数, 高电平有效.
乘法器输出端: X
: 8位总线, 作为结果输出; ready
: 表示是否已计算完毕, 高电平有效.
乘法器代码如下:
-- multiplier4bit
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;
USE IEEE.numeric_std.ALL; -- 定义了unsigned数据类型
ENTITY multiplier4bit IS
PORT(A, B: IN std_logic_vector(3 DOWNTO 0);
X: OUT std_logic_vector(7 DOWNTO 0);
clk, load: IN std_logic;
ready: OUT std_logic);
END multiplier4bit;
ARCHITECTURE behav OF multiplier4bit IS
BEGIN
PROCESS(clk)
VARIABLE count: integer RANGE 0 TO 4; -- 记录当前周期计算位数
VARIABLE pa: unsigned(8 DOWNTO 0); -- 存储中间计算结果,多一位防止加法溢出
ALIAS p: unsigned(4 DOWNTO 0)IS pa(8 DOWNTO 4); -- ALIAS是重命名,此处p是pa的高5位
BEGIN
IF(rising_edge(clk))THEN
IF load='1' THEN -- 当load高电平时,装填乘数
p:="00000"; -- 中间计算结果高4位清零
pa(3 DOWNTO 0):=unsigned(A); -- 低四位读取一个乘数A
count:=4; -- 需要计算4次加法
ready<='0'; -- 计算完毕位无效
ELSIF(count>0)THEN -- 无需装填乘数,若count>0表示当前周期仍在计算
CASE std_logic(pa(0))IS -- 第二个乘数B与中间结果第一位相乘
WHEN '1' => p:=p+unsigned(B); -- 若乘1,相当于加B
WHEN OTHERS=> NULL; -- 若乘0,相当于加0
END CASE;
pa:=shift_right(pa,1); -- 把pa右移一位
count:=count-1; -- 计算次数减1
END IF;
IF count=0 THEN ready<='1'; END IF; -- 若剩余计算位数为0,表明已计算完毕,ready置位
X<=std_logic_vector(pa(7 DOWNTO 0));-- 输出结果
END IF;
END PROCESS;
END behav;
RTL 图如下:
仿真时序图如下:
可见, 4位乘法器要消耗4个时钟周期才能完成一次计算, 这是因为4位乘法意味着4次加法, 一个加法器在一个时钟周期内只能完成一次加法运算.
7. State Machine
7.1 Classification of Sequential Circuit
-
按状态变化特点划分:
-
Synchronous Sequential Logic Circuit (同步时序逻辑电路).
电路的状态改变在统一的时钟信号作用下同时发生.
-
Asynchronous Sequential Logic Circuit (异步时序逻辑电路).
没有统一时钟信号, 电路的状态改变不是同时发生.
-
-
按输出信号的特点划分:
-
Moore Circuit (摩尔型电路).
电路的输出仅仅取决于存储器的状态.
-
Mealy Circuit (米里型电路).
电路的输出不仅取决于存储器的状态, 还取决于输入的信号.
-
7.2 Race Contention
Race Contention (竞争冒险):
- Contention (竞争): 在组合逻辑电路中, 信号经不同途径传输后, 到达电路中某一会合点的时间有先有后, 这种现象称为竞争.
- Risk (冒险): 由于竞争现象导致电路输出发生瞬间错误的现象称为冒险.
消除竞争冒险的方法:
-
接入滤波电容.
简单易行, 但是影响输出电压波形.
-
引入选通脉冲.
通过使用同步时序电路实现引入选通滤波的效果, 要选择合适的时钟周期.
设:
- 时钟周期 T T T: 同步时序电路的时钟周期.
- 建立时间 t su t_{\text{su}} tsu: 触发器的时钟信号上升沿到来以前, 数据稳定不变的时间.
- 保持时间 t hold t_{\text{hold}} thold: 触发器的时钟信号上升沿到来以后, 数据稳定不变的时间.
- 传播延时 t c-q t_{\text{c-q}} tc-q: 信号在传播路径上需要的时间. 最坏的延时为 t plogic t_{\text{plogic}} tplogic.
则, 时钟周期至少满足:
T > t su + t su + t plogic T>t_{\text{su}}+t_{\text{su}}+t_{\text{plogic}} T>tsu+tsu+tplogic
7.3 State Machine
7.3.1 ASM (Algorithm State Machine)
ASM (算法状态机) 是一种符号化描述 (同步) 时序电路的方法. ASM 图由三部分组成:
-
State Box (状态框)
是一个矩形框. 用一个状态框表示一个状态, 在矩形框内写操作内容. 在同步系统中, 一个状态至少持续一个时钟周期 (也可以是整数个时钟周期).
R <- 0
表示 R 在状态末变为 0,C='1'
表示在这个状态中 C 为 ‘1’, 也可直接写为C='0'
. -
Decision Box (判断框)
是一个菱形框. 判断框有一个入口, 多个出口, 判断框必须跟着状态框, 判断框的执行与状态框处于同一状态时间内 (一般在同一时钟周期内).
-
Conditional Output Box (条件框)
是一个圆角矩形框. 条件框必须跟着判断框的一个转移分支, 并紧接一个状态框, 仅当条件被满足时, 执行条件框内的操作. 条件框的执行与上一个判断框的判断和上一个状态框处于同一状态时间内 (一般在同一时钟周期内).
一个状态简化后的自动售邮票机的 ASM 图如下:
7.3.2 ASM Design
ASM 图的硬件实现主要有以下几种方法:
-
计数器法
采用二进制计数序列依次表示状态, 使用计数器来描述状态机.
缺点: 一旦 ASM 图有很小的改动, 就需要重新设计与次态相关的组合电路部分. 当系统的状态比较多时, 硬件变得非常复杂.
-
多路选择器
使用多路选择器为每个状态选择次态.
缺点: 要求多路选择器数量和状态数相等, 且多路选择器输入位数不应小于状态数. 当系统的状态比较多时, 非常消耗硬件资源.
-
定序法
按 ASM 图中状态转换的顺序, 为每个状态选用一个 D 触发器.
优点: 硬件逻辑易于设计, 电路清楚.
缺点: 比计数器法的体量大, 不经济. 电路发生故障时排障麻烦.
-
微程序法
使用 ROM 用来实现状态转换.
优点: 规范化.
缺点: ASM 复杂时, ROM 的容量将会剧增. 且 ROM 为完全译码, 因此存在大量冗余信息.
以上为在硬件层面对 ASM 进行实现, 更简单普遍的方法为使用 HDL 语言实现.
7.3.3 Encoding of States
使用 VHDL 实现 ASM 则必须对状态进行编码, 有以下三种方式:
-
二进制编码
使用传统的二进制编码. (如:
00
,01
,10
,11
.)优点: 需要的寄存器数量最少.
缺点: 速度较慢, 并且需要较多的外部辅助逻辑.
适用场合: 小型状态机.
ARCHITECTURE behav OF BINARY IS TYPE state_type IS(S1, S2, S3, S4, S5, S6, S7); ATTRIBUTE enum_encoding: STRING; ATTRIBUTE enum_encoding OF state_type IS "001 010 011 100 101 110 111"; BEGIN ...... END behav;
-
格雷码编码
使用格雷码编码. (如:
00
,01
,11
,10
.) 每次只有一个状态位的值发生变化.优点: 触发器使用较少, 不会发生两位同时翻转的情况.
缺点: 速度较慢
适用场合: CPLD 设计, 以及当状态位的输出需要被异步应用的场合.
ARCHITECTURE behav OF BINARY IS TYPE state_type IS(S1, S2, S3, S4, S5, S6, S7); ATTRIBUTE enum_encoding: STRING; ATTRIBUTE enum_encoding OF state_type IS "000 001 011 010 110 111 101"; BEGIN ...... END behav;
-
one-hot 编码
每个状态采用一个触发器. (如:
0001
,0010
,0100
,1000
.)优点: 逻辑简单, 速度快.
缺点: 触发器使用多.
适用场合: FPGA 设计, 大型状态机.
ARCHITECTURE behav OF BINARY IS TYPE state_type IS(S1, S2, S3, S4, S5, S6, S7); ATTRIBUTE enum_encoding: STRING; ATTRIBUTE enum_encoding OF state_type IS "0000001 0000010 0000100 0001000 0010000 0100000 1000000"; BEGIN ...... END behav;
7.4 Design State Machine with VHDL
以上图自动售邮票机的 ASM 图为例.
7.4.1 One-process State Machine
单进程状态机的代码如下:
-- oneProcessStateMachine
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY oneProcessStateMachine IS
PORT(clk: IN std_logic;
coin1: IN std_logic;
coin5: IN std_logic;
ready: OUT std_logic;
coin: OUT std_logic;
outStamp: OUT std_logic;
giveCharge: OUT std_logic;
reset: IN std_logic;
retmoney: OUT std_logic);
END oneProcessStateMachine;
ARCHITECTURE asm OF oneProcessStateMachine IS
BEGIN
PROCESS(clk, coin1, coin5)
TYPE stateType IS (s0, s1, s2, s3, s4, s6, s8);
VARIABLE state: stateType; -- state定义为变量,在单进程状态机中是允许的. 在双进程和三进程状态机中,因为state要在不同进程中共享值,所以只能定义为信号.
BEGIN
IF(reset='1')THEN
ready<='0'; coin<='0'; outStamp<='0'; giveCharge<='0'; retmoney<='0';
state:=s0; -- 因为条件涵盖不完整的IF会产生寄存器,为了不产生多余的寄存器,在此处赋初值.
ELSIF(rising_edge(clk))THEN
CASE state IS
WHEN s0=>
ready<='1'; coin<='0'; outStamp<='0'; giveCharge<='0'; retmoney<='0';
IF(coin5='1')THEN state:=s1; ready<='0';
ELSIF(coin1='1')THEN state:=s2; ready<='0';
ELSE state:=s0;
END IF;
WHEN s1=>
outStamp<='1'; giveCharge<='1';
state:=s0;
WHEN s2=>
coin<='1';
IF(coin5='1')THEN state:=s3;
ELSIF(coin1='1')THEN state:=s4;
ELSE state:=s2;
END IF;
WHEN s3=>
retmoney<='1';
state:=s0;
WHEN s4=>
coin<='1';
IF(coin5='1')THEN state:=s3;
ELSIF(coin1='1')THEN state:=s6;
ELSE state:=s4;
END IF;
WHEN s6=>
coin<='1';
IF(coin5='1')THEN state:=s3;
ELSIF(coin1='1')THEN state:=s8;
ELSE state:=s6;
END IF;
WHEN s8=>
outStamp<='1';
state:=s0;
END CASE;
END IF;
END PROCESS;
END asm;
RTL 图如下:
状态转换图如下:
仿真时序图如下:
单进程状态机是将产生状态寄存器的时序描述和产生次态和输出的组合逻辑描述合并在一个进程中. 适用于简单的设计, 对于复杂的状态机, 可读性差, 易出错, 不利于 EDA 软件的优化.
7.4.2 Two-process State Machine
双进程状态机的代码如下:
-- twoProcessStateMachine
-- Author: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY twoProcessStateMachine IS
PORT(clk: IN std_logic;
coin1: IN std_logic;
coin5: IN std_logic;
ready: OUT std_logic;
coin: OUT std_logic;
outStamp: OUT std_logic;
giveCharge: OUT std_logic;
reset: IN std_logic;
retmoney: OUT std_logic);
END twoProcessStateMachine;
ARCHITECTURE asm OF twoProcessStateMachine IS
TYPE stateType IS (s0, s1, s2, s3, s4, s6, s8);
SIGNAL presentState, nextState: stateType; -- 状态用于两个进程之间通信,要用信号
BEGIN
-- seq进程:产生状态寄存器的时序进程
seq:PROCESS(clk, reset)
BEGIN
IF(reset='1')THEN presentState<=s0;
ELSIF(rising_edge(clk))THEN presentState<=nextState;
END IF; -- 不完备的IF语句用于产生寄存器
END PROCESS seq;
-- com进程:产生次态和输出逻辑
com:PROCESS(presentState, coin1, coin5)
BEGIN
ready<='0'; coin<='0'; outStamp<='0'; giveCharge<='0'; retmoney<='0';
CASE presentState IS
WHEN s0=>
ready<='1'; coin<='0'; outStamp<='0'; giveCharge<='0'; retmoney<='0';
IF(coin5='1')THEN nextState<=s1; ready<='0';
ELSIF(coin1='1')THEN nextState<=s2; ready<='0';
ELSE nextState<=s0;
END IF;
WHEN s1=>
outStamp<='1'; giveCharge<='1';
nextState<=s0;
WHEN s2=>
coin<='1';
IF(coin5='1')THEN nextState<=s3;
ELSIF(coin1='1')THEN nextState<=s4;
ELSE nextState<=s2;
END IF;
WHEN s3=>
retmoney<='1';
nextState<=s0;
WHEN s4=>
coin<='1';
IF(coin5='1')THEN nextState<=s3;
ELSIF(coin1='1')THEN nextState<=s6;
ELSE nextState<=s4;
END IF;
WHEN s6=>
coin<='1';
IF(coin5='1')THEN nextState<=s3;
ELSIF(coin1='1')THEN nextState<=s8;
ELSE nextState<=s6;
END IF;
WHEN s8=>
outStamp<='1';
nextState<=s0;
END CASE;
END PROCESS com;
END asm;
RTL 图如下:
状态转换图和时序仿真图同单进程状态机.
双进程状态机使用两个进程: 一个用于描述时序部分, 产生状态寄存器; 一个用于描述次态和组合逻辑电路的输出部分. 这样相比起单进程状态机, 有效地控制了寄存器的引入.
7.4.3 Three-process State Machine
三进程状态机代码如下:
-- threeProcessStateMachine
-- Ahthor: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY threeProcessStateMachine IS
PORT(clk: IN std_logic;
coin1: IN std_logic;
coin5: IN std_logic;
ready: OUT std_logic;
coin: OUT std_logic;
outStamp: OUT std_logic;
giveCharge: OUT std_logic;
reset: IN std_logic;
retmoney: OUT std_logic);
END threeProcessStateMachine;
ARCHITECTURE asm OF threeProcessStateMachine IS
TYPE stateType IS (s0, s1, s2, s3, s4, s6, s8);
SIGNAL presentState, nextState: stateType;
BEGIN
seq:PROCESS(clk, reset)
BEGIN
IF(reset='1')THEN presentState<=s0;
ELSIF(rising_edge(clk))THEN presentState<=nextState;
END IF;
END PROCESS seq;
ns: PROCESS(presentState, coin1, coin5)
BEGIN
CASE presentState IS
WHEN s0=>
IF(coin5='1')THEN nextState<=s1;
ELSIF(coin1='1')THEN nextState<=s2;
ELSE nextState<=s0;
END IF;
WHEN s1=>
nextState<=s0;
WHEN s2=>
IF(coin5='1')THEN nextState<=s3;
ELSIF(coin1='1')THEN nextState<=s4;
ELSE nextState<=s2;
END IF;
WHEN s3=>
nextState<=s0;
WHEN s4=>
IF(coin5='1')THEN nextState<=s3;
ELSIF(coin1='1')THEN nextState<=s6;
ELSE nextState<=s4;
END IF;
WHEN s6=>
IF(coin5='1')THEN nextState<=s3;
ELSIF(coin1='1')THEN nextState<=s8;
ELSE nextState<=s6;
END IF;
WHEN s8=>
nextState<=s0;
END CASE;
END PROCESS ns;
op: PROCESS(presentState)
BEGIN
ready<='0'; coin<='0'; outStamp<='0'; giveCharge<='0'; retmoney<='0';
CASE presentState IS
WHEN s0=> ready<='1';
WHEN s1=> outStamp<='1'; giveCharge<='1';
WHEN s2=> coin<='1';
WHEN s3=> retmoney<='1';
WHEN s4=> coin<='1';
WHEN s6=> coin<='1';
WHEN s8=> outStamp<='1';
END CASE;
END PROCESS op;
END asm;
RTL 图如下:
状态转换图和时序仿真图同单进程状态机和双进程状态机.
三进程状态机使用三个进程来描述状态机: 第一个进程用于产生状态寄存器, 第二个进程用于产生次态逻辑, 第三个进程用于产生输出逻辑.
态寄存器; 一个用于描述次态和组合逻辑电路的输出部分. 这样相比起单进程状态机, 有效地控制了寄存器的引入.
7.4.3 Three-process State Machine
三进程状态机代码如下:
-- threeProcessStateMachine
-- Ahthor: Sijin Yu
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY threeProcessStateMachine IS
PORT(clk: IN std_logic;
coin1: IN std_logic;
coin5: IN std_logic;
ready: OUT std_logic;
coin: OUT std_logic;
outStamp: OUT std_logic;
giveCharge: OUT std_logic;
reset: IN std_logic;
retmoney: OUT std_logic);
END threeProcessStateMachine;
ARCHITECTURE asm OF threeProcessStateMachine IS
TYPE stateType IS (s0, s1, s2, s3, s4, s6, s8);
SIGNAL presentState, nextState: stateType;
BEGIN
seq:PROCESS(clk, reset)
BEGIN
IF(reset='1')THEN presentState<=s0;
ELSIF(rising_edge(clk))THEN presentState<=nextState;
END IF;
END PROCESS seq;
ns: PROCESS(presentState, coin1, coin5)
BEGIN
CASE presentState IS
WHEN s0=>
IF(coin5='1')THEN nextState<=s1;
ELSIF(coin1='1')THEN nextState<=s2;
ELSE nextState<=s0;
END IF;
WHEN s1=>
nextState<=s0;
WHEN s2=>
IF(coin5='1')THEN nextState<=s3;
ELSIF(coin1='1')THEN nextState<=s4;
ELSE nextState<=s2;
END IF;
WHEN s3=>
nextState<=s0;
WHEN s4=>
IF(coin5='1')THEN nextState<=s3;
ELSIF(coin1='1')THEN nextState<=s6;
ELSE nextState<=s4;
END IF;
WHEN s6=>
IF(coin5='1')THEN nextState<=s3;
ELSIF(coin1='1')THEN nextState<=s8;
ELSE nextState<=s6;
END IF;
WHEN s8=>
nextState<=s0;
END CASE;
END PROCESS ns;
op: PROCESS(presentState)
BEGIN
ready<='0'; coin<='0'; outStamp<='0'; giveCharge<='0'; retmoney<='0';
CASE presentState IS
WHEN s0=> ready<='1';
WHEN s1=> outStamp<='1'; giveCharge<='1';
WHEN s2=> coin<='1';
WHEN s3=> retmoney<='1';
WHEN s4=> coin<='1';
WHEN s6=> coin<='1';
WHEN s8=> outStamp<='1';
END CASE;
END PROCESS op;
END asm;
RTL 图如下:
状态转换图和时序仿真图同单进程状态机和双进程状态机.
三进程状态机使用三个进程来描述状态机: 第一个进程用于产生状态寄存器, 第二个进程用于产生次态逻辑, 第三个进程用于产生输出逻辑.