(10)HDLBits-Circuits-Sequential Logic-Latches and Flip-Flops

Dff

一、题目要求
D触发器是一种存储位并在时钟信号的正边缘(通常)定期更新的电路。D触发器是由逻辑合成器在使用时钟的always块时创建的(参见alwaysblock2)。D触发器是“组合逻辑的blob后面跟着一个触发器”的最简单形式,其中组合逻辑部分只是一根导线。创建一个D触发器。触发器电路图如下

在这里插入图片描述

二、分析

D触发器是时序逻辑电路,电路的状态在时钟信号的上升沿(时钟信号从0到1的时刻)时,输出随着输入变化。时序逻辑电路的新的输出(次态)不仅和输入状态有关,还与上一个输出的状态(初态)有关。在没有有效输入的时候,D触发器的输出保持为初态不变,当有信号输入时,输出更新为新的状态,是为次态。用D表示输入信号,CLK表示时钟信号,Q表示输出信号初态,Q*表示输出信号次态。得到以下真值表

DQQ*
000
010
101
111

这样我们可以得到输出现态的逻辑关系式为Q*=D。
在verilog中,时序的表示方法用always块,后跟边沿触发,可以是上升沿也可以是下降沿。在时序逻辑电路里边,赋值方式一般用非阻塞赋值。符号为“<=”。

上升沿触发:

always @ (posedge clk)
	begin
	……
	end

下降沿触发:

always @ (negedge clk)
	begin
	……
	end

根据上述分析得到下列代码

module top_module (

	input clk,    // Clocks are used in sequential circuits
	input d,
	output reg q );//

// Use a clocked always block
//   copy d to q at every positive edge of clk
//   Clocked always blocks should use non-blocking assignments
	always @ (posedge clk)
    	begin
        	q <= d;
    	end

endmodule

三、仿真图

在这里插入图片描述

Dff8

一、题目要求
创建8位D触发器。所有的dff都应该由clk的上升沿触发

二、分析
D触发器是时序逻辑电路,电路的状态在时钟信号的上升沿(时钟信号从0到1的时刻)时,输出随着输入变化。时序逻辑电路的新的输出(次态)不仅和输入状态有关,还与上一个输出的状态(初态)有关。在没有有效输入的时候,D触发器的输出保持为初态不变,当有信号输入时,输出更新为新的状态,是为次态。用D表示输入信号,CLK表示时钟信号,Q表示输出信号初态,Q*表示输出信号次态。得到以下真值表

DQQ*
000
010
101
111

这样我们可以得到输出现态的逻辑关系式为Q*=D。

一个D触发器只能存储一位数据,8位的D触发器需要8个触发器,并且共用一个时钟信号,第i个触发器的输出q[i]=d[i]。重复定义触发器,使用for循环即可。D触发器是时序逻辑电路,需要使用always块定义,并且赋值语句使用非阻塞赋值。代码如下

module top_module (

	input clk,
	input [7:0] d,
	output [7:0] q
);

always @ (posedge clk)
    begin
        for(integer i=0;i<=7;i++)
            begin
                q[i]<=d[i];
            end
    end
endmodule

三、仿真图

在这里插入图片描述

Dff8r

一、题目要求
创建8个高同步复位的D触发器。所有的dff都应该由clk的上升沿触发
二、分析
D触发器是时序逻辑电路,电路的状态在时钟信号的上升沿(时钟信号从0到1的时刻)时,输出随着输入变化。时序逻辑电路的新的输出(次态)不仅和输入状态有关,还与上一个输出的状态(初态)有关。在没有有效输入的时候,D触发器的输出保持为初态不变,当有信号输入时,输出更新为新的状态,是为次态。用D表示输入信号,CLK表示时钟信号,Q表示输出信号初态,Q*表示输出信号次态。得到以下真值表

DQQ*
000
010
101
111

这样我们可以得到输出现态的逻辑关系式为Q*=D。

