时序逻辑电路是一种输出不仅与当前的输入有关,而且与其输出状态的原始状态有关的电路。相当于在组合逻辑的输入端加上了一个反馈输入,在其电路中有一个存储电路,可以将输出的状态保持住。由于时序逻辑电路,包含的存储电路,因此不能采用组合逻辑电路的描述方式,时序电路引进了现态和次态的概念。使用逻辑表达式进行描述。
1.1时序电路的分类
按照触发器的动作特点,时序电路可分为同步时序逻辑电路和异步时序逻辑电路。
同步时序逻辑电路:所有的存储元件都在时钟脉冲CP统一控制下,用触发器作为存储元件。只有一个“时钟信号”,所有的内部存储器,只会在时钟的边沿时候改变。几乎现在所有的时序逻辑都是“同步逻辑”。
异步时序逻辑电路:最基础的储存元件是锁存器。锁存器可以在任何时间改变它的状态,依照其它的锁存器信号的变动,它们新的状态就会被产生出来。时序脉冲只接入了第一块触发器,异步动作。
1.2锁存器
锁存器是一种电平敏感的寄存器,典型的例子有RS锁存器与D锁存器。
1.2.1RS锁存器
S | R | Q | Q' |
0 | 0 | 1 | 1 |
0 | 1 | 0 | 1 |
1 | 0 | 1 | 0 |
1 | 1 | Q | Q' |
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY SR_latch2 IS
PORT(S,R : IN STD_LOGIC;
Q,Qbar : OUT STD_LOGIC);
END SR_latch2;
ARCHITECTURE behave OF SR_latch2 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 behave;
1.2.2D锁存器
D锁存器与RS锁存器类似,只是在功能上实现的目的不同。D锁存器通过条件涵盖不完整的if语句产生寄存器。【不完整的if语句产生时序逻辑电路;完整的if语句产生组合逻辑电路】
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY D_latch is
PORT(D,En : IN STD_LOGIC;
Q : OUT STD_LOGIC);
END D_latch;
ARCHITECTURE behave OF D_latch IS
BEGIN
PROCESS(D,En)
BEGIN
IF(En='1') then Q<=D;
END IF;
END PROCESS;
END behave;
1.3触发器
锁存器输入信号会影响输出,但触发器不会。触发器是指边沿触发的寄存器,常见的有D型、JK型、T型。在描述触发器前要注意时钟上升沿的描述。
1.3.1D触发器
当时钟上升沿到来时,把D的值赋给Q,之后保持不变。到下一个时钟上升沿到来时,再次把D的值赋给Q。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY D_FF1 IS
PORT(D,clk : IN STD_LOGIC;
Q : OUT STD_LOGIC);
END D_FF1;
ARCHITECTURE behave OF D_FF1 IS
BEGIN
-----------方法一---------------
PROCESS(clk)
BEGIN
IF(clk'event and clk='1') then Q<=D;
END IF;
END PROCESS;
END behave;
-----------方法一---------------
-----------方法二---------------
PROCESS
BEGIN
wait until(clk='1');
Q<=D;
END PROCESS;
END behave;
-----------方法二---------------
-----------方法三---------------
PROCESS(clk)
BEGIN
IF(CLK='1') THEN Q<=D;
END IF;
END PROCESS;
END behave;
-----------方法三---------------
时钟边沿检测的三种方法
方法一:
上升沿:clock'event and clock='1'=rising_edge(clk)
下降沿:clock'event and clock='0'=falling_edge(clk)
注意:if(clock'event and clock='1') 语句后面不存在else分支。当clock为STD_LOGIC类型时,也可以利用if(rising_edge(clk))或if(falling_edge(clk))进行时钟边沿检测。
方法二:
利用WAIT语句启动进程,检测clock的上升沿。注意:WAIT语句不能和敏感参数表同时存在,且WAIT语句只能出现在PROCESS进程的第一句或最后一句。
方法三:
使用PROCESS语句和IF语句相结合实现。当clock发生跳变的时候,启动PROCESS进程,而在执行IF语句时,满足clock='1'时才对Q进行赋值更新,所以相当于clock发生跳变且跳变为‘1’时,将D赋给Q,实际上就是D触发器的描述。
1.3.2带Q非的D触发器
信号法:定义中间信号
ARCHITECTURE sig OF D_FF IS
SIGNAL state : STD_LOGIC;
BEGIN
PROCESS(clock,reset)
BEGIN
if (reset='0') then
state<='0';
elsif(rising_edge(clock) then state<=D;
END IF;
END PROCESS;
Q<=state;
Qbar<=not state;
END sig;
变量法:定义一个中间变量
ARCHITECTURE sig OF D_FF IS
BEGIN
PROCESS(clock,reset)
VARIABLE state : STD_LOGIC;
BEGIN
if (reset='0') then
state:='0';
elsif(rising_edge(clock) then state<=D;
END IF;
Q<=state;
Qbar<=not state;
END PROCESS;
END sig;
注意:信号和变量的定义域和作用域不同,赋值符号也不同。在同一个进程之中对同一个信号进行多次赋值,只有最后一次有效。
信号的赋值符号式"<=" | 变量的赋值符号式“:=" |
信号具有全局特性 | 变量具有局部特性 |
信号具有硬件特性 | 变量具有软件特性 |
对信号进行赋值具有延迟特性 | 对变量进行赋值具有立即特性 |
1.4寄存器
一个D触发器就是一位寄存器,如果需要多位寄存器,就要用多个D触发器构成。触发器个数可以通过在实体中设置一个类属常数GENERIC来根据情况更改位数。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY reg IS
GENERIC(n : natural :=4);
PORT(D : IN STD_LOGIC_VECTOR(n-1 DOWNTO 0);
clock,rst : IN STD_LOGIC;
Q : OUT STD_LOGIC_VECTOR(n-1 DOWNTO 0));
END reg;
ARCHITECTURE behave OF reg IS
BEGIN
PROCESS(clock,rst)
BEGIN
IF(rst='0') then Q<=(others =>'0');
elsif rising_edge(clock) then Q<=D;
END IF;
END PROCESS;
END behave;
1.5移位寄存器
1.5.1串进并出的移位寄存器
顾名思义,输入数组是按变量一个一个进来的,所以输入端口in是变量,而移位之后的输出out则是一个向量。此处输出数组是从高到低定义的,故数组要左移,则要从倒数第二个高位到最低位的右侧再并上新数组即可,此处注意数组定义时的高低位,结合画图很容易判断数组片选下标以及新变量的添加位置。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY cjbc IS
GENERIC(n : natural :=8);
PORT(a,clk : IN STD_LOGIC;
q : OUT STD_LOGIC_VECTOR(n-1 DOWNTO 0));
END cjbc;
ARCHITECTURE behave OF cjbc IS
BEGIN
PROCESS(clk)
VARIABLE reg : STD_LOGIC_VECTOR(n-1 DOWNTO 0);
BEGIN
if rising_edge(clk) then
reg := reg(n-2 downto 0)&a;--左移
--reg:= a & reg(n-1 downto 1);--右移
END IF;
q<=reg;
END PROCESS;
END behave;
1.5.2 16位串入串出移位寄存器
串入串出说明输入、输出端口性质均为变量。此处使用元件COMPONENT和生成语句GENERATE的方法【非常常用】。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY diff_logic IS
PORT(d,clk : IN STD_LOGIC;
q :OUT STD_LOGIC);
END diff_logic;
ARCHITECTURE behave OF diff_logic IS
BEGIN
PROCESS(clk)
BEGIN
if(clk'event and clk='1') then q<=d;
END IF;
END PROCESS;
END behave;
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY shift_16 IS
PORT(a,clk : IN STD_LOGIC;
b : OUT STD_LOGIC);
END shift_16;
ARCHITECTURE behave OF shift_16 IS
COMPONENT diff_logic
PORT (d,clk : IN STD_LOGIC;
q : OUT STD_LOGIC);
END COMPONENT;
SIGNAL z:STD_LOGIC(0 TO 16);
BEGIN
z(0)<=a;
FOR i in 0 to 15 GENERATE
diffx : diff PORT MAP(z(i),clk,z(i+1));
END GENERATE;
b<=z(16);
END behave;
1.5.3 8位并进串出移位寄存器
输入端口并进为向量,输出端口串出为变量。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY bc IS
PORT(data_in : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
clk,load : IN STD-LOGIC;
data_out :OUT STD_LOGIC);
END bc;
ARCHITECTURE behave OF bc IS
SIGNAL q : STD_LOGIC_VECTOR (7 DOWNTO 0);
BEGIN
PROCESS(clk,load)
BEGIN
if load='1' then
q<=data_in;
data_out<='X';
elsif(clk'event and clk='1') then
for i in 1 to 7 loop
q(i)<=q(i-1);
END LOOP;
data_out<=q(7);
END IF;
END PROCESS;
END behave;
1.5.4 8位并进并出双向移位寄存器
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY rlshift IS
PORT(clr,lod,clk,s,dir,dil : IN BIT;
d : IN BIT_VECTOR(7 DOWNTO 0);
q : OUT BIT_VECTOR(7 DOWNTO 0));
END rlshift;
ARCHITECTURE behave OF rlshift IS
SIGNAL q_temp : BIT_VECTOR(7 DOWNTO 0);
BEGIN
PROCESS(clr,clk,lod,s,dir,dil)
BEGIN
IF clr='0' then q_temp<="00000000";
ELSIF(clk'event and clk='1') then
IF lod='1' then q_temp<=d;
ELSIF(s='1') then
FOR i in 7 downto 1 LOOP--实现右移操作
q_temp(i-1)<=q(i);
END LOOP;
q_temp(7)<=dir;
ELSE
FOR i in 0 to 6 LOOP--实现左移操作
q_temp(i-1)<=q(i);
END LOOP;
q_temp(0)<=dil;
END IF;
END IF;
q<=q_temp;
END PROCESS;
END behave;
1.6计数器
用“+”函数描述。此处‘+’是一个重载函数,需要调用IEEE.STD_LOGIC_UNSIGNED.ALL库。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY counter IS
GENERIC(n : natural :=4);
PORT(clk,reset: IN STD_LOGIC;
count : OUT STD_LOGIC_VECTOR(n-1 DOWNTO 0));
END counter;
ARCHITECTURE behave OF counter IS
BEGIN
PROCESS(clk,reset)
VARIABLE cnt : STD_LOGIC_VECTOR (n-1 DOWNTO 0);
BEGIN
if reset='1' then cnt := (others=>'0');
elsif rising_edge(clk) then cnt:=cnt+1;
END IF;
count<=cnt;
END PROCESS;
END behave;