西南交大EDA实验——Sequence Detector

本文介绍了西南交大EDA实验中的SequenceDetector设计,该设计能检测四种一致性数据序列:增量、递减和稳定。通过Mealy型状态机实现,根据MODE输入切换不同检测模式,并在满足条件时输出标志信号OUT_VALID和DATA_OUT。文章详细阐述了状态编码、状态转换逻辑以及输出信号的处理方法,并提供了testbench的编写思路。
摘要由CSDN通过智能技术生成

一、实验内容及要求

1. 目的

在这里插入图片描述

设计一种能够根据配置模式检测四个一致性数据并输出标志的序列检测器。

·支持增量模式:可以检测到四个一致性递增的数据

·支持减少模式:可以检测到四个一致性递减的数据

·支持稳定模式:可以检测到四个一致性相同的数据

2. 说明

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

·文件名:SEQUENCE.v

·模块名:SEQ_DETECTOR

·I/O端口:

RST_B:位宽为1bit的输入。系统异步复位,低电平有效。

SYSCLK:位宽为1bit的输入。系统时钟

IN_VALID:位宽为1bit的输入。高电平有效。输入信号MODEDATA_IN只有在IN_VALID = 1的时候有效。当IN_VALID = 0时,MODEDATA_IN应被忽略,并且状态应与IN_VALID = 1时相同。

MODE:位宽为2bit的输入。检测模式,这个信号决定了检测模式。00:增量检测模式,其中四个一致性增长数据(如1,2,3,4或15,0,1,2)可以置OUT_VALID为逻辑1。01:递减检测模式,其中4个一致性递减数据(如5,4,3,2或0,15,14,13)可以置OUT_VALID为逻辑1。10:稳定检测模式,其中4个相同的数据(如0,0,0,0)可以置OUT_VALID为逻辑1。11:与IN_VALID=1作用相同。

DATA_IN:位宽为4bit的输入。输入数据,该信号只有在IN_VALID = 1并且MODE != 2’b11时有效。

OUT_VALID:位宽为1bit的输出。输出有效位,高电平有效。当根据检测模式接收到四个一致性数据是,该信号才生效。

DATA_OUT:位宽为4bit的输出。当OUT_VALID生效时,DATA_OUT应等于DATA_IN,其他情况都等于0。

3. 要求

在这里插入图片描述

4. 波形

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

二、内容讲解及代码编写

首先,先把顶层模块的输入和输出写上。

module	SEQ_DETECTOR
(
    input   wire            SYSCLK      ,
    input   wire            RST_B       ,
    input   wire            IN_VALID    ,
    input   wire    [1:0]   MODE        , 
    input   wire    [3:0]   DATA_IN     ,
    
    output  reg             OUT_VALID   ,
    output  reg    [3:0]    DATA_OUT  
);
    
 
endmodule    

我们需要用到Mealy型状态机,先将需要的状态想好。初始状态S0,以增量模式(MODE=2’b00)为例,假设检测到第一个数0进入状态INCREMEN_STATE1,下一个检测到1进入状态INCREMENT_STATE2,再检测到2进入状态INCREMENT_STATE3,此时已经检测到3个增量,这时如果再检测到3,就要输出OUT_VALID = 1DATA_OUT,同时保持状态在INCREMENT_STATE3,因为1,2,3又是三个连续递增的序列,下一个数据如果是4,也可以构成一个递增的序列1,2,3,4。类似,我们还需要减少模式的状态DECREMENT_STATE1DECREMENT_STATE2 DECREMENT_STATE3和稳定模式的状态EQUAL_STATE1EQUAL_STATE2EQUAL_STATE3。因此我们共需要10个状态,对这10个状态进行编码:

parameter	S0      			= 4'd0  ,  
			INCREMEN_STATE1   	= 4'd1  ,   
			INCREMEN_STATE2   	= 4'd2  ,   
			INCREMEN_STATE3   	= 4'd3  ,   
			DECREMENT_STATE1   	= 4'd4  ,   
			DECREMENT_STATE2   	= 4'd5  ,   
			DECREMENT_STATE3   	= 4'd6  ,   
			EQUAL_STATE1   		= 4'd7  ,   
			EQUAL_STATE2   		= 4'd8  ,   
			EQUAL_STATE3   		= 4'd9  ;   

对状态进行编码后,我们就要考虑状态的转换了,状态转换就需要判断输入的序列是递增、递减还是相等的。如何判断呢?因为使用时序逻辑赋值,会使数据慢一个周期,这样可以比较输入的数据了。

reg	[3:0]	data_in_delay;
always@(posedge SYSCLK, negedge RST_B)
    begin
        if(!RST_B)
            data_in_delay <= 4'd0;
        else if(IN_VALID && MODE != 4'd3)//IN_VALID = 0或MODE = 2'b11时,输入信号是无效的
            data_in_delay <= DATA_IN;
        else
            data_in_delay <= data_in_reg;
    end

考虑完如何判断输入的序列是递增、递减还是相等后,终于到了状态转换的部分了。

在前面,我们已经考虑了增量模式下,状态的转换,另外两个模式类似。但是,我们似乎漏掉了某些特殊的情况,比如说,开始时MODE = 2’b00(增量状态),在状态INCREMENT_STATE2时,MODE发生了改变,这时,下一状态应该什么呢?所以我们现在要考虑半途MODE变化的情况(MODE它叛变了)。继续刚才的例子,假如MODE在状态INCREMENT_STATE2时变成了2’b01,那么这时我们应该检测递减的序列,是不是要回到初始状态S0重新开始呢?不,这个时候,我们已经接受到了数据,我们应该把当前接受到的数据当做递减序列的第一个数,所以我们的状态应该是DECREMENT_STATE1。同理,MODE跳变为2’b002’b10对应着INCREMENT_STATE1EQUAL_STATE1两个状态。所以,状态转换部分,我们应该这样写:

reg	[3:0]	state;
always@(posedge SYSCLK, negedge RST_B)
    begin
        if(!RST_B)
            state <=  S0  ;
        else if(IN_VALID && MODE != 2'b11)
            begin
                case(state)
                S0      :begin
                            if(MODE == 2'b00)
                                state <= INCREMEN_STATE1;
                            else if(MODE == 2'b01)
                                state <= DECREMENT_STATE1;
                            else if(MODE == 2'b10)
                                state <= EQUAL_STATE1;
                            else
                                state <= S0;
                        end
                INCREMEN_STATE1   :begin
                            if(MODE == 2'b00)
                                begin
                                    if(DATA_IN == data_in_delay + 4'd1)
                                        state <= INCREMEN_STATE2;
                                    else
                                        state <= S0;
                                end
                            else if(MODE == 2'b01)
                                state <= DECREMENT_STATE1;
                            else if(MODE == 2'b10)
                                state <= EQUAL_STATE1;
                            else
                                state <= S0;
                        end
                INCREMEN_STATE2   :begin
                            if(MODE == 2'b00)
                                begin
                                    if(DATA_IN == data_in_delay + 4'd1)
                                        state <= INCREMEN_STATE3;
                                    else
                                        state <= S0;
                                end
                            else if(MODE == 2'b01)
                                state <= DECREMENT_STATE1;
                            else if(MODE == 2'b10)
                                state <= EQUAL_STATE1;
                            else
                                state <= S0;
                        end
                INCREMEN_STATE3   :begin
                            if((MODE == 2'b00) && (DATA_IN == data_in_delay + 4'd1))
                                state <= INCREMEN_STATE3;
                            else if(MODE == 2'b01)
                                state <= DECREMENT_STATE1;
                            else if(MODE == 2'b10)
                                state <= EQUAL_STATE1;
                            else
                                state <= S0;
                        end
                DECREMENT_STATE1   :begin
                            if(MODE == 2'b00)
                                state <= INCREMEN_STATE1;
                            else if(MODE == 2'b01)
                                begin
                                    if(DATA_IN + 4'd1 == data_in_delay)
                                        state <= DECREMENT_STATE2;
                                    else
                                        state <= S0;
                                end
                            else if(MODE == 2'b10)
                                state <= EQUAL_STATE1;
                            else
                                state <= S0;
                        end
                DECREMENT_STATE2   :begin
                            if(MODE == 2'b00)
                                state <= INCREMEN_STATE1;
                            else if(MODE == 2'b01)
                                begin
                                    if(DATA_IN + 4'd1 == data_in_delay)
                                        state <= DECREMENT_STATE3;
                                    else
                                        state <= S0;
                                end
                            else if(MODE == 2'b10)
                                state <= EQUAL_STATE1;
                            else
                                state <= S0;
                        end
                DECREMENT_STATE3   :begin
                            if(MODE == 2'b00)
                                state <= INCREMEN_STATE1;
                            else if((DATA_IN + 1'b1 == data_in_delay) && (MODE == 2'b01))
                                state <= DECREMENT_STATE3;
                            else if(MODE == 2'b10)
                                state <= EQUAL_STATE1;
                            else
                                state <= S0;
                        end
                EQUAL_STATE1   :begin
                            if(MODE == 2'b00)
                                state <= INCREMEN_STATE1;
                            else if(MODE == 2'b01)
                                state <= DECREMENT_STATE1;
                            else if(MODE == 2'b10)
                                begin
                                    if(DATA_IN == data_in_delay)
                                        state <= EQUAL_STATE2;
                                    else
                                        state <= S0;
                                end
                            else
                                state <= S0;
                        end
                EQUAL_STATE2   :begin
                            if(MODE == 2'b00)
                                state <= INCREMEN_STATE1;
                            else if(MODE == 2'b01)
                                state <= DECREMENT_STATE1;
                            else if(MODE == 2'b10)
                                begin
                                    if(DATA_IN == data_in_delay)
                                        state <= EQUAL_STATE3;
                                    else
                                        state <= S0;
                                end
                            else
                                state <= S0;
                        end
                EQUAL_STATE3   :begin
                            if(MODE == 2'b00)
                                state <= INCREMEN_STATE1;
                            else if(MODE == 2'b01)
                                state <= DECREMENT_STATE1;
                            else if((DATA_IN == data_in_delay) && (MODE == 2'b10))
                                state <= EQUAL_STATE3;
                            else
                                state <= S0;
                        end
                default :state <= S0;  
                endcase
            end
        else
            state <=  state;
    end

在这里,我们没有用到常用的statenext_state来进行状态的转移。因为作者最开始就是用的这种方法,结果仿真的时候发现,我们理想的情况下,statenext_state是每个周期变化一次,但是因为使用的是时序逻辑,而在时序逻辑了,state <= next_state, next_state是在state的前提进行转换。第一个周期内state = S0next_state = S0,第二个周期内,next_state会在state = S0的条件下进行变换,next_state = INCREMENT_STATE1,第三个周期内,next_state还是会在state = S0的状态下进行变换,所以next_state = INCREMENT_STATE1,而state会在next_state = INCREMENT_STATE1的条件下变换,因为我们使用的时序逻辑。第四个周期内,next_state在state = INCREMENT_STATE1的条件下变换,next_state = INCREMENT_STATE2statenext_state = INCREMENT_STATE1的条件下变换。这样,我们发现,stagenext_stateS0INCREMENT_STATE1,从INCREMENT_STATE1INCREMENT_STATE2都需要两个周期,这与我们想要的情况不符,所以我们不采用statenext_state这种方法进行状态转移。大家也可以自己去试一试这种情况。

OK!我们已经完成了最难的部分了,接下来就是输出信号了!

首先是OUT_VALID

在状态INCREMENT_STATE3时,如果再检测到一个递增的数,就输出OUT_VALID为高电平,其他检测模式类似。

always@(posedge SYSCLK, negedge RST_B)
    begin
        if(!RST_B)
            OUT_VALID <= 1'b0;
        else if(!IN_VALID || MODE == 2'b11)//IN_VALID = 0或者MODE = 2'b11时,无效
            OUT_VALID <= 1'b0;
        else
        begin
            case(state)
            INCREMEN_STATE3   :begin
                        if((DATA_IN == data_in_delay + 1'b1) && (MODE == 2'b00))
                            OUT_VALID <= 1'b1;
                        else
                            OUT_VALID <= 1'b0;
                     end   
            DECREMENT_STATE3   :begin
                        if((DATA_IN + 1'b1 == data_in_delay) && (MODE == 2'b01))
                            OUT_VALID <= 1'b1;
                        else
                            OUT_VALID <= 1'b0;
                     end 
            EQUAL_STATE3   :begin
                        if((DATA_IN == data_in_delay) && (MODE == 2'b10))
                            OUT_VALID <= 1'b1;
                        else
                            OUT_VALID <= 1'b0;
                     end 
            default :       OUT_VALID <= 1'b0;
            endcase
        end
    end 

最后是DATA_OUT了

OUT_VALID生效时,DATA_OUT应等于DATA_IN,其他情况都等于0,因此DATA_OUT的逻辑与OUT_VALID相同

always@(posedge SYSCLK, negedge RST_B)
    begin
        if(!RST_B)
            DATA_OUT <= 1'b0;
        else if(!IN_VALID || MODE == 2'b11)//IN_VALID = 0或者MODE = 2'b11时,无效
            DATA_OUT <= 1'b0;
        else
            begin
                case(state)
                    INCREMEN_STATE3   :begin
                                if((DATA_IN == data_in_delay + 1'b1) && (MODE == 2'b00))
                                    DATA_OUT <= DATA_IN;
                                else
                                    DATA_OUT <= 1'b0;
                             end   
                    DECREMENT_STATE3   :begin
                                if((DATA_IN + 1'b1 == data_in_delay) && (MODE == 2'b01))
                                    DATA_OUT <= DATA_IN;
                                else
                                    DATA_OUT <= 1'b0;
                             end 
                    EQUAL_STATE3   :begin
                                if((DATA_IN == data_in_delay) && (MODE == 2'b10))
                                    DATA_OUT <= DATA_IN;
                                else
                                    DATA_OUT <= 1'b0;
                             end 
                    default :       DATA_OUT <= 1'b0;
                endcase
            end
    end 

这样,我们的RTL代码就写完了,编译没有报错后就可以写testbench了。

也可以看一下生成的状态机。
在这里插入图片描述

三、testbench

​ 按照波形图编写就行

`timescale 1ns/1ns

module tb();

reg             RST_B       ;
reg             SYSCLK      ;
reg             IN_VALID    ;
reg     [1:0]   MODE        ;
reg     [3:0]   DATA_IN     ;

wire            OUT_VALID   ;
wire    [3:0]   DATA_OUT    ;

initial
    begin
        RST_B       <= 1'b0;
        SYSCLK      <= 1'b1;
        IN_VALID    <= 1'b0;
        MODE        <= 2'd0;
        DATA_IN     <= 4'd0;
        #200
        RST_B       <= 1'b1;
        #20 DATA_IN     <= 4'd1;
        #20 DATA_IN     <= 4'd2;
        #20 DATA_IN     <= 4'd3;
        #20 DATA_IN     <= 4'd4;
        #20 DATA_IN     <= 4'd5;
        #20 IN_VALID    <= 1'b1;
            DATA_IN     <= 4'd6;
        #20 DATA_IN     <= 4'd7;
        #20 DATA_IN     <= 4'd8;
        #20 DATA_IN     <= 4'd9;
        #20 DATA_IN     <= 4'd9;
        #20 IN_VALID    <= 1'b0;
        #20 IN_VALID    <= 1'b1;
            MODE        <= 2'd1;
            DATA_IN     <= 4'd6;
        #20 DATA_IN     <= 4'd5;
        #20 DATA_IN     <= 4'd4;
        #20 DATA_IN     <= 4'd3;
        #20 DATA_IN     <= 4'd0;
        #20 IN_VALID    <= 1'b0;
        #20 IN_VALID    <= 1'b1;    
            MODE        <= 2'd2;
            DATA_IN     <= 4'd11;
        #80 DATA_IN     <= 4'd0;
        #20 IN_VALID    <= 1'b0;
        #20 IN_VALID    <= 1'b1;
            MODE        <= 2'd0;
            DATA_IN     <= 4'd4;
        #20 DATA_IN     <= 4'd5;
        #20 DATA_IN     <= 4'd6;
        #20 MODE        <= 2'd1;
            DATA_IN     <= 4'd7;
        #20 DATA_IN     <= 4'd6;
        #20 DATA_IN     <= 4'd5;
        #20 DATA_IN     <= 4'd4;
        #20 MODE        <= 2'd0;
            DATA_IN     <= 4'd5;
        #20 DATA_IN     <= 4'd6;
        #20 DATA_IN     <= 4'd7;
        #20 DATA_IN     <= 4'd8;
        #20 MODE        <= 2'd2;
        #80 IN_VALID    <= 1'b0;
            MODE        <= 2'b0;
        #80 DATA_IN     <= 4'd0;
        #20 IN_VALID    <= 1'b1;
        #20 IN_VALID    <= 1'b0;
            DATA_IN     <= 4'd1;
        #20 IN_VALID    <= 1'b1;  
        #20 DATA_IN     <= 4'd2;
            IN_VALID    <= 1'b0;
        #20 DATA_IN     <= 4'd3;    
        #20 DATA_IN     <= 4'd2;
            IN_VALID    <= 1'b1;
        #20 IN_VALID    <= 1'b0;
            MODE        <= 2'd2;
        #20 DATA_IN     <= 4'd3;
            MODE        <= 2'd1;
        #20 IN_VALID    <= 1'b1;   
            MODE        <= 2'd0;
        #20 IN_VALID    <= 1'b0;    
            DATA_IN     <= 4'd1;
            MODE        <= 2'd1;
        #20 MODE        <= 2'd2;
            DATA_IN     <= 4'd2;           
        #20 IN_VALID    <= 1'b1;
            MODE        <= 2'd0;
            DATA_IN     <= 4'd4; 
        #20 MODE        <= 2'd2;
            DATA_IN     <= 4'd0; 
        #20 MODE        <= 2'd0;   
        #20 MODE        <= 2'd3;
            DATA_IN     <= 4'd1;    
        #20 MODE        <= 2'd0;               
        #20 MODE        <= 2'd3;   
            DATA_IN     <= 4'd2;
        #20 DATA_IN     <= 4'd3;               
        #20 MODE        <= 2'd0;   
            DATA_IN     <= 4'd2;        
        #20 MODE        <= 2'd3;
        #20 DATA_IN     <= 4'd3;
        #20 MODE        <= 2'd0;
        #20 DATA_IN     <= 4'd1;
        
    end

always#10 SYSCLK <= ~SYSCLK;


SEQ_DETECTOR    SEQ_DETECTOR_inst
(
    .RST_B       (RST_B),
    .SYSCLK      (SYSCLK),
    .IN_VALID    (IN_VALID),
    .MODE        (MODE), 
    .DATA_IN     (DATA_IN),

    .OUT_VALID   (OUT_VALID),
    .DATA_OUT    (DATA_OUT)
);



endmodule

任务完成!

欢迎在评论区留言,感谢你的支持!!!

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

堂钰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值