当前位置:   article > 正文

HDLBits答案(19)_Verilog有限状态机(6)_verilog 状态机考试题

verilog 状态机考试题

Verilog有限状态机(6)

HDLBits链接


前言

今天继续更新状态机小节的习题。


题库

Fsm hdlc

同步帧检测涉及对数据的连续位流进行解码,以寻找指示帧(数据包)开始和结束的位模式。 6个连续的1(即01111110)是表示帧边界的“标志”。 为了避免数据流意外包含“标志”,发送方必须在接收方必须检测并丢弃的每5个连续的1秒后插入一个零。 如果连续7个或更多1,我们还需要发出错误信号。

可以通过状态机来识别下面三种序列:

0111110:表示5个1后面的0bit需被忽略;

01111110:表示一帧的开始或结束;

01111111…:错误

当状态机被复位时,它应当表现为之前的输入为0;

下面是三种波形示例:

pic1.png

pic2.png

pic3.png

官方提供的状态机设计提示:

pic4.png

Solution:

//----------------way1----------------------
module top_module(
    input clk,
    input reset,    // Synchronous reset
    input in,
    output disc,
    output flag,
    output err);

    parameter NONE = 4'd0,ONE = 4'd1,TWO = 4'd2;
    parameter THREE = 4'd3,FOUR = 4'd4,FIVE = 4'd5;
    parameter SIX = 4'd6,ERROR = 4'd7;
    parameter DISC = 4'd8,FLAG = 4'd9;

    reg [3:0] current_state,next_state;

    always @(*) begin
        case(current_state)
            NONE:begin
                next_state = in ? ONE : NONE;
            end
            ONE:begin
                next_state = in ? TWO : NONE;
            end
            TWO:begin
                next_state = in ? THREE : NONE;
            end
            THREE:begin
                next_state = in ? FOUR : NONE;
            end
            FOUR:begin
                next_state = in ? FIVE : NONE;
            end
            FIVE:begin
                next_state = in ? SIX : DISC;
            end
            SIX:begin
                next_state = in ? ERROR : FLAG;
            end
            DISC:begin
                next_state = in ? ONE : NONE;
            end
            FLAG:begin
                next_state = in ? ONE : NONE;
            end
            ERROR:begin
                next_state = in ? ERROR : NONE;
            end
        endcase
    end

    always @(posedge clk) begin
        if(reset)begin
            current_state <= NONE;
        end
        else begin
            current_state <= next_state;
        end
    end

    always @(posedge clk) begin
        if(reset)begin
            disc <= 1'd0;
            flag <= 1'd0;
            err  <= 1'd0;
        end
        else begin
            case(next_state)
                DISC:begin
                    disc <= 1'd1;
                    flag <= 1'd0;
                    err  <= 1'd0;
                end
                FLAG:begin
                    disc <= 1'd0;
                    flag <= 1'd1;
                    err  <= 1'd0;
                end
                ERROR:begin
                    disc <= 1'd0;
                    flag <= 1'd0;
                    err  <= 1'd1;
                end
                default:begin
                    disc <= 1'd0;
                    flag <= 1'd0;
                    err  <= 1'd0;
                end
            endcase
        end
    end

endmodule
//----------------way2----------------------
module top_module(
    input clk,
    input reset,    // Synchronous reset
    input in,
    output disc,
    output flag,
    output err);

    parameter NONE = 3'd0,DATA = 3'd1;
    parameter DISC = 3'd2,FLAG = 3'd3,ERROR = 3'd4;

    reg [2:0] current_state,next_state;
    reg [2:0] counter;

    always @(*) begin
        case(current_state)
            NONE:begin
                next_state = in ? DATA : NONE;
            end
            DATA:begin
                case(counter)
                    3'd5:   next_state = in ? DATA : DISC;
                    3'd6:   next_state = in ? ERROR : FLAG;
                    default:next_state = in ? DATA : NONE;
                endcase
            end
            DISC:begin
                next_state = in ? DATA : NONE;
            end
            FLAG:begin
                next_state = in ? DATA : NONE;
            end
            ERROR:begin
                next_state = in ? ERROR : NONE;
            end
        endcase
    end

    always @(posedge clk) begin
        if(reset)begin
            current_state <= NONE;
        end
        else begin
            current_state <= next_state;
        end
    end

    always @(posedge clk) begin
        if(reset)begin
            disc <= 1'd0;
            flag <= 1'd0;
            err  <= 1'd0;
            counter <= 3'd0;
        end
        else begin
            case(next_state)
                DATA:begin
                    disc <= 1'd0;
                    flag <= 1'd0;
                    err  <= 1'd0;
                    counter <= counter + 1'd1;
                end
                DISC:begin
                    disc <= 1'd1;
                    flag <= 1'd0;
                    err  <= 1'd0;
                    counter <= 3'd0;
                end
                FLAG:begin
                    disc <= 1'd0;
                    flag <= 1'd1;
                    err  <= 1'd0;
                    counter <= 3'd0;
                end
                ERROR:begin
                    disc <= 1'd0;
                    flag <= 1'd0;
                    err  <= 1'd1;
                    counter <= 3'd0;
                end
                default:begin
                    disc <= 1'd0;
                    flag <= 1'd0;
                    err  <= 1'd0;
                    counter <= 3'd0;
                end
            endcase
        end
    end

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185

