同步和异步
概述
- 在数字电路中经常有同步\异步的概念,异步输入指的是输入信号和时钟无关,同步指的是输入信号和时钟信号有关
- 实际开发中,经常有同步清0,经常有同步清0,异步清0,同步复位,异步复位等概念
- 异步电路:异步电路主要是组合逻辑电路,其逻辑输出与任何时钟信号都没有关系
// 时钟信号不会影响组合逻辑
always@(clk,a,c) begin
b = a + c;
end
- 同步电路:同步电路是由时序电路(寄存器和各种触发器)和组合逻辑电路构成的电路,其所有操作都在严格的时钟控制下完成的,这些时序电路共享同一个时钟clk,而所有的变化都在时钟的上升沿或者下降沿
always @(posedge clk)
if(!resetn) b <= 1'b0;
else b<=a;
同步复位\同步置数\同步清0
- 同步复位\同步置位\同步清0都是同步电路的一种特殊"电路动作"
- 同步复位(rst):复位信号只有在时钟上升沿来时才检测复位信号是否有效
- 同步置数(load):置数信号只有在时钟上升沿来时才能生效
- 同步清0(clr):清0信号只有在时钟上升沿到来时才有效
一般情况下,rst信号是优先级最高的信号,当时钟上升沿来临后,如果复位信号有效,则执行复位操作
异步复位\异步置数\异步清零
- 异步复位\异步置数\异步清零不受时钟信号clk的控制,只要异步信号有效,则执行
- 异步复位(rst):复位信号只要有效,则执行复位动作
- 异步置数(load):置数信号只要有效,则执行置数动作
- 异步清0:清零信号只要有效,则执行清0动作
- 一般情况下,清0信号是最高等级的信号,如果复位信号有效,则执行复位操作
注意:同步复位信号rst必须至少长于一个时钟周期clk,否则,这个信号引起的变化是不会被检测到的!
同步释放
- 释放:复位信号从有效变为无效
- 同步释放:复位信号到来的时候,不受时钟信号的同步,而是在复位信号释放的时候受到时钟信号的同步(异步复位,同步释放)
- 异步释放:没有异步释放,复位信号从有效到无效,必须等到时钟上升沿来临才能触发always块
- 异步复位信号在释放的时候(撤销复位信号),刚好发生在时钟有效沿附近,就容易使寄存器输出出现亚稳态;复位信号从低变高的时候,恰好在时钟有效沿,那么时钟有效沿采到的复位信号是不确定的,所以导致输出信号是不确定的
- 为了避免异步复位出现亚稳态,同时发挥异步复位的优点,弥补它的缺点,一般采用异步复位,同步释放的方式(采用两个寄存器)
module asr_rstn(clk,rst_i);
input clk,rst_i;
reg rst_d1,rst_d2
always@(posedge clk or negedge rst_i) begin
if(!rst_i) begin
rst_d1 <= 0;
rst_d2 <= 0;
end
else begin
rst_d1 <= 1'b1;
rst_d2 <= rst_d1;
end
end
assign rst_o = rst_d2;
endmodule
- 将复位信号进行打拍处理,是为了防止出现亚稳态
- 正常情况下,复位信号初始为低电平有效,当复位信号拉高之后,需要在上升沿将输入信号给到输出信号
- 异步复位的时候,复位信号从高电平变为低电平的时候,从此刻开始复位信号有效,输出信号在此时进行复位,与时钟没有关系
同步清0/异步清0
// 同步清0
module dff(d,clk,clr,q);
input d,clk,clr;
output q;
reg q;
always@(posedge clk) begin
if(!clr) q<= 0;
else q <= d;
end
endmodule
// 异步清0
module dff(d,clk,clr,q);
input d,clk,clr;
output q;
reg q;
always@(posedge clk or negedge clr) begin
if(!clr) q<= 0;
else q <= d;
end
endmodule
- 同步复位和异步复位的主要区别在于前者的任何复位信号都不能出现在always语句的敏感列表中,无论是同步复位还是异步复位,always语句的结构都是先考虑复位信号有效的时候执行的语句,再考虑复位信号无效的时候的语句,否则综合工具将不能正确的综合
例题
always@(posedge A or negedge B) begin
if(A)
C <= 1'b0;
else
C <= D;
end
- 这是一个带有异步复位的触发器
- 同步复位是复位在时钟沿进行,和时序逻辑使用的是一个信号沿(一般为时钟沿);异步复位是复位自己的信号沿,不在时钟复位沿(也就是时钟沿对复位没有作用),这里A就相当于复位信号(相当于平时的rst),只是在它的上升沿复位,这里的B就相当于平时的时钟,在它的上升沿进行时序逻辑跳转
循环语句 - while
- 有条件地执行一条或者多条语句
- 首先判断循环执行条件表达式是否为真,如果为真执行循环体
- 注意循环变量必须改变,防止死循环
while()
begin
end
- wile语句只有当循环块有事件控制(即@(posedge clk)时)才可以被综合
// 对一个8bit二进制数中值为1的位进行计数
module count1s_while(
input [7:0] rega,
input clk,
output reg [3:0] count // 计数变量
);
always@(posedge clk) begin
reg[7:0] tempreg;
count = 0;
tempreg = rega;
while(tempreg)
begin
if(tempreg[0]) count = count + 1;
tempreg = tempreg >> 1; // 右移一位
end
end
endmodule
// 使用for循环,组合逻辑实现
module count1s_while(
input [7:0] rega,
output reg [3:0] count // 计数变量
);
always@(*) begin
integer ;
count = 0;
for(i = 0;i<=7;i=i+1) begin
if(rega[i] == 1) count = count + 1;
else count = count;
end
end
endmodule
forever循环语句
- 无条件执行后面的语句
forever begin
end
- 不能独立写在程序中,一般用在initial语句块中
- 通常用于产生时钟周期
- 常用disable跳出循环
initial begin
clk = 0;
forever #10 clk = !clk;
end
例题
用for循环描述11人的投票表决器,如果超过6人,投赞成票,表示通过
module vote11 (
input [10:0] votek, // 11人的投票编码,每一位表示一个人的投票数
output reg pass
);
reg [3:0] count;
integer i;
always @(*) begin
count = 0;
for(i = 0;i<11;i = i+1) begin
if(vote[i] == 1) count = count + 1;
end
if(count[3]|(count[2]&count[1])) pass = 1;
else pass = 0;
end
endmodule