VHDL时序逻辑器件学习笔记

1. 触发器的设计

1.1 基本D触发器的设计

基本的D触发器分为三个端口:信号输入端D、信号输出端Q、以及时钟信号输入CLK。
其工作特性:在时钟上升沿到来的瞬间,从输入端Q获取信号来更新输出端口D的信号,其余时刻输出信号D保持不变。
以下是实现代码:

LIBRARY IEEE; 
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY DFF1 IS
	PORT(
	CLK,D	:	IN STD_LOGIC;
	Q		:	OUT STD_LOGIC
	);
END DFF1;

ARCHITECTURE BHV OF DFF1 IS
SIGNAL Q1	:	STD_LOGIC;
	BEGIN
	PROCESS(CLK,D)	BEGIN
	IF CLK'EVENT AND CLK='1'
		THEN Q1<=D;
	END IF;
	END PROCESS;
	Q<=Q1;
END BHV;

最终仿真效果如下图所示
在这里插入图片描述

1.1.1 几种不同的上升沿触发检测方式

  1. 使用event函数与逻辑与组合形式
CLK'EVENT AND CLK='1'
  1. 更保险的event+逻辑与组合形式
CLK'EVENT AND (CLK='1') AND (CLK'LAST_VALUE='0')
  1. lastvalue函数形式
CLK='1' AND CLK'LAST_VALUE='0'
  1. rising_edge()函数形式
IF RISING_EDGE(CLK)

1.2 异步复位与时钟使能的D触发器

顾名思义,就是比基本的D触发器多了两个输入端:异步复位端RST和时钟使能端EN。对于异步复位端RST,只要其输入为“1”,D触发器输出端立即清零;对于时钟使能端EN,只有其为“1”时,D触发器才能接受时钟上升沿的信号,对输出端口产生信号更新。实现代码如下:

library ieee;
use ieee.STD_logic_1164.all;
entity dff2 is
port (
  D,CLK,EN,RST    :   IN std_logic;-- EN时钟使能  RST异步清零
  Q              :   OUT std_logic
) ;
end dff2;

architecture behav of dff2 is

  signal Q1   :   std_logic;