这里要求创建8位同步复位D触发器,8个D触发器共用一个时钟信号clk,并且复位信号reset是高电平触发,即如果reset=1,则输出q[i]=0;并且复位信号是同步复位,即如果reset=1,不会立马复位,而是在clk的下一个上升沿才会复位。代码编写依旧使用always块和for循环,并且always块里边需要判断reset是否为1,如果为1,则输出全部复位,否则就将输出和输入赋值q[i]=d[i],赋值语句使用非阻塞赋值,代码如下

module top_module (

	input clk,
	input reset,            // Synchronous reset
	input [7:0] d,
	output [7:0] q
);

always @ (posedge clk)
    begin
        if(reset==1)
            q<=8'b0;
        else
            for(integer i=0;i<=7;i++)
                begin
                    q[i]<=d[i];
                end
    end
endmodule

三、仿真图

在这里插入图片描述

Dff8p

一、题目要求
创建8位D触发器且同步高电平复位。触发器必须重置为0x34而不是零。所有dff都应该由时钟的负边(下降沿)触发
二、分析

D触发器是时序逻辑电路,电路的状态在时钟信号的上升沿(时钟信号从0到1的时刻)时,输出随着输入变化。时序逻辑电路的新的输出(次态)不仅和输入状态有关,还与上一个输出的状态(初态)有关。在没有有效输入的时候,D触发器的输出保持为初态不变,当有信号输入时,输出更新为新的状态,是为次态。用D表示输入信号,CLK表示时钟信号,Q表示输出信号初态,Q*表示输出信号次态。得到以下真值表

DQQ*
000
010
101
111

这样我们可以得到输出现态的逻辑关系式为Q*=D。

创建8位D触发器,8个D触发器共用一个时钟信号,且下降沿触发,如果reset=1,则输出值为0x34,0x34是16进制表示法,用verilog表示为8’h0x34。时序逻辑电路使用always块,赋值方法使用非阻塞赋值。代码如下

module top_module (
	input clk,
	input reset,
	input [7:0] d,
	output [7:0] q
);
	always @ (negedge clk)
    	begin
        	if(reset==1)
            	q<=8'h0x34;
        	else
            	for(integer i=0;i<=7;i++)
                	q[i]<=d[i];
    	end

endmodule

三、仿真图

在这里插入图片描述

Dff8ar

一、题目要求
创建8位D触发器且异步高电平复位。所有dff都应该由时钟的正边(上升沿)触发
二、分析
D触发器是时序逻辑电路,电路的状态在时钟信号的上升沿(时钟信号从0到1的时刻)时,输出随着输入变化。时序逻辑电路的新的输出(次态)不仅和输入状态有关,还与上一个输出的状态(初态)有关。在没有有效输入的时候,D触发器的输出保持为初态不变,当有信号输入时,输出更新为新的状态,是为次态。用D表示输入信号,CLK表示时钟信号,Q表示输出信号初态,Q*表示输出信号次态。得到以下真值表

DQQ*
000
010
101
111

这样我们可以得到输出现态的逻辑关系式为Q*=D。

创建8位D触发器,每个触发器只能存储一位,故需要8个触发器,且q[i]=d[i]。异步高电平复位areset=1,不管clk和d[i]的输入如何,输出q[i]都会立刻被复位,所以arest等于的判断不在always块中,并且是在areset=1的时刻,输出立马复位,故赋值语句使用阻塞赋值。而是如果areset=0时,才有D触发器正常工作。赋值语句用非阻塞赋值。代码如下

module top_module (
	input clk,
	input areset,   // active high asynchronous reset
	input [7:0] d,
	output [7:0] q
);
	begin
	if(areset==1)
    	q=8'b0;
	else
    	begin
    	always @ (posedge clk)
        	begin
        	for(integer i=0;i<=7;i++)
            	q[i]<=d[i];
        	end
    	end
	end

endmodule

这里代码会报错
在这里插入图片描述
说明用verilog表达异步的方式不对。也就是说不能在if语句里边写always块。为此,只能考虑换一种思路,在always块里边实现异步复位。

