VHDL学习笔记

VHDL Notes

Author: Sijin Yu

1. Structure of VHDL code

Lib. declaration
Package calling
Entity description
Architecture description
Configuration-Optional

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_logicstd_logic_vector 两种数据类型. (只允许逻辑运算)
  • std_logic_arith: 扩展了三个数据类型: unsigned, signed, small_int, 并定义了算数运算符和转换函数. (只允许算数运算)
  • std_logic_signed: 定义了有符号算数运算函数.
  • std_logic_unsigned: 重载了可用于 integerstd_logic, std_logic_vector 的混合运算运算符, 并定义了不同数据类型的转换函数.

1.3 Entity Description

Entity (实体) 的描述格式如下:

-- 实体描述
Entity <实体名> is
	[类属参数说明];
	<端口说明>;
End [Entity][实体名];

注意:

  • 实体名不能以数字开头, 不能与保留字相同.

  • 实体结束可以选择两种格式: End EntityEnd <实体名>.

  • 类属参数说明是 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 内完成 QQbar 的赋值.

    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 内完成 QQbar 的赋值.

    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个: QQbar) 生成寄存器, 不为变量 (state) 生成寄存器.

  • 用变量定义 state, 并在 IF 外完成 QQbar 的赋值.

    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 内完成 QQbar 的赋值.

    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 外完成 QQbar 的赋值.

    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 图如下:

请添加图片描述

状态转换图和时序仿真图同单进程状态机和双进程状态机.

三进程状态机使用三个进程来描述状态机: 第一个进程用于产生状态寄存器, 第二个进程用于产生次态逻辑, 第三个进程用于产生输出逻辑.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sijin_Yu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值