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个状态,显然不现实。这道题目是三道题目中的基础题,大家不用考虑那么多,直接完成就好了。
Solution1:
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 module top_module( input clk, input in, input 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
题目描述2:
这道题目是上一道题目的扩展,不仅需要输出done信号,还需要输出数据。
Solution2:
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 module top_module( input clk, input in, input 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 module top_module( input clk, input in, input 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; 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 endmodule
上述第一种解法虽然正确,但是会生成锁存器,并且这里只有1个字节数据还好,用8个状态是可以的,如果换成了10个字节、100个字节,难道要80、800个状态吗?这是不可能的,于是便诞生了方法二 博主最想让大家使用的方法。大家可以好好看一下,这里将8个数据状态定义成了一个DATA状态,不用定义S1、S2、S3什么的了,在状态机的第三段,将除了DATA状态的其他状态时的counter都清零 ,只有到了DATA状态时开始计数 ,顺便将par_in中的位数用counter代替 ,这样只需要增加counter和out_byte的位宽,就可以实现任意宽度数据的输出,实用性强。
题目描述3:
较上题添加了奇偶校验位。
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 module top_module( input clk, input in, input 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; 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 assign Isdone = (next_state == START); parity u0(clk,Isdone,in,odd_temp); endmodule
该题答案与上题类似,这里我将奇偶校验位数据也计算在DATA状态内,判断起来相对较容易,大家可以借鉴一下。
注意作者在题目中给了奇偶校验的模块,大家直接调用即可。
结语 好久没更新HDLBits了,寒假在家闲来无事,希望勉励自己把HDLBits刷完吧,加油!有问题的地方欢迎大家与我讨论交流。