在这里插入图片描述

根据上面的时序图我们可以知道,虽然areset是异步复位,且为高电平复位。我们可以这样想,如果没有areset,D触发器就是在clk的上升沿触发,此时就有输出跟输入同步变化。如果有了异步复位端areset,可以在clk上升沿的时候先判断areset的状态,如果为高电平,则输出复位。如果为低,则输出跟输入同步变化。那么,这样子是否就可以了呢,我们可以先跑以下代码

module top_module (
	input clk,
	input areset,   // active high asynchronous reset
	input [7:0] d,
	output [7:0] q
);
	always @(posedge clk)
    	begin
        	if(areset==1)
            	q<=8'b0;
        	else
            	for(integer i=0;i<=7;i++)
                	q[i]<=d[i];
    	end
                               
endmodule

在这里插入图片描述
其实我们知道,上边的代码其实是同步复位的代码,而这里要求的是异步复位,那么区别到底在哪里呢。思考到这里我们忽略了一个优先性的问题,同步复位是根据时钟信号clk来的,即使复位端在clk到来时有效,也只会在下一个clk到来时才复位。而异步不一样,异步应该是根据复位信号areset来的才对。

所以,正确的思路应该是这样的,我们应该从时序的角度来考虑置位信号,而不应该从电平高低的角度来考虑。什么意思呢,就是不能简单的看areset是1还是0,这样会出现语法错误。那我们要areset=0,用时序的逻辑如何判断呢,是否可以看下降沿。如果areset出现了下降沿,是不是就说明了此时areset是无效的了,此时就不会复位,这时我们再看clk是否有上升沿,如果有,则输出跟输入同步变化,如果没有就保持不变。所以这里时序出现了clk的上升沿或者是areset的下降沿。应同时考虑在always块里边。故而得到下边的代码

module top_module (
	input clk,
	input areset,   // active high asynchronous reset
	input [7:0] d,
	output [7:0] q
);
	always @(posedge clk or negedge areset)
    	begin
        	for(integer i=0;i<=7;i++)
            	q[i]<=d[i];
    	end
                               
endmodule

在这里插入图片描述

仿真后发现还是不对,这里我们好像漏了复位了。上边我们分析了时序是在clk的上升沿或者是areset的下降沿触发,忽略了一个问题,就是我们在areset的下降沿的时候触发,然后等待clk上升沿到来,那如果在clk上升沿到来之前或者是到来的时候,areset=1,即出现上升沿了,输出也会被复位。

故在clk上升沿或者areset下降沿时电路触发,areset的优先级最高,一旦areset有下降沿,就会等待clk上升沿的到来,clk上升沿到来前或到来时,areset都应该保持为0(无效),这样电路才能正常完成D触发器的功能,一旦在clk上升沿到来前或者到来时,areset=1(有效),电路不管clk的状态如何,都会被复位,所以应该加一个if判断语句,判断areset的状态,只有在其无效时,才实现D触发器的功能。代码如下

module top_module (
	input clk,
	input areset,   // active high asynchronous reset
	input [7:0] d,
	output [7:0] q
);
	always @ (posedge clk or negedge areset)
    	begin
        	if(areset==1)
            	begin
            	q<=8'b0;
            	end
        	else
            	for(integer i=0;i<=7;i++)
                	begin
                	q[i]<=d[i];
                	end
    	end
                   
endmodule

在这里插入图片描述
这里仿真还是不对,是不是哪里错了,我们看areset的下降沿,似乎有漏了一个问题,看下降沿考虑的是areset为0,即无效的时候,才去判断clk跟areset的值,并没有考虑areset=1的时候的情况。也就是说,在areset=1的那段时间内,输出都为0,但是我们的电路检测不到。always块里边的if(areset)是在clk上升沿或者是areset下降沿判断的,并没有areset=1的判断。

