当前位置:   article > 正文

HDLBits答案(18)_Verilog有限状态机(5)_verilog有限状态机例题

verilog有限状态机例题

Verilog有限状态机(5)

HDLBits链接


前言

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


题库

题目描述1:

第一道题目比较容易,题目中的in信号包含了一个起始位(0),8个数据位和一个停止位(1),开始in为1,也就是IDLE状态,当in为0时,进入START状态,然后经过8个周期,如果in为1,则进入STOP状态,接着如果in为0,进入第二轮START状态,否则进入IDLE状态。

这里我用了很多个状态,实际上可以用计数器来代替中间的8个状态,这里是8个周期,如果是100个、200个周期,那么需要100个、200个状态,显然不现实。这道题目是三道题目中的基础题,大家不用考虑那么多,直接完成就好了。

3.png

Solution1:

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output done
); 
    parameter [3:0] START = 4'd0;
    parameter [3:0] ONE = 4'd1;
    parameter [3:0] TWO = 4'd2;
    parameter [3:0] THREE = 4'd3;
    parameter [3:0] FOUR = 4'd4;
    parameter [3:0] FIVE = 4'd5;
    parameter [3:0] SIX = 4'd6;
    parameter [3:0] SEVEN = 4'd7;
    parameter [3:0] EIGHT = 4'd8;
    parameter [3:0] STOP = 4'd9;
    parameter [3:0] IDLE = 4'd10;
    parameter [3:0] WAIT = 4'd11;
    
    reg [3:0] state,next_state;
    
    always @(*)begin
        case(state)
            START:begin
                next_state = ONE;
            end
            ONE:begin
                next_state = TWO;
            end
            TWO:begin
                next_state = THREE;
            end
            THREE:begin
                next_state = FOUR;
            end
            FOUR:begin
                next_state = FIVE;
            end
            FIVE:begin
                next_state = SIX;
            end
            SIX:begin
                next_state = SEVEN;
            end
            SEVEN:begin
                next_state = EIGHT;
            end
            EIGHT:begin
                if(in)begin
                    next_state = STOP;
                end
                else begin
                    next_state = WAIT;
                end
            end
            STOP:begin
                if(in)begin
                    next_state = IDLE;
                end
                else begin
                    next_state = START;
                end
            end
            WAIT:begin
                if(in)begin
                    next_state = IDLE;
                end
                else begin
                    next_state = WAIT;
                end
            end
            IDLE:begin
                if(~in)begin
                    next_state = START;
                end
                else begin
                    next_state = IDLE;
                end
            end
        endcase
    end
    
    always @(posedge clk)begin
        if(reset)begin
            state <= IDLE;
        end
        else begin
            state <= next_state;
        end
    end
    
    assign done = (state == STOP);

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

题目描述2:

这道题目是上一道题目的扩展,不仅需要输出done信号,还需要输出数据。

4.png

Solution2:

/* way 1*/
module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output [7:0] out_byte,
    output done
); //
    
    parameter [3:0] START = 4'd0;
    parameter [3:0] ONE = 4'd1;
    parameter [3:0] TWO = 4'd2;
    parameter [3:0] THREE = 4'd3;
    parameter [3:0] FOUR = 4'd4;
    parameter [3:0] FIVE = 4'd5;
    parameter [3:0] SIX = 4'd6;
    parameter [3:0] SEVEN = 4'd7;
    parameter [3:0] EIGHT = 4'd8;
    parameter [3:0] STOP = 4'd9;
    parameter [3:0] IDLE = 4'd10;
    parameter [3:0] WAIT = 4'd11;
    
    reg [3:0] state,next_state;
    
    reg [7:0]	par_in;
    
    always @(*)begin
        case(state)
            START:begin
                next_state = ONE;
                par_in[0] = in;
            end
            ONE:begin
                next_state = TWO;
                par_in[1] = in;
            end
            TWO:begin
                next_state = THREE;
                par_in[2] = in;
            end
            THREE:begin
                next_state = FOUR;
                par_in[3] = in;
            end
            FOUR:begin
                next_state = FIVE;
                par_in[4] = in;
            end
            FIVE:begin
                next_state = SIX;
                par_in[5] = in;
            end
            SIX:begin
                next_state = SEVEN;
                par_in[6] = in;
            end
            SEVEN:begin
                next_state = EIGHT;
                par_in[7] = in;
            end
            EIGHT:begin
                if(in)begin
                    next_state = STOP;
                end
                else begin
                    next_state = WAIT;
                end
            end
            STOP:begin
                if(in)begin
                    next_state = IDLE;
                end
                else begin
                    next_state = START;
                end
            end
            WAIT:begin
                if(in)begin
                    next_state = IDLE;
                end
                else begin
                    next_state = WAIT;
                end
            end
            IDLE:begin
                if(~in)begin
                    next_state = START;
                end
                else begin
                    next_state = IDLE;
                end
            end
        endcase
    end
    
    always @(posedge clk)begin
        if(reset)begin
            state <= IDLE;
        end
        else begin
            state <= next_state;
        end
    end
    
    assign done = (state == STOP);
    assign out_byte = (state == STOP) ? par_in : 8'd0;

endmodule