其中way1与题目提示的思路相同,其中第三段状态机一开始忘记加reset的那种情况,果然还是长时间没接触verilog手生了,以后继续练习;

way2使用counter去掉中间状态,靠输入和counter的值来决定状态转移,是一种米利状态机的思想;状态转移图如下(手绘有点丑,见谅):

pic5.jpg

米利型状态机

检测输入的X中”101“是否出现,出现的话输出Z为1,否则为0。复位为异步低电平复位;只允许出现3种状态;允许交叠检测:即输入若为10101时,Z应该在时刻3和时刻5各输出一次1;

代码中主要妙在两处:一是如何用3种状态表示,需在第三种状态中将输出与输入关联起来;二是如何进行交叠检测,状态的转移有妙处;

Solution

module top_module (
    input clk,
    input aresetn,    // Asynchronous active-low reset
    input x,
    output z ); 

    parameter S0 = 2'd0,S1 = 2'd1,S2 = 2'd2;
    reg [1:0] current_state,next_state;

    always @(*) begin
        case(current_state)
            S0: next_state = x ? S1 : S0;
            S1: next_state = x ? S1 : S2;
            S2: next_state = x ? S1 : S0;
        endcase
    end

    always @(posedge clk or negedge aresetn) begin
        if(~aresetn)begin
            current_state <= S0;
        end
        else begin
            current_state <= next_state;
        end
    end

    always @(*) begin
        z = (current_state == S2) ? x : 1'b0;
    end

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

Q5a:Serial two’s complementer(Moore FSM)

pic6.png

作者这里假设我们这边输入的都是负数,不用管符号位的问题;即补码全部都是取反加1求得。

以上图为例,输入的左边为低位数据,右边为高位数据;即输入为00110100,则取反加1后得输出为11001100;

取反操作好进行,主要麻烦在加一的操作上,不知道进位到哪一位为止,此时我们用状态机来解决;若最前面的输入都是0的话,取反均为1,低位加1的时候一直进位,则输出都是0,直到输入有个1为止(取反加1不进位),这一阶段我们用一个状态S0来表示;后面阶段就将输入取反进行输出即可,因为进位链在S0状态已结束;

因为是摩尔型状态机,输出的结果与输入无关,仅与状态有关。所以我们这里用到3个状态,代码如下所示:

Solution

module top_module (
    input clk,
    input areset,
    input x,
    output z
); 

    parameter S0 = 2'd0, S1 = 2'd1, S2 = 2'd2;
    reg [1:0] current_state, next_state;

    always @(*) begin
        case(current_state)
            S0:     next_state = x ? S1 : S0;
            S1:     next_state = x ? S2 : S1;
            S2:     next_state = x ? S2 : S1;
        endcase
    end

    always @(posedge clk or posedge areset) begin
        if(areset)begin
            current_state <= S0;
        end
        else begin
            current_state <= next_state;
        end
    end

    assign z = (current_state == S1);

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

Q5b:Serial two’s complementer(Mealy FSM)

题意与上题相同,此时用米利型状态机实现。下面是官方提供的状态转移提示:

pic7.png

module top_module (
    input clk,
    input areset,
    input x,
    output z
); 

    parameter S0 = 1'b0, S1 = 1'b1;
    reg current_state,next_state;

    always @(*) begin
        case(current_state)
            S0:     next_state = x ? S1 : S0;
            S1:     next_state = S1;
        endcase
    end

    always @(posedge clk or posedge areset) begin
        if(areset)begin
            current_state <= S0;
        end
        else begin
            current_state <= next_state;
        end
    end

    assign z = ((current_state == S0) && x) || ((current_state == S1) && ~x);

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

结语

今天先更新这几题吧,大家如果对转补码的题目还有什么疑问欢迎评论交流,代码有不足之处还望指正。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/915664
推荐阅读
相关标签
  

闽ICP备14008679号