故正确的逻辑应该是看areset的上升沿,如果areset上升沿到来后,判断areset是否为1,因为有可能上升沿到来了,很短时间又变为0了,areset=1,则直接复位,如果为0且能等到clk上升沿到来,则能完成D触发器功能。还有一种情况是,clk上升沿的时候,如果areset=1,则直接复位,否则输出和输入同步变化。所以应该将上边的代码的areset的下降沿触发改为上升沿触发。代码如下

module top_module (
	input clk,
	input areset,   // active high asynchronous reset
	input [7:0] d,
	output [7:0] q
);
	always @ (posedge clk or posedge areset)
    	begin
        	if(areset==1)
            	begin
            	q<=8'b0;
            	end
        	else
            	for(integer i=0;i<=7;i++)
                	begin
                	q[i]<=d[i];
                	end
    	end
                   
endmodule

故同步复位和异步复位在时序逻辑里边的区别就在于,如果复位是低电平触发,则异步多一个复位信号的下降沿触发,如果为高电平复位,则是上升沿触发

三、仿真图

在这里插入图片描述

Dff16e

一、题目要求
创建16个D触发器。有时只修改一组D触发器。字节启用输入控制16个寄存器的每个字节是否应该在该周期内被写入。Byteena[1]控制高八位d[15:8],而Byteena[0]控制低八位d[7:0]。

复位是一种同步的、低电平触发的重置。所有dff都应该由时钟的正边触发。
二、分析
D触发器是时序逻辑电路,电路的状态在时钟信号的上升沿(时钟信号从0到1的时刻)时,输出随着输入变化。时序逻辑电路的新的输出(次态)不仅和输入状态有关,还与上一个输出的状态(初态)有关。在没有有效输入的时候,D触发器的输出保持为初态不变,当有信号输入时,输出更新为新的状态,是为次态。用D表示输入信号,CLK表示时钟信号,Q表示输出信号初态,Q*表示输出信号次态。得到以下真值表

DQQ*
000
010
101
111

这样我们可以得到输出现态的逻辑关系式为Q*=D。

本题的D触发器是时钟信号clk的上升沿触发,且为同步低电平复位,并且Byteena分别控制高八位和低八位数据的写入,所以在时序触发的阶段,只要判断Byteena的状态即可将对应的数据写入。这里Byteena是两位二进制数,分别有00,01,10,11四种状态。根据题意,Byteena[1]控制高八位的写入,则低八位不变,Byteena[0]控制低八位的写入,则高八位不变。11时,输出全部改变(高八位和低八位同时变),00时,输出保持原样输出。q是16的数据,高八位和低八位可以用连接符“{ }”来连接,变的部分是d[i],不变的部分是q[i]。则可以使用case语句来判断。时序逻辑电路使用always块,赋值方式使用非阻塞赋值。代码如下

module top_module (
	input clk,
	input resetn,
	input [1:0] byteena,
	input [15:0] d,
	output [15:0] q
);
	always @ (posedge clk)
    	begin
    		if(resetn==0)
        		q<=16'b0;
        	else
            	case(byteena)
                	2'b00:q<=q;
                	2'b01:q<={q[15:8],d[7:0]};
                	2'b10:q<={d[15:8],q[7:0]};
                	2'b11:q<=d;
            	endcase
    	end
          
endmodule

三、仿真图

在这里插入图片描述
在这里插入图片描述

Exams/m2014 q4a

一、题目要求
创建下图所示的电路
在这里插入图片描述
注意,这是一个锁存,因此预计会有一个关于推断出锁存的Quartus警告。
二、分析
题目要求创建一个电路,注意这是一个锁存器,所以是组合逻辑电路,触发方式应该选择电平触发,ena为使能端,类似“允许工作”的意思,只有ena有效时,输出才等于输入,否则输出不变。代码如下

module top_module (
	input d, 
	input ena,
	output q);

	always @ (*)
    	begin
        	if(ena==0)
        		q<=q;
			else
    			q<=d;
    	end

endmodule