begin
reg : process( RST,EN,CLK,D )
begin
  if RST='1' then --触发器被清零
      Q1<='0';
      elsif EN='1' then
          if (CLK'EVENT AND CLK='1') then
              Q1 <= D;
          end if ;
  end if ;
end process ; -- reg
Q <= Q1;
end behav ; -- behav 

这部分存在有两个疑问,留待后续解决:

  • process的敏感变量表中的敏感变量该如何选取呢?
    将进程内部判断语句中出现的变量、赋值符号右侧的变量都纳入敏感变量表中。
  • 仿真时存在一个10ns左右的延时是合理的吗?
    合理的!

1.3 同步复位控制的D触发器

顾名思义,该触发器含有四个输入端口,信号输入端D、时钟信号CLK,时钟使能信号EN以及同步复位端RST,“RST=1”只有在等到信号上升沿到达时才能起到清零作用。
这里需要注意两个重点:

  • 同步信号放置在时钟边沿检测以内(以下),异步信号放置在时钟边沿检测以外(以上)。
  • 在if判断语句中出现else语句说明该判断语句肯定是完整的,实例化后是一个组合逻辑器件。

以下是实现代码:

library IEEE;
use IEEE.std_logic_1164.all;

entity dff3 is 
port(
	RST,EN,CLK,D	:	in  std_logic;
	Q				:	out std_logic
);
end dff3;

architecture behav of dff3 is
	signal Q1	: 	std_logic;
	
	begin ---千万不要忘记architecture里的begin!
	reg:process (CLK,EN)	begin
	if (CLK'event and CLK='1' and EN='1') then --外部的if语句是不完整的,构成了时序逻辑器件
		if RST = '1' then --内部的if是完整的,构成了一个多路选择器
			Q1<='0';
			else --加上了else肯定是完整的判断语句
				Q1 <=D;
		end if;
	end if;	
	end process;
	Q <= Q1;
end behav;

仿真效果图如下:

在这里插入图片描述

2. 锁存器的设计

2.1 基本的锁存器

基本锁存器端口组成:

  • 输入端口:时钟信号CLK以及信号输入D
  • 输出端口:信号输出Q

基本锁存器工作特性:当CLK=‘1’时,输出信号Q时刻等于输入信号D,当CLK=‘0’时,输出信号Q保持。
实现代码如下:

library IEEE;
use IEEE.std_logic_1164.all;

entity LTCH1 is 
	port(
		CLK,D	:	in  std_logic;
		Q		:	out std_logic
	);
end LTCH1;

architecture bhv of LTCH1 is 
signal Q1		:	std_logic;

begin
	reg:process(CLK,D)	begin
		if CLK='1' then
			Q1 <= D;
		end if;
	end process;
	Q <= Q1;
end; --bhv

仿真波形如下:
在这里插入图片描述

2.2 含有清零控制的锁存器

3. 计数器的设计

3.1 简单的四位二进制加法计数器

3.2 带有异步复位和同步加载功能的十进制加法计数器

4. 移位寄存器的设计

5. 实验题目

1)设计一个带计数使能、进位输出、预置数及同步清0的增1二十进制计数器

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
entity CNT20 is
  port (
	CLK,RST,EN,LOAD	:	in std_logic;-- 时钟信号、同步清零信号、计数使能信号、预置数信号
	DATA			:	in std_logic_vector(4 downto 0);--预置数信号
	DOUT			:	out std_logic_vector(4 downto 0);--计数输出
	COUT			:	out std_logic--进位输出
  ) ;
end CNT20;

architecture bhv of CNT20 is
	signal Q		:	std_logic_vector(4 downto 0);
begin
	REG : process( CLK,RST,EN,LOAD )
	begin
		if CLK'EVENT and CLK='1' then
			if RST='0' then	Q <= (others=>'0');-- 同步清零
			elsif EN='1' then
				if LOAD='0' then Q <= DATA;--采用低电平进行预置数
				elsif Q<19 then
					Q <= Q + 1;--未达到进位条件则进位
				else
					Q <= (others=>'0');--手动清零
				end if ;
			end if ;			
		end if ;
	end process ; -- REG

	COM : process( Q )
	begin
		if Q="10011" then --20进制计数到19
			COUT <= '1';
		else
			COUT <= '0';	
		end if ;
	end process ; -- COM
	DOUT <= Q;
end bhv ; -- bhv

2)设计并实现一个带计数使能及异步清0的增1、 8位二进制计数器

3)设计并实现一个带计数使能、进位输出、预置数及异步清0的增1/减1的8位二进制计数器

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
entity CNT_8 is
  port (
	CLK,RST,EN,LOAD	:	in std_logic;-- 时钟信号、异步清零信号、计数使能信号、预置数信号
	DATA			:	in std_logic_vector(7 downto 0);--预置数信号
	DOUT			:	out std_logic_vector(7 downto 0);--计数输出
	COUT			:	out std_logic--进位输出
  ) ;
end CNT_8;

architecture bhv of CNT_8 is
	signal Q		:	std_logic_vector(7 downto 0);
begin
	REG : process( CLK,RST,EN,LOAD )
	begin
		if RST='0' then	Q <= (others=>'0');
			elsif CLK'EVENT and CLK='1' then
				if EN='1' then
					if LOAD='0' then Q <= DATA;
						else
							Q <= Q + 1;
					end if ;
				end if ;			
		end if ;
	end process ; -- REG

	COM : process( Q )
	begin
		if Q="11111111" then --
			COUT <= '1';
		else
			COUT <= '0';	
		end if ;
	end process ; -- COM
	DOUT <= Q;
end bhv ; -- bhv

