本系列内容来自于知乎专栏,链接如下:https://zhuanlan.zhihu.com/c_1131528588117385216 本系列文章将和读者一起巡礼数字逻辑在线学习网站 HDLBits 的教程与习题,并附上解答和一些作者个人的理解,相信无论是想 7 分钟精通 Verilog,还是对 Verilog 和数电知识查漏补缺的同学,都能从中有所收获。
Problem 95 Detect both edges
牛刀小试
在一个8bit的变量中,从一个周期到另一个周期期间,检测输入信号变化。即上升沿变化或下降沿变化。输出应在0变为1后产生。
如下图所示为输入与输出的时序关系
解答与解析
本题需要大家来检测信号上升沿或下降沿的变化。在Problem94中我们是用 & 来检测信号的上升沿,但在本题总我们可以采取 xor 的形式来检测。
代码语言:javascript复制module top_module (
input clk,
input [7:0] in,
output reg [7:0] anyedge
);
reg [7:0] in_temp;
always @ (posedge clk)
begin
in_temp <= in;
anyedge <= in ^ in_temp;
end
endmodule
Problem 96 Edge capture register
牛刀小试
对于32bit中的每一个变量,我们需要捕获输入信号的上升沿。其中捕获的意思就是说在寄存器复位之前,输出一直保持为 ‘1’ 。
每一个输出bit类似SR触发器:输出信号从1变0发生时会保持一个周期。输出会在时钟上升沿和reset信号为高时复位。如果上述事件在同一时间发生,reset有更高的优先级。在下图所示的最后4个周期内,reset信号比set信号早一个周期,所以没有冲突发生。
解答与解析
本题就是需要我们在检测到输入信号的上升沿后,输出信号在复位之前保持为'1'。类似Problem94.
代码语言:javascript复制module top_module (
input clk,
input reset,
input [31:0] in,
output [31:0] out
);
reg [31:0] temp;
wire [31:0] capture;
//同理,我们先检测输入信号的上升沿。
always @ (posedge clk)
begin
temp <= in;
end
//这里如果采用reg的话会出现时序错误。
assign capture = ~in & temp;
//检测到上升沿之后,来确定我们的输出
always @ (posedge clk)
begin
if(reset)
out <= 32'b0;
else
begin
for (int i=0; i<32; i=i 1)
begin
if(capture[i] == 1'b1)
out[i] <= 1'b1;
end
end
end
endmodule
Probelm 97 Dual-edge triggered flip-flop
我们现在对时钟上升沿与下降沿都已经很熟悉了。但是FPGA没有一个同时检测双边沿的触发器,而且always中的敏感列表也不支持(posedge clk or negedge clk)。
牛刀小试
设计一个双边沿检测的触发器,时序如下图所示:
在本题中主要考察的是电路设计,而非verilog代码的能力。
解答与解析
本题有两中解题思路,一种是用MUX,一种是用XOR
MUX代码如下:
代码语言:javascript复制module top_module (
input clk,
input d,
output q
);
reg q1, q2;
//这里来实现clk的上升沿与下降沿
assign q = clk?q1:q2;
always @ (posedge clk)
begin
q1 <= d;
end
always @ (negedge clk)
begin
q2 <= d;
end
endmodule
XOR代码如下:
代码语言:javascript复制module top_module(
input clk,
input d,
output q);
reg p, n;
// clk的上升沿
always @(posedge clk)
p <= d ^ n;
// clk的下降沿
always @(negedge clk)
n <= d ^ p;
//在上升沿时候,p=d^n, 则q=d^n^n=d;
//在下降沿时候,n=d^p, 则q=p^d^p=d;
//加载一个新值时会取消旧值。
assign q = p ^ n;
// 这样写是无法综合的
/*always @(posedge clk, negedge clk) begin
q <= d;
end*/
endmodule
Problem 98 Four-bit binary counter
设计一个4bit的计数器,从0~15,共16个周期。reset是同步复位且复位为0。
解答与解析
代码语言:javascript复制module top_module (
input clk,
input reset, // Synchronous active-high reset
output reg [3:0] q);
always @ (posedge clk)
begin
if(reset)
q <= 4'b0000;
else
q <= q 1'b1;
end
endmodule
Problem 99 Decade counter
同样是4bit计数器,上一题是0~15, 本题我们只计算到0~9。还是同步复位且复位为0。时序图如下:
解答与解析
与上图不同就是限制条件不一样了而已。
代码语言:javascript复制module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:0] q);
always @ (posedge clk)
begin
if(reset)
q <= 4'b0000;
else if(q <= 4'b1000)
q <= q 1'b1;
else
q <= 4'b0000;
end
endmodule