Verilog实现状态机与状态机经典示例——序列检测器、自动饮料售卖机

原文链接:https://blog.csdn.net/qq_34070723/article/details/100737225
作者:King阿金

目录

1.状态机原理与三段式状态机

2.状态机示例

2.1自动饮料售卖机/卖报机

2.2序列检测器


1.状态机原理与三段式状态机

MOORE 与 MEALEY 状态机的特征?
Moore 状态机的输出仅与当前状态值有关, 且只在时钟边沿到来时才会有状态变化。次态=f(现状,输入),输出=f(现状)
Mealy 状态机的输出不仅与当前状态值有关, 而且与当前输入值有关。次态=f(现状,输入),输出=f(现状,输入)
描述同一个事务,mealy的状态更少。

通用mealy三段式状态机(建议实际工程中采用的结构)


  
  
  1. //------采用独热码或格雷码或其他方式编码状态
  2. parameter IDLE = ...
  3. parameter S0 = ...
  4. ...
  5. reg [x: 0] curr_state;
  6. reg [x: 0] next_state;
  7. //------每个时钟只产生一次状态变化
  8. always @(posedge clk or posedge asy_rst)
  9. begin
  10. if(asy_rst) curr_state <= IDLE ;
  11. else curr_state <= next_state;
  12. end
  13. //------产生的下一状态的组合逻辑
  14. always @(*)
  15. begin
  16. next_state = 'bx;
  17. case(curr_state)
  18. IDLE: if(输入) next_state = S0 ; else...;
  19. S0: if(输入) next_state = ...;
  20. ...
  21. default: next_state = ...;
  22. endcase
  23. end
  24. /************************时序或组合二选一***********************/
  25. //------时序逻辑输出(比组合逻辑延时一个时钟)
  26. always@(posedge clk or posedge asy_rst)
  27. begin
  28. if(asy_rst)out<= ...;
  29. else
  30. case(curr_state)
  31. sO: if(...) out <= ...;
  32. sO: if(...) out <= ...;
  33. default: out <= ...;
  34. endcase
  35. end
  36. //------组合逻辑输出 采用 assign 或always
  37. always @(*)
  38. begin
  39. if(asy_rst)out = ...;
  40. else
  41. case(curr_state)
  42. sO: if(...) out = ...;
  43. sO: if(...) out = ...;
  44. default: out = ...;
  45. endcase
  46. end
  47. /***********************************************************/

2.状态机示例

2.1自动饮料售卖机/卖报机

题目:商品是5分钱,只能投3种硬币:1分,2分,5分,考虑找零。

思路1:采用状态机,共分为5个状态,S0-S4代表已经投入的钱,画出状态转换图(略),采用三段式mealy状态机。

思路2:(更简单)不采用状态机,直接对输入的钱进行加法运算,多余5分就输出和找零,同时将内部加法器清零。