注意,由于这个8位计数器是计满全部位,所以不需手动设置计数最高位的清零跳转。

4)设计6位串入并出左移移位寄存器(使用状态位实现数据自动加载)

--串行输入并行输出
library IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
entity SHIFT6_LEFT is
  port (
	CR,CLK,SHIFT    :   IN STD_LOGIC;  --清零信号、时钟信号、串行输入信号
	Y               :   OUT STD_LOGIC_VECTOR(5 DOwNTO 0)   --并行四位输出
	) ;
end SHIFT6_LEFT;

architecture A of SHIFT6_LEFT is

	signal TEMP_DATA    :   STD_LOGIC_VECTOR(6 DOWNTO 0); --共计7位,增加一位作为状态位

begin

REG1:process( CLK ) --状态位"011111"工作特性的设定
begin
	if CLK'EVENT AND CLK='1' then
		if CR='0' then--信号清零
			TEMP_DATA<="0000000";
			elsif TEMP_DATA(6)='0' then--状态位重载    --此句更改了TEMP_DATA
			--默认信号初始值都为0 (一般会先存在CR信号对TEMP_DATA进行清零)
				TEMP_DATA<="111110" & SHIFT ;
				else
					TEMP_DATA <= TEMP_DATA(5 DOWNTO 0) & SHIFT ;--信号左移:串行输入一位 & 高四位右移
		end if ;
	end if ;
end process ;


REG2:process( TEMP_DATA ) --并行输出时刻的设定
--每 移动一位\状态位重载 检测一次
begin
	if CLK'event and CLK='1' then
	   if TEMP_DATA(6)='0' then --输出状态位到达
		   Y <= TEMP_DATA(5 DOWNTO 0);
	   --else
		   --Y<="0000";
		end if ; 
	end if ;
end process ;
end A ;  

5)设计6位并入串出右移移位寄存器

library IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
entity SHIFT6_RIGHT is
  port (
	CR,CLK    		:   IN STD_LOGIC; 
	SHIFT			:	IN STD_LOGIC_VECTOR(5 DOwNTO 0);
	Y               :   OUT STD_LOGIC   
	) ;
end SHIFT6_RIGHT;

architecture A of SHIFT6_RIGHT is

	signal TEMP_DATA    :   STD_LOGIC_VECTOR(11 DOWNTO 0);
begin

REG1:process( CLK )
begin
	if CLK'EVENT AND CLK='1' then
		if CR='0' then
			TEMP_DATA<=(others=>'0');
			elsif TEMP_DATA(0)='0' then 
				TEMP_DATA<=SHIFT & "011111";
				else
					TEMP_DATA(10 DOWNTO 0) <= TEMP_DATA(11 DOWNTO 1);
		end if ;
	end if ;
end process ;
Y <= TEMP_DATA(6);
end A ;  



6)设计6位串入串出右移移位寄存器

7)设计6位并入并出左移移位寄存器

6. VHDL语言书写规范

摘录了几个我目前需要改进的、可以理解的VHDL书写习惯:
(完整版参考:VHDL书写规范

  • 实体、结构名、端口信号、常量用大写标识;同样的,变量与一般信号使用首字母大写表示。
    在这里插入图片描述
  • VHDL保留字使用小写
  • 多比特信号都采用 downto描述
  • 调用IEEE库时,IEEE使用大写,其余使用小写
    在这里插入图片描述
  • 每个信号、变量、常量和端口的定义都要有注释
  • 进程之间使用“--------”隔开,若多个进程实现一个功能模块则,功能模块之间使用“–********”分隔。
  • 端口名要对齐。冒号要对齐,in或out类属要对齐,矢量定义要对齐。
  • 几个常见的信号缩写
    在这里插入图片描述
发布了5 篇原创文章 · 获赞 6 · 访问量 2217

猜你喜欢

转载自blog.csdn.net/qq_35000721/article/details/102782061