三、仿真图

在这里插入图片描述

Exams/m2014 q4b

一、题目要求
创建以下电路
在这里插入图片描述
模块代码如下

module top_module (
	input clk,
	input d, 
	input ar,   // asynchronous reset
	output q);

二、分析
这是一个异步复位的D触发器,其中ar为复位端,asynchronous reset为异步复位的意思。并且为高电平的异步复位,有关异步复位的详细介绍,详见 Dff8ar这一节。代码如下

module top_module (
	input clk,
	input d, 
	input ar,   // asynchronous reset
	output q);

	always @ (posedge clk or posedge ar)
    	begin
        	if(ar==1)
            	q<=0;
        	else
            	q<=d;
    	end

endmodule

三、仿真图

在这里插入图片描述

Exams/m2014 q4c

一、题目要求
创建以下电路
在这里插入图片描述

module top_module (
	input clk,
	input d, 
	input r,   // synchronous reset
	output q);

二、分析
上图是一个同步复位的D触发器,其中R为复位端,高电平有效。代码如下

module top_module (
	input clk,
	input d, 
	input r,   // synchronous reset
	output q);

	always @ (posedge clk)
    	begin
        	if(r==1)
            	q<=0;
        	else
            	q<=d;
    	end

endmodule

三、仿真图

在这里插入图片描述

Exams/m2014 q4d

一、题目要求
创建下列图示的电路
在这里插入图片描述

二、分析
根据电路图可以知道,这是一个D触发器,其中触发器的输入D是输入in和输出Q的异或,clk为上升沿触发。代码如下

module top_module (
	input clk,
	input in, 
	output out);

	always @ (posedge clk)
    	begin
        	out<= in ^ out;
    	end

endmodule

三、仿真图

Mt2015 muxdff

一、题目要求
假设您希望为该电路实现分层Verilog代码,使用具有触发器和多路复用器的子模块的三个实例。为这个子模块编写一个名为top_module的Verilog模块(包含一个触发器和多路复用器)。
在这里插入图片描述

module top_module (
	input clk,
	input L,
	input r_in,
	input q_in,
	output reg Q);

二、分析
根据题目给的电路图和代码可以知道,这里题目要求我们用模块化的思路来解答,将D触发器和二选一电路选择器封装成一个模块,这里不需要完整设计电路,只需要将其中的一个触发器和多路复用器封装成top_module模块即可。这里我们先进行模块的设计。

根据电路图,一个D触发器前带着一个二选一数据选择器,输入有Clock,L和r_in,q_in,L的作用是二选一数据选择器的选择端,L=1选择r_in,L=0选择q_in。输出有Q。这题q_in比较难理解,这里题目应该是为了简化,将第三个触发器的输出端Q2直接变成一个输入信号q_in给我们。这里触发器的时钟信号为上升沿触发。

在这里插入图片描述

这样我们可以定义下列模块:

module top_module (
	input clk,
	input L,
	input r_in,
	input q_in,
	output reg Q);

	always @ (posedge clk)
    	begin
        	case(L)
            	1'b0:Q<=q_in;
            	1'b1:Q<=r_in;
        	endcase
    	end

endmodule

三、仿真图

在这里插入图片描述

Exams/2014 q4a

一、题目要求
考虑如下所示的n位移位寄存器电路:
在这里插入图片描述

为该电路的一级编写一个名为top_module的Verilog模块,包括触发器和多路复用器。

module top_module (
	input clk,
	input w, R, E, L,
	output Q
);

二、分析
这里我们只需要将下图所示的电路模块化即可
在这里插入图片描述
可以看到,电路有输入端E,R,L,w和Clock,输出端为Q,输入端D前有两级二选一数据选择器,第一个的选择端为E,第二个的选择端为L,所以这里需要用到两个if语句。这里触发器的时钟信号为上升沿触发。这里为方便使用case语句,并且根据EL的值来确定输入信号,得下表

ELD
00Q
01R
10w
11R

