【IC每日一题】
IC每日一题
- 1:锁存器(latch)、触发器(flip-flop)、寄存器的概念及区别
- 1.1 概念
- 1.2 锁存器的危害
- 1.3 如何避免产生锁存器
- 2 手撕题:边沿检测
- 2.1 边沿检测(上升沿、下降沿、双边沿)
- 2.1.1 波形图
- 2.1.2 算法步骤
- 2.1.3 代码
- 2.2 序列模三检测器
- 2.2.1 描述
- 2.2.2 波形图
- 2.2.3 代码
本文主要介绍:锁存器/寄存器概念以及锁存器的危害和避免方法、边沿检测和序列模三检测;
1:锁存器(latch)、触发器(flip-flop)、寄存器的概念及区别
1.1 概念
锁存器latch:锁存器是电平出发的存储单元,数据存储的动作(状态转换)取决于输入(或使能)的信号的电平值,仅当锁存器处于使能状态时,输出才会随着数据输入发生变化;
常见的锁存器包括三个端口:数据输入口、数据输出口、使能端。当使能端为高电平时,输入口的数据直接送到输出口,此时输入输出口可以看成是直接连通的;当使能端为低电平时,输出口的数据保持之前的数据不变,无论输入口的数据怎么变化,输出都保持不变,就是把原来的状态锁存下来了(所以才叫锁存器)。
触发器(flip-flop):触发器是边沿敏感的存储单元,数据存储的动作(状态转换)只在时钟的上升沿或下降沿的到来发生;
锁存器和触发器是底层具体的物理单元
寄存器(register):是用于暂时存放参与运算的数据和运算结果值。具体来说:在实际的数字系统中,通常把能够用来存储一组二进制代码的同步时序逻辑电路称为寄存器。寄存器常用触发器来构建;一个触发器能够存储一位二进制码,因此N个触发器的时钟端口连接起来能构成存储N位二进制的寄存器;
从寄存功能角度看:寄存器和锁存器的功能是相同的;
锁存器和寄存器区别:锁存器是电平触发,而触发器(寄存器)是clk边沿触发。锁存器在不锁存数据时,输出随输入变化;但一旦数据锁存时,输入对输出不产生任何影响。在设计中,基本是要绝对的避免综合产生锁存器
1.2 锁存器的危害
1.对毛刺敏感:使能信号有效时,输出状态随输入多次变化,容易产生空翻,不能异步复位;在上电后处于不确定状态;
2.STA静态时序分析复杂:锁存器没有时钟参与,无法做STA,综合工具会将latch优化掉,造成前仿后仿结果不一致,因此静态时序分析困难;
3.资源消耗:在FPGA中,由于FPGA是由查找表和触发器组成的,生成锁存器需要消耗更多资源;但是在IC中,若是锁存器和寄存器都是由与非门搭建的话,锁存器消耗资源更少;在ASIC设计中,除了CPU(高速电路)或者RAM(面积敏感)这类电路,一般绝不提倡使用锁存器;
1.3 如何避免产生锁存器
1.组合逻辑:若是组合逻辑,组合逻辑的语句完全不适用always语句块,就可以保证综合器不会综合出锁存器;
2.基于always语句块(类wire型和真reg型):信号必须要求是reg型,但是综合后是否是reg型还是latch型,是不一定的;
不可简单看if-else,缺少else; case-default,缺少default;
Vivado综合电路
修改如下,避免产生latch:
可以把右边形式的称为"类wire"形;类wire型
–类wire型:要想避免产生latch,就一定要避免“自己等于自己”这种情况;
–真reg型:即使if没有else,case没有default,也是不会产生latch;在else缺失的情况下,寄存器的值保持不变,相当于缺省"q<=q",reg是不怕自己等于自己的;
所以下面这种情况也会产生latch;
always @(*) begin
if(~enable) begin
out1 = 1'b0;
end else begin
out1 = out1;
end
end
总结:无论是真reg型还是wire型,都心里有意识:if-else,case-default都要写全,这也是一个良好的代码意识,但同时也意识到当review别人代码时,缺省也是对的
组合逻辑中,不完整的 if - else 结构及case-default,会产生 latch
2 手撕题:边沿检测
2.1 边沿检测(上升沿、下降沿、双边沿)
2.1.1 波形图
2.1.2 算法步骤
边沿检测的核心思想是“打拍子+逻辑运算”;
上升沿检测:din & ~din_r
下降沿检测:din_r & ~din;
双边沿检测:上面两个做或运算;
2.1.3 代码
//=======================================
//--Author : colonel
//--Date :11—29
//--Module : edge_check
//--Function: check a edge including: posedge,negedge,both clk
//=======================================
module edge_check (
//==========================< 端口 >=========================
input wire clk,
input wire rst_n,
input wire din,
output wire edge_pos,
output wire edge_neg,
output wire edge_both
);
//==========================< 信号 >=========================
reg din_r;
//=========================================================
//-- din_r: flip_flop
//=========================================================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
din_r <= 1'b0;
end else begin
din_r <= din;
end
end
//=========================================================
//-- edge_pos,edge_neg,edge_both
//=========================================================
assign edge_pos = din & ~din_r;
assign edge_neg = ~din & din_r;
assign edge_both= edge_pos | edge_neg;
endmodule
2.2 序列模三检测器
2.2.1 描述
描述:输入口是1bit,每次进来一位数据,检查当前序列是否能整除3,能则输出1,否则输出0.
例如:
序列=1,out=0;
序列=11,out=1;
序列=110,out=1;
序列=1101,out=0;
输入表:
2.2.2 波形图
2.2.3 代码
//=======================================
//--Author : colonel
//--Date :11—29
//--Module : sequence_modulo3_detector
//--Function: Detect if the input signal sequence din is a multiple of 3
//=======================================
module seq_mod3_detec(
//==========================< 端口 >=========================
input wire clk,
input wire rst_n,
input wire din_vld,
input wire din,
output wire detect
);
//==========================< 参数 >=========================
localparam IDLE = 3'b000;
localparam S0 = 3'b001;
localparam S1 = 3'b010;
localparam S2 = 3'b100;
//==========================< 信号 >=========================
reg[4-1:0] sta_cur;
reg[4-1:0] sta_nxt;
//=========================================================
//-- FSM-1: state transiate
//=========================================================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
sta_cur <= IDLE;
end else begin
sta_cur <= sta_nxt;
end
end
//=========================================================
//-- FSM-2: state jump condition
//=========================================================
always @(*) begin
case (sta_cur)
IDLE: begin
if(!din_vld) begin
sta_nxt = IDLE;
end else begin
if(din) begin
sta_nxt = S0;
end else begin
sta_nxt = S1;
end
end
end
S0: begin
if(!din_vld) begin
sta_nxt = S0;
end else begin
if (din) begin
sta_nxt = S1;
end else begin
sta_nxt = S0;
end
end
end
S1 : begin
if(!din_vld) begin
sta_nxt = S1;
end else begin
if(din) begin
sta_nxt = S0;
end else begin
sta_nxt = S2;
end
end
end
S2: begin
if(!din_vld) begin
sta_nxt = IDLE;
end else begin
if(din) begin
sta_nxt = S2;
end else begin
sta_nxt = S1;
end
end
end
default: sta_nxt = IDLE;
endcase
end
//=========================================================
//-- FSM-3: state action
//=========================================================
reg mod3_res;
always @(posedge clk) begin
if(!rst_n)begin
mod3_res <= 1'b0;
end else begin
case (sta_cur)
IDLE: mod3_res <= 1'b0;
S0: mod3_res <= 1'b1;
S1: mod3_res <= 1'b0;
S2: mod3_res <= 1'b0;
default: mod3_res <= 1'b0;
endcase
end
end
//=========================================================
//-- detect
//=========================================================
assign detect = mod3_res;
endmodule
注意:以上代码已经过编译无error,但未经过testcase测试
[ref]
1.https://blog.csdn.net/aa666888io89/article/details/119646663
2.https://www.runoob.com/w3cnote/verilog-latch.html
3.https://blog.csdn.net/qq_42622433/article/details/138186418