/* way 2 */
module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output [7:0] out_byte,
    output done
); 
	parameter IDLE = 3'd0, START = 3'd1, DATA = 3'd2;
    parameter STOP = 3'd3, WAIT = 3'd4;
    reg [3:0]	current_state;
    reg [3:0]	next_state;
    reg [3:0]	counter;
    reg [7:0]	par_in;
    // Use FSM from Fsm_serial
    always @(*)begin
        case(current_state)
            IDLE:begin
                if(~in)begin
                    next_state = START;
                end
                else begin
                    next_state = IDLE;
                end
            end
            START:begin
                next_state = DATA;
            end
            DATA:begin
                if(counter == 4'd8)begin
                    next_state = in? STOP:WAIT;
                end
                else begin
                    next_state = DATA;
                end
            end
            STOP:begin
                next_state = in? IDLE:START;
            end
            WAIT:begin
                next_state = in? IDLE:WAIT;
            end
            default:begin
                next_state = IDLE;
            end
        endcase
    end
    
    always @(posedge clk)begin
        if(reset)begin
            current_state <= IDLE;
        end
        else begin
            current_state <= next_state;
        end
    end

    always @(posedge clk)begin
        if(reset)begin
            done <= 1'd0;
            out_byte <= 8'd0;
            counter <= 4'd0;
        end
        else begin
            case(next_state)
                IDLE:begin
                    done <= 1'd0;
           		    out_byte <= 8'd0;
            		counter <= 4'd0;
                end
                START:begin
                    done <= 1'd0;
           		    out_byte <= 8'd0;
            		counter <= 4'd0;
                end
                DATA:begin
                    done <= 1'd0;
           		    out_byte <= 8'd0;
                    par_in[counter] <= in;
            		counter <= counter + 1'd1;
                end
                STOP:begin
                    done <= 1'd1;
           		    out_byte <= par_in;
            		counter <= 4'd0;
                end
                WAIT:begin
                    done <= 1'd0;
           		    out_byte <= 8'd0;
            		counter <= 4'd0;
                end
            endcase
        end
    end
    // New: Datapath to latch input bits.

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
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206

上述第一种解法虽然正确,但是会生成锁存器,并且这里只有1个字节数据还好,用8个状态是可以的,如果换成了10个字节、100个字节,难道要80、800个状态吗?这是不可能的,于是便诞生了方法二博主最想让大家使用的方法。大家可以好好看一下,这里将8个数据状态定义成了一个DATA状态,不用定义S1、S2、S3什么的了,在状态机的第三段,将除了DATA状态的其他状态时的counter都清零,只有到了DATA状态时开始计数,顺便将par_in中的位数用counter代替,这样只需要增加counter和out_byte的位宽,就可以实现任意宽度数据的输出,实用性强。

题目描述3:

较上题添加了奇偶校验位。

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output [7:0] out_byte,
    output done
); //
	
    parameter IDLE = 3'd0,START = 3'd1,DATA = 3'd2;
    parameter STOP = 3'd3,WAIT = 3'd4;

    reg [2:0] current_state,next_state;
    reg [3:0] counter;
    reg [8:0] data_in;
    reg odd_temp;
    wire Isdone;

    // Modify FSM and datapath from Fsm_serialdata
    always @(*) begin
        case(current_state)
            IDLE:begin
                if(~in)begin
                    next_state = START;
                end
                else begin
                    next_state = IDLE;
                end
            end
            START:begin
                next_state = DATA;
            end
            DATA:begin
                if(counter == 4'd9)begin
                    next_state = in ? STOP : WAIT;
                end
                else begin
                    next_state = DATA;
                end
            end
            STOP:begin
                next_state = in ? IDLE : START;
            end
            WAIT:begin
                next_state = in ? IDLE : WAIT;
            end
            default:begin
                next_state = IDLE;
            end
        endcase
    end

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

    always @(posedge clk) begin
        if(reset)begin
            done <= 1'd0;
            out_byte <= 8'd0;
            counter <= 4'd0;
        end
        else begin
            case(next_state)
                IDLE:begin
                    done <= 1'd0;
                    out_byte <= 8'd0;
                    counter <= 4'd0;
                end
                START:begin
                    done <= 1'd0;
                    out_byte <= 8'd0;
                    counter <= 4'd0;
                end
                DATA:begin
                    done <= 1'd0;
                    out_byte <= 8'd0;
                    counter <= counter + 1'd1;
                    data_in[counter] <= in;
                end
                STOP:begin
                    done <= odd_temp ? 1'd1 : 1'd0;
                    out_byte <= odd_temp ? data_in[7:0] : 8'd0;
                    counter <= 4'd0;
                end
                WAIT:begin
                    done <= 1'd0;
                    out_byte <= 8'd0;
                    counter <= 4'd0;
                end
            endcase
        end
    end
    // New: Add parity checking.
    assign Isdone = (next_state == START);
    parity u0(clk,Isdone,in,odd_temp);

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

该题答案与上题类似,这里我将奇偶校验位数据也计算在DATA状态内,判断起来相对较容易,大家可以借鉴一下。

注意作者在题目中给了奇偶校验的模块,大家直接调用即可。

结语

好久没更新HDLBits了,寒假在家闲来无事,希望勉励自己把HDLBits刷完吧,加油!有问题的地方欢迎大家与我讨论交流。

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

闽ICP备14008679号