如果用if语句写,则逻辑如下
如果L=1,则输入为R,L=0,判断E的值,E=1,输入为w,否则为Q。

一、用case语句,代码如下

module top_module (
	input clk,
	input w, R, E, L,
	output Q
);
	always @ (posedge clk)
    	begin
        	case({E,L})
            	2'b00:Q<=Q;
            	2'b01:Q<=R;
            	2'b10:Q<=w;
            	2'b11:Q<=R;
        	endcase
    	end

endmodule

二、用if语句,代码如下

module top_module (
	input clk,
	input w, R, E, L,
	output Q
);
	always @ (posedge clk)
    	begin
        	if(L==1)
            	Q<=R;
        	else
            	if(E==1)
                	Q<=w;
            	else
                	Q<=Q;
    	end
                 
endmodule

三、仿真图

在这里插入图片描述

Exams/ece241 2014 q4

一、题目要求
给定如图所示的有限状态机电路,假设D个触发器在机器开始之前被初始重置为零。
在这里插入图片描述

二、分析
本题有三个D触发器,但是三个的输出都没有定义,这里需要定义中间变量来暂存触发器的输出,根据电路图我们知道,从上到下触发器的输入信号分别为x和对应触发器的输出信号的异或,与,或。注意第一个输出Q的异或,而第二第三个是输出Q的非。图中没有画出clk信号,但根据触发器的标注可以知道clk为上升沿触发。代码如下

module top_module (
	input clk,
	input x,
	output z
); 
	reg Q[2:0];

	always @ (posedge clk)
    	begin
        	Q[0]<=Q[0]^x;
        	Q[1]<=(~Q[1])&x;
        	Q[2]<=(~Q[2])|x;
    	end

	assign z=~(Q[0]|Q[1]|Q[2]);
        
endmodule

三、仿真图

在这里插入图片描述

Exams/ece241 2013 q7

一、题目要求
JK触发器的真值表如下。用d型触发器和门实现一个JK触发器。注:Qold为D触发器在正时钟边之前的输出。

JKQ
00Qold
010
101
11~Qold

二、分析
根据真值表,我们可以使用列举(if语句或者case语句)的方法来设计电路,或者根据数电知识,JK触发器的逻辑化简式为Q*=JQ’+K’Q,其中Q表示现态,Q表示次态,Q’表示Q的反。题目要求使用D触发器来实现JK触发器的功能。D触发器的逻辑表达式为Q=D。故我们只需要令D=JQ’+K’Q即可。同时注意D触发器为上升沿触发。

这里给出两种方法:

(1)case语句实现

module top_module (
	input clk,
	input j,
	input k,
	output Q);   

	always @ (posedge clk)
    	begin
        	case({j,k})
            	2'b00:Q<=Q;
            	2'b01:Q<=1'b0;
            	2'b10:Q<=1'b1;
            	2'b11:Q<=~Q;
        	endcase
    	end
            
endmodule

(2)逻辑表达式法

module top_module (
	input clk,
	input j,
	input k,
	output Q);   

	always @ (posedge clk)
    	begin
        	Q<= j & (~Q) | (~k) & Q;
    	end
            
endmodule

三、仿真图

在这里插入图片描述

Edgedetect

一、题目要求
对于8位矢量中的每个位,检测输入信号何时在一个时钟周期内从0变为下一个时钟周期的1(类似于正边缘检测)。输出位应该设置在0到1转换发生后的周期。

这里有一些例子。为清楚起见,in[1]和pedge[1]分别显示。

在这里插入图片描述

二、分析
根据题目知道,这里要求我们检测输入in出现上升沿的时候,输出pedge从0变为1,即in每有一个上升沿,则输出触发一次,并且输出在持续为1一段时间后变为0.类似于单稳态触发器的特性
。根据in[1]和pedge[1]的曲线我们知道,in[1]出现上升沿以后,在clk的下一个时钟信号上升沿,pedge变为高电平。下边介绍边沿检测的方法:

