3 Verilog入门篇之时序逻辑

VL21 根据状态转移表实现时序电路

描述

某同步时序电路转换表如下,请使用D触发器和必要的逻辑门实现此同步时序电路,用Verilog语言描述。

3 Verilog入门篇之时序逻辑_第1张图片

电路的接口如下图所示。

3 Verilog入门篇之时序逻辑_第2张图片

输入描述:

      input                A   ,
      input                clk ,
      input                rst_n

输出描述:

output wire Y

题意整理

本题要求根据时序电路的状态表实现同步时序电路,要求使用D触发器。

题解主体

基础的时序电路设计,可采用列激励方程、输出方程,进而用D触发器和组合逻辑电路实现的方案。

由状态表可得出,电路共4个状态,所以使用2个寄存器来实现状态的寄存。两个寄存器的输出为Q1和Q0。

由状态转换表可列出激励方程如下:

Q_1^{n+1}=D1=Q_1^n ⊕Q_0^n·~A+Q_1^n⊙Q_0^n·A=Q_1^n ⊕Q_0^n⊕AQ1n+1​=D1=Q1n​⊕Q0n​⋅ A+Q1n​⊙Q0n​⋅A=Q1n​⊕Q0n​⊕A

Q_0^{n+1}=D0=~Q_0^nQ0n+1​=D0= Q0n​

输出方程如下:

Y=Q_1 ·Q_0Y=Q1​⋅Q0​

表中的Qn表示现态,Qn+1表示次态

根据激励方程和输出方程以及思路整理,关键电路如下:

3 Verilog入门篇之时序逻辑_第3张图片

将电路转换成Verilog代码描述如下:

`timescale 1ns/1ns
module seq_circuit(
      input                A   ,
      input                clk ,
      input                rst_n,
 
      output   wire        Y   
);

reg Q1 ;
reg Q0 ;
      
always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
      Q1 <= 1'b0;
   else
      Q1 <= Q1 ^ Q0 ^A;
end 
always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
      Q0 <= 1'b0;
   else
      Q0 <= ~Q0;
end 
    
assign Y = Q1 & Q0; 
   
endmodule

答案2

可以看成是两个状态检测机,利用FSM实现

先拆分状态,有四个状态

  1. IDLE=2'b00;
  2. S1=2'b01;
  3. S2=2'b10;
  4. S3=2'b11;

利用两段式状态机

  1. 第一段描述状态跳变
  2. 第二段描述跳变条件
  3. 利用if 判断输入A,从而决定下一状态
    `timescale 1ns/1ns
    
    module seq_circuit(
          input                A   ,
          input                clk ,
          input                rst_n,
     
          output   wire        Y   
    );
            parameter     IDLE    =     2'b00    ;
            parameter     S1    =     2'b01    ;
            parameter     S2   =     2'b10    ;
            parameter     S3    =     2'b11    ;
        reg     [1:0]    CS    ;
        reg    [1:0]    NS    ;
        always@(posedge clk or negedge rst_n)    begin
            if(!rst_n)    begin
                CS    <=    IDLE    ;
            end
            else   
                CS    <=    NS   ;
        
        end
        
        always@(* )    begin
                case(CS)
                        IDLE:    begin
                            if(A==0)    begin
                                NS    <=    S1    ;
                            end
                            else    begin
                                NS    <=    S3    ;
                            end
                        end
                        S1:    begin
                            if(A==0)    begin
                                NS    <=    S2    ;
                            end
                            else    begin
                                NS    <=    IDLE    ;
                            end
                        end
                         S2:    begin
                             if(A==0)    begin
                                NS    <=    S3    ;
    
                             end
                            else    begin
                                NS    <=    S1    ;
    
                            end
                        end
                         S3:    begin
                             if(A==0)    begin
                                NS    <=    IDLE    ;
                             end
                            else    begin
                                NS    <=    S2    ;
                            end
                        end
                endcase
              
        
        end
        
        assign Y=(CS==S3)?1:0;
    
     
    endmodule
    
    
    
    

VL22 根据状态转移图实现时序电路 

 描述

某同步时序电路的状态转换图如下,→上表示“C/Y”,圆圈内为现态,→指向次态。

请使用D触发器和必要的逻辑门实现此同步时序电路,用Verilog语言描述。

3 Verilog入门篇之时序逻辑_第4张图片

电路的接口如下图所示,C是单bit数据输入端。 

3 Verilog入门篇之时序逻辑_第5张图片

输入描述:

   input                C   ,
   input                clk ,
   input                rst_n

输出描述:

      output   wire        Y 

题意整理

本题要求根据题目提供的状态转换图实现同步时序电路,要求使用D触发器。

题解主体

本题提供的是状态转换图,可采用状态机实现,也可采用列激励方程、输出方程,进而用D触发器和组合逻辑电路实现。本题解采用第二种方案实现。

由状态转换图可得出,电路共4个状态,所以使用2个寄存器来实现状态的寄存。两个寄存器的输出为Q1和Q0,两个寄存器的输入为D1和D0。可列出状态转换表如下:

3 Verilog入门篇之时序逻辑_第6张图片

由状态转换表可列出激励方程如下:

Q_1^{n+1}=D1=Q_1^n ·Q_0^n+Q_1^n·\bar{Q_0^n}·C+~\bar{Q_1^n}·Q_0^n·\bar{C}Q1n+1​=D1=Q1n​⋅Q0n​+Q1n​⋅Q0n​ˉ​⋅C+ Q1n​ˉ​⋅Q0n​⋅Cˉ

Q_0^{n+1}=D0=\bar{Q_1^n} ·Q_0^n+\bar{Q_1^n}·\bar{Q_0^n}·C+Q_1^n·Q_0^n·\bar{C}Q0n+1​=D0=Q1n​ˉ​⋅Q0n​+Q1n​ˉ​⋅Q0n​ˉ​⋅C+Q1n​⋅Q0n​⋅Cˉ

输出方程如下:

Y=C·Q_1+Q_1 ·Q_0Y=C⋅Q1​+Q1​⋅Q0​

根据激励方程和输出方程以及思路整理,关键电路如下:

3 Verilog入门篇之时序逻辑_第7张图片

3 Verilog入门篇之时序逻辑_第8张图片

3 Verilog入门篇之时序逻辑_第9张图片

将电路转换成Verilog代码描述如下:

reg Q1 ;

reg Q0 ;

always @(posedge clk or negedge rst_n)begin

   if(!rst_n)

      Q1 <= 1'b0;

   else

      Q1 <= (Q1 & (Q0 | C)) | (~Q1 & Q0 & ~C);

end

always @(posedge clk or negedge rst_n)begin

   if(!rst_n)

      Q0 <= 1'b0;

   else

      Q0 <= (~Q1 & (Q0 | C)) | (Q1 & Q0 & ~C);

end

   

assign Y = (C & Q1) | (Q1 & Q0);

三段式FSM

`timescale 1ns/1ns

module seq_circuit(
   input                C   ,
   input                clk ,
   input                rst_n,
 
   output   wire        Y   
);

	reg [1:0] state, next_state;
	
	
	// state transition
	always @ (posedge clk or negedge rst_n) begin
        if (!rst_n) begin
			state <= 2'b00;
		end
		else begin
			state <= next_state;
		end
	end
	
	// next_state logic
	
	always @ (*) begin
		next_state = 2'b00;
		case (state)
			2'b00: next_state = C ? 2'b01 : 2'b00;
			2'b01: next_state = C ? 2'b01 : 2'b11;
			2'b10: next_state = C ? 2'b10 : 2'b00;
			2'b11: next_state = C ? 2'b10 : 2'b11;
			default: next_state = state;
		endcase
	end
	
	// output logic
    assign Y = (next_state == 2'b10) | (state == 2'b11);
endmodule

 VL23 ROM的简单实现

描述

实现一个深度为8,位宽为4bit的ROM,数据初始化为0,2,4,6,8,10,12,14。可以通过输入地址addr,输出相应的数据data。

接口信号图如下:

      

3 Verilog入门篇之时序逻辑_第10张图片

输入描述:

clk:系统时钟

rst_n:异步复位信号,低电平有效

addr:8bit位宽的无符号数,输入到ROM的地址

输出描述:

data:4bit位宽的无符号数,从ROM中读出的数据

题解主体

       要实现ROM,首先要声明数据的存储空间,例如:[3:0] rom [7:0];变量名称rom之前的[3:0]表示每个数据具有多少位,指位宽;变量名称rom之后的[7:0]表示需要多少个数据,指深度,注意这里深度为8,应该是使用[7:0],而不是[2:0];

       声明存储变量之后,需要对rom进行初始化,写入数据,然后将输入地址作为rom的索引值,将索引值对应的数据输出。

可以按照如下的方式开辟存储空间,并进行数据初始化:

       reg [3:0] rom_data [7:0];

//保持ROM中的数据不变

       always @(posedge clk or negedge rst_n)

              if (!rst_n)                                          //对ROM中的数据进行初始化

                     begin

                            rom_data[0] <= 4'd0;

                            rom_data[1] <= 4'd2;

                            rom_data[2] <= 4'd4;

                            rom_data[3] <= 4'd6;         

                            rom_data[4] <= 4'd8;

                            rom_data[5] <= 4'd10;

                            rom_data[6] <= 4'd12;

                            rom_data[7] <= 4'd14;

                     end

              else

                     begin                                               //保持ROM中的数据不变

                            rom_data[0] <= 4'd0;

                            rom_data[1] <= 4'd2;

                            rom_data[2] <= 4'd4;

                            rom_data[3] <= 4'd6;         

                            rom_data[4] <= 4'd8;

                            rom_data[5] <= 4'd10;

                            rom_data[6] <= 4'd12;

                            rom_data[7] <= 4'd14;

                     end

初始化完成之后的rom的形式如下,内部存在地址和数据的对应关系,通过输入相应的地址,可以得到相应的输出数据。

      

3 Verilog入门篇之时序逻辑_第11张图片

       always @(posedge clk or negedge rst_n)

              if (!rst_n)

                     data <= 4'd0;

              else

                     data <= rom_data[addr];

只需要将地址作为rom的索引,即可得到相应的数据

`timescale 1ns/1ns
module rom(
	input clk,
	input rst_n,
	input [7:0]addr,
	
	output [3:0]data
);
	reg [3:0] rom_data [7:0];
	
	assign data = rom_data[addr];
