题解 | #不重叠序列检测#

不重叠序列检测

http://www.nowcoder.com/practice/9f91a38c74164f8dbdc5f953edcc49cc

1、状态机解法: 参考这个https://blog.nowcoder.net/n/5e18f294df6642bebb39f5b6e47df908?f=comment 状态机画的很好不重叠序列检测使用了zero和fail两个状态就很合理。 alt

1.1) 问题:cnt到底计数到5还是6啊?

第六个上升沿输出,所以应该计数到6

1.2) 计数到6后从1开始重新计数

是因为six跳转到one,且fail跳转到1,所以应该从1开始计数。合理,因为第二波序列到来时就是从1开始计数的才对。

1.3 正确的计数模块:计数到6后从1开始重新计数

    //计数模块
    always @ (posedge clk, negedge rst_n) begin
        if(!rst_n) begin
            cnt <= 3'd0;
        end
        else 
            cnt <= (cnt == 3'd6) ? 3'd0 : (cnt + 3'd1);

    end  

状态机正确代码:比较繁琐,可化简。

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input data,
	output reg match,
	output reg not_match
	);
    parameter [2:0] zero = 3'd0, one= 3'd1, two= 3'd2, three= 3'd3, four= 3'd4,  five= 3'd5, six= 3'd6,  fail= 3'd7;      
    reg [2:0] state, next_state, cnt;
    
    //时序模块,状态转移
    always @ (posedge clk, negedge rst_n) begin
        if(!rst_n) begin
            state <= zero;
        end
        else begin
            state <= next_state;
        end
    end
    
    //计数模块
    always @ (posedge clk, negedge rst_n) begin
        if(!rst_n) begin
            cnt <= 3'd0;
        end
        else 
            cnt <= (cnt == 3'd6) ? 3'd1 : (cnt + 3'd1);

    end    
    //组合逻辑 状态转移模块
    always @ (*) begin
        if(!rst_n)
            next_state = zero;
        else begin
        case(state) 
            zero: next_state <= data ? fail : one;
            one: begin
                if(data) //if else 太繁琐,应该使用? : 运算符。
                    next_state = two;
                else
                    next_state = fail;
            end
            two: begin
                if(data)
                    next_state = three;
                else
                    next_state = fail;
            end 
            three: begin
                if(data)
                    next_state = four;
                else
                    next_state = fail;
            end  
            four: begin
                if(data)
                    next_state = fail;
                else
                    next_state = five;
            end  
            five: begin
                if(data)
                    next_state = fail;
                else
                    next_state = six;
            end
            six: begin
                if(data)
                    next_state = fail;
                else
                    next_state = one;
            end
            fail: begin
                if(~data && cnt == 3'd6)
                    next_state = one;//fail跳变到1
                else
                    next_state = fail;
            end 
            default: next_state = zero;
            
        endcase
        end

    end

    //输出模块
    always @ (*) begin
        if(!rst_n) begin
            match = 1'b0;
            not_match = 1'b0;
        end
        else begin
            match = (cnt == 3'd6) && (state == six);
            not_match = (cnt == 3'd6) && (state == fail);
        end
    end
endmodule

2 移位寄存器

2.1 首先探讨cnt计时cnt==5和cnt==6的区别

alt

由这张图可以看出,首先flag_1是在cnt为2和4发生反转,所以,当cnt在第三个时钟上升沿递增为3的时候,在flag_1模块内还是使用cnt=2

2.2 不管状态机还是移位寄存器,如果计数到6才置位的话必须重新开始从1开始计数才可以正确.很合理,因为第二波序列到来时就是从1开始计数的才对。

    //counter
    always @ (posedge clk, negedge rst_n) begin
        if(!rst_n) begin
            cnt <= 3'd0;
        end
        else 
            cnt <= (cnt == 3'd6) ? 3'd1 : (cnt + 3'd1);
    end

2.3 自己修改的移位寄存器解法;计数到6,match赋值用组合逻辑实现

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input data,
	output reg match,
	output reg not_match
	);
    parameter t_seq = 6'b011100;
    reg [5:0] seq;
    reg [2:0] cnt;

    //counter
    always @ (posedge clk, negedge rst_n) begin
        if(!rst_n) begin
            cnt <= 3'd0;
        end
        else 
            cnt <= (cnt == 3'd6) ? 3'd1 : (cnt + 3'd1);
    end
    
    always @ (posedge clk, negedge rst_n) begin
        if(!rst_n) begin
            seq <= 6'd0;
        end
        else begin
            seq <= {seq[4:0], data};
        end
    end 
    
    always @ (*) begin
        if(!rst_n) begin
            match <= 1'b0;
            not_match <= 1'b0;
        end
        else begin
//             match <= (cnt == 3'd5) && ({seq[4:0], data} == t_seq);
//             not_match <= (cnt == 3'd5) && ({seq[4:0], data} != t_seq);
            match <= (cnt == 3'd6) && (seq == t_seq);
            not_match <= (cnt == 3'd6) && (seq != t_seq);        
        end
    end 

endmodule

2.4 如果要计数到5,那么match的赋值必须要在时序模块内,第六个上升沿到达时,match赋值模块内cnt还是以5来计算,此时最新的data还没有移位到seq中,需要手动拼接一下才可以

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input data,
	output reg match,
	output reg not_match
	);
    parameter t_seq = 6'b011100;
    reg [5:0] seq;
    reg [2:0] cnt;

    //counter
    always @ (posedge clk, negedge rst_n) begin
        if(!rst_n) begin
            cnt <= 3'd0;
        end
        else 
            cnt <= (cnt == 3'd5) ? 3'd0 : (cnt + 3'd1);
    end
    
    always @ (posedge clk, negedge rst_n) begin
        if(!rst_n) begin
            seq <= 6'd0;
        end
        else begin
            seq <= {seq[4:0], data};
        end
    end 
    
    always @ (posedge clk, negedge rst_n) begin
        if(!rst_n) begin
            match <= 1'b0;
            not_match <= 1'b0;
        end
        else begin
            match <= (cnt == 3'd5) && ({seq[4:0], data} == t_seq);
            not_match <= (cnt == 3'd5) && ({seq[4:0], data} != t_seq);
//             match <= (cnt == 3'd5) && (seq == t_seq);
//             not_match <= (cnt == 3'd5) && (seq != t_seq);        
        end
    end 

endmodule

3 正确解法:还是移位寄存器

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input data,
	output reg match,
	output reg not_match
	);
reg [5:0] seq;
reg [3:0] counter;
 
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        seq <= 6'b0;
        match <= 1'b0;
        not_match <= 1'b0;
    end
    else
        seq <= { seq[4:0], data };
end
 
always@(posedge clk) begin
    if(!rst_n) begin
        counter <= 0;
    end
    else if(counter=='d5)
        counter <= 0;
    else begin
        counter <= counter + 1;
    end
end
 
always@(posedge clk)begin
    if( {seq[4:0],data}==6'b011100 && counter=='d5 ) begin
        match <= 1;
    end
    else begin
        match <= 0;
    end
end
 
always@(posedge clk)begin
    if( {seq[4:0],data}!=6'b011100 && counter=='d5 ) begin
        not_match <= 1;
    end
    else begin
        not_match <= 0;
    end
end    
endmodule

总结:如果match使用时序模块进行赋值,则cnt计数到5即可,如果match使用组合逻辑赋值,则需要计数到6。 是否可以这样总结:对于序列检测,如果match使用时序模块进行赋值,则cnt计数到(序列长度-1)即可,如果match使用组合逻辑赋值,则需要计数到(序列长度)

全部评论

相关推荐

05-29 09:02
门头沟学院 Java
点赞 评论 收藏
分享
评论
12
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务