设置两个寄存器A和B,分别对前一状态A和后一状态B进行寄存,若前后两个状态不同,则检测到了边沿。对于上升沿和下降沿的确定可以用组合逻辑比较来确定。若前一状态A为高电平,后一状态B为低电平,则为下降沿,反之为上升沿。
若为上升沿,则A=0,B=1,则输出应为 ~ A&B。若为下降沿,则A=1,B=0,则输出应为A& ~B。

题目要求的是上升沿触发,则我们定义一个寄存器reg类型的变量in1来暂存上一状态,则输入in的状态即为后一状态。如果in1=0,in=1则说明in出现上升沿触发,则输出pedge=1。即输出pedge=in & ~ in1。注意电路为clk的上升沿触发。

代码如下

module top_module (
	input clk,
	input [7:0] in,
	output [7:0] pedge
);
	reg [7:0] in1;//暂存前一状态,in为现态即后一状态
	always @ (posedge clk)
    	begin
        	in1<=in;
    	end

	always @ (posedge clk)
    	begin
        	pedge<=~in1 & in;           
    	end

endmodule

三、仿真图

在这里插入图片描述

Edgedetect2

一、题目要求
对于8位矢量中的每个位,检测输入信号何时从一个时钟周期变化到下一个时钟周期(检测任何边缘)。输出位应该设置在0到1转换发生后的周期。

这里有一些例子。为清楚起见,在in[1]和pedge[1]分别显示

在这里插入图片描述

二、分析
题目要求检测输入in的边沿端,只要in出现上升沿或者下降沿,输出anyedge都为1。

边沿检测的方法如下:设置两个寄存器A和B,分别对前一状态A和后一状态B进行寄存,若前后两个状态不同,则检测到了边沿。对于上升沿和下降沿的确定可以用组合逻辑比较来确定。若前一状态A为高电平,后一状态B为低电平,则为下降沿,反之为上升沿。
若为上升沿,则A=0,B=1,则输出Y应为 ~ A&B。若为下降沿,则A=1,B=0,则输出Y应为A& ~B。
所以输出为Y = A&~B | ~A & B = A ^ B。注意电路为clk的上升沿触发。

代码如下

module top_module (
	input clk,
	input [7:0] in,
	output [7:0] anyedge
);
	reg [7:0] in1;//暂存前一状态
	always @ (posedge clk)
    	begin
        	in1<=in;
    	end

	always @ (posedge clk)
    	begin
        	anyedge <=in1 ^ in;
    	end

endmodule

三、仿真图

在这里插入图片描述

Edgecapture

一、题目要求
对于32位矢量中的每个位,捕获输入信号在一个时钟周期内从1变为下一个时钟周期内的0的时间。“捕获”意味着输出将保持1,直到寄存器复位(同步复位)。

每个输出位的行为就像一个SR触发器:输出位应该在1到0转换发生后的周期被设置为1。当复位高时,输出位应该在正时钟边复位(为0)。如果上述两个事件同时发生,则reset具有优先级。在下面的示例波形的最后4个周期中,“reset”事件比“set”事件早一个周期发生,因此这里不存在冲突。

在下面的示例波形中,为了清晰起见,再次分别显示reset、In[1]和out[1]。

在这里插入图片描述

二、分析
题目要求检测输入in的下降沿,如果出现,输出out保持为1输出,直到reset=1时复位。

边沿检测的方法如下:设置两个寄存器A和B,分别对前一状态A和后一状态B进行寄存,若前后两个状态不同,则检测到了边沿。对于上升沿和下降沿的确定可以用组合逻辑比较来确定。若前一状态A为高电平,后一状态B为低电平,则为下降沿,反之为上升沿。
若为上升沿,则A=0,B=1,则输出Y应为 ~ A&B。若为下降沿,则A=1,B=0,则输出Y应为A& ~B。

这里需要解决的问题是如何保持输出为1不变,直到reset复位端有效。

