FPGA逻辑设计回顾(3)多比特信号上升沿检测的设计方式与陷阱?
前言
在总结本文最后的多比特上升沿检测之前,我们先把备用知识讲清楚,摊开来,以免造成模糊不清的默许!
逻辑运算符与位元运算符
从表面上来看,逻辑运算符与位元运算符之间的区别就是一个符号写法的问题,例如:&&,&,||,|,!,~
事实上,我们应该真正的从含义上理解它们:
- 所谓的逻辑运算符就是逻辑上的运算,那它的结果也就是真和假之分,即false and true,或者1'b1 and 1'b0,它是1比特的布尔值。
- 而位元运算,其实就是单比特之间的逻辑运算而已,多比特的话就按位进行逻辑运算,例如按位与(&),按位或(|)以及按位非(~)。
有关这方面的语法,我以前有很多博客,例如:
Verilog中的逻辑运算符与按位运算符的区分
或者之前的专栏:
数字设计基础教程
由于逻辑运算符与位元运算符之间的区别在此,但这也仅仅是针对多比特信号才有的区别,对于单比特信号,其实结果是一样的,我们认为都行。
下面给出几组测试,来区分逻辑运算符以及位元运算符之间的区别:
下面给出仿真:
可见,逻辑运算符得到的结果总是1bit的,而位元运算符得到的结果和原输入数据位数一致,这和我们的认识也是相符合的。
下面给出上述设计以及仿真对应的RTL代码:
RTL设计代码:
module bitwise_test(
input [3:0] in1,
input [3:0] in2,
output [3:0] out_bitwise_and,
output [3:0] out_bitwise_or,
output [3:0] out_bitwise_not,
output out_logic_and,
output out_logic_or,
output out_logic_not
);
assign out_bitwise_and = in1 & in2 ;
assign out_logic_and = in1 && in2 ;
assign out_bitwise_or = in1 | in2 ;
assign out_logic_or = in1 || in2 ;
assign out_bitwise_not = ~in1 ;
assign out_logic_not = !in1 ;
endmodule
Testbench代码:
module sim_bitwise_test(
);
reg [3:0] in1 ;
reg [3:0] in2 ;
wire [3:0] out_bitwise_and ;
wire [3:0] out_bitwise_or ;
wire [3:0] out_bitwise_not ;
wire out_logic_and ;
wire out_logic_or ;
wire out_logic_not ;
initial begin
in1 = 4'b1001;
in2 = 4'b1100;
#5
in1 = 4'b1000;
in2 = 4'b1101;
end
bitwise_test u_bitwise_test(
.in1 ( in1 ),
.in2 ( in2 ),
.out_bitwise_and ( out_bitwise_and ),
.out_bitwise_or ( out_bitwise_or ),
.out_bitwise_not ( out_bitwise_not ),
.out_logic_and ( out_logic_and ),
.out_logic_or ( out_logic_or ),
.out_logic_not ( out_logic_not )
);
endmodule
其实说起位元运算符以及逻辑运算符,在硬件描述语言中,还要一种不得不谈起,这几者算是同宗兄弟,只是完成者不同的使命,那便是缩位运算符:
其运算方式也十分简单,例如:
-
&a [3:0] // AND:a [3]&a [2]&a [1]&a [0]
-
| b [3:0] //或:b [3] | b [2] | b [1] | b [0]。 相当于(b [3:0]!= 4'h0)
-
^ c [2:0] // XOR:c [2] ^ c [1] ^ c [0]
具体看我的其他博文吧,这里就不细讲了。
单比特信号上升沿检测
对于一个bit信号的上升沿检测,十分容易理解,实现方式也只有一种,那就是延迟,再逻辑运算,打拍得到结果。
例如,如下RTL原理图可以很清楚的说明问题:
RTL原理图:
下面是对上述电路的仿真:
仿真波形:
对于上升沿检测,我们需要注意的是:FPGA设计心得(10)关于行为仿真的一点观点
我的观点只有一个,那就是我们在行为仿真的时候不要在正正好好时钟边沿处给数据,这是由于仿真工具对边沿处数据的不同处理方式,可能会导致得不到你想要的结果。具体还是看上面的链接吧,这里不再重提了。
下面附上上述设计以及仿真的RTL代码:
RTL设计:
module pos_detect(
input wire clk ,
input wire rst ,
input wire in_a ,
output reg in_pos
);
reg reg_in_a ;
always@(posedge clk or posedge rst) begin
if(rst) begin
reg_in_a <= 1'b0 ;
end
else begin
reg_in_a <= in_a ;
end
end
always@(posedge clk or posedge rst) begin
if(rst) begin
in_pos <= 1'b0 ;
end
else begin
in_pos <= ~reg_in_a && in_a ;
end
end
endmodule
Testbench仿真:
module pos_detect_tb(
);
reg clk ;
reg rst ;
reg in_a ;
wire in_pos ;
always begin
# 2 clk = ~clk;
end
initial begin
clk = 1'b0;
rst = 1'b1;
in_a = 1'b0;
#10
rst = 1'b0;
#20
in_a = #(0.1) 1'b1;
#20
in_a = #(0.1) 1'b0;
end
pos_detect u_pos_detect(
.clk ( clk ),
.rst ( rst ),
.in_a ( in_a ),
.in_pos ( in_pos )
);
endmodule
多比特信号上升沿检测
对于多比特上升沿的检测,就要区分使用使用逻辑运算符和位元运算符了,如果用错了的话,肯定得不到想要的结果,这也就是所谓的小陷阱吧,专坑基础不牢或者马马虎虎的人。
除此之外,还有对于对比特的设计方式有如下几种,设计到for循环的使用,generate for循环的使用以及正常用法。
对于for循环以及generate for循环的含义,我在过去的博客上也多次写过,例如:
HDLBits 系列(7)对for循环以及generate for的各种实践
这篇文章对于generate for的使用提到一句比较关键的话就是generate for内部的语句要有一个名字:它的含义就是讲一个模块多次使用,形成多个模块的效果,属于并行的效果;可具体见博文,体会含义。
例如,使用generate for对全加器的多次例化,得到的文件结构是这样的:
相应的RTL原理图也如此:
使用三种方式对同一逻辑进行实现,部分RTL设计如下:
使用generate for形式:
genvar j;
generate
for(j = 0; j <= 3; j = j + 1) begin
always@(posedge clk or posedge rst) begin:pos_detect3
if(rst) begin
reg_in3[j] <= 1'b0;
out_pos3[j] <= 1'b0;
end
else begin
reg_in3[j] <= in1[j];
out_pos3[j] <= ~reg_in3[j] & in1[j];
end
end
end
至于使用for语句:
always@(posedge clk or posedge rst) begin : pos_detect1
if(rst) begin
reg_in1 <= 4'h0;
out_pos1 <= 4'b0;
end
else begin
for(i = 0; i <= 3; i = i + 1) begin : bits_pos_
reg_in1[i] <= in1[i] ;
out_pos1[i] <= ~reg_in1[i] & in1[i] ;
end
end
end
以及普通的实现方式:
always@ (posedge clk or posedge rst) begin : pos_detect2
if(rst) begin
reg_in2 <= 4'b0;
out_pos2 <= 4'b0;
end
else begin
reg_in2 <= in1;
out_pos2 <= ~reg_in2 & in1;
end
end
也能实现同样的功能,例如对其仿真示意图一致:
生成的RTL原理图虽略有差异:
但本质上还是一致的,且看综合示意图:
可见综合出来的结果,三者的结果采样了同一个中间过程,也就是最终在FPGA上的实现方式完全一致。
再给出implementation后的结果:
不用多想,结果也是一致的,虽然第2级触发器分开使用了不同的触发器,那是因为要分配给不同的输出,同时输出而非分时输出,也在意料之内,结构一致。
最终在FPGA中实现的电路也是这样的,实现是最接近底层的一级。
下面给出上述设计以及仿真的代码:
module bits_pos_detect(
input wire clk,
input wire rst,
input wire [3:0] in1,
output reg [3:0] out_pos1,
output reg [3:0] out_pos2,
output reg [3:0] out_pos3
);
reg [3:0] reg_in1 ;
reg [3:0] reg_in2 ;
reg [3:0] reg_in3 ;
integer i ;
always@(posedge clk or posedge rst) begin : pos_detect1
if(rst) begin
reg_in1 <= 4'h0;
out_pos1 <= 4'b0;
end
else begin
for(i = 0; i <= 3; i = i + 1) begin : bits_pos_
reg_in1[i] <= in1[i] ;
out_pos1[i] <= ~reg_in1[i] & in1[i] ;
end
end
end
always@ (posedge clk or posedge rst) begin : pos_detect2
if(rst) begin
reg_in2 <= 4'b0;
out_pos2 <= 4'b0;
end
else begin
reg_in2 <= in1;
out_pos2 <= ~reg_in2 & in1;
end
end
genvar j;
generate
for(j = 0; j <= 3; j = j + 1) begin
always@(posedge clk or posedge rst) begin:pos_detect3
if(rst) begin
reg_in3[j] <= 1'b0;
out_pos3[j] <= 1'b0;
end
else begin
reg_in3[j] <= in1[j];
out_pos3[j] <= ~reg_in3[j] & in1[j];
end
end
end
endgenerate
endmodule
测试平台:
module bits_pos_detect_tb(
);
reg clk;
reg rst;
reg [3:0] in1;
wire [3:0] out_pos1;
wire [3:0] out_pos2;
wire [3:0] out_pos3;
initial begin
clk = 0;
forever begin
#5 clk = ~clk;
end
end
initial begin
rst = 1;
in1 = 4'h0;
#18
rst = 0;
in1 = #(0.5) 4'b1011;
#20
in1 = #(0.5) 4'b0000;
#18
in1 = #(0.5) 4'b1101;
#20
in1 = #(0.5) 4'b1001;
#18
in1 = #(0.5) 4'b1010;
end
bits_pos_detect u_bits_pos_detect(
.clk ( clk ),
.rst ( rst ),
.in1 ( in1 ),
.out_pos1 ( out_pos1 ),
.out_pos2 ( out_pos2 ),
.out_pos3 ( out_pos3 )
);
endmodule
- 分享
- 举报
-
浏览量:8485次2021-01-09 02:07:52
-
浏览量:10625次2021-01-17 00:16:33
-
浏览量:12163次2021-01-02 00:02:19
-
浏览量:6832次2021-01-23 18:45:14
-
浏览量:13143次2021-01-01 02:53:29
-
浏览量:6877次2021-01-31 01:07:50
-
浏览量:2432次2022-05-30 11:53:09
-
浏览量:5691次2021-01-31 04:24:47
-
浏览量:10373次2020-12-13 19:59:59
-
浏览量:18994次2020-12-06 18:59:36
-
浏览量:6953次2021-01-30 23:18:56
-
浏览量:8015次2021-02-06 22:29:19
-
浏览量:6571次2021-03-14 02:34:44
-
浏览量:6863次2021-03-15 23:18:36
-
浏览量:6172次2021-01-30 01:09:16
-
浏览量:5643次2021-04-27 00:06:35
-
浏览量:5371次2021-03-17 23:24:53
-
浏览量:4809次2021-03-18 22:57:24
-
浏览量:3798次2022-09-01 09:55:19
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
李锐博恩
感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明
感谢分享