另一个版本:用Verilog实现接受0.5元,1元的可乐售卖机,单价2.5元,考虑找零和出货。


  
  
  1. module auto_sell_better #(
  2. parameter I_WD = 4 , O_WD = 4
  3. )(
  4. input clk,
  5. input asy_rst,
  6. input [I_WD -1: 0] i_dat,
  7. input i_val,
  8. output reg [O_WD -1: 0] o_money, //找零
  9. output reg o_goods //商品
  10. );
  11. parameter S0= 4 'b0000;
  12. parameter S1=4'b0001; //1分钱
  13. parameter S2= 4 'b0010;
  14. parameter S3=4'b0100;
  15. parameter S4= 4 'b1000; //4分钱
  16. reg [3:0] curr_s;
  17. reg [3:0] next_s;
  18. //每个时钟只产生一次状态变化
  19. always @(posedge clk or posedge asy_rst)
  20. begin
  21. if(asy_rst)
  22. curr_s <= S0;
  23. else
  24. curr_s <= next_s;
  25. end
  26. //产生的下一状态的组合逻辑
  27. always @(*)
  28. begin
  29. next_s = 'dx;
  30. case(curr_s)
  31. S0: if(i_dat == 1) next_s = S1;
  32. else if(i_dat == 2) next_s = S2;
  33. else if(i_dat == 5) next_s = S0;
  34. else next_s = S0;
  35. S1: if(i_dat == 1) next_s = S2;
  36. else if(i_dat == 2) next_s = S3;
  37. else if(i_dat == 5) next_s = S0;
  38. else next_s = S1;
  39. S2: if(i_dat == 1) next_s = S3;
  40. else if(i_dat == 2) next_s = S4;
  41. else if(i_dat == 5) next_s = S0;
  42. else next_s = S2;
  43. S3: if(i_dat == 1) next_s = S4;
  44. else if(i_dat == 2) next_s = S0;
  45. else if(i_dat == 5) next_s = S0;
  46. else next_s = S3;
  47. S4: if(i_dat == 1) next_s = S0;
  48. else if(i_dat == 2) next_s = S0;
  49. else if(i_dat == 5) next_s = S0;
  50. else next_s = S4;
  51. default: next_s = S0;
  52. endcase
  53. end
  54. /**************************时序逻辑的输出*******************************/
  55. always @(posedge clk or posedge asy_rst)
  56. begin
  57. if(asy_rst)
  58. begin
  59. o_money <= 0;
  60. o_goods <= 0;
  61. end
  62. else
  63. case(curr_s)
  64. S0:
  65. begin
  66. o_money <= 0;
  67. if(i_dat== 5) o_goods <= 1;
  68. else o_goods <= 0;
  69. end
  70. S1:
  71. begin
  72. if(i_dat== 5) begin o_money <= 1; o_goods <= 1; end
  73. else begin o_money <= 0; o_goods <= 0; end
  74. end
  75. S2:
  76. begin
  77. if(i_dat== 5) begin o_money <= 2; o_goods <= 1; end
  78. else begin o_money <= 0; o_goods <= 0; end
  79. end
  80. S3:
  81. begin
  82. if(i_dat== 5) begin o_money <= 3; o_goods <= 1; end
  83. else if (i_dat== 2) begin o_money <= 0; o_goods <= 1; end
  84. else begin o_money <= 0; o_goods <= 0; end
  85. end
  86. S4:
  87. begin
  88. if(i_dat== 5) begin o_money <= 4; o_goods <= 1; end
  89. else if (i_dat== 2) begin o_money <= 1; o_goods <= 1; end
  90. else if (i_dat== 1) begin o_money <= 0; o_goods <= 1; end
  91. end
  92. default :
  93. begin o_money <= 0; o_goods <= 0;end
  94. endcase
  95. end
  96. /***************************不采用状态机的方法**********************************/
  97. reg [ 3: 0] add_in; //内部计算输入的钱的和
  98. reg [ 3: 0] a_money; //找零
  99. reg a_goods; //商品
  100. always @(posedge clk or posedge asy_rst)
  101. begin
  102. if(asy_rst)
  103. begin
  104. add_in <= 0;
  105. a_money <= 0;
  106. a_goods <= 0;
  107. end
  108. else if(i_val)
  109. begin
  110. if(add_in+i_dat >= 5)
  111. begin
  112. add_in <= 0; //清零
  113. a_money <= add_in + i_dat - 5; //找零
  114. a_goods <= 1; //输出
  115. end
  116. else
  117. begin
  118. add_in <= add_in + i_dat;
  119. a_money <= 0;
  120. a_goods <= 0;
  121. end
  122. end
  123. else
  124. begin
  125. add_in <= 0;
  126. a_money <= 0;
  127. a_goods <= 0;
  128. end
  129. end
  130. endmodule
  131. /////////////////////////////////////testbench//////////////////////////////////
  132. module auto_sell_sim;
  133. parameter CLK_PERIOD = 10; //仿真周期10ns=100M
  134. parameter RST_CYCLE = 5; //复位周期数
  135. parameter RST_TIME = RST_CYCLE * CLK_PERIOD;
  136. reg sim_clk;
  137. reg sim_asy_rst;
  138. initial
  139. begin
  140. sim_clk = 0;
  141. sim_asy_rst = 1;
  142. #RST_TIME sim_asy_rst = 0;
  143. end
  144. always #(CLK_PERIOD/2) sim_clk = ~sim_clk;
  145. /******************************************************/
  146. parameter I_WD = 4;
  147. parameter O_WD = 4;
  148. reg [I_WD -1: 0]sim_dat;
  149. reg [I_WD -1: 0]sim_i_dat;
  150. reg sim_i_val;
  151. always@(posedge sim_clk or posedge sim_asy_rst)
  152. begin
  153. if(sim_asy_rst)
  154. begin
  155. sim_i_dat <= 0;
  156. sim_i_val <= 0;
  157. end
  158. else
  159. begin
  160. sim_dat <= {$random}% 6; //产生0-5的随机数
  161. if( sim_dat== 1 || sim_dat == 2 || sim_dat== 5)
  162. begin
  163. sim_i_dat <= sim_dat;
  164. sim_i_val <= 1;
  165. end
  166. else
  167. begin
  168. sim_i_dat <= 0;
  169. sim_i_val <= 1;
  170. end
  171. end
  172. end
  173. wire [O_WD -1: 0] o_money;
  174. wire o_goods;
  175. auto_sell_better auto_sell_better_u( //auto_sell auto_sell_u (
  176. .clk( sim_clk ),
  177. .asy_rst( sim_asy_rst ),
  178. .i_dat( sim_i_dat ),
  179. .i_val( sim_i_val),
  180. .o_money(o_money),
  181. .o_goods(o_goods)
  182. );