根据边沿检测的思路,输出应为Y=A& ~B,此时Y=1,输出保持不变,即一直为1,这里是时序逻辑电路,Y的值会根据clk和in的上升沿和下降沿发生变化,因而要使Y不变,只能利用组合逻辑中的与,或,非等关系。因为Y=1,所以我们可以“或”上Y本身,这样输出一直都为1,同样的道理,如果输出为0保持不变,可以与上输出本身。

注意,Y是和Y本身或,不是Y和1或,不然Y输出恒为1。

代码如下

module top_module (
	input clk,
	input reset,
	input [31:0] in,
	output [31:0] out
);
	reg [31:0] in1;
	always @ (posedge clk)
    	begin
        	in1<=in;
    	end

	always @ (posedge clk)
    	begin
        	if(reset==1)
            	out<=32'b0;
        	else
            	out <= in1 & (~ in) | out;
    	end

endmodule

三、仿真图

在这里插入图片描述
在这里插入图片描述

Dualedge

一、题目要求
你熟悉的触发器是在时钟的正边缘触发的,或者是在时钟的负边缘触发的。在时钟的两端触发双边缘触发触发器。然而,fpga没有双边触发触发器,并且总是@(posedge clk或negedge clk)不被接受为法律敏感性列表。

构建一个功能上类似于双边缘触发触发器的电路:
在这里插入图片描述
(注意:这并不一定是完全等价的:触发器的输出没有故障,但一个更大的模拟这种行为的组合电路可能会。但我们在这里忽略这个细节。)

二、分析
verilog不支持同时触发上边沿和下边沿,因为FPGA中只有单边沿触发器,没有双边沿触发器这种器件。所以,posedge clk or negedge clk是无法综合的。也就是说下边的语句是非法的

always @(posedge clk or negedge clk) begin
		q <= d;
end

这里我们知道,每有一个上升沿或者下降沿,q的状态就会改变,但我们又发现,q的状态变化不是简单的翻转而已(即从0到1,从1到0),在第三个clk的上升沿,q端的信号是保持不变的。为此我们可以考虑使用列举的方法来分析q端的输出表达式。
因为电路是在clk的上升沿和下降沿触发的,那么我们可以分别定义两个寄存器q1,q2,分别存储上升沿和下降沿时输入d的状态,然后根据q1,q2二者的电平高低来推测输出q的电平高低,看是否满足题目要求。

always @(posedge clk) begin
		q1 <= d;
end

always @(negedge clk) begin
		q2 <= d;
end

下边的clk1表示上述波形图的clk从左往右的第二个高电平对应的上升沿和下降沿

clk上升沿clk1clk2clk3clk4clk5clk6
q1101101
clk下降沿clk1clk2clk3clk4clk5clk6
q2010011
clk上升沿clk1clk2clk3clk4clk5clk6
q001001
clk下降沿clk1clk2clk3clk4clk5clk6
q101101
clk高电平clk1clk2clk3clk4clk5clk6
q101101
clk低电平clk1clk2clk3clk4clk5clk6
q010011

根据上边的q1q2,q不应该是时序触发的,即q的状态改变不应在clk的上升沿或者下降沿,否则这样就回到了最开始讲的不能有always @(posedge clk or negedge clk) 这一问题,所以我们考虑一下q是关于clk的电平触发。而根据clk的电平高低得到的q的输出表可以知道。在clk=1时,输出q=q1,clk=0时,q=q2。所以尝试一下代码:

module top_module (
	input clk,
	input d,
	output q
);
	reg q1,q2;

	always @ (posedge clk)
    	begin
        	q1<=d;
    	end

	always @ (negedge clk)
    	begin
        	q2<=d;
    	end

	always @ (*)
    	begin
        	case(clk)
            	1'b0:q<=q2;
            	1'b1:q<=q1;
        	endcase
    	end

endmodule

本题解法很多,感兴趣的读者可以查阅更专业的资料了解双边触发器的原理和实现。

三、仿真图

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值