//保持ROM中的数据不变	
	always @(posedge clk or negedge rst_n)
		if (!rst_n) 
			begin
				rom_data[0] <= 4'd0;
				rom_data[1] <= 4'd2;
				rom_data[2] <= 4'd4;
				rom_data[3] <= 4'd6;		
				rom_data[4] <= 4'd8;
				rom_data[5] <= 4'd10;
				rom_data[6] <= 4'd12;
				rom_data[7] <= 4'd14;
			end
		else 
			begin
				rom_data[0] <= rom_data[0];
				rom_data[1] <= rom_data[1];
				rom_data[2] <= rom_data[2];
				rom_data[3] <= rom_data[3];		
				rom_data[4] <= rom_data[4];
				rom_data[5] <= rom_data[5];
				rom_data[6] <= rom_data[6];
				rom_data[7] <= rom_data[7];
			end
endmodule

VL24 边沿检测

描述

有一个缓慢变化的1bit信号a,编写一个程序检测a信号的上升沿给出指示信号rise,当a信号出现下降沿时给出指示信号down。
注:rise,down应为单脉冲信号,在相应边沿出现时的下一个时钟为高,之后恢复到0,一直到再一次出现相应的边沿。

3 Verilog入门篇之时序逻辑_第12张图片

输入描述:

clk:系统时钟信号

rst_n:异步复位信号,低电平有效

a:单比特信号,作为待检测的信号

输出描述:

rise:单比特信号,当输入信号a出现上升沿时为1,其余时刻为0

down:单比特信号,当输入信号a出现下降沿时为1,其余时刻为0

题意整理

       题目要求检测输入信号a的边沿,即当a信号的值从0跳变到1,视为出现上升沿,把指示信号rise拉高;当a信号的值从1跳变到0,视为出现下降沿,把指示信号down拉高。其余时刻两个指示信号因保持0。

题解主体

       检测信号a的边沿需要缓存信号前一时刻的值,例如记为a_tem。当前一时刻为0,这一时刻为1,说明信号出现上升沿,即 a&&!a_tem = 1; 当前一时刻为1,这一时刻为0,说明信号出现上升沿,即 !a&&a_tem = 1;

       输入信号:

              系统时钟,复位信号:clk,rst_n;

              待检测边沿的信号:a;

       输出信号:

              上升沿指示信号:rise

              下降沿指示信号:down

缓存a的数值

       always @(posedge clk or negedge rst_n)

              if (!rst_n)

                     a_tem <= 1'b0;

              else

                     a_tem <= a;

分别使用a&&!a_tem和!a&&a_tem作为判断条件,判断是否出现上升沿或者下降沿。

//检测边沿,给出相应的信号

       always @(posedge clk or negedge rst_n)

              if (!rst_n)

                     begin

                            rise <= 1'b0;

                            down <= 1'b0;

                     end

else if (!a_tem && a)   //当前一时刻a=0,当前时刻a=1,表示a出现一次上升沿

                     begin

                            rise <= 1'b1;

                            down <= 1'b0;

                     end

              else if     (a_tem && !a)//当前一时刻a=1,当前时刻a=0,表示a出现一次下降沿

                     begin

                            down <= 1'b1;

                            rise <= 1'b0;

                     end

              else

                     begin

                            down <= 1'b0;

                            rise <= 1'b0;

                     end

`timescale 1ns/1ns
module edge_detect(
	input clk,
	input rst_n,
	input a,
	
	output reg rise,
	output reg down
);
	
	reg a_tem;

//缓存a的数值	
	always @(posedge clk or negedge rst_n)
		if (!rst_n)
			a_tem <= 1'b0;
		else
			a_tem <= a;
			
//检测边沿,给出相应的信号
	always @(posedge clk or negedge rst_n)
		if (!rst_n)	
			begin 
				rise <= 1'b0;
				down <= 1'b0;
			end
		else if (!a_tem && a)   		//当前一时刻a=0,当前时刻a=1,表示a出现一次上升沿
			begin
				rise <= 1'b1;
				down <= 1'b0;
			end
		else if	(a_tem && !a)			//当前一时刻a=1,当前时刻a=0,表示a出现一次下降沿
			begin
				down <= 1'b1;
				rise <= 1'b0;
			end
		else 
			begin
				down <= 1'b0;
				rise <= 1'b0;
			end
endmodule

你可能感兴趣的:(fpga开发)