2.2序列检测器

笔试题目:如果序列长度为8,需要8个状态,最少(3)个寄存器进行状态转换(mealy)。

 题目:用状态机实现 101101 的序列检测。

思路:

画出mealy状态转换图,并进行化简[1],灰色表示合并为一个:

 如果采用moore状态机,其状态就多了,且输出比mealy延时一个时钟参考[1]:


  
  
  1. //mealy状态机
  2. module seq_detect#(
  3. parameter I_WD = 1 , O_WD = 1
  4. )(
  5. input clk,
  6. input asy_rst,
  7. input [ I_WD- 1: 0] i_dat,
  8. input i_val,
  9. output reg [ O_WD- 1: 0] o_detect
  10. );
  11. parameter S0= 6'b000001;
  12. parameter S1= 6'b000010;
  13. parameter S2= 6'b000100;
  14. parameter S3= 6'b001000;
  15. parameter S4= 6'b010000;
  16. parameter S5= 6'b100000;
  17. //101101
  18. reg [ 5: 0] curr_s;
  19. reg [ 5: 0] next_s;
  20. //每个时钟只产生一次状态变化
  21. always @(posedge clk or posedge asy_rst)
  22. begin
  23. if(asy_rst)
  24. curr_s <= S0;
  25. else
  26. curr_s <= next_s;
  27. end
  28. //产生的下一状态的组合逻辑
  29. always @(*)
  30. begin
  31. next_s = 'dx;
  32. case(curr_s)
  33. S0: if(i_dat == 1) next_s = S1;
  34. else next_s = S0;
  35. S1: if(i_dat == 0) next_s = S2;
  36. else next_s = S1;
  37. S2: if(i_dat == 1) next_s = S3;
  38. else next_s = S0;
  39. S3: if(i_dat == 1) next_s = S4;
  40. else next_s = S2; ////// 1010---提取10
  41. S4: if(i_dat == 0) next_s = S5;
  42. else next_s = S1;
  43. S5: if(i_dat == 1) next_s = S0;
  44. else next_s = S0;
  45. default: next_s = S0;
  46. endcase
  47. end
  48. /**************************时序逻辑的输出*******************************/
  49. always @(posedge clk or posedge asy_rst)
  50. begin
  51. if(asy_rst)
  52. begin
  53. o_detect <= 0;
  54. end
  55. else
  56. case(curr_s)
  57. S0, S1, S2, S3, S4:
  58. begin
  59. o_detect <= 0;
  60. end
  61. S5:
  62. begin
  63. if(i_dat == 1 ) o_detect <= 1;
  64. end
  65. default :
  66. begin o_detect <= 0; end
  67. endcase
  68. end
  69. endmodule
  70. /////////////////////////////////////testbench/////////////////////////////////////
  71. module seq_detect_sim;
  72. parameter CLK_PERIOD = 10; //仿真周期10ns=100M
  73. parameter RST_CYCLE = 5; //复位周期数
  74. parameter RST_TIME = RST_CYCLE * CLK_PERIOD;
  75. reg sim_clk;
  76. reg sim_asy_rst;
  77. initial
  78. begin
  79. sim_clk = 0;
  80. sim_asy_rst = 1;
  81. # RST_TIME sim_asy_rst = 0;
  82. end
  83. always #( CLK_PERIOD/ 2) sim_clk = ~sim_clk;
  84. /******************************************************/
  85. parameter I_WD = 1;
  86. parameter O_WD = 1;
  87. parameter IN_SEQ = 32'b00101101_01011000_10110111_01010101;
  88. reg [ 4: 0]cnt;
  89. reg sim_i_val;
  90. always @(posedge sim_clk or posedge sim_asy_rst)
  91. begin
  92. if(sim_asy_rst)
  93. begin
  94. cnt <= 0;
  95. sim_i_val <= 0;
  96. end
  97. else
  98. begin
  99. cnt <= cnt + 1;
  100. sim_i_val <= 1;
  101. end
  102. end
  103. wire [ O_WD- 1: 0] o_detect;
  104. seq_detect seq_detect_u (
  105. .clk(sim_clk ),
  106. .asy_rst(sim_asy_rst ),
  107. .i_dat( IN_SEQ[cnt] ),
  108. .i_val(sim_i_val),
  109. .o_detect(o_detect)
  110. );
  111. endmodule

参考资料
[1]“101101”序列检测器Verilog设计实例与VCS仿真(mealy型和moore型)

发布了32 篇原创文章 · 获赞 2 · 访问量 1511

目录

猜你喜欢

转载自blog.csdn.net/qq_36248682/article/details/105443704