【Verilog HDL 训练】第 04 天(竞争、冒险、译码等)
1. 什么是竞争和冒险?
记得我刚学FPGA那会,恶补基础知识,其中之一就是竞争与冒险,我参考了《FPGA之道》,记录了几篇博客:
第一篇博客中写道了单输入组合逻辑,如下:
这个例子最简单,却最能说明什么是竞争,以及由竞争导致的险象,也即冒险。
输入为A先于not(A)A非到达或门,因此,如果初始令A为1,则NOT(A)为0,之后A变为0,则由于A先到或门,导致有一小段零脉冲出现在输出中,这是非预期的。
波形图如下:
当然,没人会无聊到设计这样的一个电路,但这个电路能说明一些大问题,后面我们会看到,但输入组合逻辑会产生竞争现象也被用来说明问题。
上篇博文中就讲到了多输入组合逻辑,多输入组合逻辑可以按如下方式分析:
多个输入不同时变化:若多个输入变化的间隔比较大,那么可以将其分解为若干个时刻,每个时刻有“多个输入同时变化”,“仅有一个输入变化”,然后再独立分析各个时刻即可;若这些输入变化间隔较小,那么可以将其等效转化为“多个输入同时变化”的问题,因为我们可以将这些输入变化的时间差等效折合到传输路径中的线延迟中去。
多个输入同时变化:
如下图:在多输入组合电路中,有两个及以上个输入变量同时发生了变化,虽然从输入决定输出的理论出发,组合逻辑的输出应该直接变化到新输入对应的输出值,但是由于延迟的存在,现实中情况往往并非如此。
如果A和B同时由A=0、B=1变化到A= 1、B= 0,在理想的情况下输出应该一直为0,但是正是有了线延迟,出现了如下非预期险象:
出现了一个短暂的高电平脉冲,也就是毛刺,这就是竞争导致的险象。
仅有一个输入变化:
如下图:
B和C都是固定值,仅有A变化,属于仅有一个输入变化,但是请看到,A变化后紧接着两个与门的结果会变化,再到达或门,这又变成了有多个输入同时变化问题了。
这篇博文深度剖析了什么是竞争的问题,原书作者独创性地提出了半开关的概念:
门电路的开关特性
下面提到的开关,开代表接通状态,关闭代表断开状态。
非门可以看做一个常开的开关,因此任意一个输入到非门的信号都会被取反输出。
与门具有开关特性,因为它至少由两个输入端,假设有L个输入端,那么如果L-1个输入端置1,那么对于剩下的一个输入端而言,该与门就相当于一个打开的开关,输出取决于最后一个输入端上的值。
如果其中一个输入端为0,那么对于其他L-1个输入端而言,该与门就相当于一个关闭的开关,无论其他输入端是什么,输出总是0.
或门同理!
门电路的半开关特性
非门不具有半开关特性,因为只有一个输入端。
与门具有半开关特性:当且仅当与门中有两个或以上的输入端都是由组合逻辑中的一个输入电信号直接或间接驱动时,称该与门具有半开关性,因为此时,与门的其他输入端(如果有)对该与门仍具有开关性。因此,对于一个具有半开关性的N输入与门来说,它可以等效为一个M(M小于等于N)输入与门和开关的级联。
或门同理!
竞争的定义
如果在某一个时刻,从组合逻辑的某一个输入端到其输出端存在两条以上的电信号通路时,就称该组合逻辑在当前状态下针对这个输入端存在竞争。
对于下图:
该电路的或门就是一个半开关,那么就可能存在竞争,那什么时候存在竞争呢?且看下面的分析:
当 B = 1,C = 1时,对上图进行化简:
输入端A存在竞争。
当B = 0,C= 1时,如下:
可见,电路中没有半开关,不存在竞争。
当B,C都等于0时,化简后的电路输出恒为零,不存在竞争。
这篇博文介绍了什么是险象?
险象是由于竞争导致的非预期现象,但又有一个问题,竞争一定会产生险象吗?非也,那么什么样的竞争会产生险象呢?又如何规避险象呢?这都是这篇博文以及后面的博文所要剖析的!
2. 设计一个2-4译码器。
如果按照下图的话:
-
module Decoder_2_4(
-
input [1:0] data_in,
-
input enable,
-
output reg [3:0] data_out
-
);
-
-
always @(*) begin
-
if(enable)
-
case(data_in)
-
2'b00: data_out = 4'b0001;
-
2'b01: data_out = 4'b0010;
-
2'b10: data_out = 4'b0100;
-
2'b11: data_out = 4'b1000;
-
endcase
-
else begin
-
data_out = 4'b0000;
-
end
-
end
-
-
endmodule
综合出来的RTL原理图:
3. 输入一个8bit数,输出其中1的个数。如果只能使用1bit全加器,最少需要几个?
参考这篇文章:Count number of logic 1's in 7 bit number
给出的思路。我们打个草稿:
不妨写个Verilog代码,再行为仿真下,验证是否正确。
先用行为级描述方法写一个1位全加器模块:
-
`timescale 1ns / 1ps
-
//
-
// Company:
-
// Engineer:
-
//
-
// Create Date: 2019/04/26 12:23:21
-
// Design Name:
-
// Module Name: f_add
-
//
-
-
-
module f_add(
-
input a,
-
input b,
-
input ci,
-
output s,
-
output co
-
);
-
-
assign {co,s} = a + b + ci;
-
//assign s = (a ^ b) ^ ci;
-
-
//assign co = a & b + ci & ( a ^ b );
-
-
endmodule
在使用结构级描述方法来描述我们的顶层模块:
-
`timescale 1ns / 1ps
-
//
-
// Company:
-
// Engineer:
-
//
-
// Create Date: 2019/04/26 12:23:21
-
// Design Name:
-
// Module Name: count_1_hadd
-
//
-
//
-
-
-
module count_1_hadd(
-
input [7:0] data_in,
-
output [3:0] data_out
-
);
-
-
wire s0,c0,s1,c1,s2,c2,s3,c3,s4,c4,s5,c5,s6,c6;
-
f_add u_f_add0(
-
.a(data_in[0]),
-
.b(data_in[1]),
-
.ci(data_in[2]),
-
.s(s0),
-
.co(c0)
-
);
-
f_add u_f_add1(
-
.a(data_in[3]),
-
.b(data_in[4]),
-
.ci(data_in[5]),
-
.s(s1),
-
.co(c1)
-
);
-
-
f_add u_f_add2(
-
.a(s0),
-
.b(s1),
-
.ci(data_in[6]),
-
.s(s2),
-
.co(c2)
-
);
-
-
f_add u_f_add3(
-
.a(s2),
-
.b(data_in[7]),
-
.ci(0),
-
.s(s3),
-
.co(c3)
-
);
-
-
f_add u_f_add4(
-
.a(c0),
-
.b(c1),
-
.ci(c2),
-
.s(s4),
-
.co(c4)
-
);
-
-
f_add u_f_add5(
-
.a(s4),
-
.b(c3),
-
.ci(0),
-
.s(s5),
-
.co(c5)
-
);
-
-
f_add u_f_add6(
-
.a(c4),
-
.b(c5),
-
.ci(0),
-
.s(s6),
-
.co(c6)
-
);
-
-
assign data_out = {c6,s6,s5,s3};
-
-
-
-
-
-
-
endmodule
仿真文件:
-
`timescale 1ns / 1ps
-
//
-
// Company:
-
// Engineer:
-
//
-
// Create Date: 2019/04/26 13:17:28
-
// Design Name:
-
// Module Name: count_1_sim
-
// Project Name:
-
// Target Devices:
-
// Tool Versions:
-
// Description:
-
//
-
// Dependencies:
-
//
-
// Revision:
-
// Revision 0.01 - File Created
-
// Additional Comments:
-
//
-
//
-
-
-
module count_1_sim;
-
-
reg [7:0]data_in;
-
wire [3:0]data_out;
-
-
reg clk;
-
always begin
-
#1 clk = ~clk;
-
end
-
-
initial clk = 0;
-
-
initial begin
-
data_in = 8'b1101_1011;
-
#10
-
data_in = 8'b0011_1011;
-
end
-
-
count_1_hadd u1(
-
.data_in(data_in),
-
.data_out(data_out)
-
);
-
-
-
-
-
endmodule
仿真结果:
可见,输入11011011时,输入为6,也就是输入中有6个1的意思。
输入00111011时,输出为5,符合我们的预期。
再给出RTL 电路图:
其中1位全加器放大看:
可见,综合为两个半加器。
4. 如果一个标准单元库只有三个cell:2输入mux(o = s ?a :b;),TIEH(输出常数1),TIEL(输出常数0),如何实现以下功能?
4.1 反相器inv
4.2 缓冲器buffer
4.3 两输入与门and2
4.4 两输入或门or2
4.5 四输入的mux mux4
4.6 一位全加器 fa
简单给出思路吧:
反相器:
output = S ? TIEL : TIEH;
缓冲器:
output = S ? TIEH : TIEL;
两输入与门:
output = A ? B : TIEL;
两输入或门:
output = A? TIEH:B;
四输入MUX:
用下图的符号:
控制 | 选择的输出源 | |
A1 | A0 | Y |
0 | 0 | D0 |
0 | 1 | D1 |
1 | 0 | D2 |
1 | 1 | D3 |
则这样设计为佳:
output = A1 ? ( A0 ? D3 : D2 ) : ( A0 ? D1 : D0 );
一位全加器:
一位全加器的表达式如下:
Si=Ai⊕Bi⊕Ci-1
第二个表达式也可用一个异或门来代替或门对其中两个输入信号进行求和:
从表达式来分析,倒不如先看看如何使用mux2来做异或门吧。
Ai和Bi之间的异或可以表达如下:
-
out1 = Ai ? (Bi ? TIEL:TIEH) : (Bi ? TIEH:TIEL)
-
那么可知:
Si 等于 out1和Ci-1之间的异或了,故:
-
Si = out1 ? (Ci-1 ? TIEL:TIEH) : (Ci-1 ? TIEH:TIEL)
-
= (Ai ? (Bi ? TIEL:TIEH) : (Bi ? TIEH:TIEL)) ? (Ci-1 ? TIEL:TIEH) : (Ci-1 ? TIEH:TIEL)
最后就是进位Ci了:
-
out1为Ai与Bi:
-
-
out1 = Ai ? Bi : TIEL;
-
-
out2为:Ai与Bi的异或:
-
-
out2 = Ai ? (Bi ? TIEL:TIEH) : (Bi ? TIEH:TIEL)
-
-
out3为Ci-1与out2 :
-
-
out3 = Ci-1 ? out2 : TIEL;
-
-
out4 为out1或out3,也就是Ci:
-
-
out4 = out1 ? TIEH:out3
-
-
分别代入:
-
-
Ci = (Ai ? Bi : TIEL)? TIEH : (Ci-1 ? ( Ai ? (Bi ? TIEL:TIEH) : (Bi ? TIEH:TIEL)) : TIEL)
仅仅通过仿真验证最后一个最难的:
-
`timescale 1ns / 1ps
-
//
-
// Company:
-
// Engineer:
-
//
-
// Create Date: 2019/04/26 14:25:58
-
// Design Name:
-
// Module Name: f_add1
-
// Project Name:
-
// Target Devices:
-
// Tool Versions:
-
// Description:
-
//
-
// Dependencies:
-
//
-
// Revision:
-
// Revision 0.01 - File Created
-
// Additional Comments:
-
//
-
//
-
-
-
module f_add1(
-
input A,
-
input B,
-
input Ci,
-
output S,
-
output Co
-
);
-
-
localparam TIEH = 1, TIEL = 0;
-
-
assign S = ( A ? ( B ? TIEL : TIEH ) : ( B ? TIEH : TIEL ) ) ? ( Ci ? TIEL : TIEH ) : ( Ci ? TIEH : TIEL );
-
assign Co = ( A ? B : TIEL ) ? TIEH : ( Ci ? ( A ? ( B ? TIEL : TIEH ) : ( B ? TIEH : TIEL ) ) : TIEL );
-
-
/*
-
//out1 = A & B
-
wire out1;
-
mux2 u_0(
-
.s(A),
-
.a(B),
-
.b(TIEL),
-
.out_mux2(out1)
-
);
-
-
//out2 = a ^ b;
-
-
wire out2,mid1,mid2;
-
mux2 u_11(
-
.s(B),
-
.a(TIEL),
-
.b(TIEH),
-
.out_mux2(mid1)
-
);
-
mux2 u_12(
-
.s(B),
-
.a(TIEH),
-
.b(TIEL),
-
.out_mux2(mid2)
-
);
-
mux2 u_1(
-
.s(A),
-
.a(mid1),
-
.b(mid2),
-
.out_mux2(out2)
-
);
-
-
//out3 = out2 & Ci
-
wire out3;
-
mux2 u_2(
-
.s(Ci),
-
.a(out2),
-
.b(TIEL),
-
.out_mux2(out3)
-
);
-
-
mux2 u_3(
-
.s(out1),
-
.a(TIEH),
-
.b(out3),
-
.out_mux2(Co)
-
);
-
-
//下面求S
-
//out2 = a ^ b;
-
-
wire mid3,mid4;
-
mux2 u_41(
-
.s(out2),
-
.a(TIEL),
-
.b(TIEH),
-
.out_mux2(mid3)
-
);
-
mux2 u_42(
-
.s(out2),
-
.a(TIEH),
-
.b(TIEL),
-
.out_mux2(mid4)
-
);
-
mux2 u_4(
-
.s(Ci),
-
.a(mid3),
-
.b(mid4),
-
.out_mux2(S)
-
);*/
-
-
-
-
-
endmodule
仿真文件:
-
`timescale 1ns / 1ps
-
//
-
// Company:
-
// Engineer:
-
//
-
// Create Date: 2019/04/26 14:42:41
-
// Design Name:
-
// Module Name: f_add_sim
-
// Project Name:
-
// Target Devices:
-
// Tool Versions:
-
// Description:
-
//
-
// Dependencies:
-
//
-
// Revision:
-
// Revision 0.01 - File Created
-
// Additional Comments:
-
//
-
//
-
-
-
module f_add_sim(
-
-
);
-
-
reg A;
-
reg B;
-
reg Ci;
-
wire S;
-
wire Co;
-
-
reg clk;
-
-
always begin
-
#1 clk = ~clk;
-
end
-
-
initial clk = 0;
-
-
initial begin
-
A = 1;
-
B = 0;
-
Ci = 1;
-
# 10
-
A = 0;
-
B = 1;
-
Ci = 0;
-
-
-
end
-
-
f_add1 u00(
-
.A(A),
-
.B(B),
-
.Ci(Ci),
-
.S(S),
-
.Co(Co)
-
);
-
-
-
-
endmodule
仿真结果:
可见功能符合预期。
RTL图如下:可见,这个一位全加器都是由mux2构成的呀。
文章来源: reborn.blog.csdn.net,作者:李锐博恩,版权归原作者所有,如需转载,请联系作者。
原文链接:reborn.blog.csdn.net/article/details/89518120
- 点赞
- 收藏
- 关注作者
评论(0)